Ejemplo n.º 1
0
    def __init__(self):
        gtk.Window.__init__(self)
        self.__gobject_init__()

        self.set_icon(getPixbuf("smart"))
        self.set_title(_("Change Summary"))
        self.set_modal(True)
        self.set_position(gtk.WIN_POS_CENTER)
        self.set_geometry_hints(min_width=600, min_height=400)
        def delete(widget, event):
            gtk.main_quit()
            return True
        self.connect("delete-event", delete)

        self._vbox = gtk.VBox()
        self._vbox.set_border_width(10)
        self._vbox.set_spacing(10)
        self._vbox.show()
        self.add(self._vbox)

        self._label = gtk.Label()
        self._vbox.pack_start(self._label, expand=False)

        self._pv = GtkPackageView()
        self._pv.getTreeView().set_headers_visible(False)
        self._pv.setExpandPackage(True)
        self._pv.show()
        self._vbox.pack_start(self._pv)

        self._sizelabel = gtk.Label()
        self._vbox.pack_start(self._sizelabel, expand=False)

        self._confirmbbox = gtk.HButtonBox()
        self._confirmbbox.set_spacing(10)
        self._confirmbbox.set_layout(gtk.BUTTONBOX_END)
        self._vbox.pack_start(self._confirmbbox, expand=False)

        self._cancelbutton = gtk.Button(stock="gtk-cancel")
        self._cancelbutton.show()
        self._cancelbutton.connect("clicked", lambda x: gtk.main_quit())
        self._confirmbbox.pack_start(self._cancelbutton)

        self._okbutton = gtk.Button(stock="gtk-ok")
        self._okbutton.show()
        def clicked(x):
            self._result = True
            gtk.main_quit()
        self._okbutton.connect("clicked", clicked)
        self._confirmbbox.pack_start(self._okbutton)

        self._closebbox = gtk.HButtonBox()
        self._closebbox.set_spacing(10)
        self._closebbox.set_layout(gtk.BUTTONBOX_END)
        self._vbox.pack_start(self._closebbox, expand=False)

        self._closebutton = gtk.Button(stock="gtk-close")
        self._closebutton.show()
        self._closebutton.connect("clicked", lambda x: gtk.main_quit())
        self._closebbox.pack_start(self._closebutton)
Ejemplo n.º 2
0
    def __init__(self):
        gtk.Alignment.__init__(self, 0.5, 0.5, 1.0, 1.0)

        self._pkg = None
        self._changeset = None

        font = self.style.font_desc.copy()
        font.set_size(font.get_size()-pango.SCALE)

        boldfont = font.copy()
        boldfont.set_weight(pango.WEIGHT_BOLD)

        self._notebook = gtk.Notebook()
        self._notebook.show()
        self.add(self._notebook)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        #sw.set_border_width(5)
        sw.show()

        table = gtk.Table()
        table.set_row_spacings(2)
        table.set_col_spacings(5)
        table.set_border_width(5)
        table.show()
        sw.add_with_viewport(table)

        self._info = type("Info", (), {})()

        attrsleft = pango.AttrList()
        attrsleft.insert(pango.AttrFontDesc(font, 0, -1))
        attrsright = pango.AttrList()
        attrsright.insert(pango.AttrFontDesc(boldfont, 0, -1))

        row = 0
        for attr, text in [("status", _("Status:")),
                           ("priority", _("Priority:")),
                           ("group", _("Group:")),
                           ("installedsize", _("Installed Size:")),
                           ("channels", _("Channels:"))]:
            label = gtk.Label(text)
            label.set_attributes(attrsleft)
            if attr == "channels":
                label.set_alignment(1.0, 0.0)
            else:
                label.set_alignment(1.0, 0.5)
            label.show()
            table.attach(label, 0, 1, row, row+1, gtk.FILL, gtk.FILL)
            setattr(self._info, attr+"_label", label)
            label = gtk.Label()
            label.set_attributes(attrsright)
            label.set_alignment(0.0, 0.5)
            label.show()
            table.attach(label, 1, 2, row, row+1, gtk.FILL, gtk.FILL)
            setattr(self._info, attr, label)
            row += 1

        label = gtk.Label(_("General"))
        self._notebook.append_page(sw, label)


        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.set_border_width(5)
        sw.show()

        self._descrtv = gtk.TextView()
        self._descrtv.set_editable(False)
        self._descrtv.set_cursor_visible(False)
        self._descrtv.set_left_margin(5)
        self._descrtv.set_right_margin(5)
        self._descrtv.show()
        buffer = self._descrtv.get_buffer()
        buffer.create_tag("description", font_desc=font)
        buffer.create_tag("summary", font_desc=boldfont)
        sw.add(self._descrtv)

        label = gtk.Label(_("Description"))
        self._notebook.append_page(sw, label)


        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.set_border_width(5)
        sw.show()

        self._conttv = gtk.TextView()
        self._conttv.set_editable(False)
        self._conttv.set_cursor_visible(False)
        self._conttv.set_left_margin(5)
        self._conttv.set_right_margin(5)
        self._conttv.show()
        buffer = self._conttv.get_buffer()
        buffer.create_tag("content", font_desc=font)
        sw.add(self._conttv)

        label = gtk.Label(_("Content"))
        self._notebook.append_page(sw, label)


        self._relations = GtkPackageView()
        self._relations.set_border_width(5)
        self._relations.getTreeView().set_headers_visible(False)
        self._relations.show()

        label = gtk.Label(_("Relations"))
        self._notebook.append_page(self._relations, label)


        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        sw.set_border_width(5)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.show()

        model = gtk.ListStore(gobject.TYPE_STRING,
                              gobject.TYPE_STRING,
                              gobject.TYPE_STRING)
        self._urls = gtk.TreeView(model)
        self._urls.set_headers_visible(False)
        self._urls.show()
        renderer = gtk.CellRendererText()
        renderer.set_property("font-desc", font)
        self._urls.insert_column_with_attributes(-1, _("Channel"),
                                                 renderer, text=0)
        self._urls.insert_column_with_attributes(-1, _("Size"),
                                                 renderer, text=1)
        self._urls.insert_column_with_attributes(-1, _("URL"),
                                                 renderer, text=2)
        sw.add(self._urls)

        label = gtk.Label(_("URLs"))
        self._notebook.append_page(sw, label)


        self._notebook.connect("switch_page", self._switchPage)
Ejemplo n.º 3
0
class GtkPackageInfo(gtk.Alignment):

    def __init__(self):
        gtk.Alignment.__init__(self, 0.5, 0.5, 1.0, 1.0)

        self._pkg = None
        self._changeset = None

        font = self.style.font_desc.copy()
        font.set_size(font.get_size()-pango.SCALE)

        boldfont = font.copy()
        boldfont.set_weight(pango.WEIGHT_BOLD)

        self._notebook = gtk.Notebook()
        self._notebook.show()
        self.add(self._notebook)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        #sw.set_border_width(5)
        sw.show()

        table = gtk.Table()
        table.set_row_spacings(2)
        table.set_col_spacings(5)
        table.set_border_width(5)
        table.show()
        sw.add_with_viewport(table)

        self._info = type("Info", (), {})()

        attrsleft = pango.AttrList()
        attrsleft.insert(pango.AttrFontDesc(font, 0, -1))
        attrsright = pango.AttrList()
        attrsright.insert(pango.AttrFontDesc(boldfont, 0, -1))

        row = 0
        for attr, text in [("status", _("Status:")),
                           ("priority", _("Priority:")),
                           ("group", _("Group:")),
                           ("installedsize", _("Installed Size:")),
                           ("channels", _("Channels:"))]:
            label = gtk.Label(text)
            label.set_attributes(attrsleft)
            if attr == "channels":
                label.set_alignment(1.0, 0.0)
            else:
                label.set_alignment(1.0, 0.5)
            label.show()
            table.attach(label, 0, 1, row, row+1, gtk.FILL, gtk.FILL)
            setattr(self._info, attr+"_label", label)
            label = gtk.Label()
            label.set_attributes(attrsright)
            label.set_alignment(0.0, 0.5)
            label.show()
            table.attach(label, 1, 2, row, row+1, gtk.FILL, gtk.FILL)
            setattr(self._info, attr, label)
            row += 1

        label = gtk.Label(_("General"))
        self._notebook.append_page(sw, label)


        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.set_border_width(5)
        sw.show()

        self._descrtv = gtk.TextView()
        self._descrtv.set_editable(False)
        self._descrtv.set_cursor_visible(False)
        self._descrtv.set_left_margin(5)
        self._descrtv.set_right_margin(5)
        self._descrtv.show()
        buffer = self._descrtv.get_buffer()
        buffer.create_tag("description", font_desc=font)
        buffer.create_tag("summary", font_desc=boldfont)
        sw.add(self._descrtv)

        label = gtk.Label(_("Description"))
        self._notebook.append_page(sw, label)


        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.set_border_width(5)
        sw.show()

        self._conttv = gtk.TextView()
        self._conttv.set_editable(False)
        self._conttv.set_cursor_visible(False)
        self._conttv.set_left_margin(5)
        self._conttv.set_right_margin(5)
        self._conttv.show()
        buffer = self._conttv.get_buffer()
        buffer.create_tag("content", font_desc=font)
        sw.add(self._conttv)

        label = gtk.Label(_("Content"))
        self._notebook.append_page(sw, label)


        self._relations = GtkPackageView()
        self._relations.set_border_width(5)
        self._relations.getTreeView().set_headers_visible(False)
        self._relations.show()

        label = gtk.Label(_("Relations"))
        self._notebook.append_page(self._relations, label)


        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        sw.set_border_width(5)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.show()

        model = gtk.ListStore(gobject.TYPE_STRING,
                              gobject.TYPE_STRING,
                              gobject.TYPE_STRING)
        self._urls = gtk.TreeView(model)
        self._urls.set_headers_visible(False)
        self._urls.show()
        renderer = gtk.CellRendererText()
        renderer.set_property("font-desc", font)
        self._urls.insert_column_with_attributes(-1, _("Channel"),
                                                 renderer, text=0)
        self._urls.insert_column_with_attributes(-1, _("Size"),
                                                 renderer, text=1)
        self._urls.insert_column_with_attributes(-1, _("URL"),
                                                 renderer, text=2)
        sw.add(self._urls)

        label = gtk.Label(_("URLs"))
        self._notebook.append_page(sw, label)


        self._notebook.connect("switch_page", self._switchPage)

    def _switchPage(self, notebook, page, pagenum):
        self.setPackage(self._pkg, _pagenum=pagenum)

    def setChangeSet(self, changeset):
        self._changeset = changeset

    def setPackage(self, pkg, _pagenum=None):

        self._pkg = pkg

        if _pagenum is not None:
            num = _pagenum
        else:
            num = self._notebook.get_current_page()

        if num == 0:

            # Update general information

            if not pkg:
                self._info.status.set_text("")
                self._info.group.set_text("")
                self._info.installedsize.set_text("")
                self._info.priority.set_text("")
                self._info.channels.set_text("")
                return

            group = None
            installedsize = None
            channels = []
            for loader in pkg.loaders:
                info = loader.getInfo(pkg)
                if group is None:
                    group = info.getGroup()
                if installedsize is None:
                    installedsize = info.getInstalledSize()
                channel = loader.getChannel()
                channels.append("%s (%s)" %
                                (channel.getName() or channel.getAlias(),
                                 channel.getAlias()))

            flags = pkgconf.testAllFlags(pkg)
            if flags:
                flags.sort()
                flags = " (%s)" % ", ".join(flags)
            else:
                flags = ""

            status = pkg.installed and _("Installed") or _("Available")
            self._info.status.set_text(status+flags)
            self._info.group.set_text(group or _("Unknown"))
            self._info.priority.set_text(str(pkg.getPriority()))
            self._info.channels.set_text("\n".join(channels))

            if installedsize:
                self._info.installedsize.set_text(sizeToStr(installedsize))
                self._info.installedsize.show()
                self._info.installedsize_label.show()
            else:
                self._info.installedsize.hide()
                self._info.installedsize_label.hide()

        elif num == 1:

            # Update summary/description

            descrbuf = self._descrtv.get_buffer()
            descrbuf.set_text("")
            if not pkg: return

            iter = descrbuf.get_end_iter()
            for loader in pkg.loaders:
                info = loader.getInfo(pkg)
                summary = info.getSummary()
                if summary:
                    descrbuf.insert_with_tags_by_name(iter, summary+"\n\n",
                                                      "summary")
                    description = info.getDescription()
                    if description != summary:
                        descrbuf.insert_with_tags_by_name(iter,
                                                          description+"\n\n",
                                                          "description")
                    break
            else:
                loader = pkg.loaders.keys()[0]

        elif num == 2:

            # Update contents

            contbuf = self._conttv.get_buffer()
            contbuf.set_text("")
            if not pkg: return

            iter = contbuf.get_end_iter()
            for loader in pkg.loaders:
                if loader.getInstalled():
                    break
            else:
                loader = pkg.loaders.keys()[0]
            info = loader.getInfo(pkg)
            pathlist = info.getPathList()
            pathlist.sort()
            for path in pathlist:
                contbuf.insert_with_tags_by_name(iter, path+"\n", "content")

        elif num == 3:

            # Update relations

            if not pkg:
                self._relations.setPackages([])
                return

            self._setRelations(pkg)

        elif num == 4:

            # Update URLs

            model = self._urls.get_model()
            model.clear()

            if not pkg:
                return

            items = []
            for loader in pkg.loaders:
                channel = loader.getChannel()
                alias = channel.getAlias()
                info = loader.getInfo(pkg)
                for url in info.getURLs():
                    items.append((alias, sizeToStr(info.getSize(url)), url))

            items.sort()

            lastitem = None
            for item in items:
                if item != lastitem:
                    lastitem = item
                    model.append(item)

    def _setRelations(self, pkg):

        class Sorter(str):
            ORDER = [_("Provides"), _("Upgrades"),
                     _("Requires"), _("Conflicts")]
            def __cmp__(self, other):
                return cmp(self.ORDER.index(str(self)),
                           self.ORDER.index(str(other)))
            def __lt__(self, other):
                return cmp(self, other) < 0

        relations = {}

        for prv in pkg.provides:

            prvmap = {}
            
            requiredby = []
            for req in prv.requiredby:
                requiredby.extend(req.packages)
            if requiredby:
                prvmap[_("Required By")] = requiredby

            upgradedby = []
            for upg in prv.upgradedby:
                upgradedby.extend(upg.packages)
            if upgradedby:
                prvmap[_("Upgraded By")] = upgradedby

            conflictedby = []
            for cnf in prv.conflictedby:
                conflictedby.extend(cnf.packages)
            if conflictedby:
                prvmap[_("Conflicted By")] = conflictedby

            if prvmap:
                relations.setdefault(Sorter(_("Provides")), {})[str(prv)] = \
                                                                        prvmap

        requires = {}
        for req in pkg.requires:
            lst = requires.setdefault(str(req), [])
            for prv in req.providedby:
                lst.extend(prv.packages)
            lst[:] = dict.fromkeys(lst).keys()
        if requires:
            relations[Sorter(_("Requires"))] = requires

        upgrades = {}
        for upg in pkg.upgrades:
            lst = upgrades.setdefault(str(upg), [])
            for prv in upg.providedby:
                lst.extend(prv.packages)
            lst[:] = dict.fromkeys(lst).keys()
        if upgrades:
            relations[Sorter(_("Upgrades"))] = upgrades

        conflicts = {}
        for cnf in pkg.conflicts:
            lst = conflicts.setdefault(str(cnf), [])
            for prv in cnf.providedby:
                lst.extend(prv.packages)
            lst[:] = dict.fromkeys(lst).keys()
        if conflicts:
            relations[Sorter(_("Conflicts"))] = conflicts

        self._relations.setPackages(relations, self._changeset)
Ejemplo n.º 4
0
    def __init__(self):
        gtk.Alignment.__init__(self, 0.5, 0.5, 1.0, 1.0)

        self._pkg = None
        self._changeset = None

        font = self.style.font_desc.copy()
        font.set_size(font.get_size() - pango.SCALE)

        boldfont = font.copy()
        boldfont.set_weight(pango.WEIGHT_BOLD)

        if sysconf.get("gtk-description-fontsize"):
            fontsize = int(sysconf.get("gtk-description-fontsize"))

            descfont = self.style.font_desc.copy()
            descfont.set_size(fontsize * pango.SCALE)

            bolddescfont = descfont.copy()
            bolddescfont.set_weight(pango.WEIGHT_BOLD)
        else:
            descfont = font
            bolddescfont = boldfont

        self._notebook = gtk.Notebook()
        self._notebook.show()
        self.add(self._notebook)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        #sw.set_border_width(5)
        sw.show()

        table = gtk.Table()
        table.set_row_spacings(2)
        table.set_col_spacings(5)
        table.set_border_width(5)
        table.show()
        sw.add_with_viewport(table)

        self._info = type("Info", (), {})()

        attrsleft = pango.AttrList()
        attrsleft.insert(pango.AttrFontDesc(font, 0, -1))
        attrsright = pango.AttrList()
        attrsright.insert(pango.AttrFontDesc(boldfont, 0, -1))

        style = sw.get_style()
        bgcolor = style.bg[gtk.STATE_NORMAL]

        self._reftv = gtk.TextView()
        self._reftv.modify_base(gtk.STATE_NORMAL, bgcolor)
        self._reftv.set_editable(False)
        self._reftv.set_cursor_visible(False)
        self._reftv.connect("motion-notify-event", self.motion_notify_event)
        self._reftv.connect("event-after", self.event_after)
        self._reftv.show()
        self._reftv.get_buffer().create_tag("reference", font_desc=font)

        row = 0
        for attr, text in [("status", _("Status:")),
                           ("priority", _("Priority:")),
                           ("group", _("Group:")),
                           ("installedsize", _("Installed Size:")),
                           ("channels", _("Channels:")),
                           ("reference", _("Reference URLs:"))]:
            label = gtk.Label(text)
            label.set_attributes(attrsleft)
            if attr == "channels":
                label.set_alignment(1.0, 0.0)
            else:
                label.set_alignment(1.0, 0.5)
            label.show()
            table.attach(label, 0, 1, row, row + 1, gtk.FILL, gtk.FILL)
            setattr(self._info, attr + "_label", label)
            if attr == "reference":
                label = self._reftv
            else:
                label = gtk.Label()
                label.set_attributes(attrsright)
                label.set_alignment(0.0, 0.5)
            label.show()
            table.attach(label, 1, 2, row, row + 1, gtk.FILL, gtk.FILL)
            setattr(self._info, attr, label)
            row += 1

        label = gtk.Label(_("General"))
        self._notebook.append_page(sw, label)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.set_border_width(5)
        sw.show()

        self._descrtv = gtk.TextView()
        self._descrtv.set_editable(False)
        self._descrtv.set_cursor_visible(False)
        self._descrtv.set_left_margin(5)
        self._descrtv.set_right_margin(5)
        self._descrtv.show()
        buffer = self._descrtv.get_buffer()
        buffer.create_tag("description", font_desc=descfont)
        buffer.create_tag("summary", font_desc=bolddescfont)
        sw.add(self._descrtv)

        label = gtk.Label(_("Description"))
        self._notebook.append_page(sw, label)

        vbox = gtk.VBox()
        vbox.show()

        filtertable = gtk.Table(1, 1)
        filtertable.set_row_spacings(5)
        filtertable.set_col_spacings(5)
        filtertable.set_border_width(5)
        filtertable.show()
        vbox.pack_end(filtertable, False)

        label = gtk.Label(_("Filter:"))
        label.show()
        filtertable.attach(label, 0, 1, 0, 1, 0, 0)

        if gtk.gtk_version >= (2, 16, 0) or not sexy:
            self._filterentry = gtk.Entry()
        else:
            self._filterentry = sexy.IconEntry()
        self._filterentry.connect("activate", lambda x: self.filterContent())
        self._filterentry.show()
        filtertable.attach(self._filterentry, 1, 2, 0, 1)

        align = gtk.Alignment()
        align.set(1, 0, 0, 0)
        align.set_padding(0, 0, 10, 0)
        align.show()
        filtertable.attach(align, 2, 3, 0, 1, gtk.FILL, gtk.FILL)

        if gtk.gtk_version >= (2, 16, 0):
            self._filterentry.set_property("primary-icon-stock", "gtk-find")
            self._filterentry.set_property("secondary-icon-stock", "gtk-clear")

            def press(entry, icon_pos, event):
                if int(icon_pos) == 0:  # "primary"
                    self.filterContent()
                elif int(icon_pos) == 1:  # "secondary"
                    self.filterClear()

            self._filterentry.connect("icon-press", press)
        elif sexy:
            image = gtk.Image()
            image.set_from_stock("gtk-find", gtk.ICON_SIZE_BUTTON)
            self._filterentry.set_icon(sexy.ICON_ENTRY_PRIMARY, image)
            image = gtk.Image()
            image.set_from_stock("gtk-clear", gtk.ICON_SIZE_BUTTON)
            self._filterentry.set_icon(sexy.ICON_ENTRY_SECONDARY, image)

            def pressed(entry, icon_pos, button):
                if icon_pos == 0:  # "primary"
                    self.filterContent()
                elif icon_pos == 1:  # "secondary"
                    self.filterClear()

            self._filterentry.connect("icon-pressed", pressed)
        else:
            button = gtk.Button()
            button.set_relief(gtk.RELIEF_NONE)
            button.connect("clicked", lambda x: self.filterContent())
            button.show()
            filtertable.attach(button, 3, 4, 0, 1, 0, 0)
            image = gtk.Image()
            image.set_from_stock("gtk-find", gtk.ICON_SIZE_BUTTON)
            image.show()
            button.add(image)

            button = gtk.Button()
            button.set_relief(gtk.RELIEF_NONE)
            button.connect("clicked", lambda x: self.filterClear())
            button.show()
            filtertable.attach(button, 4, 5, 0, 1, 0, 0)
            image = gtk.Image()
            image.set_from_stock("gtk-clear", gtk.ICON_SIZE_BUTTON)
            image.show()
            button.add(image)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.set_border_width(5)
        sw.show()

        self._conttv = gtk.TextView()
        self._conttv.set_editable(False)
        self._conttv.set_cursor_visible(False)
        self._conttv.set_left_margin(5)
        self._conttv.set_right_margin(5)
        self._conttv.show()
        buffer = self._conttv.get_buffer()
        buffer.create_tag("content", font_desc=font)
        sw.add(self._conttv)

        vbox.add(sw)

        label = gtk.Label(_("Content"))
        self._notebook.append_page(vbox, label)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.set_border_width(5)
        sw.show()

        self._change = gtk.TextView()
        self._change.set_editable(False)
        self._change.set_cursor_visible(False)
        self._change.set_left_margin(5)
        self._change.set_right_margin(5)
        self._change.show()
        buffer = self._change.get_buffer()
        buffer.create_tag("changetime", font_desc=boldfont)
        buffer.create_tag("changelog", font_desc=font)
        sw.add(self._change)

        label = gtk.Label(_("Changelog"))
        self._notebook.append_page(sw, label)

        self._relations = GtkPackageView()
        self._relations.set_border_width(5)
        self._relations.getTreeView().set_headers_visible(False)
        self._relations.show()

        label = gtk.Label(_("Relations"))
        self._notebook.append_page(self._relations, label)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        sw.set_border_width(5)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.show()

        model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING,
                              gobject.TYPE_STRING)
        self._urls = gtk.TreeView(model)
        self._urls.set_headers_visible(False)
        self._urls.show()
        renderer = gtk.CellRendererText()
        renderer.set_property("font-desc", font)
        self._urls.insert_column_with_attributes(-1,
                                                 _("Channel"),
                                                 renderer,
                                                 text=0)
        self._urls.insert_column_with_attributes(-1,
                                                 _("Size"),
                                                 renderer,
                                                 text=1)
        self._urls.insert_column_with_attributes(-1,
                                                 _("URL"),
                                                 renderer,
                                                 text=2)
        sw.add(self._urls)

        label = gtk.Label(_("URLs"))
        self._notebook.append_page(sw, label)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.set_border_width(5)
        sw.show()

        self._notebook.connect("switch_page", self._switchPage)
        self._notebook.set_current_page(sysconf.get("gtk-starting-tab", 0))
