MaterialBrandsModel.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. # Copyright (c) 2019 Ultimaker B.V.
  2. # Cura is released under the terms of the LGPLv3 or higher.
  3. from PyQt6.QtCore import Qt, pyqtSignal
  4. from PyQt6.QtQml import QQmlEngine
  5. from UM.Qt.ListModel import ListModel
  6. from cura.Machines.Models.BaseMaterialsModel import BaseMaterialsModel
  7. class MaterialTypesModel(ListModel):
  8. def __init__(self, parent = None):
  9. super().__init__(parent)
  10. QQmlEngine.setObjectOwnership(self, QQmlEngine.ObjectOwnership.CppOwnership)
  11. self.addRoleName(Qt.ItemDataRole.UserRole + 1, "name")
  12. self.addRoleName(Qt.ItemDataRole.UserRole + 2, "brand")
  13. self.addRoleName(Qt.ItemDataRole.UserRole + 3, "colors")
  14. class MaterialBrandsModel(BaseMaterialsModel):
  15. extruderPositionChanged = pyqtSignal()
  16. def __init__(self, parent = None):
  17. super().__init__(parent)
  18. QQmlEngine.setObjectOwnership(self, QQmlEngine.ObjectOwnership.CppOwnership)
  19. self.addRoleName(Qt.ItemDataRole.UserRole + 1, "name")
  20. self.addRoleName(Qt.ItemDataRole.UserRole + 2, "material_types")
  21. self._update()
  22. def _update(self):
  23. if not self._canUpdate():
  24. return
  25. super()._update()
  26. brand_item_list = []
  27. brand_group_dict = {}
  28. # Part 1: Generate the entire tree of brands -> material types -> specific materials
  29. for root_material_id, container_node in self._available_materials.items():
  30. # Do not include the materials from a to-be-removed package
  31. if bool(container_node.getMetaDataEntry("removed", False)):
  32. continue
  33. # Ignore materials that are marked as not visible for whatever reason
  34. if not bool(container_node.getMetaDataEntry("visible", True)):
  35. continue
  36. # Add brands we haven't seen yet to the dict, skipping generics
  37. brand = container_node.getMetaDataEntry("brand", "")
  38. if brand.lower() == "generic":
  39. continue
  40. if brand not in brand_group_dict:
  41. brand_group_dict[brand] = {}
  42. # Add material types we haven't seen yet to the dict
  43. material_type = container_node.getMetaDataEntry("material", "")
  44. if material_type not in brand_group_dict[brand]:
  45. brand_group_dict[brand][material_type] = []
  46. # Now handle the individual materials
  47. item = self._createMaterialItem(root_material_id, container_node)
  48. if item:
  49. brand_group_dict[brand][material_type].append(item)
  50. # Part 2: Organize the tree into models
  51. #
  52. # Normally, the structure of the menu looks like this:
  53. # Brand -> Material Type -> Specific Material
  54. #
  55. # To illustrate, a branded material menu may look like this:
  56. # Ultimaker ┳ PLA ┳ Yellow PLA
  57. # ┃ ┣ Black PLA
  58. # ┃ ┗ ...
  59. # ┃
  60. # ┗ ABS ┳ White ABS
  61. # ┗ ...
  62. for brand, material_dict in brand_group_dict.items():
  63. material_type_item_list = []
  64. brand_item = {
  65. "name": brand,
  66. "material_types": MaterialTypesModel()
  67. }
  68. for material_type, material_list in material_dict.items():
  69. material_type_item = {
  70. "name": material_type,
  71. "brand": brand,
  72. "colors": BaseMaterialsModel()
  73. }
  74. # Sort materials by name
  75. material_list = sorted(material_list, key = lambda x: x["name"].upper())
  76. material_type_item["colors"].setItems(material_list)
  77. material_type_item_list.append(material_type_item)
  78. # Sort material type by name
  79. material_type_item_list = sorted(material_type_item_list, key = lambda x: x["name"].upper())
  80. brand_item["material_types"].setItems(material_type_item_list)
  81. brand_item_list.append(brand_item)
  82. # Sort brand by name
  83. brand_item_list = sorted(brand_item_list, key = lambda x: x["name"].upper())
  84. self.setItems(brand_item_list)