From ef09c0af16ad9482ed3e007e946feea2bbd61e6c Mon Sep 17 00:00:00 2001 From: Chris Hennes Date: Fri, 17 Dec 2021 10:01:29 -0600 Subject: [PATCH] Addon Manager: Improve display of install details As suggested in the forums, this adds display of the installation date and installed version to the expanded display and detail view. --- src/Mod/AddonManager/AddonManager.py | 39 +++--- src/Mod/AddonManager/AddonManagerRepo.py | 2 + src/Mod/AddonManager/addonmanager_workers.py | 137 +++++++------------ src/Mod/AddonManager/package_details.py | 50 ++++++- src/Mod/AddonManager/package_details.ui | 13 ++ src/Mod/AddonManager/package_list.py | 71 ++++++++-- 6 files changed, 201 insertions(+), 111 deletions(-) diff --git a/src/Mod/AddonManager/AddonManager.py b/src/Mod/AddonManager/AddonManager.py index 78a564991f..be38767ba5 100644 --- a/src/Mod/AddonManager/AddonManager.py +++ b/src/Mod/AddonManager/AddonManager.py @@ -78,6 +78,7 @@ class CommandAddonManager: "update_metadata_cache_worker", "update_all_worker"] lock = threading.Lock() + restart_required = False def __init__(self): FreeCADGui.addPreferencePage(os.path.join(os.path.dirname(__file__), @@ -201,6 +202,7 @@ class CommandAddonManager: self.packageDetails.uninstall.connect(self.remove) self.packageDetails.update.connect(self.update) self.packageDetails.back.connect(self.on_buttonBack_clicked) + self.packageDetails.update_status.connect(self.status_updated) # center the dialog over the FreeCAD window mw = FreeCADGui.getMainWindow() @@ -276,8 +278,7 @@ class CommandAddonManager: # all threads have finished if oktoclose: - if ((hasattr(self, "install_worker") and self.install_worker) or - (hasattr(self, "addon_removed") and self.addon_removed)): + if self.restart_required: # display restart dialog m = QtWidgets.QMessageBox() m.setWindowTitle(translate("AddonsInstaller", "Addon manager")) @@ -478,9 +479,9 @@ class CommandAddonManager: self.check_worker.start() self.enable_updates(len(self.packages_with_updates)) - def status_updated(self, repo:str, status:AddonManagerRepo.UpdateStatus) -> None: - self.item_model.update_item_status(repo.name, status) - if status == AddonManagerRepo.UpdateStatus.UPDATE_AVAILABLE: + def status_updated(self, repo:AddonManagerRepo) -> None: + self.item_model.reload_item(repo) + if repo.update_status == AddonManagerRepo.UpdateStatus.UPDATE_AVAILABLE: self.packages_with_updates.append(repo) self.enable_updates(len(self.packages_with_updates)) @@ -578,6 +579,7 @@ class CommandAddonManager: return if repo.repo_type == AddonManagerRepo.RepoType.WORKBENCH or repo.repo_type == AddonManagerRepo.RepoType.PACKAGE: + self.show_progress_widgets() self.install_worker = InstallWorkbenchWorker(repo) self.install_worker.status_message.connect(self.show_information) self.current_progress_region = 1 @@ -610,7 +612,7 @@ class CommandAddonManager: "now available from the Macros dialog.") self.on_package_installed (repo, message) else: - message = translate("AddonsInstaller", "Installation of macro failed" + ":") + message = translate("AddonsInstaller", "Installation of macro failed") + ":" for error in errors: message += "\n * " message += error @@ -629,6 +631,7 @@ class CommandAddonManager: self.subupdates_succeeded = [] self.subupdates_failed = [] + self.show_progress_widgets() self.current_progress_region = 1 self.number_of_progress_regions = 1 self.update_all_worker = UpdateAllWorker(self.packages_with_updates) @@ -640,7 +643,7 @@ class CommandAddonManager: self.update_all_worker.start() def on_update_all_completed(self) -> None: - #self.show_progress_bar(False) + self.hide_progress_widgets() if not self.subupdates_failed: message = translate ("AddonsInstaller", "All packages were successfully updated. Packages:") + "\n" message += ''.join([repo.name + "\n" for repo in self.subupdates_succeeded]) @@ -654,6 +657,9 @@ class CommandAddonManager: message += ''.join([repo.name + "\n" for repo in self.subupdates_failed]) for installed_repo in self.subupdates_succeeded: + self.restart_required = True + installed_repo.update_status = AddonManagerRepo.UpdateStatus.PENDING_RESTART + self.item_model.reload_item(installed_repo) for requested_repo in self.packages_with_updates: if installed_repo.name == requested_repo.name: self.packages_with_updates.remove(installed_repo) @@ -704,22 +710,22 @@ class CommandAddonManager: self.hide_progress_widgets() def on_package_installed(self, repo:AddonManagerRepo, message:str) -> None: + self.hide_progress_widgets() QtWidgets.QMessageBox.information(None, translate("AddonsInstaller", "Installation succeeded"), message, QtWidgets.QMessageBox.Close) - if repo.contains_workbench(): - self.item_model.update_item_status(repo.name, AddonManagerRepo.UpdateStatus.PENDING_RESTART) - else: - self.item_model.update_item_status(repo.name, AddonManagerRepo.UpdateStatus.NO_UPDATE_AVAILABLE) - self.packageDetails.show_repo(repo, reload=True) + repo.update_status = AddonManagerRepo.UpdateStatus.PENDING_RESTART + self.item_model.reload_item(repo) + self.packageDetails.show_repo(repo) + self.restart_required = True def on_installation_failed(self, _:AddonManagerRepo, message:str) -> None: + self.hide_progress_widgets() QtWidgets.QMessageBox.warning(None, translate("AddonsInstaller", "Installation failed"), message, QtWidgets.QMessageBox.Close) - self.dialog.progressBar.hide() def executemacro(self, repo:AddonManagerRepo) -> None: """executes a selected macro""" @@ -732,7 +738,7 @@ class CommandAddonManager: macro_path = os.path.join(self.macro_repo_dir,macro.filename) FreeCADGui.open(str(macro_path)) self.dialog.hide() - FreeCADGui.SendMsgToActiveView("Run") + FreeCADGui.SendMsgToActiveView("Run") else: with tempfile.TemporaryDirectory() as dir: temp_install_succeeded = macro.install(dir) @@ -764,7 +770,8 @@ class CommandAddonManager: shutil.rmtree(clonedir, onerror=self.remove_readonly) self.item_model.update_item_status(repo.name, AddonManagerRepo.UpdateStatus.NOT_INSTALLED) self.addon_removed = True # A value to trigger the restart message on dialog close - self.packageDetails.show_repo(repo, reload=True) + self.packageDetails.show_repo(repo) + self.restart_required = True else: self.dialog.textBrowserReadMe.setText(translate("AddonsInstaller", "Unable to remove this addon with the Addon Manager.")) @@ -772,7 +779,7 @@ class CommandAddonManager: macro = repo.macro if macro.remove(): self.item_model.update_item_status(repo.name, AddonManagerRepo.UpdateStatus.NOT_INSTALLED) - self.packageDetails.show_repo(repo, reload=True) + self.packageDetails.show_repo(repo) else: self.dialog.textBrowserReadMe.setText(translate("AddonsInstaller", "Macro could not be removed.")) diff --git a/src/Mod/AddonManager/AddonManagerRepo.py b/src/Mod/AddonManager/AddonManagerRepo.py index 14bf76c1a9..ca34db03a9 100644 --- a/src/Mod/AddonManager/AddonManagerRepo.py +++ b/src/Mod/AddonManager/AddonManagerRepo.py @@ -82,6 +82,8 @@ class AddonManagerRepo: self.icon = None self.cached_icon_filename = "" self.macro = None # Bridge to Gaël Écorchard's macro management class + self.updated_timestamp = None + self.installed_version = None def __str__ (self) -> str: result = f"FreeCAD {self.repo_type}\n" diff --git a/src/Mod/AddonManager/addonmanager_workers.py b/src/Mod/AddonManager/addonmanager_workers.py index ef983cbbf6..986d076818 100644 --- a/src/Mod/AddonManager/addonmanager_workers.py +++ b/src/Mod/AddonManager/addonmanager_workers.py @@ -30,6 +30,7 @@ import tempfile import hashlib import threading import queue +from datetime import datetime from typing import Union, List from PySide2 import QtCore, QtGui, QtNetwork @@ -39,11 +40,11 @@ if FreeCAD.GuiUp: import FreeCADGui import addonmanager_utilities as utils -from addonmanager_utilities import translate # this needs to be as is for pylupdate from addonmanager_macro import Macro from addonmanager_metadata import MetadataDownloadWorker from AddonManagerRepo import AddonManagerRepo +translate = FreeCAD.Qt.translate have_git = False try: @@ -240,9 +241,7 @@ class LoadMacrosFromCacheWorker(QtCore.QThread): class CheckWorkbenchesForUpdatesWorker(QtCore.QThread): """This worker checks for available updates for all workbenches""" - # Emitting an Enum fails on Ubuntu 20.04, so use an int instead - #update_status = QtCore.Signal(AddonManagerRepo, AddonManagerRepo.UpdateStatus) - update_status = QtCore.Signal(AddonManagerRepo, int) + update_status = QtCore.Signal(AddonManagerRepo) progress_made = QtCore.Signal(int, int) done = QtCore.Signal() @@ -307,31 +306,47 @@ class CheckWorkbenchesForUpdatesWorker(QtCore.QThread): try: gitrepo.fetch() except Exception: - FreeCAD.Console.PrintWarning("AddonManager: Unable to fetch git updates for workbench " + wb.name) + FreeCAD.Console.PrintWarning("AddonManager: " + translate("AddonsInstaller","Unable to fetch git updates for workbench") + " " + wb.name) else: try: if "git pull" in gitrepo.status(): - self.update_status.emit(wb, AddonManagerRepo.UpdateStatus.UPDATE_AVAILABLE) + wb.update_status = AddonManagerRepo.UpdateStatus.UPDATE_AVAILABLE else: - self.update_status.emit(wb, AddonManagerRepo.UpdateStatus.NO_UPDATE_AVAILABLE) - except stderr: + wb.update_status = AddonManagerRepo.UpdateStatus.NO_UPDATE_AVAILABLE + self.update_status.emit(wb) + except Exception: FreeCAD.Console.PrintWarning("AddonManager - " + wb.name + " git status" " fatal: this operation must be run in a work tree \n") - def check_package(self, package): + def check_package(self, package:AddonManagerRepo) -> None: clonedir = self.moddir + os.sep + package.name if os.path.exists(clonedir): installed_metadata_file = os.path.join(clonedir, "package.xml") - installed_metadata = FreeCAD.Metadata(installed_metadata_file) - # Packages are considered up-to-date if the metadata version matches. Authors should update - # their version string when they want the addon manager to alert users of a new version. - if package.metadata.Version > installed_metadata.Version: - self.update_status.emit(package, AddonManagerRepo.UpdateStatus.UPDATE_AVAILABLE) + if not os.path.isfile(installed_metadata_file): + # If there is no package.xml file, then it's because the package author added it after the last time + # the local installation was updated. By definition, then, there is an update available, if only to + # download the new XML file. + package.update_status = AddonManagerRepo.UpdateStatus.UPDATE_AVAILABLE + package.installed_version = None + self.update_status.emit(package) + return else: - self.update_status.emit(package, AddonManagerRepo.UpdateStatus.NO_UPDATE_AVAILABLE) + package.updated_timestamp = os.path.getmtime(installed_metadata_file) + try: + installed_metadata = FreeCAD.Metadata(installed_metadata_file) + package.installed_version = installed_metadata.Version + # Packages are considered up-to-date if the metadata version matches. Authors should update + # their version string when they want the addon manager to alert users of a new version. + if package.metadata.Version != installed_metadata.Version: + package.update_status = AddonManagerRepo.UpdateStatus.UPDATE_AVAILABLE + else: + package.update_status = AddonManagerRepo.UpdateStatus.NO_UPDATE_AVAILABLE + self.update_status.emit(package) + except Exception as e: + FreeCAD.Console.PrintWarning(translate("AddonsInstaller", "Failed to read metadata from") + f" {installed_metadata_file}") - def check_macro(self, macro_wrapper): + def check_macro(self, macro_wrapper:AddonManagerRepo) -> None: # Make sure this macro has its code downloaded: try: if not macro_wrapper.macro.parsed and macro_wrapper.macro.on_git: @@ -365,9 +380,10 @@ class CheckWorkbenchesForUpdatesWorker(QtCore.QThread): else: return if new_sha1 == old_sha1: - self.update_status.emit(macro_wrapper, AddonManagerRepo.UpdateStatus.NO_UPDATE_AVAILABLE) + macro_wrapper.update_status = AddonManagerRepo.UpdateStatus.NO_UPDATE_AVAILABLE else: - self.update_status.emit(macro_wrapper, AddonManagerRepo.UpdateStatus.UPDATE_AVAILABLE) + macro_wrapper.update_status = AddonManagerRepo.UpdateStatus.UPDATE_AVAILABLE + self.update_status.emit(macro_wrapper) class FillMacroListWorker(QtCore.QThread): @@ -489,7 +505,7 @@ class ShowWorker(QtCore.QThread): status_message = QtCore.Signal(str) readme_updated = QtCore.Signal(str) - addon_repos = QtCore.Signal(object) + update_status = QtCore.Signal(AddonManagerRepo) done = QtCore.Signal() def __init__(self, repo, cache_path): @@ -570,9 +586,9 @@ class ShowWorker(QtCore.QThread): self.repo.description = desc if QtCore.QThread.currentThread().isInterruptionRequested(): return - self.addon_repos.emit(self.repo) - # Addon is installed so lets check if it has an update - if self.repo.update_status == AddonManagerRepo.UpdateStatus.UPDATE_AVAILABLE: + message = desc + if self.repo.update_status == AddonManagerRepo.UpdateStatus.UNCHECKED: + # Addon is installed but we haven't checked it yet, so lets check if it has an update upd = False # checking for updates if not NOGIT and have_git: @@ -598,72 +614,14 @@ class ShowWorker(QtCore.QThread): gitrepo.fetch() if "git pull" in gitrepo.status(): upd = True - # If there is an update pending, lets user know via the UI if upd: - message = """ -
-
- -""" - message += translate("AddonsInstaller", "An update is available for this addon.") - message += "

" + desc + '

Addon repository: ' + self.repo.url + "" self.repo.update_status = AddonManagerRepo.UpdateStatus.UPDATE_AVAILABLE - # If there isn't, indicate that this addon is already installed else: - message = """ -
-
- -""" - message += translate("AddonsInstaller", "This addon is already installed.") - message += "

" + desc - message += '

Addon repository: ' + self.repo.url + "" self.repo.update_status = AddonManagerRepo.UpdateStatus.NO_UPDATE_AVAILABLE - # Let the user know the install path for this addon - message += "
" + translate("AddonsInstaller", "Installed location") + ": " - message += FreeCAD.getUserAppDataDir() + os.sep + "Mod" + os.sep + self.repo.name + self.update_status.emit(self.repo) + if QtCore.QThread.currentThread().isInterruptionRequested(): return - self.addon_repos.emit(self.repo) - elif self.repo.update_status == AddonManagerRepo.UpdateStatus.PENDING_RESTART: - message = """ -
-
- -""" - message += translate("AddonsInstaller", "This addon has been updated, a restart is now required before it can be used.") - message += "

" + desc + '

Addon repository: ' + self.repo.url + "" - message += "
" + translate("AddonsInstaller", "Installed location") + ": " - message += FreeCAD.getUserAppDataDir() + os.sep + "Mod" + os.sep + self.repo.name - elif self.repo.update_status == AddonManagerRepo.UpdateStatus.NO_UPDATE_AVAILABLE: - message = """ -
-
- -""" - message += translate("AddonsInstaller", "This addon is already installed.") - message += "

" + desc - message += '

Addon repository: ' + self.repo.url + "" - message += "
" + translate("AddonsInstaller", "Installed location") + ": " - message += FreeCAD.getUserAppDataDir() + os.sep + "Mod" + os.sep + self.repo.name - elif self.repo.update_status == AddonManagerRepo.UpdateStatus.UPDATE_AVAILABLE: - message = """ -
-
- -""" - message += translate("AddonsInstaller", "An update is available for this addon.") - message += "

" + desc + '

Addon repository: ' + self.repo.url + "" - message += "
" + translate("AddonsInstaller", "Installed location") + ": " - message += FreeCAD.getUserAppDataDir() + os.sep + "Mod" + os.sep + self.repo.name - else: - message = desc + '

Addon repository: ' + self.repo.url + '' # If the Addon is obsolete, let the user know through the Addon UI if self.repo.name in obsolete: @@ -905,6 +863,7 @@ class InstallWorkbenchWorker(QtCore.QThread): self.status_message.emit("Updating submodules...") for submodule in repo_sms.submodules: submodule.update(init=True, recursive=True) + self.update_metadata() self.success.emit(self.repo, answer) def run_git_clone(self, clonedir:str) -> None: @@ -946,6 +905,7 @@ class InstallWorkbenchWorker(QtCore.QThread): "A macro has been installed and is available " "under Macro -> Macros menu") answer += ":\n" + f + "" + self.update_metadata() self.success.emit(self.repo, answer) def check_python_dependencies(self, baseurl:str) -> Union[bool,str]: @@ -960,7 +920,7 @@ class InstallWorkbenchWorker(QtCore.QThread): try: mu = utils.urlopen(depsurl) except Exception: - return True,"No metadata.txt found" + return True, translate("AddonsInstaller", "No metadata.txt found, cannot evaluate Python dependencies") if mu: # metadata.txt found depsfile = mu.read() @@ -1003,7 +963,7 @@ class InstallWorkbenchWorker(QtCore.QThread): "Missing optional python module (doesn't prevent installing)") message += ": " + pl + ", " if message and (not ok): - message = translate("AddonsInstaller", "Some errors were found that prevent to install this workbench") + message = translate("AddonsInstaller", "Some errors were found that prevent installation of this workbench") message += ": " + message + ". " message += translate("AddonsInstaller", "Please install the missing components first.") return ok, message @@ -1067,8 +1027,17 @@ class InstallWorkbenchWorker(QtCore.QThread): os.rmdir(zipdir + os.sep + master) if bakdir: shutil.rmtree(bakdir) + self.update_metadata() self.success.emit(self.repo, translate("AddonsInstaller", "Successfully installed") + " " + zipurl) + def update_metadata(self): + basedir = FreeCAD.getUserAppDataDir() + package_xml = os.path.join(basedir,"Mod",self.repo.name,"package.xml") + if os.path.isfile(package_xml): + self.repo.metadata = FreeCAD.Metadata(package_xml) + self.repo.installed_version = self.repo.metadata.Version + self.repo.updated_timestamp = datetime.now().timestamp() + class CheckSingleWorker(QtCore.QThread): """Worker to check for updates for a single addon""" diff --git a/src/Mod/AddonManager/package_details.py b/src/Mod/AddonManager/package_details.py index 5ec2afb3c7..d5ee5d2bc4 100644 --- a/src/Mod/AddonManager/package_details.py +++ b/src/Mod/AddonManager/package_details.py @@ -44,6 +44,7 @@ class PackageDetails(QWidget): uninstall = Signal(AddonManagerRepo) update = Signal(AddonManagerRepo) execute = Signal(AddonManagerRepo) + update_status = Signal(AddonManagerRepo) def __init__(self, parent=None): super().__init__(parent) @@ -86,6 +87,45 @@ class PackageDetails(QWidget): self.show_package(repo) self.ui.buttonExecute.hide() + if repo.update_status != AddonManagerRepo.UpdateStatus.NOT_INSTALLED: + installed_version_string = "" + if repo.installed_version: + installed_version_string = translate("AddonsInstaller", "Version") + " " + installed_version_string += repo.installed_version + else: + installed_version_string = translate("AddonsInstaller", "Unknown version (no package.xml file found)") + " " + + + if repo.updated_timestamp: + installed_version_string += " " + translate("AddonsInstaller", "installed on") + " " + installed_version_string += QDateTime.fromTime_t(repo.updated_timestamp).date().toString(Qt.SystemLocaleShortDate) + installed_version_string += ". " + else: + installed_version_string += translate("AddonsInstaller", "installed") + ". " + + if repo.update_status == AddonManagerRepo.UpdateStatus.UPDATE_AVAILABLE: + if repo.metadata: + installed_version_string += "" + translate("AddonsInstaller", "Update available to version") + " " + installed_version_string += repo.metadata.Version + installed_version_string += "." + else: + installed_version_string += "" + translate("AddonsInstaller", "Update available to unknown version (no package.xml file found)") + "." + elif repo.update_status == AddonManagerRepo.UpdateStatus.NO_UPDATE_AVAILABLE: + installed_version_string += translate("AddonsInstaller", "This is the latest version available") + "." + elif repo.update_status == AddonManagerRepo.UpdateStatus.PENDING_RESTART: + installed_version_string += translate("AddonsInstaller", "Updated, please restart FreeCAD to use") + "." + elif repo.update_status == AddonManagerRepo.UpdateStatus.UNCHECKED: + installed_version_string += translate("AddonsInstaller", "Update check in progress") + "." + + basedir = FreeCAD.getUserAppDataDir() + moddir = os.path.join(basedir , "Mod", repo.name) + installed_version_string += "
" + translate("AddonsInstaller", "Installation location") + ": " + moddir + + self.ui.labelPackageDetails.setText(installed_version_string) + self.ui.labelPackageDetails.show() + else: + self.ui.labelPackageDetails.hide() + if repo.update_status == AddonManagerRepo.UpdateStatus.NOT_INSTALLED: self.ui.buttonInstall.show() self.ui.buttonUninstall.hide() @@ -160,6 +200,8 @@ class PackageDetails(QWidget): self.worker = ShowWorker(repo, PackageDetails.cache_path(repo)) self.worker.readme_updated.connect(lambda desc: self.cache_readme(repo, desc)) self.worker.readme_updated.connect(lambda desc: self.ui.textBrowserReadMe.setText(desc)) + self.worker.update_status.connect(self.update_status.emit) + self.worker.update_status.connect(self.show) self.worker.start() def show_package(self, repo:AddonManagerRepo) -> None: @@ -170,6 +212,8 @@ class PackageDetails(QWidget): self.worker = ShowWorker(repo,PackageDetails.cache_path(repo)) self.worker.readme_updated.connect(lambda desc: self.cache_readme(repo, desc)) self.worker.readme_updated.connect(lambda desc: self.ui.textBrowserReadMe.setText(desc)) + self.worker.update_status.connect(self.update_status.emit) + self.worker.update_status.connect(self.show) self.worker.start() def show_macro(self, repo:AddonManagerRepo) -> None: @@ -232,9 +276,13 @@ class Ui_PackageDetails(object): self.layoutDetailsBackButton.addWidget(self.buttonExecute) - self.verticalLayout_2.addLayout(self.layoutDetailsBackButton) + self.labelPackageDetails = QLabel(PackageDetails) + self.labelPackageDetails.hide() + + self.verticalLayout_2.addWidget(self.labelPackageDetails) + self.textBrowserReadMe = QTextBrowser(PackageDetails) self.textBrowserReadMe.setObjectName(u"textBrowserReadMe") self.textBrowserReadMe.setOpenExternalLinks(True) diff --git a/src/Mod/AddonManager/package_details.ui b/src/Mod/AddonManager/package_details.ui index d8e49c6cfb..c9139ecd29 100644 --- a/src/Mod/AddonManager/package_details.ui +++ b/src/Mod/AddonManager/package_details.ui @@ -76,6 +76,19 @@ + + + + Installation details go here + + + true + + + false + + + diff --git a/src/Mod/AddonManager/package_list.py b/src/Mod/AddonManager/package_list.py index 1b75d6fb7d..4d335be22e 100644 --- a/src/Mod/AddonManager/package_list.py +++ b/src/Mod/AddonManager/package_list.py @@ -28,6 +28,7 @@ from PySide2.QtCore import * from PySide2.QtGui import * from PySide2.QtWidgets import * +import datetime from typing import Dict, Union from enum import IntEnum import threading @@ -291,18 +292,68 @@ class PackageListItemDelegate(QStyledItemDelegate): self.widget.ui.labelMaintainer.setText("") # Update status - if repo.update_status == AddonManagerRepo.UpdateStatus.NOT_INSTALLED: - self.widget.ui.labelStatus.setText("") - elif repo.update_status == AddonManagerRepo.UpdateStatus.UNCHECKED: - self.widget.ui.labelStatus.setText(translate("AddonsInstaller","Installed")) - elif repo.update_status == AddonManagerRepo.UpdateStatus.NO_UPDATE_AVAILABLE: - self.widget.ui.labelStatus.setText(translate("AddonsInstaller","Up-to-date")) - elif repo.update_status == AddonManagerRepo.UpdateStatus.UPDATE_AVAILABLE: - self.widget.ui.labelStatus.setText(translate("AddonsInstaller","Update available")) - elif repo.update_status == AddonManagerRepo.UpdateStatus.PENDING_RESTART: - self.widget.ui.labelStatus.setText(translate("AddonsInstaller","Pending restart")) + if self.displayStyle == ListDisplayStyle.EXPANDED: + self.widget.ui.labelStatus.setText(self.get_expanded_update_string(repo)) + else: + self.widget.ui.labelStatus.setText(self.get_compact_update_string(repo)) + self.widget.adjustSize() + def get_compact_update_string(self, repo:AddonManagerRepo) -> str: + """ Get a single-line string listing details about the installed version and date """ + + result = "" + if repo.update_status == AddonManagerRepo.UpdateStatus.UNCHECKED: + result = translate("AddonsInstaller","Installed") + elif repo.update_status == AddonManagerRepo.UpdateStatus.NO_UPDATE_AVAILABLE: + result = translate("AddonsInstaller","Up-to-date") + elif repo.update_status == AddonManagerRepo.UpdateStatus.UPDATE_AVAILABLE: + result = translate("AddonsInstaller","Update available") + elif repo.update_status == AddonManagerRepo.UpdateStatus.PENDING_RESTART: + result = translate("AddonsInstaller","Pending restart") + return result + + def get_expanded_update_string(self, repo:AddonManagerRepo) -> str: + """ Get a multi-line string listing details about the installed version and date """ + + result = "" + + installed_version_string = "" + if repo.update_status != AddonManagerRepo.UpdateStatus.NOT_INSTALLED: + if repo.installed_version: + installed_version_string = "\n" + translate("AddonsInstaller", "Installed version") + ": " + installed_version_string += repo.installed_version + else: + installed_version_string = "\n" + translate("AddonsInstaller", "Unknown version") + + installed_date_string = "" + if repo.updated_timestamp: + installed_date_string = "\n" + translate("AddonsInstaller", "Installed on") + ": " + installed_date_string += QDateTime.fromTime_t(repo.updated_timestamp).date().toString(Qt.SystemLocaleShortDate) + + available_version_string = "" + if repo.metadata: + available_version_string = "\n" + translate("AddonsInstaller", "Available version") + ": " + available_version_string += repo.metadata.Version + + if repo.update_status == AddonManagerRepo.UpdateStatus.UNCHECKED: + result = translate("AddonsInstaller","Installed") + result += installed_version_string + result += installed_date_string + elif repo.update_status == AddonManagerRepo.UpdateStatus.NO_UPDATE_AVAILABLE: + result = translate("AddonsInstaller","Up-to-date") + result += installed_version_string + result += installed_date_string + elif repo.update_status == AddonManagerRepo.UpdateStatus.UPDATE_AVAILABLE: + result = translate("AddonsInstaller","Update available") + result += installed_version_string + result += installed_date_string + result += available_version_string + elif repo.update_status == AddonManagerRepo.UpdateStatus.PENDING_RESTART: + result = translate("AddonsInstaller","Pending restart") + + return result + def paint(self, painter:QPainter, option:QStyleOptionViewItem, index:QModelIndex): painter.save() self.widget.resize(option.rect.size())