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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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 4bc488ca790f688b76de874656a22e93c07f0a15 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 17 Jan 2018 10:50:48 +0100 Subject: [PATCH 23/23] 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,