From 18c7a5acf37cc8e5a7371ef69c304075f019fdfb Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 23 Nov 2017 11:26:53 +0100 Subject: [PATCH 01/10] Pass optional file_name for deserialization CURA-4613 Some upgrades depend on the file_name, so the file_name is needed in this case. --- cura/Settings/CuraContainerStack.py | 4 +- cura/Settings/ExtruderStack.py | 4 +- plugins/3MFReader/ThreeMFWorkspaceReader.py | 40 ++++++++++++------- .../XmlMaterialProfile/XmlMaterialProfile.py | 4 +- 4 files changed, 31 insertions(+), 21 deletions(-) diff --git a/cura/Settings/CuraContainerStack.py b/cura/Settings/CuraContainerStack.py index 2a804def4d..9bbea044cf 100755 --- a/cura/Settings/CuraContainerStack.py +++ b/cura/Settings/CuraContainerStack.py @@ -348,8 +348,8 @@ class CuraContainerStack(ContainerStack): # # \throws InvalidContainerStackError Raised when no definition can be found for the stack. @override(ContainerStack) - def deserialize(self, contents: str) -> None: - super().deserialize(contents) + def deserialize(self, contents: str, file_name: Optional[str] = None) -> None: + super().deserialize(contents, file_name) new_containers = self._containers.copy() while len(new_containers) < len(_ContainerIndexes.IndexTypeMap): diff --git a/cura/Settings/ExtruderStack.py b/cura/Settings/ExtruderStack.py index fe7068b7ea..42a2733879 100644 --- a/cura/Settings/ExtruderStack.py +++ b/cura/Settings/ExtruderStack.py @@ -92,8 +92,8 @@ class ExtruderStack(CuraContainerStack): return self.getNextStack()._getMachineDefinition() @override(CuraContainerStack) - def deserialize(self, contents: str) -> None: - super().deserialize(contents) + def deserialize(self, contents: str, file_name: Optional[str] = None) -> None: + super().deserialize(contents, file_name) stacks = ContainerRegistry.getInstance().findContainerStacks(id=self.getMetaDataEntry("machine", "")) if stacks: self.setNextStack(stacks[0]) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index aa81399b56..8e087611ef 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -152,7 +152,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader): if not definitions: definition_container = DefinitionContainer(container_id) - definition_container.deserialize(archive.open(each_definition_container_file).read().decode("utf-8")) + definition_container.deserialize(archive.open(each_definition_container_file).read().decode("utf-8"), + file_name = each_definition_container_file) else: definition_container = definitions[0] @@ -208,7 +209,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader): instance_container = InstanceContainer(container_id) # Deserialize InstanceContainer by converting read data from bytes to string - instance_container.deserialize(archive.open(each_instance_container_file).read().decode("utf-8")) + instance_container.deserialize(archive.open(each_instance_container_file).read().decode("utf-8"), + file_name = each_instance_container_file) instance_container_list.append(instance_container) container_type = instance_container.getMetaDataEntry("type") @@ -378,7 +380,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): return WorkspaceReader.PreReadResult.accepted ## Overrides an ExtruderStack in the given GlobalStack and returns the new ExtruderStack. - def _overrideExtruderStack(self, global_stack, extruder_file_content): + def _overrideExtruderStack(self, global_stack, extruder_file_content, extruder_stack_file): # Get extruder position first extruder_config = configparser.ConfigParser() extruder_config.read_string(extruder_file_content) @@ -394,7 +396,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): return None # Override the given extruder stack - extruder_stack.deserialize(extruder_file_content) + extruder_stack.deserialize(extruder_file_content, file_name = extruder_stack_file) # return the new ExtruderStack return extruder_stack @@ -484,7 +486,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader): definitions = self._container_registry.findDefinitionContainers(id = container_id) if not definitions: definition_container = DefinitionContainer(container_id) - definition_container.deserialize(archive.open(definition_container_file).read().decode("utf-8")) + definition_container.deserialize(archive.open(definition_container_file).read().decode("utf-8"), + file_name = definition_container_file) self._container_registry.addContainer(definition_container) Job.yieldThread() @@ -502,18 +505,21 @@ class ThreeMFWorkspaceReader(WorkspaceReader): if not materials: material_container = xml_material_profile(container_id) - material_container.deserialize(archive.open(material_container_file).read().decode("utf-8")) + material_container.deserialize(archive.open(material_container_file).read().decode("utf-8"), + file_name = material_container_file) containers_to_add.append(material_container) else: material_container = materials[0] if not material_container.isReadOnly(): # Only create new materials if they are not read only. if self._resolve_strategies["material"] == "override": - material_container.deserialize(archive.open(material_container_file).read().decode("utf-8")) + material_container.deserialize(archive.open(material_container_file).read().decode("utf-8"), + file_name = material_container_file) elif self._resolve_strategies["material"] == "new": # Note that we *must* deserialize it with a new ID, as multiple containers will be # auto created & added. material_container = xml_material_profile(self.getNewId(container_id)) - material_container.deserialize(archive.open(material_container_file).read().decode("utf-8")) + material_container.deserialize(archive.open(material_container_file).read().decode("utf-8"), + file_name = material_container_file) containers_to_add.append(material_container) material_containers.append(material_container) @@ -540,7 +546,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): instance_container = InstanceContainer(container_id) # Deserialize InstanceContainer by converting read data from bytes to string - instance_container.deserialize(serialized) + instance_container.deserialize(serialized, file_name = instance_container_file) container_type = instance_container.getMetaDataEntry("type") Job.yieldThread() @@ -562,7 +568,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader): else: if self._resolve_strategies["machine"] == "override" or self._resolve_strategies["machine"] is None: instance_container = user_containers[0] - instance_container.deserialize(archive.open(instance_container_file).read().decode("utf-8")) + instance_container.deserialize(archive.open(instance_container_file).read().decode("utf-8"), + file_name = instance_container_file) instance_container.setDirty(True) elif self._resolve_strategies["machine"] == "new": # The machine is going to get a spiffy new name, so ensure that the id's of user settings match. @@ -595,7 +602,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader): # selected strategy. if self._resolve_strategies[container_type] == "override": instance_container = changes_containers[0] - instance_container.deserialize(archive.open(instance_container_file).read().decode("utf-8")) + instance_container.deserialize(archive.open(instance_container_file).read().decode("utf-8"), + file_name = instance_container_file) instance_container.setDirty(True) elif self._resolve_strategies[container_type] == "new": @@ -656,7 +664,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader): # There is a machine, check if it has authentication data. If so, keep that data. network_authentication_id = container_stacks[0].getMetaDataEntry("network_authentication_id") network_authentication_key = container_stacks[0].getMetaDataEntry("network_authentication_key") - container_stacks[0].deserialize(archive.open(global_stack_file).read().decode("utf-8")) + container_stacks[0].deserialize(archive.open(global_stack_file).read().decode("utf-8"), + file_name = global_stack_file) if network_authentication_id: container_stacks[0].addMetaDataEntry("network_authentication_id", network_authentication_id) if network_authentication_key: @@ -666,7 +675,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader): # create a new global stack stack = GlobalStack(global_stack_id_new) # Deserialize stack by converting read data from bytes to string - stack.deserialize(archive.open(global_stack_file).read().decode("utf-8")) + stack.deserialize(archive.open(global_stack_file).read().decode("utf-8"), + file_name = global_stack_file) # Ensure a unique ID and name stack._id = global_stack_id_new @@ -706,7 +716,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): if self._resolve_strategies["machine"] == "override": if global_stack.getProperty("machine_extruder_count", "value") > 1: # deserialize new extruder stack over the current ones (if any) - stack = self._overrideExtruderStack(global_stack, extruder_file_content) + stack = self._overrideExtruderStack(global_stack, extruder_file_content, extruder_stack_file) if stack is None: continue @@ -726,7 +736,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): extruder_config.write(tmp_string_io) extruder_file_content = tmp_string_io.getvalue() - stack.deserialize(extruder_file_content) + stack.deserialize(extruder_file_content, file_name = extruder_stack_file) # Ensure a unique ID and name stack._id = new_id diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index fa40819eeb..7ab4520aea 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -422,11 +422,11 @@ class XmlMaterialProfile(InstanceContainer): return version * 1000000 + setting_version ## Overridden from InstanceContainer - def deserialize(self, serialized): + def deserialize(self, serialized, file_name = None): containers_to_add = [] # update the serialized data first from UM.Settings.Interfaces import ContainerInterface - serialized = ContainerInterface.deserialize(self, serialized) + serialized = ContainerInterface.deserialize(self, serialized, file_name) try: data = ET.fromstring(serialized) From 3148027fbe7b0e70a0ab1dbc4733d85470aad674 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 23 Nov 2017 12:43:14 +0100 Subject: [PATCH 02/10] Fix version upgrade for quality_changes CURA-4613 Explained in the code comments. --- .../VersionUpgrade30to31/VersionUpgrade30to31.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/VersionUpgrade/VersionUpgrade30to31/VersionUpgrade30to31.py b/plugins/VersionUpgrade/VersionUpgrade30to31/VersionUpgrade30to31.py index 7b788f96ba..c496a66b29 100644 --- a/plugins/VersionUpgrade/VersionUpgrade30to31/VersionUpgrade30to31.py +++ b/plugins/VersionUpgrade/VersionUpgrade30to31/VersionUpgrade30to31.py @@ -116,7 +116,10 @@ class VersionUpgrade30to31(VersionUpgrade): all_quality_changes = self._getSingleExtrusionMachineQualityChanges(parser) # Note that DO NOT!!! use the quality_changes returned from _getSingleExtrusionMachineQualityChanges(). # Those are loaded from the hard drive which are original files that haven't been upgraded yet. - if len(all_quality_changes) == 1 and not parser.has_option("metadata", "extruder"): + # NOTE 2: The number can be 0 or 1 depends on whether you are loading it from the qualities folder or + # from a project file. When you load from a project file, the custom profile may not be in cura + # yet, so you will get 0. + if len(all_quality_changes) <= 1 and not parser.has_option("metadata", "extruder"): self._createExtruderQualityChangesForSingleExtrusionMachine(filename, parser) # Update version numbers @@ -199,7 +202,7 @@ class VersionUpgrade30to31(VersionUpgrade): def _createExtruderQualityChangesForSingleExtrusionMachine(self, filename, global_quality_changes): suffix = "_" + quote_plus(global_quality_changes["general"]["name"].lower()) - machine_name = filename.strip("." + os.sep).replace(suffix, "") + machine_name = os.path.os.path.basename(filename).replace(".inst.cfg", "").replace(suffix, "") new_filename = machine_name + "_" + "fdmextruder" + suffix extruder_quality_changes_parser = configparser.ConfigParser() From 17f09ec21e57cbb45e207b3682c3d8489dab19f1 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 23 Nov 2017 12:46:32 +0100 Subject: [PATCH 03/10] Fix variant/material/quality handling in stacks CURA-4613 --- cura/Settings/CuraContainerRegistry.py | 75 ++++++++++++++++++++++++-- cura/Settings/CuraContainerStack.py | 17 ++++-- 2 files changed, 84 insertions(+), 8 deletions(-) diff --git a/cura/Settings/CuraContainerRegistry.py b/cura/Settings/CuraContainerRegistry.py index 1674405824..543678ee22 100644 --- a/cura/Settings/CuraContainerRegistry.py +++ b/cura/Settings/CuraContainerRegistry.py @@ -4,6 +4,7 @@ import os import os.path import re +import configparser from typing import Optional @@ -19,6 +20,7 @@ from UM.Message import Message from UM.Platform import Platform from UM.PluginRegistry import PluginRegistry # For getting the possible profile writers to write with. from UM.Util import parseBool +from UM.Resources import Resources from . import ExtruderStack from . import GlobalStack @@ -444,21 +446,84 @@ class CuraContainerRegistry(ContainerRegistry): self.addContainer(user_container) variant_id = "default" - if machine.variant.getId() != "empty_variant": + if machine.variant.getId() not in ("empty", "empty_variant"): variant_id = machine.variant.getId() + else: + variant_id = "empty_variant" extruder_stack.setVariantById(variant_id) - extruder_stack.setMaterialById("default") - extruder_stack.setQualityById("default") - if machine.qualityChanges.getId() != "empty_quality_changes": + + material_id = "default" + if machine.material.getId() not in ("empty", "empty_material"): + # TODO: find the ID that's suitable for this extruder + pass + else: + material_id = "empty_material" + extruder_stack.setMaterialById(material_id) + + quality_id = "default" + if machine.quality.getId() not in ("empty", "empty_quality"): + # TODO: find the ID that's suitable for this extruder + pass + else: + quality_id = "empty_quality" + extruder_stack.setQualityById(quality_id) + + if machine.qualityChanges.getId() not in ("empty", "empty_quality_changes"): extruder_quality_changes_container = self.findInstanceContainers(name = machine.qualityChanges.getName(), extruder = extruder_id) if extruder_quality_changes_container: - quality_changes_id = extruder_quality_changes_container[0].getId() + extruder_quality_changes_container = extruder_quality_changes_container[0] + quality_changes_id = extruder_quality_changes_container.getId() extruder_stack.setQualityChangesById(quality_changes_id) + else: + # Some extruder quality_changes containers can be created at runtime as files in the qualities + # folder. Those files won't be loaded in the registry immediately. So we also need to search + # the folder to see if the quality_changes exists. + extruder_quality_changes_container = self._findQualityChangesContainerInCuraFolder(machine.qualityChanges.getName()) + if extruder_quality_changes_container: + quality_changes_id = extruder_quality_changes_container.getId() + extruder_stack.setQualityChangesById(quality_changes_id) + + if not extruder_quality_changes_container: + Logger.log("w", "Could not find quality_changes named [%s] for extruder [%s]", + machine.qualityChanges.getName(), extruder_stack.getId()) self.addContainer(extruder_stack) return extruder_stack + def _findQualityChangesContainerInCuraFolder(self, name): + quality_changes_dir = Resources.getPath(CuraApplication.ResourceTypes.QualityInstanceContainer) + + instance_container = None + + for item in os.listdir(quality_changes_dir): + file_path = os.path.join(quality_changes_dir, item) + if not os.path.isfile(file_path): + continue + + parser = configparser.ConfigParser() + try: + parser.read([file_path]) + except: + # skip, it is not a valid stack file + continue + + if not parser.has_option("general", "name"): + continue + + if parser["general"]["name"] == name: + # load the container + container_id = os.path.basename(file_path).replace(".inst.cfg", "") + + instance_container = InstanceContainer(container_id) + with open(file_path, "r") as f: + serialized = f.read() + instance_container.deserialize(serialized, file_path) + self.addContainer(instance_container) + break + + return instance_container + # Fix the extruders that were upgraded to ExtruderStack instances during addContainer. # The stacks are now responsible for setting the next stack on deserialize. However, # due to problems with loading order, some stacks may not have the proper next stack diff --git a/cura/Settings/CuraContainerStack.py b/cura/Settings/CuraContainerStack.py index 9bbea044cf..156883ade3 100755 --- a/cura/Settings/CuraContainerStack.py +++ b/cura/Settings/CuraContainerStack.py @@ -41,9 +41,20 @@ class CuraContainerStack(ContainerStack): def __init__(self, container_id: str, *args, **kwargs): super().__init__(container_id, *args, **kwargs) - self._empty_instance_container = ContainerRegistry.getInstance().getEmptyInstanceContainer() + self._container_registry = ContainerRegistry.getInstance() + + self._empty_instance_container = self._container_registry.getEmptyInstanceContainer() + + self._empty_quality_changes = self._container_registry.findInstanceContainers(id = "empty_quality_changes")[0] + self._empty_quality = self._container_registry.findInstanceContainers(id = "empty_quality")[0] + self._empty_material = self._container_registry.findInstanceContainers(id = "empty_material")[0] + self._empty_variant = self._container_registry.findInstanceContainers(id = "empty_variant")[0] self._containers = [self._empty_instance_container for i in range(len(_ContainerIndexes.IndexTypeMap))] + self._containers[_ContainerIndexes.QualityChanges] = self._empty_quality_changes + self._containers[_ContainerIndexes.Quality] = self._empty_quality + self._containers[_ContainerIndexes.Material] = self._empty_material + self._containers[_ContainerIndexes.Variant] = self._empty_variant self.containersChanged.connect(self._onContainersChanged) @@ -456,7 +467,7 @@ class CuraContainerStack(ContainerStack): else: search_criteria["definition"] = "fdmprinter" - if self.material != self._empty_instance_container: + if self.material != self._empty_material: search_criteria["name"] = self.material.name else: preferred_material = definition.getMetaDataEntry("preferred_material") @@ -503,7 +514,7 @@ class CuraContainerStack(ContainerStack): else: search_criteria["definition"] = "fdmprinter" - if self.quality != self._empty_instance_container: + if self.quality != self._empty_quality: search_criteria["name"] = self.quality.name else: preferred_quality = definition.getMetaDataEntry("preferred_quality") From 1141368682ba3121d29c2ffb67c422fa9536b97c Mon Sep 17 00:00:00 2001 From: Aleksei Sasin Date: Thu, 23 Nov 2017 12:54:53 +0100 Subject: [PATCH 04/10] Hide icons if monitor view is selected CURA-4527 --- resources/qml/Topbar.qml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/resources/qml/Topbar.qml b/resources/qml/Topbar.qml index 033e1a55f9..6085c6fe7e 100644 --- a/resources/qml/Topbar.qml +++ b/resources/qml/Topbar.qml @@ -228,6 +228,8 @@ Rectangle spacing: 2 + visible: !base.monitoringPrint + anchors { verticalCenter: base.verticalCenter right: viewModeButton.right From 1db448d7d89de6a2f18327380a098c487e416935 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 23 Nov 2017 13:04:03 +0100 Subject: [PATCH 05/10] Use the correct quality container for global stacks loaded from project files CURA-4613 --- plugins/3MFReader/ThreeMFWorkspaceReader.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index 8e087611ef..65f026685b 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -790,6 +790,19 @@ class ThreeMFWorkspaceReader(WorkspaceReader): for stack in [global_stack] + extruder_stacks: stack.replaceContainer(_ContainerIndexes.Quality, empty_quality_container) + # Fix quality: + # The quality specified in an old project file can be wrong, for example, for UM2, it should be "um2_normal" + # but instead it was "normal". This should be fixed by setting it to the correct quality. + # Note that this only seems to happen on single-extrusion machines on the global stack, so we only apply the + # fix for that + quality = global_stack.quality + if quality.getId() not in ("empty", "empty_quality"): + quality_type = quality.getMetaDataEntry("quality_type") + quality_containers = self._container_registry.findInstanceContainers(definition = global_stack.definition.getId(), + quality_type = quality_type) + if quality_containers: + global_stack.quality = quality_containers[0] + # Replacing the old containers if resolve is "new". # When resolve is "new", some containers will get renamed, so all the other containers that reference to those # MUST get updated too. From 2397b68cd78bb40aea3852b6f6c43cbf1f2ceb25 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 23 Nov 2017 14:07:38 +0100 Subject: [PATCH 06/10] Optimize MaterialsModel update CURA-4546 --- cura/Settings/MaterialsModel.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cura/Settings/MaterialsModel.py b/cura/Settings/MaterialsModel.py index bee9307b53..bab8929765 100644 --- a/cura/Settings/MaterialsModel.py +++ b/cura/Settings/MaterialsModel.py @@ -18,4 +18,8 @@ class MaterialsModel(InstanceContainersModel): # \param container The container whose metadata was changed. def _onContainerMetaDataChanged(self, container): if container.getMetaDataEntry("type") == "material": #Only need to update if a material was changed. - self._update() \ No newline at end of file + self._update() + + def _onContainerChanged(self, container): + if container.getMetaDataEntry("type", "") == "material": + super()._onContainerChanged(container) From dad2dfda89e0c26b409f1bb4d981bacc1a8f0b39 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 23 Nov 2017 14:08:10 +0100 Subject: [PATCH 07/10] No need to set currentItem after a material is imported CURA-4546 --- resources/qml/Preferences/MaterialsPage.qml | 1 - 1 file changed, 1 deletion(-) diff --git a/resources/qml/Preferences/MaterialsPage.qml b/resources/qml/Preferences/MaterialsPage.qml index 5e014faf24..cd04b79b20 100644 --- a/resources/qml/Preferences/MaterialsPage.qml +++ b/resources/qml/Preferences/MaterialsPage.qml @@ -322,7 +322,6 @@ UM.ManagementPage { messageDialog.icon = StandardIcon.Information messageDialog.text = catalog.i18nc("@info:status Don't translate the XML tag !", "Successfully imported material %1").arg(fileUrl) - currentItem = base.model.getItem(base.objectList.currentIndex) } else if(result.status == "duplicate") { From 033cc4fbc79cdaedd554805c2e7c12a56307363e Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 23 Nov 2017 14:12:23 +0100 Subject: [PATCH 08/10] Fix quality update in project loading CURA-4613 --- plugins/3MFReader/ThreeMFWorkspaceReader.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index 65f026685b..d54e0a724e 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -799,6 +799,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): if quality.getId() not in ("empty", "empty_quality"): quality_type = quality.getMetaDataEntry("quality_type") quality_containers = self._container_registry.findInstanceContainers(definition = global_stack.definition.getId(), + type = "quality", quality_type = quality_type) if quality_containers: global_stack.quality = quality_containers[0] From e3cdcc04fd7fc20f0f478aa0e87ec8c50267cc02 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 23 Nov 2017 14:57:28 +0100 Subject: [PATCH 09/10] Document IRC channels --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index f8d809df16..ba6a986093 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,8 @@ For crashes and similar issues, please attach the following information: If the Cura user interface still starts, you can also reach this directory from the application menu in Help -> Show settings folder +For additional support, you could also ask in the #cura channel on FreeNode IRC. For help with development, there is also the #cura-dev channel. + Dependencies ------------ From ef37f0d8c78bbbeee97737a61cbfe189808f96f9 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 23 Nov 2017 15:34:51 +0100 Subject: [PATCH 10/10] Fix project loading to reset quality if it doesn't exist CURA-4617 --- plugins/3MFReader/ThreeMFWorkspaceReader.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index d54e0a724e..ccdff869a0 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -803,6 +803,22 @@ class ThreeMFWorkspaceReader(WorkspaceReader): quality_type = quality_type) if quality_containers: global_stack.quality = quality_containers[0] + else: + # the quality_type of the quality profile cannot be found. + # this can happen if a quality_type has been removed in a newer version, for example: + # "extra_coarse" is removed from 2.7 to 3.0 + # in this case, the quality will be reset to "normal" + quality_containers = self._container_registry.findInstanceContainers( + definition = global_stack.definition.getId(), + type = "quality", + quality_type = "normal") + if quality_containers: + global_stack.quality = quality_containers[0] + else: + # This should not happen! + Logger.log("e", "Cannot find quality normal for global stack [%s] [%s]", + global_stack.getId(), global_stack.definition.getId()) + global_stack.quality = self._container_registry.findInstanceContainers(id = "empty_quality") # Replacing the old containers if resolve is "new". # When resolve is "new", some containers will get renamed, so all the other containers that reference to those