From 51ec8a539fa22390b9bea607e610e1ed1d5105c3 Mon Sep 17 00:00:00 2001 From: Dimitriovski Date: Thu, 16 Jan 2020 16:30:11 +0100 Subject: [PATCH 01/30] Added a 'Marketplace' icon in the header of the Toolbox CURA-7071 --- cura/ApplicationMetadata.py | 4 +- .../qml/components/ToolboxHeader.qml | 56 +++++++++++++------ plugins/Toolbox/src/Toolbox.py | 4 ++ 3 files changed, 46 insertions(+), 18 deletions(-) diff --git a/cura/ApplicationMetadata.py b/cura/ApplicationMetadata.py index 8da64beead..449cc6848a 100644 --- a/cura/ApplicationMetadata.py +++ b/cura/ApplicationMetadata.py @@ -1,4 +1,4 @@ -# Copyright (c) 2018 Ultimaker B.V. +# Copyright (c) 2020 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. # --------- @@ -56,3 +56,5 @@ try: except ImportError: CuraAppDisplayName = DEFAULT_CURA_DISPLAY_NAME + +WEB_MARKETPLACE_URL = "https://marketplace.ultimaker.com/app/cura/materials" \ No newline at end of file diff --git a/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml b/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml index 491567eb5f..de64eefff1 100644 --- a/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml +++ b/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml @@ -51,32 +51,25 @@ Item toolbox.viewPage = "overview" } } - } - ToolboxTabButton - { - id: installedTabButton - text: catalog.i18nc("@title:tab", "Installed") - active: toolbox.viewCategory == "installed" - enabled: !toolbox.isDownloading - anchors + ToolboxTabButton { - right: parent.right - rightMargin: UM.Theme.getSize("default_margin").width + id: installedTabButton + text: catalog.i18nc("@title:tab", "Installed") + active: toolbox.viewCategory == "installed" + enabled: !toolbox.isDownloading + onClicked: toolbox.viewCategory = "installed" + width: UM.Theme.getSize("toolbox_header_tab").width + marketplaceNotificationIcon.width - UM.Theme.getSize("default_margin").width } - onClicked: toolbox.viewCategory = "installed" - width: UM.Theme.getSize("toolbox_header_tab").width + marketplaceNotificationIcon.width - UM.Theme.getSize("default_margin").width + + } Cura.NotificationIcon { id: marketplaceNotificationIcon - visible: CuraApplication.getPackageManager().packagesWithUpdate.length > 0 - - anchors.right: installedTabButton.right - anchors.verticalCenter: installedTabButton.verticalCenter - + anchors.right: bar.right labelText: { const itemCount = CuraApplication.getPackageManager().packagesWithUpdate.length @@ -84,6 +77,35 @@ Item } } + + UM.TooltipArea + { + width: childrenRect.width; + height: childrenRect.height; + text: catalog.i18nc("@info:tooltip", "Go to Web Marketplace") + anchors + { + right: parent.right + rightMargin: UM.Theme.getSize("default_margin").width + verticalCenter: parent.verticalCenter + } + Image + { + id: cloudMarketplaceButton + source: "../../images/marketplace.png" + height: 45 + width: height + //width: UM.Theme.getSize("toolbox_header_tab").width + mipmap: true + fillMode: Image.PreserveAspectFit + MouseArea + { + anchors.fill: parent + onClicked: Qt.openUrlExternally(toolbox.getWebMarketplaceUrl) + } + } + } + ToolboxShadow { anchors.top: bar.bottom diff --git a/plugins/Toolbox/src/Toolbox.py b/plugins/Toolbox/src/Toolbox.py index b1928b4e84..c7ea5bf7cc 100644 --- a/plugins/Toolbox/src/Toolbox.py +++ b/plugins/Toolbox/src/Toolbox.py @@ -765,6 +765,10 @@ class Toolbox(QObject, Extension): def materialsGenericModel(self) -> PackagesModel: return self._materials_generic_model + @pyqtProperty(str, constant=True) + def getWebMarketplaceUrl(self) -> str: + return ApplicationMetadata.WEB_MARKETPLACE_URL + # Filter Models: # -------------------------------------------------------------------------- @pyqtSlot(str, str, str) From ddd2afa08a9769f87daa7d5d8a443a8351692ae6 Mon Sep 17 00:00:00 2001 From: Dimitriovski Date: Thu, 16 Jan 2020 16:30:58 +0100 Subject: [PATCH 02/30] Added dummy image downloaded from internet for presentation only. CURA-7071 --- plugins/Toolbox/resources/images/marketplace.png | Bin 0 -> 9916 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 plugins/Toolbox/resources/images/marketplace.png diff --git a/plugins/Toolbox/resources/images/marketplace.png b/plugins/Toolbox/resources/images/marketplace.png new file mode 100644 index 0000000000000000000000000000000000000000..ca4f41820ef3728554fedfda67f440f2e8035895 GIT binary patch literal 9916 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 literal 0 HcmV?d00001 From 812017c8140b0990451b6f9fb0f39c62b5783a38 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 28 Jan 2020 11:29:01 +0100 Subject: [PATCH 03/30] Switch out shop icon The sourceSize needs to be adjusted because this is an SVG that we don't necessarily want to stretch but just want to render directly at the correct size. Contributes to issue CURA-7071. --- plugins/Toolbox/resources/images/marketplace.png | Bin 9916 -> 0 bytes plugins/Toolbox/resources/images/shop.svg | 3 +++ .../resources/qml/components/ToolboxHeader.qml | 7 ++++--- 3 files changed, 7 insertions(+), 3 deletions(-) delete mode 100644 plugins/Toolbox/resources/images/marketplace.png create mode 100644 plugins/Toolbox/resources/images/shop.svg diff --git a/plugins/Toolbox/resources/images/marketplace.png b/plugins/Toolbox/resources/images/marketplace.png deleted file mode 100644 index ca4f41820ef3728554fedfda67f440f2e8035895..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9916 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 diff --git a/plugins/Toolbox/resources/images/shop.svg b/plugins/Toolbox/resources/images/shop.svg new file mode 100644 index 0000000000..64862834b0 --- /dev/null +++ b/plugins/Toolbox/resources/images/shop.svg @@ -0,0 +1,3 @@ + + + diff --git a/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml b/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml index de64eefff1..48d6c4836b 100644 --- a/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml +++ b/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Ultimaker B.V. +// Copyright (c) 2020 Ultimaker B.V. // Toolbox is released under the terms of the LGPLv3 or higher. import QtQuick 2.10 @@ -92,11 +92,12 @@ Item Image { id: cloudMarketplaceButton - source: "../../images/marketplace.png" + source: "../../images/shop.svg" height: 45 width: height + sourceSize.width: width + sourceSize.height: height //width: UM.Theme.getSize("toolbox_header_tab").width - mipmap: true fillMode: Image.PreserveAspectFit MouseArea { From 1d110c2c33f6d7970ace3d15b851bbb6b4f4c59b Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 28 Jan 2020 11:31:10 +0100 Subject: [PATCH 04/30] Reduce size of web marketplace link button Contributes to issue CURA-7071. --- plugins/Toolbox/resources/qml/components/ToolboxHeader.qml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml b/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml index 48d6c4836b..e980a063bf 100644 --- a/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml +++ b/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml @@ -81,7 +81,7 @@ Item UM.TooltipArea { width: childrenRect.width; - height: childrenRect.height; + height: parent.height text: catalog.i18nc("@info:tooltip", "Go to Web Marketplace") anchors { @@ -93,11 +93,11 @@ Item { id: cloudMarketplaceButton source: "../../images/shop.svg" - height: 45 + height: parent.height / 2 width: height + anchors.verticalCenter: parent.verticalCenter sourceSize.width: width sourceSize.height: height - //width: UM.Theme.getSize("toolbox_header_tab").width fillMode: Image.PreserveAspectFit MouseArea { From e6856b02a4d12b54f10d764202a40f183ebda7eb Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 28 Jan 2020 11:33:25 +0100 Subject: [PATCH 05/30] Make entire tooltip area clickable Also saves on another component. And it's more logical, easier to use and fault-tolerant. Contributes to issue CURA-7071. --- .../Toolbox/resources/qml/components/ToolboxHeader.qml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml b/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml index e980a063bf..817134590c 100644 --- a/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml +++ b/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml @@ -80,7 +80,7 @@ Item UM.TooltipArea { - width: childrenRect.width; + width: childrenRect.width height: parent.height text: catalog.i18nc("@info:tooltip", "Go to Web Marketplace") anchors @@ -89,6 +89,7 @@ Item rightMargin: UM.Theme.getSize("default_margin").width verticalCenter: parent.verticalCenter } + onClicked: Qt.openUrlExternally(toolbox.getWebMarketplaceUrl) Image { id: cloudMarketplaceButton @@ -99,11 +100,6 @@ Item sourceSize.width: width sourceSize.height: height fillMode: Image.PreserveAspectFit - MouseArea - { - anchors.fill: parent - onClicked: Qt.openUrlExternally(toolbox.getWebMarketplaceUrl) - } } } From 654a28450d789f77837eaef73bf7acc5fdf2536a Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 28 Jan 2020 11:36:42 +0100 Subject: [PATCH 06/30] Fix dark theme icon colour Contributes to issue CURA-7071. --- plugins/Toolbox/resources/qml/components/ToolboxHeader.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml b/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml index 817134590c..f751663670 100644 --- a/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml +++ b/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml @@ -90,16 +90,16 @@ Item verticalCenter: parent.verticalCenter } onClicked: Qt.openUrlExternally(toolbox.getWebMarketplaceUrl) - Image + UM.RecolorImage { id: cloudMarketplaceButton source: "../../images/shop.svg" + color: UM.Theme.getColor("text") height: parent.height / 2 width: height anchors.verticalCenter: parent.verticalCenter sourceSize.width: width sourceSize.height: height - fillMode: Image.PreserveAspectFit } } From ad2b8f140e085a13f813b56f403d3ef3f4df00af Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 28 Jan 2020 11:52:46 +0100 Subject: [PATCH 07/30] Make Marketplace link configurable from the build system This way you could set it to marketplace-staging if you like. Contributes to issue CURA-7071. --- CMakeLists.txt | 1 + cura/CuraVersion.py.in | 3 ++- plugins/Toolbox/src/Toolbox.py | 9 +++++++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4954ac46dc..f662c2b50f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,6 +23,7 @@ set(CURA_BUILDTYPE "" CACHE STRING "Build type of Cura, eg. 'PPA'") set(CURA_CLOUD_API_ROOT "" CACHE STRING "Alternative Cura cloud API root") set(CURA_CLOUD_API_VERSION "" CACHE STRING "Alternative Cura cloud API version") set(CURA_CLOUD_ACCOUNT_API_ROOT "" CACHE STRING "Alternative Cura cloud account API version") +set(CURA_MARKETPLACE_ROOT "" CACHE STRING "Alternative Marketplace location") configure_file(${CMAKE_SOURCE_DIR}/cura.desktop.in ${CMAKE_BINARY_DIR}/cura.desktop @ONLY) diff --git a/cura/CuraVersion.py.in b/cura/CuraVersion.py.in index 4583e76f67..32a67b8baa 100644 --- a/cura/CuraVersion.py.in +++ b/cura/CuraVersion.py.in @@ -1,4 +1,4 @@ -# Copyright (c) 2018 Ultimaker B.V. +# Copyright (c) 2020 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. CuraAppName = "@CURA_APP_NAME@" @@ -9,3 +9,4 @@ CuraDebugMode = True if "@_cura_debugmode@" == "ON" else False CuraCloudAPIRoot = "@CURA_CLOUD_API_ROOT@" CuraCloudAPIVersion = "@CURA_CLOUD_API_VERSION@" CuraCloudAccountAPIRoot = "@CURA_CLOUD_ACCOUNT_API_ROOT@" +CuraMarketplaceRoot = "@CURA_MARKETPLACE_ROOT@" \ No newline at end of file diff --git a/plugins/Toolbox/src/Toolbox.py b/plugins/Toolbox/src/Toolbox.py index c7ea5bf7cc..7f4bd919dd 100644 --- a/plugins/Toolbox/src/Toolbox.py +++ b/plugins/Toolbox/src/Toolbox.py @@ -4,7 +4,6 @@ import json import os import tempfile -import platform from typing import cast, Any, Dict, List, Set, TYPE_CHECKING, Tuple, Optional, Union from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal, pyqtSlot @@ -17,6 +16,7 @@ from UM.i18n import i18nCatalog from UM.Version import Version from cura import ApplicationMetadata +from cura.CuraVersion import CuraMarketplaceRoot from cura.CuraApplication import CuraApplication from cura.Machines.ContainerTree import ContainerTree from plugins.Toolbox.src.CloudApiModel import CloudApiModel @@ -33,6 +33,8 @@ if TYPE_CHECKING: i18n_catalog = i18nCatalog("cura") +DEFAULT_MARKETPLACE_ROOT = "https://marketplace.ultimaker.com" # type: str + # todo Remove license and download dialog, use SyncOrchestrator instead ## Provides a marketplace for users to download plugins an materials @@ -767,7 +769,10 @@ class Toolbox(QObject, Extension): @pyqtProperty(str, constant=True) def getWebMarketplaceUrl(self) -> str: - return ApplicationMetadata.WEB_MARKETPLACE_URL + root = CuraMarketplaceRoot + if root == "": + root = DEFAULT_MARKETPLACE_ROOT + return root + "/app/cura/materials" # Filter Models: # -------------------------------------------------------------------------- From 13644f7e41037e3b787fc3ac1b1547be1b592826 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 28 Jan 2020 11:57:40 +0100 Subject: [PATCH 08/30] Load different pages of Marketplace depending on current tab Feels intuitive actually, but if you think about it it's weird that the link should change depending on the tab that's next to it. Contributes to issue CURA-7071. --- .../Toolbox/resources/qml/components/ToolboxHeader.qml | 10 +++++++++- plugins/Toolbox/src/Toolbox.py | 6 +++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml b/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml index f751663670..df1a43911e 100644 --- a/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml +++ b/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml @@ -89,7 +89,15 @@ Item rightMargin: UM.Theme.getSize("default_margin").width verticalCenter: parent.verticalCenter } - onClicked: Qt.openUrlExternally(toolbox.getWebMarketplaceUrl) + onClicked: + { + let page = "plugins"; //Online page to go to on the Marketplace subdomain. + if(materialsTabButton.active) + { + page = "materials"; + } + Qt.openUrlExternally(toolbox.getWebMarketplaceUrl(page)); + } UM.RecolorImage { id: cloudMarketplaceButton diff --git a/plugins/Toolbox/src/Toolbox.py b/plugins/Toolbox/src/Toolbox.py index 7f4bd919dd..c957a0c10c 100644 --- a/plugins/Toolbox/src/Toolbox.py +++ b/plugins/Toolbox/src/Toolbox.py @@ -767,12 +767,12 @@ class Toolbox(QObject, Extension): def materialsGenericModel(self) -> PackagesModel: return self._materials_generic_model - @pyqtProperty(str, constant=True) - def getWebMarketplaceUrl(self) -> str: + @pyqtSlot(str, result = str) + def getWebMarketplaceUrl(self, page: str) -> str: root = CuraMarketplaceRoot if root == "": root = DEFAULT_MARKETPLACE_ROOT - return root + "/app/cura/materials" + return root + "/app/cura/" + page # Filter Models: # -------------------------------------------------------------------------- From 1c79193f9a325fd1a564da2ec25edcae8ce18e5c Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 28 Jan 2020 13:25:27 +0100 Subject: [PATCH 09/30] Always go to plug-ins page regardless of active tab This was a requirement from UX. Apparently we're adding a link to the materials elsewhere. Contributes to issue CURA-7071. --- .../Toolbox/resources/qml/components/ToolboxHeader.qml | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml b/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml index df1a43911e..e0cdb44d7d 100644 --- a/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml +++ b/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml @@ -89,15 +89,7 @@ Item rightMargin: UM.Theme.getSize("default_margin").width verticalCenter: parent.verticalCenter } - onClicked: - { - let page = "plugins"; //Online page to go to on the Marketplace subdomain. - if(materialsTabButton.active) - { - page = "materials"; - } - Qt.openUrlExternally(toolbox.getWebMarketplaceUrl(page)); - } + onClicked: Qt.openUrlExternally(toolbox.getWebMarketplaceUrl("plugins")) UM.RecolorImage { id: cloudMarketplaceButton From e51a1b18bed3ae320463a9e2848eea73fe303592 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 28 Jan 2020 14:19:33 +0100 Subject: [PATCH 10/30] Add link text to marketplace search page Contributes to issue CURA-7071. --- .../components/ToolboxDownloadsShowcase.qml | 35 ++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/plugins/Toolbox/resources/qml/components/ToolboxDownloadsShowcase.qml b/plugins/Toolbox/resources/qml/components/ToolboxDownloadsShowcase.qml index 72dd6f91a2..26d691ea8e 100644 --- a/plugins/Toolbox/resources/qml/components/ToolboxDownloadsShowcase.qml +++ b/plugins/Toolbox/resources/qml/components/ToolboxDownloadsShowcase.qml @@ -14,17 +14,36 @@ Rectangle Column { height: childrenRect.height + 2 * padding - spacing: UM.Theme.getSize("default_margin").width + spacing: UM.Theme.getSize("default_margin").height width: parent.width padding: UM.Theme.getSize("wide_margin").height - Label + Item { - id: heading - text: catalog.i18nc("@label", "Featured") - width: parent.width - color: UM.Theme.getColor("text_medium") - font: UM.Theme.getFont("large") - renderType: Text.NativeRendering + width: parent.width - parent.padding * 2 + height: childrenRect.height + Label + { + id: heading + text: catalog.i18nc("@label", "Featured") + width: contentWidth + height: contentHeight + color: UM.Theme.getColor("text_medium") + font: UM.Theme.getFont("large") + renderType: Text.NativeRendering + } + Label + { + text: catalog.i18nc("@label", "Search materials") + width: parent.width - heading.width + height: contentHeight + anchors.right: parent.right + horizontalAlignment: Text.AlignRight + elide: Text.ElideLeft + color: UM.Theme.getColor("text_medium") + font: UM.Theme.getFont("medium") + renderType: Text.NativeRendering + visible: toolbox.viewCategory === "material" + } } Grid { From 38e7a9e4df3555d187ba8d50ceca7c0a2b7b0ed8 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 28 Jan 2020 14:37:59 +0100 Subject: [PATCH 11/30] Turn Marketplace link into an actual link With consistent styling. The original design didn't have the link underlined but since the rest of the Cura UI has it underlined I let that happen here too. Contributes to issue CURA-7071. --- .../components/ToolboxDownloadsShowcase.qml | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/plugins/Toolbox/resources/qml/components/ToolboxDownloadsShowcase.qml b/plugins/Toolbox/resources/qml/components/ToolboxDownloadsShowcase.qml index 26d691ea8e..048ef937d1 100644 --- a/plugins/Toolbox/resources/qml/components/ToolboxDownloadsShowcase.qml +++ b/plugins/Toolbox/resources/qml/components/ToolboxDownloadsShowcase.qml @@ -31,18 +31,26 @@ Rectangle font: UM.Theme.getFont("large") renderType: Text.NativeRendering } - Label + UM.TooltipArea { - text: catalog.i18nc("@label", "Search materials") - width: parent.width - heading.width - height: contentHeight + width: childrenRect.width + height: childrenRect.height anchors.right: parent.right - horizontalAlignment: Text.AlignRight - elide: Text.ElideLeft - color: UM.Theme.getColor("text_medium") - font: UM.Theme.getFont("medium") - renderType: Text.NativeRendering - visible: toolbox.viewCategory === "material" + text: catalog.i18nc("@info:tooltip", "Go to Web Marketplace") + Label + { + text: "".arg(toolbox.getWebMarketplaceUrl("materials")) + catalog.i18nc("@label", "Search materials") + "" + width: contentWidth + height: contentHeight + horizontalAlignment: Text.AlignRight + font: UM.Theme.getFont("medium") + renderType: Text.NativeRendering + + linkColor: UM.Theme.getColor("text_link") + onLinkActivated: Qt.openUrlExternally(link) + + visible: toolbox.viewCategory === "material" + } } } Grid From 6553443f3b95527d45a1f2ddc89e948c97f3f1b0 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 28 Jan 2020 14:41:29 +0100 Subject: [PATCH 12/30] Make marketplace materials link slightly smaller Contributes to issue CURA-7071. --- .../resources/qml/components/ToolboxDownloadsShowcase.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/Toolbox/resources/qml/components/ToolboxDownloadsShowcase.qml b/plugins/Toolbox/resources/qml/components/ToolboxDownloadsShowcase.qml index 048ef937d1..9b34952ab6 100644 --- a/plugins/Toolbox/resources/qml/components/ToolboxDownloadsShowcase.qml +++ b/plugins/Toolbox/resources/qml/components/ToolboxDownloadsShowcase.qml @@ -43,7 +43,7 @@ Rectangle width: contentWidth height: contentHeight horizontalAlignment: Text.AlignRight - font: UM.Theme.getFont("medium") + font: UM.Theme.getFont("default") renderType: Text.NativeRendering linkColor: UM.Theme.getColor("text_link") From 242da1b3aa27620aaa14812aca21536cf9b71148 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 28 Jan 2020 14:47:00 +0100 Subject: [PATCH 13/30] Give web marketplace button a hover colour It needs to be the same as the bar beneath the marketplace tab buttons when highlit. Contributes to issue CURA-7071. --- plugins/Toolbox/resources/qml/components/ToolboxHeader.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml b/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml index e0cdb44d7d..3cba9a9ece 100644 --- a/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml +++ b/plugins/Toolbox/resources/qml/components/ToolboxHeader.qml @@ -80,6 +80,7 @@ Item UM.TooltipArea { + id: webMarketplaceButtonTooltipArea width: childrenRect.width height: parent.height text: catalog.i18nc("@info:tooltip", "Go to Web Marketplace") @@ -94,7 +95,7 @@ Item { id: cloudMarketplaceButton source: "../../images/shop.svg" - color: UM.Theme.getColor("text") + color: UM.Theme.getColor(webMarketplaceButtonTooltipArea.containsMouse ? "primary" : "text") height: parent.height / 2 width: height anchors.verticalCenter: parent.verticalCenter From 5a4661db988558b34dc2ece849258c98ab62ed90 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 28 Jan 2020 16:36:06 +0100 Subject: [PATCH 14/30] Add valueFromContainer() and extruderValueFromContainer() functions --- cura/CuraApplication.py | 2 ++ cura/Settings/CuraFormulaFunctions.py | 32 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 221ccf9fb0..ff563c8f2d 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -393,6 +393,8 @@ class CuraApplication(QtApplication): SettingFunction.registerOperator("extruderValues", self._cura_formula_functions.getValuesInAllExtruders) SettingFunction.registerOperator("resolveOrValue", self._cura_formula_functions.getResolveOrValue) SettingFunction.registerOperator("defaultExtruderPosition", self._cura_formula_functions.getDefaultExtruderPosition) + SettingFunction.registerOperator("valueFromContainer", self._cura_formula_functions.getValueFromContainerAtIndex) + SettingFunction.registerOperator("extruderValueFromContainer", self._cura_formula_functions.getValueFromContainerAtIndexInExtruder) # Adds all resources and container related resources. def __addAllResourcesAndContainerResources(self) -> None: diff --git a/cura/Settings/CuraFormulaFunctions.py b/cura/Settings/CuraFormulaFunctions.py index f39435be60..e4846a9da9 100644 --- a/cura/Settings/CuraFormulaFunctions.py +++ b/cura/Settings/CuraFormulaFunctions.py @@ -133,6 +133,38 @@ class CuraFormulaFunctions: context = self.createContextForDefaultValueEvaluation(global_stack) return self.getResolveOrValue(property_key, context = context) + # Gets the value for the given setting key starting from the given container index. + def getValueFromContainerAtIndex(self, property_key: str, container_index: int, + context: Optional["PropertyEvaluationContext"] = None) -> Any: + machine_manager = self._application.getMachineManager() + global_stack = machine_manager.activeMachine + + context = self.createContextForDefaultValueEvaluation(global_stack) + context.context["evaluate_from_container_index"] = container_index + + return global_stack.getProperty(property_key, "value", context = context) + + # Gets the extruder value for the given setting key starting from the given container index. + def getValueFromContainerAtIndexInExtruder(self, extruder_index: int, property_key: str, container_index: int, + context: Optional["PropertyEvaluationContext"] = None) -> Any: + machine_manager = self._application.getMachineManager() + global_stack = machine_manager.activeMachine + + if extruder_position == -1: + extruder_position = int(machine_manager.defaultExtruderPosition) + + global_stack = machine_manager.activeMachine + try: + extruder_stack = global_stack.extruderList[int(extruder_position)] + except IndexError: + Logger.log("w", "Value for %s of extruder %s was requested, but that extruder is not available. " % (property_key, extruder_position)) + return None + + context = self.createContextForDefaultValueEvaluation(extruder_stack) + context.context["evaluate_from_container_index"] = container_index + + return self.getValueInExtruder(extruder_index, property_key, context) + # Creates a context for evaluating default values (skip the user_changes container). def createContextForDefaultValueEvaluation(self, source_stack: "CuraContainerStack") -> "PropertyEvaluationContext": context = PropertyEvaluationContext(source_stack) From e79b3beed11717cbdec5567ea6e872bfdeefed19 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 30 Jan 2020 09:39:56 +0100 Subject: [PATCH 15/30] Remove unused URL CURA-7071 --- cura/ApplicationMetadata.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/cura/ApplicationMetadata.py b/cura/ApplicationMetadata.py index 449cc6848a..85b097c0ba 100644 --- a/cura/ApplicationMetadata.py +++ b/cura/ApplicationMetadata.py @@ -56,5 +56,3 @@ try: except ImportError: CuraAppDisplayName = DEFAULT_CURA_DISPLAY_NAME - -WEB_MARKETPLACE_URL = "https://marketplace.ultimaker.com/app/cura/materials" \ No newline at end of file From 18163af5a355eb7ee997cd5096fb92352b344992 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 30 Jan 2020 09:42:51 +0100 Subject: [PATCH 16/30] Ensure that the default default marketplace URL is used when not defined CURA-7071 --- plugins/Toolbox/src/Toolbox.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/Toolbox/src/Toolbox.py b/plugins/Toolbox/src/Toolbox.py index c957a0c10c..d2ce4c9011 100644 --- a/plugins/Toolbox/src/Toolbox.py +++ b/plugins/Toolbox/src/Toolbox.py @@ -16,7 +16,7 @@ from UM.i18n import i18nCatalog from UM.Version import Version from cura import ApplicationMetadata -from cura.CuraVersion import CuraMarketplaceRoot + from cura.CuraApplication import CuraApplication from cura.Machines.ContainerTree import ContainerTree from plugins.Toolbox.src.CloudApiModel import CloudApiModel @@ -35,6 +35,11 @@ i18n_catalog = i18nCatalog("cura") DEFAULT_MARKETPLACE_ROOT = "https://marketplace.ultimaker.com" # type: str +try: + from cura.CuraVersion import CuraMarketplaceRoot +except ImportError: + CuraMarketplaceRoot = DEFAULT_MARKETPLACE_ROOT + # todo Remove license and download dialog, use SyncOrchestrator instead ## Provides a marketplace for users to download plugins an materials From d15e64cc5b81a1caba013361c02d096298d38ebe Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 30 Jan 2020 09:44:15 +0100 Subject: [PATCH 17/30] Remove unused import --- plugins/Toolbox/src/Toolbox.py | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/Toolbox/src/Toolbox.py b/plugins/Toolbox/src/Toolbox.py index d2ce4c9011..dac985c28a 100644 --- a/plugins/Toolbox/src/Toolbox.py +++ b/plugins/Toolbox/src/Toolbox.py @@ -24,7 +24,6 @@ from plugins.Toolbox.src.CloudApiModel import CloudApiModel from .AuthorsModel import AuthorsModel from .CloudSync.LicenseModel import LicenseModel from .PackagesModel import PackagesModel -from .CloudSync.SubscribedPackagesModel import SubscribedPackagesModel from .UltimakerCloudScope import UltimakerCloudScope if TYPE_CHECKING: From 5f67331bac6490bd0a1a34a199d8ab9448c93441 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 30 Jan 2020 18:20:28 +0100 Subject: [PATCH 18/30] Fix "typo" caused by cleanup before push --- cura/Settings/CuraFormulaFunctions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cura/Settings/CuraFormulaFunctions.py b/cura/Settings/CuraFormulaFunctions.py index e4846a9da9..13e3dfb26e 100644 --- a/cura/Settings/CuraFormulaFunctions.py +++ b/cura/Settings/CuraFormulaFunctions.py @@ -145,7 +145,7 @@ class CuraFormulaFunctions: return global_stack.getProperty(property_key, "value", context = context) # Gets the extruder value for the given setting key starting from the given container index. - def getValueFromContainerAtIndexInExtruder(self, extruder_index: int, property_key: str, container_index: int, + def getValueFromContainerAtIndexInExtruder(self, extruder_position: int, property_key: str, container_index: int, context: Optional["PropertyEvaluationContext"] = None) -> Any: machine_manager = self._application.getMachineManager() global_stack = machine_manager.activeMachine @@ -163,7 +163,7 @@ class CuraFormulaFunctions: context = self.createContextForDefaultValueEvaluation(extruder_stack) context.context["evaluate_from_container_index"] = container_index - return self.getValueInExtruder(extruder_index, property_key, context) + return self.getValueInExtruder(extruder_position, property_key, context) # Creates a context for evaluating default values (skip the user_changes container). def createContextForDefaultValueEvaluation(self, source_stack: "CuraContainerStack") -> "PropertyEvaluationContext": From fa44da31557b0b94de6da0fc6336f1be240e6536 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 4 Feb 2020 11:46:29 +0100 Subject: [PATCH 19/30] Slightly improve wording 'Layer data' is a bit technical. --- plugins/SimulationView/SimulationView.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index adbeb7b6db..98eda48477 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -118,7 +118,7 @@ class SimulationView(CuraView): self._wireprint_warning_message = Message(catalog.i18nc("@info:status", "Cura does not accurately display layers when Wire Printing is enabled."), title = catalog.i18nc("@info:title", "Simulation View")) - self._slice_first_warning_message = Message(catalog.i18nc("@info:status", "Nothing is shown because you need to slice first."), title = catalog.i18nc("@info:title", "No layer data")) + self._slice_first_warning_message = Message(catalog.i18nc("@info:status", "Nothing is shown because you need to slice first."), title = catalog.i18nc("@info:title", "No layers to show")) QtApplication.getInstance().engineCreatedSignal.connect(self._onEngineCreated) From 94e97aff379927b76db268605f9b96ec62b8e63a Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 4 Feb 2020 13:02:07 +0100 Subject: [PATCH 20/30] Add a function that only gets called when upgrading from version 4.4 Contributes to issue CURA-7024. --- .../VersionUpgrade44to45.py | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py b/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py index 3ae25e05ae..10c9844dd6 100644 --- a/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py +++ b/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py @@ -1,6 +1,13 @@ +# Copyright (c) 2020 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + import configparser from typing import Tuple, List import io +import os # To get the path to check for hidden stacks to delete. +import re # To filter directories to search for hidden stacks to delete. +from UM.Resources import Resources # To get the path to check for hidden stacks to delete. +from UM.Version import Version # To sort folders by version number. from UM.VersionUpgrade import VersionUpgrade # Settings that were merged into one. Each one is a pair of settings. If both @@ -16,6 +23,36 @@ _removed_settings = { } class VersionUpgrade44to45(VersionUpgrade): + def __init__(self) -> None: + """ + Creates the version upgrade plug-in from 4.4 to 4.5. + + In this case the plug-in will also check for stacks that need to be + deleted. + """ + data_storage_root = os.path.dirname(Resources.getDataStoragePath()) + folders = os.listdir(data_storage_root) # All version folders. + folders = filter(lambda p: re.fullmatch(r"\d+\.\d+", p), folders) # Only folders with a correct version number as name. + latest_version = max(list(folders), key = Version) # Sort them by semantic version numbering. + if latest_version == "4.4": + self.removeHiddenStacks() + + def removeHiddenStacks(self) -> None: + """ + If starting the upgrade from 4.4, this will remove any hidden printer + stacks from the configuration folder as well as all of the user profiles + and definition changes profiles. + + This will ONLY run when upgrading from 4.4, not when e.g. upgrading from + 4.3 to 4.6 (through 4.4). This is because it's to fix a bug + (https://github.com/Ultimaker/Cura/issues/6731) that occurred in 4.4 + only, so only there will it have hidden stacks that need to be deleted. + If people upgrade from 4.3 they don't need to be deleted. If people + upgrade from 4.5 they have already been deleted previously or never got + the broken hidden stacks. + """ + pass + def getCfgVersion(self, serialised: str) -> int: parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialised) From 15d83cc6da140d2637c47d7cf0f6679d0795ba1c Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 4 Feb 2020 13:38:52 +0100 Subject: [PATCH 21/30] Fix typing issue --- plugins/Toolbox/src/CloudSync/LicensePresenter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/Toolbox/src/CloudSync/LicensePresenter.py b/plugins/Toolbox/src/CloudSync/LicensePresenter.py index 5f01166898..9e0a888320 100644 --- a/plugins/Toolbox/src/CloudSync/LicensePresenter.py +++ b/plugins/Toolbox/src/CloudSync/LicensePresenter.py @@ -63,7 +63,7 @@ class LicensePresenter(QObject): self._package_models[self._current_package_idx]["accepted"] = False self._checkNextPage() - def _initState(self, packages: Dict[str, Dict[str, str]]) -> None: + def _initState(self, packages: Dict[str, Dict[str, Any]]) -> None: implicitly_accepted_count = 0 From bb738318891863ecd399f7a41702541a34ee35df Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 4 Feb 2020 14:11:41 +0100 Subject: [PATCH 22/30] Cura directory may be empty Contributes to issue CURA-7024. --- .../VersionUpgrade44to45/VersionUpgrade44to45.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py b/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py index 10c9844dd6..917cd7f8a2 100644 --- a/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py +++ b/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py @@ -30,12 +30,18 @@ class VersionUpgrade44to45(VersionUpgrade): In this case the plug-in will also check for stacks that need to be deleted. """ + + # Only delete hidden stacks when upgrading from version 4.4. Not 4.3 or 4.5, just when you're starting out from 4.4. + # If you're starting from an earlier version, you can't have had the bug that produces too many hidden stacks (https://github.com/Ultimaker/Cura/issues/6731). + # If you're starting from a later version, the bug was already fixed. data_storage_root = os.path.dirname(Resources.getDataStoragePath()) folders = os.listdir(data_storage_root) # All version folders. - folders = filter(lambda p: re.fullmatch(r"\d+\.\d+", p), folders) # Only folders with a correct version number as name. - latest_version = max(list(folders), key = Version) # Sort them by semantic version numbering. - if latest_version == "4.4": - self.removeHiddenStacks() + folders = set(filter(lambda p: re.fullmatch(r"\d+\.\d+", p), folders)) # Only folders with a correct version number as name. + folders.difference_update({os.path.basename(Resources.getDataStoragePath())}) # Remove current version from candidates (since the folder was just copied). + if folders: + latest_version = max(folders, key = Version) # Sort them by semantic version numbering. + if latest_version == "4.4": + self.removeHiddenStacks() def removeHiddenStacks(self) -> None: """ From f38dc82ac8f3986707d83129d6f3656d8d033054 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 4 Feb 2020 14:12:57 +0100 Subject: [PATCH 23/30] Remove hidden stacks and their dependencies This searches for stacks that are hidden and removes them, and also removes any extruder stacks that depended on those hidden global stacks and any user and quality changes profiles referred to by those removed stacks. Contributes to issue CURA-7024. --- .../VersionUpgrade44to45.py | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py b/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py index 917cd7f8a2..4daf8cef83 100644 --- a/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py +++ b/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py @@ -3,9 +3,12 @@ import configparser from typing import Tuple, List +import fnmatch # To filter files that we need to delete. import io import os # To get the path to check for hidden stacks to delete. +import urllib.parse # To get the container IDs from file names. import re # To filter directories to search for hidden stacks to delete. +from UM.Logger import Logger from UM.Resources import Resources # To get the path to check for hidden stacks to delete. from UM.Version import Version # To sort folders by version number. from UM.VersionUpgrade import VersionUpgrade @@ -57,7 +60,44 @@ class VersionUpgrade44to45(VersionUpgrade): upgrade from 4.5 they have already been deleted previously or never got the broken hidden stacks. """ - pass + Logger.log("d", "Removing all hidden container stacks.") + hidden_global_stacks = set() # Which global stacks have been found? We'll delete anything referred to by these. Set of stack IDs. + hidden_extruder_stacks = set() # Which extruder stacks refer to the hidden global profiles? + hidden_instance_containers = set() # Which instance containers are referred to by the hidden stacks? + + # First find all of the hidden container stacks. + data_storage = Resources.getDataStoragePath() + for root, _, files in os.walk(data_storage): + for filename in fnmatch.filter(files, "*.global.cfg"): + parser = configparser.ConfigParser(interpolation = None) + parser.read(os.path.join(root, filename)) + if "metadata" in parser and "hidden" in parser["metadata"] and parser["metadata"]["hidden"] == "True": + stack_id = urllib.parse.unquote_plus(os.path.basename(filename).split(".")[0]) + hidden_global_stacks.add(stack_id) + # The user container and definition changes container are specific to this stack. We need to delete those too. + if "containers" in parser: + if "0" in parser["containers"]: + hidden_instance_containers.add(parser["containers"]["0"]) + if "6" in parser["containers"]: + hidden_instance_containers.add(parser["containers"]["6"]) + os.remove(os.path.join(root, filename)) + + # Walk a second time to find all extruder stacks referring to these hidden container stacks. + for root, _, files in os.walk(data_storage): + for filename in fnmatch.filter(files, "*.extruder.cfg"): + parser = configparser.ConfigParser(interpolation = None) + parser.read(os.path.join(root, filename)) + if "metadata" in parser and "machine" in parser["metadata"] and parser["metadata"]["machine"] in hidden_global_stacks: + stack_id = urllib.parse.unquote_plus(os.path.basename(filename).split(".")[0]) + hidden_extruder_stacks.add(stack_id) + os.remove(os.path.join(root, filename)) + + # Walk a third time to remove all instance containers that are referred to by either of those. + for root, _, files in os.walk(data_storage): + for filename in fnmatch.filter(files, "*.inst.cfg"): + container_id = urllib.parse.unquote_plus(os.path.basename(filename).split(".")[0]) + if container_id in hidden_instance_containers: + os.remove(os.path.join(root, filename)) def getCfgVersion(self, serialised: str) -> int: parser = configparser.ConfigParser(interpolation = None) From 5a7ec98f1e9def6e17a9387c23642bee89e4c35d Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 4 Feb 2020 11:46:29 +0100 Subject: [PATCH 24/30] Slightly improve wording 'Layer data' is a bit technical. --- plugins/SimulationView/SimulationView.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index adbeb7b6db..98eda48477 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -118,7 +118,7 @@ class SimulationView(CuraView): self._wireprint_warning_message = Message(catalog.i18nc("@info:status", "Cura does not accurately display layers when Wire Printing is enabled."), title = catalog.i18nc("@info:title", "Simulation View")) - self._slice_first_warning_message = Message(catalog.i18nc("@info:status", "Nothing is shown because you need to slice first."), title = catalog.i18nc("@info:title", "No layer data")) + self._slice_first_warning_message = Message(catalog.i18nc("@info:status", "Nothing is shown because you need to slice first."), title = catalog.i18nc("@info:title", "No layers to show")) QtApplication.getInstance().engineCreatedSignal.connect(self._onEngineCreated) From ccc295e2bccaddab56890c095f60edb295bcf56f Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 4 Feb 2020 14:20:08 +0100 Subject: [PATCH 25/30] Use sets for folder names from the start We use a set here because we want to remove the current version from it later on. However if we change the variable to contain a set instead of a list, MyPy will start complaining that we change the type. Contributes to issue CURA-7024. --- .../VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py b/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py index 4daf8cef83..09aab9b123 100644 --- a/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py +++ b/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py @@ -38,7 +38,7 @@ class VersionUpgrade44to45(VersionUpgrade): # If you're starting from an earlier version, you can't have had the bug that produces too many hidden stacks (https://github.com/Ultimaker/Cura/issues/6731). # If you're starting from a later version, the bug was already fixed. data_storage_root = os.path.dirname(Resources.getDataStoragePath()) - folders = os.listdir(data_storage_root) # All version folders. + folders = set(os.listdir(data_storage_root)) # All version folders. folders = set(filter(lambda p: re.fullmatch(r"\d+\.\d+", p), folders)) # Only folders with a correct version number as name. folders.difference_update({os.path.basename(Resources.getDataStoragePath())}) # Remove current version from candidates (since the folder was just copied). if folders: From b549d20ec519e4412a89bfcfc114fa68d35e4186 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 4 Feb 2020 15:17:31 +0100 Subject: [PATCH 26/30] Document which stack layer is which container type Contributes to issue CURA-7024. --- .../VersionUpgrade44to45/VersionUpgrade44to45.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py b/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py index 09aab9b123..6fa19c686d 100644 --- a/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py +++ b/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py @@ -76,9 +76,9 @@ class VersionUpgrade44to45(VersionUpgrade): hidden_global_stacks.add(stack_id) # The user container and definition changes container are specific to this stack. We need to delete those too. if "containers" in parser: - if "0" in parser["containers"]: + if "0" in parser["containers"]: # User container. hidden_instance_containers.add(parser["containers"]["0"]) - if "6" in parser["containers"]: + if "6" in parser["containers"]: # Definition changes container. hidden_instance_containers.add(parser["containers"]["6"]) os.remove(os.path.join(root, filename)) From 4307942544e3aa247783027c7d5bb2e9c1ad9aae Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 4 Feb 2020 15:33:06 +0100 Subject: [PATCH 27/30] Also remove instance containers referred to by extruder stacks Contributes to issue CURA-7024. --- .../VersionUpgrade44to45/VersionUpgrade44to45.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py b/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py index 6fa19c686d..e40ed03bbf 100644 --- a/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py +++ b/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py @@ -90,6 +90,12 @@ class VersionUpgrade44to45(VersionUpgrade): if "metadata" in parser and "machine" in parser["metadata"] and parser["metadata"]["machine"] in hidden_global_stacks: stack_id = urllib.parse.unquote_plus(os.path.basename(filename).split(".")[0]) hidden_extruder_stacks.add(stack_id) + # The user container and definition changes container are specific to this stack. We need to delete those too. + if "containers" in parser: + if "0" in parser["containers"]: # User container. + hidden_instance_containers.add(parser["containers"]["0"]) + if "6" in parser["containers"]: # Definition changes container. + hidden_instance_containers.add(parser["containers"]["6"]) os.remove(os.path.join(root, filename)) # Walk a third time to remove all instance containers that are referred to by either of those. From a1f3444271ff447e0ef194b3f017786861e483cc Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 4 Feb 2020 15:46:06 +0100 Subject: [PATCH 28/30] Don't delete containers from plugins directory Some plug-ins provide extra profiles and we don't want to check them or delete them regardless of what their content is. Contributes to issue CURA-7024. --- .../VersionUpgrade44to45/VersionUpgrade44to45.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py b/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py index e40ed03bbf..48edd6faf2 100644 --- a/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py +++ b/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py @@ -64,10 +64,12 @@ class VersionUpgrade44to45(VersionUpgrade): hidden_global_stacks = set() # Which global stacks have been found? We'll delete anything referred to by these. Set of stack IDs. hidden_extruder_stacks = set() # Which extruder stacks refer to the hidden global profiles? hidden_instance_containers = set() # Which instance containers are referred to by the hidden stacks? + exclude_directories = {"plugins"} # First find all of the hidden container stacks. data_storage = Resources.getDataStoragePath() - for root, _, files in os.walk(data_storage): + for root, dirs, files in os.walk(data_storage): + dirs[:] = [dir for dir in dirs if dir not in exclude_directories] for filename in fnmatch.filter(files, "*.global.cfg"): parser = configparser.ConfigParser(interpolation = None) parser.read(os.path.join(root, filename)) @@ -83,7 +85,8 @@ class VersionUpgrade44to45(VersionUpgrade): os.remove(os.path.join(root, filename)) # Walk a second time to find all extruder stacks referring to these hidden container stacks. - for root, _, files in os.walk(data_storage): + for root, dirs, files in os.walk(data_storage): + dirs[:] = [dir for dir in dirs if dir not in exclude_directories] for filename in fnmatch.filter(files, "*.extruder.cfg"): parser = configparser.ConfigParser(interpolation = None) parser.read(os.path.join(root, filename)) @@ -99,7 +102,8 @@ class VersionUpgrade44to45(VersionUpgrade): os.remove(os.path.join(root, filename)) # Walk a third time to remove all instance containers that are referred to by either of those. - for root, _, files in os.walk(data_storage): + for root, dirs, files in os.walk(data_storage): + dirs[:] = [dir for dir in dirs if dir not in exclude_directories] for filename in fnmatch.filter(files, "*.inst.cfg"): container_id = urllib.parse.unquote_plus(os.path.basename(filename).split(".")[0]) if container_id in hidden_instance_containers: From 35132665490aa1e059e51a5dd1ba127dcc642726 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 4 Feb 2020 15:52:12 +0100 Subject: [PATCH 29/30] Guard against unexpected file structures We shouldn't break on that. Contributes to issue CURA-7024. --- .../VersionUpgrade44to45.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py b/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py index 48edd6faf2..f300cb1c2d 100644 --- a/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py +++ b/plugins/VersionUpgrade/VersionUpgrade44to45/VersionUpgrade44to45.py @@ -72,7 +72,12 @@ class VersionUpgrade44to45(VersionUpgrade): dirs[:] = [dir for dir in dirs if dir not in exclude_directories] for filename in fnmatch.filter(files, "*.global.cfg"): parser = configparser.ConfigParser(interpolation = None) - parser.read(os.path.join(root, filename)) + try: + parser.read(os.path.join(root, filename)) + except OSError: # File not found or insufficient rights. + continue + except configparser.Error: # Invalid file format. + continue if "metadata" in parser and "hidden" in parser["metadata"] and parser["metadata"]["hidden"] == "True": stack_id = urllib.parse.unquote_plus(os.path.basename(filename).split(".")[0]) hidden_global_stacks.add(stack_id) @@ -89,7 +94,12 @@ class VersionUpgrade44to45(VersionUpgrade): dirs[:] = [dir for dir in dirs if dir not in exclude_directories] for filename in fnmatch.filter(files, "*.extruder.cfg"): parser = configparser.ConfigParser(interpolation = None) - parser.read(os.path.join(root, filename)) + try: + parser.read(os.path.join(root, filename)) + except OSError: # File not found or insufficient rights. + continue + except configparser.Error: # Invalid file format. + continue if "metadata" in parser and "machine" in parser["metadata"] and parser["metadata"]["machine"] in hidden_global_stacks: stack_id = urllib.parse.unquote_plus(os.path.basename(filename).split(".")[0]) hidden_extruder_stacks.add(stack_id) @@ -107,7 +117,10 @@ class VersionUpgrade44to45(VersionUpgrade): for filename in fnmatch.filter(files, "*.inst.cfg"): container_id = urllib.parse.unquote_plus(os.path.basename(filename).split(".")[0]) if container_id in hidden_instance_containers: - os.remove(os.path.join(root, filename)) + try: + os.remove(os.path.join(root, filename)) + except OSError: # Is a directory, file not found, or insufficient rights. + continue def getCfgVersion(self, serialised: str) -> int: parser = configparser.ConfigParser(interpolation = None) From 0520f9a4bc428a212a7d470d754ba7cdbb1d57d8 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 4 Feb 2020 16:46:35 +0100 Subject: [PATCH 30/30] Ensure that setActiveExtruderCount correctly emits the extruderEnablechanged signal --- cura/Settings/MachineManager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index f78a21aaad..25152b3d5b 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -800,7 +800,7 @@ class MachineManager(QObject): definition_changes_container.setProperty("machine_extruder_count", "value", extruder_count) self.updateDefaultExtruder() - self.updateNumberExtrudersEnabled() + self.numberExtrudersEnabledChanged.emit() self.correctExtruderSettings() # Check to see if any objects are set to print with an extruder that will no longer exist