Exemple #1
0
class PluginsWindow(object):
    '''Class for Plugins window'''
    @log_calls('PluginsWindow')
    def __init__(self):
        '''Initialize Plugins window'''
        self.xml = gtkgui_helpers.get_gtk_builder('plugins_window.ui')
        self.window = self.xml.get_object('plugins_window')
        self.window.set_transient_for(gajim.interface.roster.window)

        widgets_to_extract = ('plugins_notebook', 'plugin_name_label',
                              'plugin_version_label', 'plugin_authors_label',
                              'plugin_homepage_linkbutton',
                              'uninstall_plugin_button',
                              'configure_plugin_button',
                              'installed_plugins_treeview')

        for widget_name in widgets_to_extract:
            setattr(self, widget_name, self.xml.get_object(widget_name))

        self.plugin_description_textview = HtmlTextView()
        sw = self.xml.get_object('scrolledwindow2')
        sw.add(self.plugin_description_textview)
        self.installed_plugins_model = Gtk.ListStore(object, str, bool, bool,
                                                     GdkPixbuf.Pixbuf)
        self.installed_plugins_treeview.set_model(self.installed_plugins_model)
        self.installed_plugins_treeview.set_rules_hint(True)

        renderer = Gtk.CellRendererText()
        col = Gtk.TreeViewColumn(_('Plugin'))  #, renderer, text=NAME)
        cell = Gtk.CellRendererPixbuf()
        col.pack_start(cell, False)
        col.add_attribute(cell, 'pixbuf', ICON)
        col.pack_start(renderer, True)
        col.add_attribute(renderer, 'text', NAME)
        col.set_property('expand', True)
        self.installed_plugins_treeview.append_column(col)

        renderer = Gtk.CellRendererToggle()
        renderer.connect('toggled', self.installed_plugins_toggled_cb)
        col = Gtk.TreeViewColumn(_('Active'),
                                 renderer,
                                 active=ACTIVE,
                                 activatable=ACTIVATABLE)
        self.installed_plugins_treeview.append_column(col)

        self.def_icon = gtkgui_helpers.get_icon_pixmap('preferences-desktop')

        # connect signal for selection change
        selection = self.installed_plugins_treeview.get_selection()
        selection.connect('changed',
                          self.installed_plugins_treeview_selection_changed)
        selection.set_mode(Gtk.SelectionMode.SINGLE)

        self._clear_installed_plugin_info()

        self.fill_installed_plugins_model()
        root_iter = self.installed_plugins_model.get_iter_first()
        if root_iter:
            selection.select_iter(root_iter)

        self.xml.connect_signals(self)

        self.plugins_notebook.set_current_page(0)
        self.xml.get_object('close_button').grab_focus()

        self.window.show_all()
        gtkgui_helpers.possibly_move_window_in_current_desktop(self.window)

    def on_plugins_notebook_switch_page(self, widget, page, page_num):
        GLib.idle_add(self.xml.get_object('close_button').grab_focus)

    @log_calls('PluginsWindow')
    def installed_plugins_treeview_selection_changed(self, treeview_selection):
        model, iter = treeview_selection.get_selected()
        if iter:
            plugin = model.get_value(iter, PLUGIN)
            plugin_name = model.get_value(iter, NAME)
            is_active = model.get_value(iter, ACTIVE)

            self._display_installed_plugin_info(plugin)
        else:
            self._clear_installed_plugin_info()

    def _display_installed_plugin_info(self, plugin):
        self.plugin_name_label.set_text(plugin.name)
        self.plugin_version_label.set_text(plugin.version)
        self.plugin_authors_label.set_text(plugin.authors)
        self.plugin_homepage_linkbutton.set_uri(plugin.homepage)
        self.plugin_homepage_linkbutton.set_label(plugin.homepage)
        label = self.plugin_homepage_linkbutton.get_children()[0]
        label.set_ellipsize(Pango.EllipsizeMode.END)
        self.plugin_homepage_linkbutton.set_property('sensitive', True)

        desc_textbuffer = self.plugin_description_textview.get_buffer()
        desc_textbuffer.set_text('')
        txt = plugin.description
        txt.replace('</body>', '')
        if plugin.available_text:
            txt += '<br/><br/>' + _('Warning: %s') % plugin.available_text
        if not txt.startswith('<body '):
            txt = '<body  xmlns=\'http://www.w3.org/1999/xhtml\'>' + txt
        txt += ' </body>'
        self.plugin_description_textview.display_html(
            txt, self.plugin_description_textview, None)

        self.plugin_description_textview.set_property('sensitive', True)
        self.uninstall_plugin_button.set_property(
            'sensitive', gajim.PLUGINS_DIRS[1] in plugin.__path__)
        self.configure_plugin_button.set_property(
            'sensitive', not plugin.config_dialog is None)

    def _clear_installed_plugin_info(self):
        self.plugin_name_label.set_text('')
        self.plugin_version_label.set_text('')
        self.plugin_authors_label.set_text('')
        self.plugin_homepage_linkbutton.set_uri('')
        self.plugin_homepage_linkbutton.set_label('')
        self.plugin_homepage_linkbutton.set_property('sensitive', False)

        desc_textbuffer = self.plugin_description_textview.get_buffer()
        desc_textbuffer.set_text('')
        self.plugin_description_textview.set_property('sensitive', False)
        self.uninstall_plugin_button.set_property('sensitive', False)
        self.configure_plugin_button.set_property('sensitive', False)

    @log_calls('PluginsWindow')
    def fill_installed_plugins_model(self):
        pm = gajim.plugin_manager
        self.installed_plugins_model.clear()
        self.installed_plugins_model.set_sort_column_id(
            1, Gtk.SortType.ASCENDING)

        for plugin in pm.plugins:
            icon = self.get_plugin_icon(plugin)
            self.installed_plugins_model.append([
                plugin, plugin.name, plugin.active and plugin.activatable,
                plugin.activatable, icon
            ])

    def get_plugin_icon(self, plugin):
        icon_file = os.path.join(plugin.__path__,
                                 os.path.split(plugin.__path__)[1]) + '.png'
        icon = self.def_icon
        if os.path.isfile(icon_file):
            icon = GdkPixbuf.Pixbuf.new_from_file_at_size(icon_file, 16, 16)
        return icon

    @log_calls('PluginsWindow')
    def installed_plugins_toggled_cb(self, cell, path):
        is_active = self.installed_plugins_model[path][ACTIVE]
        plugin = self.installed_plugins_model[path][PLUGIN]

        if is_active:
            gajim.plugin_manager.deactivate_plugin(plugin)
        else:
            try:
                gajim.plugin_manager.activate_plugin(plugin)
            except GajimPluginActivateException as e:
                WarningDialog(_('Plugin failed'),
                              str(e),
                              transient_for=self.window)
                return

        self.installed_plugins_model[path][ACTIVE] = not is_active

    @log_calls('PluginsWindow')
    def on_plugins_window_destroy(self, widget):
        '''Close window'''
        del gajim.interface.instances['plugins']

    @log_calls('PluginsWindow')
    def on_close_button_clicked(self, widget):
        self.window.destroy()

    @log_calls('PluginsWindow')
    def on_configure_plugin_button_clicked(self, widget):
        #log.debug('widget: %s'%(widget))
        selection = self.installed_plugins_treeview.get_selection()
        model, iter = selection.get_selected()
        if iter:
            plugin = model.get_value(iter, PLUGIN)
            plugin_name = model.get_value(iter, NAME)
            is_active = model.get_value(iter, ACTIVE)

            result = plugin.config_dialog.run(self.window)

        else:
            # No plugin selected. this should never be reached. As configure
            # plugin button should only be clickable when plugin is selected.
            # XXX: maybe throw exception here?
            pass

    @log_calls('PluginsWindow')
    def on_uninstall_plugin_button_clicked(self, widget):
        selection = self.installed_plugins_treeview.get_selection()
        model, iter = selection.get_selected()
        if iter:
            plugin = model.get_value(iter, PLUGIN)
            plugin_name = model.get_value(iter, NAME)
            is_active = model.get_value(iter, ACTIVE)
            try:
                gajim.plugin_manager.remove_plugin(plugin)
            except PluginsystemError as e:
                WarningDialog(_('Unable to properly remove the plugin'),
                              str(e), self.window)
                return
            model.remove(iter)

    @log_calls('PluginsWindow')
    def on_install_plugin_button_clicked(self, widget):
        def show_warn_dialog():
            text = _('Archive is malformed')
            dialog = WarningDialog(text, '', transient_for=self.window)
            dialog.set_modal(False)
            dialog.popup()

        def _on_plugin_exists(zip_filename):
            def on_yes(is_checked):
                plugin = gajim.plugin_manager.install_from_zip(
                    zip_filename, True)
                if not plugin:
                    show_warn_dialog()
                    return
                model = self.installed_plugins_model

                for row in list(range(len(model))):
                    if plugin == model[row][PLUGIN]:
                        model.remove(model.get_iter((row, PLUGIN)))
                        break

                iter_ = model.append([
                    plugin, plugin.name, False, plugin.activatable,
                    self.get_plugin_icon(plugin)
                ])
                sel = self.installed_plugins_treeview.get_selection()
                sel.select_iter(iter_)

            YesNoDialog(_('Plugin already exists'),
                        sectext=_('Overwrite?'),
                        on_response_yes=on_yes,
                        transient_for=self.window)

        def _try_install(zip_filename):
            try:
                plugin = gajim.plugin_manager.install_from_zip(zip_filename)
            except PluginsystemError as er_type:
                error_text = str(er_type)
                if error_text == _('Plugin already exists'):
                    _on_plugin_exists(zip_filename)
                    return

                WarningDialog(error_text, '"%s"' % zip_filename, self.window)
                return
            if not plugin:
                show_warn_dialog()
                return
            model = self.installed_plugins_model
            iter_ = model.append(
                [plugin, plugin.name, False, plugin.activatable],
                self.get_plugin_icon(plugin))
            sel = self.installed_plugins_treeview.get_selection()
            sel.select_iter(iter_)

        self.dialog = ArchiveChooserDialog(on_response_ok=_try_install)
