Browse Source

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.
Ghostkeeper 7 years ago
parent
commit
083a4a8024
1 changed files with 41 additions and 15 deletions
  1. 41 15
      cura/Settings/ContainerManager.py

+ 41 - 15
cura/Settings/ContainerManager.py

@@ -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)
-
-        # 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)
+        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)
+
+        #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