Newer
Older
from plugins import GajimPlugin
from plugins.helpers import log_calls, log
from common import ged
from common import gajim
import cell_renderer_image
clients = {
'http://gajim.org': 'gajim.png',
'http://bombus-im.org/java': 'bombus.png',
'http://bombusmod.net.ru/caps': 'bombusmod.png',
'http://psi-dev.googlecode.com/caps': 'psiplus.png',
'http://bombusng-md.googlecode.com': 'bombusng.png',
'http://bombus-im.org/ng': 'bombusng.png',
'http://voffk.org.ru/bombus': 'bombusplus.png',
'http://bombusng-qd.googlecode.com': 'bombusqd.png',
'http://bombusmod-qd.wen.ru/caps': 'bombusqd.png',
'http://bombusmod.net.ru': 'bombusmod.png',
'http://ex-im.name/caps': 'bombusmod.png',
'http://bombusmod.eu,http://bombus.pl': 'bombuspl.png',
'http://mcabber.com/caps': 'mcabber.png',
'http://miranda-im.org/caps': 'miranda.png',
'http://www.asterisk.org/xmpp/client/caps': 'asterisk.png',
'http://www.google.com/xmpp/client/caps': 'talkonaut.png',
'http://talkgadget.google.com/client/caps': 'google.png',
'http://oneteam.im/caps': 'oneteamiphone.png',
'http://tkabber.jabber.ru/': 'tkabber.png',
'http://pidgin.im/': 'pidgin.png',

Yann Leboulanger
committed
'http://pidgin.im/caps': 'pidgin.png',
'http://exodus.jabberstudio.org/caps': 'exodus.png',
'http://bitlbee.org/xmpp/caps': 'bitlbee.png',
'http://coccinella.sourceforge.net/protocol/caps': 'coccinella.png',
'http://mcabber.lilotux.net/caps': 'mcabber.png',
'http://dev.jabbim.cz/jabbim/caps': 'jabbim.png',
'http://palringo.com/caps': 'palringo.png',
'http://vacuum-im.googlecode.com': 'vacuum.png',
'http://code.google.com/p/vacuum-im/': 'vacuum.png',
'http://jajc.jrudevels.org/caps': 'jajc.png',
'http://gaim.sf.net/caps': 'gaim.png',
'http://mchat.mgslab.com/': 'mchat.png',
'http://online.yandex.ru/caps': 'yaonline.png',
'http://psi-im.org/caps': 'psi.png',
'http://jimm.net.ru/caps': 'jimm-aspro.png',
'http://stranger.kiev.ua/caps': 'fin.png',
'http://bluendo.com/protocol/caps': 'lampiro.png',
'nimbuzz:caps': 'nimbuzz.png',
'http://nimbuzz.com/caps': 'nimbuzz.png',
'http://isida.googlecode.com': 'isida-bot.png',
'http://isida-bot.com': 'isida-bot.png',
'http://apps.radio-t.com/caps': 'radio-t.png',
'http://pda.qip.ru/caps': 'qippda.png',
'http://kopete.kde.org/jabber/caps': 'kopete.png',
'http://www.apple.com/ichat/caps': 'ichat.png',
'http://pjc.googlecode.com/caps': 'jubo.png',
'talk.google.com': 'talk.google.com.png',
'http://www.android.com/gtalk/client/caps': 'talk.google.com.png',
'http://swift.im': 'swift.png',
'http://fatal-bot.spb.ru/caps': 'bot.png',
'http://svn.posix.ru/fatal-bot/trunk': 'bot.png',
'http://storm-bot.googlecode.com/svn/trunk': 'bot.png',
'http://talk.google.com/xmpp/bot/caps': 'google.png',
'http://jabbrik.ru/caps': 'bot.png',
'http://jabrvista.net.ru': 'bot.png',
'http://xu-6.jabbrik.ru/caps': 'bot.png',
'http://2010.qip.ru/caps': 'qip.png',
'http://qip.ru/caps': 'qip.png',
'http://qip.ru/caps?QIP': 'qip.png',
'http://live.gnome.org/empathy/caps': 'telepathy.freedesktop.org.png',
'http://telepathy.freedesktop.org/caps': 'telepathy.freedesktop.org.png',
'http://www.adiumx.com/caps': 'adium.png',
'http://www.adiumx.com': 'adium.png',
'facebook.com': 'facebook.png',
'http://mail.google.com/xmpp/client/caps': 'google.com.png',
'http://snapi-bot.googlecode.com/caps': 'bot.png',
'http://www.barobin.com/caps': 'bayanicq.png',
'http://chat.ovi.com/caps': 'ovi-chat.png',
'http://trillian.im/caps': 'trillian.png',
'http://pandion.im/': 'pandion.png',
'http://agent.mail.ru/caps': 'mailruagent.png',
'http://agent.mail.ru/': 'mailruagent.png',
'http://digsby.com/caps': 'digsby.png',
'http://jabber-net.ru/caps/talisman-bot': 'bot.png',
'http://jabber-net.ru/talisman-bot/caps': 'bot.png',
'http://j-tmb.ru/caps': 'bot.png',
'http://simpleapps.ru/caps#blacksmith': 'bot.png',
'http://blacksmith-2.googlecode.com/svn/': 'bot.png',
'http://qabber.ru/jame-bot': 'bot.png',
'http://chat.freize.org/caps': 'freize.png',
'http://pyvk-t.googlecode.com/caps': 'vkontakte.png',
'http://pyvk': 'vkontakte.png',
'http://pyicq': 'pyicq-t.png',
'http://spectrum.im/transport': 'pyicq-t.png',
'http://pyaim': 'pyaim-t.png',
'http://jabbroid.akuz.de': 'android.png',
'http://jabbroid.akuz.de/caps': 'android.png',
'http://witcher-team.ucoz.ru/': 'bot.png',
'http://home.gna.org/': 'omnipresence.png',
'http://ayttm.souceforge.net/caps': 'ayttm.png',
'http://www.process-one.net/en/solutions/oneteam_iphone/': \
'oneteamiphone.png',
'http://qq-im.com/caps': 'qq.png',
'http://qq.com/caps': 'qq.png',
'http://www.lonelycatgames.com/slick/caps': 'slick.png',
'http://sim-im.org/caps': 'sim.png',
'http://www.igniterealtime.org/project/spark/caps': 'spark.png',
'http://emess.eqx.su/caps': 'emess.png',
'http://fin.jabber.ru/caps': 'bot.png',
'https://www.jappix.com/': 'jappix.png',
'http://japyt.googlecode.com': 'japyt.png',
'http://www.xfire.com/': 'xfire.png',
'http://www.xfire.com/caps': 'xfire.png',
'http://lytgeygen.ru/caps': 'bot.png',
'http://aspro.users.ru/historian-bot/': 'bot.png',
'http://pigeon.vpro.ru/caps': 'pigeon.png',
'http://jtalk.ustyugov.net/caps': 'jtalk.png',
'http://jasmineicq.ru/caps': 'jasmine.png',
'http://tomclaw.com/mandarin_im/caps': 'mandarin.png',
'http://gabber.sourceforge.net': 'gabber.png',
'http://www.igniterealtime.org/projects/smack/': 'xabber.png',
'http://megafonvolga.ru/': 'megafon.png',
'rss@isida-bot.com': 'osiris.png',
class ClientsIconsPlugin(GajimPlugin):
@log_calls('ClientsIconsPlugin')
def init(self):
self.description = _('Shows the client icons in the roster'
' and in groupchats.\nDepends: Gajim > r12506')
self.pos_list = [_('after statusicon'), _('before avatar')]
self.events_handlers = {'presence-received':
(ged.POSTGUI, self.presence_received),
'gc-presence-received':
self.disconnect_from_groupchat_control),
'roster_draw_contact': (self.connect_with_roster_draw_contact,
self.disconnect_from_roster_draw_contact)}
'show_in_roster': (True, ''),
'show_in_groupchats': (True, ''),
'show_unknown_icon': (True, ''),
'pos_in_list': (0, ''),
'show_facebook': (True, '') }
self.config_dialog = ClientsIconsPluginConfigDialog(self)
icon_path = os.path.join(self.local_file_path('icons'), 'unknown.png')
self.default_pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(icon_path,
@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
if roster.model[child_iters[0]][self.renderer_num] is None:
caps = contact.client_caps._node
if 'facebook.com' in jid and self.config['show_facebook']:
elif '@vk.com' in jid and self.config['show_facebook']:
caps = 'vk.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'
self.set_icon(roster.model, child_iters[0], self.renderer_num,
caps)
@log_calls('ClientsIconsPlugin')
def connect_with_groupchat_control(self, chat_control):
chat_control.nb_ext_renderers += 1
chat_control.columns += [gtk.gdk.Pixbuf]
self.groupchats_tree_is_transformed = True
self.chat_control = chat_control
col = gtk.TreeViewColumn()
self.muc_renderer_num = 4 + chat_control.nb_ext_renderers
client_icon_rend = ('client_icon', gtk.CellRendererPixbuf(), False,
'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']]
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
chat_control.model = gtk.TreeStore(*chat_control.columns)
chat_control.model.set_sort_func(1, chat_control.tree_compare_iters)
chat_control.model.set_sort_column_id(1, gtk.SORT_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()
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)
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] + \
gc_control.model = gtk.TreeStore(*gc_control.columns)
gc_control.model.set_sort_func(1, gc_control.tree_compare_iters)
gc_control.model.set_sort_column_id(1, gtk.SORT_ASCENDING)
gc_control.list_treeview.set_model(gc_control.model)
gc_control.draw_roster()
@log_calls('ClientsIconsPlugin')
def disconnect_from_roster_draw_contact(self, roster, jid, account,
contact):
pass
@log_calls('ClientsIconsPlugin')
def activate(self):
roster = gajim.interface.roster
col = gtk.TreeViewColumn()
roster.nb_ext_renderers += 1
self.renderer_num = 10 + roster.nb_ext_renderers
self.renderer = gtk.CellRendererPixbuf()
client_icon_rend = ('client_icon', self.renderer, False,
'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']]
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 += [gtk.gdk.Pixbuf]
roster.setup_and_draw_roster()
@log_calls('ClientsIconsPlugin')
def deactivate(self):
roster = gajim.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[
def presence_received(self, iq_obj):
contact = gajim.contacts.get_contact_with_highest_priority(
iq_obj.conn.name, iq_obj.jid)
if not contact:
return
iter_ = roster._get_contact_iter(iq_obj.jid, iq_obj.conn.name, contact,
roster.model)[0]
if roster.model[iter_][self.renderer_num] is not None:
caps = contact.client_caps._node
if caps:
self.set_icon(roster.model, iter_, self.renderer_num, caps)
return
if not caps:
if iq_obj.jid == 'juick@juick.com':
caps = 'http://juick.com/caps'
elif 'psto@psto.net' in iq_obj.jid:
caps = 'psto@psto.net'
self.set_icon(roster.model, iter_, self.renderer_num, caps)
if not self.config['show_in_groupchats']:
return
contact = gajim.contacts.get_gc_contact(iq_obj.conn.name,
iq_obj.presence_obj.jid, iq_obj.nick.decode('utf-8'))
if not contact:
return
caps = None
if tag:
caps = tag[0].getAttr('node')
iter_ = iq_obj.gc_control.get_contact_iter(iq_obj.nick.decode('utf-8'))
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):
model[iter_][pos] = self.default_pixbuf
caps_ = caps.split('#')[0].split()
if caps_:
client_icon = clients.get(caps_[0].split()[0], None)
else:
client_icon = None
if not client_icon:
if self.config['show_unknown_icon']:
model[iter_][pos] = self.default_pixbuf
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:
pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(icon_path, 16, 16)
model[iter_][pos] = pixbuf
self.icon_cache[icon_path] = pixbuf
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)
contact = gajim.contacts.get_gc_contact(control.account,
control.room_jid, model[iter_][1].decode('utf-8'))
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)
class ClientsIconsPluginConfigDialog(GajimPluginConfigDialog):
def init(self):
self.GTK_BUILDER_FILE_PATH = self.plugin.local_file_path(
'config_dialog.ui')
self.xml = gtk.Builder()
self.xml.set_translation_domain('gajim_plugins')
self.xml.add_objects_from_file(self.GTK_BUILDER_FILE_PATH,
['vbox1'])
vbox = self.xml.get_object('vbox1')
self.child.pack_start(vbox)
self.combo = self.xml.get_object('combobox1')
self.liststore = gtk.ListStore(str)
self.combo.set_model(self.liststore)
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.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)
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_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)
def on_show_unknown_icon_toggled(self, widget):
self.plugin.config['show_unknown_icon'] = widget.get_active()
self.redraw_all()
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()
self.redraw_all()