From 71a43060a60d697c4cad2394f919492560de9a48 Mon Sep 17 00:00:00 2001 From: casper Date: Mon, 6 Dec 2021 19:34:02 +0100 Subject: [PATCH] Open separate license dialog with each plugin install Previously the license dialog was instanciated once and re-used for each install. As the dialog is only shown after the plugin is downloaded it was possible to click install for multiple plugins. Plugins that finish downloading later would override the dialog of earlier downloaded plugins. Clicking "accept" would then only install the latest downloaded plugin. Now for each install a separate dialog is shown. Accepting the license agreement would only install the recently accepted plugin. Note: in the current form the license agreement does not show any identification to what plugin triggered the dialog. As multiple dialogs can be shown at once this might be unclear. cura 8587 --- plugins/Marketplace/LicenseModel.py | 31 ---------- plugins/Marketplace/PackageList.py | 59 ++++++++++--------- .../resources/qml/LicenseDialog.qml | 6 +- 3 files changed, 35 insertions(+), 61 deletions(-) delete mode 100644 plugins/Marketplace/LicenseModel.py diff --git a/plugins/Marketplace/LicenseModel.py b/plugins/Marketplace/LicenseModel.py deleted file mode 100644 index 8eb439d4d6..0000000000 --- a/plugins/Marketplace/LicenseModel.py +++ /dev/null @@ -1,31 +0,0 @@ -from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal -from UM.i18n import i18nCatalog - -catalog = i18nCatalog("cura") - -# Model for the LicenseDialog -class LicenseModel(QObject): - packageIdChanged = pyqtSignal() - licenseTextChanged = pyqtSignal() - - def __init__(self) -> None: - super().__init__() - self._license_text = "" - self._package_id = "" - - @pyqtProperty(str, notify=packageIdChanged) - def packageId(self) -> str: - return self._package_id - - def setPackageId(self, name: str) -> None: - self._package_id = name - self.packageIdChanged.emit() - - @pyqtProperty(str, notify=licenseTextChanged) - def licenseText(self) -> str: - return self._license_text - - def setLicenseText(self, license_text: str) -> None: - if self._license_text != license_text: - self._license_text = license_text - self.licenseTextChanged.emit() diff --git a/plugins/Marketplace/PackageList.py b/plugins/Marketplace/PackageList.py index 39d1d9fab6..f0a6d1de06 100644 --- a/plugins/Marketplace/PackageList.py +++ b/plugins/Marketplace/PackageList.py @@ -20,7 +20,6 @@ from cura.UltimakerCloud.UltimakerCloudScope import UltimakerCloudScope # To ma from .PackageModel import PackageModel from .Constants import USER_PACKAGES_URL -from .LicenseModel import LicenseModel if TYPE_CHECKING: from PyQt5.QtCore import QObject @@ -52,19 +51,7 @@ class PackageList(ListModel): self._ongoing_request: Optional[HttpRequestData] = None self._scope = JsonDecoratorScope(UltimakerCloudScope(CuraApplication.getInstance())) - - self._license_model = LicenseModel() - - plugin_path = self._plugin_registry.getPluginPath("Marketplace") - if plugin_path is None: - plugin_path = os.path.dirname(__file__) - - # create a QML component for the license dialog - license_dialog_component_path = os.path.join(plugin_path, "resources", "qml", "LicenseDialog.qml") - self._license_dialog = CuraApplication.getInstance().createQmlComponent(license_dialog_component_path, { - "licenseModel": self._license_model, - "handler": self - }) + self._license_dialogs: Dict[str, QObject] = {} @pyqtSlot() def updatePackages(self) -> None: @@ -137,24 +124,42 @@ class PackageList(ListModel): canInstallChanged = pyqtSignal(str, bool) - def _openLicenseDialog(self, plugin_name: str, license_content: str) -> None: - Logger.debug(f"Prompting license for {plugin_name}") - self._license_model.setPackageId(plugin_name) - self._license_model.setLicenseText(license_content) - self._license_dialog.show() + def _openLicenseDialog(self, package_id: str, license_content: str) -> None: + Logger.debug(f"Prompting license for {package_id}") - @pyqtSlot() - def onLicenseAccepted(self) -> None: - package_id = self._license_model.packageId + plugin_path = self._plugin_registry.getPluginPath("Marketplace") + if plugin_path is None: + plugin_path = os.path.dirname(__file__) + + # create a QML component for the license dialog + license_dialog_component_path = os.path.join(plugin_path, "resources", "qml", "LicenseDialog.qml") + dialog = CuraApplication.getInstance().createQmlComponent(license_dialog_component_path, { + "licenseContent": license_content, + "packageId": package_id, + "handler": self + }) + dialog.show() + # place dialog in class such that it does not get remove by garbage collector + self._license_dialogs[package_id] = dialog + + @pyqtSlot(str) + def onLicenseAccepted(self, package_id: str) -> None: Logger.debug(f"Accepted license for {package_id}") - self._license_dialog.close() + # close dialog + dialog = self._license_dialogs.pop(package_id) + if dialog is not None: + dialog.deleteLater() + # install relevant package self._install(package_id) - @pyqtSlot() - def onLicenseDeclined(self) -> None: - package_id = self._license_model.packageId + @pyqtSlot(str) + def onLicenseDeclined(self, package_id: str) -> None: Logger.debug(f"Declined license for {package_id}") - self._license_dialog.close() + # close dialog + dialog = self._license_dialogs.pop(package_id) + if dialog is not None: + dialog.deleteLater() + # reset package card package = self.getPackageModel(package_id) package.is_installing = False diff --git a/plugins/Marketplace/resources/qml/LicenseDialog.qml b/plugins/Marketplace/resources/qml/LicenseDialog.qml index 7bee6f9108..32c4ec699c 100644 --- a/plugins/Marketplace/resources/qml/LicenseDialog.qml +++ b/plugins/Marketplace/resources/qml/LicenseDialog.qml @@ -63,7 +63,7 @@ UM.Dialog Layout.fillHeight: true anchors.topMargin: UM.Theme.getSize("default_margin").height - textArea.text: licenseModel.licenseText + textArea.text: licenseContent textArea.readOnly: true } @@ -73,7 +73,7 @@ UM.Dialog Cura.PrimaryButton { text: catalog.i18nc("@button", "Accept") - onClicked: { handler.onLicenseAccepted() } + onClicked: { handler.onLicenseAccepted(packageId) } } ] @@ -82,7 +82,7 @@ UM.Dialog Cura.SecondaryButton { text: catalog.i18nc("@button", "Decline") - onClicked: { handler.onLicenseDeclined() } + onClicked: { handler.onLicenseDeclined(packageId) } } ] }