IntentSelectionModel.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. # Copyright (c) 2023 UltiMaker
  2. # Cura is released under the terms of the LGPLv3 or higher.
  3. import collections
  4. from typing import Optional
  5. from PyQt6.QtCore import Qt, QTimer, QObject, QUrl
  6. import cura
  7. from UM import i18nCatalog
  8. from UM.Logger import Logger
  9. from UM.Qt.ListModel import ListModel
  10. from UM.Resources import Resources
  11. from UM.Settings.ContainerRegistry import ContainerRegistry
  12. from UM.Settings.Interfaces import ContainerInterface
  13. from cura.Machines.Models.IntentCategoryModel import IntentCategoryModel
  14. from cura.Settings.IntentManager import IntentManager
  15. catalog = i18nCatalog("cura")
  16. class IntentSelectionModel(ListModel):
  17. NameRole = Qt.ItemDataRole.UserRole + 1
  18. IntentCategoryRole = Qt.ItemDataRole.UserRole + 2
  19. WeightRole = Qt.ItemDataRole.UserRole + 3
  20. DescriptionRole = Qt.ItemDataRole.UserRole + 4
  21. IconRole = Qt.ItemDataRole.UserRole + 5
  22. CustomIconRole = Qt.ItemDataRole.UserRole + 6
  23. def __init__(self, parent: Optional[QObject] = None) -> None:
  24. super().__init__(parent)
  25. self.addRoleName(self.NameRole, "name")
  26. self.addRoleName(self.IntentCategoryRole, "intent_category")
  27. self.addRoleName(self.WeightRole, "weight")
  28. self.addRoleName(self.DescriptionRole, "description")
  29. self.addRoleName(self.IconRole, "icon")
  30. self.addRoleName(self.CustomIconRole, "custom_icon")
  31. application = cura.CuraApplication.CuraApplication.getInstance()
  32. ContainerRegistry.getInstance().containerAdded.connect(self._onContainerChange)
  33. ContainerRegistry.getInstance().containerRemoved.connect(self._onContainerChange)
  34. machine_manager = cura.CuraApplication.CuraApplication.getInstance().getMachineManager()
  35. machine_manager.activeMaterialChanged.connect(self._update)
  36. machine_manager.activeVariantChanged.connect(self._update)
  37. machine_manager.extruderChanged.connect(self._update)
  38. extruder_manager = application.getExtruderManager()
  39. extruder_manager.extrudersChanged.connect(self._update)
  40. self._update_timer: QTimer = QTimer()
  41. self._update_timer.setInterval(100)
  42. self._update_timer.setSingleShot(True)
  43. self._update_timer.timeout.connect(self._update)
  44. self._onChange()
  45. _default_intent_categories = ["default", "visual", "engineering", "quick", "annealing", "solid"]
  46. _icons = {"default": "GearCheck", "visual": "Visual", "engineering": "Nut", "quick": "SpeedOMeter",
  47. "annealing": "Anneal", "solid": "Hammer"}
  48. def _onContainerChange(self, container: ContainerInterface) -> None:
  49. """Updates the list of intents if an intent profile was added or removed."""
  50. if container.getMetaDataEntry("type") == "intent":
  51. self._update()
  52. def _onChange(self) -> None:
  53. self._update_timer.start()
  54. def _update(self) -> None:
  55. Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__))
  56. cura_application = cura.CuraApplication.CuraApplication.getInstance()
  57. global_stack = cura_application.getGlobalContainerStack()
  58. if global_stack is None:
  59. self.setItems([])
  60. Logger.log("d", "No active GlobalStack, set quality profile model as empty.")
  61. return
  62. # Check for material compatibility
  63. if not cura_application.getMachineManager().activeMaterialsCompatible():
  64. Logger.log("d", "No active material compatibility, set quality profile model as empty.")
  65. self.setItems([])
  66. return
  67. available_categories = IntentManager.getInstance().currentAvailableIntentCategories()
  68. result = []
  69. for category in available_categories:
  70. if category in self._default_intent_categories:
  71. result.append({
  72. "name": IntentCategoryModel.translation(category, "name", category.title()),
  73. "description": IntentCategoryModel.translation(category, "description", None),
  74. "icon": self._icons[category],
  75. "custom_icon": None,
  76. "intent_category": category,
  77. "weight": self._default_intent_categories.index(category),
  78. })
  79. else:
  80. # There can be multiple intents with the same category, use one of these
  81. # intent-metadata's for the icon/description defintions for the intent
  82. intent_metadata = cura_application.getContainerRegistry().findContainersMetadata(type="intent",
  83. definition=global_stack.findInstanceContainerDefinitionId(global_stack.definition),
  84. intent_category=category)[0]
  85. intent_name = intent_metadata.get("name", category.title())
  86. icon = intent_metadata.get("icon", None)
  87. description = intent_metadata.get("description", None)
  88. if icon is not None and icon != '':
  89. try:
  90. icon = QUrl.fromLocalFile(
  91. Resources.getPath(cura.CuraApplication.CuraApplication.ResourceTypes.ImageFiles, icon))
  92. except (FileNotFoundError, NotADirectoryError, PermissionError):
  93. Logger.log("e", f"Icon file for intent {intent_name} not found.")
  94. icon = None
  95. result.append({
  96. "name": intent_name,
  97. "description": description,
  98. "custom_icon": icon,
  99. "icon": None,
  100. "intent_category": category,
  101. "weight": 5,
  102. })
  103. result.sort(key=lambda k: k["weight"])
  104. self.setItems(result)