Просмотр исходного кода

Merge branch 'master' into network_rewrite

ChrisTerBeke 7 лет назад
Родитель
Сommit
182e7de07d

+ 36 - 34
Jenkinsfile

@@ -1,45 +1,47 @@
-parallel_nodes(['linux && cura', 'windows && cura']) {
-    // Prepare building
-    stage('Prepare') {
-        // Ensure we start with a clean build directory.
-        step([$class: 'WsCleanup'])
+timeout(time: 2, unit: "HOURS") {
+    parallel_nodes(['linux && cura', 'windows && cura']) {
+        // Prepare building
+        stage('Prepare') {
+            // Ensure we start with a clean build directory.
+            step([$class: 'WsCleanup'])
 
-        // Checkout whatever sources are linked to this pipeline.
-        checkout scm
-    }
+            // Checkout whatever sources are linked to this pipeline.
+            checkout scm
+        }
 
-    // If any error occurs during building, we want to catch it and continue with the "finale" stage.
-    catchError {
-        // Building and testing should happen in a subdirectory.
-        dir('build') {
-            // Perform the "build". Since Uranium is Python code, this basically only ensures CMake is setup.
-            stage('Build') {
-                def branch = env.BRANCH_NAME
-                if(!fileExists("${env.CURA_ENVIRONMENT_PATH}/${branch}")) {
-                    branch = "master"
-                }
+        // If any error occurs during building, we want to catch it and continue with the "finale" stage.
+        catchError {
+            // Building and testing should happen in a subdirectory.
+            dir('build') {
+                // Perform the "build". Since Uranium is Python code, this basically only ensures CMake is setup.
+                stage('Build') {
+                    def branch = env.BRANCH_NAME
+                    if(!fileExists("${env.CURA_ENVIRONMENT_PATH}/${branch}")) {
+                        branch = "master"
+                    }
 
-                // Ensure CMake is setup. Note that since this is Python code we do not really "build" it.
-                def uranium_dir = get_workspace_dir("Ultimaker/Uranium/${branch}")
-                cmake("..", "-DCMAKE_PREFIX_PATH=\"${env.CURA_ENVIRONMENT_PATH}/${branch}\" -DCMAKE_BUILD_TYPE=Release -DURANIUM_DIR=\"${uranium_dir}\"")
-            }
+                    // Ensure CMake is setup. Note that since this is Python code we do not really "build" it.
+                    def uranium_dir = get_workspace_dir("Ultimaker/Uranium/${branch}")
+                    cmake("..", "-DCMAKE_PREFIX_PATH=\"${env.CURA_ENVIRONMENT_PATH}/${branch}\" -DCMAKE_BUILD_TYPE=Release -DURANIUM_DIR=\"${uranium_dir}\"")
+                }
 
-            // Try and run the unit tests. If this stage fails, we consider the build to be "unstable".
-            stage('Unit Test') {
-                try {
-                    make('test')
-                } catch(e) {
-                    currentBuild.result = "UNSTABLE"
+                // Try and run the unit tests. If this stage fails, we consider the build to be "unstable".
+                stage('Unit Test') {
+                    try {
+                        make('test')
+                    } catch(e) {
+                        currentBuild.result = "UNSTABLE"
+                    }
                 }
             }
         }
-    }
 
-    // Perform any post-build actions like notification and publishing of unit tests.
-    stage('Finalize') {
-        // Publish the test results to Jenkins.
-        junit allowEmptyResults: true, testResults: 'build/junit*.xml'
+        // Perform any post-build actions like notification and publishing of unit tests.
+        stage('Finalize') {
+            // Publish the test results to Jenkins.
+            junit allowEmptyResults: true, testResults: 'build/junit*.xml'
 
-        notify_build_result(env.CURA_EMAIL_RECIPIENTS, '#cura-dev', ['master', '2.'])
+            notify_build_result(env.CURA_EMAIL_RECIPIENTS, '#cura-dev', ['master', '2.'])
+        }
     }
 }

+ 13 - 6
cmake/CuraTests.cmake

@@ -24,16 +24,23 @@ function(cura_add_test)
     
     if(WIN32)
         string(REPLACE "|" "\\;" _PYTHONPATH ${_PYTHONPATH})
+        set(_PYTHONPATH "${_PYTHONPATH}\\;$ENV{PYTHONPATH}")
     else()
         string(REPLACE "|" ":" _PYTHONPATH ${_PYTHONPATH})
+        set(_PYTHONPATH "${_PYTHONPATH}:$ENV{PYTHONPATH}")
     endif()
 
-    add_test(
-        NAME ${_NAME}
-        COMMAND ${PYTHON_EXECUTABLE} -m pytest --junitxml=${CMAKE_BINARY_DIR}/junit-${_NAME}.xml ${_DIRECTORY}
-    )
-    set_tests_properties(${_NAME} PROPERTIES ENVIRONMENT LANG=C)
-    set_tests_properties(${_NAME} PROPERTIES ENVIRONMENT "PYTHONPATH=${_PYTHONPATH}")
+    get_test_property(${_NAME} ENVIRONMENT test_exists) #Find out if the test exists by getting a property from it that always exists (such as ENVIRONMENT because we set that ourselves).
+    if (NOT ${test_exists})
+        add_test(
+            NAME ${_NAME}
+            COMMAND ${PYTHON_EXECUTABLE} -m pytest --junitxml=${CMAKE_BINARY_DIR}/junit-${_NAME}.xml ${_DIRECTORY}
+        )
+        set_tests_properties(${_NAME} PROPERTIES ENVIRONMENT LANG=C)
+        set_tests_properties(${_NAME} PROPERTIES ENVIRONMENT "PYTHONPATH=${_PYTHONPATH}")
+    else()
+        message(WARNING "Duplicate test ${_NAME}!")
+    endif()
 endfunction()
 
 cura_add_test(NAME pytest-main DIRECTORY ${CMAKE_SOURCE_DIR}/tests PYTHONPATH "${CMAKE_SOURCE_DIR}|${URANIUM_DIR}")

+ 11 - 3
cura/CuraApplication.py

@@ -316,7 +316,7 @@ class CuraApplication(QtApplication):
         preferences.addPreference("cura/material_settings", "{}")
 
         preferences.addPreference("view/invert_zoom", False)
-        preferences.addPreference("cura/sidebar_collapse", False)
+        preferences.addPreference("cura/sidebar_collapsed", False)
 
         self._need_to_show_user_agreement = not Preferences.getInstance().getValue("general/accepted_user_agreement")
 
@@ -409,6 +409,14 @@ class CuraApplication(QtApplication):
         else:
             self.exit(0)
 
+    ##  Signal to connect preferences action in QML
+    showPreferencesWindow = pyqtSignal()
+
+    ##  Show the preferences window
+    @pyqtSlot()
+    def showPreferences(self):
+        self.showPreferencesWindow.emit()
+
     ## A reusable dialogbox
     #
     showMessageBox = pyqtSignal(str, str, str, str, int, int, arguments = ["title", "text", "informativeText", "detailedText", "buttons", "icon"])
@@ -683,7 +691,7 @@ class CuraApplication(QtApplication):
         self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml"))
         self._qml_import_paths.append(Resources.getPath(self.ResourceTypes.QmlFiles))
 
-        run_without_gui = self.getCommandLineOption("headless", False) or self.getCommandLineOption("invisible", False)
+        run_without_gui = self.getCommandLineOption("headless", False)
         if not run_without_gui:
             self.initializeEngine()
             controller.setActiveStage("PrepareStage")
@@ -1379,7 +1387,7 @@ class CuraApplication(QtApplication):
 
             if node.callDecoration("isSliceable"):
                 # Only check position if it's not already blatantly obvious that it won't fit.
-                if node.getBoundingBox().width < self._volume.getBoundingBox().width or node.getBoundingBox().depth < self._volume.getBoundingBox().depth:
+                if node.getBoundingBox() is None or self._volume.getBoundingBox() is None or node.getBoundingBox().width < self._volume.getBoundingBox().width or node.getBoundingBox().depth < self._volume.getBoundingBox().depth:
                     # Find node location
                     offset_shape_arr, hull_shape_arr = ShapeArray.fromNode(node, min_offset = min_offset)
 

+ 28 - 8
cura/PlatformPhysics.py

@@ -34,6 +34,7 @@ class PlatformPhysics:
         self._change_timer.timeout.connect(self._onChangeTimerFinished)
         self._move_factor = 1.1  # By how much should we multiply overlap to calculate a new spot?
         self._max_overlap_checks = 10  # How many times should we try to find a new spot per tick?
+        self._minimum_gap = 2 # It is a minimum distance between two models, applicable for small models
 
         Preferences.getInstance().addPreference("physics/automatic_push_free", True)
         Preferences.getInstance().addPreference("physics/automatic_drop_down", True)
@@ -76,7 +77,8 @@ class PlatformPhysics:
             if not node.getDecorator(ConvexHullDecorator):
                 node.addDecorator(ConvexHullDecorator())
 
-            if Preferences.getInstance().getValue("physics/automatic_push_free"):
+            # only push away objects if this node is a printing mesh
+            if not node.callDecoration("isNonPrintingMesh") and Preferences.getInstance().getValue("physics/automatic_push_free"):
                 # Check for collisions between convex hulls
                 for other_node in BreadthFirstIterator(root):
                     # Ignore root, ourselves and anything that is not a normal SceneNode.
@@ -98,6 +100,9 @@ class PlatformPhysics:
                     if other_node in transformed_nodes:
                         continue  # Other node is already moving, wait for next pass.
 
+                    if other_node.callDecoration("isNonPrintingMesh"):
+                        continue
+
                     overlap = (0, 0)  # Start loop with no overlap
                     current_overlap_checks = 0
                     # Continue to check the overlap until we no longer find one.
@@ -112,26 +117,41 @@ class PlatformPhysics:
                                     overlap = node.callDecoration("getConvexHull").translate(move_vector.x, move_vector.z).intersectsPolygon(other_head_hull)
                                     if overlap:
                                         # Moving ensured that overlap was still there. Try anew!
-                                        move_vector = move_vector.set(x=move_vector.x + overlap[0] * self._move_factor,
-                                                                      z=move_vector.z + overlap[1] * self._move_factor)
+                                        move_vector = move_vector.set(x = move_vector.x + overlap[0] * self._move_factor,
+                                                                      z = move_vector.z + overlap[1] * self._move_factor)
                             else:
                                 # Moving ensured that overlap was still there. Try anew!
-                                move_vector = move_vector.set(x=move_vector.x + overlap[0] * self._move_factor,
-                                                              z=move_vector.z + overlap[1] * self._move_factor)
+                                move_vector = move_vector.set(x = move_vector.x + overlap[0] * self._move_factor,
+                                                              z = move_vector.z + overlap[1] * self._move_factor)
                         else:
                             own_convex_hull = node.callDecoration("getConvexHull")
                             other_convex_hull = other_node.callDecoration("getConvexHull")
                             if own_convex_hull and other_convex_hull:
                                 overlap = own_convex_hull.translate(move_vector.x, move_vector.z).intersectsPolygon(other_convex_hull)
                                 if overlap:  # Moving ensured that overlap was still there. Try anew!
-                                    move_vector = move_vector.set(x=move_vector.x + overlap[0] * self._move_factor,
-                                                                  z=move_vector.z + overlap[1] * self._move_factor)
+                                    temp_move_vector = move_vector.set(x = move_vector.x + overlap[0] * self._move_factor,
+                                                                  z = move_vector.z + overlap[1] * self._move_factor)
+
+                                    # if the distance between two models less than 2mm then try to find a new factor
+                                    if abs(temp_move_vector.x - overlap[0]) < self._minimum_gap and abs(temp_move_vector.y - overlap[1]) < self._minimum_gap:
+                                        temp_scale_factor = self._move_factor
+                                        temp_x_factor = (abs(overlap[0]) + self._minimum_gap) / overlap[0] if overlap[0] != 0 else 0 # find x move_factor, like (3.4 + 2) / 3.4 = 1.58
+                                        temp_y_factor = (abs(overlap[1]) + self._minimum_gap) / overlap[1] if overlap[1] != 0 else 0 # find y move_factor
+                                        if abs(temp_x_factor) > abs(temp_y_factor):
+                                            temp_scale_factor = temp_x_factor
+                                        else:
+                                            temp_scale_factor = temp_y_factor
+
+                                        move_vector = move_vector.set(x = move_vector.x + overlap[0] * temp_scale_factor,
+                                                                      z = move_vector.z + overlap[1] * temp_scale_factor)
+                                    else:
+                                        move_vector = temp_move_vector
                             else:
                                 # This can happen in some cases if the object is not yet done with being loaded.
                                 #  Simply waiting for the next tick seems to resolve this correctly.
                                 overlap = None
 
-            if not Vector.Null.equals(move_vector, epsilon=1e-5):
+            if not Vector.Null.equals(move_vector, epsilon = 1e-5):
                 transformed_nodes.append(node)
                 op = PlatformPhysicsOperation.PlatformPhysicsOperation(node, move_vector)
                 op.push()

+ 44 - 4
cura/Settings/CuraContainerRegistry.py

@@ -14,6 +14,7 @@ from UM.Decorators import override
 from UM.Settings.ContainerRegistry import ContainerRegistry
 from UM.Settings.ContainerStack import ContainerStack
 from UM.Settings.InstanceContainer import InstanceContainer
+from UM.Settings.SettingInstance import SettingInstance
 from UM.Application import Application
 from UM.Logger import Logger
 from UM.Message import Message
@@ -224,7 +225,7 @@ class CuraContainerRegistry(ContainerRegistry):
                         # This is assumed to be the global profile
                         profile_id = (global_container_stack.getBottom().getId() + "_" + name_seed).lower().replace(" ", "_")
 
-                    elif len(machine_extruders) > profile_index:
+                    elif profile_index < len(machine_extruders) + 1:
                         # 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"):
@@ -430,11 +431,42 @@ class CuraContainerRegistry(ContainerRegistry):
         extruder_stack.setDefinition(extruder_definition)
         extruder_stack.addMetaDataEntry("position", extruder_definition.getMetaDataEntry("position"))
 
+        from cura.CuraApplication import CuraApplication
+
+        # create a new definition_changes container for the extruder stack
+        definition_changes_id = self.uniqueName(extruder_stack.getId() + "_settings")
+        definition_changes_name = definition_changes_id
+        definition_changes = InstanceContainer(definition_changes_id)
+        definition_changes.setName(definition_changes_name)
+        definition_changes.addMetaDataEntry("setting_version", CuraApplication.SettingVersion)
+        definition_changes.addMetaDataEntry("type", "definition_changes")
+        definition_changes.addMetaDataEntry("definition", extruder_definition.getId())
+
+        # move definition_changes settings if exist
+        for setting_key in definition_changes.getAllKeys():
+            if machine.definition.getProperty(setting_key, "settable_per_extruder"):
+                setting_value = machine.definitionChanges.getProperty(setting_key, "value")
+                if setting_value is not None:
+                    # move it to the extruder stack's definition_changes
+                    setting_definition = machine.getSettingDefinition(setting_key)
+                    new_instance = SettingInstance(setting_definition, definition_changes)
+                    new_instance.setProperty("value", setting_value)
+                    new_instance.resetState()  # Ensure that the state is not seen as a user state.
+                    definition_changes.addInstance(new_instance)
+                    definition_changes.setDirty(True)
+
+                    machine.definitionChanges.removeInstance(setting_key, postpone_emit = True)
+
+        self.addContainer(definition_changes)
+        extruder_stack.setDefinitionChanges(definition_changes)
+
         # create empty user changes container otherwise
-        user_container = InstanceContainer(extruder_stack.id + "_user")
+        user_container_id = self.uniqueName(extruder_stack.getId() + "_user")
+        user_container_name = user_container_id
+        user_container = InstanceContainer(user_container_id)
+        user_container.setName(user_container_name)
         user_container.addMetaDataEntry("type", "user")
         user_container.addMetaDataEntry("machine", extruder_stack.getId())
-        from cura.CuraApplication import CuraApplication
         user_container.addMetaDataEntry("setting_version", CuraApplication.SettingVersion)
         user_container.setDefinition(machine.definition.getId())
 
@@ -444,7 +476,15 @@ class CuraContainerRegistry(ContainerRegistry):
             for user_setting_key in machine.userChanges.getAllKeys():
                 settable_per_extruder = machine.getProperty(user_setting_key, "settable_per_extruder")
                 if settable_per_extruder:
-                    user_container.addInstance(machine.userChanges.getInstance(user_setting_key))
+                    setting_value = machine.getProperty(user_setting_key, "value")
+
+                    setting_definition = machine.getSettingDefinition(user_setting_key)
+                    new_instance = SettingInstance(setting_definition, definition_changes)
+                    new_instance.setProperty("value", setting_value)
+                    new_instance.resetState()  # Ensure that the state is not seen as a user state.
+                    user_container.addInstance(new_instance)
+                    user_container.setDirty(True)
+
                     machine.userChanges.removeInstance(user_setting_key, postpone_emit = True)
 
         self.addContainer(user_container)

+ 29 - 0
cura/Settings/ExtruderStack.py

@@ -8,6 +8,7 @@ from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase
 from UM.Settings.ContainerStack import ContainerStack
 from UM.Settings.ContainerRegistry import ContainerRegistry
 from UM.Settings.Interfaces import ContainerInterface, PropertyEvaluationContext
+from UM.Settings.SettingInstance import SettingInstance
 
 from . import Exceptions
 from .CuraContainerStack import CuraContainerStack
@@ -16,6 +17,11 @@ from .ExtruderManager import ExtruderManager
 if TYPE_CHECKING:
     from cura.Settings.GlobalStack import GlobalStack
 
+
+_EXTRUDER_SPECIFIC_DEFINITION_CHANGES_SETTINGS = ["machine_nozzle_size",
+                                                  "material_diameter"]
+
+
 ##  Represents an Extruder and its related containers.
 #
 #
@@ -39,6 +45,29 @@ class ExtruderStack(CuraContainerStack):
         # For backward compatibility: Register the extruder with the Extruder Manager
         ExtruderManager.getInstance().registerExtruder(self, stack.id)
 
+        # Now each machine will have at least one extruder stack. If this is the first extruder, the extruder-specific
+        # settings such as nozzle size and material diameter should be moved from the machine's definition_changes to
+        # the this extruder's definition_changes.
+        #
+        # We do this here because it is tooooo expansive to do it in the version upgrade: During the version upgrade,
+        # when we are upgrading a definition_changes container file, there is NO guarantee that other files such as
+        # machine an extruder stack files are upgraded before this, so we cannot read those files assuming they are in
+        # the latest format.
+        if self.getMetaDataEntry("position") == "0":
+            for key in _EXTRUDER_SPECIFIC_DEFINITION_CHANGES_SETTINGS:
+                setting_value = stack.definitionChanges.getProperty(key, "value")
+                if setting_value is None:
+                    continue
+
+                setting_definition = stack.getSettingDefinition(key)
+                new_instance = SettingInstance(setting_definition, self.definitionChanges)
+                new_instance.setProperty("value", setting_value)
+                new_instance.resetState()  # Ensure that the state is not seen as a user state.
+                self.definitionChanges.addInstance(new_instance)
+                self.definitionChanges.setDirty(True)
+
+                stack.definitionChanges.removeInstance(key, postpone_emit = True)
+
     @override(ContainerStack)
     def getNextStack(self) -> Optional["GlobalStack"]:
         return super().getNextStack()

+ 3 - 4
cura/ShapeArray.py

@@ -43,13 +43,12 @@ class ShapeArray:
         transform_x = transform._data[0][3]
         transform_y = transform._data[2][3]
         hull_verts = node.callDecoration("getConvexHull")
+        # If a model is too small then it will not contain any points
+        if hull_verts is None or not hull_verts.getPoints().any():
+            return None, None
         # For one_at_a_time printing you need the convex hull head.
         hull_head_verts = node.callDecoration("getConvexHullHead") or hull_verts
 
-        # If a model is to small then it will not contain any points
-        if not hull_verts.getPoints().any():
-            return None, None
-
         offset_verts = hull_head_verts.getMinkowskiHull(Polygon.approximatedCircle(min_offset))
         offset_points = copy.deepcopy(offset_verts._points)  # x, y
         offset_points[:, 0] = numpy.add(offset_points[:, 0], -transform_x)

+ 2 - 1
plugins/CuraEngineBackend/StartSliceJob.py

@@ -143,10 +143,11 @@ class StartSliceJob(Job):
                         if per_object_stack:
                             is_non_printing_mesh = any(per_object_stack.getProperty(key, "value") for key in NON_PRINTING_MESH_SETTINGS)
 
-                        if not getattr(node, "_outside_buildarea", False) or not is_non_printing_mesh:
+                        if not getattr(node, "_outside_buildarea", False) or is_non_printing_mesh:
                             temp_list.append(node)
                             if not is_non_printing_mesh:
                                 has_printing_mesh = True
+
                     Job.yieldThread()
 
                 #If the list doesn't have any model with suitable settings then clean the list

+ 48 - 64
plugins/MachineSettingsAction/MachineSettingsAction.py

@@ -7,14 +7,11 @@ from UM.FlameProfiler import pyqtSlot
 from cura.MachineAction import MachineAction
 
 from UM.Application import Application
-from UM.Preferences import Preferences
-from UM.Settings.InstanceContainer import InstanceContainer
 from UM.Settings.ContainerRegistry import ContainerRegistry
 from UM.Settings.DefinitionContainer import DefinitionContainer
 from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
 from UM.Logger import Logger
 
-from cura.CuraApplication import CuraApplication
 from cura.Settings.ExtruderManager import ExtruderManager
 from cura.Settings.CuraStackBuilder import CuraStackBuilder
 
@@ -36,7 +33,6 @@ class MachineSettingsAction(MachineAction):
         self._container_registry.containerAdded.connect(self._onContainerAdded)
         self._container_registry.containerRemoved.connect(self._onContainerRemoved)
         Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged)
-        ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderStackChanged)
 
         self._empty_container = self._container_registry.getEmptyInstanceContainer()
 
@@ -67,7 +63,9 @@ class MachineSettingsAction(MachineAction):
                 self._global_container_stack, self._global_container_stack.getName() + "_settings")
 
         # Notify the UI in which container to store the machine settings data
-        container_index = self._global_container_stack.getContainerIndex(definition_changes_container)
+        from cura.Settings.CuraContainerStack import CuraContainerStack, _ContainerIndexes
+
+        container_index = _ContainerIndexes.DefinitionChanges
         if container_index != self._container_index:
             self._container_index = container_index
             self.containerIndexChanged.emit()
@@ -82,17 +80,6 @@ class MachineSettingsAction(MachineAction):
         if self._backend and self._backend.determineAutoSlicing():
             self._backend.tickle()
 
-    def _onActiveExtruderStackChanged(self):
-        extruder_container_stack = ExtruderManager.getInstance().getActiveExtruderStack()
-        if not self._global_container_stack or not extruder_container_stack:
-            return
-
-        # Make sure there is a definition_changes container to store the machine settings
-        definition_changes_container = extruder_container_stack.definitionChanges
-        if definition_changes_container == self._empty_container:
-            definition_changes_container = CuraStackBuilder.createDefinitionChangesContainer(
-                extruder_container_stack, extruder_container_stack.getId() + "_settings")
-
     containerIndexChanged = pyqtSignal()
 
     @pyqtProperty(int, notify = containerIndexChanged)
@@ -217,8 +204,8 @@ class MachineSettingsAction(MachineAction):
 
         Application.getInstance().globalContainerStackChanged.emit()
 
-    @pyqtSlot()
-    def updateMaterialForDiameter(self):
+    @pyqtSlot(int)
+    def updateMaterialForDiameter(self, extruder_position: int):
         # Updates the material container to a material that matches the material diameter set for the printer
         if not self._global_container_stack:
             return
@@ -226,24 +213,22 @@ class MachineSettingsAction(MachineAction):
         if not self._global_container_stack.getMetaDataEntry("has_materials", False):
             return
 
-        material = ExtruderManager.getInstance().getActiveExtruderStack().material
-        material_diameter = material.getProperty("material_diameter", "value")
+        extruder_stack = self._global_container_stack.extruders[str(extruder_position)]
+
+        material_diameter = extruder_stack.material.getProperty("material_diameter", "value")
         if not material_diameter:
             # in case of "empty" material
             material_diameter = 0
 
         material_approximate_diameter = str(round(material_diameter))
-        definition_changes = self._global_container_stack.definitionChanges
-        machine_diameter = definition_changes.getProperty("material_diameter", "value")
+        machine_diameter = extruder_stack.definitionChanges.getProperty("material_diameter", "value")
         if not machine_diameter:
-            machine_diameter = self._global_container_stack.definition.getProperty("material_diameter", "value")
+            machine_diameter = extruder_stack.definition.getProperty("material_diameter", "value")
         machine_approximate_diameter = str(round(machine_diameter))
 
         if material_approximate_diameter != machine_approximate_diameter:
             Logger.log("i", "The the currently active material(s) do not match the diameter set for the printer. Finding alternatives.")
 
-            stacks = ExtruderManager.getInstance().getExtruderStacks()
-
             if self._global_container_stack.getMetaDataEntry("has_machine_materials", False):
                 materials_definition = self._global_container_stack.definition.getId()
                 has_material_variants = self._global_container_stack.getMetaDataEntry("has_variants", False)
@@ -251,45 +236,44 @@ class MachineSettingsAction(MachineAction):
                 materials_definition = "fdmprinter"
                 has_material_variants = False
 
-            for stack in stacks:
-                old_material = stack.material
-                search_criteria = {
-                    "type": "material",
-                    "approximate_diameter": machine_approximate_diameter,
-                    "material": old_material.getMetaDataEntry("material", "value"),
-                    "supplier": old_material.getMetaDataEntry("supplier", "value"),
-                    "color_name": old_material.getMetaDataEntry("color_name", "value"),
-                    "definition": materials_definition
-                }
-                if has_material_variants:
-                    search_criteria["variant"] = stack.variant.getId()
-
-                if old_material == self._empty_container:
-                    search_criteria.pop("material", None)
-                    search_criteria.pop("supplier", None)
-                    search_criteria.pop("definition", None)
-                    search_criteria["id"] = stack.getMetaDataEntry("preferred_material")
-
+            old_material = extruder_stack.material
+            search_criteria = {
+                "type": "material",
+                "approximate_diameter": machine_approximate_diameter,
+                "material": old_material.getMetaDataEntry("material", "value"),
+                "supplier": old_material.getMetaDataEntry("supplier", "value"),
+                "color_name": old_material.getMetaDataEntry("color_name", "value"),
+                "definition": materials_definition
+            }
+            if has_material_variants:
+                search_criteria["variant"] = extruder_stack.variant.getId()
+
+            if old_material == self._empty_container:
+                search_criteria.pop("material", None)
+                search_criteria.pop("supplier", None)
+                search_criteria.pop("definition", None)
+                search_criteria["id"] = extruder_stack.getMetaDataEntry("preferred_material")
+
+            materials = self._container_registry.findInstanceContainers(**search_criteria)
+            if not materials:
+                # Same material with new diameter is not found, search for generic version of the same material type
+                search_criteria.pop("supplier", None)
+                search_criteria["color_name"] = "Generic"
                 materials = self._container_registry.findInstanceContainers(**search_criteria)
-                if not materials:
-                    # Same material with new diameter is not found, search for generic version of the same material type
-                    search_criteria.pop("supplier", None)
-                    search_criteria["color_name"] = "Generic"
-                    materials = self._container_registry.findInstanceContainers(**search_criteria)
-                if not materials:
-                    # Generic material with new diameter is not found, search for preferred material
-                    search_criteria.pop("color_name", None)
-                    search_criteria.pop("material", None)
-                    search_criteria["id"] = stack.getMetaDataEntry("preferred_material")
-                    materials = self._container_registry.findInstanceContainers(**search_criteria)
-                if not materials:
-                    # Preferred material with new diameter is not found, search for any material
-                    search_criteria.pop("id", None)
-                    materials = self._container_registry.findInstanceContainers(**search_criteria)
-                if not materials:
-                    # Just use empty material as a final fallback
-                    materials = [self._empty_container]
+            if not materials:
+                # Generic material with new diameter is not found, search for preferred material
+                search_criteria.pop("color_name", None)
+                search_criteria.pop("material", None)
+                search_criteria["id"] = extruder_stack.getMetaDataEntry("preferred_material")
+                materials = self._container_registry.findInstanceContainers(**search_criteria)
+            if not materials:
+                # Preferred material with new diameter is not found, search for any material
+                search_criteria.pop("id", None)
+                materials = self._container_registry.findInstanceContainers(**search_criteria)
+            if not materials:
+                # Just use empty material as a final fallback
+                materials = [self._empty_container]
 
-                Logger.log("i", "Selecting new material: %s" % materials[0].getId())
+            Logger.log("i", "Selecting new material: %s" % materials[0].getId())
 
-                stack.material = materials[0]
+            extruder_stack.material = materials[0]

+ 31 - 27
plugins/MachineSettingsAction/MachineSettingsAction.qml

@@ -292,18 +292,6 @@ Cura.MachineAction
                                     }
                                 }
                             }
