summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--anaconda.spec3
-rw-r--r--iw/GroupSelector.py678
-rw-r--r--iw/package_gui.py3
-rw-r--r--ui/GroupSelector.glade395
4 files changed, 1075 insertions, 4 deletions
diff --git a/anaconda.spec b/anaconda.spec
index 6cd683d61..dda122992 100644
--- a/anaconda.spec
+++ b/anaconda.spec
@@ -27,7 +27,6 @@ BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
%define yumver 2.9.2
%define rhplver 0.170
%define partedver 1.8.1
-%define pirutver 1.1.0
%define syscfgdatever 1.9.0
%define pythonpyblockver 0.24-1
%define libbdevidver 5.1.2-1
@@ -55,7 +54,6 @@ BuildRequires: libxml2-python
BuildRequires: mkinitrd-devel >= %{mkinitrdver}
BuildRequires: newt-devel
BuildRequires: pango-devel
-BuildRequires: pirut
BuildRequires: popt-devel
BuildRequires: pykickstart >= %{pykickstartver}
BuildRequires: python-devel
@@ -77,7 +75,6 @@ Requires: booty
Requires: parted >= %{partedver}
Requires: pyparted >= %{partedver}
Requires: yum >= %{yumver}
-Requires: pirut >= %{pirutver}
Requires: libxml2-python
Requires: python-urlgrabber
Requires: system-logos
diff --git a/iw/GroupSelector.py b/iw/GroupSelector.py
new file mode 100644
index 000000000..e057345fb
--- /dev/null
+++ b/iw/GroupSelector.py
@@ -0,0 +1,678 @@
+# Copyright 2005-2007 Red Hat, Inc.
+#
+# Jeremy Katz <katzj@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 only
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import os
+import logging
+import gettext
+
+import gtk
+import gtk.glade
+import gtk.gdk as gdk
+import gobject
+
+import yum
+import yum.Errors
+try:
+ import repomd.mdErrors as mdErrors
+except ImportError: # yum 2.9.x
+ mdErrors = yum.Errors
+from yum.constants import *
+
+I18N_DOMAIN="anaconda"
+
+import rpm
+
+def sanitizeString(s, translate = True):
+ if len(s) == 0:
+ return s
+
+ if not translate:
+ i18ndomains = []
+ elif hasattr(rpm, "expandMacro"):
+ i18ndomains = rpm.expandMacro("%_i18ndomains").split(":")
+ else:
+ i18ndomains = ["redhat-dist"]
+
+ # iterate over i18ndomains to find the translation
+ for d in i18ndomains:
+ r = gettext.dgettext(d, s)
+ if r != s:
+ s = r
+ break
+
+ s = s.replace("\n\n", "\x00")
+ s = s.replace("\n", " ")
+ s = s.replace("\x00", "\n\n")
+ s = s.replace("&", "&amp;")
+ s = s.replace("<", "&lt;")
+ s = s.replace(">", "&gt;")
+ if type(s) != unicode:
+ try:
+ s = unicode(s, "utf-8")
+ except UnicodeDecodeError, e:
+ print >> sys.stderr, "Unable to convert %s to a unicode object: %s" %(s, e)
+ return ""
+ return s
+
+# given a package object, spit out a string reasonable for the list widgets
+def listEntryString(po):
+ desc = po.returnSimple('summary') or ''
+ desc = "<b>%s</b> - %s" %(po, sanitizeString(desc))
+ return desc
+
+GLADE_FILE = "GroupSelector.glade"
+
+def _getgladefile(fn):
+ if os.path.exists(fn):
+ return fn
+ elif os.path.exists("data/%s" %(fn,)):
+ return "data/%s" %(fn,)
+ else:
+ return "/usr/share/pirut/ui/%s" %(fn,)
+
+t = gettext.translation(I18N_DOMAIN, "/usr/share/locale", fallback = True)
+_ = t.lgettext
+
+def getDefaultLangs():
+ languages = []
+ for envar in ('LANGUAGE', 'LC_ALL', 'LC_MESSAGES', 'LANG'):
+ val = os.environ.get(envar)
+ if val:
+ languages = val.split(':')
+ break
+ if 'C' not in languages:
+ languages.append('C')
+
+ # now normalize and expand the languages
+ nelangs = []
+ for lang in languages:
+ for nelang in gettext._expand_lang(lang):
+ if nelang not in nelangs:
+ nelangs.append(nelang)
+ return nelangs
+
+
+# kind of lame caching of translations so we don't always have
+# to do all the looping
+strs = {}
+def _xmltrans(base, thedict):
+ if strs.has_key(base):
+ return strs[base]
+
+ langs = getDefaultLangs()
+ for l in langs:
+ if thedict.has_key(l):
+ strs[base] = thedict[l]
+ return strs[base]
+ strs[base] = base
+ return base
+
+def _ui_comps_sort(one, two):
+ if one.display_order > two.display_order:
+ return 1
+ elif one.display_order < two.display_order:
+ return -1
+ elif _xmltrans(one.name, one.translated_name) > \
+ _xmltrans(two.name, two.translated_name):
+ return 1
+ elif _xmltrans(one.name, one.translated_name) < \
+ _xmltrans(two.name, two.translated_name):
+ return -1
+ return 0
+
+def _deselectPackage(ayum, group, pkg):
+ grpid = group.groupid
+ try:
+ pkgs = ayum.pkgSack.returnNewestByName(pkg)
+ except mdErrors.PackageSackError:
+ log = logging.getLogger("yum.verbose")
+ log.debug("no such package %s from group %s" %(pkg,
+ self.group.groupid))
+ if pkgs:
+ pkgs = ayum.bestPackagesFromList(pkgs)
+ for po in pkgs:
+ txmbrs = ayum.tsInfo.getMembers(pkgtup = po.pkgtup)
+ for txmbr in txmbrs:
+ try:
+ txmbr.groups.remove(grpid)
+ except ValueError:
+ log = logging.getLogger("yum.verbose")
+ log.debug("package %s was not marked in group %s" %(po, grpid))
+ if len(txmbr.groups) == 0:
+ ayum.tsInfo.remove(po.pkgtup)
+
+def _selectPackage(ayum, group, pkg):
+ grpid = group.groupid
+ try:
+ txmbrs = ayum.install(name = pkg)
+ except yum.Errors.InstallError, e:
+ log = logging.getLogger("yum.verbose")
+ log.info("No package named %s available to be installed: %s" %(pkg, e))
+ else:
+ map(lambda x: x.groups.append(grpid), txmbrs)
+
+def _groupHasPackages(grp, ayum):
+ # this checks to see if the given group has any packages available
+ # (ie, already installed or in the sack of available packages)
+ # so that we don't show empty groups
+ for p in grp.packages:
+ try:
+ pkgs = ayum.pkgSack.returnNewestByName(p)
+ return True
+ except yum.Errors.PackageSackError:
+ pass
+ try:
+ pkgs = ayum.rpmdb.returnNewestByName(p)
+ return True
+ except (IndexError, yum.Errors.PackageSackError):
+ pass
+ return False
+
+def _catHasGroupWithPackages(cat, ayum):
+ grps = map(lambda x: ayum.comps.return_group(x),
+ filter(lambda x: ayum.comps.has_group(x), cat.groups))
+ for g in grps:
+ if _groupHasPackages(g, ayum):
+ return True
+ return False
+
+class OptionalPackageSelector:
+ def __init__(self, yumobj, group, parent = None, getgladefunc = None):
+ self.ayum = yumobj
+ self.group = group
+
+ if getgladefunc:
+ xmlfn = getgladefunc(GLADE_FILE)
+ else:
+ xmlfn = _getgladefile(GLADE_FILE)
+
+ self.xml = gtk.glade.XML(xmlfn, "groupDetailsDialog",
+ domain=I18N_DOMAIN)
+
+ self.window = self.xml.get_widget("groupDetailsDialog")
+ if parent:
+ self.window.set_transient_for(parent)
+ self.window.set_title(_("Packages in %s") %
+ _xmltrans(group.name, group.translated_name))
+ self.window.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
+ self.window.set_size_request(600, 400)
+ self._createStore()
+ self._populate()
+
+ def __search_pkgs(self, model, col, key, i):
+ val = model.get_value(i, 2).returnSimple('name')
+ if val.lower().startswith(key.lower()):
+ return False
+ return True
+
+ def _createStore(self):
+ self.pkgstore = gtk.ListStore(gobject.TYPE_BOOLEAN,
+ gobject.TYPE_STRING,
+ gobject.TYPE_PYOBJECT)
+ tree = self.xml.get_widget("packageList")
+ tree.set_model(self.pkgstore)
+
+ column = gtk.TreeViewColumn(None, None)
+ cbr = gtk.CellRendererToggle()
+ cbr.connect ("toggled", self._pkgToggled)
+ column.pack_start(cbr, False)
+ column.add_attribute(cbr, 'active', 0)
+ tree.append_column(column)
+
+ column = gtk.TreeViewColumn(None, None)
+ renderer = gtk.CellRendererText()
+ column.pack_start(renderer, True)
+ column.add_attribute(renderer, 'markup', 1)
+ tree.append_column(column)
+ tree.set_search_equal_func(self.__search_pkgs)
+ tree.connect("row-activated", self._rowToggle)
+
+ self.pkgstore.set_sort_column_id(1, gtk.SORT_ASCENDING)
+
+ def _rowToggle(self, tree, path, col):
+ self._pkgToggled(None, path)
+
+ def _pkgToggled(self, widget, path):
+ if type(path) == type(str):
+ i = self.pkgstore.get_iter_from_string(path)
+ else:
+ i = self.pkgstore.get_iter(path)
+ sel = self.pkgstore.get_value(i, 0)
+ pkg = self.pkgstore.get_value(i, 2).returnSimple('name')
+ if sel and not self.ayum.simpleDBInstalled(name = pkg):
+ _deselectPackage(self.ayum, self.group, pkg)
+ elif sel:
+ self.ayum.remove(name = pkg)
+ elif self.ayum.simpleDBInstalled(name = pkg):
+ txmbrs = self.ayum.tsInfo.matchNaevr(name = pkg)
+ for tx in txmbrs:
+ if tx.output_state == TS_ERASE:
+ self.ayum.tsInfo.remove(tx.pkgtup)
+ else:
+ _selectPackage(self.ayum, self.group, pkg)
+ self.pkgstore.set_value(i, 0, not sel)
+
+
+ def __getPackageObject(self, pkgname):
+ pos = self.ayum.pkgSack.searchNevra(name=pkgname)
+ if len(pos) > 0:
+ return pos[0]
+ return None
+
+ def _populate(self):
+ pkgs = self.group.default_packages.keys() + \
+ self.group.optional_packages.keys()
+ for pkg in pkgs:
+ po = self.__getPackageObject(pkg)
+ if not po:
+ continue
+ self.pkgstore.append([self.ayum.isPackageInstalled(pkg), listEntryString(po), po])
+
+ def run(self):
+ self.window.show_all()
+ return self.window.run()
+
+ def destroy(self):
+ return self.window.destroy()
+
+# the GroupSelector requires a YumBase object which also implements the
+# following additional methods:
+# * isPackageInstalled(p): is there a package named p installed or selected
+# * isGroupInstalled(grp): is there a group grp installed or selected
+class GroupSelector:
+ def __init__(self, yumobj, getgladefunc = None, framefunc = None):
+ self.ayum = yumobj
+
+ self.getgladefunc = getgladefunc
+ self.framefunc = framefunc
+ if getgladefunc:
+ xmlfn = getgladefunc(GLADE_FILE)
+ else:
+ xmlfn = _getgladefile(GLADE_FILE)
+
+ self.xml = gtk.glade.XML(xmlfn, "groupSelectionBox",
+ domain=I18N_DOMAIN)
+ self.vbox = self.xml.get_widget("groupSelectionBox")
+ self.xml.get_widget("detailsButton").set_sensitive(False)
+
+ self.menuxml = gtk.glade.XML(xmlfn, "groupPopupMenu",
+ domain=I18N_DOMAIN)
+ self.groupMenu = self.menuxml.get_widget("groupPopupMenu")
+
+ self._connectSignals()
+ self._createStores()
+ self.vbox.show()
+
+ def _connectSignals(self):
+ sigs = { "on_detailsButton_clicked": self._optionalPackagesDialog,
+ "on_groupList_button_press": self._groupListButtonPress,
+ "on_groupList_popup_menu": self._groupListPopup, }
+ self.xml.signal_autoconnect(sigs)
+
+ menusigs = { "on_select_activate": self._selectAllPackages,
+ "on_selectgrp_activate": self._groupSelect,
+ "on_deselectgrp_activate": self._groupDeselect,
+ "on_deselect_activate": self._deselectAllPackages }
+ self.menuxml.signal_autoconnect(menusigs)
+
+ def _createStores(self):
+ self._createCategoryStore()
+ self._createGroupStore()
+
+ b = gtk.TextBuffer()
+ self.xml.get_widget("groupDescriptionTextView").set_buffer(b)
+
+ def _createCategoryStore(self):
+ # display string, category object
+ self.catstore = gtk.TreeStore(gobject.TYPE_STRING,
+ gobject.TYPE_PYOBJECT)
+ tree = self.xml.get_widget("categoryList")
+ tree.set_model(self.catstore)
+
+ renderer = gtk.CellRendererText()
+ column = gtk.TreeViewColumn('Text', renderer, markup=0)
+ column.set_clickable(False)
+ tree.append_column(column)
+ tree.columns_autosize()
+ tree.set_enable_search(False)
+
+ selection = tree.get_selection()
+ selection.connect("changed", self._categorySelected)
+
+ def _createGroupStore(self):
+ # checkbox, display string, object
+ self.groupstore = gtk.TreeStore(gobject.TYPE_BOOLEAN,
+ gobject.TYPE_STRING,
+ gobject.TYPE_PYOBJECT,
+ gobject.TYPE_OBJECT)
+ tree = self.xml.get_widget("groupList")
+ tree.set_model(self.groupstore)
+
+ column = gtk.TreeViewColumn(None, None)
+ column.set_clickable(True)
+ pixr = gtk.CellRendererPixbuf()
+ pixr.set_property('stock-size', 1)
+ column.pack_start(pixr, False)
+ column.add_attribute(pixr, 'pixbuf', 3)
+ cbr = gtk.CellRendererToggle()
+ column.pack_start(cbr, False)
+ column.add_attribute(cbr, 'active', 0)
+ cbr.connect ("toggled", self._groupToggled)
+ tree.append_column(column)
+
+ renderer = gtk.CellRendererText()
+ column = gtk.TreeViewColumn('Text', renderer, markup=1)
+ column.set_clickable(False)
+ tree.append_column(column)
+ tree.columns_autosize()
+ tree.set_enable_search(False)
+ tree.grab_focus()
+
+ selection = tree.get_selection()
+ selection.connect("changed", self._groupSelected)
+ selection.set_mode(gtk.SELECTION_MULTIPLE)
+
+ def _get_pix(self, fn):
+ imgsize = 24
+ pix = gtk.gdk.pixbuf_new_from_file(fn)
+ if pix.get_height() != imgsize or pix.get_width() != imgsize:
+ pix = pix.scale_simple(imgsize, imgsize,
+ gtk.gdk.INTERP_BILINEAR)
+ return pix
+
+ def _categorySelected(self, selection):
+ self.groupstore.clear()
+ (model, i) = selection.get_selected()
+ if not i:
+ return
+ cat = model.get_value(i, 1)
+
+ # fall back to the category pixbuf
+ fbpix = None
+ fn = "/usr/share/pixmaps/comps/%s.png" %(cat.categoryid,)
+ if os.access(fn, os.R_OK):
+ fbpix = self._get_pix(fn)
+ self._populateGroups(cat.groups, fbpix)
+
+ def _populateGroups(self, groups, defaultpix = None):
+ grps = map(lambda x: self.ayum.comps.return_group(x),
+ filter(lambda x: self.ayum.comps.has_group(x), groups))
+ grps.sort(_ui_comps_sort)
+ for grp in grps:
+ if not _groupHasPackages(grp, self.ayum):
+ continue
+ s = "<span size=\"large\" weight=\"bold\">%s</span>" % _xmltrans(grp.name, grp.translated_name)
+
+ fn = "/usr/share/pixmaps/comps/%s.png" % grp.groupid
+ if os.access(fn, os.R_OK):
+ pix = self._get_pix(fn)
+ elif defaultpix:
+ pix = defaultpix
+ else:
+ pix = None
+ self.groupstore.append(None,
+ [self.ayum.isGroupInstalled(grp),s,grp,pix])
+
+ tree = self.xml.get_widget("groupList")
+ gobject.idle_add(lambda x: x.scroll_to_point(0, 0), tree)
+ self.xml.get_widget("optionalLabel").set_text("")
+ self.xml.get_widget("detailsButton").set_sensitive(False)
+
+ # select the first group
+ i = self.groupstore.get_iter_first()
+ if i is not None:
+ sel = self.xml.get_widget("groupList").get_selection()
+ sel.select_iter(i)
+
+ def _groupSelected(self, selection):
+ if selection.count_selected_rows() != 1:
+ # if we have more groups (or no group) selected, then
+ # we can't show a description or allow selecting optional
+ self.__setGroupDescription(None)
+ return
+ (model, paths) = selection.get_selected_rows()
+ grp = model.get_value(model.get_iter(paths[0]), 2)
+ self.__setGroupDescription(grp)
+
+ def __setGroupDescription(self, grp):
+ b = self.xml.get_widget("groupDescriptionTextView").get_buffer()
+ b.set_text("")
+ if grp is None:
+ return
+
+ if grp.description:
+ txt = _xmltrans(grp.description, grp.translated_description)
+ else:
+ txt = _xmltrans(grp.name, grp.translated_name)
+
+ inst = 0
+ cnt = 0
+ pkgs = grp.default_packages.keys() + grp.optional_packages.keys()
+ for p in pkgs:
+ if self.ayum.isPackageInstalled(p):
+ cnt += 1
+ inst += 1
+ elif self.ayum.pkgSack.searchNevra(name=p):
+ cnt += 1
+ else:
+ log = logging.getLogger("yum.verbose")
+ log.debug("no such package %s for %s" %(p, grp.groupid))
+
+ b.set_text(txt)
+ if cnt == 0 or not self.ayum.isGroupInstalled(grp):
+ self.xml.get_widget("detailsButton").set_sensitive(False)
+ self.xml.get_widget("optionalLabel").set_text("")
+ else:
+ self.xml.get_widget("detailsButton").set_sensitive(True)
+ txt = t.ngettext("%d of %d optional package selected",
+ "%d of %d optional packages selected",
+ cnt) %(inst, cnt)
+ self.xml.get_widget("optionalLabel").set_markup(_("<i>%s</i>") %(txt,))
+
+ def _groupToggled(self, widget, path, sel = None, updateText = True):
+ if type(path) == type(str):
+ i = self.groupstore.get_iter_from_string(path)
+ else:
+ i = self.groupstore.get_iter(path)
+ if sel is None:
+ sel = not self.groupstore.get_value(i, 0)
+
+ self.groupstore.set_value(i, 0, sel)
+ grp = self.groupstore.get_value(i, 2)
+
+ self.vbox.window.set_cursor(gdk.Cursor(gdk.WATCH))
+
+ if sel:
+ self.ayum.selectGroup(grp.groupid)
+ else:
+ self.ayum.deselectGroup(grp.groupid)
+ # FIXME: this doesn't mark installed packages for removal.
+ # we probably want that behavior with s-c-p, but not anaconda
+
+ if updateText:
+ self.__setGroupDescription(grp)
+
+ self.vbox.window.set_cursor(None)
+
+ def populateCategories(self):
+ self.catstore.clear()
+ cats = self.ayum.comps.categories
+ cats.sort(_ui_comps_sort)
+ for cat in cats:
+ if not _catHasGroupWithPackages(cat, self.ayum):
+ continue
+ s = "<span size=\"large\" weight=\"bold\">%s</span>" % _xmltrans(cat.name, cat.translated_name)
+ self.catstore.append(None, [s, cat])
+
+ # select the first category
+ i = self.catstore.get_iter_first()
+ if i is not None:
+ sel = self.xml.get_widget("categoryList").get_selection()
+ sel.select_iter(i)
+
+ def _setupCatchallCategory(self):
+ # FIXME: this is a bad hack, but catch groups which aren't in
+ # a category yet are supposed to be user-visible somehow.
+ # conceivably should be handled by yum
+ grps = {}
+ for g in self.ayum.comps.groups:
+ if g.user_visible and _groupHasPackages(g, self.ayum):
+ grps[g.groupid] = g
+
+ for cat in self.ayum.comps.categories:
+ for g in cat.groups:
+ if grps.has_key(g):
+ del grps[g]
+
+ if len(grps.keys()) == 0:
+ return
+ c = yum.comps.Category()
+ c.name = _("Uncategorized")
+ c._groups = grps
+ c.categoryid = "uncategorized"
+
+ self.ayum.comps._categories[c.categoryid] = c
+
+ def doRefresh(self):
+ if len(self.ayum.comps.categories) == 0:
+ self.xml.get_widget("categorySW").hide()
+ self._populateGroups(map(lambda x: x.groupid,
+ self.ayum.comps.groups))
+ else:
+ self._setupCatchallCategory()
+ self.populateCategories()
+
+ def _getSelectedGroup(self):
+ """Return the selected group.
+ NOTE: this only ever returns one group."""
+ selection = self.xml.get_widget("groupList").get_selection()
+ (model, paths) = selection.get_selected_rows()
+ for p in paths:
+ return model.get_value(model.get_iter(p), 2)
+ return None
+
+ def _optionalPackagesDialog(self, *args):
+ group = self._getSelectedGroup()
+ if group is None:
+ return
+
+ pwin = self.vbox.get_parent() # hack to find the parent window...
+ while not isinstance(pwin, gtk.Window):
+ pwin = pwin.get_parent()
+ d = OptionalPackageSelector(self.ayum, group, pwin, self.getgladefunc)
+ if self.framefunc:
+ self.framefunc(d.window)
+ rc = d.run()
+ d.destroy()
+ self.__setGroupDescription(group)
+
+ def _groupSelect(self, *args):
+ selection = self.xml.get_widget("groupList").get_selection()
+ if selection.count_selected_rows() == 0:
+ return
+
+ (model, paths) = selection.get_selected_rows()
+ for p in paths:
+ self._groupToggled(model, p, True, False)
+
+ def _groupDeselect(self, *args):
+ selection = self.xml.get_widget("groupList").get_selection()
+ if selection.count_selected_rows() == 0:
+ return
+
+ (model, paths) = selection.get_selected_rows()
+ for p in paths:
+ self._groupToggled(model, p, False, False)
+
+ def _selectAllPackages(self, *args):
+ selection = self.xml.get_widget("groupList").get_selection()
+ if selection.count_selected_rows() == 0:
+ return
+ (model, paths) = selection.get_selected_rows()
+
+ self.vbox.window.set_cursor(gdk.Cursor(gdk.WATCH))
+
+ for p in paths:
+ i = model.get_iter(p)
+ grp = model.get_value(i, 2)
+
+ # ensure the group is selected
+ self.ayum.selectGroup(grp.groupid)
+ model.set_value(i, 0, True)
+
+ for pkg in grp.default_packages.keys() + \
+ grp.optional_packages.keys():
+ if self.ayum.isPackageInstalled(pkg):
+ continue
+ elif self.ayum.simpleDBInstalled(name = pkg):
+ txmbrs = self.ayum.tsInfo.matchNaevr(name = pkg)
+ for tx in txmbrs:
+ if tx.output_state == TS_ERASE:
+ self.ayum.tsInfo.remove(tx.pkgtup)
+ else:
+ _selectPackage(self.ayum, grp, pkg)
+
+ if len(paths) == 1:
+ self.__setGroupDescription(grp)
+ self.vbox.window.set_cursor(None)
+
+ def _deselectAllPackages(self, *args):
+ selection = self.xml.get_widget("groupList").get_selection()
+ if selection.count_selected_rows() == 0:
+ return
+ (model, paths) = selection.get_selected_rows()
+
+ for p in paths:
+ i = model.get_iter(p)
+ grp = model.get_value(i, 2)
+
+ for pkg in grp.default_packages.keys() + \
+ grp.optional_packages.keys():
+ if not self.ayum.isPackageInstalled(pkg):
+ continue
+ elif self.ayum.simpleDBInstalled(name=pkg):
+ self.ayum.remove(name=pkg)
+ else:
+ _deselectPackage(self.ayum, grp, pkg)
+ if len(paths) == 1:
+ self.__setGroupDescription(grp)
+
+ def __doGroupPopup(self, button, time):
+ menu = self.groupMenu
+ menu.popup(None, None, None, button, time)
+ menu.show_all()
+
+ def _groupListButtonPress(self, widget, event):
+ if event.button == 3:
+ x = int(event.x)
+ y = int(event.y)
+ pthinfo = widget.get_path_at_pos(x, y)
+ if pthinfo is not None:
+ sel = widget.get_selection()
+ if sel.count_selected_rows() == 1:
+ path, col, cellx, celly = pthinfo
+ widget.grab_focus()
+ widget.set_cursor(path, col, 0)
+ self.__doGroupPopup(event.button, event.time)
+ return 1
+
+ def _groupListPopup(self, widget):
+ sel = widget.get_selection()
+ if sel.count_selected_rows() > 0:
+ self.__doGroupPopup(0, 0)
+
+
diff --git a/iw/package_gui.py b/iw/package_gui.py
index c75a1427d..844ffee54 100644
--- a/iw/package_gui.py
+++ b/iw/package_gui.py
@@ -20,7 +20,8 @@
#
# FIXME: group selection isn't currently backend independent
-from pirut.GroupSelector import GroupSelector
+#from pirut.GroupSelector import GroupSelector
+from GroupSelector import GroupSelector
import gui
from iw_gui import *
diff --git a/ui/GroupSelector.glade b/ui/GroupSelector.glade
new file mode 100644
index 000000000..8b4aec612
--- /dev/null
+++ b/ui/GroupSelector.glade
@@ -0,0 +1,395 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkWindow" id="groupSelectionWindow">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">window1</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <signal name="destroy_event" handler="on_groupSelectionWindow_destroy_event" last_modification_time="Fri, 02 Dec 2005 21:41:59 GMT"/>
+ <signal name="delete_event" handler="on_groupSelectionWindow_delete_event" last_modification_time="Fri, 02 Dec 2005 21:42:23 GMT"/>
+
+ <child>
+ <widget class="GtkVBox" id="groupSelectionBox">
+ <property name="border_width">12</property>
+ <property name="width_request">700</property>
+ <property name="height_request">450</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox1">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="categorySW">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="categoryList">
+ <property name="width_request">275</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">False</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ <property name="fixed_height_mode">False</property>
+ <property name="hover_selection">False</property>
+ <property name="hover_expand">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="groupSW">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="groupList">
+ <property name="width_request">325</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">False</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ <property name="fixed_height_mode">False</property>
+ <property name="hover_selection">False</property>
+ <property name="hover_expand">False</property>
+ <signal name="button_press_event" handler="on_groupList_button_press" last_modification_time="Sat, 04 Feb 2006 01:22:04 GMT"/>
+ <signal name="popup_menu" handler="on_groupList_popup_menu" last_modification_time="Sat, 04 Feb 2006 01:22:13 GMT"/>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0.75</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox2">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow3">
+ <property name="height_request">82</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTextView" id="groupDescriptionTextView">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">False</property>
+ <property name="overwrite">False</property>
+ <property name="accepts_tab">True</property>
+ <property name="justification">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap_mode">GTK_WRAP_WORD</property>
+ <property name="cursor_visible">False</property>
+ <property name="pixels_above_lines">0</property>
+ <property name="pixels_below_lines">0</property>
+ <property name="pixels_inside_wrap">0</property>
+ <property name="left_margin">0</property>
+ <property name="right_margin">0</property>
+ <property name="indent">0</property>
+ <property name="text" translatable="yes"></property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="optionalLabel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_RIGHT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.949999988079</property>
+ <property name="yalign">1</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHButtonBox" id="hbuttonbox2">
+ <property name="border_width">6</property>
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkButton" id="detailsButton">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Optional packages</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_detailsButton_clicked" last_modification_time="Fri, 02 Dec 2005 21:39:06 GMT"/>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkDialog" id="groupDetailsDialog">
+ <property name="width_request">550</property>
+ <property name="height_request">300</property>
+ <property name="title" translatable="yes">dialog1</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+ <property name="modal">True</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">True</property>
+ <signal name="destroy" handler="on_groupDetailsDialog_destroy" last_modification_time="Tue, 06 Dec 2005 21:31:56 GMT"/>
+ <signal name="delete_event" handler="on_groupDetailsDialog_delete_event" last_modification_time="Tue, 06 Dec 2005 21:32:34 GMT"/>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="groupDetailsCloseButton">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-close</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-7</property>
+ <signal name="clicked" handler="on_groupDetailsCloseButton_clicked" last_modification_time="Tue, 06 Dec 2005 21:31:46 GMT"/>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox4">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Some packages associated with this group are not required to be installed but may provide additional functionality. Please choose the packages which you would like to have installed.</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">True</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="packageSW">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="packageList">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">False</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ <property name="fixed_height_mode">False</property>
+ <property name="hover_selection">False</property>
+ <property name="hover_expand">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkMenu" id="groupPopupMenu">
+
+ <child>
+ <widget class="GtkMenuItem" id="selectgrp">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Select</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_selectgrp_activate" last_modification_time="Wed, 13 Sep 2006 16:57:47 GMT"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="select">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Select all optional packages</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_select_activate" last_modification_time="Sat, 04 Feb 2006 00:26:28 GMT"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="deselectgrp">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Deselect</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_deselectgrp_activate" last_modification_time="Wed, 13 Sep 2006 16:57:47 GMT"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="deselect">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Deselect all optional packages</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_deselect_activate" last_modification_time="Sat, 04 Feb 2006 00:26:28 GMT"/>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>