[clients_icons] Add back roster tooltips

This adds support for roster tooltips and display of client name coming
from caps features (including version number if present).
This also fixes detection of Pix-Art Messenger which uses
"http://conversations.im" as presence node value but "Pix-Art Messenger"
in caps features.
This commit is contained in:
Thilo Molitor
2018-03-04 21:31:53 +01:00
committed by Philipp Hörist
parent 9ae5d72526
commit 5a68b17b82
2 changed files with 118 additions and 47 deletions

View File

@@ -11,6 +11,7 @@ from gajim.plugins import GajimPlugin
from gajim.plugins.helpers import log_calls from gajim.plugins.helpers import log_calls
from gajim.common import ged from gajim.common import ged
from gajim.common import app from gajim.common import app
from gajim.common import caps_cache
import gajim.cell_renderer_image import gajim.cell_renderer_image
log = logging.getLogger('gajim.plugin_system.clients_icons') log = logging.getLogger('gajim.plugin_system.clients_icons')
@@ -182,18 +183,18 @@ class ClientsIconsPlugin(GajimPlugin):
self.description = _('Shows client icons in roster' self.description = _('Shows client icons in roster'
' and in groupchats.') ' and in groupchats.')
self.pos_list = [_('after statusicon'), _('before avatar')] self.pos_list = [_('after statusicon'), _('before avatar')]
self.events_handlers = {'presence-received': self.events_handlers = {'caps-presence-received':
(ged.POSTGUI, self.presence_received), (ged.POSTGUI, self.caps_presence_received),
'gc-presence-received': 'caps-disco-received':
(ged.POSTGUI, self.gc_presence_received), (ged.POSTGUI, self.caps_disco_received),
} }
self.gui_extension_points = { self.gui_extension_points = {
'groupchat_control': (self.connect_with_groupchat_control, 'groupchat_control': (self.connect_with_groupchat_control,
self.disconnect_from_groupchat_control), self.disconnect_from_groupchat_control),
'roster_draw_contact': (self.connect_with_roster_draw_contact, 'roster_draw_contact': (self.connect_with_roster_draw_contact,
self.disconnect_from_roster_draw_contact), self.disconnect_from_roster_draw_contact),
#'roster_tooltip_populate': (self.connect_with_roster_tooltip_populate, 'roster_tooltip_populate': (self.connect_with_roster_tooltip_populate,
# self.disconnect_from_roster_tooltip_populate), self.disconnect_from_roster_tooltip_populate),
'gc_tooltip_populate': (self.connect_with_gc_tooltip_populate, 'gc_tooltip_populate': (self.connect_with_gc_tooltip_populate,
self.disconnect_from_gc_tooltip_populate), self.disconnect_from_gc_tooltip_populate),
} }
@@ -215,7 +216,11 @@ class ClientsIconsPlugin(GajimPlugin):
def add_tooltip_row(self, tooltip, contact, tooltip_grid): def add_tooltip_row(self, tooltip, contact, tooltip_grid):
caps = contact.client_caps._node caps = contact.client_caps._node
log.debug('connect_with_gc_tooltip_populate, caps: %s', caps) log.debug('connect_with_gc_tooltip_populate, caps: %s', caps)
caps_image , client_name = self.get_icon(caps, contact) caps_image, client_name = self.get_icon(caps, contact)
identities = acontact.client_caps._lookup_in_cache(
caps_cache.capscache).identities
if identities:
client_name = identities[0].get('name', client_name)
caps_image.set_halign(Gtk.PositionType.RIGHT) caps_image.set_halign(Gtk.PositionType.RIGHT)
log.debug('connect_with_gc_tooltip_populate, client_name: %s', \ log.debug('connect_with_gc_tooltip_populate, client_name: %s', \
client_name) client_name)
@@ -239,8 +244,8 @@ class ClientsIconsPlugin(GajimPlugin):
label.show() label.show()
# set client table to tooltip # set client table to tooltip
tooltip_grid.insert_next_to(tooltip.resource_label, #tooltip_grid.insert_next_to(tooltip.resource_label,
Gtk.PositionType.BOTTOM) #Gtk.PositionType.BOTTOM)
tooltip_grid.attach_next_to(label, tooltip.resource_label, tooltip_grid.attach_next_to(label, tooltip.resource_label,
Gtk.PositionType.BOTTOM, 1, 1) Gtk.PositionType.BOTTOM, 1, 1)
tooltip_grid.attach_next_to(self.table, label, tooltip_grid.attach_next_to(self.table, label,
@@ -255,7 +260,7 @@ class ClientsIconsPlugin(GajimPlugin):
for child in tooltip_grid.get_children(): for child in tooltip_grid.get_children():
if child.get_name() == 'client_icons_grid': if child.get_name() == 'client_icons_grid':
caps = contact.client_caps._node caps = contact.client_caps._node
caps_image , client_name = self.get_icon(caps, contact) caps_image, client_name = self.get_icon(caps, contact)
child.remove(child.get_child_at(1, 1)) child.remove(child.get_child_at(1, 1))
child.attach(caps_image, 1, 1, 1, 1) child.attach(caps_image, 1, 1, 1, 1)
child.get_child_at(2, 1).set_markup(client_name) child.get_child_at(2, 1).set_markup(client_name)
@@ -295,13 +300,16 @@ class ClientsIconsPlugin(GajimPlugin):
self.table.insert_row(0) self.table.insert_row(0)
self.table.insert_column(0) self.table.insert_column(0)
self.table.set_property('column-spacing', 2) self.table.set_property('column-spacing', 2)
first_place = 100
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 = acontact.client_caps._node
caps_image , client_name = self.get_icon(caps, acontact) caps_image, client_name = self.get_icon(caps, acontact)
identities = acontact.client_caps._lookup_in_cache(
caps_cache.capscache).identities
if identities:
client_name = identities[0].get('name', client_name)
caps_image.set_alignment(0, 0) caps_image.set_alignment(0, 0)
self.table.attach(caps_image, 1, vcard_current_row, 1, 1) self.table.attach(caps_image, 1, vcard_current_row, 1, 1)
label = Gtk.Label() label = Gtk.Label()
@@ -309,6 +317,8 @@ class ClientsIconsPlugin(GajimPlugin):
label.set_markup(client_name) label.set_markup(client_name)
self.table.attach(label, 2, vcard_current_row, 1, 1) self.table.attach(label, 2, vcard_current_row, 1, 1)
vcard_current_row += 1 vcard_current_row += 1
self.table.show_all()
# set label # set label
label = Gtk.Label() label = Gtk.Label()
label.set_alignment(0, 0) label.set_alignment(0, 0)
@@ -318,14 +328,18 @@ class ClientsIconsPlugin(GajimPlugin):
if contact.show == 'offline': if contact.show == 'offline':
return return
label.set_markup(_('Client:')) label.set_markup(_('Client:'))
tooltip_grid.attach(label, 1, first_place, 1, 1) label.show()
# set clients table to tooltip # set clients table to tooltip
tooltip_grid.attach(self.table, 2, first_place, 1, 1) #tooltip_grid.insert_next_to(tooltip.resource_label,
#Gtk.PositionType.BOTTOM)
tooltip_grid.attach_next_to(label, tooltip.resource_label,
Gtk.PositionType.BOTTOM, 1, 1)
tooltip_grid.attach_next_to(self.table, label,
Gtk.PositionType.RIGHT, 1, 1)
def get_icon(self, caps, contact=None): def get_icon(self, caps, contact):
if not caps: if not caps:
return Gtk.Image.new_from_pixbuf(self.default_pixbuf), _('Unknown') return Gtk.Image.new_from_pixbuf(self.default_pixbuf), _('Unknown')
log.debug('get_icon, caps: %s', caps)
# libpurple returns pidgin.im/ only, we have to look for ressource name # libpurple returns pidgin.im/ only, we have to look for ressource name
if 'pidgin.im/' in caps: if 'pidgin.im/' in caps:
caps = 'libpurple' caps = 'libpurple'
@@ -340,11 +354,24 @@ class ClientsIconsPlugin(GajimPlugin):
if caps_from_jid: if caps_from_jid:
caps = caps_from_jid caps = caps_from_jid
caps_ = caps.split('#')[0].split() caps_ = caps.split('#')[0].split()
if caps_:
client_name = _('Unknown')
client_icon = None
identities = contact.client_caps._lookup_in_cache(
caps_cache.capscache).identities
if identities:
log.debug('get_icon, identities: %s', str(identities))
client_name = identities[0].get('name', _('Unknown'))
name_splits = client_name.split()
name_splits = reversed([" ".join(name_splits[:(i+1)]) for i in range(len(name_splits))])
for name in name_splits:
if not client_icon:
log.debug("get_icon, searching for name fragment '%s'..." % name)
client_icon = clients.get(name, (None,))[0]
if caps_ and not client_icon:
client_icon = clients.get(caps_[0].split()[0], (None,))[0] client_icon = clients.get(caps_[0].split()[0], (None,))[0]
client_name = clients.get(caps_[0].split()[0], ('', _('Unknown')))[1] client_name = clients.get(caps_[0].split()[0], ('', _('Unknown')))[1]
else:
client_icon = None
if not client_icon: if not client_icon:
return Gtk.Image.new_from_pixbuf(self.default_pixbuf), _('Unknown') return Gtk.Image.new_from_pixbuf(self.default_pixbuf), _('Unknown')
@@ -394,7 +421,7 @@ class ClientsIconsPlugin(GajimPlugin):
if not caps: if not caps:
caps = self.check_jid(jid) caps = self.check_jid(jid)
self.set_icon(roster.model, iter_, self.renderer_num, self.set_icon(roster.model, iter_, self.renderer_num,
caps) caps, contact)
@log_calls('ClientsIconsPlugin') @log_calls('ClientsIconsPlugin')
def connect_with_groupchat_control(self, chat_control): def connect_with_groupchat_control(self, chat_control):
@@ -438,7 +465,7 @@ class ClientsIconsPlugin(GajimPlugin):
continue continue
caps = gc_contact.client_caps._node caps = gc_contact.client_caps._node
self.set_icon(chat_control.model, iter_, self.muc_renderer_num, self.set_icon(chat_control.model, iter_, self.muc_renderer_num,
caps) caps, gc_contact)
chat_control.draw_all_roles() chat_control.draw_all_roles()
# Recalculate column width for ellipsizin # Recalculate column width for ellipsizin
chat_control.list_treeview.columns_autosize() chat_control.list_treeview.columns_autosize()
@@ -515,7 +542,40 @@ class ClientsIconsPlugin(GajimPlugin):
self.renderer_num + 1:] self.renderer_num + 1:]
roster.setup_and_draw_roster() roster.setup_and_draw_roster()
def presence_received(self, iq_obj): def caps_disco_received(self, iq_obj):
log.debug("caps disco received...")
if not self.config['show_in_roster']:
return
roster = app.interface.roster
contact = app.contacts.get_contact_from_full_jid(iq_obj.conn.name,
iq_obj.jid)
if contact is None:
room_jid, nick = app.get_room_and_nick_from_fjid(iq_obj.fjid)
contact = app.contacts.get_gc_contact(iq_obj.conn.name, room_jid,
nick)
if contact:
gc_control = app.interface.msg_win_mgr.get_gc_control(
iq_obj.jid, iq_obj.conn.name)
iter_ = gc_control.get_contact_iter(nick)
self.set_icon(gc_control.model, iter_, self.muc_renderer_num,
None, contact)
return
if not contact:
return
child_iters = roster._get_contact_iter(iq_obj.jid, iq_obj.conn.name,
contact, roster.model)
if not child_iters:
return
for iter_ in child_iters:
caps = contact.client_caps._node
caps_ = self.check_jid(iq_obj.jid)
if caps_:
caps = caps_
self.set_icon(roster.model, iter_, self.renderer_num,
caps, contact)
def caps_presence_received(self, iq_obj):
log.debug("caps presence received...")
if not self.config['show_in_roster']: if not self.config['show_in_roster']:
return return
roster = app.interface.roster roster = app.interface.roster
@@ -533,17 +593,17 @@ class ClientsIconsPlugin(GajimPlugin):
iter_ = iters[0] iter_ = iters[0]
if contact.show == 'error': if contact.show == 'error':
self.set_icon(roster.model, iter_, self.renderer_num, None) self.set_icon(roster.model, iter_, self.renderer_num, None, contact)
return return
if contact != iq_obj.contact: # higest contact changed
# higest contact changed if roster.model[iter_][self.renderer_num] is not None:
if roster.model[iter_][self.renderer_num] is not None: caps = contact.client_caps._node
caps = contact.client_caps._node if caps:
if caps: log.debug('caps_presence_received, caps: %s', caps)
log.debug('presence_received, caps: %s', caps) self.set_icon(roster.model, iter_, self.renderer_num, caps, contact)
self.set_icon(roster.model, iter_, self.renderer_num, caps) return
return
caps = None caps = None
tag = iq_obj.stanza.getTags('c') tag = iq_obj.stanza.getTags('c')
if tag: if tag:
@@ -562,9 +622,10 @@ class ClientsIconsPlugin(GajimPlugin):
caps = caps_from_jid caps = caps_from_jid
for iter_ in iters: for iter_ in iters:
self.set_icon(roster.model, iter_, self.renderer_num, caps) self.set_icon(roster.model, iter_, self.renderer_num, caps, contact)
def gc_presence_received(self, iq_obj): def gc_presence_received(self, iq_obj):
log.debug("gc presence received...")
if not self.config['show_in_groupchats']: if not self.config['show_in_groupchats']:
return return
contact = app.contacts.get_gc_contact(iq_obj.conn.name, contact = app.contacts.get_gc_contact(iq_obj.conn.name,
@@ -585,19 +646,28 @@ class ClientsIconsPlugin(GajimPlugin):
model = iq_obj.gc_control.model model = iq_obj.gc_control.model
if model[iter_][self.muc_renderer_num] is not None: if model[iter_][self.muc_renderer_num] is not None:
return return
self.set_icon(model, iter_, self.muc_renderer_num, caps) self.set_icon(model, iter_, self.muc_renderer_num, caps, contact)
def set_icon(self, model, iter_, pos, caps): def set_icon(self, model, iter_, pos, caps, contact):
if not caps: client_name = _('Unknown')
if self.config['show_unknown_icon']: client_icon = None
model[iter_][pos] = self.default_pixbuf identities = contact.client_caps._lookup_in_cache(
return caps_cache.capscache).identities
caps_ = caps.split('#')[0].split() if identities:
if caps_: log.debug('set_icon, identities: %s', str(identities))
log.debug('set_icon, caps_: %s', caps_) client_name = identities[0].get('name', _('Unknown'))
client_icon = clients.get(caps_[0].split()[0], (None,))[0] name_splits = client_name.split()
else: name_splits = reversed([" ".join(name_splits[:(i+1)]) for i in range(len(name_splits))])
client_icon = None for name in name_splits:
if not client_icon:
log.debug("set_icon, searching for name fragment '%s'..." % name)
client_icon = clients.get(name, (None,))[0]
if caps and not client_icon:
caps_ = caps.split('#')[0].split()
if caps_:
log.debug('set_icon, caps_: %s', caps_)
client_icon = clients.get(caps_[0].split()[0], (None,))[0]
if not client_icon: if not client_icon:
if self.config['show_unknown_icon']: if self.config['show_unknown_icon']:

View File

@@ -1,9 +1,10 @@
[info] [info]
name: Clients icons name: Clients icons
short_name: clients_icons short_name: clients_icons
version: 6.1 version: 7.0
description: Shows client icons in roster and in groupchats. description: Shows client icons in roster and in groupchats.
authors: Denis Fomin <fominde@gmail.com> authors: Denis Fomin <fominde@gmail.com>
Artem Klyop <art.klyop@gmail.com> Artem Klyop <art.klyop@gmail.com>
Thilo Molitor <thilo@eightysoft.de>
homepage: https://dev.gajim.org/gajim/gajim-plugins/wikis/ClientsIconsPlugin homepage: https://dev.gajim.org/gajim/gajim-plugins/wikis/ClientsIconsPlugin
min_gajim_version: 0.16.11 min_gajim_version: 0.16.11