summaryrefslogtreecommitdiff
path: root/portato/gui
diff options
context:
space:
mode:
Diffstat (limited to 'portato/gui')
-rw-r--r--portato/gui/dialogs.py14
-rw-r--r--portato/gui/exception_handling.py5
-rw-r--r--portato/gui/queue.py2
-rw-r--r--portato/gui/templates/PluginWindow.glade180
-rw-r--r--portato/gui/utils.py10
-rw-r--r--portato/gui/windows/main.py22
-rw-r--r--portato/gui/windows/plugin.py162
7 files changed, 332 insertions, 63 deletions
diff --git a/portato/gui/dialogs.py b/portato/gui/dialogs.py
index 7f8a736..bf7acc7 100644
--- a/portato/gui/dialogs.py
+++ b/portato/gui/dialogs.py
@@ -21,8 +21,8 @@ def mail_failure_dialog(e):
return ret
def queue_not_empty_dialog():
- dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, gtk.BUTTONS_NONE, _("There are some packages in the emerge queue and/or an emerge process is running.\nDo you really want to quit?"))
- #dialog.add_buttons(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_YES, gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)
+ dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, gtk.BUTTONS_NONE, _("Do you really want to quit?"))
+ dialog.format_secondary_text(_("There are some packages in the emerge queue and/or an emerge process is running."))
dialog.add_buttons(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)
ret = dialog.run()
dialog.destroy()
@@ -40,7 +40,8 @@ def io_ex_dialog (io_ex):
return ret
def blocked_dialog (blocked, blocks):
- dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("%(blocked)s is blocked by %(blocks)s.\nPlease unmerge the blocking package.") % {"blocked":blocked, "blocks" : blocks})
+ dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("%(blocked)s is blocked by %(blocks)s.") % {"blocked":blocked, "blocks" : blocks})
+ dialog.format_secondary_text(_("Please unmerge the blocking package."))
ret = dialog.run()
dialog.destroy()
return ret
@@ -52,7 +53,8 @@ def not_root_dialog ():
return ret
def unmask_dialog (cpv):
- dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, _("%s seems to be masked.\nDo you want to unmask it and its dependencies?") % cpv)
+ dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, _("%s seems to be masked.") % cpv )
+ dialog.format_secondary_text(_("Do you want to unmask it and its dependencies?"))
ret = dialog.run()
dialog.destroy()
return ret
@@ -65,8 +67,8 @@ def nothing_found_dialog ():
def changed_flags_dialog (what = "flags"):
check = gtk.CheckButton(_("Do not show this dialog again."))
- hintMB = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK,
- _("You have changed %s.\nPortato will write these changes into the appropriate files.\nPlease backup them if you think it is necessairy.") % what)
+ hintMB = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, _("Changed %s") % what)
+ hintMB.format_secondary_text(_("Portato will write these changes into the appropriate files.\nPlease backup them if you think it is necessairy."))
hintMB.vbox.add(check)
hintMB.vbox.show_all()
ret = hintMB.run()
diff --git a/portato/gui/exception_handling.py b/portato/gui/exception_handling.py
index eadf124..dae95ed 100644
--- a/portato/gui/exception_handling.py
+++ b/portato/gui/exception_handling.py
@@ -100,16 +100,13 @@ def convert (version):
def get_version_infos():
from ..constants import VERSION
from ..backend import system
- from lxml import etree
return "\n".join((
"Portato version: %s" % VERSION,
"Python version: %s" % sys.version,
"Used backend: %s" % system.get_version(),
"pygtk: %s (using GTK+: %s)" % (convert(gtk.pygtk_version), convert(gtk.gtk_version)),
- "pygobject: %s (using GLib: %s)" % (convert(gobject.pygobject_version), convert(gobject.glib_version)),
- "lxml: %s" % convert(etree.LXML_VERSION),
- ""))
+ "pygobject: %s (using GLib: %s)" % (convert(gobject.pygobject_version), convert(gobject.glib_version))))
def get_trace(type, value, tb):
trace = StringIO()
diff --git a/portato/gui/queue.py b/portato/gui/queue.py
index cb5b334..c04d449 100644
--- a/portato/gui/queue.py
+++ b/portato/gui/queue.py
@@ -248,9 +248,9 @@ class EmergeQueue:
self.update_tree(parentIt, cpv, unmask, oneshot = oneshot, type = type)
else: # not update
if type == "install":
- self._queue_append(cpv, oneshot)
if self.tree:
self.update_tree(self.tree.get_emerge_it(), cpv, unmask, type = type, oneshot = oneshot)
+ self._queue_append(cpv, oneshot)
elif type == "update" and self.tree:
self.update_tree(self.tree.get_update_it(), cpv, unmask, type = type, oneshot = oneshot)
diff --git a/portato/gui/templates/PluginWindow.glade b/portato/gui/templates/PluginWindow.glade
index 1de5fc0..f76193e 100644
--- a/portato/gui/templates/PluginWindow.glade
+++ b/portato/gui/templates/PluginWindow.glade
@@ -1,11 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
-<!--Generated with glade3 3.4.1 on Fri Feb 29 00:03:30 2008 -->
+<!--Generated with glade3 3.4.5 on Fri Jul 4 15:24:27 2008 -->
<glade-interface>
<widget class="GtkWindow" id="PluginWindow">
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Plugins</property>
+ <property name="resizable">False</property>
<property name="modal">True</property>
<property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
<property name="destroy_with_parent">True</property>
@@ -26,6 +27,7 @@
<child>
<widget class="GtkTreeView" id="pluginList">
<property name="visible">True</property>
+ <property name="headers_visible">False</property>
<property name="rules_hint">True</property>
<property name="enable_search">False</property>
</widget>
@@ -33,6 +35,180 @@
</widget>
</child>
<child>
+ <widget class="GtkFrame" id="frame1">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <child>
+ <widget class="GtkTable" id="table1">
+ <property name="visible">True</property>
+ <property name="n_rows">4</property>
+ <property name="n_columns">2</property>
+ <property name="row_spacing">10</property>
+ <child>
+ <widget class="GtkButton" id="installBtn">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">_Install dependencies</property>
+ <property name="use_underline">True</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="cb_install_clicked"/>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ <property name="x_padding">10</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkExpander" id="depExpander">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <widget class="GtkTreeView" id="depList">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">False</property>
+ <property name="headers_clickable">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Needed dependencies</property>
+ <property name="single_line_mode">True</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_padding">10</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="descrLabel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">label</property>
+ </widget>
+ <packing>
+ <property name="right_attach">2</property>
+ <property name="y_options">GTK_FILL</property>
+ <property name="y_padding">10</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Author:&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ <property name="single_line_mode">True</property>
+ </widget>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="authorLabel">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">label</property>
+ <property name="single_line_mode">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHButtonBox" id="buttonBox">
+ <property name="visible">True</property>
+ <property name="spacing">5</property>
+ <property name="homogeneous">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_EDGE</property>
+ <child>
+ <widget class="GtkRadioButton" id="enabledRB">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Enabled</property>
+ <property name="response_id">0</property>
+ <property name="active">True</property>
+ <signal name="toggled" handler="cb_state_toggled"/>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkRadioButton" id="tempEnabledRB">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Temporarily enabled</property>
+ <property name="response_id">0</property>
+ <property name="group">enabledRB</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkRadioButton" id="tempDisabledRB">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Temporarily disabled</property>
+ <property name="response_id">0</property>
+ <property name="group">enabledRB</property>
+ <signal name="toggled" handler="cb_state_toggled"/>
+ </widget>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkRadioButton" id="disabledRB">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Disabled</property>
+ <property name="response_id">0</property>
+ <property name="group">enabledRB</property>
+ <signal name="toggled" handler="cb_state_toggled"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <placeholder/>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
<widget class="GtkHButtonBox" id="hbuttonbox2">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
@@ -68,7 +244,7 @@
</widget>
<packing>
<property name="expand">False</property>
- <property name="position">1</property>
+ <property name="position">2</property>
</packing>
</child>
</widget>
diff --git a/portato/gui/utils.py b/portato/gui/utils.py
index a4e1e6e..923f2fa 100644
--- a/portato/gui/utils.py
+++ b/portato/gui/utils.py
@@ -24,7 +24,7 @@ from functools import wraps
# some backend things
from ..backend import flags, system, set_system
from ..helper import debug, info, set_log_level
-from ..constants import USE_CATAPULT, APP, LOCALE_DIR
+from ..constants import APP, LOCALE_DIR
# parser
from ..config_parser import ConfigParser
@@ -86,8 +86,7 @@ class Config (ConfigParser):
def modify_system_config (self):
"""Sets the system config.
@see: L{backend.set_system()}"""
- if not USE_CATAPULT:
- set_system(self.get("system"))
+ set_system(self.get("system"))
def modify_external_configs (self):
"""Convenience function setting all external configs."""
@@ -132,7 +131,8 @@ class Config (ConfigParser):
ConfigParser.write(self)
self.modify_external_configs()
-class PkgData:
+class PkgData (object):
+ __slots__ = ("cat", "pkg", "inst")
def __init__ (self, cat, pkg, inst):
self.cat = cat
@@ -146,7 +146,7 @@ class PkgData:
return cmp(self.pkg.lower(), other.pkg.lower())
def __repr__ (self):
- return "<Package (%(cat)s, %(pkg)s, %(inst)s)>" % self.__dict__
+ return "<Package (%(cat)s, %(pkg)s, %(inst)s)>" % {"cat" : self.cat, "pkg" : self.pkg, "inst" : self.inst}
class Database (object):
"""An internal database which holds a simple dictionary cat -> [package_list]."""
diff --git a/portato/gui/windows/main.py b/portato/gui/windows/main.py
index 188a5e1..50dd366 100644
--- a/portato/gui/windows/main.py
+++ b/portato/gui/windows/main.py
@@ -607,13 +607,13 @@ class MainWindow (Window):
# set plugins and plugin-menu
splash(_("Loading Plugins"))
- plugin.load_plugins("gtk")
- menus = plugin.get_plugin_queue().get_plugin_menus()
+ plugin.load_plugins()
+ menus = [p.menus for p in plugin.get_plugin_queue().get_plugins()]
if menus:
self.tree.get_widget("pluginMenuItem").set_no_show_all(False)
pluginMenu = self.tree.get_widget("pluginMenu")
- for m in menus:
+ for m in itt.chain(*menus):
item = gtk.MenuItem(m.label)
item.connect("activate", m.call)
pluginMenu.append(item)
@@ -1082,13 +1082,11 @@ class MainWindow (Window):
def save_plugin (p):
def _save ():
- stat_on = p.status >= p.STAT_ENABLED
- hard_on = not p.get_option("disabled")
-
- if stat_on != hard_on:
- return int(stat_on)
- else:
+ if p.status == p.STAT_HARD_DISABLED:
return ""
+
+ return int(p.status >= p.STAT_ENABLED)
+
return _save
# SESSION VERSION
@@ -1559,9 +1557,9 @@ class MainWindow (Window):
if queue is None:
plugins = []
else:
- plugins = queue.get_plugins()
-
- PluginWindow(self.window, plugins)
+ plugins = list(queue.get_plugins())
+
+ PluginWindow(self.window, plugins, self.queue)
return True
def cb_show_updates_clicked (self, *args):
diff --git a/portato/gui/windows/plugin.py b/portato/gui/windows/plugin.py
index fb9446e..a0694be 100644
--- a/portato/gui/windows/plugin.py
+++ b/portato/gui/windows/plugin.py
@@ -15,6 +15,9 @@ from __future__ import absolute_import
import gtk
from .basic import AbstractDialog
+from ..dialogs import blocked_dialog, unmask_dialog
+from ...backend import system
+from ...backend.exceptions import PackageNotFoundException, BlockedException
from ...helper import debug
class PluginWindow (AbstractDialog):
@@ -24,7 +27,7 @@ class PluginWindow (AbstractDialog):
for s in (_("Disabled"), _("Temporarily enabled"), _("Enabled"), _("Temporarily disabled")):
statsStore.append([s])
- def __init__ (self, parent, plugins):
+ def __init__ (self, parent, plugins, queue = None):
"""Constructor.
@param parent: the parent window
@@ -32,50 +35,77 @@ class PluginWindow (AbstractDialog):
AbstractDialog.__init__(self, parent)
self.plugins = plugins
+ self.queue = queue
self.changedPlugins = {}
+ self.inst = []
+ self.ninst = []
- view = self.tree.get_widget("pluginList")
- self.store = gtk.ListStore(str,str,str)
+ self.buttons = map(self.tree.get_widget, ("disabledRB", "tempEnabledRB", "enabledRB", "tempDisabledRB"))
+ map(lambda b: b.set_mode(False), self.buttons)
+
+ self.descrLabel = self.tree.get_widget("descrLabel")
+ self.authorLabel = self.tree.get_widget("authorLabel")
+
+ self.depExpander = self.tree.get_widget("depExpander")
+ self.installBtn = self.tree.get_widget("installBtn")
+ self.depList = self.tree.get_widget("depList")
+ self.build_dep_list()
+
+ self.buttonBox = self.tree.get_widget("buttonBox")
+
+ self.instIcon = self.window.render_icon(gtk.STOCK_YES, gtk.ICON_SIZE_MENU)
- view.set_model(self.store)
+ self.view = self.tree.get_widget("pluginList")
+ self.store = gtk.ListStore(str)
- cell = gtk.CellRendererText()
- col = gtk.TreeViewColumn(_("Plugin"), cell, markup = 0)
- view.append_column(col)
+ self.view.set_model(self.store)
- col = gtk.TreeViewColumn(_("Authors"), cell, text = 1)
- view.append_column(col)
-
- ccell = gtk.CellRendererCombo()
- ccell.set_property("model", self.statsStore)
- ccell.set_property("text-column", 0)
- ccell.set_property("has-entry", False)
- ccell.set_property("editable", True)
- ccell.connect("edited", self.cb_status_changed)
- col = gtk.TreeViewColumn(_("Status"), ccell, markup = 2)
- view.append_column(col)
+ cell = gtk.CellRendererText()
+ col = gtk.TreeViewColumn("Plugin", cell, markup = 0)
+ self.view.append_column(col)
- for p in (("<b>"+p.name+"</b>", p.author, _(self.statsStore[p.status][0])) for p in plugins):
- self.store.append(p)
+ for p in plugins:
+ self.store.append(["<b>%s</b>" % p.name])
+
+ self.view.get_selection().connect("changed", self.cb_list_selection)
self.window.show_all()
- def cb_status_changed (self, cell, path, new_text):
- path = int(path)
-
- self.store[path][2] = "<b>%s</b>" % new_text
+ def build_dep_list (self):
+ store = gtk.ListStore(gtk.gdk.Pixbuf, str)
+
+ self.depList.set_model(store)
+
+ col = gtk.TreeViewColumn()
+
+ cell = gtk.CellRendererPixbuf()
+ col.pack_start(cell, False)
+ col.add_attribute(cell, "pixbuf", 0)
+
+ cell = gtk.CellRendererText()
+ col.pack_start(cell, True)
+ col.add_attribute(cell, "text", 1)
+
+ self.depList.append_column(col)
+
+ def fill_dep_list (self, inst = [], ninst = []):
+ store = self.depList.get_model()
+ store.clear()
+
+ for dep in inst:
+ store.append([self.instIcon, dep])
+ for dep in ninst:
+ store.append([None, dep])
- # convert string to constant
- const = None
- for num, val in enumerate(self.statsStore):
- if val[0] == new_text:
- const = num
- break
+ def cb_state_toggled (self, rb):
+
+ plugin = self.get_actual()
- assert (const is not None)
+ if plugin:
+ state = self.buttons.index(rb)
- self.changedPlugins.update({self.plugins[path] : const})
- debug("new changed plugins: %s => %d", self.plugins[path].name, const)
+ self.changedPlugins[plugin] = state
+ debug("new changed plugins: %s => %d", plugin.name, state)
def cb_ok_clicked (self, btn):
for plugin, val in self.changedPlugins.iteritems():
@@ -83,3 +113,69 @@ class PluginWindow (AbstractDialog):
self.close()
return True
+
+ def cb_list_selection (self, selection):
+ plugin = self.get_actual()
+ self.inst = []
+ self.ninst = []
+
+ if plugin:
+ if not plugin.description:
+ self.descrLabel.hide()
+ else:
+ self.descrLabel.set_markup(plugin.description)
+ self.descrLabel.show()
+
+ self.authorLabel.set_label(plugin.author)
+
+ status = self.changedPlugins.get(plugin, plugin.status)
+ self.buttons[status].set_active(True)
+
+ if plugin.deps:
+
+ for dep in plugin.deps:
+ if system.find_packages(dep, pkgSet = system.SET_INSTALLED, with_version = False):
+ self.inst.append(dep)
+ else:
+ self.ninst.append(dep)
+
+ self.fill_dep_list(self.inst, self.ninst)
+ self.depExpander.show()
+
+ self.installBtn.show()
+ self.installBtn.set_sensitive(bool(self.ninst))
+
+ else:
+ self.installBtn.hide()
+ self.depExpander.hide()
+
+ self.buttonBox.set_sensitive(not plugin._unresolved_deps and plugin.status != plugin.STAT_HARD_DISABLED)
+
+ def cb_install_clicked (self, *args):
+ if not self.queue:
+ return False
+
+ for cpv in self.ninst:
+
+ pkg = system.find_best_match(cpv, masked = False, only_cpv = True)
+ if not pkg:
+ pkg = system.find_best_match(cpv, masked = True, only_cpv = True)
+
+ try:
+ try:
+ self.queue.append(pkg, type = "install")
+ except PackageNotFoundException, e:
+ if unmask_dialog(e[0]) == gtk.RESPONSE_YES:
+ self.queue.append(pkg, type = "install", unmask = True)
+ except BlockedException, e:
+ blocked_dialog(e[0], e[1])
+
+ return True
+
+ def get_actual (self):
+ store, it = self.view.get_selection().get_selected()
+
+ if it:
+ return self.plugins[int(store.get_path(it)[0])]
+ else:
+ return None