-
-                            Loader
-                            {
-                                id: materialDiameterField
-                                visible: Cura.MachineManager.hasMaterials
-                                sourceComponent: numericTextFieldWithUnit
-                                property string settingKey: "material_diameter"
-                                property string unit: catalog.i18nc("@label", "mm")
-                                property string tooltip: catalog.i18nc("@tooltip", "The nominal diameter of filament supported by the printer. The exact diameter will be overridden by the material and/or the profile.")
-                                property var afterOnEditingFinished: manager.updateMaterialForDiameter
-                                property string label: catalog.i18nc("@label", "Material diameter")
-                            }
                         }
                     }
 
@@ -360,7 +348,6 @@ Cura.MachineAction
                 if(currentIndex > 0)
                 {
                     contentItem.forceActiveFocus();
-                    Cura.ExtruderManager.setActiveExtruderIndex(currentIndex - 1);
                 }
             }
 
@@ -397,6 +384,25 @@ Cura.MachineAction
                             property bool isExtruderSetting: true
                         }
 
+                        Loader
+                        {
+                            id: materialDiameterField
+                            visible: Cura.MachineManager.hasMaterials
+                            sourceComponent: numericTextFieldWithUnit
+                            property string settingKey: "material_diameter"
+                            property string label: catalog.i18nc("@label", "Material diameter")
+                            property string unit: catalog.i18nc("@label", "mm")
+                            property string tooltip: catalog.i18nc("@tooltip", "The nominal diameter of filament supported by the printer. The exact diameter will be overridden by the material and/or the profile.")
+                            property var afterOnEditingFinished:
+                            {
+                                if (settingsTabs.currentIndex > 0)
+                                {
+                                    manager.updateMaterialForDiameter(settingsTabs.currentIndex - 1);
+                                }
+                            }
+                            property bool isExtruderSetting: true
+                        }
+
                         Loader
                         {
                             id: extruderOffsetXField
@@ -495,7 +501,7 @@ Cura.MachineAction
                     {
                         if(settingsTabs.currentIndex > 0)
                         {
-                            return Cura.MachineManager.activeStackId;
+                            return Cura.ExtruderManager.extruderIds[String(settingsTabs.currentIndex - 1)];
                         }
                         return "";
                     }
@@ -513,11 +519,11 @@ Cura.MachineAction
                 checked: String(propertyProvider.properties.value).toLowerCase() != 'false'
                 onClicked:
                 {
-                        propertyProvider.setPropertyValue("value", checked);
-                        if(_forceUpdateOnChange)
-                        {
-                            manager.forceUpdate();
-                        }
+                    propertyProvider.setPropertyValue("value", checked);
+                    if(_forceUpdateOnChange)
+                    {
+                        manager.forceUpdate();
+                    }
                 }
             }
         }
