--- a/PipxInterface/PipxWidget.py Thu Jun 27 17:54:24 2024 +0200 +++ b/PipxInterface/PipxWidget.py Fri Jun 28 16:25:21 2024 +0200 @@ -13,6 +13,7 @@ from PyQt6.QtWidgets import QDialog, QMenu, QTreeWidgetItem, QWidget from eric7.EricGui import EricPixmapCache +from eric7.EricGui.EricOverrideCursor import EricOverrideCursor from eric7.EricWidgets import EricFileDialog, EricMessageBox from .Pipx import Pipx @@ -31,6 +32,8 @@ PythonVersionColumn = 2 AppPathRole = Qt.ItemDataRole.UserRole + VersionRole = Qt.ItemDataRole.UserRole + 1 + LatestVersionRole = Qt.ItemDataRole.UserRole + 2 def __init__(self, plugin, fromEric=True, parent=None): """ @@ -59,10 +62,12 @@ self.pipxMenuButton.setIcon(EricPixmapCache.getIcon("superMenu")) self.refreshButton.setIcon(EricPixmapCache.getIcon("reload")) self.installButton.setIcon(EricPixmapCache.getIcon("plus")) + self.outdatedButton.setIcon(EricPixmapCache.getIcon("question")) self.upgradeButton.setIcon(EricPixmapCache.getIcon("upgrade")) self.uninstallButton.setIcon(EricPixmapCache.getIcon("minus")) self.installButton.clicked.connect(self.__installPackages) + self.outdatedButton.clicked.connect(self.__checkOutdatedPackages) self.upgradeButton.clicked.connect(self.__upgradePackage) self.uninstallButton.clicked.connect(self.__uninstallPackage) @@ -122,6 +127,10 @@ ################################################################### self.__upgradeSubmenu = QMenu(self.tr("Upgrade")) + self.__checkOutdatedPackagesAct = self.__upgradeSubmenu.addAction( + self.tr("Check Outdated Packages"), self.__checkOutdatedPackages + ) + self.__upgradeSubmenu.addSeparator() self.__upgradePackagesAct = self.__upgradeSubmenu.addAction( self.tr("Upgrade Selected Package"), self.__upgradePackage ) @@ -155,6 +164,10 @@ self.__upgradeSubmenuAct = self.__pipxMenu.addMenu(self.__upgradeSubmenu) self.__pipxMenu.addSeparator() self.__uninstallSubmenuAct = self.__pipxMenu.addMenu(self.__uninstallSubmenu) + self.__pipxMenu.addSeparator() + self.__pipxMenu.addAction( + self.tr("Standalone Interpreters"), self.__showInterpreters + ) self.__pipxMenu.aboutToShow.connect(self.__aboutToShowPipxMenu) @@ -310,28 +323,42 @@ self.on_refreshButton_clicked() @pyqtSlot() + def __checkOutdatedPackages(self): + """ + Private slot to check, if there are any outdated packages. + """ + with EricOverrideCursor(): + for row in range(self.packagesList.topLevelItemCount()): + itm = self.packagesList.topLevelItem(row) + package = itm.text(PipxWidget.PackageColumn) + latestVersion = self.__pipx.checkPackageOutdated(package) + if latestVersion is not None: + self.__markPackageOutdated(itm, latestVersion) + self.__resizePackagesColumns() + + @pyqtSlot() def __upgradePackage(self): """ Private slot to upgrade the selected package. """ - # TODO: not implemented yet - pass + package = self.__selectedPackages()[0] + self.__pipx.upgradePackage(package) + self.on_refreshButton_clicked() @pyqtSlot() def __upgradeAllPackages(self): """ Private slot to upgrade all packages. """ - # TODO: not implemented yet - pass + self.__pipx.upgradeAllPackages() + self.on_refreshButton_clicked() @pyqtSlot() def __upgradeSharedLibs(self): """ Private slot to upgrade the shared libraries. """ - # TODO: not implemented yet - pass + self.__pipx.upgradeSharedLibraries() @pyqtSlot() def __uninstallPackage(self): @@ -355,7 +382,6 @@ """ Private slot to uninstall all packages. """ - # TODO: not implemented yet yes = EricMessageBox.yesNo( self, self.tr("Uninstall All Packages"), @@ -367,6 +393,16 @@ self.__pipx.uninstallAllPackages() self.on_refreshButton_clicked() + @pyqtSlot() + def __showInterpreters(self): + """ + Private slot to show a list of standalone Python interpreters. + """ + from .PipxInterpretersDialog import PipxInterpretersDialog + + dlg = PipxInterpretersDialog(self.__pipx, self) + dlg.exec() + ####################################################################### ## Main widget related methods below ####################################################################### @@ -388,6 +424,23 @@ self.packagesList.resizeColumnToContents(PipxWidget.VersionColumn) self.packagesList.resizeColumnToContents(PipxWidget.PythonVersionColumn) + def __markPackageOutdated(self, item, latestVersion): + """ + Private method to mark the given package item as outdated. + + @param item reference to the outdated package item + @type QTreeWidgetItem + @param latestVersion latest version of the package + @type str + """ + version = item.data(0, PipxWidget.VersionRole) + item.setData(0, PipxWidget.LatestVersionRole, latestVersion) + item.setText( + PipxWidget.VersionColumn, + self.tr("{0} ({1})", "current version, latest version") + .format(version, latestVersion), + ) + def __populatePackages(self): """ Private method to populate the packages list. @@ -398,8 +451,17 @@ for package in packages: topItem = QTreeWidgetItem( self.packagesList, - [package["name"], package["version"], package["python"]], + [ + package["name"], + package["version"], + self.tr("{0}{1}", "Python version, standalone indicator") + .format( + package["python"], + self.tr(" (standalone)") if package["is_standalone"] else "", + ), + ], ) + topItem.setData(0, PipxWidget.VersionRole, package["version"]) for app, appPath in package["apps"]: itm = QTreeWidgetItem(topItem, [app]) itm.setData(0, PipxWidget.AppPathRole, appPath) @@ -413,17 +475,29 @@ self.__showPipxVersion() expandedPackages = [] + outdatedPackages = {} for row in range(self.packagesList.topLevelItemCount()): itm = self.packagesList.topLevelItem(row) if itm.isExpanded(): expandedPackages.append(itm.text(PipxWidget.PackageColumn)) + latestVersion = itm.data(0, PipxWidget.LatestVersionRole) + if latestVersion is not None: + outdatedPackages[itm.text(PipxWidget.PackageColumn)] = latestVersion self.__populatePackages() for row in range(self.packagesList.topLevelItemCount()): itm = self.packagesList.topLevelItem(row) - if itm.text(PipxWidget.PackageColumn) in expandedPackages: + package = itm.text(PipxWidget.PackageColumn) + if package in expandedPackages: itm.setExpanded(True) + + if ( + package in outdatedPackages + and itm.data(0, PipxWidget.VersionRole) != outdatedPackages[package] + ): + self.__markPackageOutdated(itm, outdatedPackages[package]) + self.__resizePackagesColumns() @pyqtSlot(QTreeWidgetItem, int)