From c3bf0b834d6e1a78849ef85604615524f1b2368e Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 20 Feb 2018 09:20:01 +0100 Subject: [PATCH 01/66] Fix location of post processing scripts on Linux On Windows and OSX, resources and preferences are stored in the same folder. On Linux, preferences are in ~/.config, resources are in ~/.local/shared. Postprocessing scripts belong in the latter, along with all the other resources (definitions, plugins, themes). Fixes #3356 --- plugins/PostProcessingPlugin/PostProcessingPlugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/PostProcessingPlugin/PostProcessingPlugin.py b/plugins/PostProcessingPlugin/PostProcessingPlugin.py index f491afbec0..92e31d9135 100644 --- a/plugins/PostProcessingPlugin/PostProcessingPlugin.py +++ b/plugins/PostProcessingPlugin/PostProcessingPlugin.py @@ -173,7 +173,7 @@ class PostProcessingPlugin(QObject, Extension): Logger.log("d", "Creating post processing plugin view.") ## Load all scripts in the scripts folders - for root in [PluginRegistry.getInstance().getPluginPath("PostProcessingPlugin"), Resources.getStoragePath(Resources.Preferences)]: + for root in [PluginRegistry.getInstance().getPluginPath("PostProcessingPlugin"), Resources.getStoragePath(Resources.Resources)]: path = os.path.join(root, "scripts") if not os.path.isdir(path): try: From 86c13e86c742610e225724a94251dd142421f8c2 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Wed, 28 Feb 2018 11:01:32 +0100 Subject: [PATCH 02/66] CURA-4400 first version that disables extruder and updates available quality profiles --- cura/Machines/Models/QualityProfilesModel.py | 1 + cura/Machines/QualityManager.py | 4 ++-- cura/Settings/ExtruderStack.py | 13 ++++++++++++- cura/Settings/MachineManager.py | 8 ++++++++ resources/qml/Cura.qml | 15 ++++++++++++++- resources/qml/ExtruderButton.qml | 2 +- resources/qml/SidebarHeader.qml | 20 ++++++++++++++------ resources/qml/SidebarSimple.qml | 6 ++---- 8 files changed, 54 insertions(+), 15 deletions(-) diff --git a/cura/Machines/Models/QualityProfilesModel.py b/cura/Machines/Models/QualityProfilesModel.py index 3bfccd409d..519213e8e2 100644 --- a/cura/Machines/Models/QualityProfilesModel.py +++ b/cura/Machines/Models/QualityProfilesModel.py @@ -35,6 +35,7 @@ class QualityProfilesModel(ListModel): # connect signals Application.getInstance().globalContainerStackChanged.connect(self._update) Application.getInstance().getMachineManager().activeQualityGroupChanged.connect(self._update) + Application.getInstance().getMachineManager().extruderChanged.connect(self._update) self._quality_manager = Application.getInstance()._quality_manager self._quality_manager.qualitiesUpdated.connect(self._update) diff --git a/cura/Machines/QualityManager.py b/cura/Machines/QualityManager.py index eb8a3611c1..08f565ac66 100644 --- a/cura/Machines/QualityManager.py +++ b/cura/Machines/QualityManager.py @@ -237,9 +237,9 @@ class QualityManager(QObject): # Updates the given quality groups' availabilities according to which extruders are being used/ enabled. def _updateQualityGroupsAvailability(self, machine: "GlobalStack", quality_group_list): used_extruders = set() - # TODO: This will change after the Machine refactoring for i in range(machine.getProperty("machine_extruder_count", "value")): - used_extruders.add(str(i)) + if machine.extruders[str(i)].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/ExtruderStack.py b/cura/Settings/ExtruderStack.py index 2995aae795..2a4207c3f3 100644 --- a/cura/Settings/ExtruderStack.py +++ b/cura/Settings/ExtruderStack.py @@ -3,7 +3,7 @@ from typing import Any, TYPE_CHECKING, Optional -from PyQt5.QtCore import pyqtProperty +from PyQt5.QtCore import pyqtProperty, pyqtSignal from UM.Decorators import override from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase @@ -28,9 +28,12 @@ class ExtruderStack(CuraContainerStack): super().__init__(container_id, *args, **kwargs) self.addMetaDataEntry("type", "extruder_train") # For backward compatibility + self._enabled = True self.propertiesChanged.connect(self._onPropertiesChanged) + enabledChanged = pyqtSignal() + ## Overridden from ContainerStack # # This will set the next stack and ensure that we register this stack as an extruder. @@ -47,6 +50,14 @@ class ExtruderStack(CuraContainerStack): def getNextStack(self) -> Optional["GlobalStack"]: return super().getNextStack() + def setEnabled(self, enabled): + self._enabled = enabled + self.enabledChanged.emit() + + @pyqtProperty(bool, notify = enabledChanged) + def isEnabled(self): + return self._enabled + @classmethod def getLoadingPriority(cls) -> int: return 3 diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 5abd5d4649..b3a2a7ed9e 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -135,6 +135,7 @@ class MachineManager(QObject): activeVariantChanged = pyqtSignal() activeQualityChanged = pyqtSignal() activeStackChanged = pyqtSignal() # Emitted whenever the active stack is changed (ie: when changing between extruders, changing a profile, but not when changing a value) + extruderChanged = pyqtSignal() globalValueChanged = pyqtSignal() # Emitted whenever a value inside global container is changed. activeStackValueChanged = pyqtSignal() # Emitted whenever a value inside the active stack is changed. @@ -764,6 +765,13 @@ class MachineManager(QObject): extruder = self._global_container_stack.extruders.get(str(position)) return extruder + @pyqtSlot(int, bool) + def setExtruderEnabled(self, position: int, enabled) -> None: + extruder = self.getExtruder(position) + extruder.setEnabled(enabled) + + self.extruderChanged.emit() + def _onMachineNameChanged(self): self.globalContainerChanged.emit() diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index aeb75a79c5..5764ff0628 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -200,8 +200,21 @@ UM.MainWindow MenuItem { text: catalog.i18nc("@action:inmenu", "Set as Active Extruder") - onTriggered: Cura.ExtruderManager.setActiveExtruderIndex(model.index) + onTriggered: Cura.MachineManager.setExtruderIndex(model.index) } + + MenuItem { + text: catalog.i18nc("@action:inmenu", "Enable Extruder") + onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, true) + visible: !Cura.MachineManager.getExtruder(model.index).isEnabled + } + + MenuItem { + text: catalog.i18nc("@action:inmenu", "Disable Extruder") + onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, false) + visible: Cura.MachineManager.getExtruder(model.index).isEnabled + } + } onObjectAdded: settingsMenu.insertItem(index, object) onObjectRemoved: settingsMenu.removeItem(object) diff --git a/resources/qml/ExtruderButton.qml b/resources/qml/ExtruderButton.qml index e4350e0a2c..2c1b80047e 100644 --- a/resources/qml/ExtruderButton.qml +++ b/resources/qml/ExtruderButton.qml @@ -19,7 +19,7 @@ Button iconSource: UM.Theme.getIcon("extruder_button") checked: Cura.ExtruderManager.selectedObjectExtruders.indexOf(extruder.id) != -1 - enabled: UM.Selection.hasSelection + enabled: UM.Selection.hasSelection && extruder.stack.isEnabled property color customColor: base.hovered ? UM.Theme.getColor("button_hover") : UM.Theme.getColor("button"); diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 5d9cbe2ad1..a9aefe4848 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -114,6 +114,18 @@ Column Behavior on color { ColorAnimation { duration: 50; } } } + function buttonColor(index) { + var extruder = Cura.MachineManager.getExtruder(index); + if (extruder.isEnabled) { + return ( + control.checked || control.pressed) ? UM.Theme.getColor("action_button_active_text") : + control.hovered ? UM.Theme.getColor("action_button_hovered_text") : + UM.Theme.getColor("action_button_text"); + } else { + return UM.Theme.getColor("action_button_disabled"); + } + } + Item { id: extruderButtonFace @@ -131,9 +143,7 @@ Column anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left - color: (control.checked || control.pressed) ? UM.Theme.getColor("action_button_active_text") : - control.hovered ? UM.Theme.getColor("action_button_hovered_text") : - UM.Theme.getColor("action_button_text") + color: buttonColor(index) font: UM.Theme.getFont("large_nonbold") text: catalog.i18nc("@label", "Extruder") @@ -176,9 +186,7 @@ Column id: extruderNumberText anchors.centerIn: parent text: index + 1; - color: (control.checked || control.pressed) ? UM.Theme.getColor("action_button_active_text") : - control.hovered ? UM.Theme.getColor("action_button_hovered_text") : - UM.Theme.getColor("action_button_text") + color: buttonColor(index) font: UM.Theme.getFont("default_bold") } diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index 877e3a1557..4181e9df73 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -67,10 +67,8 @@ Item Connections { - target: Cura.MachineManager - onActiveQualityChanged: qualityModel.update() - onActiveMaterialChanged: qualityModel.update() - onActiveVariantChanged: qualityModel.update() + target: Cura.QualityProfilesModel + onItemsChanged: qualityModel.update() } Connections { From f28bed9b4f79732d9def090e1267aff5193bc333 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Wed, 28 Feb 2018 12:56:39 +0100 Subject: [PATCH 03/66] CURA-4400 not sending objects that are printed with a disabled extruder --- cura/Settings/ExtrudersModel.py | 3 +++ plugins/CuraEngineBackend/StartSliceJob.py | 24 +++++++++++++++------- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/cura/Settings/ExtrudersModel.py b/cura/Settings/ExtrudersModel.py index 5139b9885d..c3db797e19 100644 --- a/cura/Settings/ExtrudersModel.py +++ b/cura/Settings/ExtrudersModel.py @@ -43,6 +43,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): # The variant of the extruder. VariantRole = Qt.UserRole + 7 + StackRole = Qt.UserRole + 8 ## List of colours to display if there is no material or the material has no known # colour. @@ -62,6 +63,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): self.addRoleName(self.DefinitionRole, "definition") self.addRoleName(self.MaterialRole, "material") self.addRoleName(self.VariantRole, "variant") + self.addRoleName(self.StackRole, "stack") self._update_extruder_timer = QTimer() self._update_extruder_timer.setInterval(100) @@ -188,6 +190,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): "definition": extruder.getBottom().getId(), "material": extruder.material.getName() if extruder.material else "", "variant": extruder.variant.getName() if extruder.variant else "", # e.g. print core + "stack": extruder, } items.append(item) diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index 8b7205f8b2..11d98c0e43 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -110,6 +110,7 @@ class StartSliceJob(Job): return stack = Application.getInstance().getGlobalContainerStack() + extruder_stack_id_to_position = {} # a lookup table because we need the position, not the id. if not stack: self.setResult(StartJobResult.Error) return @@ -129,7 +130,8 @@ class StartSliceJob(Job): self.setResult(StartJobResult.MaterialIncompatible) return - for extruder_stack in ExtruderManager.getInstance().getMachineExtruders(stack.getId()): + for position, extruder_stack in stack.extruders.items(): + extruder_stack_id_to_position[extruder_stack.getId()] = position material = extruder_stack.findContainer({"type": "material"}) if material: if material.getMetaDataEntry("compatible") == False: @@ -193,11 +195,19 @@ class StartSliceJob(Job): if per_object_stack: is_non_printing_mesh = any(per_object_stack.getProperty(key, "value") for key in NON_PRINTING_MESH_SETTINGS) - if node.callDecoration("getBuildPlateNumber") == self._build_plate_number: - if not getattr(node, "_outside_buildarea", False) or is_non_printing_mesh: - temp_list.append(node) - if not is_non_printing_mesh: - has_printing_mesh = True + # Find a reason not to add the node + if node.callDecoration("getBuildPlateNumber") != self._build_plate_number: + continue + if getattr(node, "_outside_buildarea", False) and is_non_printing_mesh: + continue + node_extruder_id = node.callDecoration("getActiveExtruder") + node_position = extruder_stack_id_to_position.get(node_extruder_id, "0") + if not stack.extruders[str(node_position)].isEnabled: + continue + + temp_list.append(node) + if not is_non_printing_mesh: + has_printing_mesh = True Job.yieldThread() @@ -382,7 +392,7 @@ class StartSliceJob(Job): def _buildGlobalInheritsStackMessage(self, stack): for key in stack.getAllKeys(): extruder = int(round(float(stack.getProperty(key, "limit_to_extruder")))) - if extruder >= 0: #Set to a specific extruder. + if extruder >= 0 and stack.extruders[str(extruder)].isEnabled: #Set to a specific extruder. setting_extruder = self._slice_message.addRepeatedMessage("limit_to_extruder") setting_extruder.name = key setting_extruder.extruder = extruder From 11bad271d3c809b903184798c972041a4563d44e Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Wed, 28 Feb 2018 15:50:37 +0100 Subject: [PATCH 04/66] CURA-4400 set extruder numbers of settings to an enabled extruder; added SettingOverrideDecorator by default in CuraSceneNode --- cura/Scene/CuraSceneNode.py | 9 ++- cura/Settings/MachineManager.py | 66 +++++++++++++++---- .../ProcessSlicedLayersJob.py | 3 +- plugins/CuraEngineBackend/StartSliceJob.py | 11 ++-- 4 files changed, 67 insertions(+), 22 deletions(-) diff --git a/cura/Scene/CuraSceneNode.py b/cura/Scene/CuraSceneNode.py index df346baaad..88f89522f6 100644 --- a/cura/Scene/CuraSceneNode.py +++ b/cura/Scene/CuraSceneNode.py @@ -1,9 +1,12 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from copy import deepcopy from typing import List from UM.Application import Application from UM.Scene.SceneNode import SceneNode -from copy import deepcopy -from cura.Settings.ExtrudersModel import ExtrudersModel + +from cura.Settings.SettingOverrideDecorator import SettingOverrideDecorator ## Scene nodes that are models are only seen when selecting the corresponding build plate @@ -11,6 +14,8 @@ from cura.Settings.ExtrudersModel import ExtrudersModel class CuraSceneNode(SceneNode): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) + if "no_setting_override" not in kwargs: + self.addDecorator(SettingOverrideDecorator()) # now we always have a getActiveExtruderPosition, unless explicitly disabled self._outside_buildarea = False def setOutsideBuildArea(self, new_value): diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index b3a2a7ed9e..817317bf0a 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -52,6 +52,8 @@ class MachineManager(QObject): self._current_quality_group = None self._current_quality_changes_group = None + self._default_extruder_position = "0" # to be updated when extruders are switched on and off + self.machine_extruder_material_update_dict = collections.defaultdict(list) self._error_check_timer = QTimer() @@ -696,6 +698,39 @@ class MachineManager(QObject): if containers: return containers[0].definition.getId() + ## Update extruder number to a valid value when the number of extruders are changed, or when an extruder is changed + def correctExtruderSettings(self): + definition_changes_container = self._global_container_stack.definitionChanges + extruder_count = definition_changes_container.getProperty("machine_extruder_count", "value") + + # reset all extruder number settings whose value is no longer valid + for setting_instance in self._global_container_stack.userChanges.findInstances(): + setting_key = setting_instance.definition.key + if not self._global_container_stack.getProperty(setting_key, "type") in ("extruder", "optional_extruder"): + continue + + old_value = self._global_container_stack.userChanges.getProperty(setting_key, "value") + if int(old_value) >= extruder_count: + self._global_container_stack.userChanges.removeInstance(setting_key) + Logger.log("d", "Reset [%s] because its old value [%s] is no longer valid", setting_key, old_value) + if not self._global_container_stack.extruders[str(old_value)].isEnabled: + self._global_container_stack.userChanges.removeInstance(setting_key) + Logger.log("d", "Reset [%s] because its old value [%s] is no longer valid (2)", setting_key, old_value) + + for setting_key in self._global_container_stack.definition.getAllKeys(): + if not self._global_container_stack.getProperty(setting_key, "type") in ("extruder", "optional_extruder"): + continue + if setting_key == "support_infill_extruder_nr": + print("asdf") + current_value = self._global_container_stack.getProperty(setting_key, "value") + if current_value is None: + continue + if current_value == "-1": + continue + if not self._global_container_stack.extruders[str(current_value)].isEnabled: + self._global_container_stack.userChanges.setProperty(setting_key, "value", str(self._default_extruder_position)) + Logger.log("d", "Change [%s] to [%s] because its value [%s] is not valid", setting_key, self._default_extruder_position, current_value) + ## Set the amount of extruders on the active machine (global stack) # \param extruder_count int the number of extruders to set def setActiveMachineExtruderCount(self, extruder_count): @@ -709,16 +744,10 @@ class MachineManager(QObject): if extruder_count == previous_extruder_count: return - # reset all extruder number settings whose value is no longer valid - for setting_instance in self._global_container_stack.userChanges.findInstances(): - setting_key = setting_instance.definition.key - if not self._global_container_stack.getProperty(setting_key, "type") in ("extruder", "optional_extruder"): - continue + definition_changes_container.setProperty("machine_extruder_count", "value", extruder_count) - old_value = int(self._global_container_stack.userChanges.getProperty(setting_key, "value")) - if old_value >= extruder_count: - self._global_container_stack.userChanges.removeInstance(setting_key) - Logger.log("d", "Reset [%s] because its old value [%s] is no longer valid ", setting_key, old_value) + self.updateDefaultExtruder() + self.correctExtruderSettings() # Check to see if any objects are set to print with an extruder that will no longer exist root_node = Application.getInstance().getController().getScene().getRoot() @@ -729,8 +758,6 @@ class MachineManager(QObject): if extruder_nr is not None and int(extruder_nr) > extruder_count - 1: node.callDecoration("setActiveExtruder", extruder_manager.getExtruderStack(extruder_count - 1).getId()) - definition_changes_container.setProperty("machine_extruder_count", "value", extruder_count) - # Make sure one of the extruder stacks is active extruder_manager.setActiveExtruderIndex(0) @@ -765,11 +792,26 @@ class MachineManager(QObject): extruder = self._global_container_stack.extruders.get(str(position)) return extruder + def updateDefaultExtruder(self): + extruder_items = sorted(self._global_container_stack.extruders.items()) + new_default_position = "0" + for position, extruder in extruder_items: + if extruder.isEnabled: + new_default_position = position + break + self._default_extruder_position = new_default_position + + @pyqtProperty(str, notify = extruderChanged) + def defaultExtruderPosition(self): + return self._default_extruder_position + @pyqtSlot(int, bool) def setExtruderEnabled(self, position: int, enabled) -> None: extruder = self.getExtruder(position) extruder.setEnabled(enabled) - + if enabled == False: + self.updateDefaultExtruder() + self.correctExtruderSettings() self.extruderChanged.emit() def _onMachineNameChanged(self): diff --git a/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py b/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py index c1fc597d80..cbc097bb33 100644 --- a/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py +++ b/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py @@ -81,7 +81,8 @@ class ProcessSlicedLayersJob(Job): Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged) - new_node = CuraSceneNode() + # The no_setting_override is here because adding the SettingOverrideDecorator will trigger a reslice + new_node = CuraSceneNode(no_setting_override = True) new_node.addDecorator(BuildPlateDecorator(self._build_plate_number)) # Force garbage collection. diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index 11d98c0e43..cdf33eac26 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -110,7 +110,6 @@ class StartSliceJob(Job): return stack = Application.getInstance().getGlobalContainerStack() - extruder_stack_id_to_position = {} # a lookup table because we need the position, not the id. if not stack: self.setResult(StartJobResult.Error) return @@ -131,7 +130,6 @@ class StartSliceJob(Job): return for position, extruder_stack in stack.extruders.items(): - extruder_stack_id_to_position[extruder_stack.getId()] = position material = extruder_stack.findContainer({"type": "material"}) if material: if material.getMetaDataEntry("compatible") == False: @@ -200,8 +198,7 @@ class StartSliceJob(Job): continue if getattr(node, "_outside_buildarea", False) and is_non_printing_mesh: continue - node_extruder_id = node.callDecoration("getActiveExtruder") - node_position = extruder_stack_id_to_position.get(node_extruder_id, "0") + node_position = node.callDecoration("getActiveExtruderPosition") if not stack.extruders[str(node_position)].isEnabled: continue @@ -391,11 +388,11 @@ class StartSliceJob(Job): # limit_to_extruder property. def _buildGlobalInheritsStackMessage(self, stack): for key in stack.getAllKeys(): - extruder = int(round(float(stack.getProperty(key, "limit_to_extruder")))) - if extruder >= 0 and stack.extruders[str(extruder)].isEnabled: #Set to a specific extruder. + extruder_position = int(round(float(stack.getProperty(key, "limit_to_extruder")))) + if extruder_position >= 0: # Set to a specific extruder. setting_extruder = self._slice_message.addRepeatedMessage("limit_to_extruder") setting_extruder.name = key - setting_extruder.extruder = extruder + setting_extruder.extruder = extruder_position Job.yieldThread() ## Check if a node has per object settings and ensure that they are set correctly in the message From 657a52a5e749dccf2b5c0dc21e8f909cfe495a1e Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 1 Mar 2018 11:54:31 +0100 Subject: [PATCH 05/66] CURA-4400 add checking for enabled extruder in setting _outside_buildarea, cleaned up a bit and factored some functions out BuildVolume --- cura/BuildVolume.py | 61 +++++++++++------------ cura/Scene/CuraSceneNode.py | 24 +++++++++ cura/Settings/MachineManager.py | 2 - cura/Settings/SettingOverrideDecorator.py | 7 ++- plugins/SolidView/SolidView.py | 6 +-- 5 files changed, 58 insertions(+), 42 deletions(-) diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index 6401ad77af..5d1e38f5c8 100755 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -111,6 +111,9 @@ class BuildVolume(SceneNode): # but it does not update the disallowed areas after material change Application.getInstance().getMachineManager().activeStackChanged.connect(self._onStackChanged) + # Enable and disable extruder + Application.getInstance().getMachineManager().extruderChanged.connect(self.updateNodeBoundaryCheck) + # list of settings which were updated self._changed_settings_since_last_rebuild = [] @@ -217,30 +220,26 @@ class BuildVolume(SceneNode): group_nodes.append(node) # Keep list of affected group_nodes if node.callDecoration("isSliceable") or node.callDecoration("isGroup"): - node._outside_buildarea = False - bbox = node.getBoundingBox() - - # Mark the node as outside the build volume if the bounding box test fails. - if build_volume_bounding_box.intersectsBox(bbox) != AxisAlignedBox.IntersectionResult.FullIntersection: - node._outside_buildarea = True + if node.collidesWithBbox(build_volume_bounding_box): + node.setOutsideBuildArea(True) continue - convex_hull = node.callDecoration("getConvexHull") - if convex_hull: - if not convex_hull.isValid(): - return - # Check for collisions between disallowed areas and the object - for area in self.getDisallowedAreas(): - overlap = convex_hull.intersectsPolygon(area) - if overlap is None: - continue - node._outside_buildarea = True - continue + if node.collidesWithArea(self.getDisallowedAreas()): + node.setOutsideBuildArea(True) + continue + + # 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: + node.setOutsideBuildArea(True) + continue + + node.setOutsideBuildArea(False) # Group nodes should override the _outside_buildarea property of their children. for group_node in group_nodes: for child_node in group_node.getAllChildren(): - child_node._outside_buildarea = group_node._outside_buildarea + child_node.setOutsideBuildArea(group_node.isOutsideBuildArea) ## Update the outsideBuildArea of a single node, given bounds or current build volume def checkBoundsAndUpdate(self, node: CuraSceneNode, bounds: Optional[AxisAlignedBox] = None): @@ -260,24 +259,20 @@ class BuildVolume(SceneNode): build_volume_bounding_box = bounds if node.callDecoration("isSliceable") or node.callDecoration("isGroup"): - bbox = node.getBoundingBox() - - # Mark the node as outside the build volume if the bounding box test fails. - if build_volume_bounding_box.intersectsBox(bbox) != AxisAlignedBox.IntersectionResult.FullIntersection: + if node.collidesWithBbox(build_volume_bounding_box): + node.setOutsideBuildArea(True) + return + + if node.collidesWithArea(self.getDisallowedAreas()): + node.setOutsideBuildArea(True) + return + + # 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: node.setOutsideBuildArea(True) return - convex_hull = self.callDecoration("getConvexHull") - if convex_hull: - if not convex_hull.isValid(): - return - # Check for collisions between disallowed areas and the object - for area in self.getDisallowedAreas(): - overlap = convex_hull.intersectsPolygon(area) - if overlap is None: - continue - node.setOutsideBuildArea(True) - return node.setOutsideBuildArea(False) ## Recalculates the build volume & disallowed areas. diff --git a/cura/Scene/CuraSceneNode.py b/cura/Scene/CuraSceneNode.py index 88f89522f6..cfc41eb689 100644 --- a/cura/Scene/CuraSceneNode.py +++ b/cura/Scene/CuraSceneNode.py @@ -4,6 +4,7 @@ from copy import deepcopy from typing import List from UM.Application import Application +from UM.Math.AxisAlignedBox import AxisAlignedBox from UM.Scene.SceneNode import SceneNode from cura.Settings.SettingOverrideDecorator import SettingOverrideDecorator @@ -77,6 +78,29 @@ class CuraSceneNode(SceneNode): 1.0 ] + def collidesWithBbox(self, check_bbox): + bbox = self.getBoundingBox() + + # Mark the node as outside the build volume if the bounding box test fails. + if check_bbox.intersectsBox(bbox) != AxisAlignedBox.IntersectionResult.FullIntersection: + return True + + return False + + def collidesWithArea(self, areas): + convex_hull = self.callDecoration("getConvexHull") + if convex_hull: + if not convex_hull.isValid(): + return False + + # Check for collisions between disallowed areas and the object + for area in areas: + overlap = convex_hull.intersectsPolygon(area) + if overlap is None: + continue + return True + return False + ## Taken from SceneNode, but replaced SceneNode with CuraSceneNode def __deepcopy__(self, memo): copy = CuraSceneNode() diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 817317bf0a..cb0ce4ffc5 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -720,8 +720,6 @@ class MachineManager(QObject): for setting_key in self._global_container_stack.definition.getAllKeys(): if not self._global_container_stack.getProperty(setting_key, "type") in ("extruder", "optional_extruder"): continue - if setting_key == "support_infill_extruder_nr": - print("asdf") current_value = self._global_container_stack.getProperty(setting_key, "value") if current_value is None: continue diff --git a/cura/Settings/SettingOverrideDecorator.py b/cura/Settings/SettingOverrideDecorator.py index b853c06c8e..686c546836 100644 --- a/cura/Settings/SettingOverrideDecorator.py +++ b/cura/Settings/SettingOverrideDecorator.py @@ -61,7 +61,7 @@ class SettingOverrideDecorator(SceneNodeDecorator): # use value from the stack because there can be a delay in signal triggering and "_is_non_printing_mesh" # has not been updated yet. - deep_copy._is_non_printing_mesh = any(bool(self._stack.getProperty(setting, "value")) for setting in self._non_printing_mesh_settings) + deep_copy._is_non_printing_mesh = self.evaluateIsNonPrintingMesh() return deep_copy @@ -89,10 +89,13 @@ class SettingOverrideDecorator(SceneNodeDecorator): def isNonPrintingMesh(self): return self._is_non_printing_mesh + def evaluateIsNonPrintingMesh(self): + return any(bool(self._stack.getProperty(setting, "value")) for setting in self._non_printing_mesh_settings) + def _onSettingChanged(self, instance, property_name): # Reminder: 'property' is a built-in function # Trigger slice/need slicing if the value has changed. if property_name == "value": - self._is_non_printing_mesh = any(bool(self._stack.getProperty(setting, "value")) for setting in self._non_printing_mesh_settings) + self._is_non_printing_mesh = self.evaluateIsNonPrintingMesh() Application.getInstance().getBackend().needsSlicing() Application.getInstance().getBackend().tickle() diff --git a/plugins/SolidView/SolidView.py b/plugins/SolidView/SolidView.py index 50ff2864b7..2abfe80f95 100644 --- a/plugins/SolidView/SolidView.py +++ b/plugins/SolidView/SolidView.py @@ -84,11 +84,7 @@ class SolidView(View): per_mesh_stack = node.callDecoration("getStack") - # Get color to render this mesh in from ExtrudersModel - extruder_index = 0 - extruder_id = node.callDecoration("getActiveExtruder") - if extruder_id: - extruder_index = max(0, self._extruders_model.find("id", extruder_id)) + extruder_index = int(node.callDecoration("getActiveExtruderPosition")) # Use the support extruder instead of the active extruder if this is a support_mesh if per_mesh_stack: From c94d88cd9d26c6d856205412ecca6d5b6be49025 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 1 Mar 2018 12:53:50 +0100 Subject: [PATCH 06/66] CURA-4400 added context menu on right click extruder in SidebarHeader --- resources/qml/SidebarHeader.qml | 35 ++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index a9aefe4848..cf76b5eb53 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -91,10 +91,39 @@ Column exclusiveGroup: extruderMenuGroup checked: base.currentExtruderIndex == index - onClicked: + MouseArea { - forceActiveFocus() // Changing focus applies the currently-being-typed values so it can change the displayed setting values. - Cura.ExtruderManager.setActiveExtruderIndex(index); + anchors.fill: parent + acceptedButtons: Qt.LeftButton | Qt.RightButton + onClicked: { + switch (mouse.button) { + case Qt.LeftButton: + forceActiveFocus(); // Changing focus applies the currently-being-typed values so it can change the displayed setting values. + Cura.ExtruderManager.setActiveExtruderIndex(index); + break; + case Qt.RightButton: + extruderMenu.popup(); + break; + } + + } + } + + Menu + { + id: extruderMenu + + MenuItem { + text: catalog.i18nc("@action:inmenu", "Enable Extruder") + onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, true) + visible: !Cura.MachineManager.getExtruder(model.index).isEnabled + } + + MenuItem { + text: catalog.i18nc("@action:inmenu", "Disable Extruder") + onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, false) + visible: Cura.MachineManager.getExtruder(model.index).isEnabled + } } style: ButtonStyle From 71e631150de66fc16efbacae45d52f6a25f0944b Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 1 Mar 2018 13:06:12 +0100 Subject: [PATCH 07/66] CURA-4400 update extruder disabled color --- resources/qml/SidebarHeader.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index cf76b5eb53..473f4c5cc8 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -151,7 +151,7 @@ Column control.hovered ? UM.Theme.getColor("action_button_hovered_text") : UM.Theme.getColor("action_button_text"); } else { - return UM.Theme.getColor("action_button_disabled"); + return UM.Theme.getColor("action_button_disabled_text"); } } From ba7b18a88b326b718ba8c6de395a73a9d22259b5 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 1 Mar 2018 15:02:35 +0100 Subject: [PATCH 08/66] CURA-4400 corrected getProperty in correctExtruderSettings --- cura/Settings/ContainerManager.py | 4 +++- cura/Settings/MachineManager.py | 8 ++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/cura/Settings/ContainerManager.py b/cura/Settings/ContainerManager.py index 96fff61b0b..20ce9638c1 100644 --- a/cura/Settings/ContainerManager.py +++ b/cura/Settings/ContainerManager.py @@ -346,10 +346,12 @@ class ContainerManager(QObject): # Go through global and extruder stacks and clear their topmost container (the user settings). for stack in ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks(): - container = stack.getTop() + container = stack.userChanges container.clear() send_emits_containers.append(container) + Application.getInstance().getMachineManager().correctExtruderSettings() + for container in send_emits_containers: container.sendPostponedEmits() diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index a46fedd853..52058789c3 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -699,9 +699,9 @@ class MachineManager(QObject): return containers[0].definition.getId() ## Update extruder number to a valid value when the number of extruders are changed, or when an extruder is changed + # \return if any properties has been added def correctExtruderSettings(self): - definition_changes_container = self._global_container_stack.definitionChanges - extruder_count = definition_changes_container.getProperty("machine_extruder_count", "value") + extruder_count = self._global_container_stack.getProperty("machine_extruder_count", "value") # reset all extruder number settings whose value is no longer valid for setting_instance in self._global_container_stack.userChanges.findInstances(): @@ -717,6 +717,7 @@ class MachineManager(QObject): self._global_container_stack.userChanges.removeInstance(setting_key) Logger.log("d", "Reset [%s] because its old value [%s] is no longer valid (2)", setting_key, old_value) + added_properties = False for setting_key in self._global_container_stack.definition.getAllKeys(): if not self._global_container_stack.getProperty(setting_key, "type") in ("extruder", "optional_extruder"): continue @@ -727,8 +728,11 @@ class MachineManager(QObject): continue if not self._global_container_stack.extruders[str(current_value)].isEnabled: self._global_container_stack.userChanges.setProperty(setting_key, "value", str(self._default_extruder_position)) + added_properties = True Logger.log("d", "Change [%s] to [%s] because its value [%s] is not valid", setting_key, self._default_extruder_position, current_value) + return added_properties + ## Set the amount of extruders on the active machine (global stack) # \param extruder_count int the number of extruders to set def setActiveMachineExtruderCount(self, extruder_count): From 2538c689f191430339500ba532bb81bbff121565 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 1 Mar 2018 16:22:40 +0100 Subject: [PATCH 09/66] CURA-4400 make extruder combobox disabled items grey --- cura/Settings/ExtrudersModel.py | 4 ++++ cura/Settings/MachineManager.py | 4 +++- resources/qml/Settings/SettingExtruder.qml | 22 ++++++++++++++++++---- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/cura/Settings/ExtrudersModel.py b/cura/Settings/ExtrudersModel.py index c3db797e19..ae8cff3c9a 100644 --- a/cura/Settings/ExtrudersModel.py +++ b/cura/Settings/ExtrudersModel.py @@ -24,6 +24,8 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): ## Human-readable name of the extruder. NameRole = Qt.UserRole + 2 + ## Is the extruder enabled? + EnabledRole = Qt.UserRole + 9 ## Colour of the material loaded in the extruder. ColorRole = Qt.UserRole + 3 @@ -58,6 +60,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): self.addRoleName(self.IdRole, "id") self.addRoleName(self.NameRole, "name") + self.addRoleName(self.EnabledRole, "enabled") self.addRoleName(self.ColorRole, "color") self.addRoleName(self.IndexRole, "index") self.addRoleName(self.DefinitionRole, "definition") @@ -185,6 +188,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): item = { "id": extruder.getId(), "name": extruder.getName(), + "enabled": extruder.isEnabled, "color": color, "index": position, "definition": extruder.getBottom().getId(), diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 52058789c3..5faebd4dac 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -811,10 +811,12 @@ class MachineManager(QObject): def setExtruderEnabled(self, position: int, enabled) -> None: extruder = self.getExtruder(position) extruder.setEnabled(enabled) + self.updateDefaultExtruder() if enabled == False: - self.updateDefaultExtruder() self.correctExtruderSettings() self.extruderChanged.emit() + # HACK to update items in SettingExtruder + ExtruderManager.getInstance().extrudersChanged.emit(self._global_container_stack.getId()) def _onMachineNameChanged(self): self.globalContainerChanged.emit() diff --git a/resources/qml/Settings/SettingExtruder.qml b/resources/qml/Settings/SettingExtruder.qml index 17a0dd5eee..3db5d327f4 100644 --- a/resources/qml/Settings/SettingExtruder.qml +++ b/resources/qml/Settings/SettingExtruder.qml @@ -17,14 +17,22 @@ SettingItem id: control anchors.fill: parent - model: Cura.ExtrudersModel { onModelChanged: control.color = getItem(control.currentIndex).color } + model: Cura.ExtrudersModel { + onModelChanged: { + control.color = getItem(control.currentIndex).color; + } + } textRole: "name" onActivated: { - forceActiveFocus(); - propertyProvider.setPropertyValue("value", model.getItem(index).index); + if (model.getItem(index).enabled) { + forceActiveFocus(); + propertyProvider.setPropertyValue("value", model.getItem(index).index); + } else { + currentIndex = propertyProvider.properties.value; // keep the old value + } } onActiveFocusChanged: @@ -173,7 +181,13 @@ SettingItem { text: model.name renderType: Text.NativeRendering - color: UM.Theme.getColor("setting_control_text") + color: { + if (model.enabled) { + UM.Theme.getColor("setting_control_text") + } else { + UM.Theme.getColor("action_button_disabled_text"); + } + } font: UM.Theme.getFont("default") elide: Text.ElideRight verticalAlignment: Text.AlignVCenter From 53ec846436ce2528d3b3e4418b0d4a93ba813bd5 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 1 Mar 2018 17:21:35 +0100 Subject: [PATCH 10/66] CURA-4400 introduced value -1 for extruder number setting (not optional_extruder); this one takes the defaultExtruderPosition in MachineManager --- cura/Settings/ExtruderManager.py | 22 ++++++++++++++----- cura/Settings/MachineManager.py | 17 -------------- .../CuraEngineBackend/CuraEngineBackend.py | 8 +++++++ plugins/CuraEngineBackend/StartSliceJob.py | 8 ++++++- resources/definitions/fdmprinter.def.json | 14 ++++++------ resources/qml/Settings/SettingExtruder.qml | 18 +++++++++++++++ 6 files changed, 56 insertions(+), 31 deletions(-) diff --git a/cura/Settings/ExtruderManager.py b/cura/Settings/ExtruderManager.py index fe1bb6a990..ee38055a98 100755 --- a/cura/Settings/ExtruderManager.py +++ b/cura/Settings/ExtruderManager.py @@ -241,6 +241,13 @@ class ExtruderManager(QObject): result.append(extruder_stack.getProperty(setting_key, prop)) return result + def extruderValueWithDefault(self, value): + machine_manager = self._application.getMachineManager() + if value == "-1": + return machine_manager.defaultExtruderPosition + else: + return value + ## Gets the extruder stacks that are actually being used at the moment. # # An extruder stack is being used if it is the extruder to print any mesh @@ -252,7 +259,7 @@ class ExtruderManager(QObject): # # \return A list of extruder stacks. def getUsedExtruderStacks(self) -> List["ContainerStack"]: - global_stack = Application.getInstance().getGlobalContainerStack() + global_stack = self._application.getGlobalContainerStack() container_registry = ContainerRegistry.getInstance() used_extruder_stack_ids = set() @@ -302,16 +309,19 @@ class ExtruderManager(QObject): # Check support extruders if support_enabled: - used_extruder_stack_ids.add(self.extruderIds[str(global_stack.getProperty("support_infill_extruder_nr", "value"))]) - used_extruder_stack_ids.add(self.extruderIds[str(global_stack.getProperty("support_extruder_nr_layer_0", "value"))]) + used_extruder_stack_ids.add(self.extruderIds[self.extruderValueWithDefault(str(global_stack.getProperty("support_infill_extruder_nr", "value")))]) + used_extruder_stack_ids.add(self.extruderIds[self.extruderValueWithDefault(str(global_stack.getProperty("support_extruder_nr_layer_0", "value")))]) if support_bottom_enabled: - used_extruder_stack_ids.add(self.extruderIds[str(global_stack.getProperty("support_bottom_extruder_nr", "value"))]) + used_extruder_stack_ids.add(self.extruderIds[self.extruderValueWithDefault(str(global_stack.getProperty("support_bottom_extruder_nr", "value")))]) if support_roof_enabled: - used_extruder_stack_ids.add(self.extruderIds[str(global_stack.getProperty("support_roof_extruder_nr", "value"))]) + used_extruder_stack_ids.add(self.extruderIds[self.extruderValueWithDefault(str(global_stack.getProperty("support_roof_extruder_nr", "value")))]) # The platform adhesion extruder. Not used if using none. if global_stack.getProperty("adhesion_type", "value") != "none": - used_extruder_stack_ids.add(self.extruderIds[str(global_stack.getProperty("adhesion_extruder_nr", "value"))]) + extruder_nr = str(global_stack.getProperty("adhesion_extruder_nr", "value")) + if extruder_nr == "-1": + extruder_nr = Application.getInstance().getMachineManager().defaultExtruderPosition + used_extruder_stack_ids.add(self.extruderIds[extruder_nr]) try: return [container_registry.findContainerStacks(id = stack_id)[0] for stack_id in used_extruder_stack_ids] diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 5faebd4dac..b46078176f 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -699,7 +699,6 @@ class MachineManager(QObject): return containers[0].definition.getId() ## Update extruder number to a valid value when the number of extruders are changed, or when an extruder is changed - # \return if any properties has been added def correctExtruderSettings(self): extruder_count = self._global_container_stack.getProperty("machine_extruder_count", "value") @@ -717,22 +716,6 @@ class MachineManager(QObject): self._global_container_stack.userChanges.removeInstance(setting_key) Logger.log("d", "Reset [%s] because its old value [%s] is no longer valid (2)", setting_key, old_value) - added_properties = False - for setting_key in self._global_container_stack.definition.getAllKeys(): - if not self._global_container_stack.getProperty(setting_key, "type") in ("extruder", "optional_extruder"): - continue - current_value = self._global_container_stack.getProperty(setting_key, "value") - if current_value is None: - continue - if current_value == "-1": - continue - if not self._global_container_stack.extruders[str(current_value)].isEnabled: - self._global_container_stack.userChanges.setProperty(setting_key, "value", str(self._default_extruder_position)) - added_properties = True - Logger.log("d", "Change [%s] to [%s] because its value [%s] is not valid", setting_key, self._default_extruder_position, current_value) - - return added_properties - ## Set the amount of extruders on the active machine (global stack) # \param extruder_count int the number of extruders to set def setActiveMachineExtruderCount(self, extruder_count): diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index 3982a0ad06..86c181213e 100755 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -91,6 +91,8 @@ class CuraEngineBackend(QObject, Backend): self._onGlobalStackChanged() Application.getInstance().stacksValidationFinished.connect(self._onStackErrorCheckFinished) + # extruder enable / disable. Actually wanted to use machine manager here, but the initialization order causes it to crash + ExtruderManager.getInstance().extrudersChanged.connect(self._extruderChanged) # A flag indicating if an error check was scheduled # If so, we will stop the auto-slice timer and start upon the error check @@ -773,3 +775,9 @@ class CuraEngineBackend(QObject, Backend): def tickle(self): if self._use_timer: self._change_timer.start() + + def _extruderChanged(self): + for build_plate_number in range(Application.getInstance().getMultiBuildPlateModel().maxBuildPlate + 1): + if build_plate_number not in self._build_plates_to_be_sliced: + self._build_plates_to_be_sliced.append(build_plate_number) + self._invokeSlice() diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index cdf33eac26..c426044ae2 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -280,9 +280,15 @@ class StartSliceJob(Job): # \return A dictionary of replacement tokens to the values they should be # replaced with. def _buildReplacementTokens(self, stack) -> dict: + default_extruder_position = Application.getInstance().getMachineManager().defaultExtruderPosition result = {} for key in stack.getAllKeys(): - result[key] = stack.getProperty(key, "value") + setting_type = stack.getProperty(key, "type") + value = stack.getProperty(key, "value") + if setting_type == "extruder" and value == "-1": + # replace with the default value + value = default_extruder_position + result[key] = value Job.yieldThread() result["print_bed_temperature"] = result["material_bed_temperature"] # Renamed settings. diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 8c67462667..b926dc0abc 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -3458,7 +3458,7 @@ "label": "Support Extruder", "description": "The extruder train to use for printing the support. This is used in multi-extrusion.", "type": "extruder", - "default_value": "0", + "default_value": "-1", "enabled": "(support_enable or support_tree_enable) and machine_extruder_count > 1", "settable_per_mesh": false, "settable_per_extruder": false, @@ -3468,7 +3468,7 @@ "label": "Support Infill Extruder", "description": "The extruder train to use for printing the infill of the support. This is used in multi-extrusion.", "type": "extruder", - "default_value": "0", + "default_value": "-1", "value": "support_extruder_nr", "enabled": "(support_enable or support_tree_enable) and machine_extruder_count > 1", "settable_per_mesh": false, @@ -3479,7 +3479,7 @@ "label": "First Layer Support Extruder", "description": "The extruder train to use for printing the first layer of support infill. This is used in multi-extrusion.", "type": "extruder", - "default_value": "0", + "default_value": "-1", "value": "support_extruder_nr", "enabled": "(support_enable or support_tree_enable) and machine_extruder_count > 1", "settable_per_mesh": false, @@ -3490,7 +3490,7 @@ "label": "Support Interface Extruder", "description": "The extruder train to use for printing the roofs and floors of the support. This is used in multi-extrusion.", "type": "extruder", - "default_value": "0", + "default_value": "-1", "value": "support_extruder_nr", "enabled": "(support_enable or support_tree_enable) and machine_extruder_count > 1", "settable_per_mesh": false, @@ -3502,7 +3502,7 @@ "label": "Support Roof Extruder", "description": "The extruder train to use for printing the roofs of the support. This is used in multi-extrusion.", "type": "extruder", - "default_value": "0", + "default_value": "-1", "value": "support_interface_extruder_nr", "enabled": "(support_enable or support_tree_enable) and machine_extruder_count > 1", "settable_per_mesh": false, @@ -3513,7 +3513,7 @@ "label": "Support Floor Extruder", "description": "The extruder train to use for printing the floors of the support. This is used in multi-extrusion.", "type": "extruder", - "default_value": "0", + "default_value": "-1", "value": "support_interface_extruder_nr", "enabled": "(support_enable or support_tree_enable) and machine_extruder_count > 1", "settable_per_mesh": false, @@ -4184,7 +4184,7 @@ "label": "Build Plate Adhesion Extruder", "description": "The extruder train to use for printing the skirt/brim/raft. This is used in multi-extrusion.", "type": "extruder", - "default_value": "0", + "default_value": "-1", "enabled": "machine_extruder_count > 1 and resolveOrValue('adhesion_type') != 'none'", "settable_per_mesh": false, "settable_per_extruder": false diff --git a/resources/qml/Settings/SettingExtruder.qml b/resources/qml/Settings/SettingExtruder.qml index 3db5d327f4..2a2e213142 100644 --- a/resources/qml/Settings/SettingExtruder.qml +++ b/resources/qml/Settings/SettingExtruder.qml @@ -72,6 +72,24 @@ SettingItem value: control.currentText != "" ? control.model.getItem(control.currentIndex).color : "" } + Binding + { + target: control + property: "currentIndex" + value: + { + if(propertyProvider.properties.value == -1) + { + // TODO: accidently the extruder position is also the index. fix it + return Cura.MachineManager.defaultExtruderPosition; + } + return propertyProvider.properties.value + } + // Sometimes when the value is already changed, the model is still being built. + // The when clause ensures that the current index is not updated when this happens. + when: control.model.items.length > 0 + } + indicator: UM.RecolorImage { id: downArrow From b0801d40e3f7d5b026ac5bbda3c4b336b0fb8a9b Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Mon, 5 Mar 2018 12:47:32 +0100 Subject: [PATCH 11/66] CURA-4400 added metadata entry for enabled instead of internal variable --- cura/Settings/ExtruderStack.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cura/Settings/ExtruderStack.py b/cura/Settings/ExtruderStack.py index 2a4207c3f3..fcdcdd9228 100644 --- a/cura/Settings/ExtruderStack.py +++ b/cura/Settings/ExtruderStack.py @@ -10,7 +10,7 @@ from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase from UM.Settings.ContainerStack import ContainerStack from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Settings.Interfaces import ContainerInterface, PropertyEvaluationContext -from UM.Settings.SettingInstance import SettingInstance +from UM.Util import parseBool from . import Exceptions from .CuraContainerStack import CuraContainerStack @@ -28,7 +28,6 @@ class ExtruderStack(CuraContainerStack): super().__init__(container_id, *args, **kwargs) self.addMetaDataEntry("type", "extruder_train") # For backward compatibility - self._enabled = True self.propertiesChanged.connect(self._onPropertiesChanged) @@ -51,12 +50,14 @@ class ExtruderStack(CuraContainerStack): return super().getNextStack() def setEnabled(self, enabled): - self._enabled = enabled + if "enabled" not in self._metadata: + self.addMetaDataEntry("enabled", "True") + self.setMetaDataEntry("enabled", str(enabled)) self.enabledChanged.emit() @pyqtProperty(bool, notify = enabledChanged) def isEnabled(self): - return self._enabled + return parseBool(self.getMetaDataEntry("enabled", "True")) @classmethod def getLoadingPriority(cls) -> int: From 37d02da1f147cedd4f832b277925755cf63ace90 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Mon, 5 Mar 2018 14:01:39 +0100 Subject: [PATCH 12/66] CURA-4400 restore correct default extruder, added extruders_enabled_count and use that in fdmprinters (result: i.e. one at a time can be enabled by disabling an extruder) --- cura/Settings/ExtruderManager.py | 2 + cura/Settings/MachineManager.py | 26 +++++++++--- resources/definitions/fdmprinter.def.json | 52 ++++++++++++++--------- 3 files changed, 54 insertions(+), 26 deletions(-) diff --git a/cura/Settings/ExtruderManager.py b/cura/Settings/ExtruderManager.py index ee38055a98..fcbe67e465 100755 --- a/cura/Settings/ExtruderManager.py +++ b/cura/Settings/ExtruderManager.py @@ -484,6 +484,8 @@ class ExtruderManager(QObject): result = [] for extruder in ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()): + if not extruder.isEnabled: + continue # only include values from extruders that are "active" for the current machine instance if int(extruder.getMetaDataEntry("position")) >= global_stack.getProperty("machine_extruder_count", "value"): continue diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index b46078176f..56479f40a2 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -195,7 +195,6 @@ class MachineManager(QObject): # Update the local global container stack reference self._global_container_stack = Application.getInstance().getGlobalContainerStack() - self.globalContainerChanged.emit() # after switching the global stack we reconnect all the signals and set the variant and material references @@ -309,6 +308,8 @@ class MachineManager(QObject): Application.getInstance().setGlobalContainerStack(global_stack) ExtruderManager.getInstance()._globalContainerStackChanged() self._initMachineState(containers[0]) + self.updateDefaultExtruder() + self.updateNumberExtrudersEnabled() self.globalContainerChanged.emit() self._onGlobalContainerChanged() @@ -732,6 +733,7 @@ class MachineManager(QObject): definition_changes_container.setProperty("machine_extruder_count", "value", extruder_count) self.updateDefaultExtruder() + self.updateNumberExtrudersEnabled() self.correctExtruderSettings() # Check to see if any objects are set to print with an extruder that will no longer exist @@ -748,14 +750,14 @@ class MachineManager(QObject): # Move settable_per_extruder values out of the global container # After CURA-4482 this should not be the case anymore, but we still want to support older project files. - global_user_container = self._global_container_stack.getTop() + global_user_container = self._global_container_stack.userChanges # Make sure extruder_stacks exists extruder_stacks = [] if previous_extruder_count == 1: extruder_stacks = ExtruderManager.getInstance().getActiveExtruderStacks() - global_user_container = self._global_container_stack.getTop() + global_user_container = self._global_container_stack.userChanges for setting_instance in global_user_container.findInstances(): setting_key = setting_instance.definition.key @@ -764,7 +766,7 @@ class MachineManager(QObject): if settable_per_extruder: limit_to_extruder = int(self._global_container_stack.getProperty(setting_key, "limit_to_extruder")) extruder_stack = extruder_stacks[max(0, limit_to_extruder)] - extruder_stack.getTop().setProperty(setting_key, "value", global_user_container.getProperty(setting_key, "value")) + extruder_stack.userChanges.setProperty(setting_key, "value", global_user_container.getProperty(setting_key, "value")) global_user_container.removeInstance(setting_key) # Signal that the global stack has changed @@ -779,12 +781,23 @@ class MachineManager(QObject): def updateDefaultExtruder(self): 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: if extruder.isEnabled: new_default_position = position break - self._default_extruder_position = new_default_position + if new_default_position != old_position: + self._default_extruder_position = new_default_position + self.extruderChanged.emit() + + def updateNumberExtrudersEnabled(self): + definition_changes_container = self._global_container_stack.definitionChanges + extruder_count = 0 + for position, extruder in self._global_container_stack.extruders.items(): + if extruder.isEnabled: + extruder_count += 1 + definition_changes_container.setProperty("extruders_enabled_count", "value", extruder_count) @pyqtProperty(str, notify = extruderChanged) def defaultExtruderPosition(self): @@ -795,10 +808,11 @@ class MachineManager(QObject): extruder = self.getExtruder(position) extruder.setEnabled(enabled) self.updateDefaultExtruder() + self.updateNumberExtrudersEnabled() if enabled == False: self.correctExtruderSettings() self.extruderChanged.emit() - # HACK to update items in SettingExtruder + # update items in SettingExtruder ExtruderManager.getInstance().extrudersChanged.emit(self._global_container_stack.getId()) def _onMachineNameChanged(self): diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index b926dc0abc..34dc6538b3 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -211,6 +211,18 @@ "settable_per_extruder": false, "settable_per_meshgroup": false }, + "extruders_enabled_count": + { + "label": "Number of Extruders that are enabled", + "description": "Number of extruder trains that are enabled; automatically set in software", + "default_value": "machine_extruder_count", + "minimum_value": "1", + "maximum_value": "16", + "type": "int", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false + }, "machine_nozzle_tip_outer_diameter": { "label": "Outer nozzle diameter", @@ -887,7 +899,7 @@ "settable_per_extruder": false, "settable_per_meshgroup": true, "settable_globally": true, - "enabled": "machine_extruder_count > 1", + "enabled": "extruders_enabled_count > 1", "children": { "wall_0_extruder_nr": { @@ -900,7 +912,7 @@ "settable_per_extruder": false, "settable_per_meshgroup": true, "settable_globally": true, - "enabled": "machine_extruder_count > 1" + "enabled": "extruders_enabled_count > 1" }, "wall_x_extruder_nr": { @@ -913,7 +925,7 @@ "settable_per_extruder": false, "settable_per_meshgroup": true, "settable_globally": true, - "enabled": "machine_extruder_count > 1" + "enabled": "extruders_enabled_count > 1" } } }, @@ -970,7 +982,7 @@ "settable_per_extruder": false, "settable_per_meshgroup": true, "settable_globally": true, - "enabled": "machine_extruder_count > 1 and max(extruderValues('roofing_layer_count')) > 0 and max(extruderValues('top_layers')) > 0" + "enabled": "extruders_enabled_count > 1 and max(extruderValues('roofing_layer_count')) > 0 and max(extruderValues('top_layers')) > 0" }, "roofing_layer_count": { @@ -995,7 +1007,7 @@ "settable_per_extruder": false, "settable_per_meshgroup": true, "settable_globally": true, - "enabled": "machine_extruder_count > 1" + "enabled": "extruders_enabled_count > 1" }, "top_bottom_thickness": { @@ -1465,7 +1477,7 @@ "settable_per_extruder": false, "settable_per_meshgroup": true, "settable_globally": true, - "enabled": "machine_extruder_count > 1" + "enabled": "extruders_enabled_count > 1" }, "infill_sparse_density": { @@ -1916,7 +1928,7 @@ "minimum_value": "0", "maximum_value_warning": "10.0", "maximum_value": "machine_nozzle_heat_up_speed", - "enabled": "material_flow_dependent_temperature or (machine_extruder_count > 1 and material_final_print_temperature != material_print_temperature)", + "enabled": "material_flow_dependent_temperature or (extruders_enabled_count > 1 and material_final_print_temperature != material_print_temperature)", "settable_per_mesh": false, "settable_per_extruder": true }, @@ -2179,7 +2191,7 @@ "minimum_value": "-273.15", "minimum_value_warning": "0", "maximum_value_warning": "260", - "enabled": "machine_extruder_count > 1 and machine_nozzle_temp_enabled", + "enabled": "extruders_enabled_count > 1 and machine_nozzle_temp_enabled", "settable_per_mesh": false, "settable_per_extruder": true }, @@ -3281,7 +3293,7 @@ "description": "After the machine switched from one extruder to the other, the build plate is lowered to create clearance between the nozzle and the print. This prevents the nozzle from leaving oozed material on the outside of a print.", "type": "bool", "default_value": true, - "enabled": "retraction_hop_enabled and machine_extruder_count > 1", + "enabled": "retraction_hop_enabled and extruders_enabled_count > 1", "settable_per_mesh": false, "settable_per_extruder": true } @@ -3459,7 +3471,7 @@ "description": "The extruder train to use for printing the support. This is used in multi-extrusion.", "type": "extruder", "default_value": "-1", - "enabled": "(support_enable or support_tree_enable) and machine_extruder_count > 1", + "enabled": "(support_enable or support_tree_enable) and extruders_enabled_count > 1", "settable_per_mesh": false, "settable_per_extruder": false, "children": { @@ -3470,7 +3482,7 @@ "type": "extruder", "default_value": "-1", "value": "support_extruder_nr", - "enabled": "(support_enable or support_tree_enable) and machine_extruder_count > 1", + "enabled": "(support_enable or support_tree_enable) and extruders_enabled_count > 1", "settable_per_mesh": false, "settable_per_extruder": false }, @@ -3481,7 +3493,7 @@ "type": "extruder", "default_value": "-1", "value": "support_extruder_nr", - "enabled": "(support_enable or support_tree_enable) and machine_extruder_count > 1", + "enabled": "(support_enable or support_tree_enable) and extruders_enabled_count > 1", "settable_per_mesh": false, "settable_per_extruder": false }, @@ -3492,7 +3504,7 @@ "type": "extruder", "default_value": "-1", "value": "support_extruder_nr", - "enabled": "(support_enable or support_tree_enable) and machine_extruder_count > 1", + "enabled": "(support_enable or support_tree_enable) and extruders_enabled_count > 1", "settable_per_mesh": false, "settable_per_extruder": false, "children": @@ -3504,7 +3516,7 @@ "type": "extruder", "default_value": "-1", "value": "support_interface_extruder_nr", - "enabled": "(support_enable or support_tree_enable) and machine_extruder_count > 1", + "enabled": "(support_enable or support_tree_enable) and extruders_enabled_count > 1", "settable_per_mesh": false, "settable_per_extruder": false }, @@ -3515,7 +3527,7 @@ "type": "extruder", "default_value": "-1", "value": "support_interface_extruder_nr", - "enabled": "(support_enable or support_tree_enable) and machine_extruder_count > 1", + "enabled": "(support_enable or support_tree_enable) and extruders_enabled_count > 1", "settable_per_mesh": false, "settable_per_extruder": false } @@ -4185,7 +4197,7 @@ "description": "The extruder train to use for printing the skirt/brim/raft. This is used in multi-extrusion.", "type": "extruder", "default_value": "-1", - "enabled": "machine_extruder_count > 1 and resolveOrValue('adhesion_type') != 'none'", + "enabled": "extruders_enabled_count > 1 and resolveOrValue('adhesion_type') != 'none'", "settable_per_mesh": false, "settable_per_extruder": false }, @@ -4756,7 +4768,7 @@ "label": "Enable Prime Tower", "description": "Print a tower next to the print which serves to prime the material after each nozzle switch.", "type": "bool", - "enabled": "machine_extruder_count > 1", + "enabled": "extruders_enabled_count > 1", "default_value": false, "resolve": "any(extruderValues('prime_tower_enable'))", "settable_per_mesh": false, @@ -4904,7 +4916,7 @@ "description": "Enable exterior ooze shield. This will create a shell around the model which is likely to wipe a second nozzle if it's at the same height as the first nozzle.", "type": "bool", "resolve": "any(extruderValues('ooze_shield_enabled'))", - "enabled": "machine_extruder_count > 1", + "enabled": "extruders_enabled_count > 1", "default_value": false, "settable_per_mesh": false, "settable_per_extruder": false @@ -4997,7 +5009,7 @@ "description": "Remove areas where multiple meshes are overlapping with each other. This may be used if merged dual material objects overlap with each other.", "type": "bool", "default_value": true, - "value": "machine_extruder_count > 1", + "value": "extruders_enabled_count > 1", "settable_per_mesh": false, "settable_per_extruder": false, "settable_per_meshgroup": true @@ -5044,7 +5056,7 @@ "one_at_a_time": "One at a Time" }, "default_value": "all_at_once", - "enabled": "machine_extruder_count == 1", + "enabled": "extruders_enabled_count == 1", "settable_per_mesh": false, "settable_per_extruder": false, "settable_per_meshgroup": false From 01f4e7c0e33d7d54fc9225ca54ef26b3420b2f17 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Mon, 5 Mar 2018 16:31:49 +0100 Subject: [PATCH 13/66] CURA-4400 on load mesh, set the extruder to the default extruder --- cura/CuraApplication.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index a4e86626dc..db0848bdf4 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -1601,6 +1601,8 @@ class CuraApplication(QtApplication): fixed_nodes.append(node_) arranger = Arrange.create(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() for original_node in nodes: @@ -1666,6 +1668,8 @@ class CuraApplication(QtApplication): op = AddSceneNodeOperation(node, scene.getRoot()) op.push() + + node.callDecoration("setActiveExtruder", default_extruder_id) scene.sceneChanged.emit(node) self.fileCompleted.emit(filename) From 7fd0a9b98b5faf1ab468ae8eba74bbf3e682fa1e Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Mon, 5 Mar 2018 17:01:53 +0100 Subject: [PATCH 14/66] CURA-4400 fixed multiply --- cura/Scene/CuraSceneNode.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Scene/CuraSceneNode.py b/cura/Scene/CuraSceneNode.py index cfc41eb689..588fb75667 100644 --- a/cura/Scene/CuraSceneNode.py +++ b/cura/Scene/CuraSceneNode.py @@ -103,7 +103,7 @@ class CuraSceneNode(SceneNode): ## Taken from SceneNode, but replaced SceneNode with CuraSceneNode def __deepcopy__(self, memo): - copy = CuraSceneNode() + copy = CuraSceneNode(no_setting_override = True) # Setting override will be added later copy.setTransformation(self.getLocalTransformation()) copy.setMeshData(self._mesh_data) copy.setVisible(deepcopy(self._visible, memo)) From 00a173b1bf62a1c5c23033be90c08c4c4969bb89 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Tue, 6 Mar 2018 09:45:32 +0100 Subject: [PATCH 15/66] CURA-4400 when enabling / disabling extruder, remove user changes that are no longer enabled --- cura/Settings/MachineManager.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 52887c1899..13a431824b 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -701,16 +701,22 @@ class MachineManager(QObject): # reset all extruder number settings whose value is no longer valid for setting_instance in self._global_container_stack.userChanges.findInstances(): setting_key = setting_instance.definition.key + enabled = self._global_container_stack.getProperty(setting_key, "enabled") + if not enabled: + self._global_container_stack.userChanges.removeInstance(setting_key) + Logger.log("d", "Reset setting [%s] because the setting is no longer enabled", setting_key) + continue + if not self._global_container_stack.getProperty(setting_key, "type") in ("extruder", "optional_extruder"): continue old_value = self._global_container_stack.userChanges.getProperty(setting_key, "value") if int(old_value) >= extruder_count: self._global_container_stack.userChanges.removeInstance(setting_key) - Logger.log("d", "Reset [%s] because its old value [%s] is no longer valid", setting_key, old_value) + Logger.log("d", "Reset setting [%s] because its old value [%s] is no longer valid", setting_key, old_value) if not self._global_container_stack.extruders[str(old_value)].isEnabled: self._global_container_stack.userChanges.removeInstance(setting_key) - Logger.log("d", "Reset [%s] because its old value [%s] is no longer valid (2)", setting_key, old_value) + Logger.log("d", "Reset setting [%s] because its old value [%s] is no longer valid (2)", setting_key, old_value) ## Set the amount of extruders on the active machine (global stack) # \param extruder_count int the number of extruders to set @@ -804,8 +810,7 @@ class MachineManager(QObject): extruder.setEnabled(enabled) self.updateDefaultExtruder() self.updateNumberExtrudersEnabled() - if enabled == False: - self.correctExtruderSettings() + self.correctExtruderSettings() self.extruderChanged.emit() # update items in SettingExtruder ExtruderManager.getInstance().extrudersChanged.emit(self._global_container_stack.getId()) From 8ebd77822469aaf54b1d5b333a7c6ee0ca77ca96 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Tue, 6 Mar 2018 11:44:42 +0100 Subject: [PATCH 16/66] CURA-4400 force update all settings if something changed with the extruder --- cura/Settings/MachineManager.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 13a431824b..7e75067ce6 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -772,6 +772,7 @@ class MachineManager(QObject): # Signal that the global stack has changed Application.getInstance().globalContainerStackChanged.emit() + self.forceUpdateAllSettings() @pyqtSlot(int, result = QObject) def getExtruder(self, position: int): @@ -804,6 +805,12 @@ class MachineManager(QObject): def defaultExtruderPosition(self): return self._default_extruder_position + ## This will fire the propertiesChanged for all settings so they will be updated in the front-end + def forceUpdateAllSettings(self): + property_names = ["value", "resolve"] + for setting_key in self._global_container_stack.getAllKeys(): + self._global_container_stack.propertiesChanged.emit(setting_key, property_names) + @pyqtSlot(int, bool) def setExtruderEnabled(self, position: int, enabled) -> None: extruder = self.getExtruder(position) @@ -814,6 +821,8 @@ class MachineManager(QObject): self.extruderChanged.emit() # update items in SettingExtruder ExtruderManager.getInstance().extrudersChanged.emit(self._global_container_stack.getId()) + # Make sure the front end reflects changes + self.forceUpdateAllSettings() def _onMachineNameChanged(self): self.globalContainerChanged.emit() From 63e679e4a087c7f682c9e0ccd11c5a6e2c617ccd Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Tue, 6 Mar 2018 16:28:00 +0100 Subject: [PATCH 17/66] CURA-4400 updated UM3 machine_head_with_fans_polygon --- resources/definitions/ultimaker3.def.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/definitions/ultimaker3.def.json b/resources/definitions/ultimaker3.def.json index dcf6b167c0..211e749c90 100644 --- a/resources/definitions/ultimaker3.def.json +++ b/resources/definitions/ultimaker3.def.json @@ -43,10 +43,10 @@ { "default_value": [ - [ -29, 6.1 ], - [ -29, -33.9 ], - [ 71, 6.1 ], - [ 71, -33.9 ] + [-41.9, -45.8], + [-41.9, 33.9], + [59.9, 33.9], + [59.9, -45.8] ] }, "machine_gcode_flavor": { "default_value": "Griffin" }, From 92e80fa26a12c2174e4f1a64d5eff894f9707a4e Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Tue, 6 Mar 2018 16:28:40 +0100 Subject: [PATCH 18/66] CURA-4400 Bugfix do not handle layer scene nodes in solidview --- plugins/SolidView/SolidView.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/SolidView/SolidView.py b/plugins/SolidView/SolidView.py index 2abfe80f95..de9f922267 100644 --- a/plugins/SolidView/SolidView.py +++ b/plugins/SolidView/SolidView.py @@ -78,7 +78,7 @@ class SolidView(View): for node in DepthFirstIterator(scene.getRoot()): if not node.render(renderer): - if node.getMeshData() and node.isVisible(): + if node.getMeshData() and node.isVisible() and not node.callDecoration("getLayerData"): uniforms = {} shade_factor = 1.0 From 095d9fbdf6b0e8d65ef79581d720becd2f6cfdcb Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Tue, 6 Mar 2018 16:28:40 +0100 Subject: [PATCH 19/66] CURA-4400 Bugfix do not handle layer scene nodes in solidview --- plugins/SolidView/SolidView.py | 2 +- resources/definitions/ultimaker3.def.json | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/SolidView/SolidView.py b/plugins/SolidView/SolidView.py index 2abfe80f95..de9f922267 100644 --- a/plugins/SolidView/SolidView.py +++ b/plugins/SolidView/SolidView.py @@ -78,7 +78,7 @@ class SolidView(View): for node in DepthFirstIterator(scene.getRoot()): if not node.render(renderer): - if node.getMeshData() and node.isVisible(): + if node.getMeshData() and node.isVisible() and not node.callDecoration("getLayerData"): uniforms = {} shade_factor = 1.0 diff --git a/resources/definitions/ultimaker3.def.json b/resources/definitions/ultimaker3.def.json index 211e749c90..4e2b5ad4c2 100644 --- a/resources/definitions/ultimaker3.def.json +++ b/resources/definitions/ultimaker3.def.json @@ -43,10 +43,10 @@ { "default_value": [ - [-41.9, -45.8], - [-41.9, 33.9], - [59.9, 33.9], - [59.9, -45.8] + [ -41.9, -45.8 ], + [ -41.9, 33.9 ], + [ 59.9, 33.9 ], + [ 59.9, -45.8 ] ] }, "machine_gcode_flavor": { "default_value": "Griffin" }, From bab46d7048f4f3d2c40359ad3086675c37d19cd0 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Tue, 6 Mar 2018 17:19:31 +0100 Subject: [PATCH 20/66] CURA-4400 only reevaluate non printing mesh if the setting actually matters --- cura/Settings/SettingOverrideDecorator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Settings/SettingOverrideDecorator.py b/cura/Settings/SettingOverrideDecorator.py index c9c9d7e411..357bc87024 100644 --- a/cura/Settings/SettingOverrideDecorator.py +++ b/cura/Settings/SettingOverrideDecorator.py @@ -95,7 +95,7 @@ class SettingOverrideDecorator(SceneNodeDecorator): def _onSettingChanged(self, instance, property_name): # Reminder: 'property' is a built-in function # Trigger slice/need slicing if the value has changed. - if property_name == "value": + if property_name == "value" and instance in self._non_printing_mesh_settings: self._is_non_printing_mesh = self.evaluateIsNonPrintingMesh() Application.getInstance().getBackend().needsSlicing() From 4568fab5315c48d7b79349183422144fbfc5262a Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Wed, 7 Mar 2018 11:27:23 +0100 Subject: [PATCH 21/66] CURA-4400 fix quality profiles model to not use disabled extruder and update Not Supported or select a valid quality when enabling/disabling extruder --- cura/Settings/MachineManager.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index fa5bb44757..2264038472 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -818,7 +818,11 @@ class MachineManager(QObject): self.updateDefaultExtruder() self.updateNumberExtrudersEnabled() self.correctExtruderSettings() + # ensure that the quality profile is compatible with current combination, or choose a compatible one if available + self._updateQualityWithMaterial() self.extruderChanged.emit() + # update material compatibility color + self.activeQualityGroupChanged.emit() # update items in SettingExtruder ExtruderManager.getInstance().extrudersChanged.emit(self._global_container_stack.getId()) # Make sure the front end reflects changes @@ -976,7 +980,7 @@ class MachineManager(QObject): # check material - variant compatibility if Util.parseBool(self._global_container_stack.getMetaDataEntry("has_materials", False)): for position, extruder in self._global_container_stack.extruders.items(): - if not extruder.material.getMetaDataEntry("compatible"): + if extruder.isEnabled and not extruder.material.getMetaDataEntry("compatible"): return False return True From ff1c378c08663b82cc4a980da7ddd8557cc7ed43 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Wed, 7 Mar 2018 11:38:35 +0100 Subject: [PATCH 22/66] CURA-4400 fix start slicing when disabled extruder is incompatible --- cura/Settings/MachineManager.py | 2 ++ plugins/CuraEngineBackend/StartSliceJob.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 2264038472..651714c005 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -637,6 +637,8 @@ class MachineManager(QObject): buildplate_compatible = True # It is compatible by default extruder_stacks = self._global_container_stack.extruders.values() for stack in extruder_stacks: + if not stack.isEnabled: + continue material_container = stack.material if material_container == self._empty_material_container: continue diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index aee6a46e5b..ed7731f6ec 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -131,6 +131,8 @@ class StartSliceJob(Job): for position, extruder_stack in stack.extruders.items(): material = extruder_stack.findContainer({"type": "material"}) + if not extruder_stack.isEnabled: + continue if material: if material.getMetaDataEntry("compatible") == False: self.setResult(StartJobResult.MaterialIncompatible) From 16cebe35ef381bd31b6bc33f317dd8f7edd1b71b Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Wed, 7 Mar 2018 16:41:03 +0100 Subject: [PATCH 23/66] CURA-4400 added docs to new functions --- cura/Scene/CuraSceneNode.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cura/Scene/CuraSceneNode.py b/cura/Scene/CuraSceneNode.py index 588fb75667..b29108d636 100644 --- a/cura/Scene/CuraSceneNode.py +++ b/cura/Scene/CuraSceneNode.py @@ -78,6 +78,7 @@ class CuraSceneNode(SceneNode): 1.0 ] + ## Return if the provided bbox collides with the bbox of this scene node def collidesWithBbox(self, check_bbox): bbox = self.getBoundingBox() @@ -87,6 +88,7 @@ class CuraSceneNode(SceneNode): return False + ## Return if any area collides with the convex hull of this scene node def collidesWithArea(self, areas): convex_hull = self.callDecoration("getConvexHull") if convex_hull: From 961b868424d39acec787b66da978d9818230fca0 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 8 Mar 2018 09:47:22 +0100 Subject: [PATCH 24/66] CURA-4400 fix updating quality slider --- resources/qml/SidebarSimple.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index 699365238a..b9b254e280 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -67,7 +67,7 @@ Item Connections { - target: Cura.QualityProfilesModel + target: Cura.QualityProfilesDropDownMenuModel onItemsChanged: qualityModel.update() } From a9976e93c13bcdf7c6061f852a4f97bcf103c1b2 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 8 Mar 2018 13:57:11 +0100 Subject: [PATCH 25/66] CURA-4400 fix per object setting change reslicing without reevaluate is non printing mesh all the time --- cura/Settings/SettingOverrideDecorator.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cura/Settings/SettingOverrideDecorator.py b/cura/Settings/SettingOverrideDecorator.py index 357bc87024..9054d9d04f 100644 --- a/cura/Settings/SettingOverrideDecorator.py +++ b/cura/Settings/SettingOverrideDecorator.py @@ -94,8 +94,13 @@ class SettingOverrideDecorator(SceneNodeDecorator): return any(bool(self._stack.getProperty(setting, "value")) for setting in self._non_printing_mesh_settings) def _onSettingChanged(self, instance, property_name): # Reminder: 'property' is a built-in function - # Trigger slice/need slicing if the value has changed. - if property_name == "value" and instance in self._non_printing_mesh_settings: + object_has_instance_setting = False + for container in self._stack.getContainers(): + if container.hasProperty(instance, "value"): + object_has_instance_setting = True + break + if property_name == "value" and object_has_instance_setting: + # Trigger slice/need slicing if the value has changed. self._is_non_printing_mesh = self.evaluateIsNonPrintingMesh() Application.getInstance().getBackend().needsSlicing() From f576b1f1170deb28d3a755d461201161817e2e88 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 8 Mar 2018 14:07:01 +0100 Subject: [PATCH 26/66] CURA-4400 fix crash when switching from disabled 1st extruder to single extruder machine --- cura/Settings/MachineManager.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index e3338e9ca7..d6c4671691 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -299,6 +299,7 @@ class MachineManager(QObject): containers = container_registry.findContainerStacks(id = stack_id) if containers: global_stack = containers[0] + self._default_extruder_position = "0" # start off with position 0, later on update the default extruder ExtruderManager.getInstance().setActiveExtruderIndex(0) # Switch to first extruder self._global_container_stack = global_stack Application.getInstance().setGlobalContainerStack(global_stack) From 138f77179dd6e1190dd8defc87858bbee5a57a6a Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 8 Mar 2018 14:31:55 +0100 Subject: [PATCH 27/66] CURA-4400 fix errors when switch or adding to new machine --- cura/Settings/MachineManager.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index d6c4671691..5afecb8ef5 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -192,6 +192,9 @@ class MachineManager(QObject): # Update the local global container stack reference self._global_container_stack = Application.getInstance().getGlobalContainerStack() + if self._global_container_stack: + self.updateDefaultExtruder() + self.updateNumberExtrudersEnabled() self.globalContainerChanged.emit() # after switching the global stack we reconnect all the signals and set the variant and material references @@ -299,14 +302,11 @@ class MachineManager(QObject): containers = container_registry.findContainerStacks(id = stack_id) if containers: global_stack = containers[0] - self._default_extruder_position = "0" # start off with position 0, later on update the default extruder ExtruderManager.getInstance().setActiveExtruderIndex(0) # Switch to first extruder self._global_container_stack = global_stack Application.getInstance().setGlobalContainerStack(global_stack) ExtruderManager.getInstance()._globalContainerStackChanged() self._initMachineState(containers[0]) - self.updateDefaultExtruder() - self.updateNumberExtrudersEnabled() self._onGlobalContainerChanged() self.__emitChangedSignals() From 5135a972a2e7d95d57f8d955c0230f849f62df6f Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 8 Mar 2018 14:32:10 +0100 Subject: [PATCH 28/66] CURA-4400 code style --- resources/qml/Cura.qml | 12 ++++++++---- resources/qml/Settings/SettingExtruder.qml | 9 ++++++--- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index 185e3563a5..c81281f0d7 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -194,22 +194,26 @@ UM.MainWindow NozzleMenu { title: Cura.MachineManager.activeDefinitionVariantsName; visible: Cura.MachineManager.hasVariants; extruderIndex: index } MaterialMenu { title: catalog.i18nc("@title:menu", "&Material"); visible: Cura.MachineManager.hasMaterials; extruderIndex: index } - MenuSeparator { + MenuSeparator + { visible: Cura.MachineManager.hasVariants || Cura.MachineManager.hasMaterials } - MenuItem { + MenuItem + { text: catalog.i18nc("@action:inmenu", "Set as Active Extruder") onTriggered: Cura.MachineManager.setExtruderIndex(model.index) } - MenuItem { + MenuItem + { text: catalog.i18nc("@action:inmenu", "Enable Extruder") onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, true) visible: !Cura.MachineManager.getExtruder(model.index).isEnabled } - MenuItem { + MenuItem + { text: catalog.i18nc("@action:inmenu", "Disable Extruder") onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, false) visible: Cura.MachineManager.getExtruder(model.index).isEnabled diff --git a/resources/qml/Settings/SettingExtruder.qml b/resources/qml/Settings/SettingExtruder.qml index 2a2e213142..35ad198edf 100644 --- a/resources/qml/Settings/SettingExtruder.qml +++ b/resources/qml/Settings/SettingExtruder.qml @@ -17,7 +17,8 @@ SettingItem id: control anchors.fill: parent - model: Cura.ExtrudersModel { + model: Cura.ExtrudersModel + { onModelChanged: { control.color = getItem(control.currentIndex).color; } @@ -27,10 +28,12 @@ SettingItem onActivated: { - if (model.getItem(index).enabled) { + if (model.getItem(index).enabled) + { forceActiveFocus(); propertyProvider.setPropertyValue("value", model.getItem(index).index); - } else { + } else + { currentIndex = propertyProvider.properties.value; // keep the old value } } From 0d61b6652c6ff2bebb2648685aef0b64f32ec361 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 8 Mar 2018 15:38:32 +0100 Subject: [PATCH 29/66] CURA-4400 merge two if statements in 1 --- cura/Settings/MachineManager.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 5afecb8ef5..d84b5eb3d9 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -722,12 +722,9 @@ class MachineManager(QObject): continue old_value = self._global_container_stack.userChanges.getProperty(setting_key, "value") - if int(old_value) >= extruder_count: + if int(old_value) >= extruder_count or not self._global_container_stack.extruders[str(old_value)].isEnabled: self._global_container_stack.userChanges.removeInstance(setting_key) Logger.log("d", "Reset setting [%s] because its old value [%s] is no longer valid", setting_key, old_value) - if not self._global_container_stack.extruders[str(old_value)].isEnabled: - self._global_container_stack.userChanges.removeInstance(setting_key) - Logger.log("d", "Reset setting [%s] because its old value [%s] is no longer valid (2)", setting_key, old_value) ## Set the amount of extruders on the active machine (global stack) # \param extruder_count int the number of extruders to set From 53764a8274bc862c9396777b9e69ee3cd08984bd Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 8 Mar 2018 15:39:23 +0100 Subject: [PATCH 30/66] CURA-4400 use extrudersEnabledCount for recommended mode's extruder number visibility --- resources/qml/SidebarSimple.qml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index b9b254e280..eabc1d202a 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -19,7 +19,7 @@ Item property Action configureSettings; property variant minimumPrintTime: PrintInformation.minimumPrintTime; property variant maximumPrintTime: PrintInformation.maximumPrintTime; - property bool settingsEnabled: Cura.ExtruderManager.activeExtruderStackId || machineExtruderCount.properties.value == 1 + property bool settingsEnabled: Cura.ExtruderManager.activeExtruderStackId || extrudersEnabledCount.properties.value == 1 Component.onCompleted: PrintInformation.enabled = true Component.onDestruction: PrintInformation.enabled = false @@ -804,7 +804,7 @@ Item ComboBox { id: supportExtruderCombobox - visible: enableSupportCheckBox.visible && (supportEnabled.properties.value == "True") && (machineExtruderCount.properties.value > 1) + visible: enableSupportCheckBox.visible && (supportEnabled.properties.value == "True") && (extrudersEnabledCount.properties.value > 1) model: extruderModel property string color_override: "" // for manually setting values @@ -819,11 +819,11 @@ Item textRole: "text" // this solves that the combobox isn't populated in the first time Cura is started anchors.top: enableSupportCheckBox.bottom - anchors.topMargin: ((supportEnabled.properties.value === "True") && (machineExtruderCount.properties.value > 1)) ? UM.Theme.getSize("sidebar_margin").height : 0 + anchors.topMargin: ((supportEnabled.properties.value === "True") && (extrudersEnabledCount.properties.value > 1)) ? UM.Theme.getSize("sidebar_margin").height : 0 anchors.left: infillCellRight.left width: Math.round(UM.Theme.getSize("sidebar").width * .55) - height: ((supportEnabled.properties.value == "True") && (machineExtruderCount.properties.value > 1)) ? UM.Theme.getSize("setting_control").height : 0 + height: ((supportEnabled.properties.value == "True") && (extrudersEnabledCount.properties.value > 1)) ? UM.Theme.getSize("setting_control").height : 0 Behavior on height { NumberAnimation { duration: 100 } } @@ -1020,9 +1020,9 @@ Item UM.SettingPropertyProvider { - id: machineExtruderCount + id: extrudersEnabledCount containerStackId: Cura.MachineManager.activeMachineId - key: "machine_extruder_count" + key: "extruders_enabled_count" watchedProperties: [ "value" ] storeIndex: 0 } From e09325bf82de85d5c2336bc966fba7726ca7f31e Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Fri, 9 Mar 2018 17:16:24 +0100 Subject: [PATCH 31/66] Fix project loading for version upgrade CURA-5054 --- cura/Machines/QualityManager.py | 2 +- plugins/3MFReader/ThreeMFWorkspaceReader.py | 43 +++++++-------------- 2 files changed, 15 insertions(+), 30 deletions(-) diff --git a/cura/Machines/QualityManager.py b/cura/Machines/QualityManager.py index ae7a177be4..c11858d1e5 100644 --- a/cura/Machines/QualityManager.py +++ b/cura/Machines/QualityManager.py @@ -386,7 +386,7 @@ class QualityManager(QObject): if quality_changes_group is None: # create global quality changes only new_quality_changes = self._createQualityChanges(quality_group.quality_type, quality_changes_name, - global_stack, extruder_id = None) + global_stack, None) self._container_registry.addContainer(new_quality_changes) else: new_name = self._container_registry.uniqueName(quality_changes_name) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index 7201df65e4..d8e2fd7609 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -216,11 +216,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader): archive = zipfile.ZipFile(file_name, "r") cura_file_names = [name for name in archive.namelist() if name.startswith("Cura/")] - # A few lists of containers in this project files. - # When loading the global stack file, it may be associated with those containers, which may or may not be - # in Cura already, so we need to provide them as alternative search lists. - instance_container_list = [] - resolve_strategy_keys = ["machine", "material", "quality_changes"] self._resolve_strategies = {k: None for k in resolve_strategy_keys} containers_found_dict = {k: False for k in resolve_strategy_keys} @@ -307,13 +302,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): container_info = ContainerInfo(instance_container_file_name, serialized, parser) instance_container_info_dict[container_id] = container_info - instance_container = InstanceContainer(container_id) - - # Deserialize InstanceContainer by converting read data from bytes to string - instance_container.deserialize(serialized, file_name = instance_container_file_name) - instance_container_list.append(instance_container) - - container_type = instance_container.getMetaDataEntry("type") + container_type = parser["metadata"]["type"] if container_type == "quality_changes": quality_changes_info_list.append(container_info) @@ -321,20 +310,22 @@ class ThreeMFWorkspaceReader(WorkspaceReader): self._machine_info.quality_changes_info.name = parser["general"]["name"] self._machine_info.quality_changes_info.global_info = container_info - quality_name = instance_container.getName() - num_settings_overriden_by_quality_changes += len(instance_container._instances) + quality_name = parser["general"]["name"] + num_settings_overriden_by_quality_changes += len(parser.get("values", {})) # Check if quality changes already exists. quality_changes = self._container_registry.findInstanceContainers(id = container_id) if quality_changes: containers_found_dict["quality_changes"] = True # Check if there really is a conflict by comparing the values + instance_container = InstanceContainer(container_id) + instance_container.deserialize(serialized, file_name = instance_container_file_name) if quality_changes[0] != instance_container: quality_changes_conflict = True elif container_type == "quality": if not quality_name: - quality_name = instance_container.getName() + quality_name = parser["general"]["name"] elif container_type == "user": - num_user_settings += len(instance_container._instances) + num_user_settings += len(parser["values"]) elif container_type in self._ignored_instance_container_types: # Ignore certain instance container types Logger.log("w", "Ignoring instance container [%s] with type [%s]", container_id, container_type) @@ -739,7 +730,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader): from cura.Machines.QualityManager import getMachineDefinitionIDForQualitySearch machine_definition_id_for_quality = getMachineDefinitionIDForQualitySearch(global_stack) machine_definition_for_quality = self._container_registry.findDefinitionContainers(id = machine_definition_id_for_quality)[0] - extruder_dict_for_quality = machine_definition_for_quality.getMetaDataEntry("machine_extruder_trains") quality_changes_info = self._machine_info.quality_changes_info quality_changes_quality_type = quality_changes_info.global_info.parser["metadata"]["quality_type"] @@ -752,13 +742,12 @@ class ThreeMFWorkspaceReader(WorkspaceReader): quality_changes_name = self._container_registry.uniqueName(quality_changes_name) for position, container_info in container_info_dict.items(): - extruder_definition_id = None + extruder_stack = None if position is not None: - extruder_definition_id = extruder_dict_for_quality[position] - + extruder_stack = global_stack.extruders[position] container = quality_manager._createQualityChanges(quality_changes_quality_type, quality_changes_name, - global_stack, extruder_definition_id) + global_stack, extruder_stack) container_info.container = container container.setDirty(True) self._container_registry.addContainer(container) @@ -781,18 +770,14 @@ class ThreeMFWorkspaceReader(WorkspaceReader): container_info = quality_changes_info.extruder_info_dict[position] container_info.container = container - for position, container_info in quality_changes_info.extruder_info_dict.items(): - container_info.definition_id = extruder_dict_for_quality[position] - # If there is no quality changes for any extruder, create one. if not quality_changes_info.extruder_info_dict: container_info = ContainerInfo(None, None, None) quality_changes_info.extruder_info_dict["0"] = container_info - extruder_definition_id = extruder_dict_for_quality["0"] - container_info.definition_id = extruder_definition_id + extruder_stack = global_stack.extruders["0"] container = quality_manager._createQualityChanges(quality_changes_quality_type, quality_changes_name, - global_stack, extruder_definition_id) + global_stack, extruder_stack) container_info.container = container container.setDirty(True) self._container_registry.addContainer(container) @@ -818,9 +803,9 @@ class ThreeMFWorkspaceReader(WorkspaceReader): continue if container_info.container is None: - extruder_definition_id = extruder_dict_for_quality[position] + extruder_stack = global_stack.extruders[position] container = quality_manager._createQualityChanges(quality_changes_quality_type, quality_changes_name, - global_stack, extruder_definition_id) + global_stack, extruder_stack) container_info.container = container for key, value in container_info.parser["values"].items(): From 7312ed8e3c32b8923744487b7bb4f39f0925d252 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Fri, 9 Mar 2018 19:35:21 +0100 Subject: [PATCH 32/66] Fix project loading for version upgrade CURA-5054 --- plugins/3MFReader/ThreeMFWorkspaceReader.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index d8e2fd7609..3c627a7655 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -306,12 +306,16 @@ class ThreeMFWorkspaceReader(WorkspaceReader): if container_type == "quality_changes": quality_changes_info_list.append(container_info) - if not parser.has_option("metadata", "extruder"): + if not parser.has_option("metadata", "position"): self._machine_info.quality_changes_info.name = parser["general"]["name"] self._machine_info.quality_changes_info.global_info = container_info + else: + position = parser["metadata"]["position"] + self._machine_info.quality_changes_info.extruder_info_dict[position] = container_info quality_name = parser["general"]["name"] - num_settings_overriden_by_quality_changes += len(parser.get("values", {})) + values = parser["values"] if parser.has_section("values") else dict() + num_settings_overriden_by_quality_changes += len(values) # Check if quality changes already exists. quality_changes = self._container_registry.findInstanceContainers(id = container_id) if quality_changes: @@ -444,15 +448,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader): machine_conflict = True break - if self._machine_info.quality_changes_info is not None: - for quality_changes_info in quality_changes_info_list: - if not quality_changes_info.parser.has_option("metadata", "extruder"): - continue - extruder_definition_id = quality_changes_info.parser["metadata"]["extruder"] - extruder_definition_metadata = self._container_registry.findDefinitionContainersMetadata(id = extruder_definition_id)[0] - position = extruder_definition_metadata["position"] - self._machine_info.quality_changes_info.extruder_info_dict[position] = quality_changes_info - num_visible_settings = 0 try: temp_preferences = Preferences() From aae8a31f00cf9db2b6190a43dbf1658db64311cf Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 12 Mar 2018 09:22:59 +0100 Subject: [PATCH 33/66] Don't display extruder count if you can't use it If your printer can only handle one extruder, don't display this drop-down. Don't let users get confused. --- plugins/MachineSettingsAction/MachineSettingsAction.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/MachineSettingsAction/MachineSettingsAction.qml b/plugins/MachineSettingsAction/MachineSettingsAction.qml index 4d00904f76..f941ef87b4 100644 --- a/plugins/MachineSettingsAction/MachineSettingsAction.qml +++ b/plugins/MachineSettingsAction/MachineSettingsAction.qml @@ -244,6 +244,7 @@ Cura.MachineAction height: childrenRect.height width: childrenRect.width text: machineExtruderCountProvider.properties.description + visible: extruderCountModel.count >= 2 Row { From 15212d4426b1eb72777e33d9f04dd37127990413 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 12 Mar 2018 09:38:20 +0100 Subject: [PATCH 34/66] Align for readability --- plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py b/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py index acccfd88dd..c411b4190e 100644 --- a/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py +++ b/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py @@ -8,10 +8,10 @@ upgrade = VersionUpgrade32to33.VersionUpgrade32to33() def getMetaData(): return { "version_upgrade": { - # From To Upgrade function + # From To Upgrade function ("definition_changes", 2000004): ("definition_changes", 3000004, upgrade.upgradeInstanceContainer), - ("quality_changes", 2000004): ("quality_changes", 3000004, upgrade.upgradeQualityChanges), - ("user", 2000004): ("user", 3000004, upgrade.upgradeInstanceContainer) + ("quality_changes", 2000004): ("quality_changes", 3000004, upgrade.upgradeQualityChanges), + ("user", 2000004): ("user", 3000004, upgrade.upgradeInstanceContainer) }, "sources": { "definition_changes": { From d98cab48ac464664da24510d981fa560ebbda4ad Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 12 Mar 2018 09:48:03 +0100 Subject: [PATCH 35/66] Get scripts from either Resources or Preferences We must retain the old directory for legacy. People might still have scripts there. --- plugins/PostProcessingPlugin/PostProcessingPlugin.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/PostProcessingPlugin/PostProcessingPlugin.py b/plugins/PostProcessingPlugin/PostProcessingPlugin.py index dc2d93a788..c4b760724b 100644 --- a/plugins/PostProcessingPlugin/PostProcessingPlugin.py +++ b/plugins/PostProcessingPlugin/PostProcessingPlugin.py @@ -173,7 +173,10 @@ class PostProcessingPlugin(QObject, Extension): Logger.log("d", "Creating post processing plugin view.") ## Load all scripts in the scripts folders - for root in [PluginRegistry.getInstance().getPluginPath("PostProcessingPlugin"), Resources.getStoragePath(Resources.Resources)]: + # The PostProcessingPlugin path is for built-in scripts. + # The Resources path is where the user should store custom scripts. + # The Preferences path is legacy, where the user may previously have stored scripts. + for root in [PluginRegistry.getInstance().getPluginPath("PostProcessingPlugin"), Resources.getStoragePath(Resources.Resources), Resources.getStoragePath(Resources.Preferences)]: path = os.path.join(root, "scripts") if not os.path.isdir(path): try: From 552618fcd4066bad40a219e21e1ccca1999c2fe8 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Mon, 12 Mar 2018 09:56:08 +0100 Subject: [PATCH 36/66] CURA-4400 added function to find model index by extruder position in SettingExtruder --- cura/Settings/ExtrudersModel.py | 2 +- resources/qml/Settings/SettingExtruder.qml | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/cura/Settings/ExtrudersModel.py b/cura/Settings/ExtrudersModel.py index ae8cff3c9a..4ee5ab3c3b 100644 --- a/cura/Settings/ExtrudersModel.py +++ b/cura/Settings/ExtrudersModel.py @@ -1,7 +1,7 @@ # Copyright (c) 2017 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty, QTimer +from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot, pyqtProperty, QTimer from typing import Iterable from UM.i18n import i18nCatalog diff --git a/resources/qml/Settings/SettingExtruder.qml b/resources/qml/Settings/SettingExtruder.qml index 35ad198edf..2ddbb135c7 100644 --- a/resources/qml/Settings/SettingExtruder.qml +++ b/resources/qml/Settings/SettingExtruder.qml @@ -26,6 +26,20 @@ SettingItem textRole: "name" + // knowing the extruder position, try to find the item index in the model + function getIndexByPosition(position) + { + for (var item_index in model.items) + { + var item = model.getItem(item_index) + if (item.index == position) + { + return item_index + } + } + return -1 + } + onActivated: { if (model.getItem(index).enabled) @@ -83,8 +97,7 @@ SettingItem { if(propertyProvider.properties.value == -1) { - // TODO: accidently the extruder position is also the index. fix it - return Cura.MachineManager.defaultExtruderPosition; + return control.getIndexByPosition(Cura.MachineManager.defaultExtruderPosition); } return propertyProvider.properties.value } From 2c5cc17b490e311359df3bedcf293a9f530d6470 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Mon, 12 Mar 2018 10:33:40 +0100 Subject: [PATCH 37/66] Fix build plate compatibility check CURA-5078 --- cura/Settings/MachineManager.py | 14 ++++++++++++-- plugins/XmlMaterialProfile/XmlMaterialProfile.py | 3 ++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 144f495997..b09ff9e8bd 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -919,11 +919,21 @@ class MachineManager(QObject): def activeMaterialsCompatible(self): # check material - variant compatibility + result = True + machine_has_buildplate = Util.parseBool(self._global_container_stack.getMetaDataEntry("has_variant_buildplates", False)) if Util.parseBool(self._global_container_stack.getMetaDataEntry("has_materials", False)): for position, extruder in self._global_container_stack.extruders.items(): if not extruder.material.getMetaDataEntry("compatible"): - return False - return True + result = False + break + if machine_has_buildplate: + buildplate_compatibility_dict = extruder.material.getMetaDataEntry("buildplate_compatible") + if buildplate_compatibility_dict: + buildplate_name = self._global_container_stack.variant.getName() + result = buildplate_compatibility_dict.get(buildplate_name, True) + if not result: + break + return result ## Update current quality type and machine after setting material def _updateQualityWithMaterial(self): diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index a7ba423153..e8d0c9d2f0 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -617,7 +617,8 @@ class XmlMaterialProfile(InstanceContainer): from cura.Machines.VariantManager import VariantType variant_manager = CuraApplication.getInstance().getVariantManager() - variant_node = variant_manager.getVariantNode(machine_id, buildplate_id) + variant_node = variant_manager.getVariantNode(machine_id, buildplate_id, + variant_type = VariantType.BUILD_PLATE) if not variant_node: continue From 3edc96ec8f16d0eb8724666f209d4d854aea07e6 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Mon, 12 Mar 2018 10:47:23 +0100 Subject: [PATCH 38/66] CURA-4400 fixed wrongly converted expression --- plugins/CuraEngineBackend/StartSliceJob.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index f84b20b522..63a345c13e 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -194,7 +194,7 @@ class StartSliceJob(Job): # Find a reason not to add the node if node.callDecoration("getBuildPlateNumber") != self._build_plate_number: continue - if getattr(node, "_outside_buildarea", False) and is_non_printing_mesh: + if getattr(node, "_outside_buildarea", False) and not is_non_printing_mesh: continue node_position = node.callDecoration("getActiveExtruderPosition") if not stack.extruders[str(node_position)].isEnabled: From 1f8be6ad3c6fb9dbf111d5f46b200f204b16dd78 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Mon, 12 Mar 2018 11:05:55 +0100 Subject: [PATCH 39/66] CURA-4400 moved default extruder value to value instead of default_value because of engine --- resources/definitions/fdmprinter.def.json | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 98909a3325..6d4688bb52 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -3470,7 +3470,8 @@ "label": "Support Extruder", "description": "The extruder train to use for printing the support. This is used in multi-extrusion.", "type": "extruder", - "default_value": "-1", + "default_value": "0", + "value": "-1", "enabled": "(support_enable or support_tree_enable) and extruders_enabled_count > 1", "settable_per_mesh": false, "settable_per_extruder": false, @@ -3480,7 +3481,7 @@ "label": "Support Infill Extruder", "description": "The extruder train to use for printing the infill of the support. This is used in multi-extrusion.", "type": "extruder", - "default_value": "-1", + "default_value": "0", "value": "support_extruder_nr", "enabled": "(support_enable or support_tree_enable) and extruders_enabled_count > 1", "settable_per_mesh": false, @@ -3491,7 +3492,7 @@ "label": "First Layer Support Extruder", "description": "The extruder train to use for printing the first layer of support infill. This is used in multi-extrusion.", "type": "extruder", - "default_value": "-1", + "default_value": "0", "value": "support_extruder_nr", "enabled": "(support_enable or support_tree_enable) and extruders_enabled_count > 1", "settable_per_mesh": false, @@ -3502,7 +3503,7 @@ "label": "Support Interface Extruder", "description": "The extruder train to use for printing the roofs and floors of the support. This is used in multi-extrusion.", "type": "extruder", - "default_value": "-1", + "default_value": "0", "value": "support_extruder_nr", "enabled": "(support_enable or support_tree_enable) and extruders_enabled_count > 1", "settable_per_mesh": false, @@ -3514,7 +3515,7 @@ "label": "Support Roof Extruder", "description": "The extruder train to use for printing the roofs of the support. This is used in multi-extrusion.", "type": "extruder", - "default_value": "-1", + "default_value": "0", "value": "support_interface_extruder_nr", "enabled": "(support_enable or support_tree_enable) and extruders_enabled_count > 1", "settable_per_mesh": false, @@ -3525,7 +3526,7 @@ "label": "Support Floor Extruder", "description": "The extruder train to use for printing the floors of the support. This is used in multi-extrusion.", "type": "extruder", - "default_value": "-1", + "default_value": "0", "value": "support_interface_extruder_nr", "enabled": "(support_enable or support_tree_enable) and extruders_enabled_count > 1", "settable_per_mesh": false, @@ -4196,7 +4197,8 @@ "label": "Build Plate Adhesion Extruder", "description": "The extruder train to use for printing the skirt/brim/raft. This is used in multi-extrusion.", "type": "extruder", - "default_value": "-1", + "default_value": "0", + "value": "-1", "enabled": "extruders_enabled_count > 1 and resolveOrValue('adhesion_type') != 'none'", "settable_per_mesh": false, "settable_per_extruder": false From a3d6127dcbd82405a2d960eb9766deb81ac4e80c Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Mon, 12 Mar 2018 11:33:54 +0100 Subject: [PATCH 40/66] CURA-4400 removed unnecessary correctExtruderSettings --- cura/Settings/ContainerManager.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/cura/Settings/ContainerManager.py b/cura/Settings/ContainerManager.py index 00eda480b4..2c94afccef 100644 --- a/cura/Settings/ContainerManager.py +++ b/cura/Settings/ContainerManager.py @@ -338,8 +338,6 @@ class ContainerManager(QObject): container.clear() send_emits_containers.append(container) - Application.getInstance().getMachineManager().correctExtruderSettings() - for container in send_emits_containers: container.sendPostponedEmits() From e0e2d3362baae5e1d28422710f58111fc6b89ad0 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Mon, 12 Mar 2018 13:30:31 +0100 Subject: [PATCH 41/66] CURA-4400 fix for change in fdmprinter: move -1 from default_value to value --- plugins/CuraEngineBackend/StartSliceJob.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index 63a345c13e..f3f34f4c3d 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -278,12 +278,12 @@ class StartSliceJob(Job): # \return A dictionary of replacement tokens to the values they should be # replaced with. def _buildReplacementTokens(self, stack) -> dict: - default_extruder_position = Application.getInstance().getMachineManager().defaultExtruderPosition + default_extruder_position = int(Application.getInstance().getMachineManager().defaultExtruderPosition) result = {} for key in stack.getAllKeys(): setting_type = stack.getProperty(key, "type") value = stack.getProperty(key, "value") - if setting_type == "extruder" and value == "-1": + if setting_type == "extruder" and value == -1: # replace with the default value value = default_extruder_position result[key] = value From d8897957210c50777b96cb5688c845ab91e88b19 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Mon, 12 Mar 2018 14:15:49 +0100 Subject: [PATCH 42/66] CURA-4400 correctly cope with quality changes that conflict with the current enabled extruders --- cura/Settings/ContainerManager.py | 3 +++ cura/Settings/MachineManager.py | 40 +++++++++++++++++++++---------- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/cura/Settings/ContainerManager.py b/cura/Settings/ContainerManager.py index 2c94afccef..7161169b22 100644 --- a/cura/Settings/ContainerManager.py +++ b/cura/Settings/ContainerManager.py @@ -338,6 +338,9 @@ class ContainerManager(QObject): container.clear() send_emits_containers.append(container) + # user changes are possibly added to make the current setup match the current enabled extruders + Application.getInstance().getMachineManager().correctExtruderSettings() + for container in send_emits_containers: container.sendPostponedEmits() diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 2df8c0d967..2b581d833d 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -705,26 +705,42 @@ class MachineManager(QObject): if containers: return containers[0].definition.getId() - ## Update extruder number to a valid value when the number of extruders are changed, or when an extruder is changed - def correctExtruderSettings(self): + def getIncompatibleSettingsOnEnabledExtruders(self, container): extruder_count = self._global_container_stack.getProperty("machine_extruder_count", "value") - - # reset all extruder number settings whose value is no longer valid - for setting_instance in self._global_container_stack.userChanges.findInstances(): + result = [] + for setting_instance in container.findInstances(): setting_key = setting_instance.definition.key - enabled = self._global_container_stack.getProperty(setting_key, "enabled") - if not enabled: - self._global_container_stack.userChanges.removeInstance(setting_key) - Logger.log("d", "Reset setting [%s] because the setting is no longer enabled", setting_key) + setting_enabled = self._global_container_stack.getProperty(setting_key, "enabled") + if not setting_enabled: + # A setting is not visible anymore + result.append(setting_key) + Logger.log("d", "Reset setting [%s] from [%s] because the setting is no longer enabled", setting_key, container) continue if not self._global_container_stack.getProperty(setting_key, "type") in ("extruder", "optional_extruder"): continue - old_value = self._global_container_stack.userChanges.getProperty(setting_key, "value") + old_value = container.getProperty(setting_key, "value") if int(old_value) >= extruder_count or not self._global_container_stack.extruders[str(old_value)].isEnabled: - self._global_container_stack.userChanges.removeInstance(setting_key) - Logger.log("d", "Reset setting [%s] because its old value [%s] is no longer valid", setting_key, old_value) + 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 + + ## Update extruder number to a valid value when the number of extruders are changed, or when an extruder is changed + def correctExtruderSettings(self): + for setting_key in self.getIncompatibleSettingsOnEnabledExtruders(self._global_container_stack.userChanges): + self._global_container_stack.userChanges.removeInstance(setting_key) + add_user_changes = self.getIncompatibleSettingsOnEnabledExtruders(self._global_container_stack.qualityChanges) + for setting_key in add_user_changes: + # Apply quality changes that are incompatible to user changes, so we do not change the quality changes itself. + self._global_container_stack.userChanges.setProperty(setting_key, "value", self._default_extruder_position) + if add_user_changes: + caution_message = Message(catalog.i18nc( + "@info:generic", + "Settings have been changed to match the current availability of extruders: [%s]" % ", ".join(add_user_changes)), + lifetime=0, + title = catalog.i18nc("@info:title", "Settings updated")) + caution_message.show() ## Set the amount of extruders on the active machine (global stack) # \param extruder_count int the number of extruders to set From bb7fccbd486f076fba3e5a535e207d1c3f56d521 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 12 Mar 2018 14:48:28 +0100 Subject: [PATCH 43/66] Add logging for every setting model update You can clearly see that some models are updated 4 times or so now. Contributes to issue CURA-4606. --- cura/Machines/Models/BrandMaterialsModel.py | 5 +++-- cura/Machines/Models/BuildPlateModel.py | 2 ++ .../Models/CustomQualityProfilesDropDownMenuModel.py | 2 +- cura/Machines/Models/GenericMaterialsModel.py | 5 ++++- cura/Machines/Models/MaterialManagementModel.py | 5 ++++- cura/Machines/Models/NozzleModel.py | 3 +++ cura/Machines/Models/QualityManagementModel.py | 4 +++- cura/Machines/Models/QualityProfilesDropDownMenuModel.py | 2 +- cura/Machines/Models/QualitySettingsModel.py | 2 ++ 9 files changed, 23 insertions(+), 7 deletions(-) diff --git a/cura/Machines/Models/BrandMaterialsModel.py b/cura/Machines/Models/BrandMaterialsModel.py index 1146a8acee..7c3c4c515d 100644 --- a/cura/Machines/Models/BrandMaterialsModel.py +++ b/cura/Machines/Models/BrandMaterialsModel.py @@ -4,8 +4,8 @@ from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty from UM.Qt.ListModel import ListModel - -from .BaseMaterialsModel import BaseMaterialsModel +from UM.Logger import Logger +from cura.Machines.Models.BaseMaterialsModel import BaseMaterialsModel # @@ -69,6 +69,7 @@ class BrandMaterialsModel(ListModel): return self._extruder_position def _update(self): + Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) global_stack = self._machine_manager.activeMachine if global_stack is None: self.setItems([]) diff --git a/cura/Machines/Models/BuildPlateModel.py b/cura/Machines/Models/BuildPlateModel.py index 1cb94216a6..e1b4f40d8e 100644 --- a/cura/Machines/Models/BuildPlateModel.py +++ b/cura/Machines/Models/BuildPlateModel.py @@ -4,6 +4,7 @@ from PyQt5.QtCore import Qt from UM.Application import Application +from UM.Logger import Logger from UM.Qt.ListModel import ListModel from UM.Util import parseBool @@ -29,6 +30,7 @@ class BuildPlateModel(ListModel): self._update() def _update(self): + Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) global_stack = self._machine_manager._global_container_stack if not global_stack: self.setItems([]) diff --git a/cura/Machines/Models/CustomQualityProfilesDropDownMenuModel.py b/cura/Machines/Models/CustomQualityProfilesDropDownMenuModel.py index a188a43e72..dcade8cb0d 100644 --- a/cura/Machines/Models/CustomQualityProfilesDropDownMenuModel.py +++ b/cura/Machines/Models/CustomQualityProfilesDropDownMenuModel.py @@ -12,7 +12,7 @@ from cura.Machines.Models.QualityProfilesDropDownMenuModel import QualityProfile class CustomQualityProfilesDropDownMenuModel(QualityProfilesDropDownMenuModel): def _update(self): - Logger.log("d", "Updating %s ...", self.__class__.__name__) + Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) active_global_stack = self._machine_manager.activeMachine if active_global_stack is None: diff --git a/cura/Machines/Models/GenericMaterialsModel.py b/cura/Machines/Models/GenericMaterialsModel.py index 47240ebffd..03343ba53b 100644 --- a/cura/Machines/Models/GenericMaterialsModel.py +++ b/cura/Machines/Models/GenericMaterialsModel.py @@ -1,7 +1,8 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from .BaseMaterialsModel import BaseMaterialsModel +from UM.Logger import Logger +from cura.Machines.Models.BaseMaterialsModel import BaseMaterialsModel class GenericMaterialsModel(BaseMaterialsModel): @@ -21,6 +22,8 @@ class GenericMaterialsModel(BaseMaterialsModel): self._update() def _update(self): + Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) + global_stack = self._machine_manager.activeMachine if global_stack is None: self.setItems([]) diff --git a/cura/Machines/Models/MaterialManagementModel.py b/cura/Machines/Models/MaterialManagementModel.py index 1ea0fd9cf7..46e9cb887a 100644 --- a/cura/Machines/Models/MaterialManagementModel.py +++ b/cura/Machines/Models/MaterialManagementModel.py @@ -1,8 +1,9 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from PyQt5.QtCore import Qt, pyqtProperty +from PyQt5.QtCore import Qt +from UM.Logger import Logger from UM.Qt.ListModel import ListModel @@ -60,6 +61,8 @@ class MaterialManagementModel(ListModel): self._update() def _update(self): + Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) + global_stack = self._machine_manager.activeMachine if global_stack is None: self.setItems([]) diff --git a/cura/Machines/Models/NozzleModel.py b/cura/Machines/Models/NozzleModel.py index 27d190962b..d4f9861e9d 100644 --- a/cura/Machines/Models/NozzleModel.py +++ b/cura/Machines/Models/NozzleModel.py @@ -4,6 +4,7 @@ from PyQt5.QtCore import Qt from UM.Application import Application +from UM.Logger import Logger from UM.Qt.ListModel import ListModel from UM.Util import parseBool @@ -26,6 +27,8 @@ class NozzleModel(ListModel): Application.getInstance().getMachineManager().activeMaterialChanged.connect(self._update) def _update(self): + Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) + self.items.clear() variant_manager = Application.getInstance()._variant_manager diff --git a/cura/Machines/Models/QualityManagementModel.py b/cura/Machines/Models/QualityManagementModel.py index 542016ab68..4d2b551805 100644 --- a/cura/Machines/Models/QualityManagementModel.py +++ b/cura/Machines/Models/QualityManagementModel.py @@ -4,7 +4,7 @@ from PyQt5.QtCore import Qt, pyqtSlot from UM.Qt.ListModel import ListModel - +from UM.Logger import Logger # # This the QML model for the quality management page. @@ -35,6 +35,8 @@ class QualityManagementModel(ListModel): self._update() def _update(self): + Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) + global_stack = self._machine_manager.activeMachine quality_group_dict = self._quality_manager.getQualityGroups(global_stack) diff --git a/cura/Machines/Models/QualityProfilesDropDownMenuModel.py b/cura/Machines/Models/QualityProfilesDropDownMenuModel.py index fd919639c3..40fdaaa410 100644 --- a/cura/Machines/Models/QualityProfilesDropDownMenuModel.py +++ b/cura/Machines/Models/QualityProfilesDropDownMenuModel.py @@ -46,7 +46,7 @@ class QualityProfilesDropDownMenuModel(ListModel): self._update() def _update(self): - Logger.log("d", "Updating quality profile model ...") + Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) global_stack = self._machine_manager.activeMachine if global_stack is None: diff --git a/cura/Machines/Models/QualitySettingsModel.py b/cura/Machines/Models/QualitySettingsModel.py index e0b29d77a5..15ebe37f05 100644 --- a/cura/Machines/Models/QualitySettingsModel.py +++ b/cura/Machines/Models/QualitySettingsModel.py @@ -69,6 +69,8 @@ class QualitySettingsModel(ListModel): return self._selected_quality_item def _update(self): + Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) + if not self._selected_quality_item: self.setItems([]) return From 809db6a4d9f5073dc9112c5f7f0b4281f67278fe Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Mon, 12 Mar 2018 15:09:56 +0100 Subject: [PATCH 44/66] CURA-5078 Remove material warning if the mismatch was the buildplate. --- cura/Settings/MachineManager.py | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index b09ff9e8bd..144f495997 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -919,21 +919,11 @@ class MachineManager(QObject): def activeMaterialsCompatible(self): # check material - variant compatibility - result = True - machine_has_buildplate = Util.parseBool(self._global_container_stack.getMetaDataEntry("has_variant_buildplates", False)) if Util.parseBool(self._global_container_stack.getMetaDataEntry("has_materials", False)): for position, extruder in self._global_container_stack.extruders.items(): if not extruder.material.getMetaDataEntry("compatible"): - result = False - break - if machine_has_buildplate: - buildplate_compatibility_dict = extruder.material.getMetaDataEntry("buildplate_compatible") - if buildplate_compatibility_dict: - buildplate_name = self._global_container_stack.variant.getName() - result = buildplate_compatibility_dict.get(buildplate_name, True) - if not result: - break - return result + return False + return True ## Update current quality type and machine after setting material def _updateQualityWithMaterial(self): From 220e4a64c6e9a11425f7d0ec6c0e81868002fd4c Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Mon, 12 Mar 2018 15:23:49 +0100 Subject: [PATCH 45/66] Fix VariantManager.getVariant() and simplify NozzleModel CURA-4606 --- cura/Machines/Models/NozzleModel.py | 22 +++++++++++++--------- cura/Machines/VariantManager.py | 12 ++++++++++-- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/cura/Machines/Models/NozzleModel.py b/cura/Machines/Models/NozzleModel.py index d4f9861e9d..d178b39475 100644 --- a/cura/Machines/Models/NozzleModel.py +++ b/cura/Machines/Models/NozzleModel.py @@ -21,28 +21,32 @@ class NozzleModel(ListModel): self.addRoleName(self.HotendNameRole, "hotend_name") self.addRoleName(self.ContainerNodeRole, "container_node") - Application.getInstance().globalContainerStackChanged.connect(self._update) - Application.getInstance().getMachineManager().activeVariantChanged.connect(self._update) - Application.getInstance().getMachineManager().activeStackChanged.connect(self._update) - Application.getInstance().getMachineManager().activeMaterialChanged.connect(self._update) + self._application = Application.getInstance() + self._machine_manager = self._application.getMachineManager() + self._variant_manager = self._application.getVariantManager() + + self._machine_manager.globalContainerChanged.connect(self._update) + self._machine_manager.activeVariantChanged.connect(self._update) + self._machine_manager.activeStackChanged.connect(self._update) + self._machine_manager.activeMaterialChanged.connect(self._update) def _update(self): Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) self.items.clear() - variant_manager = Application.getInstance()._variant_manager - active_global_stack = Application.getInstance().getMachineManager()._global_container_stack - if active_global_stack is None: + global_stack = self._machine_manager.activeMachine + if global_stack is None: self.setItems([]) return - has_variants = parseBool(active_global_stack.getMetaDataEntry("has_variants", False)) + has_variants = parseBool(global_stack.getMetaDataEntry("has_variants", False)) if not has_variants: self.setItems([]) return - variant_node_dict = variant_manager.getVariantNodes(active_global_stack) + from cura.Machines.VariantManager import VariantType + variant_node_dict = self._variant_manager.getVariantNodes(global_stack, VariantType.NOZZLE) if not variant_node_dict: self.setItems([]) return diff --git a/cura/Machines/VariantManager.py b/cura/Machines/VariantManager.py index 6cb0a3d7b2..1e6dcfe838 100644 --- a/cura/Machines/VariantManager.py +++ b/cura/Machines/VariantManager.py @@ -83,11 +83,19 @@ class VariantManager: # Almost the same as getVariantMetadata() except that this returns an InstanceContainer if present. # def getVariantNode(self, machine_definition_id: str, variant_name: str, - variant_type: Optional["VariantType"] = VariantType.NOZZLE) -> Optional["ContainerNode"]: + variant_type: Optional["VariantType"] = None) -> Optional["ContainerNode"]: + if variant_type is None: + variant_node = None + variant_type_dict = self._machine_to_variant_dict_map[machine_definition_id] + for variant_dict in variant_type_dict.values(): + if variant_name in variant_dict: + variant_node = variant_dict[variant_name] + break + return variant_node return self._machine_to_variant_dict_map[machine_definition_id].get(variant_type, {}).get(variant_name) def getVariantNodes(self, machine: "GlobalStack", - variant_type: Optional["VariantType"] = VariantType.NOZZLE) -> dict: + variant_type: Optional["VariantType"] = None) -> dict: machine_definition_id = machine.definition.getId() return self._machine_to_variant_dict_map.get(machine_definition_id, {}).get(variant_type, {}) From c54679ba2d76ff4febb85e56e0710c5f4e2c3a4b Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Mon, 12 Mar 2018 15:25:07 +0100 Subject: [PATCH 46/66] Gix buildplate handling in Material profile CURA-4606 --- .../XmlMaterialProfile/XmlMaterialProfile.py | 85 +++++++++++++------ 1 file changed, 60 insertions(+), 25 deletions(-) diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index e8d0c9d2f0..bbf5dfe2ba 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -205,7 +205,7 @@ class XmlMaterialProfile(InstanceContainer): self._addSettingElement(builder, instance) machine_container_map = {} - machine_nozzle_map = {} + machine_variant_map = {} variant_manager = CuraApplication.getInstance().getVariantManager() material_manager = CuraApplication.getInstance().getMaterialManager() @@ -225,13 +225,14 @@ class XmlMaterialProfile(InstanceContainer): if definition_id not in machine_container_map: machine_container_map[definition_id] = container - if definition_id not in machine_nozzle_map: - machine_nozzle_map[definition_id] = {} + if definition_id not in machine_variant_map: + machine_variant_map[definition_id] = {} variant_name = container.getMetaDataEntry("variant_name") if variant_name: - machine_nozzle_map[definition_id][variant_name] = variant_manager.getVariantNode(definition_id, - variant_name) + variant_dict = {"variant_node": variant_manager.getVariantNode(definition_id, variant_name), + "material_container": container} + machine_variant_map[definition_id][variant_name] = variant_dict continue machine_container_map[definition_id] = container @@ -265,28 +266,60 @@ class XmlMaterialProfile(InstanceContainer): self._addSettingElement(builder, instance) # Find all hotend sub-profiles corresponding to this material and machine and add them to this profile. - for hotend_name, variant_node in machine_nozzle_map[definition_id].items(): - # The hotend identifier is not the containers name, but its "name". - builder.start("hotend", {"id": hotend_name}) + buildplate_dict = {} + for variant_name, variant_dict in machine_variant_map[definition_id].items(): + variant_type = variant_dict["variant_node"].metadata["hardware_type"] + from cura.Machines.VariantManager import VariantType + variant_type = VariantType(variant_type) + if variant_type == VariantType.NOZZLE: + # The hotend identifier is not the containers name, but its "name". + builder.start("hotend", {"id": variant_name}) - # Compatible is a special case, as it's added as a meta data entry (instead of an instance). - compatible = variant_node.metadata.get("compatible") - if compatible is not None: - builder.start("setting", {"key": "hardware compatible"}) - if compatible: - builder.data("yes") - else: - builder.data("no") - builder.end("setting") + # Compatible is a special case, as it's added as a meta data entry (instead of an instance). + material_container = variant_dict["material_container"] + compatible = container.getMetaDataEntry("compatible") + if compatible is not None: + builder.start("setting", {"key": "hardware compatible"}) + if compatible: + builder.data("yes") + else: + builder.data("no") + builder.end("setting") - for instance in variant_node.getContainer().findInstances(): - if container.getInstance(instance.definition.key) and container.getProperty(instance.definition.key, "value") == instance.value: - # If the settings match that of the machine profile, just skip since we inherit the machine profile. - continue + for instance in material_container.findInstances(): + if container.getInstance(instance.definition.key) and container.getProperty(instance.definition.key, "value") == instance.value: + # If the settings match that of the machine profile, just skip since we inherit the machine profile. + continue - self._addSettingElement(builder, instance) + self._addSettingElement(builder, instance) - builder.end("hotend") + if material_container.getMetaDataEntry("buildplate_compatible") and not buildplate_dict: + buildplate_dict["buildplate_compatible"] = material_container.getMetaDataEntry("buildplate_compatible") + buildplate_dict["buildplate_recommended"] = material_container.getMetaDataEntry("buildplate_recommended") + buildplate_dict["material_container"] = material_container + + builder.end("hotend") + + if buildplate_dict: + for variant_name in buildplate_dict["buildplate_compatible"]: + builder.start("buildplate", {"id": variant_name}) + + material_container = buildplate_dict["material_container"] + buildplate_compatible_dict = material_container.getMetaDataEntry("buildplate_compatible") + buildplate_recommended_dict = material_container.getMetaDataEntry("buildplate_recommended") + if buildplate_compatible_dict: + compatible = buildplate_compatible_dict[variant_name] + recommended = buildplate_recommended_dict[variant_name] + + builder.start("setting", {"key": "hardware compatible"}) + builder.data("yes" if compatible else "no") + builder.end("setting") + + builder.start("setting", {"key": "hardware recommended"}) + builder.data("yes" if recommended else "no") + builder.end("setting") + + builder.end("buildplate") builder.end("machine") @@ -842,6 +875,8 @@ class XmlMaterialProfile(InstanceContainer): continue settings = buildplate.iterfind("./um:setting", cls.__namespaces) + buildplate_compatibility = True + buildplate_recommended = True for entry in settings: key = entry.get("key") if key == "hardware compatible": @@ -849,8 +884,8 @@ class XmlMaterialProfile(InstanceContainer): elif key == "hardware recommended": buildplate_recommended = cls._parseCompatibleValue(entry.text) - buildplate_map["buildplate_compatible"][buildplate_id] = buildplate_map["buildplate_compatible"] - buildplate_map["buildplate_recommended"][buildplate_id] = buildplate_map["buildplate_recommended"] + buildplate_map["buildplate_compatible"][buildplate_id] = buildplate_compatibility + buildplate_map["buildplate_recommended"][buildplate_id] = buildplate_recommended for hotend in machine.iterfind("./um:hotend", cls.__namespaces): hotend_name = hotend.get("id") From 1512a8096b1e7d2e3c570675e42ae7086da32fdd Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 12 Mar 2018 15:43:25 +0100 Subject: [PATCH 47/66] Require MaterialGroup to always have a base material The material group is loaded lazily whenever the base material is not yet in the dictionary. Contributes to issue CURA-4606. --- cura/Machines/MaterialGroup.py | 11 ++++++----- cura/Machines/MaterialManager.py | 16 +++++++--------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/cura/Machines/MaterialGroup.py b/cura/Machines/MaterialGroup.py index 009778943a..07b790c6bc 100644 --- a/cura/Machines/MaterialGroup.py +++ b/cura/Machines/MaterialGroup.py @@ -1,9 +1,10 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +from typing import List +from cura.Machines.MaterialNode import MaterialNode #For type checking. -# -# A MaterialGroup represents a group of material InstanceContainers that are derived from a single material profile. +## A MaterialGroup represents a group of material InstanceContainers that are derived from a single material profile. # The main InstanceContainer which has the ID of the material profile file name is called the "root_material". For # example: "generic_abs" is the root material (ID) of "generic_abs_ultimaker3" and "generic_abs_ultimaker3_AA_0.4", # and "generic_abs_ultimaker3" and "generic_abs_ultimaker3_AA_0.4" are derived materials of "generic_abs". @@ -17,10 +18,10 @@ class MaterialGroup: __slots__ = ("name", "root_material_node", "derived_material_node_list") - def __init__(self, name: str): + def __init__(self, name: str, root_material_node: MaterialNode): self.name = name - self.root_material_node = None - self.derived_material_node_list = [] + self.root_material_node = root_material_node + self.derived_material_node_list = [] #type: List[MaterialNode] def __str__(self) -> str: return "%s[%s]" % (self.__class__.__name__, self.name) diff --git a/cura/Machines/MaterialManager.py b/cura/Machines/MaterialManager.py index 7c205c0084..b01d360ab6 100644 --- a/cura/Machines/MaterialManager.py +++ b/cura/Machines/MaterialManager.py @@ -72,29 +72,27 @@ class MaterialManager(QObject): def initialize(self): # Find all materials and put them in a matrix for quick search. - material_metadata_list = self._container_registry.findContainersMetadata(type = "material") + material_metadatas = {metadata["id"]: metadata for metadata in self._container_registry.findContainersMetadata(type = "material")} self._material_group_map = dict() # Map #1 # root_material_id -> MaterialGroup - for material_metadata in material_metadata_list: - material_id = material_metadata["id"] + for material_id, material_metadata in material_metadatas.items(): # We don't store empty material in the lookup tables if material_id == "empty_material": continue root_material_id = material_metadata.get("base_file") if root_material_id not in self._material_group_map: - self._material_group_map[root_material_id] = MaterialGroup(root_material_id) + self._material_group_map[root_material_id] = MaterialGroup(root_material_id, MaterialNode(material_metadatas[root_material_id])) group = self._material_group_map[root_material_id] - # We only add root materials here - if material_id == root_material_id: - group.root_material_node = MaterialNode(material_metadata) - else: + #Store this material in the group of the appropriate root material. + if material_id != root_material_id: new_node = MaterialNode(material_metadata) group.derived_material_node_list.append(new_node) + # Order this map alphabetically so it's easier to navigate in a debugger self._material_group_map = OrderedDict(sorted(self._material_group_map.items(), key = lambda x: x[0])) @@ -179,7 +177,7 @@ class MaterialManager(QObject): # "machine" -> "variant_name" -> "root material ID" -> specific material InstanceContainer # Construct the "machine" -> "variant" -> "root material ID" -> specific material InstanceContainer self._diameter_machine_variant_material_map = dict() - for material_metadata in material_metadata_list: + for material_metadata in material_metadatas.values(): # We don't store empty material in the lookup tables if material_metadata["id"] == "empty_material": continue From 05c034558dfe88e4c3ca6e12b023ff1291baea27 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 12 Mar 2018 16:03:42 +0100 Subject: [PATCH 48/66] Set default layer height via preferred quality type So the layer heights are correct for each quality type but the default is still 0.2mm. Contributes to issue CURA-4981. --- resources/definitions/ubuild-3d_mr_bot_280.def.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/definitions/ubuild-3d_mr_bot_280.def.json b/resources/definitions/ubuild-3d_mr_bot_280.def.json index 7f9069370c..4febdcd350 100644 --- a/resources/definitions/ubuild-3d_mr_bot_280.def.json +++ b/resources/definitions/ubuild-3d_mr_bot_280.def.json @@ -11,7 +11,8 @@ "file_formats": "text/x-gcode", "icon": "icon_uBuild-3D", "platform": "mr_bot_280_platform.stl", - "has_materials": true + "has_materials": true, + "preferred_quality_type": "draft" }, "overrides": { @@ -24,7 +25,6 @@ "material_diameter": { "default_value": 1.75 }, "material_bed_temperature": { "default_value": 70 }, "machine_nozzle_size": { "default_value": 0.4 }, - "layer_height": { "default_value": 0.2 }, "layer_height_0": { "default_value": 0.1 }, "retraction_amount": { "default_value": 2 }, "retraction_speed": { "default_value": 50 }, From 1f08accbecf117b5590d1fb417d16854ac564193 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Mon, 12 Mar 2018 16:14:35 +0100 Subject: [PATCH 49/66] Fix profile importing for version upgrade CURA-4946 --- cura/Settings/CuraContainerRegistry.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cura/Settings/CuraContainerRegistry.py b/cura/Settings/CuraContainerRegistry.py index 4b576a4207..828897b4dd 100644 --- a/cura/Settings/CuraContainerRegistry.py +++ b/cura/Settings/CuraContainerRegistry.py @@ -241,7 +241,7 @@ class CuraContainerRegistry(ContainerRegistry): profile.addMetaDataEntry("type", "quality_changes") profile.addMetaDataEntry("definition", global_profile.getMetaDataEntry("definition")) profile.addMetaDataEntry("quality_type", global_profile.getMetaDataEntry("quality_type")) - profile.addMetaDataEntry("extruder", extruder.getId()) + profile.addMetaDataEntry("position", "0") profile.setDirty(True) if idx == 0: # move all per-extruder settings to the first extruder's quality_changes @@ -273,10 +273,11 @@ class CuraContainerRegistry(ContainerRegistry): elif profile_index < len(machine_extruders) + 1: # This is assumed to be an extruder profile extruder_id = machine_extruders[profile_index - 1].definition.getId() - if not profile.getMetaDataEntry("extruder"): - profile.addMetaDataEntry("extruder", extruder_id) + extuder_position = str(profile_index - 1) + if not profile.getMetaDataEntry("position"): + profile.addMetaDataEntry("position", extuder_position) else: - profile.setMetaDataEntry("extruder", extruder_id) + profile.setMetaDataEntry("position", extuder_position) profile_id = (extruder_id + "_" + name_seed).lower().replace(" ", "_") else: #More extruders in the imported file than in the machine. From 00783401752a3bbc661fc6d65c15f6fd7861bdee Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 12 Mar 2018 16:19:28 +0100 Subject: [PATCH 50/66] Only update NozzleModel when machine changes The available nozzles only change upon changing machines. Contributes to issue CURA-4606. --- cura/Machines/Models/NozzleModel.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cura/Machines/Models/NozzleModel.py b/cura/Machines/Models/NozzleModel.py index d178b39475..0879998b7d 100644 --- a/cura/Machines/Models/NozzleModel.py +++ b/cura/Machines/Models/NozzleModel.py @@ -26,9 +26,7 @@ class NozzleModel(ListModel): self._variant_manager = self._application.getVariantManager() self._machine_manager.globalContainerChanged.connect(self._update) - self._machine_manager.activeVariantChanged.connect(self._update) - self._machine_manager.activeStackChanged.connect(self._update) - self._machine_manager.activeMaterialChanged.connect(self._update) + self._update() def _update(self): Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) From 5afcf2beacfac24b56d11bab0da4a3f5efe6b1bf Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 12 Mar 2018 16:28:41 +0100 Subject: [PATCH 51/66] Don't update brand and generic materials models upon switching active extruder Because the list of materials can't change by that action. Contributes to issue CURA-4606. --- cura/Machines/Models/BrandMaterialsModel.py | 2 -- cura/Machines/Models/GenericMaterialsModel.py | 2 -- 2 files changed, 4 deletions(-) diff --git a/cura/Machines/Models/BrandMaterialsModel.py b/cura/Machines/Models/BrandMaterialsModel.py index 7c3c4c515d..e36c6448d3 100644 --- a/cura/Machines/Models/BrandMaterialsModel.py +++ b/cura/Machines/Models/BrandMaterialsModel.py @@ -54,9 +54,7 @@ class BrandMaterialsModel(ListModel): self._material_manager = CuraApplication.getInstance().getMaterialManager() self._machine_manager.globalContainerChanged.connect(self._update) - self._extruder_manager.activeExtruderChanged.connect(self._update) self._material_manager.materialsUpdated.connect(self._update) - self._update() def setExtruderPosition(self, position: int): diff --git a/cura/Machines/Models/GenericMaterialsModel.py b/cura/Machines/Models/GenericMaterialsModel.py index 03343ba53b..6b149448ea 100644 --- a/cura/Machines/Models/GenericMaterialsModel.py +++ b/cura/Machines/Models/GenericMaterialsModel.py @@ -16,9 +16,7 @@ class GenericMaterialsModel(BaseMaterialsModel): self._material_manager = CuraApplication.getInstance().getMaterialManager() self._machine_manager.globalContainerChanged.connect(self._update) - self._extruder_manager.activeExtruderChanged.connect(self._update) self._material_manager.materialsUpdated.connect(self._update) - self._update() def _update(self): From f08407cf97370bf7b1465f856bfcd64db635113b Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 12 Mar 2018 16:32:10 +0100 Subject: [PATCH 52/66] Document Available role Contributes to issue CURA-4606. --- cura/Machines/Models/QualityProfilesDropDownMenuModel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Machines/Models/QualityProfilesDropDownMenuModel.py b/cura/Machines/Models/QualityProfilesDropDownMenuModel.py index 40fdaaa410..06231491c7 100644 --- a/cura/Machines/Models/QualityProfilesDropDownMenuModel.py +++ b/cura/Machines/Models/QualityProfilesDropDownMenuModel.py @@ -29,7 +29,7 @@ class QualityProfilesDropDownMenuModel(ListModel): self.addRoleName(self.QualityTypeRole, "quality_type") self.addRoleName(self.LayerHeightRole, "layer_height") self.addRoleName(self.LayerHeightUnitRole, "layer_height_unit") - self.addRoleName(self.AvailableRole, "available") + self.addRoleName(self.AvailableRole, "available") #Whether the quality profile is available in our current nozzle + material. self.addRoleName(self.QualityGroupRole, "quality_group") self.addRoleName(self.QualityChangesGroupRole, "quality_changes_group") From 522e2977110e74b64ad09b8b421e3421cf05e1c5 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 12 Mar 2018 16:33:32 +0100 Subject: [PATCH 53/66] Add some more states to check if print_job is active --- plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py index 7a4c590acc..bcd11b3cb7 100644 --- a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py +++ b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py @@ -301,8 +301,8 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): self._updatePrintJob(print_job, print_job_data) if print_job.state != "queued": # Print job should be assigned to a printer. - if print_job.state == "failed": - # Print job was failed, so don't attach it to a printer. + if print_job.state in ["failed", "finished", "aborted"]: + # Print job was already completed, so don't attach it to a printer. printer = None else: printer = self._getPrinterByKey(print_job_data["printer_uuid"]) From 981c47ed87aece4637f2026953d74175ed783850 Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 12 Mar 2018 17:03:10 +0100 Subject: [PATCH 54/66] Put the support extruder dropdown behind the checkbox to prevent scrolling --- resources/qml/SidebarSimple.qml | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index eabc1d202a..7cc67be03a 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -786,21 +786,6 @@ Item } } - Label - { - id: supportExtruderLabel - visible: supportExtruderCombobox.visible - anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width - anchors.right: infillCellLeft.right - anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width - anchors.verticalCenter: supportExtruderCombobox.verticalCenter - text: catalog.i18nc("@label", "Support Extruder"); - font: UM.Theme.getFont("default"); - color: UM.Theme.getColor("text"); - elide: Text.ElideRight - } - ComboBox { id: supportExtruderCombobox @@ -818,12 +803,13 @@ Item textRole: "text" // this solves that the combobox isn't populated in the first time Cura is started - anchors.top: enableSupportCheckBox.bottom - anchors.topMargin: ((supportEnabled.properties.value === "True") && (extrudersEnabledCount.properties.value > 1)) ? UM.Theme.getSize("sidebar_margin").height : 0 - anchors.left: infillCellRight.left + anchors.top: enableSupportCheckBox.top + //anchors.topMargin: ((supportEnabled.properties.value === "True") && (machineExtruderCount.properties.value > 1)) ? UM.Theme.getSize("sidebar_margin").height : 0 + anchors.left: enableSupportCheckBox.right + anchors.leftMargin: Math.round(UM.Theme.getSize("sidebar_margin").width / 2) - width: Math.round(UM.Theme.getSize("sidebar").width * .55) - height: ((supportEnabled.properties.value == "True") && (extrudersEnabledCount.properties.value > 1)) ? UM.Theme.getSize("setting_control").height : 0 + width: Math.round(UM.Theme.getSize("sidebar").width * .55) - Math.round(UM.Theme.getSize("sidebar_margin").width / 2) - enableSupportCheckBox.width + height: ((supportEnabled.properties.value == "True") && (machineExtruderCount.properties.value > 1)) ? UM.Theme.getSize("setting_control").height : 0 Behavior on height { NumberAnimation { duration: 100 } } @@ -889,7 +875,7 @@ Item id: adhesionCheckBox property alias _hovered: adhesionMouseArea.containsMouse - anchors.top: enableSupportCheckBox.visible ? supportExtruderCombobox.bottom : infillCellRight.bottom + anchors.top: enableSupportCheckBox.bottom anchors.topMargin: UM.Theme.getSize("sidebar_margin").height anchors.left: infillCellRight.left From d904f677bc2c8e0a4cf6ec9b66ca0bfe1b54eccc Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 12 Mar 2018 17:07:52 +0100 Subject: [PATCH 55/66] Store extruder position of quality groups as int Instead of as a string with a number in it. For the actual global stack's extruders we still need to convert to string, sadly. I could go refactor that too, but then I won't be going home until 23 o'clock or something. Contributes to issue CURA-4606. --- cura/Machines/Models/QualitySettingsModel.py | 17 +++++++++-------- cura/Machines/QualityGroup.py | 4 ++-- cura/Settings/MachineManager.py | 4 ++-- resources/qml/Preferences/ProfileTab.qml | 2 +- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/cura/Machines/Models/QualitySettingsModel.py b/cura/Machines/Models/QualitySettingsModel.py index 15ebe37f05..5489ad0dd7 100644 --- a/cura/Machines/Models/QualitySettingsModel.py +++ b/cura/Machines/Models/QualitySettingsModel.py @@ -21,6 +21,8 @@ class QualitySettingsModel(ListModel): UserValueRole = Qt.UserRole + 6 CategoryRole = Qt.UserRole + 7 + GLOBAL_STACK_POSITION = -1 + def __init__(self, parent = None): super().__init__(parent = parent) @@ -36,8 +38,7 @@ class QualitySettingsModel(ListModel): self._application = Application.getInstance() self._quality_manager = self._application.getQualityManager() - self._selected_position = "" # empty string means GlobalStack - # strings such as "0", "1", etc. mean extruder positions + self._selected_position = self.GLOBAL_STACK_POSITION #Must be either GLOBAL_STACK_POSITION or an extruder position (0, 1, etc.) self._selected_quality_item = None # The selected quality in the quality management page self._i18n_catalog = None @@ -54,7 +55,7 @@ class QualitySettingsModel(ListModel): self.selectedPositionChanged.emit() self._update() - @pyqtProperty(str, fset = setSelectedPosition, notify = selectedPositionChanged) + @pyqtProperty(int, fset = setSelectedPosition, notify = selectedPositionChanged) def selectedPosition(self): return self._selected_position @@ -83,7 +84,7 @@ class QualitySettingsModel(ListModel): quality_group = self._selected_quality_item["quality_group"] quality_changes_group = self._selected_quality_item["quality_changes_group"] - if self._selected_position == "": + if self._selected_position == self.GLOBAL_STACK_POSITION: quality_node = quality_group.node_for_global else: quality_node = quality_group.nodes_for_extruders.get(self._selected_position) @@ -93,7 +94,7 @@ class QualitySettingsModel(ListModel): # Here, if the user has selected a quality changes, then "quality_changes_group" will not be None, and we fetch # the settings in that quality_changes_group. if quality_changes_group is not None: - if self._selected_position == "": + if self._selected_position == self.GLOBAL_STACK_POSITION: quality_changes_node = quality_changes_group.node_for_global else: quality_changes_node = quality_changes_group.nodes_for_extruders.get(self._selected_position) @@ -127,7 +128,7 @@ class QualitySettingsModel(ListModel): profile_value = new_value # Global tab should use resolve (if there is one) - if self._selected_position == "": + if self._selected_position == self.GLOBAL_STACK_POSITION: resolve_value = global_container_stack.getProperty(definition.key, "resolve") if resolve_value is not None and definition.key in settings_keys: profile_value = resolve_value @@ -135,10 +136,10 @@ class QualitySettingsModel(ListModel): if profile_value is not None: break - if not self._selected_position: + if self._selected_position == self.GLOBAL_STACK_POSITION: user_value = global_container_stack.userChanges.getProperty(definition.key, "value") else: - extruder_stack = global_container_stack.extruders[self._selected_position] + extruder_stack = global_container_stack.extruders[str(self._selected_position)] user_value = extruder_stack.userChanges.getProperty(definition.key, "value") if profile_value is None and user_value is None: diff --git a/cura/Machines/QualityGroup.py b/cura/Machines/QualityGroup.py index 6945162401..02096cfb36 100644 --- a/cura/Machines/QualityGroup.py +++ b/cura/Machines/QualityGroup.py @@ -1,7 +1,7 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from typing import Optional, List +from typing import Dict, Optional, List from PyQt5.QtCore import QObject, pyqtSlot @@ -25,7 +25,7 @@ class QualityGroup(QObject): super().__init__(parent) self.name = name self.node_for_global = None # type: Optional["QualityGroup"] - self.nodes_for_extruders = dict() # position str -> QualityGroup + self.nodes_for_extruders = {} # type: Dict[int, "QualityGroup"] self.quality_type = quality_type self.is_available = False diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 35ffc3c7d3..3a65b6df5d 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -939,9 +939,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[position].quality = node.getContainer() + self._global_container_stack.extruders[str(position)].quality = node.getContainer() if empty_quality_changes: - self._global_container_stack.extruders[position].qualityChanges = self._empty_quality_changes_container + self._global_container_stack.extruders[str(position)].qualityChanges = self._empty_quality_changes_container self.activeQualityGroupChanged.emit() self.activeQualityChangesGroupChanged.emit() diff --git a/resources/qml/Preferences/ProfileTab.qml b/resources/qml/Preferences/ProfileTab.qml index e202e933f3..0ae0899051 100644 --- a/resources/qml/Preferences/ProfileTab.qml +++ b/resources/qml/Preferences/ProfileTab.qml @@ -11,7 +11,7 @@ Tab { id: base - property string extruderPosition: "" + property int extruderPosition: -1 //Denotes the global stack. property var qualityItem: null property bool isQualityItemCurrentlyActivated: From 1db8c967f2ffca588997cedb0c09eb506702054f Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 12 Mar 2018 17:10:17 +0100 Subject: [PATCH 56/66] More specific exception catching So that we can still find programming errors in this code. Contributes to issue CURA-4606. --- cura/Machines/Models/QualitySettingsModel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Machines/Models/QualitySettingsModel.py b/cura/Machines/Models/QualitySettingsModel.py index 5489ad0dd7..4470ffc80e 100644 --- a/cura/Machines/Models/QualitySettingsModel.py +++ b/cura/Machines/Models/QualitySettingsModel.py @@ -101,7 +101,7 @@ class QualitySettingsModel(ListModel): if quality_changes_node is not None: # it can be None if number of extruders are changed during runtime try: quality_containers.insert(0, quality_changes_node.getContainer()) - except: + except RuntimeError: # FIXME: This is to prevent incomplete update of QualityManager Logger.logException("d", "Failed to get container for quality changes node %s", quality_changes_node) return From f40e9bffa9aeee2e312fbe4cbe5cab7bfa8189f6 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 12 Mar 2018 17:27:55 +0100 Subject: [PATCH 57/66] Use extruder positions directly ...instead of the keys in the _current_root_material_id map. Contributes to issue CURA-4606. --- cura/Settings/MachineManager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 3a65b6df5d..d79130e0c3 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -872,9 +872,9 @@ class MachineManager(QObject): container = extruder.userChanges container.setProperty(setting_name, property_name, property_value) - @pyqtProperty("QVariantList", notify = rootMaterialChanged) + @pyqtProperty("QVariantList", notify = globalContainerChanged) def currentExtruderPositions(self): - return sorted(list(self._current_root_material_id.keys())) + return sorted(list(self._global_container_stack.extruders.keys())) @pyqtProperty("QVariant", notify = rootMaterialChanged) def currentRootMaterialId(self): From a87db2d721e7779c4b6d3650aa60155e0de22ea4 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 13 Mar 2018 09:09:21 +0100 Subject: [PATCH 58/66] Always update root material even if not in QML Previously the _current_root_material_id and _current_root_material_name dictionaries were only updated if they are used anywhere in QML. This is unreliable. We're now directly connecting to the signal so that they are always updated, even when not in use by the GUI. This way we can rely on it in other places than the GUI. Contributes to issue CURA-4606. --- cura/Settings/MachineManager.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index d79130e0c3..afff8b96b3 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -125,6 +125,7 @@ class MachineManager(QObject): # When the materials lookup table gets updated, it can mean that a material has its name changed, which should # be reflected on the GUI. This signal emission makes sure that it happens. self._material_manager.materialsUpdated.connect(self.rootMaterialChanged) + self.rootMaterialChanged.connect(self._onRootMaterialChanged) activeQualityGroupChanged = pyqtSignal() activeQualityChangesGroupChanged = pyqtSignal() @@ -876,23 +877,26 @@ class MachineManager(QObject): def currentExtruderPositions(self): return sorted(list(self._global_container_stack.extruders.keys())) - @pyqtProperty("QVariant", notify = rootMaterialChanged) - def currentRootMaterialId(self): - # initial filling the current_root_material_id + ## Update _current_root_material_id and _current_root_material_name when + # the current root material was changed. + def _onRootMaterialChanged(self): self._current_root_material_id = {} for position in self._global_container_stack.extruders: self._current_root_material_id[position] = self._global_container_stack.extruders[position].material.getMetaDataEntry("base_file") - return self._current_root_material_id - @pyqtProperty("QVariant", notify = rootMaterialChanged) - def currentRootMaterialName(self): - # initial filling the current_root_material_name if self._global_container_stack: self._current_root_material_name = {} for position in self._global_container_stack.extruders: if position not in self._current_root_material_name: material = self._global_container_stack.extruders[position].material self._current_root_material_name[position] = material.getName() + + @pyqtProperty("QVariant", notify = rootMaterialChanged) + def currentRootMaterialId(self): + return self._current_root_material_id + + @pyqtProperty("QVariant", notify = rootMaterialChanged) + def currentRootMaterialName(self): return self._current_root_material_name ## Return the variant names in the extruder stack(s). From 69dc4fa5e018a874b69a554704e128847acbf460 Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Tue, 13 Mar 2018 09:20:42 +0100 Subject: [PATCH 59/66] Concerning the unfortunate crash... ..of the morning of the 13th day of March, in the 2018th year of our lord. --- cura/Settings/MachineManager.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index afff8b96b3..75024ad395 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -875,6 +875,8 @@ class MachineManager(QObject): @pyqtProperty("QVariantList", notify = globalContainerChanged) def currentExtruderPositions(self): + if self._global_container_stack is None: + return [] return sorted(list(self._global_container_stack.extruders.keys())) ## Update _current_root_material_id and _current_root_material_name when From b4a40915bb45612edde6150da5b101c19d62dede Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 13 Mar 2018 09:23:40 +0100 Subject: [PATCH 60/66] Code style: Brackets on new line Contributes to issue CURA-4606. --- resources/qml/Preferences/MaterialsPage.qml | 69 ++++++++++++++------- 1 file changed, 46 insertions(+), 23 deletions(-) diff --git a/resources/qml/Preferences/MaterialsPage.qml b/resources/qml/Preferences/MaterialsPage.qml index 553cfe0423..7f06ffecde 100644 --- a/resources/qml/Preferences/MaterialsPage.qml +++ b/resources/qml/Preferences/MaterialsPage.qml @@ -19,14 +19,17 @@ Item UM.I18nCatalog { id: catalog; name: "cura"; } - Cura.MaterialManagementModel { + Cura.MaterialManagementModel + { id: materialsModel } - Label { + Label + { id: titleLabel - anchors { + anchors + { top: parent.top left: parent.left right: parent.right @@ -170,22 +173,27 @@ Item Connections { target: materialsModel - onItemsChanged: { + onItemsChanged: + { var currentItemId = base.currentItem == null ? "" : base.currentItem.root_material_id; var position = Cura.ExtruderManager.activeExtruderIndex; // try to pick the currently selected item; it may have been moved - if (base.newRootMaterialIdToSwitchTo == "") { + if (base.newRootMaterialIdToSwitchTo == "") + { base.newRootMaterialIdToSwitchTo = currentItemId; } - for (var idx = 0; idx < materialsModel.rowCount(); ++idx) { + for (var idx = 0; idx < materialsModel.rowCount(); ++idx) + { var item = materialsModel.getItem(idx); - if (item.root_material_id == base.newRootMaterialIdToSwitchTo) { + if (item.root_material_id == base.newRootMaterialIdToSwitchTo) + { // Switch to the newly created profile if needed materialListView.currentIndex = idx; materialListView.activateDetailsWithIndex(materialListView.currentIndex); - if (base.toActivateNewMaterial) { + if (base.toActivateNewMaterial) + { Cura.MachineManager.setMaterial(position, item.container_node); } base.newRootMaterialIdToSwitchTo = ""; @@ -196,7 +204,8 @@ Item materialListView.currentIndex = 0; materialListView.activateDetailsWithIndex(materialListView.currentIndex); - if (base.toActivateNewMaterial) { + if (base.toActivateNewMaterial) + { Cura.MachineManager.setMaterial(position, materialsModel.getItem(0).container_node); } base.newRootMaterialIdToSwitchTo = ""; @@ -233,14 +242,17 @@ Item messageDialog.title = catalog.i18nc("@title:window", "Import Material"); messageDialog.text = catalog.i18nc("@info:status Don't translate the XML tags or !", "Could not import material %1: %2").arg(fileUrl).arg(result.message); - if (result.status == "success") { + if (result.status == "success") + { messageDialog.icon = StandardIcon.Information; messageDialog.text = catalog.i18nc("@info:status Don't translate the XML tag !", "Successfully imported material %1").arg(fileUrl); } - else if (result.status == "duplicate") { + else if (result.status == "duplicate") + { messageDialog.icon = StandardIcon.Warning; } - else { + else + { messageDialog.icon = StandardIcon.Critical; } messageDialog.open(); @@ -260,12 +272,14 @@ Item var result = Cura.ContainerManager.exportContainer(base.currentItem.root_material_id, selectedNameFilter, fileUrl); messageDialog.title = catalog.i18nc("@title:window", "Export Material"); - if (result.status == "error") { + if (result.status == "error") + { messageDialog.icon = StandardIcon.Critical; messageDialog.text = catalog.i18nc("@info:status Don't translate the XML tags and !", "Failed to export material to %1: %2").arg(fileUrl).arg(result.message); messageDialog.open(); } - else if (result.status == "success") { + else if (result.status == "success") + { messageDialog.icon = StandardIcon.Information; messageDialog.text = catalog.i18nc("@info:status Don't translate the XML tag !", "Successfully exported material to %1").arg(result.path); messageDialog.open(); @@ -283,7 +297,8 @@ Item Item { id: contentsItem - anchors { + anchors + { top: titleLabel.bottom left: parent.left right: parent.right @@ -297,7 +312,8 @@ Item Item { - anchors { + anchors + { top: buttonRow.bottom topMargin: UM.Theme.getSize("default_margin").height left: parent.left @@ -310,12 +326,14 @@ Item Label { id: captionLabel - anchors { + anchors + { top: parent.top left: parent.left } visible: text != "" - text: { + text: + { var caption = catalog.i18nc("@action:label", "Printer") + ": " + Cura.MachineManager.activeMachineName; if (Cura.MachineManager.hasVariants) { @@ -330,14 +348,16 @@ Item ScrollView { id: materialScrollView - anchors { + anchors + { top: captionLabel.visible ? captionLabel.bottom : parent.top topMargin: captionLabel.visible ? UM.Theme.getSize("default_margin").height : 0 bottom: parent.bottom left: parent.left } - Rectangle { + Rectangle + { parent: viewport anchors.fill: parent color: palette.light @@ -418,13 +438,15 @@ Item MouseArea { anchors.fill: parent - onClicked: { + onClicked: + { parent.ListView.view.currentIndex = model.index; } } } - function activateDetailsWithIndex(index) { + function activateDetailsWithIndex(index) + { var model = materialsModel.getItem(index); base.currentItem = model; materialDetailsView.containerId = model.container_id; @@ -446,7 +468,8 @@ Item { id: detailsPanel - anchors { + anchors + { left: materialScrollView.right leftMargin: UM.Theme.getSize("default_margin").width top: parent.top From b90a9c490d34a9a6ede53746d007fc4da33507a3 Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Tue, 13 Mar 2018 09:57:07 +0100 Subject: [PATCH 61/66] Don't loop extruders before checking if there is a global extruder stack --- cura/Settings/MachineManager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 75024ad395..eb720000bf 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -883,10 +883,10 @@ class MachineManager(QObject): # the current root material was changed. def _onRootMaterialChanged(self): self._current_root_material_id = {} - for position in self._global_container_stack.extruders: - self._current_root_material_id[position] = self._global_container_stack.extruders[position].material.getMetaDataEntry("base_file") if self._global_container_stack: + for position in self._global_container_stack.extruders: + self._current_root_material_id[position] = self._global_container_stack.extruders[position].material.getMetaDataEntry("base_file") self._current_root_material_name = {} for position in self._global_container_stack.extruders: if position not in self._current_root_material_name: From 73517cd176d4ce33ae657a079cd655bc5ffe38c2 Mon Sep 17 00:00:00 2001 From: Aleksei S Date: Tue, 13 Mar 2018 11:41:48 +0100 Subject: [PATCH 62/66] The infill denstiy was updated twice, first in Custom view and then in Recomended view CURA-5071 --- resources/qml/SidebarSimple.qml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index 7cc67be03a..d24c047058 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -516,7 +516,11 @@ Item // Update the slider value to represent the rounded value infillSlider.value = roundedSliderValue - Cura.MachineManager.setSettingForAllExtruders("infill_sparse_density", "value", roundedSliderValue) + // Update value only if the Recomended mode is Active, + // Otherwise if I change the value in the Custom mode the Recomended view will try to repeat + // same operation + if (UM.Preferences.getValue("cura/active_mode") == 0) + Cura.MachineManager.setSettingForAllExtruders("infill_sparse_density", "value", roundedSliderValue) } style: SliderStyle From 6d2d9c8fe2a1b5974babe2a64bc23fcc8fb304c4 Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Tue, 13 Mar 2018 12:39:10 +0100 Subject: [PATCH 63/66] CURA-4946 Fixed typo --- cura/Settings/CuraContainerRegistry.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cura/Settings/CuraContainerRegistry.py b/cura/Settings/CuraContainerRegistry.py index 828897b4dd..81cbabc0c9 100644 --- a/cura/Settings/CuraContainerRegistry.py +++ b/cura/Settings/CuraContainerRegistry.py @@ -273,11 +273,11 @@ class CuraContainerRegistry(ContainerRegistry): elif profile_index < len(machine_extruders) + 1: # This is assumed to be an extruder profile extruder_id = machine_extruders[profile_index - 1].definition.getId() - extuder_position = str(profile_index - 1) + extruder_position = str(profile_index - 1) if not profile.getMetaDataEntry("position"): - profile.addMetaDataEntry("position", extuder_position) + profile.addMetaDataEntry("position", extruder_position) else: - profile.setMetaDataEntry("position", extuder_position) + profile.setMetaDataEntry("position", extruder_position) profile_id = (extruder_id + "_" + name_seed).lower().replace(" ", "_") else: #More extruders in the imported file than in the machine. From 0897c740b080b8f7ecc271b782bb18d983850dff Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Tue, 13 Mar 2018 12:57:03 +0100 Subject: [PATCH 64/66] Fix typo in log --- 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 eb720000bf..f52b90e80f 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -335,7 +335,7 @@ class MachineManager(QObject): return False if self._global_container_stack.hasErrors(): - Logger.log("d", "Checking global stack for errors took %0.2f s and we found and error" % (time.time() - time_start)) + Logger.log("d", "Checking global stack for errors took %0.2f s and we found an error" % (time.time() - time_start)) return True # Not a very pretty solution, but the extruder manager doesn't really know how many extruders there are From d6979bc89ad3d8c90be0336a294e08d69cea98e8 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Tue, 13 Mar 2018 13:14:33 +0100 Subject: [PATCH 65/66] CURA-4400 using an intermediate variable prevents an empty popup that occured now and then --- resources/qml/SidebarHeader.qml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 473f4c5cc8..4bda8074b1 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -91,6 +91,8 @@ Column exclusiveGroup: extruderMenuGroup checked: base.currentExtruderIndex == index + property bool extruder_enabled: true + MouseArea { anchors.fill: parent @@ -102,6 +104,7 @@ Column Cura.ExtruderManager.setActiveExtruderIndex(index); break; case Qt.RightButton: + extruder_enabled = Cura.MachineManager.getExtruder(model.index).isEnabled extruderMenu.popup(); break; } @@ -116,13 +119,13 @@ Column MenuItem { text: catalog.i18nc("@action:inmenu", "Enable Extruder") onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, true) - visible: !Cura.MachineManager.getExtruder(model.index).isEnabled + visible: !extruder_enabled // using an intermediate variable prevents an empty popup that occured now and then } MenuItem { text: catalog.i18nc("@action:inmenu", "Disable Extruder") onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, false) - visible: Cura.MachineManager.getExtruder(model.index).isEnabled + visible: extruder_enabled } } From d10f0f7781a1767ed41a6dd13edff31d15d15d67 Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Tue, 13 Mar 2018 13:29:00 +0100 Subject: [PATCH 66/66] CURA-5071 Added brackets --- resources/qml/SidebarSimple.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index d24c047058..a7c8a1b8c5 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -519,8 +519,9 @@ Item // Update value only if the Recomended mode is Active, // Otherwise if I change the value in the Custom mode the Recomended view will try to repeat // same operation - if (UM.Preferences.getValue("cura/active_mode") == 0) + if (UM.Preferences.getValue("cura/active_mode") == 0) { Cura.MachineManager.setSettingForAllExtruders("infill_sparse_density", "value", roundedSliderValue) + } } style: SliderStyle