diff --git a/plugins/Marketplace/LocalPackageList.py b/plugins/Marketplace/LocalPackageList.py index 7bd2005fd2..83aac65516 100644 --- a/plugins/Marketplace/LocalPackageList.py +++ b/plugins/Marketplace/LocalPackageList.py @@ -1,5 +1,5 @@ -# Copyright (c) 2021 Ultimaker B.V. -# Cura is released under the terms of the LGPLv3 or higher. +# Copyright (c) 2021 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. from typing import Any, Dict, List, Optional, TYPE_CHECKING from operator import attrgetter @@ -39,6 +39,7 @@ class LocalPackageList(PackageList): super().__init__(parent) self._has_footer = False self._ongoing_requests["check_updates"] = None + self._manager.packagesWithUpdateChanged.connect(lambda: self.sort(attrgetter("sectionTitle", "_can_update", "displayName"), key = "package", reverse = True)) @pyqtSlot() def updatePackages(self) -> None: @@ -92,16 +93,6 @@ class LocalPackageList(PackageList): if len(response_data["data"]) == 0: return - try: - for package_data in response_data["data"]: - package = self.getPackageModel(package_data["package_id"]) - package.download_url = package_data.get("download_url", "") - package.setCanUpdate(True) - - self.sort(attrgetter("sectionTitle", "_can_update", "displayName"), key = "package", reverse = True) - self._ongoing_requests["check_updates"] = None - except RuntimeError: - # Setting the ownership of this object to not qml can still result in a RuntimeError. Which can occur when quickly toggling - # between de-/constructing RemotePackageLists. This try-except is here to prevent a hard crash when the wrapped C++ object - # was deleted when it was still parsing the response - return + packages = response_data["data"] + self._manager.setPackagesWithUpdate(dict(zip([p['package_id'] for p in packages], [p for p in packages]))) + self._ongoing_requests["check_updates"] = None diff --git a/plugins/Marketplace/PackageList.py b/plugins/Marketplace/PackageList.py index 8ddd74ead9..c245b44df9 100644 --- a/plugins/Marketplace/PackageList.py +++ b/plugins/Marketplace/PackageList.py @@ -1,5 +1,5 @@ -# Copyright (c) 2021 Ultimaker B.V. -# Cura is released under the terms of the LGPLv3 or higher. +# Copyright (c) 2021 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. import tempfile import json import os.path @@ -268,13 +268,11 @@ class PackageList(ListModel): package.uninstallPackageTriggered.connect(self.uninstallPackage) package.updatePackageTriggered.connect(self.updatePackage) - def installPackage(self, package_id: str) -> None: + def installPackage(self, package_id: str, url: str) -> None: """Install a package from the Marketplace :param package_id: the package identification string """ - package = self.getPackageModel(package_id) - url = package.download_url self.download(package_id, url, False) def uninstallPackage(self, package_id: str) -> None: @@ -282,7 +280,6 @@ class PackageList(ListModel): :param package_id: the package identification string """ - package = self.getPackageModel(package_id) self._manager.removePackage(package_id) self.unsunscribeUserFromPackage(package_id) @@ -291,7 +288,6 @@ class PackageList(ListModel): :param package_id: the package identification string """ - package = self.getPackageModel(package_id) self._manager.removePackage(package_id, force_add = True) - url = package.download_url + url = self._manager.packagesWithUpdate[package_id]["download_url"] self.download(package_id, url, True) diff --git a/plugins/Marketplace/PackageModel.py b/plugins/Marketplace/PackageModel.py index aa63d6da13..e2d785606d 100644 --- a/plugins/Marketplace/PackageModel.py +++ b/plugins/Marketplace/PackageModel.py @@ -1,5 +1,5 @@ -# Copyright (c) 2021 Ultimaker B.V. -# Cura is released under the terms of the LGPLv3 or higher. +# Copyright (c) 2021 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. import re from enum import Enum @@ -45,7 +45,7 @@ class PackageModel(QObject): self._description = package_data.get("description", "") self._formatted_description = self._format(self._description) - self.download_url = package_data.get("download_url", "") + self._download_url = package_data.get("download_url", "") self._release_notes = package_data.get("release_notes", "") # Not used yet, propose to add to description? subdata = package_data.get("data", {}) @@ -72,32 +72,21 @@ class PackageModel(QObject): self.sdk_version = package_data.get("sdk_version_semver", "") # Note that there's a lot more info in the package_data than just these specified here. - def install_clicked(package_id): - self._install_status_changing = True - self.setIsInstalling(True) - - self.installPackageTriggered.connect(install_clicked) - - def uninstall_clicked(package_id): - self._install_status_changing = False - self.setIsInstalling(True) - - self.uninstallPackageTriggered.connect(uninstall_clicked) - - def update_clicked(package_id): - self.setIsUpdating(True) - - self.updatePackageTriggered.connect(update_clicked) + self.enablePackageTriggered.connect(self._plugin_registry.enablePlugin) + self.disablePackageTriggered.connect(self._plugin_registry.disablePlugin) + self.installPackageTriggered.connect(lambda pkg_id: self.setIsInstalling(True)) + self.uninstallPackageTriggered.connect(lambda pkg_id: self.setIsInstalling(True)) + self.updatePackageTriggered.connect(lambda pkg_id: self.setIsUpdating(True)) def finished_installed(): self.setIsUpdating(False) self.setIsInstalling(False) self._package_manager.installedPackagesChanged.connect(finished_installed) - self.enablePackageTriggered.connect(self._plugin_registry.enablePlugin) - self.disablePackageTriggered.connect(self._plugin_registry.disablePlugin) self._plugin_registry.hasPluginsEnabledOrDisabledChanged.connect(self.stateManageButtonChanged) + self._package_manager.packagesWithUpdateChanged.connect(lambda : self.setCanUpdate(self._package_id in self._package_manager.packagesWithUpdate)) + def __eq__(self, other: object): if isinstance(other, PackageModel): return other == self @@ -298,11 +287,15 @@ class PackageModel(QObject): def isBundled(self) -> bool: return self._is_bundled + @pyqtProperty(str, constant = True) + def downloadURL(self) -> str: + return self._download_url + # --- manage buttons signals --- stateManageButtonChanged = pyqtSignal() - installPackageTriggered = pyqtSignal(str) + installPackageTriggered = pyqtSignal(str, str) uninstallPackageTriggered = pyqtSignal(str) @@ -314,7 +307,6 @@ class PackageModel(QObject): @pyqtProperty(bool, notify = stateManageButtonChanged) def isActive(self): - Logger.debug(f"getDisabledPlugins = {self._plugin_registry.getDisabledPlugins()}") return not self._package_id in self._plugin_registry.getDisabledPlugins() def setIsInstalling(self, value: bool) -> None: @@ -326,15 +318,6 @@ class PackageModel(QObject): def isInstalling(self) -> bool: return self._is_installing - def setInstallStatusChanging(self, value: bool) -> None: - if value != self._install_status_changing: - self._install_status_changing = value - self.stateManageButtonChanged.emit() - - @pyqtProperty(bool, fset = setInstallStatusChanging, notify = stateManageButtonChanged) - def installStatusChanging(self) -> bool: - return self._install_status_changing - @pyqtProperty(bool, notify = stateManageButtonChanged) def isInstalled(self) -> bool: return self._package_id in self._package_manager.local_packages_id diff --git a/plugins/Marketplace/resources/qml/PackageCardHeader.qml b/plugins/Marketplace/resources/qml/PackageCardHeader.qml index 5a693ece83..ec33505391 100644 --- a/plugins/Marketplace/resources/qml/PackageCardHeader.qml +++ b/plugins/Marketplace/resources/qml/PackageCardHeader.qml @@ -254,7 +254,7 @@ Item ManageButton { id: updateManageButton - visible: (showManageButtons || confirmed) && packageData.canUpdate && !installManageButton.confirmed + visible: (showManageButtons || confirmed) && (packageData.canUpdate || confirmed) && !installManageButton.confirmed enabled: !installManageButton.busy busy: packageData.isUpdating @@ -265,12 +265,12 @@ Item text: { - if (packageData.isUpdating) { return catalog.i18nc("@button", "Updating..."); } - else if (packageData.isRecentlyUpdated) { return catalog.i18nc("@button", "Updated"); } + if (busy) { return catalog.i18nc("@button", "Updating..."); } + else if (confirmed) { return catalog.i18nc("@button", "Updated"); } else { return catalog.i18nc("@button", "Update"); } } - onClicked: packageData.updatePackageTriggered(packageData.packageId) + onClicked: packageData.updatePackageTriggered(packageData.packageId, packageData.downloadURL) } } }