BrandMaterialsModel.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. # Copyright (c) 2018 Ultimaker B.V.
  2. # Cura is released under the terms of the LGPLv3 or higher.
  3. from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty
  4. from UM.Qt.ListModel import ListModel
  5. from UM.Logger import Logger
  6. from cura.Machines.Models.BaseMaterialsModel import BaseMaterialsModel
  7. #
  8. # This is an intermediate model to group materials with different colours for a same brand and type.
  9. #
  10. class MaterialsModelGroupedByType(ListModel):
  11. NameRole = Qt.UserRole + 1
  12. ColorsRole = Qt.UserRole + 2
  13. def __init__(self, parent = None):
  14. super().__init__(parent)
  15. self.addRoleName(self.NameRole, "name")
  16. self.addRoleName(self.ColorsRole, "colors")
  17. #
  18. # This model is used to show branded materials in the material drop down menu.
  19. # The structure of the menu looks like this:
  20. # Brand -> Material Type -> list of materials
  21. #
  22. # To illustrate, a branded material menu may look like this:
  23. # Ultimaker -> PLA -> Yellow PLA
  24. # -> Black PLA
  25. # -> ...
  26. # -> ABS -> White ABS
  27. # ...
  28. #
  29. class BrandMaterialsModel(ListModel):
  30. NameRole = Qt.UserRole + 1
  31. MaterialsRole = Qt.UserRole + 2
  32. extruderPositionChanged = pyqtSignal()
  33. def __init__(self, parent = None):
  34. super().__init__(parent)
  35. self.addRoleName(self.NameRole, "name")
  36. self.addRoleName(self.MaterialsRole, "materials")
  37. self._extruder_position = 0
  38. self._extruder_stack = None
  39. from cura.CuraApplication import CuraApplication
  40. self._machine_manager = CuraApplication.getInstance().getMachineManager()
  41. self._extruder_manager = CuraApplication.getInstance().getExtruderManager()
  42. self._material_manager = CuraApplication.getInstance().getMaterialManager()
  43. self._machine_manager.globalContainerChanged.connect(self._updateExtruderStack)
  44. self._machine_manager.activeStackChanged.connect(self._update) #Update when switching machines.
  45. self._material_manager.materialsUpdated.connect(self._update) #Update when the list of materials changes.
  46. self._update()
  47. def _updateExtruderStack(self):
  48. global_stack = self._machine_manager.activeMachine
  49. if global_stack is None:
  50. return
  51. if self._extruder_stack is not None:
  52. self._extruder_stack.pyqtContainersChanged.disconnect(self._update)
  53. self._extruder_stack = global_stack.extruders.get(str(self._extruder_position))
  54. if self._extruder_stack is not None:
  55. self._extruder_stack.pyqtContainersChanged.connect(self._update)
  56. # Force update the model when the extruder stack changes
  57. self._update()
  58. def setExtruderPosition(self, position: int):
  59. if self._extruder_stack is None or self._extruder_position != position:
  60. self._extruder_position = position
  61. self._updateExtruderStack()
  62. self.extruderPositionChanged.emit()
  63. @pyqtProperty(int, fset=setExtruderPosition, notify=extruderPositionChanged)
  64. def extruderPosition(self) -> int:
  65. return self._extruder_position
  66. def _update(self):
  67. Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__))
  68. global_stack = self._machine_manager.activeMachine
  69. if global_stack is None:
  70. self.setItems([])
  71. return
  72. extruder_position = str(self._extruder_position)
  73. if extruder_position not in global_stack.extruders:
  74. self.setItems([])
  75. return
  76. extruder_stack = global_stack.extruders[str(self._extruder_position)]
  77. available_material_dict = self._material_manager.getAvailableMaterialsForMachineExtruder(global_stack,
  78. extruder_stack)
  79. if available_material_dict is None:
  80. self.setItems([])
  81. return
  82. brand_item_list = []
  83. brand_group_dict = {}
  84. for root_material_id, container_node in available_material_dict.items():
  85. metadata = container_node.metadata
  86. brand = metadata["brand"]
  87. # Only add results for generic materials
  88. if brand.lower() == "generic":
  89. continue
  90. if brand not in brand_group_dict:
  91. brand_group_dict[brand] = {}
  92. material_type = metadata["material"]
  93. if material_type not in brand_group_dict[brand]:
  94. brand_group_dict[brand][material_type] = []
  95. item = {"root_material_id": root_material_id,
  96. "id": metadata["id"],
  97. "name": metadata["name"],
  98. "brand": metadata["brand"],
  99. "material": metadata["material"],
  100. "color_name": metadata["color_name"],
  101. "container_node": container_node
  102. }
  103. brand_group_dict[brand][material_type].append(item)
  104. for brand, material_dict in brand_group_dict.items():
  105. brand_item = {"name": brand,
  106. "materials": MaterialsModelGroupedByType(self)}
  107. material_type_item_list = []
  108. for material_type, material_list in material_dict.items():
  109. material_type_item = {"name": material_type,
  110. "colors": BaseMaterialsModel(self)}
  111. material_type_item["colors"].clear()
  112. # Sort materials by name
  113. material_list = sorted(material_list, key = lambda x: x["name"].upper())
  114. material_type_item["colors"].setItems(material_list)
  115. material_type_item_list.append(material_type_item)
  116. # Sort material type by name
  117. material_type_item_list = sorted(material_type_item_list, key = lambda x: x["name"].upper())
  118. brand_item["materials"].setItems(material_type_item_list)
  119. brand_item_list.append(brand_item)
  120. # Sort brand by name
  121. brand_item_list = sorted(brand_item_list, key = lambda x: x["name"].upper())
  122. self.setItems(brand_item_list)