Ejemplo n.º 5
0
class GtkPackageInfo(gtk.Alignment):
    hovering_over_link = False
    hand_cursor = gtk.gdk.Cursor(gtk.gdk.HAND2)
    regular_cursor = gtk.gdk.Cursor(gtk.gdk.XTERM)

    def __init__(self):
        gtk.Alignment.__init__(self, 0.5, 0.5, 1.0, 1.0)

        self._pkg = None
        self._changeset = None

        font = self.style.font_desc.copy()
        font.set_size(font.get_size() - pango.SCALE)

        boldfont = font.copy()
        boldfont.set_weight(pango.WEIGHT_BOLD)

        if sysconf.get("gtk-description-fontsize"):
            fontsize = int(sysconf.get("gtk-description-fontsize"))

            descfont = self.style.font_desc.copy()
            descfont.set_size(fontsize * pango.SCALE)

            bolddescfont = descfont.copy()
            bolddescfont.set_weight(pango.WEIGHT_BOLD)
        else:
            descfont = font
            bolddescfont = boldfont

        self._notebook = gtk.Notebook()
        self._notebook.show()
        self.add(self._notebook)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        #sw.set_border_width(5)
        sw.show()

        table = gtk.Table()
        table.set_row_spacings(2)
        table.set_col_spacings(5)
        table.set_border_width(5)
        table.show()
        sw.add_with_viewport(table)

        self._info = type("Info", (), {})()

        attrsleft = pango.AttrList()
        attrsleft.insert(pango.AttrFontDesc(font, 0, -1))
        attrsright = pango.AttrList()
        attrsright.insert(pango.AttrFontDesc(boldfont, 0, -1))

        style = sw.get_style()
        bgcolor = style.bg[gtk.STATE_NORMAL]

        self._reftv = gtk.TextView()
        self._reftv.modify_base(gtk.STATE_NORMAL, bgcolor)
        self._reftv.set_editable(False)
        self._reftv.set_cursor_visible(False)
        self._reftv.connect("motion-notify-event", self.motion_notify_event)
        self._reftv.connect("event-after", self.event_after)
        self._reftv.show()
        self._reftv.get_buffer().create_tag("reference", font_desc=font)

        row = 0
        for attr, text in [("status", _("Status:")),
                           ("priority", _("Priority:")),
                           ("group", _("Group:")),
                           ("installedsize", _("Installed Size:")),
                           ("channels", _("Channels:")),
                           ("reference", _("Reference URLs:"))]:
            label = gtk.Label(text)
            label.set_attributes(attrsleft)
            if attr == "channels":
                label.set_alignment(1.0, 0.0)
            else:
                label.set_alignment(1.0, 0.5)
            label.show()
            table.attach(label, 0, 1, row, row + 1, gtk.FILL, gtk.FILL)
            setattr(self._info, attr + "_label", label)
            if attr == "reference":
                label = self._reftv
            else:
                label = gtk.Label()
                label.set_attributes(attrsright)
                label.set_alignment(0.0, 0.5)
            label.show()
            table.attach(label, 1, 2, row, row + 1, gtk.FILL, gtk.FILL)
            setattr(self._info, attr, label)
            row += 1

        label = gtk.Label(_("General"))
        self._notebook.append_page(sw, label)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.set_border_width(5)
        sw.show()

        self._descrtv = gtk.TextView()
        self._descrtv.set_editable(False)
        self._descrtv.set_cursor_visible(False)
        self._descrtv.set_left_margin(5)
        self._descrtv.set_right_margin(5)
        self._descrtv.show()
        buffer = self._descrtv.get_buffer()
        buffer.create_tag("description", font_desc=descfont)
        buffer.create_tag("summary", font_desc=bolddescfont)
        sw.add(self._descrtv)

        label = gtk.Label(_("Description"))
        self._notebook.append_page(sw, label)

        vbox = gtk.VBox()
        vbox.show()

        filtertable = gtk.Table(1, 1)
        filtertable.set_row_spacings(5)
        filtertable.set_col_spacings(5)
        filtertable.set_border_width(5)
        filtertable.show()
        vbox.pack_end(filtertable, False)

        label = gtk.Label(_("Filter:"))
        label.show()
        filtertable.attach(label, 0, 1, 0, 1, 0, 0)

        if gtk.gtk_version >= (2, 16, 0) or not sexy:
            self._filterentry = gtk.Entry()
        else:
            self._filterentry = sexy.IconEntry()
        self._filterentry.connect("activate", lambda x: self.filterContent())
        self._filterentry.show()
        filtertable.attach(self._filterentry, 1, 2, 0, 1)

        align = gtk.Alignment()
        align.set(1, 0, 0, 0)
        align.set_padding(0, 0, 10, 0)
        align.show()
        filtertable.attach(align, 2, 3, 0, 1, gtk.FILL, gtk.FILL)

        if gtk.gtk_version >= (2, 16, 0):
            self._filterentry.set_property("primary-icon-stock", "gtk-find")
            self._filterentry.set_property("secondary-icon-stock", "gtk-clear")

            def press(entry, icon_pos, event):
                if int(icon_pos) == 0:  # "primary"
                    self.filterContent()
                elif int(icon_pos) == 1:  # "secondary"
                    self.filterClear()

            self._filterentry.connect("icon-press", press)
        elif sexy:
            image = gtk.Image()
            image.set_from_stock("gtk-find", gtk.ICON_SIZE_BUTTON)
            self._filterentry.set_icon(sexy.ICON_ENTRY_PRIMARY, image)
            image = gtk.Image()
            image.set_from_stock("gtk-clear", gtk.ICON_SIZE_BUTTON)
            self._filterentry.set_icon(sexy.ICON_ENTRY_SECONDARY, image)

            def pressed(entry, icon_pos, button):
                if icon_pos == 0:  # "primary"
                    self.filterContent()
                elif icon_pos == 1:  # "secondary"
                    self.filterClear()

            self._filterentry.connect("icon-pressed", pressed)
        else:
            button = gtk.Button()
            button.set_relief(gtk.RELIEF_NONE)
            button.connect("clicked", lambda x: self.filterContent())
            button.show()
            filtertable.attach(button, 3, 4, 0, 1, 0, 0)
            image = gtk.Image()
            image.set_from_stock("gtk-find", gtk.ICON_SIZE_BUTTON)
            image.show()
            button.add(image)

            button = gtk.Button()
            button.set_relief(gtk.RELIEF_NONE)
            button.connect("clicked", lambda x: self.filterClear())
            button.show()
            filtertable.attach(button, 4, 5, 0, 1, 0, 0)
            image = gtk.Image()
            image.set_from_stock("gtk-clear", gtk.ICON_SIZE_BUTTON)
            image.show()
            button.add(image)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.set_border_width(5)
        sw.show()

        self._conttv = gtk.TextView()
        self._conttv.set_editable(False)
        self._conttv.set_cursor_visible(False)
        self._conttv.set_left_margin(5)
        self._conttv.set_right_margin(5)
        self._conttv.show()
        buffer = self._conttv.get_buffer()
        buffer.create_tag("content", font_desc=font)
        sw.add(self._conttv)

        vbox.add(sw)

        label = gtk.Label(_("Content"))
        self._notebook.append_page(vbox, label)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.set_border_width(5)
        sw.show()

        self._change = gtk.TextView()
        self._change.set_editable(False)
        self._change.set_cursor_visible(False)
        self._change.set_left_margin(5)
        self._change.set_right_margin(5)
        self._change.show()
        buffer = self._change.get_buffer()
        buffer.create_tag("changetime", font_desc=boldfont)
        buffer.create_tag("changelog", font_desc=font)
        sw.add(self._change)

        label = gtk.Label(_("Changelog"))
        self._notebook.append_page(sw, label)

        self._relations = GtkPackageView()
        self._relations.set_border_width(5)
        self._relations.getTreeView().set_headers_visible(False)
        self._relations.show()

        label = gtk.Label(_("Relations"))
        self._notebook.append_page(self._relations, label)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        sw.set_border_width(5)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.show()

        model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING,
                              gobject.TYPE_STRING)
        self._urls = gtk.TreeView(model)
        self._urls.set_headers_visible(False)
        self._urls.show()
        renderer = gtk.CellRendererText()
        renderer.set_property("font-desc", font)
        self._urls.insert_column_with_attributes(-1,
                                                 _("Channel"),
                                                 renderer,
                                                 text=0)
        self._urls.insert_column_with_attributes(-1,
                                                 _("Size"),
                                                 renderer,
                                                 text=1)
        self._urls.insert_column_with_attributes(-1,
                                                 _("URL"),
                                                 renderer,
                                                 text=2)
        sw.add(self._urls)

        label = gtk.Label(_("URLs"))
        self._notebook.append_page(sw, label)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.set_border_width(5)
        sw.show()

        self._notebook.connect("switch_page", self._switchPage)
        self._notebook.set_current_page(sysconf.get("gtk-starting-tab", 0))

    '''
    this motion_notify_event/event_after code was adopted from hypertext demo
    '''

    # Update the cursor image if the pointer moved.
    def motion_notify_event(self, text_view, event):
        x, y = text_view.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET,
                                                 int(event.x), int(event.y))
        self.set_cursor_if_appropriate(text_view, x, y)
        text_view.window.get_pointer()
        return False

    # Looks at all tags covering the position (x, y) in the text view,
    # and if one of them is a link, change the cursor to the "hands" cursor
    # typically used by web browsers.
    def set_cursor_if_appropriate(self, text_view, x, y):
        hovering = False

        buffer = text_view.get_buffer()
        iter = text_view.get_iter_at_location(x, y)

        tags = iter.get_tags()
        for tag in tags:
            url = tag.get_data("url")
            if url:
                hovering = True
                break

        if hovering != self.hovering_over_link:
            self.hovering_over_link = hovering

        if self.hovering_over_link:
            text_view.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(
                self.hand_cursor)
        else:
            text_view.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(
                self.regular_cursor)

    def event_after(self, text_view, event):
        if event.type != gtk.gdk.BUTTON_RELEASE:
            return False
        if event.button != 1:
            return False
        buffer = text_view.get_buffer()

        # we shouldn't follow a link if the user has selected something
        try:
            start, end = buffer.get_selection_bounds()
        except ValueError:
            # If there is nothing selected, None is return
            pass
        else:
            if start.get_offset() != end.get_offset():
                return False

        x, y = text_view.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET,
                                                 int(event.x), int(event.y))
        iter = text_view.get_iter_at_location(x, y)

        self.follow_if_link(text_view, iter)
        return False

    def follow_if_link(self, text_view, iter):
        ''' Looks at all tags covering the position of iter in the text view,
            and if one of them is a link, follow it by opening the url.
        '''
        tags = iter.get_tags()
        for tag in tags:
            url = tag.get_data("url")
            if url:
                self.open_url(url)
                break

    def open_url(self, url):
        ''' Open the specified URL in a browser (try a few alternatives) '''
        for browser in ['xdg-open', 'gnome-open', 'exo-open', \
                        'x-www-browser', 'firefox', 'open']:
            command = [browser, url]
            try:
                if subprocess:
                    retcode = subprocess.call(command)
                else:
                    retcode = os.system(" ".join(command))
                if retcode == 0:
                    break
            except OSError:
                pass

    def _switchPage(self, notebook, page, pagenum):
        self.setPackage(self._pkg, _pagenum=pagenum)

    def setChangeSet(self, changeset):
        self._changeset = changeset

    def setPackage(self, pkg, _pagenum=None):

        self._pkg = pkg

        if _pagenum is not None:
            num = _pagenum
        else:
            num = self._notebook.get_current_page()

        if num == 0:

            # Update general information

            if not pkg:
                self._info.status.set_text("")
                self._info.group.set_text("")
                self._info.installedsize.set_text("")
                self._info.priority.set_text("")
                self._info.channels.set_text("")
                self._info.reference.get_buffer().set_text("")
                return

            group = None
            installedsize = None
            channels = []
            urls = []
            for loader in pkg.loaders:
                info = loader.getInfo(pkg)
                if group is None:
                    group = info.getGroup()
                if installedsize is None:
                    installedsize = info.getInstalledSize()
                channel = loader.getChannel()
                channels.append("%s (%s)" %
                                (channel.getName()
                                 or channel.getAlias(), channel.getAlias()))
                urls.extend(info.getReferenceURLs())

            flags = pkgconf.testAllFlags(pkg)
            if flags:
                flags.sort()
                flags = " (%s)" % ", ".join(flags)
            else:
                flags = ""

            status = pkg.installed and _("Installed") or _("Available")
            self._info.status.set_text(status + flags)
            self._info.group.set_text(group or _("Unknown"))
            self._info.priority.set_text(str(pkg.getPriority()))
            self._info.channels.set_text("\n".join(channels))
            self._info.reference.get_buffer().set_text("")
            for url in urls:
                refbuf = self._info.reference.get_buffer()
                tag = refbuf.create_tag(None,
                                        foreground="blue",
                                        underline=pango.UNDERLINE_SINGLE)
                tag.set_data("url", url)
                refbuf.insert_with_tags(refbuf.get_end_iter(), url, tag)

            if installedsize:
                self._info.installedsize.set_text(sizeToStr(installedsize))
                self._info.installedsize.show()
                self._info.installedsize_label.show()
            else:
                self._info.installedsize.hide()
                self._info.installedsize_label.hide()

        elif num == 1:

            # Update summary/description

            descrbuf = self._descrtv.get_buffer()
            descrbuf.set_text("")
            if not pkg: return

            iter = descrbuf.get_end_iter()
            for loader in pkg.loaders:
                info = loader.getInfo(pkg)
                summary = info.getSummary()
                if summary:
                    descrbuf.insert_with_tags_by_name(iter, summary + "\n\n",
                                                      "summary")
                    description = info.getDescription()
                    if description != summary:
                        descrbuf.insert_with_tags_by_name(
                            iter, description + "\n\n", "description")
                    break
            else:
                loader = pkg.loaders.keys()[0]

        elif num == 2:

            # Update contents

            if not pkg:
                contbuf = self._conttv.get_buffer()
                contbuf.set_text("")
                return

            self._setContent(pkg)

        elif num == 3:
            # Update changelog

            contbuf = self._change.get_buffer()
            contbuf.set_text("")
            if not pkg: return

            iter = contbuf.get_end_iter()
            for loader in pkg.loaders:
                if loader.getInstalled():
                    break
            else:
                loader = pkg.loaders.keys()[0]
            info = loader.getInfo(pkg)
            changelog = info.getChangeLog()

            for i in range(len(changelog) / 2):
                contbuf.insert_with_tags_by_name(iter, changelog[2 * i] + "\n",
                                                 "changetime")
                changesplit = changelog[2 * i + 1].split("\n")
                changedetails = changesplit[0] + "\n"
                for i in range(1, len(changesplit)):
                    changedetails += "  " + changesplit[i] + "\n"
                contbuf.insert_with_tags_by_name(iter, changedetails,
                                                 "changelog")

        elif num == 4:

            # Update relations

            if not pkg:
                self._relations.setPackages([])
                return

            self._setRelations(pkg)

        elif num == 5:

            # Update URLs

            model = self._urls.get_model()
            model.clear()

            if not pkg:
                return

            items = []
            for loader in pkg.loaders:
                channel = loader.getChannel()
                alias = channel.getAlias()
                info = loader.getInfo(pkg)
                for url in info.getURLs():
                    items.append((alias, sizeToStr(info.getSize(url)), url))

            items.sort()

            lastitem = None
            for item in items:
                if item != lastitem:
                    lastitem = item
                    model.append(item)

    def filterContent(self):
        if self._pkg:
            self._setContent(self._pkg)

    def filterClear(self):
        self._filterentry.set_text("")
        self.filterContent()

    def _setContent(self, pkg):

        contbuf = self._conttv.get_buffer()
        contbuf.set_text("")

        iter = contbuf.get_end_iter()
        for loader in pkg.loaders:
            if loader.getInstalled():
                break
        else:
            loader = pkg.loaders.keys()[0]
        info = loader.getInfo(pkg)
        pathlist = info.getPathList()
        filter = self._filterentry.get_text().strip()
        if filter:
            pathlist = fnmatch.filter(pathlist, filter)
        pathlist.sort()
        for path in pathlist:
            contbuf.insert_with_tags_by_name(iter, path + "\n", "content")

    def _setRelations(self, pkg):
        class Sorter(str):
            ORDER = [
                _("Provides"),
                _("Upgrades"),
                _("Requires"),
                _("Conflicts")
            ]

            def __cmp__(self, other):
                return cmp(self.ORDER.index(str(self)),
                           self.ORDER.index(str(other)))

            def __lt__(self, other):
                return cmp(self, other) < 0

        relations = {}

        for prv in pkg.provides:

            prvmap = {}

            requiredby = []
            for req in prv.requiredby:
                requiredby.extend(req.packages)
            if requiredby:
                prvmap[_("Required By")] = requiredby

            upgradedby = []
            for upg in prv.upgradedby:
                upgradedby.extend(upg.packages)
            if upgradedby:
                prvmap[_("Upgraded By")] = upgradedby

            conflictedby = []
            for cnf in prv.conflictedby:
                conflictedby.extend(cnf.packages)
            if conflictedby:
                prvmap[_("Conflicted By")] = conflictedby

            if prvmap:
                relations.setdefault(Sorter(_("Provides")), {})[str(prv)] = \
                                                                        prvmap

        requires = {}
        for req in pkg.requires:
            lst = requires.setdefault(str(req), [])
            for prv in req.providedby:
                lst.extend(prv.packages)
            lst[:] = dict.fromkeys(lst).keys()
        if requires:
            relations[Sorter(_("Requires"))] = requires

        upgrades = {}
        for upg in pkg.upgrades:
            lst = upgrades.setdefault(str(upg), [])
            for prv in upg.providedby:
                lst.extend(prv.packages)
            lst[:] = dict.fromkeys(lst).keys()
        if upgrades:
            relations[Sorter(_("Upgrades"))] = upgrades

        conflicts = {}
        for cnf in pkg.conflicts:
            lst = conflicts.setdefault(str(cnf), [])
            for prv in cnf.providedby:
                lst.extend(prv.packages)
            lst[:] = dict.fromkeys(lst).keys()
        if conflicts:
            relations[Sorter(_("Conflicts"))] = conflicts

        self._relations.setPackages(relations, self._changeset)
Ejemplo n.º 6
0
class GtkChanges(object):
    def __init__(self):

        self._window = gtk.Window()
        self._window.set_icon(getPixbuf("smart"))
        self._window.set_title(_("Change Summary"))
        self._window.set_modal(True)
        self._window.set_position(gtk.WIN_POS_CENTER)
        self._window.set_geometry_hints(min_width=600, min_height=400)

        def delete(widget, event):
            gtk.main_quit()
            return True

        self._window.connect("delete-event", delete)

        self._vbox = gtk.VBox()
        self._vbox.set_border_width(10)
        self._vbox.set_spacing(10)
        self._vbox.show()
        self._window.add(self._vbox)

        self._label = gtk.Label()
        self._vbox.pack_start(self._label, expand=False)

        self._pv = GtkPackageView()
        self._pv.getTreeView().set_headers_visible(False)
        self._pv.setExpandPackage(True)
        self._pv.show()
        self._vbox.pack_start(self._pv)

        self._sizelabel = gtk.Label()
        self._vbox.pack_start(self._sizelabel, expand=False)

        self._confirmbbox = gtk.HButtonBox()
        self._confirmbbox.set_spacing(10)
        self._confirmbbox.set_layout(gtk.BUTTONBOX_END)
        self._vbox.pack_start(self._confirmbbox, expand=False)

        self._okbutton = gtk.Button(stock="gtk-ok")
        self._okbutton.show()

        def clicked(x):
            self._result = True
            gtk.main_quit()

        self._okbutton.connect("clicked", clicked)
        self._confirmbbox.pack_start(self._okbutton)

        self._cancelbutton = gtk.Button(stock="gtk-cancel")
        self._cancelbutton.show()
        self._cancelbutton.connect("clicked", lambda x: gtk.main_quit())
        self._confirmbbox.pack_start(self._cancelbutton)

        self._closebbox = gtk.HButtonBox()
        self._closebbox.set_spacing(10)
        self._closebbox.set_layout(gtk.BUTTONBOX_END)
        self._vbox.pack_start(self._closebbox, expand=False)

        self._closebutton = gtk.Button(stock="gtk-close")
        self._closebutton.show()
        self._closebutton.connect("clicked", lambda x: gtk.main_quit())
        self._closebbox.pack_start(self._closebutton)

    def showChangeSet(self, changeset, keep=None, confirm=False, label=None):

        report = Report(changeset)
        report.compute()

        class Sorter(str):
            ORDER = [
                _("Remove"),
                _("Downgrade"),
                _("Reinstall"),
                _("Install"),
                _("Upgrade")
            ]

            def _index(self, s):
                i = 0
                for os in self.ORDER:
                    if os.startswith(s):
                        return i
                    i += 1
                return i

            def __cmp__(self, other):
                return cmp(self._index(str(self)), self._index(str(other)))

            def __lt__(self, other):
                return cmp(self, other) < 0

        packages = {}

        if report.install:
            install = {}
            reinstall = {}
            upgrade = {}
            downgrade = {}
            lst = report.install.keys()
            lst.sort()
            for pkg in lst:
                package = {}
                done = {}
                if pkg in report.upgrading:
                    for upgpkg in report.upgrading[pkg]:
                        package.setdefault(_("Upgrades"), []).append(upgpkg)
                        done[upgpkg] = True
                if pkg in report.downgrading:
                    for dwnpkg in report.downgrading[pkg]:
                        package.setdefault(_("Downgrades"), []).append(dwnpkg)
                        done[dwnpkg] = True
                if pkg in report.requires:
                    for reqpkg in report.requires[pkg]:
                        package.setdefault(_("Requires"), []).append(reqpkg)
                if pkg in report.requiredby:
                    for reqpkg in report.requiredby[pkg]:
                        package.setdefault(_("Required By"), []).append(reqpkg)
                if pkg in report.conflicts:
                    for cnfpkg in report.conflicts[pkg]:
                        if cnfpkg in done:
                            continue
                        package.setdefault(_("Conflicts"), []).append(cnfpkg)
                if pkg.installed:
                    reinstall[pkg] = package
                elif pkg in report.upgrading:
                    upgrade[pkg] = package
                elif pkg in report.downgrading:
                    downgrade[pkg] = package
                else:
                    install[pkg] = package
            if reinstall:
                packages[Sorter(_("Reinstall (%d)") % len(reinstall))] = \
                                                                    reinstall
            if install:
                packages[Sorter(_("Install (%d)") % len(install))] = install
            if upgrade:
                packages[Sorter(_("Upgrade (%d)") % len(upgrade))] = upgrade
            if downgrade:
                packages[Sorter(_("Downgrade (%d)") % len(downgrade))] = \
                                                                    downgrade

        if report.removed:
            remove = {}
            lst = report.removed.keys()
            lst.sort()
            for pkg in lst:
                package = {}
                done = {}
                if pkg in report.requires:
                    for reqpkg in report.requires[pkg]:
                        package.setdefault(_("Requires"), []).append(reqpkg)
                if pkg in report.requiredby:
                    for reqpkg in report.requiredby[pkg]:
                        package.setdefault(_("Required By"), []).append(reqpkg)
                if pkg in report.conflicts:
                    for cnfpkg in report.conflicts[pkg]:
                        if cnfpkg in done:
                            continue
                        package.setdefault(_("Conflicts"), []).append(cnfpkg)
                remove[pkg] = package
            if remove:
                packages[Sorter(_("Remove (%d)") % len(report.removed))] = \
                                                                        remove

        if keep:
            packages[Sorter(_("Keep (%d)") % len(keep))] = keep

        dsize = report.getDownloadSize()
        size = report.getInstallSize() - report.getRemoveSize()
        sizestr = ""
        if dsize:
            sizestr += _("%s of package files are needed. ") % sizeToStr(dsize)
        if size > 0:
            sizestr += _("%s will be used.") % sizeToStr(size)
        elif size < 0:
            size *= -1
            sizestr += _("%s will be freed.") % sizeToStr(size)
        if dsize or size:
            self._sizelabel.set_text(sizestr)
            self._sizelabel.show()
        else:
            self._sizelabel.hide()

        if confirm:
            self._confirmbbox.show()
            self._closebbox.hide()
        else:
            self._closebbox.show()
            self._confirmbbox.hide()

        if label:
            self._label.set_text(label)
            self._label.show()
        else:
            self._label.hide()

        self._pv.setPackages(packages, changeset)

        # Expand first level
        self._pv.setExpanded([(x, ) for x in packages])

        self._result = False
        self._window.show()
        gtk.main()
        self._window.hide()

        return self._result
Ejemplo n.º 7
0
    def __init__(self, ctrl):
        GtkInterface.__init__(self, ctrl)

        self._changeset = None

        self._window = gtk.Window()
        self._window.set_title("Smart Package Manager %s" % VERSION)
        self._window.set_position(gtk.WIN_POS_CENTER)
        self._window.set_geometry_hints(min_width=640, min_height=480)
        def delete(widget, event):
            gtk.main_quit()
            return True
        self._window.connect("delete-event", delete)

        self._log.set_transient_for(self._window)
        self._progress.set_transient_for(self._window)
        self._hassubprogress.set_transient_for(self._window)
        self._changes.set_transient_for(self._window)

        self._watch = gtk.gdk.Cursor(gtk.gdk.WATCH)

        self._undo = []
        self._redo = []

        self._topvbox = gtk.VBox()
        self._topvbox.show()
        self._window.add(self._topvbox)

        globals = {"self": self, "gtk": gtk}
        self._actions = gtk.ActionGroup("Actions")
        self._actions.add_actions(compileActions(ACTIONS, globals))

        self._filters = {}
        for name, label in [("hide-non-upgrades", _("Hide Non-upgrades")),
                            ("hide-non-newest", _("Hide Non-newest")),
                            ("hide-installed", _("Hide Installed")),
                            ("hide-uninstalled", _("Hide Uninstalled")),
                            ("hide-unmarked", _("Hide Unmarked")),
                            ("hide-unlocked", _("Hide Unlocked")),
                            ("hide-requested", _("Hide Requested")),
                            ("hide-old", _("Hide Old"))]:
            action = gtk.ToggleAction(name, label, "", "")
            action.connect("toggled", lambda x, y: self.toggleFilter(y), name)
            self._actions.add_action(action)

        treestyle = sysconf.get("package-tree")
        lastaction = None
        for name, label in [("groups", _("Groups")),
                            ("separate-groups", _("Separate Groups")),
                            ("channels", _("Channels")),
                            ("channels-groups", _("Channels & Groups")),
                            ("none", _("None"))]:
            action = gtk.RadioAction("tree-style-"+name, label, "", "", 0)
            if name == treestyle:
                action.set_active(True)
            if lastaction:
                action.set_group(lastaction)
            lastaction = action
            action.connect("toggled", lambda x, y: self.setTreeStyle(y), name)
            self._actions.add_action(action)

        self._ui = gtk.UIManager()
        self._ui.insert_action_group(self._actions, 0)
        self._ui.add_ui_from_string(UI)
        self._menubar = self._ui.get_widget("/menubar")
        self._topvbox.pack_start(self._menubar, False)

        self._toolbar = self._ui.get_widget("/toolbar")
        if sysconf.get("gtk-toolbar-names", False):
            self._toolbar.set_style(gtk.TOOLBAR_BOTH)
        else:
            self._toolbar.set_style(gtk.TOOLBAR_ICONS)
        self._topvbox.pack_start(self._toolbar, False)
        if sysconf.getReadOnly():
           # Can't update channels in readonly mode.
           updatetoolitem = self._ui.get_widget("/toolbar/update-channels")
           updatetoolitem.set_property("sensitive", False)

        self._window.add_accel_group(self._ui.get_accel_group())

        self._execmenuitem = self._ui.get_action("/menubar/file/exec-changes")
        self._execmenuitem.set_property("sensitive", False)
        self._clearmenuitem = self._ui.get_action("/menubar/edit/clear-changes")
        self._clearmenuitem.set_property("sensitive", False)
        self._undomenuitem = self._ui.get_action("/menubar/edit/undo")
        self._undomenuitem.set_property("sensitive", False)
        self._redomenuitem = self._ui.get_action("/menubar/edit/redo")
        self._redomenuitem.set_property("sensitive", False)

        # Search bar

        self._history = [""]
        self._historypos = 0

        if gtk.gtk_version >= (2, 16, 0) or sexy:
            self._searchbar = gtk.ToolItem()
            self._searchbar.set_expand(True)
            self._searchbar.set_homogeneous(False)
            self._searchbar.show()
            count = self._toolbar.get_n_items()
            find = self._toolbar.get_nth_item(count - 1)
            self._toolbar.remove(find)
            self._toolbar.insert(self._searchbar, -1)

            searchtable = gtk.Table(1, 1)
            searchtable.set_row_spacings(5)
            searchtable.set_col_spacings(5)
            searchtable.set_border_width(5)
            searchtable.show()
            self._searchbar.add(searchtable)

            if gtk.gtk_version >= (2, 16, 0):
                self._searchentry = gtk.Entry()
                self._searchentry.set_property("primary-icon-stock", "gtk-find")
                self._searchentry.set_property("secondary-icon-stock", "gtk-clear")
                def press(entry, icon_pos, event):
                    if int(icon_pos) == 0: # "primary"
                        self._searchmenu.popup(None, None, None, event.button, event.time)
                    elif int(icon_pos) == 1: # "secondary"
                        self.searchClear()
                self._searchentry.connect("icon-press", press)
            elif sexy:
                self._searchentry = sexy.IconEntry()
                image = gtk.Image()
                image.set_from_stock("gtk-find", gtk.ICON_SIZE_BUTTON)
                self._searchentry.set_icon(sexy.ICON_ENTRY_PRIMARY, image)
                image = gtk.Image()
                image.set_from_stock("gtk-clear", gtk.ICON_SIZE_BUTTON)
                self._searchentry.set_icon(sexy.ICON_ENTRY_SECONDARY, image)
                def pressed(entry, icon_pos, button):
                    if icon_pos == 0: # "primary"
                        self._searchmenu.popup(None, None, None, button, gtk.get_current_event_time())
                    elif icon_pos == 1: # "secondary"
                        self.searchClear()
                self._searchentry.connect("icon-pressed", pressed)
            self._searchentry.connect("activate", lambda x: self.searchFind())
            self._searchentry.connect("key-press-event", self.searchKeyPress)
            self._searchentry.show()
            searchtable.attach(self._searchentry, 0, 1, 0, 1)

            self._searchmenu = gtk.Menu()
            self._searchname = gtk.CheckMenuItem(_("Automatic"))
            self._searchname.set_draw_as_radio(True)
            self._searchname.set_active(True)
            def search_automatic(item):
                self._searchdesc.set_active(not item.get_active())
                self.refreshPackages()
            self._searchname.connect("activate", search_automatic)
            self._searchname.show()
            self._searchmenu.append(self._searchname)
            self._searchdesc = gtk.CheckMenuItem(_("Description"))
            self._searchdesc.set_draw_as_radio(True)
            self._searchdesc.set_active(False)
            def search_description(item):
                self._searchname.set_active(not item.get_active())
                self.refreshPackages()
            self._searchdesc.connect("activate", search_description)
            self._searchdesc.show()
            self._searchmenu.append(self._searchdesc)
        else:
            self._searchbar = gtk.Alignment()
            self._searchbar.set(0, 0, 1, 1)
            self._searchbar.set_padding(3, 3, 0, 0)
            self._topvbox.pack_start(self._searchbar, False)

            searchvp = gtk.Viewport()
            searchvp.set_shadow_type(gtk.SHADOW_OUT)
            searchvp.show()
            self._searchbar.add(searchvp)

            searchtable = gtk.Table(1, 1)
            searchtable.set_row_spacings(5)
            searchtable.set_col_spacings(5)
            searchtable.set_border_width(5)
            searchtable.show()
            searchvp.add(searchtable)

            label = gtk.Label(_("Search:"))
            label.show()
            searchtable.attach(label, 0, 1, 0, 1, 0, 0)

            self._searchentry = gtk.Entry()
            self._searchentry.connect("activate", lambda x: self.searchFind())
            self._searchentry.connect("key-press-event", self.searchKeyPress)
            self._searchentry.show()
            searchtable.attach(self._searchentry, 1, 2, 0, 1)

            button = gtk.Button()
            button.set_relief(gtk.RELIEF_NONE)
            button.connect("clicked", lambda x: self.searchFind())
            button.show()
            searchtable.attach(button, 2, 3, 0, 1, 0, 0)
            image = gtk.Image()
            image.set_from_stock("gtk-find", gtk.ICON_SIZE_BUTTON)
            image.show()
            button.add(image)

            align = gtk.Alignment()
            align.set(1, 0, 0, 0)
            align.set_padding(0, 0, 10, 0)
            align.show()
            searchtable.attach(align, 3, 4, 0, 1, gtk.FILL, gtk.FILL)
            button = gtk.Button()
            button.set_size_request(20, 20)
            button.set_relief(gtk.RELIEF_NONE)
            button.connect("clicked", lambda x: self.toggleSearch())
            button.show()
            align.add(button)
            image = gtk.Image()
            image.set_from_stock("gtk-close", gtk.ICON_SIZE_MENU)
            image.show()
            button.add(image)

            hbox = gtk.HBox()
            hbox.set_spacing(10)
            hbox.show()
            searchtable.attach(hbox, 1, 2, 1, 2)

            self._searchmenu = None
            self._searchname = gtk.RadioButton(None, _("Automatic"))
            self._searchname.set_active(True)
            self._searchname.connect("clicked", lambda x: self.refreshPackages())
            self._searchname.show()
            hbox.pack_start(self._searchname, False)
            self._searchdesc = gtk.RadioButton(self._searchname, _("Description"))
            self._searchdesc.connect("clicked", lambda x: self.refreshPackages())
            self._searchdesc.show()
            hbox.pack_start(self._searchdesc, False)

        # Packages and information

        self._hpaned = gtk.HPaned()
        self._hpaned.show()
        self._topvbox.pack_start(self._hpaned)

        scrollwin = gtk.ScrolledWindow()
        scrollwin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        scrollwin.set_shadow_type(gtk.SHADOW_IN)
        self._hpaned.pack1(scrollwin, True)

        self._pg = gtk.TreeView()
        def group_selected(treeview):
            self.refreshPackages()
        self._pg.connect("cursor_changed", group_selected)
        self._pg.show()
        scrollwin.add(self._pg)

        selection = self._pg.get_selection()
        selection.set_mode(gtk.SELECTION_MULTIPLE)

        renderer = gtk.CellRendererText()
        column = gtk.TreeViewColumn(_("Group"), renderer, text=1)
        self._pg.append_column(column)

        self._vpaned = gtk.VPaned()
        self._vpaned.show()
        self._hpaned.pack2(self._vpaned, True)

        self._pv = GtkPackageView()
        self._pv.show()
        self._vpaned.pack1(self._pv, True)

        self._pi = GtkPackageInfo()
        self._pi.show()
        self._pv.connect("package_selected",
                         lambda x, y: self._pi.setPackage(y))
        self._pv.connect("package_activated",
                         lambda x, y: self.actOnPackages(y))
        self._pv.connect("package_popup", self.packagePopup)
        self._vpaned.pack2(self._pi, False)

        self._status = gtk.Statusbar()
        self._status.show()
        self._topvbox.pack_start(self._status, False)
        
        self._legend = GtkLegend()