@@ -548,7 +554,7 @@ Cura.MachineAction
                     {
                         if(settingsTabs.currentIndex > 0)
                         {
-                            return Cura.MachineManager.activeStackId;
+                            return Cura.ExtruderManager.extruderIds[String(settingsTabs.currentIndex - 1)];
                         }
                         return "";
                     }
@@ -581,7 +587,10 @@ Cura.MachineAction
                     TextField
                     {
                         id: textField
-                        text: (propertyProvider.properties.value) ? propertyProvider.properties.value : ""
+                        text: {
+                            const value = propertyProvider.properties.value;
+                            return value ? value : "";
+                        }
                         validator: RegExpValidator { regExp: _allowNegative ? /-?[0-9\.]{0,6}/ : /[0-9\.]{0,6}/ }
                         onEditingFinished:
                         {
@@ -590,12 +599,7 @@ Cura.MachineAction
                                 propertyProvider.setPropertyValue("value", text);
                                 if(_forceUpdateOnChange)
                                 {
-                                    var extruderIndex = Cura.ExtruderManager.activeExtruderIndex;
                                     manager.forceUpdate();
-                                    if(Cura.ExtruderManager.activeExtruderIndex != extruderIndex)
-                                    {
-                                        Cura.ExtruderManager.setActiveExtruderIndex(extruderIndex)
-                                    }
                                 }
                                 if(_afterOnEditingFinished)
                                 {
@@ -641,7 +645,7 @@ Cura.MachineAction
                     {
                         if(settingsTabs.currentIndex > 0)
                         {
-                            return Cura.MachineManager.activeStackId;
+                            return Cura.ExtruderManager.extruderIds[String(settingsTabs.currentIndex - 1)];
                         }
                         return "";
                     }

Некоторые файлы не были показаны из-за большого количества измененных файлов