diff options
author | Diego Prado Gesto <d.pradogesto@ultimaker.com> | 2017-11-23 17:42:02 +0300 |
---|---|---|
committer | Diego Prado Gesto <d.pradogesto@ultimaker.com> | 2017-11-23 17:42:02 +0300 |
commit | f0dca021d80d24a0c30b0e1f7e1a8fb31781af8c (patch) | |
tree | 86250ba120829f2456b510749e3552e69a6b0148 | |
parent | 2c6b2b869ef20686cf38395c20fe94d3eb4d8f06 (diff) | |
parent | ef37f0d8c78bbbeee97737a61cbfe189808f96f9 (diff) |
Merge branch '3.1' of https://github.com/Ultimaker/Cura into 3.1
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | cura/Settings/CuraContainerRegistry.py | 75 | ||||
-rwxr-xr-x | cura/Settings/CuraContainerStack.py | 21 | ||||
-rw-r--r-- | cura/Settings/ExtruderStack.py | 4 | ||||
-rw-r--r-- | cura/Settings/MaterialsModel.py | 6 | ||||
-rwxr-xr-x | plugins/3MFReader/ThreeMFWorkspaceReader.py | 70 | ||||
-rw-r--r-- | plugins/VersionUpgrade/VersionUpgrade30to31/VersionUpgrade30to31.py | 7 | ||||
-rw-r--r-- | plugins/XmlMaterialProfile/XmlMaterialProfile.py | 4 | ||||
-rw-r--r-- | resources/qml/Preferences/MaterialsPage.qml | 1 | ||||
-rw-r--r-- | resources/qml/Topbar.qml | 2 |
10 files changed, 159 insertions, 33 deletions
@@ -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 ------------ 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 2a804def4d..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) @@ -348,8 +359,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): @@ -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") 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/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) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index aa81399b56..ccdff869a0 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 @@ -780,6 +790,36 @@ 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(), + type = "quality", + 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 # MUST get updated too. 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() 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) 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 <filename>!", "Successfully imported material <filename>%1</filename>").arg(fileUrl) - currentItem = base.model.getItem(base.objectList.currentIndex) } else if(result.status == "duplicate") { 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 |