summaryrefslogtreecommitdiffstats
path: root/iw/GroupSelector.py
diff options
context:
space:
mode:
authorJeremy Katz <katzj@redhat.com>2005-12-08 06:03:04 +0000
committerJeremy Katz <katzj@redhat.com>2005-12-08 06:03:04 +0000
commit894a0653fde6a56909937e03e044570b6a8fd7fd (patch)
tree598fac75fdc132251ddc7700503d66133aedea6c /iw/GroupSelector.py
parentadaa65374ef56bb0c16abb5bad286c5a75c89236 (diff)
downloadanaconda-894a0653fde6a56909937e03e044570b6a8fd7fd.tar.gz
anaconda-894a0653fde6a56909937e03e044570b6a8fd7fd.tar.xz
anaconda-894a0653fde6a56909937e03e044570b6a8fd7fd.zip
2005-12-08 Jeremy Katz <katzj@redhat.com>
* installclasses/fedora.py (InstallClass.setGroupSelection): Get default groups from the backend * backend.py (AnacondaBackend.getDefaultGroups): Support for getting default groups * iw/GroupSelector.py: Guts of new group/package selection code. Eventually will live in son of s-c-packages. * ui/GroupSelector.glade: glade file for new group selection code * iw/package_gui.py: Basic shell for GroupSelector use in anaconda * yuminstall.py: Update for yum 2.5 API changes. Note that we now *require* yum-2.5.0-0.20051207 or newer (isPackageInstalled): Add method to see if package is installed for group selection. (_catchallCategory): Add method to take uncategorized groups and stick them somewhere (getDefaultGroups): Backend method for finding the default selected groups based on what comps says * gui.py (stepToClass): Move to new group selection code.
Diffstat (limited to 'iw/GroupSelector.py')
-rw-r--r--iw/GroupSelector.py349
1 files changed, 349 insertions, 0 deletions
diff --git a/iw/GroupSelector.py b/iw/GroupSelector.py
new file mode 100644
index 000000000..91676a01f
--- /dev/null
+++ b/iw/GroupSelector.py
@@ -0,0 +1,349 @@
+#!/usr/bin/python -tt
+#
+# Copyright 2005 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,sys
+import string
+
+import gtk
+import gtk.glade
+import gobject
+
+import yum
+import yum.Errors
+import repomd.mdErrors as mdErrors
+
+from rhpl.translate import _, N_, getDefaultLangs
+
+GLADE_FILE = "GroupSelector.glade"
+I18N_DOMAIN = "anaconda"
+
+# 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
+
+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 = 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._createStore()
+ self._populate()
+
+ def _createStore(self):
+ self.pkgstore = gtk.TreeStore(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)
+ renderer = gtk.CellRendererText()
+ column.pack_start(renderer, True)
+ column.add_attribute(renderer, 'markup', 1)
+ tree.append_column(column)
+
+ self.pkgstore.set_sort_column_id(1, gtk.SORT_ASCENDING)
+
+ def __deselectPackage(self, pkg):
+ # FIXME: this doesn't handle removing an installed package...
+ grpid = self.group.groupid
+ try:
+ pkgs = self.ayum.pkgSack.returnNewestByName(pkg)
+ except mdErrors.PackageSackError:
+ self.ayum.log(4, "no such package %s from group %s" %
+ (pkg, self.group.groupid))
+ if pkgs:
+ pkgs = self.ayum.bestPackagesFromList(pkgs)
+ for po in pkgs:
+ txmbrs = self.ayum.tsInfo.getMembers(pkgtup = po.pkgtup)
+ for txmbr in txmbrs:
+ try:
+ txmbr.groups.remove(grpid)
+ except ValueError:
+ self.ayum.log(4, "package %s was not marked in group %s" %(po, grpid))
+ if len(txmbr.groups) == 0:
+ self.ayum.tsInfo.remove(po.pkgtup)
+
+ def __selectPackage(self, pkg):
+ grpid = self.group.groupid
+ try:
+ txmbrs = self.ayum.install(name = pkg)
+ except yum.Errors.InstallError, e:
+ self.ayum.log(3, "No package named %s available to "
+ "be installed: %s" %(pkg, e))
+ else:
+ map(lambda x: x.groups.append(grpid), txmbrs)
+
+ def _pkgToggled(self, widget, path):
+ i = self.pkgstore.get_iter_from_string(path)
+ sel = self.pkgstore.get_value(i, 0)
+ pkg = self.pkgstore.get_value(i, 2)
+ if sel:
+ self.__deselectPackage(pkg)
+ else:
+ self.__selectPackage(pkg)
+ self.pkgstore.set_value(i, 0, not sel)
+
+
+ def __getPackageDescription(self, pkgname):
+ po = None
+ if self.ayum.rpmdb.installed(name = pkgname):
+ pkgtup = self.ayum.rpmdb.returnTupleByKeyword(name=pkgname)
+ if len(pkgtup) > 0:
+ po = self.ayum.getInstalledPackageObject(pkgtup[0])
+ else:
+ pos = self.ayum.pkgSack.searchNevra(name=pkgname)
+ if len(pos) > 0:
+ po = pos[0]
+ if po:
+ return po.returnSimple('summary').replace("\n", "")
+ return None
+
+ def _populate(self):
+ pkgs = self.group.default_packages.keys() + \
+ self.group.optional_packages.keys()
+ for pkg in pkgs:
+ desc = self.__getPackageDescription(pkg)
+ if desc is not None:
+ s = "<b>%s</b> - %s" %(pkg, desc)
+ else:
+ # if there's no description, it's not in the rpmdb or
+ # the pkgsack, so showing it doesn't do much good...
+ continue
+ self.pkgstore.append(None, [self.ayum.isPackageInstalled(pkg),
+ s, pkg])
+
+ def run(self):
+ self.window.show_all()
+ return self.window.run()
+
+ def destroy(self):
+ return self.window.destroy()
+
+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 = GLADE_FILE
+
+ self.xml = gtk.glade.XML(xmlfn, "groupSelectionBox",
+ domain=I18N_DOMAIN)
+ self.vbox = self.xml.get_widget("groupSelectionBox")
+ self._connectSignals()
+ self._createStores()
+ self.vbox.show()
+
+ def _connectSignals(self):
+ sigs = { "on_detailsButton_clicked": self._optionalPackagesDialog, }
+ self.xml.signal_autoconnect(sigs)
+
+ def _createStores(self):
+ self._createCategoryStore()
+ self._createGroupStore()
+
+ b = gtk.TextBuffer()
+ self.xml.get_widget("groupDescriptionTextView").set_buffer(b)
+ tag = b.create_tag('right-just')
+ tag.set_property('justification', gtk.JUSTIFY_RIGHT)
+
+ 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()
+
+ 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()
+
+ self.groupstore.set_sort_column_id(1, gtk.SORT_ASCENDING)
+ selection = tree.get_selection()
+ selection.connect("changed", self._groupSelected)
+
+ def _categorySelected(self, selection):
+ self.groupstore.clear()
+ (model, i) = selection.get_selected()
+ if not i:
+ return
+ cat = model.get_value(i, 1)
+ for g in cat.groups:
+ grp = self.ayum.comps.groups[g]
+ 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):
+ 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)
+ else:
+ pix = None
+ # FIXME: this needs to handle selected vs installed..
+ self.groupstore.append(None, [grp.selected, s, grp, pix])
+
+ def _groupSelected(self, selection):
+ (model, i) = selection.get_selected()
+ grp = None
+ if i:
+ grp = model.get_value(i, 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 = "%s\n\n" % _xmltrans(grp.description,
+ grp.translated_description)
+ else:
+ txt = _("No description available for %s.\n\n") % _xmltrans(grp.name,
+ grp.translated_name)
+ b.set_text(txt)
+
+ i = b.get_end_iter()
+ inst = 0
+ cnt = 0
+ pkgs = grp.packages # FIXME: or do we want just optional + default?
+ for p in pkgs:
+ if self.ayum.isPackageInstalled(p):
+ cnt += 1
+ inst += 1
+ elif self.ayum.pkgSack.searchNevra(name=p):
+ cnt += 1
+ else:
+ self.ayum.log(2, "no such package %s for %s" %(p, grp.groupid))
+ b.insert_with_tags_by_name(i, _("[%d/%d installed]") %(inst, cnt),
+ "right-just")
+
+ # details makes little sense if there aren't any optional packages
+ for p in grp.mandatory_packages.keys():
+ if self.ayum.pkgSack.searchNevra(name=p):
+ cnt -= 1
+ if cnt == 0:
+ self.xml.get_widget("detailsButton").set_sensitive(False)
+ else:
+ self.xml.get_widget("detailsButton").set_sensitive(True)
+
+ def _groupToggled(self, widget, path):
+ i = self.groupstore.get_iter_from_string(path)
+ cb = self.groupstore.get_value(i, 0)
+ self.groupstore.set_value(i, 0, not cb)
+ grp = self.groupstore.get_value(i, 2)
+ if not cb:
+ 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
+ self.__setGroupDescription(grp)
+
+ def populateCategories(self):
+ self.catstore.clear()
+ for cat in self.ayum.comps.categories.values():
+ s = "<span size=\"large\" weight=\"bold\">%s</span>" % _xmltrans(cat.name, cat.translated_name)
+ self.catstore.append(None, [s, cat])
+
+ def doRefresh(self):
+ self.populateCategories()
+
+ def _optionalPackagesDialog(self, *args):
+ selection = self.xml.get_widget("groupList").get_selection()
+ (model, i) = selection.get_selected()
+ if not i:
+ return
+ group = model.get_value(i, 2)
+
+ 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)