From 2d2f6823f5360a5287b4b19d035cad4a5611fa3a Mon Sep 17 00:00:00 2001 From: necoro <> Date: Sat, 31 Mar 2007 19:29:26 +0000 Subject: Allowed Plugins to have a menu --- plugins/etc_proposals.xml | 5 + portato.py | 9 +- portato/gui/gtk/glade/portato.glade | 394 +++++++++++++++++++----------------- portato/gui/gtk/windows.py | 13 +- portato/helper.py | 12 ++ portato/plugin.py | 69 ++++++- portato/plugins/etc_proposals.py | 14 +- 7 files changed, 315 insertions(+), 201 deletions(-) diff --git a/plugins/etc_proposals.xml b/plugins/etc_proposals.xml index 5690b98..e4569e1 100644 --- a/plugins/etc_proposals.xml +++ b/plugins/etc_proposals.xml @@ -10,4 +10,9 @@ call = "etc_prop"> + + diff --git a/portato.py b/portato.py index 4db4b0e..3a81dec 100755 --- a/portato.py +++ b/portato.py @@ -15,7 +15,7 @@ from portato.constants import VERSION, FRONTENDS, STD_FRONTEND import sys -if __name__ == "__main__": +def main (): uimod = STD_FRONTEND for arg in sys.argv[1:]: @@ -41,8 +41,8 @@ Written by René 'Necoro' Neumann """ % VERSION if uimod in FRONTENDS: try: exec ("from portato.gui.%s import run" % uimod) - except ImportError: - print "'%s' should be installed, but cannot be imported. This is definitly a bug." % uimod + except ImportError, e: + print "'%s' should be installed, but cannot be imported. This is definitly a bug. (%s)" % (uimod, e[0]) sys.exit(1) else: print ("Unknown interface '%s'. Correct interfaces are:" % uimod) , @@ -52,3 +52,6 @@ Written by René 'Necoro' Neumann """ % VERSION sys.exit(1) run() + +if __name__ == "__main__": + main() diff --git a/portato/gui/gtk/glade/portato.glade b/portato/gui/gtk/glade/portato.glade index 89f52d2..7735975 100644 --- a/portato/gui/gtk/glade/portato.glade +++ b/portato/gui/gtk/glade/portato.glade @@ -255,6 +255,18 @@ + + + True + _Plugins + True + + + True + + + + True @@ -389,72 +401,48 @@ 4 2 - + True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC + 1 + True - + True + True + Installed + True + + + False + - - - 2 - 2 - 3 - 5 - 5 - - - - - True - + + True + True + Masked + True + + + + False + 1 + + + + + True + True + Testing + True + + + + False + 2 + - - - 1 - 2 - GTK_FILL - 5 - - - - - True - GTK_JUSTIFY_CENTER - True - - - 2 - GTK_FILL - - 10 - - - - - True - True - <span foreground='red'><b>MISSING KEYWORD</b></span> - True - - - 1 - 2 - 1 - 2 - GTK_FILL - - - - - True - True - <b>Installed, but not in portage anymore</b> - True 1 @@ -519,55 +507,79 @@ - + + True + True + <b>Installed, but not in portage anymore</b> + True + + + 1 + 2 + 1 + 2 + GTK_FILL + + + + + True + True + <span foreground='red'><b>MISSING KEYWORD</b></span> + True + + + 1 + 2 + 1 + 2 + GTK_FILL + + + + + True + GTK_JUSTIFY_CENTER + True + + + 2 + GTK_FILL + + 10 + + + + True - 1 - True - - True - True - Installed - True - - - - False - + + + + 1 + 2 + GTK_FILL + 5 + + + + + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC - + True - True - Masked - True - - - False - 1 - - - - - True - True - Testing - True - - - - False - 2 - - 1 2 - 1 - 2 - GTK_FILL + 2 + 3 + 5 + 5 @@ -1077,186 +1089,186 @@ - - True - 0 - 5 - <u><i>Masking Keywords</i></u> - True - True - - - 7 - 8 - 5 - - - - + True - 0 - 5 - <u><i>Testing Keywords</i></u> - True - True - 4 - 5 - 5 + 1 + 2 + 3 + 4 - + True 0 - 5 - <u><i>Use-Flags</i></u> - True + File name to use, if package.use is a directory: True - 1 - 2 - 6 + 3 + 4 - + True - - - True - 0 - GTK_SHADOW_OUT - - - True - 0 - <u>You may use the following placeholders:</u> - - <i>$(cat)</i>: category - <i>$(pkg)</i>: package name - <i>$(cat-1)/$(cat-2)</i>: first/second part of the category - True - - - - - - label_item - - - - + Add only exact version to package.use + True 2 + 2 + 3 - + True - Add only exact version to package.mask/package.unmask + Add only exact version to package.keywords True 2 - 8 - 9 + 5 + 6 - + True 0 - File name to use, if package.mask/package.unmask is a directory: + File name to use, if package.keywords is a directory: True - 9 - 10 + 6 + 7 - + True 1 2 - 9 - 10 + 6 + 7 - + True 1 2 - 6 - 7 + 9 + 10 - + True 0 - File name to use, if package.keywords is a directory: + File name to use, if package.mask/package.unmask is a directory: True - 6 - 7 + 9 + 10 - + True - Add only exact version to package.keywords + Add only exact version to package.mask/package.unmask True 2 - 5 - 6 + 8 + 9 - + True - Add only exact version to package.use - True + + + True + 0 + GTK_SHADOW_OUT + + + True + 0 + <u>You may use the following placeholders:</u> + + <i>$(cat)</i>: category + <i>$(pkg)</i>: package name + <i>$(cat-1)/$(cat-2)</i>: first/second part of the category + True + + + + + + label_item + + + + 2 - 2 - 3 - + True 0 - File name to use, if package.use is a directory: + 5 + <u><i>Use-Flags</i></u> + True True - 3 - 4 + 1 + 2 + 6 - + + True + 0 + 5 + <u><i>Testing Keywords</i></u> + True + True + + + 4 + 5 + 5 + + + + True + 0 + 5 + <u><i>Masking Keywords</i></u> + True + True - 1 - 2 - 3 - 4 + 7 + 8 + 5 diff --git a/portato/gui/gtk/windows.py b/portato/gui/gtk/windows.py index a27d156..2de772f 100644 --- a/portato/gui/gtk/windows.py +++ b/portato/gui/gtk/windows.py @@ -530,7 +530,8 @@ class PackageTable: try: self.queue.append(self.actual_package().get_cpv(), unmerge = True) except PackageNotFoundException, e: - masked_dialog(e[0]) + debug("Package could not be found",e[0], error = 1) + #masked_dialog(e[0]) def cb_combo_changed (self, combo): """Callback for the changed ComboBox. @@ -720,7 +721,17 @@ class MainWindow (Window): self.cfg.modify_external_configs() + # set plugins and plugin-menu plugin.load_plugins() + menus = plugin.get_plugins().get_plugin_menus() + if menus: + self.tree.get_widget("pluginMenuItem").set_no_show_all(False) + pluginMenu = self.tree.get_widget("pluginMenu") + + for m in menus: + item = gtk.MenuItem(m.label) + item.connect("activate", m.call) + pluginMenu.append(item) # set vpaned position vpaned = self.tree.get_widget("vpaned") diff --git a/portato/helper.py b/portato/helper.py index b41dbbe..604f2c1 100644 --- a/portato/helper.py +++ b/portato/helper.py @@ -11,6 +11,8 @@ # Written by René 'Necoro' Neumann et.al. import traceback, os.path, sys +from itertools import chain + DEBUG = True @@ -77,6 +79,16 @@ def am_i_root (): else: return False +def flatten (listOfLists): + """Flattens the given list of lists. + + @param listOfLists: the list of lists to flatten + @type listOfLists: list of lists + @returns: flattend list + @rtyoe: list""" + + return list(chain(*listOfLists)) + def unique_array(s): """Stolen from portage_utils: lifted from python cookbook, credit: Tim Peters diff --git a/portato/plugin.py b/portato/plugin.py index 4ce4099..c6e3288 100644 --- a/portato/plugin.py +++ b/portato/plugin.py @@ -14,7 +14,7 @@ import os, os.path from xml.dom.minidom import parse from constants import PLUGIN_DIR -from helper import debug +from helper import debug, flatten class ParseException (Exception): pass @@ -23,6 +23,46 @@ def error (reason, p): reason = "("+reason+")" debug("Malformed plugin:", p, reason, minus=1, error = 1) +class Menu: + """A single -element.""" + def __init__ (self, plugin, label, call): + """Constructor. + + @param plugin: the plugin this menu belongs to + @type plugin: Plugin + @param label: the label to show + @type label: string + @param call: the function to call relative to the import statement + @type call: string + + @raises ParseException: on parsing errors""" + + if not label: + raise ParseException, "label attribute missing" + + if not call: + raise ParseException, "call attribute missing" + + self.label = label + self.plugin = plugin + + if self.plugin.needs_import(): # get import + imp = self.plugin.get_import() + try: + mod = __import__(imp, globals(), locals(), [call]) + except ImportError: + raise ParseException, imp+" cannot be imported" + + try: + self.call = eval("mod."+call) # build function + except AttributeError: + raise ParseException, call+" cannot be imported" + else: + try: + self.call = eval(call) + except AttributeError: + raise ParseException, call+" cannot be imported" + class Connect: """A single -element.""" @@ -129,6 +169,7 @@ class Plugin: self.author = author self._import = None self.hooks = [] + self.menus = [] def parse_hooks (self, hooks): """Gets a list of -elements and parses them. @@ -143,6 +184,18 @@ class Plugin: hook.parse_connects(h.getElementsByTagName("connect")) self.hooks.append(hook) + def parse_menus (self, menus): + """Gets a list of -elements and parses them. + + @param menus: the list of elements + @type menus: NodeList + + @raises ParseException: on parsing errors""" + + for m in menus: + menu = Menu(self, m.getAttribute("label"), m.getAttribute("call")) + self.menus.append(menu) + def set_import (self, imports): """This gets a list of imports and parses them - setting the import needed to call the plugin. @@ -200,6 +253,9 @@ class PluginQueue: def get_plugin_data (self): return [(x.name, x.author) for x in self.list] + def get_plugin_menus (self): + return flatten([x.menus for x in self.list]) + def hook (self, hook, *hargs, **hkwargs): """This is a method taking care of calling the plugins. @@ -230,9 +286,15 @@ class PluginQueue: debug(imp,"cannot be imported", error = 1) return - f = eval("mod."+cmd.hook.call) # build function + try: + f = eval("mod."+cmd.hook.call) # build function + except AttributeError: + debug(cmd.hook.call,"cannot be imported", error = 1) else: - f = eval(cmd.hook.call) + try: + f = eval(cmd.hook.call) + except AttributeError: + debug(cmd.hook.call,"cannot be imported", error = 1) f(*hargs, **hkwargs) # call function @@ -284,6 +346,7 @@ class PluginQueue: 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) diff --git a/portato/plugins/etc_proposals.py b/portato/plugins/etc_proposals.py index bf58c06..e830115 100644 --- a/portato/plugins/etc_proposals.py +++ b/portato/plugins/etc_proposals.py @@ -10,10 +10,12 @@ # # Written by René 'Necoro' Neumann -from portato.helper import debug +from portato.helper import debug, am_i_root from portato.backend import system -import os +from portato.gui.gtk.dialogs import not_root_dialog + +from subprocess import Popen from etcproposals.etcproposals_lib import EtcProposals class PortatoEtcProposals(EtcProposals): @@ -32,4 +34,10 @@ def etc_prop (*args, **kwargs): debug(l,"files to update") if l > 0: - os.system("etc-proposals") + Popen("etc-proposals") + +def etc_prop_menu (*args, **kwargs): + if not am_i_root(): + not_root_dialog() + else: + Popen("etc-proposals") -- cgit v1.2.3