Ejemplo n.º 8
0
class GtkPackageInfo(gtk.Alignment):
    def __init__(self):
        gtk.Alignment.__init__(self)
        self.__gobject_init__()

        self._pkg = None
        self._changeset = None

        font = self.style.font_desc.copy()
        font.set_size(font.get_size() - pango.SCALE)

        boldfont = font.copy()
        boldfont.set_weight(pango.WEIGHT_BOLD)

        self._notebook = gtk.Notebook()
        self._notebook.show()
        self.add(self._notebook)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        #sw.set_border_width(5)
        sw.show()

        table = gtk.Table()
        table.set_row_spacings(2)
        table.set_col_spacings(5)
        table.set_border_width(5)
        table.show()
        sw.add_with_viewport(table)

        self._info = type("Info", (), {})()

        attrsleft = pango.AttrList()
        attrsleft.insert(pango.AttrFontDesc(font, 0, -1))
        attrsright = pango.AttrList()
        attrsright.insert(pango.AttrFontDesc(boldfont, 0, -1))

        row = 0
        for attr, text in [("status", _("Status:")),
                           ("priority", _("Priority:")),
                           ("group", _("Group:")),
                           ("installedsize", _("Installed Size:")),
                           ("channels", _("Channels:"))]:
            label = gtk.Label(text)
            label.set_attributes(attrsleft)
            if attr == "channels":
                label.set_alignment(1.0, 0.0)
            else:
                label.set_alignment(1.0, 0.5)
            label.show()
            table.attach(label, 0, 1, row, row + 1, gtk.FILL, gtk.FILL)
            setattr(self._info, attr + "_label", label)
            label = gtk.Label()
            label.set_attributes(attrsright)
            label.set_alignment(0.0, 0.5)
            label.show()
            table.attach(label, 1, 2, row, row + 1, gtk.FILL, gtk.FILL)
            setattr(self._info, attr, label)
            row += 1

        label = gtk.Label(_("General"))
        self._notebook.append_page(sw, label)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.set_border_width(5)
        sw.show()

        self._descrtv = gtk.TextView()
        self._descrtv.set_editable(False)
        self._descrtv.set_cursor_visible(False)
        self._descrtv.set_left_margin(5)
        self._descrtv.set_right_margin(5)
        self._descrtv.show()
        buffer = self._descrtv.get_buffer()
        buffer.create_tag("description", font_desc=font)
        buffer.create_tag("summary", font_desc=boldfont)
        sw.add(self._descrtv)

        label = gtk.Label(_("Description"))
        self._notebook.append_page(sw, label)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.set_border_width(5)
        sw.show()

        self._conttv = gtk.TextView()
        self._conttv.set_editable(False)
        self._conttv.set_cursor_visible(False)
        self._conttv.set_left_margin(5)
        self._conttv.set_right_margin(5)
        self._conttv.show()
        buffer = self._conttv.get_buffer()
        buffer.create_tag("content", font_desc=font)
        sw.add(self._conttv)

        label = gtk.Label(_("Content"))
        self._notebook.append_page(sw, label)

        self._relations = GtkPackageView()
        self._relations.set_border_width(5)
        self._relations.getTreeView().set_headers_visible(False)
        self._relations.show()

        label = gtk.Label(_("Relations"))
        self._notebook.append_page(self._relations, label)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        sw.set_border_width(5)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.show()

        model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING,
                              gobject.TYPE_STRING)
        self._urls = gtk.TreeView(model)
        self._urls.set_headers_visible(False)
        self._urls.show()
        renderer = gtk.CellRendererText()
        renderer.set_property("font-desc", font)
        self._urls.insert_column_with_attributes(-1,
                                                 _("Channel"),
                                                 renderer,
                                                 text=0)
        self._urls.insert_column_with_attributes(-1,
                                                 _("Size"),
                                                 renderer,
                                                 text=1)
        self._urls.insert_column_with_attributes(-1,
                                                 _("URL"),
                                                 renderer,
                                                 text=2)
        sw.add(self._urls)

        label = gtk.Label(_("URLs"))
        self._notebook.append_page(sw, label)

        self._notebook.connect("switch_page", self._switchPage)

    def _switchPage(self, notebook, page, pagenum):
        self.setPackage(self._pkg, _pagenum=pagenum)

    def setChangeSet(self, changeset):
        self._changeset = changeset

    def setPackage(self, pkg, _pagenum=None):

        self._pkg = pkg

        if _pagenum is not None:
            num = _pagenum
        else:
            num = self._notebook.get_current_page()

        if num == 0:

            # Update general information

            if not pkg:
                self._info.status.set_text("")
                self._info.group.set_text("")
                self._info.installedsize.set_text("")
                self._info.priority.set_text("")
                self._info.channels.set_text("")
                return

            group = None
            installedsize = None
            channels = []
            for loader in pkg.loaders:
                info = loader.getInfo(pkg)
                if group is None:
                    group = info.getGroup()
                if installedsize is None:
                    installedsize = info.getInstalledSize()
                channel = loader.getChannel()
                channels.append("%s (%s)" %
                                (channel.getName()
                                 or channel.getAlias(), channel.getAlias()))

            flags = pkgconf.testAllFlags(pkg)
            if flags:
                flags.sort()
                flags = " (%s)" % ", ".join(flags)
            else:
                flags = ""

            status = pkg.installed and _("Installed") or _("Available")
            self._info.status.set_text(status + flags)
            self._info.group.set_text(group or _("Unknown"))
            self._info.priority.set_text(str(pkg.getPriority()))
            self._info.channels.set_text("\n".join(channels))

            if installedsize:
                self._info.installedsize.set_text(sizeToStr(installedsize))
                self._info.installedsize.show()
                self._info.installedsize_label.show()
            else:
                self._info.installedsize.hide()
                self._info.installedsize_label.hide()

        elif num == 1:

            # Update summary/description

            descrbuf = self._descrtv.get_buffer()
            descrbuf.set_text("")
            if not pkg: return

            iter = descrbuf.get_end_iter()
            for loader in pkg.loaders:
                info = loader.getInfo(pkg)
                summary = info.getSummary()
                if summary:
                    descrbuf.insert_with_tags_by_name(iter, summary + "\n\n",
                                                      "summary")
                    description = info.getDescription()
                    if description != summary:
                        descrbuf.insert_with_tags_by_name(
                            iter, description + "\n\n", "description")
                    break
            else:
                loader = pkg.loaders.keys()[0]

        elif num == 2:

            # Update contents

            contbuf = self._conttv.get_buffer()
            contbuf.set_text("")
            if not pkg: return

            iter = contbuf.get_end_iter()
            for loader in pkg.loaders:
                if loader.getInstalled():
                    break
            else:
                loader = pkg.loaders.keys()[0]
            info = loader.getInfo(pkg)
            pathlist = info.getPathList()
            pathlist.sort()
            for path in pathlist:
                contbuf.insert_with_tags_by_name(iter, path + "\n", "content")

        elif num == 3:

            # Update relations

            if not pkg:
                self._relations.setPackages([])
                return

            self._setRelations(pkg)

        elif num == 4:

            # Update URLs

            model = self._urls.get_model()
            model.clear()

            if not pkg:
                return

            items = []
            for loader in pkg.loaders:
                channel = loader.getChannel()
                alias = channel.getAlias()
                info = loader.getInfo(pkg)
                for url in info.getURLs():
                    items.append((alias, sizeToStr(info.getSize(url)), url))

            items.sort()

            lastitem = None
            for item in items:
                if item != lastitem:
                    lastitem = item
                    model.append(item)

    def _setRelations(self, pkg):
        class Sorter(str):
            ORDER = [
                _("Provides"),
                _("Upgrades"),
                _("Requires"),
                _("Conflicts")
            ]

            def __cmp__(self, other):
                return cmp(self.ORDER.index(str(self)),
                           self.ORDER.index(str(other)))

            def __lt__(self, other):
                return cmp(self, other) < 0

        relations = {}

        for prv in pkg.provides:

            prvmap = {}

            requiredby = []
            for req in prv.requiredby:
                requiredby.extend(req.packages)
            if requiredby:
                prvmap[_("Required By")] = requiredby

            upgradedby = []
            for upg in prv.upgradedby:
                upgradedby.extend(upg.packages)
            if upgradedby:
                prvmap[_("Upgraded By")] = upgradedby

            conflictedby = []
            for cnf in prv.conflictedby:
                conflictedby.extend(cnf.packages)
            if conflictedby:
                prvmap[_("Conflicted By")] = conflictedby

            if prvmap:
                relations.setdefault(Sorter(_("Provides")), {})[str(prv)] = \
                                                                        prvmap

        requires = {}
        for req in pkg.requires:
            lst = requires.setdefault(str(req), [])
            for prv in req.providedby:
                lst.extend(prv.packages)
            lst[:] = dict.fromkeys(lst).keys()
        if requires:
            relations[Sorter(_("Requires"))] = requires

        upgrades = {}
        for upg in pkg.upgrades:
            lst = upgrades.setdefault(str(upg), [])
            for prv in upg.providedby:
                lst.extend(prv.packages)
            lst[:] = dict.fromkeys(lst).keys()
        if upgrades:
            relations[Sorter(_("Upgrades"))] = upgrades

        conflicts = {}
        for cnf in pkg.conflicts:
            lst = conflicts.setdefault(str(cnf), [])
            for prv in cnf.providedby:
                lst.extend(prv.packages)
            lst[:] = dict.fromkeys(lst).keys()
        if conflicts:
            relations[Sorter(_("Conflicts"))] = conflicts

        self._relations.setPackages(relations, self._changeset)
Ejemplo n.º 9
0
class GtkChanges(object):

    def __init__(self):

        self._window = gtk.Window()
        self._window.set_icon(getPixbuf("smart"))
        self._window.set_title(_("Change Summary"))
        self._window.set_modal(True)
        self._window.set_position(gtk.WIN_POS_CENTER)
        self._window.set_geometry_hints(min_width=600, min_height=400)
        def delete(widget, event):
            gtk.main_quit()
            return True
        self._window.connect("delete-event", delete)

        self._vbox = gtk.VBox()
        self._vbox.set_border_width(10)
        self._vbox.set_spacing(10)
        self._vbox.show()
        self._window.add(self._vbox)

        self._label = gtk.Label()
        self._vbox.pack_start(self._label, expand=False)

        self._pv = GtkPackageView()
        self._pv.getTreeView().set_headers_visible(False)
        self._pv.setExpandPackage(True)
        self._pv.show()
        self._vbox.pack_start(self._pv)

        self._sizelabel = gtk.Label()
        self._vbox.pack_start(self._sizelabel, expand=False)

        self._confirmbbox = gtk.HButtonBox()
        self._confirmbbox.set_spacing(10)
        self._confirmbbox.set_layout(gtk.BUTTONBOX_END)
        self._vbox.pack_start(self._confirmbbox, expand=False)

        self._okbutton = gtk.Button(stock="gtk-ok")
        self._okbutton.show()
        def clicked(x):
            self._result = True
            gtk.main_quit()
        self._okbutton.connect("clicked", clicked)
        self._confirmbbox.pack_start(self._okbutton)

        self._cancelbutton = gtk.Button(stock="gtk-cancel")
        self._cancelbutton.show()
        self._cancelbutton.connect("clicked", lambda x: gtk.main_quit())
        self._confirmbbox.pack_start(self._cancelbutton)

        self._closebbox = gtk.HButtonBox()
        self._closebbox.set_spacing(10)
        self._closebbox.set_layout(gtk.BUTTONBOX_END)
        self._vbox.pack_start(self._closebbox, expand=False)

        self._closebutton = gtk.Button(stock="gtk-close")
        self._closebutton.show()
        self._closebutton.connect("clicked", lambda x: gtk.main_quit())
        self._closebbox.pack_start(self._closebutton)

    def showChangeSet(self, changeset, keep=None, confirm=False, label=None):

        report = Report(changeset)
        report.compute()

        class Sorter(str):
            ORDER = [_("Remove"), _("Downgrade"), _("Reinstall"),
                     _("Install"), _("Upgrade")]
            def _index(self, s):
                i = 0
                for os in self.ORDER:
                    if os.startswith(s):
                        return i
                    i += 1
                return i
            def __cmp__(self, other):
                return cmp(self._index(str(self)), self._index(str(other)))
            def __lt__(self, other):
                return cmp(self, other) < 0

        packages = {}

        if report.install:
            install = {}
            reinstall = {}
            upgrade = {}
            downgrade = {}
            lst = report.install.keys()
            lst.sort()
            for pkg in lst:
                package = {}
                done = {}
                if pkg in report.upgrading:
                    for upgpkg in report.upgrading[pkg]:
                        package.setdefault(_("Upgrades"), []).append(upgpkg)
                        done[upgpkg] = True
                if pkg in report.downgrading:
                    for dwnpkg in report.downgrading[pkg]:
                        package.setdefault(_("Downgrades"), []).append(dwnpkg)
                        done[dwnpkg] = True
                if pkg in report.requires:
                    for reqpkg in report.requires[pkg]:
                        package.setdefault(_("Requires"), []).append(reqpkg)
                if pkg in report.requiredby:
                    for reqpkg in report.requiredby[pkg]:
                        package.setdefault(_("Required By"), []).append(reqpkg)
                if pkg in report.conflicts:
                    for cnfpkg in report.conflicts[pkg]:
                        if cnfpkg in done:
                            continue
                        package.setdefault(_("Conflicts"), []).append(cnfpkg)
                if pkg.installed:
                    reinstall[pkg] = package
                elif pkg in report.upgrading:
                    upgrade[pkg] = package
                elif pkg in report.downgrading:
                    downgrade[pkg] = package
                else:
                    install[pkg] = package
            if reinstall:
                packages[Sorter(_("Reinstall (%d)") % len(reinstall))] = \
                                                                    reinstall
            if install:
                packages[Sorter(_("Install (%d)") % len(install))] = install
            if upgrade:
                packages[Sorter(_("Upgrade (%d)") % len(upgrade))] = upgrade
            if downgrade:
                packages[Sorter(_("Downgrade (%d)") % len(downgrade))] = \
                                                                    downgrade

        if report.removed:
            remove = {}
            lst = report.removed.keys()
            lst.sort()
            for pkg in lst:
                package = {}
                done = {}
                if pkg in report.requires:
                    for reqpkg in report.requires[pkg]:
                        package.setdefault(_("Requires"), []).append(reqpkg)
                if pkg in report.requiredby:
                    for reqpkg in report.requiredby[pkg]:
                        package.setdefault(_("Required By"), []).append(reqpkg)
                if pkg in report.conflicts:
                    for cnfpkg in report.conflicts[pkg]:
                        if cnfpkg in done:
                            continue
                        package.setdefault(_("Conflicts"), []).append(cnfpkg)
                remove[pkg] = package
            if remove:
                packages[Sorter(_("Remove (%d)") % len(report.removed))] = \
                                                                        remove

        if keep:
            packages[Sorter(_("Keep (%d)") % len(keep))] = keep

        dsize = report.getDownloadSize()
        size = report.getInstallSize() - report.getRemoveSize()
        sizestr = ""
        if dsize:
            sizestr += _("%s of package files are needed. ") % sizeToStr(dsize)
        if size > 0:
            sizestr += _("%s will be used.") % sizeToStr(size)
        elif size < 0:
            size *= -1
            sizestr += _("%s will be freed.") % sizeToStr(size)
        if dsize or size:
            self._sizelabel.set_text(sizestr)
            self._sizelabel.show()
        else:
            self._sizelabel.hide()

        if confirm:
            self._confirmbbox.show()
            self._closebbox.hide()
        else:
            self._closebbox.show()
            self._confirmbbox.hide()

        if label:
            self._label.set_text(label)
            self._label.show()
        else:
            self._label.hide()

        self._pv.setPackages(packages, changeset)

        # Expand first level
        self._pv.setExpanded([(x,) for x in packages])

        self._result = False
        self._window.show()
        gtk.main()
        self._window.hide()

        return self._result
Ejemplo n.º 10
0
    def __init__(self):
        gtk.Alignment.__init__(self, 0.5, 0.5, 1.0, 1.0)

        self._pkg = None
        self._changeset = None

        font = self.style.font_desc.copy()
        font.set_size(font.get_size()-pango.SCALE)

        boldfont = font.copy()
        boldfont.set_weight(pango.WEIGHT_BOLD)

        if sysconf.get("gtk-description-fontsize"):
            fontsize = int(sysconf.get("gtk-description-fontsize"))

            descfont = self.style.font_desc.copy()
            descfont.set_size(fontsize*pango.SCALE)

            bolddescfont = descfont.copy()
            bolddescfont.set_weight(pango.WEIGHT_BOLD)
        else:
            descfont = font
            bolddescfont = boldfont

        self._notebook = gtk.Notebook()
        self._notebook.show()
        self.add(self._notebook)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        #sw.set_border_width(5)
        sw.show()

        table = gtk.Table()
        table.set_row_spacings(2)
        table.set_col_spacings(5)
        table.set_border_width(5)
        table.show()
        sw.add_with_viewport(table)

        self._info = type("Info", (), {})()

        attrsleft = pango.AttrList()
        attrsleft.insert(pango.AttrFontDesc(font, 0, -1))
        attrsright = pango.AttrList()
        attrsright.insert(pango.AttrFontDesc(boldfont, 0, -1))

        style = sw.get_style()
        bgcolor = style.bg[gtk.STATE_NORMAL]
        
        self._reftv = gtk.TextView()
        self._reftv.modify_base(gtk.STATE_NORMAL, bgcolor)
        self._reftv.set_editable(False)
        self._reftv.set_cursor_visible(False)
        self._reftv.connect("motion-notify-event", self.motion_notify_event)
        self._reftv.connect("event-after", self.event_after)
        self._reftv.show()
        self._reftv.get_buffer().create_tag("reference", font_desc=font)

        row = 0
        for attr, text in [("status", _("Status:")),
                           ("priority", _("Priority:")),
                           ("group", _("Group:")),
                           ("installedsize", _("Installed Size:")),
                           ("channels", _("Channels:")),
                           ("reference", _("Reference URLs:"))]:
            label = gtk.Label(text)
            label.set_attributes(attrsleft)
            if attr == "channels":
                label.set_alignment(1.0, 0.0)
            else:
                label.set_alignment(1.0, 0.5)
            label.show()
            table.attach(label, 0, 1, row, row+1, gtk.FILL, gtk.FILL)
            setattr(self._info, attr+"_label", label)
            if attr == "reference":
                label = self._reftv
            else:
                label = gtk.Label()
                label.set_attributes(attrsright)
                label.set_alignment(0.0, 0.5)
            label.show()
            table.attach(label, 1, 2, row, row+1, gtk.FILL, gtk.FILL)
            setattr(self._info, attr, label)
            row += 1

        label = gtk.Label(_("General"))
        self._notebook.append_page(sw, label)


        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.set_border_width(5)
        sw.show()

        self._descrtv = gtk.TextView()
        self._descrtv.set_editable(False)
        self._descrtv.set_cursor_visible(False)
        self._descrtv.set_left_margin(5)
        self._descrtv.set_right_margin(5)
        self._descrtv.show()
        buffer = self._descrtv.get_buffer()
        buffer.create_tag("description", font_desc=descfont)
        buffer.create_tag("summary", font_desc=bolddescfont)
        sw.add(self._descrtv)

        label = gtk.Label(_("Description"))
        self._notebook.append_page(sw, label)

        vbox = gtk.VBox()
        vbox.show()

        filtertable = gtk.Table(1, 1)
        filtertable.set_row_spacings(5)
        filtertable.set_col_spacings(5)
        filtertable.set_border_width(5)
        filtertable.show()
        vbox.pack_end(filtertable, False)

        label = gtk.Label(_("Filter:"))
        label.show()
        filtertable.attach(label, 0, 1, 0, 1, 0, 0)

        if gtk.gtk_version >= (2, 16, 0) or not sexy:
            self._filterentry = gtk.Entry()
        else:
            self._filterentry = sexy.IconEntry()
        self._filterentry.connect("activate", lambda x: self.filterContent())
        self._filterentry.show()
        filtertable.attach(self._filterentry, 1, 2, 0, 1)

        align = gtk.Alignment()
        align.set(1, 0, 0, 0)
        align.set_padding(0, 0, 10, 0)
        align.show()
        filtertable.attach(align, 2, 3, 0, 1, gtk.FILL, gtk.FILL)

        if gtk.gtk_version >= (2, 16, 0):
            self._filterentry.set_property("primary-icon-stock", "gtk-find")
            self._filterentry.set_property("secondary-icon-stock", "gtk-clear")
            def press(entry, icon_pos, event):
                if int(icon_pos) == 0: # "primary"
                    self.filterContent()
                elif int(icon_pos) == 1: # "secondary"
                    self.filterClear()
            self._filterentry.connect("icon-press", press)
        elif sexy:
            image = gtk.Image()
            image.set_from_stock("gtk-find", gtk.ICON_SIZE_BUTTON)
            self._filterentry.set_icon(sexy.ICON_ENTRY_PRIMARY, image)
            image = gtk.Image()
            image.set_from_stock("gtk-clear", gtk.ICON_SIZE_BUTTON)
            self._filterentry.set_icon(sexy.ICON_ENTRY_SECONDARY, image)
            def pressed(entry, icon_pos, button):
                if icon_pos == 0: # "primary"
                    self.filterContent()
                elif icon_pos == 1: # "secondary"
                    self.filterClear()
            self._filterentry.connect("icon-pressed", pressed)
        else:
            button = gtk.Button()
            button.set_relief(gtk.RELIEF_NONE)
            button.connect("clicked", lambda x: self.filterContent())
            button.show()
            filtertable.attach(button, 3, 4, 0, 1, 0, 0)
            image = gtk.Image()
            image.set_from_stock("gtk-find", gtk.ICON_SIZE_BUTTON)
            image.show()
            button.add(image)

            button = gtk.Button()
            button.set_relief(gtk.RELIEF_NONE)
            button.connect("clicked", lambda x: self.filterClear())
            button.show()
            filtertable.attach(button, 4, 5, 0, 1, 0, 0)
            image = gtk.Image()
            image.set_from_stock("gtk-clear", gtk.ICON_SIZE_BUTTON)
            image.show()
            button.add(image)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.set_border_width(5)
        sw.show()

        self._conttv = gtk.TextView()
        self._conttv.set_editable(False)
        self._conttv.set_cursor_visible(False)
        self._conttv.set_left_margin(5)
        self._conttv.set_right_margin(5)
        self._conttv.show()
        buffer = self._conttv.get_buffer()
        buffer.create_tag("content", font_desc=font)
        sw.add(self._conttv)

        vbox.add(sw)

        label = gtk.Label(_("Content"))
        self._notebook.append_page(vbox, label)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.set_border_width(5)
        sw.show()

        self._change = gtk.TextView()
        self._change.set_editable(False)
        self._change.set_cursor_visible(False)
        self._change.set_left_margin(5)
        self._change.set_right_margin(5)
        self._change.show()
        buffer = self._change.get_buffer()
        buffer.create_tag("changetime", font_desc=boldfont)
        buffer.create_tag("changelog", font_desc=font)
        sw.add(self._change)

        label = gtk.Label(_("Changelog"))
        self._notebook.append_page(sw, label)

        self._relations = GtkPackageView()
        self._relations.set_border_width(5)
        self._relations.getTreeView().set_headers_visible(False)
        self._relations.show()

        label = gtk.Label(_("Relations"))
        self._notebook.append_page(self._relations, label)


        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        sw.set_border_width(5)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.show()

        model = gtk.ListStore(gobject.TYPE_STRING,
                              gobject.TYPE_STRING,
                              gobject.TYPE_STRING)
        self._urls = gtk.TreeView(model)
        self._urls.set_headers_visible(False)
        self._urls.show()
        renderer = gtk.CellRendererText()
        renderer.set_property("font-desc", font)
        self._urls.insert_column_with_attributes(-1, _("Channel"),
                                                 renderer, text=0)
        self._urls.insert_column_with_attributes(-1, _("Size"),
                                                 renderer, text=1)
        self._urls.insert_column_with_attributes(-1, _("URL"),
                                                 renderer, text=2)
        sw.add(self._urls)

        label = gtk.Label(_("URLs"))
        self._notebook.append_page(sw, label)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.set_border_width(5)
        sw.show()

        self._notebook.connect("switch_page", self._switchPage)
        self._notebook.set_current_page(sysconf.get("gtk-starting-tab", 0))
