VariantNode.py 5.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. # Copyright (c) 2019 Ultimaker B.V.
  2. # Cura is released under the terms of the LGPLv3 or higher.
  3. from typing import TYPE_CHECKING
  4. from UM.Settings.ContainerRegistry import ContainerRegistry
  5. from UM.Settings.Interfaces import ContainerInterface
  6. from cura.Machines.ContainerNode import ContainerNode
  7. from cura.Machines.MaterialNode import MaterialNode
  8. if TYPE_CHECKING:
  9. from typing import Dict
  10. from cura.Machines.MachineNode import MachineNode
  11. ## This class represents an extruder variant in the container tree.
  12. #
  13. # The subnodes of these nodes are materials.
  14. #
  15. # This node contains materials with ALL filament diameters underneath it. The
  16. # tree of this variant is not specific to one global stack, so because the
  17. # list of materials can be different per stack depending on the compatible
  18. # material diameter setting, we cannot filter them here. Filtering must be
  19. # done in the model.
  20. class VariantNode(ContainerNode):
  21. def __init__(self, container_id: str, machine: "MachineNode") -> None:
  22. super().__init__(container_id)
  23. self.machine = machine
  24. self.materials = {} # type: Dict[str, MaterialNode] # Mapping material base files to their nodes.
  25. container_registry = ContainerRegistry.getInstance()
  26. self.variant_name = container_registry.findContainersMetadata(id = container_id)[0]["name"] # Store our own name so that we can filter more easily.
  27. container_registry.containerAdded.connect(self._materialAdded)
  28. self._loadAll()
  29. ## (Re)loads all materials under this variant.
  30. def _loadAll(self):
  31. container_registry = ContainerRegistry.getInstance()
  32. # Find all the materials for this variant's name.
  33. if not self.machine.has_machine_materials: # Printer has no specific materials. Look for all fdmprinter materials.
  34. materials = container_registry.findInstanceContainersMetadata(type = "material", definition = "fdmprinter") # These are ONLY the base materials.
  35. else: # Printer has its own material profiles. Look for material profiles with this printer's definition.
  36. all_materials = container_registry.findInstanceContainersMetadata(type = "material", definition = "fdmprinter")
  37. printer_specific_materials = container_registry.findInstanceContainersMetadata(type = "material", definition = self.machine.container_id)
  38. variant_specific_materials = container_registry.findInstanceContainersMetadata(type = "material", definition = self.machine.container_id, variant = self.variant_name)
  39. materials_per_base_file = {material["base_file"]: material for material in all_materials}
  40. materials_per_base_file.update({material["base_file"]: material for material in printer_specific_materials}) # Printer-specific profiles override global ones.
  41. materials_per_base_file.update({material["base_file"]: material for material in variant_specific_materials}) # Variant-specific profiles override all of those.
  42. materials = materials_per_base_file.values()
  43. for excluded_material in self.machine.exclude_materials:
  44. del materials[excluded_material]
  45. for material in materials:
  46. base_file = material["base_file"]
  47. if base_file not in self.materials:
  48. self.materials[base_file] = MaterialNode(material["id"], variant = self)
  49. ## When a material gets added to the set of profiles, we need to update our
  50. # tree here.
  51. def _materialAdded(self, container: ContainerInterface):
  52. if container.getMetaDataEntry("type") != "material":
  53. return # Not interested.
  54. material_definition = container.getMetaDataEntry("definition")
  55. if not self.machine.has_machine_materials:
  56. if material_definition != "fdmprinter":
  57. return
  58. base_file = container.getMetaDataEntry("base_file")
  59. if base_file in self.machine.exclude_materials:
  60. return # Material is forbidden for this printer.
  61. 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.
  62. if material_definition != "fdmprinter" and material_definition != self.machine.container_id:
  63. return
  64. material_variant = container.getMetaDataEntry("variant", "empty")
  65. if material_variant != "empty" and material_variant != self.variant_name:
  66. return
  67. else: # We already have this base profile. Replace the base profile if the new one is more specific.
  68. new_definition = container.getMetaDataEntry("definition")
  69. if new_definition == "fdmprinter":
  70. return # Just as unspecific or worse.
  71. if new_definition != self.machine.container_id:
  72. return # Doesn't match this set-up.
  73. original_metadata = ContainerRegistry.getInstance().findContainersMetadata(id = self.materials[base_file].container_id)[0]
  74. original_variant = original_metadata.get("variant", "empty")
  75. if original_variant != "empty" or container.getMetaDataEntry("variant", "empty") == "empty":
  76. return # Original was already specific or just as unspecific as the new one.
  77. self.materials[base_file] = MaterialNode(container.getId(), variant = self)