diff --git a/cura/Machines/Models/QualityManagementModel.py b/cura/Machines/Models/QualityManagementModel.py index d144e75515..ffdb022f38 100644 --- a/cura/Machines/Models/QualityManagementModel.py +++ b/cura/Machines/Models/QualityManagementModel.py @@ -116,10 +116,10 @@ class QualityManagementModel(ListModel): quality_changes_group = quality_model_item["quality_changes_group"] if quality_changes_group is None: # Create global quality changes only. - new_quality_changes = self._createQualityChanges(quality_group.quality_type, new_name, global_stack, extruder_stack = None) + new_quality_changes = self._createQualityChanges(quality_group.quality_type, None, new_name, global_stack, extruder_stack = None) container_registry.addContainer(new_quality_changes) else: - for metadata in [quality_changes_group.metadata_for_global] + quality_changes_group.metadata_per_extruder.values(): + for metadata in [quality_changes_group.metadata_for_global] + list(quality_changes_group.metadata_per_extruder.values()): containers = container_registry.findContainers(id = metadata["id"]) if not containers: continue @@ -167,9 +167,11 @@ class QualityManagementModel(ListModel): continue extruder_stack = None + intent_category = None if stack.getMetaDataEntry("position") is not None: extruder_stack = stack - new_changes = self._createQualityChanges(quality_container.getMetaDataEntry("quality_type"), unique_name, global_stack, extruder_stack) + intent_category = stack.intent.getMetaDataEntry("intent_category") + new_changes = self._createQualityChanges(quality_container.getMetaDataEntry("quality_type"), intent_category, unique_name, global_stack, extruder_stack) container_manager._performMerge(new_changes, quality_changes_container, clear_settings = False) container_manager._performMerge(new_changes, stack.userChanges) @@ -177,11 +179,12 @@ class QualityManagementModel(ListModel): ## Create a quality changes container with the given set-up. # \param quality_type The quality type of the new container. + # \param intent_category The intent category of the new container. # \param new_name The name of the container. This name must be unique. # \param machine The global stack to create the profile for. # \param extruder_stack The extruder stack to create the profile for. If # not provided, only a global container will be created. - def _createQualityChanges(self, quality_type: str, new_name: str, machine: "GlobalStack", extruder_stack: Optional["ExtruderStack"]) -> "InstanceContainer": + def _createQualityChanges(self, quality_type: str, intent_category: Optional[str], new_name: str, machine: "GlobalStack", extruder_stack: Optional["ExtruderStack"]) -> "InstanceContainer": container_registry = cura.CuraApplication.CuraApplication.getInstance().getContainerRegistry() base_id = machine.definition.getId() if extruder_stack is None else extruder_stack.getId() new_id = base_id + "_" + new_name @@ -193,6 +196,8 @@ class QualityManagementModel(ListModel): quality_changes.setName(new_name) quality_changes.setMetaDataEntry("type", "quality_changes") quality_changes.setMetaDataEntry("quality_type", quality_type) + if intent_category is not None: + quality_changes.setMetaDataEntry("intent_category", intent_category) # If we are creating a container for an extruder, ensure we add that to the container. if extruder_stack is not None: diff --git a/cura/Settings/ContainerManager.py b/cura/Settings/ContainerManager.py index d0b856a872..f2b107f1b6 100644 --- a/cura/Settings/ContainerManager.py +++ b/cura/Settings/ContainerManager.py @@ -294,7 +294,9 @@ class ContainerManager(QObject): quality_changes.setName(current_quality_changes_name) quality_changes.setMetaDataEntry("type", "quality_changes") quality_changes.setMetaDataEntry("quality_type", current_quality_type) - quality_changes.setMetaDataEntry("position", stack.getMetaDataEntry("position")) + if stack.getMetaDataEntry("position") is not None: # Extruder stacks. + quality_changes.setMetaDataEntry("position", stack.getMetaDataEntry("position")) + quality_changes.setMetaDataEntry("intent_category", stack.quality.getMetaDataEntry("intent_category", "default")) quality_changes.setMetaDataEntry("setting_version", application.SettingVersion) quality_changes.setDefinition(machine_definition_id) container_registry.addContainer(quality_changes) diff --git a/cura/Settings/CuraContainerRegistry.py b/cura/Settings/CuraContainerRegistry.py index 097185b628..97634b4da4 100644 --- a/cura/Settings/CuraContainerRegistry.py +++ b/cura/Settings/CuraContainerRegistry.py @@ -269,7 +269,6 @@ class CuraContainerRegistry(ContainerRegistry): profile.setMetaDataEntry("type", "quality_changes") profile.setMetaDataEntry("definition", expected_machine_definition) profile.setMetaDataEntry("quality_type", quality_type) - profile.setMetaDataEntry("position", "0") profile.setDirty(True) if idx == 0: # Move all per-extruder settings to the first extruder's quality_changes @@ -609,6 +608,7 @@ class CuraContainerRegistry(ContainerRegistry): extruder_quality_changes_container.setMetaDataEntry("setting_version", application.SettingVersion) extruder_quality_changes_container.setMetaDataEntry("position", extruder_definition.getMetaDataEntry("position")) extruder_quality_changes_container.setMetaDataEntry("quality_type", machine_quality_changes.getMetaDataEntry("quality_type")) + extruder_quality_changes_container.setMetaDataEntry("intent_category", "default") # Intent categories weren't a thing back then. extruder_quality_changes_container.setDefinition(machine_quality_changes.getDefinition().getId()) self.addContainer(extruder_quality_changes_container) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 79417e8ed4..7ec95cb7e5 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -1151,7 +1151,7 @@ class MachineManager(QObject): container_registry = cura.CuraApplication.CuraApplication.getInstance().getContainerRegistry() quality_changes_container = empty_quality_changes_container - quality_container = empty_quality_container # type: Optional[InstanceContainer] + quality_container = empty_quality_container # type: InstanceContainer if quality_changes_group.metadata_for_global: global_containers = container_registry.findContainers(id = quality_changes_group.metadata_for_global["id"]) if global_containers: @@ -1169,11 +1169,11 @@ class MachineManager(QObject): for position, extruder in self._global_container_stack.extruders.items(): quality_node = None if quality_group is not None: - quality_node = quality_group.nodes_for_extruders.get(position) + quality_node = quality_group.nodes_for_extruders.get(int(position)) quality_changes_container = empty_quality_changes_container quality_container = empty_quality_container - quality_changes_metadata = quality_changes_group.metadata_per_extruder.get(position) + quality_changes_metadata = quality_changes_group.metadata_per_extruder.get(int(position)) if quality_changes_metadata: containers = container_registry.findContainers(id = quality_changes_metadata["id"]) if containers: diff --git a/cura/Settings/cura_empty_instance_containers.py b/cura/Settings/cura_empty_instance_containers.py index 0ab37c5435..a09537272d 100644 --- a/cura/Settings/cura_empty_instance_containers.py +++ b/cura/Settings/cura_empty_instance_containers.py @@ -41,6 +41,7 @@ empty_quality_changes_container = copy.deepcopy(empty_container) empty_quality_changes_container.setMetaDataEntry("id", EMPTY_QUALITY_CHANGES_CONTAINER_ID) empty_quality_changes_container.setMetaDataEntry("type", "quality_changes") empty_quality_changes_container.setMetaDataEntry("quality_type", "not_supported") +empty_quality_changes_container.setMetaDataEntry("intent_category", "not_supported") # Empty intent EMPTY_INTENT_CONTAINER_ID = "empty_intent" diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index 00d7252875..37be9cfe2d 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -14,7 +14,6 @@ from UM.Application import Application from UM.Logger import Logger from UM.Message import Message from UM.i18n import i18nCatalog -from UM.Signal import postponeSignals, CompressTechnique from UM.Settings.ContainerFormatError import ContainerFormatError from UM.Settings.ContainerStack import ContainerStack from UM.Settings.DefinitionContainer import DefinitionContainer @@ -575,24 +574,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader): # \param file_name @call_on_qt_thread def read(self, file_name): - container_registry = ContainerRegistry.getInstance() - signals = [container_registry.containerAdded, - container_registry.containerRemoved, - container_registry.containerMetaDataChanged] - # The container tree updates its lookup tables upon container changes. - # It is critical to make sure that it has a complete set of data when it - # updates. - # - # In project loading, lots of the container-related signals are loosely emitted, which can create timing gaps - # for incomplete data update or other kinds of issues to happen. - # - # To avoid this, we postpone all signals so they don't get emitted immediately. But, please also be aware that, - # because of this, do not expect to have the latest data in the lookup tables in project loading. - # - with postponeSignals(*signals, compress = CompressTechnique.NoCompression): - return self._read(file_name) - - def _read(self, file_name): application = CuraApplication.getInstance() material_manager = application.getMaterialManager() @@ -760,6 +741,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): quality_changes_info = self._machine_info.quality_changes_info quality_changes_quality_type = quality_changes_info.global_info.parser["metadata"]["quality_type"] + quality_changes_intent_category_per_extruder = {position: info.parser["metadata"].get("intent_category", "default") for position, info in quality_changes_info.extruder_info_dict.items()} quality_changes_name = quality_changes_info.name create_new = self._resolve_strategies.get("quality_changes") != "override" @@ -770,9 +752,11 @@ class ThreeMFWorkspaceReader(WorkspaceReader): quality_changes_name = self._container_registry.uniqueName(quality_changes_name) for position, container_info in container_info_dict.items(): extruder_stack = None + intent_category = None # type: Optional[str] if position is not None: extruder_stack = global_stack.extruders[position] - container = self._createNewQualityChanges(quality_changes_quality_type, quality_changes_name, global_stack, extruder_stack) + intent_category = quality_changes_intent_category_per_extruder[position] + container = self._createNewQualityChanges(quality_changes_quality_type, intent_category, quality_changes_name, global_stack, extruder_stack) container_info.container = container self._container_registry.addContainer(container) @@ -801,8 +785,9 @@ class ThreeMFWorkspaceReader(WorkspaceReader): if not global_stack.extruders: ExtruderManager.getInstance().fixSingleExtrusionMachineExtruderDefinition(global_stack) extruder_stack = global_stack.extruders["0"] + intent_category = quality_changes_intent_category_per_extruder["0"] - container = self._createNewQualityChanges(quality_changes_quality_type, quality_changes_name, global_stack, extruder_stack) + container = self._createNewQualityChanges(quality_changes_quality_type, intent_category, quality_changes_name, global_stack, extruder_stack) container_info.container = container self._container_registry.addContainer(container) @@ -829,7 +814,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader): if container_info.container is None: extruder_stack = global_stack.extruders[position] - container = self._createNewQualityChanges(quality_changes_quality_type, quality_changes_name, global_stack, extruder_stack) + intent_category = quality_changes_intent_category_per_extruder[position] + container = self._createNewQualityChanges(quality_changes_quality_type, intent_category, quality_changes_name, global_stack, extruder_stack) container_info.container = container self._container_registry.addContainer(container) @@ -842,6 +828,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): # # This will then later be filled with the appropriate data. # \param quality_type The quality type of the new profile. + # \param intent_category The intent category of the new profile. # \param name The name for the profile. This will later be made unique so # it doesn't need to be unique yet. # \param global_stack The global stack showing the configuration that the @@ -849,7 +836,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): # \param extruder_stack The extruder stack showing the configuration that # the profile should be created for. If this is None, it will be created # for the global stack. - def _createNewQualityChanges(self, quality_type: str, name: str, global_stack: GlobalStack, extruder_stack: Optional[ExtruderStack]) -> InstanceContainer: + def _createNewQualityChanges(self, quality_type: str, intent_category: Optional[str], name: str, global_stack: GlobalStack, extruder_stack: Optional[ExtruderStack]) -> InstanceContainer: container_registry = CuraApplication.getInstance().getContainerRegistry() base_id = global_stack.definition.getId() if extruder_stack is None else extruder_stack.getId() new_id = base_id + "_" + name @@ -861,6 +848,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader): quality_changes.setName(name) quality_changes.setMetaDataEntry("type", "quality_changes") quality_changes.setMetaDataEntry("quality_type", quality_type) + if intent_category is not None: + quality_changes.setMetaDataEntry("intent_category", intent_category) # If we are creating a container for an extruder, ensure we add that to the container. if extruder_stack is not None: diff --git a/plugins/GCodeWriter/GCodeWriter.py b/plugins/GCodeWriter/GCodeWriter.py index edd0cebc96..792b2aff10 100644 --- a/plugins/GCodeWriter/GCodeWriter.py +++ b/plugins/GCodeWriter/GCodeWriter.py @@ -131,6 +131,8 @@ class GCodeWriter(MeshWriter): container_with_profile.setName(quality_name) container_with_profile.setMetaDataEntry("type", "quality_changes") container_with_profile.setMetaDataEntry("quality_type", quality_type) + if stack.getMetaDataEntry("position") is not None: # For extruder stacks, the quality changes should include an intent category. + container_with_profile.setMetaDataEntry("intent_category", stack.intent.getMetaDataEntry("intent_category", "default")) container_with_profile.setDefinition(machine_definition_id_for_quality) flat_global_container = self._createFlattenedContainerInstance(stack.userChanges, container_with_profile) diff --git a/plugins/UM3NetworkPrinting/src/Network/SendMaterialJob.py b/plugins/UM3NetworkPrinting/src/Network/SendMaterialJob.py index 8de732e2a6..5637f388c1 100644 --- a/plugins/UM3NetworkPrinting/src/Network/SendMaterialJob.py +++ b/plugins/UM3NetworkPrinting/src/Network/SendMaterialJob.py @@ -68,10 +68,10 @@ class SendMaterialJob(Job): # \param materials_to_send A set with id's of materials that must be sent. def _sendMaterials(self, materials_to_send: Set[str]) -> None: container_registry = CuraApplication.getInstance().getContainerRegistry() - material_manager = CuraApplication.getInstance().getMaterialManager() - material_group_dict = material_manager.getAllMaterialGroups() + all_materials = container_registry.findInstanceContainersMetadata(type = "material") + all_root_materials = {material["base_file"] for material in all_materials if "base_file" in material} # Filters out uniques by making it a set. Don't include files without base file (i.e. empty material). - for root_material_id in material_group_dict: + for root_material_id in all_root_materials: if root_material_id not in materials_to_send: # If the material does not have to be sent we skip it. continue @@ -128,20 +128,18 @@ class SendMaterialJob(Job): @staticmethod def _getLocalMaterials() -> Dict[str, LocalMaterial]: result = {} # type: Dict[str, LocalMaterial] - material_manager = CuraApplication.getInstance().getMaterialManager() - material_group_dict = material_manager.getAllMaterialGroups() + all_materials = CuraApplication.getInstance().getContainerRegistry().findInstanceContainersMetadata(type = "material") + all_root_materials = [material for material in all_materials if material["id"] == material.get("base_file")] # Don't send materials without base_file: The empty material doesn't need to be sent. # Find the latest version of all material containers in the registry. - for root_material_id, material_group in material_group_dict.items(): - material_metadata = ContainerRegistry.getInstance().findContainersMetadata(id = material_group.root_material_node.container_id)[0] - + for material_metadata in all_root_materials: try: # material version must be an int material_metadata["version"] = int(material_metadata["version"]) # Create a new local material local_material = LocalMaterial(**material_metadata) - local_material.id = root_material_id + local_material.id = material_metadata["id"] if local_material.GUID not in result or \ local_material.GUID not in result or \