diff --git a/cura/Machines/MachineNode.py b/cura/Machines/MachineNode.py index a062f0eae0..65aab19d72 100644 --- a/cura/Machines/MachineNode.py +++ b/cura/Machines/MachineNode.py @@ -3,6 +3,7 @@ from typing import TYPE_CHECKING +from UM.Util import parseBool from UM.Settings.ContainerRegistry import ContainerRegistry # To find all the variants for this machine. from UM.Settings.Interfaces import ContainerInterface from cura.Machines.ContainerNode import ContainerNode @@ -19,6 +20,7 @@ class MachineNode(ContainerNode): super().__init__(container_id, None) self.variants = {} # type: Dict[str, VariantNode] # mapping variant names to their nodes. container_registry = ContainerRegistry.getInstance() + self.has_machine_materials = parseBool(container_registry.findContainersMetadata(id = container_id)[0].get("has_machine_materials", "true")) container_registry.allMetadataLoaded.connect(self._reloadAll) container_registry.containerAdded.connect(self._variantAdded) self._reloadAll() diff --git a/cura/Machines/VariantNode.py b/cura/Machines/VariantNode.py index 93410f2a61..bd2bb63862 100644 --- a/cura/Machines/VariantNode.py +++ b/cura/Machines/VariantNode.py @@ -3,6 +3,8 @@ from typing import TYPE_CHECKING +from UM.Settings.ContainerRegistry import ContainerRegistry +from UM.Settings.Interfaces import ContainerInterface from cura.Machines.ContainerNode import ContainerNode from cura.Machines.MachineNode import MachineNode from cura.Machines.MaterialNode import MaterialNode @@ -13,7 +15,67 @@ if TYPE_CHECKING: ## This class represents an extruder variant in the container tree. # # The subnodes of these nodes are materials. +# +# This node contains materials with ALL filament diameters underneath it. The +# tree of this variant is not specific to one global stack, so because the +# list of materials can be different per stack depending on the compatible +# material diameter setting, we cannot filter them here. Filtering must be +# done in the model. class VariantNode(ContainerNode): def __init__(self, container_id: str, parent: MachineNode) -> None: super().__init__(container_id, parent) - self.variants = {} # type: Dict[str, MaterialNode] # mapping variant IDs to their nodes. \ No newline at end of file + self.materials = {} # type: Dict[str, MaterialNode] # Mapping material base files to their nodes. + container_registry = ContainerRegistry.getInstance() + self.variant_name = container_registry.findContainersMetadata(id = container_id)[0]["name"] #Store our own name so that we can filter more easily. + container_registry.allMetadataLoaded.connect(self._reloadAll) + container_registry.containerAdded.connect(self._materialAdded) + self._reloadAll() + + ## (Re)loads all materials under this variant. + def _reloadAll(self): + container_registry = ContainerRegistry.getInstance() + # Find all the materials for this variant's name. + if not self.parent.has_machine_materials: # Printer has no specific materials. Look for all fdmprinter materials. + materials = container_registry.findInstanceContainersMetadata(type = "material", definition = "fdmprinter") # These are ONLY the base materials. + else: # Printer has its own material profiles. Look for material profiles with this printer's definition. + all_materials = container_registry.findInstanceContainersMetadata(type = "material", definition = "fdmprinter") + printer_specific_materials = container_registry.findInstanceContainersMetadata(type = "material", definition = self.parent.container_id) + variant_specific_materials = container_registry.findInstanceContainersMetadata(type = "material", definition = self.parent.container_id, variant = self.variant_name) + materials_per_base_file = {material["base_file"]: material for material in all_materials} + materials_per_base_file.update({material["base_file"]: material for material in printer_specific_materials}) # Printer-specific profiles override global ones. + materials_per_base_file.update({material["base_file"]: material for material in variant_specific_materials}) # Variant-specific profiles override all of those. + materials = materials_per_base_file.values() + + for material in materials: + base_file = material["base_file"] + if base_file not in self.materials: + self.materials[base_file] = MaterialNode(material["id"], parent = self) + + ## When a material gets added to the set of profiles, we need to update our + # tree here. + def _materialAdded(self, container: ContainerInterface): + if container.getMetaDataEntry("type") != "material": + return # Not interested. + material_definition = container.getMetaDataEntry("definition") + if not self.parent.has_machine_materials: + if material_definition != "fdmprinter": + return + base_file = container.getMetaDataEntry("base_file") + if base_file not in self.materials: # Completely new base file. Always better than not having a file as long as it matches our set-up. + if material_definition != "fdmprinter" and material_definition != self.parent.container_id: + return + material_variant = container.getMetaDataEntry("variant", "empty") + if material_variant != "empty" and material_variant != self.variant_name: + return + else: # We already have this base profile. Replace the base profile if the new one is more specific. + new_definition = container.getMetaDataEntry("definition") + if new_definition == "fdmprinter": + return # Just as unspecific or worse. + if new_definition != self.parent.container_id: + return # Doesn't match this set-up. + original_metadata = ContainerRegistry.getInstance().findContainersMetadata(id = self.materials[base_file].container_id)[0] + original_variant = original_metadata.get("variant", "empty") + if original_variant != "empty" or container.getMetaDataEntry("variant", "empty") == "empty": + return # Original was already specific or just as unspecific as the new one. + + self.materials[base_file] = MaterialNode(container.getId(), parent = self) \ No newline at end of file