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

import gtk
import os

Dicson's avatar
Dicson committed
from plugins.gui import GajimPluginConfigDialog
Dicson's avatar
Dicson committed
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',
Dicson's avatar
Dicson committed
    'http://gajim.org/caps': 'gajim.png',
Dicson's avatar
Dicson committed
    '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',
Dicson's avatar
Dicson committed
    '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',
Dicson's avatar
Dicson committed
    'http://oneteam.im/caps': 'oneteamiphone.png',
    'http://tkabber.jabber.ru/': 'tkabber.png',
    'http://pidgin.im/': 'pidgin.png',
Dicson's avatar
Dicson committed
    'http://qutim.org': 'qutim.png',
    'http://qutim.org/': 'qutim.png',
Dicson's avatar
Dicson committed
    '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',
Dicson's avatar
Dicson committed
    'http://bluendo.com/protocol/caps': 'lampiro.png',
    'nimbuzz:caps': 'nimbuzz.png',
    'http://nimbuzz.com/caps': 'nimbuzz.png',
Dicson's avatar
Dicson committed
    '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',
Dicson's avatar
Dicson committed
    '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',
Dicson's avatar
Dicson committed
    'http://jabbrik.ru/caps': 'bot.png',
    'http://jabrvista.net.ru': 'bot.png',
    'http://xu-6.jabbrik.ru/caps': 'bot.png',
Dicson's avatar
Dicson committed
    'http://jabber.pdg.pl/caps': 'bombus-klub.png',
Dicson's avatar
Dicson committed
    'http://klub54.wen.ru': 'bombus-klub.png',
Dicson's avatar
Dicson committed
    'http://aqq.eu/': 'aqq.png',
    'http://2010.qip.ru/caps': 'qip.png',
    'http://qip.ru/caps': 'qip.png',
    'http://qip.ru/caps?QIP': 'qip.png',
Dicson's avatar
Dicson committed
    'http://glu.net/': 'glu.png',
Dicson's avatar
Dicson committed
    'Siemens': 'siejc.png',  # Siemens Native Jabber Client
Dicson's avatar
Dicson committed
    'telepathy.': 'telepathy.freedesktop.org.png',
Dicson's avatar
Dicson committed
    'http://live.gnome.org/empathy/caps': 'telepathy.freedesktop.org.png',
Dicson's avatar
Dicson committed
    'http://telepathy.freedesktop.org/caps': 'telepathy.freedesktop.org.png',
    'http://www.adiumx.com/caps': 'adium.png',
    'http://www.adiumx.com': 'adium.png',
Dicson's avatar
Dicson committed
    'http://juick.com/caps': 'juick.png',
    'vk.com': 'vkontakte.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',
Dicson's avatar
Dicson committed
    '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',
    'psto@psto.net': 'psto.png',
Dicson's avatar
Dicson committed
    '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',
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'
            ' and in groupchats.\nDepends: Gajim > r12506')
        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)}
Dicson's avatar
Dicson committed
        self.config_default_values = {
Dicson's avatar
Dicson committed
                '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')
Dicson's avatar
Dicson committed
        self.default_pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(icon_path,
        self.icon_cache = {}
    @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']:
                caps = 'facebook.com'
            elif '@vk.com' in jid and self.config['show_facebook']:
                caps = 'vk.com'
            elif jid == 'juick@juick.com':
Dicson's avatar
Dicson committed
            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)
Dicson's avatar
Dicson committed
    @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']]
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
        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()
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)
        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)
        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)
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
        col = gtk.TreeViewColumn()
        roster.nb_ext_renderers += 1
        self.renderer_num = 10 + roster.nb_ext_renderers
Dicson's avatar
Dicson committed
        self.renderer = gtk.CellRendererPixbuf()
        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
        roster.columns += [gtk.gdk.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)
        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[
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
        iter_ = roster._get_contact_iter(iq_obj.jid, iq_obj.conn.name, contact,
            roster.model)[0]
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 'facebook.com' in iq_obj.jid and self.config['show_facebook']:
Dicson's avatar
Dicson committed
            caps = 'facebook.com'
        if not caps:
            if iq_obj.jid == 'juick@juick.com':
                caps = 'http://juick.com/caps'
Dicson's avatar
Dicson committed
            elif '@vk.com' in iq_obj.jid and self.config['show_facebook']:
                caps = 'vk.com'
            elif 'psto@psto.net' in iq_obj.jid:
                caps = 'psto@psto.net'
        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,
            iq_obj.presence_obj.jid, iq_obj.nick.decode('utf-8'))
        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')
        iter_ = iq_obj.gc_control.get_contact_iter(iq_obj.nick.decode('utf-8'))
        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)
        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:
                pixbuf = gtk.gdk.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,
            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)
Dicson's avatar
Dicson committed

Dicson's avatar
Dicson committed
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')
Dicson's avatar
Dicson committed
        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)
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()
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()