diff --git a/data/gui/advanced_menuitem_menu.ui b/data/gui/advanced_menuitem_menu.ui deleted file mode 100644 index e99e020f0..000000000 --- a/data/gui/advanced_menuitem_menu.ui +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - False - - - False - Show _XML Console - True - - - - - True - False - Edit Archi_ving Preferences - True - - - - - False - Edit _Privacy Lists... - True - - - - - False - - - - - False - _Administrator - True - - - False - - - False - Sends a message to users currently connected to this server - _Send Server Message... - True - - - - - True - False - - - - - False - Sets Message of the Day - Set MOTD... - True - - - - - False - Updates Message of the Day - Update MOTD... - True - - - - - False - Deletes Message of the Day - Delete MOTD - - - - - - - - diff --git a/data/gui/application_menu.ui b/data/gui/application_menu.ui new file mode 100644 index 000000000..2be3e5eed --- /dev/null +++ b/data/gui/application_menu.ui @@ -0,0 +1,100 @@ + + + + + Accounts + + + View +
+ + Show Roster + win.show-roster + <Primary>R + + + Show Offline Contacts + win.show-offline + <Primary>O + + + Show Active Contacts + win.show-active + <Primary>Y + + + Show Transports + win.show-transports + +
+
+ + File Transfer + app.file-transfer + <Primary>T + + + History + app.history + +
+
+ + Help +
+ + Contents + app.content + + + FAQ + app.faq + + + Keyboard Shortcuts + app.shortcuts + + + Features + app.features + + + About + app.about + +
+
+
+ +
+ + Accounts + app.accounts + <Primary><Shift>A + + + Bookmarks + app.bookmarks + <Primary>B + + + History Manager + app.history-manager + + + Plugins + app.plugins + + + Preferences + app.preferences + <Primary>P + + + Quit + app.quit + <Primary>Q + +
+
+
\ No newline at end of file diff --git a/data/gui/roster_window.ui b/data/gui/roster_window.ui index 747720e5c..6137d2edf 100644 --- a/data/gui/roster_window.ui +++ b/data/gui/roster_window.ui @@ -25,304 +25,7 @@ False vertical - - True - False - - - True - False - _Actions - True - - - - False - - - True - False - _Start Chat... - True - - - - - False - Send Single _Message... - True - - - - - True - False - Join _Group Chat - True - - - - - True - False - - - - - True - False - Add _Contact... - True - - - - - True - False - _Discover Services - True - - - - - True - False - _Advanced - True - - - - - True - False - - - - - True - False - _Quit - True - - - - - - - - - - - True - False - _Edit - True - - - - False - - - True - False - _Accounts - True - - - - - - - True - False - Profile, A_vatar - True - - - - - True - False - - - - - True - False - _Preferences - True - - - - - - - True - False - P_lugins - True - - - - - - - - - - True - False - _View - True - - - - False - - - True - False - Show _Offline Contacts - True - - - - - - - True - False - Show Only _Active Contacts - True - - - - - - - True - False - Show T_ransports - True - - - - - - True - False - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Show _Roster - True - True - - - - - - - True - False - - - - - True - False - File _Transfers - True - - - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - _History - True - - - - - - - - - - True - False - _Help - True - - - False - - - True - False - Help online - _Contents - True - - - - - - True - False - Frequently Asked Questions (online) - _FAQ - True - - - - - - True - False - Keyboard Shortcuts - True - - - - - - True - False - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Fea_tures - True - - - - - - True - False - _About - True - - - - - - - - - - False - False - 0 - + diff --git a/src/app_actions.py b/src/app_actions.py new file mode 100644 index 000000000..644b40294 --- /dev/null +++ b/src/app_actions.py @@ -0,0 +1,223 @@ +# -*- coding: utf-8 -*- +## src/app_actions.py +## +## Copyright (C) 2017 Philipp Hörist +## +## This file is part of Gajim. +## +## Gajim is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published +## by the Free Software Foundation; version 3 only. +## +## Gajim is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Gajim. If not, see . +## + +from common import helpers +from common import gajim +from common.exceptions import GajimGeneralException +from gi.repository import Gtk +import sys +import os +import config +import dialogs +import features_window +import shortcuts_window +import plugins.gui +import history_window +import disco + + +class AppActions(): + ''' Action Callbacks ''' + def __init__(self, app: Gtk.Application): + self.application = app + + # Application Menu Actions + + def on_preferences(self, action, param): + if 'preferences' in gajim.interface.instances: + gajim.interface.instances['preferences'].window.present() + else: + gajim.interface.instances['preferences'] = \ + config.PreferencesWindow() + + def on_plugins(self, action, param): + if 'plugins' in gajim.interface.instances: + gajim.interface.instances['plugins'].window.present() + else: + gajim.interface.instances['plugins'] = plugins.gui.PluginsWindow() + + def on_accounts(self, action, param): + if 'accounts' in gajim.interface.instances: + gajim.interface.instances['accounts'].window.present() + else: + gajim.interface.instances['accounts'] = config.AccountsWindow() + + def on_history_manager(self, action, param): + if os.name == 'nt': + if os.path.exists('history_manager.exe'): + # user is running frozen application + helpers.exec_command('history_manager.exe') + else: + # user is running from source + helpers.exec_command('%s history_manager.py' % sys.executable) + else: + # Unix user + helpers.exec_command('%s history_manager.py' % sys.executable) + + def on_manage_bookmarks(self, action, param): + config.ManageBookmarksWindow() + + def on_quit(self, action, param): + gajim.interface.roster.on_quit_request() + + # Accounts Actions + + def on_profile(self, action, param): + gajim.interface.edit_own_details(param.get_string()) + + def on_activate_bookmark(self, action, param): + dict_ = param.unpack() + account, jid, nick, password = \ + dict_['account'], dict_['jid'], None, None + if 'nick' in dict_: + nick = dict_['nick'] + if 'password' in dict_: + password = dict_['password'] + gajim.interface.join_gc_room(account, jid, nick, password) + + def on_send_server_message(self, action, param): + account = param.get_string() + server = gajim.config.get_per('accounts', account, 'hostname') + server += '/announce/online' + dialogs.SingleMessageWindow(account, server, 'send') + + def on_service_disco(self, action, param): + account = param.get_string() + server_jid = gajim.config.get_per('accounts', account, 'hostname') + if server_jid in gajim.interface.instances[account]['disco']: + gajim.interface.instances[account]['disco'][server_jid].\ + window.present() + else: + try: + # Object will add itself to the window dict + disco.ServiceDiscoveryWindow(account, address_entry=True) + except GajimGeneralException: + pass + + def on_join_gc(self, action, param): + account = param.get_string() + invisible_show = gajim.SHOW_LIST.index('invisible') + if gajim.connections[account].connected == invisible_show: + dialogs.ErrorDialog(_( + 'You cannot join a group chat while you are invisible')) + return + if 'join_gc' in gajim.interface.instances[account]: + gajim.interface.instances[account]['join_gc'].window.present() + else: + try: + gajim.interface.instances[account]['join_gc'] = \ + dialogs.JoinGroupchatWindow(account) + except GajimGeneralException: + pass + + def on_add_contact(self, action, param): + dialogs.AddNewContactWindow(param.get_string()) + + def on_new_chat(self, action, param): + dialogs.NewChatDialog(param.get_string()) + + def on_single_message(self, action, param): + dialogs.SingleMessageWindow(param.get_string(), action='send') + + # Advanced Actions + + def on_archiving_preferences(self, action, param): + account = param.get_string() + if 'archiving_preferences' in gajim.interface.instances[account]: + gajim.interface.instances[account]['archiving_preferences'].window.\ + present() + else: + if gajim.connections[account].archiving_313_supported: + gajim.interface.instances[account]['archiving_preferences'] = \ + dialogs.Archiving313PreferencesWindow(account) + else: + gajim.interface.instances[account]['archiving_preferences'] = \ + dialogs.ArchivingPreferencesWindow(account) + + def on_privacy_lists(self, action, param): + account = param.get_string() + if 'privacy_lists' in gajim.interface.instances[account]: + gajim.interface.instances[account]['privacy_lists'].window.present() + else: + gajim.interface.instances[account]['privacy_lists'] = \ + dialogs.PrivacyListsWindow(account) + + def on_xml_console(self, action, param): + account = param.get_string() + if 'xml_console' in gajim.interface.instances[account]: + gajim.interface.instances[account]['xml_console'].window.present() + else: + gajim.interface.instances[account]['xml_console'] = \ + dialogs.XMLConsoleWindow(account) + + # Admin Actions + + def on_set_motd(self, action, param): + account = param.get_string() + server = gajim.config.get_per('accounts', account, 'hostname') + server += '/announce/motd' + dialogs.SingleMessageWindow(account, server, 'send') + + def on_update_motd(self, action, param): + account = param.get_string() + server = gajim.config.get_per('accounts', account, 'hostname') + server += '/announce/motd/update' + dialogs.SingleMessageWindow(account, server, 'send') + + def on_delete_motd(self, action, param): + account = param.get_string() + server = gajim.config.get_per('accounts', account, 'hostname') + server += '/announce/motd/delete' + gajim.connections[account].send_motd(server) + + # Help Actions + + def on_contents(self, action, param): + helpers.launch_browser_mailer( + 'url', 'https://dev.gajim.org/gajim/gajim/wikis') + + def on_faq(self, action, param): + helpers.launch_browser_mailer( + 'url', 'https://dev.gajim.org/gajim/gajim/wikis/help/gajimfaq') + + def on_keyboard_shortcuts(self, action, param): + shortcuts_window.show(self.application.get_active_window()) + + def on_features(self, action, param): + features_window.FeaturesWindow() + + def on_about(self, action, param): + dialogs.AboutDialog() + + # View Actions + + def on_file_transfers(self, action, param): + if gajim.interface.instances['file_transfers']. \ + window.get_property('visible'): + gajim.interface.instances['file_transfers'].window.present() + else: + gajim.interface.instances['file_transfers'].window.show_all() + + def on_history(self, action, param): + if 'logs' in gajim.interface.instances: + gajim.interface.instances['logs'].window.present() + else: + gajim.interface.instances['logs'] = history_window.\ + HistoryWindow() diff --git a/src/common/connection.py b/src/common/connection.py index 29b66f4f4..67bcccbd5 100644 --- a/src/common/connection.py +++ b/src/common/connection.py @@ -62,6 +62,8 @@ from common import exceptions from common import check_X509 from common.connection_handlers import * +from gtkgui_helpers import get_action + if gajim.HAVE_PYOPENSSL: import OpenSSL.crypto @@ -2033,6 +2035,7 @@ class Connection(CommonConnection, ConnectionHandlers): break if nbxmpp.NS_VCARD in obj.features: self.vcard_supported = True + get_action(self.name + '-profile').set_enabled(True) if nbxmpp.NS_PUBSUB in obj.features: self.pubsub_supported = True if nbxmpp.NS_PUBSUB_PUBLISH_OPTIONS in obj.features: @@ -2044,6 +2047,7 @@ class Connection(CommonConnection, ConnectionHandlers): if nbxmpp.NS_MAM in obj.features: self.archiving_supported = True self.archiving_313_supported = True + get_action(self.name + '-archive').set_enabled(True) if nbxmpp.NS_ARCHIVE in obj.features: self.archiving_supported = True self.archiving_136_supported = True @@ -2069,6 +2073,7 @@ class Connection(CommonConnection, ConnectionHandlers): self.connection.send(iq) if nbxmpp.NS_PRIVACY in obj.features: self.privacy_rules_supported = True + get_action(self.name + '-privacylists').set_enabled(True) if nbxmpp.NS_BYTESTREAM in obj.features and \ gajim.config.get_per('accounts', self.name, 'use_ft_proxies'): diff --git a/src/common/gajim.py b/src/common/gajim.py index 1346d10ea..c60b5317c 100644 --- a/src/common/gajim.py +++ b/src/common/gajim.py @@ -43,6 +43,7 @@ config = config.Config() version = config.get('version') connections = {} # 'account name': 'account (connection.Connection) instance' ipython_window = None +app = None # Gtk.Application ged = ged_module.GlobalEventsDispatcher() # Global Events Dispatcher nec = None # Network Events Controller diff --git a/src/config.py b/src/config.py index fcfeff885..257646c38 100644 --- a/src/config.py +++ b/src/config.py @@ -48,6 +48,7 @@ import message_control from chat_control_base import ChatControlBase import dataforms_widget import profile_window +import gui_menu_builder try: import gtkspell @@ -2566,7 +2567,8 @@ class AccountsWindow: else: gajim.interface.roster.regroup = False gajim.interface.roster.setup_and_draw_roster() - gajim.interface.roster.set_actions_menu_needs_rebuild() + gajim.app.remove_account_actions(account) + gui_menu_builder.build_accounts_menu() def _enable_account(self, account): if account == gajim.ZEROCONF_ACC_NAME: @@ -2612,7 +2614,8 @@ class AccountsWindow: else: gajim.interface.roster.regroup = False gajim.interface.roster.setup_and_draw_roster() - gajim.interface.roster.set_actions_menu_needs_rebuild() + gajim.app.add_account_actions(account) + gui_menu_builder.build_accounts_menu() def on_enable_zeroconf_checkbutton2_toggled(self, widget): # don't do anything if there is an account with the local name but is a @@ -3154,7 +3157,8 @@ class RemoveAccountWindow: else: gajim.interface.roster.regroup = False gajim.interface.roster.setup_and_draw_roster() - gajim.interface.roster.set_actions_menu_needs_rebuild() + gajim.app.remove_account_actions(self.account) + gui_menu_builder.build_accounts_menu() if 'accounts' in gajim.interface.instances: gajim.interface.instances['accounts'].init_accounts() gajim.interface.instances['accounts'].init_account() @@ -3356,7 +3360,7 @@ class ManageBookmarksWindow: gajim.connections[acct].bookmarks.append(bmdict) gajim.connections[acct].store_bookmarks() - gajim.interface.roster.set_actions_menu_needs_rebuild() + gui_menu_builder.build_bookmark_menu(acct) self.window.destroy() def on_cancel_button_clicked(self, widget): @@ -4091,7 +4095,8 @@ class AccountCreationWizardWindow: else: gajim.interface.roster.regroup = False gajim.interface.roster.setup_and_draw_roster() - gajim.interface.roster.set_actions_menu_needs_rebuild() + gajim.app.add_account_actions(self.account) + gui_menu_builder.build_accounts_menu() class ManagePEPServicesWindow: def __init__(self, account): diff --git a/src/disco.py b/src/disco.py index ff0e13b27..69341a186 100644 --- a/src/disco.py +++ b/src/disco.py @@ -57,6 +57,7 @@ import gtkgui_helpers import groups import adhoc_commands import search_window +import gui_menu_builder from common import gajim import nbxmpp @@ -1852,7 +1853,7 @@ class MucBrowser(AgentBrowser): gajim.connections[self.account].bookmarks.append(bm) gajim.connections[self.account].store_bookmarks() - gajim.interface.roster.set_actions_menu_needs_rebuild() + gui_menu_builder.build_bookmark_menu(self.account) dialogs.InformationDialog( _('Bookmark has been added successfully'), diff --git a/src/gajim.py b/src/gajim.py index 76a43a024..59e3b126b 100644 --- a/src/gajim.py +++ b/src/gajim.py @@ -233,11 +233,23 @@ class GajimApplication(Gtk.Application): print("Encodings: d:{}, fs:{}, p:{}".format(sys.getdefaultencoding(), sys.getfilesystemencoding(), locale.getpreferredencoding())) + # Set Application Menu + gajim.app = self + path = os.path.join(configpaths.get('GUI'), 'application_menu.ui') + builder = Gtk.Builder() + builder.set_translation_domain(i18n.APP) + builder.add_from_file(path) + self.set_menubar(builder.get_object("menubar")) + self.set_app_menu(builder.get_object("appmenu")) + def do_activate(self): Gtk.Application.do_activate(self) from gui_interface import Interface self.interface = Interface() self.interface.run(self) + self.add_actions() + import gui_menu_builder + gui_menu_builder.build_accounts_menu() def do_shutdown(self, *args): Gtk.Application.do_shutdown(self) @@ -315,6 +327,91 @@ class GajimApplication(Gtk.Application): sys.stderr = outerr warnings.filterwarnings(action='ignore') + def add_actions(self): + ''' Build Application Actions ''' + from app_actions import AppActions + action = AppActions(self) + + self.account_actions = [ + ('-start-single-chat', action.on_single_message, 'online', 's'), + ('-start-chat', action.on_new_chat, 'online', 's'), + ('-join-groupchat', action.on_join_gc, 'online', 's'), + ('-add-contact', action.on_add_contact, 'online', 's'), + ('-services', action.on_service_disco, 'online', 's'), + ('-profile', action.on_profile, 'feature', 's'), + ('-xml-console', action.on_xml_console, 'always', 's'), + ('-archive', action.on_archiving_preferences, 'feature', 's'), + ('-privacylists', action.on_privacy_lists, 'feature', 's'), + ('-send-server-message', + action.on_send_server_message, 'online', 's'), + ('-set-motd', action.on_set_motd, 'online', 's'), + ('-update-motd', action.on_update_motd, 'online', 's'), + ('-delete-motd', action.on_delete_motd, 'online', 's'), + ('-activate-bookmark', + action.on_activate_bookmark, 'online', 'a{sv}') + ] + + self.general_actions = [ + ('quit', action.on_quit), + ('accounts', action.on_accounts), + ('bookmarks', action.on_manage_bookmarks), + ('history-manager', action.on_history_manager), + ('preferences', action.on_preferences), + ('plugins', action.on_plugins), + ('file-transfer', action.on_file_transfers), + ('history', action.on_history), + ('shortcuts', action.on_keyboard_shortcuts), + ('features', action.on_features), + ('content', action.on_contents), + ('about', action.on_about), + ('faq', action.on_faq) + ] + + for action in self.general_actions: + action_name, func = action + act = Gio.SimpleAction.new(action_name, None) + act.connect("activate", func) + self.add_action(act) + + from common import gajim + accounts_list = sorted(gajim.contacts.get_accounts()) + if not accounts_list: + return + if len(accounts_list) > 1: + for acc in accounts_list: + self.add_account_actions(acc) + else: + self.add_account_actions(accounts_list[0]) + + def add_account_actions(self, account): + for action in self.account_actions: + action_name, func, state, type_ = action + action_name = account + action_name + if self.lookup_action(action_name): + # We already added this action + continue + act = Gio.SimpleAction.new( + action_name, GLib.VariantType.new(type_)) + act.connect("activate", func) + if state != 'always': + act.set_enabled(False) + self.add_action(act) + + def remove_account_actions(self, account): + for action in self.account_actions: + action_name = account + action[0] + self.remove_action(action_name) + + def set_account_actions_state(self, account, new_state=False): + for action in self.account_actions: + action_name, _, state, _ = action + if not new_state and state in ('online', 'feature'): + # We go offline + self.lookup_action(account + action_name).set_enabled(False) + elif new_state and state == 'online': + # We go online + self.lookup_action(account + action_name).set_enabled(True) + app = GajimApplication() app.run(sys.argv) diff --git a/src/gtkgui_helpers.py b/src/gtkgui_helpers.py index 1ab87acc9..28e4075a9 100644 --- a/src/gtkgui_helpers.py +++ b/src/gtkgui_helpers.py @@ -1085,3 +1085,6 @@ def __label_size_allocate(widget, allocation): if lh_old != lh: widget.set_size_request (-1, lh / Pango.SCALE) + +def get_action(action): + return gajim.app.lookup_action(action) diff --git a/src/gui_interface.py b/src/gui_interface.py index 13831827e..20dc64f14 100644 --- a/src/gui_interface.py +++ b/src/gui_interface.py @@ -56,7 +56,7 @@ if dbus_support.supported: import dbus import gtkgui_helpers - +import gui_menu_builder import dialogs import notify import message_control @@ -843,7 +843,7 @@ class Interface: # We received a bookmark item from the server (JEP48) # Auto join GC windows if neccessary - self.roster.set_actions_menu_needs_rebuild() + gui_menu_builder.build_bookmark_menu(obj.conn.name) invisible_show = gajim.SHOW_LIST.index('invisible') # do not autojoin if we are invisible if obj.conn.connected == invisible_show: @@ -2661,7 +2661,7 @@ class Interface: else: gajim.connections[account].bookmarks.append(bm) gajim.connections[account].store_bookmarks() - self.roster.set_actions_menu_needs_rebuild() + gui_menu_builder.build_bookmark_menu(account) dialogs.InformationDialog( _('Bookmark has been added successfully'), _('You can manage your bookmarks via Actions menu in your roster.')) diff --git a/src/gui_menu_builder.py b/src/gui_menu_builder.py index 1865746af..835b78578 100644 --- a/src/gui_menu_builder.py +++ b/src/gui_menu_builder.py @@ -18,15 +18,17 @@ ## along with Gajim. If not, see . ## -from gi.repository import Gtk +from gi.repository import Gtk, Gio, GLib import os import gtkgui_helpers import message_control from common import gajim from common import helpers +from common import i18n from nbxmpp.protocol import NS_COMMANDS, NS_FILE, NS_MUC, NS_ESESSION from nbxmpp.protocol import NS_JINGLE_FILE_TRANSFER, NS_CONFERENCE +from gtkgui_helpers import get_action def build_resources_submenu(contacts, account, action, room_jid=None, room_account=None, cap=None): @@ -636,3 +638,146 @@ def get_transport_menu(contact, account): menu.show_all() return menu +''' +Build dynamic Application Menus +''' + + +def get_bookmarks_menu(account, rebuild=False): + if not gajim.connections[account].bookmarks: + return None + menu = Gio.Menu() + + # Build Join Groupchat + action = 'app.{}-join-groupchat'.format(account) + menuitem = Gio.MenuItem.new(_('Join Group Chat'), action) + variant = GLib.Variant('s', account) + menuitem.set_action_and_target_value(action, variant) + menu.append_item(menuitem) + + # Build Bookmarks + section = Gio.Menu() + for bookmark in gajim.connections[account].bookmarks: + name = bookmark['name'] + if not name: + # No name was given for this bookmark. + # Use the first part of JID instead... + name = bookmark['jid'].split("@")[0] + + # Shorten long names + name = (name[:42] + '..') if len(name) > 42 else name + + action = 'app.{}-activate-bookmark'.format(account) + menuitem = Gio.MenuItem.new(name, action) + + # Create Variant Dict + dict_ = {'account': GLib.Variant('s', account), + 'jid': GLib.Variant('s', bookmark['jid'])} + if bookmark['nick']: + dict_['nick'] = GLib.Variant('s', bookmark['nick']) + if bookmark['password']: + dict_['password'] = GLib.Variant('s', bookmark['password']) + variant_dict = GLib.Variant('a{sv}', dict_) + + menuitem.set_action_and_target_value(action, variant_dict) + section.append_item(menuitem) + menu.append_section(None, section) + if not rebuild: + get_action(account + '-activate-bookmark').set_enabled(True) + + return menu + + +def get_account_menu(account): + ''' + [(action, label/sub_menu)] + action: string + label: string + sub menu: list + ''' + account_menu = [ + ('-add-contact', _('Add Contact...')), + ('-join-groupchat', _('Join Group Chat')), + ('-profile', _('Profile')), + ('-services', _('Discover Services')), + ('-start-chat', _('Start Chat...')), + ('-start-single-chat', _('Send Single Message...')), + ('Advanced', [ + ('-archive', _('Archiving Preferences')), + ('-privacylists', _('Privacy Lists')), + ('-xml-console', _('XML Console')) + ]), + ('Admin', [ + ('-send-server-message', _('Send Server Message...')), + ('-set-motd', _('Set MOTD...')), + ('-update-motd', _('Update MOTD...')), + ('-delete-motd', _('Delete MOTD...')) + ]), + ] + + def build_menu(preset): + menu = Gio.Menu() + for item in preset: + if isinstance(item[1], str): + action, label = item + if action == '-join-groupchat': + bookmark_menu = get_bookmarks_menu(account, True) + if bookmark_menu: + menu.append_submenu(label, bookmark_menu) + continue + action = 'app.{}{}'.format(account, action) + menuitem = Gio.MenuItem.new(label, action) + variant = GLib.Variant('s', account) + menuitem.set_action_and_target_value(action, variant) + menu.append_item(menuitem) + else: + label, sub_menu = item + # This is a submenu + submenu = build_menu(sub_menu) + menu.append_submenu(label, submenu) + return menu + + return build_menu(account_menu) + + +def build_accounts_menu(): + menubar = gajim.app.get_menubar() + # Accounts Submenu + acc_menu = menubar.get_item_link(0, 'submenu') + acc_menu.remove_all() + accounts_list = sorted(gajim.contacts.get_accounts()) + if not accounts_list: + no_accounts = _('No Accounts available') + acc_menu.append_item(Gio.MenuItem.new(no_accounts, None)) + return + if len(accounts_list) > 1: + for acc in accounts_list: + acc_menu.append_submenu( + acc, get_account_menu(acc)) + else: + acc_menu = get_account_menu(accounts_list[0]) + menubar.remove(0) + menubar.insert_submenu(0, 'Accounts', acc_menu) + + +def build_bookmark_menu(account): + menubar = gajim.app.get_menubar() + bookmark_menu = get_bookmarks_menu(account) + if not bookmark_menu: + return + + # Accounts Submenu + acc_menu = menubar.get_item_link(0, 'submenu') + + # We have more than one Account active + if acc_menu.get_item_link(0, 'submenu'): + for i in range(acc_menu.get_n_items()): + label = acc_menu.get_item_attribute_value(i, 'label') + if label.get_string() == account: + menu = acc_menu.get_item_link(i, 'submenu') + else: + # We have only one Account active + menu = acc_menu + label = menu.get_item_attribute_value(1, 'label').get_string() + menu.remove(1) + menu.insert_submenu(1, label, bookmark_menu) diff --git a/src/message_window.py b/src/message_window.py index 209c9e624..c4c6a5d16 100644 --- a/src/message_window.py +++ b/src/message_window.py @@ -41,6 +41,7 @@ import dialogs from chat_control_base import ChatControlBase from common import gajim +from gtkgui_helpers import get_action #################### @@ -97,8 +98,7 @@ class MessageWindow(object): else: self.parent_paned.add(self.notebook) self.parent_paned.pack2(self.notebook, resize=True, shrink=True) - gajim.interface.roster.xml.get_object('show_roster_menuitem').\ - set_sensitive(True) + get_action('show-roster').set_enabled(True) orig_window.destroy() del orig_window @@ -626,8 +626,7 @@ class MessageWindow(object): # Don't close parent window, just remove the child child = self.parent_paned.get_child2() self.parent_paned.remove(child) - gajim.interface.roster.xml.get_object('show_roster_menuitem').\ - set_sensitive(False) + get_action('show-roster').set_enabled(False) else: self.window.destroy() return # don't show_title, we are dead @@ -1273,8 +1272,7 @@ class MessageWindowMgr(GObject.GObject): # Don't close parent window, just remove the child child = w.parent_paned.get_child2() w.parent_paned.remove(child) - gajim.interface.roster.xml.get_object('show_roster_menuitem').\ - set_sensitive(False) + get_action('show-roster').set_enabled(False) gtkgui_helpers.resize_window(w.window, gajim.config.get('roster_width'), gajim.config.get('roster_height')) diff --git a/src/roster_window.py b/src/roster_window.py index e066b170c..655560489 100644 --- a/src/roster_window.py +++ b/src/roster_window.py @@ -38,8 +38,8 @@ from gi.repository import GdkPixbuf from gi.repository import Pango from gi.repository import GObject from gi.repository import GLib +from gi.repository import Gio import os -import sys import time import locale @@ -57,10 +57,6 @@ import cell_renderer_image import tooltips import message_control import adhoc_commands -import features_window -import shortcuts_window -import plugins -import plugins.gui from common import gajim from common import helpers @@ -69,11 +65,10 @@ from common import i18n from common import location_listener from common import ged from common import dbus_support - from message_window import MessageWindowMgr - from nbxmpp.protocol import NS_FILE, NS_ROSTERX, NS_CONFERENCE + class Column(IntEnum): IMG = 0 # image to show state (online, new message etc) NAME = 1 # cellrenderer text that holds contact nickame @@ -2297,7 +2292,6 @@ class RosterWindow: for contact in [c for c in lcontact if ( (c.show != 'offline' or c.is_transport()) and not ctrl)]: self.chg_contact_status(contact, 'offline', '', account) - self.set_actions_menu_needs_rebuild() self.update_status_combobox() def get_status_message(self, show, on_response, show_pep=True, @@ -2676,6 +2670,7 @@ class RosterWindow: # sensitivity for this menuitem if gajim.get_number_of_connected_accounts() == 0: model[self.status_message_menuitem_iter][3] = False + self.application.set_account_actions_state(obj.conn.name) else: # sensitivity for this menuitem model[self.status_message_menuitem_iter][3] = True @@ -2714,7 +2709,7 @@ class RosterWindow: self.redraw_metacontacts(obj.conn.name) def _nec_signed_in(self, obj): - self.set_actions_menu_needs_rebuild() + self.application.set_account_actions_state(obj.conn.name, True) self.draw_account(obj.conn.name) def _nec_decrypted_message_received(self, obj): @@ -2776,74 +2771,10 @@ class RosterWindow: ### FIXME: order callbacks in itself... ################################################################################ - def on_actions_menuitem_activate(self, widget): - self.make_menu() - - def on_edit_menuitem_activate(self, widget): - """ - Need to call make_menu to build profile, avatar item - """ - self.make_menu() - def on_bookmark_menuitem_activate(self, widget, account, bookmark): gajim.interface.join_gc_room(account, bookmark['jid'], bookmark['nick'], bookmark['password']) - def on_send_server_message_menuitem_activate(self, widget, account): - server = gajim.config.get_per('accounts', account, 'hostname') - server += '/announce/online' - dialogs.SingleMessageWindow(account, server, 'send') - - def on_xml_console_menuitem_activate(self, widget, account): - if 'xml_console' in gajim.interface.instances[account]: - gajim.interface.instances[account]['xml_console'].window.present() - else: - gajim.interface.instances[account]['xml_console'] = \ - dialogs.XMLConsoleWindow(account) - - def on_archiving_preferences_menuitem_activate(self, widget, account): - if 'archiving_preferences' in gajim.interface.instances[account]: - gajim.interface.instances[account]['archiving_preferences'].window.\ - present() - else: - if gajim.connections[account].archiving_313_supported: - gajim.interface.instances[account]['archiving_preferences'] = \ - dialogs.Archiving313PreferencesWindow(account) - else: - gajim.interface.instances[account]['archiving_preferences'] = \ - dialogs.ArchivingPreferencesWindow(account) - - def on_privacy_lists_menuitem_activate(self, widget, account): - if 'privacy_lists' in gajim.interface.instances[account]: - gajim.interface.instances[account]['privacy_lists'].window.present() - else: - gajim.interface.instances[account]['privacy_lists'] = \ - dialogs.PrivacyListsWindow(account) - - def on_set_motd_menuitem_activate(self, widget, account): - server = gajim.config.get_per('accounts', account, 'hostname') - server += '/announce/motd' - dialogs.SingleMessageWindow(account, server, 'send') - - def on_update_motd_menuitem_activate(self, widget, account): - server = gajim.config.get_per('accounts', account, 'hostname') - server += '/announce/motd/update' - dialogs.SingleMessageWindow(account, server, 'send') - - def on_delete_motd_menuitem_activate(self, widget, account): - server = gajim.config.get_per('accounts', account, 'hostname') - server += '/announce/motd/delete' - gajim.connections[account].send_motd(server) - - def on_history_manager_menuitem_activate(self, widget): - if os.name == 'nt': - if os.path.exists('history_manager.exe'): # user is running stable - helpers.exec_command('history_manager.exe') - else: # user is running svn - helpers.exec_command('%s history_manager.py' % sys.executable) - else: # Unix user - helpers.exec_command('%s history_manager.py' % sys.executable) - def on_info(self, widget, contact, account): """ Call vcard_information_window class to display contact's information @@ -3765,19 +3696,6 @@ class RosterWindow: self.get_status_message(status, on_continue) - def on_preferences_menuitem_activate(self, widget): - if 'preferences' in gajim.interface.instances: - gajim.interface.instances['preferences'].window.present() - else: - gajim.interface.instances['preferences'] = config.PreferencesWindow( - ) - - def on_plugins_menuitem_activate(self, widget): - if 'plugins' in gajim.interface.instances: - gajim.interface.instances['plugins'].window.present() - else: - gajim.interface.instances['plugins'] = plugins.gui.PluginsWindow() - def on_publish_tune_toggled(self, widget, account): active = widget.get_active() gajim.config.set_per('accounts', account, 'publish_tune', active) @@ -3841,52 +3759,14 @@ class RosterWindow: def on_new_chat_menuitem_activate(self, widget, account): dialogs.NewChatDialog(account) - def on_contents_menuitem_activate(self, widget): - helpers.launch_browser_mailer('url', 'http://trac.gajim.org/wiki') - - def on_faq_menuitem_activate(self, widget): - helpers.launch_browser_mailer('url', - 'http://trac.gajim.org/wiki/GajimFaq') - - def on_keyboard_shortcuts_menuitem_activate(self, widget): - shortcuts_window.show(self.window) - - def on_features_menuitem_activate(self, widget): - features_window.FeaturesWindow() - - def on_about_menuitem_activate(self, widget): - dialogs.AboutDialog() - - def on_accounts_menuitem_activate(self, widget): - if 'accounts' in gajim.interface.instances: - gajim.interface.instances['accounts'].window.present() - else: - gajim.interface.instances['accounts'] = config.AccountsWindow() - - def on_file_transfers_menuitem_activate(self, widget): - if gajim.interface.instances['file_transfers'].window.get_property( - 'visible'): - gajim.interface.instances['file_transfers'].window.present() - else: - gajim.interface.instances['file_transfers'].window.show_all() - - def on_history_menuitem_activate(self, widget): - if 'logs' in gajim.interface.instances: - gajim.interface.instances['logs'].window.present() - else: - gajim.interface.instances['logs'] = history_window.\ - HistoryWindow() - - def on_show_transports_menuitem_activate(self, widget): - gajim.config.set('show_transports_group', widget.get_active()) + def on_show_transports_action(self, action, param): + gajim.config.set('show_transports_group', param.get_boolean()) + action.set_state(param) self.refilter_shown_roster_items() def on_manage_bookmarks_menuitem_activate(self, widget): config.ManageBookmarksWindow() - def on_profile_avatar_menuitem_activate(self, widget, account): - gajim.interface.edit_own_details(account) - def on_execute_command(self, widget, contact, account, resource=None): """ Execute command. Full JID needed; if it is other contact, resource is @@ -4216,6 +4096,7 @@ class RosterWindow: # account = row[Column.ACCOUNT] # self._last_selected_contact.append((jid, account)) # GLib.idle_add(self.draw_contact, jid, account, True) + def on_service_disco_menuitem_activate(self, widget, account): server_jid = gajim.config.get_per('accounts', account, 'hostname') @@ -4229,50 +4110,43 @@ class RosterWindow: except GajimGeneralException: pass - def on_show_offline_contacts_menuitem_activate(self, widget): + def on_show_offline_contacts_action(self, action, param): """ When show offline option is changed: redraw the treeview """ - gajim.config.set('showoffline', not gajim.config.get('showoffline')) + action.set_state(param) + gajim.config.set('showoffline', param.get_boolean()) self.refilter_shown_roster_items() - w = self.xml.get_object('show_only_active_contacts_menuitem') - if gajim.config.get('showoffline'): + if param.get_boolean(): # We need to filter twice to show groups with no contacts inside # in the correct expand state self.refilter_shown_roster_items() - w.set_sensitive(False) + self.window.lookup_action('show-active').set_enabled(False) else: - w.set_sensitive(True) + self.window.lookup_action('show-active').set_enabled(True) - def on_show_only_active_contacts_menuitem_activate(self, widget): + def on_show_active_contacts_action(self, action, param): """ When show only active contact option is changed: redraw the treeview """ - gajim.config.set('show_only_chat_and_online', not gajim.config.get( - 'show_only_chat_and_online')) + action.set_state(param) + gajim.config.set('show_only_chat_and_online', param.get_boolean()) self.refilter_shown_roster_items() - w = self.xml.get_object('show_offline_contacts_menuitem') - if gajim.config.get('show_only_chat_and_online'): + + if param.get_boolean(): # We need to filter twice to show groups with no contacts inside # in the correct expand state self.refilter_shown_roster_items() - w.set_sensitive(False) + self.window.lookup_action('show-offline').set_enabled(False) else: - w.set_sensitive(True) + self.window.lookup_action('show-offline').set_enabled(True) - def on_view_menu_activate(self, widget): - self.make_menu() - # Hide the show roster menu if we are not in the right windowing mode. - if self.hpaned.get_child2() is not None: - self.xml.get_object('show_roster_menuitem').show() - else: - self.xml.get_object('show_roster_menuitem').hide() - - def on_show_roster_menuitem_toggled(self, widget): + def on_show_roster_action(self, action, param): # when num controls is 0 this menuitem is hidden, but still need to # disable keybinding + action.set_state(param) if self.hpaned.get_child2() is not None: - self.show_roster_vbox(widget.get_active()) + self.show_roster_vbox(param.get_boolean()) def on_rfilter_entry_changed(self, widget): """ When we update the content of the filter """ @@ -4337,7 +4211,9 @@ class RosterWindow: self._readjust_expand_collapse_state() # If roster was hidden before enable_rfilter was called, hide it back. - self.on_show_roster_menuitem_toggled(self.xml.get_object('show_roster_menuitem')) + state = self.window.lookup_action('show-roster').get_state().get_boolean() + if state is False and self.hpaned.get_child2() is not None: + self.show_roster_vbox(False) def on_roster_hpaned_notify(self, pane, gparamspec): """ @@ -5164,276 +5040,6 @@ class RosterWindow: ### FIXME: We really need to make it simpler! 1465 lines are a few to much.... ################################################################################ - def make_menu(self, force=False): - """ - Create the main window's menus - """ - if not force and not self.actions_menu_needs_rebuild: - return - history_menuitem = self.xml.get_object('history_menuitem') - new_chat_menuitem = self.xml.get_object('new_chat_menuitem') - single_message_menuitem = self.xml.get_object( - 'send_single_message_menuitem') - join_gc_menuitem = self.xml.get_object('join_gc_menuitem') - add_new_contact_menuitem = self.xml.get_object( - 'add_new_contact_menuitem') - service_disco_menuitem = self.xml.get_object('service_disco_menuitem') - advanced_menuitem = self.xml.get_object('advanced_menuitem') - profile_avatar_menuitem = self.xml.get_object('profile_avatar_menuitem') - - # destroy old advanced menus - for m in self.advanced_menus: - m.destroy() - - # make it sensitive. it is insensitive only if no accounts are - # *available* - advanced_menuitem.set_sensitive(True) - - if self.add_new_contact_handler_id: - add_new_contact_menuitem.handler_disconnect( - self.add_new_contact_handler_id) - self.add_new_contact_handler_id = None - - if self.service_disco_handler_id: - service_disco_menuitem.handler_disconnect( - self.service_disco_handler_id) - self.service_disco_handler_id = None - - if self.single_message_menuitem_handler_id: - single_message_menuitem.handler_disconnect( - self.single_message_menuitem_handler_id) - self.single_message_menuitem_handler_id = None - - if self.profile_avatar_menuitem_handler_id: - profile_avatar_menuitem.handler_disconnect( - self.profile_avatar_menuitem_handler_id) - self.profile_avatar_menuitem_handler_id = None - - # remove the existing submenus - add_new_contact_menuitem.set_submenu(None) - service_disco_menuitem.set_submenu(None) - join_gc_menuitem.set_submenu(None) - single_message_menuitem.set_submenu(None) - advanced_menuitem.set_submenu(None) - profile_avatar_menuitem.set_submenu(None) - - gc_sub_menu = Gtk.Menu() # gc is always a submenu - join_gc_menuitem.set_submenu(gc_sub_menu) - - connected_accounts = gajim.get_number_of_connected_accounts() - - connected_accounts_with_private_storage = 0 - - # items that get shown whether an account is zeroconf or not - accounts_list = sorted(gajim.contacts.get_accounts()) - if connected_accounts > 2 or \ - (connected_accounts > 1 and not gajim.zeroconf_is_connected()): - # 2 or more "real" (no zeroconf) accounts? make submenus - new_chat_sub_menu = Gtk.Menu() - - for account in accounts_list: - if gajim.connections[account].connected <= 1 or \ - gajim.config.get_per('accounts', account, 'is_zeroconf'): - # if offline or connecting or zeroconf - continue - - # new chat - new_chat_item = Gtk.MenuItem.new_with_label( - _('using account %s') % account) - new_chat_item.set_use_underline(False) - new_chat_sub_menu.append(new_chat_item) - new_chat_item.connect('activate', - self.on_new_chat_menuitem_activate, account) - - new_chat_menuitem.set_submenu(new_chat_sub_menu) - new_chat_sub_menu.show_all() - - # menu items that don't apply to zeroconf connections - if connected_accounts == 1 or (connected_accounts == 2 and \ - gajim.zeroconf_is_connected()): - # only one 'real' (non-zeroconf) account is connected, don't need - # submenus - - for account in accounts_list: - if gajim.account_is_connected(account) and \ - not gajim.config.get_per('accounts', account, 'is_zeroconf'): - # gc - if gajim.connections[account].private_storage_supported: - connected_accounts_with_private_storage += 1 - self.add_bookmarks_list(gc_sub_menu, account) - gc_sub_menu.show_all() - # add - if not self.add_new_contact_handler_id: - self.add_new_contact_handler_id = \ - add_new_contact_menuitem.connect( - 'activate', self.on_add_new_contact, account) - # disco - if not self.service_disco_handler_id: - self.service_disco_handler_id = service_disco_menuitem.\ - connect('activate', - self.on_service_disco_menuitem_activate, account) - - # single message - if not self.single_message_menuitem_handler_id: - self.single_message_menuitem_handler_id = \ - single_message_menuitem.connect('activate', \ - self.on_send_single_message_menuitem_activate, account) - - break # No other account connected - else: - # 2 or more 'real' accounts are connected, make submenus - single_message_sub_menu = Gtk.Menu() - add_sub_menu = Gtk.Menu() - disco_sub_menu = Gtk.Menu() - - for account in accounts_list: - if gajim.connections[account].connected <= 1 or \ - gajim.config.get_per('accounts', account, 'is_zeroconf'): - # skip account if it's offline or connecting or is zeroconf - continue - - # single message - single_message_item = Gtk.MenuItem.new_with_label( - _('using account %s') % account) - single_message_item.set_use_underline(False) - single_message_sub_menu.append(single_message_item) - single_message_item.connect('activate', - self.on_send_single_message_menuitem_activate, account) - - # join gc - if gajim.connections[account].private_storage_supported: - connected_accounts_with_private_storage += 1 - gc_item = Gtk.MenuItem.new_with_label( - _('using account %s') % account) - gc_item.set_use_underline(False) - gc_sub_menu.append(gc_item) - gc_menuitem_menu = Gtk.Menu() - self.add_bookmarks_list(gc_menuitem_menu, account) - gc_item.set_submenu(gc_menuitem_menu) - - # add - add_item = Gtk.MenuItem.new_with_label( - _('to %s account') % account) - add_item.set_use_underline(False) - add_sub_menu.append(add_item) - add_item.connect('activate', self.on_add_new_contact, account) - - # disco - disco_item = Gtk.MenuItem.new_with_label( - _('using %s account') % account) - disco_item.set_use_underline(False) - disco_sub_menu.append(disco_item) - disco_item.connect('activate', - self.on_service_disco_menuitem_activate, account) - - single_message_menuitem.set_submenu(single_message_sub_menu) - single_message_sub_menu.show_all() - gc_sub_menu.show_all() - add_new_contact_menuitem.set_submenu(add_sub_menu) - add_sub_menu.show_all() - service_disco_menuitem.set_submenu(disco_sub_menu) - disco_sub_menu.show_all() - - if connected_accounts == 0: - # no connected accounts, make the menuitems insensitive - for item in (new_chat_menuitem, join_gc_menuitem, - add_new_contact_menuitem, service_disco_menuitem, - single_message_menuitem): - item.set_sensitive(False) - else: # we have one or more connected accounts - for item in (new_chat_menuitem, join_gc_menuitem, - add_new_contact_menuitem, service_disco_menuitem, - single_message_menuitem): - item.set_sensitive(True) - # disable some fields if only local account is there - if connected_accounts == 1: - for account in gajim.connections: - if gajim.account_is_connected(account) and \ - gajim.connections[account].is_zeroconf: - for item in (new_chat_menuitem, join_gc_menuitem, - add_new_contact_menuitem, service_disco_menuitem, - single_message_menuitem): - item.set_sensitive(False) - - # Manage GC bookmarks - newitem = Gtk.SeparatorMenuItem.new() # separator - gc_sub_menu.append(newitem) - - newitem = Gtk.MenuItem.new_with_mnemonic(_('_Manage Bookmarks…')) - newitem.connect('activate', self.on_manage_bookmarks_menuitem_activate) - gc_sub_menu.append(newitem) - gc_sub_menu.show_all() - if connected_accounts_with_private_storage == 0: - newitem.set_sensitive(False) - - connected_accounts_with_vcard = [] - for account in gajim.connections: - if gajim.account_is_connected(account) and \ - gajim.connections[account].vcard_supported: - connected_accounts_with_vcard.append(account) - if len(connected_accounts_with_vcard) > 1: - # 2 or more accounts? make submenus - profile_avatar_sub_menu = Gtk.Menu() - for account in connected_accounts_with_vcard: - # profile, avatar - profile_avatar_item = Gtk.MenuItem.new_with_label( - _('of account %s') % account) - profile_avatar_item.set_use_underline(False) - profile_avatar_sub_menu.append(profile_avatar_item) - profile_avatar_item.connect('activate', - self.on_profile_avatar_menuitem_activate, account) - profile_avatar_menuitem.set_submenu(profile_avatar_sub_menu) - profile_avatar_sub_menu.show_all() - elif len(connected_accounts_with_vcard) == 1: - # user has only one account - account = connected_accounts_with_vcard[0] - # profile, avatar - if not self.profile_avatar_menuitem_handler_id: - self.profile_avatar_menuitem_handler_id = \ - profile_avatar_menuitem.connect('activate', - self.on_profile_avatar_menuitem_activate, account) - - if len(connected_accounts_with_vcard) == 0: - profile_avatar_menuitem.set_sensitive(False) - else: - profile_avatar_menuitem.set_sensitive(True) - - # Advanced Actions - if len(gajim.connections) == 0: # user has no accounts - advanced_menuitem.set_sensitive(False) - elif len(gajim.connections) == 1: # we have one acccount - account = list(gajim.connections.keys())[0] - advanced_menuitem_menu = \ - self.get_and_connect_advanced_menuitem_menu(account) - self.advanced_menus.append(advanced_menuitem_menu) - - self.add_history_manager_menuitem(advanced_menuitem_menu) - - advanced_menuitem.set_submenu(advanced_menuitem_menu) - advanced_menuitem_menu.show_all() - else: # user has *more* than one account : build advanced submenus - advanced_sub_menu = Gtk.Menu() - accounts = [] # Put accounts in a list to sort them - for account in gajim.connections: - accounts.append(account) - accounts.sort() - for account in accounts: - advanced_item = Gtk.MenuItem.new_with_label( - _('for account %s') % account) - advanced_item.set_use_underline(False) - advanced_sub_menu.append(advanced_item) - advanced_menuitem_menu = \ - self.get_and_connect_advanced_menuitem_menu(account) - self.advanced_menus.append(advanced_menuitem_menu) - advanced_item.set_submenu(advanced_menuitem_menu) - - self.add_history_manager_menuitem(advanced_sub_menu) - - advanced_menuitem.set_submenu(advanced_sub_menu) - advanced_sub_menu.show_all() - - self.actions_menu_needs_rebuild = False - def build_account_menu(self, account): # we have to create our own set of icons for the menu # using self.jabber_status_images is poopoo @@ -6032,34 +5638,6 @@ class RosterWindow: account, bookmark) gc_sub_menu.append(item) - def set_actions_menu_needs_rebuild(self): - self.actions_menu_needs_rebuild = True - # Just handle new_chat_menuitem to have ctrl+N working even if we don't - # open the menu - new_chat_menuitem = self.xml.get_object('new_chat_menuitem') - ag = Gtk.accel_groups_from_object(self.window)#[0] - - if self.new_chat_menuitem_handler_id: - new_chat_menuitem.handler_disconnect( - self.new_chat_menuitem_handler_id) - self.new_chat_menuitem_handler_id = None - - new_chat_menuitem.set_submenu(None) - - connected_accounts = gajim.get_number_of_connected_accounts() - if connected_accounts == 1 or (connected_accounts == 2 and \ - gajim.zeroconf_is_connected()): - # only one 'real' (non-zeroconf) account is connected, don't need - # submenus - accounts_list = sorted(gajim.contacts.get_accounts()) - for account in accounts_list: - if gajim.account_is_connected(account) and \ - not gajim.config.get_per('accounts', account, 'is_zeroconf'): - if not self.new_chat_menuitem_handler_id: - self.new_chat_menuitem_handler_id = new_chat_menuitem.\ - connect('activate', - self.on_new_chat_menuitem_activate, account) - def show_appropriate_context_menu(self, event, iters): # iters must be all of the same type model = self.modelfilter @@ -6170,6 +5748,36 @@ class RosterWindow: tooltip.populate(connected_contacts, account, typ) return True + def add_actions(self): + action = Gio.SimpleAction.new_stateful( + "show-roster", None, + GLib.Variant.new_boolean( + not self.xml.get_object('roster_vbox2').get_no_show_all())) + action.connect("change-state", + self.on_show_roster_action) + self.window.add_action(action) + + action = Gio.SimpleAction.new_stateful( + "show-offline", None, + GLib.Variant.new_boolean(gajim.config.get('showoffline'))) + action.connect("change-state", + self.on_show_offline_contacts_action) + self.window.add_action(action) + + action = Gio.SimpleAction.new_stateful( + "show-active", None, + GLib.Variant.new_boolean( + gajim.config.get('show_only_chat_and_online'))) + action.connect("change-state", + self.on_show_active_contacts_action) + self.window.add_action(action) + + action = Gio.SimpleAction.new_stateful( + "show-transports", None, + GLib.Variant.new_boolean(gajim.config.get('show_transports_group'))) + action.connect("change-state", self.on_show_transports_action) + self.window.add_action(action) + ################################################################################ ### ################################################################################ @@ -6192,6 +5800,7 @@ class RosterWindow: self.xml = gtkgui_helpers.get_gtk_builder('roster_window.ui') self.window = self.xml.get_object('roster_window') app.add_window(self.window) + self.add_actions() self.hpaned = self.xml.get_object('roster_hpaned') gajim.interface.msg_win_mgr = MessageWindowMgr(self.window, self.hpaned) gajim.interface.msg_win_mgr.connect('window-delete', @@ -6223,7 +5832,6 @@ class RosterWindow: #FIXME: When list_accel_closures will be wrapped in pygtk # no need of this variable self.have_new_chat_accel = False # Is the "Ctrl+N" shown ? - self.set_actions_menu_needs_rebuild() self.regroup = gajim.config.get('mergeaccounts') self.clicked_path = None # Used remember on wich row we clicked if len(gajim.connections) < 2: @@ -6314,24 +5922,15 @@ class RosterWindow: # selected item and not stay with that item selected self.previous_status_combobox_active = number_of_menuitem - showOffline = gajim.config.get('showoffline') - showOnlyChatAndOnline = gajim.config.get('show_only_chat_and_online') + # Enable/Disable checkboxes at start + if gajim.config.get('showoffline'): + self.window.lookup_action('show-active').set_enabled(False) - w = self.xml.get_object('show_offline_contacts_menuitem') - w.set_active(showOffline) - if showOnlyChatAndOnline: - w.set_sensitive(False) + if gajim.config.get('show_only_chat_and_online'): + self.window.lookup_action('show-offline').set_enabled(False) - w = self.xml.get_object('show_only_active_contacts_menuitem') - w.set_active(showOnlyChatAndOnline) - if showOffline: - w.set_sensitive(False) - - show_transports_group = gajim.config.get('show_transports_group') - self.xml.get_object('show_transports_menuitem').set_active( - show_transports_group) - - self.xml.get_object('show_roster_menuitem').set_active(True) + if self.hpaned.get_child2() is None: + self.window.lookup_action('show-roster').set_enabled(False) # columns col = Gtk.TreeViewColumn() @@ -6460,11 +6059,6 @@ class RosterWindow: accel_group.connect(Gdk.KEY_j, Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.MASK, self.on_ctrl_j) - # Setting CTRL+N to be the shortcut for show Start chat dialog - new_chat_menuitem = self.xml.get_object('new_chat_menuitem') - new_chat_menuitem.add_accelerator('activate', accel_group, - Gdk.KEY_n, Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE) - # Setting CTRL+S to be the shortcut to change status message accel_group = Gtk.AccelGroup() keyval, mod = Gtk.accelerator_parse('s')