Rewrite cloning of materials

The original was based on reading the original file back, but that won't work if the files are provided by an arbitrary container provider. Instead we'll actually make a copy of all the profiles that need to be copied. It's much faster as well.

Contributes to issue CURA-4243.
This commit is contained in:
Ghostkeeper 2017-12-01 16:19:58 +01:00
parent 17ede12573
commit 083a4a8024
No known key found for this signature in database
GPG key ID: 5252B696FB5E7C7A

View file

@ -1,6 +1,7 @@
# Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
import copy
import os.path
import urllib
import uuid
@ -751,27 +752,52 @@ class ContainerManager(QObject):
# \return \type{str} the id of the newly created container.
@pyqtSlot(str, result = str)
def duplicateMaterial(self, material_id: str) -> str:
containers = self._container_registry.findInstanceContainers(id = material_id)
if not containers:
original = self._container_registry.findContainersMetadata(id = material_id)
if not original:
Logger.log("d", "Unable to duplicate the material with id %s, because it doesn't exist.", material_id)
return ""
original = original[0]
base_container_id = original.get("base_file")
base_container = self._container_registry.findContainers(id = base_container_id)
if not base_container:
Logger.log("d", "Unable to duplicate the material with id {material_id}, because base_file {base_container_id} doesn't exist.".format(material_id = material_id, base_container_id = base_container_id))
return ""
base_container = base_container[0]
#We'll copy all containers with the same base.
#This way the correct variant and machine still gets assigned when loading the copy of the material.
containers_to_copy = self._container_registry.findInstanceContainers(base_file = base_container_id)
# Ensure all settings are saved.
Application.getInstance().saveSettings()
# Create a new ID & container to hold the data.
new_id = self._container_registry.uniqueName(material_id)
container_type = type(containers[0]) # Could be either a XMLMaterialProfile or a InstanceContainer
duplicated_container = container_type(new_id)
new_containers = []
new_base_id = self._container_registry.uniqueName(base_container.getId())
new_base_container = copy.deepcopy(base_container)
new_base_container.getMetaData()["id"] = new_base_id
new_base_container.getMetaData()["base_file"] = new_base_id
new_containers.append(new_base_container)
# Instead of duplicating we load the data from the basefile again.
# This ensures that the inheritance goes well and all "cut up" subclasses of the xmlMaterial profile
# are also correctly created.
with open(containers[0].getPath(), encoding="utf-8") as f:
duplicated_container.deserialize(f.read())
duplicated_container.setDirty(True)
self._container_registry.addContainer(duplicated_container)
return self._getMaterialContainerIdForActiveMachine(new_id)
#Clone all of them.
clone_of_original = None #Keeping track of which one is the clone of the original material, since we need to return that.
for container_to_copy in containers_to_copy:
#Create unique IDs for every clone.
current_id = container_to_copy.getId()
new_id = self._container_registry.uniqueName(current_id)
if current_id == material_id:
clone_of_original = new_id
new_container = copy.deepcopy(container_to_copy)
new_container.getMetaData()["id"] = new_id
new_container.getMetaData()["base_file"] = new_base_id
new_containers.append(new_container)
for container_to_add in new_containers:
container_to_add.setDirty(True)
ContainerRegistry.getInstance().addContainer(container_to_add)
return self._getMaterialContainerIdForActiveMachine(clone_of_original)
## Create a new material by cloning Generic PLA for the current material diameter and setting the GUID to something unqiue
#
@ -839,7 +865,7 @@ class ContainerManager(QObject):
if materials:
return materials[0]["id"]
Logger.log("w", "Unable to find a suitable container based on %s for the current machine .", base_file)
Logger.log("w", "Unable to find a suitable container based on %s for the current machine.", base_file)
return "" # do not activate a new material if a container can not be found
return base_file