diff options
-rw-r--r-- | geneticone/backend/flags.py | 12 | ||||
-rw-r--r-- | geneticone/backend/portage_helper.py | 2 | ||||
-rw-r--r-- | geneticone/gui/gui_helper.py | 34 | ||||
-rw-r--r-- | geneticone/gui/windows.py | 337 |
4 files changed, 209 insertions, 176 deletions
diff --git a/geneticone/backend/flags.py b/geneticone/backend/flags.py index 214faf9..20b63ef 100644 --- a/geneticone/backend/flags.py +++ b/geneticone/backend/flags.py @@ -24,7 +24,7 @@ from portage_util import unique_array def grep (pkg, path): """Grep runs "egrep" on a given path and looks for occurences of a given package. @param pkg: the package - @type pkg: string (cpv) or L{geneticone.Package}-object + @type pkg: string (cpv) or L{backend.Package}-object @param path: path to look in @type path: string @@ -40,7 +40,7 @@ def grep (pkg, path): def get_data(pkg, path): """This splits up the data of L{grep} and builds tuples in the format (file,line,criterion,list_of_flags). @param pkg: package to find - @type pkg: string (cpv) or L{geneticone.Package}-object + @type pkg: string (cpv) or L{backend.Package}-object @param path: path to look in @type path: string @@ -94,7 +94,7 @@ def set_use_flag (pkg, flag): """Sets the useflag for a given package. @param pkg: the package - @type pkg: string (cpv) or L{geneticone.Package}-object + @type pkg: string (cpv) or L{backend.Package}-object @param flag: the flag to set @type flag: string""" @@ -162,7 +162,7 @@ def set_use_flag (pkg, flag): def remove_new_use_flags (cpv): """Removes all new use-flags for a specific package. @param cpv: the package for which to remove the flags - @type cpv: string (cpv) or L{geneticone.Package}-object""" + @type cpv: string (cpv) or L{backend.Package}-object""" if isinstance(cpv, package.Package): cpv = cpv.get_cpv() @@ -174,7 +174,7 @@ def remove_new_use_flags (cpv): def get_new_use_flags (cpv): """Gets all the new use-flags for a specific package. @param cpv: the package for which to remove the flags - @type cpv: string (cpv) or L{geneticone.Package}-object + @type cpv: string (cpv) or L{backend.Package}-object @returns: list of flags @rtype: list""" @@ -438,7 +438,7 @@ arch = "" def set_testing (pkg, enable): """Enables the package for installing when it is marked as testing (~ARCH). @param pkg: the package - @type pkg: string (cpv) or L{geneticone.Package}-object + @type pkg: string (cpv) or L{backend.Package}-object @param enable: controls whether to enable (True) or disable (False) for test-installing @type enable: boolean""" diff --git a/geneticone/backend/portage_helper.py b/geneticone/backend/portage_helper.py index 3346aaf..5703875 100644 --- a/geneticone/backend/portage_helper.py +++ b/geneticone/backend/portage_helper.py @@ -33,7 +33,7 @@ def find_lambda (name): return lambda x: True def geneticize_list (list_of_packages): - """Convertes a list of gentoolkit.Packages into L{geneticone.backend.Packages}. + """Convertes a list of gentoolkit.Packages into L{backend.Package}s. @param list_of_packages: the list of packages @type list_of_packages: list of gentoolkit.Packages @returns: converted list diff --git a/geneticone/gui/gui_helper.py b/geneticone/gui/gui_helper.py index 0113342..acbccd3 100644 --- a/geneticone/gui/gui_helper.py +++ b/geneticone/gui/gui_helper.py @@ -21,13 +21,18 @@ import pty import vte class Database: + """An internal database which holds a simple dictionary cat -> [package_list].""" def __init__ (self): + """Constructor.""" self.db = {} - def populate (self, cat = None): - packages = backend.find_all_packages(name = cat, withVersion = False) - installed = backend.find_all_installed_packages(name = cat, withVersion = False) + def populate (self, category = None): + """Populates the database. + @param category: An optional category - so only packages of this category are inserted. + @type category: string""" + packages = backend.find_all_packages(name = category, withVersion = False) + installed = backend.find_all_installed_packages(name = category, withVersion = False) for p in packages: list = p.split("/") cat = list[0] @@ -37,13 +42,25 @@ class Database: if not cat in self.db: self.db[cat] = [] self.db[cat].append(pkg) + for key in self.db: + self.db[key].sort(cmp=cmp, key=str.lower) + def get_cat (self, cat): + """Returns the packages in the category. + @param cat: category to return the packages from + @type cat: string + @return: list of packages or [] + @rtype: list of strings""" try: return self.db[cat] except KeyError: # cat is in category list - but not in portage return [] def reload (self, cat): + """Reloads the given category. + @param cat: category + @type cat: string""" + del self.db[cat] self.populate(cat+"/") @@ -57,8 +74,8 @@ class EmergeQueue: @type tree: gtk.TreeStore @param console: Output is shown here. Default: None @type console: vte.Terminal - @param packages: The list of packages sorted by categories. We will delete the appropriate category if we updated sth. Default: None - @type packages: dictionary: {category: list_of_packages}.""" + @param db: A database instance. + @type db: Database""" self.mergequeue = [] self.unmergequeue = [] @@ -82,7 +99,7 @@ class EmergeQueue: @param cpv: The package to append. @type cpv: string (cat/pkg-ver) - @raise geneticone.BlockedException: When occured during dependency-calculation.""" + @raise geneticone.backend.BlockedException: When occured during dependency-calculation.""" # get dependencies if cpv in self.deps: @@ -117,7 +134,8 @@ class EmergeQueue: @param unmerge: Set to True if you want to unmerge this package - else False. Default: False @type unmerge: boolean @param update: Set to True if a package is going to be updated (e.g. if the use-flags changed). Default: False - @type update: boolean""" + @type update: boolean + @raises geneticone.backend.PackageNotFoundException: if trying to add a package which does not exist""" if not unmerge: try: @@ -151,7 +169,7 @@ class EmergeQueue: self.tree.append(self.unmergeIt, [cpv]) def _update_packages(self, packages, process = None): - """This updates the packages-list. It simply removes all affected categories so they have to be rebuilt. + """This updates the packages-list. It simply makes the db to rebuild the specific category. @param packages: The packages which we emerged. @type packages: list of cpvs diff --git a/geneticone/gui/windows.py b/geneticone/gui/windows.py index 4259848..95703ce 100644 --- a/geneticone/gui/windows.py +++ b/geneticone/gui/windows.py @@ -11,7 +11,7 @@ # our backend stuff -VERSION = "0.3.1" +VERSION = "0.3.4" MENU_EMERGE = 1 MENU_UNEMERGE = 2 @@ -34,6 +34,7 @@ import vte from portage_util import unique_array class AboutWindow: + """A window showing the "about"-informations.""" def __init__ (self, parent): # window @@ -65,6 +66,55 @@ Copyright (C) 2006 Necoro d.M. <necoro@necoro.net> self.window.show_all() +class SearchWindow: + """A window showing the results of a search process.""" + + def __init__ (self, parent, list, jump_to): + # window + self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) + self.window.set_title("Search results") + self.window.set_modal(True) + self.window.set_transient_for(parent) + self.window.set_destroy_with_parent(True) + self.window.set_resizable(False) + self.window.set_default_size(1,1) + self.window.connect("key-press-event", self.cb_key_pressed) + self.list = list + self.jump_to = jump_to + + box = gtk.HBox(False) + self.window.add(box) + + self.combo = gtk.combo_box_new_text() + for x in list: + self.combo.append_text(x) + self.combo.set_active(0) + self.combo.connect("key-press-event", self.cb_key_pressed) + + box.pack_start(self.combo) + + okBtn = gtk.Button("OK") + okBtn.connect("clicked", self.cb_ok_btn_clicked) + box.pack_start(okBtn) + + self.window.show_all() + + def cb_ok_btn_clicked (self, button, data = None): + self.window.destroy() + self.jump_to(self.list[self.combo.get_active()]) + return True + + def cb_key_pressed (self, widget, event): + keyname = gtk.gdk.keyval_name(event.keyval) + if keyname == "Return": # take it as an "OK" if Enter is pressed + self.cb_ok_btn_clicked(self,widget) + return True + elif keyname == "Escape": + self.window.destroy() + return True + else: + return False + class PackageWindow: """A window with data about a specfic package.""" @@ -86,8 +136,7 @@ class PackageWindow: self.window.set_destroy_with_parent(True) self.window.set_resizable(False) self.window.set_default_size(1,1) # as small as possible - self.window.connect("delete-event", lambda a,b: False) - #self.window.connect("configure-event", self.cbSizeCheck) + self.window.connect("key-press-event", self.cb_key_press_event) # packages and installed packages self.packages = backend.sort_package_list(backend.get_all_versions(cp)) @@ -103,12 +152,12 @@ class PackageWindow: # the label (must be here, because it depends on the combo box) desc = self.actual_package().get_env_var("DESCRIPTION") - use_markup = True if not desc: desc = "<no description>" use_markup = False else: desc = "<b>"+desc+"</b>" + use_markup = True self.descLabel = gtk.Label(desc) self.descLabel.set_line_wrap(True) self.descLabel.set_justify(gtk.JUSTIFY_CENTER) @@ -162,36 +211,54 @@ class PackageWindow: buttonHB.pack_start(self.cancelBtn) # current status - self.cb_changed(self.vCombo) + self.cb_combo_changed(self.vCombo) # show self.window.show_all() - def cb_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) + def update_checkboxes (self): + """Updates the checkboxes.""" + self.installedCheck.set_active(self.actual_package().is_installed()) + self.maskedCheck.set_active(self.actual_package().is_masked()) + self.testingCheck.set_active((self.actual_package().get_mask_status() % 3) == 1) + + 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)]) - # build new - self.useList = self.build_use_list() - self.useListScroll.add(self.useList) - self.update_checkboxes() + return store - self.useListScroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_NEVER) + def build_use_list (self): + """Builds the useList.""" + store = gtk.ListStore(bool, str, str) + self.fill_use_list(store) - # set emerge-button-label - if not self.actual_package().is_installed(): - self.emergeBtn.set_label("_Emerge") - self.unmergeBtn.set_sensitive(False) + # 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: - 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 + view.set_child_visible(True) + return view def build_vers_combo (self): """Creates the combo box with the different versions.""" @@ -215,7 +282,7 @@ class PackageWindow: except AttributeError: # no package found combo.set_active(0) - combo.connect("changed", self.cb_changed) + combo.connect("changed", self.cb_combo_changed) return combo @@ -223,6 +290,38 @@ class PackageWindow: """Returns the actual package (a backend.Package-object).""" return self.packages[self.vCombo.get_active()] + def cb_key_press_event (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 + + def cb_combo_changed (self, combo, data = None): + """Callback for the changed ComboBox. + It then rebuilds the useList and the checkboxes.""" + + store = self.useList.get_model() + store.clear() + self.fill_use_list(store) + + self.update_checkboxes() + + # 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): @@ -272,79 +371,6 @@ class PackageWindow: self.flagChanged = True return True - def update_checkboxes (self): - """Updates the checkboxes.""" - self.installedCheck.set_active(self.actual_package().is_installed()) - self.maskedCheck.set_active(self.actual_package().is_masked()) - self.testingCheck.set_active((self.actual_package().get_mask_status() % 3) == 1) - - def build_use_list (self): - """Builds the useList.""" - store = gtk.ListStore(bool, str, str) - - pkg = self.actual_package() - for use in pkg.get_all_use_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)]) - - # 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: - view.set_child_visible(False) - else: - view.set_child_visible(True) - return view - -class SearchWindow: - """A window showing the results of a search process.""" - - def __init__ (self, parent, list, jump_to): - # window - self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) - self.window.set_title("Search results") - self.window.set_modal(True) - self.window.set_transient_for(parent) - self.window.set_destroy_with_parent(True) - self.window.set_resizable(False) - self.window.set_default_size(1,1) - self.list = list - self.jump_to = jump_to - - box = gtk.HBox(False) - self.window.add(box) - - self.combo = gtk.combo_box_new_text() - for x in list: - self.combo.append_text(x) - self.combo.set_active(0) - - box.pack_start(self.combo) - - okBtn = gtk.Button("OK") - okBtn.connect("clicked", self.cb_ok_btn_clicked) - box.pack_start(okBtn) - - self.window.show_all() - - def cb_ok_btn_clicked (self, button, data = None): - self.window.destroy() - self.jump_to(self.list[self.combo.get_active()]) - class MainWindow: """Application main window.""" @@ -354,7 +380,6 @@ class MainWindow: # window self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) self.window.set_title("Genetic/One") - self.window.connect("delete_event", self.cb_delete) self.window.connect("destroy", self.cb_destroy) self.window.set_border_width(2) self.window.set_geometry_hints (self.window, min_width = 600, min_height = 800, max_height = gtk.gdk.screen_height(), max_width = gtk.gdk.screen_width()) @@ -376,6 +401,7 @@ class MainWindow: 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) @@ -465,14 +491,6 @@ class MainWindow: # set emerge queue self.queue = EmergeQueue(console=term, tree = emergeStore, db = self.db) - def cb_delete (self, widget, data = None): - """Returns false -> window is deleted.""" - return False - - def cb_destroy (self, widget, data = None): - """Calls main_quit().""" - gtk.main_quit() - def create_main_menu (self): """Creates the main menu. XXX: Rebuild to use UIManager""" # the menu-list @@ -489,35 +507,26 @@ class MainWindow: self.itemFactory.create_items(mainMenuDesc) return self.itemFactory.get_widget("<main>") - 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: - # remove old one - self.scroll_2.remove(self.pkgList) - # create new package list - self.pkgList = self.create_pkg_list(store.get_value(it,0), force) - self.scroll_2.add(self.pkgList) - self.scroll_2.show_all() - return False + 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. Gets the name of the category.""" + self.selCatName = name # actual category + 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) - 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 + return pkgList def create_cat_list (self): """Creates the category list.""" @@ -539,28 +548,38 @@ class MainWindow: return view - packages = {} # directory category -> [packages] - def create_pkg_list (self, name = None, force = False): - """Creates the package list. Gets the name of the category.""" - self.selCatName = name # actual category - store = gtk.ListStore(str) - - # calculate packages - if name: - for p in self.db.get_cat(name): - store.append([p]) - - # sort alphabetically - store.set_sort_column_id(0, gtk.SORT_ASCENDING) + 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() - # 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) + 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.pkgList.get_model().clear() + self.fill_pkg_store(self.pkgList.get_model(), store.get_value(it, 0)) + return False - return pkgList + 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.""" @@ -614,10 +633,6 @@ class MainWindow: else: SearchWindow(self.window, packages, self.jump_to) - def jump_to (self, cp): - """Is called when we want to jump to a specific package.""" - PackageWindow(self.window, cp, self.queue) - def main (self): """Main.""" gobject.threads_init() |