← Back to team overview

gtg-user team mailing list archive

[Merge] lp:~gtg-user/gtg/plugins-preferences-separation into lp:gtg

 

Izidor Matušov has proposed merging lp:~gtg-user/gtg/plugins-preferences-separation into lp:gtg.

Requested reviews:
  Bertrand Rousseau (bertrand-rousseau)
Related bugs:
  Bug #965955 in Getting Things GNOME!: "Move plugins to Edit menu"
  https://bugs.launchpad.net/gtg/+bug/965955

For more details, see:
https://code.launchpad.net/~gtg-user/gtg/plugins-preferences-separation/+merge/108265

Move Plugins dialog into Edit menu. I also cleaned the code a little bit. A little problem is that moving Plugins into a standalone dialogs from Gtk.Notebook creates weird looking dialogs. See the screenshots. Little playing with GLADE should solve that, patches are welcomed!
-- 
https://code.launchpad.net/~gtg-user/gtg/plugins-preferences-separation/+merge/108265
Your team Gtg users is subscribed to branch lp:~gtg-user/gtg/plugins-preferences-separation.
=== modified file 'GTG/gtk/__init__.py'
--- GTG/gtk/__init__.py	2012-03-17 02:20:46 +0000
+++ GTG/gtk/__init__.py	2012-06-01 00:18:21 +0000
@@ -26,4 +26,5 @@
     current_rep = os.path.dirname(os.path.abspath(__file__))
     DELETE_GLADE_FILE = os.path.join(current_rep, "deletion.glade")
     PREFERENCES_GLADE_FILE = os.path.join(current_rep, "preferences.glade")
+    PLUGINS_GLADE_FILE = os.path.join(current_rep, "plugins.glade")
     BACKENDS_GLADE_FILE = os.path.join(current_rep, "backends_dialog.glade")

=== modified file 'GTG/gtk/browser/browser.py'
--- GTG/gtk/browser/browser.py	2012-05-24 11:48:45 +0000
+++ GTG/gtk/browser/browser.py	2012-06-01 00:18:21 +0000
@@ -333,6 +333,8 @@
                 lambda w: openurl(info.REPORT_BUG_URL),
             "on_preferences_activate":
                 self.open_preferences,
+            "on_edit_plugins_activate":
+                self.open_plugins,
             "on_edit_backends_activate":
                 self.open_edit_backends,
         }
@@ -401,6 +403,9 @@
     def open_preferences(self, widget):
         self.vmanager.open_preferences(self.config)
         
+    def open_plugins(self, widget):
+        self.vmanager.configure_plugins()
+
     def open_edit_backends(self, widget):
         self.vmanager.open_edit_backends()
 

=== modified file 'GTG/gtk/browser/taskbrowser.glade'
--- GTG/gtk/browser/taskbrowser.glade	2012-05-27 18:20:57 +0000
+++ GTG/gtk/browser/taskbrowser.glade	2012-06-01 00:18:21 +0000
@@ -187,11 +187,22 @@
                       </object>
                     </child>
                     <child>
+                      <object class="GtkMenuItem" id="plugins_mi">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="use_action_appearance">False</property>
+                        <property name="label">P_lugins</property>
+                        <property name="use_underline">True</property>
+                        <signal name="activate" handler="on_edit_plugins_activate" swapped="no"/>
+                      </object>
+                    </child>
+                    <child>
                       <object class="GtkMenuItem" id="backends_mi">
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
                         <property name="use_action_appearance">False</property>
-                        <property name="label">Setup Sync. Services</property>
+                        <property name="label">_Synchronization Services</property>
+                        <property name="use_underline">True</property>
                         <signal name="activate" handler="on_edit_backends_activate" swapped="no"/>
                       </object>
                     </child>

=== modified file 'GTG/gtk/manager.py'
--- GTG/gtk/manager.py	2012-05-03 22:05:05 +0000
+++ GTG/gtk/manager.py	2012-06-01 00:18:21 +0000
@@ -34,6 +34,7 @@
 from GTG.gtk.browser.browser import TaskBrowser
 from GTG.gtk.editor.editor   import TaskEditor
 from GTG.gtk.preferences     import PreferencesDialog
+from GTG.gtk.plugins         import PluginsDialog
 from GTG.gtk.dbuswrapper     import DBusTaskWrapper
 from GTG.tools               import clipboard
 from GTG.core.plugins.engine import PluginEngine
@@ -83,7 +84,8 @@
         
         #Preferences and Backends windows
         # Initialize  dialogs
-        self.preferences_dialog = None
+        self.preferences = PreferencesDialog(self.req)
+        self.plugins = PluginsDialog(self.config_obj)
         self.edit_backends_dialog = None
 
         # Tag Editor
@@ -224,10 +226,11 @@
     def configure_backend(self, backend_id):
         self.open_edit_backends(None, backend_id)
 
-    def open_preferences(self, config_priv, sender=None):
-        if not hasattr(self, "preferences"):
-            self.preferences = PreferencesDialog(self.config_obj, self.req)
-        self.preferences.activate(config_priv)
+    def open_preferences(self, config_priv):
+        self.preferences.activate()
+
+    def configure_plugins(self):
+        self.plugins.activate()
         
     def ask_delete_tasks(self, tids):
         if not self.delete_dialog:

