summaryrefslogtreecommitdiff
path: root/portato
diff options
context:
space:
mode:
Diffstat (limited to 'portato')
-rw-r--r--portato/config_parser.py2
-rw-r--r--portato/gui/gtk/windows.py2
-rw-r--r--portato/gui/gui_helper.py6
-rw-r--r--portato/gui/qt/helper.py13
-rw-r--r--portato/gui/qt/highlighter.py74
-rw-r--r--portato/gui/qt/terminal.py71
-rw-r--r--portato/gui/qt/ui/AboutDialog.ui105
-rw-r--r--portato/gui/qt/ui/MainWindow.ui12
-rw-r--r--portato/gui/qt/windows.py67
-rw-r--r--portato/helper.py9
-rw-r--r--portato/plugin.py41
-rw-r--r--portato/plugins/etc_proposals.py8
12 files changed, 335 insertions, 75 deletions
diff --git a/portato/config_parser.py b/portato/config_parser.py
index 8418a6a..30873e7 100644
--- a/portato/config_parser.py
+++ b/portato/config_parser.py
@@ -164,7 +164,7 @@ class ConfigParser:
self.vars[section][key] = Value(val, count, bool = bool)
self.pos[count] = match.span(2)
else: # neither comment nor empty nor expression nor section => error
- debug("Unrecognized line:",line)
+ debug("Unrecognized line in configuration:", line, error = 1)
def get (self, key, section = "MAIN"):
"""Returns the value of a given key in a section.
diff --git a/portato/gui/gtk/windows.py b/portato/gui/gtk/windows.py
index d2151ab..5aeceed 100644
--- a/portato/gui/gtk/windows.py
+++ b/portato/gui/gtk/windows.py
@@ -757,7 +757,7 @@ class MainWindow (Window):
self.cfg.modify_external_configs()
# set plugins and plugin-menu
- plugin.load_plugins()
+ plugin.load_plugins("gtk")
menus = plugin.get_plugins().get_plugin_menus()
if menus:
self.tree.get_widget("pluginMenuItem").set_no_show_all(False)
diff --git a/portato/gui/gui_helper.py b/portato/gui/gui_helper.py
index e52b3f3..5cc2ee6 100644
--- a/portato/gui/gui_helper.py
+++ b/portato/gui/gui_helper.py
@@ -30,7 +30,7 @@ import time
import os
import signal
-class Config:
+class Config: # XXX: This needs to be replaced - the const-dict is just messy
"""Wrapper around a ConfigParser and for additional local configurations."""
const = {
"main_sec" : "Main",
@@ -263,7 +263,9 @@ class EmergeQueue:
@param console: Output is shown here.
@type console: Console
@param db: A database instance.
- @type db: Database"""
+ @type db: Database
+ @param title_update: A function, which will be called whenever there is a title update.
+ @type title_update: function(string)"""
# the different queues
self.mergequeue = [] # for emerge
diff --git a/portato/gui/qt/helper.py b/portato/gui/qt/helper.py
index 1b7dbdc..fa1576a 100644
--- a/portato/gui/qt/helper.py
+++ b/portato/gui/qt/helper.py
@@ -13,10 +13,23 @@
from PyQt4 import Qt
def qCheck (check):
+ """Maps True or False to Qt.Checked or Qt.Unchecked.
+
+ @param check: boolean value
+ @type check: bool
+ @returns: CheckState-Constant
+ @rtype: int"""
+
if check:
return Qt.Qt.Checked
else:
return Qt.Qt.Unchecked
def qIsChecked (check):
+ """Maps Qt.Checked and Qt.Unchecked to True and False.
+
+ @param check: CheckState-Constant
+ @type check: int
+ @returns: appropriate boolean value
+ @rtype: bool"""
return check == Qt.Qt.Checked
diff --git a/portato/gui/qt/highlighter.py b/portato/gui/qt/highlighter.py
index 5572930..74d9ac9 100644
--- a/portato/gui/qt/highlighter.py
+++ b/portato/gui/qt/highlighter.py
@@ -19,30 +19,59 @@ from portato.helper import debug
import re # prefer Python-Module over Qt-one
class EbuildHighlighter (Qt.QSyntaxHighlighter):
+ """A QSyntaxHighlighter implementation for the use with ebuild-syntax."""
NORMAL_STATE = 0
STRING_STATE = 1
def __init__ (self, edit):
+ """Constructor.
+
+ @param edit: the EditWidget to use the highlighter with
+ @type edit: Qt.QTextEdit"""
+
Qt.QSyntaxHighlighter.__init__(self, edit)
+ #
+ # the regular expressions ... *muahahaha*
+ #
+
+ # comments
self.comment = self.__create(r'#.*', color = "steelblue", italic = True)
+
+ # bash variables
self.bashVar = self.__create(r'(\$\{.+?\})|(\$\w+)', color = "green")
+ # a string
+ self.string = self.__create(r'(?<!\\)"', color = "fuchsia")
+
+ # the syntax elements, which are checked in a loop
self.syntax = {}
+
+ # bash syntax
self.syntax["bashSyn"] = self.__create(r'\b(case|do|done|elif|else|esac|exit|fi|for|function|if|in|local|read|return|select|shift|then|time|until|while)\b', color = "navy", underline = True)
+ # special bash commands
self.syntax["bashCmd"] = self.__create(r'\b(make|awk|cat|cd|chmod|chown|cp|echo|env|export|grep|head|let|ln|mkdir|mv|rm|sed|set|tail|tar|touch|unset)\b', color = "navy", bold = True)
+ # portage variables
self.syntax["portVar"] = self.__create(r'\b((ARCH|HOMEPAGE|DESCRIPTION|IUSE|SRC_URI|LICENSE|SLOT|KEYWORDS|FILESDIR|WORKDIR|(P|R)?DEPEND|PROVIDE|DISTDIR|RESTRICT|USERLAND)|(S|D|T|PV|PF|P|PN|A)|C(XX)?FLAGS|LDFLAGS|C(HOST|TARGET|BUILD))\b', color = "saddlebrown", bold = True)
+ # portage commands
self.syntax["portCmd"] = self.__create(r'\b(e(begin|end|conf|install|make|warn|infon?|error|patch)|die|built_with_use|use(_(with|enable))?|inherit|hasq?|(has|best)_version|unpack|(do|new)(ins|s?bin|doc|lib(|\.so|\.a)|man|info|exe|initd|confd|envd|pam|menu|icon)|do(python|sed|dir|hard|sym|html|jar|mo)|keepdir|prepall(|docs|info|man|strip)|prep(info|lib|lib\.(so|a)|man|strip)|(|doc|ins|exe)into|f(owners|perms)|(exe|ins|dir)opts)\b', color = "saddlebrown", bold = True)
+ # portage functions, i.e. the functions implemented by the ebuild
self.syntax["portFunc"] = self.__create(r'^(src_(unpack|compile|install|test)|pkg_(config|nofetch|setup|(pre|post)(inst|rm)))', color = "green")
- self.string = self.__create(r'(?<!\\)"', color = "fuchsia")
-
def do_reg_exp (self, syntaxTuple, string):
+ """Tries to match a regular expression and if this succeeds,
+ sets the text format.
+
+ @param syntaxTuple: tuple holding regexp and format
+ @type sytaxTuple: (RE-object, Qt.QTextCharFormat)
+ @param string: the string to look in
+ @type string: string"""
+
regexp, format = syntaxTuple
match = regexp.search(string)
@@ -55,19 +84,27 @@ class EbuildHighlighter (Qt.QSyntaxHighlighter):
match = regexp.search(string, span[1])
def highlightBlock (self, string):
+ """This function is called, whenever the edit want to have some text checked.
+
+ @param string: the text to check
+ @type string: Qt.QString"""
+
string = str(string) # we got a QString here
+ # check the normal syntax elements
for t in self.syntax.values():
self.do_reg_exp(t, string)
+ # reset to normal state :)
self.setCurrentBlockState(self.NORMAL_STATE)
# look for strings
prevStart = 0
foundEnd = False
stringMatch = self.string[0].search(string)
- if self.previousBlockState() == self.STRING_STATE:
- if stringMatch is None:
+
+ if self.previousBlockState() == self.STRING_STATE: # we were in a string last time
+ if stringMatch is None: # and there is no end of string in this line
self.setFormat(0, len(string), self.string[1])
self.setCurrentBlockState(self.STRING_STATE)
else:
@@ -75,17 +112,22 @@ class EbuildHighlighter (Qt.QSyntaxHighlighter):
while stringMatch is not None:
- if foundEnd:
+ if foundEnd: # we know that the string will end in this block
self.setCurrentBlockState(self.NORMAL_STATE)
self.setFormat(prevStart, stringMatch.end() - prevStart, self.string[1])
+
+ # look for a possible start of another string
stringMatch = self.string[0].search(string, stringMatch.end())
foundEnd = False
- else:
+
+ else: # we have entered a new string
+
prevStart = stringMatch.start()
- stringMatch = self.string[0].search(string, stringMatch.end())
+ stringMatch = self.string[0].search(string, stringMatch.end()) # the end of string
+
if stringMatch is not None:
foundEnd = True
- else:
+ else: # no string end: mark the rest of the line as string
self.setCurrentBlockState(self.STRING_STATE)
self.setFormat(prevStart, len(string) - prevStart, self.string[1])
@@ -93,6 +135,22 @@ class EbuildHighlighter (Qt.QSyntaxHighlighter):
self.do_reg_exp(self.comment, string) # do comments last
def __create (self, regexp, color = None, italic = False, bold = False, underline = False):
+ """This creates a syntax tuple.
+
+ @param regexp: the regular expression
+ @type regexp: string
+ @param color: the color to take; if None, take standard color
+ @type color: string
+ @param italic: italic-flag
+ @type italic: bool
+ @param bold: bold-flag
+ @type bold: bool
+ @param underline: underline-flag
+ @type underline: bool
+
+ @returns: the created syntax-tuple
+ @rtype: (RE-object, Qt.QTextCharFormat)
+ """
compRe = re.compile(regexp)
format = Qt.QTextCharFormat()
diff --git a/portato/gui/qt/terminal.py b/portato/gui/qt/terminal.py
index 2734aaf..85bea0e 100644
--- a/portato/gui/qt/terminal.py
+++ b/portato/gui/qt/terminal.py
@@ -46,6 +46,7 @@ backspace = 8
title_seq = ("\x1b", "]")
title_end = "\x07"
+# the attributes
attr = {}
attr[0] = None # normal
attr[1] = BoldFormat() # bold
@@ -61,8 +62,15 @@ attr[37] = ColorFormat("white")
attr[39] = None # default
class QtConsole (Console, Qt.QTextEdit):
+ """Self implemented emulation of a terminal emulation.
+ This only supports a subset of instructions known to normal terminals."""
def __init__ (self, parent):
+ """Constructor.
+
+ @param parent: parent widget
+ @type parent: Qt.QWidget"""
+
Qt.QTextEdit.__init__(self, parent)
self.pty = None
@@ -74,14 +82,23 @@ class QtConsole (Console, Qt.QTextEdit):
self.setReadOnly(True)
+ # we need these two signals, as threads are not allowed to access the GUI
+ # solution: thread sends signal, which is handled by the main loop
Qt.QObject.connect(self, Qt.SIGNAL("doSomeWriting"), self._write)
Qt.QObject.connect(self, Qt.SIGNAL("deletePrevChar()"), self._deletePrev)
def _deletePrev (self):
+ """Deletes the previous character."""
self.textCursor().deletePreviousChar()
def _write (self, text):
- if text == esc_seq[0]:
+ """Writes some text. A text of "\\x1b" signals _write() to reload
+ the current char format.
+
+ @param text: the text to print
+ @type text: string"""
+
+ if text == esc_seq[0]: # \x1b -> reload format
self.setCurrentCharFormat(self.get_format())
else:
@@ -97,13 +114,16 @@ class QtConsole (Console, Qt.QTextEdit):
self.ensureCursorVisible()
def write(self, text):
+ """Convenience function for emitting the writing signal."""
self.emit(Qt.SIGNAL("doSomeWriting"), text)
def start_new_thread (self):
- self.run = True
- self.current = Thread(target=self.__run, name="QtTerminal Listener")
- self.current.setDaemon(True) # close application even if this thread is running
- self.current.start()
+ """Starts a new thread, which will listen for some input.
+ @see: QtTerminal.__run()"""
+ self.run = True
+ self.current = Thread(target=self.__run, name="QtTerminal Listener")
+ self.current.setDaemon(True) # close application even if this thread is running
+ self.current.start()
def set_pty (self, pty):
if not self.running:
@@ -111,21 +131,22 @@ class QtConsole (Console, Qt.QTextEdit):
self.start_new_thread()
self.running = True
- else:
- # quit current thread
+ else: # quit current thread
self.run = False
- # self.current.join()
self.clear()
self.pty = pty # set this after clearing to lose no chars :)
self.start_new_thread()
def __run (self):
+ """This function is mainly a loop, which looks for some new input at the terminal,
+ and parses it for text attributes."""
+
while self.run:
s = read(self.pty, 1)
- if s == "": break
+ if s == "": break # nothing read -> finish
- if ord(s) == backspace:
+ if ord(s) == backspace: # BS
self.emit(Qt.SIGNAL("deletePrevChar()"))
continue
@@ -154,9 +175,16 @@ class QtConsole (Console, Qt.QTextEdit):
self.write(s)
def parse_seq (self, seq):
- global attr
+ """Parses a sequence of bytes.
+ If a new attribute has been encountered, a new format is created and added
+ to the internal format queue.
+
+ @param seq: sequence to parse
+ @type seq: string"""
+
+ global attr # the dict of attributes
- format = self.virgin_format()
+ format = self.virgin_format()
if seq != reset_seq: # resettet -> done
seq = seq.split(seq_sep)
@@ -178,10 +206,9 @@ class QtConsole (Console, Qt.QTextEdit):
break
self.add_format(format)
- self.write(esc_seq[0])
+ self.write(esc_seq[0]) # write \x1b to signal the occurence of a new format
def parse_title (self, seq):
-
if not seq.startswith("0;"):
return
@@ -191,15 +218,31 @@ class QtConsole (Console, Qt.QTextEdit):
return self.title
def add_format (self, format):
+ """Adds a format to the queue.
+ We have to take a queue, because the write-signals might occur asynchronus,
+ so we set a format for the wrong characters.
+
+ @param format: the format to add
+ @type format: Qt.QTextCharFormat"""
+
self.formatLock.acquire()
self.formatQueue.append(format)
self.formatLock.release()
def get_format (self):
+ """Returns a format from the queue.
+ We have to take a queue, because the write-signals might occur asynchronus,
+ so we set a format for the wrong characters.
+
+ @returns: the popped format
+ @rtype: Qt.QTextCharFormat"""
+
self.formatLock.acquire()
f = self.formatQueue.pop(0)
self.formatLock.release()
return f
def virgin_format (self):
+ """The normal standard format. It is necessary to create it as a new one for some
+ dubious reasons ... only Qt.QGod knows why."""
return Qt.QTextCharFormat(self.stdFormat)
diff --git a/portato/gui/qt/ui/AboutDialog.ui b/portato/gui/qt/ui/AboutDialog.ui
index 5ed35e2..1424270 100644
--- a/portato/gui/qt/ui/AboutDialog.ui
+++ b/portato/gui/qt/ui/AboutDialog.ui
@@ -9,7 +9,7 @@
<x>0</x>
<y>0</y>
<width>369</width>
- <height>279</height>
+ <height>270</height>
</rect>
</property>
<property name="windowTitle" >
@@ -23,32 +23,91 @@
<number>6</number>
</property>
<item>
- <widget class="QLabel" name="label" >
- <property name="text" >
- <string>TextLabel</string>
- </property>
- <property name="alignment" >
- <set>Qt::AlignCenter</set>
- </property>
- <property name="wordWrap" >
- <bool>true</bool>
+ <widget class="QTabWidget" name="tabWidget" >
+ <property name="currentIndex" >
+ <number>0</number>
</property>
+ <widget class="QWidget" name="tab" >
+ <attribute name="title" >
+ <string>About</string>
+ </attribute>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>TextLabel</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="wordWrap" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tab_2" >
+ <attribute name="title" >
+ <string>Plugins</string>
+ </attribute>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QTreeWidget" name="pluginList" >
+ <property name="editTriggers" >
+ <set>QAbstractItemView::NoEditTriggers</set>
+ </property>
+ <property name="showDropIndicator" stdset="0" >
+ <bool>false</bool>
+ </property>
+ <property name="rootIsDecorated" >
+ <bool>false</bool>
+ </property>
+ <property name="columnCount" >
+ <number>2</number>
+ </property>
+ <column>
+ <property name="text" >
+ <string>1</string>
+ </property>
+ </column>
+ <column>
+ <property name="text" >
+ <string>1</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ </layout>
+ </widget>
</widget>
</item>
<item>
- <spacer>
- <property name="orientation" >
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" >
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
diff --git a/portato/gui/qt/ui/MainWindow.ui b/portato/gui/qt/ui/MainWindow.ui
index 80c5c12..5b8d0d9 100644
--- a/portato/gui/qt/ui/MainWindow.ui
+++ b/portato/gui/qt/ui/MainWindow.ui
@@ -403,7 +403,7 @@ p, li { white-space: pre-wrap; }
<height>27</height>
</rect>
</property>
- <widget class="QMenu" name="menuFile" >
+ <widget class="QMenu" name="fileMenu" >
<property name="title" >
<string>&amp;File</string>
</property>
@@ -412,13 +412,13 @@ p, li { white-space: pre-wrap; }
<addaction name="separator" />
<addaction name="quitAction" />
</widget>
- <widget class="QMenu" name="menuHelp" >
+ <widget class="QMenu" name="helpMenu" >
<property name="title" >
<string>&amp;?</string>
</property>
<addaction name="aboutAction" />
</widget>
- <widget class="QMenu" name="menu_Emerge" >
+ <widget class="QMenu" name="emergeMenu" >
<property name="title" >
<string>&amp;Emerge</string>
</property>
@@ -431,9 +431,9 @@ p, li { white-space: pre-wrap; }
<addaction name="separator" />
<addaction name="killAction" />
</widget>
- <addaction name="menuFile" />
- <addaction name="menu_Emerge" />
- <addaction name="menuHelp" />
+ <addaction name="fileMenu" />
+ <addaction name="emergeMenu" />
+ <addaction name="helpMenu" />
</widget>
<widget class="QStatusBar" name="statusbar" >
<property name="enabled" >
diff --git a/portato/gui/qt/windows.py b/portato/gui/qt/windows.py
index f6d5103..3fa93cf 100644
--- a/portato/gui/qt/windows.py
+++ b/portato/gui/qt/windows.py
@@ -22,6 +22,9 @@ from portato.backend.exceptions import *
from portato.gui.gui_helper import Database, Config, EmergeQueue
+# plugins
+from portato import plugin
+
# own GUI stuff
from terminal import QtConsole
from tree import QtTree
@@ -34,6 +37,10 @@ import types
UI_DIR = DATA_DIR+"ui/"
class WindowMeta (sip.wrappertype, type):
+ """This is the metaclass of all Qt-Windows. It automatically
+ sets the correct base classes, so they do not have to be set
+ by the programmer.
+ @attention: The class has to have the same name as the .ui-file."""
def __new__ (cls, name, bases, dict):
new_bases = uic.loadUiType(UI_DIR+name+".ui")
@@ -47,6 +54,8 @@ class WindowMeta (sip.wrappertype, type):
super(WindowMeta, cls).__init__(name, b+bases, dict)
class Window (object):
+ """Base class of all Qt-Windows.
+ Sets up the UI and provides the watch_cursor function."""
def __init__(self, parent = None):
self._qt_base.__init__(self, parent)
@@ -72,7 +81,14 @@ class AboutDialog (Window):
"""A window showing the "about"-informations."""
__metaclass__ = WindowMeta
- def __init__ (self, parent = None):
+ def __init__ (self, parent = None, plugins = []):
+ """Constructor.
+
+ @param parent: the parent window
+ @type parent: Qt.QWidget
+ @param plugins: The list of plugins (author,name) to show in the "Plugins"-Tab.
+ @type plugins: (string, string)[]"""
+
Window.__init__(self, parent)
self.label.setText("""
@@ -84,6 +100,13 @@ Copyright (C) 2006-2007 Ren&eacute; 'Necoro' Neumann &lt;necoro@necoro.net&gt;<b
<br>
<font size=1>Thanks to Fred for support and ideas :P</font>""" % VERSION)
+ self.pluginList.setHeaderLabels(["Plugin", "Author"])
+
+ for p in plugins:
+ Qt.QTreeWidgetItem(self.pluginList, list(p))
+
+ self.pluginList.resizeColumnToContents(0)
+
self.adjustSize()
class SearchDialog (Window):
@@ -114,10 +137,16 @@ class SearchDialog (Window):
self.jumpTo(s)
class EbuildDialog (Window):
-
+ """Window showing an ebuild."""
__metaclass__ = WindowMeta
def __init__ (self, parent, package):
+ """Constructor.
+
+ @param parent: parent window
+ @type parent: Qt.QWidget
+ @param package: The package to show the ebuild of.
+ @type package: backend.Package"""
Window.__init__(self, parent)
@@ -164,11 +193,18 @@ class PreferenceWindow (Window):
}
def __init__ (self, parent, cfg):
+ """Constructor.
+
+ @param parent: parent window
+ @type parent: Qt.QWidget
+ @param cfg: the actual configuration
+ @type cfg: Config"""
Window.__init__(self, parent)
self.cfg = cfg
+ # set hintLabel background
palette = self.hintLabel.palette()
palette.setColor(Qt.QPalette.Active, Qt.QPalette.Window, Qt.QColor(Qt.Qt.yellow))
self.hintLabel.setPalette(palette)
@@ -213,6 +249,7 @@ class PreferenceWindow (Window):
io_ex_dialog(self, e)
class PackageDetails:
+ """The tab showing the details of a package."""
def __init__ (self, window):
self.window = window
@@ -288,6 +325,8 @@ class PackageDetails:
self.window.tabWidget.setCurrentIndex(self.window.PKG_PAGE)
def set_combo (self):
+ """Fills the version combo box with the right items and selects the correct one."""
+
self.window.versCombo.clear()
self.window.versCombo.addItems([x.get_version() for x in self.packages])
@@ -305,6 +344,7 @@ class PackageDetails:
self.window.versCombo.setCurrentIndex(0)
def build_use_list (self):
+ """Builds the list of use flags."""
self.window.useList.clear()
self.window.useList.setHeaderLabels(["Enabled","Flag","Description"])
@@ -461,6 +501,10 @@ class PackageDetails:
def cb_combo_changed (self):
"""Callback for the changed ComboBox.
It then rebuilds the useList and the checkboxes."""
+
+ #
+ # ATTENTION: BIG'n'DIRTY :)
+ #
# build new
self.build_use_list()
@@ -522,6 +566,7 @@ class PackageDetails:
self.window.pkgUnmergeBtn.setEnabled(True)
class MainWindow (Window):
+ """The application's main window."""
__metaclass__ = WindowMeta
@@ -552,6 +597,16 @@ class MainWindow (Window):
self.cfg.modify_external_configs()
+ # set plugins and plugin-menu
+ plugin.load_plugins("qt")
+ menus = plugin.get_plugins().get_plugin_menus()
+ if menus:
+ self.pluginMenu = Qt.QMenu("&Plugins")
+ self.menubar.insertMenu(self.helpMenu.menuAction(), self.pluginMenu)
+ for m in menus:
+ action = self.pluginMenu.addAction(m.label.replace("_","&"))
+ Qt.QObject.connect(action, Qt.SIGNAL("triggered()"), m.call)
+
# the two lists
self.build_cat_list()
Qt.QObject.connect(self.selCatListModel, Qt.SIGNAL("currentChanged(QModelIndex, QModelIndex)"), self.cb_cat_list_selected)
@@ -624,7 +679,13 @@ class MainWindow (Window):
@Qt.pyqtSignature("")
def on_aboutAction_triggered (self):
- AboutDialog(self).exec_()
+ queue = plugin.get_plugins()
+ if queue is None:
+ queue = []
+ else:
+ queue = queue.get_plugin_data()
+
+ AboutDialog(self, queue).exec_()
@Qt.pyqtSignature("")
def on_prefAction_triggered (self):
diff --git a/portato/helper.py b/portato/helper.py
index cef3537..537d631 100644
--- a/portato/helper.py
+++ b/portato/helper.py
@@ -13,7 +13,6 @@
import traceback, os.path, sys
from itertools import chain
-
DEBUG = True
def set_debug (d):
@@ -32,7 +31,13 @@ def debug(*args, **kwargs):
If debug(obj0, obj1, obj2) is called, the text part of the output
looks like the output from print obj0, obj1, obj2.
- If you pass the optional keyword-argument "name", it is used for the function-name instead of the original one."""
+ Keywords which can be used:
+ - name: Use the given name instead the correct function name.
+ - file: output file to use
+ - minus: The value given is the amount of frames to ignore in the stack to return the correct function call.
+ This should be used if you are wrapping the debug call.
+ - warn: Prints the message as a warning. Value of DEBUG is ignored.
+ - error: Prints the message as an error. Value of DEBUG is ignored."""
if not DEBUG and not ("warn" in kwargs or "error" in kwargs): return
diff --git a/portato/plugin.py b/portato/plugin.py
index c6e3288..4c5070e 100644
--- a/portato/plugin.py
+++ b/portato/plugin.py
@@ -239,12 +239,15 @@ class Plugin:
class PluginQueue:
"""Class managing and loading the plugins."""
- def __init__ (self, load = True):
+ def __init__ (self, frontend, load = True):
"""Constructor.
-
+
+ @param frontend: the frontend used
+ @type frontend: string
@param load: if False nothing is loaded
@type load: bool"""
+ self.frontend = frontend
self.list = []
self.hooks = {}
if load:
@@ -343,12 +346,30 @@ class PluginQueue:
elem = list[0]
- plugin = Plugin(p, elem.getAttribute("name"), elem.getAttribute("author"))
- plugin.parse_hooks(elem.getElementsByTagName("hook"))
- plugin.set_import(elem.getElementsByTagName("import"))
- plugin.parse_menus(elem.getElementsByTagName("menu"))
+ frontendOK = None
+ for f in elem.getElementsByTagName("frontend"):
+ if f.hasChildNodes():
+ nodes = f.childNodes
+ if len(nodes) > 1:
+ raise ParseException, "Malformed frontend"
+
+ if nodes[0].nodeType != nodes[0].TEXT_NODE:
+ raise ParseException, "Malformed frontend"
+
+ fValue = nodes[0].nodeValue.strip()
+ if fValue == self.frontend:
+ frontendOK = True # one positive is enough
+ break
+ elif frontendOK is None: # do not make negative if we already have a positive
+ frontendOK = False
+
+ if frontendOK is None or frontendOK == True:
+ plugin = Plugin(p, elem.getAttribute("name"), elem.getAttribute("author"))
+ plugin.parse_hooks(elem.getElementsByTagName("hook"))
+ plugin.set_import(elem.getElementsByTagName("import"))
+ plugin.parse_menus(elem.getElementsByTagName("menu"))
- self.list.append(plugin)
+ self.list.append(plugin)
except ParseException, e:
error(e[0],p)
@@ -435,10 +456,10 @@ class PluginQueue:
__plugins = None
-def load_plugins():
+def load_plugins(frontend):
global __plugins
- if __plugins is None:
- __plugins = PluginQueue()
+ if __plugins is None or __plugins.frontend != frontend:
+ __plugins = PluginQueue(frontend)
def get_plugins():
return __plugins
diff --git a/portato/plugins/etc_proposals.py b/portato/plugins/etc_proposals.py
index cdf0a87..a064fff 100644
--- a/portato/plugins/etc_proposals.py
+++ b/portato/plugins/etc_proposals.py
@@ -13,8 +13,6 @@
from portato.helper import debug, am_i_root
from portato.backend import system
-from portato.gui.gtk.dialogs import not_root_dialog
-
from subprocess import Popen
from etcproposals.etcproposals_lib import EtcProposals, __version__
@@ -41,10 +39,10 @@ def etc_prop (*args, **kwargs):
Popen(["etc-proposals", "--frontend", "gtk", "--fastexit"])
def etc_prop_menu (*args, **kwargs):
- if not am_i_root():
- not_root_dialog()
- else:
+ if am_i_root():
if float(__version__) < 1.1:
Popen("etc-proposals")
else:
Popen(["etc-proposals", "--frontend", "gtk"])
+ else:
+ debug("Cannot start etc-proposals. Not root!", error = 1)