VariantManager.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. # Copyright (c) 2018 Ultimaker B.V.
  2. # Cura is released under the terms of the LGPLv3 or higher.
  3. from enum import Enum
  4. from collections import OrderedDict
  5. from typing import Optional, TYPE_CHECKING
  6. from UM.Logger import Logger
  7. from UM.Settings.ContainerRegistry import ContainerRegistry
  8. from UM.Util import parseBool
  9. from cura.Machines.ContainerNode import ContainerNode
  10. from cura.Settings.GlobalStack import GlobalStack
  11. if TYPE_CHECKING:
  12. from UM.Settings.DefinitionContainer import DefinitionContainer
  13. class VariantType(Enum):
  14. BUILD_PLATE = "buildplate"
  15. NOZZLE = "nozzle"
  16. ALL_VARIANT_TYPES = (VariantType.BUILD_PLATE, VariantType.NOZZLE)
  17. #
  18. # VariantManager is THE place to look for a specific variant. It maintains a variant lookup table with the following
  19. # structure:
  20. #
  21. # [machine_definition_id] -> [variant_type] -> [variant_name] -> ContainerNode(metadata / container)
  22. # Example: "ultimaker3" -> "buildplate" -> "Glass" (if present) -> ContainerNode
  23. # -> ...
  24. # -> "nozzle" -> "AA 0.4"
  25. # -> "BB 0.8"
  26. # -> ...
  27. #
  28. # Note that the "container" field is not loaded in the beginning because it would defeat the purpose of lazy-loading.
  29. # A container is loaded when getVariant() is called to load a variant InstanceContainer.
  30. #
  31. class VariantManager:
  32. def __init__(self, container_registry):
  33. self._container_registry = container_registry # type: ContainerRegistry
  34. self._machine_to_variant_dict_map = dict() # <machine_type> -> <variant_dict>
  35. self._exclude_variant_id_list = ["empty_variant"]
  36. #
  37. # Initializes the VariantManager including:
  38. # - initializing the variant lookup table based on the metadata in ContainerRegistry.
  39. #
  40. def initialize(self):
  41. self._machine_to_variant_dict_map = OrderedDict()
  42. # Cache all variants from the container registry to a variant map for better searching and organization.
  43. variant_metadata_list = self._container_registry.findContainersMetadata(type = "variant")
  44. for variant_metadata in variant_metadata_list:
  45. if variant_metadata["id"] in self._exclude_variant_id_list:
  46. Logger.log("d", "Exclude variant [%s]", variant_metadata["id"])
  47. continue
  48. variant_name = variant_metadata["name"]
  49. variant_definition = variant_metadata["definition"]
  50. if variant_definition not in self._machine_to_variant_dict_map:
  51. self._machine_to_variant_dict_map[variant_definition] = OrderedDict()
  52. for variant_type in ALL_VARIANT_TYPES:
  53. self._machine_to_variant_dict_map[variant_definition][variant_type] = dict()
  54. variant_type = variant_metadata["hardware_type"]
  55. variant_type = VariantType(variant_type)
  56. variant_dict = self._machine_to_variant_dict_map[variant_definition][variant_type]
  57. if variant_name in variant_dict:
  58. # ERROR: duplicated variant name.
  59. raise RuntimeError("Found duplicated variant name [%s], type [%s] for machine [%s]" %
  60. (variant_name, variant_type, variant_definition))
  61. variant_dict[variant_name] = ContainerNode(metadata = variant_metadata)
  62. #
  63. # Gets the variant InstanceContainer with the given information.
  64. # Almost the same as getVariantMetadata() except that this returns an InstanceContainer if present.
  65. #
  66. def getVariantNode(self, machine_definition_id: str, variant_name: str,
  67. variant_type: Optional["VariantType"] = None) -> Optional["ContainerNode"]:
  68. if variant_type is None:
  69. variant_node = None
  70. variant_type_dict = self._machine_to_variant_dict_map[machine_definition_id]
  71. for variant_dict in variant_type_dict.values():
  72. if variant_name in variant_dict:
  73. variant_node = variant_dict[variant_name]
  74. break
  75. return variant_node
  76. return self._machine_to_variant_dict_map[machine_definition_id].get(variant_type, {}).get(variant_name)
  77. def getVariantNodes(self, machine: "GlobalStack",
  78. variant_type: Optional["VariantType"] = None) -> dict:
  79. machine_definition_id = machine.definition.getId()
  80. return self._machine_to_variant_dict_map.get(machine_definition_id, {}).get(variant_type, {})
  81. #
  82. # Gets the default variant for the given machine definition.
  83. #
  84. def getDefaultVariantNode(self, machine_definition: "DefinitionContainer",
  85. variant_type: VariantType) -> Optional["ContainerNode"]:
  86. machine_definition_id = machine_definition.getId()
  87. preferred_variant_name = None
  88. if variant_type == VariantType.BUILD_PLATE:
  89. if parseBool(machine_definition.getMetaDataEntry("has_variant_buildplates", False)):
  90. preferred_variant_name = machine_definition.getMetaDataEntry("preferred_variant_buildplate_name")
  91. else:
  92. if parseBool(machine_definition.getMetaDataEntry("has_variants", False)):
  93. preferred_variant_name = machine_definition.getMetaDataEntry("preferred_variant_name")
  94. node = None
  95. if preferred_variant_name:
  96. node = self.getVariantNode(machine_definition_id, preferred_variant_name, variant_type)
  97. return node