diff --git a/kupfer/core/plugins.py b/kupfer/core/plugins.py index 9c903a6..c6eb969 100644 --- a/kupfer/core/plugins.py +++ b/kupfer/core/plugins.py @@ -1,6 +1,7 @@ import sys from kupfer import pretty, config from kupfer.core import settings +from kupfer.plugin_support import CATEGORY_GENERIC sources_attribute = "__kupfer_sources__" text_sources_attribute = "__kupfer_text_sources__" @@ -13,6 +14,7 @@ info_attributes = [ "__version__", "__description__", "__author__", + '__kupfer_plugin_category__' ] def get_plugin_ids(): @@ -73,6 +75,7 @@ def get_plugin_info(): desc = plugin.get("__description__", "") vers = plugin.get("__version__", "") author = plugin.get("__author__", "") + category = plugin.get("__kupfer_plugin_category__", CATEGORY_GENERIC) # skip false matches; # all plugins have to have @localized_name if localized_name is None: @@ -84,6 +87,7 @@ def get_plugin_info(): "description": desc or u"", "author": author, "provides": (), + "category": category } def get_plugin_desc(): diff --git a/kupfer/plugin/audacious.py b/kupfer/plugin/audacious.py index 4f7a9dc..3fcb4d8 100644 --- a/kupfer/plugin/audacious.py +++ b/kupfer/plugin/audacious.py @@ -15,7 +15,7 @@ __kupfer_actions__ = ( __description__ = _("Control Audacious playback and playlist") __version__ = "2009-12-15" __author__ = "Horia V. Corcalciuc " - +__kupfer_plugin_category__ = plugin_support.CATEGORY_MULTIMEDIA __kupfer_settings__ = plugin_support.PluginSettings( { "key": "playlist_toplevel", diff --git a/kupfer/plugin/chromium.py b/kupfer/plugin/chromium.py index f159456..5e80fc2 100644 --- a/kupfer/plugin/chromium.py +++ b/kupfer/plugin/chromium.py @@ -11,6 +11,7 @@ __description__ = _("Index of Chromium bookmarks") __version__ = "" __author__ = "Francesco Marella " +__kupfer_plugin_category__ = plugin_support.CATEGORY_WEB_BROWSERS __kupfer_settings__ = plugin_support.PluginSettings( plugin_support.SETTING_PREFER_CATALOG, ) diff --git a/kupfer/plugin/clawsmail.py b/kupfer/plugin/clawsmail.py index 5b4be9c..a6bf54d 100644 --- a/kupfer/plugin/clawsmail.py +++ b/kupfer/plugin/clawsmail.py @@ -4,7 +4,7 @@ from xml.dom import minidom from kupfer.objects import Leaf, Action, Source from kupfer.objects import TextLeaf, UrlLeaf, RunnableLeaf, FileLeaf -from kupfer import utils +from kupfer import utils, plugin_support from kupfer.obj.apps import AppLeafContentMixin from kupfer.obj.helplib import FilesystemWatchMixin from kupfer.obj.grouping import ToplevelGroupingSource @@ -16,6 +16,7 @@ __kupfer_actions__ = ("NewMailAction", "SendFileByMail") __description__ = _("Claws Mail Contacts and Actions") __version__ = "2010-01-07" __author__ = "Karol Będkowski " +__kupfer_plugin_category__ = plugin_support.CATEGORY_EMAIL class ComposeMail(RunnableLeaf): diff --git a/kupfer/plugin/defaultmail.py b/kupfer/plugin/defaultmail.py index d1dc257..1b320bd 100644 --- a/kupfer/plugin/defaultmail.py +++ b/kupfer/plugin/defaultmail.py @@ -1,7 +1,7 @@ from kupfer.objects import Action from kupfer.objects import TextLeaf, UrlLeaf, FileLeaf from kupfer.obj.contacts import ContactLeaf, email_from_leaf -from kupfer import utils +from kupfer import utils, plugin_support __kupfer_name__ = _("Default Email Client") __kupfer_actions__ = ( @@ -11,6 +11,7 @@ __kupfer_actions__ = ( __description__ = _("Compose email using the system's default mailto: handler") __version__ = "2010-01-12" __author__ = "Ulrik Sverdrup " +__kupfer_plugin_category__ = plugin_support.CATEGORY_EMAIL class NewMailAction(Action): def __init__(self): diff --git a/kupfer/plugin/epiphany.py b/kupfer/plugin/epiphany.py index c39d606..c3b2700 100644 --- a/kupfer/plugin/epiphany.py +++ b/kupfer/plugin/epiphany.py @@ -13,6 +13,7 @@ __description__ = _("Index of Epiphany bookmarks") __version__ = "" __author__ = "Ulrik Sverdrup " +__kupfer_plugin_category__ = plugin_support.CATEGORY_WEB_BROWSERS __kupfer_settings__ = plugin_support.PluginSettings( plugin_support.SETTING_PREFER_CATALOG, ) diff --git a/kupfer/plugin/firefox.py b/kupfer/plugin/firefox.py index 841e89b..a4834b4 100644 --- a/kupfer/plugin/firefox.py +++ b/kupfer/plugin/firefox.py @@ -19,7 +19,8 @@ from kupfer.obj.helplib import FilesystemWatchMixin from kupfer import plugin_support from kupfer.plugin import firefox_support - +__kupfer_plugin_category__ = [ plugin_support.CATEGORY_WEB_BROWSERS, + plugin_support.CATEGORY_APP_SPECIFIC ] __kupfer_settings__ = plugin_support.PluginSettings( plugin_support.SETTING_PREFER_CATALOG, ) diff --git a/kupfer/plugin/gajim.py b/kupfer/plugin/gajim.py index 6a71128..9ba69fd 100644 --- a/kupfer/plugin/gajim.py +++ b/kupfer/plugin/gajim.py @@ -18,6 +18,7 @@ __kupfer_actions__ = ("ChangeStatus", 'OpenChat') __description__ = _("Access to Gajim Contacts") __version__ = "2010-01-06" __author__ = "Karol Będkowski " +__kupfer_plugin_category__ = plugin_support.CATEGORY_IM plugin_support.check_dbus_connection() diff --git a/kupfer/plugin/opera.py b/kupfer/plugin/opera.py index ed87765..7445eba 100644 --- a/kupfer/plugin/opera.py +++ b/kupfer/plugin/opera.py @@ -14,6 +14,7 @@ __kupfer_sources__ = ("BookmarksSource", ) __description__ = _("Index of Opera bookmarks") __version__ = "2010-01-12" __author__ = "Karol Będkowski " +__kupfer_plugin_category__ = plugin_support.CATEGORY_WEB_BROWSERS __kupfer_settings__ = plugin_support.PluginSettings( plugin_support.SETTING_PREFER_CATALOG, diff --git a/kupfer/plugin/pidgin.py b/kupfer/plugin/pidgin.py index 5ab6d13..d500c07 100644 --- a/kupfer/plugin/pidgin.py +++ b/kupfer/plugin/pidgin.py @@ -22,6 +22,7 @@ __description__ = _("Access to Pidgin Contacts") __version__ = "0.1" __author__ = ("Chmouel Boudjnah , " "Ulrik Sverdrup ") +__kupfer_plugin_category__ = plugin_support.CATEGORY_IM __kupfer_settings__ = plugin_support.PluginSettings( { "key" : "show_offline", diff --git a/kupfer/plugin/rhythmbox.py b/kupfer/plugin/rhythmbox.py index 33b76a6..c547d21 100644 --- a/kupfer/plugin/rhythmbox.py +++ b/kupfer/plugin/rhythmbox.py @@ -15,7 +15,7 @@ __kupfer_sources__ = ("RhythmboxSource", ) __description__ = _("Play and enqueue tracks and browse the music library") __version__ = "" __author__ = "Ulrik Sverdrup " - +__kupfer_plugin_category__ = plugin_support.CATEGORY_MULTIMEDIA __kupfer_settings__ = plugin_support.PluginSettings( { "key" : "toplevel_artists", diff --git a/kupfer/plugin/skype.py b/kupfer/plugin/skype.py index 53b7942..40e4ce4 100644 --- a/kupfer/plugin/skype.py +++ b/kupfer/plugin/skype.py @@ -16,6 +16,7 @@ __kupfer_actions__ = ("ChangeStatus", 'Chat', 'Call') __description__ = _("Access to Skype contacts") __version__ = "2010-01-07" __author__ = "Karol Będkowski " +__kupfer_plugin_category__ = plugin_support.CATEGORY_IM # This plugin Requires D-Bus to work plugin_support.check_dbus_connection() diff --git a/kupfer/plugin/thunderbird.py b/kupfer/plugin/thunderbird.py index f1852c4..9395149 100644 --- a/kupfer/plugin/thunderbird.py +++ b/kupfer/plugin/thunderbird.py @@ -8,7 +8,7 @@ from kupfer.objects import Leaf, Action, Source from kupfer.objects import TextLeaf, UrlLeaf, RunnableLeaf from kupfer.obj.apps import AppLeafContentMixin from kupfer.obj.helplib import FilesystemWatchMixin -from kupfer import utils, icons +from kupfer import utils, icons, plugin_support from kupfer.obj.grouping import ToplevelGroupingSource from kupfer.obj.contacts import EMAIL_KEY, ContactLeaf, EmailContact, email_from_leaf @@ -20,6 +20,7 @@ __kupfer_actions__ = ("NewMailAction", ) __description__ = _("Thunderbird/Icedove Contacts and Actions") __version__ = "2009-12-13" __author__ = "Karol Będkowski " +__kupfer_plugin_category__ = plugin_support.CATEGORY_EMAIL diff --git a/kupfer/plugin_support.py b/kupfer/plugin_support.py index 794f811..81a5771 100644 --- a/kupfer/plugin_support.py +++ b/kupfer/plugin_support.py @@ -1,6 +1,14 @@ from kupfer import pretty from kupfer.core import settings + +CATEGORY_GENERIC = _("Generic") +CATEGORY_WEB_BROWSERS = _("Web browsers") +CATEGORY_IM = _("Instant messaging") +CATEGORY_EMAIL = _("Email clients") +CATEGORY_MULTIMEDIA = _("Multimedia") +CATEGORY_APP_SPECIFIC = _("Application specific") + SETTING_PREFER_CATALOG = { "key" : "kupfer_toplevel", "label": _("Include in top level"), diff --git a/kupfer/ui/preferences.py b/kupfer/ui/preferences.py index 5c1718c..4e97c63 100644 --- a/kupfer/ui/preferences.py +++ b/kupfer/ui/preferences.py @@ -20,7 +20,7 @@ class PreferencesWindowController (pretty.OutputMixin): builder = gtk.Builder() builder.set_translation_domain(version.PACKAGE_NAME) ui_file = config.get_data_file("preferences.ui") - + self._current_plugin_id = None if ui_file: builder.add_from_file(ui_file) else: @@ -55,20 +55,22 @@ class PreferencesWindowController (pretty.OutputMixin): {"key": "enabled", "type": bool }, {"key": "icon-name", "type": str }, {"key": "markup", "type": str }, + {"key": "category", "type": bool }, ] # setup plugin list table column_types = [c["type"] for c in columns] self.columns = [c["key"] for c in columns] - self.store = gtk.ListStore(*column_types) + self.store = gtk.TreeStore(*column_types) self.table = gtk.TreeView(self.store) self.table.set_headers_visible(False) self.table.set_property("enable-search", False) self.table.set_rules_hint(True) self.table.connect("cursor-changed", self.plugin_table_cursor_changed) self.table.get_selection().set_mode(gtk.SELECTION_BROWSE) + self.table.set_level_indentation(-30) checkcell = gtk.CellRendererToggle() - checkcol = gtk.TreeViewColumn("item", checkcell) + checkcol = gtk.TreeViewColumn("item", checkcell, visible=4) checkcol.add_attribute(checkcell, "active", self.columns.index("enabled")) checkcell.connect("toggled", self.on_checkplugin_toggled) @@ -121,6 +123,8 @@ class PreferencesWindowController (pretty.OutputMixin): self.dirlist_parent.add(self.dir_table) self.read_directory_settings() + gtk.link_button_set_uri_hook(self.link_button_uri_hook) + def read_directory_settings(self): setctl = settings.GetSettingsController() dirs = setctl.get_directories() @@ -226,16 +230,18 @@ class PreferencesWindowController (pretty.OutputMixin): def on_closebutton_clicked(self, widget): self.hide() - def _refresh_plugin_list(self, us_filter=None): + def _refresh_plugin_list(self, us_filter=None, reselect_plugin=True): "List plugins that pass text filter @us_filter or list all if None" self.store.clear() setctl = settings.GetSettingsController() - if us_filter: + if us_filter and reselect_plugin: self.plugin_list_timer.set_ms(300, self._show_focus_topmost_plugin) else: self.plugin_list_timer.invalidate() + plugins_to_show = {} + for info in self.plugin_info: plugin_id = info["name"] if setctl.get_plugin_is_hidden(plugin_id): @@ -245,15 +251,41 @@ class PreferencesWindowController (pretty.OutputMixin): folded_name = kupferstring.tofolded(name) desc = info["description"] text = u"%s" % name + categories = info['category'] + + if isinstance(categories, list): + # first category is main plugin category + main_category = categories[0] + else: + main_category = categories + categories = [categories] if us_filter: name_score = relevance.score(name, us_filter) fold_name_score = relevance.score(folded_name, us_filter) desc_score = relevance.score(desc, us_filter) - if not name_score and not fold_name_score and desc_score < 0.9: + category_score = max(relevance.score(category, us_filter) + for category in categories) + if not name_score and not fold_name_score and desc_score < 0.9 \ + and category_score < 0.9: continue - self.store.append((plugin_id, enabled, "kupfer-object", text)) + cat_list = plugins_to_show.get(main_category) + if not cat_list: + cat_list = [] + plugins_to_show[main_category] = cat_list + cat_list.append((plugin_id, enabled, text)) + + for category, plugins in sorted(plugins_to_show.iteritems()): + cat_item = self.store.append(None) + self.store.set(cat_item, 0, None, 1, "kupfer-category", + 3, "%s" % category, 4, False) + for plugin_id, enabled, text in plugins: + child = self.store.append(cat_item) + self.store.set(child, 0, plugin_id, 1, enabled, + 2, "kupfer-object", 3, text, 4, True) + + self.table.expand_all() def _show_focus_topmost_plugin(self): try: @@ -283,11 +315,13 @@ class PreferencesWindowController (pretty.OutputMixin): """ Find the tree path of plugin @id_ """ + # set plugin status in all categories id_col = self.columns.index("plugin_id") - for row in self.store: - plugin_id = row[id_col] - if plugin_id == id_: - return row.path + for category in self.store: + for item in category.iterchildren(): + if item[id_col] == id_: + return item.path + item[1] = plugin_is_enabled raise ValueError("No such plugin %s" % id_) @@ -302,7 +336,13 @@ class PreferencesWindowController (pretty.OutputMixin): if not curpath: return plugin_id = self._id_for_table_path(curpath) - self.plugin_sidebar_update(plugin_id) + self._current_plugin_id = plugin_id + if plugin_id: + self.plugin_sidebar_update(plugin_id) + else: + oldch = self.plugin_about_parent.get_child() + if oldch: + self.plugin_about_parent.remove(oldch) def plugin_sidebar_update(self, plugin_id): about = gtk.VBox() @@ -337,6 +377,19 @@ class PreferencesWindowController (pretty.OutputMixin): label.set_markup(u"%s: %s" % (_("Version"), version)) label.set_selectable(True) infobox.pack_start(label, False) + # cateogires aka tags + tagsbox = gtk.HBox() + label = gtk.Label() + label.set_alignment(0, 0.5) + label.set_markup(_("Tags:")) + tagsbox.pack_start(label, False) + categories = info['category'] + if not isinstance(categories, list): + categories = [categories] + for category in categories: + lbutton = gtk.LinkButton('tag:'+category, unicode(category)) + tagsbox.pack_start(lbutton, False) + infobox.pack_start(tagsbox, False) about.pack_start(infobox, False) # Check for plugin load error @@ -557,6 +610,13 @@ class PreferencesWindowController (pretty.OutputMixin): return self.buttonremovedirectory.set_sensitive(True) + def link_button_uri_hook(self, obj, uri): + if not uri.startswith('tag:'): + return + us_filter = kupferstring.tounicode(uri[4:]).lower() + self.entry_plugins_filter.set_text(us_filter) + self._refresh_plugin_list(us_filter, False) + def show(self): self.window.present() def show_focus_plugin(self, plugin_id):