MaterialBrandsModel.py 3.9 KB

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