class PluginsDialog: """ Dialog for Plugins configuration """ def __init__(self, config_obj): self.config_obj = config_obj self.config = self.config_obj.get_subconfig("plugins") builder = Gtk.Builder() builder.add_from_file(ViewConfig.PLUGINS_UI_FILE) self.dialog = builder.get_object("PluginsDialog") self.dialog.set_title(_("Plugins - %s" % info.NAME)) self.plugin_tree = builder.get_object("PluginTree") self.plugin_configure = builder.get_object("plugin_configure") self.plugin_about = builder.get_object("PluginAboutDialog") self.plugin_depends = builder.get_object('PluginDepends') help.add_help_shortcut(self.dialog, "plugins") self.pengine = PluginEngine() # plugin config initiation if self.pengine.get_plugins(): self.config.set( "disabled", [p.module_name for p in self.pengine.get_plugins("disabled")], ) self.config.set( "enabled", [p.module_name for p in self.pengine.get_plugins("enabled")], ) # see constants PLUGINS_COL_* for column meanings self.plugin_store = Gtk.ListStore(str, bool, str, str, bool) builder.connect_signals({ 'on_plugins_help': self.on_help, 'on_plugins_close': self.on_close, 'on_PluginsDialog_delete_event': self.on_close, 'on_PluginTree_cursor_changed': self.on_plugin_select, 'on_plugin_about': self.on_plugin_about, 'on_plugin_configure': self.on_plugin_configure, 'on_PluginAboutDialog_close': self.on_plugin_about_close, }) def _init_plugin_tree(self): """ Initialize the PluginTree Gtk.TreeView. The format is modelled after the one used in gedit; see http://git.gnome.org/browse/gedit/tree/gedit/gedit-plugin-mapnager.c """ # force creation of the Gtk.ListStore so we can reference it self._refresh_plugin_store() # renderer for the toggle column renderer = Gtk.CellRendererToggle() renderer.set_property('xpad', 6) renderer.connect('toggled', self.on_plugin_toggle) # toggle column column = Gtk.TreeViewColumn(None, renderer, active=PLUGINS_COL_ENABLED, activatable=PLUGINS_COL_ACTIVATABLE, sensitive=PLUGINS_COL_ACTIVATABLE) self.plugin_tree.append_column(column) # plugin name column column = Gtk.TreeViewColumn() column.set_spacing(6) # icon renderer for the plugin name column icon_renderer = Gtk.CellRendererPixbuf() icon_renderer.set_property('stock-size', Gtk.IconSize.SMALL_TOOLBAR) icon_renderer.set_property('xpad', 3) column.pack_start(icon_renderer, False) column.set_cell_data_func(icon_renderer, plugin_icon) # text renderer for the plugin name column name_renderer = Gtk.CellRendererText() name_renderer.set_property('ellipsize', Pango.EllipsizeMode.END) column.pack_start(name_renderer, True) column.set_cell_data_func(name_renderer, plugin_markup, self) self.plugin_tree.append_column(column) # finish setup self.plugin_tree.set_model(self.plugin_store) self.plugin_tree.set_search_column(2) def _refresh_plugin_store(self): """ Refresh status of plugins and put it in a Gtk.ListStore """ self.plugin_store.clear() self.pengine.recheck_plugin_errors(True) for name, plugin in self.pengine.plugins.items(): # activateable if there is no error self.plugin_store.append((name, plugin.enabled, plugin.full_name, plugin.short_description, not plugin.error)) def activate(self): """ Refresh status of plugins and show the dialog """ if len(self.plugin_tree.get_columns()) == 0: self._init_plugin_tree() else: self._refresh_plugin_store() self.dialog.show_all() def on_close(self, widget, data=None): """ Close the plugins dialog.""" self.dialog.hide() return True @classmethod def on_help(cls, widget): """ Open help for plugins """ help.show_help("plugins") return True def on_plugin_toggle(self, widget, path): """Toggle a plugin enabled/disabled.""" iterator = self.plugin_store.get_iter(path) plugin_id = self.plugin_store.get_value(iterator, PLUGINS_COL_ID) plugin = self.pengine.get_plugin(plugin_id) plugin.enabled = not self.plugin_store.get_value(iterator, PLUGINS_COL_ENABLED) plugins_enabled = self.config.get("enabled") plugins_disabled = self.config.get("disabled") if plugin.enabled: self.pengine.activate_plugins([plugin]) plugins_enabled.append(plugin.module_name) if plugin.module_name in plugins_disabled: plugins_disabled.remove(plugin.module_name) else: self.pengine.deactivate_plugins([plugin]) plugins_disabled.append(plugin.module_name) if plugin.module_name in plugins_enabled: plugins_enabled.remove(plugin.module_name) self.config.set("enabled", plugins_enabled) self.config.set("disabled", plugins_disabled) self.plugin_store.set_value(iterator, PLUGINS_COL_ENABLED, plugin.enabled) self._update_plugin_configure(plugin) self.config_obj.save() def on_plugin_select(self, plugin_tree): """ Callback when user select/unselect a plugin Update the button "Configure plugin" sensitivity """ model, iterator = plugin_tree.get_selection().get_selected() if iterator is not None: plugin_id = model.get_value(iterator, PLUGINS_COL_ID) plugin = self.pengine.get_plugin(plugin_id) self._update_plugin_configure(plugin) def _update_plugin_configure(self, plugin): """ Enable the button "Configure Plugin" appropriate. """ configurable = plugin.active and plugin.is_configurable() self.plugin_configure.set_property('sensitive', configurable) def on_plugin_configure(self, widget): """ Show the dialog for plugin configuration """ _, iterator = self.plugin_tree.get_selection().get_selected() if iterator is None: return plugin_id = self.plugin_store.get_value(iterator, PLUGINS_COL_ID) plugin = self.pengine.get_plugin(plugin_id) plugin.instance.configure_dialog(self.dialog) def on_plugin_about(self, widget): """ Display information about a plugin. """ _, iterator = self.plugin_tree.get_selection().get_selected() if iterator is None: return plugin_id = self.plugin_store.get_value(iterator, PLUGINS_COL_ID) plugin = self.pengine.get_plugin(plugin_id) #FIXME About plugin dialog looks much more different than #it is in the current trunk #FIXME repair it! #FIXME Author is not usually set and is preserved from #previous plugin... :/ self.plugin_about.set_program_name(plugin.full_name) self.plugin_about.set_version(plugin.version) authors = plugin.authors if isinstance(authors, str): authors = "\n".join(author.strip() for author in authors.split(',')) authors = [authors, ] self.plugin_about.set_authors(authors) description = plugin.description.replace(r'\n', "\n") self.plugin_about.set_comments(description) self.plugin_depends.set_label(plugin_error_text(plugin)) self.plugin_about.show_all() def on_plugin_about_close(self, widget, data=None): """ Close the PluginAboutDialog. """ self.plugin_about.hide() return True
class PluginsDialog(object): """ Dialog for Plugins configuration """ def __init__(self, requester): self.req = requester self.config = self.req.get_config("plugins") builder = Gtk.Builder() builder.add_from_file(ViewConfig.PLUGINS_UI_FILE) self.dialog = builder.get_object("PluginsDialog") self.dialog.set_title(_("Plugins - %s" % info.NAME)) self.plugin_tree = builder.get_object("PluginTree") self.plugin_configure = builder.get_object("plugin_configure") self.plugin_about = builder.get_object("PluginAboutDialog") self.plugin_depends = builder.get_object('PluginDepends') help.add_help_shortcut(self.dialog, "plugins") self.pengine = PluginEngine() # plugin config initiation if self.pengine.get_plugins(): self.config.set( "disabled", [p.module_name for p in self.pengine.get_plugins("disabled")], ) self.config.set( "enabled", [p.module_name for p in self.pengine.get_plugins("enabled")], ) # see constants PLUGINS_COL_* for column meanings self.plugin_store = Gtk.ListStore(str, bool, str, str, bool) builder.connect_signals({ 'on_plugins_help': self.on_help, 'on_plugins_close': self.on_close, 'on_PluginsDialog_delete_event': self.on_close, 'on_PluginTree_cursor_changed': self.on_plugin_select, 'on_plugin_about': self.on_plugin_about, 'on_plugin_configure': self.on_plugin_configure, 'on_PluginAboutDialog_close': self.on_plugin_about_close, }) def _init_plugin_tree(self): """ Initialize the PluginTree Gtk.TreeView. The format is modelled after the one used in gedit; see http://git.gnome.org/browse/gedit/tree/gedit/gedit-plugin-mapnager.c """ # force creation of the Gtk.ListStore so we can reference it self._refresh_plugin_store() # renderer for the toggle column renderer = Gtk.CellRendererToggle() renderer.set_property('xpad', 6) renderer.connect('toggled', self.on_plugin_toggle) # toggle column column = Gtk.TreeViewColumn(None, renderer, active=PLUGINS_COL_ENABLED, activatable=PLUGINS_COL_ACTIVATABLE, sensitive=PLUGINS_COL_ACTIVATABLE) self.plugin_tree.append_column(column) # plugin name column column = Gtk.TreeViewColumn() column.set_spacing(6) # icon renderer for the plugin name column icon_renderer = Gtk.CellRendererPixbuf() icon_renderer.set_property('stock-size', Gtk.IconSize.SMALL_TOOLBAR) icon_renderer.set_property('xpad', 3) column.pack_start(icon_renderer, False) column.set_cell_data_func(icon_renderer, plugin_icon) # text renderer for the plugin name column name_renderer = Gtk.CellRendererText() name_renderer.set_property('ellipsize', Pango.EllipsizeMode.END) column.pack_start(name_renderer, True) column.set_cell_data_func(name_renderer, plugin_markup, self) self.plugin_tree.append_column(column) # finish setup self.plugin_tree.set_model(self.plugin_store) self.plugin_tree.set_search_column(2) def _refresh_plugin_store(self): """ Refresh status of plugins and put it in a Gtk.ListStore """ self.plugin_store.clear() self.pengine.recheck_plugin_errors(True) for name, plugin in self.pengine.plugins.items(): # activateable if there is no error self.plugin_store.append( (name, plugin.enabled, plugin.full_name, plugin.short_description, not plugin.error)) def activate(self): """ Refresh status of plugins and show the dialog """ if len(self.plugin_tree.get_columns()) == 0: self._init_plugin_tree() else: self._refresh_plugin_store() self.dialog.show_all() def on_close(self, widget, data=None): """ Close the plugins dialog.""" self.dialog.hide() return True @classmethod def on_help(cls, widget): """ Open help for plugins """ help.show_help("plugins") return True def on_plugin_toggle(self, widget, path): """Toggle a plugin enabled/disabled.""" iterator = self.plugin_store.get_iter(path) plugin_id = self.plugin_store.get_value(iterator, PLUGINS_COL_ID) plugin = self.pengine.get_plugin(plugin_id) plugin.enabled = not self.plugin_store.get_value( iterator, PLUGINS_COL_ENABLED) plugins_enabled = self.config.get("enabled") plugins_disabled = self.config.get("disabled") if plugin.enabled: self.pengine.activate_plugins([plugin]) plugins_enabled.append(plugin.module_name) if plugin.module_name in plugins_disabled: plugins_disabled.remove(plugin.module_name) else: self.pengine.deactivate_plugins([plugin]) plugins_disabled.append(plugin.module_name) if plugin.module_name in plugins_enabled: plugins_enabled.remove(plugin.module_name) self.config.set("enabled", plugins_enabled) self.config.set("disabled", plugins_disabled) self.plugin_store.set_value(iterator, PLUGINS_COL_ENABLED, plugin.enabled) self._update_plugin_configure(plugin) def on_plugin_select(self, plugin_tree): """ Callback when user select/unselect a plugin Update the button "Configure plugin" sensitivity """ model, iterator = plugin_tree.get_selection().get_selected() if iterator is not None: plugin_id = model.get_value(iterator, PLUGINS_COL_ID) plugin = self.pengine.get_plugin(plugin_id) self._update_plugin_configure(plugin) def _update_plugin_configure(self, plugin): """ Enable the button "Configure Plugin" appropriate. """ configurable = plugin.active and plugin.is_configurable() self.plugin_configure.set_property('sensitive', configurable) def on_plugin_configure(self, widget): """ Show the dialog for plugin configuration """ _, iterator = self.plugin_tree.get_selection().get_selected() if iterator is None: return plugin_id = self.plugin_store.get_value(iterator, PLUGINS_COL_ID) plugin = self.pengine.get_plugin(plugin_id) plugin.instance.configure_dialog(self.dialog) def on_plugin_about(self, widget): """ Display information about a plugin. """ _, iterator = self.plugin_tree.get_selection().get_selected() if iterator is None: return plugin_id = self.plugin_store.get_value(iterator, PLUGINS_COL_ID) plugin = self.pengine.get_plugin(plugin_id) # FIXME About plugin dialog looks much more different than # it is in the current trunk # FIXME repair it! # FIXME Author is not usually set and is preserved from # previous plugin... :/ self.plugin_about.set_program_name(plugin.full_name) self.plugin_about.set_version(plugin.version) authors = plugin.authors if isinstance(authors, str): authors = "\n".join(author.strip() for author in authors.split(',')) authors = [ authors, ] self.plugin_about.set_authors(authors) description = plugin.description.replace(r'\n', "\n") self.plugin_about.set_comments(description) self.plugin_depends.set_label(plugin_error_text(plugin)) self.plugin_about.show_all() def on_plugin_about_close(self, widget, data=None): """ Close the PluginAboutDialog. """ self.plugin_about.hide() return True
class PreferencesDialog: __AUTOSTART_DIRECTORY = os.path.join(xdg_config_home, "autostart") __AUTOSTART_FILE = "gtg.desktop" def __init__(self, config_obj): """Constructor.""" self.config_obj = config_obj self.config = self.config_obj.conf_dict self.builder = gtk.Builder() self.builder.add_from_file(ViewConfig.PREFERENCES_GLADE_FILE) # store references to some objects widgets = { 'dialog': 'PreferencesDialog', 'backend_tree': 'BackendTree', 'plugin_tree': 'PluginTree', 'plugin_about_dialog': 'PluginAboutDialog', 'plugin_configure': 'plugin_configure', 'plugin_depends': 'PluginDepends', 'plugin_config_dialog': 'PluginConfigDialog', 'pref_autostart': 'pref_autostart', 'pref_show_preview': 'pref_show_preview' } for attr, widget in widgets.iteritems(): setattr(self, attr, self.builder.get_object(widget)) # keep a reference to the parent task browser #FIXME: this is not needed and should be removed # self.tb = taskbrowser self.pengine = PluginEngine() # initialize tree models self._init_backend_tree() # this can't happen yet, due to the order of things in # TaskBrowser.__init__(). Happens in activate() instead. # self._init_plugin_tree() pref_signals_dic = self.get_signals_dict() self.builder.connect_signals(pref_signals_dic) def _init_backend_tree(self): """Initialize the BackendTree gtk.TreeView.""" self._refresh_backend_store() # TODO def _refresh_backend_store(self): """Populate a gtk.ListStore with backend information.""" # create and clear a gtk.ListStore for backend information if not hasattr(self, 'backend_store'): # TODO: create the liststore. It should have one column for each # backend. self.backend_store = gtk.ListStore(str) self.backend_store.clear() # TODO def _refresh_plugin_store(self): """Populate a gtk.ListStore with plugin information.""" # create and clear a gtk.ListStore if not hasattr(self, 'plugin_store'): # see constants PLUGINS_COL_* for column meanings self.plugin_store = gtk.ListStore(str, 'gboolean', str, str, str, 'gboolean',) self.plugin_store.clear() # refresh the status of all plugins self.pengine.recheck_plugin_errors(True) # repopulate the store for name, p in self.pengine.plugins.iteritems(): self.plugin_store.append([name, p.enabled, p.full_name, p.short_description, p.description, not p.error,]) # activateable if there is no error def _refresh_preferences_store(self): """Sets the correct value in the preferences checkboxes""" autostart_path = os.path.join(self.__AUTOSTART_DIRECTORY, \ self.__AUTOSTART_FILE) self.pref_autostart.set_active(os.path.isfile(autostart_path)) #This set_active method doesn't even understand what a boolean is! #what a PITA ! if self.config_priv.get("contents_preview_enable"): toset = 1 else: toset = 0 self.pref_show_preview.set_active(toset) def _init_plugin_tree(self): """Initialize the PluginTree gtk.TreeView. The format is modelled after the one used in gedit; see http://git.gnome.org/browse/gedit/tree/gedit/gedit-plugin-mapnager.c """ # force creation of the gtk.ListStore so we can reference it self._refresh_plugin_store() # renderer for the toggle column renderer = gtk.CellRendererToggle() renderer.set_property('xpad', 6) renderer.connect('toggled', self.on_plugin_toggle) # toggle column column = gtk.TreeViewColumn(None, renderer, active=PLUGINS_COL_ENABLED, activatable=PLUGINS_COL_ACTIVATABLE, sensitive=PLUGINS_COL_ACTIVATABLE) self.plugin_tree.append_column(column) # plugin name column column = gtk.TreeViewColumn() column.set_spacing(6) # icon renderer for the plugin name column icon_renderer = gtk.CellRendererPixbuf() icon_renderer.set_property('stock-size', gtk.ICON_SIZE_SMALL_TOOLBAR) icon_renderer.set_property('xpad', 3) column.pack_start(icon_renderer, expand=False) column.set_cell_data_func(icon_renderer, plugin_icon) # text renderer for the plugin name column name_renderer = gtk.CellRendererText() name_renderer.set_property('ellipsize', pango.ELLIPSIZE_END) column.pack_start(name_renderer) column.set_cell_data_func(name_renderer, plugin_markup) self.plugin_tree.append_column(column) # finish setup self.plugin_tree.set_model(self.plugin_store) self.plugin_tree.set_search_column(2) ## GTK signals & related functions def get_signals_dict(self): """A dictionary of signals and functions to be connected.""" SIGNAL_CONNECTIONS_DIC = { # 'on_preferences_activate': # self.activate, # buttons in the dialog itself 'on_prefs_close': self.on_close, 'on_prefs_help': self.on_help, # preferences on the Tasks tab 'on_pref_show_preview_toggled': self.toggle_preview, 'on_pref_check_spelling_toggled': self.toggle_spellcheck, # buttons on the Plugins tab 'on_PluginTree_cursor_changed': self.on_plugin_select, 'on_plugin_about': self.on_plugin_about, 'on_plugin_configure': self.on_plugin_configure, # the PluginAboutDialog 'on_PluginAboutDialog_close': self.on_plugin_about_close, 'on_PluginAboutDialog_response': self.on_plugin_about_close, # the PluginConfigDialog 'on_PluginConfigClose_released': self.on_plugin_config_close, 'on_PreferencesDialog_delete_event': self.on_close, 'on_pref_autostart_toggled': self.on_autostart_toggled, } return SIGNAL_CONNECTIONS_DIC def activate(self, config_priv, widget=None): """Activate the preferences dialog.""" self.config_priv = config_priv if len(self.plugin_tree.get_columns()) == 0: # late setup of PluginTree self._init_plugin_tree() else: self._refresh_plugin_store() self._refresh_backend_store() self._refresh_preferences_store() self.dialog.present() self.dialog.show_all() def on_close(self, widget, data = None): """Close the preferences dialog.""" if self.pengine.get_plugins(): self.config["plugins"] = {} self.config["plugins"]["disabled"] = \ [p.module_name for p in self.pengine.get_plugins("disabled")] self.config["plugins"]["enabled"] = \ [p.module_name for p in self.pengine.get_plugins("enabled")] self.config_obj.save() self.dialog.hide() return True def on_help(self, widget): """Provide help for the preferences dialog.""" return True def on_plugin_about(self, widget): """Display information about a plugin.""" (junk, iter) = self.plugin_tree.get_selection().get_selected() if iter == None: return plugin_id = self.plugin_store.get_value(iter, PLUGINS_COL_ID) p = self.pengine.get_plugin(plugin_id) pad = self.plugin_about_dialog pad.set_name(p.full_name) pad.set_version(p.version) authors = p.authors if isinstance(authors, str): authors = [authors, ] pad.set_authors(authors) pad.set_comments(p.description.replace(r'\n', "\n")) self.plugin_depends.set_label(plugin_error_text(p)) pad.show_all() def on_plugin_about_close(self, widget, *args): """Close the PluginAboutDialog.""" self.plugin_about_dialog.hide() def on_plugin_configure(self, widget): """Configure a plugin.""" (junk, iter) = self.plugin_tree.get_selection().get_selected() plugin_id = self.plugin_store.get_value(iter, PLUGINS_COL_ID) # TODO: load plugin's configuration UI and insert into pc-vbox1 in # position 0. Something like... #pcd = self.plugin_config_dialog #pcd.show_all() # ...for now, use existing code. self.pengine.get_plugin(plugin_id).instance.configure_dialog(self.dialog) def on_plugin_config_close(self, widget): """Close the PluginConfigDialog.""" self.plugin_config_dialog.hide() def on_plugin_select(self, plugin_tree): (model, iter) = plugin_tree.get_selection().get_selected() if iter is not None: plugin_id = model.get_value(iter, PLUGINS_COL_ID) self._update_plugin_configure(self.pengine.get_plugin(plugin_id)) def on_plugin_toggle(self, widget, path): """Toggle a plugin enabled/disabled.""" iter = self.plugin_store.get_iter(path) plugin_id = self.plugin_store.get_value(iter, PLUGINS_COL_ID) p = self.pengine.get_plugin(plugin_id) p.enabled = not self.plugin_store.get_value(iter, PLUGINS_COL_ENABLED) if p.enabled: self.pengine.activate_plugins([p]) else: self.pengine.deactivate_plugins([p]) self.plugin_store.set_value(iter, PLUGINS_COL_ENABLED, p.enabled) self._update_plugin_configure(p) def toggle_preview(self, widget): """Toggle previews in the task view on or off.""" self.config_priv.set("contents_preview_enable",widget.get_active()) def toggle_spellcheck(self, widget): """Toggle spell checking on or off.""" print __name__ def _update_plugin_configure(self, plugin): """Enable the "Configure Plugin" button if appropriate.""" configurable = plugin.active and plugin.is_configurable() self.plugin_configure.set_property('sensitive', configurable) def on_autostart_toggled(self, widget): """Toggle GTG autostarting with the GNOME desktop""" autostart_path = os.path.join(self.__AUTOSTART_DIRECTORY, \ self.__AUTOSTART_FILE) if widget.get_active() == False: #Disable autostart, removing the file in autostart_path if os.path.isfile(autostart_path): os.remove(autostart_path) else: #Enable autostart #We look for the desktop file desktop_file_path = None desktop_file_directories = ["../..", "../../../applications", "../../../../../share/applications"] this_directory = os.path.dirname(os.path.abspath(__file__)) for path in desktop_file_directories: fullpath = os.path.normpath(os.path.join(this_directory, path, \ self.__AUTOSTART_FILE)) if os.path.isfile(fullpath): desktop_file_path = fullpath break #If we have found the desktop file, we make a link to in in # autostart_path. If symbolic linking is not possible # (that is, if we are running on Windows), then copy the file if desktop_file_path: if not os.path.exists(self.__AUTOSTART_DIRECTORY): os.mkdir(self.__AUTOSTART_DIRECTORY) if os.path.isdir(self.__AUTOSTART_DIRECTORY) and \ not os.path.exists(autostart_path): if hasattr(os, "symlink"): os.symlink(desktop_file_path, \ autostart_path) else: shutil.copyfile(desktop_file_path, \ autostart_path)