diff --git a/po/de.po b/po/de.po index d8a64ccd6..7862724ef 100644 --- a/po/de.po +++ b/po/de.po @@ -1286,7 +1286,7 @@ msgstr "Spitz_name ändern …" #: ../data/glade/gc_control_popup_menu.glade.h:2 msgid "Change _Subject..." -msgstr "_Design ändern …" +msgstr "_Thema ändern …" #: ../data/glade/gc_control_popup_menu.glade.h:3 msgid "Configure _Room..." @@ -2630,7 +2630,7 @@ msgstr "Einzelne _Nachricht senden …" #: ../data/glade/roster_window.glade.h:26 msgid "_View" -msgstr "_Ansicht" +msgstr "A_nsicht" #: ../data/glade/search_window.glade.h:1 msgid "Please wait while retrieving search form..." @@ -5225,17 +5225,17 @@ msgstr[1] "%d neue Nachrichten" #: ../src/common/helpers.py:1174 #, python-format msgid " from room %s" -msgstr "Vom Chatraum %s" +msgstr " vom Chatraum %s" #: ../src/common/helpers.py:1177 ../src/common/helpers.py:1196 #, python-format msgid " from user %s" -msgstr "Vom Benutzer %s" +msgstr " vom Benutzer %s" #: ../src/common/helpers.py:1179 #, python-format msgid " from %s" -msgstr "Von %s" +msgstr " von %s" #: ../src/common/helpers.py:1186 ../src/common/helpers.py:1193 #, python-format diff --git a/src/gtkgui_helpers.py b/src/gtkgui_helpers.py index 6a8b1b1cf..26c8c13aa 100644 --- a/src/gtkgui_helpers.py +++ b/src/gtkgui_helpers.py @@ -1028,4 +1028,307 @@ def __label_size_allocate(widget, allocation): if lh_old != lh: widget.set_size_request (-1, lh / pango.SCALE) +def build_resources_submenu(self, contacts, account, action, room_jid=None, +room_account=None, cap=None): + ''' Build a submenu with contact's resources. + room_jid and room_account are for action self.on_invite_to_room ''' + sub_menu = gtk.Menu() + + iconset = gajim.config.get('iconset') + if not iconset: + iconset = gajim.config.DEFAULT_ICONSET + path = os.path.join(helpers.get_iconset_path(iconset), '16x16') + for c in contacts: + # icon MUST be different instance for every item + state_images = gtkgui_helpers.load_iconset(path) + item = gtk.ImageMenuItem('%s (%s)' % (c.resource, str(c.priority))) + icon_name = helpers.get_icon_name_to_show(c, account) + icon = state_images[icon_name] + item.set_image(icon) + sub_menu.append(item) + + if action == roster.on_invite_to_room: + item.connect('activate', action, [(c, account)], room_jid, + room_account, c.resource) + elif action == roster.on_invite_to_new_room: + item.connect('activate', action, [(c, account)], c.resource) + else: # start_chat, execute_command, send_file + item.connect('activate', action, c, account, c.resource) + + if cap and not gajim.capscache.is_supported(c, cap): + item.set_sensitive(False) + + return sub_menu + + +def get_contact_menu(self, contact, account, use_multiple_contacts=True): + if not contact: + return + + jid = contact.jid + our_jid = jid == gajim.get_jid_from_account(account) + roster = gajim.interface.roster + + if gajim.config.get_per('accounts', account, 'is_zeroconf'): + xml = get_glade('zeroconf_contact_context_menu.glade') + else: + xml = get_glade('roster_contact_context_menu.glade') + + start_chat_menuitem = xml.get_widget('start_chat_menuitem') + execute_command_menuitem = xml.get_widget('execute_command_menuitem') + rename_menuitem = xml.get_widget('rename_menuitem') + edit_groups_menuitem = xml.get_widget('edit_groups_menuitem') + send_file_menuitem = xml.get_widget('send_file_menuitem') + assign_openpgp_key_menuitem = xml.get_widget('assign_openpgp_key_menuitem') + add_special_notification_menuitem = xml.get_widget( + 'add_special_notification_menuitem') + information_menuitem = xml.get_widget('information_menuitem') + history_menuitem = xml.get_widget('history_menuitem') + + # add a special img for send file menuitem + path_to_upload_img = os.path.join(gajim.DATA_DIR, 'pixmaps', 'upload.png') + img = gtk.Image() + img.set_from_file(path_to_upload_img) + send_file_menuitem.set_image(img) + + if not our_jid: + # add a special img for rename menuitem + path_to_kbd_input_img = os.path.join(gajim.DATA_DIR, 'pixmaps', + 'kbd_input.png') + img = gtk.Image() + img.set_from_file(path_to_kbd_input_img) + rename_menuitem.set_image(img) + + contacts = gajim.contacts.get_contacts(account, jid) + if len(contacts) > 1 and use_multiple_contacts: # several resources + start_chat_menuitem.set_submenu(self.build_resources_submenu(contacts, + account, gajim.interface.on_open_chat_window)) + send_file_menuitem.set_submenu(self.build_resources_submenu(contacts, + account, roster.on_send_file_menuitem_activate, cap=NS_FILE)) + execute_command_menuitem.set_submenu(self.build_resources_submenu( + contacts, account, roster.on_execute_command, cap=NS_COMMANDS)) + else: + start_chat_menuitem.connect('activate', + gajim.interface.on_open_chat_window, contact, account) + if gajim.capscache.is_supported(contact, NS_FILE): + send_file_menuitem.set_sensitive(True) + send_file_menuitem.connect('activate', + roster.on_send_file_menuitem_activate, contact, account) + else: + send_file_menuitem.set_sensitive(False) + + if gajim.capscache.is_supported(contact, NS_COMMANDS): + execute_command_menuitem.set_sensitive(True) + execute_command_menuitem.connect('activate', roster.on_execute_command, + contact, account, contact.resource) + else: + execute_command_menuitem.set_sensitive(False) + + rename_menuitem.connect('activate', roster.on_rename, 'contact', jid, + account) + history_menuitem.connect('activate', roster.on_history, contact, account) + + if _('Not in Roster') not in contact.get_shown_groups(): + # contact is in normal group + edit_groups_menuitem.connect('activate', roster.on_edit_groups, [(contact, + account)]) + + if gajim.connections[account].gpg: + assign_openpgp_key_menuitem.connect('activate', + roster.on_assign_pgp_key, contact, account) + else: + assign_openpgp_key_menuitem.set_sensitive(False) + else: + # contact is in group 'Not in Roster' + edit_groups_menuitem.set_sensitive(False) + assign_openpgp_key_menuitem.set_sensitive(False) + + # Hide items when it's self contact row + if our_jid: + for menuitem in (rename_menuitem, edit_groups_menuitem): + menuitem.set_no_show_all(True) + menuitem.hide() + + # Unsensitive many items when account is offline + if gajim.account_is_disconnected(account): + for widget in (start_chat_menuitem, rename_menuitem, + edit_groups_menuitem, send_file_menuitem): + widget.set_sensitive(False) + + event_button = get_possible_button_event(event) + + # Zeroconf Account + if gajim.config.get_per('accounts', account, 'is_zeroconf'): + xml = get_glade('zeroconf_contact_context_menu.glade') + contact_context_menu = xml.get_widget('zeroconf_contact_context_menu') + + if contact.show in ('offline', 'error'): + information_menuitem.set_sensitive(False) + send_file_menuitem.set_sensitive(False) + else: + information_menuitem.connect('activate', roster.on_info_zeroconf, + contact, account) + + contact_context_menu.connect('selection-done', destroy_widget) + contact_context_menu.show_all() + contact_context_menu.popup(None, None, None, event_button, event.time) + return contact_context_menu + + # normal account + xml = get_glade('roster_contact_context_menu.glade') + contact_context_menu = xml.get_widget('roster_contact_context_menu') + + send_custom_status_menuitem = xml.get_widget('send_custom_status_menuitem') + send_single_message_menuitem = xml.get_widget('send_single_message_menuitem') + invite_menuitem = xml.get_widget('invite_menuitem') + block_menuitem = xml.get_widget('block_menuitem') + unblock_menuitem = xml.get_widget('unblock_menuitem') + ignore_menuitem = xml.get_widget('ignore_menuitem') + unignore_menuitem = xml.get_widget('unignore_menuitem') + set_custom_avatar_menuitem = xml.get_widget('set_custom_avatar_menuitem') + + # send custom status icon + blocked = False + if helpers.jid_is_blocked(account, jid): + blocked = True + else: + for group in contact.get_shown_groups(): + if helpers.group_is_blocked(account, group): + blocked = True + break + if gajim.get_transport_name_from_jid(jid, use_config_setting=False): + # Transport contact, send custom status unavailable + send_custom_status_menuitem.set_sensitive(False) + elif blocked: + send_custom_status_menuitem.set_image( \ + gtkgui_helpers.load_icon('offline')) + send_custom_status_menuitem.set_sensitive(False) + elif account in gajim.interface.status_sent_to_users and \ + jid in gajim.interface.status_sent_to_users[account]: + send_custom_status_menuitem.set_image( + gtkgui_helpers.load_icon( \ + gajim.interface.status_sent_to_users[account][jid])) + else: + icon = gtk.image_new_from_stock(gtk.STOCK_NETWORK, gtk.ICON_SIZE_MENU) + send_custom_status_menuitem.set_image(icon) + + muc_icon = gtkgui_helpers.load_icon('muc_active') + if muc_icon: + invite_menuitem.set_image(muc_icon) + + self.build_invite_submenu(invite_menuitem, [(contact, account)]) + + # Subscription submenu + subscription_menuitem = xml.get_widget('subscription_menuitem') + send_auth_menuitem, ask_auth_menuitem, revoke_auth_menuitem = \ + subscription_menuitem.get_submenu().get_children() + add_to_roster_menuitem = xml.get_widget('add_to_roster_menuitem') + remove_from_roster_menuitem = xml.get_widget( + 'remove_from_roster_menuitem') + + # One or several resource, we do the same for send_custom_status + status_menuitems = gtk.Menu() + send_custom_status_menuitem.set_submenu(status_menuitems) + iconset = gajim.config.get('iconset') + path = os.path.join(helpers.get_iconset_path(iconset), '16x16') + for s in ('online', 'chat', 'away', 'xa', 'dnd', 'offline'): + # icon MUST be different instance for every item + state_images = gtkgui_helpers.load_iconset(path) + status_menuitem = gtk.ImageMenuItem(helpers.get_uf_show(s)) + status_menuitem.connect('activate', roster.on_send_custom_status, + [(contact, account)], s) + icon = state_images[s] + status_menuitem.set_image(icon) + status_menuitems.append(status_menuitem) + + send_single_message_menuitem.connect('activate', + roster.on_send_single_message_menuitem_activate, account, contact) + + remove_from_roster_menuitem.connect('activate', roster.on_req_usub, + [(contact, account)]) + information_menuitem.connect('activate', roster.on_info, contact, account) + + if _('Not in Roster') not in contact.get_shown_groups(): + # contact is in normal group + add_to_roster_menuitem.hide() + add_to_roster_menuitem.set_no_show_all(True) + + if contact.sub in ('from', 'both'): + send_auth_menuitem.set_sensitive(False) + else: + send_auth_menuitem.connect('activate', roster.authorize, jid, account) + if contact.sub in ('to', 'both'): + ask_auth_menuitem.set_sensitive(False) + add_special_notification_menuitem.connect('activate', + roster.on_add_special_notification_menuitem_activate, jid) + else: + ask_auth_menuitem.connect('activate', roster.req_sub, jid, + _('I would like to add you to my roster'), account, + contact.groups, contact.name) + if contact.sub in ('to', 'none') or gajim.get_transport_name_from_jid( + jid, use_config_setting=False): + revoke_auth_menuitem.set_sensitive(False) + else: + revoke_auth_menuitem.connect('activate', roster.revoke_auth, jid, + account) + + else: + # contact is in group 'Not in Roster' + add_to_roster_menuitem.set_no_show_all(False) + subscription_menuitem.set_sensitive(False) + + add_to_roster_menuitem.connect('activate', roster.on_add_to_roster, + contact, account) + + set_custom_avatar_menuitem.connect('activate', + roster.on_set_custom_avatar_activate, contact, account) + + # Hide items when it's self contact row + if our_jid: + menuitem = xml.get_widget('manage_contact') + menuitem.set_sensitive(False) + + # Unsensitive items when account is offline + if gajim.account_is_disconnected(account): + for widget in (send_single_message_menuitem, subscription_menuitem, + add_to_roster_menuitem, remove_from_roster_menuitem, + execute_command_menuitem, send_custom_status_menuitem): + widget.set_sensitive(False) + + if gajim.connections[account] and gajim.connections[account].\ + privacy_rules_supported: + if helpers.jid_is_blocked(account, jid): + block_menuitem.set_no_show_all(True) + block_menuitem.hide() + if gajim.get_transport_name_from_jid(jid, use_config_setting=False): + unblock_menuitem.set_no_show_all(True) + unblock_menuitem.hide() + unignore_menuitem.set_no_show_all(False) + unignore_menuitem.connect('activate', roster.on_unblock, [(contact, + account)]) + else: + unblock_menuitem.connect('activate', roster.on_unblock, [(contact, + account)]) + else: + unblock_menuitem.set_no_show_all(True) + unblock_menuitem.hide() + if gajim.get_transport_name_from_jid(jid, use_config_setting=False): + block_menuitem.set_no_show_all(True) + block_menuitem.hide() + ignore_menuitem.set_no_show_all(False) + ignore_menuitem.connect('activate', roster.on_block, [(contact, + account)]) + else: + block_menuitem.connect('activate', roster.on_block, [(contact, + account)]) + else: + unblock_menuitem.set_no_show_all(True) + block_menuitem.set_sensitive(False) + unblock_menuitem.hide() + + contact_context_menu.connect('selection-done', destroy_widget) + contact_context_menu.show_all() + contact_context_menu.popup(None, None, None, event_button, event.time) + return contact_context_menu + # vim: se ts=3: diff --git a/src/roster_window.py b/src/roster_window.py index 9043a9b9f..cda2692bb 100644 --- a/src/roster_window.py +++ b/src/roster_window.py @@ -5357,8 +5357,10 @@ class RosterWindow: jid = model[titer][C_JID].decode('utf-8') tree_path = model.get_path(titer) account = model[titer][C_ACCOUNT].decode('utf-8') - our_jid = jid == gajim.get_jid_from_account(account) contact = gajim.contacts.get_contact_with_highest_priority(account, jid) + menu = gtkgui_helpers.get_contact_menu(contact, account) + menu.attach_to_widget(self.tree, None) + if not contact: return