diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 0f45f0a7b1..8354f3a140 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -8,7 +8,10 @@ import UM.Settings class MachineManagerModel(QObject): def __init__(self, parent = None): super().__init__(parent) + + self._global_container_stack = None Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged) + self._onGlobalContainerChanged() ## When the global container is changed, active material probably needs to be updated. self.globalContainerChanged.connect(self.activeMaterialChanged) @@ -31,10 +34,16 @@ class MachineManagerModel(QObject): activeQualityChanged = pyqtSignal() def _onGlobalContainerChanged(self): - Preferences.getInstance().setValue("cura/active_machine", Application.getInstance().getGlobalContainerStack().getId()) - Application.getInstance().getGlobalContainerStack().containersChanged.connect(self._onInstanceContainersChanged) + if self._global_container_stack: + self._global_container_stack.containersChanged.disconnect(self._onInstanceContainersChanged) + + self._global_container_stack = Application.getInstance().getGlobalContainerStack() self.globalContainerChanged.emit() + if self._global_container_stack: + Preferences.getInstance().setValue("cura/active_machine", self._global_container_stack.getId()) + self._global_container_stack.containersChanged.connect(self._onInstanceContainersChanged) + def _onInstanceContainersChanged(self, container): container_type = container.getMetaDataEntry("type") if container_type == "material": @@ -54,34 +63,52 @@ class MachineManagerModel(QObject): def addMachine(self,name, definition_id): definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id=definition_id) if definitions: + definition = definitions[0] + new_global_stack = UM.Settings.ContainerStack(name) new_global_stack.addMetaDataEntry("type", "machine") UM.Settings.ContainerRegistry.getInstance().addContainer(new_global_stack) + empty_container = UM.Settings.ContainerRegistry.getInstance().getEmptyInstanceContainer() + + variants = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "variant", definition = definition.id) + if variants: + new_global_stack.addMetaDataEntry("has_variants", True) + + preferred_variant_id = definitions[0].getMetaDataEntry("preferred_variant") + variant_instance_container = empty_container + if preferred_variant_id: + preferred_variant_id = preferred_variant_id.lower() + container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = preferred_variant_id) + if container: + variant_instance_container = container[0] + + if variants and variant_instance_container == empty_container: + variant_instance_container = variants[0] + + materials = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "material", definition = definition.id) + if materials: + new_global_stack.addMetaDataEntry("has_materials", True) preferred_material_id = definitions[0].getMetaDataEntry("preferred_material") - material_instance_container = None + material_instance_container = empty_container if preferred_material_id: preferred_material_id = preferred_material_id.lower() container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = preferred_material_id) if container: material_instance_container = container[0] + if materials and material_instance_container == empty_container: + material_instance_container = materials[0] + preferred_quality_id = definitions[0].getMetaDataEntry("preferred_quality") - quality_instance_container = None + quality_instance_container = empty_container if preferred_quality_id: preferred_quality_id = preferred_quality_id.lower() container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = preferred_quality_id) if container: quality_instance_container = container[0] - ## DEBUG CODE - variant_instance_container = UM.Settings.InstanceContainer("test_variant") - variant_instance_container.addMetaDataEntry("type", "variant") - variant_instance_container.setDefinition(definitions[0]) - - UM.Settings.ContainerRegistry.getInstance().addContainer(variant_instance_container) - current_settings_instance_container = UM.Settings.InstanceContainer(name + "_current_settings") current_settings_instance_container.addMetaDataEntry("machine", name) current_settings_instance_container.addMetaDataEntry("type", "user") @@ -90,9 +117,10 @@ class MachineManagerModel(QObject): # If a definition is found, its a list. Should only have one item. new_global_stack.addContainer(definitions[0]) + if variant_instance_container: + new_global_stack.addContainer(variant_instance_container) if material_instance_container: new_global_stack.addContainer(material_instance_container) - new_global_stack.addContainer(variant_instance_container) if quality_instance_container: new_global_stack.addContainer(quality_instance_container) new_global_stack.addContainer(current_settings_instance_container) @@ -101,78 +129,111 @@ class MachineManagerModel(QObject): @pyqtProperty(str, notify = globalContainerChanged) def activeMachineName(self): - return Application.getInstance().getGlobalContainerStack().getName() + if self._global_container_stack: + return self._global_container_stack.getName() + + return "" @pyqtProperty(str, notify = globalContainerChanged) def activeMachineId(self): - return Application.getInstance().getGlobalContainerStack().getId() + if self._global_container_stack: + return self._global_container_stack.getId() + + return "" @pyqtProperty(str, notify = activeMaterialChanged) def activeMaterialName(self): - material = Application.getInstance().getGlobalContainerStack().findContainer({"type":"material"}) - if material: - return material.getName() + if self._global_container_stack: + material = self._global_container_stack.findContainer({"type":"material"}) + if material: + return material.getName() + + return "" @pyqtProperty(str, notify=activeMaterialChanged) def activeMaterialId(self): - material = Application.getInstance().getGlobalContainerStack().findContainer({"type": "material"}) - if material: - return material.getId() + if self._global_container_stack: + material = self._global_container_stack.findContainer({"type": "material"}) + if material: + return material.getId() + + return "" @pyqtProperty(str, notify=activeQualityChanged) def activeQualityName(self): - quality = Application.getInstance().getGlobalContainerStack().findContainer({"type": "quality"}) - if quality: - return quality.getName() + if self._global_container_stack: + quality = self._global_container_stack.findContainer({"type": "quality"}) + if quality: + return quality.getName() + return "" @pyqtProperty(str, notify=activeQualityChanged) def activeQualityId(self): - quality = Application.getInstance().getGlobalContainerStack().findContainer({"type": "quality"}) - if quality: - return quality.getId() + if self._global_container_stack: + quality = self._global_container_stack.findContainer({"type": "quality"}) + if quality: + return quality.getId() + return "" @pyqtSlot(str) def setActiveMaterial(self, material_id): containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=material_id) - old_material = Application.getInstance().getGlobalContainerStack().findContainer({"type":"material"}) + if not containers or not self._global_container_stack: + return + + old_material = self._global_container_stack.findContainer({"type":"material"}) if old_material: - material_index = Application.getInstance().getGlobalContainerStack().getContainerIndex(old_material) - Application.getInstance().getGlobalContainerStack().replaceContainer(material_index, containers[0]) + material_index = self._global_container_stack.getContainerIndex(old_material) + self._global_container_stack.replaceContainer(material_index, containers[0]) @pyqtSlot(str) def setActiveVariant(self, variant_id): containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=variant_id) - old_variant = Application.getInstance().getGlobalContainerStack().findContainer({"type": "variant"}) + if not containers or not self._global_container_stack: + return + + old_variant = self._global_container_stack.findContainer({"type": "variant"}) if old_variant: - variant_index = Application.getInstance().getGlobalContainerStack().getContainerIndex(old_variant) - Application.getInstance().getGlobalContainerStack().replaceContainer(variant_index, containers[0]) + variant_index = self._global_container_stack.getContainerIndex(old_variant) + self._global_container_stack.replaceContainer(variant_index, containers[0]) @pyqtSlot(str) def setActiveQuality(self, quality_id): containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = quality_id) - old_quality = Application.getInstance().getGlobalContainerStack().findContainer({"type": "quality"}) + if not containers or not self._global_container_stack: + return + + old_quality = self._global_container_stack.findContainer({"type": "quality"}) if old_quality: - quality_index = Application.getInstance().getGlobalContainerStack().getContainerIndex(old_quality) - Application.getInstance().getGlobalContainerStack().replaceContainer(quality_index, containers[0]) + quality_index = self._global_container_stack.getContainerIndex(old_quality) + self._global_container_stack.replaceContainer(quality_index, containers[0]) @pyqtProperty(str, notify = activeVariantChanged) def activeVariantName(self): - variant = Application.getInstance().getGlobalContainerStack().findContainer({"type": "variant"}) - if variant: - return variant.getName() + if self._global_container_stack: + variant = self._global_container_stack.findContainer({"type": "variant"}) + if variant: + return variant.getName() + + return "" @pyqtProperty(str, notify = activeVariantChanged) def activeVariantId(self): - variant = Application.getInstance().getGlobalContainerStack().findContainer({"type": "variant"}) - if variant: - return variant.getId() + if self._global_container_stack: + variant = self._global_container_stack.findContainer({"type": "variant"}) + if variant: + return variant.getId() + + return "" @pyqtProperty(str, notify = globalContainerChanged) def activeDefinitionId(self): - definition = Application.getInstance().getGlobalContainerStack().getBottom() - if definition: - return definition.id - return None + if self._global_container_stack: + definition = self._global_container_stack.getBottom() + if definition: + return definition.id + + return "" @pyqtSlot(str, str) def renameMachine(self, machine_id, new_name): @@ -184,17 +245,19 @@ class MachineManagerModel(QObject): def removeMachine(self, machine_id): UM.Settings.ContainerRegistry.getInstance().removeContainer(machine_id) - @pyqtProperty(bool) + @pyqtProperty(bool, notify = globalContainerChanged) def hasMaterials(self): - # Todo: Still hardcoded. - # We should implement this properly when it's clear how a machine notifies us if it can handle materials - return True + if self._global_container_stack: + return self._global_container_stack.getMetaDataEntry("has_materials", False) - @pyqtProperty(bool) + return False + + @pyqtProperty(bool, notify = globalContainerChanged) def hasVariants(self): - # Todo: Still hardcoded. - # We should implement this properly when it's clear how a machine notifies us if it can handle variants - return True + if self._global_container_stack: + return self._global_container_stack.getMetaDataEntry("has_variants", False) + + return False def createMachineManagerModel(engine, script_engine): return MachineManagerModel() diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index cc0d1b1600..e7fb946bb6 100644 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -57,7 +57,8 @@ class CuraEngineBackend(Backend): #When any setting property changed, call the _onSettingChanged function. #This function will then see if we need to start slicing. - Application.getInstance().getGlobalContainerStack().propertyChanged.connect(self._onSettingChanged) + if Application.getInstance().getGlobalContainerStack(): + Application.getInstance().getGlobalContainerStack().propertyChanged.connect(self._onSettingChanged) #When you update a setting and other settings get changed through inheritance, many propertyChanged signals are fired. #This timer will group them up, and only slice for the last setting changed signal. diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index 5566301a09..50c39238fd 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -2,10 +2,16 @@ # Cura is released under the terms of the AGPLv3 or higher. import math +import copy import xml.etree.ElementTree as ET +from UM.Logger import Logger + import UM.Settings +# The namespace is prepended to the tag name but between {}. +# We are only interested in the actual tag name, so discard everything +# before the last } def _tag_without_namespace(element): return element.tag[element.tag.rfind("}") + 1:] @@ -17,7 +23,6 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer): raise NotImplementedError("Writing material profiles has not yet been implemented") def deserialize(self, serialized): - print("deserialize material profile") data = ET.fromstring(serialized) self.addMetaDataEntry("type", "material") @@ -27,9 +32,7 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer): metadata = data.iterfind("./um:metadata/*", self.__namespaces) for entry in metadata: - # The namespace is prepended to the tag name but between {}. - # We are only interested in the actual tag name. - tag_name = entry.tag[entry.tag.rfind("}") + 1:] + tag_name = _tag_without_namespace(entry) if tag_name == "name": brand = entry.find("./um:brand", self.__namespaces) @@ -47,7 +50,7 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer): property_values = {} properties = data.iterfind("./um:properties/*", self.__namespaces) for entry in properties: - tag_name = entry.tag[entry.tag.rfind("}") + 1:] + tag_name = _tag_without_namespace(entry) property_values[tag_name] = entry.text diameter = float(property_values.get("diameter", 2.85)) # In mm @@ -66,12 +69,50 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer): self.addMetaDataEntry("properties", property_values) + global_setting_values = {} settings = data.iterfind("./um:settings/um:setting", self.__namespaces) for entry in settings: - tag_name = _tag_without_namespace(entry) + key = entry.get("key") + if key in self.__material_property_setting_map: + self.setProperty(self.__material_property_setting_map[key], "value", entry.text, self._definition) + global_setting_values[key] = entry.text + + machines = data.iterfind("./um:settings/um:machine", self.__namespaces) + for machine in machines: + machine_setting_values = {} + settings = machine.iterfind("./um:setting", self.__namespaces) + for entry in settings: + key = entry.get("key") + if key in self.__material_property_setting_map: + machine_setting_values[self.__material_property_setting_map[key]] = entry.text + + identifiers = machine.iterfind("./um:machine_identifier", self.__namespaces) + for identifier in identifiers: + machine_id = self.__product_id_map.get(identifier.get("product"), None) + if machine_id is None: + Logger.log("w", "Cannot create material for unknown machine %s", machine_id) + continue + + definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id = machine_id) + if not definitions: + Logger.log("w", "No definition found for machine ID %s", machine_id) + continue + + new_material = XmlMaterialProfile(self.id + "_" + machine_id) + new_material.setName(self.getName()) + new_material.setMetaData(self.getMetaData()) + new_material.setDefinition(definitions[0]) + + for key, value in global_setting_values.items(): + new_material.setProperty(key, "value", value, definitions[0]) + + for key, value in machine_setting_values.items(): + new_material.setProperty(key, "value", value, definitions[0]) + + new_material._dirty = False + + UM.Settings.ContainerRegistry.getInstance().addContainer(new_material) - if tag_name in self.__material_property_setting_map: - self.setProperty(self.__material_property_setting_map[tag_name], "value", entry.text) __material_property_setting_map = { "print temperature": "material_print_temperature", @@ -79,6 +120,16 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer): "standby temperature": "material_standby_temperature", } + __product_id_map = { + "Ultimaker2": "ultimaker2", + "Ultimaker2+": "ultimaker2_plus", + "Ultimaker2go": "ultimaker2_go", + "Ultimaker2extended": "ultimaker2_extended", + "Ultimaker2extended+": "ultimaker2_extended_plus", + "Ultimaker Original": "ultimaker_original", + "Ultimaker Original+": "ultimaker_original_plus" + } + __namespaces = { "um": "http://www.ultimaker.com/material" } diff --git a/resources/definitions/ultimaker2_plus.def.json b/resources/definitions/ultimaker2_plus.def.json index 646b424c5c..9f68c2a16b 100644 --- a/resources/definitions/ultimaker2_plus.def.json +++ b/resources/definitions/ultimaker2_plus.def.json @@ -10,7 +10,10 @@ "category": "Ultimaker", "file_formats": "text/x-gcode", "platform": "ultimaker2_platform.obj", - "platform_texture": "Ultimaker2Plusbackplate.png" + "platform_texture": "Ultimaker2Plusbackplate.png", + "preferred_variant": "ultimaker2_plus_0.4", + "preferred_material": "pla", + "preferred_quality": "high" }, "overrides": { diff --git a/resources/materials/generic_pla.xml.fdm_material b/resources/materials/generic_pla.xml.fdm_material index b64ecdc61b..a4fe02c195 100644 --- a/resources/materials/generic_pla.xml.fdm_material +++ b/resources/materials/generic_pla.xml.fdm_material @@ -16,7 +16,6 @@ Generic PLA profile. Serves as an example file, data in this file is not correct 1.3 2.85 - 750 210 @@ -24,9 +23,8 @@ Generic PLA profile. Serves as an example file, data in this file is not correct 175 - - - + + 150 @@ -36,6 +34,7 @@ Generic PLA profile. Serves as an example file, data in this file is not correct + 150 80 diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index 52a8498f5e..42098e9883 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -813,9 +813,8 @@ UM.MainWindow base.visible = true; restart(); } - else if(Cura.MachineManager.activeMachineName == "") + else if(Cura.MachineManager.activeMachineId == null || Cura.MachineManager.activeMachineId == "") { - addMachineDialog.firstRun = true; addMachineDialog.open(); } } diff --git a/resources/qml/Preferences/MaterialsPage.qml b/resources/qml/Preferences/MaterialsPage.qml index f1f3432a41..03ede39a5c 100644 --- a/resources/qml/Preferences/MaterialsPage.qml +++ b/resources/qml/Preferences/MaterialsPage.qml @@ -6,6 +6,7 @@ import QtQuick.Controls 1.1 import QtQuick.Dialogs 1.2 import UM 1.2 as UM +import Cura 1.0 as Cura UM.ManagementPage { @@ -13,7 +14,7 @@ UM.ManagementPage title: catalog.i18nc("@title:tab", "Materials"); - model: UM.InstanceContainersModel { filter: { "type": "material" } } + model: UM.InstanceContainersModel { filter: { "type": "material", "definition": Cura.MachineManager.activeDefinitionId } } /* onAddObject: { var selectedMaterial = UM.MaterialManager.createProfile(); base.selectMaterial(selectedMaterial); } onRemoveObject: confirmDialog.open(); diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 5284178ba7..d8bc4291bb 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -197,7 +197,7 @@ Item id: materialSelectionInstantiator model: UM.InstanceContainersModel { - filter: {"type": "material"} + filter: { "type": "material", "definition": Cura.MachineManager.activeDefinitionId } } MenuItem { diff --git a/resources/quality/high.inst.cfg b/resources/quality/high.inst.cfg index 89dcd4c9bc..0329e9ffe1 100644 --- a/resources/quality/high.inst.cfg +++ b/resources/quality/high.inst.cfg @@ -7,3 +7,4 @@ definition = fdmprinter type = quality [values] +layer_height = 0.06