From 1287ebdc519954339ac7bc622200b847fc5341f2 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Tue, 21 Jan 2020 14:43:02 +0100 Subject: [PATCH 1/6] Change backgroundColor and margin for licenseDialog CURA-7129 --- plugins/Toolbox/resources/qml/dialogs/ToolboxLicenseDialog.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/Toolbox/resources/qml/dialogs/ToolboxLicenseDialog.qml b/plugins/Toolbox/resources/qml/dialogs/ToolboxLicenseDialog.qml index 3e7cdc9df8..5d29e70f97 100644 --- a/plugins/Toolbox/resources/qml/dialogs/ToolboxLicenseDialog.qml +++ b/plugins/Toolbox/resources/qml/dialogs/ToolboxLicenseDialog.qml @@ -20,6 +20,8 @@ UM.Dialog minimumHeight: UM.Theme.getSize("license_window_minimum").height width: minimumWidth height: minimumHeight + backgroundColor: UM.Theme.getColor("main_background") + margin: screenScaleFactor * 10 Item { @@ -27,7 +29,6 @@ UM.Dialog UM.I18nCatalog{id: catalog; name: "cura"} - Label { id: licenseHeader From b3812a36300dc54a7201981e7665a4ce966a3127 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Tue, 21 Jan 2020 17:07:21 +0100 Subject: [PATCH 2/6] Add icon to licenseDialog (clowd flow) CURA-7129 --- .../qml/dialogs/ToolboxLicenseDialog.qml | 47 +++++++++++++++---- .../src/CloudSync/DownloadPresenter.py | 12 ++++- plugins/Toolbox/src/CloudSync/LicenseModel.py | 23 ++++++--- .../Toolbox/src/CloudSync/LicensePresenter.py | 10 ++-- .../Toolbox/src/CloudSync/SyncOrchestrator.py | 4 +- 5 files changed, 72 insertions(+), 24 deletions(-) diff --git a/plugins/Toolbox/resources/qml/dialogs/ToolboxLicenseDialog.qml b/plugins/Toolbox/resources/qml/dialogs/ToolboxLicenseDialog.qml index 5d29e70f97..dba4a5ba58 100644 --- a/plugins/Toolbox/resources/qml/dialogs/ToolboxLicenseDialog.qml +++ b/plugins/Toolbox/resources/qml/dialogs/ToolboxLicenseDialog.qml @@ -5,6 +5,7 @@ import QtQuick 2.10 import QtQuick.Dialogs 1.1 import QtQuick.Window 2.2 import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.3 import QtQuick.Controls.Styles 1.4 // TODO: Switch to QtQuick.Controls 2.x and remove QtQuick.Controls.Styles @@ -23,7 +24,7 @@ UM.Dialog backgroundColor: UM.Theme.getColor("main_background") margin: screenScaleFactor * 10 - Item + ColumnLayout { anchors.fill: parent @@ -32,20 +33,48 @@ UM.Dialog Label { id: licenseHeader - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - text: licenseModel.headerText + Layout.fillWidth: true + text: catalog.i18nc("@label", "You need to accept the license to install the package") wrapMode: Text.Wrap renderType: Text.NativeRendering } + + Row { + id: packageRow + + anchors.left: parent.left + anchors.right: parent.right + height: childrenRect.height + + + Image + { + id: icon + width: 30 * screenScaleFactor + height: width + fillMode: Image.PreserveAspectFit + source: licenseModel.iconUrl || "../../images/logobot.svg" + mipmap: true + } + + Label + { + id: packageName + text: licenseModel.packageName + anchors.verticalCenter: icon.verticalCenter + height: contentHeight + wrapMode: Text.Wrap + renderType: Text.NativeRendering + } + + + } + TextArea { id: licenseText - anchors.top: licenseHeader.bottom - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right + Layout.fillWidth: true + Layout.fillHeight: true anchors.topMargin: UM.Theme.getSize("default_margin").height readOnly: true text: licenseModel.licenseText diff --git a/plugins/Toolbox/src/CloudSync/DownloadPresenter.py b/plugins/Toolbox/src/CloudSync/DownloadPresenter.py index f19cac047a..d79d031949 100644 --- a/plugins/Toolbox/src/CloudSync/DownloadPresenter.py +++ b/plugins/Toolbox/src/CloudSync/DownloadPresenter.py @@ -62,7 +62,8 @@ class DownloadPresenter: "received": 0, "total": 1, # make sure this is not considered done yet. Also divByZero-safe "file_written": None, - "request_data": request_data + "request_data": request_data, + "package_model": item } self._started = True @@ -128,7 +129,14 @@ class DownloadPresenter: if not item["file_written"]: return False - success_items = {package_id : value["file_written"] for package_id, value in self._progress.items()} + success_items = { + package_id: + { + "package_path": value["file_written"], + "icon_url": value["package_model"]["icon_url"] + } + for package_id, value in self._progress.items() + } error_items = [package_id for package_id in self._error] self._progress_message.hide() diff --git a/plugins/Toolbox/src/CloudSync/LicenseModel.py b/plugins/Toolbox/src/CloudSync/LicenseModel.py index c3b5ee5d31..66ea6ca5da 100644 --- a/plugins/Toolbox/src/CloudSync/LicenseModel.py +++ b/plugins/Toolbox/src/CloudSync/LicenseModel.py @@ -7,8 +7,9 @@ catalog = i18nCatalog("cura") # Model for the ToolboxLicenseDialog class LicenseModel(QObject): dialogTitleChanged = pyqtSignal() - headerChanged = pyqtSignal() + packageNameChanged = pyqtSignal() licenseTextChanged = pyqtSignal() + iconChanged = pyqtSignal() def __init__(self) -> None: super().__init__() @@ -16,21 +17,29 @@ class LicenseModel(QObject): self._current_page_idx = 0 self._page_count = 1 self._dialogTitle = "" - self._header_text = "" self._license_text = "" self._package_name = "" + self._icon_url = "" @pyqtProperty(str, notify=dialogTitleChanged) def dialogTitle(self) -> str: return self._dialogTitle - @pyqtProperty(str, notify=headerChanged) - def headerText(self) -> str: - return self._header_text + @pyqtProperty(str, notify=packageNameChanged) + def packageName(self) -> str: + return self._package_name def setPackageName(self, name: str) -> None: - self._header_text = name + ": " + catalog.i18nc("@label", "This plugin contains a license.\nYou need to accept this license to install this plugin.\nDo you agree with the terms below?") - self.headerChanged.emit() + self._package_name = name + self.packageNameChanged.emit() + + @pyqtProperty(str, notify=iconChanged) + def iconUrl(self) -> str: + return self._icon_url + + def setIconUrl(self, url: str): + self._icon_url = url + self.iconChanged.emit() @pyqtProperty(str, notify=licenseTextChanged) def licenseText(self) -> str: diff --git a/plugins/Toolbox/src/CloudSync/LicensePresenter.py b/plugins/Toolbox/src/CloudSync/LicensePresenter.py index cefe6f4037..5abf4a3b48 100644 --- a/plugins/Toolbox/src/CloudSync/LicensePresenter.py +++ b/plugins/Toolbox/src/CloudSync/LicensePresenter.py @@ -34,7 +34,7 @@ class LicensePresenter(QObject): ## Show a license dialog for multiple packages where users can read a license and accept or decline them # \param plugin_path: Root directory of the Toolbox plugin # \param packages: Dict[package id, file path] - def present(self, plugin_path: str, packages: Dict[str, str]) -> None: + def present(self, plugin_path: str, packages: Dict[str, Dict[str, str]]) -> None: path = os.path.join(plugin_path, self._compatibility_dialog_path) self._initState(packages) @@ -60,14 +60,15 @@ class LicensePresenter(QObject): self._package_models[self._current_package_idx]["accepted"] = False self._checkNextPage() - def _initState(self, packages: Dict[str, str]) -> None: + def _initState(self, packages: Dict[str, Dict[str, str]]) -> None: self._package_models = [ { "package_id" : package_id, - "package_path" : package_path, + "package_path" : item["package_path"], + "icon_url" : item["icon_url"], "accepted" : None #: None: no answer yet } - for package_id, package_path in packages.items() + for package_id, item in packages.items() ] def _presentCurrentPackage(self) -> None: @@ -80,6 +81,7 @@ class LicensePresenter(QObject): self._license_model.setCurrentPageIdx(self._current_package_idx) self._license_model.setPackageName(package_model["package_id"]) + self._license_model.setIconUrl(package_model["icon_url"]) self._license_model.setLicenseText(license_content) if self._dialog: self._dialog.open() # Does nothing if already open diff --git a/plugins/Toolbox/src/CloudSync/SyncOrchestrator.py b/plugins/Toolbox/src/CloudSync/SyncOrchestrator.py index e97bdbcbc4..4b8b3cf7f9 100644 --- a/plugins/Toolbox/src/CloudSync/SyncOrchestrator.py +++ b/plugins/Toolbox/src/CloudSync/SyncOrchestrator.py @@ -63,9 +63,9 @@ class SyncOrchestrator(Extension): self._download_presenter.download(mutations) ## Called when a set of packages have finished downloading - # \param success_items: Dict[package_id, file_path] + # \param success_items: Dict[package_id, Dict[str, str]] # \param error_items: List[package_id] - def _onDownloadFinished(self, success_items: Dict[str, str], error_items: List[str]) -> None: + def _onDownloadFinished(self, success_items: Dict[str, Dict[str, str]], error_items: List[str]) -> None: if error_items: message = i18n_catalog.i18nc("@info:generic", "{} plugins failed to download".format(len(error_items))) self._showErrorMessage(message) From 2f3cf3c493698834d9ee7cbe8c7f5c220c4610e2 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Tue, 21 Jan 2020 17:22:33 +0100 Subject: [PATCH 3/6] LicenseDialog layout tweaking CURA-7129 --- .../qml/dialogs/ToolboxLicenseDialog.qml | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/plugins/Toolbox/resources/qml/dialogs/ToolboxLicenseDialog.qml b/plugins/Toolbox/resources/qml/dialogs/ToolboxLicenseDialog.qml index dba4a5ba58..67f850ca9e 100644 --- a/plugins/Toolbox/resources/qml/dialogs/ToolboxLicenseDialog.qml +++ b/plugins/Toolbox/resources/qml/dialogs/ToolboxLicenseDialog.qml @@ -27,6 +27,7 @@ UM.Dialog ColumnLayout { anchors.fill: parent + spacing: UM.Theme.getSize("thick_margin").height UM.I18nCatalog{id: catalog; name: "cura"} @@ -45,22 +46,24 @@ UM.Dialog anchors.left: parent.left anchors.right: parent.right height: childrenRect.height - + spacing: UM.Theme.getSize("default_margin").width + leftPadding: UM.Theme.getSize("narrow_margin").width Image { - id: icon - width: 30 * screenScaleFactor - height: width - fillMode: Image.PreserveAspectFit - source: licenseModel.iconUrl || "../../images/logobot.svg" - mipmap: true + id: icon + width: 30 * screenScaleFactor + height: width + fillMode: Image.PreserveAspectFit + source: licenseModel.iconUrl || "../../images/logobot.svg" + mipmap: true } Label { id: packageName text: licenseModel.packageName + font.bold: true anchors.verticalCenter: icon.verticalCenter height: contentHeight wrapMode: Text.Wrap From 3b534ea986ae1e3b3161b39c1a037d197cc403ce Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Wed, 22 Jan 2020 10:54:05 +0100 Subject: [PATCH 4/6] Add icon to licenseDialog (Toolbox flow) CURA-7129 --- plugins/Toolbox/src/Toolbox.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/plugins/Toolbox/src/Toolbox.py b/plugins/Toolbox/src/Toolbox.py index e0d04bed5b..4835651b99 100644 --- a/plugins/Toolbox/src/Toolbox.py +++ b/plugins/Toolbox/src/Toolbox.py @@ -154,10 +154,11 @@ class Toolbox(QObject, Extension): def getLicenseDialogPluginFileLocation(self) -> str: return self._license_dialog_plugin_file_location - def openLicenseDialog(self, plugin_name: str, license_content: str, plugin_file_location: str) -> None: + def openLicenseDialog(self, plugin_name: str, license_content: str, plugin_file_location: str, icon_url: str) -> None: # Set page 1/1 when opening the dialog for a single package self._license_model.setCurrentPageIdx(0) self._license_model.setPageCount(1) + self._license_model.setIconUrl(icon_url) self._license_model.setPackageName(plugin_name) self._license_model.setLicenseText(license_content) @@ -670,14 +671,17 @@ class Toolbox(QObject, Extension): return license_content = self._package_manager.getPackageLicense(file_path) + package_id = package_info["package_id"] if license_content is not None: - self.openLicenseDialog(package_info["package_id"], license_content, file_path) + # get the icon url for package_id, make sure the result is a string, never None + icon_url = next((x["icon_url"] for x in self.packagesModel.items if x["id"] == package_id), None) or "" + self.openLicenseDialog(package_id, license_content, file_path, icon_url) return - package_id = self.install(file_path) - if package_id != package_info["package_id"]: - Logger.error("Installed package {} does not match {}".format(package_id, package_info["package_id"])) - self.subscribe(package_id) + installed_id = self.install(file_path) + if installed_id != package_id: + Logger.error("Installed package {} does not match {}".format(installed_id, package_id)) + self.subscribe(installed_id) # Getter & Setters for Properties: # -------------------------------------------------------------------------- @@ -699,14 +703,14 @@ class Toolbox(QObject, Extension): def isDownloading(self) -> bool: return self._is_downloading - def setActivePackage(self, package: Dict[str, Any]) -> None: + def setActivePackage(self, package: QObject) -> None: if self._active_package != package: self._active_package = package self.activePackageChanged.emit() ## The active package is the package that is currently being downloaded @pyqtProperty(QObject, fset = setActivePackage, notify = activePackageChanged) - def activePackage(self) -> Optional[Dict[str, Any]]: + def activePackage(self) -> Optional[QObject]: return self._active_package def setViewCategory(self, category: str = "plugin") -> None: From 95def2850d4419cf56b58edcf066ffac6397245f Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Wed, 22 Jan 2020 11:17:03 +0100 Subject: [PATCH 5/6] Make license decline button text context-dependant CURA-7129 --- .../resources/qml/dialogs/ToolboxLicenseDialog.qml | 4 ++-- plugins/Toolbox/src/CloudSync/LicenseModel.py | 14 +++++++++++++- plugins/Toolbox/src/CloudSync/LicensePresenter.py | 6 ++++-- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/plugins/Toolbox/resources/qml/dialogs/ToolboxLicenseDialog.qml b/plugins/Toolbox/resources/qml/dialogs/ToolboxLicenseDialog.qml index 67f850ca9e..c37bb099d0 100644 --- a/plugins/Toolbox/resources/qml/dialogs/ToolboxLicenseDialog.qml +++ b/plugins/Toolbox/resources/qml/dialogs/ToolboxLicenseDialog.qml @@ -90,7 +90,7 @@ UM.Dialog leftPadding: UM.Theme.getSize("dialog_primary_button_padding").width rightPadding: UM.Theme.getSize("dialog_primary_button_padding").width - text: catalog.i18nc("@button", "Agree") + text: licenseModel.acceptButtonText onClicked: { handler.onLicenseAccepted() } } ] @@ -100,7 +100,7 @@ UM.Dialog Cura.SecondaryButton { id: declineButton - text: catalog.i18nc("@button", "Decline and remove from account") + text: licenseModel.declineButtonText onClicked: { handler.onLicenseDeclined() } } ] diff --git a/plugins/Toolbox/src/CloudSync/LicenseModel.py b/plugins/Toolbox/src/CloudSync/LicenseModel.py index 66ea6ca5da..bb62cb8abd 100644 --- a/plugins/Toolbox/src/CloudSync/LicenseModel.py +++ b/plugins/Toolbox/src/CloudSync/LicenseModel.py @@ -6,12 +6,15 @@ catalog = i18nCatalog("cura") # Model for the ToolboxLicenseDialog class LicenseModel(QObject): + DEFAULT_DECLINE_BUTTON_TEXT = catalog.i18nc("@button", "Decline") + ACCEPT_BUTTON_TEXT = catalog.i18nc("@button", "Agree") + dialogTitleChanged = pyqtSignal() packageNameChanged = pyqtSignal() licenseTextChanged = pyqtSignal() iconChanged = pyqtSignal() - def __init__(self) -> None: + def __init__(self, decline_button_text: str = DEFAULT_DECLINE_BUTTON_TEXT) -> None: super().__init__() self._current_page_idx = 0 @@ -20,6 +23,15 @@ class LicenseModel(QObject): self._license_text = "" self._package_name = "" self._icon_url = "" + self._decline_button_text = decline_button_text + + @pyqtProperty(str, constant = True) + def acceptButtonText(self): + return self.ACCEPT_BUTTON_TEXT + + @pyqtProperty(str, constant = True) + def declineButtonText(self): + return self._decline_button_text @pyqtProperty(str, notify=dialogTitleChanged) def dialogTitle(self) -> str: diff --git a/plugins/Toolbox/src/CloudSync/LicensePresenter.py b/plugins/Toolbox/src/CloudSync/LicensePresenter.py index 5abf4a3b48..0982bb4162 100644 --- a/plugins/Toolbox/src/CloudSync/LicensePresenter.py +++ b/plugins/Toolbox/src/CloudSync/LicensePresenter.py @@ -17,6 +17,7 @@ class LicensePresenter(QObject): def __init__(self, app: CuraApplication) -> None: super().__init__() + self._catalog = i18nCatalog("cura") self._dialog = None # type: Optional[QObject] self._package_manager = app.getPackageManager() # type: PackageManager # Emits List[Dict[str, [Any]] containing for example @@ -25,7 +26,8 @@ class LicensePresenter(QObject): self._current_package_idx = 0 self._package_models = [] # type: List[Dict] - self._license_model = LicenseModel() # type: LicenseModel + decline_button_text = self._catalog.i18nc("@button", "Decline and remove from account") + self._license_model = LicenseModel(decline_button_text=decline_button_text) # type: LicenseModel self._app = app @@ -42,7 +44,7 @@ class LicensePresenter(QObject): if self._dialog is None: context_properties = { - "catalog": i18nCatalog("cura"), + "catalog": self._catalog, "licenseModel": self._license_model, "handler": self } From a02e8d3b587da570f8bcc805924f32ae250c7e7e Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Fri, 24 Jan 2020 10:36:36 +0100 Subject: [PATCH 6/6] Use display_name for the package name in the license dialog Implemented for both CloudSync and Toolbox --- plugins/Toolbox/src/CloudSync/LicensePresenter.py | 3 ++- plugins/Toolbox/src/Toolbox.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/Toolbox/src/CloudSync/LicensePresenter.py b/plugins/Toolbox/src/CloudSync/LicensePresenter.py index 0982bb4162..74fc2a3099 100644 --- a/plugins/Toolbox/src/CloudSync/LicensePresenter.py +++ b/plugins/Toolbox/src/CloudSync/LicensePresenter.py @@ -75,6 +75,7 @@ class LicensePresenter(QObject): def _presentCurrentPackage(self) -> None: package_model = self._package_models[self._current_package_idx] + package_info = self._package_manager.getPackageInfo(package_model["package_path"]) license_content = self._package_manager.getPackageLicense(package_model["package_path"]) if license_content is None: # Implicitly accept when there is no license @@ -82,7 +83,7 @@ class LicensePresenter(QObject): return self._license_model.setCurrentPageIdx(self._current_package_idx) - self._license_model.setPackageName(package_model["package_id"]) + self._license_model.setPackageName(package_info["display_name"]) self._license_model.setIconUrl(package_model["icon_url"]) self._license_model.setLicenseText(license_content) if self._dialog: diff --git a/plugins/Toolbox/src/Toolbox.py b/plugins/Toolbox/src/Toolbox.py index 4835651b99..72e1f59615 100644 --- a/plugins/Toolbox/src/Toolbox.py +++ b/plugins/Toolbox/src/Toolbox.py @@ -675,7 +675,7 @@ class Toolbox(QObject, Extension): if license_content is not None: # get the icon url for package_id, make sure the result is a string, never None icon_url = next((x["icon_url"] for x in self.packagesModel.items if x["id"] == package_id), None) or "" - self.openLicenseDialog(package_id, license_content, file_path, icon_url) + self.openLicenseDialog(package_info["display_name"], license_content, file_path, icon_url) return installed_id = self.install(file_path)