=== added file 'GTG/gtk/plugins.glade'
--- GTG/gtk/plugins.glade	1970-01-01 00:00:00 +0000
+++ GTG/gtk/plugins.glade	2012-06-01 00:18:21 +0000
@@ -0,0 +1,233 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy toplevel-contextual -->
+  <object class="GtkAboutDialog" id="PluginAboutDialog">
+    <property name="border_width">5</property>
+    <property name="window_position">mouse</property>
+    <property name="type_hint">dialog</property>
+    <signal name="close" handler="on_PluginAboutDialog_close"/>
+    <signal name="response" handler="on_PluginAboutDialog_close"/>
+    <signal name="delete-event" handler="on_PluginAboutDialog_close" swapped="no"/>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="pa-vbox1">
+        <property name="visible">True</property>
+        <property name="spacing">2</property>
+        <child>
+          <object class="GtkFrame" id="pa-frame1">
+            <property name="visible">True</property>
+            <property name="label_xalign">0</property>
+            <property name="shadow_type">none</property>
+            <child>
+              <object class="GtkAlignment" id="pa-alignment1">
+                <property name="visible">True</property>
+                <property name="left_padding">12</property>
+                <child>
+                  <object class="GtkLabel" id="PluginDepends">
+                    <property name="visible">True</property>
+                    <property name="use_markup">True</property>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child type="label">
+              <object class="GtkLabel" id="pa-label1">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">&lt;b&gt;Dependencies&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="position">3</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="pa-action_area1">
+            <property name="visible">True</property>
+            <property name="layout_style">end</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+  <object class="GtkDialog" id="PluginsDialog">
+    <property name="can_focus">False</property>
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Plugins - Getting Things GNOME!</property>
+    <property name="window_position">center-on-parent</property>
+    <property name="default_width">500</property>
+    <property name="default_height">500</property>
+    <property name="type_hint">dialog</property>
+    <signal name="delete-event" handler="on_PluginsDialog_delete_event" swapped="no"/>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="dialog-vbox5">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="dialog-action_area5">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="plugins_help">
+                <property name="label">gtk-help</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="no_show_all">True</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_stock">True</property>
+                <signal name="released" handler="on_plugins_help" swapped="no"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="plugins_close">
+                <property name="label">gtk-close</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_stock">True</property>
+                <signal name="released" handler="on_plugins_close" swapped="no"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkVBox" id="plugins-vbox6">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="spacing">6</property>
+            <child>
+              <object class="GtkLabel" id="plugins-label7">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;Available Plugins&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+                <property name="use_underline">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkScrolledWindow" id="plugins-scrolledwindow2">
+                <property name="width_request">240</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="hscrollbar_policy">automatic</property>
+                <property name="vscrollbar_policy">automatic</property>
+                <property name="shadow_type">in</property>
+                <child>
+                  <object class="GtkTreeView" id="PluginTree">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="headers_visible">False</property>
+                    <property name="rules_hint">True</property>
+                    <property name="show_expanders">False</property>
+                    <signal name="cursor_changed" handler="on_PluginTree_cursor_changed"/>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkHButtonBox" id="plugins-hbuttonbox1">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="spacing">8</property>
+                <property name="layout_style">end</property>
+                <child>
+                  <object class="GtkButton" id="plugin_about">
+                    <property name="label" translatable="yes">_About Plugin</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                    <property name="use_underline">True</property>
+                    <property name="image">img_plugin_about</property>
+                    <signal name="released" handler="on_plugin_about"/>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkButton" id="plugin_configure">
+                    <property name="label">C_onfigure Plugin</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                    <property name="use_underline">True</property>
+                    <property name="image">img_plugin_conf</property>
+                    <signal name="released" handler="on_plugin_configure"/>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="0">plugins_help</action-widget>
+      <action-widget response="0">plugins_close</action-widget>
+    </action-widgets>
+  </object>
+  <object class="GtkImage" id="img_plugin_about">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="stock">gtk-about</property>
+  </object>
+  <object class="GtkImage" id="img_plugin_conf">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="stock">gtk-preferences</property>
+  </object>
+</interface>

