From 3384091af579dbafdc366753cf846e3e63c61f7b Mon Sep 17 00:00:00 2001 From: necoro <> Date: Fri, 27 Oct 2006 13:58:52 +0000 Subject: Moved gtk-specific stuff to an extra subdir to make it more flexible for qt --- geneticone/backend/package.py | 3 +- geneticone/gui/__init__.py | 4 +- geneticone/gui/dialogs.py | 55 --- geneticone/gui/gtk/__init__.py | 13 + geneticone/gui/gtk/dialogs.py | 56 +++ geneticone/gui/gtk/windows.py | 1033 ++++++++++++++++++++++++++++++++++++++++ geneticone/gui/gui_helper.py | 54 +-- geneticone/gui/windows.py | 1022 --------------------------------------- 8 files changed, 1130 insertions(+), 1110 deletions(-) delete mode 100644 geneticone/gui/dialogs.py create mode 100644 geneticone/gui/gtk/__init__.py create mode 100644 geneticone/gui/gtk/dialogs.py create mode 100644 geneticone/gui/gtk/windows.py delete mode 100644 geneticone/gui/windows.py (limited to 'geneticone') diff --git a/geneticone/backend/package.py b/geneticone/backend/package.py index edc3da1..d628a56 100644 --- a/geneticone/backend/package.py +++ b/geneticone/backend/package.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # # File: geneticone/backend/package.py # This file is part of the Genetic/One-Project, a graphical portage-frontend. @@ -275,7 +276,7 @@ class Package (gentoolkit.Package): if dep[0] == '!': # blocking sth blocked = find_installed_packages(dep[1:]) if blocked != []: - raise BlockedException, blocked[0].get_cpv() + raise BlockedException, (self.get_cpv(), blocked[0].get_cpv()) else: # next flag continue diff --git a/geneticone/gui/__init__.py b/geneticone/gui/__init__.py index d5e75c3..25123c8 100644 --- a/geneticone/gui/__init__.py +++ b/geneticone/gui/__init__.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # # File: geneticone/gui/__init__.py # This file is part of the Genetic/One-Project, a graphical portage-frontend. @@ -9,4 +10,5 @@ # # Written by René 'Necoro' Neumann -from windows import * +import gtk +from gtk import * diff --git a/geneticone/gui/dialogs.py b/geneticone/gui/dialogs.py deleted file mode 100644 index 4de66f1..0000000 --- a/geneticone/gui/dialogs.py +++ /dev/null @@ -1,55 +0,0 @@ -# -# File: geneticone/gui/dialogs.py -# This file is part of the Genetic/One-Project, a graphical portage-frontend. -# -# Copyright (C) 2006 René 'Necoro' Neumann -# This is free software. You may redistribute copies of it under the terms of -# the GNU General Public License version 2. -# There is NO WARRANTY, to the extent permitted by law. -# -# Written by René 'Necoro' Neumann - -import gtk - -def blocked_dialog (blocked, blocks): - dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, blocked+" is blocked by "+blocks+".\nPlease unmerge the blocking package.") - dialog.run() - dialog.destroy() - -def not_root_dialog (): - errorMB = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, "You cannot (un)merge without being root.") - errorMB.run() - errorMB.destroy() - -def masked_dialog (cpv): - dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, cpv+" seems to be masked.\nPlease edit the appropriate file(s) to unmask it and restart Genetic/One.\n") - dialog.run() - dialog.destroy() - -def unmask_dialog (cpv): - dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, cpv+" seems to be masked.\nDo you want to unmask it and its dependencies?.\n") - 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!") - dialog.run() - dialog.destroy() - -def changed_flags_dialog (what = "flags"): - hintMB = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, - "You have changed %s. Genetic/One will write these changes into the appropriate files. Please backup them if you think it is necessairy." % what) - hintMB.run() - hintMB.destroy() - -def remove_deps_dialog (): - infoMB = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, "You cannot remove dependencies. :)") - infoMB.run() - infoMB.destroy() - -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 diff --git a/geneticone/gui/gtk/__init__.py b/geneticone/gui/gtk/__init__.py new file mode 100644 index 0000000..e58319a --- /dev/null +++ b/geneticone/gui/gtk/__init__.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +# +# File: geneticone/gui/__init__.py +# This file is part of the Genetic/One-Project, a graphical portage-frontend. +# +# Copyright (C) 2006 René 'Necoro' Neumann +# This is free software. You may redistribute copies of it under the terms of +# the GNU General Public License version 2. +# There is NO WARRANTY, to the extent permitted by law. +# +# Written by René 'Necoro' Neumann + +from windows import MainWindow diff --git a/geneticone/gui/gtk/dialogs.py b/geneticone/gui/gtk/dialogs.py new file mode 100644 index 0000000..92b3c7f --- /dev/null +++ b/geneticone/gui/gtk/dialogs.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +# +# File: geneticone/gui/dialogs.py +# This file is part of the Genetic/One-Project, a graphical portage-frontend. +# +# Copyright (C) 2006 René 'Necoro' Neumann +# This is free software. You may redistribute copies of it under the terms of +# the GNU General Public License version 2. +# There is NO WARRANTY, to the extent permitted by law. +# +# Written by René 'Necoro' Neumann + +import gtk + +def blocked_dialog (blocked, blocks): + dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, blocked+" is blocked by "+blocks+".\nPlease unmerge the blocking package.") + dialog.run() + dialog.destroy() + +def not_root_dialog (): + errorMB = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, "You cannot (un)merge without being root.") + errorMB.run() + errorMB.destroy() + +def masked_dialog (cpv): + dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, cpv+" seems to be masked.\nPlease edit the appropriate file(s) to unmask it and restart Genetic/One.\n") + dialog.run() + dialog.destroy() + +def unmask_dialog (cpv): + dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, cpv+" seems to be masked.\nDo you want to unmask it and its dependencies?.\n") + 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!") + dialog.run() + dialog.destroy() + +def changed_flags_dialog (what = "flags"): + hintMB = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, + "You have changed %s. Genetic/One will write these changes into the appropriate files. Please backup them if you think it is necessairy." % what) + hintMB.run() + hintMB.destroy() + +def remove_deps_dialog (): + infoMB = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, "You cannot remove dependencies. :)") + infoMB.run() + infoMB.destroy() + +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 diff --git a/geneticone/gui/gtk/windows.py b/geneticone/gui/gtk/windows.py new file mode 100644 index 0000000..0277e51 --- /dev/null +++ b/geneticone/gui/gtk/windows.py @@ -0,0 +1,1033 @@ +# -*- coding: utf-8 -*- +# +# File: geneticone/gui/windows.py +# This file is part of the Genetic/One-Project, a graphical portage-frontend. +# +# Copyright (C) 2006 René 'Necoro' Neumann +# This is free software. You may redistribute copies of it under the terms of +# the GNU General Public License version 2. +# There is NO WARRANTY, to the extent permitted by law. +# +# Written by René 'Necoro' Neumann + +VERSION = "0.4.5" +CONFIG_LOCATION = "/etc/geneticone/geneticone.cfg" + +# gtk stuff +import pygtk +pygtk.require("2.0") +import gtk +import gobject + +#our backend stuff +from geneticone.helper import * +from geneticone import backend +from geneticone.backend import flags +from geneticone.backend.exceptions import * + +# more GUI stuff +from geneticone.gui.gui_helper import Database, Config, EmergeQueue +from dialogs import * + +# for the terminal +import vte + +# other +from portage_util import unique_array + +class AbstractDialog: + """A class all our dialogs get derived from. It sets useful default vars and automatically handles the ESC-Button.""" + + def __init__ (self, parent, title): + """Constructor. + + @param parent: the parent window + @type parent: gtk.Window + @param title: the title of the window + @type title: string""" + + # create new + self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) + + # set title + self.window.set_title(title) + + # set modal and transient for the parent --> you have to close this one to get back to the parent + self.window.set_modal(True) + self.window.set_transient_for(parent) + self.window.set_destroy_with_parent(True) + + # not resizable + self.window.set_resizable(False) + + # default size = (1,1) ==> as small as possible + self.window.set_default_size(1,1) + + # 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.window.destroy() + return True + else: + return False + +class AboutWindow (AbstractDialog): + """A window showing the "about"-informations.""" + + def __init__ (self, parent): + """Constructor. + + @param parent: the parent window + @type parent: gtk.Window""" + + AbstractDialog.__init__(self, parent, "About Genetic/One") + + box = gtk.VBox(False) + self.window.add(box) + + # about label + label = gtk.Label() + label.set_justify(gtk.JUSTIFY_CENTER) + label.set_markup(""" +Genetic/One v.%s +A Portage-GUI + +This software is licensed under the terms of the GPLv2. +Copyright (C) 2006 René 'Necoro' Neumann <necoro@necoro.net> + +Thanks to Fred for support and ideas :P +""" % VERSION) + box.pack_start(label) + + # button + okBtn = gtk.Button("OK") + okBtn.connect("clicked", lambda x: self.window.destroy()) + box.pack_start(okBtn) + + # finished -> show + self.window.show_all() + +class SearchWindow (AbstractDialog): + """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, "Search results") + + self.list = list # list to show + self.jump_to = jump_to # function to call for jumping + + box = gtk.HBox(False) + self.window.add(box) + + # combo box + self.combo = gtk.combo_box_new_text() + for x in list: + self.combo.append_text(x) + self.combo.set_active(0) # first item + self.combo.connect("key-press-event", self.cb_key_pressed_combo) + + box.pack_start(self.combo) + + # ok-button + okBtn = gtk.Button("OK") + okBtn.connect("clicked", self.cb_ok_btn_clicked) + box.pack_start(okBtn) + + # finished --> show + self.window.show_all() + + def cb_ok_btn_clicked (self, button): + """Called if the OK-Button is clicked. + Calls self.jump_to(selected_entry) and closes the window.""" + self.window.destroy() + self.jump_to(self.list[self.combo.get_active()]) + return True + + 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.cb_ok_btn_clicked(widget) + return True + else: + return False + +class PreferenceWindow (AbstractDialog): + """Window displaying some preferences.""" + + def __init__ (self, parent, cfg): + """Constructor. + + @param parent: parent window + @type parent: gtk.Window + @param cfg: configuration object + @type cfg: gui_helper.Config""" + + AbstractDialog.__init__(self, parent, "Preferences") + self.window.set_resizable(True) # override the default of the AbstractDialog + + # our config + self.cfg = cfg + + box = gtk.VBox() + box.set_spacing(5) + + self.window.add(box) + + # En-/Disable Debugging + self.debugCb = self.draw_cb(box, "Debugging modus", "debug_opt") + + # --deep + self.deepCb = self.draw_cb(box, "--deep", "deep_opt") + + # --newuse + #self.newuseCb = self.draw_cb(box, "--newuse", "newuse_opt") + + pHolderLabel = gtk.Label("""For the following options, you might use these placeholders: +$(cat) = category +$(pkg) = package-name +$(cat-1)/$(cat-2) = first/second part of the category""") + pHolderLabel.set_use_markup(True) + pHolderLabel.set_alignment(0,0) + box.pack_start(pHolderLabel) + + # The use/mask/keywording checkboxes and edits + self.usePerVersionCb, self.useFileEdit = self.draw_cb_and_edit(box, "package.use", "usePerVersion_opt", "useFile_opt") + self.maskPerVersionCb, self.maskFileEdit = self.draw_cb_and_edit(box, "package.mask/package.unmask", "maskPerVersion_opt", "maskFile_opt") + self.testPerVersionCb, self.testFileEdit = self.draw_cb_and_edit(box, "package.keywords", "testingPerVersion_opt", "testingFile_opt") + # buttons + buttonHB = gtk.HButtonBox() + buttonHB.set_layout(gtk.BUTTONBOX_SPREAD) + + okBtn = gtk.Button("_OK") + cancelBtn = gtk.Button("_Cancel") + okBtn.connect("clicked", self.cb_ok_clicked) + cancelBtn.connect("clicked", lambda x: self.window.destroy()) + buttonHB.pack_start(okBtn) + buttonHB.pack_start(cancelBtn) + + box.pack_start(buttonHB, True, True, 5) + + # finished --> show all + self.window.show_all() + + def draw_cb_and_edit (self, box, string, cb_opt, edit_opt): + """Draws a checkbox and an edit-field. + + @param box: box to place the both things into + @type box: gtk.Box + @param string: string to show + @type string: string + @param cb_opt: the option string for the Config.const-dict + @type cb_opt: string + @param edit_opt: the option string for the Config.const-dic + @type edit_opt: string + + @return: the checkbox and the edit-field + @rtype: (gtk.CheckButton, gtk.Edit)""" + + # check-button + cb = self.draw_cb(box, label=("Add to %s on a per-version-base" % string), opt = cb_opt) + + # edit with label + hBox = gtk.HBox() + label = gtk.Label("File name to use if %s is a directory:" % string) + edit = gtk.Entry() + edit.set_text(self.cfg.get(self.cfg.const[edit_opt])) + hBox.pack_start(label, False) + hBox.pack_start(edit, True, True, 5) + box.pack_start(hBox, True, True) + + return (cb, edit) + + def draw_cb (self, box, label, opt): + """Draws a checkbox. + + @param box: box to place the cb into + @type box: gtk.Box + @param label: Label to show + @type label: string + @param opt: the option string for the Config.const-dict + @type opt: string + @returns: the checkbox + @rtype: gtk.CheckButton""" + + cb = gtk.CheckButton(label=label) + cb.set_active(self.cfg.get_boolean(self.cfg.const[opt])) + box.pack_start(cb, True, True) + + return cb + + def _save(self): + """Sets all options in the Config-instance.""" + self.cfg.set(self.cfg.const["usePerVersion_opt"], str(self.usePerVersionCb.get_active())) + self.cfg.set(self.cfg.const["useFile_opt"], self.useFileEdit.get_text()) + self.cfg.set(self.cfg.const["maskPerVersion_opt"], str(self.maskPerVersionCb.get_active())) + self.cfg.set(self.cfg.const["maskFile_opt"], self.maskFileEdit.get_text()) + self.cfg.set(self.cfg.const["testingPerVersion_opt"], str(self.testPerVersionCb.get_active())) + self.cfg.set(self.cfg.const["testingFile_opt"], self.testFileEdit.get_text()) + self.cfg.set(self.cfg.const["debug_opt"], str(self.debugCb.get_active())) + self.cfg.set(self.cfg.const["deep_opt"], str(self.deepCb.get_active())) + #self.cfg.set(self.cfg.const["newuse_opt"], str(self.newuseCb.get_active())) + + def cb_ok_clicked(self, button): + """Saves, writes to config-file and closes the window.""" + self._save() + self.cfg.write() + self.window.destroy() + +class PackageWindow (AbstractDialog): + """A window with data about a specfic package.""" + + def __init__ (self, parent, cp, queue = None, version = None, delOnClose = True, doEmerge = True): + """Build up window contents.""" + AbstractDialog.__init__(self, parent, cp) + + self.cp = cp # category/package + self.version = version # version - if not None this is used + self.queue = queue + self.delOnClose = delOnClose + self.doEmerge = doEmerge + self.flagChanged = False + + # packages and installed packages + self.packages = backend.sort_package_list(backend.get_all_versions(cp)) + self.instPackages = backend.sort_package_list(backend.get_all_installed_versions(cp)) + + # main structure - the table + self.table = gtk.Table(rows=4,columns=2) + self.window.add(self.table) + + # version-combo-box + self.vCombo = self.build_vers_combo() + self.table.attach(self.vCombo, 0, 1, 1, 2, yoptions = gtk.FILL) + if not self.doEmerge: self.vCombo.set_sensitive(False) + + # the label (must be here, because it depends on the combo box) + desc = self.actual_package().get_env_var("DESCRIPTION") + if not desc: + desc = "" + use_markup = False + else: + desc = ""+desc+"" + use_markup = True + self.descLabel = gtk.Label(desc) + self.descLabel.set_line_wrap(True) + self.descLabel.set_justify(gtk.JUSTIFY_CENTER) + self.descLabel.set_use_markup(use_markup) + self.table.attach(self.descLabel, 0, 2, 0, 1, xoptions = gtk.FILL, ypadding = 10) + + # the check boxes + checkHB = gtk.HBox (True, 1) + self.table.attach(checkHB, 1, 2, 1, 2, yoptions = gtk.FILL) + + self.installedCheck = gtk.CheckButton() + self.installedCheck.connect("button-press-event", self.cb_button_pressed) + self.installedCheck.set_label("Installed") + self.installedCheck.set_no_show_all(True) + checkHB.pack_start(self.installedCheck, True, False) + + self.maskedCheck = gtk.CheckButton() + self.maskedCheck.connect("toggled", self.cb_masked_toggled) + self.maskedCheck.set_label("Masked") + self.maskedCheck.set_no_show_all(True) + checkHB.pack_start(self.maskedCheck, True, False) + + self.testingCheck = gtk.CheckButton() + self.testingCheck.connect("toggled", self.cb_testing_toggled) + self.testingCheck.set_label("Testing") + self.testingCheck.set_no_show_all(True) + checkHB.pack_start(self.testingCheck, True, False) + + self.missing_label = gtk.Label("MISSING KEYWORD") + self.missing_label.set_use_markup(True) + self.missing_label.set_no_show_all(True) + self.table.attach(self.missing_label, 1, 2, 1, 2, yoptions = gtk.FILL) + + self.not_in_sys_label = gtk.Label("Installed, but not in portage anymore") + self.not_in_sys_label.set_use_markup(True) + self.not_in_sys_label.set_no_show_all(True) + self.table.attach(self.not_in_sys_label, 1, 2, 1, 2, yoptions = gtk.FILL) + + # use list + self.useList = self.build_use_list() + self.useListScroll = gtk.ScrolledWindow() + self.useListScroll.add(self.useList) + self.useListScroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_NEVER) # XXX: make this work correctly + self.table.attach(self.useListScroll, 0, 2, 2, 3, ypadding = 10) + + # buttons + buttonHB = gtk.HButtonBox() + buttonHB.set_layout(gtk.BUTTONBOX_SPREAD) + self.table.attach(buttonHB, 0, 2, 3, 4) + + self.emergeBtn = gtk.Button("_Emerge") + self.unmergeBtn = gtk.Button("_Unmerge") + if not self.queue or not self.doEmerge: + self.emergeBtn.set_sensitive(False) + self.unmergeBtn.set_sensitive(False) + self.cancelBtn = gtk.Button("_Cancel") + if not self.delOnClose: + self.cancelBtn.set_label("_Close") + self.cancelBtn.connect("clicked", self.cb_cancel_clicked) + self.emergeBtn.connect("clicked", self.cb_emerge_clicked) + self.unmergeBtn.connect("clicked", self.cb_unmerge_clicked) + buttonHB.pack_start(self.emergeBtn) + buttonHB.pack_start(self.unmergeBtn) + buttonHB.pack_start(self.cancelBtn) + + # current status + self.cb_combo_changed(self.vCombo) + + # show + self.window.show_all() + + def fill_use_list(self, store): + pkg = self.actual_package() + pkg_flags = pkg.get_all_use_flags() + pkg_flags.sort() + for use in pkg_flags: + if pkg.is_installed() and use in pkg.get_actual_use_flags(): # flags set during install + enabled = True + elif (not pkg.is_installed()) and use in pkg.get_settings("USE").split() and not flags.invert_use_flag(use) in pkg.get_new_use_flags(): # flags that would be set + enabled = True + elif use in pkg.get_new_use_flags(): + enabled = True + else: + enabled = False + store.append([enabled, use, backend.get_use_desc(use, self.cp)]) + + return store + + def build_use_list (self): + """Builds the useList.""" + store = gtk.ListStore(bool, str, str) + self.fill_use_list(store) + + # build view + view = gtk.TreeView(store) + cell = gtk.CellRendererText() + tCell = gtk.CellRendererToggle() + tCell.set_property("activatable", True) + tCell.connect("toggled", self.cb_use_flag_toggled, store) + view.append_column(gtk.TreeViewColumn("Enabled", tCell, active = 0)) + view.append_column(gtk.TreeViewColumn("Flags", cell, text = 1)) + view.append_column(gtk.TreeViewColumn("Description", cell, text = 2)) + + if store.iter_n_children(None) == 0: # if there are no nodes in the list ... + view.set_child_visible(False) # ... do not show the list + else: + view.set_child_visible(True) + return view + + def build_vers_combo (self): + """Creates the combo box with the different versions.""" + combo = gtk.combo_box_new_text() + + # append versions + for s in [x.get_version() for x in self.packages]: + combo.append_text(s) + + # activate the first one + try: + best_version = "" + if self.version: + best_version = self.version + else: + best_version = backend.find_best_match(self.packages[0].get_cp(), (self.instPackages != [])).get_version() + for i in range(len(self.packages)): + if self.packages[i].get_version() == best_version: + combo.set_active(i) + break + except AttributeError: # no package found + debug('catched AttributeError => no "best package" found. Selected first one.') + combo.set_active(0) + + combo.connect("changed", self.cb_combo_changed) + + return combo + + def actual_package (self): + """Returns the actual package (a backend.Package-object).""" + return self.packages[self.vCombo.get_active()] + + def cb_combo_changed (self, combo, data = None): + """Callback for the changed ComboBox. + It then rebuilds the useList and the checkboxes.""" + + # remove old useList + self.useListScroll.remove(self.useList) + + # build new + self.useList = self.build_use_list() + self.useListScroll.add(self.useList) + pkg = self.actual_package() + + if (not pkg.is_in_system()) or pkg.is_missing_keyword(): + if not pkg.is_in_system(): + self.missing_label.hide() + self.not_in_sys_label.show() + else: # missing keyword + self.missing_label.show() + self.not_in_sys_label.hide() + + self.installedCheck.hide() + self.maskedCheck.hide() + self.testingCheck.hide() + self.emergeBtn.set_sensitive(False) + else: + self.missing_label.hide() + self.not_in_sys_label.hide() + self.installedCheck.show() + self.maskedCheck.show() + self.testingCheck.show() + if self.doEmerge: + self.emergeBtn.set_sensitive(True) + self.installedCheck.set_active(pkg.is_installed()) + self.maskedCheck.set_active(pkg.is_masked()) + if pkg.is_testing(allowed = False) and not pkg.is_testing(allowed=True): + self.testingCheck.set_label("(Testing)") + self.testingCheck.get_child().set_use_markup(True) + else: + self.testingCheck.set_label("Testing") + self.testingCheck.set_active(pkg.is_testing(allowed = False)) + + if self.doEmerge: + # set emerge-button-label + if not self.actual_package().is_installed(): + self.emergeBtn.set_label("_Emerge") + self.unmergeBtn.set_sensitive(False) + else: + self.emergeBtn.set_label("R_emerge") + self.unmergeBtn.set_sensitive(True) + + # refresh - make window as small as possible + self.table.show_all() + self.window.resize(1,1) + return True + + def cb_button_pressed (self, b, event, data = None): + """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_cancel_clicked (self, button, data = None): + if self.delOnClose: + self.actual_package().remove_new_use_flags() + self.actual_package().remove_new_masked() + self.actual_package().remove_new_testing() + elif self.flagChanged: + if self.queue: + try: + try: + self.queue.append(self.actual_package().get_cpv(), update = True) + except backend.PackageNotFoundException, e: + if unmask_dialog(e[0]) == gtk.RESPONSE_YES: + self.queue.append(self.actual_package().get_cpv(), update = True, unmask = True) + except backend.BlockedException, e: + blocked_dialog(e[0], e[1]) + + self.window.destroy() + return True + + def cb_emerge_clicked (self, button, data = None): + """Adds the package to the EmergeQueue.""" + if not am_i_root(): + not_root_dialog() + else: + try: + try: + self.queue.append(self.actual_package().get_cpv(), unmerge = False) + self.window.destroy() + except backend.PackageNotFoundException, e: + if unmask_dialog(e[0]) == gtk.RESPONSE_YES: + self.queue.append(self.actual_package().get_cpv(), unmerge = False, unmask = True) + self.window.destroy() + except BlockedException, e: + blocked_dialog(e[0], e[1]) + return True + + def cb_unmerge_clicked (self, button, data = None): + """Adds the package to the UnmergeQueue.""" + if not am_i_root(): + not_root_dialog() + else: + try: + self.queue.append(self.actual_package().get_cpv(), unmerge = True) + except backend.PackageNotFoundException, e: + masked_dialog(e[0]) + + self.window.destroy() + return True + + def cb_testing_toggled (self, button): + status = button.get_active() + + if self.actual_package().is_testing(allowed = False) == status: + return False + + if not self.actual_package().is_testing(allowed = True): + self.actual_package().set_testing(False) + button.set_label("Testing") + button.set_active(True) + else: + self.actual_package().set_testing(True) + if self.actual_package().is_testing(allowed=False): + button.set_label("(Testing)") + button.get_child().set_use_markup(True) + button.set_active(True) + self.flagChanged = True + return True + + def cb_masked_toggled (self, button): + status = button.get_active() + self.actual_package().set_masked(status) + self.flagChanged = True + return True + + def cb_use_flag_toggled (self, cell, path, store, data = None): + store[path][0] = not store[path][0] + prefix = "" + if not store[path][0]: + prefix = "-" + self.actual_package().set_use_flag(prefix+store[path][1]) + self.flagChanged = True + return True + +class MainWindow: + """Application main window.""" + + def __init__ (self): + """Build up window""" + # window + self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) + self.window.set_title(("Genetic/One (%s)" % VERSION)) + self.window.connect("destroy", self.cb_destroy) + self.window.set_border_width(2) + self.window.set_resizable(True) + + mHeight = 800 + if gtk.gdk.screen_height() <= 800: mHeight = 600 + self.window.set_geometry_hints (self.window, min_width = 600, min_height = mHeight, max_height = gtk.gdk.screen_height(), max_width = gtk.gdk.screen_width()) + + # booleans + self.doUpdate = False + + # package db + self.db = Database() + self.db.populate() + + # config + self.cfg = Config(CONFIG_LOCATION) + self.cfg.modify_external_configs() + + # actions needed + self.emergeAction = gtk.Action("Emerge", "_Emerge", None, None) + self.emergeAction.connect("activate", self.cb_emerge_clicked) + self.unmergeAction = gtk.Action("Unmerge", "_Unmerge", None, None) + self.unmergeAction.connect("activate", self.cb_emerge_clicked) + self.updateAction = gtk.Action("UpdateWorld", "Update _World", None, None) + self.updateAction.connect("activate", self.cb_update_clicked) + + # main vb + vb = gtk.VBox(False, 1) + self.window.add(vb) + + # menus + self.uimanager = self.create_uimanager() + self.queuePopup = self.uimanager.get_widget("/popupQueue") + menubar = self.uimanager.get_widget("/bar") + vb.pack_start(menubar, False) + + # search + self.searchEntry = gtk.Entry() + self.searchBtn = gtk.Button("_Search") + self.searchBtn.connect("clicked", self.cb_search_clicked) + self.searchEntry.connect("activate", self.cb_search_clicked) + hbSearch = gtk.HBox(False, 5) + hbSearch.pack_start(self.searchEntry, True, True) + hbSearch.pack_start(self.searchBtn, False, False) + vb.pack_start(hbSearch, False, False, 5) + + # VPaned holding the lists and the Terminal + vpaned = gtk.VPaned() + vpaned.set_position(mHeight/2) + vb.pack_start(vpaned, True, True) + + # a HB holding the lists + hb = gtk.HBox(True, 5) + hbFrame = gtk.Frame() + hbFrame.add(hb) + hbFrame.set_shadow_type(gtk.SHADOW_IN) + vpaned.pack1(hbFrame, shrink = True, resize = True) + + self.scroll_1 = gtk.ScrolledWindow() + self.scroll_2 = gtk.ScrolledWindow() + self.scroll_1.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) + self.scroll_2.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) + hb.pack_start(self.scroll_1, True, True) + hb.pack_start(self.scroll_2, True, True) + + # create cat List + self.catList = self.create_cat_list() + self.scroll_1.add(self.catList) + + # create pkg list + self.pkgList = self.create_pkg_list() + self.scroll_2.add(self.pkgList) + + # queue list + queueHB = gtk.HBox(False, 0) + + queueScroll = gtk.ScrolledWindow() + queueScroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + emergeStore = gtk.TreeStore(str,str) + self.emergeView = gtk.TreeView(emergeStore) + cell = gtk.CellRendererText() + col = gtk.TreeViewColumn("Queue", cell, text = 0) + self.emergeView.append_column(col) + col = gtk.TreeViewColumn("Options", cell, markup = 1) + self.emergeView.append_column(col) + self.emergeView.connect("row-activated", self.cb_row_activated, emergeStore) + self.emergeView.connect("button-press-event", self.cb_queue_right_click) + self.emergeView.set_headers_visible(False) + queueScroll.add(self.emergeView) + queueHB.pack_start(queueScroll, True, True) + + # buttons right to the queue list + buttonBox = gtk.VButtonBox() + buttonBox.set_layout(gtk.BUTTONBOX_SPREAD) + queueHB.pack_start(buttonBox, False) + + emergeBtn = gtk.Button() + self.emergeAction.connect_proxy(emergeBtn) + + updateBtn = gtk.Button() + self.updateAction.connect_proxy(updateBtn) + + unmergeBtn = gtk.Button() + self.unmergeAction.connect_proxy(unmergeBtn) + + removeBtn = gtk.Button("_Remove") + removeBtn.connect("clicked", self.cb_remove_clicked) + + buttonBox.pack_start(emergeBtn) + buttonBox.pack_start(unmergeBtn) + buttonBox.pack_start(updateBtn) + buttonBox.pack_start(removeBtn) + + # the terminal + term = vte.Terminal() + term.set_scrollback_lines(1024) + term.set_scroll_on_output(True) + term.set_font_from_string("Monospace 11") + # XXX why is this not working with the colors + term.set_color_background(gtk.gdk.color_parse("white")) + term.set_color_foreground(gtk.gdk.color_parse("black")) + termBox = gtk.HBox(False, 0) + termScroll = gtk.VScrollbar(term.get_adjustment()) + termBox.pack_start(term, True, True) + termBox.pack_start(termScroll, False) + + # notebook + self.notebook = gtk.Notebook() + self.notebook.append_page(queueHB, gtk.Label("Queue")) + self.notebook.append_page(termBox, gtk.Label("Console")) + + vpaned.pack2(self.notebook, shrink = True, resize = True) + + # the status line + self.statusLabel = gtk.Label("Genetic/One - A Portage GUI") + self.statusLabel.set_alignment(0.0,0.7) + self.statusLabel.set_single_line_mode(True) + vb.pack_start(self.statusLabel, False, False) + + # show + self.window.show_all() + + # set emerge queue + self.queue = EmergeQueue(console=term, tree = emergeStore, db = self.db) + + def create_uimanager(self): + ui =""" + + + + + + + + + + + + + + + + + + + + + + """ + + um = gtk.UIManager() + group = gtk.ActionGroup("MenuActions") + group.add_actions([ + ("File", None, "_File"), + ("EmergeMenu", None, "_Emerge"), + ("Help", None, "_?"), + ("Sync", None, "_Sync", None, None, self.cb_sync_clicked), + ("Prefs", None, "_Preferences", None, None, lambda x: PreferenceWindow(self.window, self.cfg)), + ("Reload", None, "_Reload Portage", None, None, self.cb_reload_clicked), + ("Close", None, "_Close", None, None, self.cb_destroy), + ("About", None, "_About", None, None, lambda x: AboutWindow(self.window))]) + group.add_action(self.emergeAction) + group.add_action(self.unmergeAction) + group.add_action(self.updateAction) + um.insert_action_group(group,0) + + group = gtk.ActionGroup("PopupActions") + group.add_actions([ + ("Oneshot", None, "Oneshot", None, None, self.cb_oneshot_clicked)]) + + um.insert_action_group(group, 1) + + um.add_ui_from_string(ui) + return um + + def fill_pkg_store (self, store, name = None): + if name: + for p in self.db.get_cat(name): + store.append([p]) + return store + + def create_pkg_list (self, name = None, force = False): + """Creates the package list.""" + store = gtk.ListStore(str) + self.fill_pkg_store(store,name) + + # build view + pkgList = gtk.TreeView(store) + cell = gtk.CellRendererText() + col = gtk.TreeViewColumn("Packages", cell, text = 0) + pkgList.append_column(col) + pkgList.connect("row-activated", self.cb_row_activated, store) + + return pkgList + + def create_cat_list (self): + """Creates the category list.""" + store = gtk.ListStore(str) + + # build categories + for p in backend.list_categories(): + store.append([p]) + # sort them alphabetically + store.set_sort_column_id(0, gtk.SORT_ASCENDING) + + view = gtk.TreeView(store) + cell = gtk.CellRendererText() + col = gtk.TreeViewColumn("Categories", cell, text = 0) + view.append_column(col) + view.connect("cursor-changed", self.cb_cat_list_selection) + view.connect("row-activated", lambda v,p,c : self.cb_cat_list_selection(v)) + view.set_search_column(0) + + return view + + def jump_to (self, cp): + """Is called when we want to jump to a specific package.""" + PackageWindow(self.window, cp, self.queue) + + def cb_destroy (self, widget, data = None): + """Calls main_quit().""" + gtk.main_quit() + + def cb_cat_list_selection (self, view, data = None, force = False): + """Callback for a category-list selection. Updates the package list with these packages in the category.""" + if view == self.catList: # be sure it is the catList + # get the selected category + sel = view.get_selection() + store, it = sel.get_selected() + if it: + self.selCatName = store.get_value(it, 0) + self.pkgList.get_model().clear() + self.fill_pkg_store(self.pkgList.get_model(), self.selCatName) + return False + + def cb_row_activated (self, view, path, col, store = None): + """Callback for an activated row in the pkgList. Opens a package window.""" + if view == self.pkgList: + package = store.get_value(store.get_iter(path), 0) + if package[-1] == '*': package = package[:-1] + PackageWindow(self.window, self.selCatName+"/"+package, self.queue) + elif view == self.emergeView: + if len(path) > 1: + package = store.get_value(store.get_iter(path), 0) + cat, name, vers, rev = backend.split_package_name(package) + if rev != "r0": vers = vers+"-"+rev + PackageWindow(self.window, cat+"/"+name, queue = self.queue, version = vers, delOnClose = False, doEmerge = False) + return True + + def cb_remove_clicked (self, button, data = None): + """Removes a selected item in the (un)emerge-queue if possible.""" + selected = self.emergeView.get_selection() + + if selected: + model, iter = selected.get_selected() + + if not model.iter_parent(iter): # top-level + if model.iter_n_children(iter) > 0: # and has children which can be removed :) + if remove_queue_dialog() == gtk.RESPONSE_YES : + self.queue.remove_children(iter) + self.doUpdate = False + + elif model.iter_parent(model.iter_parent(iter)): # this is in the 3rd level => dependency + remove_deps_dialog() + else: + self.queue.remove_children(iter) # remove children first + self.queue.remove(iter) + self.doUpdate = False + + return True + + def cb_emerge_clicked (self, action): + """Do emerge or unemerge.""" + + self.notebook.set_current_page(1) + + if action == self.emergeAction: + if len(flags.newUseFlags) > 0: + changed_flags_dialog("use flags") + flags.write_use_flags() + + if len(flags.new_masked)>0 or len(flags.new_unmasked)>0 or len(flags.newTesting)>0: + changed_flags_dialog("masking keywords") + flags.write_masked() + flags.write_testing() + backend.reload_settings() + + if not self.doUpdate: + self.queue.emerge(force=True) + else: + self.queue.update_world(force=True, newuse = self.cfg.get_boolean(self.cfg.const["newuse_opt"]), deep = self.cfg.get_boolean(self.cfg.const["deep_opt"])) + self.doUpdate = False + + elif action == self.unmergeAction: + self.queue.unmerge(force=True) + + return True + + 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""" + 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 + + @watch_cursor + def cb_update_clicked (self, action): + if not backend.am_i_root(): + not_root_dialog() + + else: + updating = backend.update_world(newuse = self.cfg.get_boolean(self.cfg.const["newuse_opt"]), deep = self.cfg.get_boolean(self.cfg.const["deep_opt"])) + + debug("updating list:", [(x.get_cpv(), y.get_cpv()) for x,y in updating]) + try: + for pkg, old_pkg in updating: + self.queue.append(pkg.get_cpv()) + except BlockedException, e: + blocked_dialog(e[0], e[1]) + if len(updating): self.doUpdate = True + return True + + def cb_sync_clicked (self, action): + self.notebook.set_current_page(1) + self.queue.sync() + + @watch_cursor + def cb_reload_clicked (self, action): + """Reloads the portage settings and the database.""" + backend.reload_settings() + del self.db + self.db = Database() + self.db.populate() + + @watch_cursor + def cb_search_clicked (self, button, data = None): + """Do a search.""" + if self.searchEntry.get_text() != "": + packages = backend.find_all_packages(self.searchEntry.get_text(), withVersion = False) + + if packages == []: + nothing_found_dialog() + else: + if len(packages) == 1: + self.jump_to(packages[0]) + else: + SearchWindow(self.window, packages, self.jump_to) + + def cb_queue_right_click (self, queue, event): + if event.button == 3: + x = int(event.x) + y = int(event.y) + time = event.time + pthinfo = queue.get_path_at_pos(x, y) + if pthinfo is not None: + path, col, cellx, celly = pthinfo + queue.grab_focus() + queue.set_cursor( path, col, 0) + self.queuePopup.popup( None, None, None, event.button, time) + return True + else: + return False + + def cb_oneshot_clicked (self, action): + sel = self.emergeView.get_selection() + store, it = sel.get_selected() + if it: + package = store.get_value(it, 0) + if not self.cfg.get_local(package, self.cfg.const["oneshot_opt"]): + set = True + else: + set = False + + self.cfg.set_local(package, self.cfg.const["oneshot_opt"], set) + self.queue.append(package, update = True, oneshot = set, forceUpdate = True) + + + 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 + gtk.main() diff --git a/geneticone/gui/gui_helper.py b/geneticone/gui/gui_helper.py index 1c0ae90..2f758b2 100644 --- a/geneticone/gui/gui_helper.py +++ b/geneticone/gui/gui_helper.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # # File: geneticone/gui/gui_helper.py # This file is part of the Genetic/One-Project, a graphical portage-frontend. @@ -14,9 +15,6 @@ from geneticone import backend from geneticone.backend import flags from geneticone.helper import * -# our dialogs -import dialogs - # some stuff needed from subprocess import Popen, PIPE, STDOUT from threading import Thread @@ -356,35 +354,29 @@ class EmergeQueue: @raises geneticone.backend.PackageNotFoundException: if trying to add a package which does not exist""" if not unmerge: # emerge - try: - # insert dependencies - pkg = self._get_pkg_from_cpv(cpv, unmask) - deps = pkg.get_dep_packages() - - if update: - if not forceUpdate and deps == self.deps[cpv]: - return # nothing changed - return - else: - hasBeenInQueue = (cpv in self.mergequeue or cpv in self.oneshotmerge) - parentIt = self.tree.iter_parent(self.iters[cpv]) - - # delete it out of the tree - but NOT the changed flags - self.remove_with_children(self.iters[cpv], removeNewFlags = False) - - if hasBeenInQueue: # package has been in queue before - options += self._queue_append(cpv, oneshot) - - self.update_tree(parentIt, cpv, unmask, options = options) - else: # not update - options += self._queue_append(cpv, oneshot) - if self.emergeIt: - self.update_tree(self.emergeIt, cpv, unmask, options) + # insert dependencies + pkg = self._get_pkg_from_cpv(cpv, unmask) + deps = pkg.get_dep_packages() + + if update: + if not forceUpdate and deps == self.deps[cpv]: + return # nothing changed - return + else: + hasBeenInQueue = (cpv in self.mergequeue or cpv in self.oneshotmerge) + parentIt = self.tree.iter_parent(self.iters[cpv]) + + # delete it out of the tree - but NOT the changed flags + self.remove_with_children(self.iters[cpv], removeNewFlags = False) + + if hasBeenInQueue: # package has been in queue before + options += self._queue_append(cpv, oneshot) + + self.update_tree(parentIt, cpv, unmask, options = options) + else: # not update + options += self._queue_append(cpv, oneshot) + if self.emergeIt: + self.update_tree(self.emergeIt, cpv, unmask, options) - except backend.BlockedException, e : # there is sth blocked --> call blocked_dialog - blocks = e[0] - dialogs.blocked_dialog(cpv, blocks) - return - else: # unmerge self.unmergequeue.append(cpv) if self.unmergeIt: # update tree diff --git a/geneticone/gui/windows.py b/geneticone/gui/windows.py deleted file mode 100644 index 3daab81..0000000 --- a/geneticone/gui/windows.py +++ /dev/null @@ -1,1022 +0,0 @@ -# -# File: geneticone/gui/windows.py -# This file is part of the Genetic/One-Project, a graphical portage-frontend. -# -# Copyright (C) 2006 René 'Necoro' Neumann -# This is free software. You may redistribute copies of it under the terms of -# the GNU General Public License version 2. -# There is NO WARRANTY, to the extent permitted by law. -# -# Written by René 'Necoro' Neumann - -VERSION = "0.4.5" -CONFIG_LOCATION = "/etc/geneticone/geneticone.cfg" - -# gtk stuff -import pygtk -pygtk.require("2.0") -import gtk -import gobject - -#our backend stuff -from geneticone.helper import * -from geneticone import backend -from geneticone.backend import flags - -# more GUI stuff -from gui_helper import Database, Config, EmergeQueue -from dialogs import * - -# for the terminal -import vte - -# other -from portage_util import unique_array - -class AbstractDialog: - """A class all our dialogs get derived from. It sets useful default vars and automatically handles the ESC-Button.""" - - def __init__ (self, parent, title): - """Constructor. - - @param parent: the parent window - @type parent: gtk.Window - @param title: the title of the window - @type title: string""" - - # create new - self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) - - # set title - self.window.set_title(title) - - # set modal and transient for the parent --> you have to close this one to get back to the parent - self.window.set_modal(True) - self.window.set_transient_for(parent) - self.window.set_destroy_with_parent(True) - - # not resizable - self.window.set_resizable(False) - - # default size = (1,1) ==> as small as possible - self.window.set_default_size(1,1) - - # 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.window.destroy() - return True - else: - return False - -class AboutWindow (AbstractDialog): - """A window showing the "about"-informations.""" - - def __init__ (self, parent): - """Constructor. - - @param parent: the parent window - @type parent: gtk.Window""" - - AbstractDialog.__init__(self, parent, "About Genetic/One") - - box = gtk.VBox(False) - self.window.add(box) - - # about label - label = gtk.Label() - label.set_justify(gtk.JUSTIFY_CENTER) - label.set_markup(""" -Genetic/One v.%s -A Portage-GUI - -This software is licensed under the terms of the GPLv2. -Copyright (C) 2006 René 'Necoro' Neumann <necoro@necoro.net> - -Thanks to Fred for support and ideas :P -""" % VERSION) - box.pack_start(label) - - # button - okBtn = gtk.Button("OK") - okBtn.connect("clicked", lambda x: self.window.destroy()) - box.pack_start(okBtn) - - # finished -> show - self.window.show_all() - -class SearchWindow (AbstractDialog): - """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, "Search results") - - self.list = list # list to show - self.jump_to = jump_to # function to call for jumping - - box = gtk.HBox(False) - self.window.add(box) - - # combo box - self.combo = gtk.combo_box_new_text() - for x in list: - self.combo.append_text(x) - self.combo.set_active(0) # first item - self.combo.connect("key-press-event", self.cb_key_pressed_combo) - - box.pack_start(self.combo) - - # ok-button - okBtn = gtk.Button("OK") - okBtn.connect("clicked", self.cb_ok_btn_clicked) - box.pack_start(okBtn) - - # finished --> show - self.window.show_all() - - def cb_ok_btn_clicked (self, button): - """Called if the OK-Button is clicked. - Calls self.jump_to(selected_entry) and closes the window.""" - self.window.destroy() - self.jump_to(self.list[self.combo.get_active()]) - return True - - 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.cb_ok_btn_clicked(widget) - return True - else: - return False - -class PreferenceWindow (AbstractDialog): - """Window displaying some preferences.""" - - def __init__ (self, parent, cfg): - """Constructor. - - @param parent: parent window - @type parent: gtk.Window - @param cfg: configuration object - @type cfg: gui_helper.Config""" - - AbstractDialog.__init__(self, parent, "Preferences") - self.window.set_resizable(True) # override the default of the AbstractDialog - - # our config - self.cfg = cfg - - box = gtk.VBox() - box.set_spacing(5) - - self.window.add(box) - - # En-/Disable Debugging - self.debugCb = self.draw_cb(box, "Debugging modus", "debug_opt") - - # --deep - self.deepCb = self.draw_cb(box, "--deep", "deep_opt") - - # --newuse - #self.newuseCb = self.draw_cb(box, "--newuse", "newuse_opt") - - pHolderLabel = gtk.Label("""For the following options, you might use these placeholders: -$(cat) = category -$(pkg) = package-name -$(cat-1)/$(cat-2) = first/second part of the category""") - pHolderLabel.set_use_markup(True) - pHolderLabel.set_alignment(0,0) - box.pack_start(pHolderLabel) - - # The use/mask/keywording checkboxes and edits - self.usePerVersionCb, self.useFileEdit = self.draw_cb_and_edit(box, "package.use", "usePerVersion_opt", "useFile_opt") - self.maskPerVersionCb, self.maskFileEdit = self.draw_cb_and_edit(box, "package.mask/package.unmask", "maskPerVersion_opt", "maskFile_opt") - self.testPerVersionCb, self.testFileEdit = self.draw_cb_and_edit(box, "package.keywords", "testingPerVersion_opt", "testingFile_opt") - # buttons - buttonHB = gtk.HButtonBox() - buttonHB.set_layout(gtk.BUTTONBOX_SPREAD) - - okBtn = gtk.Button("_OK") - cancelBtn = gtk.Button("_Cancel") - okBtn.connect("clicked", self.cb_ok_clicked) - cancelBtn.connect("clicked", lambda x: self.window.destroy()) - buttonHB.pack_start(okBtn) - buttonHB.pack_start(cancelBtn) - - box.pack_start(buttonHB, True, True, 5) - - # finished --> show all - self.window.show_all() - - def draw_cb_and_edit (self, box, string, cb_opt, edit_opt): - """Draws a checkbox and an edit-field. - - @param box: box to place the both things into - @type box: gtk.Box - @param string: string to show - @type string: string - @param cb_opt: the option string for the Config.const-dict - @type cb_opt: string - @param edit_opt: the option string for the Config.const-dic - @type edit_opt: string - - @return: the checkbox and the edit-field - @rtype: (gtk.CheckButton, gtk.Edit)""" - - # check-button - cb = self.draw_cb(box, label=("Add to %s on a per-version-base" % string), opt = cb_opt) - - # edit with label - hBox = gtk.HBox() - label = gtk.Label("File name to use if %s is a directory:" % string) - edit = gtk.Entry() - edit.set_text(self.cfg.get(self.cfg.const[edit_opt])) - hBox.pack_start(label, False) - hBox.pack_start(edit, True, True, 5) - box.pack_start(hBox, True, True) - - return (cb, edit) - - def draw_cb (self, box, label, opt): - """Draws a checkbox. - - @param box: box to place the cb into - @type box: gtk.Box - @param label: Label to show - @type label: string - @param opt: the option string for the Config.const-dict - @type opt: string - @returns: the checkbox - @rtype: gtk.CheckButton""" - - cb = gtk.CheckButton(label=label) - cb.set_active(self.cfg.get_boolean(self.cfg.const[opt])) - box.pack_start(cb, True, True) - - return cb - - def _save(self): - """Sets all options in the Config-instance.""" - self.cfg.set(self.cfg.const["usePerVersion_opt"], str(self.usePerVersionCb.get_active())) - self.cfg.set(self.cfg.const["useFile_opt"], self.useFileEdit.get_text()) - self.cfg.set(self.cfg.const["maskPerVersion_opt"], str(self.maskPerVersionCb.get_active())) - self.cfg.set(self.cfg.const["maskFile_opt"], self.maskFileEdit.get_text()) - self.cfg.set(self.cfg.const["testingPerVersion_opt"], str(self.testPerVersionCb.get_active())) - self.cfg.set(self.cfg.const["testingFile_opt"], self.testFileEdit.get_text()) - self.cfg.set(self.cfg.const["debug_opt"], str(self.debugCb.get_active())) - self.cfg.set(self.cfg.const["deep_opt"], str(self.deepCb.get_active())) - #self.cfg.set(self.cfg.const["newuse_opt"], str(self.newuseCb.get_active())) - - def cb_ok_clicked(self, button): - """Saves, writes to config-file and closes the window.""" - self._save() - self.cfg.write() - self.window.destroy() - -class PackageWindow (AbstractDialog): - """A window with data about a specfic package.""" - - def __init__ (self, parent, cp, queue = None, version = None, delOnClose = True, doEmerge = True): - """Build up window contents.""" - AbstractDialog.__init__(self, parent, cp) - - self.cp = cp # category/package - self.version = version # version - if not None this is used - self.queue = queue - self.delOnClose = delOnClose - self.doEmerge = doEmerge - self.flagChanged = False - - # packages and installed packages - self.packages = backend.sort_package_list(backend.get_all_versions(cp)) - self.instPackages = backend.sort_package_list(backend.get_all_installed_versions(cp)) - - # main structure - the table - self.table = gtk.Table(rows=4,columns=2) - self.window.add(self.table) - - # version-combo-box - self.vCombo = self.build_vers_combo() - self.table.attach(self.vCombo, 0, 1, 1, 2, yoptions = gtk.FILL) - if not self.doEmerge: self.vCombo.set_sensitive(False) - - # the label (must be here, because it depends on the combo box) - desc = self.actual_package().get_env_var("DESCRIPTION") - if not desc: - desc = "" - use_markup = False - else: - desc = ""+desc+"" - use_markup = True - self.descLabel = gtk.Label(desc) - self.descLabel.set_line_wrap(True) - self.descLabel.set_justify(gtk.JUSTIFY_CENTER) - self.descLabel.set_use_markup(use_markup) - self.table.attach(self.descLabel, 0, 2, 0, 1, xoptions = gtk.FILL, ypadding = 10) - - # the check boxes - checkHB = gtk.HBox (True, 1) - self.table.attach(checkHB, 1, 2, 1, 2, yoptions = gtk.FILL) - - self.installedCheck = gtk.CheckButton() - self.installedCheck.connect("button-press-event", self.cb_button_pressed) - self.installedCheck.set_label("Installed") - self.installedCheck.set_no_show_all(True) - checkHB.pack_start(self.installedCheck, True, False) - - self.maskedCheck = gtk.CheckButton() - self.maskedCheck.connect("toggled", self.cb_masked_toggled) - self.maskedCheck.set_label("Masked") - self.maskedCheck.set_no_show_all(True) - checkHB.pack_start(self.maskedCheck, True, False) - - self.testingCheck = gtk.CheckButton() - self.testingCheck.connect("toggled", self.cb_testing_toggled) - self.testingCheck.set_label("Testing") - self.testingCheck.set_no_show_all(True) - checkHB.pack_start(self.testingCheck, True, False) - - self.missing_label = gtk.Label("MISSING KEYWORD") - self.missing_label.set_use_markup(True) - self.missing_label.set_no_show_all(True) - self.table.attach(self.missing_label, 1, 2, 1, 2, yoptions = gtk.FILL) - - self.not_in_sys_label = gtk.Label("Installed, but not in portage anymore") - self.not_in_sys_label.set_use_markup(True) - self.not_in_sys_label.set_no_show_all(True) - self.table.attach(self.not_in_sys_label, 1, 2, 1, 2, yoptions = gtk.FILL) - - # use list - self.useList = self.build_use_list() - self.useListScroll = gtk.ScrolledWindow() - self.useListScroll.add(self.useList) - self.useListScroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_NEVER) # XXX: make this work correctly - self.table.attach(self.useListScroll, 0, 2, 2, 3, ypadding = 10) - - # buttons - buttonHB = gtk.HButtonBox() - buttonHB.set_layout(gtk.BUTTONBOX_SPREAD) - self.table.attach(buttonHB, 0, 2, 3, 4) - - self.emergeBtn = gtk.Button("_Emerge") - self.unmergeBtn = gtk.Button("_Unmerge") - if not self.queue or not self.doEmerge: - self.emergeBtn.set_sensitive(False) - self.unmergeBtn.set_sensitive(False) - self.cancelBtn = gtk.Button("_Cancel") - if not self.delOnClose: - self.cancelBtn.set_label("_Close") - self.cancelBtn.connect("clicked", self.cb_cancel_clicked) - self.emergeBtn.connect("clicked", self.cb_emerge_clicked) - self.unmergeBtn.connect("clicked", self.cb_unmerge_clicked) - buttonHB.pack_start(self.emergeBtn) - buttonHB.pack_start(self.unmergeBtn) - buttonHB.pack_start(self.cancelBtn) - - # current status - self.cb_combo_changed(self.vCombo) - - # show - self.window.show_all() - - def fill_use_list(self, store): - pkg = self.actual_package() - pkg_flags = pkg.get_all_use_flags() - pkg_flags.sort() - for use in pkg_flags: - if pkg.is_installed() and use in pkg.get_actual_use_flags(): # flags set during install - enabled = True - elif (not pkg.is_installed()) and use in pkg.get_settings("USE").split() and not flags.invert_use_flag(use) in pkg.get_new_use_flags(): # flags that would be set - enabled = True - elif use in pkg.get_new_use_flags(): - enabled = True - else: - enabled = False - store.append([enabled, use, backend.get_use_desc(use, self.cp)]) - - return store - - def build_use_list (self): - """Builds the useList.""" - store = gtk.ListStore(bool, str, str) - self.fill_use_list(store) - - # build view - view = gtk.TreeView(store) - cell = gtk.CellRendererText() - tCell = gtk.CellRendererToggle() - tCell.set_property("activatable", True) - tCell.connect("toggled", self.cb_use_flag_toggled, store) - view.append_column(gtk.TreeViewColumn("Enabled", tCell, active = 0)) - view.append_column(gtk.TreeViewColumn("Flags", cell, text = 1)) - view.append_column(gtk.TreeViewColumn("Description", cell, text = 2)) - - if store.iter_n_children(None) == 0: # if there are no nodes in the list ... - view.set_child_visible(False) # ... do not show the list - else: - view.set_child_visible(True) - return view - - def build_vers_combo (self): - """Creates the combo box with the different versions.""" - combo = gtk.combo_box_new_text() - - # append versions - for s in [x.get_version() for x in self.packages]: - combo.append_text(s) - - # activate the first one - try: - best_version = "" - if self.version: - best_version = self.version - else: - best_version = backend.find_best_match(self.packages[0].get_cp(), (self.instPackages != [])).get_version() - for i in range(len(self.packages)): - if self.packages[i].get_version() == best_version: - combo.set_active(i) - break - except AttributeError: # no package found - debug('catched AttributeError => no "best package" found. Selected first one.') - combo.set_active(0) - - combo.connect("changed", self.cb_combo_changed) - - return combo - - def actual_package (self): - """Returns the actual package (a backend.Package-object).""" - return self.packages[self.vCombo.get_active()] - - def cb_combo_changed (self, combo, data = None): - """Callback for the changed ComboBox. - It then rebuilds the useList and the checkboxes.""" - - # remove old useList - self.useListScroll.remove(self.useList) - - # build new - self.useList = self.build_use_list() - self.useListScroll.add(self.useList) - pkg = self.actual_package() - - if (not pkg.is_in_system()) or pkg.is_missing_keyword(): - if not pkg.is_in_system(): - self.missing_label.hide() - self.not_in_sys_label.show() - else: # missing keyword - self.missing_label.show() - self.not_in_sys_label.hide() - - self.installedCheck.hide() - self.maskedCheck.hide() - self.testingCheck.hide() - self.emergeBtn.set_sensitive(False) - else: - self.missing_label.hide() - self.not_in_sys_label.hide() - self.installedCheck.show() - self.maskedCheck.show() - self.testingCheck.show() - if self.doEmerge: - self.emergeBtn.set_sensitive(True) - self.installedCheck.set_active(pkg.is_installed()) - self.maskedCheck.set_active(pkg.is_masked()) - if pkg.is_testing(allowed = False) and not pkg.is_testing(allowed=True): - self.testingCheck.set_label("(Testing)") - self.testingCheck.get_child().set_use_markup(True) - else: - self.testingCheck.set_label("Testing") - self.testingCheck.set_active(pkg.is_testing(allowed = False)) - - if self.doEmerge: - # set emerge-button-label - if not self.actual_package().is_installed(): - self.emergeBtn.set_label("_Emerge") - self.unmergeBtn.set_sensitive(False) - else: - self.emergeBtn.set_label("R_emerge") - self.unmergeBtn.set_sensitive(True) - - # refresh - make window as small as possible - self.table.show_all() - self.window.resize(1,1) - return True - - def cb_button_pressed (self, b, event, data = None): - """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_cancel_clicked (self, button, data = None): - if self.delOnClose: - self.actual_package().remove_new_use_flags() - self.actual_package().remove_new_masked() - self.actual_package().remove_new_testing() - elif self.flagChanged: - if self.queue: - try: - self.queue.append(self.actual_package().get_cpv(), update = True) - except backend.PackageNotFoundException, e: - if unmask_dialog(e[0]) == gtk.RESPONSE_YES: - self.queue.append(self.actual_package().get_cpv(), update = True, unmask = True) - self.window.destroy() - return True - - def cb_emerge_clicked (self, button, data = None): - """Adds the package to the EmergeQueue.""" - if not am_i_root(): - not_root_dialog() - else: - try: - self.queue.append(self.actual_package().get_cpv(), unmerge = False) - self.window.destroy() - except backend.PackageNotFoundException, e: - if unmask_dialog(e[0]) == gtk.RESPONSE_YES: - self.queue.append(self.actual_package().get_cpv(), unmerge = False, unmask = True) - self.window.destroy() - return True - - def cb_unmerge_clicked (self, button, data = None): - """Adds the package to the UnmergeQueue.""" - if not am_i_root(): - not_root_dialog() - else: - try: - self.queue.append(self.actual_package().get_cpv(), unmerge = True) - except backend.PackageNotFoundException, e: - masked_dialog(e[0]) - - self.window.destroy() - return True - - def cb_testing_toggled (self, button): - status = button.get_active() - - if self.actual_package().is_testing(allowed = False) == status: - return False - - if not self.actual_package().is_testing(allowed = True): - self.actual_package().set_testing(False) - button.set_label("Testing") - button.set_active(True) - else: - self.actual_package().set_testing(True) - if self.actual_package().is_testing(allowed=False): - button.set_label("(Testing)") - button.get_child().set_use_markup(True) - button.set_active(True) - self.flagChanged = True - return True - - def cb_masked_toggled (self, button): - status = button.get_active() - self.actual_package().set_masked(status) - self.flagChanged = True - return True - - def cb_use_flag_toggled (self, cell, path, store, data = None): - store[path][0] = not store[path][0] - prefix = "" - if not store[path][0]: - prefix = "-" - self.actual_package().set_use_flag(prefix+store[path][1]) - self.flagChanged = True - return True - -class MainWindow: - """Application main window.""" - - def __init__ (self): - """Build up window""" - # window - self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) - self.window.set_title(("Genetic/One (%s)" % VERSION)) - self.window.connect("destroy", self.cb_destroy) - self.window.set_border_width(2) - self.window.set_resizable(True) - - mHeight = 800 - if gtk.gdk.screen_height() <= 800: mHeight = 600 - self.window.set_geometry_hints (self.window, min_width = 600, min_height = mHeight, max_height = gtk.gdk.screen_height(), max_width = gtk.gdk.screen_width()) - - # booleans - self.doUpdate = False - - # package db - self.db = Database() - self.db.populate() - - # config - self.cfg = Config(CONFIG_LOCATION) - self.cfg.modify_external_configs() - - # actions needed - self.emergeAction = gtk.Action("Emerge", "_Emerge", None, None) - self.emergeAction.connect("activate", self.cb_emerge_clicked) - self.unmergeAction = gtk.Action("Unmerge", "_Unmerge", None, None) - self.unmergeAction.connect("activate", self.cb_emerge_clicked) - self.updateAction = gtk.Action("UpdateWorld", "Update _World", None, None) - self.updateAction.connect("activate", self.cb_update_clicked) - - # main vb - vb = gtk.VBox(False, 1) - self.window.add(vb) - - # menus - self.uimanager = self.create_uimanager() - self.queuePopup = self.uimanager.get_widget("/popupQueue") - menubar = self.uimanager.get_widget("/bar") - vb.pack_start(menubar, False) - - # search - self.searchEntry = gtk.Entry() - self.searchBtn = gtk.Button("_Search") - self.searchBtn.connect("clicked", self.cb_search_clicked) - self.searchEntry.connect("activate", self.cb_search_clicked) - hbSearch = gtk.HBox(False, 5) - hbSearch.pack_start(self.searchEntry, True, True) - hbSearch.pack_start(self.searchBtn, False, False) - vb.pack_start(hbSearch, False, False, 5) - - # VPaned holding the lists and the Terminal - vpaned = gtk.VPaned() - vpaned.set_position(mHeight/2) - vb.pack_start(vpaned, True, True) - - # a HB holding the lists - hb = gtk.HBox(True, 5) - hbFrame = gtk.Frame() - hbFrame.add(hb) - hbFrame.set_shadow_type(gtk.SHADOW_IN) - vpaned.pack1(hbFrame, shrink = True, resize = True) - - self.scroll_1 = gtk.ScrolledWindow() - self.scroll_2 = gtk.ScrolledWindow() - self.scroll_1.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) - self.scroll_2.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) - hb.pack_start(self.scroll_1, True, True) - hb.pack_start(self.scroll_2, True, True) - - # create cat List - self.catList = self.create_cat_list() - self.scroll_1.add(self.catList) - - # create pkg list - self.pkgList = self.create_pkg_list() - self.scroll_2.add(self.pkgList) - - # queue list - queueHB = gtk.HBox(False, 0) - - queueScroll = gtk.ScrolledWindow() - queueScroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) - emergeStore = gtk.TreeStore(str,str) - self.emergeView = gtk.TreeView(emergeStore) - cell = gtk.CellRendererText() - col = gtk.TreeViewColumn("Queue", cell, text = 0) - self.emergeView.append_column(col) - col = gtk.TreeViewColumn("Options", cell, markup = 1) - self.emergeView.append_column(col) - self.emergeView.connect("row-activated", self.cb_row_activated, emergeStore) - self.emergeView.connect("button-press-event", self.cb_queue_right_click) - self.emergeView.set_headers_visible(False) - queueScroll.add(self.emergeView) - queueHB.pack_start(queueScroll, True, True) - - # buttons right to the queue list - buttonBox = gtk.VButtonBox() - buttonBox.set_layout(gtk.BUTTONBOX_SPREAD) - queueHB.pack_start(buttonBox, False) - - emergeBtn = gtk.Button() - self.emergeAction.connect_proxy(emergeBtn) - - updateBtn = gtk.Button() - self.updateAction.connect_proxy(updateBtn) - - unmergeBtn = gtk.Button() - self.unmergeAction.connect_proxy(unmergeBtn) - - removeBtn = gtk.Button("_Remove") - removeBtn.connect("clicked", self.cb_remove_clicked) - - buttonBox.pack_start(emergeBtn) - buttonBox.pack_start(unmergeBtn) - buttonBox.pack_start(updateBtn) - buttonBox.pack_start(removeBtn) - - # the terminal - term = vte.Terminal() - term.set_scrollback_lines(1024) - term.set_scroll_on_output(True) - term.set_font_from_string("Monospace 11") - # XXX why is this not working with the colors - term.set_color_background(gtk.gdk.color_parse("white")) - term.set_color_foreground(gtk.gdk.color_parse("black")) - termBox = gtk.HBox(False, 0) - termScroll = gtk.VScrollbar(term.get_adjustment()) - termBox.pack_start(term, True, True) - termBox.pack_start(termScroll, False) - - # notebook - self.notebook = gtk.Notebook() - self.notebook.append_page(queueHB, gtk.Label("Queue")) - self.notebook.append_page(termBox, gtk.Label("Console")) - - vpaned.pack2(self.notebook, shrink = True, resize = True) - - # the status line - self.statusLabel = gtk.Label("Genetic/One - A Portage GUI") - self.statusLabel.set_alignment(0.0,0.7) - self.statusLabel.set_single_line_mode(True) - vb.pack_start(self.statusLabel, False, False) - - # show - self.window.show_all() - - # set emerge queue - self.queue = EmergeQueue(console=term, tree = emergeStore, db = self.db) - - def create_uimanager(self): - ui =""" - - - - - - - - - - - - - - - - - - - - - - """ - - um = gtk.UIManager() - group = gtk.ActionGroup("MenuActions") - group.add_actions([ - ("File", None, "_File"), - ("EmergeMenu", None, "_Emerge"), - ("Help", None, "_?"), - ("Sync", None, "_Sync", None, None, self.cb_sync_clicked), - ("Prefs", None, "_Preferences", None, None, lambda x: PreferenceWindow(self.window, self.cfg)), - ("Reload", None, "_Reload Portage", None, None, self.cb_reload_clicked), - ("Close", None, "_Close", None, None, self.cb_destroy), - ("About", None, "_About", None, None, lambda x: AboutWindow(self.window))]) - group.add_action(self.emergeAction) - group.add_action(self.unmergeAction) - group.add_action(self.updateAction) - um.insert_action_group(group,0) - - group = gtk.ActionGroup("PopupActions") - group.add_actions([ - ("Oneshot", None, "Oneshot", None, None, self.cb_oneshot_clicked)]) - - um.insert_action_group(group, 1) - - um.add_ui_from_string(ui) - return um - - def fill_pkg_store (self, store, name = None): - if name: - for p in self.db.get_cat(name): - store.append([p]) - return store - - def create_pkg_list (self, name = None, force = False): - """Creates the package list.""" - store = gtk.ListStore(str) - self.fill_pkg_store(store,name) - - # build view - pkgList = gtk.TreeView(store) - cell = gtk.CellRendererText() - col = gtk.TreeViewColumn("Packages", cell, text = 0) - pkgList.append_column(col) - pkgList.connect("row-activated", self.cb_row_activated, store) - - return pkgList - - def create_cat_list (self): - """Creates the category list.""" - store = gtk.ListStore(str) - - # build categories - for p in backend.list_categories(): - store.append([p]) - # sort them alphabetically - store.set_sort_column_id(0, gtk.SORT_ASCENDING) - - view = gtk.TreeView(store) - cell = gtk.CellRendererText() - col = gtk.TreeViewColumn("Categories", cell, text = 0) - view.append_column(col) - view.connect("cursor-changed", self.cb_cat_list_selection) - view.connect("row-activated", lambda v,p,c : self.cb_cat_list_selection(v)) - view.set_search_column(0) - - return view - - def jump_to (self, cp): - """Is called when we want to jump to a specific package.""" - PackageWindow(self.window, cp, self.queue) - - def cb_destroy (self, widget, data = None): - """Calls main_quit().""" - gtk.main_quit() - - def cb_cat_list_selection (self, view, data = None, force = False): - """Callback for a category-list selection. Updates the package list with these packages in the category.""" - if view == self.catList: # be sure it is the catList - # get the selected category - sel = view.get_selection() - store, it = sel.get_selected() - if it: - self.selCatName = store.get_value(it, 0) - self.pkgList.get_model().clear() - self.fill_pkg_store(self.pkgList.get_model(), self.selCatName) - return False - - def cb_row_activated (self, view, path, col, store = None): - """Callback for an activated row in the pkgList. Opens a package window.""" - if view == self.pkgList: - package = store.get_value(store.get_iter(path), 0) - if package[-1] == '*': package = package[:-1] - PackageWindow(self.window, self.selCatName+"/"+package, self.queue) - elif view == self.emergeView: - if len(path) > 1: - package = store.get_value(store.get_iter(path), 0) - cat, name, vers, rev = backend.split_package_name(package) - if rev != "r0": vers = vers+"-"+rev - PackageWindow(self.window, cat+"/"+name, queue = self.queue, version = vers, delOnClose = False, doEmerge = False) - return True - - def cb_remove_clicked (self, button, data = None): - """Removes a selected item in the (un)emerge-queue if possible.""" - selected = self.emergeView.get_selection() - - if selected: - model, iter = selected.get_selected() - - if not model.iter_parent(iter): # top-level - if model.iter_n_children(iter) > 0: # and has children which can be removed :) - if remove_queue_dialog() == gtk.RESPONSE_YES : - self.queue.remove_children(iter) - self.doUpdate = False - - elif model.iter_parent(model.iter_parent(iter)): # this is in the 3rd level => dependency - remove_deps_dialog() - else: - self.queue.remove_children(iter) # remove children first - self.queue.remove(iter) - self.doUpdate = False - - return True - - def cb_emerge_clicked (self, action): - """Do emerge or unemerge.""" - - self.notebook.set_current_page(1) - - if action == self.emergeAction: - if len(flags.newUseFlags) > 0: - changed_flags_dialog("use flags") - flags.write_use_flags() - - if len(flags.new_masked)>0 or len(flags.new_unmasked)>0 or len(flags.newTesting)>0: - changed_flags_dialog("masking keywords") - flags.write_masked() - flags.write_testing() - backend.reload_settings() - - if not self.doUpdate: - self.queue.emerge(force=True) - else: - self.queue.update_world(force=True, newuse = self.cfg.get_boolean(self.cfg.const["newuse_opt"]), deep = self.cfg.get_boolean(self.cfg.const["deep_opt"])) - self.doUpdate = False - - elif action == self.unmergeAction: - self.queue.unmerge(force=True) - - return True - - 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""" - 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 - - @watch_cursor - def cb_update_clicked (self, action): - if not backend.am_i_root(): - not_root_dialog() - - else: - updating = backend.update_world(newuse = self.cfg.get_boolean(self.cfg.const["newuse_opt"]), deep = self.cfg.get_boolean(self.cfg.const["deep_opt"])) - - debug("updating list:", [(x.get_cpv(), y.get_cpv()) for x,y in updating]) - for pkg, old_pkg in updating: - self.queue.append(pkg.get_cpv()) - - if len(updating): self.doUpdate = True - return True - - def cb_sync_clicked (self, action): - self.notebook.set_current_page(1) - self.queue.sync() - - @watch_cursor - def cb_reload_clicked (self, action): - """Reloads the portage settings and the database.""" - backend.reload_settings() - del self.db - self.db = Database() - self.db.populate() - - @watch_cursor - def cb_search_clicked (self, button, data = None): - """Do a search.""" - if self.searchEntry.get_text() != "": - packages = backend.find_all_packages(self.searchEntry.get_text(), withVersion = False) - - if packages == []: - nothing_found_dialog() - else: - if len(packages) == 1: - self.jump_to(packages[0]) - else: - SearchWindow(self.window, packages, self.jump_to) - - def cb_queue_right_click (self, queue, event): - if event.button == 3: - x = int(event.x) - y = int(event.y) - time = event.time - pthinfo = queue.get_path_at_pos(x, y) - if pthinfo is not None: - path, col, cellx, celly = pthinfo - queue.grab_focus() - queue.set_cursor( path, col, 0) - self.queuePopup.popup( None, None, None, event.button, time) - return True - else: - return False - - def cb_oneshot_clicked (self, action): - sel = self.emergeView.get_selection() - store, it = sel.get_selected() - if it: - package = store.get_value(it, 0) - if not self.cfg.get_local(package, self.cfg.const["oneshot_opt"]): - set = True - else: - set = False - - self.cfg.set_local(package, self.cfg.const["oneshot_opt"], set) - self.queue.append(package, update = True, oneshot = set, forceUpdate = True) - - - 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 - gtk.main() -- cgit v1.2.3-54-g00ecf