Exemple #2
0
Fichier : gui.py Projet : irl/gajim
class PluginsWindow(object):
    '''Class for Plugins window'''

    @log_calls('PluginsWindow')
    def __init__(self):
        '''Initialize Plugins window'''
        self.xml = gtkgui_helpers.get_gtk_builder('plugins_window.ui')
        self.window = self.xml.get_object('plugins_window')
        self.window.set_transient_for(gajim.interface.roster.window)

        widgets_to_extract = ('plugins_notebook', 'plugin_name_label',
            'plugin_version_label', 'plugin_authors_label',
            'plugin_homepage_linkbutton', 'uninstall_plugin_button',
            'configure_plugin_button', 'installed_plugins_treeview')

        for widget_name in widgets_to_extract:
            setattr(self, widget_name, self.xml.get_object(widget_name))

        self.plugin_description_textview = HtmlTextView()
        sw = self.xml.get_object('scrolledwindow2')
        sw.add(self.plugin_description_textview)
        self.installed_plugins_model = Gtk.ListStore(object, str, bool, bool,
            GdkPixbuf.Pixbuf)
        self.installed_plugins_treeview.set_model(self.installed_plugins_model)
        self.installed_plugins_treeview.set_rules_hint(True)

        renderer = Gtk.CellRendererText()
        col = Gtk.TreeViewColumn(_('Plugin'))#, renderer, text=NAME)
        cell = Gtk.CellRendererPixbuf()
        col.pack_start(cell, False)
        col.add_attribute(cell, 'pixbuf', ICON)
        col.pack_start(renderer, True)
        col.add_attribute(renderer, 'text', NAME)
        col.set_property('expand', True)
        self.installed_plugins_treeview.append_column(col)

        renderer = Gtk.CellRendererToggle()
        renderer.connect('toggled', self.installed_plugins_toggled_cb)
        col = Gtk.TreeViewColumn(_('Active'), renderer, active=ACTIVE,
            activatable=ACTIVATABLE)
        self.installed_plugins_treeview.append_column(col)

        icon = Gtk.Image()
        self.def_icon = icon.render_icon_pixbuf(Gtk.STOCK_PREFERENCES,
            Gtk.IconSize.MENU)

        # connect signal for selection change
        selection = self.installed_plugins_treeview.get_selection()
        selection.connect('changed',
            self.installed_plugins_treeview_selection_changed)
        selection.set_mode(Gtk.SelectionMode.SINGLE)

        self._clear_installed_plugin_info()

        self.fill_installed_plugins_model()
        root_iter = self.installed_plugins_model.get_iter_first()
        if root_iter:
            selection.select_iter(root_iter )

        self.xml.connect_signals(self)

        self.plugins_notebook.set_current_page(0)
        self.xml.get_object('close_button').grab_focus()

        self.window.show_all()
        gtkgui_helpers.possibly_move_window_in_current_desktop(self.window)


    def on_plugins_notebook_switch_page(self, widget, page, page_num):
        GLib.idle_add(self.xml.get_object('close_button').grab_focus)

    @log_calls('PluginsWindow')
    def installed_plugins_treeview_selection_changed(self, treeview_selection):
        model, iter = treeview_selection.get_selected()
        if iter:
            plugin = model.get_value(iter, PLUGIN)
            plugin_name = model.get_value(iter, NAME)
            is_active = model.get_value(iter, ACTIVE)

            self._display_installed_plugin_info(plugin)
        else:
            self._clear_installed_plugin_info()

    def _display_installed_plugin_info(self, plugin):
        self.plugin_name_label.set_text(plugin.name)
        self.plugin_version_label.set_text(plugin.version)
        self.plugin_authors_label.set_text(plugin.authors)
        self.plugin_homepage_linkbutton.set_uri(plugin.homepage)
        self.plugin_homepage_linkbutton.set_label(plugin.homepage)
        label = self.plugin_homepage_linkbutton.get_children()[0]
        label.set_ellipsize(Pango.EllipsizeMode.END)
        self.plugin_homepage_linkbutton.set_property('sensitive', True)

        desc_textbuffer = self.plugin_description_textview.get_buffer()
        desc_textbuffer.set_text('')
        txt = plugin.description
        txt.replace('</body>', '')
        if plugin.available_text:
            txt += '<br/><br/>' + _('Warning: %s') % plugin.available_text
        if not txt.startswith('<body '):
            txt = '<body  xmlns=\'http://www.w3.org/1999/xhtml\'>' + txt
        txt += ' </body>'
        self.plugin_description_textview.display_html(txt,
            self.plugin_description_textview, None)

        self.plugin_description_textview.set_property('sensitive', True)
        self.uninstall_plugin_button.set_property('sensitive',
            gajim.PLUGINS_DIRS[1] in plugin.__path__)
        self.configure_plugin_button.set_property(
            'sensitive', not plugin.config_dialog is None)

    def _clear_installed_plugin_info(self):
        self.plugin_name_label.set_text('')
        self.plugin_version_label.set_text('')
        self.plugin_authors_label.set_text('')
        self.plugin_homepage_linkbutton.set_uri('')
        self.plugin_homepage_linkbutton.set_label('')
        self.plugin_homepage_linkbutton.set_property('sensitive', False)

        desc_textbuffer = self.plugin_description_textview.get_buffer()
        desc_textbuffer.set_text('')
        self.plugin_description_textview.set_property('sensitive', False)
        self.uninstall_plugin_button.set_property('sensitive', False)
        self.configure_plugin_button.set_property('sensitive', False)

    @log_calls('PluginsWindow')
    def fill_installed_plugins_model(self):
        pm = gajim.plugin_manager
        self.installed_plugins_model.clear()
        self.installed_plugins_model.set_sort_column_id(1, Gtk.SortType.ASCENDING)

        for plugin in pm.plugins:
            icon = self.get_plugin_icon(plugin)
            self.installed_plugins_model.append([plugin, plugin.name,
                plugin.active and plugin.activatable, plugin.activatable, icon])

    def get_plugin_icon(self, plugin):
        icon_file = os.path.join(plugin.__path__, os.path.split(
                plugin.__path__)[1]) + '.png'
        icon = self.def_icon
        if os.path.isfile(icon_file):
            icon = GdkPixbuf.Pixbuf.new_from_file_at_size(icon_file, 16, 16)
        return icon

    @log_calls('PluginsWindow')
    def installed_plugins_toggled_cb(self, cell, path):
        is_active = self.installed_plugins_model[path][ACTIVE]
        plugin = self.installed_plugins_model[path][PLUGIN]

        if is_active:
            gajim.plugin_manager.deactivate_plugin(plugin)
        else:
            try:
                gajim.plugin_manager.activate_plugin(plugin)
            except GajimPluginActivateException as e:
                WarningDialog(_('Plugin failed'), str(e),
                    transient_for=self.window)
                return

        self.installed_plugins_model[path][ACTIVE] = not is_active

    @log_calls('PluginsWindow')
    def on_plugins_window_destroy(self, widget):
        '''Close window'''
        del gajim.interface.instances['plugins']

    @log_calls('PluginsWindow')
    def on_close_button_clicked(self, widget):
        self.window.destroy()

    @log_calls('PluginsWindow')
    def on_configure_plugin_button_clicked(self, widget):
        #log.debug('widget: %s'%(widget))
        selection = self.installed_plugins_treeview.get_selection()
        model, iter = selection.get_selected()
        if iter:
            plugin = model.get_value(iter, PLUGIN)
            plugin_name = model.get_value(iter, NAME)
            is_active = model.get_value(iter, ACTIVE)


            result = plugin.config_dialog.run(self.window)

        else:
            # No plugin selected. this should never be reached. As configure
            # plugin button should only be clickable when plugin is selected.
            # XXX: maybe throw exception here?
            pass

    @log_calls('PluginsWindow')
    def on_uninstall_plugin_button_clicked(self, widget):
        selection = self.installed_plugins_treeview.get_selection()
        model, iter = selection.get_selected()
        if iter:
            plugin = model.get_value(iter, PLUGIN)
            plugin_name = model.get_value(iter, NAME)
            is_active = model.get_value(iter, ACTIVE)
            try:
                gajim.plugin_manager.remove_plugin(plugin)
            except PluginsystemError as e:
                WarningDialog(_('Unable to properly remove the plugin'),
                    str(e), self.window)
                return
            model.remove(iter)

    @log_calls('PluginsWindow')
    def on_install_plugin_button_clicked(self, widget):
        def show_warn_dialog():
            text = _('Archive is malformed')
            dialog = WarningDialog(text, '', transient_for=self.window)
            dialog.set_modal(False)
            dialog.popup()

        def _on_plugin_exists(zip_filename):
            def on_yes(is_checked):
                plugin = gajim.plugin_manager.install_from_zip(zip_filename,
                    True)
                if not plugin:
                    show_warn_dialog()
                    return
                model = self.installed_plugins_model

                for row in list(range(len(model))):
                    if plugin == model[row][PLUGIN]:
                        model.remove(model.get_iter((row, PLUGIN)))
                        break

                iter_ = model.append([plugin, plugin.name, False,
                    plugin.activatable, self.get_plugin_icon(plugin)])
                sel = self.installed_plugins_treeview.get_selection()
                sel.select_iter(iter_)

            YesNoDialog(_('Plugin already exists'), sectext=_('Overwrite?'),
                on_response_yes=on_yes, transient_for=self.window)

        def _try_install(zip_filename):
            try:
                plugin = gajim.plugin_manager.install_from_zip(zip_filename)
            except PluginsystemError as er_type:
                error_text = str(er_type)
                if error_text == _('Plugin already exists'):
                    _on_plugin_exists(zip_filename)
                    return

                WarningDialog(error_text, '"%s"' % zip_filename, self.window)
                return
            if not plugin:
                show_warn_dialog()
                return
            model = self.installed_plugins_model
            iter_ = model.append([plugin, plugin.name, False,
                plugin.activatable], self.get_plugin_icon(plugin))
            sel = self.installed_plugins_treeview.get_selection()
            sel.select_iter(iter_)

        self.dialog = ArchiveChooserDialog(on_response_ok=_try_install)
