Skip to content
Snippets Groups Projects
clients_icons.py 28.7 KiB
Newer Older
Dicson's avatar
Dicson committed
# -*- coding: utf-8 -*-
##

Dicson's avatar
Dicson committed
from gi.repository import Gtk
from gi.repository import GdkPixbuf
Dicson's avatar
Dicson committed
import os

Dicson's avatar
Dicson committed
from plugins.gui import GajimPluginConfigDialog
Dicson's avatar
Dicson committed
from plugins import GajimPlugin
Dicson's avatar
Dicson committed
from plugins.helpers import log_calls
Dicson's avatar
Dicson committed
from common import ged
from common import gajim
import cell_renderer_image

clients = {
Yann Leboulanger's avatar
Yann Leboulanger committed
    'http://gajim.org': ['gajim.png', 'Gajim'],
    'http://gajim.org/caps': ['gajim.png', 'Gajim'],
    'http://bombus-im.org/java': ['bombus.png', 'Bombus'],
    'http://bombusmod.net.ru/caps': ['bombusmod.png', 'Bombusmod'],
    'http://psi-dev.googlecode.com/caps': ['psiplus.png', 'Psi+'],
    'http://bombusng-md.googlecode.com': ['bombusng.png', 'Bombus-NG'],
    'http://bombus-im.org/ng': ['bombusng.png', 'Bombus-NG'],
    'http://voffk.org.ru/bombus': ['bombusplus.png', 'Bombus+'],
    'http://bombusng-qd.googlecode.com': ['bombusqd.png', 'Bombus-NG'],
    'http://bombusmod-qd.wen.ru/caps': ['bombusqd.png', 'BombusQD'],
Yann Leboulanger's avatar
Yann Leboulanger committed
    'http://bombusmod.net.ru': ['bombusmod.png', 'Bombusmod'],
    'http://ex-im.name/caps': ['bombusmod.png', 'Bombusmod'],
    'http://bombusmod.eu,http://bombus.pl': ['bombuspl.png', 'Bombusmod'],
    'http://mcabber.com/caps': ['mcabber.png', 'MCabber'],
    'http://miranda-im.org/caps': ['miranda.png', 'Miranda'],
    'http://www.asterisk.org/xmpp/client/caps': ['asterisk.png', 'Asterisk'],
    'http://www.google.com/xmpp/client/caps': ['talkonaut.png', 'Talkonaut'],
    'http://talkgadget.google.com/client/caps': ['google.png', 'GTalk'],
    'http://oneteam.im/caps': ['oneteamiphone.png', 'OneTeam'],
    'http://tkabber.jabber.ru/': ['tkabber.png', 'Tkabber'],
    'http://pidgin.im/': ['pidgin.png', 'Pidgin'],
    'http://pidgin.im/caps': ['pidgin.png', 'Pidgin'],
    'http://qutim.org': ['qutim.png', 'QutIM'],
    'http://qutim.org/': ['qutim.png', 'QutIM'],
    'http://exodus.jabberstudio.org/caps': ['exodus.png', 'Exodus'],
    'http://bitlbee.org/xmpp/caps': ['bitlbee.png', 'Bitlbee'],
    'http://coccinella.sourceforge.net/protocol/caps': ['coccinella.png', 'Coccinella'],
    'http://mcabber.lilotux.net/caps': ['mcabber.png', 'MCabber'],
    'http://dev.jabbim.cz/jabbim/caps': ['jabbim.png', 'Jabbim'],
    'http://palringo.com/caps': ['palringo.png', 'Palringo'],
    'http://vacuum-im.googlecode.com': ['vacuum.png', 'Vacuum'],
    'http://code.google.com/p/vacuum-im/': ['vacuum.png', 'Vacuum'],
    'http://jajc.jrudevels.org/caps': ['jajc.png', 'JAJC'],
    'http://gaim.sf.net/caps': ['gaim.png', 'Gaim'],
    'http://mchat.mgslab.com/': ['mchat.png', 'Mchat'],
    'http://online.yandex.ru/caps': ['yaonline.png', 'Yaonline'],
    'http://psi-im.org/caps': ['psi.png', 'Psi'],
    'http://jimm.net.ru/caps': ['jimm-aspro.png', 'Jimm'],
Dicson's avatar
Dicson committed
    'http://jabga.ru': ['fin.png', 'Fin jabber'],
Yann Leboulanger's avatar
Yann Leboulanger committed
    'http://bluendo.com/protocol/caps': ['lampiro.png', 'Lampiro'],
    'nimbuzz:caps': ['nimbuzz.png', 'Nimbuzz'],
    'http://nimbuzz.com/caps': ['nimbuzz.png', 'Nimbuzz'],
    'http://isida.googlecode.com': ['isida-bot.png', 'Isida'],
    'http://isida-bot.com': ['isida-bot.png', 'Isida'],
    'http://apps.radio-t.com/caps': ['radio-t.png', 'Radio-t'],
    'http://pda.qip.ru/caps': ['qippda.png', 'Qip-PDA'],
    'http://kopete.kde.org/jabber/caps': ['kopete.png', 'Kopete'],
    'http://www.apple.com/ichat/caps': ['ichat.png', 'IChat'],
    'http://pjc.googlecode.com/caps': ['jubo.png', 'Jubo'],
    'talk.google.com': ['talk.google.com.png', 'GTalk'],
    'http://www.android.com/gtalk/client/caps': ['talk.google.com.png', 'GTalk'],
    'http://swift.im': ['swift.png', 'Swift'],
    'http://fatal-bot.spb.ru/caps': ['bot.png', 'Fatal-bot'],
    'http://svn.posix.ru/fatal-bot/trunk': ['bot.png', 'Fatal-bot'],
    'http://storm-bot.googlecode.com/svn/trunk': ['bot.png', 'Storm-bot'],
    'http://talk.google.com/xmpp/bot/caps': ['google.png', 'GTalk'],
    'http://jabbrik.ru/caps': ['bot.png', 'Jabbrik'],
    'http://jabrvista.net.ru': ['bot.png', 'Jabvista'],
    'http://xu-6.jabbrik.ru/caps': ['bot.png', 'XU-6'],
    'http://jabber.pdg.pl/caps': ['bombus-klub.png', 'Bombus-klub'],
    'http://klub54.wen.ru': ['bombus-klub.png', 'Bombus-klub'],
    'http://aqq.eu/': ['aqq.png', 'Aqq'],
    'http://2010.qip.ru/caps': ['qip.png', 'Qip'],
    'http://qip.ru/caps': ['qip.png', 'Qip'],
    'http://qip.ru/caps?QIP': ['qip.png', 'Qip'],
    'http://glu.net/': ['glu.png', 'Glu'],
    'Siemens': ['siejc.png', 'Siemens'],  # Siemens Native Jabber Client
    'telepathy.': ['telepathy.freedesktop.org.png', 'Telepathy'],
    'http://live.gnome.org/empathy/caps': ['telepathy.freedesktop.org.png', 'Empathy'],
    'http://telepathy.freedesktop.org/caps': ['telepathy.freedesktop.org.png', 'Telepathy'],
    'http://www.adiumx.com/caps': ['adium.png', 'Adium'],
    'http://www.adiumx.com': ['adium.png', 'Adium'],
    'http://juick.com/caps': ['juick.png', 'Juick'],
    'vk.com': ['vkontakte.png', 'Vkontakte'],
    'facebook.com': ['facebook.png', 'Facebook'],
    'http://mail.google.com/xmpp/client/caps': ['google.com.png', 'GMail'],
    'http://snapi-bot.googlecode.com/caps': ['bot.png', 'Snapi-bot'],
    'http://www.barobin.com/caps': ['bayanicq.png', 'Bayanicq'],
    'http://chat.ovi.com/caps': ['ovi-chat.png', 'Ovi-chat'],
    'http://trillian.im/caps': ['trillian.png', 'Trillian'],
    'http://pandion.im/': ['pandion.png', 'Pandion'],
    'http://agent.mail.ru/caps': ['mailruagent.png', 'Mailruagent'],
    'http://agent.mail.ru/': ['mailruagent.png', 'Mailruagent'],
    'http://digsby.com/caps': ['digsby.png', 'Digsby'],
    'http://jabber-net.ru/caps/talisman-bot': ['bot.png', 'Talisman-bot'],
    'http://jabber-net.ru/talisman-bot/caps': ['bot.png', 'Talisman-bot'],
    'http://j-tmb.ru/caps': ['bot.png', 'J-tmb'],
    'http://simpleapps.ru/caps#blacksmith': ['bot.png', 'Blacksmith'],
    'http://blacksmith-2.googlecode.com/svn/': ['bot.png', 'Blacksmith-2'],
    'http://qabber.ru/jame-bot': ['bot.png', 'Jame-bot'],
    'http://chat.freize.org/caps': ['freize.png', 'Freize'],
    'http://pyvk-t.googlecode.com/caps': ['vkontakte.png', 'Vkontakte'],
    'http://pyvk': ['vkontakte.png', 'Vkontakte'],
    'http://pyicq': ['pyicq-t.png', 'PyICQ-t'],
    'http://spectrum.im/transport': ['pyicq-t.png', 'PyICQ-t'],
    'http://pyaim': ['pyaim-t.png', 'PyAIM-t'],
    'http://jabbroid.akuz.de': ['android.png', 'Jabbroid'],
    'http://jabbroid.akuz.de/caps': ['android.png', 'Jabbroid'],
    'http://witcher-team.ucoz.ru/': ['bot.png', 'Witcher'],
    'http://home.gna.org/': ['omnipresence.png', 'Omnipresence'],
    'http://ayttm.souceforge.net/caps': ['ayttm.png', 'Ayttm'],
    'http://www.process-one.net/en/solutions/oneteam_iphone/': \
Yann Leboulanger's avatar
Yann Leboulanger committed
        ['oneteamiphone.png', 'OneTeam-iphone'],
    'http://qq-im.com/caps': ['qq.png', 'QQ'],
    'http://qq.com/caps': ['qq.png', 'QQ'],
    'http://www.lonelycatgames.com/slick/caps': ['slick.png', 'Slick'],
    'http://sim-im.org/caps': ['sim.png', 'Sim'],
    'http://www.igniterealtime.org/project/spark/caps': ['spark.png', 'Spark'],
    'http://emess.eqx.su/caps': ['emess.png', 'Emess'],
    'https://www.jappix.com/': ['jappix.png', 'Jappix'],
    'http://japyt.googlecode.com': ['japyt.png', 'Japyt'],
    'http://www.xfire.com/': ['xfire.png', 'Xfire'],
    'http://www.xfire.com/caps': ['xfire.png', 'Xfire'],
    'http://lytgeygen.ru/caps': ['bot.png', 'Lytgeygen'],
    'http://aspro.users.ru/historian-bot/': ['bot.png', 'Historian-bot'],
    'http://pigeon.vpro.ru/caps': ['pigeon.png', 'Pigeon'],
    'http://jtalk.ustyugov.net/caps': ['jtalk.png', 'Jtalk'],
    'psto@psto.net': ['psto.png', 'Psto'],
    'http://jasmineicq.ru/caps': ['jasmine.png', 'Jasmine'],
    'http://tomclaw.com/mandarin_im/caps': ['mandarin.png', 'Mandarin'],
    'http://gabber.sourceforge.net': ['gabber.png', 'Gabber'],
    'http://www.igniterealtime.org/projects/smack/': ['xabber.png', 'Xabber'],
    'http://megafonvolga.ru/': ['megafon.png', 'Megafon'],
    'rss@isida-bot.com': ['osiris.png', 'Osiris'],
    'libpurple': ['libpurple.png', 'Libpurple'],
    'http://www.adium.im/': ['adium.png', 'Adium'],
    'http://eqo.com/': ['libpurple.png', 'Eqo'],
    'http://instantbird.com/': ['instantbird.png', 'Instantbird'],
    'https://www.meebo.com/': ['meebo.png', 'Meebo'],
    'http://opensource.palm.com/packages.html': ['palm.png', 'Palm'],
    'http://spectrum.im/': ['spectrum.png', 'Spectrum'],
    'http://tigase.org/messenger': ['tigase.png', 'Tigase'],
    'httр://sleekxmpp.com/ver/1.1.11': ['poezio.png', 'Poezio'],
Dicson's avatar
Dicson committed
    'http://jitsi.org' :['jitsi.png', 'Jitsi'],
Dicson's avatar
Dicson committed
    'http://miranda-ng.org/caps' :['miranda_ng.png', 'Miranda NG'],
}
libpurple_clients ={
    'adium': 'http://www.adium.im/',
    'eqo': 'http://eqo.com/',
    'finch': 'http://pidgin.im/',
    'instantbird': 'http://instantbird.com/',
    'meebo': 'https://www.meebo.com/',
    'palm': 'http://opensource.palm.com/packages.html',
    'pidgin': 'http://pidgin.im/',
    'spectrum': 'http://spectrum.im/',
    'telepathy-haze': 'http://pidgin.im/'
Dicson's avatar
Dicson committed
}
Dicson's avatar
Dicson committed

