MaterialBrandsModel.py 3.8 KB

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