Browse Source

Fix loading .curaproject files with stack setups from earlier versions - CURA-4646

ChrisTerBeke 7 years ago
parent
commit
3abf067d25

+ 12 - 1
cura/Settings/ContainerManager.py

@@ -61,7 +61,17 @@ class ContainerManager(QObject):
             return ""
 
         container = containers[0]
+        new_container = self.duplicateContainerInstance(container)
+        return new_container.getId()
 
+    ##  Create a duplicate of the given container instance
+    #
+    #   This will create and add a duplicate of the container that was passed.
+    #
+    #   \param container \type{ContainerInterface} The container to duplicate.
+    #
+    #   \return The duplicated container, or None if duplication failed.
+    def duplicateContainerInstance(self, container):
         new_container = None
         new_name = self._container_registry.uniqueName(container.getName())
         # Only InstanceContainer has a duplicate method at the moment.
@@ -73,10 +83,11 @@ class ContainerManager(QObject):
             new_container.deserialize(container.serialize())
             new_container.setName(new_name)
 
+        # TODO: we probably don't want to add it to the registry here!
         if new_container:
             self._container_registry.addContainer(new_container)
 
-        return new_container.getId()
+        return new_container
 
     ##  Change the name of a specified container to a new name.
     #

+ 41 - 39
cura/Settings/CuraContainerRegistry.py

@@ -205,53 +205,55 @@ class CuraContainerRegistry(ContainerRegistry):
                 # Note that this will fail quickly. That is, if any profile reader throws an exception, it will stop reading. It will only continue reading if the reader returned None.
                 Logger.log("e", "Failed to import profile from %s: %s while using profile reader. Got exception %s", file_name,profile_reader.getPluginId(), str(e))
                 return { "status": "error", "message": catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, str(e))}
-            if profile_or_list: # Success!
+
+            if profile_or_list:
                 name_seed = os.path.splitext(os.path.basename(file_name))[0]
                 new_name = self.uniqueName(name_seed)
-                if type(profile_or_list) is not list:
-                    profile = profile_or_list
 
-                    result = self._configureProfile(profile, name_seed, new_name)
-                    if result is not None:
-                        return {"status": "error", "message": catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, result)}
-
-                    return {"status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile.getName())}
-                else:
-                    profile_index = -1
-                    global_profile = None
-
-                    for profile in profile_or_list:
-                        if profile_index >= 0:
-                            if len(machine_extruders) > profile_index:
-                                extruder_id = Application.getInstance().getMachineManager().getQualityDefinitionId(machine_extruders[profile_index].getBottom())
-                                # Ensure the extruder profiles get non-conflicting names
-                                # NB: these are not user-facing
-                                if "extruder" in profile.getMetaData():
-                                    profile.setMetaDataEntry("extruder", extruder_id)
-                                else:
-                                    profile.addMetaDataEntry("extruder", extruder_id)
-                                profile_id = (extruder_id + "_" + name_seed).lower().replace(" ", "_")
-                            elif profile_index == 0:
-                                # Importing a multiextrusion profile into a single extrusion machine; merge 1st extruder profile into global profile
-                                profile._id = self.uniqueName("temporary_profile")
-                                self.addContainer(profile)
-                                ContainerManager.getInstance().mergeContainers(global_profile.getId(), profile.getId())
-                                self.removeContainer(profile.getId())
-                                break
-                            else:
-                                # The imported composite profile has a profile for an extruder that this machine does not have. Ignore this extruder-profile
-                                break
+                # Ensure it is always a list of profiles
+                if type(profile_or_list) is not list:
+                    profile_or_list = [profile_or_list]
+
+                if len(profile_or_list) == 1:
+                    # If there is only 1 stack file it means we're loading a legacy (pre-3.1) .curaprofile.
+                    # In that case we find the per-extruder settings and put those in a new quality_changes container
+                    # so that it is compatible with the new stack setup.
+                    profile = profile_or_list[0]
+                    extruder_stack_quality_changes_container = ContainerManager.getInstance().duplicateContainerInstance(profile)
+                    extruder_stack_quality_changes_container.addMetaDataEntry("extruder", "fdmextruder")
+
+                    for quality_changes_setting_key in extruder_stack_quality_changes_container.getAllKeys():
+                        settable_per_extruder = extruder_stack_quality_changes_container.getProperty(quality_changes_setting_key, "settable_per_extruder")
+                        if settable_per_extruder:
+                            profile.removeInstance(quality_changes_setting_key, postpone_emit = True)
                         else:
-                            global_profile = profile
-                            profile_id = (global_container_stack.getBottom().getId() + "_" + name_seed).lower().replace(" ", "_")
+                            extruder_stack_quality_changes_container.removeInstance(quality_changes_setting_key, postpone_emit = True)
+
+                    # We add the new container to the profile list so things like extruder positions are taken care of
+                    # in the next code segment.
+                    profile_or_list.append(extruder_stack_quality_changes_container)
 
+                # Import all profiles
+                for profile_index, profile in enumerate(profile_or_list):
+                    if profile_index == 0:
+                        # This is assumed to be the global profile
+                        profile_id = (global_container_stack.getBottom().getId() + "_" + name_seed).lower().replace(" ", "_")
                         result = self._configureProfile(profile, profile_id, new_name)
                         if result is not None:
-                            return {"status": "error", "message": catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, result)}
-
-                        profile_index += 1
+                            return {"status": "error", "message": catalog.i18nc(
+                                "@info:status Don't translate the XML tags <filename> or <message>!",
+                                "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>",
+                                file_name, result)}
+
+                    elif len(machine_extruders) > profile_index:
+                        # This is assumed to be an extruder profile
+                        extruder_id = Application.getInstance().getMachineManager().getQualityDefinitionId(machine_extruders[profile_index - 1].getBottom())
+                        if not profile.getMetaDataEntry("extruder"):
+                            profile.addMetaDataEntry("extruder", extruder_id)
+                        else:
+                            profile.setMetaDataEntry("extruder", extruder_id)
 
-                    return {"status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile_or_list[0].getName())}
+                return {"status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile_or_list[0].getName())}
 
         # If it hasn't returned by now, none of the plugins loaded the profile successfully.
         return {"status": "error", "message": catalog.i18nc("@info:status", "Profile {0} has an unknown file type or is corrupted.", file_name)}

+ 8 - 0
plugins/VersionUpgrade/VersionUpgrade30to31/VersionUpgrade30to31.py

@@ -203,6 +203,14 @@ class VersionUpgrade30to31(VersionUpgrade):
     def _createExtruderQualityChangesForSingleExtrusionMachine(self, filename, global_quality_changes):
         suffix = "_" + quote_plus(global_quality_changes["general"]["name"].lower())
         machine_name = os.path.os.path.basename(filename).replace(".inst.cfg", "").replace(suffix, "")
+
+        # Why is this here?!
+        # When we load a .curaprofile file the deserialize will trigger a version upgrade, creating a dangling file.
+        # This file can be recognized by it's lack of a machine name in the target filename.
+        # So when we detect that situation here, we don't create the file and return.
+        if machine_name == "":
+            return
+
         new_filename = machine_name + "_" + "fdmextruder" + suffix
 
         extruder_quality_changes_parser = configparser.ConfigParser()