Merge branch 'feature_material_inheritance' of github.com:Ultimaker/Cura

This commit is contained in:
Jaime van Kessel 2016-08-30 16:05:10 +02:00
commit fbbbdb61e3
2 changed files with 77 additions and 2 deletions

View file

@ -19,6 +19,7 @@ from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
import time
import os
class MachineManager(QObject):
def __init__(self, parent = None):
@ -502,7 +503,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 +536,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 +556,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
@ -829,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:

View file

@ -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
@ -18,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):
@ -48,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)
@ -246,6 +252,50 @@ 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")
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 +305,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: