Browse Source

Merge branch 'fix_multiple_extruder_issues' of github.com:Ultimaker/Cura into 3.0

Jaime van Kessel 7 years ago
parent
commit
437da52f65

+ 25 - 5
cura/Settings/ExtruderManager.py

@@ -41,7 +41,7 @@ class ExtruderManager(QObject):
     def __init__(self, parent = None):
         super().__init__(parent)
         self._extruder_trains = { } #Per machine, a dictionary of extruder container stack IDs. Only for separately defined extruders.
-        self._active_extruder_index = 0
+        self._active_extruder_index = -1 # Indicates the index of the active extruder stack. -1 means no active extruder stack
         self._selected_object_extruders = []
         Application.getInstance().globalContainerStackChanged.connect(self.__globalContainerStackChanged)
         self._global_container_stack_definition_id = None
@@ -74,14 +74,18 @@ class ExtruderManager(QObject):
         except KeyError:
             return 0
 
+    ##  Gets a dict with the extruder stack ids with the extruder number as the key.
+    #   The key "-1" indicates the global stack id.
+    #
     @pyqtProperty("QVariantMap", notify = extrudersChanged)
     def extruderIds(self):
-        map = {}
+        extruder_stack_ids = {}
         global_stack_id = Application.getInstance().getGlobalContainerStack().getId()
+        extruder_stack_ids["-1"] = global_stack_id
         if global_stack_id in self._extruder_trains:
             for position in self._extruder_trains[global_stack_id]:
-                map[position] = self._extruder_trains[global_stack_id][position].getId()
-        return map
+                extruder_stack_ids[position] = self._extruder_trains[global_stack_id][position].getId()
+        return extruder_stack_ids
 
     @pyqtSlot(str, result = str)
     def getQualityChangesIdByExtruderStackId(self, id: str) -> str:
@@ -513,17 +517,33 @@ class ExtruderManager(QObject):
         global_stack = Application.getInstance().getGlobalContainerStack()
 
         result = []
+        machine_extruder_count = global_stack.getProperty("machine_extruder_count", "value")
+
+        # In case the printer is using one extruder, shouldn't exist active extruder stacks
+        if machine_extruder_count == 1:
+            return result
+
         if global_stack and global_stack.getId() in self._extruder_trains:
             for extruder in sorted(self._extruder_trains[global_stack.getId()]):
                 result.append(self._extruder_trains[global_stack.getId()][extruder])
 
-        return result[:global_stack.getProperty("machine_extruder_count", "value")]
+        return result[:machine_extruder_count]
 
     def __globalContainerStackChanged(self) -> None:
         global_container_stack = Application.getInstance().getGlobalContainerStack()
         if global_container_stack and global_container_stack.getBottom() and global_container_stack.getBottom().getId() != self._global_container_stack_definition_id:
             self._global_container_stack_definition_id = global_container_stack.getBottom().getId()
             self.globalContainerStackDefinitionChanged.emit()
+
+        # If the global container changed, the number of extruders could be changed and so the active_extruder_index is updated
+        extruder_count = global_container_stack.getProperty("machine_extruder_count", "value")
+        if extruder_count > 1:
+            if self._active_extruder_index == -1:
+                self.setActiveExtruderIndex(0)
+        else:
+            if self._active_extruder_index != -1:
+                self.setActiveExtruderIndex(-1)
+
         self.activeExtruderChanged.emit()
 
         self.resetSelectedObjectExtruders()

+ 11 - 3
cura/Settings/MachineManager.py

@@ -271,7 +271,6 @@ class MachineManager(QObject):
                     extruder_stack.containersChanged.disconnect(self._onInstanceContainersChanged)
 
         self._global_container_stack = Application.getInstance().getGlobalContainerStack()
-        self._active_container_stack = self._global_container_stack
 
         self.globalContainerChanged.emit()
 
@@ -303,6 +302,9 @@ class MachineManager(QObject):
 
                 quality = self._global_container_stack.quality
                 quality.nameChanged.connect(self._onQualityNameChanged)
+
+                self._active_container_stack = self._global_container_stack
+
         self._error_check_timer.start()
 
     ##  Update self._stacks_valid according to _checkStacksForErrors and emit if change.
@@ -543,16 +545,22 @@ class MachineManager(QObject):
 
         return result
 
+    ##  Gets a dict with the active materials ids set in all extruder stacks and the global stack
+    #   (when there is one extruder, the material is set in the global stack)
+    #
+    #   \return The material ids in all stacks
     @pyqtProperty("QVariantMap", notify = activeMaterialChanged)
     def allActiveMaterialIds(self) -> Dict[str, str]:
         result = {}
         active_stacks = ExtruderManager.getInstance().getActiveExtruderStacks()