Ejemplo n.º 11
0
class GtkPackageInfo(gtk.Alignment):
    hovering_over_link = False
    hand_cursor = gtk.gdk.Cursor(gtk.gdk.HAND2)
    regular_cursor = gtk.gdk.Cursor(gtk.gdk.XTERM)

    def __init__(self):
        gtk.Alignment.__init__(self, 0.5, 0.5, 1.0, 1.0)

        self._pkg = None
        self._changeset = None

        font = self.style.font_desc.copy()
        font.set_size(font.get_size()-pango.SCALE)

        boldfont = font.copy()
        boldfont.set_weight(pango.WEIGHT_BOLD)

        if sysconf.get("gtk-description-fontsize"):
            fontsize = int(sysconf.get("gtk-description-fontsize"))

            descfont = self.style.font_desc.copy()
            descfont.set_size(fontsize*pango.SCALE)

            bolddescfont = descfont.copy()
            bolddescfont.set_weight(pango.WEIGHT_BOLD)
        else:
            descfont = font
            bolddescfont = boldfont

        self._notebook = gtk.Notebook()
        self._notebook.show()
        self.add(self._notebook)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        #sw.set_border_width(5)
        sw.show()

        table = gtk.Table()
        table.set_row_spacings(2)
        table.set_col_spacings(5)
        table.set_border_width(5)
        table.show()
        sw.add_with_viewport(table)

        self._info = type("Info", (), {})()

        attrsleft = pango.AttrList()
        attrsleft.insert(pango.AttrFontDesc(font, 0, -1))
        attrsright = pango.AttrList()
        attrsright.insert(pango.AttrFontDesc(boldfont, 0, -1))

        style = sw.get_style()
        bgcolor = style.bg[gtk.STATE_NORMAL]
        
        self._reftv = gtk.TextView()
        self._reftv.modify_base(gtk.STATE_NORMAL, bgcolor)
        self._reftv.set_editable(False)
        self._reftv.set_cursor_visible(False)
        self._reftv.connect("motion-notify-event", self.motion_notify_event)
        self._reftv.connect("event-after", self.event_after)
        self._reftv.show()
        self._reftv.get_buffer().create_tag("reference", font_desc=font)

        row = 0
        for attr, text in [("status", _("Status:")),
                           ("priority", _("Priority:")),
                           ("group", _("Group:")),
                           ("installedsize", _("Installed Size:")),
                           ("channels", _("Channels:")),
                           ("reference", _("Reference URLs:"))]:
            label = gtk.Label(text)
            label.set_attributes(attrsleft)
            if attr == "channels":
                label.set_alignment(1.0, 0.0)
            else:
                label.set_alignment(1.0, 0.5)
            label.show()
            table.attach(label, 0, 1, row, row+1, gtk.FILL, gtk.FILL)
            setattr(self._info, attr+"_label", label)
            if attr == "reference":
                label = self._reftv
            else:
                label = gtk.Label()
                label.set_attributes(attrsright)
                label.set_alignment(0.0, 0.5)
            label.show()
            table.attach(label, 1, 2, row, row+1, gtk.FILL, gtk.FILL)
            setattr(self._info, attr, label)
            row += 1

        label = gtk.Label(_("General"))
        self._notebook.append_page(sw, label)


        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.set_border_width(5)
        sw.show()

        self._descrtv = gtk.TextView()
        self._descrtv.set_editable(False)
        self._descrtv.set_cursor_visible(False)
        self._descrtv.set_left_margin(5)
        self._descrtv.set_right_margin(5)
        self._descrtv.show()
        buffer = self._descrtv.get_buffer()
        buffer.create_tag("description", font_desc=descfont)
        buffer.create_tag("summary", font_desc=bolddescfont)
        sw.add(self._descrtv)

        label = gtk.Label(_("Description"))
        self._notebook.append_page(sw, label)

        vbox = gtk.VBox()
        vbox.show()

        filtertable = gtk.Table(1, 1)
        filtertable.set_row_spacings(5)
        filtertable.set_col_spacings(5)
        filtertable.set_border_width(5)
        filtertable.show()
        vbox.pack_end(filtertable, False)

        label = gtk.Label(_("Filter:"))
        label.show()
        filtertable.attach(label, 0, 1, 0, 1, 0, 0)

        if gtk.gtk_version >= (2, 16, 0) or not sexy:
            self._filterentry = gtk.Entry()
        else:
            self._filterentry = sexy.IconEntry()
        self._filterentry.connect("activate", lambda x: self.filterContent())
        self._filterentry.show()
        filtertable.attach(self._filterentry, 1, 2, 0, 1)

        align = gtk.Alignment()
        align.set(1, 0, 0, 0)
        align.set_padding(0, 0, 10, 0)
        align.show()
        filtertable.attach(align, 2, 3, 0, 1, gtk.FILL, gtk.FILL)

        if gtk.gtk_version >= (2, 16, 0):
            self._filterentry.set_property("primary-icon-stock", "gtk-find")
            self._filterentry.set_property("secondary-icon-stock", "gtk-clear")
            def press(entry, icon_pos, event):
                if int(icon_pos) == 0: # "primary"
                    self.filterContent()
                elif int(icon_pos) == 1: # "secondary"
                    self.filterClear()
            self._filterentry.connect("icon-press", press)
        elif sexy:
            image = gtk.Image()
            image.set_from_stock("gtk-find", gtk.ICON_SIZE_BUTTON)
            self._filterentry.set_icon(sexy.ICON_ENTRY_PRIMARY, image)
            image = gtk.Image()
            image.set_from_stock("gtk-clear", gtk.ICON_SIZE_BUTTON)
            self._filterentry.set_icon(sexy.ICON_ENTRY_SECONDARY, image)
            def pressed(entry, icon_pos, button):
                if icon_pos == 0: # "primary"
                    self.filterContent()
                elif icon_pos == 1: # "secondary"
                    self.filterClear()
            self._filterentry.connect("icon-pressed", pressed)
        else:
            button = gtk.Button()
            button.set_relief(gtk.RELIEF_NONE)
            button.connect("clicked", lambda x: self.filterContent())
            button.show()
            filtertable.attach(button, 3, 4, 0, 1, 0, 0)
            image = gtk.Image()
            image.set_from_stock("gtk-find", gtk.ICON_SIZE_BUTTON)
            image.show()
            button.add(image)

            button = gtk.Button()
            button.set_relief(gtk.RELIEF_NONE)
            button.connect("clicked", lambda x: self.filterClear())
            button.show()
            filtertable.attach(button, 4, 5, 0, 1, 0, 0)
            image = gtk.Image()
            image.set_from_stock("gtk-clear", gtk.ICON_SIZE_BUTTON)
            image.show()
            button.add(image)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.set_border_width(5)
        sw.show()

        self._conttv = gtk.TextView()
        self._conttv.set_editable(False)
        self._conttv.set_cursor_visible(False)
        self._conttv.set_left_margin(5)
        self._conttv.set_right_margin(5)
        self._conttv.show()
        buffer = self._conttv.get_buffer()
        buffer.create_tag("content", font_desc=font)
        sw.add(self._conttv)

        vbox.add(sw)

        label = gtk.Label(_("Content"))
        self._notebook.append_page(vbox, label)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.set_border_width(5)
        sw.show()

        self._change = gtk.TextView()
        self._change.set_editable(False)
        self._change.set_cursor_visible(False)
        self._change.set_left_margin(5)
        self._change.set_right_margin(5)
        self._change.show()
        buffer = self._change.get_buffer()
        buffer.create_tag("changetime", font_desc=boldfont)
        buffer.create_tag("changelog", font_desc=font)
        sw.add(self._change)

        label = gtk.Label(_("Changelog"))
        self._notebook.append_page(sw, label)

        self._relations = GtkPackageView()
        self._relations.set_border_width(5)
        self._relations.getTreeView().set_headers_visible(False)
        self._relations.show()

        label = gtk.Label(_("Relations"))
        self._notebook.append_page(self._relations, label)


        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        sw.set_border_width(5)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.show()

        model = gtk.ListStore(gobject.TYPE_STRING,
                              gobject.TYPE_STRING,
                              gobject.TYPE_STRING)
        self._urls = gtk.TreeView(model)
        self._urls.set_headers_visible(False)
        self._urls.show()
        renderer = gtk.CellRendererText()
        renderer.set_property("font-desc", font)
        self._urls.insert_column_with_attributes(-1, _("Channel"),
                                                 renderer, text=0)
        self._urls.insert_column_with_attributes(-1, _("Size"),
                                                 renderer, text=1)
        self._urls.insert_column_with_attributes(-1, _("URL"),
                                                 renderer, text=2)
        sw.add(self._urls)

        label = gtk.Label(_("URLs"))
        self._notebook.append_page(sw, label)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.set_border_width(5)
        sw.show()

        self._notebook.connect("switch_page", self._switchPage)
        self._notebook.set_current_page(sysconf.get("gtk-starting-tab", 0))

    '''
    this motion_notify_event/event_after code was adopted from hypertext demo
    '''

    # Update the cursor image if the pointer moved.
    def motion_notify_event(self, text_view, event):
        x, y = text_view.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET,
            int(event.x), int(event.y))
        self.set_cursor_if_appropriate(text_view, x, y)
        text_view.window.get_pointer()
        return False

    # Looks at all tags covering the position (x, y) in the text view,
    # and if one of them is a link, change the cursor to the "hands" cursor
    # typically used by web browsers.
    def set_cursor_if_appropriate(self, text_view, x, y):
        hovering = False

        buffer = text_view.get_buffer()
        iter = text_view.get_iter_at_location(x, y)

        tags = iter.get_tags()
        for tag in tags:
            url = tag.get_data("url")
            if url:
                hovering = True
                break

        if hovering != self.hovering_over_link:
            self.hovering_over_link = hovering

        if self.hovering_over_link:
            text_view.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(self.hand_cursor)
        else:
            text_view.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(self.regular_cursor)

    def event_after(self, text_view, event):
        if event.type != gtk.gdk.BUTTON_RELEASE:
            return False
        if event.button != 1:
            return False
        buffer = text_view.get_buffer()

        # we shouldn't follow a link if the user has selected something
        try:
            start, end = buffer.get_selection_bounds()
        except ValueError:
            # If there is nothing selected, None is return
            pass
        else:
            if start.get_offset() != end.get_offset():
                return False

        x, y = text_view.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET,
            int(event.x), int(event.y))
        iter = text_view.get_iter_at_location(x, y)

        self.follow_if_link(text_view, iter)
        return False

    def follow_if_link(self, text_view, iter):
        ''' Looks at all tags covering the position of iter in the text view,
            and if one of them is a link, follow it by opening the url.
        '''
        tags = iter.get_tags()
        for tag in tags:
            url = tag.get_data("url")
            if url:
                self.open_url(url)
                break

    def open_url(self, url):
        ''' Open the specified URL in a browser (try a few alternatives) '''
        for browser in ['xdg-open', 'gnome-open', 'exo-open', \
                        'x-www-browser', 'firefox', 'open']:
            command = [browser, url]
            try:
                if subprocess:
                    retcode = subprocess.call(command)
                else:
                    retcode = os.system(" ".join(command))
                if retcode == 0:
                    break
            except OSError:
                pass

    def _switchPage(self, notebook, page, pagenum):
        self.setPackage(self._pkg, _pagenum=pagenum)

    def setChangeSet(self, changeset):
        self._changeset = changeset

    def setPackage(self, pkg, _pagenum=None):

        self._pkg = pkg

        if _pagenum is not None:
            num = _pagenum
        else:
            num = self._notebook.get_current_page()

        if num == 0:

            # Update general information

            if not pkg:
                self._info.status.set_text("")
                self._info.group.set_text("")
                self._info.installedsize.set_text("")
                self._info.priority.set_text("")
                self._info.channels.set_text("")
                self._info.reference.get_buffer().set_text("")
                return

            group = None
            installedsize = None
            channels = []
            urls = []
            for loader in pkg.loaders:
                info = loader.getInfo(pkg)
                if group is None:
                    group = info.getGroup()
                if installedsize is None:
                    installedsize = info.getInstalledSize()
                channel = loader.getChannel()
                channels.append("%s (%s)" %
                                (channel.getName() or channel.getAlias(),
                                 channel.getAlias()))
                urls.extend(info.getReferenceURLs())

            flags = pkgconf.testAllFlags(pkg)
            if flags:
                flags.sort()
                flags = " (%s)" % ", ".join(flags)
            else:
                flags = ""

            status = pkg.installed and _("Installed") or _("Available")
            self._info.status.set_text(status+flags)
            self._info.group.set_text(group or _("Unknown"))
            self._info.priority.set_text(str(pkg.getPriority()))
            self._info.channels.set_text("\n".join(channels))
            self._info.reference.get_buffer().set_text("")
            for url in urls:
                refbuf = self._info.reference.get_buffer()
                tag = refbuf.create_tag(None,
                        foreground="blue", underline=pango.UNDERLINE_SINGLE)
                tag.set_data("url", url)
                refbuf.insert_with_tags(refbuf.get_end_iter(), url, tag)

            if installedsize:
                self._info.installedsize.set_text(sizeToStr(installedsize))
                self._info.installedsize.show()
                self._info.installedsize_label.show()
            else:
                self._info.installedsize.hide()
                self._info.installedsize_label.hide()

        elif num == 1:

            # Update summary/description

            descrbuf = self._descrtv.get_buffer()
            descrbuf.set_text("")
            if not pkg: return

            iter = descrbuf.get_end_iter()
            for loader in pkg.loaders:
                info = loader.getInfo(pkg)
                summary = info.getSummary()
                if summary:
                    descrbuf.insert_with_tags_by_name(iter, summary+"\n\n",
                                                      "summary")
                    description = info.getDescription()
                    if description != summary:
                        descrbuf.insert_with_tags_by_name(iter,
                                                          description+"\n\n",
                                                          "description")
                    break
            else:
                loader = pkg.loaders.keys()[0]

        elif num == 2:

            # Update contents

            if not pkg:
                contbuf = self._conttv.get_buffer()
                contbuf.set_text("")
                return

            self._setContent(pkg)

        elif num == 3:
            # Update changelog

            contbuf = self._change.get_buffer()
            contbuf.set_text("")
            if not pkg: return

            iter = contbuf.get_end_iter()
            for loader in pkg.loaders:
                if loader.getInstalled():
                    break
            else:
                loader = pkg.loaders.keys()[0]
            info = loader.getInfo(pkg)
            changelog = info.getChangeLog()

            for i in range(len(changelog)/2):
                contbuf.insert_with_tags_by_name(iter, changelog[2*i]+"\n", "changetime")
                changesplit = changelog[2*i+1].split("\n")
                changedetails = changesplit[0] + "\n"
                for i in range(1, len(changesplit)):
                    changedetails += "  " + changesplit[i] + "\n"
                contbuf.insert_with_tags_by_name(iter, changedetails, "changelog")

        elif num == 4:

            # Update relations

            if not pkg:
                self._relations.setPackages([])
                return

            self._setRelations(pkg)

        elif num == 5:

            # Update URLs

            model = self._urls.get_model()
            model.clear()

            if not pkg:
                return

            items = []
            for loader in pkg.loaders:
                channel = loader.getChannel()
                alias = channel.getAlias()
                info = loader.getInfo(pkg)
                for url in info.getURLs():
                    items.append((alias, sizeToStr(info.getSize(url)), url))

            items.sort()

            lastitem = None
            for item in items:
                if item != lastitem:
                    lastitem = item
                    model.append(item)

    def filterContent(self):
        if self._pkg:
            self._setContent(self._pkg)

    def filterClear(self):
        self._filterentry.set_text("")
        self.filterContent()

    def _setContent(self, pkg):

            contbuf = self._conttv.get_buffer()
            contbuf.set_text("")

            iter = contbuf.get_end_iter()
            for loader in pkg.loaders:
                if loader.getInstalled():
                    break
            else:
                loader = pkg.loaders.keys()[0]
            info = loader.getInfo(pkg)
            pathlist = info.getPathList()
            filter = self._filterentry.get_text().strip()
            if filter:
                pathlist = fnmatch.filter(pathlist, filter)
            pathlist.sort()
            for path in pathlist:
                contbuf.insert_with_tags_by_name(iter, path+"\n", "content")

    def _setRelations(self, pkg):

        class Sorter(str):
            ORDER = [_("Provides"), _("Upgrades"),
                     _("Requires"), _("Conflicts")]
            def __cmp__(self, other):
                return cmp(self.ORDER.index(str(self)),
                           self.ORDER.index(str(other)))
            def __lt__(self, other):
                return cmp(self, other) < 0

        relations = {}

        for prv in pkg.provides:

            prvmap = {}
            
            requiredby = []
            for req in prv.requiredby:
                requiredby.extend(req.packages)
            if requiredby:
                prvmap[_("Required By")] = requiredby

            upgradedby = []
            for upg in prv.upgradedby:
                upgradedby.extend(upg.packages)
            if upgradedby:
                prvmap[_("Upgraded By")] = upgradedby

            conflictedby = []
            for cnf in prv.conflictedby:
                conflictedby.extend(cnf.packages)
            if conflictedby:
                prvmap[_("Conflicted By")] = conflictedby

            if prvmap:
                relations.setdefault(Sorter(_("Provides")), {})[str(prv)] = \
                                                                        prvmap

        requires = {}
        for req in pkg.requires:
            lst = requires.setdefault(str(req), [])
            for prv in req.providedby:
                lst.extend(prv.packages)
            lst[:] = dict.fromkeys(lst).keys()
        if requires:
            relations[Sorter(_("Requires"))] = requires

        upgrades = {}
        for upg in pkg.upgrades:
            lst = upgrades.setdefault(str(upg), [])
            for prv in upg.providedby:
                lst.extend(prv.packages)
            lst[:] = dict.fromkeys(lst).keys()
        if upgrades:
            relations[Sorter(_("Upgrades"))] = upgrades

        conflicts = {}
        for cnf in pkg.conflicts:
            lst = conflicts.setdefault(str(cnf), [])
            for prv in cnf.providedby:
                lst.extend(prv.packages)
            lst[:] = dict.fromkeys(lst).keys()
        if conflicts:
            relations[Sorter(_("Conflicts"))] = conflicts

        self._relations.setPackages(relations, self._changeset)
Ejemplo n.º 12
0
    def __init__(self, ctrl):
        GtkInterface.__init__(self, ctrl)

        self._changeset = None

        self._window = gtk.Window()
        self._window.set_title("Smart Package Manager %s" % VERSION)
        self._window.set_position(gtk.WIN_POS_CENTER)
        self._window.set_geometry_hints(min_width=640, min_height=480)
        def delete(widget, event):
            gtk.main_quit()
            return True
        self._window.connect("delete-event", delete)

        self._log.set_transient_for(self._window)
        self._progress.set_transient_for(self._window)
        self._hassubprogress.set_transient_for(self._window)
        self._changes.set_transient_for(self._window)

        self._watch = gtk.gdk.Cursor(gtk.gdk.WATCH)

        self._undo = []
        self._redo = []

        self._topvbox = gtk.VBox()
        self._topvbox.show()
        self._window.add(self._topvbox)

        globals = {"self": self, "gtk": gtk}
        self._actions = gtk.ActionGroup("Actions")
        self._actions.add_actions(compileActions(ACTIONS, globals))

        self._filters = {}
        for name, label in [("hide-non-upgrades", _("Hide Non-upgrades")),
                            ("hide-installed", _("Hide Installed")),
                            ("hide-uninstalled", _("Hide Uninstalled")),
                            ("hide-unmarked", _("Hide Unmarked")),
                            ("hide-old", _("Hide Old"))]:
            action = gtk.ToggleAction(name, label, "", "")
            action.connect("toggled", lambda x, y: self.toggleFilter(y), name)
            self._actions.add_action(action)

        treestyle = sysconf.get("package-tree")
        lastaction = None
        for name, label in [("groups", _("Groups")),
                            ("channels", _("Channels")),
                            ("channels-groups", _("Channels & Groups")),
                            ("none", _("None"))]:
            action = gtk.RadioAction("tree-style-"+name, label, "", "", 0)
            if name == treestyle:
                action.set_active(True)
            if lastaction:
                action.set_group(lastaction)
            lastaction = action
            action.connect("toggled", lambda x, y: self.setTreeStyle(y), name)
            self._actions.add_action(action)

        self._ui = gtk.UIManager()
        self._ui.insert_action_group(self._actions, 0)
        self._ui.add_ui_from_string(UI)
        self._menubar = self._ui.get_widget("/menubar")
        self._topvbox.pack_start(self._menubar, False)

        self._toolbar = self._ui.get_widget("/toolbar")
        self._toolbar.set_style(gtk.TOOLBAR_ICONS)
        self._topvbox.pack_start(self._toolbar, False)

        self._window.add_accel_group(self._ui.get_accel_group())

        self._execmenuitem = self._ui.get_action("/menubar/file/exec-changes")
        self._execmenuitem.set_property("sensitive", False)
        self._clearmenuitem = self._ui.get_action("/menubar/edit/clear-changes")
        self._clearmenuitem.set_property("sensitive", False)
        self._undomenuitem = self._ui.get_action("/menubar/edit/undo")
        self._undomenuitem.set_property("sensitive", False)
        self._redomenuitem = self._ui.get_action("/menubar/edit/redo")
        self._redomenuitem.set_property("sensitive", False)

        # Search bar

        self._searchbar = gtk.Alignment()
        self._searchbar.set(0, 0, 1, 1)
        self._searchbar.set_padding(3, 3, 0, 0)
        self._topvbox.pack_start(self._searchbar, False)

        searchvp = gtk.Viewport()
        searchvp.set_shadow_type(gtk.SHADOW_OUT)
        searchvp.show()
        self._searchbar.add(searchvp)

        searchtable = gtk.Table(1, 1)
        searchtable.set_row_spacings(5)
        searchtable.set_col_spacings(5)
        searchtable.set_border_width(5)
        searchtable.show()
        searchvp.add(searchtable)

        label = gtk.Label(_("Search:"))
        label.show()
        searchtable.attach(label, 0, 1, 0, 1, 0, 0)

        self._searchentry = gtk.Entry()
        self._searchentry.connect("activate", lambda x: self.refreshPackages())
        self._searchentry.show()
        searchtable.attach(self._searchentry, 1, 2, 0, 1)

        button = gtk.Button()
        button.set_relief(gtk.RELIEF_NONE)
        button.connect("clicked", lambda x: self.refreshPackages())
        button.show()
        searchtable.attach(button, 2, 3, 0, 1, 0, 0)
        image = gtk.Image()
        image.set_from_stock("gtk-find", gtk.ICON_SIZE_BUTTON)
        image.show()
        button.add(image)

        align = gtk.Alignment()
        align.set(1, 0, 0, 0)
        align.set_padding(0, 0, 10, 0)
        align.show()
        searchtable.attach(align, 3, 4, 0, 1, gtk.FILL, gtk.FILL)
        button = gtk.Button()
        button.set_size_request(20, 20)
        button.set_relief(gtk.RELIEF_NONE)
        button.connect("clicked", lambda x: self.toggleSearch())
        button.show()
        align.add(button)
        image = gtk.Image()
        image.set_from_stock("gtk-close", gtk.ICON_SIZE_MENU)
        image.show()
        button.add(image)

        hbox = gtk.HBox()
        hbox.set_spacing(10)
        hbox.show()
        searchtable.attach(hbox, 1, 2, 1, 2)

        self._searchname = gtk.RadioButton(None, _("Automatic"))
        self._searchname.set_active(True)
        self._searchname.connect("clicked", lambda x: self.refreshPackages())
        self._searchname.show()
        hbox.pack_start(self._searchname, False)
        self._searchdesc = gtk.RadioButton(self._searchname, _("Description"))
        self._searchdesc.connect("clicked", lambda x: self.refreshPackages())
        self._searchdesc.show()
        hbox.pack_start(self._searchdesc, False)

        # Packages and information

        self._vpaned = gtk.VPaned()
        self._vpaned.show()
        self._topvbox.pack_start(self._vpaned)

        self._pv = GtkPackageView()
        self._pv.show()
        self._vpaned.pack1(self._pv, True)

        self._pi = GtkPackageInfo()
        self._pi.show()
        self._pv.connect("package_selected",
                         lambda x, y: self._pi.setPackage(y))
        self._pv.connect("package_activated",
                         lambda x, y: self.actOnPackages(y))
        self._pv.connect("package_popup", self.packagePopup)
        self._vpaned.pack2(self._pi, False)

        self._status = gtk.Statusbar()
        self._status.show()
        self._topvbox.pack_start(self._status, False)
Ejemplo n.º 13
0
class GtkInteractiveInterface(GtkInterface):

    def __init__(self, ctrl):
        GtkInterface.__init__(self, ctrl)

        self._changeset = None

        self._window = gtk.Window()
        self._window.set_title("Smart Package Manager %s" % VERSION)
        self._window.set_position(gtk.WIN_POS_CENTER)
        self._window.set_geometry_hints(min_width=640, min_height=480)
        def delete(widget, event):
            gtk.main_quit()
            return True
        self._window.connect("delete-event", delete)

        self._log.set_transient_for(self._window)
        self._progress.set_transient_for(self._window)
        self._hassubprogress.set_transient_for(self._window)
        self._changes.set_transient_for(self._window)

        self._watch = gtk.gdk.Cursor(gtk.gdk.WATCH)

        self._undo = []
        self._redo = []

        self._topvbox = gtk.VBox()
        self._topvbox.show()
        self._window.add(self._topvbox)

        globals = {"self": self, "gtk": gtk}
        self._actions = gtk.ActionGroup("Actions")
        self._actions.add_actions(compileActions(ACTIONS, globals))

        self._filters = {}
        for name, label in [("hide-non-upgrades", _("Hide Non-upgrades")),
                            ("hide-installed", _("Hide Installed")),
                            ("hide-uninstalled", _("Hide Uninstalled")),
                            ("hide-unmarked", _("Hide Unmarked")),
                            ("hide-old", _("Hide Old"))]:
            action = gtk.ToggleAction(name, label, "", "")
            action.connect("toggled", lambda x, y: self.toggleFilter(y), name)
            self._actions.add_action(action)

        treestyle = sysconf.get("package-tree")
        lastaction = None
        for name, label in [("groups", _("Groups")),
                            ("channels", _("Channels")),
                            ("channels-groups", _("Channels & Groups")),
                            ("none", _("None"))]:
            action = gtk.RadioAction("tree-style-"+name, label, "", "", 0)
            if name == treestyle:
                action.set_active(True)
            if lastaction:
                action.set_group(lastaction)
            lastaction = action
            action.connect("toggled", lambda x, y: self.setTreeStyle(y), name)
            self._actions.add_action(action)

        self._ui = gtk.UIManager()
        self._ui.insert_action_group(self._actions, 0)
        self._ui.add_ui_from_string(UI)
        self._menubar = self._ui.get_widget("/menubar")
        self._topvbox.pack_start(self._menubar, False)

        self._toolbar = self._ui.get_widget("/toolbar")
        self._toolbar.set_style(gtk.TOOLBAR_ICONS)
        self._topvbox.pack_start(self._toolbar, False)

        self._window.add_accel_group(self._ui.get_accel_group())

        self._execmenuitem = self._ui.get_action("/menubar/file/exec-changes")
        self._execmenuitem.set_property("sensitive", False)
        self._clearmenuitem = self._ui.get_action("/menubar/edit/clear-changes")
        self._clearmenuitem.set_property("sensitive", False)
        self._undomenuitem = self._ui.get_action("/menubar/edit/undo")
        self._undomenuitem.set_property("sensitive", False)
        self._redomenuitem = self._ui.get_action("/menubar/edit/redo")
        self._redomenuitem.set_property("sensitive", False)

        # Search bar

        self._searchbar = gtk.Alignment()
        self._searchbar.set(0, 0, 1, 1)
        self._searchbar.set_padding(3, 3, 0, 0)
        self._topvbox.pack_start(self._searchbar, False)

        searchvp = gtk.Viewport()
        searchvp.set_shadow_type(gtk.SHADOW_OUT)
        searchvp.show()
        self._searchbar.add(searchvp)

        searchtable = gtk.Table(1, 1)
        searchtable.set_row_spacings(5)
        searchtable.set_col_spacings(5)
        searchtable.set_border_width(5)
        searchtable.show()
        searchvp.add(searchtable)

        label = gtk.Label(_("Search:"))
        label.show()
        searchtable.attach(label, 0, 1, 0, 1, 0, 0)

        self._searchentry = gtk.Entry()
        self._searchentry.connect("activate", lambda x: self.refreshPackages())
        self._searchentry.show()
        searchtable.attach(self._searchentry, 1, 2, 0, 1)

        button = gtk.Button()
        button.set_relief(gtk.RELIEF_NONE)
        button.connect("clicked", lambda x: self.refreshPackages())
        button.show()
        searchtable.attach(button, 2, 3, 0, 1, 0, 0)
        image = gtk.Image()
        image.set_from_stock("gtk-find", gtk.ICON_SIZE_BUTTON)
        image.show()
        button.add(image)

        align = gtk.Alignment()
        align.set(1, 0, 0, 0)
        align.set_padding(0, 0, 10, 0)
        align.show()
        searchtable.attach(align, 3, 4, 0, 1, gtk.FILL, gtk.FILL)
        button = gtk.Button()
        button.set_size_request(20, 20)
        button.set_relief(gtk.RELIEF_NONE)
        button.connect("clicked", lambda x: self.toggleSearch())
        button.show()
        align.add(button)
        image = gtk.Image()
        image.set_from_stock("gtk-close", gtk.ICON_SIZE_MENU)
        image.show()
        button.add(image)

        hbox = gtk.HBox()
        hbox.set_spacing(10)
        hbox.show()
        searchtable.attach(hbox, 1, 2, 1, 2)

        self._searchname = gtk.RadioButton(None, _("Automatic"))
        self._searchname.set_active(True)
        self._searchname.connect("clicked", lambda x: self.refreshPackages())
        self._searchname.show()
        hbox.pack_start(self._searchname, False)
        self._searchdesc = gtk.RadioButton(self._searchname, _("Description"))
        self._searchdesc.connect("clicked", lambda x: self.refreshPackages())
        self._searchdesc.show()
        hbox.pack_start(self._searchdesc, False)

        # Packages and information

        self._vpaned = gtk.VPaned()
        self._vpaned.show()
        self._topvbox.pack_start(self._vpaned)

        self._pv = GtkPackageView()
        self._pv.show()
        self._vpaned.pack1(self._pv, True)

        self._pi = GtkPackageInfo()
        self._pi.show()
        self._pv.connect("package_selected",
                         lambda x, y: self._pi.setPackage(y))
        self._pv.connect("package_activated",
                         lambda x, y: self.actOnPackages(y))
        self._pv.connect("package_popup", self.packagePopup)
        self._vpaned.pack2(self._pi, False)

        self._status = gtk.Statusbar()
        self._status.show()
        self._topvbox.pack_start(self._status, False)

    def showStatus(self, msg):
        self._status.pop(0)
        self._status.push(0, msg)
        while gtk.events_pending():
            gtk.main_iteration()

    def hideStatus(self):
        self._status.pop(0)
        while gtk.events_pending():
            gtk.main_iteration()

    def run(self, command=None, argv=None):
        self.setCatchExceptions(True)
        self.loadState()
        self._window.set_icon(getPixbuf("smart"))
        self._window.show()
        self._ctrl.reloadChannels()
        self._changeset = ChangeSet(self._ctrl.getCache())
        self._pi.setChangeSet(self._changeset)
        self._progress.hide()
        self.refreshPackages()
        gtk.main()
        self.saveState()
        self.setCatchExceptions(False)

    # Non-standard interface methods:

    def saveState(self):
        sysconf.set("gtk-size", self._window.get_size())
        #sysconf.set("gtk-position", self._window.get_position())
        sysconf.set("gtk-vpaned-position", self._vpaned.get_position())

    def loadState(self):
        var = sysconf.get("gtk-size")
        if var is not None:
            self._window.set_size_request(*var)
        #var = sysconf.get("gtk-position")
        #if var is not None:
        #    self._window.move(*var)
        var = sysconf.get("gtk-vpaned-position")
        if var is not None:
            self._vpaned.set_position(var)

    def getChangeSet(self):
        return self._changeset

    def updateChannels(self, selected=False, channels=None):
        if selected:
            aliases = GtkChannelSelector().show()
            channels = [channel for channel in self._ctrl.getChannels()
                        if channel.getAlias() in aliases]
            if not channels:
                return
        state = self._changeset.getPersistentState()
        self._ctrl.reloadChannels(channels, caching=NEVER)
        self._changeset.setPersistentState(state)
        self.refreshPackages()

    def rebuildCache(self):
        state = self._changeset.getPersistentState()
        self._ctrl.reloadChannels()
        self._changeset.setPersistentState(state)
        self.refreshPackages()

    def applyChanges(self, confirm=True):
        transaction = Transaction(self._ctrl.getCache(),
                                  changeset=self._changeset)
        if self._ctrl.commitTransaction(transaction, confirm=confirm):
            del self._undo[:]
            del self._redo[:]
            self._redomenuitem.set_property("sensitive", False)
            self._undomenuitem.set_property("sensitive", False)
            self._changeset.clear()
            self._ctrl.reloadChannels()
            self.refreshPackages()
            self.changedMarks()
        self._progress.hide()

    def clearChanges(self):
        self.saveUndo()
        self._changeset.clear()
        self.changedMarks()

    def showChanges(self):
        return self._changes.showChangeSet(self._changeset)

    def toggleFilter(self, filter):
        if filter in self._filters:
            del self._filters[filter]
        else:
            self._filters[filter] = True
        self.refreshPackages()

    def upgradeAll(self):
        transaction = Transaction(self._ctrl.getCache())
        transaction.setState(self._changeset)
        for pkg in self._ctrl.getCache().getPackages():
            if pkg.installed:
                transaction.enqueue(pkg, UPGRADE)
        transaction.setPolicy(PolicyUpgrade)
        transaction.run()
        changeset = transaction.getChangeSet()
        if changeset != self._changeset:
            if self.confirmChange(self._changeset, changeset):
                self.saveUndo()
                emptychangeset = not self._changeset
                self._changeset.setState(changeset)
                self.changedMarks()
                if self.askYesNo(_("Apply marked changes now?"), True):
                    self.applyChanges(confirm=not emptychangeset)
        else:
            self.showStatus(_("No interesting upgrades available!"))

    def actOnPackages(self, pkgs, op=None):
        cache = self._ctrl.getCache()
        transaction = Transaction(cache, policy=PolicyInstall)
        transaction.setState(self._changeset)
        changeset = transaction.getChangeSet()
        if op is None:
            if not [pkg for pkg in pkgs if pkg not in changeset]:
                op = KEEP
            else:
                for pkg in pkgs:
                    if not pkg.installed:
                        op = INSTALL
                        break
                else:
                    op = REMOVE
        if op is REMOVE:
            transaction.setPolicy(PolicyRemove)
        policy = transaction.getPolicy()
        for pkg in pkgs:
            if op is KEEP:
                transaction.enqueue(pkg, op)
            elif op in (REMOVE, REINSTALL, FIX):
                if pkg.installed:
                    transaction.enqueue(pkg, op)
                    if op is REMOVE:
                        for _pkg in cache.getPackages(pkg.name):
                            if not _pkg.installed:
                                policy.setLocked(_pkg, True)
            elif op is INSTALL:
                if not pkg.installed:
                    transaction.enqueue(pkg, op)
        transaction.run()
        if op is FIX:
            expected = 0
        else:
            expected = 1
        if self.confirmChange(self._changeset, changeset, expected):
            self.saveUndo()
            self._changeset.setState(changeset)
            self.changedMarks()

    def packagePopup(self, packageview, pkgs, event):

        menu = gtk.Menu()

        hasinstalled = bool([pkg for pkg in pkgs if pkg.installed
                             and self._changeset.get(pkg) is not REMOVE])
        hasnoninstalled = bool([pkg for pkg in pkgs if not pkg.installed
                                and self._changeset.get(pkg) is not INSTALL])

        image = gtk.Image()
        image.set_from_pixbuf(getPixbuf("package-install"))
        item = gtk.ImageMenuItem(_("Install"))
        item.set_image(image)
        item.connect("activate", lambda x: self.actOnPackages(pkgs, INSTALL))
        if not hasnoninstalled:
            item.set_sensitive(False)
        menu.append(item)

        image = gtk.Image()
        image.set_from_pixbuf(getPixbuf("package-reinstall"))
        item = gtk.ImageMenuItem(_("Reinstall"))
        item.set_image(image)
        item.connect("activate", lambda x: self.actOnPackages(pkgs, REINSTALL))
        if not hasinstalled:
            item.set_sensitive(False)
        menu.append(item)


        image = gtk.Image()
        image.set_from_pixbuf(getPixbuf("package-remove"))
        item = gtk.ImageMenuItem(_("Remove"))
        item.set_image(image)
        item.connect("activate", lambda x: self.actOnPackages(pkgs, REMOVE))
        if not hasinstalled:
            item.set_sensitive(False)
        menu.append(item)

        image = gtk.Image()
        if not hasinstalled:
            image.set_from_pixbuf(getPixbuf("package-available"))
        else:
            image.set_from_pixbuf(getPixbuf("package-installed"))
        item = gtk.ImageMenuItem(_("Keep"))
        item.set_image(image)
        item.connect("activate", lambda x: self.actOnPackages(pkgs, KEEP))
        if not [pkg for pkg in pkgs if pkg in self._changeset]:
            item.set_sensitive(False)
        menu.append(item)

        image = gtk.Image()
        image.set_from_pixbuf(getPixbuf("package-broken"))
        item = gtk.ImageMenuItem(_("Fix problems"))
        item.set_image(image)
        item.connect("activate", lambda x: self.actOnPackages(pkgs, FIX))
        if not hasinstalled:
            item.set_sensitive(False)
        menu.append(item)

        inconsistent = False
        thislocked = None
        alllocked = None
        names = pkgconf.getFlagTargets("lock")
        if [pkg for pkg in pkgs if pkg in self._changeset]:
            inconsistent = True
        else:
            for pkg in pkgs:
                if (names and pkg.name in names and 
                    ("=", pkg.version) in names[pkg.name]):
                    newthislocked = True
                    newalllocked = len(names[pkg.name]) > 1
                else:
                    newthislocked = False
                    newalllocked = pkgconf.testFlag("lock", pkg)
                if (thislocked is not None and thislocked != newthislocked or
                    alllocked is not None and alllocked != newalllocked):
                    inconsistent = True
                    break
                thislocked = newthislocked
                alllocked = newalllocked

        image = gtk.Image()
        if thislocked:
            item = gtk.ImageMenuItem(_("Unlock this version"))
            if not hasnoninstalled:
                image.set_from_pixbuf(getPixbuf("package-installed"))
            else:
                image.set_from_pixbuf(getPixbuf("package-available"))
            def unlock_this(x):
                for pkg in pkgs:
                    pkgconf.clearFlag("lock", pkg.name, "=", pkg.version)
                self._pv.queue_draw()
                self._pi.setPackage(pkgs[0])
            item.connect("activate", unlock_this)
        else:
            item = gtk.ImageMenuItem(_("Lock this version"))
            if not hasnoninstalled:
                image.set_from_pixbuf(getPixbuf("package-installed-locked"))
            else:
                image.set_from_pixbuf(getPixbuf("package-available-locked"))
            def lock_this(x):
                for pkg in pkgs:
                    pkgconf.setFlag("lock", pkg.name, "=", pkg.version)
                self._pv.queue_draw()
                self._pi.setPackage(pkgs[0])
            item.connect("activate", lock_this)
        item.set_image(image)
        if inconsistent:
            item.set_sensitive(False)
        menu.append(item)

        image = gtk.Image()
        if alllocked:
            item = gtk.ImageMenuItem(_("Unlock all versions"))
            if not hasnoninstalled:
                image.set_from_pixbuf(getPixbuf("package-installed"))
            else:
                image.set_from_pixbuf(getPixbuf("package-available"))
            def unlock_all(x):
                for pkg in pkgs:
                    pkgconf.clearFlag("lock", pkg.name)
                self._pv.queue_draw()
                self._pi.setPackage(pkgs[0])
            item.connect("activate", unlock_all)
        else:
            item = gtk.ImageMenuItem(_("Lock all versions"))
            if not hasnoninstalled:
                image.set_from_pixbuf(getPixbuf("package-installed-locked"))
            else:
                image.set_from_pixbuf(getPixbuf("package-available-locked"))
            def lock_all(x):
                for pkg in pkgs:
                    pkgconf.setFlag("lock", pkg.name)
                self._pv.queue_draw()
                self._pi.setPackage(pkgs[0])
            item.connect("activate", lock_all)
        item.set_image(image)
        if inconsistent:
            item.set_sensitive(False)
        menu.append(item)

        item = gtk.MenuItem(_("Priority"))
        def priority(x):
            GtkSinglePriority(self._window).show(pkgs[0])
            self._pi.setPackage(pkgs[0])
        item.connect("activate", priority)
        if len(pkgs) != 1:
            item.set_sensitive(False)
        menu.append(item)

        menu.show_all()
        menu.popup(None, None, None, event.button, event.time)

    def checkPackages(self, all=False, uninstalled=False):
        installed = not uninstalled
        available = all or uninstalled
        self.info(_("Checking relations..."))
        if checkPackagesSimple(self._ctrl.getCache(), report=True,
                               installed=installed, available=available):
            self.info(_("All checked packages have correct relations."))

    def fixAllProblems(self):
        self.actOnPackages([pkg for pkg in self._ctrl.getCache().getPackages()
                            if pkg.installed], FIX)

    def undo(self):
        if self._undo:
            state = self._undo.pop(0)
            if not self._undo:
                self._undomenuitem.set_property("sensitive", False)
            self._redo.insert(0, self._changeset.getPersistentState())
            self._redomenuitem.set_property("sensitive", True)
            self._changeset.setPersistentState(state)
            self.changedMarks()

    def redo(self):
        if self._redo:
            state = self._redo.pop(0)
            if not self._redo:
                self._redomenuitem.set_property("sensitive", False)
            self._undo.insert(0, self._changeset.getPersistentState())
            self._undomenuitem.set_property("sensitive", True)
            self._changeset.setPersistentState(state)
            self.changedMarks()

    def saveUndo(self):
        self._undo.insert(0, self._changeset.getPersistentState())
        del self._redo[:]
        del self._undo[20:]
        self._undomenuitem.set_property("sensitive", True)
        self._redomenuitem.set_property("sensitive", False)

    def setTreeStyle(self, mode):
        if mode != sysconf.get("package-tree"):
            sysconf.set("package-tree", mode)
            self.refreshPackages()

    def editChannels(self):
        if GtkChannels(self._window).show():
            self.rebuildCache()

    def editMirrors(self):
        GtkMirrors(self._window).show()

    def editFlags(self):
        GtkFlags(self._window).show()

    def editPriorities(self):
        GtkPriorities(self._window).show()

    def setBusy(self, flag):
        if flag:
            self._window.window.set_cursor(self._watch)
            while gtk.events_pending():
                gtk.main_iteration()
        else:
            self._window.window.set_cursor(None)

    def changedMarks(self):
        if "hide-unmarked" in self._filters:
            self.refreshPackages()
        else:
            self._pv.queue_draw()
        self._execmenuitem.set_property("sensitive", bool(self._changeset))
        self._clearmenuitem.set_property("sensitive", bool(self._changeset))

    def toggleSearch(self):
        visible = not self._searchbar.get_property('visible')
        self._searchbar.set_property('visible', visible)
        self.refreshPackages()
        if visible:
            self._searchentry.grab_focus()

    def refreshPackages(self):
        if not self._ctrl:
            return

        self.setBusy(True)

        tree = sysconf.get("package-tree", "groups")
        ctrl = self._ctrl
        changeset = self._changeset

        if self._searchbar.get_property("visible"):

            searcher = Searcher()
            dosearch = False
            if self._searchdesc.get_active():
                text = self._searchentry.get_text().strip()
                if text:
                    dosearch = True
                    searcher.addDescription(text)
                    searcher.addSummary(text)
            else:
                try:
                    tokens = shlex.split(self._searchentry.get_text())
                except ValueError:
                    pass
                else:
                    if tokens:
                        dosearch = True
                        for tok in tokens:
                            if searcher.hasAutoMeaning(tok):
                                searcher.addAuto(tok)
                            else:
                                searcher.addNameVersion("*%s*" % tok)

            packages = []
            if dosearch:
                self._ctrl.getCache().search(searcher)
                for ratio, obj in searcher.getResults():
                    if isinstance(obj, Package):
                        packages.append(obj)
                    else:
                        packages.extend(obj.packages)
        else:
            packages = ctrl.getCache().getPackages()

        filters = self._filters
        if filters:
            if "hide-non-upgrades" in filters:
                newpackages = {}
                for pkg in packages:
                    if pkg.installed:
                        upgpkgs = {}
                        try:
                            for prv in pkg.provides:
                                for upg in prv.upgradedby:
                                    for upgpkg in upg.packages:
                                        if upgpkg.installed:
                                            raise StopIteration
                                        upgpkgs[upgpkg] = True
                        except StopIteration:
                            pass
                        else:
                            newpackages.update(upgpkgs)
                packages = newpackages.keys()
            if "hide-uninstalled" in filters:
                packages = [x for x in packages if x.installed]
            if "hide-unmarked" in filters:
                packages = [x for x in packages if x in changeset]
            if "hide-installed" in filters:
                packages = [x for x in packages if not x.installed]
            if "hide-old" in filters:
                packages = pkgconf.filterByFlag("new", packages)

        if tree == "groups":
            groups = {}
            done = {}
            for pkg in packages:
                lastgroup = None
                for loader in pkg.loaders:
                    info = loader.getInfo(pkg)
                    group = info.getGroup()
                    donetuple = (group, pkg)
                    if donetuple not in done:
                        done[donetuple] = True
                        if group in groups:
                            groups[group].append(pkg)
                        else:
                            groups[group] = [pkg]

        elif tree == "channels":
            groups = {}
            done = {}
            for pkg in packages:
                for loader in pkg.loaders:
                    channel = loader.getChannel()
                    group = channel.getName() or channel.getAlias()
                    donetuple = (group, pkg)
                    if donetuple not in done:
                        done[donetuple] = True
                        if group in groups:
                            groups[group].append(pkg)
                        else:
                            groups[group] = [pkg]

        elif tree == "channels-groups":
            groups = {}
            done = {}
            for pkg in packages:
                for loader in pkg.loaders:
                    channel = loader.getChannel()
                    group = channel.getName() or channel.getAlias()
                    subgroup = loader.getInfo(pkg).getGroup()
                    donetuple = (group, subgroup, pkg)
                    if donetuple not in done:
                        done[donetuple] = True
                        if group in groups:
                            if subgroup in groups[group]:
                                groups[group][subgroup].append(pkg)
                            else:
                                groups[group][subgroup] = [pkg]
                        else:
                            groups[group] = {subgroup: [pkg]}

        else:
            groups = packages

        self._pv.setPackages(groups, changeset, keepstate=True)

        self.setBusy(False)

    def showAbout(widget):
        license = """
            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; either version 2 of the License, or
            (at your option) any later version.

            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 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.
            """
        credits=["""Gustavo Niemeyer - Original author and lead developer.""",
            """Conectiva Inc. - Original project funder up to August 2005.""",
            """Canonical Ltd. - Funding Smart development since September of 2005.""",
            """And many others - Check our website for the complete list.""",
            ]
        website = "http://labix.org/smart"    

        aboutdialog = gtk.AboutDialog()
        aboutdialog.set_name("Smart Package Manager")
        aboutdialog.set_version(VERSION)
        aboutdialog.set_copyright("2006 Canonical, 2004 Conectiva, Inc.")
        aboutdialog.set_authors(credits)
        aboutdialog.set_license(license)
        aboutdialog.set_website(website)
        aboutdialog.run()
        aboutdialog.destroy()
