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)
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 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 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/" 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>")