diff options
author | natural <natural> | 2006-12-17 10:06:18 +0000 |
---|---|---|
committer | natural <natural> | 2006-12-17 10:06:18 +0000 |
commit | 99b44818d60794aae11dca5f67722ab32c98f137 (patch) | |
tree | 8e54863077d35d0cbb88925c3fd012827d328a80 /kberylsettings/pluginframe.py | |
parent | fcfa23f8e1b16bc68329c9e9aa3cb31d906ee572 (diff) | |
download | kberylsettings-99b44818d60794aae11dca5f67722ab32c98f137.tar.gz kberylsettings-99b44818d60794aae11dca5f67722ab32c98f137.tar.bz2 |
Implemented search -- search for plugin settings by keyword.
Refactored views and content frames.
Many docstrings.
Diffstat (limited to 'kberylsettings/pluginframe.py')
-rw-r--r-- | kberylsettings/pluginframe.py | 283 |
1 files changed, 169 insertions, 114 deletions
diff --git a/kberylsettings/pluginframe.py b/kberylsettings/pluginframe.py index 306a883..e3116e8 100644 --- a/kberylsettings/pluginframe.py +++ b/kberylsettings/pluginframe.py @@ -1,83 +1,172 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -from qt import Qt, QFrame, QListViewItem, QListViewItemIterator, QVBoxLayout +""" kberylsettings.pluginframe -> defines the left side plugin views. +and search view. + +""" +from re import sub + +from qt import QLabel, QListViewItem from kdecore import KIconLoader, i18n -from kdeui import KListView from kberylsettings.beryl import Setting from kberylsettings.lib import Signals, icon -from kberylsettings.widget import Popup +from kberylsettings.widget import Frame, ListView, ValueListViewItem, \ + WidgetStack -class PluginFrame(QFrame): - """ PluginFrame -> encapsulates an icon ListView and a tree - ListView and swaps between them. +class PluginFrame(WidgetStack): + """ PluginFrame -> stack with Icon View, Tree View, and Search widget. """ + iconPageId, treePageId, searchPageId = range(3) + def __init__(self, parent): - QFrame.__init__(self, parent) - layout = QVBoxLayout(self) - layout.setAutoAdd(True) + WidgetStack.__init__(self, parent) + self.buildWidgets() + self.buildConnections() + + def buildWidgets(self): + """ builds widgets on this instance + + @return None + """ self.iconView = PluginIconView(self) self.treeView = PluginTreeView(self) + self.searchView = SearchView(self) + self.addWidget(self.iconView, self.iconPageId) + self.addWidget(self.treeView, self.treePageId) + self.addWidget(self.searchView, self.searchPageId) + def buildConnections(self): + """ build the connections for this instance + + @return None + """ root = self.topLevelWidget() connect = self.connect - connect(root, Signals.viewModeChanged, self.onViewMode) + connect(root, Signals.viewModeChanged, self.raiseWidget) connect(root, Signals.iconSizeChanged, self.iconView.onIconSize) - - views = (self.iconView, self.treeView) - for view in views: + connect(root, Signals.berylContextChanged, self.searchView.rebuildIndex) + connect(self.searchView, Signals.pluginAbout, root, Signals.pluginAbout) + connect(self.searchView, Signals.showSettings, Signals.showSettings) + for view in (self.iconView, self.treeView): connect(view, Signals.showSettings, Signals.showSettings) - connect(view, Signals.berylSettingChanged, root.settingsChanged) - connect(view, Signals.pluginAbout, root.showAboutPlugin) + connect(view, Signals.berylSettingChanged, root.onContextChanged) + connect(view, Signals.pluginAbout, root, Signals.pluginAbout) connect(view, Signals.statusMessage, root.showMessage) connect(root, Signals.berylContextChanged, view.onBerylContext) connect(root, Signals.berylPluginEnabled, view.enablePluginItem) - for receiver in views: - connect(view, Signals.berylPluginEnabled, - receiver.enablePluginItem) - def onViewMode(self, value): - """ user requested view mode change + def showSearch(self, value): + """ displays the search page and tickles it with the search value - @param value view mode; 0 or 1 @return None """ - items = [self.treeView, self.iconView, ] - if value: - items.reverse() + self.raiseWidget(self.searchPageId) + self.searchView.showKeywords(value) - last = items[0].selectedItem() - if last: - for item in items[1]: - item.setSelected(item.text(0) == last.text(0)) - items[0].hide() - items[1].show() - -class PluginView(KListView): - """ PluginView -> mixin for shared view functionality +class SearchView(Frame): + """ SearchView -> a frame to display found keywords and their results """ def __init__(self, parent): - KListView.__init__(self, parent) - self.addColumn('') - self.setSorting(-1) - self.header().hide() + Frame.__init__(self, parent) + self.index = {} self.loader = KIconLoader(self.__class__.__name__) - self.connect(self, Signals.contextMenuRequest, self.onContextMenu) + self.keywordLabel = QLabel(i18n('Keywords:'), self) + self.keywordsList = ListView(self) + configList(self.keywordsList) + self.resultsLabel = QLabel(i18n('Results:'), self) + self.resultsList = ListView(self) + configList(self.resultsList) + self.connect(self.keywordsList, Signals.itemSelected, self.showResults) + self.connect(self.resultsList, Signals.itemSelected, self.emitResult) + + + def rebuildIndex(self, context): + """ reconstructs the search 'index' given a berylsetting context + + This might look slow at first glance, but my machine, this + function takes less than 0.1 second. + + @param context berylsetting.Context instance + @return None + """ + index = self.index + index.clear() + for p in context.plugins: + for key in itemKeywords(p): + seq = index.setdefault(key, []) + seq.append((p, None)) + for s in p.Settings: + for key in itemKeywords(s): + seq = index.setdefault(key, []) + seq.append((p, s)) + + def showKeywords(self, text): + """ displays keywords from the index that match the given text + + @param text search value + @return None + """ + text = str(text) + if not text: + return + searchtext = text.lower() + index = self.index + parent = self.keywordsList + parent.clear() + for keyword in self.index: + if searchtext in keyword.lower(): + item = ValueListViewItem(parent, keyword, index[keyword]) - def __iter__(self): - """ iterate over QListView items + def showResults(self, item): + """ displays plugin/setting items from the selected keyword + @return None """ - it = QListViewItemIterator(self) - item = it.current() - while item: - yield item - it += 1 - item = it.current() + parent = self.resultsList + parent.clear() + cache = {} + for plugin, setting in item.value: + desc = plugin.ShortDesc + item = cache.get(plugin) + if item is None: + value = (plugin, None) + item = cache[plugin] = ValueListViewItem(parent, desc, value) + item.setPixmap(0, plugin.icon(16, self.loader)) + if setting: + desc = setting.ShortDesc + sub = cache.get((plugin, setting)) + if sub is None: + sub = cache[(plugin, setting)] = \ + ValueListViewItem(item, desc, (plugin, setting)) + item.setOpen(True) + + def emitResult(self, item): + """ emits signal to show a plugin or a setting + + @param item result list view item + @return None + """ + plugin, setting = item.value + if setting is None: + self.emit(Signals.pluginAbout, (plugin, )) + else: + self.emit(Signals.showSettings, (plugin, Setting(setting), )) + + +class PluginView(ListView): + """ PluginView -> mixin for shared view functionality + + """ + def __init__(self, parent): + ListView.__init__(self, parent) + configList(self) + self.loader = KIconLoader(self.__class__.__name__) + self.connect(self, Signals.itemSelected, self.onSelected) def addPlugins(self): """ adds list view items for every plugin in context @@ -99,7 +188,6 @@ class PluginView(KListView): if not item: item = QListViewItem(self, plugin.ShortDesc) item.setVisible(True) - ##item.setEnabled(plugin.Name in active or plugin.isGeneral) item.setVisible(plugin.Name in active) item.setPixmap(0, plugin.icon(self.iconSize, self.loader)) item.setText(0, plugin.ShortDesc) @@ -114,63 +202,14 @@ class PluginView(KListView): self.context = context self.addPlugins() - def onContextMenu(self, item, point, value): - """ display a context menu - - @param item QListViewItem instance - @param point QPoint at click - @param value ignored - @return None - """ - if not item: - return - - plugins = list(self.context.plugins) - plugin = [p for p in plugins if p.ShortDesc==item.text(0)] - if not plugin: - return - else: - plugin = plugin[0] - - pop = Popup(self) - pop.insertItem(plugin.ShortDesc) - pop.insertSeparator() - if plugin.Name in self.context.active: - menuid = pop.insertItem(i18n('&Disable')) - else: - menuid = pop.insertItem(i18n('&Enable')) - pop.setItemEnabled(menuid, not plugin.isGeneral) - pop.setItemParameter(menuid, plugins.index(plugin)) - pop.connectItem(menuid, self.enablePlugin) - pop.popup(point) - - def enablePlugin(self, index): - """ toggle the active state of a plugin - - @param index position of plugin within plugins list - @return None - """ - plugin = self.context.plugin(index) - active = self.context.active - if plugin.Name in active: - active.remove(plugin.Name) - else: - active.append(plugin.Name) - self.context.active = active - self.emit(Signals.berylPluginEnabled, (plugin, plugin.Name in active)) - self.emit(Signals.berylSettingChanged, ()) - def enablePluginItem(self, plugin, enable): """ toggle the enabled state of a plugin list view item @param index position of plugin within plugins list @return None """ - for item in self: - if item.text(0) == plugin.ShortDesc: - #item.setOpen(enable) - #item.setEnabled(enable) - item.setVisible(enable) + for item in [i for i in self if i.text(0)==plugin.ShortDesc]: + item.setVisible(enable) class PluginIconView(PluginView): @@ -181,8 +220,7 @@ class PluginIconView(PluginView): def __init__(self, parent): PluginView.__init__(self, parent) - self.connect(self, Signals.itemClicked, self.onSelected) - self.selectedPlugin = self.selectedSetting = None + self.selectedPlugin = None def onIconSize(self, size): """ update the icon size @@ -216,26 +254,19 @@ class PluginIconView(PluginView): item.setVisible(True) else: item.setVisible(False) - elif self.selectedSetting != text: - self.selectedSetting = text - plugin = self.selectedPlugin - name = str(text) - print '***', name - self.emit(Signals.showSettings, (plugin, name)) + else: + args = (self.selectedPlugin, str(text), ) + self.emit(Signals.showSettings, args) def navToSettings(self, plugin): + """ needs to be renamed and reworked + + """ self.emit(Signals.statusMessage, ('%s.navToSettings(%r)' % (self.__class__.__name__, plugin), )) self.selectedPlugin = plugin groups = plugin.settings - - for k, v in groups.items(): - print k - for a in v: - print ' ', a.ShortDesc - keys = groups.keys() keys.sort() - for key in keys: label = key #Setting.label(key) sub = self.findItem(label, 0) @@ -265,7 +296,6 @@ class PluginTreeView(PluginView): def __init__(self, parent): PluginView.__init__(self, parent) self.setRootIsDecorated(True) - self.connect(self, Signals.itemSelected, self.onSelected) def listItem(self, plugin, active): """ create an item for the plugin and sub items for its settings @@ -297,3 +327,28 @@ class PluginTreeView(PluginView): plugin = self.context.plugin(item.parent().text(0)) name = str(item.text(0)) self.emit(Signals.showSettings, (plugin, name)) + + +def configList(obj): + """ configures a ListView with a single column, no sorting, hidden + header and no horizontal scrollbar. + + @param obj KListView or QListView instance + @return None + """ + obj.addColumn('') + obj.setSorting(-1) + obj.header().hide() + obj.setHScrollBarMode(obj.AlwaysOff) + + +def itemKeywords(obj): + """ creates a list of keywords for the given berylsettings object + + @param obj berylsettings Plugin or Setting instance + @return list of keywords + """ + values = [obj.ShortDesc, obj.LongDesc, ] + \ + obj.ShortDesc.split() + \ + obj.LongDesc.split() + return [sub('\W|_', ' ', v) for v in values] |