class QtInteractiveInterface(QtInterface): def __init__(self, ctrl, argv=None): QtInterface.__init__(self, ctrl, argv) self._changeset = None self._window = QtGui.QMainWindow() self._window.setWindowTitle("Smart Package Manager %s" % VERSION) centerWindow(self._window) self._window.setMinimumSize(640, 480) app.connect(app, QtCore.SIGNAL('lastWindowClosed()'), app, QtCore.SLOT('quit()')) self._undo = [] self._redo = [] globals = {"self": self, "QtGui": QtGui, "QtCore": QtCore} #group = QtGui.QActionGroup(self._window, "Actions") group = QtGui.QActionGroup(self._window) self._actions = compileActions(group, ACTIONS, globals) class ToggleAction(QtGui.QAction): def __init__(self, group, name, label): QtGui.QAction.__init__(self, name, group) #self.setToggleAction(True) self.setCheckable(True) self.setText(label.replace("&","&&")) self._name = name def connect(self, signal, callback, userdata): self._callback = callback self._userdata = userdata QtCore.QObject.connect(self, QtCore.SIGNAL(signal), self.slot) def slot(self): self._callback(self._userdata) 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-unlocked", _("Hide Unlocked")), ("hide-requested", _("Hide Requested")), ("hide-old", _("Hide Old"))]: act = ToggleAction(None, name, label) act.connect("activated()", self.toggleFilter, name) self._actions[name] = act treestyle = sysconf.get("package-tree") for name, label in [("groups", _("Groups")), ("channels", _("Channels")), ("channels-groups", _("Channels & Groups")), ("none", _("None"))]: act = ToggleAction(group, "tree-style-"+name, label) if name == treestyle: act.setChecked(True) act.connect("activated()", self.setTreeStyle, name) self._actions["tree-style-"+name] = act self._menubar = self._window.menuBar() for MENU in MENUBAR: def insertmenu(menubar, menu): item = menu[0] action = self._actions[item] m = QtGui.QMenu(menubar) m.setTitle(action.text()) menubar.addMenu(m) for item in menu[1]: if isinstance(item, tuple): insertmenu(m, item) elif item: action = self._actions[item] #i = QtGui.QPopupMenu(m) i = QtGui.QMenu(m) #text = action.menuText() i.setTitle(action.text()) #m.insertItem(text, i) #action.addTo(m) m.addAction(action) else: m.addSeparator() insertmenu(self._menubar, MENU) self._toolbar = QtGui.QToolBar(self._window) for TOOL in TOOLBAR: def inserttool(toolbar, tool): if tool: action = self._actions[tool] pixmap = getPixmap(TOOLBARICONS[tool]) action.setIcon(QtGui.QIcon(pixmap)) toolbar.addAction(action) else: toolbar.addSeparator() inserttool(self._toolbar, TOOL) self._window.addToolBar( self._toolbar) #self._window.add_accel_group(self._ui.get_accel_group()) self._actions["exec-changes"].setShortcut(QtGui.QKeySequence("Ctrl+C")) self._actions["find"].setShortcut(QtGui.QKeySequence("Ctrl+F")) self._actions["expand-all"].setShortcut(QtGui.QKeySequence("Ctrl+O")) self._actions["collapse-all"].setShortcut(QtGui.QKeySequence("Ctrl+W")) self._actions["summary-window"].setShortcut(QtGui.QKeySequence("Ctrl+S")) self._actions["exec-changes"].setEnabled(False) self._actions["clear-changes"].setEnabled(False) self._actions["undo"].setEnabled(False) self._actions["redo"].setEnabled(False) # Search bar self._searchbar = QtGui.QToolBar(self._window) self._searchbar.hide() self._window.addToolBar(self._searchbar) label = QtGui.QLabel(_("Search:"), self._searchbar) label.show() self._searchbar.addWidget(label) self._searchentry = QtGui.QLineEdit(self._searchbar) QtCore.QObject.connect(self._searchentry, QtCore.SIGNAL("returnPressed()"), self.refreshPackages) self._searchentry.show() self._searchbar.addWidget(self._searchentry) button = QtGui.QPushButton(self._searchbar) QtCore.QObject.connect(button, QtCore.SIGNAL("clicked()"), self.refreshPackages) pixmap = getPixmap("crystal-search") button.setIcon(QtGui.QIcon(pixmap)) button.show() self._searchbar.addWidget(button) buttongroup = QtGui.QButtonGroup(self._searchbar) #buttongroup.hide() self._searchname = QtGui.QRadioButton(_("Automatic"), self._searchbar) self._searchname.setChecked(True) QtCore.QObject.connect(self._searchname, QtCore.SIGNAL("clicked()"), self.refreshPackages) buttongroup.addButton(self._searchname) self._searchbar.addWidget(self._searchname) self._searchname.show() self._searchdesc = QtGui.QRadioButton(_("Description"), self._searchbar) self._searchdesc.setChecked(False) QtCore.QObject.connect(self._searchdesc, QtCore.SIGNAL("clicked()"), self.refreshPackages) self._searchdesc.show() buttongroup.addButton(self._searchdesc) self._searchbar.addWidget(self._searchdesc) # Packages and information self._splitter = QtGui.QSplitter(QtCore.Qt.Vertical, self._window) self._window.setCentralWidget(self._splitter) self._pv = QtPackageView(self._splitter) self._pv.show() self._pi = QtPackageInfo(self._splitter) self._pi.show() QtCore.QObject.connect(self._pv, QtCore.SIGNAL("packageSelected"), self._pi.setPackage) QtCore.QObject.connect(self._pv, QtCore.SIGNAL("packageActivated"), self.actOnPackages) QtCore.QObject.connect(self._pv, QtCore.SIGNAL("packagePopup"), self.packagePopup) self._status = self._window.statusBar() self._status.show() self._legend = QtLegend(self._window) def showStatus(self, msg): self._status.showMessage(msg) def hideStatus(self): self._status.clearMessage() def run(self, command=None, argv=None): self.setCatchExceptions(True) self.loadState() self._window.setWindowIcon(QtGui.QIcon(getPixmap("smart"))) self._window.show() self._ctrl.reloadChannels() self._changeset = ChangeSet(self._ctrl.getCache()) self._pi.setChangeSet(self._changeset) self._progress.hide() self.refreshPackages() app.exec_() self.saveState() self.setCatchExceptions(False) # Non-standard interface methods: def saveState(self): # Note: QtCore.QSize and QtCore.QPoint are not pickleable, unfortunately sysconf.set("qt-size", (self._window.width(),self._window.height())) sysconf.set("qt-position", (self._window.x(),self._window.y())) sysconf.set("qt-splitter-sizes", self._splitter.sizes()) def loadState(self): var = sysconf.get("qt-size") if var is not None: self._window.resize(*var) var = sysconf.get("qt-position") if var is not None: self._window.move(*var) var = sysconf.get("qt-splitter-sizes") if var is not None: self._splitter.setSizes(var) def getChangeSet(self): return self._changeset def selectedChannels(self): self.updateChannels(selected=True) def allChannels(self): self.updateChannels(selected=False) def updateChannels(self, selected=False, channels=None): if selected: aliases = QtChannelSelector().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._actions["redo"].setEnabled(False) self._actions["undo"].setEnabled(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.expandAll() def collapsePackages(self): self._pv.collapseAll() 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(pkgs) def lockPackages(self, pkgs, lock): if not lock: for pkg in pkgs: pkgconf.clearFlag("lock", pkg.name, "=", pkg.version) self._pv.update() self._pi.setPackage(pkgs[0]) else: for pkg in pkgs: pkgconf.setFlag("lock", pkg.name, "=", pkg.version) self._pv.update() self._pi.setPackage(pkgs[0]) def lockAllPackages(self, pkgs, lock): if not lock: for pkg in pkgs: pkgconf.clearFlag("lock", pkg.name) self._pv.update() self._pi.setPackage(pkgs[0]) else: for pkg in pkgs: pkgconf.setFlag("lock", pkg.name) self._pv.update() self._pi.setPackage(pkgs[0]) def priorityPackages(self, pkgs, none): QtSinglePriority(self._window).show(pkgs[0]) self._pi.setPackage(pkgs[0]) def packagePopup(self, packageview, pkgs, pnt): menu = QtGui.QMenu(packageview) menu.move(pnt) 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]) class PackagesAction(object): def __init__(self, pkgs): self._pkgs = pkgs self._callback = None self._userdata = None def connect(self, item, callback, userdata=None): self._callback = callback self._userdata = userdata def slot(self): self._callback(self._pkgs, self._userdata) installaction = PackagesAction(pkgs) iconset = QtGui.QIcon(getPixmap("package-install")) item = menu.addAction(iconset, _("Install"), installaction.slot) installaction.connect(item, self.actOnPackages, INSTALL) if not hasnoninstalled: item.setEnabled(False) reinstallaction = PackagesAction(pkgs) iconset = QtGui.QIcon(getPixmap("package-reinstall")) item = menu.addAction(iconset, _("Reinstall"), reinstallaction.slot) reinstallaction.connect(item, self.actOnPackages, REINSTALL) if not hasinstalled: item.setEnabled(False) removeaction = PackagesAction(pkgs) iconset = QtGui.QIcon(getPixmap("package-remove")) item = menu.addAction(iconset, _("Remove"), removeaction.slot) removeaction.connect(item, self.actOnPackages, REMOVE) if not hasinstalled: item.setEnabled(False) keepaction = PackagesAction(pkgs) if not hasinstalled: iconset = QtGui.QIcon(getPixmap("package-available")) else: iconset = QtGui.QIcon(getPixmap("package-installed")) item = menu.addAction(iconset, _("Keep"), keepaction.slot) keepaction.connect(item, self.actOnPackages, KEEP) if not [pkg for pkg in pkgs if pkg in self._changeset]: item.setEnabled(False) fixaction = PackagesAction(pkgs) iconset = QtGui.QIcon(getPixmap("package-broken")) item = menu.addAction(iconset, _("Fix problems"), fixaction.slot) fixaction.connect(item, self.actOnPackages, FIX) if not hasinstalled: item.setEnabled(False) 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 lockaction = PackagesAction(pkgs) if thislocked: if not hasnoninstalled: iconset = QtGui.QIcon(getPixmap("package-installed")) else: iconset = QtGui.QIcon(getPixmap("package-available")) item = menu.addAction(iconset, _("Unlock this version"), lockaction.slot) lockaction.connect(item, self.lockPackages, False) else: if not hasnoninstalled: iconset = QtGui.QIcon(getPixmap("package-installed-locked")) else: iconset = QtGui.QIcon(getPixmap("package-available-locked")) item = menu.addAction(iconset, _("Lock this version"), lockaction.slot) lockaction.connect(item, self.lockPackages, True) if inconsistent: item.setEnabled(False) lockallaction = PackagesAction(pkgs) if alllocked: if not hasnoninstalled: iconset = QtGui.QIcon(getPixmap("package-installed")) else: iconset = QtGui.QIcon(getPixmap("package-available")) item = menu.addAction(iconset, _("Unlock all versions"), lockallaction.slot) lockallaction.connect(item, self.lockAllPackages, False) else: if not hasnoninstalled: iconset = QtGui.QIcon(getPixmap("package-installed-locked")) else: iconset = QtGui.QIcon(getPixmap("package-available-locked")) item = menu.addAction(iconset, _("Lock all versions"), lockallaction.slot) lockallaction.connect(item, self.lockAllPackages, True) if inconsistent: item.setEnabled(False) priorityaction = PackagesAction(pkgs) item = menu.addAction(_("Priority"), priorityaction.slot) priorityaction.connect(item, self.priorityPackages) if len(pkgs) != 1: item.setEnabled(False) menu.show() menu.exec_(packageview.mapToGlobal(pnt)) 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._actions["undo"].setEnabled(False) self._redo.insert(0, self._changeset.getPersistentState()) self._actions["redo"].setEnabled(True) self._changeset.setPersistentState(state) self.changedMarks() def redo(self): if self._redo: state = self._redo.pop(0) if not self._redo: self._actions["redo"].setEnabled(False) self._undo.insert(0, self._changeset.getPersistentState()) self._actions["undo"].setEnabled(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._actions["undo"].setEnabled(True) self._actions["redo"].setEnabled(False) def setTreeStyle(self, mode): if mode != sysconf.get("package-tree"): sysconf.set("package-tree", mode) self.refreshPackages() def editChannels(self): if QtChannels(self._window).show(): self.rebuildCache() def editMirrors(self): QtMirrors(self._window).show() def editFlags(self): QtFlags(self._window).show() def editPriorities(self): QtPriorities(self._window).show() def setBusy(self, flag): if flag: QtGui.QApplication.setOverrideCursor( QtGui.QCursor(QtCore.Qt.WaitCursor) ) #while QtGui.QApplication.eventLoop().hasPendingEvents(): # QtGui.QApplication.eventLoop().processEvents(QtGui.QEventLoop.AllEvents) else: QtGui.QApplication.restoreOverrideCursor() def changedMarks(self, pkgs=[]): if "hide-unmarked" in self._filters: self.refreshPackages() else: self._pv.updatePackages(pkgs, self._changeset) self._pv.update() self._actions["exec-changes"].setEnabled(bool(self._changeset)) self._actions["clear-changes"].setEnabled(bool(self._changeset)) def toggleSearch(self): visible = not self._searchentry.isVisible() if visible: self._searchbar.show() else: self._searchbar.hide() self.refreshPackages() if visible: self._searchentry.setFocus() 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.isVisible() and \ self._searchentry.text(): # temporary searcher = Searcher() dosearch = False if self._searchdesc.isChecked(): text = self._searchentry.text() if text: text = str(text).strip() dosearch = True searcher.addDescription(text) searcher.addSummary(text) else: try: text = self._searchentry.text() tokens = shlex.split(str(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-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 == "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(self): copyright = "2010-2014 Smart PM 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. - Funded 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.github.io/smart" QtGui.QMessageBox.about(self._window, "About " + "Smart Package Manager", "<h2>" + "Smart Package Manager" + " " + VERSION + "</h2>" + \ "<p>Copyright © " + copyright + \ "<p><small>" + license + "</small>" + \ "<p><h3>Credits</h3>" + "<br>".join(credits) + \ "<p><a href=\""+website+"\">"+website+"</a>")
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()
class QtInteractiveInterface(QtInterface): def __init__(self, ctrl, argv=None): QtInterface.__init__(self, ctrl, argv) self._changeset = None self._window = qt.QMainWindow() self._window.setCaption("Smart Package Manager %s" % VERSION) centerWindow(self._window) self._window.setMinimumSize(640, 480) app.connect(app, qt.SIGNAL('lastWindowClosed()'), app, qt.SLOT('quit()')) self._undo = [] self._redo = [] globals = {"self": self, "qt": qt} group = qt.QActionGroup(self._window, "Actions") self._actions = compileActions(group, ACTIONS, globals) class ToggleAction(qt.QAction): def __init__(self, group, name, label): qt.QAction.__init__(self, group, name) self.setToggleAction(True) self.setMenuText(label.replace("&","&&")) self._name = name def connect(self, signal, callback, userdata): self._callback = callback self._userdata = userdata qt.QObject.connect(self, qt.SIGNAL(signal), self.slot) def slot(self): self._callback(self._userdata) 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-unlocked", _("Hide Unlocked")), ("hide-requested", _("Hide Requested")), ("hide-old", _("Hide Old"))]: act = ToggleAction(None, name, label) act.connect("activated()", self.toggleFilter, name) self._actions[name] = act treestyle = sysconf.get("package-tree") for name, label in [("groups", _("Groups")), ("channels", _("Channels")), ("channels-groups", _("Channels & Groups")), ("none", _("None"))]: act = ToggleAction(group, "tree-style-"+name, label) if name == treestyle: act.setOn(True) act.connect("activated()", self.setTreeStyle, name) self._actions["tree-style-"+name] = act self._menubar = self._window.menuBar() for MENU in MENUBAR: def insertmenu(menubar, menu): item = menu[0] action = self._actions[item] m = qt.QPopupMenu(menubar) text = action.menuText() menubar.insertItem(text, m) for item in menu[1]: if isinstance(item, tuple): insertmenu(m, item) elif item: action = self._actions[item] #i = qt.QPopupMenu(m) #text = action.menuText() #m.insertItem(text, i) action.addTo(m) else: m.insertSeparator() insertmenu(self._menubar, MENU) self._toolbar = qt.QToolBar(self._window) for TOOL in TOOLBAR: def inserttool(toolbar, tool): if tool: action = self._actions[tool] #b = qt.QToolButton(toolbar, TOOL) #b.setTextLabel(action.toolTip()) pixmap = getPixmap(TOOLBARICONS[tool]) #b.setIconSet(qt.QIconSet(pixmap)) action.setIconSet(qt.QIconSet(pixmap)) action.addTo(toolbar) else: toolbar.addSeparator() inserttool(self._toolbar, TOOL) #self._window.add_accel_group(self._ui.get_accel_group()) self._actions["exec-changes"].setAccel(qt.QKeySequence("Ctrl+C")) self._actions["find"].setAccel(qt.QKeySequence("Ctrl+F")) self._actions["expand-all"].setAccel(qt.QKeySequence("Ctrl+O")) self._actions["collapse-all"].setAccel(qt.QKeySequence("Ctrl+W")) self._actions["summary-window"].setAccel(qt.QKeySequence("Ctrl+S")) self._actions["exec-changes"].setEnabled(False) self._actions["clear-changes"].setEnabled(False) self._actions["undo"].setEnabled(False) self._actions["redo"].setEnabled(False) # Search bar self._searchbar = qt.QToolBar(self._window) self._searchbar.hide() label = qt.QLabel(_("Search:"), self._searchbar) label.show() self._searchentry = qt.QLineEdit(self._searchbar) qt.QObject.connect(self._searchentry, qt.SIGNAL("returnPressed()"), self.refreshPackages) self._searchentry.show() button = qt.QPushButton(self._searchbar) qt.QObject.connect(button, qt.SIGNAL("clicked()"), self.refreshPackages) pixmap = getPixmap("crystal-search") button.setIconSet(qt.QIconSet(pixmap)) button.show() buttongroup = qt.QButtonGroup(self._searchbar) buttongroup.hide() self._searchname = qt.QRadioButton(_("Automatic"), self._searchbar) self._searchname.setChecked(True) qt.QObject.connect(self._searchname, qt.SIGNAL("clicked()"), self.refreshPackages) buttongroup.insert(self._searchname) self._searchname.show() self._searchdesc = qt.QRadioButton(_("Description"), self._searchbar) self._searchdesc.setChecked(False) qt.QObject.connect(self._searchdesc, qt.SIGNAL("clicked()"), self.refreshPackages) self._searchdesc.show() buttongroup.insert(self._searchdesc) # Packages and information self._splitter = qt.QSplitter(qt.Qt.Vertical, self._window) self._window.setCentralWidget(self._splitter) self._pv = QtPackageView(self._splitter) self._pv.show() self._pi = QtPackageInfo(self._splitter) self._pi.show() qt.QObject.connect(self._pv, qt.PYSIGNAL("packageSelected"), self._pi.setPackage) qt.QObject.connect(self._pv, qt.PYSIGNAL("packageActivated"), self.actOnPackages) qt.QObject.connect(self._pv, qt.PYSIGNAL("packagePopup"), self.packagePopup) self._status = self._window.statusBar() self._status.show() self._legend = QtLegend(self._window) def showStatus(self, msg): self._status.message(msg) def hideStatus(self): self._status.clear() def run(self, command=None, argv=None): self.setCatchExceptions(True) self.loadState() self._window.setIcon(getPixmap("smart")) self._window.show() self._ctrl.reloadChannels() self._changeset = ChangeSet(self._ctrl.getCache()) self._pi.setChangeSet(self._changeset) self._progress.hide() self.refreshPackages() app.exec_loop() self.saveState() self.setCatchExceptions(False) # Non-standard interface methods: def saveState(self): # Note: qt.QSize and qt.QPoint are not pickleable, unfortunately sysconf.set("qt-size", (self._window.width(),self._window.height())) sysconf.set("qt-position", (self._window.x(),self._window.y())) sysconf.set("qt-splitter-sizes", self._splitter.sizes()) def loadState(self): var = sysconf.get("qt-size") if var is not None: self._window.resize(*var) var = sysconf.get("qt-position") if var is not None: self._window.move(*var) var = sysconf.get("qt-splitter-sizes") if var is not None: self._splitter.setSizes(var) def getChangeSet(self): return self._changeset def updateSelected(self): self.updateChannels(selected=True) def updateChannels(self, selected=False, channels=None): if selected: aliases = QtChannelSelector().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._actions["redo"].setEnabled(False) self._actions["undo"].setEnabled(False) pkgs = self._changeset.copy() self._changeset.clear() self._ctrl.reloadChannels() self.refreshPackages() self.changedMarks(pkgs) self._progress.hide() def clearChanges(self): self.saveUndo() pkgs = self._changeset.copy() self._changeset.clear() self.changedMarks(pkgs) 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.expandAll() def collapsePackages(self): self._pv.collapseAll() 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) pkgs.extend(changeset) self.changedMarks(pkgs) def lockPackages(self, pkgs, lock): if not lock: for pkg in pkgs: pkgconf.clearFlag("lock", pkg.name, "=", pkg.version) self._pv.updatePackages(pkgs) self._pv.update() self._pi.setPackage(pkgs[0]) else: for pkg in pkgs: pkgconf.setFlag("lock", pkg.name, "=", pkg.version) self._pv.updatePackages(pkgs) self._pv.update() self._pi.setPackage(pkgs[0]) def lockAllPackages(self, pkgs, lock): if not lock: for pkg in pkgs: pkgconf.clearFlag("lock", pkg.name) self._pv.updatePackages(pkgs) self._pv.update() self._pi.setPackage(pkgs[0]) else: for pkg in pkgs: pkgconf.setFlag("lock", pkg.name) self._pv.updatePackages(pkgs) self._pv.update() self._pi.setPackage(pkgs[0]) def priorityPackages(self, pkgs, none): QtSinglePriority(self._window).show(pkgs[0]) self._pi.setPackage(pkgs[0]) def packagePopup(self, packageview, pkgs, pnt): menu = qt.QPopupMenu(packageview) menu.move(pnt) 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]) class PackagesAction(object): def __init__(self, pkgs): self._pkgs = pkgs self._callback = {} self._userdata = {} def connect(self, item, callback, userdata=None): self._callback[item] = callback self._userdata[item] = userdata def slot(self, index): self._callback[index](self._pkgs, self._userdata[index]) action = PackagesAction(pkgs) iconset = qt.QIconSet(getPixmap("package-install")) item = menu.insertItem(iconset, _("Install"), action.slot) action.connect(item, self.actOnPackages, INSTALL) if not hasnoninstalled: menu.setItemEnabled(item, False) iconset = qt.QIconSet(getPixmap("package-reinstall")) item = menu.insertItem(iconset, _("Reinstall"), action.slot) action.connect(item, self.actOnPackages, REINSTALL) if not hasinstalled: menu.setItemEnabled(item, False) iconset = qt.QIconSet(getPixmap("package-remove")) item = menu.insertItem(iconset, _("Remove"), action.slot) action.connect(item, self.actOnPackages, REMOVE) if not hasinstalled: menu.setItemEnabled(item, False) if not hasinstalled: iconset = qt.QIconSet(getPixmap("package-available")) else: iconset = qt.QIconSet(getPixmap("package-installed")) item = menu.insertItem(iconset, _("Keep"), action.slot) action.connect(item, self.actOnPackages, KEEP) if not [pkg for pkg in pkgs if pkg in self._changeset]: menu.setItemEnabled(item, False) iconset = qt.QIconSet(getPixmap("package-broken")) item = menu.insertItem(iconset, _("Fix problems"), action.slot) action.connect(item, self.actOnPackages, FIX) if not hasinstalled: menu.setItemEnabled(item, False) 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 lockaction = PackagesAction(pkgs) if thislocked: if not hasnoninstalled: iconset = qt.QIconSet(getPixmap("package-installed")) else: iconset = qt.QIconSet(getPixmap("package-available")) item = menu.insertItem(iconset, _("Unlock this version"), lockaction.slot) lockaction.connect(item, self.lockPackages, False) else: if not hasnoninstalled: iconset = qt.QIconSet(getPixmap("package-installed-locked")) else: iconset = qt.QIconSet(getPixmap("package-available-locked")) item = menu.insertItem(iconset, _("Lock this version"), lockaction.slot) lockaction.connect(item, self.lockPackages, True) if inconsistent: menu.setItemEnabled(item, False) lockallaction = PackagesAction(pkgs) if alllocked: if not hasnoninstalled: iconset = qt.QIconSet(getPixmap("package-installed")) else: iconset = qt.QIconSet(getPixmap("package-available")) item = menu.insertItem(iconset, _("Unlock all versions"), lockallaction.slot) lockallaction.connect(item, self.lockAllPackages, False) else: if not hasnoninstalled: iconset = qt.QIconSet(getPixmap("package-installed-locked")) else: iconset = qt.QIconSet(getPixmap("package-available-locked")) item = menu.insertItem(iconset, _("Lock all versions"), lockallaction.slot) lockallaction.connect(item, self.lockAllPackages, True) if inconsistent: menu.setItemEnabled(item, False) priorityaction = PackagesAction(pkgs) item = menu.insertItem(_("Priority"), priorityaction.slot) priorityaction.connect(item, self.priorityPackages) if len(pkgs) != 1: menu.setItemEnabled(item, False) menu.show() menu.exec_loop(packageview.mapToGlobal(pnt)) def checkInstalledPackages(self): self.checkPackages() def checkUninstalledPackages(self): self.checkPackages(uninstalled=True) def checkAllPackages(self): self.checkPackages(all=True) 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._actions["undo"].setEnabled(False) self._redo.insert(0, self._changeset.getPersistentState()) self._actions["redo"].setEnabled(True) pkgs = self._changeset.copy() self._changeset.setPersistentState(state) pkgs.update(self._changeset) self.changedMarks(pkgs) def redo(self): if self._redo: state = self._redo.pop(0) if not self._redo: self._actions["redo"].setEnabled(False) self._undo.insert(0, self._changeset.getPersistentState()) self._actions["undo"].setEnabled(True) pkgs = self._changeset.copy() self._changeset.setPersistentState(state) pkgs.update(self._changeset) self.changedMarks(pkgs) def saveUndo(self): self._undo.insert(0, self._changeset.getPersistentState()) del self._redo[:] del self._undo[20:] self._actions["undo"].setEnabled(True) self._actions["redo"].setEnabled(False) def setTreeStyle(self, mode): if mode != sysconf.get("package-tree"): sysconf.set("package-tree", mode) self.refreshPackages() def editChannels(self): if QtChannels(self._window).show(): self.rebuildCache() def editMirrors(self): QtMirrors(self._window).show() def editFlags(self): QtFlags(self._window).show() def editPriorities(self): QtPriorities(self._window).show() def setBusy(self, flag): if flag: qt.QApplication.setOverrideCursor( qt.QCursor(qt.Qt.WaitCursor) ) while qt.QApplication.eventLoop().hasPendingEvents(): qt.QApplication.eventLoop().processEvents(qt.QEventLoop.AllEvents) else: qt.QApplication.restoreOverrideCursor() def changedMarks(self, pkgs=[]): if "hide-unmarked" in self._filters: self.refreshPackages() else: self._pv.updatePackages(pkgs, self._changeset) self._pv.update() self._actions["exec-changes"].setEnabled(bool(self._changeset)) self._actions["clear-changes"].setEnabled(bool(self._changeset)) def toggleSearch(self): visible = not self._searchentry.isVisible() if visible: self._searchbar.show() else: self._searchbar.hide() self.refreshPackages() if visible: self._searchentry.setFocus() 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.isVisible() and \ self._searchentry.text(): # temporary searcher = Searcher() dosearch = False if self._searchdesc.isChecked(): text = self._searchentry.text() if text: text = str(text).strip() dosearch = True searcher.addDescription(text) searcher.addSummary(text) else: try: text = self._searchentry.text() tokens = shlex.split(str(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-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 == "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(self): 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. - Funded 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/" qt.QMessageBox.about(self._window, "About " + "Smart Package Manager", "<h2>" + "Smart Package Manager" + " " + VERSION + "</h2>" + \ "<p>Copyright © " + copyright + \ "<p><small>" + license + "</small>" + \ "<p><h3>Credits</h3>" + "<br>".join(credits) + \ "<p><a href=\""+website+"\">"+website+"</a>")
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)
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()
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()