Browse Source

Have variant nodes build their own children

When a variant and a variant love each other...

Contributes to issue CURA-6600.
Ghostkeeper 5 years ago
parent
commit
b46d4eb2b5
2 changed files with 65 additions and 1 deletions
  1. 2 0
      cura/Machines/MachineNode.py
  2. 63 1
      cura/Machines/VariantNode.py

+ 2 - 0
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()

+ 63 - 1
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.
+        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)