Dicson's avatar
Dicson committed
class ClientsIconsPlugin(GajimPlugin):

    @log_calls('ClientsIconsPlugin')
    def init(self):
Dicson's avatar
Dicson committed
        self.description = _('Shows the client icons in the roster'
Dicson's avatar
Dicson committed
            ' and in groupchats.\nFor icons in tooltip support, '
Dicson's avatar
Dicson committed
            'you need to install Gajim r14117 or above.')
        self.pos_list = [_('after statusicon'), _('before avatar')]
        self.events_handlers = {'presence-received':
Dicson's avatar
Dicson committed
                                    (ged.POSTGUI, self.presence_received),
                                'gc-presence-received':
Dicson's avatar
Dicson committed
                                    (ged.POSTGUI, self.gc_presence_received), }
Dicson's avatar
Dicson committed
        self.gui_extension_points = {
Dicson's avatar
Dicson committed
            'groupchat_control': (self.connect_with_groupchat_control,
                                    self.disconnect_from_groupchat_control),
Dicson's avatar
Dicson committed
            'roster_draw_contact': (self.connect_with_roster_draw_contact,
                                    self.disconnect_from_roster_draw_contact),
            'roster_tooltip_populate': (self.connect_with_roster_tooltip_populate,
                                    self.disconnect_from_roster_tooltip_populate),
            'gc_tooltip_populate': (self.connect_with_gc_tooltip_populate,
                                    self.disconnect_from_gc_tooltip_populate),}
Dicson's avatar
Dicson committed
        self.config_default_values = {
Dicson's avatar
Dicson committed
                'show_in_roster': (True, ''),
                'show_in_groupchats': (True, ''),
                'show_in_tooltip': (True, ''),
Dicson's avatar
Dicson committed
                'show_unknown_icon': (True, ''),
                'show_facebook': (True, ''),}
        self.config_dialog = ClientsIconsPluginConfigDialog(self)
        icon_path = os.path.join(self.local_file_path('icons'), 'unknown.png')
Dicson's avatar
Dicson committed
        self.default_pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(icon_path,
        self.icon_cache = {}
    @log_calls('ClientsIconsPlugin')
    def connect_with_gc_tooltip_populate(self, tooltip, contact,
    vcard_table):
        if not self.config['show_in_tooltip']:
            return

        #fill clients table
Dicson's avatar
Dicson committed
        self.table = Gtk.Grid()
        self.table.insert_row(0)
        self.table.insert_row(0)
        self.table.insert_column(0)
        self.table.set_property('column-spacing', 2)

        caps = contact.client_caps._node
        caps_image , client_name = self.get_icon(caps, contact)
        caps_image.set_alignment(0, 0)
Dicson's avatar
Dicson committed
        self.table.attach(caps_image, 1, 1, 1, 1)
Dicson's avatar
Dicson committed
        label = Gtk.Label()
        label.set_alignment(0, 0)
        label.set_markup(client_name)
Dicson's avatar
Dicson committed
        self.table.attach(label, 2, 1, 1, 1)
        # set label
Dicson's avatar
Dicson committed
        label = Gtk.Label()
        label.set_alignment(0, 0)
        label.set_markup(_('Client:'))
Dicson's avatar
Dicson committed
        vcard_table.attach(label, 1, 100, 1,1)
        # set client table to tooltip
Dicson's avatar
Dicson committed
        vcard_table.attach(self.table, 2, 100, 1,1)
    def connect_with_roster_tooltip_populate(self, tooltip, contacts,
    vcard_table):
        if not self.config['show_in_tooltip']:
            return
        if len(contacts) == 1 and contacts[0].jid in gajim.get_our_jids():
            return
        # put contacts in dict, where key is priority
        num_resources = 0
        contacts_dict = {}
        for contact in contacts:
            if contact.resource:
                num_resources += 1
                if contact.priority in contacts_dict:
                    contacts_dict[contact.priority].append(contact)
                else:
                    contacts_dict[contact.priority] = [contact]
        contact_keys = sorted(contacts_dict.keys())
        contact_keys.reverse()

Dicson's avatar
Dicson committed
        #fill clients table
Dicson's avatar
Dicson committed
        self.table = Gtk.Grid()
        self.table.insert_row(0)
        self.table.insert_row(0)
        self.table.insert_column(0)
Dicson's avatar
Dicson committed
        self.table.set_property('column-spacing', 2)
Dicson's avatar
Dicson committed
        first_place = 100
Dicson's avatar
Dicson committed
        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)
