From f4395cc6471a01ed16680c13900fae92fb96c57c Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Thu, 12 Sep 2019 14:04:30 +0200 Subject: [PATCH 01/28] Correct comment. --- cura/PreviewPass.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/PreviewPass.py b/cura/PreviewPass.py index c1a64cb07c..58205ba708 100644 --- a/cura/PreviewPass.py +++ b/cura/PreviewPass.py @@ -64,7 +64,7 @@ class PreviewPass(RenderPass): self._shader.setUniformValue("u_ambientColor", [0.1, 0.1, 0.1, 1.0]) self._shader.setUniformValue("u_specularColor", [0.6, 0.6, 0.6, 1.0]) self._shader.setUniformValue("u_shininess", 20.0) - self._shader.setUniformValue("u_faceId", -1) # de-select any selected faces + self._shader.setUniformValue("u_faceId", -1) # Don't render any selected faces in the preview. if not self._non_printing_shader: if self._non_printing_shader: From 2d2bf9e2794c748402c2c83d3687556cf3a46b7b Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 12 Sep 2019 15:25:01 +0200 Subject: [PATCH 02/28] Use logger for errors instead of printing them to stdout This way they will show up in users' logs. --- .../UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py index b775d603d8..bacf52e649 100644 --- a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py +++ b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py @@ -1,10 +1,11 @@ # Copyright (c) 2019 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from typing import Dict, List, Optional +from typing import Dict, List, Optional from PyQt5.QtCore import QTimer from UM import i18nCatalog +from UM.Logger import Logger # To log errors talking to the API. from UM.Signal import Signal from cura.API import Account from cura.CuraApplication import CuraApplication @@ -37,7 +38,7 @@ class CloudOutputDeviceManager: # Persistent dict containing the remote clusters for the authenticated user. self._remote_clusters = {} # type: Dict[str, CloudOutputDevice] self._account = CuraApplication.getInstance().getCuraAPI().account # type: Account - self._api = CloudApiClient(self._account, on_error=lambda error: print(error)) + self._api = CloudApiClient(self._account, on_error = lambda error: Logger.log("e", error)) self._account.loginStateChanged.connect(self._onLoginStateChanged) # Create a timer to update the remote cluster list From 3a3aeb92a98c03261d61bba76e287b917aae8fa7 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 12 Sep 2019 15:45:10 +0200 Subject: [PATCH 03/28] Log errors rather than printing them This way we can debug them if a user sends us the logs. --- .../src/Network/LocalClusterOutputDevice.py | 4 +++- .../src/Network/LocalClusterOutputDeviceManager.py | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py b/plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py index fd9a9e2f60..a149b9f404 100644 --- a/plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py +++ b/plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py @@ -1,5 +1,6 @@ # Copyright (c) 2019 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. + from typing import Optional, Dict, List, Callable, Any from PyQt5.QtGui import QDesktopServices @@ -8,6 +9,7 @@ from PyQt5.QtNetwork import QNetworkReply from UM.FileHandler.FileHandler import FileHandler from UM.i18n import i18nCatalog +from UM.Logger import Logger from UM.Scene.SceneNode import SceneNode from cura.PrinterOutput.NetworkedPrinterOutputDevice import AuthState from cura.PrinterOutput.PrinterOutputDevice import ConnectionType @@ -167,5 +169,5 @@ class LocalClusterOutputDevice(UltimakerNetworkedPrinterOutputDevice): ## Get the API client instance. def _getApiClient(self) -> ClusterApiClient: if not self._cluster_api: - self._cluster_api = ClusterApiClient(self.address, on_error=lambda error: print(error)) + self._cluster_api = ClusterApiClient(self.address, on_error = lambda error: Logger.log("e", error)) return self._cluster_api diff --git a/plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDeviceManager.py b/plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDeviceManager.py index 89fd71d03c..9422927a37 100644 --- a/plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDeviceManager.py +++ b/plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDeviceManager.py @@ -1,5 +1,6 @@ # Copyright (c) 2019 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. + from typing import Dict, Optional, Callable, List from UM import i18nCatalog @@ -66,7 +67,7 @@ class LocalClusterOutputDeviceManager: ## Add a networked printer manually by address. def addManualDevice(self, address: str, callback: Optional[Callable[[bool, str], None]] = None) -> None: - api_client = ClusterApiClient(address, lambda error: print(error)) + api_client = ClusterApiClient(address, lambda error: Logger.log("e", error)) api_client.getSystem(lambda status: self._onCheckManualDeviceResponse(address, status, callback)) ## Remove a manually added networked printer. From b8ab04df4a992f1be8e3558083125030a6a780f3 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 12 Sep 2019 15:58:09 +0200 Subject: [PATCH 04/28] Correct type of logged item --- .../UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py | 2 +- .../UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py | 2 +- .../src/Network/LocalClusterOutputDeviceManager.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py index bacf52e649..8d35b41fa2 100644 --- a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py +++ b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py @@ -38,7 +38,7 @@ class CloudOutputDeviceManager: # Persistent dict containing the remote clusters for the authenticated user. self._remote_clusters = {} # type: Dict[str, CloudOutputDevice] self._account = CuraApplication.getInstance().getCuraAPI().account # type: Account - self._api = CloudApiClient(self._account, on_error = lambda error: Logger.log("e", error)) + self._api = CloudApiClient(self._account, on_error = lambda error: Logger.log("e", str(error))) self._account.loginStateChanged.connect(self._onLoginStateChanged) # Create a timer to update the remote cluster list diff --git a/plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py b/plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py index a149b9f404..dd9c0a7d2a 100644 --- a/plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py +++ b/plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py @@ -169,5 +169,5 @@ class LocalClusterOutputDevice(UltimakerNetworkedPrinterOutputDevice): ## Get the API client instance. def _getApiClient(self) -> ClusterApiClient: if not self._cluster_api: - self._cluster_api = ClusterApiClient(self.address, on_error = lambda error: Logger.log("e", error)) + self._cluster_api = ClusterApiClient(self.address, on_error = lambda error: Logger.log("e", str(error))) return self._cluster_api diff --git a/plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDeviceManager.py b/plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDeviceManager.py index 9422927a37..b725224d81 100644 --- a/plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDeviceManager.py +++ b/plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDeviceManager.py @@ -67,7 +67,7 @@ class LocalClusterOutputDeviceManager: ## Add a networked printer manually by address. def addManualDevice(self, address: str, callback: Optional[Callable[[bool, str], None]] = None) -> None: - api_client = ClusterApiClient(address, lambda error: Logger.log("e", error)) + api_client = ClusterApiClient(address, lambda error: Logger.log("e", str(error))) api_client.getSystem(lambda status: self._onCheckManualDeviceResponse(address, status, callback)) ## Remove a manually added networked printer. From 1e130637ee444e77a3cac2acbf43898c401a52d7 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 13 Sep 2019 10:38:52 +0200 Subject: [PATCH 05/28] Remove retry action from login It doesn't work anyway and there is another way that does work (eg; login via the top right) --- cura/OAuth2/AuthorizationService.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/cura/OAuth2/AuthorizationService.py b/cura/OAuth2/AuthorizationService.py index 95ea47112e..68756f8df6 100644 --- a/cura/OAuth2/AuthorizationService.py +++ b/cura/OAuth2/AuthorizationService.py @@ -199,8 +199,6 @@ class AuthorizationService: self._unable_to_get_data_message.hide() self._unable_to_get_data_message = Message(i18n_catalog.i18nc("@info", "Unable to reach the Ultimaker account server."), title = i18n_catalog.i18nc("@info:title", "Warning")) - self._unable_to_get_data_message.addAction("retry", i18n_catalog.i18nc("@action:button", "Retry"), "[no_icon]", "[no_description]") - self._unable_to_get_data_message.actionTriggered.connect(self._onMessageActionTriggered) self._unable_to_get_data_message.show() except ValueError: Logger.logException("w", "Could not load auth data from preferences") @@ -222,6 +220,3 @@ class AuthorizationService: self.accessTokenChanged.emit() - def _onMessageActionTriggered(self, _, action): - if action == "retry": - self.loadAuthDataFromPreferences() From e8b48a299b0a3ff0fad29fed4ea43a9a559eb2a4 Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Fri, 13 Sep 2019 10:45:42 +0200 Subject: [PATCH 06/28] Store in preferences if the user wants to hide the message --- .../Messages/CloudPrinterDetectedMessage.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/plugins/UM3NetworkPrinting/src/Messages/CloudPrinterDetectedMessage.py b/plugins/UM3NetworkPrinting/src/Messages/CloudPrinterDetectedMessage.py index 0acb6c5066..3a1a9f0e0f 100644 --- a/plugins/UM3NetworkPrinting/src/Messages/CloudPrinterDetectedMessage.py +++ b/plugins/UM3NetworkPrinting/src/Messages/CloudPrinterDetectedMessage.py @@ -2,7 +2,7 @@ # Cura is released under the terms of the LGPLv3 or higher. from UM import i18nCatalog from UM.Message import Message - +from cura.CuraApplication import CuraApplication I18N_CATALOG = i18nCatalog("cura") @@ -13,16 +13,25 @@ class CloudPrinterDetectedMessage(Message): # Singleton used to prevent duplicate messages of this type at the same time. __is_visible = False + # Store in preferences to hide this message in the future. + _preference_key = "cloud/block_new_printers_popup" + def __init__(self) -> None: super().__init__( title=I18N_CATALOG.i18nc("@info:title", "New cloud printers found"), text=I18N_CATALOG.i18nc("@info:message", "New printers have been found connected to your account, " "you can find them in your list of discovered printers."), - lifetime=10, - dismissable=True + lifetime=0, + dismissable=True, + option_state=False, + option_text=I18N_CATALOG.i18nc("@info:option_text", "Do not show this message again") ) + self.optionToggled.connect(self._onDontAskMeAgain) + CuraApplication.getInstance().getPreferences().addPreference(self._preference_key, False) def show(self) -> None: + if CuraApplication.getInstance().getPreferences().getValue(self._preference_key): + return if CloudPrinterDetectedMessage.__is_visible: return super().show() @@ -31,3 +40,6 @@ class CloudPrinterDetectedMessage(Message): def hide(self, send_signal = True) -> None: super().hide(send_signal) CloudPrinterDetectedMessage.__is_visible = False + + def _onDontAskMeAgain(self, checked: bool) -> None: + CuraApplication.getInstance().getPreferences().setValue(self._preference_key, checked) From 2395567f1eb505a814f3b305e5a59138dfe8c144 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 13 Sep 2019 10:49:35 +0200 Subject: [PATCH 07/28] Only show printerTypes for active machine --- resources/qml/PrinterSelector/MachineSelectorButton.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/qml/PrinterSelector/MachineSelectorButton.qml b/resources/qml/PrinterSelector/MachineSelectorButton.qml index c37823ba82..7fa2006687 100644 --- a/resources/qml/PrinterSelector/MachineSelectorButton.qml +++ b/resources/qml/PrinterSelector/MachineSelectorButton.qml @@ -72,6 +72,7 @@ Button verticalCenter: parent.verticalCenter } spacing: UM.Theme.getSize("narrow_margin").width + visible: machineSelectorButton.checked Repeater { From 5dfb8216df28675a6c27fbb8b4abd92bf16181d9 Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Fri, 13 Sep 2019 11:06:34 +0200 Subject: [PATCH 08/28] Fix loading popup image on windows --- plugins/UM3NetworkPrinting/src/Messages/CloudFlowMessage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/UM3NetworkPrinting/src/Messages/CloudFlowMessage.py b/plugins/UM3NetworkPrinting/src/Messages/CloudFlowMessage.py index 4f2f7a71a2..311356de8e 100644 --- a/plugins/UM3NetworkPrinting/src/Messages/CloudFlowMessage.py +++ b/plugins/UM3NetworkPrinting/src/Messages/CloudFlowMessage.py @@ -28,7 +28,7 @@ class CloudFlowMessage(Message): lifetime=0, dismissable=True, option_state=False, - image_source=image_path, + image_source=QUrl.fromLocalFile(image_path), image_caption=I18N_CATALOG.i18nc("@info:status Ultimaker Cloud should not be translated.", "Connect to Ultimaker Cloud"), ) From 55cdb07c1c8dd760bc4119dbfd582c472330d2cc Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Fri, 13 Sep 2019 11:06:34 +0200 Subject: [PATCH 09/28] Fix loading popup image on windows --- plugins/UM3NetworkPrinting/src/Messages/CloudFlowMessage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/UM3NetworkPrinting/src/Messages/CloudFlowMessage.py b/plugins/UM3NetworkPrinting/src/Messages/CloudFlowMessage.py index 4f2f7a71a2..311356de8e 100644 --- a/plugins/UM3NetworkPrinting/src/Messages/CloudFlowMessage.py +++ b/plugins/UM3NetworkPrinting/src/Messages/CloudFlowMessage.py @@ -28,7 +28,7 @@ class CloudFlowMessage(Message): lifetime=0, dismissable=True, option_state=False, - image_source=image_path, + image_source=QUrl.fromLocalFile(image_path), image_caption=I18N_CATALOG.i18nc("@info:status Ultimaker Cloud should not be translated.", "Connect to Ultimaker Cloud"), ) From 756c21cd1928b91f9e82e84a94f81c1e43877709 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Fri, 13 Sep 2019 13:33:06 +0200 Subject: [PATCH 10/28] Remove extra empty lines in ChangeAtZ-scipt output. --- plugins/PostProcessingPlugin/scripts/ChangeAtZ.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/PostProcessingPlugin/scripts/ChangeAtZ.py b/plugins/PostProcessingPlugin/scripts/ChangeAtZ.py index ba7b06bb1b..cdbb4a79ef 100644 --- a/plugins/PostProcessingPlugin/scripts/ChangeAtZ.py +++ b/plugins/PostProcessingPlugin/scripts/ChangeAtZ.py @@ -367,6 +367,8 @@ class ChangeAtZ(Script): modified_gcode = "" lines = active_layer.split("\n") for line in lines: + if line.strip() == "": + continue if ";Generated with Cura_SteamEngine" in line: TWinstances += 1 modified_gcode += ";ChangeAtZ instances: %d\n" % TWinstances From 0ff9d72c4c3bba930dc7f6eac243a981cbc3e641 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 13 Sep 2019 14:11:55 +0200 Subject: [PATCH 11/28] Remove use of deprecated extruders property --- cura/BuildVolume.py | 15 ++-- cura/CuraApplication.py | 6 +- cura/Machines/MachineErrorChecker.py | 6 +- cura/Machines/Models/BaseMaterialsModel.py | 16 ++-- cura/Machines/Models/UserChangesModel.py | 2 +- cura/Machines/QualityManager.py | 9 ++- cura/Settings/CuraFormulaFunctions.py | 15 ++-- cura/Settings/ExtruderManager.py | 10 ++- cura/Settings/ExtruderStack.py | 7 +- cura/Settings/MachineManager.py | 81 ++++++++++--------- cura/Settings/SimpleModeSettingsManager.py | 4 +- cura/UI/PrintInformation.py | 6 +- .../CuraEngineBackend/CuraEngineBackend.py | 7 +- plugins/ModelChecker/ModelChecker.py | 8 +- plugins/SolidView/SolidView.py | 9 ++- 15 files changed, 111 insertions(+), 90 deletions(-) diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index 17b28c12c8..567bc0cd16 100755 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -269,10 +269,11 @@ class BuildVolume(SceneNode): continue # Mark the node as outside build volume if the set extruder is disabled extruder_position = node.callDecoration("getActiveExtruderPosition") - if extruder_position not in self._global_container_stack.extruders: - continue - if not self._global_container_stack.extruders[extruder_position].isEnabled: - node.setOutsideBuildArea(True) + try: + if not self._global_container_stack.extrudersList[int(extruder_position)].isEnabled: + node.setOutsideBuildArea(True) + continue + except IndexError: continue node.setOutsideBuildArea(False) @@ -319,7 +320,7 @@ class BuildVolume(SceneNode): # Mark the node as outside build volume if the set extruder is disabled extruder_position = node.callDecoration("getActiveExtruderPosition") - if not self._global_container_stack.extruders[extruder_position].isEnabled: + if not self._global_container_stack.extruderList[int(extruder_position)].isEnabled: node.setOutsideBuildArea(True) return @@ -549,7 +550,7 @@ class BuildVolume(SceneNode): return old_raft_thickness = self._raft_thickness - if self._global_container_stack.extruders: + if self._global_container_stack.extruderList: # This might be called before the extruder stacks have initialised, in which case getting the adhesion_type fails self._adhesion_type = self._global_container_stack.getProperty("adhesion_type", "value") self._raft_thickness = 0.0 @@ -1098,7 +1099,7 @@ class BuildVolume(SceneNode): # not part of the collision radius, such as bed adhesion (skirt/brim/raft) # and travel avoid distance. def getEdgeDisallowedSize(self): - if not self._global_container_stack or not self._global_container_stack.extruders: + if not self._global_container_stack or not self._global_container_stack.extruderList: return 0 container_stack = self._global_container_stack diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index ef85bf7457..0877aedb1b 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -660,14 +660,14 @@ class CuraApplication(QtApplication): def discardOrKeepProfileChangesClosed(self, option: str) -> None: global_stack = self.getGlobalContainerStack() if option == "discard": - for extruder in global_stack.extruders.values(): + for extruder in global_stack.extruderList: extruder.userChanges.clear() global_stack.userChanges.clear() # if the user decided to keep settings then the user settings should be re-calculated and validated for errors # before slicing. To ensure that slicer uses right settings values elif option == "keep": - for extruder in global_stack.extruders.values(): + for extruder in global_stack.extruderList: extruder.userChanges.update() global_stack.userChanges.update() @@ -1668,7 +1668,7 @@ class CuraApplication(QtApplication): arranger = Arrange.create(x = machine_width, y = machine_depth, fixed_nodes = fixed_nodes) min_offset = 8 default_extruder_position = self.getMachineManager().defaultExtruderPosition - default_extruder_id = self._global_container_stack.extruders[default_extruder_position].getId() + default_extruder_id = self._global_container_stack.extruderList[int(default_extruder_position)].getId() select_models_on_load = self.getPreferences().getValue("cura/select_models_on_load") diff --git a/cura/Machines/MachineErrorChecker.py b/cura/Machines/MachineErrorChecker.py index 964331909c..cfeeb630df 100644 --- a/cura/Machines/MachineErrorChecker.py +++ b/cura/Machines/MachineErrorChecker.py @@ -67,7 +67,7 @@ class MachineErrorChecker(QObject): self._global_stack.propertyChanged.disconnect(self.startErrorCheckPropertyChanged) self._global_stack.containersChanged.disconnect(self.startErrorCheck) - for extruder in self._global_stack.extruders.values(): + for extruder in self._global_stack.extruderList: extruder.propertyChanged.disconnect(self.startErrorCheckPropertyChanged) extruder.containersChanged.disconnect(self.startErrorCheck) @@ -77,7 +77,7 @@ class MachineErrorChecker(QObject): self._global_stack.propertyChanged.connect(self.startErrorCheckPropertyChanged) self._global_stack.containersChanged.connect(self.startErrorCheck) - for extruder in self._global_stack.extruders.values(): + for extruder in self._global_stack.extruderList: extruder.propertyChanged.connect(self.startErrorCheckPropertyChanged) extruder.containersChanged.connect(self.startErrorCheck) @@ -127,7 +127,7 @@ class MachineErrorChecker(QObject): # Populate the (stack, key) tuples to check self._stacks_and_keys_to_check = deque() - for stack in global_stack.extruders.values(): + for stack in global_stack.extruderList: for key in stack.getAllKeys(): self._stacks_and_keys_to_check.append((stack, key)) diff --git a/cura/Machines/Models/BaseMaterialsModel.py b/cura/Machines/Models/BaseMaterialsModel.py index e936877923..2c9c7607ad 100644 --- a/cura/Machines/Models/BaseMaterialsModel.py +++ b/cura/Machines/Models/BaseMaterialsModel.py @@ -70,7 +70,12 @@ class BaseMaterialsModel(ListModel): if self._extruder_stack is not None: self._extruder_stack.pyqtContainersChanged.disconnect(self._update) self._extruder_stack.approximateMaterialDiameterChanged.disconnect(self._update) - self._extruder_stack = global_stack.extruders.get(str(self._extruder_position)) + + try: + self._extruder_stack = global_stack.extruderList[self._extruder_position] + except IndexError: + self._extruder_stack = None + if self._extruder_stack is not None: self._extruder_stack.pyqtContainersChanged.connect(self._update) self._extruder_stack.approximateMaterialDiameterChanged.connect(self._update) @@ -113,12 +118,11 @@ class BaseMaterialsModel(ListModel): if global_stack is None or not self._enabled: return False - extruder_position = str(self._extruder_position) - - if extruder_position not in global_stack.extruders: + try: + extruder_stack = global_stack.extruderList[self._extruder_position] + except IndexError: return False - - extruder_stack = global_stack.extruders[extruder_position] + self._available_materials = self._material_manager.getAvailableMaterialsForMachineExtruder(global_stack, extruder_stack) if self._available_materials is None: return False diff --git a/cura/Machines/Models/UserChangesModel.py b/cura/Machines/Models/UserChangesModel.py index e629295397..ec623f0f38 100644 --- a/cura/Machines/Models/UserChangesModel.py +++ b/cura/Machines/Models/UserChangesModel.py @@ -50,7 +50,7 @@ class UserChangesModel(ListModel): return stacks = [global_stack] - stacks.extend(global_stack.extruders.values()) + stacks.extend(global_stack.extruderList) # Check if the definition container has a translation file and ensure it's loaded. definition = global_stack.getBottom() diff --git a/cura/Machines/QualityManager.py b/cura/Machines/QualityManager.py index 7da4f4f0d6..70fadc792b 100644 --- a/cura/Machines/QualityManager.py +++ b/cura/Machines/QualityManager.py @@ -154,8 +154,13 @@ class QualityManager(QObject): def _updateQualityGroupsAvailability(self, machine: "GlobalStack", quality_group_list) -> None: used_extruders = set() for i in range(machine.getProperty("machine_extruder_count", "value")): - if str(i) in machine.extruders and machine.extruders[str(i)].isEnabled: - used_extruders.add(str(i)) + try: + extruder = machine.extruderList[int(i)] + except IndexError: + pass + else: + if extruder.isEnabled: + used_extruders.add(str(i)) # Update the "is_available" flag for each quality group. for quality_group in quality_group_list: diff --git a/cura/Settings/CuraFormulaFunctions.py b/cura/Settings/CuraFormulaFunctions.py index a8b416eeb5..b35069da6f 100644 --- a/cura/Settings/CuraFormulaFunctions.py +++ b/cura/Settings/CuraFormulaFunctions.py @@ -40,8 +40,8 @@ class CuraFormulaFunctions: global_stack = machine_manager.activeMachine try: - extruder_stack = global_stack.extruders[str(extruder_position)] - except KeyError: + extruder_stack = global_stack.extruderList[int(extruder_position)] + except IndexError: if extruder_position != 0: Logger.log("w", "Value for %s of extruder %s was requested, but that extruder is not available. Returning the result form extruder 0 instead" % (property_key, extruder_position)) # This fixes a very specific fringe case; If a profile was created for a custom printer and one of the @@ -104,11 +104,14 @@ class CuraFormulaFunctions: machine_manager = self._application.getMachineManager() global_stack = machine_manager.activeMachine - extruder_stack = global_stack.extruders[str(extruder_position)] + try: + extruder_stack = global_stack.extruderList[extruder_position] + except IndexError: + Logger.log("w", "Unable to find extruder on in index %s", extruder_position) + else: + context = self.createContextForDefaultValueEvaluation(extruder_stack) - context = self.createContextForDefaultValueEvaluation(extruder_stack) - - return self.getValueInExtruder(extruder_position, property_key, context = context) + return self.getValueInExtruder(extruder_position, property_key, context = context) # Gets all default setting values as a list from all extruders of the currently active machine. # The default values are those excluding the values in the user_changes container. diff --git a/cura/Settings/ExtruderManager.py b/cura/Settings/ExtruderManager.py index 2fa90f9636..417f7b01ff 100755 --- a/cura/Settings/ExtruderManager.py +++ b/cura/Settings/ExtruderManager.py @@ -74,7 +74,7 @@ class ExtruderManager(QObject): global_container_stack = self._application.getGlobalContainerStack() if global_container_stack: - extruder_stack_ids = {position: extruder.id for position, extruder in global_container_stack.extruders.items()} + extruder_stack_ids = {extruder.getMetaDataEntry("position", ""): extruder.id for extruder in global_container_stack.extruderList} return extruder_stack_ids @@ -360,10 +360,14 @@ class ExtruderManager(QObject): def fixSingleExtrusionMachineExtruderDefinition(self, global_stack: "GlobalStack") -> None: container_registry = ContainerRegistry.getInstance() expected_extruder_definition_0_id = global_stack.getMetaDataEntry("machine_extruder_trains")["0"] - extruder_stack_0 = global_stack.extruders.get("0") + try: + extruder_stack_0 = global_stack.extruderList[0] + except IndexError: + extruder_stack_0 = None + # At this point, extruder stacks for this machine may not have been loaded yet. In this case, need to look in # the container registry as well. - if not global_stack.extruders: + if not global_stack.extruderList: extruder_trains = container_registry.findContainerStacks(type = "extruder_train", machine = global_stack.getId()) if extruder_trains: diff --git a/cura/Settings/ExtruderStack.py b/cura/Settings/ExtruderStack.py index edb0e7d41f..9983ab6c98 100644 --- a/cura/Settings/ExtruderStack.py +++ b/cura/Settings/ExtruderStack.py @@ -135,12 +135,15 @@ class ExtruderStack(CuraContainerStack): if limit_to_extruder == -1: limit_to_extruder = int(cura.CuraApplication.CuraApplication.getInstance().getMachineManager().defaultExtruderPosition) limit_to_extruder = str(limit_to_extruder) + if (limit_to_extruder is not None and limit_to_extruder != "-1") and self.getMetaDataEntry("position") != str(limit_to_extruder): - if str(limit_to_extruder) in self.getNextStack().extruders: - result = self.getNextStack().extruders[str(limit_to_extruder)].getProperty(key, property_name, context) + try: + result = self.getNextStack().extruderList[int(limit_to_extruder)].getProperty(key, property_name, context) if result is not None: context.popContainer() return result + except IndexError: + pass result = super().getProperty(key, property_name, context) context.popContainer() diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 7b7974e6b2..560cb2ad5c 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -184,7 +184,7 @@ class MachineManager(QObject): # Create the configuration model with the current data in Cura self._current_printer_configuration.printerType = self._global_container_stack.definition.getName() self._current_printer_configuration.extruderConfigurations = [] - for extruder in self._global_container_stack.extruders.values(): + for extruder in self._global_container_stack.extruderList: extruder_configuration = ExtruderConfigurationModel() # For compare just the GUID is needed at this moment mat_type = extruder.material.getMetaDataEntry("material") if extruder.material != empty_material_container else None @@ -294,13 +294,13 @@ class MachineManager(QObject): ## Given a global_stack, make sure that it's all valid by searching for this quality group and applying it again def _initMachineState(self, global_stack: "CuraContainerStack") -> None: material_dict = {} - for position, extruder in global_stack.extruders.items(): - material_dict[position] = extruder.material.getMetaDataEntry("base_file") + for position, extruder in enumerate(global_stack.extruderList): + material_dict[str(position)] = extruder.material.getMetaDataEntry("base_file") self._current_root_material_id = material_dict # Update materials to make sure that the diameters match with the machine's - for position in global_stack.extruders: - self.updateMaterialWithVariant(position) + for position, _ in enumerate(global_stack.extruderList): + self.updateMaterialWithVariant(str(position)) global_quality = global_stack.quality quality_type = global_quality.getMetaDataEntry("quality_type") @@ -686,7 +686,7 @@ class MachineManager(QObject): def isCurrentSetupSupported(self) -> bool: if not self._global_container_stack: return False - for stack in [self._global_container_stack] + list(self._global_container_stack.extruders.values()): + for stack in [self._global_container_stack] + self._global_container_stack.extruderList: for container in stack.getContainers(): if not container: return False @@ -712,8 +712,8 @@ class MachineManager(QObject): def copyAllValuesToExtruders(self) -> None: if self._active_container_stack is None or self._global_container_stack is None: return - extruder_stacks = list(self._global_container_stack.extruders.values()) - for extruder_stack in extruder_stacks: + + for extruder_stack in self._global_container_stack.extruderList: if extruder_stack != self._active_container_stack: for key in self._active_container_stack.userChanges.getAllKeys(): new_value = self._active_container_stack.getProperty(key, "value") @@ -843,8 +843,7 @@ class MachineManager(QObject): return True buildplate_compatible = True # It is compatible by default - extruder_stacks = self._global_container_stack.extruders.values() - for stack in extruder_stacks: + for stack in self._global_container_stack.extruderList: if not stack.isEnabled: continue material_container = stack.material @@ -867,8 +866,8 @@ class MachineManager(QObject): # (material_left_compatible or material_left_usable) and # (material_right_compatible or material_right_usable) result = not self.variantBuildplateCompatible - extruder_stacks = self._global_container_stack.extruders.values() - for stack in extruder_stacks: + + for stack in self._global_container_stack.extruderList: material_container = stack.material if material_container == empty_material_container: continue @@ -904,7 +903,7 @@ class MachineManager(QObject): old_value = old_value(self._global_container_stack) if int(old_value) < 0: continue - if int(old_value) >= extruder_count or not self._global_container_stack.extruders[str(old_value)].isEnabled: + if int(old_value) >= extruder_count or not self._global_container_stack.extruderList[int(old_value)].isEnabled: result.append(setting_key) Logger.log("d", "Reset setting [%s] in [%s] because its old value [%s] is no longer valid", setting_key, container, old_value) return result @@ -993,18 +992,18 @@ class MachineManager(QObject): @deprecated("use Cura.MachineManager.activeMachine.extruders instead", "4.2") def _getExtruder(self, position) -> Optional[ExtruderStack]: if self._global_container_stack: - return self._global_container_stack.extruders.get(str(position)) + return self._global_container_stack.extruderList[int(position)] return None def updateDefaultExtruder(self) -> None: if self._global_container_stack is None: return - extruder_items = sorted(self._global_container_stack.extruders.items()) + old_position = self._default_extruder_position new_default_position = "0" - for position, extruder in extruder_items: + for extruder in self._global_container_stack.extruderList: if extruder.isEnabled: - new_default_position = position + new_default_position = extruder.getMetaDataEntry("position", "0") break if new_default_position != old_position: self._default_extruder_position = new_default_position @@ -1016,7 +1015,7 @@ class MachineManager(QObject): definition_changes_container = self._global_container_stack.definitionChanges machine_extruder_count = self._global_container_stack.getProperty("machine_extruder_count", "value") extruder_count = 0 - for position, extruder in self._global_container_stack.extruders.items(): + for position, extruder in enumerate(self._global_container_stack.extruderList): if extruder.isEnabled and int(position) < machine_extruder_count: extruder_count += 1 if self.numberExtrudersEnabled != extruder_count: @@ -1040,7 +1039,7 @@ class MachineManager(QObject): return with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): property_names = ["value", "resolve", "validationState"] - for container in [self._global_container_stack] + list(self._global_container_stack.extruders.values()): + for container in [self._global_container_stack] + self._global_container_stack.extruderList: for setting_key in container.getAllKeys(): container.propertiesChanged.emit(setting_key, property_names) @@ -1089,7 +1088,7 @@ class MachineManager(QObject): def setSettingForAllExtruders(self, setting_name: str, property_name: str, property_value: str) -> None: if self._global_container_stack is None: return - for key, extruder in self._global_container_stack.extruders.items(): + for extruder in self._global_container_stack.extruderList: container = extruder.userChanges container.setProperty(setting_name, property_name, property_value) @@ -1099,7 +1098,7 @@ class MachineManager(QObject): def resetSettingForAllExtruders(self, setting_name: str) -> None: if self._global_container_stack is None: return - for key, extruder in self._global_container_stack.extruders.items(): + for extruder in self._global_container_stack.extruderList: container = extruder.userChanges container.removeInstance(setting_name) @@ -1117,8 +1116,9 @@ class MachineManager(QObject): changed = False if self._global_container_stack: - for position in self._global_container_stack.extruders: - material_id = self._global_container_stack.extruders[position].material.getMetaDataEntry("base_file") + for extruder in self._global_container_stack.extruderList: + material_id = extruder.material.getMetaDataEntry("base_file") + position = extruder.getMetaDataEntry("position") if position not in self._current_root_material_id or material_id != self._current_root_material_id[position]: changed = True self._current_root_material_id[position] = material_id @@ -1155,7 +1155,7 @@ class MachineManager(QObject): self._current_quality_changes_group = None self._global_container_stack.quality = empty_quality_container self._global_container_stack.qualityChanges = empty_quality_changes_container - for extruder in self._global_container_stack.extruders.values(): + for extruder in self._global_container_stack.extruderList: extruder.quality = empty_quality_container extruder.qualityChanges = empty_quality_changes_container @@ -1186,9 +1186,9 @@ class MachineManager(QObject): # Set quality and quality_changes for each ExtruderStack for position, node in quality_group.nodes_for_extruders.items(): - self._global_container_stack.extruders[str(position)].quality = node.getContainer() + self._global_container_stack.extruderList[int(position)].quality = node.getContainer() if empty_quality_changes: - self._global_container_stack.extruders[str(position)].qualityChanges = empty_quality_changes_container + self._global_container_stack.extruderList[int(position)].qualityChanges = empty_quality_changes_container self.activeQualityGroupChanged.emit() self.activeQualityChangesGroupChanged.emit() @@ -1224,7 +1224,8 @@ class MachineManager(QObject): self._global_container_stack.quality = quality_container self._global_container_stack.qualityChanges = quality_changes_container - for position, extruder in self._global_container_stack.extruders.items(): + for extruder in self._global_container_stack.extruderList: + position = str(extruder.getMetaDataEntry("position", "0")) quality_changes_node = quality_changes_group.nodes_for_extruders.get(position) quality_node = None if quality_group is not None: @@ -1248,7 +1249,7 @@ class MachineManager(QObject): def _setVariantNode(self, position: str, container_node: "ContainerNode") -> None: if container_node.getContainer() is None or self._global_container_stack is None: return - self._global_container_stack.extruders[position].variant = container_node.getContainer() + self._global_container_stack.extruderList[int(position)].variant = container_node.getContainer() self.activeVariantChanged.emit() def _setGlobalVariant(self, container_node: "ContainerNode") -> None: @@ -1262,10 +1263,10 @@ class MachineManager(QObject): if self._global_container_stack is None: return if container_node and container_node.getContainer(): - self._global_container_stack.extruders[position].material = container_node.getContainer() + self._global_container_stack.extruderList[int(position)].material = container_node.getContainer() root_material_id = container_node.getMetaDataEntry("base_file", None) else: - self._global_container_stack.extruders[position].material = empty_material_container + self._global_container_stack.extruderList[int(position)].material = empty_material_container root_material_id = None # The _current_root_material_id is used in the MaterialMenu to see which material is selected if root_material_id != self._current_root_material_id[position]: @@ -1276,7 +1277,7 @@ class MachineManager(QObject): # Check material - variant compatibility if self._global_container_stack is not None: if Util.parseBool(self._global_container_stack.getMetaDataEntry("has_materials", False)): - for position, extruder in self._global_container_stack.extruders.items(): + for extruder in self._global_container_stack.extruderList: if not extruder.isEnabled: continue if not extruder.material.getMetaDataEntry("compatible"): @@ -1336,7 +1337,7 @@ class MachineManager(QObject): buildplate_name = self._global_container_stack.variant.getName() for position_item in position_list: - extruder = self._global_container_stack.extruders[position_item] + extruder = self._global_container_stack.extruderList[int(position_item)] current_material_base_name = extruder.material.getMetaDataEntry("base_file") current_nozzle_name = None @@ -1421,7 +1422,7 @@ class MachineManager(QObject): extruders_to_disable.add(extruder_configuration.position) # If there's no material and/or nozzle on the printer, enable the first extruder and disable the rest. - if len(extruders_to_disable) == len(self._global_container_stack.extruders): + if len(extruders_to_disable) == len(self._global_container_stack.extruderList): extruders_to_disable.remove(min(extruders_to_disable)) for extruder_configuration in configuration.extruderConfigurations: @@ -1429,7 +1430,7 @@ class MachineManager(QObject): # If the machine doesn't have a hotend or material, disable this extruder if int(position) in extruders_to_disable: - self._global_container_stack.extruders[position].setEnabled(False) + self._global_container_stack.extruderList[int(position)].setEnabled(False) need_to_show_message = True disabled_used_extruder_position_set.add(int(position)) @@ -1445,13 +1446,13 @@ class MachineManager(QObject): if variant_container_node: self._setVariantNode(position, variant_container_node) else: - self._global_container_stack.extruders[position].variant = empty_variant_container + self._global_container_stack.extruderList[int(position)].variant = empty_variant_container if material_container_node: self._setMaterial(position, material_container_node) else: - self._global_container_stack.extruders[position].material = empty_material_container - self._global_container_stack.extruders[position].setEnabled(True) + self._global_container_stack.extruderList[int(position)].material = empty_material_container + self._global_container_stack.extruderList[int(position)].setEnabled(True) self.updateMaterialWithVariant(position) self.updateDefaultExtruder() @@ -1473,7 +1474,7 @@ class MachineManager(QObject): # Show human-readable extruder names such as "Extruder Left", "Extruder Front" instead of "Extruder 1, 2, 3". extruder_names = [] for extruder_position in sorted(disabled_used_extruder_position_set): - extruder_stack = self._global_container_stack.extruders[str(extruder_position)] + extruder_stack = self._global_container_stack.extruderList[int(extruder_position)] extruder_name = extruder_stack.definition.getName() extruder_names.append(extruder_name) extruders_str = ", ".join(extruder_names) @@ -1504,7 +1505,7 @@ class MachineManager(QObject): machine_definition_id = self._global_container_stack.definition.id position = str(position) - extruder_stack = self._global_container_stack.extruders[position] + extruder_stack = self._global_container_stack.extruderList[int(position)] nozzle_name = extruder_stack.variant.getName() material_diameter = extruder_stack.getApproximateMaterialDiameter() material_node = self._material_manager.getMaterialNode(machine_definition_id, nozzle_name, buildplate_name, @@ -1516,7 +1517,7 @@ class MachineManager(QObject): @pyqtSlot(str, "QVariant") def setMaterial(self, position: str, container_node, global_stack: Optional["GlobalStack"] = None) -> None: if global_stack is not None and global_stack != self._global_container_stack: - global_stack.extruders[position].material = container_node.getContainer() + global_stack.extruderList[int(position)].material = container_node.getContainer() return position = str(position) self.blurSettings.emit() diff --git a/cura/Settings/SimpleModeSettingsManager.py b/cura/Settings/SimpleModeSettingsManager.py index b1896a9205..3923435e63 100644 --- a/cura/Settings/SimpleModeSettingsManager.py +++ b/cura/Settings/SimpleModeSettingsManager.py @@ -39,8 +39,8 @@ class SimpleModeSettingsManager(QObject): user_setting_keys.update(global_stack.userChanges.getAllKeys()) # check user settings in the extruder stacks - if global_stack.extruders: - for extruder_stack in global_stack.extruders.values(): + if global_stack.extruderList: + for extruder_stack in global_stack.extruderList: user_setting_keys.update(extruder_stack.userChanges.getAllKeys()) # remove settings that are visible in recommended (we don't show the reset button for those) diff --git a/cura/UI/PrintInformation.py b/cura/UI/PrintInformation.py index 3fafaaba12..abf1083836 100644 --- a/cura/UI/PrintInformation.py +++ b/cura/UI/PrintInformation.py @@ -197,11 +197,7 @@ class PrintInformation(QObject): material_preference_values = json.loads(self._application.getInstance().getPreferences().getValue("cura/material_settings")) - extruder_stacks = global_stack.extruders - - for position in extruder_stacks: - extruder_stack = extruder_stacks[position] - index = int(position) + for index, extruder_stack in enumerate(global_stack.extruderList): if index >= len(self._material_amounts): continue amount = self._material_amounts[index] diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index ddf7864bb3..9d2e4d1506 100755 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -834,9 +834,8 @@ class CuraEngineBackend(QObject, Backend): if self._global_container_stack: self._global_container_stack.propertyChanged.disconnect(self._onSettingChanged) self._global_container_stack.containersChanged.disconnect(self._onChanged) - extruders = list(self._global_container_stack.extruders.values()) - for extruder in extruders: + for extruder in self._global_container_stack.extruderList: extruder.propertyChanged.disconnect(self._onSettingChanged) extruder.containersChanged.disconnect(self._onChanged) @@ -845,8 +844,8 @@ class CuraEngineBackend(QObject, Backend): if self._global_container_stack: self._global_container_stack.propertyChanged.connect(self._onSettingChanged) # Note: Only starts slicing when the value changed. self._global_container_stack.containersChanged.connect(self._onChanged) - extruders = list(self._global_container_stack.extruders.values()) - for extruder in extruders: + + for extruder in self._global_container_stack.extruderList: extruder.propertyChanged.connect(self._onSettingChanged) extruder.containersChanged.connect(self._onChanged) self._onChanged() diff --git a/plugins/ModelChecker/ModelChecker.py b/plugins/ModelChecker/ModelChecker.py index 0619c95d67..0afed28f19 100644 --- a/plugins/ModelChecker/ModelChecker.py +++ b/plugins/ModelChecker/ModelChecker.py @@ -76,7 +76,9 @@ class ModelChecker(QObject, Extension): # This function can be triggered in the middle of a machine change, so do not proceed if the machine change # has not done yet. - if str(node_extruder_position) not in global_container_stack.extruders: + try: + extruder = global_container_stack.extruderList[int(node_extruder_position)] + except IndexError: Application.getInstance().callLater(lambda: self.onChanged.emit()) return False @@ -131,9 +133,9 @@ class ModelChecker(QObject, Extension): material_shrinkage = {} # Get all shrinkage values of materials used - for extruder_position, extruder in global_container_stack.extruders.items(): + for extruder_position, extruder in enumerate(global_container_stack.extruderList): shrinkage = extruder.material.getProperty("material_shrinkage_percentage", "value") if shrinkage is None: shrinkage = 0 - material_shrinkage[extruder_position] = shrinkage + material_shrinkage[str(extruder_position)] = shrinkage return material_shrinkage diff --git a/plugins/SolidView/SolidView.py b/plugins/SolidView/SolidView.py index 536006ffaa..61954f5bca 100644 --- a/plugins/SolidView/SolidView.py +++ b/plugins/SolidView/SolidView.py @@ -57,9 +57,12 @@ class SolidView(View): # As the rendering is called a *lot* we really, dont want to re-evaluate the property every time. So we store em! global_container_stack = Application.getInstance().getGlobalContainerStack() if global_container_stack: - support_extruder_nr = global_container_stack.getExtruderPositionValueWithDefault("support_extruder_nr") - support_angle_stack = global_container_stack.extruders.get(str(support_extruder_nr)) - if support_angle_stack: + support_extruder_nr = int(global_container_stack.getExtruderPositionValueWithDefault("support_extruder_nr")) + try: + support_angle_stack = global_container_stack.extruderList[support_extruder_nr] + except IndexError: + pass + else: self._support_angle = support_angle_stack.getProperty("support_angle", "value") def beginRendering(self): From fb5ec97cb8c0c7ab6fd4bde2ac82716c33844a01 Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Sat, 14 Sep 2019 09:15:41 +0100 Subject: [PATCH 12/28] Fix spelling. --- resources/definitions/fdmprinter.def.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index b609088afa..2d6848ade8 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -7563,7 +7563,7 @@ "small_feature_speed_factor": { "label": "Small Feature Speed", - "description": "Small features will be printed at this percentage of their normal print speed. Slower printing can help with adhestion and accuracy.", + "description": "Small features will be printed at this percentage of their normal print speed. Slower printing can help with adhesion and accuracy.", "unit": "%", "type": "float", "default_value": 50, @@ -7575,7 +7575,7 @@ "small_feature_speed_factor_0": { "label": "First Layer Speed", - "description": "Small features on the first layer will be printed at this percentage of their normal print speed. Slower printing can help with adhestion and accuracy.", + "description": "Small features on the first layer will be printed at this percentage of their normal print speed. Slower printing can help with adhesion and accuracy.", "unit": "%", "type": "float", "default_value": 50, From 57a50c9c3d212dbe9f1d6ea4dd3f7fbf07d66b61 Mon Sep 17 00:00:00 2001 From: Daniel Green Date: Sun, 15 Sep 2019 09:56:21 -0700 Subject: [PATCH 13/28] Correction for build volume. --- resources/definitions/flsun_qq.def.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/definitions/flsun_qq.def.json b/resources/definitions/flsun_qq.def.json index ce69317b33..02b3849c12 100644 --- a/resources/definitions/flsun_qq.def.json +++ b/resources/definitions/flsun_qq.def.json @@ -19,13 +19,13 @@ "default_value": true }, "machine_width": { - "default_value": 240 + "default_value": 260 }, "machine_height": { "default_value": 285 }, "machine_depth": { - "default_value": 240 + "default_value": 260 }, "machine_center_is_zero": { "default_value": true From 0f8dfeafc127ffbca9087ed0710e3097fccfa26e Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 16 Sep 2019 09:26:12 +0200 Subject: [PATCH 14/28] fix typo --- cura/BuildVolume.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index 567bc0cd16..42bf1b693a 100755 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -270,7 +270,7 @@ class BuildVolume(SceneNode): # Mark the node as outside build volume if the set extruder is disabled extruder_position = node.callDecoration("getActiveExtruderPosition") try: - if not self._global_container_stack.extrudersList[int(extruder_position)].isEnabled: + if not self._global_container_stack.extruderList[int(extruder_position)].isEnabled: node.setOutsideBuildArea(True) continue except IndexError: From c0db1a17be654e3889c3608b25e0f2208b6bf740 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 16 Sep 2019 11:40:08 +0200 Subject: [PATCH 15/28] Fix the false positive failure in the unit test --- tests/TestMachineManager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/TestMachineManager.py b/tests/TestMachineManager.py index 1e8cd8fb12..1d5d1a45cb 100644 --- a/tests/TestMachineManager.py +++ b/tests/TestMachineManager.py @@ -142,7 +142,7 @@ def test_resetSettingForAllExtruders(machine_manager): extruder_2 = createMockedExtruder("extruder_2") extruder_1.userChanges = createMockedInstanceContainer("settings_1") extruder_2.userChanges = createMockedInstanceContainer("settings_2") - global_stack.extruders = {"1": extruder_1, "2": extruder_2} + global_stack.extruderList = [extruder_1, extruder_2] machine_manager.resetSettingForAllExtruders("whatever") From e964035653fe27b59b1acbdf90c0ac7a6187f4ff Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 16 Sep 2019 11:40:32 +0200 Subject: [PATCH 16/28] Fix adding custom FFF printer --- cura/Settings/MachineManager.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 560cb2ad5c..de231e4584 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -992,7 +992,10 @@ class MachineManager(QObject): @deprecated("use Cura.MachineManager.activeMachine.extruders instead", "4.2") def _getExtruder(self, position) -> Optional[ExtruderStack]: if self._global_container_stack: - return self._global_container_stack.extruderList[int(position)] + try: + return self._global_container_stack.extruderList[int(position)] + except IndexError: + return None return None def updateDefaultExtruder(self) -> None: @@ -1186,9 +1189,12 @@ class MachineManager(QObject): # Set quality and quality_changes for each ExtruderStack for position, node in quality_group.nodes_for_extruders.items(): - self._global_container_stack.extruderList[int(position)].quality = node.getContainer() - if empty_quality_changes: - self._global_container_stack.extruderList[int(position)].qualityChanges = empty_quality_changes_container + try: + self._global_container_stack.extruderList[int(position)].quality = node.getContainer() + if empty_quality_changes: + self._global_container_stack.extruderList[int(position)].qualityChanges = empty_quality_changes_container + except IndexError: + return self.activeQualityGroupChanged.emit() self.activeQualityChangesGroupChanged.emit() From 6ff59bf5ab1074ba277d3f7b04daab173833cec6 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 16 Sep 2019 11:48:10 +0200 Subject: [PATCH 17/28] Fix some more issues with the custom FF printer --- cura/Settings/MachineManager.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index de231e4584..d1811bb31d 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -1194,7 +1194,7 @@ class MachineManager(QObject): if empty_quality_changes: self._global_container_stack.extruderList[int(position)].qualityChanges = empty_quality_changes_container except IndexError: - return + continue # This can be ignored as in some cases the quality group gets set for an extruder that's not active (eg custom fff printer) self.activeQualityGroupChanged.emit() self.activeQualityChangesGroupChanged.emit() @@ -1231,7 +1231,7 @@ class MachineManager(QObject): self._global_container_stack.qualityChanges = quality_changes_container for extruder in self._global_container_stack.extruderList: - position = str(extruder.getMetaDataEntry("position", "0")) + position = int(extruder.getMetaDataEntry("position", "0")) quality_changes_node = quality_changes_group.nodes_for_extruders.get(position) quality_node = None if quality_group is not None: @@ -1343,7 +1343,10 @@ class MachineManager(QObject): buildplate_name = self._global_container_stack.variant.getName() for position_item in position_list: - extruder = self._global_container_stack.extruderList[int(position_item)] + try: + extruder = self._global_container_stack.extruderList[int(position_item)] + except IndexError: + continue current_material_base_name = extruder.material.getMetaDataEntry("base_file") current_nozzle_name = None From 28310e03f25ddd7067d5a72bb435f8c388f0b7bf Mon Sep 17 00:00:00 2001 From: Ellecross <32929710+Ellecross@users.noreply.github.com> Date: Mon, 16 Sep 2019 15:05:09 +0200 Subject: [PATCH 18/28] Revert "Only show printerTypes for active machine" This reverts commit 2395567f1eb505a814f3b305e5a59138dfe8c144. --- resources/qml/PrinterSelector/MachineSelectorButton.qml | 1 - 1 file changed, 1 deletion(-) diff --git a/resources/qml/PrinterSelector/MachineSelectorButton.qml b/resources/qml/PrinterSelector/MachineSelectorButton.qml index 7fa2006687..c37823ba82 100644 --- a/resources/qml/PrinterSelector/MachineSelectorButton.qml +++ b/resources/qml/PrinterSelector/MachineSelectorButton.qml @@ -72,7 +72,6 @@ Button verticalCenter: parent.verticalCenter } spacing: UM.Theme.getSize("narrow_margin").width - visible: machineSelectorButton.checked Repeater { From 021a04c427fa5ad92d804e94c8edb86bcc67a522 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Mon, 16 Sep 2019 15:29:34 +0200 Subject: [PATCH 19/28] Show the printer types list when we show the label every time or when only show the label for the active printer. --- resources/qml/PrinterSelector/MachineSelectorButton.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/qml/PrinterSelector/MachineSelectorButton.qml b/resources/qml/PrinterSelector/MachineSelectorButton.qml index c37823ba82..115957dd64 100644 --- a/resources/qml/PrinterSelector/MachineSelectorButton.qml +++ b/resources/qml/PrinterSelector/MachineSelectorButton.qml @@ -72,6 +72,7 @@ Button verticalCenter: parent.verticalCenter } spacing: UM.Theme.getSize("narrow_margin").width + visible: (updatePrinterTypesOnlyWhenChecked && machineSelectorButton.checked) || !updatePrinterTypesOnlyWhenChecked Repeater { From 5efc0e7f27ca1c3e65d72cbb0b71d0970147fae3 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Mon, 16 Sep 2019 15:40:51 +0200 Subject: [PATCH 20/28] Mypy: do not stop after finding issues in a module --- run_mypy.py | 160 ++++++++++++++++++++++++++-------------------------- 1 file changed, 80 insertions(+), 80 deletions(-) diff --git a/run_mypy.py b/run_mypy.py index 27f07cd281..62984bce27 100644 --- a/run_mypy.py +++ b/run_mypy.py @@ -1,80 +1,80 @@ -#!/usr/bin/env python -import os -import sys -import subprocess - - -# A quick Python implementation of unix 'where' command. -def where(exe_name: str, search_path: str = os.getenv("PATH")) -> str: - if search_path is None: - search_path = "" - paths = search_path.split(os.pathsep) - result = "" - print(" -> sys.executable location: %s" % sys.executable) - sys_exec_dir = os.path.dirname(sys.executable) - root_dir = os.path.dirname(sys_exec_dir) - paths += [sys_exec_dir, - os.path.join(root_dir, "bin"), - os.path.join(root_dir, "scripts"), - ] - paths = set(paths) - - for path in sorted(paths): - print(" -> Searching %s" % path) - candidate_path = os.path.join(path, exe_name) - if os.path.exists(candidate_path): - result = candidate_path - break - return result - - -def findModules(path): - result = [] - for entry in os.scandir(path): - if entry.is_dir() and os.path.exists(os.path.join(path, entry.name, "__init__.py")): - result.append(entry.name) - return result - - -def main(): - # Find Uranium via the PYTHONPATH var - uraniumUMPath = where("UM", os.getenv("PYTHONPATH")) - if uraniumUMPath is None: - uraniumUMPath = os.path.join("..", "Uranium") - uraniumPath = os.path.dirname(uraniumUMPath) - - mypy_path_parts = [".", os.path.join(".", "plugins"), os.path.join(".", "plugins", "VersionUpgrade"), - uraniumPath, os.path.join(uraniumPath, "stubs")] - if sys.platform == "win32": - os.putenv("MYPYPATH", ";".join(mypy_path_parts)) - else: - os.putenv("MYPYPATH", ":".join(mypy_path_parts)) - - # Mypy really needs to be run via its Python script otherwise it can't find its data files. - mypy_exe_name = "mypy.exe" if sys.platform == "win32" else "mypy" - mypy_exe_dir = where(mypy_exe_name) - mypy_module = os.path.join(os.path.dirname(mypy_exe_dir), mypy_exe_name) - print("Found mypy exe path: %s" % mypy_exe_dir) - print("Found mypy module path: %s" % mypy_module) - - plugins = findModules("plugins") - plugins.sort() - - mods = ["cura"] + plugins + findModules("plugins/VersionUpgrade") - - for mod in mods: - print("------------- Checking module {mod}".format(**locals())) - if sys.platform == "win32": - result = subprocess.run([mypy_module, "-p", mod, "--ignore-missing-imports"]) - else: - result = subprocess.run([sys.executable, mypy_module, "-p", mod, "--ignore-missing-imports"]) - if result.returncode != 0: - print("\nModule {mod} failed checking. :(".format(**locals())) - return 1 - else: - print("\n\nDone checking. All is good.") - return 0 - - -if __name__ == "__main__": - sys.exit(main()) +#!/usr/bin/env python +import os +import sys +import subprocess + + +# A quick Python implementation of unix 'where' command. +def where(exe_name: str, search_path: str = os.getenv("PATH")) -> str: + if search_path is None: + search_path = "" + paths = search_path.split(os.pathsep) + result = "" + print(" -> sys.executable location: %s" % sys.executable) + sys_exec_dir = os.path.dirname(sys.executable) + root_dir = os.path.dirname(sys_exec_dir) + paths += [sys_exec_dir, + os.path.join(root_dir, "bin"), + os.path.join(root_dir, "scripts"), + ] + paths = set(paths) + + for path in sorted(paths): + print(" -> Searching %s" % path) + candidate_path = os.path.join(path, exe_name) + if os.path.exists(candidate_path): + result = candidate_path + break + return result + + +def findModules(path): + result = [] + for entry in os.scandir(path): + if entry.is_dir() and os.path.exists(os.path.join(path, entry.name, "__init__.py")): + result.append(entry.name) + return result + + +def main(): + # Find Uranium via the PYTHONPATH var + uraniumUMPath = where("UM", os.getenv("PYTHONPATH")) + if uraniumUMPath is None: + uraniumUMPath = os.path.join("..", "Uranium") + uraniumPath = os.path.dirname(uraniumUMPath) + + mypy_path_parts = [".", os.path.join(".", "plugins"), os.path.join(".", "plugins", "VersionUpgrade"), + uraniumPath, os.path.join(uraniumPath, "stubs")] + if sys.platform == "win32": + os.putenv("MYPYPATH", ";".join(mypy_path_parts)) + else: + os.putenv("MYPYPATH", ":".join(mypy_path_parts)) + + # Mypy really needs to be run via its Python script otherwise it can't find its data files. + mypy_exe_name = "mypy.exe" if sys.platform == "win32" else "mypy" + mypy_exe_dir = where(mypy_exe_name) + mypy_module = os.path.join(os.path.dirname(mypy_exe_dir), mypy_exe_name) + print("Found mypy exe path: %s" % mypy_exe_dir) + print("Found mypy module path: %s" % mypy_module) + + plugins = findModules("plugins") + plugins.sort() + + mods = ["cura"] + plugins + findModules("plugins/VersionUpgrade") + result = 0 + for mod in mods: + print("------------- Checking module {mod}".format(**locals())) + if sys.platform == "win32": + result = subprocess.run([mypy_module, "-p", mod, "--ignore-missing-imports"]) + else: + result = subprocess.run([sys.executable, mypy_module, "-p", mod, "--ignore-missing-imports"]) + if result.returncode != 0: + print("\nModule {mod} failed checking. :(".format(**locals())) + result = 1 + else: + print("\n\nDone checking. All is good.") + return result + + +if __name__ == "__main__": + sys.exit(main()) From 008566015394a5fb70c8fdd7188594a496cb4541 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Mon, 16 Sep 2019 15:59:21 +0200 Subject: [PATCH 21/28] Use non-abbreviated names in the configurations list --- .../qml/Menus/ConfigurationMenu/ConfigurationListView.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml index afb3aba82b..b47d77243c 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml @@ -107,8 +107,9 @@ Item Cura.PrinterTypeLabel { id: printerTypeLabel - text: Cura.MachineManager.getAbbreviatedMachineName(section) + text: section anchors.verticalCenter: parent.verticalCenter //One default margin above and one below. + autoFit: true } } From b4d4a0e291a6e79216a6acdcd4cd5dc85e301ab5 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Mon, 16 Sep 2019 16:49:12 +0200 Subject: [PATCH 22/28] Add the Trimesh Reader to the list of bundled plugins --- resources/bundled_packages/cura.json | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/resources/bundled_packages/cura.json b/resources/bundled_packages/cura.json index 4d23d56e5c..2e561b6763 100644 --- a/resources/bundled_packages/cura.json +++ b/resources/bundled_packages/cura.json @@ -475,6 +475,23 @@ } } }, + "TrimeshReader": { + "package_info": { + "package_id": "TrimeshReader", + "package_type": "plugin", + "display_name": "Trimesh Reader", + "description": "Provides support for reading model files.", + "package_version": "1.0.0", + "sdk_version": "6.0.0", + "website": "https://ultimaker.com", + "author": { + "author_id": "UltimakerPackages", + "display_name": "Ultimaker B.V.", + "email": "plugins@ultimaker.com", + "website": "https://ultimaker.com" + } + } + }, "Toolbox": { "package_info": { "package_id": "Toolbox", From e4edd5732f18a4a707c80d7d7ff8a8b96c636527 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 17 Sep 2019 09:35:12 +0200 Subject: [PATCH 23/28] Fix success code in MyPy script The 'return' variable was used for two things, shadowing each other. Because of that, it would fill the variable with a subprocess.run result which would evaluate to True so it would always say that the test failed. --- run_mypy.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/run_mypy.py b/run_mypy.py index 62984bce27..c32484a47b 100644 --- a/run_mypy.py +++ b/run_mypy.py @@ -61,7 +61,7 @@ def main(): plugins.sort() mods = ["cura"] + plugins + findModules("plugins/VersionUpgrade") - result = 0 + success_code = 0 for mod in mods: print("------------- Checking module {mod}".format(**locals())) if sys.platform == "win32": @@ -70,10 +70,10 @@ def main(): result = subprocess.run([sys.executable, mypy_module, "-p", mod, "--ignore-missing-imports"]) if result.returncode != 0: print("\nModule {mod} failed checking. :(".format(**locals())) - result = 1 + success_code = 1 else: print("\n\nDone checking. All is good.") - return result + return success_code if __name__ == "__main__": From e4c3ab33f89275f9d3cceeb6ed4915850bf7c7e0 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 17 Sep 2019 09:37:18 +0200 Subject: [PATCH 24/28] Fix message saying all is good if it isn't --- run_mypy.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/run_mypy.py b/run_mypy.py index c32484a47b..6be424bda8 100644 --- a/run_mypy.py +++ b/run_mypy.py @@ -71,6 +71,8 @@ def main(): if result.returncode != 0: print("\nModule {mod} failed checking. :(".format(**locals())) success_code = 1 + if success_code: + print("\n\nSome modules failed checking!") else: print("\n\nDone checking. All is good.") return success_code From 5a95788493622e205dc0b8244856e9630e7dc95c Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 17 Sep 2019 09:52:44 +0200 Subject: [PATCH 25/28] Use the setting's default value when the global variant instance container is empty Otherwise it will never show as a matching configuration in the configuration list. --- cura/Settings/MachineManager.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 7b7974e6b2..dbb81f31f4 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -201,7 +201,8 @@ class MachineManager(QObject): # An empty build plate configuration from the network printer is presented as an empty string, so use "" for an # empty build plate. - self._current_printer_configuration.buildplateConfiguration = self._global_container_stack.getProperty("machine_buildplate_type", "value") if self._global_container_stack.variant != empty_variant_container else "" + self._current_printer_configuration.buildplateConfiguration = self._global_container_stack.getProperty("machine_buildplate_type", "value")\ + if self._global_container_stack.variant != empty_variant_container else self._global_container_stack.getProperty("machine_buildplate_type", "default_value") self.currentConfigurationChanged.emit() @pyqtSlot(QObject, result = bool) From cd4f6ff3f4bc0f97f9e7b65f608f1f42c66bb016 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 17 Sep 2019 10:41:57 +0200 Subject: [PATCH 26/28] Add tooltip to object list Contributes to issue CURA-6666. --- resources/qml/ObjectItemButton.qml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/resources/qml/ObjectItemButton.qml b/resources/qml/ObjectItemButton.qml index 683d0ed52b..7acfa7a7b5 100644 --- a/resources/qml/ObjectItemButton.qml +++ b/resources/qml/ObjectItemButton.qml @@ -51,5 +51,22 @@ Button border.color: objectItemButton.checked ? UM.Theme.getColor("primary") : "transparent" } + ToolTip + { + visible: hovered + delay: 1000 + + contentItem: Text + { + text: objectItemButton.text + font: UM.Theme.getFont("default") + color: UM.Theme.getColor("tooltip_text") + } + background: Rectangle + { + color: UM.Theme.getColor("tooltip") + } + } + onClicked: Cura.SceneController.changeSelection(index) } From d0b7a52ef5a084b79723b37b08dd1adf74a6dbfa Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 17 Sep 2019 13:10:25 +0200 Subject: [PATCH 27/28] Remove unused definition ID field --- resources/definitions/Mark2_for_Ultimaker2.def.json | 1 - 1 file changed, 1 deletion(-) diff --git a/resources/definitions/Mark2_for_Ultimaker2.def.json b/resources/definitions/Mark2_for_Ultimaker2.def.json index 6a385c4b8b..5aada425fd 100644 --- a/resources/definitions/Mark2_for_Ultimaker2.def.json +++ b/resources/definitions/Mark2_for_Ultimaker2.def.json @@ -1,5 +1,4 @@ { - "id": "Mark2_for_Ultimaker2", "version": 2, "name": "Mark2 for Ultimaker2", "inherits": "ultimaker2_plus", From b9ed619c9aba2371dc4140c36c66db19aa8bab34 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 17 Sep 2019 13:52:37 +0200 Subject: [PATCH 28/28] Reuse the Cura ToolTip while showing long object item It will only show the tooltip when the text is longer than the elided text. Contributes to CURA-6666. --- resources/qml/ObjectItemButton.qml | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/resources/qml/ObjectItemButton.qml b/resources/qml/ObjectItemButton.qml index 7acfa7a7b5..b454fd929a 100644 --- a/resources/qml/ObjectItemButton.qml +++ b/resources/qml/ObjectItemButton.qml @@ -51,21 +51,20 @@ Button border.color: objectItemButton.checked ? UM.Theme.getColor("primary") : "transparent" } - ToolTip + TextMetrics { - visible: hovered - delay: 1000 + id: buttonTextMetrics + text: buttonText.text + font: buttonText.font + elide: buttonText.elide + elideWidth: buttonText.width + } - contentItem: Text - { - text: objectItemButton.text - font: UM.Theme.getFont("default") - color: UM.Theme.getColor("tooltip_text") - } - background: Rectangle - { - color: UM.Theme.getColor("tooltip") - } + Cura.ToolTip + { + id: tooltip + tooltipText: objectItemButton.text + visible: objectItemButton.hovered && buttonTextMetrics.elidedText != buttonText.text } onClicked: Cura.SceneController.changeSelection(index)