=== added file 'GTG/gtk/plugins.py'
--- GTG/gtk/plugins.py	1970-01-01 00:00:00 +0000
+++ GTG/gtk/plugins.py	2012-06-01 00:18:21 +0000
@@ -0,0 +1,319 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Gettings Things Gnome! - a personal organizer for the GNOME desktop
+# Copyright (c) 2008-2012 - Lionel Dricot & Bertrand Rousseau
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation, either version 3 of the License, or (at your option) any later
+# version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program.  If not, see <http://www.gnu.org/licenses/>.
+# -----------------------------------------------------------------------------
+
+""" Dialog for configuring plugins """
+
+import gtk
+import pango
+
+from GTG.core.plugins import GnomeConfig
+from GTG.core.plugins.engine import PluginEngine
+from GTG.gtk import ViewConfig
+
+# columns in PluginsDialog.plugin_store
+PLUGINS_COL_ID = 0
+PLUGINS_COL_ENABLED = 1
+PLUGINS_COL_NAME = 2
+PLUGINS_COL_SHORT_DESC = 3
+PLUGINS_COL_ACTIVATABLE = 4
+
+
+def plugin_icon(column, cell, store, iterator): # pylint: disable-msg=W0613
+    """ Callback to set the content of a PluginTree cell.
+
+    See PluginsDialog._init_plugin_tree().
+    """
+    cell.set_property('icon-name', 'gtg-plugin')
+    cell.set_property('sensitive',
+        store.get_value(iterator, PLUGINS_COL_ACTIVATABLE))
+
+
+def plugin_error_short_text(plugin):
+    """ Return small version of description of missing module dependencies
+    for displaying in plugin markup """
+    if not plugin.error:
+        return ""
+
+    # get lists
+    modules = plugin.missing_modules
+    dbus = plugin.missing_dbus
+
+    # convert to strings
+    if modules:
+        modules = "<small><b>%s</b></small>" % ', '.join(modules)
+    if dbus:
+        ifaces = ["%s:%s" % (a, b) for (a, b) in dbus]
+        dbus = "<small><b>%s</b></small>" % ', '.join(ifaces)
+
+    # combine
+    if modules and not dbus:
+        text = '\n'.join((GnomeConfig.miss2, modules))
+    elif dbus and not modules:
+        text = '\n'.join((GnomeConfig.dmiss2, dbus))
+    elif modules and dbus:
+        text = '\n'.join((GnomeConfig.bmiss2, modules, dbus))
+    else:
+        text = ""
+
+    return text
+
+
+def plugin_error_text(plugin):
+    """ Generate some helpful text about missing module dependencies. """
+    if not plugin.error:
+        return GnomeConfig.CANLOAD
+
+    # describe missing dependencies
+    text = "<b>%s</b>. \n" % GnomeConfig.CANNOTLOAD
+    # get lists
+    modules = plugin.missing_modules
+    dbus = plugin.missing_dbus
+
+    # convert to strings
+    if modules:
+        modules = "<small><b>%s</b></small>" % ', '.join(modules)
+    if dbus:
+        ifaces = ["%s:%s" % (a, b) for (a, b) in dbus]
+        dbus = "<small><b>%s</b></small>" % ', '.join(ifaces)
+
+    # combine
+    if modules and not dbus:
+        text += '\n'.join((GnomeConfig.MODULEMISSING, modules))
+    elif dbus and not modules:
+        text += '\n'.join((GnomeConfig.DBUSMISSING, dbus))
+    elif modules and dbus:
+        text += '\n'.join((GnomeConfig.MODULANDDBUS, modules, dbus))
+    else:
+        text += GnomeConfig.UNKNOWN
+
+    return text
+
+
+def plugin_markup(column, cell, store, iterator, self):
+    # pylint: disable-msg=W0613
+    """ Callback to set the content of a PluginTree cell.
+
+    See PluginsDialog._init_plugin_tree().
+    """
+    name = store.get_value(iterator, PLUGINS_COL_NAME)
+    desc = store.get_value(iterator, PLUGINS_COL_SHORT_DESC)
+
+    plugin_id = store.get_value(iterator, PLUGINS_COL_ID)
+    plugin = self.pengine.get_plugin(plugin_id)
+    error_text = plugin_error_short_text(plugin)
+    if error_text != "":
+        text = "<b>%s</b>\n%s\n<i>%s</i>" % (name, desc, error_text)
+    else:
+        text = "<b>%s</b>\n%s" % (name, desc)
+
+    cell.set_property('markup', text)
+    cell.set_property('sensitive',
+        store.get_value(iterator, PLUGINS_COL_ACTIVATABLE))
+
+
+class PluginsDialog:
+    """ Dialog for Plugins configuration """
+    # pylint: disable-msg=R0902
+    def __init__(self, config_obj):
+        self.config_obj = config_obj
+        self.config = self.config_obj.conf_dict
+        builder = gtk.Builder()
+        builder.add_from_file(ViewConfig.PLUGINS_GLADE_FILE)
+
+        self.dialog = builder.get_object("PluginsDialog")
+        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')
+
+        self.pengine = PluginEngine()
+        #plugin config initiation, if never used
+        if "plugins" in self.config:
+            if "enabled" not in self.config["plugins"]:
+                self.config["plugins"]["enabled"] = []
+
+            if "disabled" not in self.config["plugins"]:
+                self.config["plugins"]["disabled"] = []
+        elif 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")]
+
+        # 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.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)
+
+        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.iteritems():
+            # 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): # pylint: disable-msg=W0613
+        """ Close the plugins dialog."""
+        self.dialog.hide()
+        return True
+
+    @classmethod
+    def on_help(cls, widget): # pylint: disable-msg=W0613
+        """ In future, this will open help for plugins """
+        return True
+
+    def on_plugin_toggle(self, widget, path): # pylint: disable-msg=W0613
+        """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)
+        if plugin.enabled:
+            self.pengine.activate_plugins([plugin])
+            self.config["plugins"]["enabled"].append(plugin.module_name)
+            if plugin.module_name in self.config["plugins"]["disabled"]:
+                self.config["plugins"]["disabled"].remove(plugin.module_name)
+        else:
+            self.pengine.deactivate_plugins([plugin])
+            self.config["plugins"]["disabled"].append(plugin.module_name)
+            if plugin.module_name in self.config["plugins"]["enabled"]:
+                self.config["plugins"]["enabled"].remove(plugin.module_name)
+        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): # pylint: disable-msg=W0613
+        """ 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): # pylint: disable-msg=W0613
+        """ 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)
+
+        self.plugin_about.set_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):
+        # pylint: disable-msg=W0613
+        """ Close the PluginAboutDialog. """
+        self.plugin_about.hide()
+        return True

=== modified file 'GTG/gtk/preferences.glade'
--- GTG/gtk/preferences.glade	2012-05-24 11:48:45 +0000
+++ GTG/gtk/preferences.glade	2012-06-01 00:18:21 +0000
@@ -1,376 +1,34 @@
-<?xml version="1.0"?>
+<?xml version="1.0" encoding="UTF-8"?>
 <interface>
   <requires lib="gtk+" version="2.16"/>
   <!-- interface-naming-policy toplevel-contextual -->
-  <object class="GtkAccelGroup" id="accelgroup1"/>
-  <object class="GtkImage" id="image1">
-    <property name="visible">True</property>
-    <property name="stock">gtk-save-as</property>
-  </object>
   <object class="GtkDialog" id="PreferencesDialog">
+    <property name="can_focus">False</property>
     <property name="border_width">5</property>
     <property name="title" translatable="yes">Preferences - Getting Things GNOME!</property>
     <property name="window_position">center-on-parent</property>
     <property name="default_width">500</property>
     <property name="default_height">500</property>
     <property name="type_hint">dialog</property>
-    <signal name="delete_event" handler="on_PreferencesDialog_delete_event"/>
+    <signal name="delete-event" handler="on_PreferencesDialog_delete_event" swapped="no"/>
     <child internal-child="vbox">
       <object class="GtkVBox" id="prefs-vbox1">
         <property name="visible">True</property>
-        <child>
-          <object class="GtkAlignment" id="prefs-alignment1">
-            <property name="visible">True</property>
-            <property name="top_padding">6</property>
-            <property name="bottom_padding">6</property>
-            <property name="left_padding">6</property>
-            <property name="right_padding">6</property>
-            <child>
-              <object class="GtkNotebook" id="prefs-notebook1">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <child>
-                  <object class="GtkAlignment" id="prefs-alignment2">
-                    <property name="visible">True</property>
-                    <property name="top_padding">10</property>
-                    <property name="bottom_padding">10</property>
-                    <property name="left_padding">10</property>
-                    <property name="right_padding">10</property>
-                    <child>
-                      <object class="GtkVBox" id="prefs-vbox2">
-                        <property name="visible">True</property>
-                        <child>
-                          <object class="GtkFrame" id="prefs-frame3">
-                            <property name="visible">True</property>
-                            <property name="label_xalign">0</property>
-                            <property name="shadow_type">none</property>
-                            <child>
-                              <object class="GtkAlignment" id="prefs-alignment7">
-                                <property name="visible">True</property>
-                                <property name="bottom_padding">15</property>
-                                <property name="left_padding">12</property>
-                                <child>
-                                  <object class="GtkVBox" id="prefs-vbox7">
-                                    <property name="visible">True</property>
-                                    <child>
-                                      <object class="GtkCheckButton" id="pref_autostart">
-                                        <property name="label" translatable="yes">Start Getting Things GNOME! on every login</property>
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">True</property>
-                                        <property name="receives_default">False</property>
-                                        <property name="draw_indicator">True</property>
-                                        <signal name="toggled" handler="on_pref_autostart_toggled"/>
-                                      </object>
-                                      <packing>
-                                        <property name="expand">False</property>
-                                        <property name="padding">3</property>
-                                        <property name="position">0</property>
-                                      </packing>
-                                    </child>
-                                  </object>
-                                </child>
-                              </object>
-                            </child>
-                            <child type="label">
-                              <object class="GtkLabel" id="prefs-label8">
-                                <property name="visible">True</property>
-                                <property name="ypad">5</property>
-                                <property name="label" translatable="yes">&lt;b&gt;Startup&lt;/b&gt;</property>
-                                <property name="use_markup">True</property>
-                              </object>
-                            </child>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="position">0</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkFrame" id="prefs-frame1">
-                            <property name="visible">True</property>
-                            <property name="label_xalign">0</property>
-                            <property name="shadow_type">none</property>
-                            <child>
-                              <object class="GtkAlignment" id="prefs-alignment5">
-                                <property name="visible">True</property>
-                                <property name="bottom_padding">15</property>
-                                <property name="left_padding">12</property>
-                                <child>
-                                  <object class="GtkVBox" id="prefs-vbox3">
-                                    <property name="visible">True</property>
-                                    <child>
-                                      <object class="GtkCheckButton" id="pref_show_preview">
-                                        <property name="label" translatable="yes">Show description preview in the task list.</property>
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">True</property>
-                                        <property name="receives_default">False</property>
-                                        <property name="draw_indicator">True</property>
-                                        <signal name="toggled" handler="on_pref_show_preview_toggled"/>
-                                      </object>
-                                      <packing>
-                                        <property name="expand">False</property>
-                                        <property name="padding">3</property>
-                                        <property name="position">0</property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <object class="GtkCheckButton" id="bg_color_enable">
-                                        <property name="label" translatable="yes">Enable colored backgrounds in the task list</property>
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">True</property>
-                                        <property name="receives_default">False</property>
-                                        <property name="draw_indicator">True</property>
-                                        <signal name="toggled" handler="on_bg_color_toggled"/>
-                                      </object>
-                                      <packing>
-                                        <property name="expand">False</property>
-                                        <property name="padding">3</property>
-                                        <property name="position">1</property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <object class="GtkHBox" id="prefs-hbox1">
-                                        <property name="no_show_all">True</property>
-                                        <child>
-                                          <object class="GtkCheckButton" id="pref_hide_closed">
-                                            <property name="label" translatable="yes">Hide closed tasks older than </property>
-                                            <property name="visible">True</property>
-                                            <property name="sensitive">False</property>
-                                            <property name="can_focus">True</property>
-                                            <property name="receives_default">False</property>
-                                            <property name="draw_indicator">True</property>
-                                          </object>
-                                          <packing>
-                                            <property name="expand">False</property>
-                                            <property name="position">0</property>
-                                          </packing>
-                                        </child>
-                                        <child>
-                                          <object class="GtkComboBox" id="pref_hide_closed_age">
-                                            <property name="visible">True</property>
-                                            <property name="sensitive">False</property>
-                                            <property name="can_focus">True</property>
-                                          </object>
-                                          <packing>
-                                            <property name="position">1</property>
-                                          </packing>
-                                        </child>
-                                      </object>
-                                      <packing>
-                                        <property name="expand">False</property>
-                                        <property name="padding">3</property>
-                                        <property name="position">2</property>
-                                      </packing>
-                                    </child>
-                                  </object>
-                                </child>
-                              </object>
-                            </child>
-                            <child type="label">
-                              <object class="GtkLabel" id="prefs-label4">
-                                <property name="visible">True</property>
-                                <property name="ypad">5</property>
-                                <property name="label" translatable="yes">&lt;b&gt;Task Browser&lt;/b&gt;</property>
-                                <property name="use_markup">True</property>
-                              </object>
-                            </child>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="position">1</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkFrame" id="prefs-frame2">
-                            <property name="visible">True</property>
-                            <property name="label_xalign">0</property>
-                            <property name="shadow_type">none</property>
-                            <child>
-                              <object class="GtkAlignment" id="prefs-alignment6">
-                                <property name="visible">True</property>
-                                <property name="bottom_padding">15</property>
-                                <property name="left_padding">12</property>
-                                <child>
-                                  <object class="GtkVBox" id="prefs-vbox4">
-                                    <property name="visible">True</property>
-                                    <child>
-                                      <object class="GtkCheckButton" id="pref_check_spelling">
-                                        <property name="label" translatable="yes">Check spelling</property>
-                                        <property name="sensitive">False</property>
-                                        <property name="can_focus">True</property>
-                                        <property name="receives_default">False</property>
-                                        <property name="no_show_all">True</property>
-                                        <property name="draw_indicator">True</property>
-                                        <signal name="toggled" handler="on_pref_check_spelling_toggled"/>
-                                      </object>
-                                      <packing>
-                                        <property name="expand">False</property>
-                                        <property name="padding">3</property>
-                                        <property name="position">0</property>
-                                      </packing>
-                                    </child>
-                                  </object>
-                                </child>
-                              </object>
-                            </child>
-                            <child type="label">
-                              <object class="GtkLabel" id="prefs-label5">
-                                <property name="no_show_all">True</property>
-                                <property name="ypad">5</property>
-                                <property name="label" translatable="yes">&lt;b&gt;Task Editor&lt;/b&gt;</property>
-                                <property name="use_markup">True</property>
-                              </object>
-                            </child>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="position">2</property>
-                          </packing>
-                        </child>
-                      </object>
-                    </child>
-                  </object>
-                </child>
-                <child type="tab">
-                  <object class="GtkLabel" id="prefs-label1">
-                    <property name="visible">True</property>
-                    <property name="label" translatable="yes">General</property>
-                  </object>
-                  <packing>
-                    <property name="tab_fill">False</property>
-                  </packing>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child type="tab">
-                  <placeholder/>
-                </child>
-                <child>
-                  <object class="GtkAlignment" id="prefs-alignment4">
-                    <property name="visible">True</property>
-                    <property name="top_padding">10</property>
-                    <property name="bottom_padding">10</property>
-                    <property name="left_padding">10</property>
-                    <property name="right_padding">10</property>
-                    <child>
-                      <object class="GtkVBox" id="prefs-vbox6">
-                        <property name="visible">True</property>
-                        <property name="spacing">6</property>
-                        <child>
-                          <object class="GtkLabel" id="prefs-label7">
-                            <property name="visible">True</property>
-                            <property name="xalign">0</property>
-                            <property name="label" translatable="yes">Active _Plugins:</property>
-                            <property name="use_underline">True</property>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="position">0</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkScrolledWindow" id="prefs-scrolledwindow2">
-                            <property name="width_request">240</property>
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="hscrollbar_policy">automatic</property>
-                            <property name="vscrollbar_policy">automatic</property>
-                            <property name="shadow_type">in</property>
-                            <child>
-                              <object class="GtkTreeView" id="PluginTree">
-                                <property name="visible">True</property>
-                                <property name="can_focus">True</property>
-                                <property name="headers_visible">False</property>
-                                <property name="rules_hint">True</property>
-                                <property name="show_expanders">False</property>
-                                <signal name="cursor_changed" handler="on_PluginTree_cursor_changed"/>
-                              </object>
-                            </child>
-                          </object>
-                          <packing>
-                            <property name="position">1</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkHButtonBox" id="prefs-hbuttonbox1">
-                            <property name="visible">True</property>
-                            <property name="spacing">8</property>
-                            <property name="layout_style">end</property>
-                            <child>
-                              <object class="GtkButton" id="plugin_about">
-                                <property name="label" translatable="yes">_About Plugin</property>
-                                <property name="visible">True</property>
-                                <property name="can_focus">True</property>
-                                <property name="receives_default">True</property>
-                                <property name="image">pref_img_plugin_about</property>
-                                <property name="use_underline">True</property>
-                                <signal name="released" handler="on_plugin_about"/>
-                              </object>
-                              <packing>
-                                <property name="expand">False</property>
-                                <property name="fill">False</property>
-                                <property name="position">0</property>
-                              </packing>
-                            </child>
-                            <child>
-                              <object class="GtkButton" id="plugin_configure">
-                                <property name="label">C_onfigure Plugin</property>
-                                <property name="sensitive">False</property>
-                                <property name="can_focus">True</property>
-                                <property name="receives_default">True</property>
-                                <property name="image">pref_img_plugin_conf</property>
-                                <property name="use_underline">True</property>
-                                <signal name="released" handler="on_plugin_configure"/>
-                              </object>
-                              <packing>
-                                <property name="expand">False</property>
-                                <property name="fill">False</property>
-                                <property name="position">1</property>
-                              </packing>
-                            </child>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="position">2</property>
-                          </packing>
-                        </child>
-                      </object>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="position">2</property>
-                  </packing>
-                </child>
-                <child type="tab">
-                  <object class="GtkLabel" id="prefs-label3">
-                    <property name="visible">True</property>
-                    <property name="label" translatable="yes">Plugins</property>
-                  </object>
-                  <packing>
-                    <property name="position">2</property>
-                    <property name="tab_fill">False</property>
-                  </packing>
-                </child>
-              </object>
-            </child>
-          </object>
-          <packing>
-            <property name="position">1</property>
-          </packing>
-        </child>
+        <property name="can_focus">False</property>
         <child internal-child="action_area">
           <object class="GtkHButtonBox" id="prefs-action_area">
             <property name="visible">True</property>
+            <property name="can_focus">False</property>
             <property name="layout_style">end</property>
             <child>
               <object class="GtkButton" id="prefs_help">
                 <property name="label">gtk-help</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
                 <property name="no_show_all">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
                 <property name="use_stock">True</property>
-                <signal name="activate" handler="on_prefs_help"/>
+                <signal name="activate" handler="on_prefs_help" swapped="no"/>
               </object>
               <packing>
                 <property name="expand">False</property>
@@ -384,8 +42,9 @@
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
                 <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
                 <property name="use_stock">True</property>
-                <signal name="released" handler="on_prefs_close"/>
+                <signal name="released" handler="on_prefs_close" swapped="no"/>
               </object>
               <packing>
                 <property name="expand">False</property>
@@ -396,10 +55,145 @@
           </object>
           <packing>
             <property name="expand">False</property>
+            <property name="fill">True</property>
             <property name="pack_type">end</property>
             <property name="position">0</property>
           </packing>
         </child>
+        <child>
+          <object class="GtkVBox" id="prefs-vbox2">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <child>
+              <object class="GtkFrame" id="prefs-frame3">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label_xalign">0</property>
+                <property name="shadow_type">none</property>
+                <child>
+                  <object class="GtkAlignment" id="prefs-alignment7">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="bottom_padding">15</property>
+                    <property name="left_padding">12</property>
+                    <child>
+                      <object class="GtkVBox" id="prefs-vbox7">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <child>
+                          <object class="GtkCheckButton" id="pref_autostart">
+                            <property name="label" translatable="yes">Start Getting Things GNOME! on every login</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="use_action_appearance">False</property>
+                            <property name="draw_indicator">True</property>
+                            <signal name="toggled" handler="on_pref_autostart_toggled" swapped="no"/>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="padding">3</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child type="label">
+                  <object class="GtkLabel" id="prefs-label8">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="ypad">5</property>
+                    <property name="label" translatable="yes">&lt;b&gt;Startup&lt;/b&gt;</property>
+                    <property name="use_markup">True</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkFrame" id="prefs-frame1">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label_xalign">0</property>
+                <property name="shadow_type">none</property>
+                <child>
+                  <object class="GtkAlignment" id="prefs-alignment5">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="bottom_padding">15</property>
+                    <property name="left_padding">12</property>
+                    <child>
+                      <object class="GtkVBox" id="prefs-vbox3">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <child>
+                          <object class="GtkCheckButton" id="pref_show_preview">
+                            <property name="label" translatable="yes">Show description preview in the task list.</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="use_action_appearance">False</property>
+                            <property name="draw_indicator">True</property>
+                            <signal name="toggled" handler="on_pref_show_preview_toggled" swapped="no"/>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="padding">3</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkCheckButton" id="bg_color_enable">
+                            <property name="label" translatable="yes">Enable colored backgrounds in the task list</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="use_action_appearance">False</property>
+                            <property name="draw_indicator">True</property>
+                            <signal name="toggled" handler="on_bg_color_toggled" swapped="no"/>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="padding">3</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child type="label">
+                  <object class="GtkLabel" id="prefs-label4">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="ypad">5</property>
+                    <property name="label" translatable="yes">&lt;b&gt;Task Browser&lt;/b&gt;</property>
+                    <property name="use_markup">True</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
       </object>
     </child>
     <action-widgets>
@@ -407,113 +201,4 @@
       <action-widget response="0">prefs_close</action-widget>
     </action-widgets>
   </object>
-  <object class="GtkImage" id="pref_img_plugin_conf">
-    <property name="visible">True</property>
-    <property name="stock">gtk-preferences</property>
-  </object>
-  <object class="GtkImage" id="pref_img_plugin_about">
-    <property name="visible">True</property>
-    <property name="stock">gtk-about</property>
-  </object>
-  <object class="GtkAboutDialog" id="PluginAboutDialog">
-    <property name="border_width">5</property>
-    <property name="window_position">mouse</property>
-    <property name="type_hint">dialog</property>
-    <signal name="close" handler="on_PluginAboutDialog_close"/>
-    <signal name="response" handler="on_PluginAboutDialog_close"/>
-    <child internal-child="vbox">
-      <object class="GtkVBox" id="pa-vbox1">
-        <property name="visible">True</property>
-        <property name="spacing">2</property>
-        <child>
-          <object class="GtkFrame" id="pa-frame1">
-            <property name="visible">True</property>
-            <property name="label_xalign">0</property>
-            <property name="shadow_type">none</property>
-            <child>
-              <object class="GtkAlignment" id="pa-alignment1">
-                <property name="visible">True</property>
-                <property name="left_padding">12</property>
-                <child>
-                  <object class="GtkLabel" id="PluginDepends">
-                    <property name="visible">True</property>
-                    <property name="use_markup">True</property>
-                  </object>
-                </child>
-              </object>
-            </child>
-            <child type="label">
-              <object class="GtkLabel" id="pa-label1">
-                <property name="visible">True</property>
-                <property name="label" translatable="yes">&lt;b&gt;Dependencies&lt;/b&gt;</property>
-                <property name="use_markup">True</property>
-              </object>
-            </child>
-          </object>
-          <packing>
-            <property name="position">3</property>
-          </packing>
-        </child>
-        <child internal-child="action_area">
-          <object class="GtkHButtonBox" id="pa-action_area1">
-            <property name="visible">True</property>
-            <property name="layout_style">end</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="pack_type">end</property>
-            <property name="position">0</property>
-          </packing>
-        </child>
-      </object>
-    </child>
-  </object>
-  <object class="GtkImage" id="pref_img_plugin">
-    <property name="visible">True</property>
-    <property name="icon_name">gtg-plugin</property>
-  </object>
-  <object class="GtkDialog" id="PluginConfigDialog">
-    <property name="border_width">5</property>
-    <property name="window_position">mouse</property>
-    <property name="type_hint">dialog</property>
-    <property name="has_separator">False</property>
-    <child internal-child="vbox">
-      <object class="GtkVBox" id="pc-vbox1">
-        <property name="visible">True</property>
-        <property name="spacing">2</property>
-        <child>
-          <placeholder/>
-        </child>
-        <child internal-child="action_area">
-          <object class="GtkHButtonBox" id="pc-action_area1">
-            <property name="visible">True</property>
-            <property name="layout_style">end</property>
-            <child>
-              <object class="GtkButton" id="PluginConfigClose">
-                <property name="label">gtk-close</property>
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">True</property>
-                <property name="use_stock">True</property>
-                <signal name="released" handler="on_PluginConfigClose_released"/>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">False</property>
-                <property name="position">0</property>
-              </packing>
-            </child>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="pack_type">end</property>
-            <property name="position">0</property>
-          </packing>
-        </child>
-      </object>
-    </child>
-    <action-widgets>
-      <action-widget response="0">PluginConfigClose</action-widget>
-    </action-widgets>
-  </object>
 </interface>

=== modified file 'GTG/gtk/preferences.py'
--- GTG/gtk/preferences.py	2012-05-27 15:33:03 +0000
+++ GTG/gtk/preferences.py	2012-06-01 00:18:21 +0000
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 # -----------------------------------------------------------------------------
 # Gettings Things Gnome! - a personal organizer for the GNOME desktop
-# Copyright (c) 2008-2009 - Lionel Dricot & Bertrand Rousseau
+# Copyright (c) 2008-2012 - Lionel Dricot & Bertrand Rousseau
 #
 # This program is free software: you can redistribute it and/or modify it under
 # the terms of the GNU General Public License as published by the Free Software
@@ -16,447 +16,132 @@
 # You should have received a copy of the GNU General Public License along with
 # this program.  If not, see <http://www.gnu.org/licenses/>.
 # -----------------------------------------------------------------------------
-""" The Preferences Dialog for loading plugins and configuring GTG """
+
+""" The Preferences Dialog for configuring GTG """
+
 import os
 import shutil
 
 import gtk
-import pango
+from GTG.gtk import ViewConfig
 from xdg.BaseDirectory import xdg_config_home
 
-from GTG              import _
-from GTG.core.plugins import GnomeConfig
-from GTG.gtk          import ViewConfig
-from GTG.core.plugins.engine import PluginEngine
-
-
-__all__ = [
-  'PreferencesDialog',
-  ]
-
-# Default plugin information text
-PLUGINS_DEFAULT_DESC = _("Click on a plugin name to view its description here.")
-
-# columns in PreferencesDialog.plugin_store
-PLUGINS_COL_ID = 0
-PLUGINS_COL_ENABLED = 1
-PLUGINS_COL_NAME = 2
-PLUGINS_COL_SHORT_DESC = 3
-PLUGINS_COL_DESC = 4
-PLUGINS_COL_ACTIVATABLE = 5
-
-def plugin_icon(column, cell, store, iter):
-    """Callback to set the content of a PluginTree cell.
-
-    See PreferencesDialog._init_plugin_tree().
-
-    """
-    cell.set_property('icon-name', 'gtg-plugin')
-    cell.set_property('sensitive', store.get_value(iter,
-      PLUGINS_COL_ACTIVATABLE))
-
-
-def plugin_markup(column, cell, store, iter, self):
-    """Callback to set the content of a PluginTree cell.
-
-    See PreferencesDialog._init_plugin_tree().
-
-    """
-    name = store.get_value(iter, PLUGINS_COL_NAME)
-    desc = store.get_value(iter, PLUGINS_COL_SHORT_DESC)
-    plugin_id = store.get_value(iter, PLUGINS_COL_ID)
-    p = self.pengine.get_plugin(plugin_id)
-    error_text = plugin_error_short_text(p)
-    if error_text != "":
-        cell.set_property('markup', "<b>%s</b>\n%s\n<i>%s</i>" % (name, desc, error_text))
-    else:
-        cell.set_property('markup', "<b>%s</b>\n%s" % (name, desc))
-    cell.set_property('sensitive', store.get_value(iter,
-      PLUGINS_COL_ACTIVATABLE))
-
-def plugin_error_short_text(plugin):
-    """ Return small version of description of missing module dependencies
-    for displaying in plugin markup """
-    if not plugin.error:
-        return ""
-
-    # get lists
-    modules = plugin.missing_modules
-    dbus = plugin.missing_dbus
-    
-    # convert to strings
-    if modules:
-        modules = "<small><b>%s</b></small>" % ', '.join(modules)
-    if dbus:
-        ifaces = ["%s:%s" % (a, b) for (a, b) in dbus]
-        dbus = "<small><b>%s</b></small>" % ', '.join(ifaces)
-    # combine
-    if modules and not dbus:
-        text = '\n'.join((GnomeConfig.miss2, modules))
-    elif dbus and not modules:
-        text = '\n'.join((GnomeConfig.dmiss2, dbus))
-    elif modules and dbus:
-        text = '\n'.join((GnomeConfig.bmiss2, modules, dbus))
-    else:
-        text = ""
-    return text
-
-def plugin_error_text(plugin):
-    """Generate some helpful text about missing module dependencies."""
-    if not plugin.error:
-        return GnomeConfig.CANLOAD
-    # describe missing dependencies
-    text = "<b>%s</b>. \n" % GnomeConfig.CANNOTLOAD
-    # get lists
-    modules = plugin.missing_modules
-    dbus = plugin.missing_dbus
-    # convert to strings
-    if modules:
-        modules = "<small><b>%s</b></small>" % ', '.join(modules)
-    if dbus:
-        ifaces = ["%s:%s" % (a, b) for (a, b) in dbus]
-        dbus = "<small><b>%s</b></small>" % ', '.join(ifaces)
-    # combine
-    if modules and not dbus:
-        text += '\n'.join((GnomeConfig.MODULEMISSING, modules))
-    elif dbus and not modules:
-        text += '\n'.join((GnomeConfig.DBUSMISSING, dbus))
-    elif modules and dbus:
-        text += '\n'.join((GnomeConfig.MODULANDDBUS, modules, dbus))
-    else:
-        text += GnomeConfig.UNKNOWN
-    return text
+AUTOSTART_DIRECTORY = os.path.join(xdg_config_home, "autostart")
+AUTOSTART_FILE = "gtg.desktop"
+AUTOSTART_PATH = os.path.join(AUTOSTART_DIRECTORY, AUTOSTART_FILE)
+
+
+def enable_gtg_autostart():
+    """ Enable autostart
+
+    Firstly, locate gtg.desktop file. Then link it in AUTOSTART_FILE.
+    On Windows, there is no os.symlink, just copy the file. """
+    desktop_file_path = None
+    this_directory = os.path.dirname(os.path.abspath(__file__))
+    for path in ["../..", "../../../applications",
+                "../../../../../share/applications"]:
+        fullpath = os.path.join(this_directory, path, AUTOSTART_FILE)
+        fullpath = os.path.normpath(fullpath)
+        if os.path.isfile(fullpath):
+            desktop_file_path = fullpath
+            break
+
+    if desktop_file_path:
+        if not os.path.exists(AUTOSTART_DIRECTORY):
+            os.mkdir(AUTOSTART_DIRECTORY)
+
+        if os.path.isdir(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)
+
+
+def disable_gtg_autostart():
+    """ Disable autostart, removing the file in autostart_path """
+    if os.path.isfile(AUTOSTART_PATH):
+        os.remove(AUTOSTART_PATH)
 
 
 class PreferencesDialog:
-
-    __AUTOSTART_DIRECTORY = os.path.join(xdg_config_home, "autostart")
-    __AUTOSTART_FILE = "gtg.desktop"
-
-    def __init__(self, config_obj, req):
-        """Constructor."""
-        self.config_obj = config_obj
+    """ Show preference dialog """
+
+    def __init__(self, req):
         self.req = req
-        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',
-          'bg_color_enable': 'bg_color_enable',
-          }
-        for attr, widget in widgets.iteritems():
-            setattr(self, attr, self.builder.get_object(widget))
-        # keep a reference to the parent task browser
-        self.pengine = PluginEngine()
-        #plugin config initiation, if never used
-        if "plugins" in self.config:
-            if "enabled" not in self.config["plugins"]:
-                self.config["plugins"]["enabled"] = []
-            
-            if "disabled" not in self.config["plugins"]:
-                self.config["plugins"]["disabled"] = []
-        elif 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")]
-        # 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)
-        
-        #this line enables the about dialog widget to be reused
-        self.plugin_about_dialog.connect("delete-event", lambda w, e: self.plugin_about_dialog.hide() or True)
-
-    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))
-
-        show_preview = self.config_priv.get("contents_preview_enable")
-        self.pref_show_preview.set_active(show_preview)
-
-        bg_color = self.config_priv.get("bg_color_enable")
-        self.bg_color_enable.set_active(bg_color)
-
-    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)
-
-        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
+        self.config = self.req.get_config('browser')
+        builder = gtk.Builder()
+        builder.add_from_file(ViewConfig.PREFERENCES_GLADE_FILE)
+
+        self.dialog = builder.get_object("PreferencesDialog")
+        self.pref_autostart = builder.get_object("pref_autostart")
+        self.pref_show_preview = builder.get_object("pref_show_preview")
+        self.bg_color_enable = builder.get_object("bg_color_enable")
+
+        builder.connect_signals({
+          'on_pref_autostart_toggled':
+            self.on_autostart_toggled,
           'on_pref_show_preview_toggled':
             self.toggle_preview,
           'on_bg_color_toggled':
             self.on_bg_color_toggled,
-          '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_prefs_help':
+            self.on_help,
+          'on_prefs_close':
+            self.on_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()
+        })
+
+    def  _refresh_preferences_store(self):
+        """ Sets the correct value in the preferences checkboxes """
+        has_autostart = os.path.isfile(AUTOSTART_PATH)
+        self.pref_autostart.set_active(has_autostart)
+
+        show_preview = self.config.get("contents_preview_enable")
+        self.pref_show_preview.set_active(show_preview)
+
+        bg_color = self.config.get("bg_color_enable")
+        self.bg_color_enable.set_active(bg_color)
+
+    def _refresh_task_browser(self):
+        """ Refresh tasks in task browser """
+        task_tree = self.req.get_tasks_tree(refresh=False).get_basetree()
+        task_tree.refresh_all()
+
+    def activate(self):
+        """ Activate the preferences dialog."""
         self._refresh_preferences_store()
-        self.dialog.present()
         self.dialog.show_all()
 
-    def on_close(self, widget, data = None):
-        """Close the preferences dialog."""
-
+    def on_close(self, widget, data=None): # pylint: disable-msg=W0613
+        """ Close the preferences dialog."""
         self.dialog.hide()
         return True
 
-    def on_help(self, widget):
-        """Provide help for the preferences dialog."""
+    @classmethod
+    def on_help(cls, widget): # pylint: disable-msg=W0613
+        """ In future, this will open help for preferences """
         return True
 
-    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)
-        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."""
-        _, iterator = self.plugin_tree.get_selection().get_selected()
-        if iterator is None:
-            return
-        plugin_id = self.plugin_store.get_value(iterator, 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.
-        plugin = self.pengine.get_plugin(plugin_id)
-        plugin.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):
-        """ 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 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])
-            self.config["plugins"]["enabled"].append(p.module_name)
-            if p.module_name in self.config["plugins"]["disabled"]:
-                self.config["plugins"]["disabled"].remove(p.module_name)
+    @classmethod
+    def on_autostart_toggled(cls, widget):
+        """ Toggle GTG autostarting with the GNOME desktop """
+        if widget.get_active():
+            enable_gtg_autostart()
         else:
-            self.pengine.deactivate_plugins([p])
-            self.config["plugins"]["disabled"].append(p.module_name)
-            if p.module_name in self.config["plugins"]["enabled"]:
-                self.config["plugins"]["enabled"].remove(p.module_name)
-        self.plugin_store.set_value(iter, PLUGINS_COL_ENABLED, p.enabled)
-        self._update_plugin_configure(p)
-        
-        self.config_obj.save()
+            disable_gtg_autostart()
 
     def toggle_preview(self, widget):
-        """Toggle previews in the task view on or off."""
-        curstate = self.config_priv.get("contents_preview_enable")
+        """ Toggle previews in the task view on or off."""
+        curstate = self.config.get("contents_preview_enable")
         if curstate != widget.get_active():
-            self.config_priv.set("contents_preview_enable", not curstate)
-            view = self.req.get_tasks_tree(refresh=False)
-            view.refresh_all()
+            self.config.set("contents_preview_enable", not curstate)
+            self._refresh_task_browser()
 
     def on_bg_color_toggled(self, widget):
         """ Save configuration and refresh nodes to apply the change """
-        curstate = self.config_priv.get("bg_color_enable")
+        curstate = self.config.get("bg_color_enable")
         if curstate != widget.get_active():
-            self.config_priv.set("bg_color_enable", not curstate)
-            task_tree = self.req.get_tasks_tree(refresh=False).get_basetree()
-            task_tree.refresh_all()
-
-    def toggle_spellcheck(self, widget):
-        """Toggle spell checking on or off."""
-        print __name__
-
-    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_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)
+            self.config.set("bg_color_enable", not curstate)
+            self._refresh_task_browser()


Follow ups