BaseMaterialsModel.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. # Copyright (c) 2018 Ultimaker B.V.
  2. # Cura is released under the terms of the LGPLv3 or higher.
  3. from typing import Optional, Dict, Set
  4. from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty
  5. from UM.Qt.ListModel import ListModel
  6. ## This is the base model class for GenericMaterialsModel and MaterialBrandsModel.
  7. # Those 2 models are used by the material drop down menu to show generic materials and branded materials separately.
  8. # The extruder position defined here is being used to bound a menu to the correct extruder. This is used in the top
  9. # bar menu "Settings" -> "Extruder nr" -> "Material" -> this menu
  10. from cura.Machines.MaterialNode import MaterialNode
  11. class BaseMaterialsModel(ListModel):
  12. extruderPositionChanged = pyqtSignal()
  13. enabledChanged = pyqtSignal()
  14. def __init__(self, parent = None):
  15. super().__init__(parent)
  16. from cura.CuraApplication import CuraApplication
  17. self._application = CuraApplication.getInstance()
  18. # Make these managers available to all material models
  19. self._container_registry = self._application.getInstance().getContainerRegistry()
  20. self._machine_manager = self._application.getMachineManager()
  21. self._material_manager = self._application.getMaterialManager()
  22. # Update the stack and the model data when the machine changes
  23. self._machine_manager.globalContainerChanged.connect(self._updateExtruderStack)
  24. # Update this model when switching machines
  25. self._machine_manager.activeStackChanged.connect(self._update)
  26. # Update this model when list of materials changes
  27. self._material_manager.materialsUpdated.connect(self._update)
  28. self.addRoleName(Qt.UserRole + 1, "root_material_id")
  29. self.addRoleName(Qt.UserRole + 2, "id")
  30. self.addRoleName(Qt.UserRole + 3, "GUID")
  31. self.addRoleName(Qt.UserRole + 4, "name")
  32. self.addRoleName(Qt.UserRole + 5, "brand")
  33. self.addRoleName(Qt.UserRole + 6, "description")
  34. self.addRoleName(Qt.UserRole + 7, "material")
  35. self.addRoleName(Qt.UserRole + 8, "color_name")
  36. self.addRoleName(Qt.UserRole + 9, "color_code")
  37. self.addRoleName(Qt.UserRole + 10, "density")
  38. self.addRoleName(Qt.UserRole + 11, "diameter")
  39. self.addRoleName(Qt.UserRole + 12, "approximate_diameter")
  40. self.addRoleName(Qt.UserRole + 13, "adhesion_info")
  41. self.addRoleName(Qt.UserRole + 14, "is_read_only")
  42. self.addRoleName(Qt.UserRole + 15, "container_node")
  43. self.addRoleName(Qt.UserRole + 16, "is_favorite")
  44. self._extruder_position = 0
  45. self._extruder_stack = None
  46. self._available_materials = None # type: Optional[Dict[str, MaterialNode]]
  47. self._favorite_ids = set() # type: Set[str]
  48. self._enabled = True
  49. def _updateExtruderStack(self):
  50. global_stack = self._machine_manager.activeMachine
  51. if global_stack is None:
  52. return
  53. if self._extruder_stack is not None:
  54. self._extruder_stack.pyqtContainersChanged.disconnect(self._update)
  55. self._extruder_stack.approximateMaterialDiameterChanged.disconnect(self._update)
  56. self._extruder_stack = global_stack.extruders.get(str(self._extruder_position))
  57. if self._extruder_stack is not None:
  58. self._extruder_stack.pyqtContainersChanged.connect(self._update)
  59. self._extruder_stack.approximateMaterialDiameterChanged.connect(self._update)
  60. # Force update the model when the extruder stack changes
  61. self._update()
  62. def setExtruderPosition(self, position: int):
  63. if self._extruder_stack is None or self._extruder_position != position:
  64. self._extruder_position = position
  65. self._updateExtruderStack()
  66. self.extruderPositionChanged.emit()
  67. @pyqtProperty(int, fset = setExtruderPosition, notify = extruderPositionChanged)
  68. def extruderPosition(self) -> int:
  69. return self._extruder_position
  70. def setEnabled(self, enabled):
  71. if self._enabled != enabled:
  72. self._enabled = enabled
  73. if self._enabled:
  74. # ensure the data is there again.
  75. self._update()
  76. self.enabledChanged.emit()
  77. @pyqtProperty(bool, fset=setEnabled, notify=enabledChanged)
  78. def enabled(self):
  79. return self._enabled
  80. ## This is an abstract method that needs to be implemented by the specific
  81. # models themselves.
  82. def _update(self):
  83. pass
  84. ## This method is used by all material models in the beginning of the
  85. # _update() method in order to prevent errors. It's the same in all models
  86. # so it's placed here for easy access.
  87. def _canUpdate(self):
  88. global_stack = self._machine_manager.activeMachine
  89. if global_stack is None or not self._enabled:
  90. return False
  91. extruder_position = str(self._extruder_position)
  92. if extruder_position not in global_stack.extruders:
  93. return False
  94. extruder_stack = global_stack.extruders[extruder_position]
  95. self._available_materials = self._material_manager.getAvailableMaterialsForMachineExtruder(global_stack, extruder_stack)
  96. if self._available_materials is None:
  97. return False
  98. return True
  99. ## This is another convenience function which is shared by all material
  100. # models so it's put here to avoid having so much duplicated code.
  101. def _createMaterialItem(self, root_material_id, container_node):
  102. metadata = container_node.getMetadata()
  103. item = {
  104. "root_material_id": root_material_id,
  105. "id": metadata["id"],
  106. "container_id": metadata["id"], # TODO: Remove duplicate in material manager qml
  107. "GUID": metadata["GUID"],
  108. "name": metadata["name"],
  109. "brand": metadata["brand"],
  110. "description": metadata["description"],
  111. "material": metadata["material"],
  112. "color_name": metadata["color_name"],
  113. "color_code": metadata.get("color_code", ""),
  114. "density": metadata.get("properties", {}).get("density", ""),
  115. "diameter": metadata.get("properties", {}).get("diameter", ""),
  116. "approximate_diameter": metadata["approximate_diameter"],
  117. "adhesion_info": metadata["adhesion_info"],
  118. "is_read_only": self._container_registry.isReadOnly(metadata["id"]),
  119. "container_node": container_node,
  120. "is_favorite": root_material_id in self._favorite_ids
  121. }
  122. return item