Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/Ultimaker/Cura.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDiego Prado Gesto <d.pradogesto@ultimaker.com>2017-11-23 17:42:02 +0300
committerDiego Prado Gesto <d.pradogesto@ultimaker.com>2017-11-23 17:42:02 +0300
commitf0dca021d80d24a0c30b0e1f7e1a8fb31781af8c (patch)
tree86250ba120829f2456b510749e3552e69a6b0148
parent2c6b2b869ef20686cf38395c20fe94d3eb4d8f06 (diff)
parentef37f0d8c78bbbeee97737a61cbfe189808f96f9 (diff)
Merge branch '3.1' of https://github.com/Ultimaker/Cura into 3.1
-rw-r--r--README.md2
-rw-r--r--cura/Settings/CuraContainerRegistry.py75
-rwxr-xr-xcura/Settings/CuraContainerStack.py21
-rw-r--r--cura/Settings/ExtruderStack.py4
-rw-r--r--cura/Settings/MaterialsModel.py6
-rwxr-xr-xplugins/3MFReader/ThreeMFWorkspaceReader.py70
-rw-r--r--plugins/VersionUpgrade/VersionUpgrade30to31/VersionUpgrade30to31.py7
-rw-r--r--plugins/XmlMaterialProfile/XmlMaterialProfile.py4
-rw-r--r--resources/qml/Preferences/MaterialsPage.qml1
-rw-r--r--resources/qml/Topbar.qml2
10 files changed, 159 insertions, 33 deletions
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
------------
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