Dicson's avatar
Dicson committed
                caps_image.set_alignment(0, 0)
Dicson's avatar
Dicson committed
                self.table.attach(caps_image, 1, vcard_current_row, 1, 1)
Dicson's avatar
Dicson committed
                label = Gtk.Label()
Dicson's avatar
Dicson committed
                label.set_alignment(0, 0)
                label.set_markup(client_name)
Dicson's avatar
Dicson committed
                self.table.attach(label, 2, vcard_current_row, 1, 1)
Dicson's avatar
Dicson committed
                vcard_current_row += 1
Dicson's avatar
Dicson committed
        label = Gtk.Label()
        label.set_alignment(0, 0)
        if num_resources > 1:
            label.set_markup(_('Clients:'))
        else:
            if contact.show == 'offline':
                return
            label.set_markup(_('Client:'))
Dicson's avatar
Dicson committed
        vcard_table.attach(label, 1, first_place,  1, 1)
        # set clients table to tooltip
Dicson's avatar
Dicson committed
        vcard_table.attach(self.table, 2, first_place, 1, 1)

    def get_icon(self, caps, contact=None):
        if not caps:
            return Gtk.Image.new_from_pixbuf(self.default_pixbuf), _('Unknown')
Dicson's avatar
Dicson committed
        if 'pidgin.im/' in caps:
            caps = 'libpurple'
            for client in libpurple_clients:
                if client in contact.resource.lower():
                    caps = libpurple_clients[client]

        if 'sleekxmpp.com'in caps:
            caps = 'httр://sleekxmpp.com/ver/1.1.11'

Dicson's avatar
Dicson committed
        caps_from_jid = self.check_jid(contact.jid)
        if caps_from_jid:
            caps = caps_from_jid

        caps_ = caps.split('#')[0].split()
        if caps_:
            client_icon = clients.get(caps_[0].split()[0], (None,))[0]
Dicson's avatar
Dicson committed
            client_name = clients.get(caps_[0].split()[0], ('', _('Unknown')))[1]
        else:
            client_icon = None

        if not client_icon:
            return Gtk.Image.new_from_pixbuf(self.default_pixbuf), _('Unknown')
        else:
            icon_path = os.path.join(self.local_file_path('icons'),
                client_icon)
            if icon_path in self.icon_cache:
                return Gtk.Image.new_from_pixbuf(self.icon_cache[icon_path]), \
                    client_name
            else:
Dicson's avatar
Dicson committed
                pb = GdkPixbuf.Pixbuf.new_from_file_at_size(icon_path, 16, 16)
                self.icon_cache[icon_path] = pb
                return Gtk.Image.new_from_pixbuf(pb), client_name

    @log_calls('ClientsIconsPlugin')
    def disconnect_from_roster_tooltip_populate(self, tooltip, contacts,
    vcard_table):
        pass
Dicson's avatar
Dicson committed
    def check_jid(self, jid):
        caps = None
        if 'facebook.com' in jid and self.config['show_facebook']:
            caps = 'facebook.com'
        elif '@vk.com' in jid and self.config['show_facebook']:
            caps = 'vk.com'
        elif jid == 'juick@juick.com':
            caps = 'http://juick.com/caps'
        elif jid == 'psto@psto.net':
            caps = 'psto@psto.net'
        elif jid == 'rss@isida-bot.com':
            caps = 'rss@isida-bot.com'
        return caps

    @log_calls('ClientsIconsPlugin')
    def connect_with_roster_draw_contact(self, roster, jid, account, contact):
        if not self.active:
            return
        if not self.config['show_in_roster']:
            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:
                caps = contact.client_caps._node
                if not caps:
                    caps = self.check_jid(jid)
                self.set_icon(roster.model, iter_, self.renderer_num,
                    caps)
Dicson's avatar
Dicson committed
    @log_calls('ClientsIconsPlugin')
    def connect_with_groupchat_control(self, chat_control):
        chat_control.nb_ext_renderers += 1
Dicson's avatar
Dicson committed
        chat_control.columns += [GdkPixbuf.Pixbuf]
Dicson's avatar
Dicson committed
        self.groupchats_tree_is_transformed = True
        self.chat_control = chat_control
Dicson's avatar
Dicson committed
        col = Gtk.TreeViewColumn()
Dicson's avatar
Dicson committed
        self.muc_renderer_num = 4 + chat_control.nb_ext_renderers
Dicson's avatar
Dicson committed
        client_icon_rend = ('client_icon', Gtk.CellRendererPixbuf(), False,
Dicson's avatar
Dicson committed
                'pixbuf', self.muc_renderer_num,
                self.tree_cell_data_func, chat_control)
        # remove old column
        chat_control.list_treeview.remove_column(
            chat_control.list_treeview.get_column(0))
        # add new renderer in renderers list
        position_list = ['name', 'avatar']
        position = position_list[self.config['pos_in_list']]
Dicson's avatar
Dicson committed
        for renderer in chat_control.renderers_list:
            if renderer[0] == position:
Dicson's avatar
Dicson committed
                break
        num = chat_control.renderers_list.index(renderer)
        chat_control.renderers_list.insert(num, client_icon_rend)
        # fill and append column
        chat_control.fill_column(col)
        chat_control.list_treeview.insert_column(col, 0)
        # redraw roster