Ejemplo n.º 14
0
class GtkInteractiveInterface(GtkInterface):

    def __init__(self, ctrl):
        GtkInterface.__init__(self, ctrl)

        self._changeset = None

        self._window = gtk.Window()
        self._window.set_title("Smart Package Manager %s" % VERSION)
        self._window.set_position(gtk.WIN_POS_CENTER)
        self._window.set_geometry_hints(min_width=640, min_height=480)
        def delete(widget, event):
            gtk.main_quit()
            return True
        self._window.connect("delete-event", delete)

        self._log.set_transient_for(self._window)
        self._progress.set_transient_for(self._window)
        self._hassubprogress.set_transient_for(self._window)
        self._changes.set_transient_for(self._window)

        self._watch = gtk.gdk.Cursor(gtk.gdk.WATCH)

        self._undo = []
        self._redo = []

        self._topvbox = gtk.VBox()
        self._topvbox.show()
        self._window.add(self._topvbox)

        globals = {"self": self, "gtk": gtk}
        self._actions = gtk.ActionGroup("Actions")
        self._actions.add_actions(compileActions(ACTIONS, globals))

        self._filters = {}
        for name, label in [("hide-non-upgrades", _("Hide Non-upgrades")),
                            ("hide-non-newest", _("Hide Non-newest")),
                            ("hide-installed", _("Hide Installed")),
                            ("hide-uninstalled", _("Hide Uninstalled")),
                            ("hide-unmarked", _("Hide Unmarked")),
                            ("hide-unlocked", _("Hide Unlocked")),
                            ("hide-requested", _("Hide Requested")),
                            ("hide-old", _("Hide Old"))]:
            action = gtk.ToggleAction(name, label, "", "")
            action.connect("toggled", lambda x, y: self.toggleFilter(y), name)
            self._actions.add_action(action)

        treestyle = sysconf.get("package-tree")
        lastaction = None
        for name, label in [("groups", _("Groups")),
                            ("separate-groups", _("Separate Groups")),
                            ("channels", _("Channels")),
                            ("channels-groups", _("Channels & Groups")),
                            ("none", _("None"))]:
            action = gtk.RadioAction("tree-style-"+name, label, "", "", 0)
            if name == treestyle:
                action.set_active(True)
            if lastaction:
                action.set_group(lastaction)
            lastaction = action
            action.connect("toggled", lambda x, y: self.setTreeStyle(y), name)
            self._actions.add_action(action)

        self._ui = gtk.UIManager()
        self._ui.insert_action_group(self._actions, 0)
        self._ui.add_ui_from_string(UI)
        self._menubar = self._ui.get_widget("/menubar")
        self._topvbox.pack_start(self._menubar, False)

        self._toolbar = self._ui.get_widget("/toolbar")
        self._toolbar.set_style(gtk.TOOLBAR_ICONS)
        self._topvbox.pack_start(self._toolbar, False)
        if sysconf.getReadOnly():
           # Can't update channels in readonly mode.
           updatetoolitem = self._ui.get_widget("/toolbar/update-channels")
           updatetoolitem.set_property("sensitive", False)

        self._window.add_accel_group(self._ui.get_accel_group())

        self._execmenuitem = self._ui.get_action("/menubar/file/exec-changes")
        self._execmenuitem.set_property("sensitive", False)
        self._clearmenuitem = self._ui.get_action("/menubar/edit/clear-changes")
        self._clearmenuitem.set_property("sensitive", False)
        self._undomenuitem = self._ui.get_action("/menubar/edit/undo")
        self._undomenuitem.set_property("sensitive", False)
        self._redomenuitem = self._ui.get_action("/menubar/edit/redo")
        self._redomenuitem.set_property("sensitive", False)

        # Search bar

        if gtk.gtk_version >= (2, 16, 0) or sexy:
            self._searchbar = gtk.ToolItem()
            self._searchbar.set_expand(True)
            self._searchbar.set_homogeneous(False)
            self._searchbar.show()
            count = self._toolbar.get_n_items()
            find = self._toolbar.get_nth_item(count - 1)
            self._toolbar.remove(find)
            self._toolbar.insert(self._searchbar, -1)

            searchtable = gtk.Table(1, 1)
            searchtable.set_row_spacings(5)
            searchtable.set_col_spacings(5)
            searchtable.set_border_width(5)
            searchtable.show()
            self._searchbar.add(searchtable)

            if gtk.gtk_version >= (2, 16, 0):
                self._searchentry = gtk.Entry()
                self._searchentry.set_property("primary-icon-name", "gtk-find")
                self._searchentry.set_property("secondary-icon-name", "gtk-clear")
                def press(entry, icon_pos, event):
                    if int(icon_pos) == 0: # "primary"
                        self._searchmenu.popup(None, None, None, event.button, event.time)
                    elif int(icon_pos) == 1: # "secondary"
                        self._searchentry.set_text("")
                        self.refreshPackages()
                self._searchentry.connect("icon-press", press)
            elif sexy:
                self._searchentry = sexy.IconEntry()
                image = gtk.Image()
                image.set_from_stock("gtk-find", gtk.ICON_SIZE_BUTTON)
                self._searchentry.set_icon(sexy.ICON_ENTRY_PRIMARY, image)
                image = gtk.Image()
                image.set_from_stock("gtk-clear", gtk.ICON_SIZE_BUTTON)
                self._searchentry.set_icon(sexy.ICON_ENTRY_SECONDARY, image)
                def pressed(entry, icon_pos, button):
                    if icon_pos == 0: # "primary"
                        self._searchmenu.popup(None, None, None, button, gtk.get_current_event_time())
                    elif icon_pos == 1: # "secondary"
                        self._searchentry.set_text("")
                        self.refreshPackages()
                self._searchentry.connect("icon-pressed", pressed)
            self._searchentry.connect("activate", lambda x: self.refreshPackages())
            self._searchentry.show()
            searchtable.attach(self._searchentry, 0, 1, 0, 1)

            self._searchmenu = gtk.Menu()
            self._searchname = gtk.CheckMenuItem(_("Automatic"))
            self._searchname.set_draw_as_radio(True)
            self._searchname.set_active(True)
            def search_automatic(item):
                self._searchdesc.set_active(not item.get_active())
                self.refreshPackages()
            self._searchname.connect("activate", search_automatic)
            self._searchname.show()
            self._searchmenu.append(self._searchname)
            self._searchdesc = gtk.CheckMenuItem(_("Description"))
            self._searchdesc.set_draw_as_radio(True)
            self._searchdesc.set_active(False)
            def search_description(item):
                self._searchname.set_active(not item.get_active())
                self.refreshPackages()
            self._searchdesc.connect("activate", search_description)
            self._searchdesc.show()
            self._searchmenu.append(self._searchdesc)
        else:
            self._searchbar = gtk.Alignment()
            self._searchbar.set(0, 0, 1, 1)
            self._searchbar.set_padding(3, 3, 0, 0)
            self._topvbox.pack_start(self._searchbar, False)

            searchvp = gtk.Viewport()
            searchvp.set_shadow_type(gtk.SHADOW_OUT)
            searchvp.show()
            self._searchbar.add(searchvp)

            searchtable = gtk.Table(1, 1)
            searchtable.set_row_spacings(5)
            searchtable.set_col_spacings(5)
            searchtable.set_border_width(5)
            searchtable.show()
            searchvp.add(searchtable)

            label = gtk.Label(_("Search:"))
            label.show()
            searchtable.attach(label, 0, 1, 0, 1, 0, 0)

            self._searchentry = gtk.Entry()
            self._searchentry.connect("activate", lambda x: self.refreshPackages())
            self._searchentry.show()
            searchtable.attach(self._searchentry, 1, 2, 0, 1)

            button = gtk.Button()
            button.set_relief(gtk.RELIEF_NONE)
            button.connect("clicked", lambda x: self.refreshPackages())
            button.show()
            searchtable.attach(button, 2, 3, 0, 1, 0, 0)
            image = gtk.Image()
            image.set_from_stock("gtk-find", gtk.ICON_SIZE_BUTTON)
            image.show()
            button.add(image)

            align = gtk.Alignment()
            align.set(1, 0, 0, 0)
            align.set_padding(0, 0, 10, 0)
            align.show()
            searchtable.attach(align, 3, 4, 0, 1, gtk.FILL, gtk.FILL)
            button = gtk.Button()
            button.set_size_request(20, 20)
            button.set_relief(gtk.RELIEF_NONE)
            button.connect("clicked", lambda x: self.toggleSearch())
            button.show()
            align.add(button)
            image = gtk.Image()
            image.set_from_stock("gtk-close", gtk.ICON_SIZE_MENU)
            image.show()
            button.add(image)

            hbox = gtk.HBox()
            hbox.set_spacing(10)
            hbox.show()
            searchtable.attach(hbox, 1, 2, 1, 2)

            self._searchmenu = None
            self._searchname = gtk.RadioButton(None, _("Automatic"))
            self._searchname.set_active(True)
            self._searchname.connect("clicked", lambda x: self.refreshPackages())
            self._searchname.show()
            hbox.pack_start(self._searchname, False)
            self._searchdesc = gtk.RadioButton(self._searchname, _("Description"))
            self._searchdesc.connect("clicked", lambda x: self.refreshPackages())
            self._searchdesc.show()
            hbox.pack_start(self._searchdesc, False)

        # Packages and information

        self._hpaned = gtk.HPaned()
        self._hpaned.show()
        self._topvbox.pack_start(self._hpaned)

        scrollwin = gtk.ScrolledWindow()
        scrollwin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        scrollwin.set_shadow_type(gtk.SHADOW_IN)
        self._hpaned.pack1(scrollwin, True)

        self._pg = gtk.TreeView()
        def group_selected(treeview):
            self.refreshPackages()
        self._pg.connect("cursor_changed", group_selected)
        self._pg.show()
        scrollwin.add(self._pg)

        selection = self._pg.get_selection()
        selection.set_mode(gtk.SELECTION_MULTIPLE)

        renderer = gtk.CellRendererText()
        column = gtk.TreeViewColumn(_("Group"), renderer, text=1)
        self._pg.append_column(column)

        self._vpaned = gtk.VPaned()
        self._vpaned.show()
        self._hpaned.pack2(self._vpaned, True)

        self._pv = GtkPackageView()
        self._pv.show()
        self._vpaned.pack1(self._pv, True)

        self._pi = GtkPackageInfo()
        self._pi.show()
        self._pv.connect("package_selected",
                         lambda x, y: self._pi.setPackage(y))
        self._pv.connect("package_activated",
                         lambda x, y: self.actOnPackages(y))
        self._pv.connect("package_popup", self.packagePopup)
        self._vpaned.pack2(self._pi, False)

        self._status = gtk.Statusbar()
        self._status.show()
        self._topvbox.pack_start(self._status, False)
        
        self._legend = GtkLegend()

    def showStatus(self, msg):
        self._status.pop(0)
        self._status.push(0, msg)
        while gtk.events_pending():
            gtk.main_iteration()

    def hideStatus(self):
        self._status.pop(0)
        while gtk.events_pending():
            gtk.main_iteration()

    def run(self, command=None, argv=None):
        self.setCatchExceptions(True)
        self.loadState()
        self._window.set_icon(getPixbuf("smart"))
        self._window.show()
        self._ctrl.reloadChannels()
        self._changeset = ChangeSet(self._ctrl.getCache())
        self._pi.setChangeSet(self._changeset)
        self._progress.hide()
        self.refreshPackages()
        gtk.main()
        self.saveState()
        self.setCatchExceptions(False)

    # Non-standard interface methods:

    def saveState(self):
        sysconf.set("gtk-size", self._window.get_size())
        #sysconf.set("gtk-position", self._window.get_position())
        sysconf.set("gtk-hpaned-position", self._hpaned.get_position())
        sysconf.set("gtk-vpaned-position", self._vpaned.get_position())

    def loadState(self):
        var = sysconf.get("gtk-size")
        if var is not None:
            self._window.set_size_request(*var)
        #var = sysconf.get("gtk-position")
        #if var is not None:
        #    self._window.move(*var)
        var = sysconf.get("gtk-hpaned-position")
        if var is not None:
            self._hpaned.set_position(var)
        var = sysconf.get("gtk-vpaned-position")
        if var is not None:
            self._vpaned.set_position(var)

    def getChangeSet(self):
        return self._changeset

    def updateSelected(self):
        self.updateChannels(selected=True)

    def updateChannels(self, selected=False, channels=None):
        if self._changeset is None:
            return
        if selected:
            aliases = GtkChannelSelector().show()
            channels = [channel for channel in self._ctrl.getChannels()
                        if channel.getAlias() in aliases]
            if not channels:
                return
        state = self._changeset.getPersistentState()
        self._ctrl.reloadChannels(channels, caching=NEVER)
        self._changeset.setPersistentState(state)
        self.refreshPackages()

    def rebuildCache(self):
        if self._changeset is None:
            return
        state = self._changeset.getPersistentState()
        self._ctrl.reloadChannels()
        self._changeset.setPersistentState(state)
        self.refreshPackages()

    def applyChanges(self, confirm=True):
        transaction = Transaction(self._ctrl.getCache(),
                                  changeset=self._changeset)
        if self._ctrl.commitTransaction(transaction, confirm=confirm):
            del self._undo[:]
            del self._redo[:]
            self._redomenuitem.set_property("sensitive", False)
            self._undomenuitem.set_property("sensitive", False)
            self._changeset.clear()
            self._ctrl.reloadChannels()
            self.refreshPackages()
            self.changedMarks()
        self._progress.hide()

    def clearChanges(self):
        self.saveUndo()
        self._changeset.clear()
        self.changedMarks()

    def showChanges(self):
        return self._changes.showChangeSet(self._changeset)

    def showLog(self):
        return self._log.show()

    def showLegend(self):
        return self._legend.show()

    def expandPackages(self):
        self._pv.getTreeView().expand_all()

    def collapsePackages(self):
        self._pv.getTreeView().collapse_all()

    def toggleFilter(self, filter):
        if filter in self._filters:
            del self._filters[filter]
        else:
            self._filters[filter] = True
        self.refreshPackages()

    def upgradeAll(self):
        transaction = Transaction(self._ctrl.getCache())
        transaction.setState(self._changeset)
        for pkg in self._ctrl.getCache().getPackages():
            if pkg.installed:
                transaction.enqueue(pkg, UPGRADE)
        transaction.setPolicy(PolicyUpgrade)
        transaction.run()
        changeset = transaction.getChangeSet()
        if changeset != self._changeset:
            if self.confirmChange(self._changeset, changeset):
                self.saveUndo()
                emptychangeset = not self._changeset
                self._changeset.setState(changeset)
                self.changedMarks()
                if self.askYesNo(_("Apply marked changes now?"), True):
                    self.applyChanges(confirm=not emptychangeset)
        else:
            self.showStatus(_("No interesting upgrades available!"))

    def removeAuto(self):
        changeset = self._ctrl.markAndSweep()
        if changeset != self._changeset:
            if self.confirmChange(self._changeset, changeset):
                self.saveUndo()
                self._changeset.setState(changeset)
                self.changedMarks()
                self.applyChanges(confirm=True)
        else:
            self.showStatus(_("No automatic removals possible!"))

    def actOnPackages(self, pkgs, op=None):
        cache = self._ctrl.getCache()
        transaction = Transaction(cache, policy=PolicyInstall)
        transaction.setState(self._changeset)
        changeset = transaction.getChangeSet()
        if op is None:
            if not [pkg for pkg in pkgs if pkg not in changeset]:
                op = KEEP
            else:
                for pkg in pkgs:
                    if not pkg.installed:
                        op = INSTALL
                        break
                else:
                    op = REMOVE
        if op is REMOVE:
            transaction.setPolicy(PolicyRemove)
        policy = transaction.getPolicy()
        for pkg in pkgs:
            if op is KEEP:
                transaction.enqueue(pkg, op)
            elif op in (REMOVE, REINSTALL, FIX):
                if pkg.installed:
                    transaction.enqueue(pkg, op)
                    if op is REMOVE:
                        for _pkg in cache.getPackages(pkg.name):
                            if not _pkg.installed:
                                policy.setLocked(_pkg, True)
            elif op is INSTALL:
                if not pkg.installed:
                    transaction.enqueue(pkg, op)
        transaction.run()
        if op is FIX:
            expected = 0
        else:
            expected = 1
        if self.confirmChange(self._changeset, changeset, expected):
            self.saveUndo()
            self._changeset.setState(changeset)
            self.changedMarks()

    def lockPackages(self, pkgs, lock):
        if not lock:
             for pkg in pkgs:
                  pkgconf.clearFlag("lock", pkg.name, "=", pkg.version)
             self._pv.queue_draw()
             self._pi.setPackage(pkgs[0])
        else:
             for pkg in pkgs:
                  pkgconf.setFlag("lock", pkg.name, "=", pkg.version)
             self._pv.queue_draw()
             self._pi.setPackage(pkgs[0])

    def lockAllPackages(self, pkgs, lock):
        if not lock:
             for pkg in pkgs:
                  pkgconf.clearFlag("lock", pkg.name)
             self._pv.queue_draw()
             self._pi.setPackage(pkgs[0])
        else:
             for pkg in pkgs:
                  pkgconf.setFlag("lock", pkg.name)
             self._pv.queue_draw()
             self._pi.setPackage(pkgs[0])

    def packagePopup(self, packageview, pkgs, event):

        menu = gtk.Menu()

        hasinstalled = bool([pkg for pkg in pkgs if pkg.installed
                             and self._changeset.get(pkg) is not REMOVE])
        hasnoninstalled = bool([pkg for pkg in pkgs if not pkg.installed
                                and self._changeset.get(pkg) is not INSTALL])

        image = gtk.Image()
        image.set_from_pixbuf(getPixbuf("package-install"))
        item = gtk.ImageMenuItem(_("Install"))
        item.set_image(image)
        item.connect("activate", lambda x: self.actOnPackages(pkgs, INSTALL))
        if not hasnoninstalled:
            item.set_sensitive(False)
        menu.append(item)

        image = gtk.Image()
        image.set_from_pixbuf(getPixbuf("package-reinstall"))
        item = gtk.ImageMenuItem(_("Reinstall"))
        item.set_image(image)
        item.connect("activate", lambda x: self.actOnPackages(pkgs, REINSTALL))
        if not hasinstalled:
            item.set_sensitive(False)
        menu.append(item)


        image = gtk.Image()
        image.set_from_pixbuf(getPixbuf("package-remove"))
        item = gtk.ImageMenuItem(_("Remove"))
        item.set_image(image)
        item.connect("activate", lambda x: self.actOnPackages(pkgs, REMOVE))
        if not hasinstalled:
            item.set_sensitive(False)
        menu.append(item)

        image = gtk.Image()
        if not hasinstalled:
            image.set_from_pixbuf(getPixbuf("package-available"))
        else:
            image.set_from_pixbuf(getPixbuf("package-installed"))
        item = gtk.ImageMenuItem(_("Keep"))
        item.set_image(image)
        item.connect("activate", lambda x: self.actOnPackages(pkgs, KEEP))
        if not [pkg for pkg in pkgs if pkg in self._changeset]:
            item.set_sensitive(False)
        menu.append(item)

        image = gtk.Image()
        image.set_from_pixbuf(getPixbuf("package-broken"))
        item = gtk.ImageMenuItem(_("Fix problems"))
        item.set_image(image)
        item.connect("activate", lambda x: self.actOnPackages(pkgs, FIX))
        if not hasinstalled:
            item.set_sensitive(False)
        menu.append(item)

        inconsistent = False
        thislocked = None
        alllocked = None
        names = pkgconf.getFlagTargets("lock")
        if [pkg for pkg in pkgs if pkg in self._changeset]:
            inconsistent = True
        else:
            for pkg in pkgs:
                if (names and pkg.name in names and 
                    ("=", pkg.version) in names[pkg.name]):
                    newthislocked = True
                    newalllocked = len(names[pkg.name]) > 1
                else:
                    newthislocked = False
                    newalllocked = pkgconf.testFlag("lock", pkg)
                if (thislocked is not None and thislocked != newthislocked or
                    alllocked is not None and alllocked != newalllocked):
                    inconsistent = True
                    break
                thislocked = newthislocked
                alllocked = newalllocked

        image = gtk.Image()
        if thislocked:
            item = gtk.ImageMenuItem(_("Unlock this version"))
            if not hasnoninstalled:
                image.set_from_pixbuf(getPixbuf("package-installed"))
            else:
                image.set_from_pixbuf(getPixbuf("package-available"))
            def unlock_this(x):
                self.lockPackages(pkgs, False)
            item.connect("activate", unlock_this)
        else:
            item = gtk.ImageMenuItem(_("Lock this version"))
            if not hasnoninstalled:
                image.set_from_pixbuf(getPixbuf("package-installed-locked"))
            else:
                image.set_from_pixbuf(getPixbuf("package-available-locked"))
            def lock_this(x):
                self.lockPackages(pkgs, True)
            item.connect("activate", lock_this)
        item.set_image(image)
        if inconsistent:
            item.set_sensitive(False)
        menu.append(item)

        image = gtk.Image()
        if alllocked:
            item = gtk.ImageMenuItem(_("Unlock all versions"))
            if not hasnoninstalled:
                image.set_from_pixbuf(getPixbuf("package-installed"))
            else:
                image.set_from_pixbuf(getPixbuf("package-available"))
            def unlock_all(x):
                self.lockAllPackages(pkgs, False)
            item.connect("activate", unlock_all)
        else:
            item = gtk.ImageMenuItem(_("Lock all versions"))
            if not hasnoninstalled:
                image.set_from_pixbuf(getPixbuf("package-installed-locked"))
            else:
                image.set_from_pixbuf(getPixbuf("package-available-locked"))
            def lock_all(x):
                self.lockAllPackages(pkgs, True)
            item.connect("activate", lock_all)
        item.set_image(image)
        if inconsistent:
            item.set_sensitive(False)
        menu.append(item)

        item = gtk.MenuItem(_("Priority"))
        def priority(x):
            GtkSinglePriority(self._window).show(pkgs[0])
            self._pi.setPackage(pkgs[0])
        item.connect("activate", priority)
        if len(pkgs) != 1:
            item.set_sensitive(False)
        menu.append(item)

        menu.show_all()
        menu.popup(None, None, None, event.button, event.time)

    def checkPackages(self, all=False, uninstalled=False):
        installed = not uninstalled
        available = all or uninstalled
        self.info(_("Checking relations..."))
        if checkPackagesSimple(self._ctrl.getCache(), report=True,
                               installed=installed, available=available):
            self.info(_("All checked packages have correct relations."))

    def fixAllProblems(self):
        self.actOnPackages([pkg for pkg in self._ctrl.getCache().getPackages()
                            if pkg.installed], FIX)

    def undo(self):
        if self._undo:
            state = self._undo.pop(0)
            if not self._undo:
                self._undomenuitem.set_property("sensitive", False)
            self._redo.insert(0, self._changeset.getPersistentState())
            self._redomenuitem.set_property("sensitive", True)
            self._changeset.setPersistentState(state)
            self.changedMarks()

    def redo(self):
        if self._redo:
            state = self._redo.pop(0)
            if not self._redo:
                self._redomenuitem.set_property("sensitive", False)
            self._undo.insert(0, self._changeset.getPersistentState())
            self._undomenuitem.set_property("sensitive", True)
            self._changeset.setPersistentState(state)
            self.changedMarks()

    def saveUndo(self):
        self._undo.insert(0, self._changeset.getPersistentState())
        del self._redo[:]
        del self._undo[20:]
        self._undomenuitem.set_property("sensitive", True)
        self._redomenuitem.set_property("sensitive", False)

    def setTreeStyle(self, mode):
        if mode != sysconf.get("package-tree"):
            if not sysconf.getReadOnly():
                sysconf.set("package-tree", mode)
            else:
                sysconf.set("package-tree", mode, weak=True)
            self.refreshPackages()

    def editChannels(self):
        if GtkChannels(self._window).show():
            self.rebuildCache()

    def editMirrors(self):
        GtkMirrors(self._window).show()

    def editFlags(self):
        GtkFlags(self._window).show()

    def editPriorities(self):
        GtkPriorities(self._window).show()

    def setBusy(self, flag):
        if flag:
            self._window.window.set_cursor(self._watch)
            while gtk.events_pending():
                gtk.main_iteration()
        else:
            self._window.window.set_cursor(None)

    def changedMarks(self):
        if "hide-unmarked" in self._filters:
            self.refreshPackages()
        else:
            self._pv.queue_draw()
        self._execmenuitem.set_property("sensitive", bool(self._changeset))
        self._clearmenuitem.set_property("sensitive", bool(self._changeset))

    def toggleSearch(self):
        if not isinstance(self._searchbar, gtk.ToolItem):
            visible = not self._searchbar.get_property('visible')
            self._searchbar.set_property('visible', visible)
        else:
            # always show the ToolItem
            visible = True
        self.refreshPackages()
        if visible:
            self._searchentry.grab_focus()

    def refreshPackages(self):
        if not self._ctrl:
            return

        self.setBusy(True)

        tree = sysconf.get("package-tree", "groups")
        ctrl = self._ctrl
        changeset = self._changeset

        self._pg.parent.set_property('visible', tree == "separate-groups")
        if self._pg.get_property('visible'):
            model = self._pg.get_model()
            if not model:
                packages = ctrl.getCache().getPackages()
                packagegroups = {}
                for pkg in packages:
                    for loader in pkg.loaders:
                        info = loader.getInfo(pkg)
                        group = info.getGroup()
                        if group in packagegroups:
                            packagegroups[group] += 1
                        else:
                            packagegroups[group] = 1

                groups = []
                names = {}
                all = "%s (%d)" % (_("All"), len(packages))
                for group, count in packagegroups.iteritems():
                     displayicon = None
                     displayname = "%s (%d)" % (group, count)
                     groups.append(displayname)
                     names[displayname] = group
                groups.sort()
                    
                model = gtk.ListStore(gobject.TYPE_STRING,
                                      gobject.TYPE_STRING)
                self._pg.set_model(model)
                iter = model.append()
                model.set(iter, 0, None)
                model.set(iter, 1, all)
                self._pg.get_selection().select_iter(iter)
                for group in groups:
                    iter = model.append()
                    model.set(iter, 0, names[group])
                    model.set(iter, 1, group)
                self._pg.queue_draw()

        columns = sysconf.get("package-columns", "name,version")
        self._pv.setVisibleColumns(columns.split(","))

        if self._searchbar.get_property("visible"):

            searcher = Searcher()
            dosearch = False
            if self._searchdesc.get_active():
                text = self._searchentry.get_text().strip()
                if text:
                    dosearch = True
                    searcher.addDescription(text)
                    searcher.addSummary(text)
            else:
                try:
                    tokens = shlex.split(self._searchentry.get_text())
                except ValueError:
                    pass
                else:
                    if tokens:
                        dosearch = True
                        for tok in tokens:
                            if searcher.hasAutoMeaning(tok):
                                searcher.addAuto(tok)
                            else:
                                searcher.addNameVersion("*%s*" % tok)

            packages = []
            if dosearch:
                self._ctrl.getCache().search(searcher)
                for ratio, obj in searcher.getResults():
                    if isinstance(obj, Package):
                        packages.append(obj)
                    else:
                        packages.extend(obj.packages)
            elif isinstance(self._searchbar, gtk.ToolItem):
                packages = ctrl.getCache().getPackages()
        else:
            packages = ctrl.getCache().getPackages()

        filters = self._filters
        if filters:
            if "hide-non-upgrades" in filters:
                newpackages = {}
                for pkg in packages:
                    if pkg.installed:
                        upgpkgs = {}
                        try:
                            for prv in pkg.provides:
                                for upg in prv.upgradedby:
                                    for upgpkg in upg.packages:
                                        if upgpkg.installed:
                                            raise StopIteration
                                        upgpkgs[upgpkg] = True
                        except StopIteration:
                            pass
                        else:
                            newpackages.update(upgpkgs)
                packages = newpackages.keys()
            if "hide-non-newest" in filters:
                newest = {}
                for pkg in packages:
                    if pkg.name in newest:
                        if pkg > newest[pkg.name]:
                            newest[pkg.name] = pkg
                    else:
                        newest[pkg.name] = pkg
                packages = [pkg for pkg in packages if pkg == newest[pkg.name]]
            if "hide-uninstalled" in filters:
                packages = [x for x in packages if x.installed]
            if "hide-unmarked" in filters:
                packages = [x for x in packages if x in changeset]
            if "hide-installed" in filters:
                packages = [x for x in packages if not x.installed]
            if "hide-unlocked" in filters:
                packages = pkgconf.filterByFlag("lock", packages)
            if "hide-requested" in filters:
                packages = pkgconf.filterByFlag("auto", packages)
            if "hide-old" in filters:
                packages = pkgconf.filterByFlag("new", packages)

        if tree == "groups":
            groups = {}
            done = {}
            for pkg in packages:
                lastgroup = None
                for loader in pkg.loaders:
                    info = loader.getInfo(pkg)
                    group = info.getGroup()
                    donetuple = (group, pkg)
                    if donetuple not in done:
                        done[donetuple] = True
                        if group in groups:
                            groups[group].append(pkg)
                        else:
                            groups[group] = [pkg]

        elif tree == "separate-groups":
            showgroups = {}
            selection = self._pg.get_selection()
            model, paths = selection.get_selected_rows()
            for path in paths:
                iter = model.get_iter(path)
                value = model.get_value(iter, 0)
                showgroups[value] = True
            if showgroups and None not in showgroups:
                newpackages = []
                done = {}
                for pkg in packages:
                    for loader in pkg.loaders:
                        info = loader.getInfo(pkg)
                        group = info.getGroup()
                        donetuple = (group, pkg)
                        if donetuple not in done:
                            done[donetuple] = True
                            if group in showgroups:
                                newpackages.append(pkg)
                groups = newpackages
            else:
                groups = packages

        elif tree == "channels":
            groups = {}
            done = {}
            for pkg in packages:
                for loader in pkg.loaders:
                    channel = loader.getChannel()
                    group = channel.getName() or channel.getAlias()
                    donetuple = (group, pkg)
                    if donetuple not in done:
                        done[donetuple] = True
                        if group in groups:
                            groups[group].append(pkg)
                        else:
                            groups[group] = [pkg]

        elif tree == "channels-groups":
            groups = {}
            done = {}
            for pkg in packages:
                for loader in pkg.loaders:
                    channel = loader.getChannel()
                    group = channel.getName() or channel.getAlias()
                    subgroup = loader.getInfo(pkg).getGroup()
                    donetuple = (group, subgroup, pkg)
                    if donetuple not in done:
                        done[donetuple] = True
                        if group in groups:
                            if subgroup in groups[group]:
                                groups[group][subgroup].append(pkg)
                            else:
                                groups[group][subgroup] = [pkg]
                        else:
                            groups[group] = {subgroup: [pkg]}

        else:
            groups = packages

        self._pv.setPackages(groups, changeset, keepstate=True)

        packages = ctrl.getCache().getPackages()
        self.showStatus(_("%d packages, %d installed") %
            (len(packages), len([pkg for pkg in packages if pkg.installed])))

        self.setBusy(False)

    def showAbout(widget):
        copyright = "2010 Smart Team, 2006 Canonical Ltd., 2004 Conectiva, Inc."
        license = """
            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; either version 2 of the License, or
            (at your option) any later version.

            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 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.
            """
        credits=["""Gustavo Niemeyer - Original author and lead developer.""",
           u"""Anders F Bj\u00f6rklund - Current maintainer and developer.""",
            """Conectiva Inc. - Original project funder up to August 2005.""",
            """Canonical Ltd. - Funding Smart up to November of 2009.""",
            """Unity Linux - Smart development and deployment support.""",
            """And many others - Check our website for the complete list.""",
            ]
        website = "http://smartpm.org/"

        if gtk.pygtk_version < (2,6,0):
             dialog = gtk.MessageDialog(buttons=gtk.BUTTONS_CLOSE)
             dialog.set_markup("<b>Smart Package Manager %s</b>\n"
                               "<small>(C) %s</small>\n" % (VERSION, copyright) +
                               "<small>%s</small>\n" % license.replace(" " * 12, "") +
                               "<span>%s</span>\n" % "\n".join(credits) +
                               "\n<tt>%s</tt>" % website)
             dialog.run()
             dialog.destroy()
             return

        aboutdialog = gtk.AboutDialog()
        aboutdialog.set_name("Smart Package Manager")
        aboutdialog.set_version(VERSION)
        aboutdialog.set_copyright(copyright)
        aboutdialog.set_authors(credits)
        aboutdialog.set_license(license)
        aboutdialog.set_website(website)
        aboutdialog.run()
        aboutdialog.destroy()
