1#Copyright (c) 2019 Ultimaker B.V. 2#Cura is released under the terms of the LGPLv3 or higher. 3 4import collections 5from PyQt5.QtCore import Qt, QTimer 6from typing import TYPE_CHECKING, Optional, Dict 7 8from cura.Machines.Models.IntentModel import IntentModel 9from cura.Settings.IntentManager import IntentManager 10from UM.Qt.ListModel import ListModel 11from UM.Settings.ContainerRegistry import ContainerRegistry #To update the list if anything changes. 12from PyQt5.QtCore import pyqtSignal 13import cura.CuraApplication 14if TYPE_CHECKING: 15 from UM.Settings.ContainerRegistry import ContainerInterface 16 17from UM.i18n import i18nCatalog 18catalog = i18nCatalog("cura") 19 20 21class IntentCategoryModel(ListModel): 22 """Lists the intent categories that are available for the current printer configuration. """ 23 24 NameRole = Qt.UserRole + 1 25 IntentCategoryRole = Qt.UserRole + 2 26 WeightRole = Qt.UserRole + 3 27 QualitiesRole = Qt.UserRole + 4 28 DescriptionRole = Qt.UserRole + 5 29 30 modelUpdated = pyqtSignal() 31 32 _translations = collections.OrderedDict() # type: "collections.OrderedDict[str,Dict[str,Optional[str]]]" 33 34 @classmethod 35 def _get_translations(cls): 36 """Translations to user-visible string. Ordered by weight. 37 38 TODO: Create a solution for this name and weight to be used dynamically. 39 """ 40 if len(cls._translations) == 0: 41 cls._translations["default"] = { 42 "name": catalog.i18nc("@label", "Default") 43 } 44 cls._translations["visual"] = { 45 "name": catalog.i18nc("@label", "Visual"), 46 "description": catalog.i18nc("@text", "The visual profile is designed to print visual prototypes and models with the intent of high visual and surface quality.") 47 } 48 cls._translations["engineering"] = { 49 "name": catalog.i18nc("@label", "Engineering"), 50 "description": catalog.i18nc("@text", "The engineering profile is designed to print functional prototypes and end-use parts with the intent of better accuracy and for closer tolerances.") 51 } 52 cls._translations["quick"] = { 53 "name": catalog.i18nc("@label", "Draft"), 54 "description": catalog.i18nc("@text", "The draft profile is designed to print initial prototypes and concept validation with the intent of significant print time reduction.") 55 } 56 return cls._translations 57 58 def __init__(self, intent_category: str) -> None: 59 """Creates a new model for a certain intent category. 60 61 :param intent_category: category to list the intent profiles for. 62 """ 63 64 super().__init__() 65 self._intent_category = intent_category 66 67 self.addRoleName(self.NameRole, "name") 68 self.addRoleName(self.IntentCategoryRole, "intent_category") 69 self.addRoleName(self.WeightRole, "weight") 70 self.addRoleName(self.QualitiesRole, "qualities") 71 self.addRoleName(self.DescriptionRole, "description") 72 73 application = cura.CuraApplication.CuraApplication.getInstance() 74 75 ContainerRegistry.getInstance().containerAdded.connect(self._onContainerChange) 76 ContainerRegistry.getInstance().containerRemoved.connect(self._onContainerChange) 77 machine_manager = cura.CuraApplication.CuraApplication.getInstance().getMachineManager() 78 machine_manager.activeMaterialChanged.connect(self.update) 79 machine_manager.activeVariantChanged.connect(self.update) 80 machine_manager.extruderChanged.connect(self.update) 81 82 extruder_manager = application.getExtruderManager() 83 extruder_manager.extrudersChanged.connect(self.update) 84 85 self._update_timer = QTimer() 86 self._update_timer.setInterval(500) 87 self._update_timer.setSingleShot(True) 88 self._update_timer.timeout.connect(self._update) 89 90 self.update() 91 92 def _onContainerChange(self, container: "ContainerInterface") -> None: 93 """Updates the list of intents if an intent profile was added or removed.""" 94 95 if container.getMetaDataEntry("type") == "intent": 96 self.update() 97 98 def update(self): 99 self._update_timer.start() 100 101 def _update(self) -> None: 102 """Updates the list of intents.""" 103 104 available_categories = IntentManager.getInstance().currentAvailableIntentCategories() 105 result = [] 106 for category in available_categories: 107 qualities = IntentModel() 108 qualities.setIntentCategory(category) 109 result.append({ 110 "name": IntentCategoryModel.translation(category, "name", catalog.i18nc("@label", "Unknown")), 111 "description": IntentCategoryModel.translation(category, "description", None), 112 "intent_category": category, 113 "weight": list(IntentCategoryModel._get_translations().keys()).index(category), 114 "qualities": qualities 115 }) 116 result.sort(key = lambda k: k["weight"]) 117 self.setItems(result) 118 119 @staticmethod 120 def translation(category: str, key: str, default: Optional[str] = None): 121 """Get a display value for a category.for categories and keys""" 122 123 display_strings = IntentCategoryModel._get_translations().get(category, {}) 124 return display_strings.get(key, default) 125