Dicson's avatar
Dicson committed
        chat_control.model = Gtk.TreeStore(*chat_control.columns)
        chat_control.model.set_sort_func(1, chat_control.tree_compare_iters)
Dicson's avatar
Dicson committed
        chat_control.model.set_sort_column_id(1, Gtk.SortType.ASCENDING)
        chat_control.list_treeview.set_model(chat_control.model)
        # draw roster
        for nick in gajim.contacts.get_nick_list(chat_control.account,
            chat_control.room_jid):
            gc_contact = gajim.contacts.get_gc_contact(chat_control.account,
                chat_control.room_jid, nick)
            iter_ = chat_control.add_contact_to_roster(nick, gc_contact.show,
                gc_contact.role, gc_contact.affiliation, gc_contact.status,
                gc_contact.jid)
            if not self.config['show_in_groupchats']:
                continue
            caps = gc_contact.client_caps._node
            self.set_icon(chat_control.model, iter_, self.muc_renderer_num,
                caps)
        chat_control.draw_all_roles()
        # Recalculate column width for ellipsizin
        chat_control.list_treeview.columns_autosize()
Dicson's avatar
Dicson committed

    @log_calls('ClientsIconsPlugin')
    def disconnect_from_groupchat_control(self, gc_control):
        gc_control.nb_ext_renderers -= 1
        col = gc_control.list_treeview.get_column(0)
        gc_control.list_treeview.remove_column(col)
Dicson's avatar
Dicson committed
        col = Gtk.TreeViewColumn()
        for renderer in gc_control.renderers_list:
            if renderer[0] == 'client_icon':
                gc_control.renderers_list.remove(renderer)
                break
        gc_control.fill_column(col)
        gc_control.list_treeview.insert_column(col, 0)
        gc_control.columns = gc_control.columns[:self.muc_renderer_num] + \
Dicson's avatar
Dicson committed
            gc_control.columns[self.muc_renderer_num + 1:]
Dicson's avatar
Dicson committed
        gc_control.model = Gtk.TreeStore(*gc_control.columns)
Dicson's avatar
Dicson committed
        gc_control.model.set_sort_func(1, gc_control.tree_compare_iters)
Dicson's avatar
Dicson committed
        gc_control.model.set_sort_column_id(1, Gtk.SortType.ASCENDING)
Dicson's avatar
Dicson committed
        gc_control.list_treeview.set_model(gc_control.model)
Dicson's avatar
Dicson committed

    @log_calls('ClientsIconsPlugin')
    def disconnect_from_roster_draw_contact(self, roster, jid, account,
        contact):
        pass

Dicson's avatar
Dicson committed
    @log_calls('ClientsIconsPlugin')
    def activate(self):
Dicson's avatar
Dicson committed
        self.active = None
Dicson's avatar
Dicson committed
        roster = gajim.interface.roster
Dicson's avatar
Dicson committed
        col = Gtk.TreeViewColumn()
Dicson's avatar
Dicson committed
        roster.nb_ext_renderers += 1
        self.renderer_num = 10 + roster.nb_ext_renderers
Dicson's avatar
Dicson committed
        self.renderer = Gtk.CellRendererPixbuf()
