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)
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)
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