IntentModel.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. # Copyright (c) 2019 Ultimaker B.V.
  2. # Cura is released under the terms of the LGPLv3 or higher.
  3. from typing import Optional, Dict, Any, Set, List
  4. from PyQt5.QtCore import Qt, QObject, pyqtProperty, pyqtSignal
  5. import cura.CuraApplication
  6. from UM.Qt.ListModel import ListModel
  7. from UM.Settings.ContainerRegistry import ContainerRegistry
  8. from cura.Machines.ContainerTree import ContainerTree
  9. from cura.Machines.MaterialNode import MaterialNode
  10. from cura.Machines.Models.MachineModelUtils import fetch_layer_height
  11. from cura.Machines.QualityGroup import QualityGroup
  12. class IntentModel(ListModel):
  13. NameRole = Qt.UserRole + 1
  14. QualityTypeRole = Qt.UserRole + 2
  15. LayerHeightRole = Qt.UserRole + 3
  16. AvailableRole = Qt.UserRole + 4
  17. IntentRole = Qt.UserRole + 5
  18. def __init__(self, parent: Optional[QObject] = None) -> None:
  19. super().__init__(parent)
  20. self.addRoleName(self.NameRole, "name")
  21. self.addRoleName(self.QualityTypeRole, "quality_type")
  22. self.addRoleName(self.LayerHeightRole, "layer_height")
  23. self.addRoleName(self.AvailableRole, "available")
  24. self.addRoleName(self.IntentRole, "intent_category")
  25. self._intent_category = "engineering"
  26. machine_manager = cura.CuraApplication.CuraApplication.getInstance().getMachineManager()
  27. machine_manager.globalContainerChanged.connect(self._update)
  28. machine_manager.extruderChanged.connect(self._update) # We also need to update if an extruder gets disabled
  29. ContainerRegistry.getInstance().containerAdded.connect(self._onChanged)
  30. ContainerRegistry.getInstance().containerRemoved.connect(self._onChanged)
  31. self._layer_height_unit = "" # This is cached
  32. self._update()
  33. intentCategoryChanged = pyqtSignal()
  34. def setIntentCategory(self, new_category: str) -> None:
  35. if self._intent_category != new_category:
  36. self._intent_category = new_category
  37. self.intentCategoryChanged.emit()
  38. self._update()
  39. @pyqtProperty(str, fset = setIntentCategory, notify = intentCategoryChanged)
  40. def intentCategory(self) -> str:
  41. return self._intent_category
  42. def _onChanged(self, container):
  43. if container.getMetaDataEntry("type") == "intent":
  44. self._update()
  45. def _update(self) -> None:
  46. new_items = [] # type: List[Dict[str, Any]]
  47. global_stack = cura.CuraApplication.CuraApplication.getInstance().getGlobalContainerStack()
  48. if not global_stack:
  49. self.setItems(new_items)
  50. return
  51. quality_groups = ContainerTree.getInstance().getCurrentQualityGroups()
  52. material_nodes = self._get_active_materials()
  53. layer_heights_added = []
  54. for material_node in material_nodes:
  55. intents = self._get_intents_for_material(material_node, quality_groups)
  56. for intent in intents:
  57. if intent["layer_height"] not in layer_heights_added:
  58. new_items.append(intent)
  59. layer_heights_added.append(intent["layer_height"])
  60. # Now that we added all intents that we found something for, ensure that we set add ticks (and layer_heights)
  61. # for all groups that we don't have anything for (and set it to not available)
  62. for quality_tuple, quality_group in quality_groups.items():
  63. # Add the intents that are of the correct category
  64. if quality_tuple[0] != self._intent_category:
  65. layer_height = fetch_layer_height(quality_group)
  66. if layer_height not in layer_heights_added:
  67. new_items.append({"name": "Unavailable",
  68. "quality_type": "",
  69. "layer_height": layer_height,
  70. "intent_category": self._intent_category,
  71. "available": False})
  72. layer_heights_added.append(layer_height)
  73. new_items = sorted(new_items, key=lambda x: x["layer_height"])
  74. self.setItems(new_items)
  75. ## Get the active materials for all extruders. No duplicates will be returned
  76. def _get_active_materials(self) -> Set[MaterialNode]:
  77. global_stack = cura.CuraApplication.CuraApplication.getInstance().getGlobalContainerStack()
  78. container_tree = ContainerTree.getInstance()
  79. machine_node = container_tree.machines[global_stack.definition.getId()]
  80. nodes = set() # type: Set[MaterialNode]
  81. for extruder in global_stack.extruderList:
  82. active_variant_name = extruder.variant.getMetaDataEntry("name")
  83. active_variant_node = machine_node.variants[active_variant_name]
  84. active_material_node = active_variant_node.materials[extruder.material.getMetaDataEntry("base_file")]
  85. nodes.add(active_material_node)
  86. return nodes
  87. def _get_intents_for_material(self, active_material_node: MaterialNode, quality_groups: Dict[str, QualityGroup]) -> List[Dict[str, Any]]:
  88. extruder_intents = [] # type: List[Dict[str, Any]]
  89. for quality_id, quality_node in active_material_node.qualities.items():
  90. if quality_node.quality_type not in quality_groups: # Don't add the empty quality type (or anything else that would crash, defensively).
  91. continue
  92. quality_group = quality_groups[quality_node.quality_type]
  93. layer_height = fetch_layer_height(quality_group)
  94. for intent_id, intent_node in quality_node.intents.items():
  95. if intent_node.intent_category != self._intent_category:
  96. continue
  97. extruder_intents.append({"name": quality_group.name,
  98. "quality_type": quality_group.quality_type,
  99. "layer_height": layer_height,
  100. "available": quality_group.is_available,
  101. "intent_category": self._intent_category
  102. })
  103. return extruder_intents
  104. def __repr__(self):
  105. return str(self.items)