Ejemplo n.º 15
0
class GtkInteractiveInterface(GtkInterface):
    def __init__(self, ctrl):
        GtkInterface.__init__(self, ctrl)

        self._changeset = None

        self._window = gtk.Window()
        self._window.set_title("Smart Package Manager %s" % VERSION)
        self._window.set_position(gtk.WIN_POS_CENTER)
        self._window.set_geometry_hints(min_width=640, min_height=480)
        self._window.connect("destroy", lambda x: gtk.main_quit())

        self._log.set_transient_for(self._window)
        self._progress.set_transient_for(self._window)
        self._hassubprogress.set_transient_for(self._window)

        self._watch = gtk.gdk.Cursor(gtk.gdk.WATCH)

        self._undo = []
        self._redo = []

        self._topvbox = gtk.VBox()
        self._topvbox.show()
        self._window.add(self._topvbox)

        globals = {"self": self, "gtk": gtk}
        self._actions = gtk.ActionGroup("Actions")
        self._actions.add_actions(compileActions(ACTIONS, globals))

        self._filters = {}
        for name, label in [("hide-non-upgrades", _("Hide Non-upgrades")),
                            ("hide-installed", _("Hide Installed")),
                            ("hide-uninstalled", _("Hide Uninstalled")),
                            ("hide-unmarked", _("Hide Unmarked")),
                            ("hide-old", _("Hide Old"))]:
            action = gtk.ToggleAction(name, label, "", "")
            action.connect("toggled", lambda x, y: self.toggleFilter(y), name)
            self._actions.add_action(action)

        treestyle = sysconf.get("package-tree")
        lastaction = None
        for name, label in [("groups", _("Groups")),
                            ("channels", _("Channels")),
                            ("channels-groups", _("Channels & Groups")),
                            ("none", _("None"))]:
            action = gtk.RadioAction("tree-style-" + name, label, "", "", 0)
            if name == treestyle:
                action.set_active(True)
            if lastaction:
                action.set_group(lastaction)
            lastaction = action
            action.connect("toggled", lambda x, y: self.setTreeStyle(y), name)
            self._actions.add_action(action)

        self._ui = gtk.UIManager()
        self._ui.insert_action_group(self._actions, 0)
        self._ui.add_ui_from_string(UI)
        self._menubar = self._ui.get_widget("/menubar")
        self._topvbox.pack_start(self._menubar, False)

        self._toolbar = self._ui.get_widget("/toolbar")
        self._toolbar.set_style(gtk.TOOLBAR_ICONS)
        self._topvbox.pack_start(self._toolbar, False)

        self._window.add_accel_group(self._ui.get_accel_group())

        self._execmenuitem = self._ui.get_action("/menubar/file/exec-changes")
        self._execmenuitem.set_property("sensitive", False)
        self._clearmenuitem = self._ui.get_action(
            "/menubar/edit/clear-changes")
        self._clearmenuitem.set_property("sensitive", False)
        self._undomenuitem = self._ui.get_action("/menubar/edit/undo")
        self._undomenuitem.set_property("sensitive", False)
        self._redomenuitem = self._ui.get_action("/menubar/edit/redo")
        self._redomenuitem.set_property("sensitive", False)

        # Search bar

        self._searchbar = gtk.Alignment()
        self._searchbar.set(0, 0, 1, 1)
        self._searchbar.set_padding(3, 3, 0, 0)
        self._topvbox.pack_start(self._searchbar, False)

        searchvp = gtk.Viewport()
        searchvp.set_shadow_type(gtk.SHADOW_OUT)
        searchvp.show()
        self._searchbar.add(searchvp)

        searchtable = gtk.Table(1, 1)
        searchtable.set_row_spacings(5)
        searchtable.set_col_spacings(5)
        searchtable.set_border_width(5)
        searchtable.show()
        searchvp.add(searchtable)

        label = gtk.Label(_("Search:"))
        label.show()
        searchtable.attach(label, 0, 1, 0, 1, 0, 0)

        self._searchentry = gtk.Entry()
        self._searchentry.connect("activate", lambda x: self.refreshPackages())
        self._searchentry.show()
        searchtable.attach(self._searchentry, 1, 2, 0, 1)

        button = gtk.Button()
        button.set_relief(gtk.RELIEF_NONE)
        button.connect("clicked", lambda x: self.refreshPackages())
        button.show()
        searchtable.attach(button, 2, 3, 0, 1, 0, 0)
        image = gtk.Image()
        image.set_from_stock("gtk-find", gtk.ICON_SIZE_BUTTON)
        image.show()
        button.add(image)

        align = gtk.Alignment()
        align.set(1, 0, 0, 0)
        align.set_padding(0, 0, 10, 0)
        align.show()
        searchtable.attach(align, 3, 4, 0, 1, gtk.FILL, gtk.FILL)
        button = gtk.Button()
        button.set_size_request(20, 20)
        button.set_relief(gtk.RELIEF_NONE)
        button.connect("clicked", lambda x: self.toggleSearch())
        button.show()
        align.add(button)
        image = gtk.Image()
        image.set_from_stock("gtk-close", gtk.ICON_SIZE_MENU)
        image.show()
        button.add(image)

        hbox = gtk.HBox()
        hbox.set_spacing(10)
        hbox.show()
        searchtable.attach(hbox, 1, 2, 1, 2)

        self._searchname = gtk.RadioButton(None, _("Automatic"))
        self._searchname.set_active(True)
        self._searchname.connect("clicked", lambda x: self.refreshPackages())
        self._searchname.show()
        hbox.pack_start(self._searchname, False)
        self._searchdesc = gtk.RadioButton(self._searchname, _("Description"))
        self._searchdesc.connect("clicked", lambda x: self.refreshPackages())
        self._searchdesc.show()
        hbox.pack_start(self._searchdesc, False)

        # Packages and information

        self._vpaned = gtk.VPaned()
        self._vpaned.show()
        self._topvbox.pack_start(self._vpaned)

        self._pv = GtkPackageView()
        self._pv.show()
        self._vpaned.pack1(self._pv, True)

        self._pi = GtkPackageInfo()
        self._pi.show()
        self._pv.connect("package_selected",
                         lambda x, y: self._pi.setPackage(y))
        self._pv.connect("package_activated",
                         lambda x, y: self.actOnPackages(y))
        self._pv.connect("package_popup", self.packagePopup)
        self._vpaned.pack2(self._pi, False)

        self._status = gtk.Statusbar()
        self._status.show()
        self._topvbox.pack_start(self._status, False)

    def showStatus(self, msg):
        self._status.pop(0)
        self._status.push(0, msg)
        while gtk.events_pending():
            gtk.main_iteration()

    def hideStatus(self):
        self._status.pop(0)
        while gtk.events_pending():
            gtk.main_iteration()

    def run(self, command=None, argv=None):
        self.setCatchExceptions(True)
        self._window.set_icon(getPixbuf("smart"))
        self._window.show()
        self._ctrl.reloadChannels()
        self._changeset = ChangeSet(self._ctrl.getCache())
        self._pi.setChangeSet(self._changeset)
        self._progress.hide()
        self.refreshPackages()
        gtk.main()
        self.setCatchExceptions(False)

    # Non-standard interface methods:

    def getChangeSet(self):
        return self._changeset

    def updateChannels(self, selected=False, channels=None):
        if selected:
            aliases = GtkChannelSelector().show()
            channels = [
                channel for channel in self._ctrl.getChannels()
                if channel.getAlias() in aliases
            ]
            if not channels:
                return
        state = self._changeset.getPersistentState()
        self._ctrl.reloadChannels(channels, caching=NEVER)
        self._changeset.setPersistentState(state)
        self.refreshPackages()

    def rebuildCache(self):
        state = self._changeset.getPersistentState()
        self._ctrl.reloadChannels()
        self._changeset.setPersistentState(state)
        self.refreshPackages()

    def applyChanges(self):
        transaction = Transaction(self._ctrl.getCache(),
                                  changeset=self._changeset)
        if self._ctrl.commitTransaction(transaction):
            del self._undo[:]
            del self._redo[:]
            self._redomenuitem.set_property("sensitive", False)
            self._undomenuitem.set_property("sensitive", False)
            self._changeset.clear()
            self._ctrl.reloadChannels()
            self.refreshPackages()
            self.changedMarks()
        self._progress.hide()

    def clearChanges(self):
        self.saveUndo()
        self._changeset.clear()
        self.changedMarks()

    def showChanges(self):
        return self._changes.showChangeSet(self._changeset)

    def toggleFilter(self, filter):
        if filter in self._filters:
            del self._filters[filter]
        else:
            self._filters[filter] = True
        self.refreshPackages()

    def upgradeAll(self):
        transaction = Transaction(self._ctrl.getCache())
        transaction.setState(self._changeset)
        for pkg in self._ctrl.getCache().getPackages():
            if pkg.installed:
                transaction.enqueue(pkg, UPGRADE)
        transaction.setPolicy(PolicyUpgrade)
        transaction.run()
        changeset = transaction.getChangeSet()
        if changeset != self._changeset:
            if self.confirmChange(self._changeset, changeset):
                self.saveUndo()
                self._changeset.setState(changeset)
                self.changedMarks()
                if self.askYesNo(_("Apply marked changes now?"), True):
                    self.applyChanges()
        else:
            self.showStatus(_("No interesting upgrades available!"))

    def actOnPackages(self, pkgs, op=None):
        cache = self._ctrl.getCache()
        transaction = Transaction(cache, policy=PolicyInstall)
        transaction.setState(self._changeset)
        changeset = transaction.getChangeSet()
        if op is None:
            if not [pkg for pkg in pkgs if pkg not in changeset]:
                op = KEEP
            else:
                for pkg in pkgs:
                    if not pkg.installed:
                        op = INSTALL
                        break
                else:
                    op = REMOVE
        if op is REMOVE:
            transaction.setPolicy(PolicyRemove)
        policy = transaction.getPolicy()
        for pkg in pkgs:
            if op is KEEP:
                transaction.enqueue(pkg, op)
            elif op in (REMOVE, REINSTALL, FIX):
                if pkg.installed:
                    transaction.enqueue(pkg, op)
                    if op is REMOVE:
                        for _pkg in cache.getPackages(pkg.name):
                            if not _pkg.installed:
                                policy.setLocked(_pkg, True)
            elif op is INSTALL:
                if not pkg.installed:
                    transaction.enqueue(pkg, op)
        transaction.run()
        if op is FIX:
            expected = 0
        else:
            expected = 1
        if self.confirmChange(self._changeset, changeset, expected):
            self.saveUndo()
            self._changeset.setState(changeset)
            self.changedMarks()

    def packagePopup(self, packageview, pkgs, event):

        menu = gtk.Menu()

        hasinstalled = bool([
            pkg for pkg in pkgs
            if pkg.installed and self._changeset.get(pkg) is not REMOVE
        ])
        hasnoninstalled = bool([
            pkg for pkg in pkgs
            if not pkg.installed and self._changeset.get(pkg) is not INSTALL
        ])

        image = gtk.Image()
        image.set_from_pixbuf(getPixbuf("package-install"))
        item = gtk.ImageMenuItem(_("Install"))
        item.set_image(image)
        item.connect("activate", lambda x: self.actOnPackages(pkgs, INSTALL))
        if not hasnoninstalled:
            item.set_sensitive(False)
        menu.append(item)

        image = gtk.Image()
        image.set_from_pixbuf(getPixbuf("package-reinstall"))
        item = gtk.ImageMenuItem(_("Reinstall"))
        item.set_image(image)
        item.connect("activate", lambda x: self.actOnPackages(pkgs, REINSTALL))
        if not hasinstalled:
            item.set_sensitive(False)
        menu.append(item)

        image = gtk.Image()
        image.set_from_pixbuf(getPixbuf("package-remove"))
        item = gtk.ImageMenuItem(_("Remove"))
        item.set_image(image)
        item.connect("activate", lambda x: self.actOnPackages(pkgs, REMOVE))
        if not hasinstalled:
            item.set_sensitive(False)
        menu.append(item)

        image = gtk.Image()
        if not hasinstalled:
            image.set_from_pixbuf(getPixbuf("package-available"))
        else:
            image.set_from_pixbuf(getPixbuf("package-installed"))
        item = gtk.ImageMenuItem(_("Keep"))
        item.set_image(image)
        item.connect("activate", lambda x: self.actOnPackages(pkgs, KEEP))
        if not [pkg for pkg in pkgs if pkg in self._changeset]:
            item.set_sensitive(False)
        menu.append(item)

        image = gtk.Image()
        image.set_from_pixbuf(getPixbuf("package-broken"))
        item = gtk.ImageMenuItem(_("Fix problems"))
        item.set_image(image)
        item.connect("activate", lambda x: self.actOnPackages(pkgs, FIX))
        if not hasinstalled:
            item.set_sensitive(False)
        menu.append(item)

        inconsistent = False
        thislocked = None
        alllocked = None
        names = pkgconf.getFlagTargets("lock")
        if [pkg for pkg in pkgs if pkg in self._changeset]:
            inconsistent = True
        else:
            for pkg in pkgs:
                if (names and pkg.name in names
                        and ("=", pkg.version) in names[pkg.name]):
                    newthislocked = True
                    newalllocked = len(names[pkg.name]) > 1
                else:
                    newthislocked = False
                    newalllocked = pkgconf.testFlag("lock", pkg)
                if (thislocked is not None and thislocked != newthislocked or
                        alllocked is not None and alllocked != newalllocked):
                    inconsistent = True
                    break
                thislocked = newthislocked
                alllocked = newalllocked

        image = gtk.Image()
        if thislocked:
            item = gtk.ImageMenuItem(_("Unlock this version"))
            if not hasnoninstalled:
                image.set_from_pixbuf(getPixbuf("package-installed"))
            else:
                image.set_from_pixbuf(getPixbuf("package-available"))

            def unlock_this(x):
                for pkg in pkgs:
                    pkgconf.clearFlag("lock", pkg.name, "=", pkg.version)
                self._pv.queue_draw()
                self._pi.setPackage(pkgs[0])

            item.connect("activate", unlock_this)
        else:
            item = gtk.ImageMenuItem(_("Lock this version"))
            if not hasnoninstalled:
                image.set_from_pixbuf(getPixbuf("package-installed-locked"))
            else:
                image.set_from_pixbuf(getPixbuf("package-available-locked"))

            def lock_this(x):
                for pkg in pkgs:
                    pkgconf.setFlag("lock", pkg.name, "=", pkg.version)
                self._pv.queue_draw()
                self._pi.setPackage(pkgs[0])

            item.connect("activate", lock_this)
        item.set_image(image)
        if inconsistent:
            item.set_sensitive(False)
        menu.append(item)

        image = gtk.Image()
        if alllocked:
            item = gtk.ImageMenuItem(_("Unlock all versions"))
            if not hasnoninstalled:
                image.set_from_pixbuf(getPixbuf("package-installed"))
            else:
                image.set_from_pixbuf(getPixbuf("package-available"))

            def unlock_all(x):
                for pkg in pkgs:
                    pkgconf.clearFlag("lock", pkg.name)
                self._pv.queue_draw()
                self._pi.setPackage(pkgs[0])

            item.connect("activate", unlock_all)
        else:
            item = gtk.ImageMenuItem(_("Lock all versions"))
            if not hasnoninstalled:
                image.set_from_pixbuf(getPixbuf("package-installed-locked"))
            else:
                image.set_from_pixbuf(getPixbuf("package-available-locked"))

            def lock_all(x):
                for pkg in pkgs:
                    pkgconf.setFlag("lock", pkg.name)
                self._pv.queue_draw()
                self._pi.setPackage(pkgs[0])

            item.connect("activate", lock_all)
        item.set_image(image)
        if inconsistent:
            item.set_sensitive(False)
        menu.append(item)

        item = gtk.MenuItem(_("Priority"))

        def priority(x):
            GtkSinglePriority(self._window).show(pkgs[0])
            self._pi.setPackage(pkgs[0])

        item.connect("activate", priority)
        if len(pkgs) != 1:
            item.set_sensitive(False)
        menu.append(item)

        menu.show_all()
        menu.popup(None, None, None, event.button, event.time)

    def checkPackages(self, all=False, uninstalled=False):
        cache = self._ctrl.getCache()
        if checkPackages(cache,
                         cache.getPackages(),
                         report=True,
                         all=all,
                         uninstalled=uninstalled):
            self.info(_("All checked packages have correct relations."))

    def fixAllProblems(self):
        self.actOnPackages([
            pkg for pkg in self._ctrl.getCache().getPackages() if pkg.installed
        ], FIX)

    def undo(self):
        if self._undo:
            state = self._undo.pop(0)
            if not self._undo:
                self._undomenuitem.set_property("sensitive", False)
            self._redo.insert(0, self._changeset.getPersistentState())
            self._redomenuitem.set_property("sensitive", True)
            self._changeset.setPersistentState(state)
            self.changedMarks()

    def redo(self):
        if self._redo:
            state = self._redo.pop(0)
            if not self._redo:
                self._redomenuitem.set_property("sensitive", False)
            self._undo.insert(0, self._changeset.getPersistentState())
            self._undomenuitem.set_property("sensitive", True)
            self._changeset.setPersistentState(state)
            self.changedMarks()

    def saveUndo(self):
        self._undo.insert(0, self._changeset.getPersistentState())
        del self._redo[:]
        del self._undo[20:]
        self._undomenuitem.set_property("sensitive", True)
        self._redomenuitem.set_property("sensitive", False)

    def setTreeStyle(self, mode):
        if mode != sysconf.get("package-tree"):
            sysconf.set("package-tree", mode)
            self.refreshPackages()

    def editChannels(self):
        if GtkChannels(self._window).show():
            self.rebuildCache()

    def editMirrors(self):
        GtkMirrors(self._window).show()

    def editFlags(self):
        GtkFlags(self._window).show()

    def editPriorities(self):
        GtkPriorities(self._window).show()

    def setBusy(self, flag):
        if flag:
            self._window.window.set_cursor(self._watch)
            while gtk.events_pending():
                gtk.main_iteration()
        else:
            self._window.window.set_cursor(None)

    def changedMarks(self):
        if "hide-unmarked" in self._filters:
            self.refreshPackages()
        else:
            self._pv.queue_draw()
        self._execmenuitem.set_property("sensitive", bool(self._changeset))
        self._clearmenuitem.set_property("sensitive", bool(self._changeset))

    def toggleSearch(self):
        visible = not self._searchbar.get_property('visible')
        self._searchbar.set_property('visible', visible)
        self.refreshPackages()
        if visible:
            self._searchentry.grab_focus()

    def refreshPackages(self):
        if not self._ctrl:
            return

        self.setBusy(True)

        tree = sysconf.get("package-tree", "groups")
        ctrl = self._ctrl
        changeset = self._changeset

        if self._searchbar.get_property("visible"):

            searcher = Searcher()
            dosearch = False
            if self._searchdesc.get_active():
                text = self._searchentry.get_text().strip()
                if text:
                    dosearch = True
                    searcher.addDescription(text)
                    searcher.addSummary(text)
            else:
                try:
                    tokens = shlex.split(self._searchentry.get_text())
                except ValueError:
                    pass
                else:
                    if tokens:
                        dosearch = True
                        for tok in tokens:
                            searcher.addAuto(tok)

            packages = []
            if dosearch:
                self._ctrl.getCache().search(searcher)
                for ratio, obj in searcher.getResults():
                    if isinstance(obj, Package):
                        packages.append(obj)
                    else:
                        packages.extend(obj.packages)
        else:
            packages = ctrl.getCache().getPackages()

        filters = self._filters
        if filters:
            if "hide-non-upgrades" in filters:
                newpackages = {}
                for pkg in packages:
                    if pkg.installed:
                        upgpkgs = {}
                        try:
                            for prv in pkg.provides:
                                for upg in prv.upgradedby:
                                    for upgpkg in upg.packages:
                                        if upgpkg.installed:
                                            raise StopIteration
                                        upgpkgs[upgpkg] = True
                        except StopIteration:
                            pass
                        else:
                            newpackages.update(upgpkgs)
                packages = newpackages.keys()
            if "hide-uninstalled" in filters:
                packages = [x for x in packages if x.installed]
            if "hide-unmarked" in filters:
                packages = [x for x in packages if x in changeset]
            if "hide-installed" in filters:
                packages = [x for x in packages if not x.installed]
            if "hide-old" in filters:
                packages = pkgconf.filterByFlag("new", packages)

        if tree == "groups":
            groups = {}
            done = {}
            for pkg in packages:
                lastgroup = None
                for loader in pkg.loaders:
                    info = loader.getInfo(pkg)
                    group = info.getGroup()
                    donetuple = (group, pkg)
                    if donetuple not in done:
                        done[donetuple] = True
                        if group in groups:
                            groups[group].append(pkg)
                        else:
                            groups[group] = [pkg]

        elif tree == "channels":
            groups = {}
            done = {}
            for pkg in packages:
                for loader in pkg.loaders:
                    channel = loader.getChannel()
                    group = channel.getName() or channel.getAlias()
                    donetuple = (group, pkg)
                    if donetuple not in done:
                        done[donetuple] = True
                        if group in groups:
                            groups[group].append(pkg)
                        else:
                            groups[group] = [pkg]

        elif tree == "channels-groups":
            groups = {}
            done = {}
            for pkg in packages:
                for loader in pkg.loaders:
                    channel = loader.getChannel()
                    group = channel.getName() or channel.getAlias()
                    subgroup = loader.getInfo(pkg).getGroup()
                    donetuple = (group, subgroup, pkg)
                    if donetuple not in done:
                        done[donetuple] = True
                        if group in groups:
                            if subgroup in groups[group]:
                                groups[group][subgroup].append(pkg)
                            else:
                                groups[group][subgroup] = [pkg]
                        else:
                            groups[group] = {subgroup: [pkg]}

        else:
            groups = packages

        self._pv.setPackages(groups, changeset, keepstate=True)

        self.setBusy(False)
