From d31eaca1b7d1caeed1aba27c8b68ad07ea643b94 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 9 Jan 2018 13:35:42 +0100 Subject: [PATCH 01/45] CURA-4461 Add default buildplate temperature setting --- resources/definitions/fdmprinter.def.json | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 6eef6b1e9b..e042906014 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -1981,14 +1981,28 @@ "settable_per_mesh": false, "settable_per_extruder": true }, + "default_material_bed_temperature": + { + "label": "Default Build Plate Temperature", + "description": "The default temperature used for the heated build plate. This should be the \"base\" temperature of a build plate. All other print temperatures should use offsets based on this value", + "resolve": "max(extruderValues('default_material_bed_temperature'))", + "default_value": 60, + "minimum_value": "-273.15", + "minimum_value_warning": "0", + "maximum_value_warning": "130", + "enabled": "machine_heated_bed and machine_gcode_flavor != \"UltiGCode\"", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false + }, "material_bed_temperature": { "label": "Build Plate Temperature", "description": "The temperature used for the heated build plate. If this is 0, the bed temperature will not be adjusted.", "unit": "°C", "type": "float", - "resolve": "max(extruderValues('material_bed_temperature'))", "default_value": 60, + "value": "default_material_bed_temperature", "minimum_value": "-273.15", "minimum_value_warning": "0", "maximum_value_warning": "130", From 342bdda64125251fc7ecc426c791bbe2a864eed3 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 9 Jan 2018 13:54:01 +0100 Subject: [PATCH 02/45] CURA-4461 Add missing keys --- resources/definitions/fdmprinter.def.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index e042906014..61bccbce59 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -1985,6 +1985,8 @@ { "label": "Default Build Plate Temperature", "description": "The default temperature used for the heated build plate. This should be the \"base\" temperature of a build plate. All other print temperatures should use offsets based on this value", + "unit": "°C", + "type": "float", "resolve": "max(extruderValues('default_material_bed_temperature'))", "default_value": 60, "minimum_value": "-273.15", From becb0cf7b9edaf4a0324a1e36d571f8bb6e8e2f2 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 9 Jan 2018 15:42:10 +0100 Subject: [PATCH 03/45] CURA-4461 Add dropdown menu in the UI for selecting the buildplate if the printer has different buildplates. --- cura/Settings/MachineManager.py | 21 ++++- .../XmlMaterialProfile/XmlMaterialProfile.py | 2 +- resources/qml/Menus/BuildplateMenu.qml | 87 +++++++++++++++++++ resources/qml/SidebarHeader.qml | 42 ++++++++- 4 files changed, 149 insertions(+), 3 deletions(-) create mode 100644 resources/qml/Menus/BuildplateMenu.qml diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 05aed1f5e2..7662eb64d6 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -844,6 +844,11 @@ class MachineManager(QObject): else: Logger.log("w", "While trying to set the active variant, no variant was found to replace.") + @pyqtSlot(str) + def setActiveVariantBuildplate(self, variant_buildplate_id: str): + Logger.log("d", "Attempting to change the active buildplate to %s", variant_buildplate_id) + pass + ## set the active quality # \param quality_id The quality_id of either a quality or a quality_changes @pyqtSlot(str) @@ -1105,6 +1110,15 @@ class MachineManager(QObject): return "" + @pyqtProperty(str, notify = activeVariantChanged) + def activeVariantBuildplateName(self) -> str: + if self._global_container_stack: + variant = self._global_container_stack.variant + if variant: + return variant.getName() + + return "" + @pyqtProperty(str, notify = globalContainerChanged) def activeDefinitionId(self) -> str: if self._global_container_stack: @@ -1202,7 +1216,6 @@ class MachineManager(QObject): def hasMaterials(self) -> bool: if self._global_container_stack: return Util.parseBool(self._global_container_stack.getMetaDataEntry("has_materials", False)) - return False @pyqtProperty(bool, notify = globalContainerChanged) @@ -1211,6 +1224,12 @@ class MachineManager(QObject): return Util.parseBool(self._global_container_stack.getMetaDataEntry("has_variants", False)) return False + @pyqtProperty(bool, notify = globalContainerChanged) + def hasVariantBuildplates(self) -> bool: + if self._global_container_stack: + return Util.parseBool(self._global_container_stack.getMetaDataEntry("has_variant_buildplates", False)) + return False + ## Property to indicate if a machine has "specialized" material profiles. # Some machines have their own material profiles that "override" the default catch all profiles. @pyqtProperty(bool, notify = globalContainerChanged) diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index 125fe1e344..8e3c25bb23 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -874,7 +874,7 @@ class XmlMaterialProfile(InstanceContainer): # Map XML file setting names to internal names __material_settings_setting_map = { "print temperature": "default_material_print_temperature", - "heated bed temperature": "material_bed_temperature", + "heated bed temperature": "default_material_bed_temperature", "standby temperature": "material_standby_temperature", "processing temperature graph": "material_flow_temp_graph", "print cooling": "cool_fan_speed", diff --git a/resources/qml/Menus/BuildplateMenu.qml b/resources/qml/Menus/BuildplateMenu.qml new file mode 100644 index 0000000000..756126f60a --- /dev/null +++ b/resources/qml/Menus/BuildplateMenu.qml @@ -0,0 +1,87 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.2 +import QtQuick.Controls 1.1 + +import UM 1.2 as UM +import Cura 1.0 as Cura + +Menu +{ + id: menu + title: "Build plate" + + property int buildplateIndex: 0 + property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0 + property bool isClusterPrinter: + { + if(Cura.MachineManager.printerOutputDevices.length == 0) + { + return false; + } + var clusterSize = Cura.MachineManager.printerOutputDevices[0].clusterSize; + // This is not a cluster printer or the cluster it is just one printer + if(clusterSize == undefined || clusterSize == 1) + { + return false; + } + return true; + } + +// MenuItem +// { +// id: automaticBuildplate +// text: +// { +// if(printerConnected && Cura.MachineManager.buildplateIds.length > buildplateIndex && !isClusterPrinter) +// { +// var buildplateName = Cura.MachineManager.buildplateIds[buildplateIndex] +// return catalog.i18nc("@title:menuitem %1 is the buildplate currently loaded in the printer", "Automatic: %1").arg(buildplateName) +// } +// return "" +// } +// visible: printerConnected && Cura.MachineManager.buildplateIds.length > buildplateIndex && !isClusterPrinter +// onTriggered: +// { +// var buildplateId = Cura.MachineManager.buildplateIds[buildplateIndex] +// var itemIndex = buildplateInstantiator.model.find("name", buildplateId); +// if(itemIndex > -1) +// { +// Cura.MachineManager.setActiveVariantBuildplate(buildplateInstantiator.model.getItem(itemIndex).id); +// } +// } +// } +// +// MenuSeparator +// { +// visible: automaticBuildplate.visible +// } + + Instantiator + { + id: buildplateInstantiator + model: UM.InstanceContainersModel + { + filter: + { + "type": "variant", + "definition": Cura.MachineManager.activeQualityDefinitionId //Only show variants of this machine + } + } + MenuItem { + text: model.name + checkable: true + checked: model.id == Cura.MachineManager.buildplateIds[buildplateIndex] + exclusiveGroup: group + onTriggered: + { + Cura.MachineManager.setActiveVariantBuildplate(model.id); + } + } + onObjectAdded: menu.insertItem(index, object) + onObjectRemoved: menu.removeItem(object) + } + + ExclusiveGroup { id: group } +} diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 3e1e85824a..4ddd3c7ace 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -279,7 +279,7 @@ Column { id: variantRow height: UM.Theme.getSize("sidebar_setup").height - visible: Cura.MachineManager.hasVariants && !sidebar.monitoringPrint && !sidebar.hideSettings + visible: Cura.MachineManager.hasBuildPlateVariant && !sidebar.monitoringPrint && !sidebar.hideSettings anchors { @@ -314,6 +314,46 @@ Column } } + //Buildplate row + Item + { + id: buildplateRow + height: UM.Theme.getSize("sidebar_setup").height + visible: Cura.MachineManager.hasVariantBuildplates && !sidebar.monitoringPrint && !sidebar.hideSettings + + anchors + { + left: parent.left + leftMargin: UM.Theme.getSize("sidebar_margin").width + right: parent.right + rightMargin: UM.Theme.getSize("sidebar_margin").width + } + + Label + { + id: bulidplateLabel + text: catalog.i18nc("@label","Buildplate"); + width: Math.floor(parent.width * 0.45 - UM.Theme.getSize("default_margin").width) + font: UM.Theme.getFont("default"); + color: UM.Theme.getColor("text"); + } + + ToolButton { + id: buildplateSelection + text: Cura.MachineManager.activeVariantBuildplateName + tooltip: Cura.MachineManager.activeVariantBuildplateName + visible: Cura.MachineManager.hasVariantBuildplates + + height: UM.Theme.getSize("setting_control").height + width: Math.floor(parent.width * 0.7 + UM.Theme.getSize("sidebar_margin").width) + anchors.right: parent.right + style: UM.Theme.styles.sidebar_header_button + activeFocusOnPress: true; + + menu: BuildplateMenu + } + } + // Material info row Item { From 2613b4d1a37090e868346c9f7566913835135885 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 9 Jan 2018 16:08:30 +0100 Subject: [PATCH 04/45] CURA-4461 Add menu item for build plates --- resources/qml/Cura.qml | 1 + resources/qml/Menus/BuildplateMenu.qml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index c130cf041b..760cd9c6a6 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -204,6 +204,7 @@ UM.MainWindow onObjectRemoved: settingsMenu.removeItem(object) } + BuildplateMenu { title: catalog.i18nc("@title:menu", "&Build plate"); visible: Cura.MachineManager.hasVariantBuildplates } NozzleMenu { title: Cura.MachineManager.activeDefinitionVariantsName; visible: machineExtruderCount.properties.value <= 1 && Cura.MachineManager.hasVariants } MaterialMenu { title: catalog.i18nc("@title:menu", "&Material"); visible: machineExtruderCount.properties.value <= 1 && Cura.MachineManager.hasMaterials } ProfileMenu { title: catalog.i18nc("@title:menu", "&Profile"); visible: machineExtruderCount.properties.value <= 1 } diff --git a/resources/qml/Menus/BuildplateMenu.qml b/resources/qml/Menus/BuildplateMenu.qml index 756126f60a..10e248aaed 100644 --- a/resources/qml/Menus/BuildplateMenu.qml +++ b/resources/qml/Menus/BuildplateMenu.qml @@ -66,7 +66,7 @@ Menu filter: { "type": "variant", - "definition": Cura.MachineManager.activeQualityDefinitionId //Only show variants of this machine + "definition": Cura.MachineManager.activeDefinitionId //Only show variants of this machine } } MenuItem { From fd46f6968bb5ea11e71eff71e0ac8f68f9f4473e Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 10 Jan 2018 11:42:43 +0100 Subject: [PATCH 05/45] CURA-4461 Show nozzles and buildplates separately depending on the hardware_type metadata in variants --- resources/qml/Menus/BuildplateMenu.qml | 4 ++-- resources/qml/Menus/NozzleMenu.qml | 13 +++++++++++-- resources/qml/SidebarHeader.qml | 8 ++++---- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/resources/qml/Menus/BuildplateMenu.qml b/resources/qml/Menus/BuildplateMenu.qml index 10e248aaed..c379992386 100644 --- a/resources/qml/Menus/BuildplateMenu.qml +++ b/resources/qml/Menus/BuildplateMenu.qml @@ -12,7 +12,6 @@ Menu id: menu title: "Build plate" - property int buildplateIndex: 0 property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0 property bool isClusterPrinter: { @@ -66,13 +65,14 @@ Menu filter: { "type": "variant", + "hardware_type": "buildplate", "definition": Cura.MachineManager.activeDefinitionId //Only show variants of this machine } } MenuItem { text: model.name checkable: true - checked: model.id == Cura.MachineManager.buildplateIds[buildplateIndex] +// checked: model.id == Cura.MachineManager.buildplateIds[buildplateIndex] exclusiveGroup: group onTriggered: { diff --git a/resources/qml/Menus/NozzleMenu.qml b/resources/qml/Menus/NozzleMenu.qml index f70e639872..cc3ea66b07 100644 --- a/resources/qml/Menus/NozzleMenu.qml +++ b/resources/qml/Menus/NozzleMenu.qml @@ -68,8 +68,17 @@ Menu { filter: { - "type": "variant", - "definition": Cura.MachineManager.activeQualityDefinitionId //Only show variants of this machine + var filter_dict = + { + "type": "variant", + "definition": Cura.MachineManager.activeQualityDefinitionId //Only show variants of this machine + } + if (Cura.MachineManager.hasVariantBuildplates) + { + filter_dict["hardware_type"] = "nozzle" + } + + return filter_dict } } MenuItem { diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 4ddd3c7ace..e66da9da5e 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -242,7 +242,7 @@ Column Label { id: materialLabel - text: catalog.i18nc("@label","Material"); + text: catalog.i18nc("@label", "Material"); width: Math.floor(parent.width * 0.45 - UM.Theme.getSize("default_margin").width) font: UM.Theme.getFont("default"); color: UM.Theme.getColor("text"); @@ -279,7 +279,7 @@ Column { id: variantRow height: UM.Theme.getSize("sidebar_setup").height - visible: Cura.MachineManager.hasBuildPlateVariant && !sidebar.monitoringPrint && !sidebar.hideSettings + visible: Cura.MachineManager.hasVariants && !sidebar.monitoringPrint && !sidebar.hideSettings anchors { @@ -332,7 +332,7 @@ Column Label { id: bulidplateLabel - text: catalog.i18nc("@label","Buildplate"); + text: catalog.i18nc("@label", "Build plate"); width: Math.floor(parent.width * 0.45 - UM.Theme.getSize("default_margin").width) font: UM.Theme.getFont("default"); color: UM.Theme.getColor("text"); @@ -350,7 +350,7 @@ Column style: UM.Theme.styles.sidebar_header_button activeFocusOnPress: true; - menu: BuildplateMenu + menu: BuildplateMenu {} } } From cea9f359cdc4ec97d4e551535d0b435ba9c8f7c0 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 10 Jan 2018 14:05:38 +0100 Subject: [PATCH 06/45] CURA-4461 Set active buildplate in the global container stack when is changed in the UI. Add a new setting for distinguish between types of build plates. --- cura/Settings/MachineManager.py | 38 +++++++++++++++++++++-- resources/definitions/fdmprinter.def.json | 15 +++++++++ resources/qml/Menus/BuildplateMenu.qml | 5 ++- 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 7662eb64d6..8ec8a5923f 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -50,6 +50,7 @@ class MachineManager(QObject): # Used to store the new containers until after confirming the dialog self._new_variant_container = None + self._new_buildplate_container = None self._new_material_container = None self._new_quality_containers = [] @@ -158,6 +159,10 @@ class MachineManager(QObject): def newVariant(self): return self._new_variant_container + @property + def newBuildplate(self): + return self._new_buildplate_container + @property def newMaterial(self): return self._new_material_container @@ -664,6 +669,14 @@ class MachineManager(QObject): return quality.getId() return "" + @pyqtProperty(str, notify=activeVariantChanged) + def globalVariantId(self) -> str: + if self._global_container_stack: + variant = self._global_container_stack.variant + if variant and not isinstance(variant, type(self._empty_variant_container)): + return variant.getId() + return "" + @pyqtProperty(str, notify = activeQualityChanged) def activeQualityType(self) -> str: if self._active_container_stack: @@ -846,8 +859,24 @@ class MachineManager(QObject): @pyqtSlot(str) def setActiveVariantBuildplate(self, variant_buildplate_id: str): - Logger.log("d", "Attempting to change the active buildplate to %s", variant_buildplate_id) - pass + with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): + containers = ContainerRegistry.getInstance().findInstanceContainers(id = variant_buildplate_id) + if not containers or not self._global_container_stack: + return + Logger.log("d", "Attempting to change the active buildplate to %s", variant_buildplate_id) + old_buildplate = self._global_container_stack.variant + old_material = self._active_container_stack.material + if old_buildplate: + self.blurSettings.emit() + self._new_buildplate_container = containers[0] # self._active_container_stack will be updated with a delay + Logger.log("d", "Active buildplate changed to {active_variant_buildplate_id}".format(active_variant_buildplate_id = containers[0].getId())) + preferred_material_name = None + if old_material: + preferred_material_name = old_material.getName() + preferred_material_id = self._updateMaterialContainer(self._global_container_stack.definition, self._global_container_stack, containers[0], preferred_material_name).id + self.setActiveMaterial(preferred_material_id) + else: + Logger.log("w", "While trying to set the active buildplate, no buildplate was found to replace.") ## set the active quality # \param quality_id The quality_id of either a quality or a quality_changes @@ -926,6 +955,10 @@ class MachineManager(QObject): self._active_container_stack.variant = self._new_variant_container self._new_variant_container = None + if self._new_buildplate_container is not None: + self._global_container_stack.variant = self._new_buildplate_container + self._new_buildplate_container = None + if self._new_material_container is not None: self._active_container_stack.material = self._new_material_container self._new_material_container = None @@ -946,6 +979,7 @@ class MachineManager(QObject): # Used for ignoring any changes when switching between printers (setActiveMachine) def _cancelDelayedActiveContainerStackChanges(self): self._new_material_container = None + self._new_buildplate_container = None self._new_variant_container = None ## Determine the quality and quality changes settings for the current machine for a quality name. diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 61bccbce59..c61f950978 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -154,6 +154,21 @@ "settable_per_extruder": false, "settable_per_meshgroup": false }, + "machine_buildplate_type": + { + "label": "Build Plate Material", + "description": "The material of the build plate installed on the printer.", + "default_value": "glass", + "type": "enum", + "options": + { + "glass": "Glass", + "aluminium": "Aluminium" + }, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false + }, "machine_height": { "label": "Machine Height", diff --git a/resources/qml/Menus/BuildplateMenu.qml b/resources/qml/Menus/BuildplateMenu.qml index c379992386..8807e834ac 100644 --- a/resources/qml/Menus/BuildplateMenu.qml +++ b/resources/qml/Menus/BuildplateMenu.qml @@ -12,6 +12,7 @@ Menu id: menu title: "Build plate" + property int extruderIndex: 0 property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0 property bool isClusterPrinter: { @@ -72,10 +73,12 @@ Menu MenuItem { text: model.name checkable: true -// checked: model.id == Cura.MachineManager.buildplateIds[buildplateIndex] + checked: model.id == Cura.MachineManager.globalVariantId exclusiveGroup: group onTriggered: { + print("Cura.MachineManager.activeDefinitionId", Cura.MachineManager.activeDefinitionId) + print("Cura.MachineManager.allActiveVariantIds[Cura.MachineManager.activeDefinitionId]", JSON.stringify(Cura.MachineManager.globalVariantId)) Cura.MachineManager.setActiveVariantBuildplate(model.id); } } From 0abb2e0d55fa3b626f98b7d607845188f1966ecc Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 10 Jan 2018 15:00:12 +0100 Subject: [PATCH 07/45] CURA-4461 When reading instance containers, just allow a variant in the global stack if it is a buildplate. --- cura/Settings/MachineManager.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 8ec8a5923f..9f14dd471b 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -303,10 +303,11 @@ class MachineManager(QObject): self._global_container_stack.containersChanged.connect(self._onInstanceContainersChanged) self._global_container_stack.propertyChanged.connect(self._onPropertyChanged) - # set the global variant to empty as we now use the extruder stack at all times - CURA-4482 + # Global stack can have only a variant if it is a buildplate global_variant = self._global_container_stack.variant if global_variant != self._empty_variant_container: - self._global_container_stack.setVariant(self._empty_variant_container) + if global_variant.getMetaDataEntry("hardware_type") != "buildplate": + self._global_container_stack.setVariant(self._empty_variant_container) # set the global material to empty as we now use the extruder stack at all times - CURA-4482 global_material = self._global_container_stack.material @@ -865,16 +866,10 @@ class MachineManager(QObject): return Logger.log("d", "Attempting to change the active buildplate to %s", variant_buildplate_id) old_buildplate = self._global_container_stack.variant - old_material = self._active_container_stack.material if old_buildplate: self.blurSettings.emit() self._new_buildplate_container = containers[0] # self._active_container_stack will be updated with a delay Logger.log("d", "Active buildplate changed to {active_variant_buildplate_id}".format(active_variant_buildplate_id = containers[0].getId())) - preferred_material_name = None - if old_material: - preferred_material_name = old_material.getName() - preferred_material_id = self._updateMaterialContainer(self._global_container_stack.definition, self._global_container_stack, containers[0], preferred_material_name).id - self.setActiveMaterial(preferred_material_id) else: Logger.log("w", "While trying to set the active buildplate, no buildplate was found to replace.") From ff10af905cf70f23769f9f5d0aec2f9d9d538ffa Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 10 Jan 2018 16:04:30 +0100 Subject: [PATCH 08/45] CURA-4461 Add code to set the default preferred buildplate when adding a new machine that has different buildplates. --- cura/Settings/CuraContainerStack.py | 45 +++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/cura/Settings/CuraContainerStack.py b/cura/Settings/CuraContainerStack.py index 8e13b24358..d194080778 100755 --- a/cura/Settings/CuraContainerStack.py +++ b/cura/Settings/CuraContainerStack.py @@ -435,6 +435,51 @@ class CuraContainerStack(ContainerStack): Logger.log("w", "Could not find a valid default variant for stack {stack}", stack = self.id) return None + ## Find the global variant that should be used as "default". This is used for the buildplates. + # + # This will search for variants that match the current definition and pick the preferred one, + # if specified by the machine definition. + # + # The following criteria are used to find the default global variant: + # - If the machine definition does not have a metadata entry "has_variant_buildplates" set to True, return None + # - The definition of the variant should be the same as the machine definition for this stack. + # - The container should have a metadata entry "type" with value "variant" and "hardware_type" with value "buildplate". + # - If the machine definition has a metadata entry "preferred_variant_buildplate", filter the variant IDs based on that. + # + # \return The container that should be used as default, or None if nothing was found or the machine does not use variants. + # + # \note This method assumes the stack has a valid machine definition. + def findDefaultVariantBuildplate(self) -> Optional[ContainerInterface]: + definition = self._getMachineDefinition() + # has_variant_buildplates can be overridden in other containers and stacks. + # In the case of UM2, it is overridden in the GlobalStack + if not self.getMetaDataEntry("has_variant_buildplates"): + # If the machine does not use variants, we should never set a variant. + return None + + # First add any variant. Later, overwrite with preference if the preference is valid. + variant = None + definition_id = self._findInstanceContainerDefinitionId(definition) + variants = ContainerRegistry.getInstance().findInstanceContainers(definition = definition_id, type = "variant", hardware_type = "buildplate") + if variants: + variant = variants[0] + + preferred_variant_buildplate_id = definition.getMetaDataEntry("preferred_variant_buildplate") + if preferred_variant_buildplate_id: + preferred_variant_buildplates = ContainerRegistry.getInstance().findInstanceContainers(id = preferred_variant_buildplate_id, definition = definition_id, type = "variant") + if preferred_variant_buildplates: + variant = preferred_variant_buildplates[0] + else: + Logger.log("w", "The preferred variant buildplate \"{variant}\" of stack {stack} does not exist or is not a variant.", + variant = preferred_variant_buildplate_id, stack = self.id) + # And leave it at the default variant. + + if variant: + return variant + + Logger.log("w", "Could not find a valid default buildplate variant for stack {stack}", stack = self.id) + return None + ## Find the material that should be used as "default" material. # # This will search for materials that match the current definition and pick the preferred one, From 10320b7f2e5aba93849075ce2d333e2cff68adcd Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 10 Jan 2018 17:05:22 +0100 Subject: [PATCH 09/45] CURA-4461 Remove debug outputs --- resources/qml/Menus/BuildplateMenu.qml | 2 -- 1 file changed, 2 deletions(-) diff --git a/resources/qml/Menus/BuildplateMenu.qml b/resources/qml/Menus/BuildplateMenu.qml index 8807e834ac..89a5e6df77 100644 --- a/resources/qml/Menus/BuildplateMenu.qml +++ b/resources/qml/Menus/BuildplateMenu.qml @@ -77,8 +77,6 @@ Menu exclusiveGroup: group onTriggered: { - print("Cura.MachineManager.activeDefinitionId", Cura.MachineManager.activeDefinitionId) - print("Cura.MachineManager.allActiveVariantIds[Cura.MachineManager.activeDefinitionId]", JSON.stringify(Cura.MachineManager.globalVariantId)) Cura.MachineManager.setActiveVariantBuildplate(model.id); } } From 3a01a407cf0689927b8ee1b970b16ffdfc70dbdf Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Thu, 11 Jan 2018 09:16:11 +0100 Subject: [PATCH 10/45] CURA-4461 Set default variant builplate when the new printer is added --- cura/Settings/CuraContainerStack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Settings/CuraContainerStack.py b/cura/Settings/CuraContainerStack.py index d194080778..ff1e3fdd76 100755 --- a/cura/Settings/CuraContainerStack.py +++ b/cura/Settings/CuraContainerStack.py @@ -199,7 +199,7 @@ class CuraContainerStack(ContainerStack): def setVariantById(self, new_variant_id: str) -> None: variant = self._empty_variant if new_variant_id == "default": - new_variant = self.findDefaultVariant() + new_variant = self.findDefaultVariantBuildplate() if self.getMetaDataEntry("type") == "machine" else self.findDefaultVariant() if new_variant: variant = new_variant else: From e5e6da297059c882ee7ef12df61faa48665dff05 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Thu, 11 Jan 2018 09:49:07 +0100 Subject: [PATCH 11/45] Change comments --- cura/Settings/CuraContainerStack.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cura/Settings/CuraContainerStack.py b/cura/Settings/CuraContainerStack.py index ff1e3fdd76..b97bb3314e 100755 --- a/cura/Settings/CuraContainerStack.py +++ b/cura/Settings/CuraContainerStack.py @@ -144,7 +144,7 @@ class CuraContainerStack(ContainerStack): ## Set the material container. # - # \param new_quality_changes The new material container. It is expected to have a "type" metadata entry with the value "quality_changes". + # \param new_material The new material container. It is expected to have a "type" metadata entry with the value "material". def setMaterial(self, new_material: InstanceContainer, postpone_emit = False) -> None: self.replaceContainer(_ContainerIndexes.Material, new_material, postpone_emit = postpone_emit) @@ -155,7 +155,7 @@ class CuraContainerStack(ContainerStack): # to whatever the machine definition specifies as "preferred" container, or a fallback value. See findDefaultMaterial # for details. # - # \param new_quality_changes_id The ID of the new material container. + # \param new_material_id The ID of the new material container. # # \throws Exceptions.InvalidContainerError Raised when no container could be found with the specified ID. def setMaterialById(self, new_material_id: str) -> None: @@ -182,7 +182,7 @@ class CuraContainerStack(ContainerStack): ## Set the variant container. # - # \param new_quality_changes The new variant container. It is expected to have a "type" metadata entry with the value "quality_changes". + # \param new_variant The new variant container. It is expected to have a "type" metadata entry with the value "variant". def setVariant(self, new_variant: InstanceContainer) -> None: self.replaceContainer(_ContainerIndexes.Variant, new_variant) @@ -193,7 +193,7 @@ class CuraContainerStack(ContainerStack): # to whatever the machine definition specifies as "preferred" container, or a fallback value. See findDefaultVariant # for details. # - # \param new_quality_changes_id The ID of the new variant container. + # \param new_variant_id The ID of the new variant container. # # \throws Exceptions.InvalidContainerError Raised when no container could be found with the specified ID. def setVariantById(self, new_variant_id: str) -> None: @@ -220,13 +220,13 @@ class CuraContainerStack(ContainerStack): ## Set the definition changes container. # - # \param new_quality_changes The new definition changes container. It is expected to have a "type" metadata entry with the value "quality_changes". + # \param new_definition_changes The new definition changes container. It is expected to have a "type" metadata entry with the value "definition_changes". def setDefinitionChanges(self, new_definition_changes: InstanceContainer) -> None: self.replaceContainer(_ContainerIndexes.DefinitionChanges, new_definition_changes) ## Set the definition changes container by an ID. # - # \param new_quality_changes_id The ID of the new definition changes container. + # \param new_definition_changes_id The ID of the new definition changes container. # # \throws Exceptions.InvalidContainerError Raised when no container could be found with the specified ID. def setDefinitionChangesById(self, new_definition_changes_id: str) -> None: @@ -245,13 +245,13 @@ class CuraContainerStack(ContainerStack): ## Set the definition container. # - # \param new_quality_changes The new definition container. It is expected to have a "type" metadata entry with the value "quality_changes". + # \param new_definition The new definition container. It is expected to have a "type" metadata entry with the value "definition". def setDefinition(self, new_definition: DefinitionContainerInterface) -> None: self.replaceContainer(_ContainerIndexes.Definition, new_definition) ## Set the definition container by an ID. # - # \param new_quality_changes_id The ID of the new definition container. + # \param new_definition_id The ID of the new definition container. # # \throws Exceptions.InvalidContainerError Raised when no container could be found with the specified ID. def setDefinitionById(self, new_definition_id: str) -> None: From a2089c6afd9f6a5201c7d4e19ead7ad591e6e9e8 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Thu, 11 Jan 2018 09:49:48 +0100 Subject: [PATCH 12/45] CURA-4461 Force set the active quality as it is when changing the buildplate type, so the values are updated --- cura/Settings/MachineManager.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 9f14dd471b..526a9ab1b0 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -870,6 +870,9 @@ class MachineManager(QObject): self.blurSettings.emit() self._new_buildplate_container = containers[0] # self._active_container_stack will be updated with a delay Logger.log("d", "Active buildplate changed to {active_variant_buildplate_id}".format(active_variant_buildplate_id = containers[0].getId())) + + # Force set the active quality as it is so the values are updated + self.setActiveQuality(self._active_container_stack.quality.getId()) else: Logger.log("w", "While trying to set the active buildplate, no buildplate was found to replace.") From de98a62dc88bfc2e15b6dbf2b5ba94188562e06d Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Thu, 11 Jan 2018 13:03:35 +0100 Subject: [PATCH 13/45] CURA-4461 Read buildplate id from the printer and set the automatic option --- cura/PrinterOutputDevice.py | 20 +++++++ .../NetworkPrinterOutputDevice.py | 2 + resources/qml/Menus/BuildplateMenu.qml | 57 +++++++++---------- 3 files changed, 50 insertions(+), 29 deletions(-) diff --git a/cura/PrinterOutputDevice.py b/cura/PrinterOutputDevice.py index b147019b37..5f9e000856 100644 --- a/cura/PrinterOutputDevice.py +++ b/cura/PrinterOutputDevice.py @@ -36,6 +36,7 @@ class PrinterOutputDevice(QObject, OutputDevice): self._target_hotend_temperatures = [0] * self._num_extruders self._material_ids = [""] * self._num_extruders self._hotend_ids = [""] * self._num_extruders + self._buildplate_id = "" self._progress = 0 self._head_x = 0 self._head_y = 0 @@ -99,6 +100,9 @@ class PrinterOutputDevice(QObject, OutputDevice): # Signal to be emitted when either of the hotend ids is changed hotendIdChanged = pyqtSignal(int, str, arguments = ["index", "id"]) + # Signal to be emitted when the buildplate is changed + buildplateChanged = pyqtSignal() + # Signal that is emitted every time connection state is changed. # it also sends it's own device_id (for convenience sake) connectionStateChanged = pyqtSignal(str) @@ -495,6 +499,22 @@ class PrinterOutputDevice(QObject, OutputDevice): self._hotend_ids[index] = None self.hotendIdChanged.emit(index, None) + @pyqtProperty(str, notify = buildplateChanged) + def buildplateId(self): + return self._buildplate_id + + ## Protected setter for the current buildplate id. + # /param buildplate_id id of the buildplate + def _setBuildplateId(self, buildplate_id): + if buildplate_id and buildplate_id != self._buildplate_id: + Logger.log("d", "Setting buildplate id to %s." % (buildplate_id)) + self._buildplate_id = buildplate_id + self.buildplateChanged.emit(buildplate_id) + elif not buildplate_id: + Logger.log("d", "Removing buildplate id.") + self._buildplate_id = None + self.buildplateChanged.emit(None) + ## Let the user decide if the hotends and/or material should be synced with the printer # NB: the UX needs to be implemented by the plugin def materialHotendChangedMessage(self, callback): diff --git a/plugins/UM3NetworkPrinting/NetworkPrinterOutputDevice.py b/plugins/UM3NetworkPrinting/NetworkPrinterOutputDevice.py index 6b8946b755..e075eaab00 100755 --- a/plugins/UM3NetworkPrinting/NetworkPrinterOutputDevice.py +++ b/plugins/UM3NetworkPrinting/NetworkPrinterOutputDevice.py @@ -583,6 +583,8 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice): hotend_id = "" self._setHotendId(index, hotend_id) + # TODO Set the buildplate id depending on the info from the printer. To be discussed... + bed_temperatures = self._json_printer_state["bed"]["temperature"] self._setBedTemperature(bed_temperatures["current"]) self._updateTargetBedTemperature(bed_temperatures["target"]) diff --git a/resources/qml/Menus/BuildplateMenu.qml b/resources/qml/Menus/BuildplateMenu.qml index 89a5e6df77..908cccf1c8 100644 --- a/resources/qml/Menus/BuildplateMenu.qml +++ b/resources/qml/Menus/BuildplateMenu.qml @@ -12,7 +12,6 @@ Menu id: menu title: "Build plate" - property int extruderIndex: 0 property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0 property bool isClusterPrinter: { @@ -29,34 +28,34 @@ Menu return true; } -// MenuItem -// { -// id: automaticBuildplate -// text: -// { -// if(printerConnected && Cura.MachineManager.buildplateIds.length > buildplateIndex && !isClusterPrinter) -// { -// var buildplateName = Cura.MachineManager.buildplateIds[buildplateIndex] -// return catalog.i18nc("@title:menuitem %1 is the buildplate currently loaded in the printer", "Automatic: %1").arg(buildplateName) -// } -// return "" -// } -// visible: printerConnected && Cura.MachineManager.buildplateIds.length > buildplateIndex && !isClusterPrinter -// onTriggered: -// { -// var buildplateId = Cura.MachineManager.buildplateIds[buildplateIndex] -// var itemIndex = buildplateInstantiator.model.find("name", buildplateId); -// if(itemIndex > -1) -// { -// Cura.MachineManager.setActiveVariantBuildplate(buildplateInstantiator.model.getItem(itemIndex).id); -// } -// } -// } -// -// MenuSeparator -// { -// visible: automaticBuildplate.visible -// } + MenuItem + { + id: automaticBuildplate + text: + { + if(printerConnected && Cura.MachineManager.printerOutputDevices[0].buildplateId != "" && !isClusterPrinter) + { + var buildplateName = Cura.MachineManager.printerOutputDevices[0].buildplateId + return catalog.i18nc("@title:menuitem %1 is the buildplate currently loaded in the printer", "Automatic: %1").arg(buildplateName) + } + return "" + } + visible: printerConnected && Cura.MachineManager.printerOutputDevices[0].buildplateId != "" && !isClusterPrinter + onTriggered: + { + var buildplateId = Cura.MachineManager.printerOutputDevices[0].buildplateId + var itemIndex = buildplateInstantiator.model.find("name", buildplateId) + if(itemIndex > -1) + { + Cura.MachineManager.setActiveVariantBuildplate(buildplateInstantiator.model.getItem(itemIndex).id) + } + } + } + + MenuSeparator + { + visible: automaticBuildplate.visible + } Instantiator { From 10c9ea68b49b910c8a0d34ba73e4f96bce4d0dec Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Thu, 11 Jan 2018 13:53:09 +0100 Subject: [PATCH 14/45] CURA-4461 Change builplate type's label --- resources/definitions/fdmprinter.def.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index c61f950978..e326ee9d4e 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -163,7 +163,7 @@ "options": { "glass": "Glass", - "aluminium": "Aluminium" + "aluminum": "Aluminum" }, "settable_per_mesh": false, "settable_per_extruder": false, From c3c44e9ac442302b655cc7650c27c7e8118fcc02 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Fri, 12 Jan 2018 16:01:48 +0100 Subject: [PATCH 15/45] Compatibility with materials and buildplates --- .../XmlMaterialProfile/XmlMaterialProfile.py | 197 +++++++++++++++--- 1 file changed, 172 insertions(+), 25 deletions(-) diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index 8e3c25bb23..222939bddd 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -187,6 +187,7 @@ class XmlMaterialProfile(InstanceContainer): machine_container_map = {} machine_nozzle_map = {} + machine_buildplate_map = {} all_containers = registry.findInstanceContainers(GUID = self.getMetaDataEntry("GUID"), base_file = self.getId()) for container in all_containers: @@ -202,6 +203,7 @@ class XmlMaterialProfile(InstanceContainer): variant = container.getMetaDataEntry("variant") if variant: + print("#############variant", variant) machine_nozzle_map[definition_id][variant] = container continue @@ -261,6 +263,34 @@ class XmlMaterialProfile(InstanceContainer): builder.end("hotend") + # Find all buildplate sub-profiles corresponding to this material and machine and add them to this profile. + for buildplate_id, buildplate in machine_buildplate_map[definition_id].items(): + variant_containers = registry.findInstanceContainersMetadata(id = buildplate.getMetaDataEntry("variant")) + if not variant_containers: + continue + + # The buildplate identifier is not the containers name, but its "name". + builder.start("buildplate", {"id": variant_containers[0]["name"]}) + + # Compatible is a special case, as it's added as a meta data entry (instead of an instance). + compatible = buildplate.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 buildplate.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) + + builder.end("buildplate") + builder.end("machine") builder.end("settings") @@ -576,6 +606,74 @@ class XmlMaterialProfile(InstanceContainer): if is_new_material: containers_to_add.append(new_material) + buildplates = machine.iterfind("./um:buildplate", self.__namespaces) + buildplate_map = {} + for buildplate in buildplates: + buildplate_id = buildplate.get("id") + if buildplate_id is None: + continue + + variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata( + id = buildplate_id) + if not variant_containers: + # It is not really properly defined what "ID" is so also search for variants by name. + variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata( + definition = machine_id, name = buildplate_id) + + if not variant_containers: + continue + + buildplate_compatibility = machine_compatibility + buildplate_recommended = machine_compatibility + settings = buildplate.iterfind("./um:setting", self.__namespaces) + for entry in settings: + key = entry.get("key") + if key in self.__unmapped_settings: + if key == "hardware compatible": + buildplate_compatibility = self._parseCompatibleValue(entry.text) + elif key == "hardware recommended": + buildplate_recommended = self._parseCompatibleValue(entry.text) + else: + Logger.log("d", "Unsupported material setting %s", key) + + buildplate_map[buildplate_id] = {} + buildplate_map[buildplate_id]["buildplate_compatible"] = buildplate_compatibility + buildplate_map[buildplate_id]["buildplate_recommended"] = buildplate_recommended + + # # Same as machine compatibility, keep the derived material containers consistent with the parent + # # material + # if ContainerRegistry.getInstance().isLoaded(new_buildplate_id): + # new_buildplate_material = ContainerRegistry.getInstance().findContainers(id = new_buildplate_id)[0] + # is_new_material = False + # else: + # new_buildplate_material = XmlMaterialProfile(new_buildplate_id) + # is_new_material = True + # + # new_buildplate_material.setMetaData(copy.deepcopy(self.getMetaData())) + # new_buildplate_material.getMetaData()["id"] = new_buildplate_id + # new_buildplate_material.getMetaData()["name"] = self.getName() + # new_buildplate_material.getMetaData()["variant"] = variant_containers[0]["id"] + # new_buildplate_material.setDefinition(machine_id) + # # Don't use setMetadata, as that overrides it for all materials with same base file + # new_buildplate_material.getMetaData()["compatible"] = buildplate_compatibility + # new_buildplate_material.getMetaData()["machine_manufacturer"] = machine_manufacturer + # new_buildplate_material.getMetaData()["definition"] = machine_id + # + # cached_buildplate_setting_properties = cached_machine_setting_properties.copy() + # cached_buildplate_setting_properties.update(buildplate_setting_values) + # + # new_buildplate_material.setCachedValues(cached_buildplate_setting_properties) + # + # new_buildplate_material._dirty = False + # + # if is_new_material: + # containers_to_add.append(new_buildplate_material) + + # If no buildplate was found, then the material is created without buildplate information + if not buildplate_map: + buildplate_map[""] = {"buildplate_compatible" : machine_compatibility, + "buildplate_recommended" : machine_compatibility} + hotends = machine.iterfind("./um:hotend", self.__namespaces) for hotend in hotends: hotend_id = hotend.get("id") @@ -603,36 +701,44 @@ class XmlMaterialProfile(InstanceContainer): else: Logger.log("d", "Unsupported material setting %s", key) - new_hotend_id = self.getId() + "_" + machine_id + "_" + hotend_id.replace(" ", "_") + for buildplate_id in buildplate_map: - # Same as machine compatibility, keep the derived material containers consistent with the parent - # material - if ContainerRegistry.getInstance().isLoaded(new_hotend_id): - new_hotend_material = ContainerRegistry.getInstance().findContainers(id = new_hotend_id)[0] - is_new_material = False - else: - new_hotend_material = XmlMaterialProfile(new_hotend_id) - is_new_material = True + new_hotend_id = self.getId() + "_" + machine_id + "_" + hotend_id.replace(" ", "_") + \ + ("_" if buildplate_id != "" else "") + buildplate_id.replace(" ", "_") - new_hotend_material.setMetaData(copy.deepcopy(self.getMetaData())) - new_hotend_material.getMetaData()["id"] = new_hotend_id - new_hotend_material.getMetaData()["name"] = self.getName() - new_hotend_material.getMetaData()["variant"] = variant_containers[0]["id"] - new_hotend_material.setDefinition(machine_id) - # Don't use setMetadata, as that overrides it for all materials with same base file - new_hotend_material.getMetaData()["compatible"] = hotend_compatibility - new_hotend_material.getMetaData()["machine_manufacturer"] = machine_manufacturer - new_hotend_material.getMetaData()["definition"] = machine_id + buildplate_compatibility = buildplate_map[buildplate_id]["buildplate_compatible"] + buildplate_recommended = buildplate_map[buildplate_id]["buildplate_recommended"] - cached_hotend_setting_properties = cached_machine_setting_properties.copy() - cached_hotend_setting_properties.update(hotend_setting_values) + # Same as machine compatibility, keep the derived material containers consistent with the parent + # material + if ContainerRegistry.getInstance().isLoaded(new_hotend_id): + new_hotend_material = ContainerRegistry.getInstance().findContainers(id = new_hotend_id)[0] + is_new_material = False + else: + new_hotend_material = XmlMaterialProfile(new_hotend_id) + is_new_material = True - new_hotend_material.setCachedValues(cached_hotend_setting_properties) + new_hotend_material.setMetaData(copy.deepcopy(self.getMetaData())) + new_hotend_material.getMetaData()["id"] = new_hotend_id + new_hotend_material.getMetaData()["name"] = self.getName() + new_hotend_material.getMetaData()["variant"] = variant_containers[0]["id"] + new_hotend_material.setDefinition(machine_id) + # Don't use setMetadata, as that overrides it for all materials with same base file + new_hotend_material.getMetaData()["compatible"] = hotend_compatibility + new_hotend_material.getMetaData()["buildplate_compatible"] = buildplate_compatibility + new_hotend_material.getMetaData()["buildplate_recommended"] = buildplate_recommended + new_hotend_material.getMetaData()["machine_manufacturer"] = machine_manufacturer + new_hotend_material.getMetaData()["definition"] = machine_id - new_hotend_material._dirty = False + cached_hotend_setting_properties = cached_machine_setting_properties.copy() + cached_hotend_setting_properties.update(hotend_setting_values) - if is_new_material: - containers_to_add.append(new_hotend_material) + new_hotend_material.setCachedValues(cached_hotend_setting_properties) + + new_hotend_material._dirty = False + + if is_new_material: + containers_to_add.append(new_hotend_material) # there is only one ID for a machine. Once we have reached here, it means we have already found # a workable ID for that machine, so there is no need to continue @@ -803,6 +909,46 @@ class XmlMaterialProfile(InstanceContainer): if len(found_materials) == 0: result_metadata.append(new_hotend_material_metadata) + for buildplate in machine.iterfind("./um:buildplate", cls.__namespaces): + buildplate_id = buildplate.get("id") + if buildplate_id is None: + continue + + variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = buildplate_id) + if not variant_containers: + # It is not really properly defined what "ID" is so also search for variants by name. + variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(definition = machine_id, name = buildplate_id) + + buildplate_compatibility = machine_compatibility + for entry in buildplate.iterfind("./um:setting", cls.__namespaces): + key = entry.get("key") + if key == "hardware compatible": + buildplate_compatibility = cls._parseCompatibleValue(entry.text) + + new_buildplate_id = container_id + "_" + machine_id + "_" + buildplate_id.replace(" ", "_") + + # Same as machine compatibility, keep the derived material containers consistent with the parent + # material + found_materials = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = new_buildplate_id) + if found_materials: + new_buildplate_material_metadata = found_materials[0] + else: + new_buildplate_material_metadata = {} + + new_buildplate_material_metadata.update(base_metadata) + if variant_containers: + new_buildplate_material_metadata["variant"] = variant_containers[0]["id"] + else: + new_buildplate_material_metadata["variant"] = buildplate_id + _with_missing_variants.append(new_buildplate_material_metadata) + new_buildplate_material_metadata["compatible"] = buildplate_compatibility + new_buildplate_material_metadata["machine_manufacturer"] = machine_manufacturer + new_buildplate_material_metadata["id"] = new_buildplate_id + new_buildplate_material_metadata["definition"] = machine_id + + if len(found_materials) == 0: + result_metadata.append(new_buildplate_material_metadata) + # there is only one ID for a machine. Once we have reached here, it means we have already found # a workable ID for that machine, so there is no need to continue break @@ -884,7 +1030,8 @@ class XmlMaterialProfile(InstanceContainer): "surface energy": "material_surface_energy" } __unmapped_settings = [ - "hardware compatible" + "hardware compatible", + "hardware recommended" ] __material_properties_setting_map = { "diameter": "material_diameter" From 67ca4d25cd69bae61bf0c00b7cc8dac979610a46 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Mon, 15 Jan 2018 11:35:17 +0100 Subject: [PATCH 16/45] CURA-4461 Deserialize materials with buildplates compatibility --- .../XmlMaterialProfile/XmlMaterialProfile.py | 154 ++++++++---------- 1 file changed, 65 insertions(+), 89 deletions(-) diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index 222939bddd..894377ed82 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -640,35 +640,6 @@ class XmlMaterialProfile(InstanceContainer): buildplate_map[buildplate_id]["buildplate_compatible"] = buildplate_compatibility buildplate_map[buildplate_id]["buildplate_recommended"] = buildplate_recommended - # # Same as machine compatibility, keep the derived material containers consistent with the parent - # # material - # if ContainerRegistry.getInstance().isLoaded(new_buildplate_id): - # new_buildplate_material = ContainerRegistry.getInstance().findContainers(id = new_buildplate_id)[0] - # is_new_material = False - # else: - # new_buildplate_material = XmlMaterialProfile(new_buildplate_id) - # is_new_material = True - # - # new_buildplate_material.setMetaData(copy.deepcopy(self.getMetaData())) - # new_buildplate_material.getMetaData()["id"] = new_buildplate_id - # new_buildplate_material.getMetaData()["name"] = self.getName() - # new_buildplate_material.getMetaData()["variant"] = variant_containers[0]["id"] - # new_buildplate_material.setDefinition(machine_id) - # # Don't use setMetadata, as that overrides it for all materials with same base file - # new_buildplate_material.getMetaData()["compatible"] = buildplate_compatibility - # new_buildplate_material.getMetaData()["machine_manufacturer"] = machine_manufacturer - # new_buildplate_material.getMetaData()["definition"] = machine_id - # - # cached_buildplate_setting_properties = cached_machine_setting_properties.copy() - # cached_buildplate_setting_properties.update(buildplate_setting_values) - # - # new_buildplate_material.setCachedValues(cached_buildplate_setting_properties) - # - # new_buildplate_material._dirty = False - # - # if is_new_material: - # containers_to_add.append(new_buildplate_material) - # If no buildplate was found, then the material is created without buildplate information if not buildplate_map: buildplate_map[""] = {"buildplate_compatible" : machine_compatibility, @@ -703,8 +674,8 @@ class XmlMaterialProfile(InstanceContainer): for buildplate_id in buildplate_map: - new_hotend_id = self.getId() + "_" + machine_id + "_" + hotend_id.replace(" ", "_") + \ - ("_" if buildplate_id != "" else "") + buildplate_id.replace(" ", "_") + new_hotend_id = self.getId() + "_" + machine_id + ("_" if buildplate_id != "" else "") + \ + buildplate_id.replace(" ", "_") + "_" + hotend_id.replace(" ", "_") buildplate_compatibility = buildplate_map[buildplate_id]["buildplate_compatible"] buildplate_recommended = buildplate_map[buildplate_id]["buildplate_recommended"] @@ -729,6 +700,8 @@ class XmlMaterialProfile(InstanceContainer): new_hotend_material.getMetaData()["buildplate_recommended"] = buildplate_recommended new_hotend_material.getMetaData()["machine_manufacturer"] = machine_manufacturer new_hotend_material.getMetaData()["definition"] = machine_id + # if machine_id == "ultimaker3_xl" and self.getId() == "generic_abs": + # print("&&&&&&&&&&&& HotendID", new_hotend_id) cached_hotend_setting_properties = cached_machine_setting_properties.copy() cached_hotend_setting_properties.update(hotend_setting_values) @@ -869,6 +842,40 @@ class XmlMaterialProfile(InstanceContainer): if len(found_materials) == 0: #This is a new material. result_metadata.append(new_material_metadata) + buildplates = machine.iterfind("./um:buildplate", cls.__namespaces) + buildplate_map = {} + for buildplate in buildplates: + buildplate_id = buildplate.get("id") + if buildplate_id is None: + continue + + variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = buildplate_id) + if not variant_containers: + # It is not really properly defined what "ID" is so also search for variants by name. + variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(definition = machine_id, name = buildplate_id) + + if not variant_containers: + continue + + buildplate_compatibility = machine_compatibility + buildplate_recommended = machine_compatibility + settings = buildplate.iterfind("./um:setting", cls.__namespaces) + for entry in settings: + key = entry.get("key") + if key == "hardware compatible": + buildplate_compatibility = cls._parseCompatibleValue(entry.text) + elif key == "hardware recommended": + buildplate_recommended = cls._parseCompatibleValue(entry.text) + + buildplate_map[buildplate_id] = {} + buildplate_map[buildplate_id]["buildplate_compatible"] = buildplate_compatibility + buildplate_map[buildplate_id]["buildplate_recommended"] = buildplate_recommended + + # If no buildplate was found, then the material is created without buildplate information + if not buildplate_map: + buildplate_map[""] = {"buildplate_compatible": machine_compatibility, + "buildplate_recommended": machine_compatibility} + for hotend in machine.iterfind("./um:hotend", cls.__namespaces): hotend_id = hotend.get("id") if hotend_id is None: @@ -885,69 +892,38 @@ class XmlMaterialProfile(InstanceContainer): if key == "hardware compatible": hotend_compatibility = cls._parseCompatibleValue(entry.text) - new_hotend_id = container_id + "_" + machine_id + "_" + hotend_id.replace(" ", "_") + for buildplate_id in buildplate_map: - # Same as machine compatibility, keep the derived material containers consistent with the parent - # material - found_materials = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = new_hotend_id) - if found_materials: - new_hotend_material_metadata = found_materials[0] - else: - new_hotend_material_metadata = {} + new_hotend_id = container_id + "_" + machine_id + ("_" if buildplate_id != "" else "") + \ + buildplate_id.replace(" ", "_") + "_" + hotend_id.replace(" ", "_") - new_hotend_material_metadata.update(base_metadata) - if variant_containers: - new_hotend_material_metadata["variant"] = variant_containers[0]["id"] - else: - new_hotend_material_metadata["variant"] = hotend_id - _with_missing_variants.append(new_hotend_material_metadata) - new_hotend_material_metadata["compatible"] = hotend_compatibility - new_hotend_material_metadata["machine_manufacturer"] = machine_manufacturer - new_hotend_material_metadata["id"] = new_hotend_id - new_hotend_material_metadata["definition"] = machine_id + buildplate_compatibility = buildplate_map[buildplate_id]["buildplate_compatible"] + buildplate_recommended = buildplate_map[buildplate_id]["buildplate_recommended"] - if len(found_materials) == 0: - result_metadata.append(new_hotend_material_metadata) + # Same as machine compatibility, keep the derived material containers consistent with the parent material + found_materials = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = new_hotend_id) + if found_materials: + new_hotend_material_metadata = found_materials[0] + else: + new_hotend_material_metadata = {} - for buildplate in machine.iterfind("./um:buildplate", cls.__namespaces): - buildplate_id = buildplate.get("id") - if buildplate_id is None: - continue + new_hotend_material_metadata.update(base_metadata) + if variant_containers: + new_hotend_material_metadata["variant"] = variant_containers[0]["id"] + else: + new_hotend_material_metadata["variant"] = hotend_id + _with_missing_variants.append(new_hotend_material_metadata) + new_hotend_material_metadata["compatible"] = hotend_compatibility + new_hotend_material_metadata["buildplate_compatible"] = buildplate_compatibility + new_hotend_material_metadata["buildplate_recommended"] = buildplate_recommended + new_hotend_material_metadata["machine_manufacturer"] = machine_manufacturer + new_hotend_material_metadata["id"] = new_hotend_id + new_hotend_material_metadata["definition"] = machine_id + # if machine_id == "ultimaker3_xl" and container_id == "generic_abs": + # print("############# HotendID", new_hotend_id) - variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = buildplate_id) - if not variant_containers: - # It is not really properly defined what "ID" is so also search for variants by name. - variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(definition = machine_id, name = buildplate_id) - - buildplate_compatibility = machine_compatibility - for entry in buildplate.iterfind("./um:setting", cls.__namespaces): - key = entry.get("key") - if key == "hardware compatible": - buildplate_compatibility = cls._parseCompatibleValue(entry.text) - - new_buildplate_id = container_id + "_" + machine_id + "_" + buildplate_id.replace(" ", "_") - - # Same as machine compatibility, keep the derived material containers consistent with the parent - # material - found_materials = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = new_buildplate_id) - if found_materials: - new_buildplate_material_metadata = found_materials[0] - else: - new_buildplate_material_metadata = {} - - new_buildplate_material_metadata.update(base_metadata) - if variant_containers: - new_buildplate_material_metadata["variant"] = variant_containers[0]["id"] - else: - new_buildplate_material_metadata["variant"] = buildplate_id - _with_missing_variants.append(new_buildplate_material_metadata) - new_buildplate_material_metadata["compatible"] = buildplate_compatibility - new_buildplate_material_metadata["machine_manufacturer"] = machine_manufacturer - new_buildplate_material_metadata["id"] = new_buildplate_id - new_buildplate_material_metadata["definition"] = machine_id - - if len(found_materials) == 0: - result_metadata.append(new_buildplate_material_metadata) + if len(found_materials) == 0: + result_metadata.append(new_hotend_material_metadata) # there is only one ID for a machine. Once we have reached here, it means we have already found # a workable ID for that machine, so there is no need to continue From badf5a9043dd8cb7649faab3b758384f3044392b Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Mon, 15 Jan 2018 14:31:52 +0100 Subject: [PATCH 17/45] CURA-4461 Store buildplate compatibility in the material profile --- .../XmlMaterialProfile/XmlMaterialProfile.py | 138 ++++++++---------- 1 file changed, 57 insertions(+), 81 deletions(-) diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index 894377ed82..4babbeae77 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -606,8 +606,11 @@ class XmlMaterialProfile(InstanceContainer): if is_new_material: containers_to_add.append(new_material) + # Find the buildplates compatibility buildplates = machine.iterfind("./um:buildplate", self.__namespaces) buildplate_map = {} + buildplate_map["buildplate_compatible"] = {} + buildplate_map["buildplate_recommended"] = {} for buildplate in buildplates: buildplate_id = buildplate.get("id") if buildplate_id is None: @@ -636,14 +639,8 @@ class XmlMaterialProfile(InstanceContainer): else: Logger.log("d", "Unsupported material setting %s", key) - buildplate_map[buildplate_id] = {} - buildplate_map[buildplate_id]["buildplate_compatible"] = buildplate_compatibility - buildplate_map[buildplate_id]["buildplate_recommended"] = buildplate_recommended - - # If no buildplate was found, then the material is created without buildplate information - if not buildplate_map: - buildplate_map[""] = {"buildplate_compatible" : machine_compatibility, - "buildplate_recommended" : machine_compatibility} + buildplate_map["buildplate_compatible"][buildplate_id] = buildplate_compatibility + buildplate_map["buildplate_recommended"][buildplate_id] = buildplate_recommended hotends = machine.iterfind("./um:hotend", self.__namespaces) for hotend in hotends: @@ -672,46 +669,38 @@ class XmlMaterialProfile(InstanceContainer): else: Logger.log("d", "Unsupported material setting %s", key) - for buildplate_id in buildplate_map: + new_hotend_id = self.getId() + "_" + machine_id + "_" + hotend_id.replace(" ", "_") - new_hotend_id = self.getId() + "_" + machine_id + ("_" if buildplate_id != "" else "") + \ - buildplate_id.replace(" ", "_") + "_" + hotend_id.replace(" ", "_") + # Same as machine compatibility, keep the derived material containers consistent with the parent material + if ContainerRegistry.getInstance().isLoaded(new_hotend_id): + new_hotend_material = ContainerRegistry.getInstance().findContainers(id = new_hotend_id)[0] + is_new_material = False + else: + new_hotend_material = XmlMaterialProfile(new_hotend_id) + is_new_material = True - buildplate_compatibility = buildplate_map[buildplate_id]["buildplate_compatible"] - buildplate_recommended = buildplate_map[buildplate_id]["buildplate_recommended"] + new_hotend_material.setMetaData(copy.deepcopy(self.getMetaData())) + new_hotend_material.getMetaData()["id"] = new_hotend_id + new_hotend_material.getMetaData()["name"] = self.getName() + new_hotend_material.getMetaData()["variant"] = variant_containers[0]["id"] + new_hotend_material.setDefinition(machine_id) + # Don't use setMetadata, as that overrides it for all materials with same base file + new_hotend_material.getMetaData()["compatible"] = hotend_compatibility + new_hotend_material.getMetaData()["machine_manufacturer"] = machine_manufacturer + new_hotend_material.getMetaData()["definition"] = machine_id + if buildplate_map["buildplate_compatible"]: + new_hotend_material.getMetaData()["buildplate_compatible"] = buildplate_map["buildplate_compatible"] + new_hotend_material.getMetaData()["buildplate_recommended"] = buildplate_map["buildplate_recommended"] - # Same as machine compatibility, keep the derived material containers consistent with the parent - # material - if ContainerRegistry.getInstance().isLoaded(new_hotend_id): - new_hotend_material = ContainerRegistry.getInstance().findContainers(id = new_hotend_id)[0] - is_new_material = False - else: - new_hotend_material = XmlMaterialProfile(new_hotend_id) - is_new_material = True + cached_hotend_setting_properties = cached_machine_setting_properties.copy() + cached_hotend_setting_properties.update(hotend_setting_values) - new_hotend_material.setMetaData(copy.deepcopy(self.getMetaData())) - new_hotend_material.getMetaData()["id"] = new_hotend_id - new_hotend_material.getMetaData()["name"] = self.getName() - new_hotend_material.getMetaData()["variant"] = variant_containers[0]["id"] - new_hotend_material.setDefinition(machine_id) - # Don't use setMetadata, as that overrides it for all materials with same base file - new_hotend_material.getMetaData()["compatible"] = hotend_compatibility - new_hotend_material.getMetaData()["buildplate_compatible"] = buildplate_compatibility - new_hotend_material.getMetaData()["buildplate_recommended"] = buildplate_recommended - new_hotend_material.getMetaData()["machine_manufacturer"] = machine_manufacturer - new_hotend_material.getMetaData()["definition"] = machine_id - # if machine_id == "ultimaker3_xl" and self.getId() == "generic_abs": - # print("&&&&&&&&&&&& HotendID", new_hotend_id) + new_hotend_material.setCachedValues(cached_hotend_setting_properties) - cached_hotend_setting_properties = cached_machine_setting_properties.copy() - cached_hotend_setting_properties.update(hotend_setting_values) + new_hotend_material._dirty = False - new_hotend_material.setCachedValues(cached_hotend_setting_properties) - - new_hotend_material._dirty = False - - if is_new_material: - containers_to_add.append(new_hotend_material) + if is_new_material: + containers_to_add.append(new_hotend_material) # there is only one ID for a machine. Once we have reached here, it means we have already found # a workable ID for that machine, so there is no need to continue @@ -844,6 +833,8 @@ class XmlMaterialProfile(InstanceContainer): buildplates = machine.iterfind("./um:buildplate", cls.__namespaces) buildplate_map = {} + buildplate_map["buildplate_compatible"] = {} + buildplate_map["buildplate_recommended"] = {} for buildplate in buildplates: buildplate_id = buildplate.get("id") if buildplate_id is None: @@ -857,8 +848,6 @@ class XmlMaterialProfile(InstanceContainer): if not variant_containers: continue - buildplate_compatibility = machine_compatibility - buildplate_recommended = machine_compatibility settings = buildplate.iterfind("./um:setting", cls.__namespaces) for entry in settings: key = entry.get("key") @@ -867,14 +856,8 @@ class XmlMaterialProfile(InstanceContainer): elif key == "hardware recommended": buildplate_recommended = cls._parseCompatibleValue(entry.text) - buildplate_map[buildplate_id] = {} - buildplate_map[buildplate_id]["buildplate_compatible"] = buildplate_compatibility - buildplate_map[buildplate_id]["buildplate_recommended"] = buildplate_recommended - - # If no buildplate was found, then the material is created without buildplate information - if not buildplate_map: - buildplate_map[""] = {"buildplate_compatible": machine_compatibility, - "buildplate_recommended": machine_compatibility} + buildplate_map["buildplate_compatible"][buildplate_id] = buildplate_map["buildplate_compatible"] + buildplate_map["buildplate_recommended"][buildplate_id] = buildplate_map["buildplate_recommended"] for hotend in machine.iterfind("./um:hotend", cls.__namespaces): hotend_id = hotend.get("id") @@ -892,38 +875,31 @@ class XmlMaterialProfile(InstanceContainer): if key == "hardware compatible": hotend_compatibility = cls._parseCompatibleValue(entry.text) - for buildplate_id in buildplate_map: + new_hotend_id = container_id + "_" + machine_id + "_" + hotend_id.replace(" ", "_") - new_hotend_id = container_id + "_" + machine_id + ("_" if buildplate_id != "" else "") + \ - buildplate_id.replace(" ", "_") + "_" + hotend_id.replace(" ", "_") + # Same as machine compatibility, keep the derived material containers consistent with the parent material + found_materials = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = new_hotend_id) + if found_materials: + new_hotend_material_metadata = found_materials[0] + else: + new_hotend_material_metadata = {} - buildplate_compatibility = buildplate_map[buildplate_id]["buildplate_compatible"] - buildplate_recommended = buildplate_map[buildplate_id]["buildplate_recommended"] + new_hotend_material_metadata.update(base_metadata) + if variant_containers: + new_hotend_material_metadata["variant"] = variant_containers[0]["id"] + else: + new_hotend_material_metadata["variant"] = hotend_id + _with_missing_variants.append(new_hotend_material_metadata) + new_hotend_material_metadata["compatible"] = hotend_compatibility + new_hotend_material_metadata["machine_manufacturer"] = machine_manufacturer + new_hotend_material_metadata["id"] = new_hotend_id + new_hotend_material_metadata["definition"] = machine_id + if buildplate_map["buildplate_compatible"]: + new_hotend_material_metadata["buildplate_compatible"] = buildplate_map["buildplate_compatible"] + new_hotend_material_metadata["buildplate_recommended"] = buildplate_map["buildplate_recommended"] - # Same as machine compatibility, keep the derived material containers consistent with the parent material - found_materials = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = new_hotend_id) - if found_materials: - new_hotend_material_metadata = found_materials[0] - else: - new_hotend_material_metadata = {} - - new_hotend_material_metadata.update(base_metadata) - if variant_containers: - new_hotend_material_metadata["variant"] = variant_containers[0]["id"] - else: - new_hotend_material_metadata["variant"] = hotend_id - _with_missing_variants.append(new_hotend_material_metadata) - new_hotend_material_metadata["compatible"] = hotend_compatibility - new_hotend_material_metadata["buildplate_compatible"] = buildplate_compatibility - new_hotend_material_metadata["buildplate_recommended"] = buildplate_recommended - new_hotend_material_metadata["machine_manufacturer"] = machine_manufacturer - new_hotend_material_metadata["id"] = new_hotend_id - new_hotend_material_metadata["definition"] = machine_id - # if machine_id == "ultimaker3_xl" and container_id == "generic_abs": - # print("############# HotendID", new_hotend_id) - - if len(found_materials) == 0: - result_metadata.append(new_hotend_material_metadata) + if len(found_materials) == 0: + result_metadata.append(new_hotend_material_metadata) # there is only one ID for a machine. Once we have reached here, it means we have already found # a workable ID for that machine, so there is no need to continue From e51eaab08e3723d23da464f6175b8cb0687b38d7 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Mon, 15 Jan 2018 16:33:15 +0100 Subject: [PATCH 18/45] CURA-4461 Don't allow Cura to Slice when the buildplate is not compatible with the material --- plugins/CuraEngineBackend/StartSliceJob.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index b0e19e7f39..4c27485883 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -122,6 +122,11 @@ class StartSliceJob(Job): self.setResult(StartJobResult.BuildPlateError) return + # Don't slice if the buildplate or the nozzle type is incompatible with the materials + if not Application.getInstance().getMachineManager().variantBuildplateCompatible: + self.setResult(StartJobResult.MaterialIncompatible) + return + for extruder_stack in ExtruderManager.getInstance().getMachineExtruders(stack.getId()): material = extruder_stack.findContainer({"type": "material"}) if material: From 0f497545bc5a88715b0ffd0db7f99d991c4b144c Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Mon, 15 Jan 2018 18:00:49 +0100 Subject: [PATCH 19/45] CURA-4461 Create properties to know when a buildplate is compatible or usable. Show colors indicating the compatibility. Also minor fixes --- cura/Settings/MachineManager.py | 43 +++++++++++++++++++++- plugins/CuraEngineBackend/StartSliceJob.py | 3 +- resources/qml/SidebarHeader.qml | 3 ++ 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 526a9ab1b0..56c43c7f3d 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -872,7 +872,7 @@ class MachineManager(QObject): Logger.log("d", "Active buildplate changed to {active_variant_buildplate_id}".format(active_variant_buildplate_id = containers[0].getId())) # Force set the active quality as it is so the values are updated - self.setActiveQuality(self._active_container_stack.quality.getId()) + self.setActiveMaterial(self._active_container_stack.material.getId()) else: Logger.log("w", "While trying to set the active buildplate, no buildplate was found to replace.") @@ -1262,6 +1262,47 @@ class MachineManager(QObject): return Util.parseBool(self._global_container_stack.getMetaDataEntry("has_variant_buildplates", False)) return False + ## The selected buildplate is compatible if it is compatible with all the materials in all the extruders + @pyqtProperty(bool, notify = activeMaterialChanged) + def variantBuildplateCompatible(self) -> bool: + if not self._global_container_stack: + return True + + buildplate_compatible = True # It is compatible by default + extruder_stacks = self._global_container_stack.extruders.values() + for stack in extruder_stacks: + material_container = stack.material + if material_container == self._empty_material_container: + continue + if material_container.getMetaDataEntry("buildplate_compatible"): + buildplate_compatible = buildplate_compatible and material_container.getMetaDataEntry("buildplate_compatible")[self.activeVariantBuildplateName] + + return buildplate_compatible + + ## The selected buildplate is usable if it is usable for all materials OR it is compatible for one but not compatible + # for the other material but the buildplate is still usable + @pyqtProperty(bool, notify = activeMaterialChanged) + def variantBuildplateUsable(self) -> bool: + if not self._global_container_stack: + return True + + # Here the next formula is being calculated: + # result = (not (material_left_compatible and material_right_compatible)) and + # (material_left_compatible or material_left_usable) and + # (material_right_compatible or material_right_usable) + result = not self.variantBuildplateCompatible + extruder_stacks = self._global_container_stack.extruders.values() + for stack in extruder_stacks: + material_container = stack.material + if material_container == self._empty_material_container: + continue + buildplate_compatible = material_container.getMetaDataEntry("buildplate_compatible")[self.activeVariantBuildplateName] if material_container.getMetaDataEntry("buildplate_compatible") else True + buildplate_usable = material_container.getMetaDataEntry("buildplate_recommended")[self.activeVariantBuildplateName] if material_container.getMetaDataEntry("buildplate_recommended") else True + + result = result and (buildplate_compatible or buildplate_usable) + + return result + ## Property to indicate if a machine has "specialized" material profiles. # Some machines have their own material profiles that "override" the default catch all profiles. @pyqtProperty(bool, notify = globalContainerChanged) diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index 4c27485883..fa5473ba38 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -123,7 +123,8 @@ class StartSliceJob(Job): return # Don't slice if the buildplate or the nozzle type is incompatible with the materials - if not Application.getInstance().getMachineManager().variantBuildplateCompatible: + if not Application.getInstance().getMachineManager().variantBuildplateCompatible and \ + not Application.getInstance().getMachineManager().variantBuildplateUsable: self.setResult(StartJobResult.MaterialIncompatible) return diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index e66da9da5e..d3a8b5c8d6 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -351,6 +351,9 @@ Column activeFocusOnPress: true; menu: BuildplateMenu {} + + property var valueError: !Cura.MachineManager.variantBuildplateCompatible && !Cura.MachineManager.variantBuildplateUsable + property var valueWarning: Cura.MachineManager.variantBuildplateUsable } } From aace0e03170fc1a8df76add53bf13a592ec6c946 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Mon, 15 Jan 2018 18:10:52 +0100 Subject: [PATCH 20/45] CURA-4461 Remove unused code --- .../XmlMaterialProfile/XmlMaterialProfile.py | 30 ------------------- 1 file changed, 30 deletions(-) diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index 4babbeae77..8767377db0 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -187,7 +187,6 @@ class XmlMaterialProfile(InstanceContainer): machine_container_map = {} machine_nozzle_map = {} - machine_buildplate_map = {} all_containers = registry.findInstanceContainers(GUID = self.getMetaDataEntry("GUID"), base_file = self.getId()) for container in all_containers: @@ -203,7 +202,6 @@ class XmlMaterialProfile(InstanceContainer): variant = container.getMetaDataEntry("variant") if variant: - print("#############variant", variant) machine_nozzle_map[definition_id][variant] = container continue @@ -263,34 +261,6 @@ class XmlMaterialProfile(InstanceContainer): builder.end("hotend") - # Find all buildplate sub-profiles corresponding to this material and machine and add them to this profile. - for buildplate_id, buildplate in machine_buildplate_map[definition_id].items(): - variant_containers = registry.findInstanceContainersMetadata(id = buildplate.getMetaDataEntry("variant")) - if not variant_containers: - continue - - # The buildplate identifier is not the containers name, but its "name". - builder.start("buildplate", {"id": variant_containers[0]["name"]}) - - # Compatible is a special case, as it's added as a meta data entry (instead of an instance). - compatible = buildplate.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 buildplate.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) - - builder.end("buildplate") - builder.end("machine") builder.end("settings") From a7beb142ff273e536c34f55ce3be583a379b5fb0 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 16 Jan 2018 09:23:39 +0100 Subject: [PATCH 21/45] CURA-4461 Add line separator when the build plate selector is visible --- resources/qml/SidebarHeader.qml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index d3a8b5c8d6..432f920b93 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -314,6 +314,19 @@ Column } } + //Buildplate row separator + Rectangle { + id: separator + + anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width + anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width + anchors.horizontalCenter: parent.horizontalCenter + visible: buildplateRow.visible + width: parent.width - UM.Theme.getSize("sidebar_margin").width * 2 + height: visible ? UM.Theme.getSize("sidebar_lining").height / 2 : 0 + color: UM.Theme.getColor("sidebar_lining") + } + //Buildplate row Item { From cd4b162b86d0d249d864986fa8894811486dbafd Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 16 Jan 2018 09:47:33 +0100 Subject: [PATCH 22/45] CURA-4461 Change sizes and theme colors for the separator --- resources/qml/SidebarHeader.qml | 4 ++-- resources/themes/cura-dark/theme.json | 1 + resources/themes/cura-light/theme.json | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 432f920b93..bc45d9ddac 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -323,8 +323,8 @@ Column anchors.horizontalCenter: parent.horizontalCenter visible: buildplateRow.visible width: parent.width - UM.Theme.getSize("sidebar_margin").width * 2 - height: visible ? UM.Theme.getSize("sidebar_lining").height / 2 : 0 - color: UM.Theme.getColor("sidebar_lining") + height: visible ? UM.Theme.getSize("sidebar_lining_thin").height / 2 : 0 + color: UM.Theme.getColor("sidebar_lining_thin") } //Buildplate row diff --git a/resources/themes/cura-dark/theme.json b/resources/themes/cura-dark/theme.json index 9e99945d3d..80a5eec09c 100644 --- a/resources/themes/cura-dark/theme.json +++ b/resources/themes/cura-dark/theme.json @@ -43,6 +43,7 @@ "sidebar_header_text_hover": [255, 255, 255, 255], "sidebar_header_text_inactive": [255, 255, 255, 127], "sidebar_lining": [31, 36, 39, 255], + "sidebar_lining_thin": [255, 255, 255, 30], "button": [39, 44, 48, 255], "button_hover": [39, 44, 48, 255], diff --git a/resources/themes/cura-light/theme.json b/resources/themes/cura-light/theme.json index 53bef1e7d9..51c96a5f82 100644 --- a/resources/themes/cura-light/theme.json +++ b/resources/themes/cura-light/theme.json @@ -91,6 +91,7 @@ "sidebar_header_text_active": [255, 255, 255, 255], "sidebar_header_text_hover": [255, 255, 255, 255], "sidebar_lining": [245, 245, 245, 255], + "sidebar_lining_thin": [127, 127, 127, 255], "button": [31, 36, 39, 255], "button_hover": [68, 72, 75, 255], From 71e4d424095f0dcd27367bdb52ccf0ae5214f154 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Tue, 16 Jan 2018 10:47:30 +0100 Subject: [PATCH 23/45] CURA-4795 set build plate of newly loaded 3mf files to active build plate --- plugins/3MFReader/ThreeMFReader.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/3MFReader/ThreeMFReader.py b/plugins/3MFReader/ThreeMFReader.py index 727bce2112..09ed1e126d 100755 --- a/plugins/3MFReader/ThreeMFReader.py +++ b/plugins/3MFReader/ThreeMFReader.py @@ -81,8 +81,10 @@ class ThreeMFReader(MeshReader): self._object_count += 1 node_name = "Object %s" % self._object_count + active_build_plate = Application.getInstance().getBuildPlateModel().activeBuildPlate + um_node = CuraSceneNode() - um_node.addDecorator(BuildPlateDecorator(0)) + um_node.addDecorator(BuildPlateDecorator(active_build_plate)) um_node.setName(node_name) transformation = self._createMatrixFromTransformationString(savitar_node.getTransformation()) um_node.setTransformation(transformation) From 063eb8e5cdc23399c1c23603cafe0f997b2d78a4 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 16 Jan 2018 10:32:37 +0100 Subject: [PATCH 24/45] Don't give an error when reading normal 3MF files We have a signalling return value for this case. Let's use it. Contributes to issue CURA-4810. --- plugins/3MFReader/ThreeMFWorkspaceReader.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index 5c62c361c3..65896b3ec7 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -168,11 +168,9 @@ class ThreeMFWorkspaceReader(WorkspaceReader): Logger.log("w", "Unknown definition container type %s for %s", definition_container_type, each_definition_container_file) Job.yieldThread() - # sanity check + if machine_definition_container_count != 1: - msg = "Expecting one machine definition container but got %s" % machine_definition_container_count - Logger.log("e", msg) - raise RuntimeError(msg) + return WorkspaceReader.PreReadResult.failed #Not a workspace file but ordinary 3MF. material_labels = [] material_conflict = False From 1e892dc45c24fff0bae8a117c8507e8e828674a3 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 16 Jan 2018 10:38:11 +0100 Subject: [PATCH 25/45] Remove unused variables Contributes to issue CURA-4810. --- plugins/3MFReader/ThreeMFWorkspaceReader.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index 65896b3ec7..77a7da8b6a 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -269,7 +269,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader): # if the global stack is found, we check if there are conflicts in the extruder stacks if containers_found_dict["machine"] and not machine_conflict: for extruder_stack_file in extruder_stack_files: - container_id = self._stripFileToId(extruder_stack_file) serialized = archive.open(extruder_stack_file).read().decode("utf-8") parser = configparser.ConfigParser() parser.read_string(serialized) @@ -301,7 +300,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader): break num_visible_settings = 0 - has_visible_settings_string = False try: temp_preferences = Preferences() serialized = archive.open("Cura/preferences.cfg").read().decode("utf-8") From 27c0ca4dea6205f8360c4e2253c0c1adb8755473 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 16 Jan 2018 10:39:08 +0100 Subject: [PATCH 26/45] Move some things outside of try-catch clause Only the pre-read should really be in there. Otherwise we'd hide some mistakes in our code. Contributes to issue CURA-4810. --- cura/CuraApplication.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 099c71c708..402917d748 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -1518,12 +1518,11 @@ class CuraApplication(QtApplication): """ Checks if the given file URL is a valid project file. """ + file_path = QUrl(file_url).toLocalFile() + workspace_reader = self.getWorkspaceFileHandler().getReaderForFile(file_path) + if workspace_reader is None: + return False # non-project files won't get a reader try: - file_path = QUrl(file_url).toLocalFile() - workspace_reader = self.getWorkspaceFileHandler().getReaderForFile(file_path) - if workspace_reader is None: - return False # non-project files won't get a reader - result = workspace_reader.preRead(file_path, show_dialog=False) return result == WorkspaceReader.PreReadResult.accepted except Exception as e: From a0738c29770a4283fa7b1526cc2207e84e221de7 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Tue, 16 Jan 2018 11:49:45 +0100 Subject: [PATCH 27/45] CURA-4808 fix extruder setting change trigger slice. re-introduce extrudersAdded signal, probably needed because of timing issues (extruder added after loading global container). it's the inversion of 225b03e98ee1d92467176a1fd1ef3605ce0999c7 --- cura/Settings/ExtruderManager.py | 4 ++++ plugins/CuraEngineBackend/CuraEngineBackend.py | 1 + 2 files changed, 5 insertions(+) diff --git a/cura/Settings/ExtruderManager.py b/cura/Settings/ExtruderManager.py index 351843ae14..b5f9a35914 100755 --- a/cura/Settings/ExtruderManager.py +++ b/cura/Settings/ExtruderManager.py @@ -49,6 +49,9 @@ class ExtruderManager(QObject): ## Notify when the user switches the currently active extruder. activeExtruderChanged = pyqtSignal() + ## The signal notifies subscribers if extruders are added + extrudersAdded = pyqtSignal() + ## Gets the unique identifier of the currently active extruder stack. # # The currently active extruder stack is the stack that is currently being @@ -406,6 +409,7 @@ class ExtruderManager(QObject): if extruders_changed: self.extrudersChanged.emit(global_stack_id) + self.extrudersAdded.emit() self.setActiveExtruderIndex(0) ## Get all extruder values for a certain setting. diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index 97463e07da..9713211ad3 100755 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -88,6 +88,7 @@ class CuraEngineBackend(QObject, Backend): # self._global_container_stack = None Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged) + Application.getInstance().getExtruderManager().extrudersAdded.connect(self._onGlobalStackChanged) self._onGlobalStackChanged() Application.getInstance().stacksValidationFinished.connect(self._onStackErrorCheckFinished) From abece3c415c792c424d499387070e0a10a6a77b5 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Tue, 16 Jan 2018 11:54:25 +0100 Subject: [PATCH 28/45] Add quality_type = not_supported to empty_quality_changes CURA-4807 --- cura/CuraApplication.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 402917d748..b453504f08 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -299,6 +299,7 @@ class CuraApplication(QtApplication): empty_quality_changes_container = copy.deepcopy(empty_container) empty_quality_changes_container.setMetaDataEntry("id", "empty_quality_changes") empty_quality_changes_container.addMetaDataEntry("type", "quality_changes") + empty_quality_changes_container.addMetaDataEntry("quality_type", "not_supported") ContainerRegistry.getInstance().addContainer(empty_quality_changes_container) with ContainerRegistry.getInstance().lockFile(): From 8a570c4b01981dfae96f7feeeeeed2a69f0d8728 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Tue, 16 Jan 2018 11:55:54 +0100 Subject: [PATCH 29/45] Show user profiles based on Not Supported CURA-4807 --- cura/Settings/QualityAndUserProfilesModel.py | 8 +++++++- cura/Settings/QualitySettingsModel.py | 2 +- cura/Settings/UserProfilesModel.py | 5 +++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/cura/Settings/QualityAndUserProfilesModel.py b/cura/Settings/QualityAndUserProfilesModel.py index 8396e62417..645e63acdb 100644 --- a/cura/Settings/QualityAndUserProfilesModel.py +++ b/cura/Settings/QualityAndUserProfilesModel.py @@ -1,17 +1,21 @@ # Copyright (c) 2016 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. from UM.Application import Application +from UM.Settings.ContainerRegistry import ContainerRegistry from cura.QualityManager import QualityManager from cura.Settings.ProfilesModel import ProfilesModel from cura.Settings.ExtruderManager import ExtruderManager + ## QML Model for listing the current list of valid quality and quality changes profiles. # class QualityAndUserProfilesModel(ProfilesModel): def __init__(self, parent = None): super().__init__(parent) + self._empty_quality = ContainerRegistry.getInstance().findInstanceContainers(id = "empty_quality")[0] + ## Fetch the list of containers to display. # # See UM.Settings.Models.InstanceContainersModel._fetchInstanceContainers(). @@ -35,7 +39,9 @@ class QualityAndUserProfilesModel(ProfilesModel): # Filter the quality_change by the list of available quality_types quality_type_set = set([x.getMetaDataEntry("quality_type") for x in quality_list]) - filtered_quality_changes = {qc.getId():qc for qc in quality_changes_list if + # Also show custom profiles based on "Not Supported" quality profile + quality_type_set.add(self._empty_quality.getMetaDataEntry("quality_type")) + filtered_quality_changes = {qc.getId(): qc for qc in quality_changes_list if qc.getMetaDataEntry("quality_type") in quality_type_set and qc.getMetaDataEntry("extruder") is not None and (qc.getMetaDataEntry("extruder") == active_extruder.definition.getMetaDataEntry("quality_definition") or diff --git a/cura/Settings/QualitySettingsModel.py b/cura/Settings/QualitySettingsModel.py index 0e17237ff7..fb1aa9a6b2 100644 --- a/cura/Settings/QualitySettingsModel.py +++ b/cura/Settings/QualitySettingsModel.py @@ -107,7 +107,7 @@ class QualitySettingsModel(UM.Qt.ListModel.ListModel): else: quality_changes_container = containers[0] - if quality_changes_container.getMetaDataEntry("quality_type") == "not_supported": + if quality_changes_container.getMetaDataEntry("quality_type") == self._empty_quality.getMetaDataEntry("quality_type"): quality_container = self._empty_quality else: criteria = { diff --git a/cura/Settings/UserProfilesModel.py b/cura/Settings/UserProfilesModel.py index e093c6c132..6605f52f8a 100644 --- a/cura/Settings/UserProfilesModel.py +++ b/cura/Settings/UserProfilesModel.py @@ -2,6 +2,8 @@ # Cura is released under the terms of the LGPLv3 or higher. from UM.Application import Application +from UM.Settings.ContainerRegistry import ContainerRegistry + from cura.QualityManager import QualityManager from cura.Settings.ProfilesModel import ProfilesModel from cura.Settings.ExtruderManager import ExtruderManager @@ -22,6 +24,8 @@ class UserProfilesModel(ProfilesModel): for material in self.__current_materials: material.metaDataChanged.connect(self._onContainerChanged) + self._empty_quality = ContainerRegistry.getInstance().findContainers(id = "empty_quality")[0] + ## Fetch the list of containers to display. # # See UM.Settings.Models.InstanceContainersModel._fetchInstanceContainers(). @@ -45,6 +49,7 @@ class UserProfilesModel(ProfilesModel): # Filter the quality_change by the list of available quality_types quality_type_set = set([x.getMetaDataEntry("quality_type") for x in quality_list]) + quality_type_set.add(self._empty_quality.getMetaDataEntry("quality_type")) filtered_quality_changes = {qc.getId():qc for qc in quality_changes_list if qc.getMetaDataEntry("quality_type") in quality_type_set and From aa8057e80c609ded20c58a813f5df5d04b58a2a8 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 16 Jan 2018 11:57:39 +0100 Subject: [PATCH 30/45] Change style of Add/Remove printers link in Monitor tab --- plugins/UM3NetworkPrinting/ClusterMonitorItem.qml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/plugins/UM3NetworkPrinting/ClusterMonitorItem.qml b/plugins/UM3NetworkPrinting/ClusterMonitorItem.qml index df102915ff..86bdaae0a5 100644 --- a/plugins/UM3NetworkPrinting/ClusterMonitorItem.qml +++ b/plugins/UM3NetworkPrinting/ClusterMonitorItem.qml @@ -52,13 +52,19 @@ Component { id: addRemovePrintersLabel anchors.right: parent.right - text: "Add / remove printers" + text: catalog.i18nc("@label link to connect manager", "Add/Remove printers") + font: UM.Theme.getFont("default") + color: UM.Theme.getColor("text") + linkColor: UM.Theme.getColor("text_link") } MouseArea { anchors.fill: addRemovePrintersLabel + hoverEnabled: true onClicked: Cura.MachineManager.printerOutputDevices[0].openPrinterControlPanel() + onEntered: addRemovePrintersLabel.font.underline = true + onExited: addRemovePrintersLabel.font.underline = false } } From 0a4c30603faa66844edd777a65f1ae8148aa2097 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 16 Jan 2018 11:57:39 +0100 Subject: [PATCH 31/45] Change style of Add/Remove printers link in Monitor tab --- plugins/UM3NetworkPrinting/ClusterMonitorItem.qml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/plugins/UM3NetworkPrinting/ClusterMonitorItem.qml b/plugins/UM3NetworkPrinting/ClusterMonitorItem.qml index e78c7d1cc9..ef82ac7638 100644 --- a/plugins/UM3NetworkPrinting/ClusterMonitorItem.qml +++ b/plugins/UM3NetworkPrinting/ClusterMonitorItem.qml @@ -52,13 +52,19 @@ Component { id: addRemovePrintersLabel anchors.right: parent.right - text: "Add / remove printers" + text: catalog.i18nc("@label link to connect manager", "Add/Remove printers") + font: UM.Theme.getFont("default") + color: UM.Theme.getColor("text") + linkColor: UM.Theme.getColor("text_link") } MouseArea { anchors.fill: addRemovePrintersLabel + hoverEnabled: true onClicked: Cura.MachineManager.printerOutputDevices[0].openPrinterControlPanel() + onEntered: addRemovePrintersLabel.font.underline = true + onExited: addRemovePrintersLabel.font.underline = false } } From 51b49c89f4ddf6a1fca225ef1a527ff7ab381818 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Tue, 16 Jan 2018 12:43:56 +0100 Subject: [PATCH 32/45] Switch to LayerView after GCode has been fully loaded CURA-4805 --- cura/CuraApplication.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index b453504f08..f4f121eda8 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -1461,11 +1461,7 @@ class CuraApplication(QtApplication): extension = os.path.splitext(filename)[1] if extension.lower() in self._non_sliceable_extensions: - self.getController().setActiveView("SimulationView") - view = self.getController().getActiveView() - view.resetLayerData() - view.setLayer(9999999) - view.calculateMaxLayers() + self.callLater(lambda: self.getController().setActiveView("SimulationView")) block_slicing_decorator = BlockSlicingDecorator() node.addDecorator(block_slicing_decorator) From f948203a63fc246abb7d6e3c62dac63616d4fecf Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 16 Jan 2018 13:43:28 +0100 Subject: [PATCH 33/45] Fix crash when clearing build plate We shouldn't delete the singleton PrintInformation object. We should rather just zero out the print information. And instead of doing that explicitly in deleteAll, listen to scene changes from PrintInformation in order to keep the logic related to the print information contained within its class. Contributes to issue CURA-4810. --- cura/CuraApplication.py | 3 --- cura/PrintInformation.py | 5 +++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index f4f121eda8..37952a42ac 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -1061,9 +1061,6 @@ class CuraApplication(QtApplication): op.push() Selection.clear() - Logger.log("i", "Reseting print information") - self._print_information = PrintInformation.PrintInformation() - # stay on the same build plate #self.getCuraSceneController().setActiveBuildPlate(0) # Select first build plate diff --git a/cura/PrintInformation.py b/cura/PrintInformation.py index 838628e37c..5d5d59ed3b 100644 --- a/cura/PrintInformation.py +++ b/cura/PrintInformation.py @@ -1,4 +1,4 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty @@ -65,6 +65,7 @@ class PrintInformation(QObject): self._backend = Application.getInstance().getBackend() if self._backend: self._backend.printDurationMessage.connect(self._onPrintDurationMessage) + Application.getInstance().getController().getScene().sceneChanged.connect(self.setToZeroPrintInformation) self._base_name = "" self._abbr_machine = "" @@ -171,7 +172,7 @@ class PrintInformation(QObject): def printTimes(self): return self._print_time_message_values[self._active_build_plate] - def _onPrintDurationMessage(self, build_plate_number, print_time, material_amounts): + def _onPrintDurationMessage(self, build_plate_number, print_time: Dict[str, int], material_amounts: list): self._updateTotalPrintTimePerFeature(build_plate_number, print_time) self.currentPrintTimeChanged.emit() From b0d2ef0f72e590054e0db36a246c778c30b2bed4 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Tue, 16 Jan 2018 13:48:12 +0100 Subject: [PATCH 34/45] Correct default material diameter value for single-extrusion machines CURA-4812 --- .../MachineSettingsAction.py | 5 ++++- resources/definitions/fdmextruder.def.json | 21 ------------------- 2 files changed, 4 insertions(+), 22 deletions(-) diff --git a/plugins/MachineSettingsAction/MachineSettingsAction.py b/plugins/MachineSettingsAction/MachineSettingsAction.py index a939d033fc..101ba54ed0 100755 --- a/plugins/MachineSettingsAction/MachineSettingsAction.py +++ b/plugins/MachineSettingsAction/MachineSettingsAction.py @@ -225,7 +225,10 @@ class MachineSettingsAction(MachineAction): material_approximate_diameter = str(round(material_diameter)) machine_diameter = extruder_stack.definitionChanges.getProperty("material_diameter", "value") if not machine_diameter: - machine_diameter = extruder_stack.definition.getProperty("material_diameter", "value") + if extruder_stack.definition.hasProperty("material_diameter", "value"): + machine_diameter = extruder_stack.definition.getProperty("material_diameter", "value") + else: + machine_diameter = self._global_container_stack.definition.getProperty("material_diameter", "value") machine_approximate_diameter = str(round(machine_diameter)) if material_approximate_diameter != machine_approximate_diameter: diff --git a/resources/definitions/fdmextruder.def.json b/resources/definitions/fdmextruder.def.json index 3a59e7df1e..2b314cd6a5 100644 --- a/resources/definitions/fdmextruder.def.json +++ b/resources/definitions/fdmextruder.def.json @@ -181,27 +181,6 @@ } } }, - "material": { - "label": "Material", - "icon": "category_material", - "description": "Material", - "type": "category", - "children": { - "material_diameter": { - "label": "Diameter", - "description": "Adjusts the diameter of the filament used. Match this value with the diameter of the used filament.", - "unit": "mm", - "type": "float", - "default_value": 2.85, - "minimum_value": "0.0001", - "minimum_value_warning": "0.4", - "maximum_value_warning": "3.5", - "enabled": "machine_gcode_flavor != \"UltiGCode\"", - "settable_per_mesh": false, - "settable_per_extruder": true - } - } - }, "platform_adhesion": { "label": "Build Plate Adhesion", From 54698ada7f6563d3b0c5b22b1d80e604e8848212 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Tue, 16 Jan 2018 15:36:57 +0100 Subject: [PATCH 35/45] CURA-4807 fix not choosing 'not supported' if there are valid options after changing variant; partly undoing 4abbd4b9887fc3e3d98ebf06481d2b21a9e9be0e --- cura/QualityManager.py | 3 --- cura/Settings/ProfilesModel.py | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/cura/QualityManager.py b/cura/QualityManager.py index d984bd17a1..76a0c86a5f 100644 --- a/cura/QualityManager.py +++ b/cura/QualityManager.py @@ -136,9 +136,6 @@ class QualityManager: if basic_materials: result = self._getFilteredContainersForStack(machine_definition, basic_materials, **criteria) - empty_quality = ContainerRegistry.getInstance().findInstanceContainers(id = "empty_quality")[0] - result.append(empty_quality) - return result ## Find all quality changes for a machine. diff --git a/cura/Settings/ProfilesModel.py b/cura/Settings/ProfilesModel.py index 15b123d12f..77cd407457 100644 --- a/cura/Settings/ProfilesModel.py +++ b/cura/Settings/ProfilesModel.py @@ -87,7 +87,7 @@ class ProfilesModel(InstanceContainersModel): if quality.getMetaDataEntry("quality_type") not in quality_type_set: result.append(quality) - if len(result) > 1: + if len(result) > 1 and self._empty_quality in result: result.remove(self._empty_quality) return {item.getId(): item for item in result}, {} #Only return true profiles for now, no metadata. The quality manager is not able to get only metadata yet. From cffeff0299b4593c403b8640a21037ed6575ad20 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Tue, 16 Jan 2018 15:58:14 +0100 Subject: [PATCH 36/45] CURA-4805 remove modifiable settings when loading non sliceable file (gcode) --- resources/qml/Sidebar.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/qml/Sidebar.qml b/resources/qml/Sidebar.qml index e1c0a07f89..d12515c004 100644 --- a/resources/qml/Sidebar.qml +++ b/resources/qml/Sidebar.qml @@ -96,7 +96,7 @@ Rectangle SidebarHeader { id: header width: parent.width - visible: (machineExtruderCount.properties.value > 1 || Cura.MachineManager.hasMaterials || Cura.MachineManager.hasVariants) && !monitoringPrint + visible: !hideSettings && (machineExtruderCount.properties.value > 1 || Cura.MachineManager.hasMaterials || Cura.MachineManager.hasVariants) && !monitoringPrint anchors.top: machineSelection.bottom onShowTooltip: base.showTooltip(item, location, text) @@ -128,7 +128,7 @@ Rectangle text: !hideSettings ? catalog.i18nc("@label:listbox", "Print Setup") : catalog.i18nc("@label:listbox", "Print Setup disabled\nG-code files cannot be modified") anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width - anchors.top: headerSeparator.bottom + anchors.top: hideSettings ? machineSelection.bottom : headerSeparator.bottom anchors.topMargin: UM.Theme.getSize("sidebar_margin").height width: Math.floor(parent.width * 0.45) font: UM.Theme.getFont("large") From ba1f915633a0ac455cd36981d9f710d3966ee9fa Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Tue, 16 Jan 2018 16:30:10 +0100 Subject: [PATCH 37/45] Fix for CURA-4789 `deleteAll()` within `CuraApplication.py` now resets the print information by calling its `setToZeroPrintInformation()` method, rather than by reinstatiating the `PrintInformation` class. --- cura/CuraApplication.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 37952a42ac..3c5eca2f21 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -1061,6 +1061,9 @@ class CuraApplication(QtApplication): op.push() Selection.clear() + # Reset the print information: + self._print_information.setToZeroPrintInformation(self.getBuildPlateModel().activeBuildPlate) + # stay on the same build plate #self.getCuraSceneController().setActiveBuildPlate(0) # Select first build plate From fad43be23b80aa82628722a9ad1e2dbecb4e132a Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Tue, 16 Jan 2018 17:03:52 +0100 Subject: [PATCH 38/45] Fixes CURA-4789 Emits `sceneChanged` which `PrintInformation` listens for and then resets with. Same result re: print time, but also will update anythign else which is listening for `sceneChanged`. --- cura/CuraApplication.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 3c5eca2f21..0ac50c9e5e 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -1062,7 +1062,8 @@ class CuraApplication(QtApplication): Selection.clear() # Reset the print information: - self._print_information.setToZeroPrintInformation(self.getBuildPlateModel().activeBuildPlate) + self.getController().getScene().sceneChanged.emit(node) + # self._print_information.setToZeroPrintInformation(self.getBuildPlateModel().activeBuildPlate) # stay on the same build plate #self.getCuraSceneController().setActiveBuildPlate(0) # Select first build plate From 4bc488ca790f688b76de874656a22e93c07f0a15 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 17 Jan 2018 10:50:48 +0100 Subject: [PATCH 39/45] Change wording to "Aluminium" CURA-4461 --- resources/definitions/fdmprinter.def.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index a24d21b1ad..c7f80666ff 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -163,7 +163,7 @@ "options": { "glass": "Glass", - "aluminum": "Aluminum" + "aluminium": "Aluminium" }, "settable_per_mesh": false, "settable_per_extruder": false, From 26371c9c3a58578c7f1b5bf4ac91a5311812d1b8 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 17 Jan 2018 10:57:11 +0100 Subject: [PATCH 40/45] CURA-4815 When creating the unique name for a machine, don't look at the definition instance container for the id, just look at the container stack ids. --- cura/Settings/CuraContainerRegistry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Settings/CuraContainerRegistry.py b/cura/Settings/CuraContainerRegistry.py index 9202e57285..b945ec0609 100644 --- a/cura/Settings/CuraContainerRegistry.py +++ b/cura/Settings/CuraContainerRegistry.py @@ -94,7 +94,7 @@ class CuraContainerRegistry(ContainerRegistry): def _containerExists(self, container_type, container_name): container_class = ContainerStack if container_type == "machine" else InstanceContainer - return self.findContainersMetadata(id = container_name, type = container_type, ignore_case = True) or \ + return self.findContainersMetadata(container_type = container_class, id = container_name, type = container_type, ignore_case = True) or \ self.findContainersMetadata(container_type = container_class, name = container_name, type = container_type) ## Exports an profile to a file From 4680996a491f47d42b5fa790a68a0f282d22db2d Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 17 Jan 2018 11:32:43 +0100 Subject: [PATCH 41/45] Print window no longer gets an ever increasing list of print targets CL-720 --- plugins/UM3NetworkPrinting/PrintWindow.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/UM3NetworkPrinting/PrintWindow.qml b/plugins/UM3NetworkPrinting/PrintWindow.qml index 13d087f930..d84b0f30ec 100644 --- a/plugins/UM3NetworkPrinting/PrintWindow.qml +++ b/plugins/UM3NetworkPrinting/PrintWindow.qml @@ -31,6 +31,7 @@ UM.Dialog property var printersModel: ListModel{} function resetPrintersModel() { + printersModel.clear() printersModel.append({ name: "Automatic", key: ""}) for (var index in OutputDevice.printers) From 8dd21892d33277bec88895393f992b612b7af526 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 17 Jan 2018 11:34:25 +0100 Subject: [PATCH 42/45] Avoid zero thickness to be shown in layer view. Also fix some typos. --- plugins/SimulationView/SimulationView.py | 4 ++-- plugins/SimulationView/SimulationViewProxy.py | 4 ++-- plugins/SimulationView/__init__.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index f667aff998..9249cd4a54 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -1,4 +1,4 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. import sys @@ -344,7 +344,7 @@ class SimulationView(View): self._max_feedrate = max(float(p.lineFeedrates.max()), self._max_feedrate) self._min_feedrate = min(float(p.lineFeedrates.min()), self._min_feedrate) self._max_thickness = max(float(p.lineThicknesses.max()), self._max_thickness) - self._min_thickness = min(float(p.lineThicknesses.min()), self._min_thickness) + self._min_thickness = min(float(p.lineThicknesses[numpy.nonzero(p.lineThicknesses)].min()), self._min_thickness) if max_layer_number < layer_id: max_layer_number = layer_id if min_layer_number > layer_id: diff --git a/plugins/SimulationView/SimulationViewProxy.py b/plugins/SimulationView/SimulationViewProxy.py index e144b841e6..a84b151983 100644 --- a/plugins/SimulationView/SimulationViewProxy.py +++ b/plugins/SimulationView/SimulationViewProxy.py @@ -1,4 +1,4 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty @@ -117,7 +117,7 @@ class SimulationViewProxy(QObject): def setSimulationViewType(self, layer_view_type): active_view = self._controller.getActiveView() if isinstance(active_view, SimulationView.SimulationView.SimulationView): - active_view.setSimulationViewisinstance(layer_view_type) + active_view.setSimulationViewType(layer_view_type) @pyqtSlot(result=int) def getSimulationViewType(self): diff --git a/plugins/SimulationView/__init__.py b/plugins/SimulationView/__init__.py index 15e113bd8e..360fdc1de9 100644 --- a/plugins/SimulationView/__init__.py +++ b/plugins/SimulationView/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. from PyQt5.QtQml import qmlRegisterSingletonType @@ -18,7 +18,7 @@ def getMetaData(): } def createSimulationViewProxy(engine, script_engine): - return SimulationViewProxy.SimulatorViewProxy() + return SimulationViewProxy.SimulationViewProxy() def register(app): simulation_view = SimulationView.SimulationView() From cc89ddf5f76433f2a9b363018cfe43f6e910034c Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 17 Jan 2018 11:39:38 +0100 Subject: [PATCH 43/45] Revert "Avoid zero thickness to be shown in layer view." I saw that with these changes, Cura crashes when loading a GCode. This reverts commit 8dd21892d33277bec88895393f992b612b7af526. --- plugins/SimulationView/SimulationView.py | 4 ++-- plugins/SimulationView/SimulationViewProxy.py | 4 ++-- plugins/SimulationView/__init__.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 9249cd4a54..f667aff998 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -1,4 +1,4 @@ -# Copyright (c) 2018 Ultimaker B.V. +# Copyright (c) 2017 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. import sys @@ -344,7 +344,7 @@ class SimulationView(View): self._max_feedrate = max(float(p.lineFeedrates.max()), self._max_feedrate) self._min_feedrate = min(float(p.lineFeedrates.min()), self._min_feedrate) self._max_thickness = max(float(p.lineThicknesses.max()), self._max_thickness) - self._min_thickness = min(float(p.lineThicknesses[numpy.nonzero(p.lineThicknesses)].min()), self._min_thickness) + self._min_thickness = min(float(p.lineThicknesses.min()), self._min_thickness) if max_layer_number < layer_id: max_layer_number = layer_id if min_layer_number > layer_id: diff --git a/plugins/SimulationView/SimulationViewProxy.py b/plugins/SimulationView/SimulationViewProxy.py index a84b151983..e144b841e6 100644 --- a/plugins/SimulationView/SimulationViewProxy.py +++ b/plugins/SimulationView/SimulationViewProxy.py @@ -1,4 +1,4 @@ -# Copyright (c) 2018 Ultimaker B.V. +# Copyright (c) 2017 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty @@ -117,7 +117,7 @@ class SimulationViewProxy(QObject): def setSimulationViewType(self, layer_view_type): active_view = self._controller.getActiveView() if isinstance(active_view, SimulationView.SimulationView.SimulationView): - active_view.setSimulationViewType(layer_view_type) + active_view.setSimulationViewisinstance(layer_view_type) @pyqtSlot(result=int) def getSimulationViewType(self): diff --git a/plugins/SimulationView/__init__.py b/plugins/SimulationView/__init__.py index 360fdc1de9..15e113bd8e 100644 --- a/plugins/SimulationView/__init__.py +++ b/plugins/SimulationView/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2018 Ultimaker B.V. +# Copyright (c) 2017 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. from PyQt5.QtQml import qmlRegisterSingletonType @@ -18,7 +18,7 @@ def getMetaData(): } def createSimulationViewProxy(engine, script_engine): - return SimulationViewProxy.SimulationViewProxy() + return SimulationViewProxy.SimulatorViewProxy() def register(app): simulation_view = SimulationView.SimulationView() From e6169a7c618ecfd0aa3fc3360a3cd6e9e26b6bfb Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 17 Jan 2018 11:53:31 +0100 Subject: [PATCH 44/45] Fix some typos --- plugins/SimulationView/SimulationViewProxy.py | 4 ++-- plugins/SimulationView/__init__.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/SimulationView/SimulationViewProxy.py b/plugins/SimulationView/SimulationViewProxy.py index e144b841e6..a84b151983 100644 --- a/plugins/SimulationView/SimulationViewProxy.py +++ b/plugins/SimulationView/SimulationViewProxy.py @@ -1,4 +1,4 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty @@ -117,7 +117,7 @@ class SimulationViewProxy(QObject): def setSimulationViewType(self, layer_view_type): active_view = self._controller.getActiveView() if isinstance(active_view, SimulationView.SimulationView.SimulationView): - active_view.setSimulationViewisinstance(layer_view_type) + active_view.setSimulationViewType(layer_view_type) @pyqtSlot(result=int) def getSimulationViewType(self): diff --git a/plugins/SimulationView/__init__.py b/plugins/SimulationView/__init__.py index 15e113bd8e..360fdc1de9 100644 --- a/plugins/SimulationView/__init__.py +++ b/plugins/SimulationView/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. from PyQt5.QtQml import qmlRegisterSingletonType @@ -18,7 +18,7 @@ def getMetaData(): } def createSimulationViewProxy(engine, script_engine): - return SimulationViewProxy.SimulatorViewProxy() + return SimulationViewProxy.SimulationViewProxy() def register(app): simulation_view = SimulationView.SimulationView() From 5c0e2d39a366d2daf78262f16826c27bf853a406 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 17 Jan 2018 11:54:22 +0100 Subject: [PATCH 45/45] Avoid zero thickness to be shown in layer view. --- plugins/SimulationView/SimulationView.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index f667aff998..dfecda06bb 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -1,4 +1,4 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. import sys @@ -344,7 +344,12 @@ class SimulationView(View): self._max_feedrate = max(float(p.lineFeedrates.max()), self._max_feedrate) self._min_feedrate = min(float(p.lineFeedrates.min()), self._min_feedrate) self._max_thickness = max(float(p.lineThicknesses.max()), self._max_thickness) - self._min_thickness = min(float(p.lineThicknesses.min()), self._min_thickness) + try: + self._min_thickness = min(float(p.lineThicknesses[numpy.nonzero(p.lineThicknesses)].min()), self._min_thickness) + except: + # Sometimes, when importing a GCode the line thicknesses are zero and so the minimum (avoiding + # the zero) can't be calculated + Logger.log("i", "Min thickness can't be calculated because all the values are zero") if max_layer_number < layer_id: max_layer_number = layer_id if min_layer_number > layer_id: