From 6a2e5ffe771831bfa3cfb8482a5aeac62ec469c8 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 30 Aug 2016 14:48:34 +0200 Subject: [PATCH 1/5] Added inheritance support to XML material profile deserialization CURA-2108 --- .../XmlMaterialProfile/XmlMaterialProfile.py | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index 77f775ee27..c1db8f8f2f 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -7,8 +7,10 @@ import io import xml.etree.ElementTree as ET import uuid +from UM.Resources import Resources from UM.Logger import Logger from UM.Util import parseBool +from cura.CuraApplication import CuraApplication import UM.Dictionary @@ -246,6 +248,51 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer): return stream.getvalue() + # Recursively resolve loading inherited files + def _resolveInheritance(self, file_name): + xml = self._loadFile(file_name) + + inherits = xml.find("./um:inherits", self.__namespaces) + if inherits is not None: + inherited = self._resolveInheritance(inherits.text) + xml = self._mergeXML(inherited, xml) + + return xml + + def _loadFile(self, file_name): + path = Resources.getPath(CuraApplication.getInstance().ResourceTypes.MaterialInstanceContainer, file_name + ".xml.fdm_material") + + contents = {} + with open(path, encoding="utf-8") as f: + contents = f.read() + + #self._inherited_files.append(path) + return ET.fromstring(contents) + + def _mergeXML(self, first, second): + result = copy.deepcopy(first) + self._combineElement(result, second) + return result + + # Recursively merges XML elements. Updates either the text or children if another element is found in first. + # If it does not exist, copies it from second. + def _combineElement(self, first, second): + # Create a mapping from tag name to element. + mapping = {el.tag: el for el in first} + for el in second: + if len(el): # Check if element has children. + try: + self._combineElement(mapping[el.tag], el) # Multiple elements, handle those. + except KeyError: + mapping[el.tag] = el + first.append(el) + else: + try: + mapping[el.tag].text = el.text + except KeyError: # Not in the mapping, so simply add it + mapping[el.tag] = el + first.append(el) + ## Overridden from InstanceContainer def deserialize(self, serialized): data = ET.fromstring(serialized) @@ -255,6 +302,11 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer): # TODO: Add material verfication self.addMetaDataEntry("status", "unknown") + #for inherit in data.findall("./um:inherits", self.__namespaces): + inherits = data.find("./um:inherits", self.__namespaces) + if inherits is not None: + inherited = self._resolveInheritance(inherits.text) + data = self._mergeXML(inherited, data) metadata = data.iterfind("./um:metadata/*", self.__namespaces) for entry in metadata: From 7a54f21633eccad82c88c15adbc7b8e899d0cdc4 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 30 Aug 2016 14:51:27 +0200 Subject: [PATCH 2/5] Added inherited_files property --- plugins/XmlMaterialProfile/XmlMaterialProfile.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index c1db8f8f2f..f9d2fc4e4b 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -20,6 +20,7 @@ import UM.Settings class XmlMaterialProfile(UM.Settings.InstanceContainer): def __init__(self, container_id, *args, **kwargs): super().__init__(container_id, *args, **kwargs) + self._inherited_files = [] ## Overridden from InstanceContainer def duplicate(self, new_id, new_name = None): @@ -262,11 +263,10 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer): def _loadFile(self, file_name): path = Resources.getPath(CuraApplication.getInstance().ResourceTypes.MaterialInstanceContainer, file_name + ".xml.fdm_material") - contents = {} with open(path, encoding="utf-8") as f: contents = f.read() - #self._inherited_files.append(path) + self._inherited_files.append(path) return ET.fromstring(contents) def _mergeXML(self, first, second): From 0a811b2164ee56b1697e2ca34d7ae921443e808e Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 30 Aug 2016 15:42:37 +0200 Subject: [PATCH 3/5] Added more logging to changing of containers CURA-2108 --- cura/Settings/MachineManager.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 5bfc27f334..75bd588c76 100644 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -502,7 +502,7 @@ class MachineManager(QObject): containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = material_id) if not containers or not self._active_container_stack: return - + Logger.log("d", "Attempting to change the active material to %s", material_id) old_variant = self._active_container_stack.findContainer({"type": "variant"}) old_material = self._active_container_stack.findContainer({"type": "material"}) old_quality = self._active_container_stack.findContainer({"type": "quality"}) @@ -535,6 +535,7 @@ class MachineManager(QObject): containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = variant_id) if not containers or not self._active_container_stack: return + Logger.log("d", "Attempting to change the active variant to %s", variant_id) old_variant = self._active_container_stack.findContainer({"type": "variant"}) old_material = self._active_container_stack.findContainer({"type": "material"}) if old_variant: @@ -554,6 +555,9 @@ class MachineManager(QObject): containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = quality_id) if not containers or not self._global_container_stack: return + + Logger.log("d", "Attempting to change the active quality to %s", quality_id) + self.blurSettings.emit() quality_container = None quality_changes_container = self._empty_quality_changes_container From dcbf7b5a355f42cd1e5e2e9b74dd966706c3b5db Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 30 Aug 2016 16:01:21 +0200 Subject: [PATCH 4/5] When unable to find quality for material, we also use inherited files (if any) to resolve it CURA-2108 --- cura/Settings/MachineManager.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 75bd588c76..348ce6a49c 100644 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -19,6 +19,7 @@ from UM.i18n import i18nCatalog catalog = i18nCatalog("cura") import time +import os class MachineManager(QObject): def __init__(self, parent = None): @@ -833,7 +834,22 @@ class MachineManager(QObject): return containers[0] if "material" in search_criteria: - # If a quality for this specific material cannot be found, try finding qualities for a generic version of the material + # First check if we can solve our material not found problem by checking if we can find quality containers + # that are assigned to the parents of this material profile. + try: + inherited_files = material_container.getInheritedFiles() + if inherited_files: + for inherited_file in inherited_files: + # Extract the ID from the path we used to load the file. + search_criteria["material"] = os.path.basename(inherited_file).split(".")[0] + containers = container_registry.findInstanceContainers(**search_criteria) + if containers: + return containers[0] + except AttributeError: # Material_container does not support inheritance. + pass + + # We still weren't able to find a quality for this specific material. + # Try to find qualities for a generic version of the material. material_search_criteria = { "type": "material", "material": material_container.getMetaDataEntry("material"), "color_name": "Generic" } if definition.getMetaDataEntry("has_machine_quality"): if material_container: From 1940d45971c7677f4b7048569e9017adea12e726 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 30 Aug 2016 16:04:05 +0200 Subject: [PATCH 5/5] Added way to acces inherited files CURA-2108 --- plugins/XmlMaterialProfile/XmlMaterialProfile.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index f9d2fc4e4b..b5337258e5 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -51,6 +51,9 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer): result.setMetaDataEntry("base_file", result.id) return result + def getInheritedFiles(self): + return self._inherited_files + ## Overridden from InstanceContainer def setReadOnly(self, read_only): super().setReadOnly(read_only)