MaterialNode.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. # Copyright (c) 2019 Ultimaker B.V.
  2. # Cura is released under the terms of the LGPLv3 or higher.
  3. from typing import Any, TYPE_CHECKING
  4. from UM.Settings.ContainerRegistry import ContainerRegistry
  5. from UM.Settings.Interfaces import ContainerInterface
  6. from UM.Signal import Signal
  7. from cura.Machines.ContainerNode import ContainerNode
  8. from cura.Machines.QualityNode import QualityNode
  9. if TYPE_CHECKING:
  10. from typing import Dict
  11. from cura.Machines.VariantNode import VariantNode
  12. ## Represents a material in the container tree.
  13. #
  14. # Its subcontainers are quality profiles.
  15. class MaterialNode(ContainerNode):
  16. def __init__(self, container_id, variant: "VariantNode") -> None:
  17. super().__init__(container_id)
  18. self.variant = variant
  19. self.qualities = {} # type: Dict[str, QualityNode] # Mapping container IDs to quality profiles.
  20. self.materialChanged = Signal() # Triggered when the material is removed or its metadata is updated.
  21. container_registry = ContainerRegistry.getInstance()
  22. my_metadata = container_registry.findContainersMetadata(id = container_id)[0]
  23. self.base_file = my_metadata["base_file"]
  24. self.material_type = my_metadata["material"]
  25. self.guid = my_metadata["GUID"]
  26. self._loadAll()
  27. container_registry.containerRemoved.connect(self._onRemoved)
  28. container_registry.containerMetaDataChanged.connect(self._onMetadataChanged)
  29. def _loadAll(self) -> None:
  30. container_registry = ContainerRegistry.getInstance()
  31. # Find all quality profiles that fit on this material.
  32. if not self.variant.machine.has_machine_quality: # Need to find the global qualities.
  33. qualities = container_registry.findInstanceContainersMetadata(type = "quality", definition = "fdmprinter")
  34. else:
  35. # Need to find the qualities that specify a material profile with the same material type.
  36. my_material_type = self.material_type
  37. qualities = []
  38. qualities_any_material = container_registry.findInstanceContainersMetadata(type = "quality", definition = self.variant.machine.quality_definition, variant = self.variant.variant_name)
  39. for material_metadata in container_registry.findInstanceContainersMetadata(type = "material", material = my_material_type):
  40. qualities.extend((quality for quality in qualities_any_material if quality["material"] == material_metadata["id"]))
  41. if not qualities: # No quality profiles found. Go by GUID then.
  42. my_guid = self.guid
  43. for material_metadata in container_registry.findInstanceContainersMetadata(type = "material", guid = my_guid):
  44. qualities.extend((quality for quality in qualities_any_material if quality["material"] == material_metadata["id"]))
  45. for quality in qualities:
  46. quality_id = quality["id"]
  47. if quality_id not in self.qualities:
  48. self.qualities[quality_id] = QualityNode(quality_id, parent = self)
  49. if not self.qualities:
  50. self.qualities["empty_quality"] = QualityNode("empty_quality", parent = self)
  51. ## Triggered when any container is removed, but only handles it when the
  52. # container is removed that this node represents.
  53. # \param container The container that was allegedly removed.
  54. def _onRemoved(self, container: ContainerInterface) -> None:
  55. if container.getId() == self.container_id:
  56. # Remove myself from my parent.
  57. if self.base_file in self.variant.materials:
  58. del self.variant.materials[self.base_file]
  59. if not self.variant.materials:
  60. self.variant.materials["empty_material"] = MaterialNode("empty_material", variant = self.variant)
  61. self.materialChanged.emit(self)
  62. ## Triggered when any metadata changed in any container, but only handles
  63. # it when the metadata of this node is changed.
  64. # \param container The container whose metadata changed.
  65. # \param kwargs Key-word arguments provided when changing the metadata.
  66. # These are ignored. As far as I know they are never provided to this
  67. # call.
  68. def _onMetadataChanged(self, container: ContainerInterface, **kwargs: Any) -> None:
  69. if container.getId() != self.container_id:
  70. return
  71. new_metadata = container.getMetaData()
  72. old_base_file = self.base_file
  73. if new_metadata["base_file"] != old_base_file:
  74. self.base_file = new_metadata["base_file"]
  75. if old_base_file in self.variant.materials: # Move in parent node.
  76. del self.variant.materials[old_base_file]
  77. self.variant.materials[self.base_file] = self
  78. old_material_type = self.material_type
  79. self.material_type = new_metadata["material"]
  80. old_guid = self.guid
  81. self.guid = new_metadata["GUID"]
  82. if self.base_file != old_base_file or self.material_type != old_material_type or self.guid != old_guid: # List of quality profiles could've changed.
  83. self.qualities = {}
  84. self._loadAll() # Re-load the quality profiles for this node.
  85. self.materialChanged.emit(self)