-        if active_stacks is not None: #If we have a global stack.
+
+        result[self._global_container_stack.getId()] = self._global_container_stack.material.getId()
+
+        if active_stacks is not None:  # If we have extruder stacks
             for stack in active_stacks:
                 material_container = stack.material
                 if not material_container:
                     continue
-
                 result[stack.getId()] = material_container.getId()
 
         return result

+ 4 - 10
cura/Settings/ProfilesModel.py

@@ -98,16 +98,10 @@ class ProfilesModel(InstanceContainersModel):
         extruder_manager = ExtruderManager.getInstance()
         active_extruder = extruder_manager.getActiveExtruderStack()
         extruder_stacks = extruder_manager.getActiveExtruderStacks()
-        if extruder_stacks:
-            if multiple_extrusion:
-                # Place the active extruder at the front of the list.
-                if active_extruder in extruder_stacks:
-                    extruder_stacks.remove(active_extruder)
-                    extruder_stacks = [active_extruder] + extruder_stacks
-            else:
-                # The active extruder is the first in the list and only the active extruder is use to compute the usable qualities
-                active_extruder = None
-                extruder_stacks = []
+        if multiple_extrusion:
+            # Place the active extruder at the front of the list.
+            extruder_stacks.remove(active_extruder)
+            extruder_stacks = [active_extruder] + extruder_stacks
 
         # Get a list of usable/available qualities for this machine and material
         qualities = QualityManager.getInstance().findAllUsableQualitiesForMachineAndExtruders(global_container_stack,

+ 10 - 12
cura/Settings/QualityAndUserProfilesModel.py

@@ -31,16 +31,10 @@ class QualityAndUserProfilesModel(ProfilesModel):
         extruder_manager = ExtruderManager.getInstance()
         active_extruder = extruder_manager.getActiveExtruderStack()
         extruder_stacks = extruder_manager.getActiveExtruderStacks()
-        if extruder_stacks:
-            if multiple_extrusion:
-                # Place the active extruder at the front of the list.
-                if active_extruder in extruder_stacks:
-                    extruder_stacks.remove(active_extruder)
-                    extruder_stacks = [active_extruder] + extruder_stacks
-            else:
-                # The active extruder is the first in the list and only the active extruder is use to compute the usable qualities
-                active_extruder = None
-                extruder_stacks = []
+        if multiple_extrusion:
+            # Place the active extruder at the front of the list.
+            extruder_stacks.remove(active_extruder)
+            extruder_stacks = [active_extruder] + extruder_stacks
 
         # Fetch the list of useable qualities across all extruders.
         # The actual list of quality profiles come from the first extruder in the extruder list.
@@ -52,9 +46,13 @@ class QualityAndUserProfilesModel(ProfilesModel):
 
         if multiple_extrusion:
             # If the printer has multiple extruders then quality changes related to the current extruder are kept
-            filtered_quality_changes = [qc for qc in quality_changes_list if qc.getMetaDataEntry("quality_type") in quality_type_set and qc.getMetaDataEntry("extruder") == active_extruder.definition.getId()]
+            filtered_quality_changes = [qc for qc in quality_changes_list if qc.getMetaDataEntry("quality_type") in quality_type_set and
+                                        qc.getMetaDataEntry("extruder") is not None and
+                                        qc.getMetaDataEntry("extruder") == active_extruder.definition.getMetaDataEntry("quality_definition") or
+                                        qc.getMetaDataEntry("extruder") == active_extruder.definition.getId()]
         else:
             # If not, the quality changes of the global stack are selected
-            filtered_quality_changes = [qc for qc in quality_changes_list if qc.getMetaDataEntry("quality_type") in quality_type_set and qc.getMetaDataEntry("extruder") is None]
+            filtered_quality_changes = [qc for qc in quality_changes_list if qc.getMetaDataEntry("quality_type") in quality_type_set and
+                                        qc.getMetaDataEntry("extruder") is None]
 
         return quality_list + filtered_quality_changes

+ 10 - 12
cura/Settings/UserProfilesModel.py

@@ -31,16 +31,10 @@ class UserProfilesModel(ProfilesModel):
         extruder_manager = ExtruderManager.getInstance()
         active_extruder = extruder_manager.getActiveExtruderStack()
         extruder_stacks = extruder_manager.getActiveExtruderStacks()
-        if extruder_stacks:
-            if multiple_extrusion:
-                # Place the active extruder at the front of the list.
-                if active_extruder in extruder_stacks:
-                    extruder_stacks.remove(active_extruder)
-                    extruder_stacks = [active_extruder] + extruder_stacks
-            else:
-                # The active extruder is the first in the list and only the active extruder is use to compute the usable qualities
-                active_extruder = None
-                extruder_stacks = []
+        if multiple_extrusion:
+            # Place the active extruder at the front of the list.
+            extruder_stacks.remove(active_extruder)
+            extruder_stacks = [active_extruder] + extruder_stacks
 
         # Fetch the list of useable qualities across all extruders.
         # The actual list of quality profiles come from the first extruder in the extruder list.
@@ -52,9 +46,13 @@ class UserProfilesModel(ProfilesModel):
 
         if multiple_extrusion:
             # If the printer has multiple extruders then quality changes related to the current extruder are kept
-            filtered_quality_changes = [qc for qc in quality_changes_list if qc.getMetaDataEntry("quality_type") in quality_type_set and qc.getMetaDataEntry("extruder") == active_extruder.definition.getId()]
+            filtered_quality_changes = [qc for qc in quality_changes_list if qc.getMetaDataEntry("quality_type") in quality_type_set and
+                                        qc.getMetaDataEntry("extruder") is not None and
+                                        qc.getMetaDataEntry("extruder") == active_extruder.definition.getMetaDataEntry("quality_definition") or
+                                        qc.getMetaDataEntry("extruder") == active_extruder.definition.getId()]
         else:
             # If not, the quality changes of the global stack are selected
-            filtered_quality_changes = [qc for qc in quality_changes_list if qc.getMetaDataEntry("quality_type") in quality_type_set and qc.getMetaDataEntry("extruder") is None]
+            filtered_quality_changes = [qc for qc in quality_changes_list if qc.getMetaDataEntry("quality_type") in quality_type_set and
+                                        qc.getMetaDataEntry("extruder") is None]
 
         return filtered_quality_changes

+ 45 - 46
plugins/3MFReader/ThreeMFWorkspaceReader.py

@@ -693,54 +693,53 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
 
         # --
         # load extruder stack files
-        if extruder_count_from_global_stack > 1:
-            try:
-                for extruder_stack_file in extruder_stack_files:
-                    container_id = self._stripFileToId(extruder_stack_file)
-                    extruder_file_content = archive.open(extruder_stack_file, "r").read().decode("utf-8")
+        try:
+            for extruder_stack_file in extruder_stack_files:
+                container_id = self._stripFileToId(extruder_stack_file)
+                extruder_file_content = archive.open(extruder_stack_file, "r").read().decode("utf-8")
+
+                if self._resolve_strategies["machine"] == "override":
+                    # deserialize new extruder stack over the current ones
+                    stack = self._overrideExtruderStack(global_stack, extruder_file_content)
+
+                elif self._resolve_strategies["machine"] == "new":
+                    new_id = extruder_stack_id_map[container_id]
+                    stack = ExtruderStack(new_id)
+
+                    # HACK: the global stack can have a new name, so we need to make sure that this extruder stack
+                    #       references to the new name instead of the old one. Normally, this can be done after
+                    #       deserialize() by setting the metadata, but in the case of ExtruderStack, deserialize()
+                    #       also does addExtruder() to its machine stack, so we have to make sure that it's pointing
+                    #       to the right machine BEFORE deserialization.
+                    extruder_config = configparser.ConfigParser()
+                    extruder_config.read_string(extruder_file_content)
+                    extruder_config.set("metadata", "machine", global_stack_id_new)
+                    tmp_string_io = io.StringIO()
+                    extruder_config.write(tmp_string_io)
+                    extruder_file_content = tmp_string_io.getvalue()
+
+                    stack.deserialize(extruder_file_content)
+
+                    # Ensure a unique ID and name
+                    stack._id = new_id
+
+                    self._container_registry.addContainer(stack)
+                    extruder_stacks_added.append(stack)
+                    containers_added.append(stack)
+                else:
+                    Logger.log("w", "Unknown resolve strategy: %s", self._resolve_strategies["machine"])
 
-                    if self._resolve_strategies["machine"] == "override":
-                        # deserialize new extruder stack over the current ones
-                        stack = self._overrideExtruderStack(global_stack, extruder_file_content)
+                # Create a new definition_changes container if it was empty
+                if stack.definitionChanges == self._container_registry.getEmptyInstanceContainer():
+                    stack.setDefinitionChanges(CuraStackBuilder.createDefinitionChangesContainer(stack, stack._id + "_settings"))
 
-                    elif self._resolve_strategies["machine"] == "new":
-                        new_id = extruder_stack_id_map[container_id]
-                        stack = ExtruderStack(new_id)
-
-                        # HACK: the global stack can have a new name, so we need to make sure that this extruder stack
-                        #       references to the new name instead of the old one. Normally, this can be done after
-                        #       deserialize() by setting the metadata, but in the case of ExtruderStack, deserialize()
-                        #       also does addExtruder() to its machine stack, so we have to make sure that it's pointing
-                        #       to the right machine BEFORE deserialization.
-                        extruder_config = configparser.ConfigParser()
-                        extruder_config.read_string(extruder_file_content)
-                        extruder_config.set("metadata", "machine", global_stack_id_new)
-                        tmp_string_io = io.StringIO()
-                        extruder_config.write(tmp_string_io)
-                        extruder_file_content = tmp_string_io.getvalue()
-
-                        stack.deserialize(extruder_file_content)
-
-                        # Ensure a unique ID and name
-                        stack._id = new_id
-
-                        self._container_registry.addContainer(stack)
-                        extruder_stacks_added.append(stack)
-                        containers_added.append(stack)
-                    else:
-                        Logger.log("w", "Unknown resolve strategy: %s", self._resolve_strategies["machine"])
-
-                    # Create a new definition_changes container if it was empty
-                    if stack.definitionChanges == self._container_registry.getEmptyInstanceContainer():
-                        stack.setDefinitionChanges(CuraStackBuilder.createDefinitionChangesContainer(stack, stack._id + "_settings"))
-
-                    extruder_stacks.append(stack)
-            except:
-                Logger.logException("w", "We failed to serialize the stack. Trying to clean up.")
-                # Something went really wrong. Try to remove any data that we added.
-                for container in containers_added:
-                    self._container_registry.removeContainer(container.getId())
-                return
+                extruder_stacks.append(stack)
+        except:
+            Logger.logException("w", "We failed to serialize the stack. Trying to clean up.")
+            # Something went really wrong. Try to remove any data that we added.
+            for container in containers_added:
+                self._container_registry.removeContainer(container.getId())
+            return
 
         #
         # Replacing the old containers if resolve is "new".

+ 3 - 8
plugins/MachineSettingsAction/MachineSettingsAction.py

@@ -112,13 +112,7 @@ class MachineSettingsAction(MachineAction):
         if not self._global_container_stack:
             return 0
 
-        # If there is a printer that originally is multi-extruder, it's not allowed to change the number of extruders
-        # It's just allowed in case of Custom FDM printers
-        definition_container = self._global_container_stack.getBottom()
-        if definition_container.getId() == "custom":
-            return len(self._global_container_stack.getMetaDataEntry("machine_extruder_trains"))
-        return 0
-
+        return len(self._global_container_stack.getMetaDataEntry("machine_extruder_trains"))
 
     @pyqtSlot(int)
     def setMachineExtruderCount(self, extruder_count):
@@ -176,7 +170,6 @@ class MachineSettingsAction(MachineAction):
                     node.callDecoration("setActiveExtruder", extruder_manager.getExtruderStack(extruder_count - 1).getId())
 
         definition_changes_container.setProperty("machine_extruder_count", "value", extruder_count)
-        self.forceUpdate()
 
         if extruder_count > 1:
             # Multiextrusion
@@ -221,6 +214,8 @@ class MachineSettingsAction(MachineAction):
 
                 preferences.setValue("cura/choice_on_profile_override", choice_on_profile_override)
 
+        self.forceUpdate()
+
 
     @pyqtSlot()
     def forceUpdate(self):

+ 2 - 1
resources/extruders/ultimaker3_extended_extruder_left.def.json

@@ -5,7 +5,8 @@
     "inherits": "fdmextruder",
     "metadata": {
         "machine": "ultimaker3_extended",
-        "position": "0"
+        "position": "0",
+        "quality_definition": "ultimaker3_extruder_left"
     },
 
     "overrides": {

+ 2 - 1
resources/extruders/ultimaker3_extended_extruder_right.def.json

@@ -5,7 +5,8 @@
     "inherits": "fdmextruder",
     "metadata": {
         "machine": "ultimaker3_extended",
-        "position": "1"
+        "position": "1",
+        "quality_definition": "ultimaker3_extruder_right"
     },
 
     "overrides": {

+ 2 - 1
resources/extruders/ultimaker3_extruder_left.def.json

@@ -5,7 +5,8 @@
     "inherits": "fdmextruder",
     "metadata": {
         "machine": "ultimaker3",
-        "position": "0"
+        "position": "0",
+        "quality_definition": "ultimaker3_extruder_left"
     },
 
     "overrides": {

Some files were not shown because too many files changed in this diff