Dicson's avatar
Dicson committed
        client_icon_rend = ('client_icon', self.renderer, False,
Dicson's avatar
Dicson committed
                'pixbuf', self.renderer_num,
                roster._fill_pep_pixbuf_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[self.config['pos_in_list']]
Dicson's avatar
Dicson committed
        for renderer in roster.renderers_list:
            if renderer[0] == position:
Dicson's avatar
Dicson committed
                break
        num = roster.renderers_list.index(renderer)
Dicson's avatar
Dicson committed
        roster.renderers_list.insert(num, client_icon_rend)
Dicson's avatar
Dicson committed
        # fill and append column
        roster.fill_column(col)
        roster.tree.insert_column(col, 0)
        # redraw roster
Dicson's avatar
Dicson committed
        roster.columns += [GdkPixbuf.Pixbuf]
Dicson's avatar
Dicson committed
        self.active = True
Dicson's avatar
Dicson committed
        roster.setup_and_draw_roster()

    @log_calls('ClientsIconsPlugin')
    def deactivate(self):
Dicson's avatar
Dicson committed
        self.active = None
Dicson's avatar
Dicson committed
        roster = gajim.interface.roster
        roster.nb_ext_renderers -= 1
        col = roster.tree.get_column(0)
        roster.tree.remove_column(col)
Dicson's avatar
Dicson committed
        col = Gtk.TreeViewColumn()
Dicson's avatar
Dicson committed
        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[
Dicson's avatar
Dicson committed
            self.renderer_num + 1:]
Dicson's avatar
Dicson committed
        roster.setup_and_draw_roster()

    def presence_received(self, iq_obj):
Dicson's avatar
Dicson committed
        if not self.config['show_in_roster']:
            return
Dicson's avatar
Dicson committed
        roster = gajim.interface.roster
        contact = gajim.contacts.get_contact_with_highest_priority(
            iq_obj.conn.name, iq_obj.jid)
        if not contact:
            return
Dicson's avatar
Dicson committed
        if iq_obj.resource == 'local':
            # zeroconf
            return

        iters = roster._get_contact_iter(iq_obj.jid, iq_obj.conn.name, contact,
            roster.model)
        iter_ = iters[0]

        if contact.show == 'error':
            self.set_icon(roster.model, iter_, self.renderer_num, None)
            return

Dicson's avatar
Dicson committed
        if contact != iq_obj.contact:
Dicson's avatar
Dicson committed
            # higest contact changed
            if roster.model[iter_][self.renderer_num] is not None:
                caps = contact.client_caps._node
Dicson's avatar
Dicson committed
                if caps:
                    self.set_icon(roster.model, iter_, self.renderer_num, caps)
                    return
Dicson's avatar
Dicson committed
        caps = None
Dicson's avatar
Dicson committed
        tag = iq_obj.stanza.getTags('c')
Dicson's avatar
Dicson committed
        if tag:
            caps = tag[0].getAttr('node')
Dicson's avatar
Dicson committed
            if caps:
Dicson's avatar
Dicson committed
                if 'pidgin.im/' in caps:
Dicson's avatar
Dicson committed
                    caps = 'libpurple'
                    for client in libpurple_clients:
                        if client in contact.resource.lower():
                            caps = libpurple_clients[client]
                if 'sleekxmpp.com'in caps:
                    caps = 'httр://sleekxmpp.com/ver/1.1.11'
Dicson's avatar
Dicson committed

        caps_from_jid = self.check_jid(iq_obj.jid)
        if caps_from_jid:
            caps = caps_from_jid

        for iter_ in iters:
            self.set_icon(roster.model, iter_, self.renderer_num, caps)
Dicson's avatar
Dicson committed

    def gc_presence_received(self, iq_obj):
Dicson's avatar
Dicson committed
        if not self.config['show_in_groupchats']:
            return
Dicson's avatar
Dicson committed
        contact = gajim.contacts.get_gc_contact(iq_obj.conn.name,
Dicson's avatar
Dicson committed
            iq_obj.presence_obj.jid, iq_obj.nick)
Dicson's avatar
Dicson committed
        if not contact:
            return
        caps = None
Dicson's avatar
Dicson committed
        tag = iq_obj.stanza.getTags('c')
Dicson's avatar
Dicson committed
        if tag:
            caps = tag[0].getAttr('node')
Dicson's avatar
Dicson committed
            if 'pidgin.im/' in caps:
            if 'sleekxmpp.com' in caps:
                caps = 'httр://sleekxmpp.com/ver/1.1.11'
Dicson's avatar
Dicson committed
        iter_ = iq_obj.gc_control.get_contact_iter(iq_obj.nick)
        model = iq_obj.gc_control.model
Dicson's avatar
Dicson committed
        if model[iter_][self.muc_renderer_num] is not None:
            return
        self.set_icon(model, iter_, self.muc_renderer_num, caps)

    def set_icon(self, model, iter_, pos, caps):
Dicson's avatar
Dicson committed
        if not caps:
Dicson's avatar
Dicson committed
            if self.config['show_unknown_icon']:
                model[iter_][pos] = self.default_pixbuf
Dicson's avatar
Dicson committed
            return
Dicson's avatar
Dicson committed

        caps_ = caps.split('#')[0].split()
        if caps_:
            client_icon = clients.get(caps_[0].split()[0], (None,))[0]
Dicson's avatar
Dicson committed
        else:
            client_icon = None

Dicson's avatar
Dicson committed
        if not client_icon:
            if self.config['show_unknown_icon']:
                model[iter_][pos] = self.default_pixbuf
Dicson's avatar
Dicson committed
        else:
            icon_path = os.path.join(self.local_file_path('icons'),
                client_icon)
            if icon_path in self.icon_cache:
                model[iter_][pos] = self.icon_cache[icon_path]
            else:
Dicson's avatar
Dicson committed
                pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(icon_path, 16, 16)
                model[iter_][pos] = pixbuf
                self.icon_cache[icon_path] = pixbuf
Dicson's avatar
Dicson committed

    def tree_cell_data_func(self, column, renderer, model, iter_, control):
        if not model.iter_parent(iter_):
            renderer.set_property('visible', False)
            return
        elif model[iter_][self.muc_renderer_num]:
            renderer.set_property('visible', True)
Dicson's avatar
Dicson committed

        contact = gajim.contacts.get_gc_contact(control.account,
Dicson's avatar
Dicson committed
            control.room_jid, model[iter_][1])
Dicson's avatar
Dicson committed
        if not contact:
            return

        bgcolor = gajim.config.get_per('themes', gajim.config.get(
            'roster_theme'), 'contactbgcolor')
        if bgcolor:
            renderer.set_property('cell-background', bgcolor)
        else:
            renderer.set_property('cell-background', None)
        renderer.set_property('width', 16)
    @log_calls('ClientsIconsPlugin')
    def disconnect_from_gc_tooltip_populate(self, tooltip, contact,
    vcard_table):
        pass

Dicson's avatar
Dicson committed

Dicson's avatar
Dicson committed
class ClientsIconsPluginConfigDialog(GajimPluginConfigDialog):
    def init(self):
Dicson's avatar
Dicson committed
        self.Gtk_BUILDER_FILE_PATH = self.plugin.local_file_path(
Dicson's avatar
Dicson committed
                'config_dialog.ui')
Dicson's avatar
Dicson committed
        self.xml = Gtk.Builder()
        self.xml.set_translation_domain('gajim_plugins')
Dicson's avatar
Dicson committed
        self.xml.add_objects_from_file(self.Gtk_BUILDER_FILE_PATH,
Dicson's avatar
Dicson committed
                ['vbox1'])
        vbox = self.xml.get_object('vbox1')
Dicson's avatar
Dicson committed
        self.get_child().pack_start(vbox, True, True, 0)
        self.combo = self.xml.get_object('combobox1')
Dicson's avatar
Dicson committed
        self.liststore = Gtk.ListStore(str)
        self.combo.set_model(self.liststore)
Dicson's avatar
Dicson committed
        cellrenderer = Gtk.CellRendererText()
        self.combo.pack_start(cellrenderer, True)
        self.combo.add_attribute(cellrenderer, 'text', 0)

        for item in self.plugin.pos_list:
            self.liststore.append((item,))
        self.combo.set_active(self.plugin.config['pos_in_list'])
        self.xml.get_object('show_in_roster').set_active(
            self.plugin.config['show_in_roster'])
        self.xml.get_object('show_in_groupchats').set_active(
            self.plugin.config['show_in_groupchats'])
        self.xml.get_object('show_unknown_icon').set_active(
            self.plugin.config['show_unknown_icon'])
        self.xml.get_object('show_facebook').set_active(
            self.plugin.config['show_facebook'])
        self.xml.get_object('show_in_tooltip').set_active(
            self.plugin.config['show_in_tooltip'])
        self.xml.connect_signals(self)

    def redraw_all(self):
        self.plugin.deactivate()
        self.plugin.activate()
        for gc_control in gajim.interface.msg_win_mgr.get_controls('gc'):
            self.plugin.disconnect_from_groupchat_control(gc_control)
        for gc_control in gajim.interface.msg_win_mgr.get_controls('gc'):
            self.plugin.connect_with_groupchat_control(gc_control)
Dicson's avatar
Dicson committed

    def on_show_in_roster_toggled(self, widget):
        self.plugin.config['show_in_roster'] = widget.get_active()
        self.plugin.deactivate()
        self.plugin.activate()
    def on_show_in_tooltip_toggled(self, widget):
        self.plugin.config['show_in_tooltip'] = widget.get_active()

Dicson's avatar
Dicson committed
    def on_show_in_groupchats_toggled(self, widget):
        self.plugin.config['show_in_groupchats'] = widget.get_active()
        for gc_control in gajim.interface.msg_win_mgr.get_controls('gc'):
            self.plugin.disconnect_from_groupchat_control(gc_control)
        for gc_control in gajim.interface.msg_win_mgr.get_controls('gc'):
            self.plugin.connect_with_groupchat_control(gc_control)
Dicson's avatar
Dicson committed

    def on_show_unknown_icon_toggled(self, widget):
        self.plugin.config['show_unknown_icon'] = widget.get_active()
    def on_show_facebook_toggled(self, widget):
        self.plugin.config['show_facebook'] = widget.get_active()
        self.redraw_all()

    def on_combobox1_changed(self, widget):
        self.plugin.config['pos_in_list'] = widget.get_active()