Exemple #3
0
class PluginInstaller(GajimPlugin):

    @log_calls('PluginInstallerPlugin')
    def init(self):
        self.config_dialog = PluginInstallerPluginConfigDialog(self)
        self.config_default_values = {'http_server': ('https://ftp.gajim.org', ''),
                                      'check_update': (True, ''),
                                      }
        self.window = None
        self.progressbar = None
        self.available_plugins_model = None
        self.upgrading = False # True when opened from upgrade popup dialog
        self.timeout_id = 0
        self.connected_ids = {}
        icon = gtk.Image()
        self.def_icon = icon.render_icon(gtk.STOCK_PREFERENCES,
            gtk.ICON_SIZE_MENU)
        if gajim.version.startswith('0.15'):
            self.server_folder = 'plugins_0.15'
        elif gajim.version.startswith('0.16.10'):
            self.server_folder = 'plugins_gtk3'
        else:
            self.server_folder = 'plugins_0.16_zip'

    @log_calls('PluginInstallerPlugin')
    def activate(self):
        self.pl_menuitem = gajim.interface.roster.xml.get_object(
            'plugins_menuitem')
        self.id_ = self.pl_menuitem.connect_after('activate', self.on_activate)
        if 'plugins' in gajim.interface.instances:
            self.on_activate(None)
        if self.config['check_update']:
            self.timeout_id = gobject.timeout_add_seconds(30, self.check_update)

    @log_calls('PluginInstallerPlugin')
    def warn_update(self, plugins):
        def open_update(dummy):
            self.upgrading = True
            self.pl_menuitem.activate()
            nb = gajim.interface.instances['plugins'].plugins_notebook
            page = nb.page_num(self.hpaned)
            gobject.idle_add(nb.set_current_page, page)
        if plugins:
            plugins_str = '\n'.join(plugins)
            YesNoDialog(_('Plugins updates'), _('Some updates are available for'
                ' your installer plugins. Do you want to update those plugins:'
                '\n%s') % plugins_str, on_response_yes=open_update)

    def parse_manifest(self, buf):
        '''
        given the buffer of the zipfile, returns the list of plugin manifests
        '''
        zip_file = zipfile.ZipFile(buf)
        manifest_list = zip_file.namelist()
        plugins = []
        for filename in manifest_list:
            config = ConfigParser.ConfigParser()
            config.readfp(zip_file.open(filename))
            if not config.has_section('info'):
                continue
            plugins.append(config)
        return plugins

    def retrieve_path(self, directory, fname):
        server = self.config['http_server']
        if not server:
            server = self.config_default_values['http_server'][0]
        if not urlparse.urlparse(server).scheme:
            server = 'https://' + server
        if urlparse.urlparse(server).scheme != 'https':
            log.warn('Warning: not using HTTPS is a '
                     'very serious security issue!')
        location = posixpath.join(directory, fname)
        uri = urlparse.urljoin(server, location)
        log.debug('Fetching {}'.format(uri))
        request = urllib2.urlopen(uri)
        manifest_buffer = io.BytesIO(request.read())

        return manifest_buffer

    def retrieve_manifest(self):
        return self.retrieve_path(self.server_folder, 'manifests.zip')

    @log_calls('PluginInstallerPlugin')
    def check_update(self):
        def _run():
            try:
                to_update = []
                zipbuf = self.retrieve_manifest()
                plugin_manifests = self.parse_manifest(zipbuf)
                for config in plugin_manifests:
                    opts = config.options('info')
                    if 'name' not in opts or 'version' not in opts or \
                       'description' not in opts or 'authors' not in opts or \
                       'homepage' not in opts:
                        continue
                    local_version = ftp.get_plugin_version(config.get(
                        'info', 'name'))
                    if local_version:
                        local = convert_version_to_list(local_version)
                        remote = convert_version_to_list(config.get('info',
                                                                    'version'))
                        if remote > local:
                            to_update.append(config.get('info', 'name'))
                gobject.idle_add(self.warn_update, to_update)
            except Exception as e:
                log.exception('Ftp error when check for updates: ')
        ftp = Ftp(self)
        ftp.run = _run
        ftp.start()
        self.timeout_id = 0

    @log_calls('PluginInstallerPlugin')
    def deactivate(self):
        self.pl_menuitem.disconnect(self.id_)
        if hasattr(self, 'page_num'):
            self.notebook.remove_page(self.notebook.page_num(self.hpaned))
            self.notebook.set_current_page(0)
            for id_, widget in self.connected_ids.items():
                widget.disconnect(id_)
            del self.page_num
        if hasattr(self, 'ftp'):
            del self.ftp
        if self.timeout_id > 0:
            gobject.source_remove(self.timeout_id)
            self.timeout_id = 0

    def on_activate(self, widget):
        if 'plugins' not in gajim.interface.instances:
            return
        if hasattr(self, 'page_num'):
            # 'Available' tab exists
            return
        self.installed_plugins_model = gajim.interface.instances[
            'plugins'].installed_plugins_model
        self.notebook = gajim.interface.instances['plugins'].plugins_notebook
        id_ = self.notebook.connect('switch-page', self.on_notebook_switch_page)
        self.connected_ids[id_] = self.notebook
        self.window = gajim.interface.instances['plugins'].window
        id_ = self.window.connect('destroy', self.on_win_destroy)
        self.connected_ids[id_] = self.window
        self.GTK_BUILDER_FILE_PATH = self.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, ['hpaned2',
            'image1'])
        self.hpaned = self.xml.get_object('hpaned2')
        self.page_num = self.notebook.append_page(self.hpaned,
            gtk.Label(_('Available')))

        widgets_to_extract = ('plugin_name_label1',
        'available_treeview', 'progressbar', 'inslall_upgrade_button',
        'plugin_authors_label1', 'plugin_authors_label1',
        'plugin_homepage_linkbutton1')

        for widget_name in widgets_to_extract:
            setattr(self, widget_name, self.xml.get_object(widget_name))

        attr_list = pango.AttrList()
        attr_list.insert(pango.AttrWeight(pango.WEIGHT_BOLD, 0, -1))
        self.plugin_name_label1.set_attributes(attr_list)

        self.available_plugins_model = gtk.ListStore(gtk.gdk.Pixbuf,
            gobject.TYPE_PYOBJECT, gobject.TYPE_STRING, gobject.TYPE_STRING,
            gobject.TYPE_STRING, gobject.TYPE_BOOLEAN, gobject.TYPE_PYOBJECT,
            gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)
        self.available_treeview.set_model(self.available_plugins_model)
        self.available_treeview.set_rules_hint(True)
        self.available_plugins_model.set_sort_column_id(2, gtk.SORT_ASCENDING)

        self.progressbar.set_property('no-show-all', True)
        renderer = gtk.CellRendererText()
        col = gtk.TreeViewColumn(_('Plugin'))
        cell = gtk.CellRendererPixbuf()
        col.pack_start(cell, False)
        col.add_attribute(cell, 'pixbuf', C_PIXBUF)
        col.pack_start(renderer, True)
        col.add_attribute(renderer, 'text', C_NAME)
        col.set_resizable(True)
        col.set_property('expand', True)
        col.set_sizing(gtk.TREE_VIEW_COLUMN_GROW_ONLY)
        self.available_treeview.append_column(col)
        col = gtk.TreeViewColumn(_('Installed\nversion'), renderer,
            text=C_LOCAL_VERSION)
        self.available_treeview.append_column(col)
        col = gtk.TreeViewColumn(_('Available\nversion'), renderer,
            text=C_VERSION)
        col.set_property('expand', False)
        self.available_treeview.append_column(col)

        renderer = gtk.CellRendererToggle()
        renderer.set_property('activatable', True)
        renderer.connect('toggled', self.available_plugins_toggled_cb)
        col = gtk.TreeViewColumn(_('Install /\nUpgrade'), renderer,
            active=C_UPGRADE)
        self.available_treeview.append_column(col)

        if gobject.signal_lookup('error_signal', self.window) is 0:
            gobject.signal_new('error_signal', self.window,
                gobject.SIGNAL_RUN_LAST, gobject.TYPE_STRING,
                (gobject.TYPE_STRING,))
            gobject.signal_new('plugin_downloaded', self.window,
                gobject.SIGNAL_RUN_LAST, gobject.TYPE_STRING,
                (gobject.TYPE_PYOBJECT,))
        id_ = self.window.connect('error_signal', self.on_some_ftp_error)
        self.connected_ids[id_] = self.window
        id_ = self.window.connect('plugin_downloaded',
            self.on_plugin_downloaded)
        self.connected_ids[id_] = self.window

        selection = self.available_treeview.get_selection()
        selection.connect('changed',
            self.available_plugins_treeview_selection_changed)
        selection.set_mode(gtk.SELECTION_SINGLE)

        self._clear_available_plugin_info()

        self.plugin_description_textview = HtmlTextView()
        sw = self.xml.get_object('scrolledwindow1')
        sw.add(self.plugin_description_textview)

        self.xml.connect_signals(self)
        self.window.show_all()

    def on_win_destroy(self, widget):
        if hasattr(self, 'ftp'):
            del self.ftp
        if hasattr(self, 'page_num'):
            del self.page_num

    def available_plugins_toggled_cb(self, cell, path):
        is_active = self.available_plugins_model[path][C_UPGRADE]
        self.available_plugins_model[path][C_UPGRADE] = not is_active
        dir_list = []
        for i in xrange(len(self.available_plugins_model)):
            if self.available_plugins_model[i][C_UPGRADE]:
                dir_list.append(self.available_plugins_model[i][C_DIR])
        if not dir_list:
            self.inslall_upgrade_button.set_property('sensitive', False)
        else:
            self.inslall_upgrade_button.set_property('sensitive', True)

    def on_notebook_switch_page(self, widget, page, page_num):
        tab_label_text = self.notebook.get_tab_label_text(self.hpaned)
        if tab_label_text != (_('Available')):
            return
        if not hasattr(self, 'ftp'):
            self.available_plugins_model.clear()
            self.progressbar.show()
            self.ftp = Ftp(self)
            self.ftp.remote_dirs = None
            self.ftp.upgrading = True
            self.ftp.start()

    def on_inslall_upgrade_clicked(self, widget):
        self.inslall_upgrade_button.set_property('sensitive', False)
        dir_list = []
        for i in xrange(len(self.available_plugins_model)):
            if self.available_plugins_model[i][C_UPGRADE]:
                dir_list.append(self.available_plugins_model[i][C_DIR])

        ftp = Ftp(self)
        ftp.remote_dirs = dir_list
        ftp.start()

    def on_some_ftp_error(self, widget, error_text):
        for i in xrange(len(self.available_plugins_model)):
            self.available_plugins_model[i][C_UPGRADE] = False
        self.progressbar.hide()
        log.error(error_text)
        traceback.print_exc()
        WarningDialog(_('Ftp error'), error_text, self.window)

    def on_plugin_downloaded(self, widget, plugin_dirs):
        dialog = HigDialog(None, gtk.MESSAGE_INFO, gtk.BUTTONS_OK,
            '', _('All selected plugins downloaded'))
        dialog.set_modal(False)
        dialog.set_transient_for(self.window)

        for _dir in plugin_dirs:
            is_active = False
            plugins = None
            plugin_dir = os.path.join(gajim.PLUGINS_DIRS[1], _dir)
            plugin = gajim.plugin_manager.get_plugin_by_path(plugin_dir)
            if plugin:
                if plugin.active:
                    is_active = True
                    gobject.idle_add(gajim.plugin_manager.deactivate_plugin,
                        plugin)
                gajim.plugin_manager.plugins.remove(plugin)

                model = self.installed_plugins_model
                for row in xrange(len(model)):
                    if plugin == model[row][0]:
                        model.remove(model.get_iter((row, 0)))
                        break

            plugins = self.scan_dir_for_plugin(plugin_dir)
            if not plugins:
                continue
            gajim.plugin_manager.add_plugin(plugins[0])
            plugin = gajim.plugin_manager.plugins[-1]
            for row in xrange(len(self.available_plugins_model)):
                if plugin.name == self.available_plugins_model[row][C_NAME]:
                    self.available_plugins_model[row][C_LOCAL_VERSION] = \
                        plugin.version
                    self.available_plugins_model[row][C_UPGRADE] = False
            if is_active:
                gobject.idle_add(gajim.plugin_manager.activate_plugin, plugin)
            # get plugin icon
            icon_file = os.path.join(plugin.__path__, os.path.split(
                plugin.__path__)[1]) + '.png'
            icon = self.def_icon
            if os.path.isfile(icon_file):
                icon = gtk.gdk.pixbuf_new_from_file_at_size(icon_file, 16, 16)
            if not hasattr(plugin, 'activatable'):
                # version 0.15
                plugin.activatable = False
            max_row = [plugin, plugin.name, is_active, plugin.activatable, icon]
            # support old plugin system
            if len(self.installed_plugins_model):
                row_len = len(self.installed_plugins_model[0])
            else:
                row_len = 5
            row = max_row[0: row_len]
            self.installed_plugins_model.append(row)

        dialog.popup()

    def available_plugins_treeview_selection_changed(self, treeview_selection):
        model, iter = treeview_selection.get_selected()
        self.xml.get_object('scrolledwindow1').get_children()[0].destroy()
        self.plugin_description_textview = HtmlTextView()
        sw = self.xml.get_object('scrolledwindow1')
        sw.add(self.plugin_description_textview)
        sw.show_all()
        if iter:
            self.plugin_name_label1.set_text(model.get_value(iter, C_NAME))
            self.plugin_authors_label1.set_text(model.get_value(iter, C_AUTHORS))
            self.plugin_homepage_linkbutton1.set_uri(model.get_value(iter,
                C_HOMEPAGE))
            self.plugin_homepage_linkbutton1.set_label(model.get_value(iter,
                C_HOMEPAGE))
            label = self.plugin_homepage_linkbutton1.get_children()[0]
            label.set_ellipsize(pango.ELLIPSIZE_END)
            self.plugin_homepage_linkbutton1.set_property('sensitive', True)
            desc = _(model.get_value(iter, C_DESCRIPTION))
            if not desc.startswith('<body '):
                desc = "<body  xmlns='http://www.w3.org/1999/xhtml'>" + \
                    desc + ' </body>'
                desc = desc.replace('\n', '<br/>')
            self.plugin_description_textview.display_html(desc,
                self.plugin_description_textview, None)
            self.plugin_description_textview.set_property('sensitive', True)
        else:
            self._clear_available_plugin_info()

    def _clear_available_plugin_info(self):
        self.plugin_name_label1.set_text('')
        self.plugin_authors_label1.set_text('')
        self.plugin_homepage_linkbutton1.set_uri('')
        self.plugin_homepage_linkbutton1.set_label('')
        self.plugin_homepage_linkbutton1.set_property('sensitive', False)

    def scan_dir_for_plugin(self, path):
        plugins_found = []
        conf = ConfigParser.ConfigParser()
        fields = ('name', 'short_name', 'version', 'description', 'authors',
            'homepage')
        if not os.path.isdir(path):
            return plugins_found

        dir_list = os.listdir(path)
        dir_, mod = os.path.split(path)
        sys.path.insert(0, dir_)

        manifest_path = os.path.join(path, 'manifest.ini')
        if not os.path.isfile(manifest_path):
            return plugins_found

        for elem_name in dir_list:
            file_path = os.path.join(path, elem_name)
            module = None

            if os.path.isfile(file_path) and fnmatch.fnmatch(file_path, '*.py'):
                module_name = os.path.splitext(elem_name)[0]
                if module_name == '__init__':
                    continue
                try:
                    full_module_name = '%s.%s' % (mod, module_name)
                    if full_module_name in sys.modules:
                        module = reload(sys.modules[full_module_name])
                    else:
                        module = __import__(full_module_name)
                except ValueError, value_error:
                    pass
                except ImportError, import_error:
                    pass
                except AttributeError, attribute_error:
                    pass