Ejemplo n.º 16
0
    def __init__(self, ctrl):
        GtkInterface.__init__(self, ctrl)

        self._changeset = None

        self._window = gtk.Window()
        self._window.set_title("Smart Package Manager %s" % VERSION)
        self._window.set_position(gtk.WIN_POS_CENTER)
        self._window.set_geometry_hints(min_width=640, min_height=480)
        def delete(widget, event):
            gtk.main_quit()
            return True
        self._window.connect("delete-event", delete)

        self._log.set_transient_for(self._window)
        self._progress.set_transient_for(self._window)
        self._hassubprogress.set_transient_for(self._window)
        self._changes.set_transient_for(self._window)

        self._watch = gtk.gdk.Cursor(gtk.gdk.WATCH)

        self._undo = []
        self._redo = []

        self._topvbox = gtk.VBox()
        self._topvbox.show()
        self._window.add(self._topvbox)

        globals = {"self": self, "gtk": gtk}
        self._actions = gtk.ActionGroup("Actions")
        self._actions.add_actions(compileActions(ACTIONS, globals))

        self._filters = {}
        for name, label in [("hide-non-upgrades", _("Hide Non-upgrades")),
                            ("hide-non-newest", _("Hide Non-newest")),
                            ("hide-installed", _("Hide Installed")),
                            ("hide-uninstalled", _("Hide Uninstalled")),
                            ("hide-unmarked", _("Hide Unmarked")),
                            ("hide-unlocked", _("Hide Unlocked")),
                            ("hide-requested", _("Hide Requested")),
                            ("hide-old", _("Hide Old"))]:
            action = gtk.ToggleAction(name, label, "", "")
            action.connect("toggled", lambda x, y: self.toggleFilter(y), name)
            self._actions.add_action(action)

        treestyle = sysconf.get("package-tree")
        lastaction = None
        for name, label in [("groups", _("Groups")),
                            ("separate-groups", _("Separate Groups")),
                            ("channels", _("Channels")),
                            ("channels-groups", _("Channels & Groups")),
                            ("none", _("None"))]:
            action = gtk.RadioAction("tree-style-"+name, label, "", "", 0)
            if name == treestyle:
                action.set_active(True)
            if lastaction:
                action.set_group(lastaction)
            lastaction = action
            action.connect("toggled", lambda x, y: self.setTreeStyle(y), name)
            self._actions.add_action(action)

        self._ui = gtk.UIManager()
        self._ui.insert_action_group(self._actions, 0)
        self._ui.add_ui_from_string(UI)
        self._menubar = self._ui.get_widget("/menubar")
        self._topvbox.pack_start(self._menubar, False)

        self._toolbar = self._ui.get_widget("/toolbar")
        self._toolbar.set_style(gtk.TOOLBAR_ICONS)
        self._topvbox.pack_start(self._toolbar, False)
        if sysconf.getReadOnly():
           # Can't update channels in readonly mode.
           updatetoolitem = self._ui.get_widget("/toolbar/update-channels")
           updatetoolitem.set_property("sensitive", False)

        self._window.add_accel_group(self._ui.get_accel_group())

        self._execmenuitem = self._ui.get_action("/menubar/file/exec-changes")
        self._execmenuitem.set_property("sensitive", False)
        self._clearmenuitem = self._ui.get_action("/menubar/edit/clear-changes")
        self._clearmenuitem.set_property("sensitive", False)
        self._undomenuitem = self._ui.get_action("/menubar/edit/undo")
        self._undomenuitem.set_property("sensitive", False)
        self._redomenuitem = self._ui.get_action("/menubar/edit/redo")
        self._redomenuitem.set_property("sensitive", False)

        # Search bar

        if gtk.gtk_version >= (2, 16, 0) or sexy:
            self._searchbar = gtk.ToolItem()
            self._searchbar.set_expand(True)
            self._searchbar.set_homogeneous(False)
            self._searchbar.show()
            count = self._toolbar.get_n_items()
            find = self._toolbar.get_nth_item(count - 1)
            self._toolbar.remove(find)
            self._toolbar.insert(self._searchbar, -1)

            searchtable = gtk.Table(1, 1)
            searchtable.set_row_spacings(5)
            searchtable.set_col_spacings(5)
            searchtable.set_border_width(5)
            searchtable.show()
            self._searchbar.add(searchtable)

            if gtk.gtk_version >= (2, 16, 0):
                self._searchentry = gtk.Entry()
                self._searchentry.set_property("primary-icon-name", "gtk-find")
                self._searchentry.set_property("secondary-icon-name", "gtk-clear")
                def press(entry, icon_pos, event):
                    if int(icon_pos) == 0: # "primary"
                        self._searchmenu.popup(None, None, None, event.button, event.time)
                    elif int(icon_pos) == 1: # "secondary"
                        self._searchentry.set_text("")
                        self.refreshPackages()
                self._searchentry.connect("icon-press", press)
            elif sexy:
                self._searchentry = sexy.IconEntry()
                image = gtk.Image()
                image.set_from_stock("gtk-find", gtk.ICON_SIZE_BUTTON)
                self._searchentry.set_icon(sexy.ICON_ENTRY_PRIMARY, image)
                image = gtk.Image()
                image.set_from_stock("gtk-clear", gtk.ICON_SIZE_BUTTON)
                self._searchentry.set_icon(sexy.ICON_ENTRY_SECONDARY, image)
                def pressed(entry, icon_pos, button):
                    if icon_pos == 0: # "primary"
                        self._searchmenu.popup(None, None, None, button, gtk.get_current_event_time())
                    elif icon_pos == 1: # "secondary"
                        self._searchentry.set_text("")
                        self.refreshPackages()
                self._searchentry.connect("icon-pressed", pressed)
            self._searchentry.connect("activate", lambda x: self.refreshPackages())
            self._searchentry.show()
            searchtable.attach(self._searchentry, 0, 1, 0, 1)

            self._searchmenu = gtk.Menu()
            self._searchname = gtk.CheckMenuItem(_("Automatic"))
            self._searchname.set_draw_as_radio(True)
            self._searchname.set_active(True)
            def search_automatic(item):
                self._searchdesc.set_active(not item.get_active())
                self.refreshPackages()
            self._searchname.connect("activate", search_automatic)
            self._searchname.show()
            self._searchmenu.append(self._searchname)
            self._searchdesc = gtk.CheckMenuItem(_("Description"))
            self._searchdesc.set_draw_as_radio(True)
            self._searchdesc.set_active(False)
            def search_description(item):
                self._searchname.set_active(not item.get_active())
                self.refreshPackages()
            self._searchdesc.connect("activate", search_description)
            self._searchdesc.show()
            self._searchmenu.append(self._searchdesc)
        else:
            self._searchbar = gtk.Alignment()
            self._searchbar.set(0, 0, 1, 1)
            self._searchbar.set_padding(3, 3, 0, 0)
            self._topvbox.pack_start(self._searchbar, False)

            searchvp = gtk.Viewport()
            searchvp.set_shadow_type(gtk.SHADOW_OUT)
            searchvp.show()
            self._searchbar.add(searchvp)

            searchtable = gtk.Table(1, 1)
            searchtable.set_row_spacings(5)
            searchtable.set_col_spacings(5)
            searchtable.set_border_width(5)
            searchtable.show()
            searchvp.add(searchtable)

            label = gtk.Label(_("Search:"))
            label.show()
            searchtable.attach(label, 0, 1, 0, 1, 0, 0)

            self._searchentry = gtk.Entry()
            self._searchentry.connect("activate", lambda x: self.refreshPackages())
            self._searchentry.show()
            searchtable.attach(self._searchentry, 1, 2, 0, 1)

            button = gtk.Button()
            button.set_relief(gtk.RELIEF_NONE)
            button.connect("clicked", lambda x: self.refreshPackages())
            button.show()
            searchtable.attach(button, 2, 3, 0, 1, 0, 0)
            image = gtk.Image()
            image.set_from_stock("gtk-find", gtk.ICON_SIZE_BUTTON)
            image.show()
            button.add(image)

            align = gtk.Alignment()
            align.set(1, 0, 0, 0)
            align.set_padding(0, 0, 10, 0)
            align.show()
            searchtable.attach(align, 3, 4, 0, 1, gtk.FILL, gtk.FILL)
            button = gtk.Button()
            button.set_size_request(20, 20)
            button.set_relief(gtk.RELIEF_NONE)
            button.connect("clicked", lambda x: self.toggleSearch())
            button.show()
            align.add(button)
            image = gtk.Image()
            image.set_from_stock("gtk-close", gtk.ICON_SIZE_MENU)
            image.show()
            button.add(image)

            hbox = gtk.HBox()
            hbox.set_spacing(10)
            hbox.show()
            searchtable.attach(hbox, 1, 2, 1, 2)

            self._searchmenu = None
            self._searchname = gtk.RadioButton(None, _("Automatic"))
            self._searchname.set_active(True)
            self._searchname.connect("clicked", lambda x: self.refreshPackages())
            self._searchname.show()
            hbox.pack_start(self._searchname, False)
            self._searchdesc = gtk.RadioButton(self._searchname, _("Description"))
            self._searchdesc.connect("clicked", lambda x: self.refreshPackages())
            self._searchdesc.show()
            hbox.pack_start(self._searchdesc, False)

        # Packages and information

        self._hpaned = gtk.HPaned()
        self._hpaned.show()
        self._topvbox.pack_start(self._hpaned)

        scrollwin = gtk.ScrolledWindow()
        scrollwin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        scrollwin.set_shadow_type(gtk.SHADOW_IN)
        self._hpaned.pack1(scrollwin, True)

        self._pg = gtk.TreeView()
        def group_selected(treeview):
            self.refreshPackages()
        self._pg.connect("cursor_changed", group_selected)
        self._pg.show()
        scrollwin.add(self._pg)

        selection = self._pg.get_selection()
        selection.set_mode(gtk.SELECTION_MULTIPLE)

        renderer = gtk.CellRendererText()
        column = gtk.TreeViewColumn(_("Group"), renderer, text=1)
        self._pg.append_column(column)

        self._vpaned = gtk.VPaned()
        self._vpaned.show()
        self._hpaned.pack2(self._vpaned, True)

        self._pv = GtkPackageView()
        self._pv.show()
        self._vpaned.pack1(self._pv, True)

        self._pi = GtkPackageInfo()
        self._pi.show()
        self._pv.connect("package_selected",
                         lambda x, y: self._pi.setPackage(y))
        self._pv.connect("package_activated",
                         lambda x, y: self.actOnPackages(y))
        self._pv.connect("package_popup", self.packagePopup)
        self._vpaned.pack2(self._pi, False)

        self._status = gtk.Statusbar()
        self._status.show()
        self._topvbox.pack_start(self._status, False)
        
        self._legend = GtkLegend()
Ejemplo n.º 17
0
    def __init__(self, ctrl):
        GtkInterface.__init__(self, ctrl)

        self._changeset = None

        self._window = gtk.Window()
        self._window.set_title("Smart Package Manager %s" % VERSION)
        self._window.set_position(gtk.WIN_POS_CENTER)
        self._window.set_geometry_hints(min_width=640, min_height=480)
        self._window.connect("destroy", lambda x: gtk.main_quit())

        self._log.set_transient_for(self._window)
        self._progress.set_transient_for(self._window)
        self._hassubprogress.set_transient_for(self._window)

        self._watch = gtk.gdk.Cursor(gtk.gdk.WATCH)

        self._undo = []
        self._redo = []

        self._topvbox = gtk.VBox()
        self._topvbox.show()
        self._window.add(self._topvbox)

        globals = {"self": self, "gtk": gtk}
        self._actions = gtk.ActionGroup("Actions")
        self._actions.add_actions(compileActions(ACTIONS, globals))

        self._filters = {}
        for name, label in [("hide-non-upgrades", _("Hide Non-upgrades")),
                            ("hide-installed", _("Hide Installed")),
                            ("hide-uninstalled", _("Hide Uninstalled")),
                            ("hide-unmarked", _("Hide Unmarked")),
                            ("hide-old", _("Hide Old"))]:
            action = gtk.ToggleAction(name, label, "", "")
            action.connect("toggled", lambda x, y: self.toggleFilter(y), name)
            self._actions.add_action(action)

        treestyle = sysconf.get("package-tree")
        lastaction = None
        for name, label in [("groups", _("Groups")),
                            ("channels", _("Channels")),
                            ("channels-groups", _("Channels & Groups")),
                            ("none", _("None"))]:
            action = gtk.RadioAction("tree-style-" + name, label, "", "", 0)
            if name == treestyle:
                action.set_active(True)
            if lastaction:
                action.set_group(lastaction)
            lastaction = action
            action.connect("toggled", lambda x, y: self.setTreeStyle(y), name)
            self._actions.add_action(action)

        self._ui = gtk.UIManager()
        self._ui.insert_action_group(self._actions, 0)
        self._ui.add_ui_from_string(UI)
        self._menubar = self._ui.get_widget("/menubar")
        self._topvbox.pack_start(self._menubar, False)

        self._toolbar = self._ui.get_widget("/toolbar")
        self._toolbar.set_style(gtk.TOOLBAR_ICONS)
        self._topvbox.pack_start(self._toolbar, False)

        self._window.add_accel_group(self._ui.get_accel_group())

        self._execmenuitem = self._ui.get_action("/menubar/file/exec-changes")
        self._execmenuitem.set_property("sensitive", False)
        self._clearmenuitem = self._ui.get_action(
            "/menubar/edit/clear-changes")
        self._clearmenuitem.set_property("sensitive", False)
        self._undomenuitem = self._ui.get_action("/menubar/edit/undo")
        self._undomenuitem.set_property("sensitive", False)
        self._redomenuitem = self._ui.get_action("/menubar/edit/redo")
        self._redomenuitem.set_property("sensitive", False)

        # Search bar

        self._searchbar = gtk.Alignment()
        self._searchbar.set(0, 0, 1, 1)
        self._searchbar.set_padding(3, 3, 0, 0)
        self._topvbox.pack_start(self._searchbar, False)

        searchvp = gtk.Viewport()
        searchvp.set_shadow_type(gtk.SHADOW_OUT)
        searchvp.show()
        self._searchbar.add(searchvp)

        searchtable = gtk.Table(1, 1)
        searchtable.set_row_spacings(5)
        searchtable.set_col_spacings(5)
        searchtable.set_border_width(5)
        searchtable.show()
        searchvp.add(searchtable)

        label = gtk.Label(_("Search:"))
        label.show()
        searchtable.attach(label, 0, 1, 0, 1, 0, 0)

        self._searchentry = gtk.Entry()
        self._searchentry.connect("activate", lambda x: self.refreshPackages())
        self._searchentry.show()
        searchtable.attach(self._searchentry, 1, 2, 0, 1)

        button = gtk.Button()
        button.set_relief(gtk.RELIEF_NONE)
        button.connect("clicked", lambda x: self.refreshPackages())
        button.show()
        searchtable.attach(button, 2, 3, 0, 1, 0, 0)
        image = gtk.Image()
        image.set_from_stock("gtk-find", gtk.ICON_SIZE_BUTTON)
        image.show()
        button.add(image)

        align = gtk.Alignment()
        align.set(1, 0, 0, 0)
        align.set_padding(0, 0, 10, 0)
        align.show()
        searchtable.attach(align, 3, 4, 0, 1, gtk.FILL, gtk.FILL)
        button = gtk.Button()
        button.set_size_request(20, 20)
        button.set_relief(gtk.RELIEF_NONE)
        button.connect("clicked", lambda x: self.toggleSearch())
        button.show()
        align.add(button)
        image = gtk.Image()
        image.set_from_stock("gtk-close", gtk.ICON_SIZE_MENU)
        image.show()
        button.add(image)

        hbox = gtk.HBox()
        hbox.set_spacing(10)
        hbox.show()
        searchtable.attach(hbox, 1, 2, 1, 2)

        self._searchname = gtk.RadioButton(None, _("Automatic"))
        self._searchname.set_active(True)
        self._searchname.connect("clicked", lambda x: self.refreshPackages())
        self._searchname.show()
        hbox.pack_start(self._searchname, False)
        self._searchdesc = gtk.RadioButton(self._searchname, _("Description"))
        self._searchdesc.connect("clicked", lambda x: self.refreshPackages())
        self._searchdesc.show()
        hbox.pack_start(self._searchdesc, False)

        # Packages and information

        self._vpaned = gtk.VPaned()
        self._vpaned.show()
        self._topvbox.pack_start(self._vpaned)

        self._pv = GtkPackageView()
        self._pv.show()
        self._vpaned.pack1(self._pv, True)

        self._pi = GtkPackageInfo()
        self._pi.show()
        self._pv.connect("package_selected",
                         lambda x, y: self._pi.setPackage(y))
        self._pv.connect("package_activated",
                         lambda x, y: self.actOnPackages(y))
        self._pv.connect("package_popup", self.packagePopup)
        self._vpaned.pack2(self._pi, False)

        self._status = gtk.Statusbar()
        self._status.show()
        self._topvbox.pack_start(self._status, False)
Ejemplo n.º 18
0
    def __init__(self):
        gtk.Alignment.__init__(self)
        self.__gobject_init__()

        self._pkg = None
        self._changeset = None

        font = self.style.font_desc.copy()
        font.set_size(font.get_size() - pango.SCALE)

        boldfont = font.copy()
        boldfont.set_weight(pango.WEIGHT_BOLD)

        self._notebook = gtk.Notebook()
        self._notebook.show()
        self.add(self._notebook)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        #sw.set_border_width(5)
        sw.show()

        table = gtk.Table()
        table.set_row_spacings(2)
        table.set_col_spacings(5)
        table.set_border_width(5)
        table.show()
        sw.add_with_viewport(table)

        self._info = type("Info", (), {})()

        attrsleft = pango.AttrList()
        attrsleft.insert(pango.AttrFontDesc(font, 0, -1))
        attrsright = pango.AttrList()
        attrsright.insert(pango.AttrFontDesc(boldfont, 0, -1))

        row = 0
        for attr, text in [("status", _("Status:")),
                           ("priority", _("Priority:")),
                           ("group", _("Group:")),
                           ("installedsize", _("Installed Size:")),
                           ("channels", _("Channels:"))]:
            label = gtk.Label(text)
            label.set_attributes(attrsleft)
            if attr == "channels":
                label.set_alignment(1.0, 0.0)
            else:
                label.set_alignment(1.0, 0.5)
            label.show()
            table.attach(label, 0, 1, row, row + 1, gtk.FILL, gtk.FILL)
            setattr(self._info, attr + "_label", label)
            label = gtk.Label()
            label.set_attributes(attrsright)
            label.set_alignment(0.0, 0.5)
            label.show()
            table.attach(label, 1, 2, row, row + 1, gtk.FILL, gtk.FILL)
            setattr(self._info, attr, label)
            row += 1

        label = gtk.Label(_("General"))
        self._notebook.append_page(sw, label)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.set_border_width(5)
        sw.show()

        self._descrtv = gtk.TextView()
        self._descrtv.set_editable(False)
        self._descrtv.set_cursor_visible(False)
        self._descrtv.set_left_margin(5)
        self._descrtv.set_right_margin(5)
        self._descrtv.show()
        buffer = self._descrtv.get_buffer()
        buffer.create_tag("description", font_desc=font)
        buffer.create_tag("summary", font_desc=boldfont)
        sw.add(self._descrtv)

        label = gtk.Label(_("Description"))
        self._notebook.append_page(sw, label)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.set_border_width(5)
        sw.show()

        self._conttv = gtk.TextView()
        self._conttv.set_editable(False)
        self._conttv.set_cursor_visible(False)
        self._conttv.set_left_margin(5)
        self._conttv.set_right_margin(5)
        self._conttv.show()
        buffer = self._conttv.get_buffer()
        buffer.create_tag("content", font_desc=font)
        sw.add(self._conttv)

        label = gtk.Label(_("Content"))
        self._notebook.append_page(sw, label)

        self._relations = GtkPackageView()
        self._relations.set_border_width(5)
        self._relations.getTreeView().set_headers_visible(False)
        self._relations.show()

        label = gtk.Label(_("Relations"))
        self._notebook.append_page(self._relations, label)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        sw.set_border_width(5)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.show()

        model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING,
                              gobject.TYPE_STRING)
        self._urls = gtk.TreeView(model)
        self._urls.set_headers_visible(False)
        self._urls.show()
        renderer = gtk.CellRendererText()
        renderer.set_property("font-desc", font)
        self._urls.insert_column_with_attributes(-1,
                                                 _("Channel"),
                                                 renderer,
                                                 text=0)
        self._urls.insert_column_with_attributes(-1,
                                                 _("Size"),
                                                 renderer,
                                                 text=1)
        self._urls.insert_column_with_attributes(-1,
                                                 _("URL"),
                                                 renderer,
                                                 text=2)
        sw.add(self._urls)

        label = gtk.Label(_("URLs"))
        self._notebook.append_page(sw, label)

        self._notebook.connect("switch_page", self._switchPage)
