summaryrefslogtreecommitdiff
path: root/kberylsettings
diff options
context:
space:
mode:
authornatural <natural>2006-12-28 13:30:24 +0000
committernatural <natural>2006-12-28 13:30:24 +0000
commit6353813802ba776b05241f07cb8fee9c90310c40 (patch)
treebbdb3641c28de20c9c6164748436d7411be468ff /kberylsettings
parentc8ad4394c474f9f6854904f377ab28a38172b867 (diff)
downloadkberylsettings-6353813802ba776b05241f07cb8fee9c90310c40.tar.gz
kberylsettings-6353813802ba776b05241f07cb8fee9c90310c40.tar.bz2
Support for plugin categories.
Fixed scroll view layouts. Many other bug fixes and enhancements.
Diffstat (limited to 'kberylsettings')
-rw-r--r--kberylsettings/beryl.py93
-rw-r--r--kberylsettings/contentframe.py493
-rw-r--r--kberylsettings/lib.py6
-rw-r--r--kberylsettings/main.py50
-rw-r--r--kberylsettings/plugindialog.py18
-rw-r--r--kberylsettings/pluginframe.py349
-rw-r--r--kberylsettings/widget.py46
7 files changed, 721 insertions, 334 deletions
diff --git a/kberylsettings/beryl.py b/kberylsettings/beryl.py
index 2594361..d07d89a 100644
--- a/kberylsettings/beryl.py
+++ b/kberylsettings/beryl.py
@@ -27,19 +27,24 @@ class Context(QObject):
context.Read()
self.context = context
+ def __repr__(self):
+ args = (self.__module__, self.__class__.__name__, hex(abs(id(self))))
+ return "<%s.%s instance at %s>" % args
+
def getCategories(self):
- return self.context.Categories
+ seq = [Category(c) for c in self.context.Categories]
+ seq.sort()
+ return seq
categories = property(getCategories)
-
def getPlugins(self):
""" sorted plugin sequence
@return sequence of Plugin wrapper instances
"""
seq = [Plugin(p) for p in self.context.Plugins]
- seq.sort(reverse=True)
- return iter(seq)
+ seq.sort()
+ return seq
plugins = property(getPlugins)
def plugin(self, value):
@@ -53,9 +58,9 @@ class Context(QObject):
except (TypeError, ):
for plugin in self.plugins:
if value == plugin.ShortDesc:
- return plugin
+ return Plugin(plugin)
if value == plugin.Name:
- return plugin
+ return Plugin(plugin)
else:
return list(self.plugins)[value]
@@ -102,6 +107,26 @@ class Context(QObject):
self.emit(Signals.statusMessage, ('Beryl settings reloaded.', ))
+class Category:
+ def __init__(self, category):
+ self.category = category
+
+ def __cmp__(self, other):
+ return cmp(self.ShortDesc, other.ShortDesc)
+
+ def __getattr__(self, value):
+ return getattr(self.category, value)
+
+ def icon(self, size, loader):
+ return loader.loadIcon('unknown', KIcon.NoGroup, size)
+
+ def plugins(self):
+ seq = [Plugin(p) for p in self.category.Plugins]
+ seq.sort()
+ return seq
+ plugins = property(plugins)
+
+
class Plugin:
generalName = '_'
iconCache = {}
@@ -109,16 +134,26 @@ class Plugin:
def __init__(self, plugin):
self.plugin = plugin
- def __getattr__(self, value):
- return getattr(self.plugin, value)
-
def __cmp__(self, other):
- if self.isGeneral:
+ if other is None:
return -1
if not isinstance(other, Plugin):
other = Plugin(other)
+ if self.isGeneral:
+ return -1
+ if other.isGeneral:
+ return 1
return cmp(self.plugin.ShortDesc, other.plugin.ShortDesc)
+ def __getattr__(self, value):
+ return getattr(self.plugin, value)
+
+ def __repr__(self):
+ args = (self.__module__, self.__class__.__name__,
+ self.Name,
+ hex(abs(id(self))))
+ return "<%s.%s instance name='%s' at %s>" % args
+
def isGeneral(self):
return self.plugin.Name == self.generalName
isGeneral = property(isGeneral)
@@ -175,9 +210,39 @@ class Plugin:
for seq in mapping.values():
seq.sort()
return mapping
-
settings = property(settings)
+ def groups(self):
+ groups = [Group(g) for g in self.plugin.Groups]
+ groups.sort()
+ return groups
+ groups = property(groups)
+
+
+class Group:
+ def __init__(self, group):
+ self.group = group
+
+ def __getattr__(self, value):
+ return getattr(self.group, value)
+
+ def __cmp__(self, other):
+ if not isinstance(other, Group):
+ other = Group(other)
+ return cmp(self.label, other.label)
+
+ def label(self):
+ return self.Name or self.Desc or 'Uncategorized'
+ label = property(label)
+
+ def settings(self, plugin):
+ if not isinstance(plugin, Plugin):
+ plugin = Plugin(plugin)
+ group = self.Name
+ settings = [Setting(s) for s in plugin.Settings if s.Group==group]
+ settings.sort()
+ return settings
+
class Setting:
iconNameMap = {
@@ -214,6 +279,12 @@ class Setting:
def __getattr__(self, value):
return getattr(self.setting, value)
+ def __repr__(self):
+ args = (self.__module__, self.__class__.__name__,
+ self.Name,
+ hex(abs(id(self))))
+ return "<%s.%s instance name='%s' at %s>" % args
+
def set(self, value):
self.setting.Value = value
diff --git a/kberylsettings/contentframe.py b/kberylsettings/contentframe.py
index 68e8582..c4085fe 100644
--- a/kberylsettings/contentframe.py
+++ b/kberylsettings/contentframe.py
@@ -4,98 +4,89 @@
"""
from kdecore import KIcon, i18n
-from kdeui import KMessageBox, KPassivePopup, KPushButton, \
- KSeparator, KStdGuiItem
+from kdeui import KDialog, KMessageBox, KPassivePopup, \
+ KSeparator, KStdGuiItem, KTabWidget
from qt import Qt, QFrame, QHBoxLayout, QLabel, QScrollView, QSize, \
QSizePolicy, QStringList, QToolTip, QVBoxLayout
+from kberylsettings.beryl import Setting
from kberylsettings.lib import App, Signals, buildPart, icon, iconLoader, iconSet
-from kberylsettings.widget import Frame, SmallPushButton, WidgetStack
+from kberylsettings.widget import Frame, SmallPushButton, WidgetStack, guiButton
from kberylsettings.settingwidget import settingWidget
+marginHint = KDialog.marginHint()
+spacingHint = KDialog.spacingHint()
+
+
class ContentFrame(WidgetStack):
- """ ContentFrame -> stack with About page, Settings Page.
+ """ ContentFrame -> multiple displays of plugin information
+
+ This widget stack builds and manages three types of pages:
+ 1. an 'about' page for displaying plugin information.
+
+ 2. a 'single' page for displaying a setting or a
+ sequence of settings.
+
+ 3. a 'multiple' page for displaying settings in groups
+ via a tabbed interface.
+
"""
- aboutPageId = 0
- settingsPageId = 1
-
+ aboutPageId, singlePageId, tabPageId = range(3)
+
def __init__(self, parent):
WidgetStack.__init__(self, parent)
- self.loader = iconLoader()
- self.buildAboutPage()
- self.buildSettingsPage()
- self.buildConnections()
-
- def buildAboutPage(self):
- """ builds the About Plugin page
+ self.aboutPage = aboutPage = AboutPage(self)
+ self.singlePage = singlePage = SinglePage(self)
+ self.tabPage = tabPage = TabPage(self)
+
+ addWidget = self.addWidget
+ addWidget(aboutPage, self.aboutPageId)
+ addWidget(singlePage, self.singlePageId)
+ addWidget(tabPage, self.tabPageId)
+
+ root = self.topLevelWidget()
+ connect = self.connect
+ connect(root, Signals.showAbout, self.showAboutPage)
+ connect(root, Signals.showSettings, self.showSinglePage)
+ connect(root, Signals.showGroups, self.showTabPage)
+
+ def showAboutPage(self, plugin):
+ """ displays the about page
+ @param plugin berylsettings Plugin instance
@return None
"""
- self.aboutPage = Frame(self, margin=6, spacing=10)
- self.addWidget(self.aboutPage, self.aboutPageId)
- self.infoHtml = buildPart(self.aboutPage, 'text/html',
- "Type == 'Service'", True)
-
+ self.aboutPage.showAbout(plugin)
+ self.raiseWidget(self.aboutPageId)
- def buildSettingsPage(self):
- """ builds page for displaying one or more settings
+ def showSinglePage(self, plugin, arg):
+ """ displays the page for a single type of setting
+ @param plugin berylsettings Plugin instance
@return None
"""
- self.settingsPage = page = Frame(self, 6, 10)
- self.addWidget(page, self.settingsPageId)
-
- self.pluginHeader = header = QFrame(page)
- self.pluginIconLabel = QLabel(header)
- self.pluginNameLabel = QLabel(header)
-
- headerLayout = QHBoxLayout(header)
- headerLayout.addWidget(self.pluginIconLabel, 1)
- headerLayout.addWidget(self.pluginNameLabel, 10)
-
- self.settingsMain = main = SettingsContainer(page)
- self.scrollerWrap = wrap = Frame(page)
- self.settingsScroller = scroller = ContentScroll(wrap, main)
-
- KSeparator(KSeparator.Horizontal, page)
- self.settingsFooter = footer = QFrame(page)
- footerLayout = QHBoxLayout(footer)
-
- def contentButton(name):
- gui = getattr(KStdGuiItem, name)()
- button = KPushButton(gui.iconSet(), gui.text(), footer)
- footerLayout.addWidget(button)
- return button
-
- self.helpButton = contentButton('help')
- self.defaultsButton = contentButton('defaults')
- footerLayout.addStretch(2)
- self.applyButton = applyButton = contentButton('apply')
- applyButton.setEnabled(False)
- self.resetButton = resetButton = contentButton('reset')
- resetButton.setEnabled(False)
-
- def buildConnections(self):
- """ build the connections for this instance
+ self.singlePage.showSettings(plugin, arg)
+ self.raiseWidget(self.singlePageId)
+ def showTabPage(self, plugin):
+ """ displays the page for groups of settings
+
+ @param plugin berylsettings Plugin instance
@return None
"""
- connect = self.connect
- connect(self.helpButton, Signals.clicked, self.settingHelp)
- connect(self.defaultsButton, Signals.clicked, self.settingDefaults)
- connect(self.resetButton, Signals.clicked, self.settingsReset)
- connect(self.applyButton, Signals.clicked, self.settingApply)
- root = self.topLevelWidget()
- connect(self, Signals.berylSettingChanged, root.onContextChanged)
- connect(self, Signals.statusMessage, root.showMessage)
- connect(self.settingsMain, Signals.someChange,
- self.onSomethingChanged)
+ self.tabPage.setGroups(plugin)
+ self.raiseWidget(self.tabPageId)
- def onSomethingChanged(self):
- self.applyButton.setEnabled(True)
- self.resetButton.setEnabled(True)
+
+class AboutPage(Frame):
+ """ AboutPage -> frame to display a bit of info about a plugin
+
+ """
+ def __init__(self, parent):
+ Frame.__init__(self, parent)
+ self.infoHtml = buildPart(self, 'text/html', "Type == 'Service'", True)
def showAbout(self, plugin):
""" displays the About Plugin page with information from the plugin
@@ -109,90 +100,135 @@ class ContentFrame(WidgetStack):
pluginname = 'Beryl Settings'
plugindesc = 'Beryl Settings - Get Your Effects On!'
else:
- #logofile = 'file://%s' % App.basedir + '/pixmaps/beryl-settings-section-%s.png' % plugin.Name
pluginname = plugin.ShortDesc
plugindesc = plugin.LongDesc
self.infoHtml.begin()
self.infoHtml.write(htmlsrc % locals())
self.infoHtml.end()
- self.raiseWidget(self.aboutPageId)
- unsavedText = """There are unsaved changes in the active settings.
- Do you want to apply the changes before changing views or discard the changes?
+class SettingPage:
+ """ SettingPage -> mixin with methods common to both the
+ SinglePage and the TabPage types.
+
"""
-
- def showSettings(self, plugin, arg):
- """ displays the settings page with individual setting frames
+ unsavedText = ('There are unsaved changes in the active settings.\n'
+ 'Do you want to apply the changes before changing views '
+ 'or discard the changes?')
+
+ def buildConnections(self):
+ """ build the connections for this instance
+
+ @return None
+ """
+ connect = self.connect
+ connect(self.footer.helpButton, Signals.clicked, self.settingHelp)
+ connect(self.footer.defaultsButton, Signals.clicked, self.settingDefaults)
+ connect(self.footer.resetButton, Signals.clicked, self.settingsReset)
+ connect(self.footer.applyButton, Signals.clicked, self.settingApply)
+ root = self.topLevelWidget()
+ connect(self, Signals.berylSettingChanged, root.onContextChanged)
+ connect(self, Signals.statusMessage, root.showMessage)
+ connect(self, Signals.selectPrevious, root, Signals.selectPrevious)
+
+ def onSomethingChanged(self):
+ """ enable apply and reset buttons on setting value change
+
+ @return None
+ """
+ self.enableApplyReset(True, True)
+
+ def enableApplyReset(self, enableApply, enableReset):
+ """ convenience for setting enabled state of apply and reset buttons
+
+ @return None
+ """
+ self.footer.applyButton.setEnabled(enableApply)
+ self.footer.resetButton.setEnabled(enableReset)
+
+ def unsaved(self):
+ """ checks for unsaved items (defers to apply button enabled state)
+
+ @return True if unsaved settings
+ """
+ return self.footer.applyButton.isEnabled()
+
+ def unsavedDialog(self):
+ """ display a dialog warning of unsaved changes
+
+ @return KMessageBox.Yes, .No, or .Cancel
+ """
+ msg = KMessageBox.warningYesNoCancel
+ return msg(self, self.unsavedText,
+ i18n('Unsaved Changes'),
+ KStdGuiItem.apply(),
+ KStdGuiItem.discard())
+
+ def unsavedCheck(self, plugin, arg):
+ """ checks for unsaved items and prompts for action if any
@param plugin berylsettings Plugin instance
@param arg setting name or setting section name
- @return None
+ @return True if no save needed, changes discarded or applied;
+ False otherwise
"""
- if self.applyButton.isEnabled():
- msg = KMessageBox.warningYesNoCancel
- res = msg(self, self.unsavedText, i18n('Unsaved Changes'),
- KStdGuiItem.apply(), KStdGuiItem.discard())
+ ret = True
+ if self.unsaved():
+ res = self.unsavedDialog()
if res == KMessageBox.Cancel:
- return
+ self.emit(Signals.selectPrevious, (plugin, arg))
+ ret = False
elif res == KMessageBox.Yes:
self.settingApply()
- #else it's no/discard so fall thru
- ico = plugin.icon(KIcon.SizeLarge, self.loader)
- self.pluginIconLabel.setPixmap(ico)
- if arg in plugin.settings:
- settings = plugin.settings[arg]
- extra = ' - %s' % (arg, )
- else:
- settings = [arg, ]
- extra = ''
- self.pluginNameLabel.setText('<b>%s%s</b>' % (plugin.ShortDesc, extra))
- self.settingsMain.addSettings(plugin, settings)
- self.applyButton.setEnabled(False)
- self.resetButton.setEnabled(False)
- self.raiseWidget(self.settingsPageId)
+ else:
+ self.settingDiscard()
+ return ret
def settingHelp(self):
""" not implemented
"""
+ def settingDiscard(self):
+ """ unsaved changes discarded; disable apply and reset buttons
+
+ @return None
+ """
+ self.enableApplyReset(False, False)
+
+
def settingDefaults(self):
""" set each setting to its default value
@return None
"""
- frame = self.settingsPage
- widgets = frame.queryList('SettingFrame')
+ widgets = self.queryList('SettingFrame')
for widget in widgets:
try:
widget.setDefault()
except (Exception, ), exc:
print 'reset exception:', exc
- self.applyButton.setEnabled(True)
- self.resetButton.setEnabled(True)
+ self.enableApplyReset(True, True)
def settingsReset(self):
""" set each setting to its previous value
@return None
"""
- frame = self.settingsPage
- widgets = frame.queryList('SettingWidget')
+ widgets = self.queryList('SettingWidget')
for widget in widgets:
try:
widget.reset()
except (Exception, ), exc:
print 'reset exception:', exc
- self.applyButton.setEnabled(True)
- self.resetButton.setEnabled(False)
+ self.enableApplyReset(False, False)
def settingApply(self):
""" not final
"""
excs = []
- for w in self.settingsPage.queryList('SettingWidget'):
+ for w in self.queryList('SettingWidget'):
try:
v = w.value()
w.setting.set(v)
@@ -205,48 +241,154 @@ class ContentFrame(WidgetStack):
excstrs.append('Plugin:%s Setting:%s Exception:%s' % exc)
KMessageBox.errorList(None, 'Exceptions Saving Settings',
excstrs)
- self.applyButton.setEnabled(False)
- self.resetButton.setEnabled(False)
+ self.enableApplyReset(False, False)
self.emit(Signals.statusMessage, ('Saving settings...', ))
self.emit(Signals.berylSettingChanged, ())
-class SettingsContainer(QFrame):
+class SinglePage(Frame, SettingPage):
+ """ SinglePage -> frame to display a single group of settings
+
+ """
def __init__(self, parent):
- QFrame.__init__(self, parent)
- self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
- self.settingFrames = []
- layout = QVBoxLayout(self, 5)
+ Frame.__init__(self, parent, marginHint, spacingHint)
+ self.previous = (None, None)
+ self.header = ContentHeader(self)
+ self.main = MultiSettingFrame(self)
+ self.footer = ContentFooter(self)
+ self.buildConnections()
+
+ def buildConnections(self):
+ """ build the connections for this instance
+
+ @return None
+ """
+ SettingPage.buildConnections(self)
+ self.connect(self.main.container, Signals.someChange,
+ self.onSomethingChanged)
+
+ 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
+ """
+ if not self.unsavedCheck(*self.previous):
+ return
+ self.previous = (plugin, arg)
+ self.header.setFromPlugin(plugin, arg)
+ self.main.setPlugin(plugin, arg)
+
+
+class TabPage(Frame, SettingPage):
+ """ TabPage -> tab widget to display multiple groups of settings
+
+ """
+ def __init__(self, parent):
+ Frame.__init__(self, parent, marginHint, spacingHint)
+ self.header = ContentHeader(self)
+ self.tabs = KTabWidget(self)
+ sep = KSeparator(KSeparator.Horizontal, self)
+ self.footer = ContentFooter(self)
+ self.buildConnections()
+
+ def setGroups(self, plugin):
+ """ builds new page for each plugin setting group
+
+ @param plugin berylsettings Plugin instance
+ @return None
+ """
+ if not self.unsavedCheck(plugin, None):
+ return
+ self.header.setFromPlugin(plugin)
+ self.clearPages()
+ tabs = self.tabs
+ changed = Signals.someChange
+ for group in plugin.groups:
+ page = MultiSettingFrame(tabs)
+ page.setPlugin(plugin, group.settings(plugin))
+ tabs.addTab(page, group.label)
+ self.connect(page.container, changed, self.onSomethingChanged)
+ tabs.setCurrentPage(0)
+
+ def clearPages(self):
+ """ deletes all pages from the tab widget child
+
+ @return None
+ """
+ tabs = self.tabs
+ page = tabs.currentPage()
+ while page:
+ tabs.removePage(page)
+ page.deleteLater()
+ page = tabs.currentPage()
+
+
+class MultiSettingFrame(Frame):
+ """ MultiSettingFrame -> a scrollable view of multiple settings
+
+ """
+ def __init__(self, parent, *args, **kwds):
+ Frame.__init__(self, parent)
+ self.frames = []
+ self.previous = (None, None)
+ self.scroll = ContentScroll(self)
+ viewport = self.scroll.viewport()
+ self.container = Frame(viewport, marginHint, spacingHint, False)
+ self.scroll.addChild(self.container)
+
+ def setPlugin(self, plugin, arg):
+ """ displays the settings page with individual setting frames
- def addSettings(self, plugin, settings):
- self.clearFrames()
- layout = self.layout()
+ @param plugin berylsettings Plugin instance
+ @param arg setting name, setting type name, or sequence of settings
+ @return None
+ """
+ if isinstance(arg, basestring):
+ settings = plugin.settings[arg]
+ elif isinstance(arg, Setting):
+ settings = [arg, ]
+ elif isinstance(arg, (list, tuple)):
+ settings = arg
+ else:
+ print 'unknown setting type', arg
+ settings = ()
+ if self.previous == (plugin, settings):
+ return
+ self.previous = (plugin, settings)
+ self.clearFrames()
+ container = self.container
+ layout = container.layout()
changed = Signals.someChange
+ frames = self.frames
for setting in settings:
- frame = SettingFrame(self, plugin, setting)
- self.settingFrames.append(frame)
- layout.addWidget(frame, 0, Qt.AlignTop)
- self.connect(frame, changed, self, changed)
- layout.addStretch(5)
- for frame in self.settingFrames:
+ frame = SettingFrame(container, plugin, setting)
frame.show()
- self.updateGeometry()
+ frames.append(frame)
+ layout.addWidget(frame, 0, Qt.AlignTop)
+ self.connect(frame, changed, container, changed)
+ layout.addStretch(1)
def clearFrames(self):
- for widget in self.settingFrames:
- widget.close(True)
- self.layout().deleteAllItems()
- self.settingFrames = []
+ """ removes child frames and clears the container frame
+
+ @return None
+ """
+ for widget in self.frames:
+ widget.close(True)
+ self.container.layout().deleteAllItems()
+ self.frames = []
class SettingFrame(QFrame):
- """ SettingFrame -> displays editing widgets for a single Setting instance.
+ """ SettingFrame -> display and editing widgets for a single Setting.
"""
def __init__(self, parent, plugin, setting):
QFrame.__init__(self, parent)
mainLayout = QVBoxLayout(self)
- innerLayout = QHBoxLayout(mainLayout, 3)
+ innerLayout = QHBoxLayout(mainLayout)
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
self.infoCaption = setting.ShortDesc
self.infoText = setting.LongDesc
@@ -261,33 +403,40 @@ class SettingFrame(QFrame):
align = Qt.AlignLeft | Qt.AlignTop
innerLayout.addWidget(info, 0, align)
innerLayout.addWidget(reset, 0, align)
- innerLayout.addWidget(widget, 10)
- mainLayout.addSpacing(10)
+ innerLayout.addWidget(widget, 1)
+ mainLayout.addSpacing(spacingHint)
connect = self.connect
- connect(info, Signals.clicked, self.showInfo)
+ connect(info, Signals.clicked, self.showTip)
connect(reset, Signals.clicked, self.setDefault)
- connect(widget, Signals.someChange,
- self, Signals.someChange)
+ connect(widget, Signals.someChange, self, Signals.someChange)
def setDefault(self):
- w = self.settingWidget
- curv = w.value()
- newv = w.initial = w.setting.ResetToDefault()
- w.setting.set(curv) # because it's not applied yet
- w.reset()
+ """ set the setting value to its default
- def showInfo(self):
+ The berylsettings extension module performs the reset directly
+ on the setting object. In this method, we save the current
+ value as defined by the widget and set that value again after
+ the reset.
+ """
+ widget = self.settingWidget
+ current = widget.value()
+ widget.initial = widget.setting.ResetToDefault()
+ widget.setting.set(current)
+ widget.reset()
+ widget.initial = current
+
+ def showTip(self):
""" show a balloon tip with the setting description
@return None
"""
parent = self.resetButton
- ico = icon('help', size=KIcon.SizeLarge)
- txt = self.infoText
- cap = self.infoCaption
- msg = KPassivePopup.message
- pop = msg(KPassivePopup.Balloon, cap, txt, ico, parent)
+ pop = KPassivePopup.message(KPassivePopup.Balloon,
+ self.infoCaption,
+ self.infoText,
+ icon('help', size=KIcon.SizeLarge),
+ parent)
pos = pop.pos()
pos.setY(pos.y() + (parent.height() / 2))
pos.setX(pos.x() + (parent.width() * 2))
@@ -295,12 +444,64 @@ class SettingFrame(QFrame):
pop.move(pos)
+class ContentHeader(QFrame):
+ """ ContentHeader -> header frame with a pixmap and label for plugin
+
+ """
+ def __init__(self, parent):
+ QFrame.__init__(self, parent)
+ layout = QHBoxLayout(self)
+ self.pluginIconLabel = iconLabel = QLabel(self)
+ self.pluginNameLabel = nameLabel = QLabel(self)
+ layout.addWidget(iconLabel)
+ layout.addWidget(nameLabel, 1)
+
+ def setFromPlugin(self, plugin, extra=''):
+ """ sets this header icon and label to plugin values
+
+ @param plugin berylsettings Plugin instance
+ @param extra any object; if string or unicode, added to end of label
+ @return None
+ """
+ ico = plugin.icon(KIcon.SizeLarge, iconLoader())
+ self.pluginIconLabel.setPixmap(ico)
+ if isinstance(extra, basestring) and extra:
+ extra = ' - %s' % (extra, )
+ else:
+ extra = ''
+ values = (plugin.ShortDesc, extra)
+ self.pluginNameLabel.setText('<b>%s%s</b>' % values)
+
+
+class ContentFooter(QFrame):
+ """ ContentFooter -> footer frame with common buttons
+
+ """
+ def __init__(self, parent):
+ QFrame.__init__(self, parent)
+ layout = QHBoxLayout(self)
+ self.helpButton = guiButton(self, 'help', layout)
+ self.defaultsButton = guiButton(self, 'defaults', layout)
+ layout.addStretch(1)
+ self.applyButton = guiButton(self, 'apply', layout, False)
+ self.resetButton = guiButton(self, 'reset', layout, False)
+
+
class ContentScroll(QScrollView):
""" ContentScroll -> a scroll view fitted to a single child
+ The redefined sizeHint method is important -- without it, the
+ widget size isn't picked up correctly by the parent. Found in
+ kcontrol sources.
"""
- def __init__(self, parent, child):
+ def __init__(self, parent):
QScrollView.__init__(self, parent)
self.setResizePolicy(QScrollView.AutoOneFit)
self.setFrameShape(self.NoFrame)
- self.addChild(child)
+
+ def sizeHint(self):
+ """ recommended size for this widget
+
+ @return QSize instance
+ """
+ return self.minimumSizeHint()
diff --git a/kberylsettings/lib.py b/kberylsettings/lib.py
index 2eebdd3..a9986ff 100644
--- a/kberylsettings/lib.py
+++ b/kberylsettings/lib.py
@@ -37,8 +37,9 @@ class Signals:
berylContextChanged = PYSIGNAL('berylContextChanged')
berylSettingChanged = PYSIGNAL('berylSettingChanged')
berylPluginEnabled = PYSIGNAL('berylPluginEnabled')
- pluginAbout = PYSIGNAL('pluginAbout')
+ showAbout = PYSIGNAL('showAbout')
showSettings = PYSIGNAL('showSettings')
+ showGroups = PYSIGNAL('showGroups')
statusMessage = PYSIGNAL('statusMessage')
someChange = PYSIGNAL('someChange')
clicked = SIGNAL('clicked()')
@@ -59,6 +60,8 @@ class Signals:
colorChanged = SIGNAL('changed(const QColor &)')
contextMenuRequest = \
SIGNAL('contextMenuRequested(QListViewItem*,const QPoint&,int)')
+ searchInput = PYSIGNAL('searchInput')
+ selectPrevious = PYSIGNAL('selectPrevious')
class Slots:
@@ -175,3 +178,4 @@ def buildPart(parent, servicetype, constraint, writable=False):
if part:
break
return part
+
diff --git a/kberylsettings/main.py b/kberylsettings/main.py
index 98a3031..b1aedff 100644
--- a/kberylsettings/main.py
+++ b/kberylsettings/main.py
@@ -25,8 +25,8 @@ class KBerylSettings(KMainWindow):
""" The main window.
"""
- viewMode = 0
- iconSize = 16
+ viewMode = PluginFrame.categoryPageId
+ iconSize = KIcon.SizeMedium
startDir = '::kberylsettings'
def __init__(self):
@@ -46,7 +46,8 @@ class KBerylSettings(KMainWindow):
actions.setHighlightingEnabled(True)
self.mainSplitter = splitter = Splitter(self, Qt.Horizontal)
self.leftFrame = left = Frame(splitter)
- self.contentFrame = ContentFrame(splitter)
+ self.rightFrame = right = Frame(splitter)
+ self.contentFrame = ContentFrame(right)
self.searchWidget = search = QWidget(self.leftFrame)
searchLayout = QHBoxLayout(search, 6, 6)
searchLayout.setAutoAdd(True)
@@ -101,12 +102,8 @@ class KBerylSettings(KMainWindow):
connect = self.connect
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)
+ connect(self.clearSearch, Signals.clicked, self.onClearSearch)
+ connect(self.inputSearch, Signals.textChanged, self.onInputSearch)
statusBar = self.statusBar()
connect(self.sysTray, Signals.quitSelected, self.onQuitSelected)
connect(self.quitAction, Signals.activated, self.onQuitSelected)
@@ -133,13 +130,15 @@ class KBerylSettings(KMainWindow):
self.restoreWindowSize(config)
self.mainSplitter.setSizes([self.width()*0.25, self.width()*0.75])
config = self.config('mainview')
- self.emit(Signals.iconSizeChanged,
- (config.readNumEntry('iconsize', self.iconSize), ))
- self.emit(Signals.viewModeChanged,
- (config.readNumEntry('viewmode', self.viewMode), ))
+ emit = self.emit
+ emit(Signals.showAbout, (None, ))
+ emit(Signals.iconSizeChanged,
+ (config.readNumEntry('iconsize', self.iconSize), ))
+
+ viewMode = config.readNumEntry('viewmode', self.viewMode)
+ emit(Signals.viewModeChanged, (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
@@ -216,7 +215,7 @@ class KBerylSettings(KMainWindow):
"""
pop = self.modePopup = Popup(self)
ids = self.modePopupIds = {}
- for value, label in ((0, '&Icon View'), (1, '&Tree View')):
+ for value, label in PluginFrame.modePages:
modeid = ids[value] = pop.insertItem(i18n(label))
pop.setItemParameter(modeid, value)
pop.connectItem(modeid, self, Signals.viewModeChanged)
@@ -280,12 +279,19 @@ class KBerylSettings(KMainWindow):
for size, menuid in self.iconSizePopupIds.items():
self.iconSizePopup.setItemChecked(menuid, size==value)
+ def onInputSearch(self, value):
+ """ emits signal to change view mode and signal to search for text
+
+ """
+ self.emit(Signals.searchInput, (value, ))
+ self.emit(Signals.viewModeChanged, (2, ))
+
def onPluginDialogOk(self):
""" sets current context active plugins
@return None
"""
- items = self.pluginDialog.pluginMap.items()
+ items = self.pluginDialogItems.items()
active = [name for name, enabled in items if enabled]
context = self.context
for p in context.plugins:
@@ -307,10 +313,11 @@ class KBerylSettings(KMainWindow):
@return None
"""
- self.pluginDialog = PluginDialog(self, self.context)
- self.connect(self.pluginDialog, Signals.okClicked,
+ self.pluginDialogItems = {}
+ dialog = PluginDialog(self, self.context, self.pluginDialogItems)
+ self.connect(dialog, Signals.okClicked,
self.onPluginDialogOk)
- self.pluginDialog.exec_loop()
+ dialog.exec_loop()
def onMode(self, value):
""" changes the View Mode menu, enables/disables Icon Size menu items
@@ -318,9 +325,12 @@ class KBerylSettings(KMainWindow):
@param value new view mode
@return None
"""
+ if value == PluginFrame.searchPageId:
+ return
self.viewMode = value
+ isIconMode = value == PluginFrame.iconPageId
for menuid in self.iconSizePopupIds.values():
- self.iconSizePopup.setItemEnabled(menuid, not value)
+ self.iconSizePopup.setItemEnabled(menuid, isIconMode)
for mode, menuid in self.modePopupIds.items():
self.modePopup.setItemChecked(menuid, mode==value)
diff --git a/kberylsettings/plugindialog.py b/kberylsettings/plugindialog.py
index 578d2d8..9a35164 100644
--- a/kberylsettings/plugindialog.py
+++ b/kberylsettings/plugindialog.py
@@ -10,31 +10,31 @@ from kdeui import KDialogBase, KListView, KMessageBox
from qt import QCheckListItem, QLabel
from kberylsettings.lib import Signals, iconLoader
+from kberylsettings.widget import ListView
-
-class PluginList(KListView):
+class PluginList(ListView):
""" PluginList -> list view for the select plugins dialog
"""
def __init__(self, parent):
- KListView.__init__(self, parent)
+ ListView.__init__(self, parent)
self.addColumn(i18n('Plugin'))
self.addColumn(i18n('Categories'))
self.addColumn(i18n('Description'))
-
- def addPlugins(self, context):
+ self.setSorting(self.columns()+1)
+
+ def addPlugins(self, context, stateMap):
""" creates list view items from plugins in context
@param context berylsetting Context instance
@return mapping of plugin names and their enabled state
"""
- stateMap = {}
active = context.active
count = textlen = 0
loader = iconLoader()
cats = context.categories
- for p in context.plugins:
+ for p in context.plugins[::-1]:
item = QCheckListItem(self, p.ShortDesc, QCheckListItem.CheckBox)
item.setEnabled(not p.isGeneral)
cnames = str.join(',', [c.ShortDesc for c in cats if p in c.Plugins])
@@ -69,7 +69,7 @@ class PluginDialog(KDialogBase):
""" PluginDialog -> a dialog for enabling and disabling plugins
"""
- def __init__(self, parent, context):
+ def __init__(self, parent, context, mapping):
KDialogBase.__init__(self, parent, '', True, i18n('Select Plugins'),
KDialogBase.Ok|KDialogBase.Cancel)
self.context = context
@@ -77,7 +77,7 @@ class PluginDialog(KDialogBase):
self.label = QLabel('Enable or disable plugins below.', main)
self.listView = PluginList(main)
self.connect(self.listView, Signals.itemClicked, self.changePlugin)
- self.pluginMap = self.listView.addPlugins(context)
+ self.pluginMap = self.listView.addPlugins(context, mapping)
def changePlugin(self, item):
""" handle a possible change to the plugins checkbox
diff --git a/kberylsettings/pluginframe.py b/kberylsettings/pluginframe.py
index a867fee..d7e4e79 100644
--- a/kberylsettings/pluginframe.py
+++ b/kberylsettings/pluginframe.py
@@ -1,70 +1,55 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-""" kberylsettings.pluginframe -> defines the left side plugin views.
+""" kberylsettings.pluginframe -> defines the left side plugin views
and search view.
"""
from re import sub
-from qt import QLabel, QListViewItem
+from qt import QLabel
from kdecore import KIcon, i18n
from kberylsettings.beryl import Setting
from kberylsettings.lib import Signals, icon, iconLoader
-from kberylsettings.widget import Frame, ListView, ValueListViewItem, \
- WidgetStack
+from kberylsettings.widget import BasicListView, Frame, ValueListViewItem, \
+ WidgetStack
class PluginFrame(WidgetStack):
- """ PluginFrame -> stack with Icon View, Tree View, and Search widget.
+ """ PluginFrame -> stack with various plugin views and search widget.
"""
- iconPageId, treePageId, searchPageId = range(3)
-
+ iconPageId, treePageId, searchPageId, categoryPageId = pageIds = range(4)
+ modePages = (
+ (iconPageId, '&Icon View'),
+ (treePageId, '&Tree View'),
+ ## search does not have a mode menu
+ ## entry selectable by the user.
+ (categoryPageId, '&Category View')
+ )
+
def __init__(self, parent):
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()
+ pages = (IconView(self), TreeView(self), SearchView(self),
+ CategoryView(self))
+ addWidget = self.addWidget
+ for pageId, page in zip(self.pageIds, pages):
+ addWidget(page, pageId)
connect = self.connect
+ root = self.topLevelWidget()
connect(root, Signals.viewModeChanged, self.raiseWidget)
- connect(root, Signals.iconSizeChanged, self.iconView.onIconSize)
- 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.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)
-
- def showSearch(self, value):
- """ displays the search page and tickles it with the search value
-
- @return None
- """
- self.raiseWidget(self.searchPageId)
- self.searchView.showKeywords(value)
+ for page in pages:
+ connect(page, Signals.berylSettingChanged, root.onContextChanged)
+ connect(page, Signals.showAbout, root, Signals.showAbout)
+ connect(page, Signals.showSettings, root, Signals.showSettings)
+ connect(page, Signals.showGroups, root, Signals.showGroups)
+ connect(page, Signals.statusMessage, root.showMessage)
+ try:
+ connect(root, Signals.berylContextChanged, page.onBerylContext)
+ connect(root, Signals.berylPluginEnabled, page.enablePluginItem)
+ connect(root, Signals.selectPrevious, page.selectPluginItem)
+ except (AttributeError, ):
+ pass
class SearchView(Frame):
@@ -76,14 +61,15 @@ class SearchView(Frame):
self.index = {}
self.loader = iconLoader()
self.keywordLabel = QLabel(i18n('Keywords:'), self)
- self.keywordsList = ListView(self)
- configList(self.keywordsList)
+ self.keywordsList = keywordsList = BasicListView(self)
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)
-
+ self.resultsList = resultsList = BasicListView(self)
+ connect = self.connect
+ connect(keywordsList, Signals.itemSelected, self.showResults)
+ connect(resultsList, Signals.itemSelected, self.emitResult)
+ root = self.topLevelWidget()
+ connect(root, Signals.searchInput, self.showKeywords)
+ connect(root, Signals.berylContextChanged, self.rebuildIndex)
def rebuildIndex(self, context):
""" reconstructs the search 'index' given a berylsetting context
@@ -96,7 +82,8 @@ class SearchView(Frame):
"""
index = self.index
index.clear()
- for p in context.plugins:
+ itemKeywords = self.itemKeywords
+ for p in context.plugins[::-1]:
for key in itemKeywords(p):
seq = index.setdefault(key, [])
seq.append((p, None))
@@ -105,6 +92,17 @@ class SearchView(Frame):
seq = index.setdefault(key, [])
seq.append((p, s))
+ def itemKeywords(self, 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]
+
def showKeywords(self, text):
""" displays keywords from the index that match the given text
@@ -153,28 +151,34 @@ class SearchView(Frame):
"""
plugin, setting = item.value
if setting is None:
- self.emit(Signals.pluginAbout, (plugin, ))
+ self.emit(Signals.showAbout, (plugin, ))
else:
self.emit(Signals.showSettings, (plugin, Setting(setting), ))
-class PluginView(ListView):
- """ PluginView -> mixin for shared view functionality
+class BasicPluginView(BasicListView):
+ """ BasicPluginView -> mixin for shared view functionality
"""
def __init__(self, parent):
- ListView.__init__(self, parent)
- configList(self)
+ BasicListView.__init__(self, parent)
self.loader = iconLoader()
- self.connect(self, Signals.itemSelected, self.onSelected)
+ self.connect(self, Signals.itemClicked, self.onItemClick)
- def addPlugins(self):
+ def selectPluginItem(self, plugin, setting):
+ match = (plugin, setting)
+ for item in self:
+ if item.value == match:
+ self.setCurrentItem(item)
+ return
+
+ def addItems(self):
""" adds list view items for every plugin in context
@return None
"""
active = self.context.active
- for plugin in self.context.plugins:
+ for plugin in self.context.plugins[::-1]:
self.listItem(plugin, active)
def listItem(self, plugin, active):
@@ -184,13 +188,17 @@ class PluginView(ListView):
@param active sequence of active plugin names
@return QListViewItem instance
"""
- item = self.findItem(plugin.ShortDesc, 0)
+ item = None
+ for i in self:
+ p, s = i.value
+ if p and p.Name == plugin.Name and s is None:
+ item = i
+ break
if not item:
- item = QListViewItem(self, plugin.ShortDesc)
- item.setVisible(True)
+ item = ValueListViewItem(self, plugin.ShortDesc, (None, None))
+ item.value = (plugin, None)
item.setVisible(plugin.Name in active)
item.setPixmap(0, plugin.icon(self.iconSize, self.loader))
- item.setText(0, plugin.ShortDesc)
return item
def onBerylContext(self, context):
@@ -200,7 +208,7 @@ class PluginView(ListView):
@return None
"""
self.context = context
- self.addPlugins()
+ self.addItems()
def enablePluginItem(self, plugin, enable):
""" toggle the enabled state of a plugin list view item
@@ -208,19 +216,22 @@ class PluginView(ListView):
@param index position of plugin within plugins list
@return None
"""
- for item in [i for i in self if i.text(0)==plugin.ShortDesc]:
- item.setVisible(enable)
+ for item in self:
+ p, s = item.value
+ if p == plugin and s is None:
+ item.setVisible(enable)
-class PluginIconView(PluginView):
- """ PluginIconView -> icon list view of plugins
+class IconView(BasicPluginView):
+ """ IconView -> icon list view of plugins
"""
- iconSize = 32
+ iconSize = KIcon.SizeMedium
def __init__(self, parent):
- PluginView.__init__(self, parent)
- self.selectedPlugin = None
+ BasicPluginView.__init__(self, parent)
+ root = self.topLevelWidget()
+ self.connect(root, Signals.iconSizeChanged, self.onIconSize)
def onIconSize(self, size):
""" update the icon size
@@ -230,71 +241,80 @@ class PluginIconView(PluginView):
"""
self.iconSize = size
for item in self:
- plugin = self.context.plugin(item.text(0))
+ plugin, setting = item.value
if plugin:
item.setPixmap(0, plugin.icon(size, self.loader))
else:
- item.setPixmap(0, Setting.icon(item.text(0), size))
+ item.setPixmap(0, Setting.icon(setting, size))
- def onSelected(self, item):
+ def onItemClick(self, item):
""" emit a signal if a plugin item is selected
@param item QListViewItem instance
@return None
"""
- plugin = self.context.plugin(item.text(0))
- text = item.text(0)
- if plugin:
- self.navToSettings(plugin)
- self.emit(Signals.pluginAbout, (plugin, ))
+ if not item:
+ return
+ plugin, setting = item.value
+ if plugin and not setting:
+ self.showSettingItems(plugin)
+ self.emit(Signals.showAbout, (plugin, ))
elif item == self.firstChild():
- for item in self:
- plugin = self.context.plugin(item.text(0))
- if plugin:
- item.setVisible(True)
- else:
- item.setVisible(False)
+ self.showPlugins()
else:
- args = (self.selectedPlugin, str(text), )
- self.emit(Signals.showSettings, args)
+ self.emit(Signals.showSettings, (plugin, setting))
- 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
- keys = groups.keys()
- keys.sort()
- for key in keys:
- label = key #Setting.label(key)
- sub = self.findItem(label, 0)
- if not sub:
- sub = QListViewItem(self, self.lastItem(), label, )
- sub.setPixmap(0, Setting.icon(key, self.iconSize))
+ def showPlugins(self):
+ active = self.context.active
+ for item in self:
+ plugin, setting = item.value
+ if plugin and plugin.Name in active and not setting:
+ item.setVisible(True)
+ else:
+ item.setVisible(False)
- back = self.findItem(i18n('Back'), 0)
- if not back:
- back = QListViewItem(self, i18n('Back'))
+ def backItem(self):
+ back = self.findItem(i18n('Back'), 0)
+ if back is None:
+ back = ValueListViewItem(self, i18n('Back'), (None, None))
back.setPixmap(0, icon('back', size=self.iconSize))
+ return back
+
+ def showSettingItems(self, plugin):
+ keys = plugin.settings.keys()
+ keys.sort()
+ back = self.backItem()
+ back.setVisible(True)
+
+ settings = []
for item in self:
- plugin = self.context.plugin(item.text(0))
- if plugin or (item.text(0) not in keys and item != back):
+ p, s = item.value
+ if p and s:
+ if s in keys:
+ item.setVisible(True)
+ item.value = (plugin, s)
+ settings.append(s)
+ else:
+ item.setVisible(False)
+ elif p and not s:
item.setVisible(False)
- else:
- item.setVisible(True)
+
+ for key in keys[::-1]:
+ if key not in settings:
+ sub = ValueListViewItem(self, key, (plugin, key))
+ sub.setPixmap(0, Setting.icon(key, self.iconSize))
+ sub.moveItem(back)
-class PluginTreeView(PluginView):
- """ PluginTreeView -> tree list view of plugins
+class TreeView(BasicPluginView):
+ """ TreeView -> tree list view of plugins
"""
- iconSize = 16
+ iconSize = KIcon.SizeSmall
def __init__(self, parent):
- PluginView.__init__(self, parent)
+ BasicPluginView.__init__(self, parent)
self.setRootIsDecorated(True)
def listItem(self, plugin, active):
@@ -305,56 +325,93 @@ class PluginTreeView(PluginView):
@param size icon size
@return QListViewItem instance with children
"""
- item = PluginView.listItem(self, plugin, active)
+ item = BasicPluginView.listItem(self, plugin, active)
groups = plugin.settings
keys = groups.keys()
keys.sort()
-
child = item.firstChild()
while child:
item.takeItem(child)
child = item.firstChild()
-
for key in keys:
- sub = QListViewItem(item, key)
+ sub = ValueListViewItem(item, key, (plugin, key))
sub.setPixmap(0, Setting.icon(key, self.iconSize))
return item
- def onSelected(self, item):
+ def onItemClick(self, item):
""" emit a signal if a plugin item is selected
@param item QListViewItem instance
@return None
"""
- plugin = self.context.plugin(item.text(0))
- if plugin:
- self.emit(Signals.pluginAbout, (plugin, ))
+ if not item:
+ return
+ plugin, setting = item.value
+ if plugin and setting:
+ self.emit(Signals.showSettings, (plugin, setting))
else:
- plugin = self.context.plugin(item.parent().text(0))
- name = str(item.text(0))
- self.emit(Signals.showSettings, (plugin, name))
+ self.emit(Signals.showAbout, (plugin, ))
-def configList(obj):
- """ configures a ListView with a single column, no sorting, hidden
- header and no horizontal scrollbar.
+class CategoryView(BasicPluginView):
+ """ CategoryView -> tree list view of plugins by category
- @param obj KListView or QListView instance
- @return None
"""
- obj.addColumn('')
- obj.setSorting(-1)
- obj.header().hide()
- obj.setHScrollBarMode(obj.AlwaysOff)
+ iconSize = KIcon.SizeMedium
+ def __init__(self, parent):
+ BasicPluginView.__init__(self, parent)
+ self.setRootIsDecorated(True)
-def itemKeywords(obj):
- """ creates a list of keywords for the given berylsettings object
+ def onItemClick(self, item):
+ """ emit appropriate signal when plugin or category selected
- @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]
+ @param item QListViewItem instance
+ @return None
+ """
+ if not item:
+ return
+ plugin, setting = item.value
+ if plugin:
+ self.emit(Signals.showGroups, (plugin, ))
+
+ def addItems(self):
+ """ adds list view items for each category and plugin in context
+
+ @return None
+ """
+ active = self.context.active
+ for category in self.context.categories[::-1]:
+ plugins = [p for p in category.plugins[::-1] if p.Name in active]
+ catitem = self.categoryItem(category)
+ catitem.setVisible(bool(plugins))
+ for plugin in plugins:
+ if plugin.Name in active:
+ self.pluginItem(plugin, catitem)
+
+ def categoryItem(self, category):
+ """ create a list view item for a category
+
+ @param category
+ @return QListViewItem instance
+ """
+ desc = category.ShortDesc
+ item = self.findItem(desc, 0)
+ if not item:
+ item = ValueListViewItem(self, desc, (None, None))
+ item.setPixmap(0, category.icon(self.iconSize, self.loader))
+ return item
+
+ def pluginItem(self, plugin, parent):
+ """ create a list view item for a plugin
+
+ @param category
+ @return QListViewItem instance
+ """
+ for item in [i for i in self if i.parent() == parent]:
+ if item.value[0].Name == plugin.Name:
+ item.value = (plugin, None)
+ return item
+ item = ValueListViewItem(parent, plugin.ShortDesc, (plugin, None))
+ item.setPixmap(0, plugin.icon(self.iconSize, self.loader))
+ return item
diff --git a/kberylsettings/widget.py b/kberylsettings/widget.py
index 2f9e6ca..d6a60f9 100644
--- a/kberylsettings/widget.py
+++ b/kberylsettings/widget.py
@@ -5,7 +5,7 @@
"""
from qt import Qt, QFrame, QGroupBox, QListViewItem, QListViewItemIterator, \
QSizePolicy, QSplitter, QVBoxLayout, QWidgetStack
-from kdeui import KListView, KPopupMenu, KPushButton
+from kdeui import KListView, KPopupMenu, KPushButton, KStdGuiItem
class Frame(QFrame):
@@ -62,6 +62,9 @@ class ListView(KListView):
"""
def __init__(self, parent):
KListView.__init__(self, parent)
+ self.configList()
+
+ def configList(self):
self.setSorting(-1)
def __iter__(self):
@@ -77,6 +80,9 @@ class ListView(KListView):
class ShortListView(ListView):
+ """ ShortListView -> KListView with height set equal to a number of items
+
+ """
def __init__(self, parent, text, lines):
ListView.__init__(self, parent)
self.addColumn(text)
@@ -89,6 +95,18 @@ class ShortListView(ListView):
self.setMaximumHeight(height)
+class BasicListView(ListView):
+ """ BasicListView -> KListView configured for a single column, no
+ sorting, hidden header and no horizontal scrollbar.
+
+ """
+ def configList(self):
+ self.addColumn('')
+ self.setSorting(-1)
+ self.header().hide()
+ self.setHScrollBarMode(self.AlwaysOff)
+
+
class WidgetStack(QWidgetStack):
""" WidgetStack -> QWidgetStack with QVBoxLayout
@@ -100,6 +118,9 @@ class WidgetStack(QWidgetStack):
class GroupBox(QGroupBox):
+ """ GroupBox -> QGroupBox with nicer parameters
+
+ """
def __init__(self, strips, orient, text, parent, margin=0, spacing=0):
QGroupBox.__init__(self, strips, orient, text, parent)
self.setFlat(True)
@@ -107,5 +128,28 @@ class GroupBox(QGroupBox):
self.setInsideSpacing(spacing)
def addSpaces(self, count, size=0):
+ """ adds a number of spaces to the groupbox
+
+ @param count number of spaces to add
+ @param size size of each space
+ @return None
+ """
for i in range(count):
self.addSpace(size)
+
+
+def guiButton(parent, name, layout=None, enable=True):
+ """ builds a standard push button by name
+
+ @param parent parent of button
+ @param name name of standard item; refer to KStdGuiItem static members
+ @keyparam layout=None if given, new button is added to this layout
+ @keyparam enable=True initial enabled state of button
+ @return KPushButton instance
+ """
+ gui = getattr(KStdGuiItem, name)()
+ button = KPushButton(gui.iconSet(), gui.text(), parent)
+ if layout:
+ layout.addWidget(button)
+ button.setEnabled(enable)
+ return button