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 | |
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.
-rw-r--r-- | kberylsettings/__init__.py | 3 | ||||
-rw-r--r-- | kberylsettings/about.py | 11 | ||||
-rw-r--r-- | kberylsettings/beryl.py | 75 | ||||
-rw-r--r-- | kberylsettings/contentframe.py | 158 | ||||
-rw-r--r-- | kberylsettings/lib.py | 90 | ||||
-rw-r--r-- | kberylsettings/main.py | 343 | ||||
-rw-r--r-- | kberylsettings/plugindialog.py | 69 | ||||
-rw-r--r-- | kberylsettings/pluginframe.py | 283 | ||||
-rw-r--r-- | kberylsettings/settingframe.py | 61 | ||||
-rw-r--r-- | kberylsettings/widget.py | 55 |
10 files changed, 804 insertions, 344 deletions
diff --git a/kberylsettings/__init__.py b/kberylsettings/__init__.py index e69de29..c3790ef 100644 --- a/kberylsettings/__init__.py +++ b/kberylsettings/__init__.py @@ -0,0 +1,3 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# package marker diff --git a/kberylsettings/about.py b/kberylsettings/about.py index 854f148..0940395 100644 --- a/kberylsettings/about.py +++ b/kberylsettings/about.py @@ -1,5 +1,9 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +""" kberylsettings.about -> defines KAboutData and attributes for the package. + +See the 'about' function below. +""" from kdecore import KAboutData @@ -11,11 +15,16 @@ version = '0.1' shortDescription = 'KDE Beryl Settings' licenseType = KAboutData.License_GPL_V2 copyrightStatement = '(c) 2006, %s' % (authorName, ) -homePageAddress = 'http://www.riverbankcomputing.co.uk/pykde/' +homePageAddress = \ + 'http://bugs.beryl-project.org/trac/browser/branches/kberylsettings/' aboutText = ("The Beryl Settings Manager for KDE.") def about(): + """ returns an instance of KAboutData for this application + + @return KAboutData instance + """ data = KAboutData( appName, progName, diff --git a/kberylsettings/beryl.py b/kberylsettings/beryl.py index ed0f5ae..ba8a791 100644 --- a/kberylsettings/beryl.py +++ b/kberylsettings/beryl.py @@ -1,16 +1,25 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +""" kberylsettings.beryl -> wrappers around berylsettings objects. + +""" import berylsettings -import re + from os.path import abspath, exists +from re import sub + from qt import QImage, QPixmap, QObject from kdecore import KIcon -from kberylsettings.lib import appDebug, appBase, iconCache, icon, Signals +from kberylsettings.lib import App, Signals, icon class Context(QObject): + """ Context -> wraps berylsetting.Context instances with extra + methods and properties. + + """ activePluginsSettingName = 'active_plugins' - + def __init__(self, context=None): QObject.__init__(self) if context is None: @@ -18,43 +27,67 @@ class Context(QObject): context.read() self.context = context + def getPlugins(self): + """ sorted plugin sequence - def plugins(self): + @return sequence of Plugin wrapper instances + """ seq = [Plugin(p) for p in self.context.Plugins] seq.sort(reverse=True) return iter(seq) - plugins = property(plugins) - + plugins = property(getPlugins) def plugin(self, value): + """ locates plugin by name, description, or index + + @param value plugin name, short description, or index + @return Plugin wrapper instance + """ try: value + 0 except (TypeError, ): for plugin in self.plugins: if value == plugin.ShortDesc: return plugin + if value == plugin.Name: + return plugin else: return list(self.plugins)[value] - def getActive(self): + """ sequence of active plugin names + + @return sequence of active plugin names + """ act = self.general.Setting(self.activePluginsSettingName).Value return act + [Plugin.generalName, ] def setActive(self, active): + """ sets active plugins + + @param active sequence of plugin names to set as active + @return None + """ self.general.Setting(self.activePluginsSettingName).Value = active active = property(getActive, setActive) + def getGeneral(self): + """ general plugin instance - def general(self): - return self.context.Plugin(Plugin.generalName) - - general = property(general) + @return Plugin wrapper instance + """ + return Plugin(self.context.Plugin(Plugin.generalName)) + general = property(getGeneral) def write(self): + """ saves the beryl context and messages the extension to + reload the new settings. + + @return None + """ self.emit(Signals.statusMessage, ('Saving Beryl settings....', )) self.context.write() berylsettings.send_reload() @@ -63,44 +96,40 @@ class Context(QObject): class Plugin: generalName = '_' + iconCache = {} def __init__(self, plugin): self.plugin = plugin - def __getattr__(self, value): return getattr(self.plugin, value) - def __cmp__(self, other): if self.isGeneral: return -1 return cmp(self.plugin.ShortDesc, getattr(other.plugin, 'ShortDesc', None)) - def isGeneral(self): return self.plugin.Name == self.generalName isGeneral = property(isGeneral) - def icon(self, size, loader): - if appDebug: + if App.debug: return loader.loadIcon('empty', KIcon.NoGroup, size) name = self.plugin.Name try: - pix = iconCache[(name, size)] + pix = self.iconCache[(name, size)] except (KeyError, ): - path = abspath(appBase + '/pixmaps/beryl-settings-section-%s.svg' % name) + path = abspath(App.basedir + '/pixmaps/beryl-settings-section-%s.svg' % name) if not exists(path): path = 'unknown' ico = loader.loadIcon(path, KIcon.NoGroup) img = ico.convertToImage() - pix = iconCache[(name, size)] = QPixmap() + pix = self.iconCache[(name, size)] = QPixmap() pix.convertFromImage(img.smoothScale(size, size, QImage.ScaleMin)) return pix - def nativeSettingsGroups(self): settingsMap = {} for setting in self.plugin.Settings: @@ -108,7 +137,6 @@ class Plugin: seq.append(setting) return settingsMap - def regroupSettings(self): mapping = self.nativeSettingsGroups() remap = {} @@ -119,7 +147,6 @@ class Plugin: seq.extend(values) return remap - def alternateGroup(self, typ, val, mapping): if typ in ('Int', 'Float'): return 'Numeric Values' @@ -187,7 +214,7 @@ class Setting: value = self.ShortDesc value = value.title() for pattern, repl in self.fixes: - value = re.sub(pattern, repl, value) + value = sub(pattern, repl, value) return value return settingLabelMap.get(value, value) label = property(label) @@ -205,5 +232,3 @@ class Setting: (' Svg', ' SVG'), (' Vblank', ' VBlank'), ] - - diff --git a/kberylsettings/contentframe.py b/kberylsettings/contentframe.py new file mode 100644 index 0000000..72155b3 --- /dev/null +++ b/kberylsettings/contentframe.py @@ -0,0 +1,158 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" kberylsettings.contentframe -> defines the right side about/setting views. + +""" +from os.path import abspath + +from qt import Qt, QFrame, QLabel, QHBoxLayout, QScrollView, QVBoxLayout +from kdecore import KIcon, KIconLoader +from kdeui import KStdGuiItem, KPushButton + +from kberylsettings.lib import App, Signals, buildPart +from kberylsettings.settingframe import SettingFrame +from kberylsettings.widget import Frame, WidgetStack + + +class ContentFrame(WidgetStack): + """ ContentFrame -> stack with About page, Settings Page. + + """ + aboutPageId = 0 + settingsPageId = 1 + + def __init__(self, parent): + WidgetStack.__init__(self, parent) + self.loader = KIconLoader(self.__class__.__name__) + self.buildAboutPage() + self.buildSettingsPage() + self.buildConnections() + + def buildAboutPage(self): + """ builds the About Plugin page + + @return None + """ + self.aboutPage = Frame(self, margin=6, spacing=10) + self.infoHtml = buildPart(self.aboutPage, 'text/html', + "Type == 'Service'", True) + self.addWidget(self.aboutPage, self.aboutPageId) + + def buildSettingsPage(self): + """ builds page for displaying one or more settings + + @return None + """ + self.settingsPage = Frame(self, margin=6, spacing=10) + self.pluginHeader = QFrame(self.settingsPage) + self.pluginIconLabel = QLabel(self.pluginHeader) + self.pluginNameLabel = QLabel(self.pluginHeader) + layout = QHBoxLayout(self.pluginHeader) + layout.addWidget(self.pluginIconLabel) + layout.addWidget(self.pluginNameLabel, 100) + + self.settingsMain = QFrame(self) + self.settingsMain.settingsWidgets = [] + layout = QVBoxLayout(self.settingsMain) + + self.settingsScroller = ContentScroll(self.settingsPage, self.settingsMain) + if not App.debug: + self.settingsScroller.setFrameShape(Frame.NoFrame) + self.settingsFooter = QFrame(self.settingsPage) + layout = QHBoxLayout(self.settingsFooter) + + def contentButton(name): + gui = getattr(KStdGuiItem, name)() + button = KPushButton(gui.iconSet(), gui.text(), self.settingsFooter) + layout.addWidget(button) + return button + + self.helpButton = contentButton('help') + self.defaultsButton = contentButton('defaults') + layout.addStretch(100) + self.applyButton = contentButton('apply') + self.resetButton = contentButton('reset') + self.addWidget(self.settingsPage, self.settingsPageId) + + def buildConnections(self): + """ build the connections for this instance + + @return None + """ + self.connect(self.helpButton, Signals.clicked, self.settingHelp) + self.connect(self.defaultsButton, Signals.clicked, self.settingDefaults) + self.connect(self.applyButton, Signals.clicked, self.settingApply) + + def showAbout(self, plugin): + """ displays the About Plugin page with information from the plugin + + @param plugin berylsettings Plugin instance + @return None + """ + logofile = 'file://%s' % (abspath(App.basedir + '/html/beryl-manager.png'), ) + htmlsrc = open(abspath(App.basedir + '/html/plugin.html')).read() + if plugin is None: + pluginname = 'Beryl Settings' + plugindesc = 'Beryl Settings - Get Your Effects On!' + else: + pluginname = plugin.ShortDesc + plugindesc = plugin.LongDesc + self.infoHtml.begin() + self.infoHtml.write(htmlsrc % locals()) + self.infoHtml.end() + self.raiseWidget(self.aboutPageId) + + def showSettings(self, plugin, arg): + """ displays the settings page with individual setting frames + + @param plugin berylsettings Plugin instance + @param arg setting name or setting section name + @return None + """ + self.settingsMain.hide() + for widget in self.settingsMain.settingsWidgets: + widget.close() + layout = self.settingsMain.layout() + layout.deleteAllItems() + if arg in plugin.settings: + settings = plugin.settings[arg] + extra = ' - %s' % (arg, ) + else: + settings = [arg, ] + extra = '' + ico = plugin.icon(KIcon.SizeLarge, self.loader) + self.pluginIconLabel.setPixmap(ico) + self.pluginNameLabel.setText('<b>%s%s</b>' % (plugin.ShortDesc, extra)) + for setting in settings: + frame = SettingFrame(self.settingsMain, setting) + self.settingsMain.settingsWidgets.append(frame) + layout.addWidget(frame, 0, Qt.AlignTop) + frame.show() + layout.addStretch(100) + self.settingsMain.show() + self.raiseWidget(self.settingsPageId) + + def settingHelp(self): + """ not implemented + + """ + + def settingDefaults(self): + """ not implemented + + """ + + def settingApply(self): + """ not implemented + + """ + + +class ContentScroll(QScrollView): + """ ContentScroll -> a scroll view fitted to a single child + + """ + def __init__(self, parent, child): + QScrollView.__init__(self, parent) + self.addChild(child) + self.setResizePolicy(QScrollView.AutoOneFit) diff --git a/kberylsettings/lib.py b/kberylsettings/lib.py index 5f2e484..8a2d795 100644 --- a/kberylsettings/lib.py +++ b/kberylsettings/lib.py @@ -1,24 +1,37 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +""" kberylsettings.lib -> library classes, functions, and attributes. + +""" from os import environ from os.path import abspath, dirname -from qt import SIGNAL, PYSIGNAL, QPixmap, QImage -from qt import QSizePolicy +from qt import PYSIGNAL, SIGNAL, SLOT, QPixmap, QImage from kdecore import KGlobal, KIcon, KShortcut, i18n from kdeui import KAction, KStdAction from kio import KTrader -from khtml import KHTMLPart # without this, the part isn't created correctly. :( +from khtml import KHTMLPart # without this, the KHTMLParts aren't created. from kparts import createReadOnlyPart, createReadWritePart -appDebug = environ.get('DEBUG', False) -appBase = abspath(dirname(__file__)) +## +# a cache for already-created icons iconCache = {} +class App: + """ class for application-wide settings + + """ + debug = environ.get('DEBUG') + basedir = abspath(dirname(__file__)) + + class Signals: + """ class with SIGNAL and PYSIGNAL attributes + + """ viewModeChanged = PYSIGNAL('viewModeChanged') iconSizeChanged = PYSIGNAL('iconSizeChanged') berylContextChanged = PYSIGNAL('berylContextChanged') @@ -32,15 +45,34 @@ class Signals: itemSelected = SIGNAL('selectionChanged(QListViewItem *)') okClicked = SIGNAL('okClicked()') activated = SIGNAL('activated()') + textChanged = SIGNAL('textChanged(const QString&)') contextMenuRequest = \ SIGNAL('contextMenuRequested(QListViewItem*,const QPoint&,int)') -def minSizePolicy(): - return QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) +class Slots: + """ class with SLOT attributes + + """ + close = SLOT('close()') def icon(name, group=KIcon.NoGroup, size=KIcon.SizeSmall): + """ loads pixmap by name + + This function could return the icon directly from the loadIcon + call, but that method (for some reason) doesn't apply any icon + effects. + + @param name icon name + @param group KIcon group + @param size KIcon size + @return icon as QPixmap instance + """ + try: + return iconCache[(name, size)] + except (KeyError, ): + pass ico = KGlobal.instance().iconLoader().loadIcon(name, group) img = ico.convertToImage() pix = iconCache[(name, size)] = QPixmap() @@ -49,11 +81,29 @@ def icon(name, group=KIcon.NoGroup, size=KIcon.SizeSmall): def iconSet(name, group=KIcon.NoGroup, size=KIcon.SizeSmall): + """ load icon set by name + + @param name icon set name + @param group KIcon group + @param size KIcon size + @return icon as QIconSet instance + """ return KGlobal.instance().iconLoader().loadIconSet(name, group, size) -def action(name, label, icon, accel, tip, collection, pluggable): - obj = KAction(collection, name) +def action(text, label, icon, accel, tip, collection, pluggable): + """ creates and configures a KAction instance + + @param text display value for action + @param label value associated with action + @param icon pixmap for action + @param accel constructor parameter for KAccel + @param tip tooltip text for actin + @param collection KActionCollection instance + @param pluggable any object with plug method + @return KAction instance + """ + obj = KAction(text) obj.setShortcut(KShortcut(accel)) obj.setIconSet(iconSet(icon)) obj.setIcon(icon) @@ -66,14 +116,32 @@ def action(name, label, icon, accel, tip, collection, pluggable): def stdAction(parent, name, slot, collection, pluggable): + """ creates a named KStdAction instance + + @param parent receiver of action + @param name attribute of KStdAction class + @param slot slot for KStdAction instance + @param collection KActionCollection instance + @param pluggable any object with plug method + @return KStdAction instance + """ typ = getattr(KStdAction, name) obj = typ(parent, slot, collection) obj.plug(pluggable) return obj -def buildPart(parent, query, constraint, writable=False): - offers = KTrader.self().query(query, constraint) +def buildPart(parent, servicetype, constraint, writable=False): + """ build a KDE part + + @param parent parent object of created part + @param servicetype mime type as string, or other service name + @param constraint value to limit KTrader query + @keyparam writable=False if True, creates read-write part + @return KParts.ReadOnlyPart or KParts.ReadWritePart instance + """ + offers = KTrader.self().query(servicetype, constraint) + part = None for ptr in offers: if writable: builder = createReadWritePart diff --git a/kberylsettings/main.py b/kberylsettings/main.py index 1d26493..4b928ce 100644 --- a/kberylsettings/main.py +++ b/kberylsettings/main.py @@ -1,23 +1,27 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +""" kberylsettings.main -> defines KBerylSettings main window. + +""" from sys import argv -from os.path import abspath -from qt import Qt, QFrame, QWidget, QHBoxLayout, QLabel, SLOT, QScrollView -from kdecore import KCmdLineArgs, KApplication, KIconLoader, KWin, i18n, KIcon, KGlobal -from kdeui import KMainWindow, KStdGuiItem, KLineEdit, KPushButton +from qt import Qt, QWidget, QHBoxLayout, QLabel +from kdecore import KApplication, KCmdLineArgs, KIcon, KGlobal, KWin, i18n +from kdeui import KMainWindow, KStdGuiItem, KLineEdit from kberylsettings.about import about from kberylsettings.beryl import Context -from kberylsettings.lib import action, stdAction, Signals, buildPart, minSizePolicy -from kberylsettings.lib import appDebug, appBase, icon +from kberylsettings.contentframe import ContentFrame +from kberylsettings.lib import Signals, Slots, action, stdAction, icon from kberylsettings.plugindialog import PluginDialog from kberylsettings.pluginframe import PluginFrame -from kberylsettings.settingframe import SettingFrame from kberylsettings.widget import Frame, Popup, SmallPushButton, Splitter class KBerylSetttings(KMainWindow): + """ The main window. + + """ viewMode = 0 iconSize = 16 @@ -26,58 +30,101 @@ class KBerylSetttings(KMainWindow): self.buildWidgets() self.buildMenus() self.buildConnections() - self.buildContentFrame() self.buildFinal() - def buildWidgets(self): - self.loader = KIconLoader(self.__class__.__name__) + """ builds widgets on this instance + + @return None + """ + self.loader = KGlobal.iconLoader() self.mainSplitter = Splitter(self, Qt.Horizontal) self.leftFrame = Frame(self.mainSplitter) self.rightFrame = Frame(self.mainSplitter) self.searchWidget = search = QWidget(self.leftFrame) searchLayout = QHBoxLayout(search, 6, 6) searchLayout.setAutoAdd(True) - clear = KStdGuiItem.clear() self.clearSearch = SmallPushButton(clear.iconSet(), '', search) self.labelSearch = QLabel(i18n('Search: '), search) self.inputSearch = KLineEdit(search) self.pluginList = PluginFrame(self.leftFrame) self.setCentralWidget(self.mainSplitter) + self.contentFrame = ContentFrame(self.rightFrame) statusBar = self.statusBar() + def buildMenus(self): + """ builds the menus for this instance - def showMessage(self, text): - self.statusBar().message(text, 3000) - + @return None + """ + menu = self.menuBar() + menu.insertItem(i18n('&File'), self.fileMenu()) + menu.insertItem(i18n('&View'), self.viewMenu()) + menu.insertItem(i18n('&Settings'), self.settingsMenu()) + menu.insertItem(i18n('&Help'), self.helpMenu()) def buildConnections(self): + """ builds the connections for this instance + + @return None + """ connect = self.connect - connect(self, Signals.viewModeChanged, self.setViewMode) - connect(self, Signals.iconSizeChanged, self.setIconSize) - connect(self.pluginList, Signals.showSettings, self.showPluginHeader) - connect(self.pluginList, Signals.showSettings, self.showPluginSettings) + connect(self, Signals.viewModeChanged, self.onMode) + connect(self, Signals.iconSizeChanged, self.onIconSize) + connect(self, Signals.pluginAbout, self.contentFrame.showAbout) + connect(self.pluginList, Signals.showSettings, self.contentFrame.showSettings) + connect(self.inputSearch, Signals.textChanged, self.pluginList.showSearch) + connect(self.clearSearch, Signals.clicked, self.onClearSearch) statusBar = self.statusBar() actions = self.actionCollection() actions.setHighlightingEnabled(True) - ## broken! #connect(actions, SIGNAL('actionStatusText(const QString &)'), # self.statusBar(), SLOT('message( const QString & )')) #connect(actions, SIGNAL('clearStatusText()'), # self.statusBar(), SLOT('clear()')) + def buildFinal(self): + """ do everything else needed to create the widget - def buildMenus(self): - menu = self.menuBar() - menu.insertItem(i18n('&File'), self.fileMenu()) - menu.insertItem(i18n('&View'), self.viewMenu()) - menu.insertItem(i18n('&Settings'), self.settingsMenu()) - menu.insertItem(i18n('&Help'), self.helpMenu()) + @return None + """ + self.context = context = Context() + self.emit(Signals.berylContextChanged, (context, )) + connect = self.connect + connect(context, Signals.statusMessage, self.showMessage) + KWin.setIcons(self.winId(), + icon('configure', size=KIcon.SizeLarge), + icon('configure', size=KIcon.SizeSmall)) + config = self.config('mainwindow') + self.restoreWindowSize(config) + self.mainSplitter.setSizes([self.width()*0.35, self.width()*0.65]) + config = self.config('mainview') + self.emit(Signals.iconSizeChanged, + (config.readNumEntry('iconsize', self.iconSize), )) + self.emit(Signals.viewModeChanged, + (config.readNumEntry('viewmode', self.viewMode), )) + ## done after initial emit to prevent spurious context update + connect(self, Signals.berylContextChanged, self.onContextChanged) + self.contentFrame.showAbout(None) + + def config(self, group=None): + """ loads the general configuration object + @keyparam group=None if provided, config group set to this value + @return KConfig instance + """ + config = KGlobal.instance().config() + if group is not None: + config.setGroup(group) + return config def fileMenu(self): + """ creates a new File menu + + @return KPopupMenu instance + """ pop = Popup(self) actions = self.actionCollection() self.importAction = action('import', 'Import', '', 'Import settings', @@ -85,45 +132,36 @@ class KBerylSetttings(KMainWindow): self.exportAction = action('export', 'Export', '', 'Export current settings', 'Export profile', actions, pop) pop.insertSeparator() - self.quitAction = stdAction(self, 'quit', SLOT('close()'), - actions, pop) + self.quitAction = stdAction(self, 'quit', Slots.close, actions, pop) return pop - def viewMenu(self): + """ creates a new View menu + + @return KPopupMenu instance + """ pop = Popup(self) pop.insertItem(i18n('&Mode'), self.modeMenu()) pop.insertItem(i18n('Icon &Size'), self.iconSizeMenu()) return pop - def settingsMenu(self): + """ creates a new Settings menu + + @return KPopupMenu instance + """ pop = Popup(self) self.pluginsAction = action('plugins', 'Select Plugins...', '', 'Select plugins', 'Select plugins', self.actionCollection(), pop) - self.connect(self.pluginsAction, Signals.activated, self.selectPlugins) + self.connect(self.pluginsAction, Signals.activated, self.onSelectPlugins) return pop - - def selectPlugins(self): - self.pluginDialog = PluginDialog(self, self.context) - self.connect(self.pluginDialog, Signals.okClicked, self.updatePlugins) - self.pluginDialog.exec_loop() - - - def updatePlugins(self): - active = [n for n, on in self.pluginDialog.pluginMap.items() if on] - context = self.context - - for p in context.plugins: - self.emit(Signals.berylPluginEnabled, (p, p.Name in active)) - - context.active = active - self.emit(Signals.berylContextChanged, (context, )) - - def modeMenu(self): + """ creates a new View Mode menu + + @return KPopupMenu instance + """ pop = self.modePopup = Popup(self) ids = self.modePopupIds = {} for value, label in ((0, '&Icon View'), (1, '&Tree View')): @@ -132,171 +170,124 @@ class KBerylSetttings(KMainWindow): pop.connectItem(modeid, self, Signals.viewModeChanged) return pop - def iconSizeMenu(self): + """ creates a new View Icon Size menu + + @return KPopupMenu instance + """ pop = self.iconSizePopup = Popup(self) ids = self.iconSizePopupIds = {} - sizelabels = self.iconSizeMap() - for size, label in sizelabels: + for size, label in iconSizes(): sizeid = ids[size] = pop.insertItem(i18n(label)) pop.setItemParameter(sizeid, size) pop.connectItem(sizeid, self, Signals.iconSizeChanged) pop.setItemChecked(sizeid, True) return pop + def queryClose(self): + """ abuse the queryClose method because other close methods are goofy - def buildContentFrame(self): - self.aboutFrame = Frame(self.rightFrame, margin=6, spacing=10) - self.aboutFrame.hide() - self.aboutHtml = buildPart(self.aboutFrame, 'text/html', "Type == 'Service'", True) - self.contentFrame = Frame(self.rightFrame, margin=6, spacing=10) - self.buildContentHeader() - self.contentMain = Frame(self.contentFrame) - self.contentMain.setSizePolicy(minSizePolicy()) - self.contentScroll = QScrollView(self.contentFrame) - self.contentScroll.addChild(self.contentMain) - self.contentScroll.setResizePolicy(QScrollView.AutoOneFit) - if not appDebug: - self.contentScroll.setFrameShape(QFrame.NoFrame) - self.buildContentFooter() - - - def buildContentHeader(self): - self.contentHeader = header = QFrame(self.contentFrame) - self.contentIcon = QLabel(header) - self.contentLabel = QLabel(header) - layout = QHBoxLayout(header) - layout.addWidget(self.contentIcon) - layout.addWidget(self.contentLabel, 100) - - - def buildContentFooter(self): - self.contentFooter = QFrame(self.contentFrame) - layout = QHBoxLayout(self.contentFooter) + This method may grow in the future to prompt the user for + unsaved changes. - def contentButton(name): - gui = getattr(KStdGuiItem, name)() - button = KPushButton(gui.iconSet(), gui.text(), self.contentFooter) - layout.addWidget(button) - return button - - self.helpButton = contentButton('help') - self.defaultsButton = contentButton('defaults') - layout.addStretch(100) - self.applyButton = contentButton('apply') - self.resetButton = contentButton('reset') - - - def buildFinal(self): - self.context = context = Context() - self.emit(Signals.berylContextChanged, (context, )) - connect = self.connect - connect(context, Signals.statusMessage, self.showMessage) - KWin.setIcons(self.winId(), - icon('configure', size=KIcon.SizeLarge), - icon('configure', size=KIcon.SizeSmall)) - config = self.config('mainwindow') - self.restoreWindowSize(config) - self.mainSplitter.setSizes([self.width()*0.35, self.width()*0.65]) + @return True + """ + self.saveMainWindowSettings(self.config()) + self.saveWindowSize(self.config('mainwindow')) config = self.config('mainview') - self.emit(Signals.iconSizeChanged, - (config.readNumEntry('iconsize', self.iconSize), )) - self.emit(Signals.viewModeChanged, - (config.readNumEntry('viewmode', self.viewMode), )) - - ## done after initial emit to prevent spurious context update - connect(self, Signals.berylContextChanged, self.settingsChanged) - self.showAboutPlugin(None) + config.writeEntry('iconsize', self.iconSize) + config.writeEntry('viewmode', self.viewMode) + return True + def onClearSearch(self): + """ clears the search input, emits signal to set view mode - def config(self, group=None): - config = KGlobal.instance().config() - if group is not None: - config.setGroup(group) - return config + @return None + """ + self.inputSearch.clear() + self.emit(Signals.viewModeChanged, (self.viewMode, )) + def onContextChanged(self): + """ writes the beryl context - def setViewMode(self, value): - self.viewMode = value - for menuid in self.iconSizePopupIds.values(): - self.iconSizePopup.setItemEnabled(menuid, not value) - for mode, menuid in self.modePopupIds.items(): - self.modePopup.setItemChecked(menuid, mode==value) + @return None + """ + self.context.write() + def onIconSize(self, value): + """ changes the View Icon Size menu - def setIconSize(self, value): + @param value new icon size + @return None + """ self.iconSize = value for size, menuid in self.iconSizePopupIds.items(): self.iconSizePopup.setItemChecked(menuid, size==value) + def onPluginDialogOk(self): + """ sets current context active plugins - def queryClose(self): - self.saveMainWindowSettings(self.config()) - self.saveWindowSize(self.config('mainwindow')) - config = self.config('mainview') - config.writeEntry('iconsize', self.iconSize) - config.writeEntry('viewmode', self.viewMode) - return True - - - def showPluginHeader(self, plugin, section): - self.aboutFrame.hide() - ico = plugin.icon(KIcon.SizeLarge, self.loader) - self.contentIcon.setPixmap(ico) - self.contentLabel.setText('<b>%s</b>' % (plugin.ShortDesc, )) - self.contentFrame.show() - + @return None + """ + items = self.pluginDialog.pluginMap.items() + active = [name for name, enabled in items if enabled] + context = self.context + for p in context.plugins: + self.emit(Signals.berylPluginEnabled, (p, p.Name in active)) + context.active = active + self.emit(Signals.berylContextChanged, (context, )) - def showPluginSettings(self, plugin, section): - parent = self.contentMain - parent.hide() - for widget in parent.queryList('QFrame'): - widget.close() + def onSelectPlugins(self): + """ shows dialog to select/deselect active plugins - settings = plugin.settings[section] - for setting in settings: - frame = SettingFrame(parent, setting) - parent.show() + @return None + """ + self.pluginDialog = PluginDialog(self, self.context) + self.connect(self.pluginDialog, Signals.okClicked, + self.onPluginDialogOk) + self.pluginDialog.exec_loop() - def settingsChanged(self): - self.context.write() + def onMode(self, value): + """ changes the View Mode menu, enables/disables Icon Size menu items + @param value new view mode + @return None + """ + self.viewMode = value + for menuid in self.iconSizePopupIds.values(): + self.iconSizePopup.setItemEnabled(menuid, not value) + for mode, menuid in self.modePopupIds.items(): + self.modePopup.setItemChecked(menuid, mode==value) - def showAboutPlugin(self, plugin): - self.contentFrame.hide() - for widget in self.aboutFrame.queryList('QWidget'): - widget.close() - logofile = 'file://%s' % (abspath(appBase + '/html/beryl-manager.png'), ) - htmlsrc = open(abspath(appBase + '/html/plugin.html')).read() - if plugin is None: - pluginname = 'Beryl Settings' - plugindesc = 'Beryl Settings - Get Your Effects On!' - else: - pluginname = plugin.ShortDesc - plugindesc = plugin.LongDesc - self.aboutHtml.begin() - self.aboutHtml.write(htmlsrc % locals()) - self.aboutHtml.end() - self.aboutFrame.show() + def showMessage(self, text): + self.statusBar().message(text, 3000) - def iconSizeMap(self): - okay = lambda x:x.startswith('Size') and x != 'SizeSmallMedium' - labels = [a for a in dir(KIcon) if okay(a)] - sizes = [getattr(KIcon, a) for a in labels] - labels = [l.replace('Size', '') for l in labels] - sizelabels = zip(sizes, labels) - sizelabels.sort() - return sizelabels +def iconSizes(): + """ creates list of KIcon sizes and their names + @return sequence of two-tuples in the form of (size, name) + """ + def sizeOk(attr): + return attr.startswith('Size') and attr != 'SizeSmallMedium' + names = [a for a in dir(KIcon) if sizeOk(a)] + sizes = [getattr(KIcon, a) for a in names] + names = [l.replace('Size', '') for l in names] + sizenames = zip(sizes, names) + sizenames.sort() + return sizenames def main(): + """ runs the KBerylSettings window with a KApplication + + @return None + """ aboutdata = about() KCmdLineArgs.init(argv, aboutdata) app = KApplication() - mainWindow = KBerylSetttings() - mainWindow.show() + obj = KBerylSetttings() + obj.show() app.exec_loop() diff --git a/kberylsettings/plugindialog.py b/kberylsettings/plugindialog.py index 5c395a2..dc97831 100644 --- a/kberylsettings/plugindialog.py +++ b/kberylsettings/plugindialog.py @@ -1,8 +1,11 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +""" kberylsettings.plugindialog -> defines a dialog box for selecting plugins. + +""" from qt import QCheckListItem, QLabel from kdecore import i18n -from kdeui import KDialogBase, KListView +from kdeui import KDialogBase, KListView, KMessageBox from kberylsettings.lib import Signals @@ -51,7 +54,7 @@ class PluginList(KListView): """ height = count * self.fontMetrics().height() self.setMinimumHeight(height * 0.5) - width = maxlen * self.fontMetrics().maxWidth() * 0.25 + width = maxlen * self.fontMetrics().maxWidth() * 0.2 self.setMinimumWidth(width) @@ -69,13 +72,69 @@ class PluginDialog(KDialogBase): self.connect(self.listView, Signals.itemClicked, self.changePlugin) self.pluginMap = self.listView.addPlugins(context, parent.loader) - def changePlugin(self, item): + """ handle a possible change to the plugins checkbox + + @param item QCheckListItem instance + @return None + """ if not item: return - state = item.state() plugin = self.context.plugin(item.text(0)) + state = item.state() if state == item.On: self.pluginMap[plugin.Name] = 1 + self.satisfy(plugin) elif state == item.Off: - self.pluginMap[plugin.Name] = 0 + remaining = self.needs(plugin) + if remaining: + item.setState(item.On) + text = 'Cannot remove plugin "%s" required by %s.' + need = ['"%s"' % r.ShortDesc for r in remaining] + text %= (plugin.ShortDesc, str.join(', ', need)) + KMessageBox.sorry(self, text) + else: + self.pluginMap[plugin.Name] = 0 + + def satisfy(self, plugin): + """ enable requirement for plugin if necessary + + @param plugin berylsettings Plugin instance + @return None + """ + for requirement in plugin.Requires: + for p in self.context.plugins: + if requirement in p.Provides: + if not self.pluginMap[p.Name]: + self.pluginMap[p.Name] = 1 + item = self.listView.findItem(p.ShortDesc, 0) + if item: + item.setState(item.On) + for req in p.Requires: + self.satisfy(p) + + def needs(self, plugin): + """ check that all requirements for plugin are met + + @param plugin berylsettings Plugin instance + @return sequence of required plugins + """ + pending = self.pending(plugin) + allProvided = [] + for p in pending: + allProvided.extend(p.Provides) + notMet = [] + for p in pending: + for req in p.Requires: + if req not in allProvided: + notMet.append(p) + return notMet + + def pending(self, exclude): + """ generates a sequence of enabled plugins, based on current selections + + @param exclude plugin to exclude from returned list + @return list of berylsetting Plugin instances + """ + names = [name for name, enabled in self.pluginMap.items() if enabled] + return [self.context.plugin(n) for n in names if n != exclude.Name] 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] diff --git a/kberylsettings/settingframe.py b/kberylsettings/settingframe.py index c9673c4..7ead0a3 100644 --- a/kberylsettings/settingframe.py +++ b/kberylsettings/settingframe.py @@ -1,15 +1,26 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +""" kberylsettings.settingframe -> defines SettingFrame for displaying +berylsettings.Setting instances. + +""" +from qt import Qt, QFrame, QHBoxLayout, QSizePolicy, QLabel, QVBoxLayout, \ + QCheckBox, QColor, qRgba, QToolTip -from qt import QFrame, QHBoxLayout, QSizePolicy, QLabel, Qt, QVBoxLayout, QCheckBox, QColor, qRgba, QToolTip from kdecore import KShortcut, KKey -from kdeui import KIntNumInput, KDoubleNumInput, KComboBox, KLineEdit, KKeyButton, KColorButton +from kdeui import KIntNumInput, KDoubleNumInput, KComboBox, KLineEdit, \ + KKeyButton, KColorButton -from kberylsettings.lib import appDebug, iconSet, Signals +from kberylsettings.lib import App, Signals, iconSet from kberylsettings.widget import SmallPushButton def numberInput(cls): + """ returns closure to display indicated class + + @param cls KIntNumInput or KDoubleNumInput + @return function for displaying cls + """ def builder(self): layout = QVBoxLayout() try: @@ -27,18 +38,25 @@ def numberInput(cls): class SettingFrame(QFrame): + """ SettingFrame -> displays editing widgets for a single Setting instance. + + """ def __init__(self, parent, setting): QFrame.__init__(self, parent) layout = QHBoxLayout(self, 3, 3) self.setting = setting - if appDebug: + if App.debug: self.setFrameStyle(QFrame.Box|QFrame.Plain) - self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) + self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, + QSizePolicy.Minimum)) self.buildWidgets() def buildWidgets(self): + """ builds widgets on this instance + + @return None + """ layout = self.layout() - print '*****', self.setting.label self.label = QLabel(self.setting.label, self) self.infoButton = SmallPushButton(iconSet('help'), '', self) tooltip = QToolTip.add(self.infoButton, self.setting.LongDesc or '') @@ -50,8 +68,14 @@ class SettingFrame(QFrame): nextlayout = builder() layout.addLayout(nextlayout, 100) + buildInt = numberInput(KIntNumInput) + buildFloat = numberInput(KDoubleNumInput) def buildBool(self): + """ builds widget for a boolean setting + + @return layout instance + """ layout = QHBoxLayout() self.cb = QCheckBox(self) self.cb.setChecked(self.setting.Value) @@ -59,10 +83,11 @@ class SettingFrame(QFrame): layout.addWidget(self.label, 100) return layout - buildInt = numberInput(KIntNumInput) - buildFloat = numberInput(KDoubleNumInput) - def buildString(self): + """ builds widget for a string setting + + @return layout instance + """ layout = QVBoxLayout() try: s = self.setting.Value @@ -84,6 +109,10 @@ class SettingFrame(QFrame): return layout def buildColor(self): + """ builds widget for a color setting + + @return layout instance + """ layout = QHBoxLayout() self.color = QColor(qRgba(*[a/256 for a in self.setting.Value])) self.colorButton = KColorButton(self) @@ -93,6 +122,10 @@ class SettingFrame(QFrame): return layout def buildUnknown(self): + """ builds widget for an unknown setting + + @return layout instance + """ layout = QHBoxLayout() text = '%s (Unknown Type %s)' % (self.setting.ShortDesc, self.setting.Type, ) self.label.setText(text) @@ -109,6 +142,10 @@ class SettingFrame(QFrame): ## def buildBinding(self): + """ builds widget for a binding setting + + @return layout instance + """ layout = QHBoxLayout() self.line = KLineEdit('%s || %s' % (self.setting.Value, self.setting.Restrictions, ), self) self.keybutton = KKeyButton(self) @@ -121,8 +158,12 @@ class SettingFrame(QFrame): def toKKey(v): + """ creates a KKey instance from a key setting + + @param v key setting as string + @return KKey instance + """ v = v.replace("Control", "ctrl") v = v.replace('<', '') v = v.replace('>', '+') return KKey(v) - diff --git a/kberylsettings/widget.py b/kberylsettings/widget.py index 5b2dc29..246c29d 100644 --- a/kberylsettings/widget.py +++ b/kberylsettings/widget.py @@ -1,10 +1,17 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -from qt import Qt, QFrame, QSizePolicy, QSplitter, QVBoxLayout -from kdeui import KPopupMenu, KPushButton +""" kberylsettings.widget -> various common widgets. + +""" +from qt import Qt, QFrame, QListViewItem, QListViewItemIterator, QSizePolicy, \ + QSplitter, QVBoxLayout, QWidgetStack +from kdeui import KListView, KPopupMenu, KPushButton class Frame(QFrame): + """ Frame -> QFrame with QVBoxLayout + + """ def __init__(self, parent, margin=0, spacing=-1): QFrame.__init__(self, parent) layout = QVBoxLayout(self, margin, spacing) @@ -13,21 +20,65 @@ class Frame(QFrame): class Popup(KPopupMenu): + """ Popup -> KPopupMenu always set to checkable + + """ def __init__(self, parent): KPopupMenu.__init__(self, parent) self.setCheckable(True) class Splitter(QSplitter): + """ Splitter -> QSplitter always set to opaque resize + + """ def __init__(self, parent, style): QSplitter.__init__(self, style, parent) self.setOpaqueResize(True) class SmallPushButton(KPushButton): + """ SmallPushButton -> KPushButton with fixed sizes + + """ def __init__(self, icon, text, parent): KPushButton.__init__(self, icon, text, parent) self.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) +class ValueListViewItem(QListViewItem): + """ ValueListViewItem -> QListViewItem with extra 'value' attribute + + """ + def __init__(self, parent, text, value=None): + QListViewItem.__init__(self, parent, text) + self.value = value + + +class ListView(KListView): + """ ListView -> KListView that is directly iterable + """ + def __init__(self, parent): + KListView.__init__(self, parent) + + def __iter__(self): + """ iterate over QListView items + + """ + it = QListViewItemIterator(self) + item = it.current() + while item: + yield item + it += 1 + item = it.current() + + +class WidgetStack(QWidgetStack): + """ WidgetStack -> QWidgetStack with QVBoxLayout + + """ + def __init__(self, parent): + QWidgetStack.__init__(self, parent) + layout = QVBoxLayout(self) + layout.setAutoAdd(True) |