diff --git a/clients_icons/clients.py b/clients_icons/clients.py index 0eefd30..29936e6 100644 --- a/clients_icons/clients.py +++ b/clients_icons/clients.py @@ -1,3 +1,18 @@ +# 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, either version 3 of the License, or +# (at your option) any later version. +# +# 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 collections import UserDict from collections import namedtuple diff --git a/clients_icons/clients_icons.py b/clients_icons/clients_icons.py index 99c4fcf..6ae728d 100644 --- a/clients_icons/clients_icons.py +++ b/clients_icons/clients_icons.py @@ -1,13 +1,25 @@ +# 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, either version 3 of the License, or +# (at your option) any later version. +# +# 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 . + import logging from pathlib import Path from functools import partial from gi.repository import Gtk -from gajim.roster_window import Column -from gajim.common import ged from gajim.common import app -from gajim.common import caps_cache from gajim.gtk.util import load_icon from gajim.plugins import GajimPlugin @@ -16,8 +28,6 @@ from gajim.plugins.plugins_i18n import _ from clients_icons import clients from clients_icons.config_dialog import ClientsIconsConfigDialog -from nbxmpp import JID - log = logging.getLogger('gajim.p.client_icons') @@ -27,15 +37,7 @@ class ClientsIconsPlugin(GajimPlugin): ' and in groupchats.') self.config_dialog = partial(ClientsIconsConfigDialog, self) - self.events_handlers = { - 'caps-update': ( - ged.POSTGUI, self._on_caps_update), - } - self.gui_extension_points = { - 'roster_draw_contact': ( - self.connect_with_roster_draw_contact, - None), 'roster_tooltip_populate': ( self.connect_with_roster_tooltip_populate, None), @@ -45,11 +47,8 @@ class ClientsIconsPlugin(GajimPlugin): } self.config_default_values = { - 'show_in_roster': (True, ''), 'show_in_tooltip': (True, ''), 'show_unknown_icon': (True, ''), - 'pos_in_list': ('0', ''), - 'show_facebook': (True, ''), } _icon_theme = Gtk.IconTheme.get_default() @@ -57,16 +56,29 @@ class ClientsIconsPlugin(GajimPlugin): _icon_theme.append_search_path(str(Path(__file__).parent)) @staticmethod - def get_client_identity_name(contact): - identities = contact.client_caps.get_cache_lookup_strategy()( - caps_cache.capscache).identities - if identities: - for entry in identities: - if entry.category == 'client': - return entry.name + def _get_client_identity_name(disco_info): + for identity in disco_info.identities: + if identity.category == 'client': + return identity.name + + def _get_image_and_client_name(self, contact, widget): + disco_info = app.logger.get_last_disco_info(contact.get_full_jid()) + if disco_info is None: + return None + + if disco_info.node is None: + return None + + node = disco_info.node.split('#')[0] + client_name = self._get_client_identity_name(disco_info) + + log.info('Lookup client: %s %s', client_name, node) + client_name, icon_name = clients.get_data(client_name, node) + surface = load_icon(icon_name, widget=widget) + return Gtk.Image.new_from_surface(surface), client_name @staticmethod - def is_groupchat(contact): + def _is_groupchat(contact): if hasattr(contact, 'is_groupchat'): return contact.is_groupchat return False @@ -108,9 +120,12 @@ class ClientsIconsPlugin(GajimPlugin): if not self.config['show_in_tooltip']: return - # Check if clients info already attached to tooltip - node = contact.client_caps._node - image, client_name = self.get_icon(node, contact, tooltip_grid) + result = self._get_image_and_client_name(contact, tooltip_grid) + if result is None: + return + + image, client_name = result + label = Gtk.Label(label=client_name) box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) @@ -127,9 +142,11 @@ class ClientsIconsPlugin(GajimPlugin): tooltip_grid): if not self.config['show_in_tooltip']: return + if len(contacts) == 1 and contacts[0].jid in app.get_our_jids(): return - if self.is_groupchat(contacts[0]): + + if self._is_groupchat(contacts[0]): return # Put contacts in dict, where key is priority @@ -157,11 +174,14 @@ class ClientsIconsPlugin(GajimPlugin): vcard_current_row = 0 for priority in contact_keys: for acontact in contacts_dict[priority]: - caps = acontact.client_caps._node - caps_image, client_name = self.get_icon( - caps, acontact, tooltip_grid) - caps_image.set_valign(Gtk.Align.START) - grid.attach(caps_image, 1, vcard_current_row, 1, 1) + + result = self._get_image_and_client_name(acontact, tooltip_grid) + if result is None: + continue + image, client_name = result + + image.set_valign(Gtk.Align.START) + grid.attach(image, 1, vcard_current_row, 1, 1) label = Gtk.Label(label=client_name) label.set_valign(Gtk.Align.START) label.set_halign(Gtk.Align.START) @@ -188,161 +208,3 @@ class ClientsIconsPlugin(GajimPlugin): Gtk.PositionType.BOTTOM, 1, 1) tooltip_grid.attach_next_to(grid, label, Gtk.PositionType.RIGHT, 1, 1) - - def get_icon(self, node, contact, widget): - identity_name = self.get_client_identity_name(contact) - client_name, icon_name = clients.get_data(identity_name, node) - surface = load_icon(icon_name, widget=widget) - return Gtk.Image.new_from_surface(surface), client_name - - def connect_with_roster_draw_contact(self, roster, jid, account, contact): - if not self.active: - return - if not self.config['show_in_roster']: - return - if self.is_groupchat(contact): - return - child_iters = roster._get_contact_iter( - jid, account, contact, roster.model) - if not child_iters: - return - for iter_ in child_iters: - if roster.model[iter_][self.renderer_num] is None: - node = contact.client_caps._node - self.set_icon( - roster.model, iter_, self.renderer_num, node, contact) - - def activate(self): - self.active = None - roster = app.interface.roster - col = Gtk.TreeViewColumn() - roster.nb_ext_renderers += 1 - self.renderer_num = 11 + roster.nb_ext_renderers - self.renderer = Gtk.CellRendererPixbuf() - client_icon_rend = ( - 'client_icon', self.renderer, False, - 'icon_name', self.renderer_num, - self._roster_icon_renderer, self.renderer_num) - - # Remove old column - roster.tree.remove_column(roster.tree.get_column(0)) - - # Add new renderer in renderers list - position_list = ['name', 'avatar'] - position = position_list[int(self.config['pos_in_list'])] - for renderer in roster.renderers_list: - if renderer[0] == position: - break - num = roster.renderers_list.index(renderer) - roster.renderers_list.insert(num, client_icon_rend) - - # Fill and append column - roster.fill_column(col) - roster.tree.insert_column(col, 0) - - # Redraw roster - roster.columns += [str] - self.active = True - roster.setup_and_draw_roster() - - def _roster_icon_renderer(self, column, renderer, model, titer, data=None): - try: - type_ = model[titer][Column.TYPE] - except TypeError: - return - - # Allocate space for the icon only if needed - if model[titer][data] is None: - renderer.set_property('visible', False) - else: - renderer.set_property('visible', True) - - if type_ == 'account': - app.interface.roster._set_account_row_background_color(renderer) - renderer.set_property('xalign', 1) - elif type_: - if (not model[titer][Column.JID] or - not model[titer][Column.ACCOUNT]): - # This can append at the moment we add the row - return - jid = model[titer][Column.JID] - account = model[titer][Column.ACCOUNT] - app.interface.roster._set_contact_row_background_color( - renderer, jid, account) - - def deactivate(self): - self.active = None - roster = app.interface.roster - roster.nb_ext_renderers -= 1 - col = roster.tree.get_column(0) - roster.tree.remove_column(col) - col = Gtk.TreeViewColumn() - for renderer in roster.renderers_list: - if renderer[0] == 'client_icon': - roster.renderers_list.remove(renderer) - break - roster.fill_column(col) - roster.tree.insert_column(col, 0) - roster.columns = roster.columns[:self.renderer_num] + roster.columns[ - self.renderer_num + 1:] - roster.setup_and_draw_roster() - - def _on_caps_update(self, event): - # Zeroconf - if event.account == 'Local': - return - - contact = self._get_contact_or_gc_contact_for_jid( - event.account, event.fjid) - if contact is None: - return - - if contact.is_gc_contact: - return - self._draw_roster_contact(event, contact) - - def _draw_roster_contact(self, event, contact): - if not self.config['show_in_roster']: - return - - if contact.is_groupchat: - return - roster = app.interface.roster - iters = roster._get_contact_iter( - event.jid, event.account, contact, roster.model) - iter_ = iters[0] - - # Highest contact changed - caps = contact.client_caps._node - if not caps: - return - - if roster.model[iter_][self.renderer_num] is not None: - self.set_icon( - roster.model, iter_, self.renderer_num, caps, contact) - return - - for iter_ in iters: - self.set_icon( - roster.model, iter_, self.renderer_num, caps, contact) - - def _get_contact_or_gc_contact_for_jid(self, account, fjid): - contact = app.contacts.get_contact_from_full_jid(account, fjid) - - if contact is None: - fjid = JID(fjid) - room_jid, resource = fjid.getStripped(), fjid.getResource() - contact = app.contacts.get_gc_contact(account, room_jid, resource) - return contact - - def set_icon(self, model, iter_, pos, node, contact): - identity_name = self.get_client_identity_name(contact) - _client_name, icon_name = clients.get_data(identity_name, node) - if 'unknown' in icon_name: - if node is not None: - log.warning('Unknown client: %s %s', identity_name, node) - if not self.config['show_unknown_icon']: - model[iter_][pos] = None - return - - model[iter_][pos] = icon_name diff --git a/clients_icons/config_dialog.py b/clients_icons/config_dialog.py index 3dcdda7..042c0b6 100644 --- a/clients_icons/config_dialog.py +++ b/clients_icons/config_dialog.py @@ -15,8 +15,6 @@ from gi.repository import Gtk -from gajim.common import app - from gajim.gtk.settings import SettingsDialog from gajim.gtk.const import Setting from gajim.gtk.const import SettingKind @@ -28,15 +26,8 @@ from gajim.plugins.plugins_i18n import _ class ClientsIconsConfigDialog(SettingsDialog): def __init__(self, plugin, parent): - icon_position = [ - ('0', _('Before Avatar')), - ('1', _('After Status Icon'))] - self.plugin = plugin settings = [ - Setting(SettingKind.SWITCH, _('Show Icons in Contact List'), - SettingType.VALUE, self.plugin.config['show_in_roster'], - callback=self._on_setting, data='show_in_roster'), Setting(SettingKind.SWITCH, _('Show Icons in Tooltip'), SettingType.VALUE, self.plugin.config['show_in_tooltip'], @@ -46,15 +37,6 @@ class ClientsIconsConfigDialog(SettingsDialog): SettingType.VALUE, self.plugin.config['show_unknown_icon'], callback=self._on_setting, data='show_unknown_icon'), - Setting(SettingKind.SWITCH, _('Show Icon for Transports'), - SettingType.VALUE, self.plugin.config['show_facebook'], - desc=_('Icons for facebook.com and vk.com'), - callback=self._on_setting, data='show_facebook'), - - Setting(SettingKind.COMBO, _('Icon Position'), - SettingType.VALUE, self.plugin.config['pos_in_list'], - callback=self._on_setting, data='pos_in_list', - props={'combo_items': icon_position}), ] SettingsDialog.__init__(self, parent, _('Clients Icons Configuration'), @@ -62,12 +44,3 @@ class ClientsIconsConfigDialog(SettingsDialog): def _on_setting(self, value, data): self.plugin.config[data] = value - self._redraw_all() - - def _redraw_all(self): - self.plugin.deactivate() - self.plugin.activate() - for gc_control in app.interface.msg_win_mgr.get_controls('gc'): - self.plugin.disconnect_from_groupchat_control(gc_control) - for gc_control in app.interface.msg_win_mgr.get_controls('gc'): - self.plugin.connect_with_groupchat_control(gc_control)