diff --git a/cura/Machines/MaterialManager.py b/cura/Machines/MaterialManager.py index c2b3f00210..26dba85b54 100644 --- a/cura/Machines/MaterialManager.py +++ b/cura/Machines/MaterialManager.py @@ -79,145 +79,7 @@ class MaterialManager(QObject): self._default_machine_definition_id = "fdmprinter" self._default_approximate_diameter_for_quality_search = "3" - # When a material gets added/imported, there can be more than one InstanceContainers. In those cases, we don't - # want to react on every container/metadata changed signal. The timer here is to buffer it a bit so we don't - # react too many time. - self._update_timer = QTimer(self) - self._update_timer.setInterval(300) - self._update_timer.setSingleShot(True) - self._update_timer.timeout.connect(self._updateMaps) - - container_registry = CuraContainerRegistry.getInstance() - container_registry.containerMetaDataChanged.connect(self._onContainerMetadataChanged) - container_registry.containerAdded.connect(self._onContainerMetadataChanged) - container_registry.containerRemoved.connect(self._onContainerMetadataChanged) - - self._favorites = set() # type: Set[str] - - def initialize(self) -> None: - # Find all materials and put them in a matrix for quick search. - container_registry = CuraContainerRegistry.getInstance() - material_metadatas = {metadata["id"]: metadata for metadata in - container_registry.findContainersMetadata(type = "material") if - metadata.get("GUID")} # type: Dict[str, Dict[str, Any]] - - self._material_group_map = dict() # type: Dict[str, MaterialGroup] - - # Map #1 - # root_material_id -> MaterialGroup - for material_id, material_metadata in material_metadatas.items(): - # We don't store empty material in the lookup tables - if material_id == "empty_material": - continue - - root_material_id = material_metadata.get("base_file", "") - if root_material_id not in material_metadatas: #Not a registered material profile. Don't store this in the look-up tables. - continue - if root_material_id not in self._material_group_map: - self._material_group_map[root_material_id] = MaterialGroup(root_material_id, MaterialNode(material_metadatas[root_material_id])) - self._material_group_map[root_material_id].is_read_only = container_registry.isReadOnly(root_material_id) - group = self._material_group_map[root_material_id] - - # Store this material in the group of the appropriate root material. - if material_id != root_material_id: - new_node = MaterialNode(material_metadata) - group.derived_material_node_list.append(new_node) - - # Order this map alphabetically so it's easier to navigate in a debugger - self._material_group_map = OrderedDict(sorted(self._material_group_map.items(), key = lambda x: x[0])) - - # Map #1.5 - # GUID -> material group list - self._guid_material_groups_map = defaultdict(list) # type: Dict[str, List[MaterialGroup]] - for root_material_id, material_group in self._material_group_map.items(): - guid = material_group.root_material_node.getMetaDataEntry("GUID", "") - self._guid_material_groups_map[guid].append(material_group) - - # Map #2 - # Lookup table for material type -> fallback material metadata, only for read-only materials - grouped_by_type_dict = dict() # type: Dict[str, Any] - material_types_without_fallback = set() - for root_material_id, material_node in self._material_group_map.items(): - material_type = material_node.root_material_node.getMetaDataEntry("material", "") - if material_type not in grouped_by_type_dict: - grouped_by_type_dict[material_type] = {"generic": None, - "others": []} - material_types_without_fallback.add(material_type) - brand = material_node.root_material_node.getMetaDataEntry("brand", "") - if brand.lower() == "generic": - to_add = True - if material_type in grouped_by_type_dict: - diameter = material_node.root_material_node.getMetaDataEntry("approximate_diameter", "") - if diameter != self._default_approximate_diameter_for_quality_search: - to_add = False # don't add if it's not the default diameter - - if to_add: - # Checking this first allow us to differentiate between not read only materials: - # - if it's in the list, it means that is a new material without fallback - # - if it is not, then it is a custom material with a fallback material (parent) - if material_type in material_types_without_fallback: - grouped_by_type_dict[material_type] = material_node.root_material_node._metadata - material_types_without_fallback.remove(material_type) - - # Remove the materials that have no fallback materials - for material_type in material_types_without_fallback: - del grouped_by_type_dict[material_type] - self._fallback_materials_map = grouped_by_type_dict - - # Map #3 - # There can be multiple material profiles for the same material with different diameters, such as "generic_pla" - # and "generic_pla_175". This is inconvenient when we do material-specific quality lookup because a quality can - # be for either "generic_pla" or "generic_pla_175", but not both. This map helps to get the correct material ID - # for quality search. - self._material_diameter_map = defaultdict(dict) - self._diameter_material_map = dict() - - # Group the material IDs by the same name, material, brand, and color but with different diameters. - material_group_dict = dict() # type: Dict[Tuple[Any], Dict[str, str]] - keys_to_fetch = ("name", "material", "brand", "color") - for root_material_id, machine_node in self._material_group_map.items(): - root_material_metadata = machine_node.root_material_node._metadata - - key_data_list = [] # type: List[Any] - for key in keys_to_fetch: - key_data_list.append(machine_node.root_material_node.getMetaDataEntry(key)) - key_data = cast(Tuple[Any], tuple(key_data_list)) # type: Tuple[Any] - - # If the key_data doesn't exist, it doesn't matter if the material is read only... - if key_data not in material_group_dict: - material_group_dict[key_data] = dict() - else: - # ...but if key_data exists, we just overwrite it if the material is read only, otherwise we skip it - if not machine_node.is_read_only: - continue - approximate_diameter = machine_node.root_material_node.getMetaDataEntry("approximate_diameter", "") - material_group_dict[key_data][approximate_diameter] = machine_node.root_material_node.getMetaDataEntry("id", "") - - # Map [root_material_id][diameter] -> root_material_id for this diameter - for data_dict in material_group_dict.values(): - for root_material_id1 in data_dict.values(): - if root_material_id1 in self._material_diameter_map: - continue - diameter_map = data_dict - for root_material_id2 in data_dict.values(): - self._material_diameter_map[root_material_id2] = diameter_map - - default_root_material_id = data_dict.get(self._default_approximate_diameter_for_quality_search) - if default_root_material_id is None: - default_root_material_id = list(data_dict.values())[0] # no default diameter present, just take "the" only one - for root_material_id in data_dict.values(): - self._diameter_material_map[root_material_id] = default_root_material_id - - # Map #4 - # "machine" -> "nozzle name" -> "buildplate name" -> "root material ID" -> specific material InstanceContainer - self._diameter_machine_nozzle_buildplate_material_map = dict() # type: Dict[str, Dict[str, MaterialNode]] - for material_metadata in material_metadatas.values(): - self.__addMaterialMetadataIntoLookupTree(material_metadata) - - favorites = cura.CuraApplication.CuraApplication.getInstance().getPreferences().getValue("cura/favorite_materials") - for item in favorites.split(";"): - self._favorites.add(item) - + self._favorites = set(cura.CuraApplication.CuraApplication.getInstance().getPreferences().getValue("cura/favorite_materials").split(";")) self.materialsUpdated.emit() def __addMaterialMetadataIntoLookupTree(self, material_metadata: Dict[str, Any]) -> None: @@ -285,21 +147,6 @@ class MaterialManager(QObject): current_node.material_map[root_material_id] = MaterialNode(material_metadata) - def _updateMaps(self): - Logger.log("i", "Updating material lookup data ...") - self.initialize() - - def _onContainerMetadataChanged(self, container): - self._onContainerChanged(container) - - def _onContainerChanged(self, container): - container_type = container.getMetaDataEntry("type") - if container_type != "material": - return - - # update the maps - self._update_timer.start() - def getMaterialGroup(self, root_material_id: str) -> Optional[MaterialGroup]: return self._material_group_map.get(root_material_id)