[client_icons] Only show icons in tooltips
- Only show icons in tooltips - Adapt to Gajim changes
This commit is contained in:
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from collections import UserDict
|
from collections import UserDict
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
|
|||||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from gi.repository import Gtk
|
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 app
|
||||||
from gajim.common import caps_cache
|
|
||||||
from gajim.gtk.util import load_icon
|
from gajim.gtk.util import load_icon
|
||||||
|
|
||||||
from gajim.plugins import GajimPlugin
|
from gajim.plugins import GajimPlugin
|
||||||
@@ -16,8 +28,6 @@ from gajim.plugins.plugins_i18n import _
|
|||||||
from clients_icons import clients
|
from clients_icons import clients
|
||||||
from clients_icons.config_dialog import ClientsIconsConfigDialog
|
from clients_icons.config_dialog import ClientsIconsConfigDialog
|
||||||
|
|
||||||
from nbxmpp import JID
|
|
||||||
|
|
||||||
log = logging.getLogger('gajim.p.client_icons')
|
log = logging.getLogger('gajim.p.client_icons')
|
||||||
|
|
||||||
|
|
||||||
@@ -27,15 +37,7 @@ class ClientsIconsPlugin(GajimPlugin):
|
|||||||
' and in groupchats.')
|
' and in groupchats.')
|
||||||
self.config_dialog = partial(ClientsIconsConfigDialog, self)
|
self.config_dialog = partial(ClientsIconsConfigDialog, self)
|
||||||
|
|
||||||
self.events_handlers = {
|
|
||||||
'caps-update': (
|
|
||||||
ged.POSTGUI, self._on_caps_update),
|
|
||||||
}
|
|
||||||
|
|
||||||
self.gui_extension_points = {
|
self.gui_extension_points = {
|
||||||
'roster_draw_contact': (
|
|
||||||
self.connect_with_roster_draw_contact,
|
|
||||||
None),
|
|
||||||
'roster_tooltip_populate': (
|
'roster_tooltip_populate': (
|
||||||
self.connect_with_roster_tooltip_populate,
|
self.connect_with_roster_tooltip_populate,
|
||||||
None),
|
None),
|
||||||
@@ -45,11 +47,8 @@ class ClientsIconsPlugin(GajimPlugin):
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.config_default_values = {
|
self.config_default_values = {
|
||||||
'show_in_roster': (True, ''),
|
|
||||||
'show_in_tooltip': (True, ''),
|
'show_in_tooltip': (True, ''),
|
||||||
'show_unknown_icon': (True, ''),
|
'show_unknown_icon': (True, ''),
|
||||||
'pos_in_list': ('0', ''),
|
|
||||||
'show_facebook': (True, ''),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_icon_theme = Gtk.IconTheme.get_default()
|
_icon_theme = Gtk.IconTheme.get_default()
|
||||||
@@ -57,16 +56,29 @@ class ClientsIconsPlugin(GajimPlugin):
|
|||||||
_icon_theme.append_search_path(str(Path(__file__).parent))
|
_icon_theme.append_search_path(str(Path(__file__).parent))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_client_identity_name(contact):
|
def _get_client_identity_name(disco_info):
|
||||||
identities = contact.client_caps.get_cache_lookup_strategy()(
|
for identity in disco_info.identities:
|
||||||
caps_cache.capscache).identities
|
if identity.category == 'client':
|
||||||
if identities:
|
return identity.name
|
||||||
for entry in identities:
|
|
||||||
if entry.category == 'client':
|
def _get_image_and_client_name(self, contact, widget):
|
||||||
return entry.name
|
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
|
@staticmethod
|
||||||
def is_groupchat(contact):
|
def _is_groupchat(contact):
|
||||||
if hasattr(contact, 'is_groupchat'):
|
if hasattr(contact, 'is_groupchat'):
|
||||||
return contact.is_groupchat
|
return contact.is_groupchat
|
||||||
return False
|
return False
|
||||||
@@ -108,9 +120,12 @@ class ClientsIconsPlugin(GajimPlugin):
|
|||||||
if not self.config['show_in_tooltip']:
|
if not self.config['show_in_tooltip']:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Check if clients info already attached to tooltip
|
result = self._get_image_and_client_name(contact, tooltip_grid)
|
||||||
node = contact.client_caps._node
|
if result is None:
|
||||||
image, client_name = self.get_icon(node, contact, tooltip_grid)
|
return
|
||||||
|
|
||||||
|
image, client_name = result
|
||||||
|
|
||||||
label = Gtk.Label(label=client_name)
|
label = Gtk.Label(label=client_name)
|
||||||
|
|
||||||
box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
|
box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
|
||||||
@@ -127,9 +142,11 @@ class ClientsIconsPlugin(GajimPlugin):
|
|||||||
tooltip_grid):
|
tooltip_grid):
|
||||||
if not self.config['show_in_tooltip']:
|
if not self.config['show_in_tooltip']:
|
||||||
return
|
return
|
||||||
|
|
||||||
if len(contacts) == 1 and contacts[0].jid in app.get_our_jids():
|
if len(contacts) == 1 and contacts[0].jid in app.get_our_jids():
|
||||||
return
|
return
|
||||||
if self.is_groupchat(contacts[0]):
|
|
||||||
|
if self._is_groupchat(contacts[0]):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Put contacts in dict, where key is priority
|
# Put contacts in dict, where key is priority
|
||||||
@@ -157,11 +174,14 @@ class ClientsIconsPlugin(GajimPlugin):
|
|||||||
vcard_current_row = 0
|
vcard_current_row = 0
|
||||||
for priority in contact_keys:
|
for priority in contact_keys:
|
||||||
for acontact in contacts_dict[priority]:
|
for acontact in contacts_dict[priority]:
|
||||||
caps = acontact.client_caps._node
|
|
||||||
caps_image, client_name = self.get_icon(
|
result = self._get_image_and_client_name(acontact, tooltip_grid)
|
||||||
caps, acontact, tooltip_grid)
|
if result is None:
|
||||||
caps_image.set_valign(Gtk.Align.START)
|
continue
|
||||||
grid.attach(caps_image, 1, vcard_current_row, 1, 1)
|
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 = Gtk.Label(label=client_name)
|
||||||
label.set_valign(Gtk.Align.START)
|
label.set_valign(Gtk.Align.START)
|
||||||
label.set_halign(Gtk.Align.START)
|
label.set_halign(Gtk.Align.START)
|
||||||
@@ -188,161 +208,3 @@ class ClientsIconsPlugin(GajimPlugin):
|
|||||||
Gtk.PositionType.BOTTOM, 1, 1)
|
Gtk.PositionType.BOTTOM, 1, 1)
|
||||||
tooltip_grid.attach_next_to(grid, label,
|
tooltip_grid.attach_next_to(grid, label,
|
||||||
Gtk.PositionType.RIGHT, 1, 1)
|
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
|
|
||||||
|
|||||||
@@ -15,8 +15,6 @@
|
|||||||
|
|
||||||
from gi.repository import Gtk
|
from gi.repository import Gtk
|
||||||
|
|
||||||
from gajim.common import app
|
|
||||||
|
|
||||||
from gajim.gtk.settings import SettingsDialog
|
from gajim.gtk.settings import SettingsDialog
|
||||||
from gajim.gtk.const import Setting
|
from gajim.gtk.const import Setting
|
||||||
from gajim.gtk.const import SettingKind
|
from gajim.gtk.const import SettingKind
|
||||||
@@ -28,15 +26,8 @@ from gajim.plugins.plugins_i18n import _
|
|||||||
class ClientsIconsConfigDialog(SettingsDialog):
|
class ClientsIconsConfigDialog(SettingsDialog):
|
||||||
def __init__(self, plugin, parent):
|
def __init__(self, plugin, parent):
|
||||||
|
|
||||||
icon_position = [
|
|
||||||
('0', _('Before Avatar')),
|
|
||||||
('1', _('After Status Icon'))]
|
|
||||||
|
|
||||||
self.plugin = plugin
|
self.plugin = plugin
|
||||||
settings = [
|
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'),
|
Setting(SettingKind.SWITCH, _('Show Icons in Tooltip'),
|
||||||
SettingType.VALUE, self.plugin.config['show_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'],
|
SettingType.VALUE, self.plugin.config['show_unknown_icon'],
|
||||||
callback=self._on_setting, data='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'),
|
SettingsDialog.__init__(self, parent, _('Clients Icons Configuration'),
|
||||||
@@ -62,12 +44,3 @@ class ClientsIconsConfigDialog(SettingsDialog):
|
|||||||
|
|
||||||
def _on_setting(self, value, data):
|
def _on_setting(self, value, data):
|
||||||
self.plugin.config[data] = value
|
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)
|
|
||||||
|
|||||||
Reference in New Issue
Block a user