Ejemplo n.º 19
0
class GtkInteractiveInterface(GtkInterface):

    def __init__(self, ctrl):
        GtkInterface.__init__(self, ctrl)

        self._changeset = None

        self._window = gtk.Window()
        self._window.set_title("Smart Package Manager %s" % VERSION)
        self._window.set_position(gtk.WIN_POS_CENTER)
        self._window.set_geometry_hints(min_width=640, min_height=480)
        def delete(widget, event):
            gtk.main_quit()
            return True
        self._window.connect("delete-event", delete)

        self._log.set_transient_for(self._window)
        self._progress.set_transient_for(self._window)
        self._hassubprogress.set_transient_for(self._window)
        self._changes.set_transient_for(self._window)

        self._watch = gtk.gdk.Cursor(gtk.gdk.WATCH)

        self._undo = []
        self._redo = []

        self._topvbox = gtk.VBox()
        self._topvbox.show()
        self._window.add(self._topvbox)

        globals = {"self": self, "gtk": gtk}
        self._actions = gtk.ActionGroup("Actions")
        self._actions.add_actions(compileActions(ACTIONS, globals))

        self._filters = {}
        for name, label in [("hide-non-upgrades", _("Hide Non-upgrades")),
                            ("hide-non-newest", _("Hide Non-newest")),
                            ("hide-installed", _("Hide Installed")),
                            ("hide-uninstalled", _("Hide Uninstalled")),
                            ("hide-unmarked", _("Hide Unmarked")),
                            ("hide-unlocked", _("Hide Unlocked")),
                            ("hide-requested", _("Hide Requested")),
                            ("hide-old", _("Hide Old"))]:
            action = gtk.ToggleAction(name, label, "", "")
            action.connect("toggled", lambda x, y: self.toggleFilter(y), name)
            self._actions.add_action(action)

        treestyle = sysconf.get("package-tree")
        lastaction = None
        for name, label in [("groups", _("Groups")),
                            ("separate-groups", _("Separate Groups")),
                            ("channels", _("Channels")),
                            ("channels-groups", _("Channels & Groups")),
                            ("none", _("None"))]:
            action = gtk.RadioAction("tree-style-"+name, label, "", "", 0)
            if name == treestyle:
                action.set_active(True)
            if lastaction:
                action.set_group(lastaction)
            lastaction = action
            action.connect("toggled", lambda x, y: self.setTreeStyle(y), name)
            self._actions.add_action(action)

        self._ui = gtk.UIManager()
        self._ui.insert_action_group(self._actions, 0)
        self._ui.add_ui_from_string(UI)
        self._menubar = self._ui.get_widget("/menubar")
        self._topvbox.pack_start(self._menubar, False)

        self._toolbar = self._ui.get_widget("/toolbar")
        if sysconf.get("gtk-toolbar-names", False):
            self._toolbar.set_style(gtk.TOOLBAR_BOTH)
        else:
            self._toolbar.set_style(gtk.TOOLBAR_ICONS)
        self._topvbox.pack_start(self._toolbar, False)
        if sysconf.getReadOnly():
           # Can't update channels in readonly mode.
           updatetoolitem = self._ui.get_widget("/toolbar/update-channels")
           updatetoolitem.set_property("sensitive", False)

        self._window.add_accel_group(self._ui.get_accel_group())

        self._execmenuitem = self._ui.get_action("/menubar/file/exec-changes")
        self._execmenuitem.set_property("sensitive", False)
        self._clearmenuitem = self._ui.get_action("/menubar/edit/clear-changes")
        self._clearmenuitem.set_property("sensitive", False)
        self._undomenuitem = self._ui.get_action("/menubar/edit/undo")
        self._undomenuitem.set_property("sensitive", False)
        self._redomenuitem = self._ui.get_action("/menubar/edit/redo")
        self._redomenuitem.set_property("sensitive", False)

        # Search bar

        self._history = [""]
        self._historypos = 0

        if gtk.gtk_version >= (2, 16, 0) or sexy:
            self._searchbar = gtk.ToolItem()
            self._searchbar.set_expand(True)
            self._searchbar.set_homogeneous(False)
            self._searchbar.show()
            count = self._toolbar.get_n_items()
            find = self._toolbar.get_nth_item(count - 1)
            self._toolbar.remove(find)
            self._toolbar.insert(self._searchbar, -1)

            searchtable = gtk.Table(1, 1)
            searchtable.set_row_spacings(5)
            searchtable.set_col_spacings(5)
            searchtable.set_border_width(5)
            searchtable.show()
            self._searchbar.add(searchtable)

            if gtk.gtk_version >= (2, 16, 0):
                self._searchentry = gtk.Entry()
                self._searchentry.set_property("primary-icon-stock", "gtk-find")
                self._searchentry.set_property("secondary-icon-stock", "gtk-clear")
                def press(entry, icon_pos, event):
                    if int(icon_pos) == 0: # "primary"
                        self._searchmenu.popup(None, None, None, event.button, event.time)
                    elif int(icon_pos) == 1: # "secondary"
                        self.searchClear()
                self._searchentry.connect("icon-press", press)
            elif sexy:
                self._searchentry = sexy.IconEntry()
                image = gtk.Image()
                image.set_from_stock("gtk-find", gtk.ICON_SIZE_BUTTON)
                self._searchentry.set_icon(sexy.ICON_ENTRY_PRIMARY, image)
                image = gtk.Image()
                image.set_from_stock("gtk-clear", gtk.ICON_SIZE_BUTTON)
                self._searchentry.set_icon(sexy.ICON_ENTRY_SECONDARY, image)
                def pressed(entry, icon_pos, button):
                    if icon_pos == 0: # "primary"
                        self._searchmenu.popup(None, None, None, button, gtk.get_current_event_time())
                    elif icon_pos == 1: # "secondary"
                        self.searchClear()
                self._searchentry.connect("icon-pressed", pressed)
            self._searchentry.connect("activate", lambda x: self.searchFind())
            self._searchentry.connect("key-press-event", self.searchKeyPress)
            self._searchentry.show()
            searchtable.attach(self._searchentry, 0, 1, 0, 1)

            self._searchmenu = gtk.Menu()
            self._searchname = gtk.CheckMenuItem(_("Automatic"))
            self._searchname.set_draw_as_radio(True)
            self._searchname.set_active(True)
            def search_automatic(item):
                self._searchdesc.set_active(not item.get_active())
                self.refreshPackages()
            self._searchname.connect("activate", search_automatic)
            self._searchname.show()
            self._searchmenu.append(self._searchname)
            self._searchdesc = gtk.CheckMenuItem(_("Description"))
            self._searchdesc.set_draw_as_radio(True)
            self._searchdesc.set_active(False)
            def search_description(item):
                self._searchname.set_active(not item.get_active())
                self.refreshPackages()
            self._searchdesc.connect("activate", search_description)
            self._searchdesc.show()
            self._searchmenu.append(self._searchdesc)
        else:
            self._searchbar = gtk.Alignment()
            self._searchbar.set(0, 0, 1, 1)
            self._searchbar.set_padding(3, 3, 0, 0)
            self._topvbox.pack_start(self._searchbar, False)

            searchvp = gtk.Viewport()
            searchvp.set_shadow_type(gtk.SHADOW_OUT)
            searchvp.show()
            self._searchbar.add(searchvp)

            searchtable = gtk.Table(1, 1)
            searchtable.set_row_spacings(5)
            searchtable.set_col_spacings(5)
            searchtable.set_border_width(5)
            searchtable.show()
            searchvp.add(searchtable)

            label = gtk.Label(_("Search:"))
            label.show()
            searchtable.attach(label, 0, 1, 0, 1, 0, 0)

            self._searchentry = gtk.Entry()
            self._searchentry.connect("activate", lambda x: self.searchFind())
            self._searchentry.connect("key-press-event", self.searchKeyPress)
            self._searchentry.show()
            searchtable.attach(self._searchentry, 1, 2, 0, 1)

            button = gtk.Button()
            button.set_relief(gtk.RELIEF_NONE)
            button.connect("clicked", lambda x: self.searchFind())
            button.show()
            searchtable.attach(button, 2, 3, 0, 1, 0, 0)
            image = gtk.Image()
            image.set_from_stock("gtk-find", gtk.ICON_SIZE_BUTTON)
            image.show()
            button.add(image)

            align = gtk.Alignment()
            align.set(1, 0, 0, 0)
            align.set_padding(0, 0, 10, 0)
            align.show()
            searchtable.attach(align, 3, 4, 0, 1, gtk.FILL, gtk.FILL)
            button = gtk.Button()
            button.set_size_request(20, 20)
            button.set_relief(gtk.RELIEF_NONE)
            button.connect("clicked", lambda x: self.toggleSearch())
            button.show()
            align.add(button)
            image = gtk.Image()
            image.set_from_stock("gtk-close", gtk.ICON_SIZE_MENU)
            image.show()
            button.add(image)

            hbox = gtk.HBox()
            hbox.set_spacing(10)
            hbox.show()
            searchtable.attach(hbox, 1, 2, 1, 2)

            self._searchmenu = None
            self._searchname = gtk.RadioButton(None, _("Automatic"))
            self._searchname.set_active(True)
            self._searchname.connect("clicked", lambda x: self.refreshPackages())
            self._searchname.show()
            hbox.pack_start(self._searchname, False)
            self._searchdesc = gtk.RadioButton(self._searchname, _("Description"))
            self._searchdesc.connect("clicked", lambda x: self.refreshPackages())
            self._searchdesc.show()
            hbox.pack_start(self._searchdesc, False)

        # Packages and information

        self._hpaned = gtk.HPaned()
        self._hpaned.show()
        self._topvbox.pack_start(self._hpaned)

        scrollwin = gtk.ScrolledWindow()
        scrollwin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        scrollwin.set_shadow_type(gtk.SHADOW_IN)
        self._hpaned.pack1(scrollwin, True)

        self._pg = gtk.TreeView()
        def group_selected(treeview):
            self.refreshPackages()
        self._pg.connect("cursor_changed", group_selected)
        self._pg.show()
        scrollwin.add(self._pg)

        selection = self._pg.get_selection()
        selection.set_mode(gtk.SELECTION_MULTIPLE)

        renderer = gtk.CellRendererText()
        column = gtk.TreeViewColumn(_("Group"), renderer, text=1)
        self._pg.append_column(column)

        self._vpaned = gtk.VPaned()
        self._vpaned.show()
        self._hpaned.pack2(self._vpaned, True)

        self._pv = GtkPackageView()
        self._pv.show()
        self._vpaned.pack1(self._pv, True)

        self._pi = GtkPackageInfo()
        self._pi.show()
        self._pv.connect("package_selected",
                         lambda x, y: self._pi.setPackage(y))
        self._pv.connect("package_activated",
                         lambda x, y: self.actOnPackages(y))
        self._pv.connect("package_popup", self.packagePopup)
        self._vpaned.pack2(self._pi, False)

        self._status = gtk.Statusbar()
        self._status.show()
        self._topvbox.pack_start(self._status, False)
        
        self._legend = GtkLegend()

    def showStatus(self, msg):
        self._status.pop(0)
        self._status.push(0, msg)
        while gtk.events_pending():
            gtk.main_iteration()

    def hideStatus(self):
        self._status.pop(0)
        while gtk.events_pending():
            gtk.main_iteration()

    def run(self, command=None, argv=None):
        self.setCatchExceptions(True)
        self.loadState()
        self._window.set_icon(getPixbuf("smart"))
        self._window.show()
        self._ctrl.reloadChannels()
        self._changeset = ChangeSet(self._ctrl.getCache())
        self._pi.setChangeSet(self._changeset)
        self._progress.hide()
        self.refreshPackages()
        gtk.main()
        self.saveState()
        self.setCatchExceptions(False)

    # Non-standard interface methods:

    def saveState(self):
        sysconf.set("gtk-size", self._window.get_size())
        #sysconf.set("gtk-position", self._window.get_position())
        sysconf.set("gtk-hpaned-position", self._hpaned.get_position())
        sysconf.set("gtk-vpaned-position", self._vpaned.get_position())

    def loadState(self):
        var = sysconf.get("gtk-size")
        if var is not None:
            self._window.set_size_request(*var)
        #var = sysconf.get("gtk-position")
        #if var is not None:
        #    self._window.move(*var)
        var = sysconf.get("gtk-hpaned-position")
        if var is not None:
            self._hpaned.set_position(var)
        var = sysconf.get("gtk-vpaned-position")
        if var is not None:
            self._vpaned.set_position(var)

    def getChangeSet(self):
        return self._changeset

    def updateSelected(self):
        self.updateChannels(selected=True)

    def updateChannels(self, selected=False, channels=None):
        if self._changeset is None:
            return
        if selected:
            aliases = GtkChannelSelector().show()
            channels = [channel for channel in self._ctrl.getChannels()
                        if channel.getAlias() in aliases]
            if not channels:
                return
        state = self._changeset.getPersistentState()
        self._ctrl.reloadChannels(channels, caching=NEVER)
        self._changeset.setPersistentState(state)
        self.refreshPackages()

    def rebuildCache(self):
        if self._changeset is None:
            return
        state = self._changeset.getPersistentState()
        self._ctrl.reloadChannels()
        self._changeset.setPersistentState(state)
        self.refreshPackages()

    def applyChanges(self, confirm=True):
        transaction = Transaction(self._ctrl.getCache(),
                                  changeset=self._changeset)
        if self._ctrl.commitTransaction(transaction, confirm=confirm):
            del self._undo[:]
            del self._redo[:]
            self._redomenuitem.set_property("sensitive", False)
            self._undomenuitem.set_property("sensitive", False)
            self._changeset.clear()
            self._ctrl.reloadChannels()
            self.refreshPackages()
            self.changedMarks()
        self._progress.hide()

    def clearChanges(self):
        self.saveUndo()
        self._changeset.clear()
        self.changedMarks()

    def showChanges(self):
        return self._changes.showChangeSet(self._changeset)

    def showLog(self):
        return self._log.show()

    def showLegend(self):
        return self._legend.show()

    def expandPackages(self):
        self._pv.getTreeView().expand_all()

    def collapsePackages(self):
        self._pv.getTreeView().collapse_all()

    def toggleFilter(self, filter):
        if filter in self._filters:
            del self._filters[filter]
        else:
            self._filters[filter] = True
        self.refreshPackages()

    def upgradeAll(self):
        transaction = Transaction(self._ctrl.getCache())
        transaction.setState(self._changeset)
        for pkg in self._ctrl.getCache().getPackages():
            if pkg.installed:
                transaction.enqueue(pkg, UPGRADE)
        transaction.setPolicy(PolicyUpgrade)
        transaction.run()
        changeset = transaction.getChangeSet()
        if changeset != self._changeset:
            if self.confirmChange(self._changeset, changeset):
                self.saveUndo()
                emptychangeset = not self._changeset
                self._changeset.setState(changeset)
                self.changedMarks()
                if self.askYesNo(_("Apply marked changes now?"), True):
                    self.applyChanges(confirm=not emptychangeset)
        else:
            self.showStatus(_("No interesting upgrades available!"))

    def removeAuto(self):
        changeset = self._ctrl.markAndSweep()
        if changeset != self._changeset:
            if self.confirmChange(self._changeset, changeset):
                self.saveUndo()
                self._changeset.setState(changeset)
                self.changedMarks()
                self.applyChanges(confirm=True)
        else:
            self.showStatus(_("No automatic removals possible!"))

    def actOnPackages(self, pkgs, op=None):
        cache = self._ctrl.getCache()
        transaction = Transaction(cache, policy=PolicyInstall)
        transaction.setState(self._changeset)
        changeset = transaction.getChangeSet()
        if op is None:
            if not [pkg for pkg in pkgs if pkg not in changeset]:
                op = KEEP
            else:
                for pkg in pkgs:
                    if not pkg.installed:
                        op = INSTALL
                        break
                else:
                    op = REMOVE
        if op is REMOVE:
            transaction.setPolicy(PolicyRemove)
        policy = transaction.getPolicy()
        for pkg in pkgs:
            if op is KEEP:
                transaction.enqueue(pkg, op)
            elif op in (REMOVE, REINSTALL, FIX):
                if pkg.installed:
                    transaction.enqueue(pkg, op)
                    if op is REMOVE:
                        for _pkg in cache.getPackages(pkg.name):
                            if not _pkg.installed:
                                policy.setLocked(_pkg, True)
            elif op is INSTALL:
                if not pkg.installed:
                    transaction.enqueue(pkg, op)
        transaction.run()
        if op is FIX:
            expected = 0
        else:
            expected = 1
        if self.confirmChange(self._changeset, changeset, expected):
            self.saveUndo()
            self._changeset.setState(changeset)
            self.changedMarks()

    def lockPackages(self, pkgs, lock):
        if not lock:
             for pkg in pkgs:
                  pkgconf.clearFlag("lock", pkg.name, "=", pkg.version)
             self._pv.queue_draw()
             self._pi.setPackage(pkgs[0])
        else:
             for pkg in pkgs:
                  pkgconf.setFlag("lock", pkg.name, "=", pkg.version)
             self._pv.queue_draw()
             self._pi.setPackage(pkgs[0])

    def lockAllPackages(self, pkgs, lock):
        if not lock:
             for pkg in pkgs:
                  pkgconf.clearFlag("lock", pkg.name)
             self._pv.queue_draw()
             self._pi.setPackage(pkgs[0])
        else:
             for pkg in pkgs:
                  pkgconf.setFlag("lock", pkg.name)
             self._pv.queue_draw()
             self._pi.setPackage(pkgs[0])

    def packagePopup(self, packageview, pkgs, event):

        menu = gtk.Menu()

        hasinstalled = bool([pkg for pkg in pkgs if pkg.installed
                             and self._changeset.get(pkg) is not REMOVE])
        hasnoninstalled = bool([pkg for pkg in pkgs if not pkg.installed
                                and self._changeset.get(pkg) is not INSTALL])

        image = gtk.Image()
        image.set_from_pixbuf(getPixbuf("package-install"))
        item = gtk.ImageMenuItem(_("Install"))
        item.set_image(image)
        item.connect("activate", lambda x: self.actOnPackages(pkgs, INSTALL))
        if not hasnoninstalled:
            item.set_sensitive(False)
        menu.append(item)

        image = gtk.Image()
        image.set_from_pixbuf(getPixbuf("package-reinstall"))
        item = gtk.ImageMenuItem(_("Reinstall"))
        item.set_image(image)
        item.connect("activate", lambda x: self.actOnPackages(pkgs, REINSTALL))
        if not hasinstalled:
            item.set_sensitive(False)
        menu.append(item)


        image = gtk.Image()
        image.set_from_pixbuf(getPixbuf("package-remove"))
        item = gtk.ImageMenuItem(_("Remove"))
        item.set_image(image)
        item.connect("activate", lambda x: self.actOnPackages(pkgs, REMOVE))
        if not hasinstalled:
            item.set_sensitive(False)
        menu.append(item)

        image = gtk.Image()
        if not hasinstalled:
            image.set_from_pixbuf(getPixbuf("package-available"))
        else:
            image.set_from_pixbuf(getPixbuf("package-installed"))
        item = gtk.ImageMenuItem(_("Keep"))
        item.set_image(image)
        item.connect("activate", lambda x: self.actOnPackages(pkgs, KEEP))
        if not [pkg for pkg in pkgs if pkg in self._changeset]:
            item.set_sensitive(False)
        menu.append(item)

        image = gtk.Image()
        image.set_from_pixbuf(getPixbuf("package-broken"))
        item = gtk.ImageMenuItem(_("Fix problems"))
        item.set_image(image)
        item.connect("activate", lambda x: self.actOnPackages(pkgs, FIX))
        if not hasinstalled:
            item.set_sensitive(False)
        menu.append(item)

        inconsistent = False
        thislocked = None
        alllocked = None
        names = pkgconf.getFlagTargets("lock")
        if [pkg for pkg in pkgs if pkg in self._changeset]:
            inconsistent = True
        else:
            for pkg in pkgs:
                if (names and pkg.name in names and 
                    ("=", pkg.version) in names[pkg.name]):
                    newthislocked = True
                    newalllocked = len(names[pkg.name]) > 1
                else:
                    newthislocked = False
                    newalllocked = pkgconf.testFlag("lock", pkg)
                if (thislocked is not None and thislocked != newthislocked or
                    alllocked is not None and alllocked != newalllocked):
                    inconsistent = True
                    break
                thislocked = newthislocked
                alllocked = newalllocked

        image = gtk.Image()
        if thislocked:
            item = gtk.ImageMenuItem(_("Unlock this version"))
            if not hasnoninstalled:
                image.set_from_pixbuf(getPixbuf("package-installed"))
            else:
                image.set_from_pixbuf(getPixbuf("package-available"))
            def unlock_this(x):
                self.lockPackages(pkgs, False)
            item.connect("activate", unlock_this)
        else:
            item = gtk.ImageMenuItem(_("Lock this version"))
            if not hasnoninstalled:
                image.set_from_pixbuf(getPixbuf("package-installed-locked"))
            else:
                image.set_from_pixbuf(getPixbuf("package-available-locked"))
            def lock_this(x):
                self.lockPackages(pkgs, True)
            item.connect("activate", lock_this)
        item.set_image(image)
        if inconsistent:
            item.set_sensitive(False)
        menu.append(item)

        image = gtk.Image()
        if alllocked:
            item = gtk.ImageMenuItem(_("Unlock all versions"))
            if not hasnoninstalled:
                image.set_from_pixbuf(getPixbuf("package-installed"))
            else:
                image.set_from_pixbuf(getPixbuf("package-available"))
            def unlock_all(x):
                self.lockAllPackages(pkgs, False)
            item.connect("activate", unlock_all)
        else:
            item = gtk.ImageMenuItem(_("Lock all versions"))
            if not hasnoninstalled:
                image.set_from_pixbuf(getPixbuf("package-installed-locked"))
            else:
                image.set_from_pixbuf(getPixbuf("package-available-locked"))
            def lock_all(x):
                self.lockAllPackages(pkgs, True)
            item.connect("activate", lock_all)
        item.set_image(image)
        if inconsistent:
            item.set_sensitive(False)
        menu.append(item)

        item = gtk.MenuItem(_("Priority"))
        def priority(x):
            GtkSinglePriority(self._window).show(pkgs[0])
            self._pi.setPackage(pkgs[0])
        item.connect("activate", priority)
        if len(pkgs) != 1:
            item.set_sensitive(False)
        menu.append(item)

        menu.show_all()
        menu.popup(None, None, None, event.button, event.time)

    def checkPackages(self, all=False, uninstalled=False):
        installed = not uninstalled
        available = all or uninstalled
        self.info(_("Checking relations..."))
        if checkPackagesSimple(self._ctrl.getCache(), report=True,
                               installed=installed, available=available):
            self.info(_("All checked packages have correct relations."))

    def fixAllProblems(self):
        self.actOnPackages([pkg for pkg in self._ctrl.getCache().getPackages()
                            if pkg.installed], FIX)

    def undo(self):
        if self._undo:
            state = self._undo.pop(0)
            if not self._undo:
                self._undomenuitem.set_property("sensitive", False)
            self._redo.insert(0, self._changeset.getPersistentState())
            self._redomenuitem.set_property("sensitive", True)
            self._changeset.setPersistentState(state)
            self.changedMarks()

    def redo(self):
        if self._redo:
            state = self._redo.pop(0)
            if not self._redo:
                self._redomenuitem.set_property("sensitive", False)
            self._undo.insert(0, self._changeset.getPersistentState())
            self._undomenuitem.set_property("sensitive", True)
            self._changeset.setPersistentState(state)
            self.changedMarks()

    def saveUndo(self):
        self._undo.insert(0, self._changeset.getPersistentState())
        del self._redo[:]
        del self._undo[20:]
        self._undomenuitem.set_property("sensitive", True)
        self._redomenuitem.set_property("sensitive", False)

    def setTreeStyle(self, mode):
        if mode != sysconf.get("package-tree"):
            if not sysconf.getReadOnly():
                sysconf.set("package-tree", mode)
            else:
                sysconf.set("package-tree", mode, weak=True)
            self.refreshPackages()

    def editChannels(self):
        if GtkChannels(self._window).show():
            self.rebuildCache()

    def editMirrors(self):
        GtkMirrors(self._window).show()

    def editFlags(self):
        GtkFlags(self._window).show()

    def editPriorities(self):
        GtkPriorities(self._window).show()

    def editPreferences(self):
        GtkPreferences().show()

    def setBusy(self, flag):
        if flag:
            self._window.window.set_cursor(self._watch)
            while gtk.events_pending():
                gtk.main_iteration()
        else:
            self._window.window.set_cursor(None)

    def changedMarks(self):
        if "hide-unmarked" in self._filters:
            self.refreshPackages()
        else:
            self._pv.queue_draw()
        self._execmenuitem.set_property("sensitive", bool(self._changeset))
        self._clearmenuitem.set_property("sensitive", bool(self._changeset))

    def toggleSearch(self):
        if not isinstance(self._searchbar, gtk.ToolItem):
            visible = not self._searchbar.get_property('visible')
            self._searchbar.set_property('visible', visible)
        else:
            # always show the ToolItem
            visible = True
        self.refreshPackages()
        if visible:
            self._searchentry.grab_focus()

    def searchFind(self):
        if self._searchentry.get_text() not in self._history:
            text = self._searchentry.get_text()
            self._historypos = len(self._history) - 1
            self._history[self._historypos] = text
            self._historypos = self._historypos + 1
            self._history.append("")
        self.refreshPackages()

    def searchClear(self):
        self._historypos = len(self._history)
        self._searchentry.set_text("")
        self.refreshPackages()

    def searchKeyPress(self, widget, event):
        if event.keyval == gtk.keysyms.Up:
            if self._historypos > 0:
                self._historypos = self._historypos - 1
                text = self._history[self._historypos]
                self._searchentry.set_text(text)
            return True
        elif event.keyval == gtk.keysyms.Down:
            if self._historypos < len(self._history) - 1:
                self._historypos = self._historypos + 1
                text = self._history[self._historypos]
                self._searchentry.set_text(text)
            return True
        return False

    def refreshPackages(self):
        if not self._ctrl:
            return

        self.setBusy(True)

        tree = sysconf.get("package-tree", "groups")
        ctrl = self._ctrl
        changeset = self._changeset

        self._pg.parent.set_property('visible', tree == "separate-groups")
        if self._pg.get_property('visible'):
            model = self._pg.get_model()
            if not model:
                packages = ctrl.getCache().getPackages()
                packagegroups = {}
                for pkg in packages:
                    for loader in pkg.loaders:
                        info = loader.getInfo(pkg)
                        group = info.getGroup()
                        if group in packagegroups:
                            packagegroups[group] += 1
                        else:
                            packagegroups[group] = 1

                groups = []
                names = {}
                all = "%s (%d)" % (_("All"), len(packages))
                for group, count in packagegroups.iteritems():
                     displayicon = None
                     displayname = "%s (%d)" % (group, count)
                     groups.append(displayname)
                     names[displayname] = group
                groups.sort()
                    
                model = gtk.ListStore(gobject.TYPE_STRING,
                                      gobject.TYPE_STRING)
                self._pg.set_model(model)
                iter = model.append()
                model.set(iter, 0, None)
                model.set(iter, 1, all)
                self._pg.get_selection().select_iter(iter)
                for group in groups:
                    iter = model.append()
                    model.set(iter, 0, names[group])
                    model.set(iter, 1, group)
                self._pg.queue_draw()

        columns = sysconf.get("package-columns", "name,version")
        self._pv.setVisibleColumns(columns.split(","))

        if self._searchbar.get_property("visible"):

            searcher = Searcher()
            dosearch = False
            if self._searchdesc.get_active():
                text = self._searchentry.get_text().strip()
                if text:
                    dosearch = True
                    searcher.addDescription(text)
                    searcher.addSummary(text)
            else:
                try:
                    tokens = shlex.split(self._searchentry.get_text())
                except ValueError:
                    pass
                else:
                    if tokens:
                        dosearch = True
                        for tok in tokens:
                            if searcher.hasAutoMeaning(tok):
                                searcher.addAuto(tok)
                            else:
                                searcher.addNameVersion("*%s*" % tok)

            packages = []
            if dosearch:
                self._ctrl.getCache().search(searcher)
                for ratio, obj in searcher.getResults():
                    if isinstance(obj, Package):
                        packages.append(obj)
                    else:
                        packages.extend(obj.packages)
            elif isinstance(self._searchbar, gtk.ToolItem):
                packages = ctrl.getCache().getPackages()
        else:
            packages = ctrl.getCache().getPackages()

        filters = self._filters
        if filters:
            if "hide-non-upgrades" in filters:
                newpackages = {}
                for pkg in packages:
                    if pkg.installed:
                        upgpkgs = {}
                        try:
                            for prv in pkg.provides:
                                for upg in prv.upgradedby:
                                    for upgpkg in upg.packages:
                                        if upgpkg.installed:
                                            raise StopIteration
                                        upgpkgs[upgpkg] = True
                        except StopIteration:
                            pass
                        else:
                            newpackages.update(upgpkgs)
                packages = newpackages.keys()
            if "hide-non-newest" in filters:
                newest = {}
                for pkg in packages:
                    if pkg.name in newest:
                        if pkg > newest[pkg.name]:
                            newest[pkg.name] = pkg
                    else:
                        newest[pkg.name] = pkg
                packages = [pkg for pkg in packages if pkg == newest[pkg.name]]
            if "hide-uninstalled" in filters:
                packages = [x for x in packages if x.installed]
            if "hide-unmarked" in filters:
                packages = [x for x in packages if x in changeset]
            if "hide-installed" in filters:
                packages = [x for x in packages if not x.installed]
            if "hide-unlocked" in filters:
                packages = pkgconf.filterByFlag("lock", packages)
            if "hide-requested" in filters:
                packages = pkgconf.filterByFlag("auto", packages)
            if "hide-old" in filters:
                packages = pkgconf.filterByFlag("new", packages)

        if tree == "groups":
            groups = {}
            done = {}
            for pkg in packages:
                lastgroup = None
                for loader in pkg.loaders:
                    info = loader.getInfo(pkg)
                    group = info.getGroup()
                    donetuple = (group, pkg)
                    if donetuple not in done:
                        done[donetuple] = True
                        if group in groups:
                            groups[group].append(pkg)
                        else:
                            groups[group] = [pkg]

        elif tree == "separate-groups":
            showgroups = {}
            selection = self._pg.get_selection()
            model, paths = selection.get_selected_rows()
            for path in paths:
                iter = model.get_iter(path)
                value = model.get_value(iter, 0)
                showgroups[value] = True
            if showgroups and None not in showgroups:
                newpackages = []
                done = {}
                for pkg in packages:
                    for loader in pkg.loaders:
                        info = loader.getInfo(pkg)
                        group = info.getGroup()
                        donetuple = (group, pkg)
                        if donetuple not in done:
                            done[donetuple] = True
                            if group in showgroups:
                                newpackages.append(pkg)
                groups = newpackages
            else:
                groups = packages

        elif tree == "channels":
            groups = {}
            done = {}
            for pkg in packages:
                for loader in pkg.loaders:
                    channel = loader.getChannel()
                    group = channel.getName() or channel.getAlias()
                    donetuple = (group, pkg)
                    if donetuple not in done:
                        done[donetuple] = True
                        if group in groups:
                            groups[group].append(pkg)
                        else:
                            groups[group] = [pkg]

        elif tree == "channels-groups":
            groups = {}
            done = {}
            for pkg in packages:
                for loader in pkg.loaders:
                    channel = loader.getChannel()
                    group = channel.getName() or channel.getAlias()
                    subgroup = loader.getInfo(pkg).getGroup()
                    donetuple = (group, subgroup, pkg)
                    if donetuple not in done:
                        done[donetuple] = True
                        if group in groups:
                            if subgroup in groups[group]:
                                groups[group][subgroup].append(pkg)
                            else:
                                groups[group][subgroup] = [pkg]
                        else:
                            groups[group] = {subgroup: [pkg]}

        else:
            groups = packages

        self._pv.setPackages(groups, changeset, keepstate=True)

        packages = ctrl.getCache().getPackages()
        self.showStatus(_("%d packages, %d installed") %
            (len(packages), len([pkg for pkg in packages if pkg.installed])))

        self.setBusy(False)

    def showAbout(widget):
        copyright = "2010 Smart Team, 2006 Canonical Ltd., 2004 Conectiva, Inc."
        license = """
            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; either version 2 of the License, or
            (at your option) any later version.

            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 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.
            """
        credits=["""Gustavo Niemeyer - Original author and lead developer.""",
           u"""Anders F Bj\u00f6rklund - Current maintainer and developer.""",
            """Conectiva Inc. - Original project funder up to August 2005.""",
            """Canonical Ltd. - Funding Smart up to November of 2009.""",
            """Unity Linux - Smart development and deployment support.""",
            """And many others - Check our website for the complete list.""",
            ]
        website = "http://smartpm.org/"

        if gtk.pygtk_version < (2,6,0):
             dialog = gtk.MessageDialog(buttons=gtk.BUTTONS_CLOSE)
             dialog.set_markup("<b>Smart Package Manager %s</b>\n"
                               "<small>(C) %s</small>\n" % (VERSION, copyright) +
                               "<small>%s</small>\n" % license.replace(" " * 12, "") +
                               "<span>%s</span>\n" % "\n".join(credits) +
                               "\n<tt>%s</tt>" % website)
             dialog.run()
             dialog.destroy()
             return

        aboutdialog = gtk.AboutDialog()
        aboutdialog.set_name("Smart Package Manager")
        aboutdialog.set_version(VERSION)
        aboutdialog.set_copyright(copyright)
        aboutdialog.set_authors(credits)
        aboutdialog.set_license(license)
        aboutdialog.set_website(website)
        aboutdialog.run()
        aboutdialog.destroy()