From 53f4e6ccd74d217409ec38b506d7e7e4aeb7d738 Mon Sep 17 00:00:00 2001
From: Necoro <>
Date: Fri, 18 Jan 2008 01:36:13 +0000
Subject: r643@Devoty: necoro | 2008-01-16 18:55:49 +0100 Fixed small bug in
PackageTable.cb_package_revert_clicked r646@Devoty: necoro | 2008-01-18
00:12:30 +0100 Make tabpositions being configurable by the user
r647@Devoty: necoro | 2008-01-18 01:38:19 +0100 Renamed 'shm' to '_shm' to
not hide the global one r648@Devoty: necoro | 2008-01-18 01:38:29 +0100
Renamed 'shm' to '_shm' to not hide the global one r649@Devoty: necoro |
2008-01-18 02:34:43 +0100 Added update queues; general UI improvement
---
portato/gui/gtk/dialogs.py | 6 +
portato/gui/gtk/windows.py | 153 ++++++++----
portato/gui/gtk/wrapper.py | 38 ++-
portato/gui/gui_helper.py | 66 ++++--
portato/gui/templates/portato.glade | 455 +++++++++++++++++++++++-------------
portato/gui/wrapper.py | 34 +++
6 files changed, 508 insertions(+), 244 deletions(-)
(limited to 'portato/gui')
diff --git a/portato/gui/gtk/dialogs.py b/portato/gui/gtk/dialogs.py
index 7bea2b8..7a1f28d 100644
--- a/portato/gui/gtk/dialogs.py
+++ b/portato/gui/gtk/dialogs.py
@@ -68,6 +68,12 @@ def remove_deps_dialog ():
infoMB.destroy()
return ret
+def remove_updates_dialog():
+ askMB = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, _("This is the updates queue. You cannot remove single elements.\nDo you want to clear the whole queue instead?"))
+ ret = askMB.run()
+ askMB.destroy()
+ return ret
+
def remove_queue_dialog ():
askMB = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, _("Do you really want to clear the whole queue?"))
ret = askMB.run()
diff --git a/portato/gui/gtk/windows.py b/portato/gui/gtk/windows.py
index 3f5255f..d8366a0 100644
--- a/portato/gui/gtk/windows.py
+++ b/portato/gui/gtk/windows.py
@@ -37,7 +37,7 @@ from .exception_handling import GtkThread
from .views import LogView, HighlightView, InstalledOnlyView
from .dialogs import (blocked_dialog, changed_flags_dialog, io_ex_dialog,
nothing_found_dialog, queue_not_empty_dialog, remove_deps_dialog,
- remove_queue_dialog, unmask_dialog)
+ remove_queue_dialog, remove_updates_dialog, unmask_dialog)
class AboutWindow (AbstractDialog):
"""A window showing the "about"-informations."""
@@ -304,23 +304,37 @@ class PreferenceWindow (AbstractDialog):
"browserEdit" : ("browserCmd", "GUI")
}
- def __init__ (self, parent, cfg, set_console_font):
+ # the mappings for the tabpos combos
+ tabpos = {
+ 1 : gtk.POS_TOP,
+ 2 : gtk.POS_BOTTOM,
+ 3 : gtk.POS_LEFT,
+ 4 : gtk.POS_RIGHT
+ }
+
+ def __init__ (self, parent, cfg, console_fn, linkbtn_fn, tabpos_fn):
"""Constructor.
@param parent: parent window
@type parent: gtk.Window
@param cfg: configuration object
@type cfg: gui_helper.Config
- @param set_console_font: function to call to set the console font
- @type set_console_font: function(string)"""
+ @param console_fn: function to call to set the console font
+ @type console_fn: function(string)
+ @param linkbtn_fn: function to call to set the linkbutton behavior
+ @type linkbtn_fn: function(string)
+ @param tabpos_fn: function to call to set the tabposition of the notebooks
+ @type tabpos_fn: function(gtk.ComboBox,int)"""
AbstractDialog.__init__(self, parent)
# our config
self.cfg = cfg
- # the console font setter
- self.set_console_font = set_console_font
+ # the setter functions
+ self.console_fn = console_fn
+ self.linkbtn_fn = linkbtn_fn
+ self.tabpos_fn = tabpos_fn
# set the bg-color of the hint
hintEB = self.tree.get_widget("hintEB")
@@ -348,6 +362,19 @@ class PreferenceWindow (AbstractDialog):
self.consoleFontBtn = self.tree.get_widget("consoleFontBtn")
self.consoleFontBtn.set_font_name(self.cfg.get("consolefont", section = "GTK"))
+ # the comboboxes
+ self.systemTabCombo = self.tree.get_widget("systemTabCombo")
+ self.pkgTabCombo = self.tree.get_widget("packageTabCombo")
+
+ for c in (self.systemTabCombo, self.pkgTabCombo):
+ m = c.get_model()
+ m.clear()
+ for i in (_("Top"), _("Bottom"), _("Left"), _("Right")):
+ m.append((i,))
+
+ self.systemTabCombo.set_active(int(self.cfg.get("systemTabPos", section = "GTK"))-1)
+ self.pkgTabCombo.set_active(int(self.cfg.get("packageTabPos", section = "GTK"))-1)
+
self.window.show_all()
def _save(self):
@@ -367,9 +394,17 @@ class PreferenceWindow (AbstractDialog):
font = self.consoleFontBtn.get_font_name()
self.cfg.set("consolefont", font, section = "GTK")
- self.set_console_font(font)
+ self.console_fn(font)
+
+ pkgPos = self.pkgTabCombo.get_active()+1
+ sysPos = self.systemTabCombo.get_active()+1
+
+ self.cfg.set("packageTabPos", str(pkgPos), section = "GTK")
+ self.cfg.set("systemTabPos", str(sysPos), section = "GTK")
+
+ self.tabpos_fn(map(self.tabpos.get, (pkgPos, sysPos)))
- gtk.link_button_set_uri_hook(lambda btn, x: get_listener().send_cmd([self.cfg.get("browserCmd", section = "GUI"), btn.get_uri()]))
+ self.linkbtn_fn(self.cfg.get("browserCmd", section="GUI"))
def cb_ok_clicked(self, button):
"""Saves, writes to config-file and closes the window."""
@@ -642,15 +677,15 @@ class PackageTable:
if emerge:
try:
try:
- self.queue.append(self.actual_package().get_cpv(), unmerge = False, update = update)
+ self.queue.append(self.actual_package().get_cpv(), type = "install", update = update)
except PackageNotFoundException, e:
if unmask_dialog(e[0]) == gtk.RESPONSE_YES:
- self.queue.append(self.actual_package().get_cpv(), unmerge = False, unmask = True, update = update)
+ self.queue.append(self.actual_package().get_cpv(), type = "install", unmask = True, update = update)
except BlockedException, e:
blocked_dialog(e[0], e[1])
else:
try:
- self.queue.append(self.actual_package().get_cpv(), unmerge = True)
+ self.queue.append(self.actual_package().get_cpv(), type = "uninstall")
except PackageNotFoundException, e:
error(_("Package could not be found: %s"), e[0])
#masked_dialog(e[0])
@@ -752,9 +787,9 @@ class PackageTable:
self.actual_package().remove_new_use_flags()
self.actual_package().remove_new_masked()
self.actual_package().remove_new_testing()
- self.versList.get_model().clear()
- self.fill_vers_list()
- self.cb_vers_list_changed()
+ self.versionCombo.get_model().clear()
+ self.fill_version_combo()
+ self.cb_version_combo_changed()
if self.instantChange:
self._update_keywords(True, update = True)
return True
@@ -762,13 +797,13 @@ class PackageTable:
def cb_package_emerge_clicked (self, button):
"""Callback for pressed emerge-button. Adds the package to the EmergeQueue."""
self._update_keywords(True)
- self.main.notebook.set_current_page(self.main.QUEUE_PAGE)
+ self.main.sysNotebook.set_current_page(self.main.QUEUE_PAGE)
return True
def cb_package_unmerge_clicked (self, button):
"""Callback for pressed unmerge-button clicked. Adds the package to the UnmergeQueue."""
self._update_keywords(False)
- self.main.notebook.set_current_page(self.main.QUEUE_PAGE)
+ self.main.sysNotebook.set_current_page(self.main.QUEUE_PAGE)
return True
def cb_testing_toggled (self, button):
@@ -978,8 +1013,9 @@ class MainWindow (Window):
splash(_("Finishing startup"))
- # notebook
- self.notebook = self.tree.get_widget("systemNotebook")
+ # notebooks
+ self.sysNotebook = self.tree.get_widget("systemNotebook")
+ self.pkgNotebook = self.tree.get_widget("packageNotebook")
self.window.show_all()
# the hidden stuff
@@ -1025,7 +1061,7 @@ class MainWindow (Window):
self.queueList.set_model(store)
cell = gtk.CellRendererText()
- col = gtk.TreeViewColumn(_("Queue"), cell, text = 0)
+ col = gtk.TreeViewColumn(_("Queue"), cell, markup = 0)
self.queueList.append_column(col)
col = gtk.TreeViewColumn(_("Options"), cell, markup = 1)
@@ -1163,6 +1199,13 @@ class MainWindow (Window):
"""Is called when we want to jump to a specific package."""
self.show_package(cp, self.queue, version = version)
+ def set_uri_hook (self, browser):
+ gtk.link_button_set_uri_hook(lambda btn, x: get_listener().send_cmd([browser, btn.get_uri()]))
+
+ def set_notebook_tabpos (self, tabposlist):
+ self.pkgNotebook.set_tab_pos(tabposlist[0])
+ self.sysNotebook.set_tab_pos(tabposlist[1])
+
def title_update (self, title):
def window_title_update (title):
@@ -1189,7 +1232,7 @@ class MainWindow (Window):
else:
title = (_("Console (%(title)s)") % {"title" : title})
- self.notebook.set_tab_label_text(self.termHB, title)
+ self.sysNotebook.set_tab_label_text(self.termHB, title)
return False
@@ -1297,10 +1340,8 @@ class MainWindow (Window):
tooltip.set_markup(string)
return string != ""
- def cb_emerge_clicked (self, action):
- """Do emerge."""
-
- self.notebook.set_current_page(self.CONSOLE_PAGE)
+ def cb_execute_clicked (self, action):
+ """Execute the current queue."""
if len(flags.newUseFlags) > 0:
changed_flags_dialog(_("use flags"))
@@ -1314,20 +1355,27 @@ class MainWindow (Window):
flags.write_masked()
flags.write_testing()
system.reload_settings()
+
+ model, iter = self.queueList.get_selection().get_selected()
+
+ if iter is None:
+ if model.iter_n_children(None) == 1: # only one queue there - take this as being selected
+ iter = model.get_iter_root()
+ else:
+ return False
+
+ self.sysNotebook.set_current_page(self.CONSOLE_PAGE)
- if not self.doUpdate:
- self.queue.emerge(force=True)
+ # test which type of queue we have here
+ if self.queueTree.is_in_emerge(iter):
+ self.queue.emerge(force = True)
+ elif self.queueTree.is_in_unmerge(iter):
+ self.queue.unmerge(force = True)
else:
self.queue.update_world(force=True, newuse = self.cfg.get_boolean("newuse"), deep = self.cfg.get_boolean("deep"))
- self.doUpdate = False
-
- def cb_unmerge_clicked (self, button):
- """Do unmerge."""
- self.notebook.set_current_page(self.CONSOLE_PAGE)
- self.queue.unmerge(force=True)
return True
-
+
def cb_update_clicked (self, action):
def __update():
@@ -1335,15 +1383,15 @@ class MainWindow (Window):
try:
try:
for pkg, old_pkg in updating:
- self.queue.append(pkg.get_cpv(), unmask = False)
+ self.queue.append(pkg.get_cpv(), type = "update", unmask = False)
except PackageNotFoundException, e:
if unmask_dialog(e[0]) == gtk.RESPONSE_YES:
for pkg, old_pkg in updating:
- self.queue.append(pkg.get_cpv(), unmask = True)
+ self.queue.append(pkg.get_cpv(), type = "update", unmask = True)
except BlockedException, e:
blocked_dialog(e[0], e[1])
- self.queue.remove_children(self.queue.emergeIt)
+ self.queue.remove_children(self.queueTree.get_update_it())
return False
@@ -1353,7 +1401,6 @@ class MainWindow (Window):
updating = system.update_world(newuse = self.cfg.get_boolean("newuse"), deep = self.cfg.get_boolean("deep"))
debug("updating list: %s --> length: %s", [(x.get_cpv(), y.get_cpv()) for x,y in updating], len(updating))
gobject.idle_add(cb_idle_append, updating)
- if len(updating): self.doUpdate = True
finally:
self.window.window.set_cursor(None)
@@ -1363,29 +1410,35 @@ class MainWindow (Window):
def cb_remove_clicked (self, button):
"""Removes a selected item in the (un)emerge-queue if possible."""
- selected = self.queueList.get_selection()
+ model, iter = self.queueList.get_selection().get_selected()
- if selected:
- model, iter = selected.get_selected()
+ if iter:
+ parent = model.iter_parent(iter)
- if iter == None: return False
-
- if not model.iter_parent(iter): # top-level
+ if self.queueTree.is_in_update(iter) and parent:
+ if remove_updates_dialog() == gtk.RESPONSE_YES:
+ self.queue.remove_with_children(self.queueTree.get_update_it())
+
+ elif not parent: # top-level
if model.iter_n_children(iter) > 0: # and has children which can be removed :)
if remove_queue_dialog() == gtk.RESPONSE_YES :
- self.queue.remove_children(iter)
- self.doUpdate = False
+ self.queue.remove_with_children(iter)
+ else:
+ self.queue.remove(iter)
- elif model.iter_parent(model.iter_parent(iter)): # this is in the 3rd level => dependency
+ elif model.iter_parent(parent): # this is in the 3rd level => dependency
remove_deps_dialog()
else:
self.queue.remove_with_children(iter)
- self.doUpdate = False
+
+ if model.iter_n_children(parent) == 0: # no more children left - remove queue too
+ self.queue.remove(parent)
- return True
+ return True
+ return False
def cb_sync_clicked (self, action):
- self.notebook.set_current_page(self.CONSOLE_PAGE)
+ self.sysNotebook.set_current_page(self.CONSOLE_PAGE)
cmd = self.cfg.get("syncCommand")
if cmd != "emerge --sync":
@@ -1424,7 +1477,7 @@ class MainWindow (Window):
SearchWindow(self.window, packages, self.jump_to)
def cb_preferences_clicked (self, button):
- PreferenceWindow(self.window, self.cfg, self.console.set_font_from_string)
+ PreferenceWindow(self.window, self.cfg, self.console.set_font_from_string, self.set_uri_hook, self.set_notebook_tabpos)
return True
def cb_about_clicked (self, button):
diff --git a/portato/gui/gtk/wrapper.py b/portato/gui/gtk/wrapper.py
index a322514..cadec6a 100644
--- a/portato/gui/gtk/wrapper.py
+++ b/portato/gui/gtk/wrapper.py
@@ -29,8 +29,9 @@ class GtkTree (Tree):
self.tree = tree
self.cpv_col = col
- self.emergeIt = self.append(None, ["Emerge", ""])
- self.unmergeIt = self.append(None, ["Unmerge", ""])
+ self.emergeIt = None
+ self.unmergeIt = None
+ self.updateIt = None
def build_append_value (self, cpv, oneshot = False, update = False, downgrade = False, version = None, useChange = []):
string = ""
@@ -60,17 +61,38 @@ class GtkTree (Tree):
return [cpv, string]
+ def set_in_progress (self, it):
+ iter = self.tree.get_iter_from_string(self.tree.get_string_from_iter(it).split(":")[0])
+ self.tree.set_value(iter, 1, "%s" % _("(In Progress)"))
+
def get_emerge_it (self):
+ if self.emergeIt is None:
+ self.emergeIt = self.append(None, ["%s" % _("Install"), ""])
return self.emergeIt
def get_unmerge_it (self):
+ if self.unmergeIt is None:
+ self.unmergeIt = self.append(None, ["%s" % _("Uninstall"), ""])
+
return self.unmergeIt
+ def get_update_it (self):
+ if self.updateIt is None:
+ self.updateIt = self.append(None, ["%s" % _("Update"), ""])
+
+ return self.updateIt
+
+ def is_in (self, it, in_it):
+ return in_it and self.tree.get_string_from_iter(it).split(":")[0] == self.tree.get_string_from_iter(in_it)
+
def is_in_emerge (self, it):
- return self.tree.get_string_from_iter(it).split(":")[0] == self.tree.get_string_from_iter(self.emergeIt)
+ return self.is_in(it, self.emergeIt)
def is_in_unmerge (self, it):
- return self.tree.get_string_from_iter(it).split(":")[0] == self.tree.get_string_from_iter(self.unmergeIt)
+ return self.is_in(it, self.unmergeIt)
+
+ def is_in_update (self, it):
+ return self.is_in(it, self.updateIt)
def iter_has_parent (self, it):
return (self.tree.iter_parent(it) != None)
@@ -90,10 +112,18 @@ class GtkTree (Tree):
def get_value (self, it, column):
return self.tree.get_value(it, column)
+ def iter_equal (self, it, other_it):
+ return self.tree.get_string_from_iter(it) == self.tree.get_string_from_iter(other_it)
+
def append (self, parent = None, values = None):
return self.tree.append(parent, values)
def remove (self, it):
+
+ if self.emergeIt and self.iter_equal(it, self.emergeIt) : self.emergeIt = None
+ elif self.unmergeIt and self.iter_equal(it, self.unmergeIt) : self.unmergeIt = None
+ elif self.updateIt and self.iter_equal(it, self.updateIt) : self.updateIt = None
+
self.tree.remove(it)
def get_original (self):
diff --git a/portato/gui/gui_helper.py b/portato/gui/gui_helper.py
index 1e465a7..0459d5b 100644
--- a/portato/gui/gui_helper.py
+++ b/portato/gui/gui_helper.py
@@ -264,13 +264,6 @@ class EmergeQueue:
self.db = db
self.title_update = title_update
- # our iterators pointing at the toplevels; they are set to None if we do not have a tree
- if self.tree:
- self.emergeIt = self.tree.get_emerge_it()
- self.unmergeIt = self.tree.get_unmerge_it()
- else:
- self.emergeIt = self.unmergeIt = None
-
def _get_pkg_from_cpv (self, cpv, unmask = False):
"""Gets a L{backend.Package}-object from a cpv.
@@ -390,14 +383,14 @@ class EmergeQueue:
self.remove_with_children(subIt)
raise
- def append (self, cpv, unmerge = False, update = False, forceUpdate = False, unmask = False, oneshot = False):
+ def append (self, cpv, type = "install", update = False, forceUpdate = False, unmask = False, oneshot = False):
"""Appends a cpv either to the merge queue or to the unmerge-queue.
Also updates the tree-view.
@param cpv: Package to add
@type cpv: string (cat/pkg-ver)
- @param unmerge: Set to True if you want to unmerge this package - else False.
- @type unmerge: boolean
+ @param type: The type of this append process. Possible values are "install", "uninstall", "update".
+ @type unmerge: string
@param update: Set to True if a package is going to be updated (e.g. if the use-flags changed).
@type update: boolean
@param forceUpdate: Set to True if the update should be forced.
@@ -409,7 +402,7 @@ class EmergeQueue:
@raises portato.backend.PackageNotFoundException: if trying to add a package which does not exist"""
- if not unmerge: # emerge
+ if type in ("install", "update"): # emerge
# insert dependencies
pkg = self._get_pkg_from_cpv(cpv, unmask)
deps = pkg.get_dep_packages()
@@ -429,14 +422,17 @@ class EmergeQueue:
self.update_tree(parentIt, cpv, unmask, oneshot = oneshot)
else: # not update
- self._queue_append(cpv, oneshot)
- if self.emergeIt:
- self.update_tree(self.emergeIt, cpv, unmask, oneshot = oneshot)
+ if type == "install":
+ self._queue_append(cpv, oneshot)
+ if self.tree:
+ self.update_tree(self.tree.get_emerge_it(), cpv, unmask, oneshot = oneshot)
+ elif type == "update" and self.tree:
+ self.update_tree(self.tree.get_update_it(), cpv, unmask, oneshot = oneshot)
else: # unmerge
self.unmergequeue.append(cpv)
- if self.unmergeIt: # update tree
- self.tree.append(self.unmergeIt, self.tree.build_append_value(cpv))
+ if self.tree: # update tree
+ self.tree.append(self.tree.get_unmerge_it(), self.tree.build_append_value(cpv))
def _queue_append (self, cpv, oneshot = False):
"""Convenience function appending a cpv either to self.mergequeue or to self.oneshotmerge.
@@ -453,8 +449,11 @@ class EmergeQueue:
if cpv not in self.oneshotmerge:
self.oneshotmerge.append(cpv)
- def doEmerge (self, *args, **kwargs):
- self.threadQueue.put(self.__emerge, *args, **kwargs)
+ def doEmerge (self, options, packages, it, *args, **kwargs):
+ if self.tree and it:
+ self.tree.set_in_progress(it[0])
+
+ self.threadQueue.put(self.__emerge, options, packages, it, *args, **kwargs)
def __emerge (self, options, packages, it, command = None):
"""Calls emerge and updates the terminal.
@@ -530,14 +529,21 @@ class EmergeQueue:
its = []
for k in queue:
list += ["="+k]
- its.append(self.iters[k])
+ if self.tree: its.append(self.iters[k])
return list, its
+ if self.tree:
+ ownit = [self.tree.get_emerge_it()]
+ else:
+ ownit = []
+
# oneshot-queue
if self.oneshotmerge:
# prepare package-list for oneshot
list, its = prepare(self.oneshotmerge)
+ if not self.mergequeue :# the other one does not exist - remove completely
+ its = ownit
s = system.get_oneshot_option()
if not force: s += system.get_pretend_option()
@@ -549,6 +555,8 @@ class EmergeQueue:
if self.mergequeue:
# prepare package-list
list, its = prepare(self.mergequeue)
+ if not self.oneshotmerge: # the other one does not exist - remove completely
+ its = ownit
s = []
if not force: s = system.get_pretend_option()
@@ -573,7 +581,12 @@ class EmergeQueue:
if not force: s += system.get_pretend_option()
if options is not None: s += options
- self.doEmerge(s,list, [self.unmergeIt], caller = self.unmerge)
+ if self.tree:
+ it = [self.tree.get_unmerge_it()]
+ else:
+ it = []
+
+ self.doEmerge(s,list, it, caller = self.unmerge)
def update_world(self, force = False, newuse = False, deep = False, options = None):
"""Does an update world. newuse and deep are the arguments handed to emerge.
@@ -594,7 +607,12 @@ class EmergeQueue:
if not force: opts += system.get_pretend_option()
if options is not None: opts += options
- self.doEmerge(opts, ["world"], [self.emergeIt], caller = self.update_world)
+ if self.tree:
+ it = [self.tree.get_update_it()]
+ else:
+ it = []
+
+ self.doEmerge(opts, ["world"], it, caller = self.update_world)
def sync (self, command = None):
"""Calls "emerge --sync".
@@ -677,7 +695,7 @@ class EmergeQueue:
@param removeNewFlags: True if new flags should be removed; False otherwise. Default: True.
@type removeNewFlags: boolean"""
- if self.tree.iter_has_parent(it): # NEVER remove our top stuff
+ if self.tree.iter_has_parent(it):
cpv = self.tree.get_value(it, self.tree.get_cpv_column())
if self.tree.is_in_emerge(it): # Emerge
del self.iters[cpv]
@@ -698,10 +716,10 @@ class EmergeQueue:
flags.remove_new_masked(cpv)
flags.remove_new_testing(cpv)
- else: # in Unmerge
+ elif self.tree.is_in_unmerge(it): # in Unmerge
self.unmergequeue.remove(cpv)
- self.tree.remove(it)
+ self.tree.remove(it)
def is_empty (self):
"""Checks whether the current queue is empty and not working. Therefore it looks, whether the queues are empty,
diff --git a/portato/gui/templates/portato.glade b/portato/gui/templates/portato.glade
index cb0fe6a..f6ca9a1 100644
--- a/portato/gui/templates/portato.glade
+++ b/portato/gui/templates/portato.glade
@@ -86,9 +86,10 @@