summaryrefslogtreecommitdiff
path: root/portato/gui
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--portato/gui/__init__.py18
-rw-r--r--portato/gui/dialogs.py134
-rw-r--r--portato/gui/exception_handling.py196
-rw-r--r--portato/gui/queue.py1234
-rw-r--r--portato/gui/session.py16
-rw-r--r--portato/gui/updater.py200
-rw-r--r--portato/gui/utils.py530
-rw-r--r--portato/gui/views.py214
-rw-r--r--portato/gui/windows/about.py16
-rw-r--r--portato/gui/windows/basic.py180
-rw-r--r--portato/gui/windows/mailinfo.py106
-rw-r--r--portato/gui/windows/main.py3482
-rw-r--r--portato/gui/windows/plugin.py316
-rw-r--r--portato/gui/windows/preference.py384
-rw-r--r--portato/gui/windows/search.py98
-rw-r--r--portato/gui/windows/splash.py60
-rw-r--r--portato/gui/windows/update.py188
-rw-r--r--portato/gui/wrapper.py622
18 files changed, 3997 insertions, 3997 deletions
diff --git a/portato/gui/__init__.py b/portato/gui/__init__.py
index 0df890c..5bbe4c8 100644
--- a/portato/gui/__init__.py
+++ b/portato/gui/__init__.py
@@ -16,13 +16,13 @@ from .. import get_listener
from .exception_handling import register_ex_handler
def run ():
- from .windows.splash import SplashScreen
- s = SplashScreen(_("Loading Backend"))
+ from .windows.splash import SplashScreen
+ s = SplashScreen(_("Loading Backend"))
- register_ex_handler()
- s.show()
-
- from .windows.main import MainWindow
- m = MainWindow(s)
- s.hide()
- m.main()
+ register_ex_handler()
+ s.show()
+
+ from .windows.main import MainWindow
+ m = MainWindow(s)
+ s.hide()
+ m.main()
diff --git a/portato/gui/dialogs.py b/portato/gui/dialogs.py
index bf7acc7..f178d2b 100644
--- a/portato/gui/dialogs.py
+++ b/portato/gui/dialogs.py
@@ -14,95 +14,95 @@ import gtk
from ..helper import error
def mail_failure_dialog(e):
- dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("Mail could not be sent"))
- dialog.format_secondary_text(_("The error was: %s") % e)
- ret = dialog.run()
- dialog.destroy()
- return ret
+ dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("Mail could not be sent"))
+ dialog.format_secondary_text(_("The error was: %s") % e)
+ ret = dialog.run()
+ dialog.destroy()
+ return ret
def queue_not_empty_dialog():
- 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()
- return ret
+ 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()
+ return ret
def io_ex_dialog (io_ex):
- string = io_ex.strerror
- if io_ex.filename:
- string = string+": "+io_ex.filename
-
- error(string)
- dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, string)
- ret = dialog.run()
- dialog.destroy()
- return ret
+ string = io_ex.strerror
+ if io_ex.filename:
+ string = string+": "+io_ex.filename
+
+ error(string)
+ dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, string)
+ ret = dialog.run()
+ dialog.destroy()
+ 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.") % {"blocked":blocked, "blocks" : blocks})
- dialog.format_secondary_text(_("Please unmerge the blocking package."))
- ret = dialog.run()
- dialog.destroy()
- return ret
+ 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
def not_root_dialog ():
- errorMB = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("You are not root."))
- ret = errorMB.run()
- errorMB.destroy()
- return ret
+ errorMB = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("You are not root."))
+ ret = errorMB.run()
+ errorMB.destroy()
+ 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.") % cpv )
- dialog.format_secondary_text(_("Do you want to unmask it and its dependencies?"))
- ret = dialog.run()
- dialog.destroy()
- return ret
+ 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
def nothing_found_dialog ():
- dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, _("Package not found!"))
- ret = dialog.run()
- dialog.destroy()
- return ret
+ dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, _("Package not found!"))
+ ret = dialog.run()
+ dialog.destroy()
+ return ret
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, _("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()
- hintMB.destroy()
+ check = gtk.CheckButton(_("Do not show this dialog again."))
+ 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()
+ hintMB.destroy()
- return ret, check.get_active()
+ return ret, check.get_active()
def remove_deps_dialog ():
- infoMB = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, _("You cannot remove dependencies. :)"))
- ret = infoMB.run()
- infoMB.destroy()
- return ret
+ infoMB = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, _("You cannot remove dependencies. :)"))
+ ret = infoMB.run()
+ 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
+ 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()
- askMB.destroy()
- return ret
+ 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()
+ askMB.destroy()
+ return ret
def file_chooser_dialog (title, parent):
- fc = gtk.FileChooserDialog(title = title, parent = parent, action = gtk.FILE_CHOOSER_ACTION_SAVE, buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
- fc.set_do_overwrite_confirmation(True)
- ret = fc.run()
+ fc = gtk.FileChooserDialog(title = title, parent = parent, action = gtk.FILE_CHOOSER_ACTION_SAVE, buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
+ fc.set_do_overwrite_confirmation(True)
+ ret = fc.run()
- if ret == gtk.RESPONSE_ACCEPT:
- ret = fc.get_filename()
- else:
- ret = None
+ if ret == gtk.RESPONSE_ACCEPT:
+ ret = fc.get_filename()
+ else:
+ ret = None
- fc.destroy()
- return ret
+ fc.destroy()
+ return ret
diff --git a/portato/gui/exception_handling.py b/portato/gui/exception_handling.py
index dae95ed..df555de 100644
--- a/portato/gui/exception_handling.py
+++ b/portato/gui/exception_handling.py
@@ -24,108 +24,108 @@ from .windows.mailinfo import MailInfoWindow
from .utils import GtkThread
class UncaughtExceptionDialog(gtk.MessageDialog):
- """Original idea by Gustavo Carneiro - original code: http://www.daa.com.au/pipermail/pygtk/attachments/20030828/2d304204/gtkexcepthook.py."""
-
- def __init__(self, type, value, tb, thread = None):
-
- super(UncaughtExceptionDialog,self).__init__(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=gtk.BUTTONS_NONE, message_format=_("A programming error has been detected during the execution of this program."))
- self.set_title(_("Bug Detected"))
- self.format_secondary_text(_("It probably isn't fatal, but should be reported to the developers nonetheless."))
-
- self.add_button(_("Show Details"), 1)
- self.add_button(_("Send..."), 3)
- self.add_button(gtk.STOCK_SAVE_AS, 2)
- self.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)
-
- # Details
- self.textview = gtk.TextView()
- self.textview.set_editable(False)
- self.textview.modify_font(pango.FontDescription("Monospace"))
-
- self.sw = gtk.ScrolledWindow();
- self.sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
- self.sw.add(self.textview)
-
- self.tbFrame = gtk.Frame()
- self.tbFrame.set_shadow_type(gtk.SHADOW_IN)
- self.tbFrame.add(self.sw)
- self.tbFrame.set_border_width(6)
-
- self.vbox.add(self.tbFrame)
-
- textbuffer = self.textview.get_buffer()
- self.text = get_trace(type, value, tb)
- if thread:
- self.text = _("Exception in thread \"%(thread)s\":\n%(trace)s") % {"thread": thread, "trace": self.text}
- textbuffer.set_text(self.text)
- self.textview.set_size_request(gtk.gdk.screen_width()/2, gtk.gdk.screen_height()/3)
-
- self.details = self.tbFrame
- self.set_position(gtk.WIN_POS_CENTER)
- self.set_gravity(gtk.gdk.GRAVITY_CENTER)
-
- def run (self):
- while True:
- resp = super(UncaughtExceptionDialog, self).run()
- if resp == 1:
- self.details.show_all()
- self.set_response_sensitive(1, False)
- elif resp == 2:
- debug("Want to save")
- file = file_chooser_dialog(_("Save traceback..."), self)
- if file:
- debug("Save to %s", file)
-
- try:
- with open(file, "w") as f:
- f.writelines(self.text)
- except IOError, e:
- io_ex_dialog(e)
-
- else:
- debug("Nothing to save")
- elif resp == 3:
- debug("Send bug per mail")
- self.destroy()
- MailInfoWindow(None, self.text)
- return
- else:
- break
- self.destroy()
+ """Original idea by Gustavo Carneiro - original code: http://www.daa.com.au/pipermail/pygtk/attachments/20030828/2d304204/gtkexcepthook.py."""
+
+ def __init__(self, type, value, tb, thread = None):
+
+ super(UncaughtExceptionDialog,self).__init__(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=gtk.BUTTONS_NONE, message_format=_("A programming error has been detected during the execution of this program."))
+ self.set_title(_("Bug Detected"))
+ self.format_secondary_text(_("It probably isn't fatal, but should be reported to the developers nonetheless."))
+
+ self.add_button(_("Show Details"), 1)
+ self.add_button(_("Send..."), 3)
+ self.add_button(gtk.STOCK_SAVE_AS, 2)
+ self.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)
+
+ # Details
+ self.textview = gtk.TextView()
+ self.textview.set_editable(False)
+ self.textview.modify_font(pango.FontDescription("Monospace"))
+
+ self.sw = gtk.ScrolledWindow();
+ self.sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ self.sw.add(self.textview)
+
+ self.tbFrame = gtk.Frame()
+ self.tbFrame.set_shadow_type(gtk.SHADOW_IN)
+ self.tbFrame.add(self.sw)
+ self.tbFrame.set_border_width(6)
+
+ self.vbox.add(self.tbFrame)
+
+ textbuffer = self.textview.get_buffer()
+ self.text = get_trace(type, value, tb)
+ if thread:
+ self.text = _("Exception in thread \"%(thread)s\":\n%(trace)s") % {"thread": thread, "trace": self.text}
+ textbuffer.set_text(self.text)
+ self.textview.set_size_request(gtk.gdk.screen_width()/2, gtk.gdk.screen_height()/3)
+
+ self.details = self.tbFrame
+ self.set_position(gtk.WIN_POS_CENTER)
+ self.set_gravity(gtk.gdk.GRAVITY_CENTER)
+
+ def run (self):
+ while True:
+ resp = super(UncaughtExceptionDialog, self).run()
+ if resp == 1:
+ self.details.show_all()
+ self.set_response_sensitive(1, False)
+ elif resp == 2:
+ debug("Want to save")
+ file = file_chooser_dialog(_("Save traceback..."), self)
+ if file:
+ debug("Save to %s", file)
+
+ try:
+ with open(file, "w") as f:
+ f.writelines(self.text)
+ except IOError, e:
+ io_ex_dialog(e)
+
+ else:
+ debug("Nothing to save")
+ elif resp == 3:
+ debug("Send bug per mail")
+ self.destroy()
+ MailInfoWindow(None, self.text)
+ return
+ else:
+ break
+ self.destroy()
def convert (version):
- """Converts a version given as int-tuple to a normal version string."""
- return ".".join(map(str, version))
+ """Converts a version given as int-tuple to a normal version string."""
+ return ".".join(map(str, version))
def get_version_infos():
- from ..constants import VERSION
- from ..backend import system
-
- 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))))
+ from ..constants import VERSION
+ from ..backend import system
+
+ 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))))
def get_trace(type, value, tb):
- trace = StringIO()
- traceback.print_exception(type, value, tb, None, trace)
- traceStr = trace.getvalue()
- trace.close()
- return traceStr + "\n" + get_version_infos()
-
+ trace = StringIO()
+ traceback.print_exception(type, value, tb, None, trace)
+ traceStr = trace.getvalue()
+ trace.close()
+ return traceStr + "\n" + get_version_infos()
+
def register_ex_handler():
-
- def handler(type, val, tb, thread = None):
- def run_dialog():
- UncaughtExceptionDialog(type, val, tb, thread).run()
-
- if thread:
- error(_("Exception in thread \"%(thread)s\":\n%(trace)s"), {"thread": thread, "trace": get_trace(type, val, tb)})
- else:
- error(_("Exception:\n%s"), get_trace(type, val, tb))
-
- gobject.idle_add(run_dialog)
-
- sys.excepthook = handler
+
+ def handler(type, val, tb, thread = None):
+ def run_dialog():
+ UncaughtExceptionDialog(type, val, tb, thread).run()
+
+ if thread:
+ error(_("Exception in thread \"%(thread)s\":\n%(trace)s"), {"thread": thread, "trace": get_trace(type, val, tb)})
+ else:
+ error(_("Exception:\n%s"), get_trace(type, val, tb))
+
+ gobject.idle_add(run_dialog)
+
+ sys.excepthook = handler
diff --git a/portato/gui/queue.py b/portato/gui/queue.py
index b5fb736..5ff600f 100644
--- a/portato/gui/queue.py
+++ b/portato/gui/queue.py
@@ -31,620 +31,620 @@ from .updater import Updater
from .wrapper import GtkConsole, GtkTree
class EmergeQueue:
- """This class manages the emerge queue."""
-
- def __init__ (self, tree = None, console = None, db = None, title_update = None, threadClass = threading.Thread):
- """Constructor.
-
- @param tree: Tree to append all the items to.
- @type tree: GtkTree
- @param console: Output is shown here.
- @type console: GtkConsole
- @param db: A database instance.
- @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
- self.unmergequeue = [] # for emerge -C
- self.oneshotmerge = [] # for emerge --oneshot
-
- # the emerge process
- self.process = None
- self.threadQueue = WaitingQueue(threadClass = threadClass)
- self.pty = None
-
- # dictionaries with data about the packages in the queue
- self.iters = {"install" : {}, "uninstall" : {}, "update" : {}} # iterator in the tree
- self.deps = {"install" : {}, "update" : {}} # all the deps of the package
- self.blocks = {"install" : OrderedDict(), "update" : OrderedDict()}
-
- # member vars
- self.tree = tree
- if self.tree and not isinstance(self.tree, GtkTree): raise TypeError, "tree passed is not a GtkTree-object"
-
- self.console = console
- if self.console and not isinstance(self.console, GtkConsole): raise TypeError, "console passed is not a GtkConsole-object"
-
- self.db = db
- self.title_update = title_update
- self.threadClass = threadClass
-
- if self.console:
- self.pty = pty.openpty()
- self.console.set_pty(self.pty[0])
-
- def _get_pkg_from_cpv (self, cpv, unmask = False):
- """Gets a L{backend.Package}-object from a cpv.
-
- @param cpv: the cpv to get the package for
- @type cpv: string (cpv)
- @param unmask: if True we will look for masked packages if we cannot find unmasked ones
- @type unmask: boolean
- @return: created package
- @rtype: backend.Package
-
- @raises backend.PackageNotFoundException: If no package could be found - normally it is existing but masked."""
-
- # for the beginning: let us create a package object - but it is not guaranteed, that it actually exists in portage
- pkg = system.new_package(cpv)
- masked = not (pkg.is_masked() or pkg.is_testing(use_keywords=True)) # we are setting this to True in case we have unmasked it already, but portage does not know this
-
- # and now try to find it in portage
- pkg = system.find_packages("="+cpv, masked = masked)
-
- if pkg: # gotcha
- pkg = pkg[0]
-
- elif unmask: # no pkg returned, but we are allowed to unmask it
- pkg = system.find_packages("="+cpv, masked = True)
-
- if not pkg:
- raise backend.PackageNotFoundException(cpv) # also not found
- else:
- pkg = pkg[0]
-
- if pkg.is_testing(use_keywords = True):
- pkg.set_testing(True)
- if pkg.is_masked():
- pkg.set_masked()
-
- else: # no pkg returned - and we are not allowed to unmask
- raise backend.PackageNotFoundException(cpv)
-
- return pkg
-
- def update_tree (self, it, cpv, unmask = False, oneshot = False, type = "install"):
- """This updates the tree recursivly, or? Isn't it? Bjorn!
-
- @param it: iterator where to append
- @type it: Iterator
- @param cpv: The package to append.
- @type cpv: string (cat/pkg-ver)
- @param unmask: True if we are allowed to look for masked packages
- @type unmask: boolean
- @param oneshot: True if we want to emerge is oneshot
- @type oneshot: boolean
- @param type: the type of the updating
- @type type: string
-
- @raises backend.BlockedException: When occured during dependency-calculation.
- @raises backend.PackageNotFoundException: If no package could be found - normally it is existing but masked."""
-
- if cpv in self.deps[type]:
- return # in list already and therefore it's already in the tree too
-
- # try to find an already installed instance
- update = False
- downgrade = False
- uVersion = None
- changedUse = []
- try:
- pkg = self._get_pkg_from_cpv(cpv, unmask)
- if not pkg.is_installed():
- old = system.find_packages(pkg.get_slot_cp(), system.SET_INSTALLED)
- if old:
- old = old[0] # assume we have only one there
- cmp = pkg.compare_version(old)
- if cmp > 0:
- update = True
- elif cmp < 0:
- downgrade = True
-
- uVersion = old.get_version()
-
- old_iuse = set(old.get_iuse_flags())
- new_iuse = set(pkg.get_iuse_flags())
-
- for i in old_iuse.difference(new_iuse):
- changedUse.append("-"+i)
-
- for i in new_iuse.difference(old_iuse):
- changedUse.append("+"+i)
- else:
- old_iuse = set(pkg.get_iuse_flags(installed = True))
- new_iuse = set(pkg.get_iuse_flags(installed = False))
-
- for i in old_iuse.difference(new_iuse):
- changedUse.append("-"+i)
-
- for i in new_iuse.difference(old_iuse):
- changedUse.append("+"+i)
-
- except backend.PackageNotFoundException, e: # package not found / package is masked -> delete current tree and re-raise the exception
- if type == "update": # remove complete tree
- self.remove_with_children(self.tree.first_iter(it), removeNewFlags = False)
-
- elif type == "install": # remove only the intentionally added package
- top = self.tree.first_iter(it)
- parent = self.tree.parent_iter(it)
-
- if parent:
- while not self.tree.iter_equal(top, parent):
- parent = self.tree.parent_iter(parent)
- it = self.tree.parent_iter(it)
-
- self.remove_with_children(it, removeNewFlags = False)
-
- if not self.tree.iter_has_children(top): # remove completely if nothing left
- self.remove(top)
- raise
-
- # add iter
- subIt = self.tree.append(it, self.tree.build_append_value(cpv, oneshot = oneshot, update = update, downgrade = downgrade, version = uVersion, useChange = changedUse))
- self.iters[type][cpv] = subIt
-
- # get dependencies
- deps = pkg.get_dep_packages(return_blocks = True)
- self.deps[type][cpv] = deps
-
- for d in deps:
- if d[0] == "!": # block
- dep = d[1:]
- if not dep in self.blocks[type]:
- self.blocks[type][dep] = set()
-
- self.blocks[type][dep].add(cpv)
- else: # recursive call
- self.update_tree(subIt, d, unmask, type = type)
-
- 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 type: The type of this append process. Possible values are "install", "uninstall", "update".
- @type type: 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.
- @type forceUpdate: boolean
- @param unmask: True if we are allowed to look for masked packages
- @type unmask: boolean
- @param oneshot: True if this package should not be added to the world-file.
- @type oneshot: boolean
-
- @raises portato.backend.PackageNotFoundException: if trying to add a package which does not exist"""
-
- if type in ("install", "update"): # emerge
- if update:
- pkg = self._get_pkg_from_cpv(cpv, unmask)
- deps = pkg.get_dep_packages(return_blocks = True)
-
- if not forceUpdate and cpv in self.deps[type] and deps == self.deps[type][cpv]:
- return # nothing changed - return
- else:
- hasBeenInQueue = (cpv in self.mergequeue or cpv in self.oneshotmerge)
- parentIt = self.tree.parent_iter(self.iters[type][cpv])
-
- # delete it out of the tree - but NOT the changed flags
- self.remove_with_children(self.iters[type][cpv], removeNewFlags = False)
-
- if hasBeenInQueue: # package has been in queue before
- self._queue_append(cpv, oneshot)
-
- self.update_tree(parentIt, cpv, unmask, oneshot = oneshot, type = type)
- else: # not update
- if type == "install":
- 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)
-
- # handle blocks
- if self.blocks[type]:
- # check whether anything blocks something in the queue
- for block in self.blocks[type]:
- for c in self.iters[type]:
- if system.cpv_matches(c, block):
- blocked = ", ".join(self.blocks[type][block])
- warning("'%s' is blocked by: %s", c, blocked)
- self.remove_with_children(self.iters[type][c], False)
- raise BlockedException(c, blocked)
-
- #
- # check whether we block a version that we are going to replace nevertheless
- #
-
- # get the blocks that block an installed package
- inst = []
- for block in self.blocks[type]:
- pkgs = system.find_packages(block, system.SET_INSTALLED)
- if pkgs:
- inst.append((pkgs, block))
-
- # the slot-cp's of the packages in the queue
- slots = {}
- for c in self.iters[type]:
- slots[system.new_package(c).get_slot_cp()] = cpv
-
- # check the installed blocks against the slot-cp's
- for pkgs, block in inst[:]:
- done = False
- for pkg in pkgs:
- done = False
- if pkg.get_slot_cp() in slots:
- debug("Block '%s' can be ignored, because the blocking package is going to be replaced with '%s'.", block, slots[pkg.get_slot_cp()])
- done = True
- if done:
- inst.remove((pkgs,block))
-
- if inst: # there is still something left to block
- for pkgs, block in inst:
- blocked = ", ".join(self.blocks[type][block])
- warning("'%s' blocks the installation of: %s", pkgs[0].get_cpv(), blocked)
- self.remove_with_children(self.iters[type][cpv], False)
- raise BlockedException(blocked, pkgs[0].get_cpv())
-
- else: # unmerge
- self.unmergequeue.append(cpv)
- if self.tree: # update tree
- self.iters["uninstall"].update({cpv: 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.
-
- @param cpv: cpv to add
- @type cpv: string (cpv)
- @param oneshot: True if this package should not be added to the world-file.
- @type oneshot: boolean"""
-
- if not oneshot:
- if cpv not in self.mergequeue:
- self.mergequeue.append(cpv)
- else:
- if cpv not in self.oneshotmerge:
- self.oneshotmerge.append(cpv)
-
- def doEmerge (self, options, packages, it, *args, **kwargs):
- top = None
- if self.tree and it:
- for v in it.itervalues():
- self.tree.set_in_progress(v)
- top = self.tree.first_iter(v)
- break
-
- self.threadQueue.put(self.__emerge, options, packages, it, top, *args, **kwargs)
-
- def __emerge (self, options, packages, it, top, command = None):
- """Calls emerge and updates the terminal.
-
- @param options: options to send to emerge
- @type options: string[]
- @param packages: packages to emerge
- @type packages: string[]
- @param it: Iterators which point to these entries whose children will be removed after completion.
- @type it: dict(string -> Iterator)
- @param top: The top iterator
- @type top: Iterator
- @param command: the command to execute - default is "/usr/bin/python /usr/bin/emerge"
- @type command: string[]"""
-
- @plugin.hook("emerge", packages = packages, command = command, console = self.console, title_update = self.title_update)
- def sub_emerge(command):
- if command is None:
- command = system.get_merge_command()
-
- # open tty
- if self.console:
- self.console.reset()
-
- def pre ():
- os.setsid() # new session
- if self.console:
- import fcntl, termios
- fcntl.ioctl(self.pty[1], termios.TIOCSCTTY, 0) # set pty-slave as session tty
- os.dup2(self.pty[1], 0)
- os.dup2(self.pty[1], 1)
- os.dup2(self.pty[1], 2)
-
- # get all categories that are being touched during the emerge process
- cats = set(map(lambda x: x.split("/")[0], it.iterkeys()))
-
- # start emerge
- self.process = Popen(command+options+packages, shell = False, env = system.get_environment(), preexec_fn = pre)
-
- # remove packages from queue
- if self.tree and it and not self.tree.is_in_unmerge(top):
- self.up = Updater(self, it, self.threadClass)
- else:
- self.up = None
-
- # update title
- if self.console:
- old_title = self.console.get_window_title()
- while self.process and self.process.poll() is None:
- if self.title_update :
- title = self.console.get_window_title()
- if title != old_title:
- self.title_update(title)
- old_title = title
- time.sleep(0.5)
-
- if self.up:
- self.up.stop()
- if it:
- self.tree.set_in_progress(top, False)
- else:
- self.remove(top)
- elif self.tree and it:
- self.remove_with_children(top)
-
- if self.title_update: self.title_update(None)
-
- if self.process is None: # someone resetted this
- self.threadQueue.next()
- return
- else:
- ret = self.process.returncode
- self.process = None
- self.threadQueue.next()
-
- @plugin.hook("after_emerge", packages = packages, retcode = ret)
- def update_packages():
- if self.db:
- for cat in cats:
- self.db.reload(cat)
- debug("Category %s refreshed", cat)
-
- update_packages()
-
- sub_emerge(command)
-
- def emerge (self, force = False, options = None):
- """Emerges everything in the merge-queue.
-
- @param force: If False, '-pv' is send to emerge. Default: False.
- @type force: boolean
- @param options: Additional options to send to the emerge command
- @type options: string[]"""
-
- def prepare(queue):
- """Prepares the list of iterators and the list of packages."""
- list = []
- its = {}
- for k in queue:
- list += ["="+k]
- if self.tree:
- its.update({k : self.iters["install"][k]})
-
- return list, its
-
- if self.tree:
- ownit = self.iters["install"]
- 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()
- if options is not None: s += options
-
- self.doEmerge(s, list, its, caller = self.emerge)
-
- # normal queue
- 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()
- if options is not None: s += options
-
- self.doEmerge(s, list, its, caller = self.emerge)
-
- def unmerge (self, force = False, options = None):
- """Unmerges everything in the umerge-queue.
-
- @param force: If False, '-pv' is send to emerge. Default: False.
- @type force: boolean
- @param options: Additional options to send to the emerge command
- @type options: string[]"""
-
- if len(self.unmergequeue) == 0: return # nothing in queue
-
- list = self.unmergequeue[:] # copy the unmerge-queue
-
- # set options
- s = system.get_unmerge_option()
- if not force: s += system.get_pretend_option()
- if options is not None: s += options
-
- if self.tree:
- it = self.iters["uninstall"]
- else:
- it = {}
-
- self.doEmerge(s,list, it, caller = self.unmerge)
-
- def update_world(self, sets = ("world",), force = False, newuse = False, deep = False, options = None):
- """Does an update world. newuse and deep are the arguments handed to emerge.
-
- @param sets: The sets to update.
- @type sets: string[]
- @param force: If False, '-pv' is send to emerge. Default: False.
- @type force: boolean
- @param newuse: If True, append newuse options
- @type newuse: boolean
- @param deep: If True, append deep options
- @type deep: boolean
- @param options: Additional options to send to the emerge command
- @type options: string[]"""
-
- opts = system.get_update_option()
-
- if newuse: opts += system.get_newuse_option()
- if deep: opts += system.get_deep_option()
- if not force: opts += system.get_pretend_option()
- if options is not None: opts += options
-
- if self.tree:
- it = self.iters["update"]
- else:
- it = {}
-
- self.doEmerge(opts, list(sets), it, caller = self.update_world)
-
- def sync (self, command = None):
- """Calls "emerge --sync".
-
- @param command: command to execute to sync. If None "emerge --sync" is taken.
- @type command: string[]"""
-
- if command is None:
- command = system.get_sync_command()
-
- try:
- while True:
- idx = command.index("&&")
- self.doEmerge([],[],{}, command[:idx], caller = self.sync)
- command = command[idx+1:]
- except ValueError: # no && in command
- self.doEmerge([],[],{}, command, caller = self.sync)
-
- def kill_emerge (self):
- """Kills the emerge process."""
- if self.process is not None:
- self.threadQueue.clear() # remove all pending emerge threads
- try:
- pgid = os.getpgid(self.process.pid)
- os.killpg(pgid, signal.SIGTERM)
- debug("Process should be terminated")
- if self.process.poll() is None:
- os.killpg(pgid, signal.SIGKILL)
- debug("Process should be killed")
- except AttributeError:
- debug("AttributeError occured ==> process not exisiting - ignore")
- except OSError:
- debug("OSError occured ==> process already stopped - ignore")
-
- self.process = None
-
- def stop_emerge (self):
- if self.process is not None:
- os.killpg(os.getpgid(self.process.pid), signal.SIGSTOP)
- debug("Process should be stopped")
-
- def continue_emerge (self):
- if self.process is not None:
- os.killpg(os.getpgid(self.process.pid), signal.SIGCONT)
- debug("Process should continue")
-
- def remove_with_children (self, it, removeNewFlags = True):
- """Convenience function which removes all children of an iterator and than the iterator itself.
-
- @param it: The iter which to remove.
- @type it: Iterator
- @param removeNewFlags: True if new flags should be removed; False otherwise. Default: True.
- @type removeNewFlags: boolean"""
-
- self.remove_children(it, removeNewFlags)
- self.remove(it, removeNewFlags)
-
- def remove_children (self, parentIt, removeNewFlags = True):
- """Removes all children of a given parent TreeIter recursivly.
-
- @param parentIt: The iter from which to remove all children.
- @type parentIt: Iterator
- @param removeNewFlags: True if new flags should be removed; False otherwise. Default: True.
- @type removeNewFlags: boolean"""
-
- childIt = self.tree.first_child_iter(parentIt)
-
- while childIt:
- if (self.tree.iter_has_children(childIt)): # recursive call
- self.remove_children(childIt, removeNewFlags)
- temp = childIt
- childIt = self.tree.next_iter(childIt)
- self.remove(temp, removeNewFlags)
-
- def remove (self, it, removeNewFlags = True):
- """Removes a specific item in the tree. This does not remove the top-entries.
-
- @param it: Iterator which points to the entry we are going to remove.
- @type it: Iterator
- @param removeNewFlags: True if new flags should be removed; False otherwise. Default: True.
- @type removeNewFlags: boolean"""
-
- def __remove (type, cpv):
- del self.iters[type][cpv]
- try:
- del self.deps[type][cpv]
- except KeyError: # this seems to be removed due to a BlockedException - so no deps here atm ;)
- debug("Catched KeyError => %s seems not to be in self.deps. Should be no harm in normal cases.", cpv)
-
- for key in self.blocks[type].keys():
- if cpv in self.blocks[type][key]:
- self.blocks[type][key].remove(cpv)
-
- if not self.blocks[type][key]: # list is empty -> remove the whole key
- del self.blocks[type][key]
-
- if removeNewFlags: # remove the changed flags
- flags.remove_new_use_flags(cpv)
- flags.remove_new_masked(cpv)
- flags.remove_new_testing(cpv)
-
- 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
-
- __remove("install", cpv)
-
- try:
- self.mergequeue.remove(cpv)
- except ValueError: # this is a dependency - ignore
- try:
- self.oneshotmerge.remove(cpv)
- except ValueError:
- debug("Catched ValueError => %s seems not to be in merge-queue. Should be no harm.", cpv)
-
- elif self.tree.is_in_unmerge(it): # in Unmerge
- del self.iters["uninstall"][cpv]
- self.unmergequeue.remove(cpv)
-
- elif self.tree.is_in_update(it):
- __remove("update", cpv)
-
-
- 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,
- and the process is not running.
-
- @returns: True if everything is empty and the process is not running.
- @rtype: bool"""
-
- return not (self.process or any(map(len, self.iters.itervalues())))
+ """This class manages the emerge queue."""
+
+ def __init__ (self, tree = None, console = None, db = None, title_update = None, threadClass = threading.Thread):
+ """Constructor.
+
+ @param tree: Tree to append all the items to.
+ @type tree: GtkTree
+ @param console: Output is shown here.
+ @type console: GtkConsole
+ @param db: A database instance.
+ @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
+ self.unmergequeue = [] # for emerge -C
+ self.oneshotmerge = [] # for emerge --oneshot
+
+ # the emerge process
+ self.process = None
+ self.threadQueue = WaitingQueue(threadClass = threadClass)
+ self.pty = None
+
+ # dictionaries with data about the packages in the queue
+ self.iters = {"install" : {}, "uninstall" : {}, "update" : {}} # iterator in the tree
+ self.deps = {"install" : {}, "update" : {}} # all the deps of the package
+ self.blocks = {"install" : OrderedDict(), "update" : OrderedDict()}
+
+ # member vars
+ self.tree = tree
+ if self.tree and not isinstance(self.tree, GtkTree): raise TypeError, "tree passed is not a GtkTree-object"
+
+ self.console = console
+ if self.console and not isinstance(self.console, GtkConsole): raise TypeError, "console passed is not a GtkConsole-object"
+
+ self.db = db
+ self.title_update = title_update
+ self.threadClass = threadClass
+
+ if self.console:
+ self.pty = pty.openpty()
+ self.console.set_pty(self.pty[0])
+
+ def _get_pkg_from_cpv (self, cpv, unmask = False):
+ """Gets a L{backend.Package}-object from a cpv.
+
+ @param cpv: the cpv to get the package for
+ @type cpv: string (cpv)
+ @param unmask: if True we will look for masked packages if we cannot find unmasked ones
+ @type unmask: boolean
+ @return: created package
+ @rtype: backend.Package
+
+ @raises backend.PackageNotFoundException: If no package could be found - normally it is existing but masked."""
+
+ # for the beginning: let us create a package object - but it is not guaranteed, that it actually exists in portage
+ pkg = system.new_package(cpv)
+ masked = not (pkg.is_masked() or pkg.is_testing(use_keywords=True)) # we are setting this to True in case we have unmasked it already, but portage does not know this
+
+ # and now try to find it in portage
+ pkg = system.find_packages("="+cpv, masked = masked)
+
+ if pkg: # gotcha
+ pkg = pkg[0]
+
+ elif unmask: # no pkg returned, but we are allowed to unmask it
+ pkg = system.find_packages("="+cpv, masked = True)
+
+ if not pkg:
+ raise backend.PackageNotFoundException(cpv) # also not found
+ else:
+ pkg = pkg[0]
+
+ if pkg.is_testing(use_keywords = True):
+ pkg.set_testing(True)
+ if pkg.is_masked():
+ pkg.set_masked()
+
+ else: # no pkg returned - and we are not allowed to unmask
+ raise backend.PackageNotFoundException(cpv)
+
+ return pkg
+
+ def update_tree (self, it, cpv, unmask = False, oneshot = False, type = "install"):
+ """This updates the tree recursivly, or? Isn't it? Bjorn!
+
+ @param it: iterator where to append
+ @type it: Iterator
+ @param cpv: The package to append.
+ @type cpv: string (cat/pkg-ver)
+ @param unmask: True if we are allowed to look for masked packages
+ @type unmask: boolean
+ @param oneshot: True if we want to emerge is oneshot
+ @type oneshot: boolean
+ @param type: the type of the updating
+ @type type: string
+
+ @raises backend.BlockedException: When occured during dependency-calculation.
+ @raises backend.PackageNotFoundException: If no package could be found - normally it is existing but masked."""
+
+ if cpv in self.deps[type]:
+ return # in list already and therefore it's already in the tree too
+
+ # try to find an already installed instance
+ update = False
+ downgrade = False
+ uVersion = None
+ changedUse = []
+ try:
+ pkg = self._get_pkg_from_cpv(cpv, unmask)
+ if not pkg.is_installed():
+ old = system.find_packages(pkg.get_slot_cp(), system.SET_INSTALLED)
+ if old:
+ old = old[0] # assume we have only one there
+ cmp = pkg.compare_version(old)
+ if cmp > 0:
+ update = True
+ elif cmp < 0:
+ downgrade = True
+
+ uVersion = old.get_version()
+
+ old_iuse = set(old.get_iuse_flags())
+ new_iuse = set(pkg.get_iuse_flags())
+
+ for i in old_iuse.difference(new_iuse):
+ changedUse.append("-"+i)
+
+ for i in new_iuse.difference(old_iuse):
+ changedUse.append("+"+i)
+ else:
+ old_iuse = set(pkg.get_iuse_flags(installed = True))
+ new_iuse = set(pkg.get_iuse_flags(installed = False))
+
+ for i in old_iuse.difference(new_iuse):
+ changedUse.append("-"+i)
+
+ for i in new_iuse.difference(old_iuse):
+ changedUse.append("+"+i)
+
+ except backend.PackageNotFoundException, e: # package not found / package is masked -> delete current tree and re-raise the exception
+ if type == "update": # remove complete tree
+ self.remove_with_children(self.tree.first_iter(it), removeNewFlags = False)
+
+ elif type == "install": # remove only the intentionally added package
+ top = self.tree.first_iter(it)
+ parent = self.tree.parent_iter(it)
+
+ if parent:
+ while not self.tree.iter_equal(top, parent):
+ parent = self.tree.parent_iter(parent)
+ it = self.tree.parent_iter(it)
+
+ self.remove_with_children(it, removeNewFlags = False)
+
+ if not self.tree.iter_has_children(top): # remove completely if nothing left
+ self.remove(top)
+ raise
+
+ # add iter
+ subIt = self.tree.append(it, self.tree.build_append_value(cpv, oneshot = oneshot, update = update, downgrade = downgrade, version = uVersion, useChange = changedUse))
+ self.iters[type][cpv] = subIt
+
+ # get dependencies
+ deps = pkg.get_dep_packages(return_blocks = True)
+ self.deps[type][cpv] = deps
+
+ for d in deps:
+ if d[0] == "!": # block
+ dep = d[1:]
+ if not dep in self.blocks[type]:
+ self.blocks[type][dep] = set()
+
+ self.blocks[type][dep].add(cpv)
+ else: # recursive call
+ self.update_tree(subIt, d, unmask, type = type)
+
+ 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 type: The type of this append process. Possible values are "install", "uninstall", "update".
+ @type type: 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.
+ @type forceUpdate: boolean
+ @param unmask: True if we are allowed to look for masked packages
+ @type unmask: boolean
+ @param oneshot: True if this package should not be added to the world-file.
+ @type oneshot: boolean
+
+ @raises portato.backend.PackageNotFoundException: if trying to add a package which does not exist"""
+
+ if type in ("install", "update"): # emerge
+ if update:
+ pkg = self._get_pkg_from_cpv(cpv, unmask)
+ deps = pkg.get_dep_packages(return_blocks = True)
+
+ if not forceUpdate and cpv in self.deps[type] and deps == self.deps[type][cpv]:
+ return # nothing changed - return
+ else:
+ hasBeenInQueue = (cpv in self.mergequeue or cpv in self.oneshotmerge)
+ parentIt = self.tree.parent_iter(self.iters[type][cpv])
+
+ # delete it out of the tree - but NOT the changed flags
+ self.remove_with_children(self.iters[type][cpv], removeNewFlags = False)
+
+ if hasBeenInQueue: # package has been in queue before
+ self._queue_append(cpv, oneshot)
+
+ self.update_tree(parentIt, cpv, unmask, oneshot = oneshot, type = type)
+ else: # not update
+ if type == "install":
+ 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)
+
+ # handle blocks
+ if self.blocks[type]:
+ # check whether anything blocks something in the queue
+ for block in self.blocks[type]:
+ for c in self.iters[type]:
+ if system.cpv_matches(c, block):
+ blocked = ", ".join(self.blocks[type][block])
+ warning("'%s' is blocked by: %s", c, blocked)
+ self.remove_with_children(self.iters[type][c], False)
+ raise BlockedException(c, blocked)
+
+ #
+ # check whether we block a version that we are going to replace nevertheless
+ #
+
+ # get the blocks that block an installed package
+ inst = []
+ for block in self.blocks[type]:
+ pkgs = system.find_packages(block, system.SET_INSTALLED)
+ if pkgs:
+ inst.append((pkgs, block))
+
+ # the slot-cp's of the packages in the queue
+ slots = {}
+ for c in self.iters[type]:
+ slots[system.new_package(c).get_slot_cp()] = cpv
+
+ # check the installed blocks against the slot-cp's
+ for pkgs, block in inst[:]:
+ done = False
+ for pkg in pkgs:
+ done = False
+ if pkg.get_slot_cp() in slots:
+ debug("Block '%s' can be ignored, because the blocking package is going to be replaced with '%s'.", block, slots[pkg.get_slot_cp()])
+ done = True
+ if done:
+ inst.remove((pkgs,block))
+
+ if inst: # there is still something left to block
+ for pkgs, block in inst:
+ blocked = ", ".join(self.blocks[type][block])
+ warning("'%s' blocks the installation of: %s", pkgs[0].get_cpv(), blocked)
+ self.remove_with_children(self.iters[type][cpv], False)
+ raise BlockedException(blocked, pkgs[0].get_cpv())
+
+ else: # unmerge
+ self.unmergequeue.append(cpv)
+ if self.tree: # update tree
+ self.iters["uninstall"].update({cpv: 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.
+
+ @param cpv: cpv to add
+ @type cpv: string (cpv)
+ @param oneshot: True if this package should not be added to the world-file.
+ @type oneshot: boolean"""
+
+ if not oneshot:
+ if cpv not in self.mergequeue:
+ self.mergequeue.append(cpv)
+ else:
+ if cpv not in self.oneshotmerge:
+ self.oneshotmerge.append(cpv)
+
+ def doEmerge (self, options, packages, it, *args, **kwargs):
+ top = None
+ if self.tree and it:
+ for v in it.itervalues():
+ self.tree.set_in_progress(v)
+ top = self.tree.first_iter(v)
+ break
+
+ self.threadQueue.put(self.__emerge, options, packages, it, top, *args, **kwargs)
+
+ def __emerge (self, options, packages, it, top, command = None):
+ """Calls emerge and updates the terminal.
+
+ @param options: options to send to emerge
+ @type options: string[]
+ @param packages: packages to emerge
+ @type packages: string[]
+ @param it: Iterators which point to these entries whose children will be removed after completion.
+ @type it: dict(string -> Iterator)
+ @param top: The top iterator
+ @type top: Iterator
+ @param command: the command to execute - default is "/usr/bin/python /usr/bin/emerge"
+ @type command: string[]"""
+
+ @plugin.hook("emerge", packages = packages, command = command, console = self.console, title_update = self.title_update)
+ def sub_emerge(command):
+ if command is None:
+ command = system.get_merge_command()
+
+ # open tty
+ if self.console:
+ self.console.reset()
+
+ def pre ():
+ os.setsid() # new session
+ if self.console:
+ import fcntl, termios
+ fcntl.ioctl(self.pty[1], termios.TIOCSCTTY, 0) # set pty-slave as session tty
+ os.dup2(self.pty[1], 0)
+ os.dup2(self.pty[1], 1)
+ os.dup2(self.pty[1], 2)
+
+ # get all categories that are being touched during the emerge process
+ cats = set(map(lambda x: x.split("/")[0], it.iterkeys()))
+
+ # start emerge
+ self.process = Popen(command+options+packages, shell = False, env = system.get_environment(), preexec_fn = pre)
+
+ # remove packages from queue
+ if self.tree and it and not self.tree.is_in_unmerge(top):
+ self.up = Updater(self, it, self.threadClass)
+ else:
+ self.up = None
+
+ # update title
+ if self.console:
+ old_title = self.console.get_window_title()
+ while self.process and self.process.poll() is None:
+ if self.title_update :
+ title = self.console.get_window_title()
+ if title != old_title:
+ self.title_update(title)
+ old_title = title
+ time.sleep(0.5)
+
+ if self.up:
+ self.up.stop()
+ if it:
+ self.tree.set_in_progress(top, False)
+ else:
+ self.remove(top)
+ elif self.tree and it:
+ self.remove_with_children(top)
+
+ if self.title_update: self.title_update(None)
+
+ if self.process is None: # someone resetted this
+ self.threadQueue.next()
+ return
+ else:
+ ret = self.process.returncode
+ self.process = None
+ self.threadQueue.next()
+
+ @plugin.hook("after_emerge", packages = packages, retcode = ret)
+ def update_packages():
+ if self.db:
+ for cat in cats:
+ self.db.reload(cat)
+ debug("Category %s refreshed", cat)
+
+ update_packages()
+
+ sub_emerge(command)
+
+ def emerge (self, force = False, options = None):
+ """Emerges everything in the merge-queue.
+
+ @param force: If False, '-pv' is send to emerge. Default: False.
+ @type force: boolean
+ @param options: Additional options to send to the emerge command
+ @type options: string[]"""
+
+ def prepare(queue):
+ """Prepares the list of iterators and the list of packages."""
+ list = []
+ its = {}
+ for k in queue:
+ list += ["="+k]
+ if self.tree:
+ its.update({k : self.iters["install"][k]})
+
+ return list, its
+
+ if self.tree:
+ ownit = self.iters["install"]
+ 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()
+ if options is not None: s += options
+
+ self.doEmerge(s, list, its, caller = self.emerge)
+
+ # normal queue
+ 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()
+ if options is not None: s += options
+
+ self.doEmerge(s, list, its, caller = self.emerge)
+
+ def unmerge (self, force = False, options = None):
+ """Unmerges everything in the umerge-queue.
+
+ @param force: If False, '-pv' is send to emerge. Default: False.
+ @type force: boolean
+ @param options: Additional options to send to the emerge command
+ @type options: string[]"""
+
+ if len(self.unmergequeue) == 0: return # nothing in queue
+
+ list = self.unmergequeue[:] # copy the unmerge-queue
+
+ # set options
+ s = system.get_unmerge_option()
+ if not force: s += system.get_pretend_option()
+ if options is not None: s += options
+
+ if self.tree:
+ it = self.iters["uninstall"]
+ else:
+ it = {}
+
+ self.doEmerge(s,list, it, caller = self.unmerge)
+
+ def update_world(self, sets = ("world",), force = False, newuse = False, deep = False, options = None):
+ """Does an update world. newuse and deep are the arguments handed to emerge.
+
+ @param sets: The sets to update.
+ @type sets: string[]
+ @param force: If False, '-pv' is send to emerge. Default: False.
+ @type force: boolean
+ @param newuse: If True, append newuse options
+ @type newuse: boolean
+ @param deep: If True, append deep options
+ @type deep: boolean
+ @param options: Additional options to send to the emerge command
+ @type options: string[]"""
+
+ opts = system.get_update_option()
+
+ if newuse: opts += system.get_newuse_option()
+ if deep: opts += system.get_deep_option()
+ if not force: opts += system.get_pretend_option()
+ if options is not None: opts += options
+
+ if self.tree:
+ it = self.iters["update"]
+ else:
+ it = {}
+
+ self.doEmerge(opts, list(sets), it, caller = self.update_world)
+
+ def sync (self, command = None):
+ """Calls "emerge --sync".
+
+ @param command: command to execute to sync. If None "emerge --sync" is taken.
+ @type command: string[]"""
+
+ if command is None:
+ command = system.get_sync_command()
+
+ try:
+ while True:
+ idx = command.index("&&")
+ self.doEmerge([],[],{}, command[:idx], caller = self.sync)
+ command = command[idx+1:]
+ except ValueError: # no && in command
+ self.doEmerge([],[],{}, command, caller = self.sync)
+
+ def kill_emerge (self):
+ """Kills the emerge process."""
+ if self.process is not None:
+ self.threadQueue.clear() # remove all pending emerge threads
+ try:
+ pgid = os.getpgid(self.process.pid)
+ os.killpg(pgid, signal.SIGTERM)
+ debug("Process should be terminated")
+ if self.process.poll() is None:
+ os.killpg(pgid, signal.SIGKILL)
+ debug("Process should be killed")
+ except AttributeError:
+ debug("AttributeError occured ==> process not exisiting - ignore")
+ except OSError:
+ debug("OSError occured ==> process already stopped - ignore")
+
+ self.process = None
+
+ def stop_emerge (self):
+ if self.process is not None:
+ os.killpg(os.getpgid(self.process.pid), signal.SIGSTOP)
+ debug("Process should be stopped")
+
+ def continue_emerge (self):
+ if self.process is not None:
+ os.killpg(os.getpgid(self.process.pid), signal.SIGCONT)
+ debug("Process should continue")
+
+ def remove_with_children (self, it, removeNewFlags = True):
+ """Convenience function which removes all children of an iterator and than the iterator itself.
+
+ @param it: The iter which to remove.
+ @type it: Iterator
+ @param removeNewFlags: True if new flags should be removed; False otherwise. Default: True.
+ @type removeNewFlags: boolean"""
+
+ self.remove_children(it, removeNewFlags)
+ self.remove(it, removeNewFlags)
+
+ def remove_children (self, parentIt, removeNewFlags = True):
+ """Removes all children of a given parent TreeIter recursivly.
+
+ @param parentIt: The iter from which to remove all children.
+ @type parentIt: Iterator
+ @param removeNewFlags: True if new flags should be removed; False otherwise. Default: True.
+ @type removeNewFlags: boolean"""
+
+ childIt = self.tree.first_child_iter(parentIt)
+
+ while childIt:
+ if (self.tree.iter_has_children(childIt)): # recursive call
+ self.remove_children(childIt, removeNewFlags)
+ temp = childIt
+ childIt = self.tree.next_iter(childIt)
+ self.remove(temp, removeNewFlags)
+
+ def remove (self, it, removeNewFlags = True):
+ """Removes a specific item in the tree. This does not remove the top-entries.
+
+ @param it: Iterator which points to the entry we are going to remove.
+ @type it: Iterator
+ @param removeNewFlags: True if new flags should be removed; False otherwise. Default: True.
+ @type removeNewFlags: boolean"""
+
+ def __remove (type, cpv):
+ del self.iters[type][cpv]
+ try:
+ del self.deps[type][cpv]
+ except KeyError: # this seems to be removed due to a BlockedException - so no deps here atm ;)
+ debug("Catched KeyError => %s seems not to be in self.deps. Should be no harm in normal cases.", cpv)
+
+ for key in self.blocks[type].keys():
+ if cpv in self.blocks[type][key]:
+ self.blocks[type][key].remove(cpv)
+
+ if not self.blocks[type][key]: # list is empty -> remove the whole key
+ del self.blocks[type][key]
+
+ if removeNewFlags: # remove the changed flags
+ flags.remove_new_use_flags(cpv)
+ flags.remove_new_masked(cpv)
+ flags.remove_new_testing(cpv)
+
+ 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
+
+ __remove("install", cpv)
+
+ try:
+ self.mergequeue.remove(cpv)
+ except ValueError: # this is a dependency - ignore
+ try:
+ self.oneshotmerge.remove(cpv)
+ except ValueError:
+ debug("Catched ValueError => %s seems not to be in merge-queue. Should be no harm.", cpv)
+
+ elif self.tree.is_in_unmerge(it): # in Unmerge
+ del self.iters["uninstall"][cpv]
+ self.unmergequeue.remove(cpv)
+
+ elif self.tree.is_in_update(it):
+ __remove("update", cpv)
+
+
+ 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,
+ and the process is not running.
+
+ @returns: True if everything is empty and the process is not running.
+ @rtype: bool"""
+
+ return not (self.process or any(map(len, self.iters.itervalues())))
diff --git a/portato/gui/session.py b/portato/gui/session.py
index a37cd85..1eca248 100644
--- a/portato/gui/session.py
+++ b/portato/gui/session.py
@@ -18,16 +18,16 @@ SESSION_VERSION = 1
class SessionException (Exception):
- error = _("Version mismatch.")
- def __init__ (self, got, expected):
- self.got = got
- self.expected = expected
+ error = _("Version mismatch.")
+ def __init__ (self, got, expected):
+ self.got = got
+ self.expected = expected
- def __str__ (self):
- return "%s %s" % (self.error, (_("Got '%d' - expected '%d'.") % (self.got, self.expected)))
+ def __str__ (self):
+ return "%s %s" % (self.error, (_("Got '%d' - expected '%d'.") % (self.got, self.expected)))
class OldSessionException (SessionException):
- error = _("Current session format is too old.")
+ error = _("Current session format is too old.")
class NewSessionException (SessionException):
- error = _("Current session format is newer than this version supports.")
+ error = _("Current session format is newer than this version supports.")
diff --git a/portato/gui/updater.py b/portato/gui/updater.py
index c4c81e7..c4ad2a5 100644
--- a/portato/gui/updater.py
+++ b/portato/gui/updater.py
@@ -18,109 +18,109 @@ import threading, subprocess, time
from ..helper import debug, warning, error
class Updater (object):
- """
- This class is intended to check what package is currently being installed and remove this one from the queue.
+ """
+ This class is intended to check what package is currently being installed and remove this one from the queue.
- @cvar SED_EXP: The sed expression to strip the package name out of the qlop call.
- """
-
- SED_EXP = r"""
+ @cvar SED_EXP: The sed expression to strip the package name out of the qlop call.
+ """
+
+ SED_EXP = r"""
/\*/{
s/ \* //
n
}
d"""
-
- def __init__ (self, queue, iterators, threadClass = threading.Thread):
- """
- Constructor.
- Also directly initializes the thread.
-
- @param queue: an emerge queue instance
- @type queue: EmergeQueue
- @param iterators: a dictionary of iterators in the current queue
- @type iterators: dict(string->Iterator)
- """
-
- if not issubclass(threadClass, threading.Thread):
- raise ValueError, "Only subclasses of threading.Thread are allowed."
-
- self.queue = queue
- self.iterators = iterators
- self.threadClass = threadClass
- self.stopEvent = threading.Event()
- self.removed = set()
-
- t = threadClass(name = "Queue Updater Thread", target = self.run)
- t.setDaemon(True)
- t.start()
-
- def run (self):
- """
- Run and run and run ...
- Checks the packages until being stopped.
- """
-
- curr = set()
- while not self.stopEvent.isSet():
-
- # this = $(qlop -cCq | sed $SED_EXP)
- p1 = subprocess.Popen(["qlop", "--current", "--nocolor", "--quiet"], stdout = subprocess.PIPE)
- this = subprocess.Popen(["sed", self.SED_EXP], stdout = subprocess.PIPE, stdin = p1.stdout).communicate()[0]
-
- this = set(this.split()) if this else set()
- for removed in curr - this:
- self.remove(self.find(removed)) # remove the previous
- curr = this
-
- time.sleep(2.0)
-
- self.removed = set()
-
- def stop (self):
- """
- Stops the current updater.
- """
- self.stopEvent.set()
-
- def find (self, pv, masked = False):
- """
- As qlop only returns 'package-version' we need to assign it to a cpv.
- This is done here.
- """
-
- pkgs = system.find_packages("=%s" % pv, only_cpv = True, masked = masked)
-
- if len(pkgs) > 1: # ambigous - try to find the one which is also in the iterators
- for p in pkgs:
- if p in self.iterators:
- return p
- elif not pkgs: # nothing found =|
- if not masked:
- warning(_("No unmasked version of package '%s' found. Trying masked ones. This normally should not happen..."), pv)
- return self.find(pv, True)
-
- else:
- error(_("Trying to remove package '%s' from queue which does not exist in system."), pv)
- return None
- else: # only one choice =)
- return pkgs[0]
-
- def remove (self, cpv):
- """
- Remove a package from the queue.
- """
-
- if cpv is None:
- debug("Nothing to remove.")
- return
-
- if cpv in self.removed:
- return
-
- self.removed.add(cpv)
-
- try:
- self.queue.remove_with_children(self.iterators[cpv])
- except KeyError:
- debug("'%s' should be removed, but is not in queue.", cpv)
+
+ def __init__ (self, queue, iterators, threadClass = threading.Thread):
+ """
+ Constructor.
+ Also directly initializes the thread.
+
+ @param queue: an emerge queue instance
+ @type queue: EmergeQueue
+ @param iterators: a dictionary of iterators in the current queue
+ @type iterators: dict(string->Iterator)
+ """
+
+ if not issubclass(threadClass, threading.Thread):
+ raise ValueError, "Only subclasses of threading.Thread are allowed."
+
+ self.queue = queue
+ self.iterators = iterators
+ self.threadClass = threadClass
+ self.stopEvent = threading.Event()
+ self.removed = set()
+
+ t = threadClass(name = "Queue Updater Thread", target = self.run)
+ t.setDaemon(True)
+ t.start()
+
+ def run (self):
+ """
+ Run and run and run ...
+ Checks the packages until being stopped.
+ """
+
+ curr = set()
+ while not self.stopEvent.isSet():
+
+ # this = $(qlop -cCq | sed $SED_EXP)
+ p1 = subprocess.Popen(["qlop", "--current", "--nocolor", "--quiet"], stdout = subprocess.PIPE)
+ this = subprocess.Popen(["sed", self.SED_EXP], stdout = subprocess.PIPE, stdin = p1.stdout).communicate()[0]
+
+ this = set(this.split()) if this else set()
+ for removed in curr - this:
+ self.remove(self.find(removed)) # remove the previous
+ curr = this
+
+ time.sleep(2.0)
+
+ self.removed = set()
+
+ def stop (self):
+ """
+ Stops the current updater.
+ """
+ self.stopEvent.set()
+
+ def find (self, pv, masked = False):
+ """
+ As qlop only returns 'package-version' we need to assign it to a cpv.
+ This is done here.
+ """
+
+ pkgs = system.find_packages("=%s" % pv, only_cpv = True, masked = masked)
+
+ if len(pkgs) > 1: # ambigous - try to find the one which is also in the iterators
+ for p in pkgs:
+ if p in self.iterators:
+ return p
+ elif not pkgs: # nothing found =|
+ if not masked:
+ warning(_("No unmasked version of package '%s' found. Trying masked ones. This normally should not happen..."), pv)
+ return self.find(pv, True)
+
+ else:
+ error(_("Trying to remove package '%s' from queue which does not exist in system."), pv)
+ return None
+ else: # only one choice =)
+ return pkgs[0]
+
+ def remove (self, cpv):
+ """
+ Remove a package from the queue.
+ """
+
+ if cpv is None:
+ debug("Nothing to remove.")
+ return
+
+ if cpv in self.removed:
+ return
+
+ self.removed.add(cpv)
+
+ try:
+ self.queue.remove_with_children(self.iterators[cpv])
+ except KeyError:
+ debug("'%s' should be removed, but is not in queue.", cpv)
diff --git a/portato/gui/utils.py b/portato/gui/utils.py
index cd5c50c..661af6b 100644
--- a/portato/gui/utils.py
+++ b/portato/gui/utils.py
@@ -32,280 +32,280 @@ from ..constants import APP, LOCALE_DIR
from ..config_parser import ConfigParser
def get_color (cfg, name):
- return gtk.gdk.color_parse("#%s" % cfg.get(name, section = "COLORS"))
+ return gtk.gdk.color_parse("#%s" % cfg.get(name, section = "COLORS"))
class GtkThread (Thread):
- def run(self):
- # for some reason, I have to install this for each thread ...
- gettext.install(APP, LOCALE_DIR, unicode = True)
- try:
- Thread.run(self)
- except SystemExit:
- raise # let normal thread handle it
- except:
- type, val, tb = sys.exc_info()
- try:
- sys.excepthook(type, val, tb, thread = self.getName())
- except TypeError:
- raise type, val, tb # let normal thread handle it
- finally:
- del type, val, tb
+ def run(self):
+ # for some reason, I have to install this for each thread ...
+ gettext.install(APP, LOCALE_DIR, unicode = True)
+ try:
+ Thread.run(self)
+ except SystemExit:
+ raise # let normal thread handle it
+ except:
+ type, val, tb = sys.exc_info()
+ try:
+ sys.excepthook(type, val, tb, thread = self.getName())
+ except TypeError:
+ raise type, val, tb # let normal thread handle it
+ finally:
+ del type, val, tb
class Config (ConfigParser):
-
- def __init__ (self, cfgFile):
- """Constructor.
-
- @param cfgFile: path to config file
- @type cfgFile: string"""
-
- ConfigParser.__init__(self, cfgFile)
-
- # read config
- self.parse()
-
- # local configs
- self.local = {}
-
- def modify_flags_config (self):
- """Sets the internal config of the L{flags}-module.
- @see: L{flags.set_config()}"""
-
- flagCfg = {
- "usefile": self.get("useFile"),
- "usePerVersion" : self.get_boolean("usePerVersion"),
- "maskfile" : self.get("maskFile"),
- "maskPerVersion" : self.get_boolean("maskPerVersion"),
- "testingfile" : self.get("keywordFile"),
- "testingPerVersion" : self.get_boolean("keywordPerVersion")}
- flags.set_config(flagCfg)
-
- def modify_debug_config (self):
- if self.get_boolean("debug"):
- level = logging.DEBUG
- else:
- level = logging.INFO
-
- set_log_level(level)
-
- def modify_system_config (self):
- """Sets the system config.
- @see: L{backend.set_system()}"""
- set_system(self.get("system"))
-
- def modify_external_configs (self):
- """Convenience function setting all external configs."""
- self.modify_debug_config()
- self.modify_flags_config()
- self.modify_system_config()
-
- def set_local(self, cpv, name, val):
- """Sets some local config.
-
- @param cpv: the cpv describing the package for which to set this option
- @type cpv: string (cpv)
- @param name: the option's name
- @type name: string
- @param val: the value to set
- @type val: any"""
-
- if not cpv in self.local:
- self.local[cpv] = {}
-
- self.local[cpv].update({name:val})
-
- def get_local(self, cpv, name):
- """Returns something out of the local config.
-
- @param cpv: the cpv describing the package from which to get this option
- @type cpv: string (cpv)
- @param name: the option's name
- @type name: string
- @return: value stored for the cpv and name or None if not found
- @rtype: any"""
-
- if not cpv in self.local:
- return None
- if not name in self.local[cpv]:
- return None
-
- return self.local[cpv][name]
-
- def write(self):
- """Writes to the config file and modify any external configs."""
- ConfigParser.write(self)
- self.modify_external_configs()
+
+ def __init__ (self, cfgFile):
+ """Constructor.
+
+ @param cfgFile: path to config file
+ @type cfgFile: string"""
+
+ ConfigParser.__init__(self, cfgFile)
+
+ # read config
+ self.parse()
+
+ # local configs
+ self.local = {}
+
+ def modify_flags_config (self):
+ """Sets the internal config of the L{flags}-module.
+ @see: L{flags.set_config()}"""
+
+ flagCfg = {
+ "usefile": self.get("useFile"),
+ "usePerVersion" : self.get_boolean("usePerVersion"),
+ "maskfile" : self.get("maskFile"),
+ "maskPerVersion" : self.get_boolean("maskPerVersion"),
+ "testingfile" : self.get("keywordFile"),
+ "testingPerVersion" : self.get_boolean("keywordPerVersion")}
+ flags.set_config(flagCfg)
+
+ def modify_debug_config (self):
+ if self.get_boolean("debug"):
+ level = logging.DEBUG
+ else:
+ level = logging.INFO
+
+ set_log_level(level)
+
+ def modify_system_config (self):
+ """Sets the system config.
+ @see: L{backend.set_system()}"""
+ set_system(self.get("system"))
+
+ def modify_external_configs (self):
+ """Convenience function setting all external configs."""
+ self.modify_debug_config()
+ self.modify_flags_config()
+ self.modify_system_config()
+
+ def set_local(self, cpv, name, val):
+ """Sets some local config.
+
+ @param cpv: the cpv describing the package for which to set this option
+ @type cpv: string (cpv)
+ @param name: the option's name
+ @type name: string
+ @param val: the value to set
+ @type val: any"""
+
+ if not cpv in self.local:
+ self.local[cpv] = {}
+
+ self.local[cpv].update({name:val})
+
+ def get_local(self, cpv, name):
+ """Returns something out of the local config.
+
+ @param cpv: the cpv describing the package from which to get this option
+ @type cpv: string (cpv)
+ @param name: the option's name
+ @type name: string
+ @return: value stored for the cpv and name or None if not found
+ @rtype: any"""
+
+ if not cpv in self.local:
+ return None
+ if not name in self.local[cpv]:
+ return None
+
+ return self.local[cpv][name]
+
+ def write(self):
+ """Writes to the config file and modify any external configs."""
+ ConfigParser.write(self)
+ self.modify_external_configs()
class PkgData (object):
- __slots__ = ("cat", "pkg", "inst")
+ __slots__ = ("cat", "pkg", "inst")
- def __init__ (self, cat, pkg, inst):
- self.cat = cat
- self.pkg = pkg
- self.inst = inst
+ def __init__ (self, cat, pkg, inst):
+ self.cat = cat
+ self.pkg = pkg
+ self.inst = inst
- def __iter__ (self):
- return iter((self.cat, self.pkg, self.inst))
+ def __iter__ (self):
+ return iter((self.cat, self.pkg, self.inst))
- def __cmp__ (self, other):
- return cmp(self.pkg.lower(), other.pkg.lower())
+ def __cmp__ (self, other):
+ return cmp(self.pkg.lower(), other.pkg.lower())
- def __repr__ (self):
- return "<Package (%(cat)s, %(pkg)s, %(inst)s)>" % {"cat" : self.cat, "pkg" : self.pkg, "inst" : self.inst}
+ def __repr__ (self):
+ 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]."""
-
- ALL = _("ALL")
-
- def __init__ (self):
- """Constructor."""
- self.__initialize()
- self._lock = RLock()
-
- def lock (f):
- @wraps(f)
- def wrapper (self, *args, **kwargs):
- with self._lock:
- r = f(self, *args, **kwargs)
- return r
-
- return wrapper
-
- def __initialize (self):
- self._db = defaultdict(list)
- self.inst_cats = set([self.ALL])
- self._restrict = None
-
- def __sort_key (self, x):
- return x.pkg.lower()
-
- @lock
- def populate (self, category = None):
- """Populates the database.
-
- @param category: An optional category - so only packages of this category are inserted.
- @type category: string
- """
-
- # get the lists
- packages = system.find_packages(category, with_version = False)
- installed = system.find_packages(category, system.SET_INSTALLED, with_version = False)
-
- # cycle through packages
- for p in packages:
- cat, pkg = p.split("/")
- inst = p in installed
- t = PkgData(cat, pkg, inst)
- self._db[cat].append(t)
- self._db[self.ALL].append(t)
-
- if inst:
- self.inst_cats.add(cat)
-
- for key in self._db: # sort alphabetically
- self._db[key].sort(key = self.__sort_key)
-
- @lock
- def get_cat (self, cat = None, byName = True):
- """Returns the packages in the category.
-
- @param cat: category to return the packages from; if None it defaults to "ALL"
- @type cat: string
- @param byName: selects whether to return the list sorted by name or by installation
- @type byName: boolean
- @return: an iterator over a list of tuples: (category, name, is_installed) or []
- @rtype: (string, string, boolean)<iterator>
- """
-
- if not cat:
- cat = self.ALL
-
- def get_pkgs():
- if byName:
- for pkg in self._db[cat]:
- yield pkg
- else:
- ninst = []
- for pkg in self._db[cat]:
- if pkg.inst:
- yield pkg
- else:
- ninst.append(pkg)
-
- for pkg in ninst:
- yield pkg
-
- try:
- if self.restrict:
- return (pkg for pkg in get_pkgs() if self.restrict.search(pkg.pkg))#if pkg[1].find(self.restrict) != -1)
- else:
- return get_pkgs()
-
- except KeyError: # cat is in category list - but not in portage
- info(_("Catched KeyError => %s seems not to be an available category. Have you played with rsync-excludes?"), cat)
-
- @lock
- def get_categories (self, installed = False):
- """Returns all categories.
-
- @param installed: Only return these with at least one installed package.
- @type installed: boolean
- @returns: the list of categories
- @rtype: string<iterator>
- """
-
- if not self.restrict:
- if installed:
- cats = self.inst_cats
- else:
- cats = self._db.iterkeys()
-
- else:
- if installed:
- cats = set((pkg.cat for pkg in self.get_cat(self.ALL) if pkg.inst))
- else:
- cats = set((pkg.cat for pkg in self.get_cat(self.ALL)))
-
- if len(cats)>1:
- cats.add(self.ALL)
-
- return (cat for cat in cats)
-
- @lock
- def reload (self, cat = None):
- """Reloads the given category.
-
- @param cat: category
- @type cat: string
- """
-
- if cat:
- del self._db[cat]
- try:
- self.inst_cats.remove(cat)
- except KeyError: # not in inst_cats - can be ignored
- pass
-
- self._db[self.ALL] = filter(lambda x: x.cat != cat, self._db[self.ALL])
- self.populate(cat+"/*")
- else:
- self.__initialize()
- self.populate()
-
- def get_restrict (self):
- return self._restrict
-
- @lock
- def set_restrict (self, restrict):
- if not restrict:
- self._restrict = None
- else:
- try:
- regex = re.compile(restrict, re.I)
- except re.error, e:
- info(_("Error while compiling search expression: '%s'."), str(e))
- else: # only set self._restrict if no error occurred
- self._restrict = regex
-
- restrict = property(get_restrict, set_restrict)
+ """An internal database which holds a simple dictionary cat -> [package_list]."""
+
+ ALL = _("ALL")
+
+ def __init__ (self):
+ """Constructor."""
+ self.__initialize()
+ self._lock = RLock()
+
+ def lock (f):
+ @wraps(f)
+ def wrapper (self, *args, **kwargs):
+ with self._lock:
+ r = f(self, *args, **kwargs)
+ return r
+
+ return wrapper
+
+ def __initialize (self):
+ self._db = defaultdict(list)
+ self.inst_cats = set([self.ALL])
+ self._restrict = None
+
+ def __sort_key (self, x):
+ return x.pkg.lower()
+
+ @lock
+ def populate (self, category = None):
+ """Populates the database.
+
+ @param category: An optional category - so only packages of this category are inserted.
+ @type category: string
+ """
+
+ # get the lists
+ packages = system.find_packages(category, with_version = False)
+ installed = system.find_packages(category, system.SET_INSTALLED, with_version = False)
+
+ # cycle through packages
+ for p in packages:
+ cat, pkg = p.split("/")
+ inst = p in installed
+ t = PkgData(cat, pkg, inst)
+ self._db[cat].append(t)
+ self._db[self.ALL].append(t)
+
+ if inst:
+ self.inst_cats.add(cat)
+
+ for key in self._db: # sort alphabetically
+ self._db[key].sort(key = self.__sort_key)
+
+ @lock
+ def get_cat (self, cat = None, byName = True):
+ """Returns the packages in the category.
+
+ @param cat: category to return the packages from; if None it defaults to "ALL"
+ @type cat: string
+ @param byName: selects whether to return the list sorted by name or by installation
+ @type byName: boolean
+ @return: an iterator over a list of tuples: (category, name, is_installed) or []
+ @rtype: (string, string, boolean)<iterator>
+ """
+
+ if not cat:
+ cat = self.ALL
+
+ def get_pkgs():
+ if byName:
+ for pkg in self._db[cat]:
+ yield pkg
+ else:
+ ninst = []
+ for pkg in self._db[cat]:
+ if pkg.inst:
+ yield pkg
+ else:
+ ninst.append(pkg)
+
+ for pkg in ninst:
+ yield pkg
+
+ try:
+ if self.restrict:
+ return (pkg for pkg in get_pkgs() if self.restrict.search(pkg.pkg))#if pkg[1].find(self.restrict) != -1)
+ else:
+ return get_pkgs()
+
+ except KeyError: # cat is in category list - but not in portage
+ info(_("Catched KeyError => %s seems not to be an available category. Have you played with rsync-excludes?"), cat)
+
+ @lock
+ def get_categories (self, installed = False):
+ """Returns all categories.
+
+ @param installed: Only return these with at least one installed package.
+ @type installed: boolean
+ @returns: the list of categories
+ @rtype: string<iterator>
+ """
+
+ if not self.restrict:
+ if installed:
+ cats = self.inst_cats
+ else:
+ cats = self._db.iterkeys()
+
+ else:
+ if installed:
+ cats = set((pkg.cat for pkg in self.get_cat(self.ALL) if pkg.inst))
+ else:
+ cats = set((pkg.cat for pkg in self.get_cat(self.ALL)))
+
+ if len(cats)>1:
+ cats.add(self.ALL)
+
+ return (cat for cat in cats)
+
+ @lock
+ def reload (self, cat = None):
+ """Reloads the given category.
+
+ @param cat: category
+ @type cat: string
+ """
+
+ if cat:
+ del self._db[cat]
+ try:
+ self.inst_cats.remove(cat)
+ except KeyError: # not in inst_cats - can be ignored
+ pass
+
+ self._db[self.ALL] = filter(lambda x: x.cat != cat, self._db[self.ALL])
+ self.populate(cat+"/*")
+ else:
+ self.__initialize()
+ self.populate()
+
+ def get_restrict (self):
+ return self._restrict
+
+ @lock
+ def set_restrict (self, restrict):
+ if not restrict:
+ self._restrict = None
+ else:
+ try:
+ regex = re.compile(restrict, re.I)
+ except re.error, e:
+ info(_("Error while compiling search expression: '%s'."), str(e))
+ else: # only set self._restrict if no error occurred
+ self._restrict = regex
+
+ restrict = property(get_restrict, set_restrict)
diff --git a/portato/gui/views.py b/portato/gui/views.py
index bd98ad8..a2d0468 100644
--- a/portato/gui/views.py
+++ b/portato/gui/views.py
@@ -20,130 +20,130 @@ import logging
from ..helper import warning
class LazyView (object):
- def __init__ (self):
- self.connect("map", self.cb_mapped)
+ def __init__ (self):
+ self.connect("map", self.cb_mapped)
- self.pkg = None
- self.updated = False
+ self.pkg = None
+ self.updated = False
- def update (self, pkg, force = False):
- self.pkg = pkg
- self.updated = True
-
- if force:
- self.cb_mapped()
+ def update (self, pkg, force = False):
+ self.pkg = pkg
+ self.updated = True
+
+ if force:
+ self.cb_mapped()
- def cb_mapped (self, *args):
- if self.updated and self.pkg:
- self.set_text("".join(self._get_content()))
- self.updated = False
+ def cb_mapped (self, *args):
+ if self.updated and self.pkg:
+ self.set_text("".join(self._get_content()))
+ self.updated = False
- return False
+ return False
- def set_text (self, text):
- raise NotImplementedError
+ def set_text (self, text):
+ raise NotImplementedError
- def _get_content (self):
- raise NotImplementedError
+ def _get_content (self):
+ raise NotImplementedError
class ListView (gtk.TextView, LazyView):
- def __init__ (self, content_fn):
- self.content_fn = content_fn
+ def __init__ (self, content_fn):
+ self.content_fn = content_fn
- gtk.TextView.__init__(self)
- LazyView.__init__(self)
+ gtk.TextView.__init__(self)
+ LazyView.__init__(self)
- self.set_editable(False)
- self.set_cursor_visible(False)
+ self.set_editable(False)
+ self.set_cursor_visible(False)
- def set_text (self, text):
- self.get_buffer().set_text(text)
+ def set_text (self, text):
+ self.get_buffer().set_text(text)
- def _get_content (self):
- return self.content_fn(self.pkg)
+ def _get_content (self):
+ return self.content_fn(self.pkg)
class InstalledOnlyView (ListView):
- def _get_content (self):
- if self.pkg:
- if not self.pkg.is_installed():
- return _("Package is not installed")
- else:
- return ListView._get_content(self)
- else:
- return "Huh?"
+ def _get_content (self):
+ if self.pkg:
+ if not self.pkg.is_installed():
+ return _("Package is not installed")
+ else:
+ return ListView._get_content(self)
+ else:
+ return "Huh?"
class HighlightView (gtksourceview2.View, LazyView):
- def __init__ (self, get_file_fn, languages = []):
- self.get_fn = get_file_fn
-
- man = gtksourceview2.LanguageManager()
-
- language = None
- old_lang = None
- for lang in languages:
- if old_lang:
- warning(_("No %(old)s language file installed. Falling back to %(new)s."), {"old" : old_lang, "new" : lang})
-
- language = man.get_language(lang)
- if language:
- break
- else:
- old_lang = lang
-
- if not language and old_lang:
- warning(_("No %(old)s language file installed. Disable highlighting."), {"old" : old_lang})
-
- buf = gtksourceview2.Buffer()
- buf.set_language(language)
-
- gtksourceview2.View.__init__(self, buf)
- LazyView.__init__(self)
-
- self.set_editable(False)
- self.set_cursor_visible(False)
-
- def set_text (self, text):
- self.get_buffer().set_text(text)
-
- def _get_content (self):
- try:
- with open(self.get_fn(self.pkg)) as f:
- return f.readlines()
- except IOError, e:
- return _("Error: %s") % e.strerror
-
+ def __init__ (self, get_file_fn, languages = []):
+ self.get_fn = get_file_fn
+
+ man = gtksourceview2.LanguageManager()
+
+ language = None
+ old_lang = None
+ for lang in languages:
+ if old_lang:
+ warning(_("No %(old)s language file installed. Falling back to %(new)s."), {"old" : old_lang, "new" : lang})
+
+ language = man.get_language(lang)
+ if language:
+ break
+ else:
+ old_lang = lang
+
+ if not language and old_lang:
+ warning(_("No %(old)s language file installed. Disable highlighting."), {"old" : old_lang})
+
+ buf = gtksourceview2.Buffer()
+ buf.set_language(language)
+
+ gtksourceview2.View.__init__(self, buf)
+ LazyView.__init__(self)
+
+ self.set_editable(False)
+ self.set_cursor_visible(False)
+
+ def set_text (self, text):
+ self.get_buffer().set_text(text)
+
+ def _get_content (self):
+ try:
+ with open(self.get_fn(self.pkg)) as f:
+ return f.readlines()
+ except IOError, e:
+ return _("Error: %s") % e.strerror
+
class LogView (logging.Handler):
- colors = (
- (logging.DEBUG, "debug", "blue"),
- (logging.INFO, "info", "green"),
- (logging.WARNING, "warning", "yellow"),
- (-1, "error", "red")
- )
-
- def __init__ (self, view):
- logging.Handler.__init__(self, logging.DEBUG)
-
- self.view = view
- self.buf = view.get_buffer()
-
- # set tags
- for lvl, name, color in self.colors:
- self.buf.create_tag("log_%s" % name, foreground = color,weight = pango.WEIGHT_BOLD)
-
- logging.getLogger("portatoLogger").addHandler(self)
-
- def emit (self, record):
-
- for lvl, name, color in self.colors:
- if lvl == -1 or record.levelno <= lvl:
- tag = "log_%s" % name
- break
-
- def _add():
- self.buf.insert_with_tags_by_name(self.buf.get_end_iter(), "* ", tag)
- self.buf.insert(self.buf.get_end_iter(), record.getMessage()+"\n")
-
- gobject.idle_add(_add) # logger might be called from another thread
+ colors = (
+ (logging.DEBUG, "debug", "blue"),
+ (logging.INFO, "info", "green"),
+ (logging.WARNING, "warning", "yellow"),
+ (-1, "error", "red")
+ )
+
+ def __init__ (self, view):
+ logging.Handler.__init__(self, logging.DEBUG)
+
+ self.view = view
+ self.buf = view.get_buffer()
+
+ # set tags
+ for lvl, name, color in self.colors:
+ self.buf.create_tag("log_%s" % name, foreground = color,weight = pango.WEIGHT_BOLD)
+
+ logging.getLogger("portatoLogger").addHandler(self)
+
+ def emit (self, record):
+
+ for lvl, name, color in self.colors:
+ if lvl == -1 or record.levelno <= lvl:
+ tag = "log_%s" % name
+ break
+
+ def _add():
+ self.buf.insert_with_tags_by_name(self.buf.get_end_iter(), "* ", tag)
+ self.buf.insert(self.buf.get_end_iter(), record.getMessage()+"\n")
+
+ gobject.idle_add(_add) # logger might be called from another thread
diff --git a/portato/gui/windows/about.py b/portato/gui/windows/about.py
index df724f3..21608c0 100644
--- a/portato/gui/windows/about.py
+++ b/portato/gui/windows/about.py
@@ -18,17 +18,17 @@ from .basic import AbstractDialog
from ...constants import VERSION, APP_ICON
class AboutWindow (AbstractDialog):
- """A window showing the "about"-informations."""
+ """A window showing the "about"-informations."""
- def __init__ (self, parent):
+ def __init__ (self, parent):
- AbstractDialog.__init__(self, parent)
+ AbstractDialog.__init__(self, parent)
- img = gtk.Image()
- img.set_from_file(APP_ICON)
+ img = gtk.Image()
+ img.set_from_file(APP_ICON)
- self.window.set_version(VERSION)
- self.window.set_logo(img.get_pixbuf())
+ self.window.set_version(VERSION)
+ self.window.set_logo(img.get_pixbuf())
- self.window.show_all()
+ self.window.show_all()
diff --git a/portato/gui/windows/basic.py b/portato/gui/windows/basic.py
index 09d0d7e..6d74858 100644
--- a/portato/gui/windows/basic.py
+++ b/portato/gui/windows/basic.py
@@ -27,101 +27,101 @@ gtk.glade.bindtextdomain (APP, LOCALE_DIR)
gtk.glade.textdomain (APP)
class WrappedTree (object):
- __slots__ = ("klass", "tree", "get_widget")
- def __init__ (self, klass, tree):
- self.tree = tree
- self.klass = klass
-
- def __getattribute__ (self, name):
- if name in WrappedTree.__slots__:
- return object.__getattribute__(self, name)
- else:
- return getattr(self.tree, name)
-
- def get_widget(self, name):
- w = self.tree.get_widget(name)
- if w is None:
- error("Widget '%s' could not be found in class '%s'.", name, self.klass)
- return w
+ __slots__ = ("klass", "tree", "get_widget")
+ def __init__ (self, klass, tree):
+ self.tree = tree
+ self.klass = klass
+
+ def __getattribute__ (self, name):
+ if name in WrappedTree.__slots__:
+ return object.__getattribute__(self, name)
+ else:
+ return getattr(self.tree, name)
+
+ def get_widget(self, name):
+ w = self.tree.get_widget(name)
+ if w is None:
+ error("Widget '%s' could not be found in class '%s'.", name, self.klass)
+ return w
class Window (object):
- def __init__ (self):
-
- if not hasattr(self, "__tree__"):
- self.__tree__ = self.__class__.__name__
-
- if not hasattr(self, "__window__"):
- self.__window__ = self.__class__.__name__
-
- if not hasattr(self, "__file__"):
- self.__file__ = self.__class__.__name__
-
- self.tree = self.get_tree(self.__tree__)
- self.tree.signal_autoconnect(self)
- self.window = self.tree.get_widget(self.__window__)
- self.window.set_icon_from_file(APP_ICON)
-
- @staticmethod
- def watch_cursor (func):
- """This is a decorator for functions being so time consuming, that it is appropriate to show the watch-cursor.
- @attention: this function relies on the gtk.Window-Object being stored as self.window"""
-
- @wraps(func)
- def wrapper (self, *args, **kwargs):
- ret = None
- def cb_idle():
- try:
- ret = func(self, *args, **kwargs)
- finally:
- self.window.window.set_cursor(None)
- return False
-
- watch = gtk.gdk.Cursor(gtk.gdk.WATCH)
- self.window.window.set_cursor(watch)
- gobject.idle_add(cb_idle)
- return ret
-
- return wrapper
-
- def get_tree (self, name):
- return WrappedTree(self.__class__.__name__, gtk.glade.XML(os.path.join(TEMPLATE_DIR, self.__file__+".glade"), name))
+ def __init__ (self):
+
+ if not hasattr(self, "__tree__"):
+ self.__tree__ = self.__class__.__name__
+
+ if not hasattr(self, "__window__"):
+ self.__window__ = self.__class__.__name__
+
+ if not hasattr(self, "__file__"):
+ self.__file__ = self.__class__.__name__
+
+ self.tree = self.get_tree(self.__tree__)
+ self.tree.signal_autoconnect(self)
+ self.window = self.tree.get_widget(self.__window__)
+ self.window.set_icon_from_file(APP_ICON)
+
+ @staticmethod
+ def watch_cursor (func):
+ """This is a decorator for functions being so time consuming, that it is appropriate to show the watch-cursor.
+ @attention: this function relies on the gtk.Window-Object being stored as self.window"""
+
+ @wraps(func)
+ def wrapper (self, *args, **kwargs):
+ ret = None
+ def cb_idle():
+ try:
+ ret = func(self, *args, **kwargs)
+ finally:
+ self.window.window.set_cursor(None)
+ return False
+
+ watch = gtk.gdk.Cursor(gtk.gdk.WATCH)
+ self.window.window.set_cursor(watch)
+ gobject.idle_add(cb_idle)
+ return ret
+
+ return wrapper
+
+ def get_tree (self, name):
+ return WrappedTree(self.__class__.__name__, gtk.glade.XML(os.path.join(TEMPLATE_DIR, self.__file__+".glade"), name))
class AbstractDialog (Window):
- """A class all our dialogs get derived from. It sets useful default vars and automatically handles the ESC-Button."""
-
- def __init__ (self, parent):
- """Constructor.
-
- @param parent: the parent window
- @type parent: gtk.Window"""
-
- Window.__init__(self)
-
- # set parent
- self.window.set_transient_for(parent)
- self.parent = parent
-
- # catch the ESC-key
- self.window.connect("key-press-event", self.cb_key_pressed)
-
- def cb_key_pressed (self, widget, event):
- """Closes the window if ESC is pressed."""
- keyname = gtk.gdk.keyval_name(event.keyval)
- if keyname == "Escape":
- self.close()
- return True
- else:
- return False
-
- def close (self, *args):
- self.window.destroy()
+ """A class all our dialogs get derived from. It sets useful default vars and automatically handles the ESC-Button."""
+
+ def __init__ (self, parent):
+ """Constructor.
+
+ @param parent: the parent window
+ @type parent: gtk.Window"""
+
+ Window.__init__(self)
+
+ # set parent
+ self.window.set_transient_for(parent)
+ self.parent = parent
+
+ # catch the ESC-key
+ self.window.connect("key-press-event", self.cb_key_pressed)
+
+ def cb_key_pressed (self, widget, event):
+ """Closes the window if ESC is pressed."""
+ keyname = gtk.gdk.keyval_name(event.keyval)
+ if keyname == "Escape":
+ self.close()
+ return True
+ else:
+ return False
+
+ def close (self, *args):
+ self.window.destroy()
class Popup (object):
- def __init__ (self, name, parent, file = "popups"):
- self.tree = gtk.glade.XML(os.path.join(TEMPLATE_DIR, file+".glade"), root = name)
- self.tree.signal_autoconnect(parent)
- self._popup = self.tree.get_widget(name)
+ def __init__ (self, name, parent, file = "popups"):
+ self.tree = gtk.glade.XML(os.path.join(TEMPLATE_DIR, file+".glade"), root = name)
+ self.tree.signal_autoconnect(parent)
+ self._popup = self.tree.get_widget(name)
- def popup (self, *args):
- self._popup.popup(*args)
+ def popup (self, *args):
+ self._popup.popup(*args)
diff --git a/portato/gui/windows/mailinfo.py b/portato/gui/windows/mailinfo.py
index 5d0a24c..22e750a 100644
--- a/portato/gui/windows/mailinfo.py
+++ b/portato/gui/windows/mailinfo.py
@@ -22,69 +22,69 @@ from ...helper import debug, info
from ...constants import VERSION
class MailInfoWindow (AbstractDialog):
- TO = "bugs@portato.necoro.net"
+ TO = "bugs@portato.necoro.net"
- def __init__ (self, parent, tb):
+ def __init__ (self, parent, tb):
- AbstractDialog.__init__(self, parent)
-
- self.tb = tb
- self.window.show_all()
+ AbstractDialog.__init__(self, parent)
+
+ self.tb = tb
+ self.window.show_all()
- def set_data (self):
- name = self.tree.get_widget("nameEntry").get_text()
- addr = self.tree.get_widget("mailEntry").get_text()
+ def set_data (self):
+ name = self.tree.get_widget("nameEntry").get_text()
+ addr = self.tree.get_widget("mailEntry").get_text()
- if not addr:
- addr = self.TO
+ if not addr:
+ addr = self.TO
- if name:
- fro = "%s <%s>" % (name, addr)
- else:
- fro = addr
+ if name:
+ fro = "%s <%s>" % (name, addr)
+ else:
+ fro = addr
- commentBuffer = self.tree.get_widget("commentEntry").get_buffer()
- text = commentBuffer.get_text(*commentBuffer.get_bounds())
+ commentBuffer = self.tree.get_widget("commentEntry").get_buffer()
+ text = commentBuffer.get_text(*commentBuffer.get_bounds())
- if text:
- text += "\n\n===========\n"
+ if text:
+ text += "\n\n===========\n"
- text += self.tb
+ text += self.tb
- message = """From: %s
+ message = """From: %s
To: %s
Subject: %s
%s""" % ( fro, self.TO, ("[Bug Report] Bug in Portato %s" % VERSION), text)
- self.addr = addr
- self.message = message
-
- def send (self):
- try:
- debug("Connecting to server")
- server = smtplib.SMTP("mail.necoro.eu")
- debug("Sending mail")
- try:
- try:
- server.sendmail(self.addr, self.TO, self.message)
- except smtplib.SMTPRecipientsRefused, e:
- info(_("An error occurred while sending. I think we were greylisted. The error: %s") % e)
- info(_("Retrying after waiting 60 seconds."))
- time.sleep(60)
- server.sendmail(self.addr, self.TO, self.message)
- debug("Sent")
- finally:
- server.quit()
- except socket.error, e:
- mail_failure_dialog("%s (Code: %s)" % (e.args[1], e.args[0]))
-
- def cb_cancel_clicked (self, *args):
-
- self.close()
- return True
-
- def cb_send_clicked (self, *args):
- self.set_data()
- GtkThread(target = self.send, name = "Mail Send Thread").start()
- self.close()
- return True
+ self.addr = addr
+ self.message = message
+
+ def send (self):
+ try:
+ debug("Connecting to server")
+ server = smtplib.SMTP("mail.necoro.eu")
+ debug("Sending mail")
+ try:
+ try:
+ server.sendmail(self.addr, self.TO, self.message)
+ except smtplib.SMTPRecipientsRefused, e:
+ info(_("An error occurred while sending. I think we were greylisted. The error: %s") % e)
+ info(_("Retrying after waiting 60 seconds."))
+ time.sleep(60)
+ server.sendmail(self.addr, self.TO, self.message)
+ debug("Sent")
+ finally:
+ server.quit()
+ except socket.error, e:
+ mail_failure_dialog("%s (Code: %s)" % (e.args[1], e.args[0]))
+
+ def cb_cancel_clicked (self, *args):
+
+ self.close()
+ return True
+
+ def cb_send_clicked (self, *args):
+ self.set_data()
+ GtkThread(target = self.send, name = "Mail Send Thread").start()
+ self.close()
+ return True
diff --git a/portato/gui/windows/main.py b/portato/gui/windows/main.py
index 1b7c0f0..fca4535 100644
--- a/portato/gui/windows/main.py
+++ b/portato/gui/windows/main.py
@@ -36,8 +36,8 @@ from ..session import SESSION_VERSION, SessionException, OldSessionException, Ne
from ..wrapper import GtkTree, GtkConsole
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, remove_updates_dialog, unmask_dialog)
+ nothing_found_dialog, queue_not_empty_dialog, remove_deps_dialog,
+ remove_queue_dialog, remove_updates_dialog, unmask_dialog)
# even more GUI stuff
from .basic import Window, Popup
@@ -48,1744 +48,1744 @@ from .search import SearchWindow
from .update import UpdateWindow
class PackageTable:
- """A window with data about a specfic package."""
-
- def __init__ (self, main):
- """Build up window contents.
-
- @param main: the main window
- @type main: MainWindow"""
-
- self.main = main
- self.tree = main.tree
- self.window = main.window
- self.tree.signal_autoconnect(self)
-
- # all the package data is in this one VB
- self.vb = self.tree.get_widget("packageVB")
-
- # the notebook
- self.notebook = self.tree.get_widget("packageNotebook")
-
- # chechboxes
- self.installedCheck = self.tree.get_widget("installedCheck")
- self.maskedCheck = self.tree.get_widget("maskedCheck")
- self.testingCheck = self.tree.get_widget("testingCheck")
- self.maskedLabel = self.tree.get_widget("maskedLabel")
-
- # labels
- generalVB = self.tree.get_widget("generalVB")
- generalVB.modify_bg(gtk.STATE_NORMAL, get_color(self.main.cfg, "packagetable"))
-
- self.nameLabel = self.tree.get_widget("nameLabel")
- self.descLabel = self.tree.get_widget("descLabel")
- self.overlayLabel = self.tree.get_widget("overlayLabel")
- self.overlayLL = self.tree.get_widget("overlayLabelLabel")
- self.licenseLabel = self.tree.get_widget("licenseLabel")
- self.linkBox = self.tree.get_widget("linkBox")
- self.notInSysLabel = self.tree.get_widget("notInSysLabel")
- self.missingLabel = self.tree.get_widget("missingLabel")
- self.useFlagsLabel = self.tree.get_widget("useFlagsLabel")
- self.useFlagsLL = self.tree.get_widget("useFlagsLabelLabel")
-
- # buttons
- self.emergeBtn = self.tree.get_widget("pkgEmergeBtn")
- self.unmergeBtn = self.tree.get_widget("pkgUnmergeBtn")
- self.revertBtn = self.tree.get_widget("pkgRevertBtn")
-
- # useList
- self.useList = self.tree.get_widget("useList")
- self.build_use_list()
-
- # depList
- self.depList = self.tree.get_widget("dependencyList")
- self.build_dep_list()
-
- # views
- self.ebuildView = self.tree.get_widget("ebuildScroll").get_child()
- self.changelogView = self.tree.get_widget("changelogScroll").get_child()
- self.filesView = self.tree.get_widget("filesScroll").get_child()
-
- # icons
- self.icons = {}
- self.icons["use"] = self.window.render_icon(gtk.STOCK_REMOVE, gtk.ICON_SIZE_MENU)
- self.icons["installed"] = self.window.render_icon(gtk.STOCK_YES, gtk.ICON_SIZE_MENU)
- self.icons["or"] = self.window.render_icon(gtk.STOCK_MEDIA_PAUSE, gtk.ICON_SIZE_MENU)
- self.icons["block"] = self.window.render_icon(gtk.STOCK_NO, gtk.ICON_SIZE_MENU)
-
- def update (self, pkg, queue = None, doEmerge = True, instantChange = False, type = None):
- """Updates the table to show the contents for the package.
-
- @param pkg: the selected package
- @type pkg: Package
- @param queue: emerge-queue (if None the emerge-buttons are disabled)
- @type queue: EmergeQueue
- @param doEmerge: if False, the emerge buttons are disabled
- @type doEmerge: boolean
- @param instantChange: if True the changed keywords are updated instantly
- @type instantChange: boolean
- @param type: the type of the queue this package is in; if None there is no queue :)
- @type type: string"""
-
- self.pkg = pkg
- self.queue = queue
- self.doEmerge = doEmerge
- self.instantChange = instantChange
- self.type = type
-
- if not self.queue or not self.doEmerge:
- self.emergeBtn.set_sensitive(False)
- self.unmergeBtn.set_sensitive(False)
-
- # current status
- self._update_table()
- self.vb.show_all()
-
- def hide (self):
- self.vb.hide_all()
-
- def set_labels (self):
- pkg = self.pkg
-
- # name
- self.nameLabel.set_markup("<b>%s</b>" % pkg.get_cpv())
-
- # description
- desc = pkg.get_package_settings("DESCRIPTION") or _("<no description>")
- self.descLabel.set_label(desc)
-
- # overlay
- if pkg.is_in_overlay():
- self.overlayLabel.set_label(pkg.get_overlay_path())
- self.overlayLabel.show()
- self.overlayLL.show()
- else:
- self.overlayLabel.hide()
- self.overlayLL.hide()
-
- # license
- self.licenseLabel.set_label(pkg.get_package_settings("LICENSE"))
-
- # link
- for c in self.linkBox.get_children():
- self.linkBox.remove(c)
-
- text = pkg.get_package_settings("HOMEPAGE")
- texts = text.split(" ")
- ftexts = []
-
- for count, t in enumerate(texts):
- if not t.startswith(("http", "ftp")):
- if count == 0:
- error(_("The first homepage part does not start with 'http' or 'ftp'."))
- ftexts.append(t)
- continue
- else:
- info(_("Blank inside homepage."))
- ftexts[-1] += " %s" % t
- else:
- ftexts.append(t)
-
- for t in ftexts:
- link = gtk.LinkButton(t)
- link.set_alignment(0.0, 0.5)
- link.set_border_width(0)
- self.linkBox.add(link)
-
- # useflags
- flaglist = list(itt.ifilterfalse(pkg.use_expanded, pkg.get_iuse_flags()))
- flaglist.sort()
- flags = ", ".join(flaglist)
-
- if flags:
- self.useFlagsLL.show()
- self.useFlagsLabel.show()
- self.useFlagsLabel.set_label(flags)
- else:
- self.useFlagsLL.hide()
- self.useFlagsLabel.hide()
-
- def fill_dep_list(self):
-
- store = self.depList.get_model()
-
- def add (tree, it):
-
- def get_icon (dep):
- if dep.satisfied:
- return self.icons["installed"]
- elif dep.dep[0] == "!":
- return self.icons["block"]
- else:
- return None
-
- # useflags
- for use, usetree in tree.flags.iteritems():
- if use[0] == "!":
- usestring = _("If '%s' is disabled") % use[1:]
- else:
- usestring = _("If '%s' is enabled") % use
- useit = store.append(it, [self.icons["use"], usestring])
- add(usetree, useit)
-
- # ORs
- ordeps = (dep for dep in tree.deps if isinstance(dep, dependency.OrDependency))
-
- for ordep in ordeps:
- orit = store.append(it, [self.icons["or"], _("One of the following")])
-
- for dep in ordep.dep:
- if isinstance(dep, dependency.AllOfDependency): # a list inside or
- allit = store.append(orit, [None, _("All of the following")])
- for adep in dep.dep:
- store.append(allit, [get_icon(adep), adep.dep])
- else:
- store.append(orit, [get_icon(dep), dep.dep])
-
- # normal
- def sort_key (x):
- split = system.split_cpv(x.dep)
-
- if split is None: # split_cpv returns None if this is only a CP; we assume there are only valid deps
- return x.dep
- else:
- return "/".join(split[0:2])
-
- ndeps = [dep for dep in tree.deps if not isinstance(dep, dependency.OrDependency)]
- ndeps.sort(key = sort_key)
- for dep in ndeps:
- store.append(it, [get_icon(dep), dep.dep])
-
- try:
- deptree = self.pkg.get_dependencies()
- except AssertionError:
- w = _("Can't display dependencies: This package has an unsupported dependency string.")
- error(w)
- store.append(None, [None, w])
- else:
- add(deptree, None)
-
- def fill_use_list(self):
-
- pkg = self.pkg
- pkg_flags = pkg.get_iuse_flags()
- pkg_flags.sort()
-
- actual_exp = None
- actual_exp_it = None
-
- euse = pkg.get_actual_use_flags()
- instuse = pkg.get_installed_use_flags()
-
- store = self.useList.get_model()
-
- for use in pkg_flags:
- exp = pkg.use_expanded(use, suggest = actual_exp)
- if exp is not None:
- if exp != actual_exp:
- actual_exp_it = store.append(None, [None, None, exp, "<i>%s</i>" % _("This is an expanded use flag and cannot be selected")])
- actual_exp = exp
- else:
- actual_exp_it = None
- actual_exp = None
-
- enabled = use in euse
- installed = use in instuse
- store.append(actual_exp_it, [enabled, installed, use, system.get_use_desc(use, self.pkg.get_cp())])
-
- def build_dep_list (self):
- store = gtk.TreeStore(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 build_use_list (self):
- """Builds the useList."""
- store = gtk.TreeStore(bool, bool, str, str)
- self.useList.set_model(store)
-
- # build view
- cell = gtk.CellRendererText()
- iCell = gtk.CellRendererToggle()
- iCell.set_property("activatable", False)
- tCell = gtk.CellRendererToggle()
- tCell.set_property("activatable", True)
- tCell.connect("toggled", self.cb_use_flag_toggled, store)
- self.useList.append_column(gtk.TreeViewColumn(_("Enabled"), tCell, active = 0))
- self.useList.append_column(gtk.TreeViewColumn(_("Installed"), iCell, active = 1))
- self.useList.append_column(gtk.TreeViewColumn(_("Flag"), cell, text = 2))
- self.useList.append_column(gtk.TreeViewColumn(_("Description"), cell, markup = 3))
-
- self.useList.set_search_column(2)
- self.useList.set_enable_tree_lines(True)
-
- def _update_keywords (self, emerge, update = False):
- if emerge:
- type = "install" if not self.type else self.type
- try:
- try:
- self.queue.append(self.pkg.get_cpv(), type = type, update = update)
- except PackageNotFoundException, e:
- if unmask_dialog(e[0]) == gtk.RESPONSE_YES:
- self.queue.append(self.pkg.get_cpv(), type = type, unmask = True, update = update)
- except BlockedException, e:
- blocked_dialog(e[0], e[1])
- else:
- try:
- self.queue.append(self.pkg.get_cpv(), type = "uninstall")
- except PackageNotFoundException, e:
- error(_("Package could not be found: %s"), e[0])
- #masked_dialog(e[0])
-
- def _update_table (self, *args):
-
- pkg = self.pkg
-
- # set the views
- for v in (self.ebuildView, self.changelogView, self.filesView):
- v.update(pkg, force = self.notebook.get_nth_page(self.notebook.get_current_page()) == v.get_parent())
-
- # set the labels
- self.set_labels()
-
- # set use list
- self.useList.get_model().clear()
- self.useList.columns_autosize()
- self.fill_use_list()
-
- # set dep list
- self.depList.get_model().clear()
- self.useList.columns_autosize()
- self.fill_dep_list()
-
- #
- # rebuild the buttons and checkboxes in all the different manners which are possible
- #
- if (not pkg.is_in_system()) or pkg.is_missing_keyword():
- if not pkg.is_in_system():
- self.missingLabel.hide()
- self.notInSysLabel.show()
- else: # missing keyword
- self.missingLabel.show()
- self.notInSysLabel.hide()
-#
- self.installedCheck.hide()
- self.maskedCheck.hide()
- self.maskedLabel.hide()
- self.testingCheck.hide()
- self.emergeBtn.set_sensitive(False)
- else: # normal package
- self.missingLabel.hide()
- self.notInSysLabel.hide()
- self.installedCheck.show()
- self.maskedCheck.show()
- self.maskedLabel.show()
- self.testingCheck.show()
- if self.doEmerge:
- self.emergeBtn.set_sensitive(True)
- self.installedCheck.set_active(pkg.is_installed())
-
- reason = pkg.get_masking_reason() or " "
- if pkg.is_masked(use_changed = False) and not pkg.is_masked(use_changed = True):
- self.maskedCheck.set_label("<i>(%s)</i>" % _("Masked"))
- self.maskedCheck.get_child().set_use_markup(True)
- else:
- self.maskedCheck.set_label(_("Masked"))
-
- if pkg.is_locally_masked():
- self.maskedCheck.set_label("<b>%s</b>" % _("Masked"))
- self.maskedCheck.get_child().set_use_markup(True)
- self.maskedCheck.set_active(True)
- reason = _("Masked by user")
- else:
- self.maskedCheck.set_active(pkg.is_masked(use_changed = False))
-
- if reason:
- self.maskedLabel.set_label(reason)
-
- if pkg.is_testing(use_keywords = False) and not pkg.is_testing(use_keywords = True):
- self.testingCheck.set_label("<i>(%s)</i>" % _("Testing"))
- self.testingCheck.get_child().set_use_markup(True)
- else:
- self.testingCheck.set_label(_("Testing"))
-
- self.testingCheck.set_active(pkg.is_testing(use_keywords = False))
-
- if self.doEmerge:
- # set emerge-button-label
- if not pkg.is_installed():
- self.unmergeBtn.set_sensitive(False)
- else:
- self.unmergeBtn.set_sensitive(True)
-
- self.vb.show_all()
- return True
-
- def cb_button_pressed (self, b, event):
- """Callback for pressed checkboxes. Just quits the event-loop - no redrawing."""
- if not isinstance(b, gtk.CellRendererToggle):
- b.emit_stop_by_name("button-press-event")
- return True
-
- def cb_package_revert_clicked (self, button):
- """Callback for pressed revert-button."""
- self.pkg.remove_new_use_flags()
- self.pkg.remove_new_masked()
- self.pkg.remove_new_testing()
- self._update_table()
- if self.instantChange:
- self._update_keywords(True, update = True)
- return True
-
- def cb_package_emerge_clicked (self, button):
- """Callback for pressed emerge-button. Adds the package to the EmergeQueue."""
- self._update_keywords(True)
- 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.sysNotebook.set_current_page(self.main.QUEUE_PAGE)
- return True
-
- def cb_testing_toggled (self, button):
- """Callback for toggled testing-checkbox."""
- status = button.get_active()
-
- # end of recursion :)
- if self.pkg.is_testing(use_keywords = False) == status:
- return False
-
- # if the package is not testing - don't allow to set it as such
- if not self.pkg.is_testing(use_keywords = False):
- button.set_active(False)
- return True
-
- # re-set to testing status
- if not self.pkg.is_testing(use_keywords = True):
- self.pkg.set_testing(False)
- button.set_label(_("Testing"))
- button.set_active(True)
- else: # disable testing
- self.pkg.set_testing(True)
- button.set_label("<i>(%s)</i>" % _("Testing"))
- button.get_child().set_use_markup(True)
- button.set_active(True)
-
- if self.instantChange:
- self._update_keywords(True, update = True)
-
- return True
-
- def cb_masked_toggled (self, button):
- """Callback for toggled masking-checkbox."""
- status = button.get_active()
- pkg = self.pkg
-
- if pkg.is_masked(use_changed = False) == status and not pkg.is_locally_masked():
- return False
-
- if pkg.is_locally_masked() and status:
- return False
-
- if not pkg.is_masked(use_changed = True):
- pkg.set_masked(True)
- if pkg.is_locally_masked():
- button.set_label("<b>%s</b>" % _("Masked"))
- button.get_child().set_use_markup(True)
- self.maskedLabel.set_label(_("Masked by user"))
- else:
- button.set_label(_("Masked"))
-
- button.set_active(True)
- else:
- locally = pkg.is_locally_masked()
- pkg.set_masked(False)
- if pkg.is_masked(use_changed=False) and not locally:
- button.set_label("<i>(%s)</i>" % _("Masked"))
- button.get_child().set_use_markup(True)
- button.set_active(True)
- else:
- button.set_label(_("Masked"))
- self.maskedLabel.set_label("")
-
- if self.instantChange:
- self._update_keywords(True, update = True)
-
- return True
-
- def cb_use_flag_toggled (self, cell, path, store):
- """Callback for a toggled use-flag button."""
- flag = store[path][2]
- pkg = self.pkg
-
- if pkg.use_expanded(flag): # ignore expanded flags
- return False
-
- store[path][0] = not store[path][0]
- prefix = ""
- if not store[path][0]:
- prefix = "-"
-
- pkg.set_use_flag(prefix+flag)
- if self.instantChange:
- self._update_keywords(True, update = True)
-
- return True
+ """A window with data about a specfic package."""
+
+ def __init__ (self, main):
+ """Build up window contents.
+
+ @param main: the main window
+ @type main: MainWindow"""
+
+ self.main = main
+ self.tree = main.tree
+ self.window = main.window
+ self.tree.signal_autoconnect(self)
+
+ # all the package data is in this one VB
+ self.vb = self.tree.get_widget("packageVB")
+
+ # the notebook
+ self.notebook = self.tree.get_widget("packageNotebook")
+
+ # chechboxes
+ self.installedCheck = self.tree.get_widget("installedCheck")
+ self.maskedCheck = self.tree.get_widget("maskedCheck")
+ self.testingCheck = self.tree.get_widget("testingCheck")
+ self.maskedLabel = self.tree.get_widget("maskedLabel")
+
+ # labels
+ generalVB = self.tree.get_widget("generalVB")
+ generalVB.modify_bg(gtk.STATE_NORMAL, get_color(self.main.cfg, "packagetable"))
+
+ self.nameLabel = self.tree.get_widget("nameLabel")
+ self.descLabel = self.tree.get_widget("descLabel")
+ self.overlayLabel = self.tree.get_widget("overlayLabel")
+ self.overlayLL = self.tree.get_widget("overlayLabelLabel")
+ self.licenseLabel = self.tree.get_widget("licenseLabel")
+ self.linkBox = self.tree.get_widget("linkBox")
+ self.notInSysLabel = self.tree.get_widget("notInSysLabel")
+ self.missingLabel = self.tree.get_widget("missingLabel")
+ self.useFlagsLabel = self.tree.get_widget("useFlagsLabel")
+ self.useFlagsLL = self.tree.get_widget("useFlagsLabelLabel")
+
+ # buttons
+ self.emergeBtn = self.tree.get_widget("pkgEmergeBtn")
+ self.unmergeBtn = self.tree.get_widget("pkgUnmergeBtn")
+ self.revertBtn = self.tree.get_widget("pkgRevertBtn")
+
+ # useList
+ self.useList = self.tree.get_widget("useList")
+ self.build_use_list()
+
+ # depList
+ self.depList = self.tree.get_widget("dependencyList")
+ self.build_dep_list()
+
+ # views
+ self.ebuildView = self.tree.get_widget("ebuildScroll").get_child()
+ self.changelogView = self.tree.get_widget("changelogScroll").get_child()
+ self.filesView = self.tree.get_widget("filesScroll").get_child()
+
+ # icons
+ self.icons = {}
+ self.icons["use"] = self.window.render_icon(gtk.STOCK_REMOVE, gtk.ICON_SIZE_MENU)
+ self.icons["installed"] = self.window.render_icon(gtk.STOCK_YES, gtk.ICON_SIZE_MENU)
+ self.icons["or"] = self.window.render_icon(gtk.STOCK_MEDIA_PAUSE, gtk.ICON_SIZE_MENU)
+ self.icons["block"] = self.window.render_icon(gtk.STOCK_NO, gtk.ICON_SIZE_MENU)
+
+ def update (self, pkg, queue = None, doEmerge = True, instantChange = False, type = None):
+ """Updates the table to show the contents for the package.
+
+ @param pkg: the selected package
+ @type pkg: Package
+ @param queue: emerge-queue (if None the emerge-buttons are disabled)
+ @type queue: EmergeQueue
+ @param doEmerge: if False, the emerge buttons are disabled
+ @type doEmerge: boolean
+ @param instantChange: if True the changed keywords are updated instantly
+ @type instantChange: boolean
+ @param type: the type of the queue this package is in; if None there is no queue :)
+ @type type: string"""
+
+ self.pkg = pkg
+ self.queue = queue
+ self.doEmerge = doEmerge
+ self.instantChange = instantChange
+ self.type = type
+
+ if not self.queue or not self.doEmerge:
+ self.emergeBtn.set_sensitive(False)
+ self.unmergeBtn.set_sensitive(False)
+
+ # current status
+ self._update_table()
+ self.vb.show_all()
+
+ def hide (self):
+ self.vb.hide_all()
+
+ def set_labels (self):
+ pkg = self.pkg
+
+ # name
+ self.nameLabel.set_markup("<b>%s</b>" % pkg.get_cpv())
+
+ # description
+ desc = pkg.get_package_settings("DESCRIPTION") or _("<no description>")
+ self.descLabel.set_label(desc)
+
+ # overlay
+ if pkg.is_in_overlay():
+ self.overlayLabel.set_label(pkg.get_overlay_path())
+ self.overlayLabel.show()
+ self.overlayLL.show()
+ else:
+ self.overlayLabel.hide()
+ self.overlayLL.hide()
+
+ # license
+ self.licenseLabel.set_label(pkg.get_package_settings("LICENSE"))
+
+ # link
+ for c in self.linkBox.get_children():
+ self.linkBox.remove(c)
+
+ text = pkg.get_package_settings("HOMEPAGE")
+ texts = text.split(" ")
+ ftexts = []
+
+ for count, t in enumerate(texts):
+ if not t.startswith(("http", "ftp")):
+ if count == 0:
+ error(_("The first homepage part does not start with 'http' or 'ftp'."))
+ ftexts.append(t)
+ continue
+ else:
+ info(_("Blank inside homepage."))
+ ftexts[-1] += " %s" % t
+ else:
+ ftexts.append(t)
+
+ for t in ftexts:
+ link = gtk.LinkButton(t)
+ link.set_alignment(0.0, 0.5)
+ link.set_border_width(0)
+ self.linkBox.add(link)
+
+ # useflags
+ flaglist = list(itt.ifilterfalse(pkg.use_expanded, pkg.get_iuse_flags()))
+ flaglist.sort()
+ flags = ", ".join(flaglist)
+
+ if flags:
+ self.useFlagsLL.show()
+ self.useFlagsLabel.show()
+ self.useFlagsLabel.set_label(flags)
+ else:
+ self.useFlagsLL.hide()
+ self.useFlagsLabel.hide()
+
+ def fill_dep_list(self):
+
+ store = self.depList.get_model()
+
+ def add (tree, it):
+
+ def get_icon (dep):
+ if dep.satisfied:
+ return self.icons["installed"]
+ elif dep.dep[0] == "!":
+ return self.icons["block"]
+ else:
+ return None
+
+ # useflags
+ for use, usetree in tree.flags.iteritems():
+ if use[0] == "!":
+ usestring = _("If '%s' is disabled") % use[1:]
+ else:
+ usestring = _("If '%s' is enabled") % use
+ useit = store.append(it, [self.icons["use"], usestring])
+ add(usetree, useit)
+
+ # ORs
+ ordeps = (dep for dep in tree.deps if isinstance(dep, dependency.OrDependency))
+
+ for ordep in ordeps:
+ orit = store.append(it, [self.icons["or"], _("One of the following")])
+
+ for dep in ordep.dep:
+ if isinstance(dep, dependency.AllOfDependency): # a list inside or
+ allit = store.append(orit, [None, _("All of the following")])
+ for adep in dep.dep:
+ store.append(allit, [get_icon(adep), adep.dep])
+ else:
+ store.append(orit, [get_icon(dep), dep.dep])
+
+ # normal
+ def sort_key (x):
+ split = system.split_cpv(x.dep)
+
+ if split is None: # split_cpv returns None if this is only a CP; we assume there are only valid deps
+ return x.dep
+ else:
+ return "/".join(split[0:2])
+
+ ndeps = [dep for dep in tree.deps if not isinstance(dep, dependency.OrDependency)]
+ ndeps.sort(key = sort_key)
+ for dep in ndeps:
+ store.append(it, [get_icon(dep), dep.dep])
+
+ try:
+ deptree = self.pkg.get_dependencies()
+ except AssertionError:
+ w = _("Can't display dependencies: This package has an unsupported dependency string.")
+ error(w)
+ store.append(None, [None, w])
+ else:
+ add(deptree, None)
+
+ def fill_use_list(self):
+
+ pkg = self.pkg
+ pkg_flags = pkg.get_iuse_flags()
+ pkg_flags.sort()
+
+ actual_exp = None
+ actual_exp_it = None
+
+ euse = pkg.get_actual_use_flags()
+ instuse = pkg.get_installed_use_flags()
+
+ store = self.useList.get_model()
+
+ for use in pkg_flags:
+ exp = pkg.use_expanded(use, suggest = actual_exp)
+ if exp is not None:
+ if exp != actual_exp:
+ actual_exp_it = store.append(None, [None, None, exp, "<i>%s</i>" % _("This is an expanded use flag and cannot be selected")])
+ actual_exp = exp
+ else:
+ actual_exp_it = None
+ actual_exp = None
+
+ enabled = use in euse
+ installed = use in instuse
+ store.append(actual_exp_it, [enabled, installed, use, system.get_use_desc(use, self.pkg.get_cp())])
+
+ def build_dep_list (self):
+ store = gtk.TreeStore(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 build_use_list (self):
+ """Builds the useList."""
+ store = gtk.TreeStore(bool, bool, str, str)
+ self.useList.set_model(store)
+
+ # build view
+ cell = gtk.CellRendererText()
+ iCell = gtk.CellRendererToggle()
+ iCell.set_property("activatable", False)
+ tCell = gtk.CellRendererToggle()
+ tCell.set_property("activatable", True)
+ tCell.connect("toggled", self.cb_use_flag_toggled, store)
+ self.useList.append_column(gtk.TreeViewColumn(_("Enabled"), tCell, active = 0))
+ self.useList.append_column(gtk.TreeViewColumn(_("Installed"), iCell, active = 1))
+ self.useList.append_column(gtk.TreeViewColumn(_("Flag"), cell, text = 2))
+ self.useList.append_column(gtk.TreeViewColumn(_("Description"), cell, markup = 3))
+
+ self.useList.set_search_column(2)
+ self.useList.set_enable_tree_lines(True)
+
+ def _update_keywords (self, emerge, update = False):
+ if emerge:
+ type = "install" if not self.type else self.type
+ try:
+ try:
+ self.queue.append(self.pkg.get_cpv(), type = type, update = update)
+ except PackageNotFoundException, e:
+ if unmask_dialog(e[0]) == gtk.RESPONSE_YES:
+ self.queue.append(self.pkg.get_cpv(), type = type, unmask = True, update = update)
+ except BlockedException, e:
+ blocked_dialog(e[0], e[1])
+ else:
+ try:
+ self.queue.append(self.pkg.get_cpv(), type = "uninstall")
+ except PackageNotFoundException, e:
+ error(_("Package could not be found: %s"), e[0])
+ #masked_dialog(e[0])
+
+ def _update_table (self, *args):
+
+ pkg = self.pkg
+
+ # set the views
+ for v in (self.ebuildView, self.changelogView, self.filesView):
+ v.update(pkg, force = self.notebook.get_nth_page(self.notebook.get_current_page()) == v.get_parent())
+
+ # set the labels
+ self.set_labels()
+
+ # set use list
+ self.useList.get_model().clear()
+ self.useList.columns_autosize()
+ self.fill_use_list()
+
+ # set dep list
+ self.depList.get_model().clear()
+ self.useList.columns_autosize()
+ self.fill_dep_list()
+
+ #
+ # rebuild the buttons and checkboxes in all the different manners which are possible
+ #
+ if (not pkg.is_in_system()) or pkg.is_missing_keyword():
+ if not pkg.is_in_system():
+ self.missingLabel.hide()
+ self.notInSysLabel.show()
+ else: # missing keyword
+ self.missingLabel.show()
+ self.notInSysLabel.hide()
+#
+ self.installedCheck.hide()
+ self.maskedCheck.hide()
+ self.maskedLabel.hide()
+ self.testingCheck.hide()
+ self.emergeBtn.set_sensitive(False)
+ else: # normal package
+ self.missingLabel.hide()
+ self.notInSysLabel.hide()
+ self.installedCheck.show()
+ self.maskedCheck.show()
+ self.maskedLabel.show()
+ self.testingCheck.show()
+ if self.doEmerge:
+ self.emergeBtn.set_sensitive(True)
+ self.installedCheck.set_active(pkg.is_installed())
+
+ reason = pkg.get_masking_reason() or " "
+ if pkg.is_masked(use_changed = False) and not pkg.is_masked(use_changed = True):
+ self.maskedCheck.set_label("<i>(%s)</i>" % _("Masked"))
+ self.maskedCheck.get_child().set_use_markup(True)
+ else:
+ self.maskedCheck.set_label(_("Masked"))
+
+ if pkg.is_locally_masked():
+ self.maskedCheck.set_label("<b>%s</b>" % _("Masked"))
+ self.maskedCheck.get_child().set_use_markup(True)
+ self.maskedCheck.set_active(True)
+ reason = _("Masked by user")
+ else:
+ self.maskedCheck.set_active(pkg.is_masked(use_changed = False))
+
+ if reason:
+ self.maskedLabel.set_label(reason)
+
+ if pkg.is_testing(use_keywords = False) and not pkg.is_testing(use_keywords = True):
+ self.testingCheck.set_label("<i>(%s)</i>" % _("Testing"))
+ self.testingCheck.get_child().set_use_markup(True)
+ else:
+ self.testingCheck.set_label(_("Testing"))
+
+ self.testingCheck.set_active(pkg.is_testing(use_keywords = False))
+
+ if self.doEmerge:
+ # set emerge-button-label
+ if not pkg.is_installed():
+ self.unmergeBtn.set_sensitive(False)
+ else:
+ self.unmergeBtn.set_sensitive(True)
+
+ self.vb.show_all()
+ return True
+
+ def cb_button_pressed (self, b, event):
+ """Callback for pressed checkboxes. Just quits the event-loop - no redrawing."""
+ if not isinstance(b, gtk.CellRendererToggle):
+ b.emit_stop_by_name("button-press-event")
+ return True
+
+ def cb_package_revert_clicked (self, button):
+ """Callback for pressed revert-button."""
+ self.pkg.remove_new_use_flags()
+ self.pkg.remove_new_masked()
+ self.pkg.remove_new_testing()
+ self._update_table()
+ if self.instantChange:
+ self._update_keywords(True, update = True)
+ return True
+
+ def cb_package_emerge_clicked (self, button):
+ """Callback for pressed emerge-button. Adds the package to the EmergeQueue."""
+ self._update_keywords(True)
+ 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.sysNotebook.set_current_page(self.main.QUEUE_PAGE)
+ return True
+
+ def cb_testing_toggled (self, button):
+ """Callback for toggled testing-checkbox."""
+ status = button.get_active()
+
+ # end of recursion :)
+ if self.pkg.is_testing(use_keywords = False) == status:
+ return False
+
+ # if the package is not testing - don't allow to set it as such
+ if not self.pkg.is_testing(use_keywords = False):
+ button.set_active(False)
+ return True
+
+ # re-set to testing status
+ if not self.pkg.is_testing(use_keywords = True):
+ self.pkg.set_testing(False)
+ button.set_label(_("Testing"))
+ button.set_active(True)
+ else: # disable testing
+ self.pkg.set_testing(True)
+ button.set_label("<i>(%s)</i>" % _("Testing"))
+ button.get_child().set_use_markup(True)
+ button.set_active(True)
+
+ if self.instantChange:
+ self._update_keywords(True, update = True)
+
+ return True
+
+ def cb_masked_toggled (self, button):
+ """Callback for toggled masking-checkbox."""
+ status = button.get_active()
+ pkg = self.pkg
+
+ if pkg.is_masked(use_changed = False) == status and not pkg.is_locally_masked():
+ return False
+
+ if pkg.is_locally_masked() and status:
+ return False
+
+ if not pkg.is_masked(use_changed = True):
+ pkg.set_masked(True)
+ if pkg.is_locally_masked():
+ button.set_label("<b>%s</b>" % _("Masked"))
+ button.get_child().set_use_markup(True)
+ self.maskedLabel.set_label(_("Masked by user"))
+ else:
+ button.set_label(_("Masked"))
+
+ button.set_active(True)
+ else:
+ locally = pkg.is_locally_masked()
+ pkg.set_masked(False)
+ if pkg.is_masked(use_changed=False) and not locally:
+ button.set_label("<i>(%s)</i>" % _("Masked"))
+ button.get_child().set_use_markup(True)
+ button.set_active(True)
+ else:
+ button.set_label(_("Masked"))
+ self.maskedLabel.set_label("")
+
+ if self.instantChange:
+ self._update_keywords(True, update = True)
+
+ return True
+
+ def cb_use_flag_toggled (self, cell, path, store):
+ """Callback for a toggled use-flag button."""
+ flag = store[path][2]
+ pkg = self.pkg
+
+ if pkg.use_expanded(flag): # ignore expanded flags
+ return False
+
+ store[path][0] = not store[path][0]
+ prefix = ""
+ if not store[path][0]:
+ prefix = "-"
+
+ pkg.set_use_flag(prefix+flag)
+ if self.instantChange:
+ self._update_keywords(True, update = True)
+
+ return True
class MainWindow (Window):
- """
- Application main window.
- """
-
- # NOTEBOOK PAGE CONSTANTS
- (
- QUEUE_PAGE,
- CONSOLE_PAGE,
- LOG_PAGE
- ) = range(3)
-
- def __init__ (self, splash = None):
- """
- Build up window.
-
- @param splash: the splash screen =)
- @type splash: SplashScreen
- """
-
- if splash is None:
- splash = lambda x: True
-
- # the title
- self.main_title = "Portato (%s)" % VERSION
-
- # main window stuff
- Window.__init__(self)
- self.window.set_title(self.main_title)
- self.window.set_geometry_hints (self.window, max_height = gtk.gdk.screen_height(), max_width = gtk.gdk.screen_width())
-
- # booleans
- self.doUpdate = False
- self.showAll = True # show only installed or all packages?
- self.__searchChanged = False
-
- # installed pixbuf
- self.instPixbuf = self.window.render_icon(gtk.STOCK_YES, gtk.ICON_SIZE_MENU)
-
- # get the logging window as soon as possible
- self.logView = LogView(self.tree.get_widget("logView"))
-
- # config
- splash(_("Loading Config"))
- try:
- self.cfg = Config(CONFIG_LOCATION)
- except IOError, e:
- io_ex_dialog(e)
- raise
-
- self.cfg.modify_external_configs()
- self.set_uri_hook(self.cfg.get("browserCmd", section = "GUI"))
- gtk.about_dialog_set_url_hook(lambda *args: True) # dummy - if not set link is not set as link; if link is clicked the normal uuri_hook is called too - thus do not call browser here
-
- # package db
- splash(_("Creating Database"))
- self.db = Database()
- self.db.populate()
-
- # set plugins and plugin-menu
- splash(_("Loading Plugins"))
-
- 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 itt.chain(*menus):
- item = gtk.MenuItem(m.label)
- item.connect("activate", m.call)
- pluginMenu.append(item)
-
- splash(_("Building frontend"))
- # set paned position
- self.vpaned = self.tree.get_widget("vpaned")
- self.vpaned.set_position(int(self.window.get_size()[1]/2))
- self.hpaned = self.tree.get_widget("hpaned")
- self.hpaned.set_position(int(self.window.get_size()[0]/1.5))
-
- # lists
- self.selCatName = ""
- self.selCP = ""
- self.selCPV = ""
- self.sortPkgListByName = True
- self.catList = self.tree.get_widget("catList")
- self.pkgList = self.tree.get_widget("pkgList")
- self.versionList = self.tree.get_widget("versionList")
- self.build_cat_list()
- self.build_pkg_list()
- self.build_version_list()
-
- # search entry
- self.searchEntry = self.tree.get_widget("searchEntry")
-
- # queue list
- self.queueOneshot = self.tree.get_widget("oneshotCB")
- self.queueOneshotHandler = self.queueOneshot.connect("toggled", self.cb_oneshot_clicked)
- self.queueList = self.tree.get_widget("queueList")
- self.build_queue_list()
-
- # the terminal
- self.console = GtkConsole()
- self.termHB = self.tree.get_widget("termHB")
- self.build_terminal()
-
- # notebooks
- self.sysNotebook = self.tree.get_widget("systemNotebook")
- self.pkgNotebook = self.tree.get_widget("packageNotebook")
- self.set_notebook_tabpos(map(PreferenceWindow.tabpos.get, map(int, (self.cfg.get("packageTabPos", "GUI"), self.cfg.get("systemTabPos", "GUI")))))
-
- # the different scrolls
- ebuildScroll = self.tree.get_widget("ebuildScroll")
- ebuildScroll.add(HighlightView(lambda p: p.get_ebuild_path(), ["gentoo", "sh"]))
-
- changelogScroll = self.tree.get_widget("changelogScroll")
- changelogScroll.add(HighlightView(lambda p: os.path.join(p.get_package_path(), "ChangeLog"), ["changelog"]))
-
- def show_files (p):
- try:
- for f in p.get_files():
- yield " %s\n" % f
- except IOError, e:
- yield _("Error: %s") % e.strerror
-
- filesScroll = self.tree.get_widget("filesScroll")
- filesScroll.add(InstalledOnlyView(show_files))
-
- # table
- self.packageTable = PackageTable(self)
-
- # popups
- self.consolePopup = Popup("consolePopup", self, self.__file__)
- self.trayPopup = Popup("systrayPopup", self)
-
- # pause menu items
- self.emergePaused = False
- self.pauseItems = {}
- self.pauseItems["tray"] = self.trayPopup.tree.get_widget("pauseItemTray")
- self.pauseItems["popup"] = self.consolePopup.tree.get_widget("pauseItemPopup")
- self.pauseItems["menu"] = self.tree.get_widget("pauseItemMenu")
-
- for k,v in self.pauseItems.iteritems():
- self.pauseItems[k] = (v, v.connect_after("activate", self.cb_pause_emerge(k)))
-
- # systray
- if self.cfg.get_boolean("showSystray", "GUI"):
- self.tray = gtk.status_icon_new_from_file(APP_ICON)
- self.tray.connect("activate", self.cb_systray_activated)
- self.tray.connect("popup-menu", lambda icon, btn, time: self.trayPopup.popup(None, None, None, btn, time))
- else:
- self.tray = None
-
- # set emerge queue
- self.queueTree = GtkTree(self.queueList.get_model())
- self.queue = EmergeQueue(console = self.console, tree = self.queueTree, db = self.db, title_update = self.title_update, threadClass = GtkThread)
-
- # session
- splash(_("Restoring Session"))
- try:
- try:
- self.load_session()
- except OldSessionException, e:
- self.load_session(e)
- except SessionException, e:
- warning(str(e))
-
- splash(_("Finishing startup"))
-
- self.window.show_all()
-
- def show_package (self, pkg = None, cpv = None, cp = None, version = None, **kwargs):
- p = None
-
- if pkg:
- p = pkg
- elif cpv:
- p = system.find_packages("="+cpv, masked = True)[0]
- elif cp:
- if version:
- p = system.find_packages("=%s-%s" % (cp, version), masked = True)[0]
-
- else:
- best = system.find_best_match(cp)
- if best:
- p = best
- else:
- p = system.find_packages(cp)[0]
-
- self.packageTable.update(p, **kwargs)
-
- def build_terminal (self):
- """
- Builds the terminal.
- """
-
- self.console.set_scrollback_lines(int(self.cfg.get("scrollbacklines", "GUI")))
- self.console.set_scroll_on_output(True)
- self.console.set_font_from_string(self.cfg.get("consolefont", "GUI"))
- self.console.connect("button-press-event", self.cb_right_click)
- self.termHB.pack_start(self.console, True, True)
-
- # add scrollbar
- termScroll = gtk.VScrollbar(self.console.get_adjustment())
- self.termHB.pack_start(termScroll, False)
-
- def build_queue_list (self):
- """
- Builds the queue list.
- """
-
- store = gtk.TreeStore(str,str,bool)
-
- self.queueList.set_model(store)
-
- cell = gtk.CellRendererText()
- col = gtk.TreeViewColumn(_("Queue"), cell, markup = 0)
- self.queueList.append_column(col)
-
- col = gtk.TreeViewColumn(_("Options"), cell, markup = 1)
- self.queueList.append_column(col)
-
- self.queueList.get_selection().connect("changed", self.cb_queue_list_selection)
-
- def build_cat_list (self):
- """
- Builds the category list.
- """
-
- store = gtk.TreeStore(str)
-
- self.fill_cat_store(store)
-
- self.catList.set_model(store)
- cell = gtk.CellRendererText()
- col = gtk.TreeViewColumn(_("Categories"), cell, text = 0)
- self.catList.append_column(col)
-
- self.catList.get_selection().connect("changed", self.cb_cat_list_selection)
-
- def fill_cat_store (self, store = None):
- """
- Fills the category store with data.
-
- @param store: the store to fill
- @type store: gtk.ListStore
- """
-
- if store is None:
- store = self.catList.get_model()
-
- store.clear()
-
- cats = self.db.get_categories(installed = not self.showAll)
-
- if not self.cfg.get_boolean("collapseCats", "GUI"):
- for p in cats:
- store.append(None, [p])
- else:
- splitCats = defaultdict(list)
- for c in cats:
- try:
- pre, post = c.split("-", 1)
- except ValueError: # no "-" in cat name -- do not split
- debug("Category '%s' can't be split up. Should be no harm.", c)
- splitCats["not-split"].append(c)
- else:
- splitCats[pre].append(post)
-
- for sc in splitCats:
- if sc == "not-split":
- it = None # append not splitted stuff to root
- else:
- it = store.append(None, [sc])
- for cat in splitCats[sc]:
- store.append(it, [cat])
-
- # sort them alphabetically
- store.set_sort_column_id(0, gtk.SORT_ASCENDING)
-
- def build_pkg_list (self, name = None):
- """
- Builds the package list.
-
- @param name: name of the selected catetegory
- @type name: string
- """
-
- store = gtk.ListStore(gtk.gdk.Pixbuf, str, str)
- self.fill_pkg_store(store, name)
-
- # build view
- self.pkgList.set_model(store)
-
- col = gtk.TreeViewColumn(_("Packages"))
- col.set_clickable(True)
- col.connect("clicked", self.cb_pkg_list_header_clicked)
-
- # adding the pixbuf
- cell = gtk.CellRendererPixbuf()
- col.pack_start(cell, False)
- col.add_attribute(cell, "pixbuf", 0)
-
- # adding the package name
- cell = gtk.CellRendererText()
- col.pack_start(cell, True)
- col.add_attribute(cell, "text", 1)
-
- self.pkgList.append_column(col)
-
- self.pkgList.get_selection().connect("changed", self.cb_pkg_list_selection)
-
- def fill_pkg_store (self, store = None, name = None):
- """
- Fills a given ListStore with the packages in a category.
-
- @param store: the store to fill
- @type store: gtk.ListStore
- @param name: the name of the category
- @type name: string
- """
-
- if store is None:
- store = self.pkgList.get_model()
- store.clear()
-
- if name:
- for cat, pkg, is_inst in self.db.get_cat(name, self.sortPkgListByName):
- if is_inst:
- icon = self.instPixbuf
- elif not self.showAll:
- continue # ignore not installed packages
- else:
- icon = None
- store.append([icon, pkg, cat])
-
- def build_version_list (self):
- store = gtk.ListStore(gtk.gdk.Pixbuf, str, str)
-
- # build view
- self.versionList.set_model(store)
-
- col = gtk.TreeViewColumn(_("Versions"))
- col.set_property("expand", True)
-
- self.slotcol = gtk.TreeViewColumn(_("Slot"))
- self.slotcol.set_property("expand", True)
-
- # adding the pixbuf
- cell = gtk.CellRendererPixbuf()
- col.pack_start(cell, False)
- col.add_attribute(cell, "pixbuf", 0)
-
- # adding the package name
- cell = gtk.CellRendererText()
- col.pack_start(cell, True)
- col.add_attribute(cell, "text", 1)
-
- # adding the slot
- cell = gtk.CellRendererText()
- self.slotcol.pack_start(cell, True)
- self.slotcol.add_attribute(cell, "text", 2)
-
- self.versionList.append_column(col)
- self.versionList.append_column(self.slotcol)
-
- self.versionList.get_selection().connect("changed", self.cb_vers_list_selection)
-
- def fill_version_list (self, cp, version = None):
-
- store = self.versionList.get_model()
- store.clear()
-
- # this is here for performance reasons
- # to not query the package with info, we do not need
- if self.cfg.get_boolean("showSlots", "GUI"):
- def get_slot(pkg):
- return pkg.get_package_settings("SLOT")
-
- self.slotcol.set_visible(True)
-
- else:
- def get_slot(*args):
- return ""
-
- self.slotcol.set_visible(False)
-
- packages = system.sort_package_list(system.find_packages(cp, masked=True))
-
- # append versions
- for vers, inst, slot in ((x.get_version(), x.is_installed(), get_slot(x)) for x in packages):
- if inst:
- icon = self.instPixbuf
- else:
- icon = None
-
- store.append([icon, vers, slot])
-
- pos = ((0,)) # default
-
- # activate the first one
- try:
- best_version = ""
- if version:
- best_version = version
- else:
- best_version = system.find_best_match(packages[0].get_cp()).get_version()
- for i, p in enumerate(packages):
- if p.get_version() == best_version:
- pos = (i,)
- break
- except AttributeError: # no package found
- pass
-
- self.versionList.get_selection().select_path(pos)
- self.versionList.scroll_to_cell(pos)
-
- def refresh_stores (self):
- """
- Refreshes the category and package stores.
- """
- self.fill_cat_store()
-
- if self.selCatName:
- self.fill_pkg_store(name = self.selCatName)
- else: # no selCatName -> so no category selected --> ignore
- debug("No category selected --> should be no harm.")
-
- def load_session(self, sessionEx = None):
- """
- Loads the session data.
- """
- try:
- self.session = Session("gtk_session.cfg")
- except (OSError, IOError), e:
- io_ex_dialog(e)
- return
-
- oldVersion = SESSION_VERSION
- allowedVersions = (0,1)
-
- if sessionEx and isinstance(sessionEx, SessionException):
- if sessionEx.got in allowedVersions:
- info(_("Translating session from version %d to %d.") % (sessionEx.got, sessionEx.expected))
- oldVersion = sessionEx.got
- else:
- warning(_("Cannot translate session from version %d to %d.") % (sessionEx.got, sessionEx.expected))
- raise sessionEx
-
- #
- # the callbacks for the different session variables
- #
-
- # QUEUE
- def load_queue (merge, unmerge, oneshot):
- def _load(q, **kwargs):
- if q:
- for i in q.split(","):
- self.queue.append(i, **kwargs)
-
- _load(merge)
- _load(unmerge, unmerge = True)
- _load(oneshot, oneshot = True)
-
- def save_queue ():
- if self.__save_queue:
- return (",".join(self.queue.mergequeue), ",".join(self.queue.unmergequeue), ",".join(self.queue.oneshotmerge))
- else:
- return ("", "", "")
-
- # PANED
- def load_paned (*pos):
- pos = map(int, pos)
- [x.set_position(p) for x,p in zip((self.vpaned, self.hpaned), pos)]
-
- def save_paned ():
- return [x.get_position() for x in (self.vpaned, self.hpaned)]
-
- # SELECTION
- def load_selection (list, col):
- def _load (name):
- pos = "0" # default
-
- if name:
- for cname, path in ((x[col], x.path) for x in list.get_model()):
- if cname == name:
- pos = path
- break
-
- if self.cfg.get_boolean("collapseCats", "GUI") and \
- pos == "0" and isinstance(list.get_model(), gtk.TreeStore): # try the new split up
-
- try:
- pre, post = name.split("-", 1)
- except ValueError: # nothing to split
- pass
- else:
- for row in list.get_model():
- if row[col] == pre: # found first part
- pos = row.path
- list.expand_row(pos, False)
- for cname, path in ((x[col], x.path) for x in row.iterchildren()):
- if cname == post: # found second
- pos = ":".join(map(str,path))
- break
- break
-
- debug("Selecting path '%s'.", pos)
- list.get_selection().select_path(pos)
- list.scroll_to_cell(pos)
-
- return _load
-
- def save_pkg_selection ():
- store, iter = self.pkgList.get_selection().get_selected()
- if iter:
- return store.get_value(iter, 1)
- else:
- return ""
-
- def save_cat_selection ():
- # try to find the correct category using the pkgList selection
- # so we do not select ALL =)
- # if no package has been selected - return selCatName
- store, iter = self.pkgList.get_selection().get_selected()
- if iter:
- return store.get_value(iter, 2)
- else:
- return self.selCatName
-
- # PLUGIN
- def load_plugin (p):
- def _load(val):
- if val:
- p.status = int(val)*2
-
- return _load
-
- def save_plugin (p):
- def _save ():
- if p.status == p.STAT_HARD_DISABLED:
- return ""
-
- return int(p.status >= p.STAT_ENABLED)
-
- return _save
-
- # SESSION VERSION
- def load_session_version (version):
- if oldVersion != SESSION_VERSION: # we are trying to convert
- return
-
- version = int(version)
-
- if version < SESSION_VERSION:
- raise OldSessionException(version, SESSION_VERSION)
- elif version > SESSION_VERSION:
- raise NewSessionException(version, SESSION_VERSION)
-
- def _add (value):
- if len(value) == 4:
- self.session.add_handler(value[:3], default = value[3])
- else:
- self.session.add_handler(value)
-
- # set the simple ones :)
- map(_add,[
- ([("gtksessionversion", "session")], load_session_version, lambda: SESSION_VERSION),
- ([("width", "window"), ("height", "window")], lambda w,h: self.window.resize(int(w), int(h)), self.window.get_size),
- ([("vpanedpos", "window"), ("hpanedpos", "window")], load_paned, save_paned),
- ([("catsel", "window")], load_selection(self.catList, 0), save_cat_selection, ["app-portage"]),
- ([("pkgsel", "window")], load_selection(self.pkgList, 1), save_pkg_selection, ["portato"])
- #([("merge", "queue"), ("unmerge", "queue"), ("oneshot", "queue")], load_queue, save_queue),
- ])
-
- # set the plugins
- queue = plugin.get_plugin_queue()
- if queue:
- for p in queue.get_plugins():
- self.session.add_handler(([(p.name.replace(" ","_"), "plugins")], load_plugin(p), save_plugin(p)))
-
- # now we have the handlers -> load
- self.session.load()
-
- def jump_to (self, cp, version = None):
- """
- Is called when we want to jump to a specific package.
-
- @param cp: the CP to jump to
- @type cp: string
- @param version: if not None jump to a specific version
- @type version: string
- """
-
- cat, pkg = cp.split("/")
-
- for list, idx, what, expr in ((self.catList, 0, "categories", cat), (self.pkgList, 1, "packages", pkg)):
- pathes = [row.path for row in list.get_model() if row[idx] == expr]
-
- if len(pathes) == 1:
- list.get_selection().select_path(pathes[0])
- list.scroll_to_cell(pathes[0])
- else:
- debug("Unexpected number of %s returned after search: %d", what, len(pathes))
- break
-
- self.show_package(cp = cp, version = version, queue = self.queue)
-
- def set_uri_hook (self, browser):
- """
- Sets the browser command which is called when a URL is going to be opened.
-
- @param browser: the browser command
- @type browser: string
- """
-
- browser = browser.split()
- gtk.link_button_set_uri_hook(lambda btn, x: get_listener().send_cmd(browser+[btn.get_uri()]))
-
- def set_notebook_tabpos (self, tabposlist):
- """
- Sets the positions of the tabs of the notebooks.
-
- @param tabposlist: the list of positions: first comes the one for package tabs; sndly for sys tabs
- @type tabposlist: int[]
- """
- self.pkgNotebook.set_tab_pos(tabposlist[0])
- self.sysNotebook.set_tab_pos(tabposlist[1])
-
- def title_update (self, title):
- """
- Updates the titles of the window and the systray.
- Mainly used with emerge term titles.
-
- @param title: the title
- @type title: string
- """
-
- def window_title_update (title):
- """
- Updates the title of the main window.
- """
- if title is None or not self.cfg.get_boolean("updateTitle", "GUI"):
- self.window.set_title(self.main_title)
- else:
- title = title.strip()
- if title[0] == '*':
- self.window.set_title(self.main_title)
- else:
- space_idx = title.rfind(" ")
- if space_idx != -1:
- title = title[:space_idx]
-
- self.window.set_title(("Portato >>> %s" % title))
-
- def __update(title):
- if self.tray:
- self.tray.set_tooltip(title)
-
- window_title_update(title)
- if title is None or not self.cfg.get_boolean("updateConsole", "GUI"):
- title = _("Console")
- else:
- title = ("%s (%s)") % (_("Console"), title)
-
- tlength = int(self.cfg.get("titlelength", "GUI"))
- if (len(title) > tlength): title = "%s..." % title[:tlength-3]
- self.sysNotebook.set_tab_label_text(self.termHB, title)
-
- return False
-
- # as this might get called from other threads use gobject.idle_add
- gobject.idle_add(__update, title)
-
- def cb_cat_list_selection (self, selection):
- """
- Callback for a category-list selection.
- Updates the package list with the packages in the category.
- """
- # get the selected category
- store, it = selection.get_selected()
- if it:
- if not self.cfg.get_boolean("collapseCats", "GUI"):
- self.selCatName = store.get_value(it, 0)
- else:
- parent = store.iter_parent(it)
- if parent is None:
- if store.iter_has_child(it): # this is a split up selector -> do nothing
- return True
- else:
- self.selCatName = store.get_value(it, 0) # this is a non-split up top
- else:
- self.selCatName = ("%s-%s" % (store.get_value(parent, 0), store.get_value(it, 0)))
-
- self.fill_pkg_store(name = self.selCatName)
- return True
-
- def cb_pkg_list_selection (self, selection):
- """
- Callback for a package-list selection.
- Updates the version list.
- """
- store, it = selection.get_selected()
- if it:
- self.selCP = "%s/%s" % (store.get_value(it, 2), store.get_value(it, 1))
- self.fill_version_list(self.selCP)
- return True
-
- def cb_pkg_list_header_clicked(self, col):
- self.sortPkgListByName = not self.sortPkgListByName
- self.fill_pkg_store(name = self.selCatName)
- return True
-
- def cb_vers_list_selection (self, selection):
- """
- Callback for a package-list selection.
- Updates the version list.
- """
- store, it = selection.get_selected()
- if it:
- self.selCPV = "%s-%s" % (self.selCP, store.get_value(it, 1))
- self.show_package(cpv = self.selCPV, queue = self.queue)
-
- return True
-
- def cb_queue_list_selection (self, selection):
-
- def set_val (val):
- self.queueOneshot.handler_block(self.queueOneshotHandler)
- self.queueOneshot.set_active(val)
- self.queueOneshot.handler_unblock(self.queueOneshotHandler)
-
- store, it = selection.get_selected()
- if it:
- parent = self.queueTree.parent_iter(it)
- if self.queueTree.is_in_emerge(it) and parent and not self.queueTree.iter_has_parent(parent):
- package = store.get_value(it, 0)
- self.queueOneshot.set_sensitive(True)
- set_val(package in self.queue.oneshotmerge)
- return True
-
- self.queueOneshot.set_sensitive(False)
- set_val(False)
- return True
-
- def cb_queue_row_activated (self, view, path, *args):
- """Callback for an activated row in the emergeQueue. Opens a package window."""
- store = self.queueTree
- if len(path) > 1:
- iterator = store.get_original().get_iter(path)
- if store.iter_has_parent(iterator):
- package = store.get_value(iterator, store.get_cpv_column())
-
- if store.is_in_emerge(iterator):
- type = "install"
- elif store.is_in_unmerge(iterator):
- type = "uninstall"
- elif store.is_in_update(iterator):
- type = "update"
-
- self.show_package(cpv = package, queue = self.queue, instantChange = True, doEmerge = False, type = type)
- return True
-
- def cb_queue_tooltip_queried (self, view, x, y, is_keyboard, tooltip):
- store = self.queueList.get_model()
- path = self.queueList.get_path_at_pos(x,y)
-
- if path is None:
- return False
-
- it = store.get_iter(path[0])
-
- if store.iter_parent(it) is None:
- return False # do not show tooltips for the root entries
-
- pkg = system.new_package(store.get_value(it, 0))
-
- enabled = []
- disabled = []
- expanded = set()
-
- pkg_flags = pkg.get_iuse_flags()
- pkg_flags.sort()
- if not pkg_flags: # no flags - stop here
- return None
-
- actual = set(pkg.get_actual_use_flags())
-
- if pkg.is_installed():
- installed = set(pkg.get_iuse_flags()).intersection(pkg.get_installed_use_flags())
- else:
- inst = system.find_packages(pkg.get_slot_cp(), system.SET_INSTALLED)
- if inst:
- installed = set(inst[0].get_iuse_flags()).intersection(inst[0].get_installed_use_flags())
- else:
- installed = set()
-
- diff = actual.symmetric_difference(installed)
-
- for use in pkg_flags:
- exp = pkg.use_expanded(use)
- if exp:
- expanded.add(exp)
-
- else:
- useStr = use
- if installed and use in diff:
- useStr += " %"
- if use in actual:
- enabled.append(useStr)
- else:
- disabled.append(useStr)
-
- string = ""
-
- if enabled:
- string = "<b>+%s</b>" % ("\n+".join(enabled),)
- if len(disabled) > 0:
- string = string + "\n"
-
- if disabled:
- string = string+"<i>- %s</i>" % ("\n- ".join(disabled),)
-
- if expanded:
- string = string+"\n\n"+"\n".join(expanded)
-
- tooltip.set_markup(string)
- return string != ""
-
- def cb_execute_clicked (self, action):
- """Execute the current queue."""
-
- if len(flags.newUseFlags) > 0:
- if not self.session.get_boolean("useflags", "dialogs"):
- self.session.set("useflags", changed_flags_dialog(_("use flags"))[1], "dialogs")
- try:
- flags.write_use_flags()
- except IOError, e:
- io_ex_dialog(e)
- return True
-
- if len(flags.new_masked)>0 or len(flags.new_unmasked)>0 or len(flags.newTesting)>0:
- debug("new masked: %s",flags.new_masked)
- debug("new unmasked: %s", flags.new_unmasked)
- debug("new testing: %s", flags.newTesting)
- if not self.session.get_boolean("keywords", "dialogs"):
- self.session.set("keywords", changed_flags_dialog(_("masking keywords"))[1], "dialogs")
- try:
- flags.write_masked()
- flags.write_testing()
- except IOError, e:
- io_ex_dialog(e)
- return True
- else:
- 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)
-
- # 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(sets = self.updateSets, force=True, newuse = self.cfg.get_boolean("newuse"), deep = self.cfg.get_boolean("deep"))
-
- return True
-
- def cb_update_clicked (self, action):
- def __update():
-
- def cb_idle_append (updating):
- try:
- try:
- for pkg, old_pkg in updating:
- 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(), type = "update", unmask = True)
-
- except BlockedException, e:
- blocked_dialog(e[0], e[1])
- self.queue.remove_children(self.queueTree.get_update_it())
-
- return False
-
- watch = gtk.gdk.Cursor(gtk.gdk.WATCH)
- self.window.window.set_cursor(watch)
- try:
- if system.has_set_support():
- confsets = [x.strip() for x in self.cfg.get("updatesets").split(",")]
- self.updateSets = [s for s in confsets if s in system.get_sets()]
- updating = system.update_world(sets = self.updateSets, newuse = self.cfg.get_boolean("newuse"), deep = self.cfg.get_boolean("deep"))
- else:
- updating = system.update_world(newuse = self.cfg.get_boolean("newuse"), deep = self.cfg.get_boolean("deep"))
- self.updateSets = ("world",)
-
- 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)
- finally:
- self.window.window.set_cursor(None)
-
- GtkThread(name="Update-Thread", target=__update).start()
-
- return True
-
- def cb_remove_clicked (self, button):
- """Removes a selected item in the (un)emerge-queue if possible."""
- model, iter = self.queueList.get_selection().get_selected()
-
- if iter:
- parent = model.iter_parent(iter)
-
- 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_with_children(iter)
- else:
- self.queue.remove(iter)
-
- elif model.iter_parent(parent): # this is in the 3rd level => dependency
- remove_deps_dialog()
- else:
- self.queue.remove_with_children(iter)
-
- if model.iter_n_children(parent) == 0: # no more children left - remove queue too
- self.queue.remove(parent)
-
- return True
- return False
-
- def cb_sync_clicked (self, action):
- self.sysNotebook.set_current_page(self.CONSOLE_PAGE)
- cmd = self.cfg.get("syncCommand")
-
- if cmd != "emerge --sync":
- cmd = cmd.split()
- self.queue.sync(cmd)
- else:
- self.queue.sync()
-
- def cb_save_flags_clicked (self, action):
- try:
- flags.write_use_flags()
- flags.write_testing()
- flags.write_masked()
- except IOError, e:
- io_ex_dialog(e)
-
- @Window.watch_cursor
- def cb_reload_clicked (self, action):
- """Reloads the portage settings and the database."""
- system.reload_settings()
- self.db.reload()
-
- @Window.watch_cursor
- def cb_search_clicked (self, entry):
- """Do a search."""
- text = entry.get_text()
- if text != "":
- if "/" not in text:
- text = "/.*"+text # only look for package names
-
- packages = system.find_packages(text, with_version = False)
-
- if packages == []:
- nothing_found_dialog()
- else:
- if len(packages) == 1:
- self.jump_to(packages[0])
- else:
- SearchWindow(self.window, packages, self.jump_to)
-
- return True
-
- def cb_search_changed (self, *args):
- """
- Called when the user enters something in the search field.
- Updates the packages according to the search expression.
- """
- if not self.__searchChanged and self.cfg.get_boolean("searchOnType", section="GUI"):
- self.__searchChanged = True
-
- def __update():
- self.__searchChanged = False
- txt = self.searchEntry.get_text()
-
- if txt or self.db.restrict:
- self.db.restrict = txt
-
- self.refresh_stores()
- self.catList.get_selection().select_path("0") # XXX make this smarter
-
- return False # not again ;)
-
- gobject.timeout_add(100, __update)
-
- def cb_delete_search_clicked (self, *args):
- self.searchEntry.set_text("")
- return True
-
- def cb_preferences_clicked (self, *args):
- """
- User wants to open preferences.
- """
- PreferenceWindow(self.window, self.cfg, self.console.set_font_from_string, self.set_uri_hook, self.set_notebook_tabpos, self.fill_cat_store)
- return True
-
- def cb_about_clicked (self, *args):
- """
- User wants to open about dialog.
- """
- AboutWindow(self.window)
- return True
-
- def cb_plugins_clicked (self, *args):
- """
- User wants to open plugin dialog.
- """
- queue = plugin.get_plugin_queue()
- if queue is None:
- plugins = []
- else:
- plugins = list(queue.get_plugins())
-
- PluginWindow(self.window, plugins, self.queue)
- return True
-
- def cb_show_updates_clicked (self, *args):
- """
- Show the list of updateble packages.
- """
-
- def __update():
- def cb_idle_show(packages):
- """
- Callback opening the menu when the calculation is finished.
-
- @returns: False to signal that it is finished
- """
- UpdateWindow(self.window, packages, self.queue, self.jump_to)
- return False
-
- watch = gtk.gdk.Cursor(gtk.gdk.WATCH)
- self.window.window.set_cursor(watch)
-
- packages = []
- try:
- packages.extend(system.get_updated_packages())
- finally:
- self.window.window.set_cursor(None)
-
- gobject.idle_add(cb_idle_show, packages)
-
- GtkThread(name="Show Updates Thread", target = __update).start()
- return True
-
- def cb_show_installed_toggled (self, *args):
- """
- Toggle the "show only installed" option.
- """
- self.showAll = not self.showAll
- self.refresh_stores()
-
- def cb_right_click (self, object, event):
- """
- Called when the user right clicks somewhere.
- Used to display a menu.
-
- This method should handle ALL such menus.
-
- @param object: the object/widget where the click is done
- @type object: gtk.Widget
- @param event: the event triggered
- @type event: gtk.gdk.Event
- """
-
- if event.type == gtk.gdk.BUTTON_PRESS and event.button == 3: # 3 == right click
- x = int(event.x)
- y = int(event.y)
- time = event.time
-
- if object == self.console:
- self.consolePopup.popup(None, None, None, event.button, time)
- else:
- return False
- else:
- return False
-
- def cb_oneshot_clicked (self, *args):
- """
- Mark a package as oneshot.
- """
- sel = self.queueList.get_selection()
- store, it = sel.get_selected()
- if it:
- if self.queueTree.is_in_emerge(it) and self.queueTree.iter_has_parent(it):
- package = store.get_value(it, 0)
- set = (package not in self.queue.oneshotmerge)
-
- self.queue.append(package, update = True, oneshot = set, forceUpdate = True)
-
- def cb_pause_emerge (self, curr):
- """
- This method returns a callback for a "pause emerge" toggle button.
- It is needed as there are different toggle buttons of this type and if one is clicked,
- the others should be marked too.
-
- @param curr: The button to return the callback for.
- @type curr: gtk.ToggleButton
- """
- def pause (cb):
- """
- The actual callback.
-
- Mark all other buttons too.
-
- @param cb: The button which got toggled.
- @type cb: gtk.ToggleButton
- """
-
- # pause or continue
- self.emergePaused = cb.get_active()
- if not self.emergePaused:
- self.queue.continue_emerge()
- #self.tray.set_from_file(APP_ICON)
- else:
- self.queue.stop_emerge()
- #self.tray.set_from_file(os.path.join(ICON_DIR, "pausing.png"))
-
- # block the handlers of the other buttons
- # so that calling "set_active" does not call this callback recursivly
- for v in self.pauseItems.itervalues():
- v[0].handler_block(v[1])
-
- # mark the others
- for k, v in self.pauseItems.iteritems():
- if k != curr:
- v[0].set_active(self.emergePaused)
-
- # unblock
- for v in self.pauseItems.itervalues():
- v[0].handler_unblock(v[1])
-
- return False
- return pause
-
- def cb_kill_clicked (self, *args):
- """
- Kill emerge.
- """
- self.queue.kill_emerge()
- if self.emergePaused: # unmark the "pause emerge" buttons
- self.pauseItems["menu"][0].set_active(False) # calling one button is enough (see: cb_pause_emerge)
-
- def cb_copy_clicked (self, *args):
- """
- Copy marked text in the terminal to clipboard.
- """
- self.console.copy_clipboard()
-
- def cb_delete (self, *args):
- """
- Called when the user wants to quit the application.
-
- Asks the user for confirmation if there is something in the queue.
- Also saves session data.
- """
-
- self.__save_queue = False
-
- if not self.queue.is_empty():
- ret = queue_not_empty_dialog()
- if ret == gtk.RESPONSE_CANCEL:
- return True
- else: # there is sth in queue AND the user still wants to close -> kill emerge
- self.__save_queue = (ret == gtk.RESPONSE_YES)
- self.queue.kill_emerge()
-
- # write session
- self.session.save()
-
- return False
-
- def cb_minimized (self, window, event):
- """
- User wants to minimize the window.
- If it is possible to minimize to tray, it is done.
- """
-
- if self.tray and self.cfg.get_boolean("hideOnMinimize", "GUI"):
- if event.changed_mask & gtk.gdk.WINDOW_STATE_ICONIFIED:
- if event.new_window_state & gtk.gdk.WINDOW_STATE_ICONIFIED:
- self.window.hide()
- return True
-
- return False
-
- def cb_systray_activated (self, *args):
- """
- Systray was activated. Show or hide the window.
- """
- if self.window.iconify_initially:
- self.window.deiconify()
- self.window.show()
- self.window.window.show()
- else:
- self.window.iconify()
-
- def cb_close (self, *args):
- """
- "Close" menu entry called.
- Emulate normal quitting.
- """
- if not self.cb_delete(): # do the checks
- self.window.destroy()
-
- def cb_destroy (self, *args):
- """
- Calls main_quit().
- """
- gtk.main_quit()
-
- def main (self):
- """
- Main.
- """
- gobject.threads_init()
- # now subthreads can run normally, but are not allowed to touch the GUI. If threads should change sth there - use gobject.idle_add().
- # for more informations on threading and gtk: http://www.async.com.br/faq/pygtk/index.py?req=show&file=faq20.006.htp
- plugin.hook("main")(gtk.main)()
+ """
+ Application main window.
+ """
+
+ # NOTEBOOK PAGE CONSTANTS
+ (
+ QUEUE_PAGE,
+ CONSOLE_PAGE,
+ LOG_PAGE
+ ) = range(3)
+
+ def __init__ (self, splash = None):
+ """
+ Build up window.
+
+ @param splash: the splash screen =)
+ @type splash: SplashScreen
+ """
+
+ if splash is None:
+ splash = lambda x: True
+
+ # the title
+ self.main_title = "Portato (%s)" % VERSION
+
+ # main window stuff
+ Window.__init__(self)
+ self.window.set_title(self.main_title)
+ self.window.set_geometry_hints (self.window, max_height = gtk.gdk.screen_height(), max_width = gtk.gdk.screen_width())
+
+ # booleans
+ self.doUpdate = False
+ self.showAll = True # show only installed or all packages?
+ self.__searchChanged = False
+
+ # installed pixbuf
+ self.instPixbuf = self.window.render_icon(gtk.STOCK_YES, gtk.ICON_SIZE_MENU)
+
+ # get the logging window as soon as possible
+ self.logView = LogView(self.tree.get_widget("logView"))
+
+ # config
+ splash(_("Loading Config"))
+ try:
+ self.cfg = Config(CONFIG_LOCATION)
+ except IOError, e:
+ io_ex_dialog(e)
+ raise
+
+ self.cfg.modify_external_configs()
+ self.set_uri_hook(self.cfg.get("browserCmd", section = "GUI"))
+ gtk.about_dialog_set_url_hook(lambda *args: True) # dummy - if not set link is not set as link; if link is clicked the normal uuri_hook is called too - thus do not call browser here
+
+ # package db
+ splash(_("Creating Database"))
+ self.db = Database()
+ self.db.populate()
+
+ # set plugins and plugin-menu
+ splash(_("Loading Plugins"))
+
+ 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 itt.chain(*menus):
+ item = gtk.MenuItem(m.label)
+ item.connect("activate", m.call)
+ pluginMenu.append(item)
+
+ splash(_("Building frontend"))
+ # set paned position
+ self.vpaned = self.tree.get_widget("vpaned")
+ self.vpaned.set_position(int(self.window.get_size()[1]/2))
+ self.hpaned = self.tree.get_widget("hpaned")
+ self.hpaned.set_position(int(self.window.get_size()[0]/1.5))
+
+ # lists
+ self.selCatName = ""
+ self.selCP = ""
+ self.selCPV = ""
+ self.sortPkgListByName = True
+ self.catList = self.tree.get_widget("catList")
+ self.pkgList = self.tree.get_widget("pkgList")
+ self.versionList = self.tree.get_widget("versionList")
+ self.build_cat_list()
+ self.build_pkg_list()
+ self.build_version_list()
+
+ # search entry
+ self.searchEntry = self.tree.get_widget("searchEntry")
+
+ # queue list
+ self.queueOneshot = self.tree.get_widget("oneshotCB")
+ self.queueOneshotHandler = self.queueOneshot.connect("toggled", self.cb_oneshot_clicked)
+ self.queueList = self.tree.get_widget("queueList")
+ self.build_queue_list()
+
+ # the terminal
+ self.console = GtkConsole()
+ self.termHB = self.tree.get_widget("termHB")
+ self.build_terminal()
+
+ # notebooks
+ self.sysNotebook = self.tree.get_widget("systemNotebook")
+ self.pkgNotebook = self.tree.get_widget("packageNotebook")
+ self.set_notebook_tabpos(map(PreferenceWindow.tabpos.get, map(int, (self.cfg.get("packageTabPos", "GUI"), self.cfg.get("systemTabPos", "GUI")))))
+
+ # the different scrolls
+ ebuildScroll = self.tree.get_widget("ebuildScroll")
+ ebuildScroll.add(HighlightView(lambda p: p.get_ebuild_path(), ["gentoo", "sh"]))
+
+ changelogScroll = self.tree.get_widget("changelogScroll")
+ changelogScroll.add(HighlightView(lambda p: os.path.join(p.get_package_path(), "ChangeLog"), ["changelog"]))
+
+ def show_files (p):
+ try:
+ for f in p.get_files():
+ yield " %s\n" % f
+ except IOError, e:
+ yield _("Error: %s") % e.strerror
+
+ filesScroll = self.tree.get_widget("filesScroll")
+ filesScroll.add(InstalledOnlyView(show_files))
+
+ # table
+ self.packageTable = PackageTable(self)
+
+ # popups
+ self.consolePopup = Popup("consolePopup", self, self.__file__)
+ self.trayPopup = Popup("systrayPopup", self)
+
+ # pause menu items
+ self.emergePaused = False
+ self.pauseItems = {}
+ self.pauseItems["tray"] = self.trayPopup.tree.get_widget("pauseItemTray")
+ self.pauseItems["popup"] = self.consolePopup.tree.get_widget("pauseItemPopup")
+ self.pauseItems["menu"] = self.tree.get_widget("pauseItemMenu")
+
+ for k,v in self.pauseItems.iteritems():
+ self.pauseItems[k] = (v, v.connect_after("activate", self.cb_pause_emerge(k)))
+
+ # systray
+ if self.cfg.get_boolean("showSystray", "GUI"):
+ self.tray = gtk.status_icon_new_from_file(APP_ICON)
+ self.tray.connect("activate", self.cb_systray_activated)
+ self.tray.connect("popup-menu", lambda icon, btn, time: self.trayPopup.popup(None, None, None, btn, time))
+ else:
+ self.tray = None
+
+ # set emerge queue
+ self.queueTree = GtkTree(self.queueList.get_model())
+ self.queue = EmergeQueue(console = self.console, tree = self.queueTree, db = self.db, title_update = self.title_update, threadClass = GtkThread)
+
+ # session
+ splash(_("Restoring Session"))
+ try:
+ try:
+ self.load_session()
+ except OldSessionException, e:
+ self.load_session(e)
+ except SessionException, e:
+ warning(str(e))
+
+ splash(_("Finishing startup"))
+
+ self.window.show_all()
+
+ def show_package (self, pkg = None, cpv = None, cp = None, version = None, **kwargs):
+ p = None
+
+ if pkg:
+ p = pkg
+ elif cpv:
+ p = system.find_packages("="+cpv, masked = True)[0]
+ elif cp:
+ if version:
+ p = system.find_packages("=%s-%s" % (cp, version), masked = True)[0]
+
+ else:
+ best = system.find_best_match(cp)
+ if best:
+ p = best
+ else:
+ p = system.find_packages(cp)[0]
+
+ self.packageTable.update(p, **kwargs)
+
+ def build_terminal (self):
+ """
+ Builds the terminal.
+ """
+
+ self.console.set_scrollback_lines(int(self.cfg.get("scrollbacklines", "GUI")))
+ self.console.set_scroll_on_output(True)
+ self.console.set_font_from_string(self.cfg.get("consolefont", "GUI"))
+ self.console.connect("button-press-event", self.cb_right_click)
+ self.termHB.pack_start(self.console, True, True)
+
+ # add scrollbar
+ termScroll = gtk.VScrollbar(self.console.get_adjustment())
+ self.termHB.pack_start(termScroll, False)
+
+ def build_queue_list (self):
+ """
+ Builds the queue list.
+ """
+
+ store = gtk.TreeStore(str,str,bool)
+
+ self.queueList.set_model(store)
+
+ cell = gtk.CellRendererText()
+ col = gtk.TreeViewColumn(_("Queue"), cell, markup = 0)
+ self.queueList.append_column(col)
+
+ col = gtk.TreeViewColumn(_("Options"), cell, markup = 1)
+ self.queueList.append_column(col)
+
+ self.queueList.get_selection().connect("changed", self.cb_queue_list_selection)
+
+ def build_cat_list (self):
+ """
+ Builds the category list.
+ """
+
+ store = gtk.TreeStore(str)
+
+ self.fill_cat_store(store)
+
+ self.catList.set_model(store)
+ cell = gtk.CellRendererText()
+ col = gtk.TreeViewColumn(_("Categories"), cell, text = 0)
+ self.catList.append_column(col)
+
+ self.catList.get_selection().connect("changed", self.cb_cat_list_selection)
+
+ def fill_cat_store (self, store = None):
+ """
+ Fills the category store with data.
+
+ @param store: the store to fill
+ @type store: gtk.ListStore
+ """
+
+ if store is None:
+ store = self.catList.get_model()
+
+ store.clear()
+
+ cats = self.db.get_categories(installed = not self.showAll)
+
+ if not self.cfg.get_boolean("collapseCats", "GUI"):
+ for p in cats:
+ store.append(None, [p])
+ else:
+ splitCats = defaultdict(list)
+ for c in cats:
+ try:
+ pre, post = c.split("-", 1)
+ except ValueError: # no "-" in cat name -- do not split
+ debug("Category '%s' can't be split up. Should be no harm.", c)
+ splitCats["not-split"].append(c)
+ else:
+ splitCats[pre].append(post)
+
+ for sc in splitCats:
+ if sc == "not-split":
+ it = None # append not splitted stuff to root
+ else:
+ it = store.append(None, [sc])
+ for cat in splitCats[sc]:
+ store.append(it, [cat])
+
+ # sort them alphabetically
+ store.set_sort_column_id(0, gtk.SORT_ASCENDING)
+
+ def build_pkg_list (self, name = None):
+ """
+ Builds the package list.
+
+ @param name: name of the selected catetegory
+ @type name: string
+ """
+
+ store = gtk.ListStore(gtk.gdk.Pixbuf, str, str)
+ self.fill_pkg_store(store, name)
+
+ # build view
+ self.pkgList.set_model(store)
+
+ col = gtk.TreeViewColumn(_("Packages"))
+ col.set_clickable(True)
+ col.connect("clicked", self.cb_pkg_list_header_clicked)
+
+ # adding the pixbuf
+ cell = gtk.CellRendererPixbuf()
+ col.pack_start(cell, False)
+ col.add_attribute(cell, "pixbuf", 0)
+
+ # adding the package name
+ cell = gtk.CellRendererText()
+ col.pack_start(cell, True)
+ col.add_attribute(cell, "text", 1)
+
+ self.pkgList.append_column(col)
+
+ self.pkgList.get_selection().connect("changed", self.cb_pkg_list_selection)
+
+ def fill_pkg_store (self, store = None, name = None):
+ """
+ Fills a given ListStore with the packages in a category.
+
+ @param store: the store to fill
+ @type store: gtk.ListStore
+ @param name: the name of the category
+ @type name: string
+ """
+
+ if store is None:
+ store = self.pkgList.get_model()
+ store.clear()
+
+ if name:
+ for cat, pkg, is_inst in self.db.get_cat(name, self.sortPkgListByName):
+ if is_inst:
+ icon = self.instPixbuf
+ elif not self.showAll:
+ continue # ignore not installed packages
+ else:
+ icon = None
+ store.append([icon, pkg, cat])
+
+ def build_version_list (self):
+ store = gtk.ListStore(gtk.gdk.Pixbuf, str, str)
+
+ # build view
+ self.versionList.set_model(store)
+
+ col = gtk.TreeViewColumn(_("Versions"))
+ col.set_property("expand", True)
+
+ self.slotcol = gtk.TreeViewColumn(_("Slot"))
+ self.slotcol.set_property("expand", True)
+
+ # adding the pixbuf
+ cell = gtk.CellRendererPixbuf()
+ col.pack_start(cell, False)
+ col.add_attribute(cell, "pixbuf", 0)
+
+ # adding the package name
+ cell = gtk.CellRendererText()
+ col.pack_start(cell, True)
+ col.add_attribute(cell, "text", 1)
+
+ # adding the slot
+ cell = gtk.CellRendererText()
+ self.slotcol.pack_start(cell, True)
+ self.slotcol.add_attribute(cell, "text", 2)
+
+ self.versionList.append_column(col)
+ self.versionList.append_column(self.slotcol)
+
+ self.versionList.get_selection().connect("changed", self.cb_vers_list_selection)
+
+ def fill_version_list (self, cp, version = None):
+
+ store = self.versionList.get_model()
+ store.clear()
+
+ # this is here for performance reasons
+ # to not query the package with info, we do not need
+ if self.cfg.get_boolean("showSlots", "GUI"):
+ def get_slot(pkg):
+ return pkg.get_package_settings("SLOT")
+
+ self.slotcol.set_visible(True)
+
+ else:
+ def get_slot(*args):
+ return ""
+
+ self.slotcol.set_visible(False)
+
+ packages = system.sort_package_list(system.find_packages(cp, masked=True))
+
+ # append versions
+ for vers, inst, slot in ((x.get_version(), x.is_installed(), get_slot(x)) for x in packages):
+ if inst:
+ icon = self.instPixbuf
+ else:
+ icon = None
+
+ store.append([icon, vers, slot])
+
+ pos = ((0,)) # default
+
+ # activate the first one
+ try:
+ best_version = ""
+ if version:
+ best_version = version
+ else:
+ best_version = system.find_best_match(packages[0].get_cp()).get_version()
+ for i, p in enumerate(packages):
+ if p.get_version() == best_version:
+ pos = (i,)
+ break
+ except AttributeError: # no package found
+ pass
+
+ self.versionList.get_selection().select_path(pos)
+ self.versionList.scroll_to_cell(pos)
+
+ def refresh_stores (self):
+ """
+ Refreshes the category and package stores.
+ """
+ self.fill_cat_store()
+
+ if self.selCatName:
+ self.fill_pkg_store(name = self.selCatName)
+ else: # no selCatName -> so no category selected --> ignore
+ debug("No category selected --> should be no harm.")
+
+ def load_session(self, sessionEx = None):
+ """
+ Loads the session data.
+ """
+ try:
+ self.session = Session("gtk_session.cfg")
+ except (OSError, IOError), e:
+ io_ex_dialog(e)
+ return
+
+ oldVersion = SESSION_VERSION
+ allowedVersions = (0,1)
+
+ if sessionEx and isinstance(sessionEx, SessionException):
+ if sessionEx.got in allowedVersions:
+ info(_("Translating session from version %d to %d.") % (sessionEx.got, sessionEx.expected))
+ oldVersion = sessionEx.got
+ else:
+ warning(_("Cannot translate session from version %d to %d.") % (sessionEx.got, sessionEx.expected))
+ raise sessionEx
+
+ #
+ # the callbacks for the different session variables
+ #
+
+ # QUEUE
+ def load_queue (merge, unmerge, oneshot):
+ def _load(q, **kwargs):
+ if q:
+ for i in q.split(","):
+ self.queue.append(i, **kwargs)
+
+ _load(merge)
+ _load(unmerge, unmerge = True)
+ _load(oneshot, oneshot = True)
+
+ def save_queue ():
+ if self.__save_queue:
+ return (",".join(self.queue.mergequeue), ",".join(self.queue.unmergequeue), ",".join(self.queue.oneshotmerge))
+ else:
+ return ("", "", "")
+
+ # PANED
+ def load_paned (*pos):
+ pos = map(int, pos)
+ [x.set_position(p) for x,p in zip((self.vpaned, self.hpaned), pos)]
+
+ def save_paned ():
+ return [x.get_position() for x in (self.vpaned, self.hpaned)]
+
+ # SELECTION
+ def load_selection (list, col):
+ def _load (name):
+ pos = "0" # default
+
+ if name:
+ for cname, path in ((x[col], x.path) for x in list.get_model()):
+ if cname == name:
+ pos = path
+ break
+
+ if self.cfg.get_boolean("collapseCats", "GUI") and \
+ pos == "0" and isinstance(list.get_model(), gtk.TreeStore): # try the new split up
+
+ try:
+ pre, post = name.split("-", 1)
+ except ValueError: # nothing to split
+ pass
+ else:
+ for row in list.get_model():
+ if row[col] == pre: # found first part
+ pos = row.path
+ list.expand_row(pos, False)
+ for cname, path in ((x[col], x.path) for x in row.iterchildren()):
+ if cname == post: # found second
+ pos = ":".join(map(str,path))
+ break
+ break
+
+ debug("Selecting path '%s'.", pos)
+ list.get_selection().select_path(pos)
+ list.scroll_to_cell(pos)
+
+ return _load
+
+ def save_pkg_selection ():
+ store, iter = self.pkgList.get_selection().get_selected()
+ if iter:
+ return store.get_value(iter, 1)
+ else:
+ return ""
+
+ def save_cat_selection ():
+ # try to find the correct category using the pkgList selection
+ # so we do not select ALL =)
+ # if no package has been selected - return selCatName
+ store, iter = self.pkgList.get_selection().get_selected()
+ if iter:
+ return store.get_value(iter, 2)
+ else:
+ return self.selCatName
+
+ # PLUGIN
+ def load_plugin (p):
+ def _load(val):
+ if val:
+ p.status = int(val)*2
+
+ return _load
+
+ def save_plugin (p):
+ def _save ():
+ if p.status == p.STAT_HARD_DISABLED:
+ return ""
+
+ return int(p.status >= p.STAT_ENABLED)
+
+ return _save
+
+ # SESSION VERSION
+ def load_session_version (version):
+ if oldVersion != SESSION_VERSION: # we are trying to convert
+ return
+
+ version = int(version)
+
+ if version < SESSION_VERSION:
+ raise OldSessionException(version, SESSION_VERSION)
+ elif version > SESSION_VERSION:
+ raise NewSessionException(version, SESSION_VERSION)
+
+ def _add (value):
+ if len(value) == 4:
+ self.session.add_handler(value[:3], default = value[3])
+ else:
+ self.session.add_handler(value)
+
+ # set the simple ones :)
+ map(_add,[
+ ([("gtksessionversion", "session")], load_session_version, lambda: SESSION_VERSION),
+ ([("width", "window"), ("height", "window")], lambda w,h: self.window.resize(int(w), int(h)), self.window.get_size),
+ ([("vpanedpos", "window"), ("hpanedpos", "window")], load_paned, save_paned),
+ ([("catsel", "window")], load_selection(self.catList, 0), save_cat_selection, ["app-portage"]),
+ ([("pkgsel", "window")], load_selection(self.pkgList, 1), save_pkg_selection, ["portato"])
+ #([("merge", "queue"), ("unmerge", "queue"), ("oneshot", "queue")], load_queue, save_queue),
+ ])
+
+ # set the plugins
+ queue = plugin.get_plugin_queue()
+ if queue:
+ for p in queue.get_plugins():
+ self.session.add_handler(([(p.name.replace(" ","_"), "plugins")], load_plugin(p), save_plugin(p)))
+
+ # now we have the handlers -> load
+ self.session.load()
+
+ def jump_to (self, cp, version = None):
+ """
+ Is called when we want to jump to a specific package.
+
+ @param cp: the CP to jump to
+ @type cp: string
+ @param version: if not None jump to a specific version
+ @type version: string
+ """
+
+ cat, pkg = cp.split("/")
+
+ for list, idx, what, expr in ((self.catList, 0, "categories", cat), (self.pkgList, 1, "packages", pkg)):
+ pathes = [row.path for row in list.get_model() if row[idx] == expr]
+
+ if len(pathes) == 1:
+ list.get_selection().select_path(pathes[0])
+ list.scroll_to_cell(pathes[0])
+ else:
+ debug("Unexpected number of %s returned after search: %d", what, len(pathes))
+ break
+
+ self.show_package(cp = cp, version = version, queue = self.queue)
+
+ def set_uri_hook (self, browser):
+ """
+ Sets the browser command which is called when a URL is going to be opened.
+
+ @param browser: the browser command
+ @type browser: string
+ """
+
+ browser = browser.split()
+ gtk.link_button_set_uri_hook(lambda btn, x: get_listener().send_cmd(browser+[btn.get_uri()]))
+
+ def set_notebook_tabpos (self, tabposlist):
+ """
+ Sets the positions of the tabs of the notebooks.
+
+ @param tabposlist: the list of positions: first comes the one for package tabs; sndly for sys tabs
+ @type tabposlist: int[]
+ """
+ self.pkgNotebook.set_tab_pos(tabposlist[0])
+ self.sysNotebook.set_tab_pos(tabposlist[1])
+
+ def title_update (self, title):
+ """
+ Updates the titles of the window and the systray.
+ Mainly used with emerge term titles.
+
+ @param title: the title
+ @type title: string
+ """
+
+ def window_title_update (title):
+ """
+ Updates the title of the main window.
+ """
+ if title is None or not self.cfg.get_boolean("updateTitle", "GUI"):
+ self.window.set_title(self.main_title)
+ else:
+ title = title.strip()
+ if title[0] == '*':
+ self.window.set_title(self.main_title)
+ else:
+ space_idx = title.rfind(" ")
+ if space_idx != -1:
+ title = title[:space_idx]
+
+ self.window.set_title(("Portato >>> %s" % title))
+
+ def __update(title):
+ if self.tray:
+ self.tray.set_tooltip(title)
+
+ window_title_update(title)
+ if title is None or not self.cfg.get_boolean("updateConsole", "GUI"):
+ title = _("Console")
+ else:
+ title = ("%s (%s)") % (_("Console"), title)
+
+ tlength = int(self.cfg.get("titlelength", "GUI"))
+ if (len(title) > tlength): title = "%s..." % title[:tlength-3]
+ self.sysNotebook.set_tab_label_text(self.termHB, title)
+
+ return False
+
+ # as this might get called from other threads use gobject.idle_add
+ gobject.idle_add(__update, title)
+
+ def cb_cat_list_selection (self, selection):
+ """
+ Callback for a category-list selection.
+ Updates the package list with the packages in the category.
+ """
+ # get the selected category
+ store, it = selection.get_selected()
+ if it:
+ if not self.cfg.get_boolean("collapseCats", "GUI"):
+ self.selCatName = store.get_value(it, 0)
+ else:
+ parent = store.iter_parent(it)
+ if parent is None:
+ if store.iter_has_child(it): # this is a split up selector -> do nothing
+ return True
+ else:
+ self.selCatName = store.get_value(it, 0) # this is a non-split up top
+ else:
+ self.selCatName = ("%s-%s" % (store.get_value(parent, 0), store.get_value(it, 0)))
+
+ self.fill_pkg_store(name = self.selCatName)
+ return True
+
+ def cb_pkg_list_selection (self, selection):
+ """
+ Callback for a package-list selection.
+ Updates the version list.
+ """
+ store, it = selection.get_selected()
+ if it:
+ self.selCP = "%s/%s" % (store.get_value(it, 2), store.get_value(it, 1))
+ self.fill_version_list(self.selCP)
+ return True
+
+ def cb_pkg_list_header_clicked(self, col):
+ self.sortPkgListByName = not self.sortPkgListByName
+ self.fill_pkg_store(name = self.selCatName)
+ return True
+
+ def cb_vers_list_selection (self, selection):
+ """
+ Callback for a package-list selection.
+ Updates the version list.
+ """
+ store, it = selection.get_selected()
+ if it:
+ self.selCPV = "%s-%s" % (self.selCP, store.get_value(it, 1))
+ self.show_package(cpv = self.selCPV, queue = self.queue)
+
+ return True
+
+ def cb_queue_list_selection (self, selection):
+
+ def set_val (val):
+ self.queueOneshot.handler_block(self.queueOneshotHandler)
+ self.queueOneshot.set_active(val)
+ self.queueOneshot.handler_unblock(self.queueOneshotHandler)
+
+ store, it = selection.get_selected()
+ if it:
+ parent = self.queueTree.parent_iter(it)
+ if self.queueTree.is_in_emerge(it) and parent and not self.queueTree.iter_has_parent(parent):
+ package = store.get_value(it, 0)
+ self.queueOneshot.set_sensitive(True)
+ set_val(package in self.queue.oneshotmerge)
+ return True
+
+ self.queueOneshot.set_sensitive(False)
+ set_val(False)
+ return True
+
+ def cb_queue_row_activated (self, view, path, *args):
+ """Callback for an activated row in the emergeQueue. Opens a package window."""
+ store = self.queueTree
+ if len(path) > 1:
+ iterator = store.get_original().get_iter(path)
+ if store.iter_has_parent(iterator):
+ package = store.get_value(iterator, store.get_cpv_column())
+
+ if store.is_in_emerge(iterator):
+ type = "install"
+ elif store.is_in_unmerge(iterator):
+ type = "uninstall"
+ elif store.is_in_update(iterator):
+ type = "update"
+
+ self.show_package(cpv = package, queue = self.queue, instantChange = True, doEmerge = False, type = type)
+ return True
+
+ def cb_queue_tooltip_queried (self, view, x, y, is_keyboard, tooltip):
+ store = self.queueList.get_model()
+ path = self.queueList.get_path_at_pos(x,y)
+
+ if path is None:
+ return False
+
+ it = store.get_iter(path[0])
+
+ if store.iter_parent(it) is None:
+ return False # do not show tooltips for the root entries
+
+ pkg = system.new_package(store.get_value(it, 0))
+
+ enabled = []
+ disabled = []
+ expanded = set()
+
+ pkg_flags = pkg.get_iuse_flags()
+ pkg_flags.sort()
+ if not pkg_flags: # no flags - stop here
+ return None
+
+ actual = set(pkg.get_actual_use_flags())
+
+ if pkg.is_installed():
+ installed = set(pkg.get_iuse_flags()).intersection(pkg.get_installed_use_flags())
+ else:
+ inst = system.find_packages(pkg.get_slot_cp(), system.SET_INSTALLED)
+ if inst:
+ installed = set(inst[0].get_iuse_flags()).intersection(inst[0].get_installed_use_flags())
+ else:
+ installed = set()
+
+ diff = actual.symmetric_difference(installed)
+
+ for use in pkg_flags:
+ exp = pkg.use_expanded(use)
+ if exp:
+ expanded.add(exp)
+
+ else:
+ useStr = use
+ if installed and use in diff:
+ useStr += " %"
+ if use in actual:
+ enabled.append(useStr)
+ else:
+ disabled.append(useStr)
+
+ string = ""
+
+ if enabled:
+ string = "<b>+%s</b>" % ("\n+".join(enabled),)
+ if len(disabled) > 0:
+ string = string + "\n"
+
+ if disabled:
+ string = string+"<i>- %s</i>" % ("\n- ".join(disabled),)
+
+ if expanded:
+ string = string+"\n\n"+"\n".join(expanded)
+
+ tooltip.set_markup(string)
+ return string != ""
+
+ def cb_execute_clicked (self, action):
+ """Execute the current queue."""
+
+ if len(flags.newUseFlags) > 0:
+ if not self.session.get_boolean("useflags", "dialogs"):
+ self.session.set("useflags", changed_flags_dialog(_("use flags"))[1], "dialogs")
+ try:
+ flags.write_use_flags()
+ except IOError, e:
+ io_ex_dialog(e)
+ return True
+
+ if len(flags.new_masked)>0 or len(flags.new_unmasked)>0 or len(flags.newTesting)>0:
+ debug("new masked: %s",flags.new_masked)
+ debug("new unmasked: %s", flags.new_unmasked)
+ debug("new testing: %s", flags.newTesting)
+ if not self.session.get_boolean("keywords", "dialogs"):
+ self.session.set("keywords", changed_flags_dialog(_("masking keywords"))[1], "dialogs")
+ try:
+ flags.write_masked()
+ flags.write_testing()
+ except IOError, e:
+ io_ex_dialog(e)
+ return True
+ else:
+ 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)
+
+ # 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(sets = self.updateSets, force=True, newuse = self.cfg.get_boolean("newuse"), deep = self.cfg.get_boolean("deep"))
+
+ return True
+
+ def cb_update_clicked (self, action):
+ def __update():
+
+ def cb_idle_append (updating):
+ try:
+ try:
+ for pkg, old_pkg in updating:
+ 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(), type = "update", unmask = True)
+
+ except BlockedException, e:
+ blocked_dialog(e[0], e[1])
+ self.queue.remove_children(self.queueTree.get_update_it())
+
+ return False
+
+ watch = gtk.gdk.Cursor(gtk.gdk.WATCH)
+ self.window.window.set_cursor(watch)
+ try:
+ if system.has_set_support():
+ confsets = [x.strip() for x in self.cfg.get("updatesets").split(",")]
+ self.updateSets = [s for s in confsets if s in system.get_sets()]
+ updating = system.update_world(sets = self.updateSets, newuse = self.cfg.get_boolean("newuse"), deep = self.cfg.get_boolean("deep"))
+ else:
+ updating = system.update_world(newuse = self.cfg.get_boolean("newuse"), deep = self.cfg.get_boolean("deep"))
+ self.updateSets = ("world",)
+
+ 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)
+ finally:
+ self.window.window.set_cursor(None)
+
+ GtkThread(name="Update-Thread", target=__update).start()
+
+ return True
+
+ def cb_remove_clicked (self, button):
+ """Removes a selected item in the (un)emerge-queue if possible."""
+ model, iter = self.queueList.get_selection().get_selected()
+
+ if iter:
+ parent = model.iter_parent(iter)
+
+ 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_with_children(iter)
+ else:
+ self.queue.remove(iter)
+
+ elif model.iter_parent(parent): # this is in the 3rd level => dependency
+ remove_deps_dialog()
+ else:
+ self.queue.remove_with_children(iter)
+
+ if model.iter_n_children(parent) == 0: # no more children left - remove queue too
+ self.queue.remove(parent)
+
+ return True
+ return False
+
+ def cb_sync_clicked (self, action):
+ self.sysNotebook.set_current_page(self.CONSOLE_PAGE)
+ cmd = self.cfg.get("syncCommand")
+
+ if cmd != "emerge --sync":
+ cmd = cmd.split()
+ self.queue.sync(cmd)
+ else:
+ self.queue.sync()
+
+ def cb_save_flags_clicked (self, action):
+ try:
+ flags.write_use_flags()
+ flags.write_testing()
+ flags.write_masked()
+ except IOError, e:
+ io_ex_dialog(e)
+
+ @Window.watch_cursor
+ def cb_reload_clicked (self, action):
+ """Reloads the portage settings and the database."""
+ system.reload_settings()
+ self.db.reload()
+
+ @Window.watch_cursor
+ def cb_search_clicked (self, entry):
+ """Do a search."""
+ text = entry.get_text()
+ if text != "":
+ if "/" not in text:
+ text = "/.*"+text # only look for package names
+
+ packages = system.find_packages(text, with_version = False)
+
+ if packages == []:
+ nothing_found_dialog()
+ else:
+ if len(packages) == 1:
+ self.jump_to(packages[0])
+ else:
+ SearchWindow(self.window, packages, self.jump_to)
+
+ return True
+
+ def cb_search_changed (self, *args):
+ """
+ Called when the user enters something in the search field.
+ Updates the packages according to the search expression.
+ """
+ if not self.__searchChanged and self.cfg.get_boolean("searchOnType", section="GUI"):
+ self.__searchChanged = True
+
+ def __update():
+ self.__searchChanged = False
+ txt = self.searchEntry.get_text()
+
+ if txt or self.db.restrict:
+ self.db.restrict = txt
+
+ self.refresh_stores()
+ self.catList.get_selection().select_path("0") # XXX make this smarter
+
+ return False # not again ;)
+
+ gobject.timeout_add(100, __update)
+
+ def cb_delete_search_clicked (self, *args):
+ self.searchEntry.set_text("")
+ return True
+
+ def cb_preferences_clicked (self, *args):
+ """
+ User wants to open preferences.
+ """
+ PreferenceWindow(self.window, self.cfg, self.console.set_font_from_string, self.set_uri_hook, self.set_notebook_tabpos, self.fill_cat_store)
+ return True
+
+ def cb_about_clicked (self, *args):
+ """
+ User wants to open about dialog.
+ """
+ AboutWindow(self.window)
+ return True
+
+ def cb_plugins_clicked (self, *args):
+ """
+ User wants to open plugin dialog.
+ """
+ queue = plugin.get_plugin_queue()
+ if queue is None:
+ plugins = []
+ else:
+ plugins = list(queue.get_plugins())
+
+ PluginWindow(self.window, plugins, self.queue)
+ return True
+
+ def cb_show_updates_clicked (self, *args):
+ """
+ Show the list of updateble packages.
+ """
+
+ def __update():
+ def cb_idle_show(packages):
+ """
+ Callback opening the menu when the calculation is finished.
+
+ @returns: False to signal that it is finished
+ """
+ UpdateWindow(self.window, packages, self.queue, self.jump_to)
+ return False
+
+ watch = gtk.gdk.Cursor(gtk.gdk.WATCH)
+ self.window.window.set_cursor(watch)
+
+ packages = []
+ try:
+ packages.extend(system.get_updated_packages())
+ finally:
+ self.window.window.set_cursor(None)
+
+ gobject.idle_add(cb_idle_show, packages)
+
+ GtkThread(name="Show Updates Thread", target = __update).start()
+ return True
+
+ def cb_show_installed_toggled (self, *args):
+ """
+ Toggle the "show only installed" option.
+ """
+ self.showAll = not self.showAll
+ self.refresh_stores()
+
+ def cb_right_click (self, object, event):
+ """
+ Called when the user right clicks somewhere.
+ Used to display a menu.
+
+ This method should handle ALL such menus.
+
+ @param object: the object/widget where the click is done
+ @type object: gtk.Widget
+ @param event: the event triggered
+ @type event: gtk.gdk.Event
+ """
+
+ if event.type == gtk.gdk.BUTTON_PRESS and event.button == 3: # 3 == right click
+ x = int(event.x)
+ y = int(event.y)
+ time = event.time
+
+ if object == self.console:
+ self.consolePopup.popup(None, None, None, event.button, time)
+ else:
+ return False
+ else:
+ return False
+
+ def cb_oneshot_clicked (self, *args):
+ """
+ Mark a package as oneshot.
+ """
+ sel = self.queueList.get_selection()
+ store, it = sel.get_selected()
+ if it:
+ if self.queueTree.is_in_emerge(it) and self.queueTree.iter_has_parent(it):
+ package = store.get_value(it, 0)
+ set = (package not in self.queue.oneshotmerge)
+
+ self.queue.append(package, update = True, oneshot = set, forceUpdate = True)
+
+ def cb_pause_emerge (self, curr):
+ """
+ This method returns a callback for a "pause emerge" toggle button.
+ It is needed as there are different toggle buttons of this type and if one is clicked,
+ the others should be marked too.
+
+ @param curr: The button to return the callback for.
+ @type curr: gtk.ToggleButton
+ """
+ def pause (cb):
+ """
+ The actual callback.
+
+ Mark all other buttons too.
+
+ @param cb: The button which got toggled.
+ @type cb: gtk.ToggleButton
+ """
+
+ # pause or continue
+ self.emergePaused = cb.get_active()
+ if not self.emergePaused:
+ self.queue.continue_emerge()
+ #self.tray.set_from_file(APP_ICON)
+ else:
+ self.queue.stop_emerge()
+ #self.tray.set_from_file(os.path.join(ICON_DIR, "pausing.png"))
+
+ # block the handlers of the other buttons
+ # so that calling "set_active" does not call this callback recursivly
+ for v in self.pauseItems.itervalues():
+ v[0].handler_block(v[1])
+
+ # mark the others
+ for k, v in self.pauseItems.iteritems():
+ if k != curr:
+ v[0].set_active(self.emergePaused)
+
+ # unblock
+ for v in self.pauseItems.itervalues():
+ v[0].handler_unblock(v[1])
+
+ return False
+ return pause
+
+ def cb_kill_clicked (self, *args):
+ """
+ Kill emerge.
+ """
+ self.queue.kill_emerge()
+ if self.emergePaused: # unmark the "pause emerge" buttons
+ self.pauseItems["menu"][0].set_active(False) # calling one button is enough (see: cb_pause_emerge)
+
+ def cb_copy_clicked (self, *args):
+ """
+ Copy marked text in the terminal to clipboard.
+ """
+ self.console.copy_clipboard()
+
+ def cb_delete (self, *args):
+ """
+ Called when the user wants to quit the application.
+
+ Asks the user for confirmation if there is something in the queue.
+ Also saves session data.
+ """
+
+ self.__save_queue = False
+
+ if not self.queue.is_empty():
+ ret = queue_not_empty_dialog()
+ if ret == gtk.RESPONSE_CANCEL:
+ return True
+ else: # there is sth in queue AND the user still wants to close -> kill emerge
+ self.__save_queue = (ret == gtk.RESPONSE_YES)
+ self.queue.kill_emerge()
+
+ # write session
+ self.session.save()
+
+ return False
+
+ def cb_minimized (self, window, event):
+ """
+ User wants to minimize the window.
+ If it is possible to minimize to tray, it is done.
+ """
+
+ if self.tray and self.cfg.get_boolean("hideOnMinimize", "GUI"):
+ if event.changed_mask & gtk.gdk.WINDOW_STATE_ICONIFIED:
+ if event.new_window_state & gtk.gdk.WINDOW_STATE_ICONIFIED:
+ self.window.hide()
+ return True
+
+ return False
+
+ def cb_systray_activated (self, *args):
+ """
+ Systray was activated. Show or hide the window.
+ """
+ if self.window.iconify_initially:
+ self.window.deiconify()
+ self.window.show()
+ self.window.window.show()
+ else:
+ self.window.iconify()
+
+ def cb_close (self, *args):
+ """
+ "Close" menu entry called.
+ Emulate normal quitting.
+ """
+ if not self.cb_delete(): # do the checks
+ self.window.destroy()
+
+ def cb_destroy (self, *args):
+ """
+ Calls main_quit().
+ """
+ gtk.main_quit()
+
+ def main (self):
+ """
+ Main.
+ """
+ gobject.threads_init()
+ # now subthreads can run normally, but are not allowed to touch the GUI. If threads should change sth there - use gobject.idle_add().
+ # for more informations on threading and gtk: http://www.async.com.br/faq/pygtk/index.py?req=show&file=faq20.006.htp
+ plugin.hook("main")(gtk.main)()
diff --git a/portato/gui/windows/plugin.py b/portato/gui/windows/plugin.py
index a0694be..eccf302 100644
--- a/portato/gui/windows/plugin.py
+++ b/portato/gui/windows/plugin.py
@@ -21,161 +21,161 @@ from ...backend.exceptions import PackageNotFoundException, BlockedException
from ...helper import debug
class PluginWindow (AbstractDialog):
-
- statsStore = gtk.ListStore(str)
-
- for s in (_("Disabled"), _("Temporarily enabled"), _("Enabled"), _("Temporarily disabled")):
- statsStore.append([s])
-
- def __init__ (self, parent, plugins, queue = None):
- """Constructor.
-
- @param parent: the parent window
- @type parent: gtk.Window"""
-
- AbstractDialog.__init__(self, parent)
- self.plugins = plugins
- self.queue = queue
- self.changedPlugins = {}
- self.inst = []
- self.ninst = []
-
- 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)
-
- self.view = self.tree.get_widget("pluginList")
- self.store = gtk.ListStore(str)
-
- self.view.set_model(self.store)
-
- cell = gtk.CellRendererText()
- col = gtk.TreeViewColumn("Plugin", cell, markup = 0)
- self.view.append_column(col)
-
- 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 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])
-
- def cb_state_toggled (self, rb):
-
- plugin = self.get_actual()
-
- if plugin:
- state = self.buttons.index(rb)
-
- 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():
- plugin.status = val
-
- 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
+
+ statsStore = gtk.ListStore(str)
+
+ for s in (_("Disabled"), _("Temporarily enabled"), _("Enabled"), _("Temporarily disabled")):
+ statsStore.append([s])
+
+ def __init__ (self, parent, plugins, queue = None):
+ """Constructor.
+
+ @param parent: the parent window
+ @type parent: gtk.Window"""
+
+ AbstractDialog.__init__(self, parent)
+ self.plugins = plugins
+ self.queue = queue
+ self.changedPlugins = {}
+ self.inst = []
+ self.ninst = []
+
+ 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)
+
+ self.view = self.tree.get_widget("pluginList")
+ self.store = gtk.ListStore(str)
+
+ self.view.set_model(self.store)
+
+ cell = gtk.CellRendererText()
+ col = gtk.TreeViewColumn("Plugin", cell, markup = 0)
+ self.view.append_column(col)
+
+ 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 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])
+
+ def cb_state_toggled (self, rb):
+
+ plugin = self.get_actual()
+
+ if plugin:
+ state = self.buttons.index(rb)
+
+ 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():
+ plugin.status = val
+
+ 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
diff --git a/portato/gui/windows/preference.py b/portato/gui/windows/preference.py
index dba28b1..94d7ade 100644
--- a/portato/gui/windows/preference.py
+++ b/portato/gui/windows/preference.py
@@ -22,197 +22,197 @@ from ..utils import get_color
from ...helper import debug
class PreferenceWindow (AbstractDialog):
- """Window displaying some preferences."""
-
- # all checkboxes in the window
- # widget name -> option name
- checkboxes = {
- "collapseCatCheck" : ("collapseCats", "GUI"),
- "consoleUpdateCheck" : ("updateConsole", "GUI"),
- "debugCheck" : "debug",
- "deepCheck" : "deep",
- "newUseCheck" : "newuse",
- "maskPerVersionCheck" : "maskPerVersion",
- "minimizeCheck" : ("hideOnMinimize", "GUI"),
- "searchOnTypeCheck" : ("searchOnType", "GUI"),
- "showSlotsCheck" : ("showSlots", "GUI"),
- "systrayCheck" : ("showSystray", "GUI"),
- "testPerVersionCheck" : "keywordPerVersion",
- "titleUpdateCheck" : ("updateTitle", "GUI"),
- "usePerVersionCheck" : "usePerVersion"
- }
-
- # all edits in the window
- # widget name -> option name
- edits = {
- "maskFileEdit" : "maskFile",
- "testFileEdit" : "keywordFile",
- "useFileEdit" : "useFile",
- "syncCommandEdit" : "syncCommand",
- "browserEdit" : ("browserCmd", "GUI")
- }
-
- # 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, catmodel_fn):
- """Constructor.
-
- @param parent: parent window
- @type parent: gtk.Window
- @param cfg: configuration object
- @type cfg: gui_helper.Config
- @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)
- @param catmodel_fn: function to call to set the model of the cat list (collapsed/not collapsed)
- @type catmodel_fn: function()"""
-
- AbstractDialog.__init__(self, parent)
-
- # our config
- self.cfg = cfg
-
- # the setter functions
- self.console_fn = console_fn
- self.linkbtn_fn = linkbtn_fn
- self.tabpos_fn = tabpos_fn
- self.catmodel_fn = catmodel_fn
-
- # set the bg-color of the hint
- hintEB = self.tree.get_widget("hintEB")
- hintEB.modify_bg(gtk.STATE_NORMAL, get_color(self.cfg, "prefhint"))
-
- # the checkboxes
- for box, val in self.checkboxes.iteritems():
- if isinstance(val, tuple):
- self.tree.get_widget(box).\
- set_active(self.cfg.get_boolean(val[0], section = val[1]))
- else:
- self.tree.get_widget(box).\
- set_active(self.cfg.get_boolean(val))
-
- # the edits
- for edit, val in self.edits.iteritems():
- if isinstance(val,tuple):
- self.tree.get_widget(edit).\
- set_text(self.cfg.get(val[0], section = val[1]))
- else:
- self.tree.get_widget(edit).\
- set_text(self.cfg.get(val))
-
- # the set list
- self.setList = self.tree.get_widget("setList")
- if system.has_set_support():
- self.fill_setlist()
- self.tree.get_widget("setFrame").show()
-
- # the console font button
- self.consoleFontBtn = self.tree.get_widget("consoleFontBtn")
- self.consoleFontBtn.set_font_name(self.cfg.get("consolefont", section = "GUI"))
-
- # the console title length spin button
- self.titleLengthSpinBtn = self.tree.get_widget("titleLengthSpinBtn")
- self.titleLengthSpinBtn.set_value(int(self.cfg.get("titlelength", section = "GUI")))
-
- # 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 = "GUI"))-1)
- self.pkgTabCombo.set_active(int(self.cfg.get("packageTabPos", section = "GUI"))-1)
-
- self.window.show_all()
-
- def _save(self):
- """Sets all options in the Config-instance."""
-
- for box, val in self.checkboxes.iteritems():
- if isinstance(val, tuple):
- self.cfg.set_boolean(val[0], self.tree.get_widget(box).get_active(), section = val[1])
- else:
- self.cfg.set_boolean(val, self.tree.get_widget(box).get_active())
-
- for edit, val in self.edits.iteritems():
- if isinstance(val,tuple):
- self.cfg.set(val[0], self.tree.get_widget(edit).get_text(), section = val[1])
- else:
- self.cfg.set(val,self.tree.get_widget(edit).get_text())
-
- if system.has_set_support():
- self.cfg.set("updatesets", ", ".join(sorted(name for enabled, markup, descr, name in self.setList.get_model() if enabled)))
-
- font = self.consoleFontBtn.get_font_name()
- self.cfg.set("consolefont", font, section = "GUI")
- self.console_fn(font)
-
- self.cfg.set("titlelength", str(self.titleLengthSpinBtn.get_value_as_int()), section = "GUI")
-
- pkgPos = self.pkgTabCombo.get_active()+1
- sysPos = self.systemTabCombo.get_active()+1
-
- self.cfg.set("packageTabPos", str(pkgPos), section = "GUI")
- self.cfg.set("systemTabPos", str(sysPos), section = "GUI")
-
- self.tabpos_fn(map(self.tabpos.get, (pkgPos, sysPos)))
-
- self.linkbtn_fn(self.cfg.get("browserCmd", section="GUI"))
-
- self.catmodel_fn()
-
- def fill_setlist (self):
- store = gtk.ListStore(bool, str, str, str)
-
- enabled = [x.strip() for x in self.cfg.get("updatesets").split(",")]
-
- for set, descr in system.get_sets(description = True):
- store.append([set in enabled, "<i>%s</i>" % set, descr, set])
-
- tCell = gtk.CellRendererToggle()
- tCell.set_property("activatable", True)
- tCell.connect("toggled", self.cb_check_toggled) # emulate the normal toggle behavior ...
-
- sCell = gtk.CellRendererText()
-
- col = gtk.TreeViewColumn(_("Package Set"), tCell, active = 0)
- col.pack_start(sCell)
- col.add_attribute(sCell, "markup", 1)
- self.setList.append_column(col)
-
- self.setList.append_column(gtk.TreeViewColumn(_("Description"), sCell, text = 2))
-
- self.setList.set_model(store)
-
- def cb_ok_clicked(self, button):
- """Saves, writes to config-file and closes the window."""
- self._save()
- try:
- self.cfg.write()
- except IOError, e:
- io_ex_dialog(e)
-
- self.window.destroy()
+ """Window displaying some preferences."""
+
+ # all checkboxes in the window
+ # widget name -> option name
+ checkboxes = {
+ "collapseCatCheck" : ("collapseCats", "GUI"),
+ "consoleUpdateCheck" : ("updateConsole", "GUI"),
+ "debugCheck" : "debug",
+ "deepCheck" : "deep",
+ "newUseCheck" : "newuse",
+ "maskPerVersionCheck" : "maskPerVersion",
+ "minimizeCheck" : ("hideOnMinimize", "GUI"),
+ "searchOnTypeCheck" : ("searchOnType", "GUI"),
+ "showSlotsCheck" : ("showSlots", "GUI"),
+ "systrayCheck" : ("showSystray", "GUI"),
+ "testPerVersionCheck" : "keywordPerVersion",
+ "titleUpdateCheck" : ("updateTitle", "GUI"),
+ "usePerVersionCheck" : "usePerVersion"
+ }
+
+ # all edits in the window
+ # widget name -> option name
+ edits = {
+ "maskFileEdit" : "maskFile",
+ "testFileEdit" : "keywordFile",
+ "useFileEdit" : "useFile",
+ "syncCommandEdit" : "syncCommand",
+ "browserEdit" : ("browserCmd", "GUI")
+ }
+
+ # 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, catmodel_fn):
+ """Constructor.
+
+ @param parent: parent window
+ @type parent: gtk.Window
+ @param cfg: configuration object
+ @type cfg: gui_helper.Config
+ @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)
+ @param catmodel_fn: function to call to set the model of the cat list (collapsed/not collapsed)
+ @type catmodel_fn: function()"""
+
+ AbstractDialog.__init__(self, parent)
+
+ # our config
+ self.cfg = cfg
+
+ # the setter functions
+ self.console_fn = console_fn
+ self.linkbtn_fn = linkbtn_fn
+ self.tabpos_fn = tabpos_fn
+ self.catmodel_fn = catmodel_fn
+
+ # set the bg-color of the hint
+ hintEB = self.tree.get_widget("hintEB")
+ hintEB.modify_bg(gtk.STATE_NORMAL, get_color(self.cfg, "prefhint"))
+
+ # the checkboxes
+ for box, val in self.checkboxes.iteritems():
+ if isinstance(val, tuple):
+ self.tree.get_widget(box).\
+ set_active(self.cfg.get_boolean(val[0], section = val[1]))
+ else:
+ self.tree.get_widget(box).\
+ set_active(self.cfg.get_boolean(val))
+
+ # the edits
+ for edit, val in self.edits.iteritems():
+ if isinstance(val,tuple):
+ self.tree.get_widget(edit).\
+ set_text(self.cfg.get(val[0], section = val[1]))
+ else:
+ self.tree.get_widget(edit).\
+ set_text(self.cfg.get(val))
+
+ # the set list
+ self.setList = self.tree.get_widget("setList")
+ if system.has_set_support():
+ self.fill_setlist()
+ self.tree.get_widget("setFrame").show()
+
+ # the console font button
+ self.consoleFontBtn = self.tree.get_widget("consoleFontBtn")
+ self.consoleFontBtn.set_font_name(self.cfg.get("consolefont", section = "GUI"))
+
+ # the console title length spin button
+ self.titleLengthSpinBtn = self.tree.get_widget("titleLengthSpinBtn")
+ self.titleLengthSpinBtn.set_value(int(self.cfg.get("titlelength", section = "GUI")))
+
+ # 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 = "GUI"))-1)
+ self.pkgTabCombo.set_active(int(self.cfg.get("packageTabPos", section = "GUI"))-1)
+
+ self.window.show_all()
+
+ def _save(self):
+ """Sets all options in the Config-instance."""
+
+ for box, val in self.checkboxes.iteritems():
+ if isinstance(val, tuple):
+ self.cfg.set_boolean(val[0], self.tree.get_widget(box).get_active(), section = val[1])
+ else:
+ self.cfg.set_boolean(val, self.tree.get_widget(box).get_active())
+
+ for edit, val in self.edits.iteritems():
+ if isinstance(val,tuple):
+ self.cfg.set(val[0], self.tree.get_widget(edit).get_text(), section = val[1])
+ else:
+ self.cfg.set(val,self.tree.get_widget(edit).get_text())
+
+ if system.has_set_support():
+ self.cfg.set("updatesets", ", ".join(sorted(name for enabled, markup, descr, name in self.setList.get_model() if enabled)))
+
+ font = self.consoleFontBtn.get_font_name()
+ self.cfg.set("consolefont", font, section = "GUI")
+ self.console_fn(font)
+
+ self.cfg.set("titlelength", str(self.titleLengthSpinBtn.get_value_as_int()), section = "GUI")
+
+ pkgPos = self.pkgTabCombo.get_active()+1
+ sysPos = self.systemTabCombo.get_active()+1
+
+ self.cfg.set("packageTabPos", str(pkgPos), section = "GUI")
+ self.cfg.set("systemTabPos", str(sysPos), section = "GUI")
+
+ self.tabpos_fn(map(self.tabpos.get, (pkgPos, sysPos)))
+
+ self.linkbtn_fn(self.cfg.get("browserCmd", section="GUI"))
+
+ self.catmodel_fn()
+
+ def fill_setlist (self):
+ store = gtk.ListStore(bool, str, str, str)
+
+ enabled = [x.strip() for x in self.cfg.get("updatesets").split(",")]
+
+ for set, descr in system.get_sets(description = True):
+ store.append([set in enabled, "<i>%s</i>" % set, descr, set])
+
+ tCell = gtk.CellRendererToggle()
+ tCell.set_property("activatable", True)
+ tCell.connect("toggled", self.cb_check_toggled) # emulate the normal toggle behavior ...
+
+ sCell = gtk.CellRendererText()
+
+ col = gtk.TreeViewColumn(_("Package Set"), tCell, active = 0)
+ col.pack_start(sCell)
+ col.add_attribute(sCell, "markup", 1)
+ self.setList.append_column(col)
+
+ self.setList.append_column(gtk.TreeViewColumn(_("Description"), sCell, text = 2))
+
+ self.setList.set_model(store)
+
+ def cb_ok_clicked(self, button):
+ """Saves, writes to config-file and closes the window."""
+ self._save()
+ try:
+ self.cfg.write()
+ except IOError, e:
+ io_ex_dialog(e)
+
+ self.window.destroy()
- def cb_cancel_clicked (self, button):
- """Just closes - w/o saving."""
- self.window.destroy()
+ def cb_cancel_clicked (self, button):
+ """Just closes - w/o saving."""
+ self.window.destroy()
- def cb_check_toggled (self, cell, path):
- # for whatever reason we have to define normal toggle behavior explicitly
- store = self.setList.get_model()
- store[path][0] = not store[path][0]
- return True
+ def cb_check_toggled (self, cell, path):
+ # for whatever reason we have to define normal toggle behavior explicitly
+ store = self.setList.get_model()
+ store[path][0] = not store[path][0]
+ return True
diff --git a/portato/gui/windows/search.py b/portato/gui/windows/search.py
index e776dd1..415cbfe 100644
--- a/portato/gui/windows/search.py
+++ b/portato/gui/windows/search.py
@@ -17,59 +17,59 @@ from .basic import AbstractDialog
from ...helper import debug
class SearchWindow (AbstractDialog):
- """A window showing the results of a search process."""
-
- def __init__ (self, parent, list, jump_to):
- """Constructor.
+ """A window showing the results of a search process."""
+
+ def __init__ (self, parent, list, jump_to):
+ """Constructor.
- @param parent: parent-window
- @type parent: gtk.Window
- @param list: list of results to show
- @type list: string[]
- @param jump_to: function to call if "OK"-Button is hit
- @type jump_to: function(string)"""
-
- AbstractDialog.__init__(self, parent)
-
- self.jump_to = jump_to # function to call for jumping
- self.list = list
- self.list.sort()
-
- # combo box
- self.searchList = self.tree.get_widget("searchList")
- self.build_sort_list()
- self.searchList.get_selection().select_path(0)
+ @param parent: parent-window
+ @type parent: gtk.Window
+ @param list: list of results to show
+ @type list: string[]
+ @param jump_to: function to call if "OK"-Button is hit
+ @type jump_to: function(string)"""
+
+ AbstractDialog.__init__(self, parent)
+
+ self.jump_to = jump_to # function to call for jumping
+ self.list = list
+ self.list.sort()
+
+ # combo box
+ self.searchList = self.tree.get_widget("searchList")
+ self.build_sort_list()
+ self.searchList.get_selection().select_path(0)
- # finished --> show
- self.window.show_all()
+ # finished --> show
+ self.window.show_all()
- def build_sort_list (self):
- """Builds the sort list."""
-
- store = gtk.ListStore(str)
- self.searchList.set_model(store)
+ def build_sort_list (self):
+ """Builds the sort list."""
+
+ store = gtk.ListStore(str)
+ self.searchList.set_model(store)
- # build categories
- for p in self.list:
- store.append(["%s/<b>%s</b>" % tuple(p.split("/"))])
+ # build categories
+ for p in self.list:
+ store.append(["%s/<b>%s</b>" % tuple(p.split("/"))])
- cell = gtk.CellRendererText()
- col = gtk.TreeViewColumn(_("Results"), cell, markup = 0)
- self.searchList.append_column(col)
+ cell = gtk.CellRendererText()
+ col = gtk.TreeViewColumn(_("Results"), cell, markup = 0)
+ self.searchList.append_column(col)
- def ok (self, *args):
- self.jump()
- self.close()
-
- def jump (self, *args):
- model, iter = self.searchList.get_selection().get_selected()
- self.jump_to(self.list[model.get_path(iter)[0]])
+ def ok (self, *args):
+ self.jump()
+ self.close()
+
+ def jump (self, *args):
+ model, iter = self.searchList.get_selection().get_selected()
+ self.jump_to(self.list[model.get_path(iter)[0]])
- def cb_key_pressed_combo (self, widget, event):
- """Emulates a ok-button-click."""
- keyname = gtk.gdk.keyval_name(event.keyval)
- if keyname == "Return": # take it as an "OK" if Enter is pressed
- self.jump()
- return True
- else:
- return False
+ def cb_key_pressed_combo (self, widget, event):
+ """Emulates a ok-button-click."""
+ keyname = gtk.gdk.keyval_name(event.keyval)
+ if keyname == "Return": # take it as an "OK" if Enter is pressed
+ self.jump()
+ return True
+ else:
+ return False
diff --git a/portato/gui/windows/splash.py b/portato/gui/windows/splash.py
index df19a9b..c27f74f 100644
--- a/portato/gui/windows/splash.py
+++ b/portato/gui/windows/splash.py
@@ -18,33 +18,33 @@ from .basic import Window
from ...constants import VERSION, APP_ICON
class SplashScreen (Window):
-
- def __init__ (self, startStr = ""):
- Window.__init__(self)
-
- self.image = self.tree.get_widget("image")
- self.genLabel = self.tree.get_widget("generalLabel")
- self.descrLabel = self.tree.get_widget("descrLabel")
-
- self.image.set_from_file(APP_ICON)
- self.genLabel.set_label("<b><big>Portato %s ...</big></b>" % VERSION)
-
- self.set_descr(startStr)
-
- def set_descr (self, string):
- self.descrLabel.set_label(_("... is starting up: %s") % string)
- self.do_iteration()
-
- def do_iteration (self):
- while gtk.events_pending():
- gtk.main_iteration()
-
- def show (self):
- self.window.show_all()
- self.do_iteration()
-
- def hide (self):
- self.window.hide()
- self.do_iteration()
-
- __call__ = set_descr
+
+ def __init__ (self, startStr = ""):
+ Window.__init__(self)
+
+ self.image = self.tree.get_widget("image")
+ self.genLabel = self.tree.get_widget("generalLabel")
+ self.descrLabel = self.tree.get_widget("descrLabel")
+
+ self.image.set_from_file(APP_ICON)
+ self.genLabel.set_label("<b><big>Portato %s ...</big></b>" % VERSION)
+
+ self.set_descr(startStr)
+
+ def set_descr (self, string):
+ self.descrLabel.set_label(_("... is starting up: %s") % string)
+ self.do_iteration()
+
+ def do_iteration (self):
+ while gtk.events_pending():
+ gtk.main_iteration()
+
+ def show (self):
+ self.window.show_all()
+ self.do_iteration()
+
+ def hide (self):
+ self.window.hide()
+ self.do_iteration()
+
+ __call__ = set_descr
diff --git a/portato/gui/windows/update.py b/portato/gui/windows/update.py
index e369c49..297f666 100644
--- a/portato/gui/windows/update.py
+++ b/portato/gui/windows/update.py
@@ -21,97 +21,97 @@ from ...helper import debug
class UpdateWindow (AbstractDialog):
- def __init__ (self, parent, packages, queue, jump_to):
- AbstractDialog.__init__(self, parent)
-
- self.queue = queue
- self.jump = jump_to
-
- self.packages = system.sort_package_list(packages)
-
- self.build_list()
-
- self.window.show_all()
-
- def build_list (self):
-
- store = gtk.ListStore(bool, str)
- self.view = self.tree.get_widget("packageList")
- self.view.set_model(store)
-
- cell = gtk.CellRendererText()
- tCell = gtk.CellRendererToggle()
- tCell.set_property("activatable", True)
- tCell.connect("toggled", self.cb_check_toggled) # emulate the normal toggle behavior ...
-
- self.view.append_column(gtk.TreeViewColumn(_("Enabled"), tCell, active = 0))
- self.view.append_column(gtk.TreeViewColumn(_("Package"), cell, text = 1))
-
- for p in self.packages:
- store.append([False, p.get_cpv()])
-
- def cb_set_size (self, *args):
- """
- This callback is called shortly before drawing.
- It calculates the optimal size of the window.
- The optimum is defined as: as large as possible w/o scrollbars
- """
-
- bb = self.tree.get_widget("updateBB")
- vals = (self.view.get_vadjustment().upper+bb.size_request()[1]+10, # max size of list + size of BB + constant
- self.parent.get_size()[1]) # size of the parent -> maximum size
- debug("Size values for the list and for the parent: %d / %d", *vals)
- val = int(min(vals))
- debug("Minimum value: %d", val)
- self.window.set_geometry_hints(self.window, min_height = val)
-
- def cb_select_all_clicked (self, btn):
- model = self.view.get_model()
- iter = model.get_iter_first()
-
- while iter:
- model.set_value(iter, 0, True)
- iter = model.iter_next(iter)
-
- return True
-
- def cb_install_clicked (self, btn):
- model = self.view.get_model()
- iter = model.get_iter_first()
- if iter is None: return
-
- items = []
- while iter:
- if model.get_value(iter, 0):
- items.append(model.get_value(iter, 1))
- iter = model.iter_next(iter)
-
- for item in items:
- try:
- try:
- self.queue.append(item, type = "install", oneshot = True)
- except PackageNotFoundException, e:
- if unmask_dialog(e[0]) == gtk.RESPONSE_YES :
- self.queue.append(item, type = "install", unmask = True, oneshot = True)
-
- except BlockedException, e:
- blocked_dialog(e[0], e[1])
-
- self.close()
- return True
-
- def cb_package_selected (self, view):
- sel = view.get_selection()
- store, it = sel.get_selected()
- if it:
- package = system.new_package(store.get_value(it, 1))
-
- self.jump(package.get_cp(), package.get_version())
-
- return True
-
- def cb_check_toggled (self, cell, path):
- # for whatever reason we have to define normal toggle behavior explicitly
- store = self.view.get_model()
- store[path][0] = not store[path][0]
- return True
+ def __init__ (self, parent, packages, queue, jump_to):
+ AbstractDialog.__init__(self, parent)
+
+ self.queue = queue
+ self.jump = jump_to
+
+ self.packages = system.sort_package_list(packages)
+
+ self.build_list()
+
+ self.window.show_all()
+
+ def build_list (self):
+
+ store = gtk.ListStore(bool, str)
+ self.view = self.tree.get_widget("packageList")
+ self.view.set_model(store)
+
+ cell = gtk.CellRendererText()
+ tCell = gtk.CellRendererToggle()
+ tCell.set_property("activatable", True)
+ tCell.connect("toggled", self.cb_check_toggled) # emulate the normal toggle behavior ...
+
+ self.view.append_column(gtk.TreeViewColumn(_("Enabled"), tCell, active = 0))
+ self.view.append_column(gtk.TreeViewColumn(_("Package"), cell, text = 1))
+
+ for p in self.packages:
+ store.append([False, p.get_cpv()])
+
+ def cb_set_size (self, *args):
+ """
+ This callback is called shortly before drawing.
+ It calculates the optimal size of the window.
+ The optimum is defined as: as large as possible w/o scrollbars
+ """
+
+ bb = self.tree.get_widget("updateBB")
+ vals = (self.view.get_vadjustment().upper+bb.size_request()[1]+10, # max size of list + size of BB + constant
+ self.parent.get_size()[1]) # size of the parent -> maximum size
+ debug("Size values for the list and for the parent: %d / %d", *vals)
+ val = int(min(vals))
+ debug("Minimum value: %d", val)
+ self.window.set_geometry_hints(self.window, min_height = val)
+
+ def cb_select_all_clicked (self, btn):
+ model = self.view.get_model()
+ iter = model.get_iter_first()
+
+ while iter:
+ model.set_value(iter, 0, True)
+ iter = model.iter_next(iter)
+
+ return True
+
+ def cb_install_clicked (self, btn):
+ model = self.view.get_model()
+ iter = model.get_iter_first()
+ if iter is None: return
+
+ items = []
+ while iter:
+ if model.get_value(iter, 0):
+ items.append(model.get_value(iter, 1))
+ iter = model.iter_next(iter)
+
+ for item in items:
+ try:
+ try:
+ self.queue.append(item, type = "install", oneshot = True)
+ except PackageNotFoundException, e:
+ if unmask_dialog(e[0]) == gtk.RESPONSE_YES :
+ self.queue.append(item, type = "install", unmask = True, oneshot = True)
+
+ except BlockedException, e:
+ blocked_dialog(e[0], e[1])
+
+ self.close()
+ return True
+
+ def cb_package_selected (self, view):
+ sel = view.get_selection()
+ store, it = sel.get_selected()
+ if it:
+ package = system.new_package(store.get_value(it, 1))
+
+ self.jump(package.get_cp(), package.get_version())
+
+ return True
+
+ def cb_check_toggled (self, cell, path):
+ # for whatever reason we have to define normal toggle behavior explicitly
+ store = self.view.get_model()
+ store[path][0] = not store[path][0]
+ return True
diff --git a/portato/gui/wrapper.py b/portato/gui/wrapper.py
index 2c492d4..a160e2f 100644
--- a/portato/gui/wrapper.py
+++ b/portato/gui/wrapper.py
@@ -16,316 +16,316 @@ import vte
from ..helper import debug
class GtkTree (object):
- """The implementation of the abstract tree."""
-
- def __init__ (self, tree, col = 0):
- """Constructor.
-
- @param tree: original tree
- @type tree: gtk.TreeStore
- @param col: the column where the cpv is stored
- @type col: int"""
-
- self.tree = tree
- self.cpv_col = col
- self.emergeIt = None
- self.unmergeIt = None
- self.updateIt = None
-
- def build_append_value (self, cpv, oneshot = False, update = False, downgrade = False, version = None, useChange = []):
- """
- Builds the list, which is going to be passed to append.
-
- @param cpv: the cpv
- @type cpv: string (cpv)
- @param oneshot: True if oneshot
- @type oneshot: boolean
- @param update: True if this is an update
- @type update: boolean
- @param downgrade: True if this is a downgrade
- @type downgrade: boolean
- @param version: the version we update from
- @type version: string
- @param useChange: list of changed useflags; use "-use" for removed and "+use" for added flags
- @type useChange: string[]
-
- @returns: the created list
- @rtype: list
- """
-
- string = ""
-
- if oneshot:
- string += "<i>%s</i>" % _("oneshot")
-
- if update:
- if oneshot: string += "; "
- if version is not None:
- string += "<i>%s</i>" % (_("updating from version %s") % version)
- else:
- string += "<i>%s</i>" % _("updating")
-
- elif downgrade:
- if oneshot: string += "; "
- if version is not None:
- string += "<i>%s</i>" % (_("downgrading from version %s") % version)
- else:
- string += "<i>%s</i>" % _("downgrading")
-
- if useChange:
- if update or downgrade or oneshot: string += "; "
- string += "<i><b>%s </b></i>" % _("IUSE changes:")
- useChange.sort()
- string += "<i>%s</i>" % " ".join(useChange)
-
- return [cpv, string, False]
-
- def set_in_progress (self, it, to = True):
- """
- Marks the queue where the given iterator belongs as being in progress.
-
- @param it: one iterator of the queue to mark to
- @type it: Iterator
- @param to: whether to enable or disable
- @type to: boolean
- """
-
- iter = self.first_iter(it)
- if to:
- self.tree.set_value(iter, 1, "<b>%s</b>" % _("(In Progress)"))
- else:
- self.tree.set_value(iter, 1, "")
-
- self.tree.set_value(iter, 2, to)
-
- def is_in_progress (self, it):
- """
- Returns whether the queue where the given iterator belongs to, is marked as "being in progress".
-
- @param it: the iterator
- @type it: Iterator
- @returns: whether the queue is marked "in progress"
- @rtype: boolean
- """
- return self.tree.get_value(it, 2)
-
- def get_emerge_it (self):
- """
- Returns an iterator signaling the top of the emerge section.
-
- @returns: emerge-iterator
- @rtype: Iterator
- """
- if self.emergeIt is None:
- self.emergeIt = self.append(None, ["<b>%s</b>" % _("Install"), "", False])
- return self.emergeIt
-
- def get_unmerge_it (self):
- """
- Returns an iterator signaling the top of the unmerge section.
-
- @returns: unmerge-iterator
- @rtype: Iterator
- """
- if self.unmergeIt is None:
- self.unmergeIt = self.append(None, ["<b>%s</b>" % _("Uninstall"), "", False])
-
- return self.unmergeIt
-
- def get_update_it (self):
- """
- Returns an iterator signaling the top of the update section.
-
- @returns: unmerge-iterator
- @rtype: Iterator
- """
- if self.updateIt is None:
- self.updateIt = self.append(None, ["<b>%s</b>" % _("Update"), "", False])
-
- return self.updateIt
-
- def first_iter (self, it):
- """
- Returns the iterator at the top.
-
- @param it: the iterator
- @type it: Iterator
- @returns: the top iterator
- @rtype: Iterator
- """
- return self.tree.get_iter_from_string(self.tree.get_string_from_iter(it).split(":")[0])
-
- def is_in (self, it, in_it):
- return in_it and self.iter_equal(self.first_iter(it), in_it)
-
- def is_in_emerge (self, it):
- """
- Checks whether an iterator is part of the "Emerge" section.
-
- @param it: the iterator to check
- @type it: Iterator
- @returns: True if the iter is part; False otherwise
- @rtype: boolean
- """
- return self.is_in(it, self.emergeIt)
-
- def is_in_unmerge (self, it):
- """
- Checks whether an iterator is part of the "Unmerge" section.
-
- @param it: the iterator to check
- @type it: Iterator
- @returns: True if the iter is part; False otherwise
- @rtype: boolean
- """
- return self.is_in(it, self.unmergeIt)
-
- def is_in_update (self, it):
- """
- Checks whether an iterator is part of the "Update" section.
-
- @param it: the iterator to check
- @type it: Iterator
- @returns: True if the iter is part; False otherwise
- @rtype: boolean
- """
- return self.is_in(it, self.updateIt)
-
- def iter_has_parent (self, it):
- """
- Returns whether the actual iterator has a parent.
- @param it: the iterator
- @type it: Iterator
- @returns: True if it has a parent it, else False.
- @rtype: boolean
- """
- return (self.tree.iter_parent(it) != None)
-
- def parent_iter (self, it):
- """
- Returns the parent iter.
-
- @param it: the iterator
- @type it: Iterator
- @returns: Parent iterator or None if the current it has no parent.
- @rtype: Iterator; None
- """
- return self.tree.iter_parent(it)
-
- def first_child_iter (self, it):
- """
- Returns the first child iter.
-
- @param it: the iterator
- @type it: Iterator
- @returns: First child iterator or None if the current it has no children.
- @rtype: Iterator; None
- """
-
- return self.tree.iter_children(it)
-
- def iter_has_children (self, it):
- """
- Returns whether the actual iterator has children.
-
- @param it: the iterator
- @type it: Iterator
- @returns: True if it has children, else False.
- @rtype: boolean
- """
-
- return self.tree.iter_has_child(it)
-
- def next_iter (self, it):
- """
- Returns the next iter.
-
- @param it: the iterator
- @type it: Iterator
- @returns: Next iterator or None if the current iter is the last one.
- @rtype: Iterator; None
- """
- return self.tree.iter_next(it)
-
- def get_value (self, it, column):
- """
- Returns the value of the specific column at the given iterator.
-
- @param it: the iterator
- @type it: Iterator
- @param column: the column of the iterator from where to get the value
- @type column: int
- @returns: the value
- @rtype: anything
- """
-
- return self.tree.get_value(it, column)
-
- def iter_equal (self, it, other_it):
- """
- Checks whether to iterators are equal.
-
- @param it: the one iterator to compare
- @type it: Iterator
- @param other_it: the other iterator to compare
- @type other_it: Iterator
- @returns: True if both iterators are equal; False otherwise
- @rtype boolean
- """
- return self.tree.get_string_from_iter(it) == self.tree.get_string_from_iter(other_it)
-
- def append (self, parent = None, values = None):
- """
- Appends some values right after the given parent. If parent is None, it is appended as the first element.
-
- @param parent: the iterator to append the values right after; if None it symbolizes the top
- @type parent: Iterator
- @param values: a list of values which are going to be appended to the tree
- @type values: list
- @returns: Iterator pointing to the newly appended stuff
- @rtype: Iterator
- """
-
- return self.tree.append(parent, values)
-
- def remove (self, it):
- """
- Removes an iterator out of the tree.
- @attention: The iterator can point to anything hereafter. Do not reuse!
-
- @param it: iterator to remove
- @type it: Iterator
- """
-
- 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):
- """
- Returns the original tree-object.
-
- @returns: original tree-object
- @rtype: tree-object
- """
- return self.tree
-
- def get_cpv_column (self):
- """
- Returns the number of the column where the cpv's are stored.
-
- @returns: column with cpv's
- @rtype: int
- """
- return self.cpv_col
+ """The implementation of the abstract tree."""
+
+ def __init__ (self, tree, col = 0):
+ """Constructor.
+
+ @param tree: original tree
+ @type tree: gtk.TreeStore
+ @param col: the column where the cpv is stored
+ @type col: int"""
+
+ self.tree = tree
+ self.cpv_col = col
+ self.emergeIt = None
+ self.unmergeIt = None
+ self.updateIt = None
+
+ def build_append_value (self, cpv, oneshot = False, update = False, downgrade = False, version = None, useChange = []):
+ """
+ Builds the list, which is going to be passed to append.
+
+ @param cpv: the cpv
+ @type cpv: string (cpv)
+ @param oneshot: True if oneshot
+ @type oneshot: boolean
+ @param update: True if this is an update
+ @type update: boolean
+ @param downgrade: True if this is a downgrade
+ @type downgrade: boolean
+ @param version: the version we update from
+ @type version: string
+ @param useChange: list of changed useflags; use "-use" for removed and "+use" for added flags
+ @type useChange: string[]
+
+ @returns: the created list
+ @rtype: list
+ """
+
+ string = ""
+
+ if oneshot:
+ string += "<i>%s</i>" % _("oneshot")
+
+ if update:
+ if oneshot: string += "; "
+ if version is not None:
+ string += "<i>%s</i>" % (_("updating from version %s") % version)
+ else:
+ string += "<i>%s</i>" % _("updating")
+
+ elif downgrade:
+ if oneshot: string += "; "
+ if version is not None:
+ string += "<i>%s</i>" % (_("downgrading from version %s") % version)
+ else:
+ string += "<i>%s</i>" % _("downgrading")
+
+ if useChange:
+ if update or downgrade or oneshot: string += "; "
+ string += "<i><b>%s </b></i>" % _("IUSE changes:")
+ useChange.sort()
+ string += "<i>%s</i>" % " ".join(useChange)
+
+ return [cpv, string, False]
+
+ def set_in_progress (self, it, to = True):
+ """
+ Marks the queue where the given iterator belongs as being in progress.
+
+ @param it: one iterator of the queue to mark to
+ @type it: Iterator
+ @param to: whether to enable or disable
+ @type to: boolean
+ """
+
+ iter = self.first_iter(it)
+ if to:
+ self.tree.set_value(iter, 1, "<b>%s</b>" % _("(In Progress)"))
+ else:
+ self.tree.set_value(iter, 1, "")
+
+ self.tree.set_value(iter, 2, to)
+
+ def is_in_progress (self, it):
+ """
+ Returns whether the queue where the given iterator belongs to, is marked as "being in progress".
+
+ @param it: the iterator
+ @type it: Iterator
+ @returns: whether the queue is marked "in progress"
+ @rtype: boolean
+ """
+ return self.tree.get_value(it, 2)
+
+ def get_emerge_it (self):
+ """
+ Returns an iterator signaling the top of the emerge section.
+
+ @returns: emerge-iterator
+ @rtype: Iterator
+ """
+ if self.emergeIt is None:
+ self.emergeIt = self.append(None, ["<b>%s</b>" % _("Install"), "", False])
+ return self.emergeIt
+
+ def get_unmerge_it (self):
+ """
+ Returns an iterator signaling the top of the unmerge section.
+
+ @returns: unmerge-iterator
+ @rtype: Iterator
+ """
+ if self.unmergeIt is None:
+ self.unmergeIt = self.append(None, ["<b>%s</b>" % _("Uninstall"), "", False])
+
+ return self.unmergeIt
+
+ def get_update_it (self):
+ """
+ Returns an iterator signaling the top of the update section.
+
+ @returns: unmerge-iterator
+ @rtype: Iterator
+ """
+ if self.updateIt is None:
+ self.updateIt = self.append(None, ["<b>%s</b>" % _("Update"), "", False])
+
+ return self.updateIt
+
+ def first_iter (self, it):
+ """
+ Returns the iterator at the top.
+
+ @param it: the iterator
+ @type it: Iterator
+ @returns: the top iterator
+ @rtype: Iterator
+ """
+ return self.tree.get_iter_from_string(self.tree.get_string_from_iter(it).split(":")[0])
+
+ def is_in (self, it, in_it):
+ return in_it and self.iter_equal(self.first_iter(it), in_it)
+
+ def is_in_emerge (self, it):
+ """
+ Checks whether an iterator is part of the "Emerge" section.
+
+ @param it: the iterator to check
+ @type it: Iterator
+ @returns: True if the iter is part; False otherwise
+ @rtype: boolean
+ """
+ return self.is_in(it, self.emergeIt)
+
+ def is_in_unmerge (self, it):
+ """
+ Checks whether an iterator is part of the "Unmerge" section.
+
+ @param it: the iterator to check
+ @type it: Iterator
+ @returns: True if the iter is part; False otherwise
+ @rtype: boolean
+ """
+ return self.is_in(it, self.unmergeIt)
+
+ def is_in_update (self, it):
+ """
+ Checks whether an iterator is part of the "Update" section.
+
+ @param it: the iterator to check
+ @type it: Iterator
+ @returns: True if the iter is part; False otherwise
+ @rtype: boolean
+ """
+ return self.is_in(it, self.updateIt)
+
+ def iter_has_parent (self, it):
+ """
+ Returns whether the actual iterator has a parent.
+ @param it: the iterator
+ @type it: Iterator
+ @returns: True if it has a parent it, else False.
+ @rtype: boolean
+ """
+ return (self.tree.iter_parent(it) != None)
+
+ def parent_iter (self, it):
+ """
+ Returns the parent iter.
+
+ @param it: the iterator
+ @type it: Iterator
+ @returns: Parent iterator or None if the current it has no parent.
+ @rtype: Iterator; None
+ """
+ return self.tree.iter_parent(it)
+
+ def first_child_iter (self, it):
+ """
+ Returns the first child iter.
+
+ @param it: the iterator
+ @type it: Iterator
+ @returns: First child iterator or None if the current it has no children.
+ @rtype: Iterator; None
+ """
+
+ return self.tree.iter_children(it)
+
+ def iter_has_children (self, it):
+ """
+ Returns whether the actual iterator has children.
+
+ @param it: the iterator
+ @type it: Iterator
+ @returns: True if it has children, else False.
+ @rtype: boolean
+ """
+
+ return self.tree.iter_has_child(it)
+
+ def next_iter (self, it):
+ """
+ Returns the next iter.
+
+ @param it: the iterator
+ @type it: Iterator
+ @returns: Next iterator or None if the current iter is the last one.
+ @rtype: Iterator; None
+ """
+ return self.tree.iter_next(it)
+
+ def get_value (self, it, column):
+ """
+ Returns the value of the specific column at the given iterator.
+
+ @param it: the iterator
+ @type it: Iterator
+ @param column: the column of the iterator from where to get the value
+ @type column: int
+ @returns: the value
+ @rtype: anything
+ """
+
+ return self.tree.get_value(it, column)
+
+ def iter_equal (self, it, other_it):
+ """
+ Checks whether to iterators are equal.
+
+ @param it: the one iterator to compare
+ @type it: Iterator
+ @param other_it: the other iterator to compare
+ @type other_it: Iterator
+ @returns: True if both iterators are equal; False otherwise
+ @rtype boolean
+ """
+ return self.tree.get_string_from_iter(it) == self.tree.get_string_from_iter(other_it)
+
+ def append (self, parent = None, values = None):
+ """
+ Appends some values right after the given parent. If parent is None, it is appended as the first element.
+
+ @param parent: the iterator to append the values right after; if None it symbolizes the top
+ @type parent: Iterator
+ @param values: a list of values which are going to be appended to the tree
+ @type values: list
+ @returns: Iterator pointing to the newly appended stuff
+ @rtype: Iterator
+ """
+
+ return self.tree.append(parent, values)
+
+ def remove (self, it):
+ """
+ Removes an iterator out of the tree.
+ @attention: The iterator can point to anything hereafter. Do not reuse!
+
+ @param it: iterator to remove
+ @type it: Iterator
+ """
+
+ 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):
+ """
+ Returns the original tree-object.
+
+ @returns: original tree-object
+ @rtype: tree-object
+ """
+ return self.tree
+
+ def get_cpv_column (self):
+ """
+ Returns the number of the column where the cpv's are stored.
+
+ @returns: column with cpv's
+ @rtype: int
+ """
+ return self.cpv_col
class GtkConsole (vte.Terminal):
- """The implementation of the abstract Console for GTK."""
-
- def reset (self):
- """
- Resets the terminal.
- """
- vte.Terminal.reset(self, True, True)
+ """The implementation of the abstract Console for GTK."""
+
+ def reset (self):
+ """
+ Resets the terminal.
+ """
+ vte.Terminal.reset(self, True, True)