Browse Source

Fix auto-slicing upon value changes and error checks

CURA-4092

- Keep the error check finished signal.
- Restore the old way of triggering an auto-slicing which depends on a
  setting value change singal.
- Add a mechanism to make sure that if there is an error check, the
  auto-slicing will only be triggered after the check finishes.
Lipu Fei 7 years ago
parent
commit
d9d39c41df
1 changed files with 81 additions and 6 deletions
  1. 81 6
      plugins/CuraEngineBackend/CuraEngineBackend.py

+ 81 - 6
plugins/CuraEngineBackend/CuraEngineBackend.py

@@ -76,9 +76,28 @@ class CuraEngineBackend(QObject, Backend):
         self._scene = Application.getInstance().getController().getScene()
         self._scene.sceneChanged.connect(self._onSceneChanged)
 
-        # trigger auto-slicing on error check finished
+        # Triggers for auto-slicing. Auto-slicing is triggered as follows:
+        #  - auto-slicing is started with a timer
+        #  - whenever there is a value change, we start the timer
+        #  - sometimes an error check can get scheduled for a value change, in that case, we ONLY want to start the
+        #    auto-slicing timer when that error check is finished
+        #  If there is an error check, it will set the "_is_error_check_scheduled" flag, stop the auto-slicing timer,
+        #  and only wait for the error check to be finished to start the auto-slicing timer again.
+        #
+        self._global_container_stack = None
+        Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged)
+        self._onGlobalStackChanged()
+
+        self._active_extruder_stack = None
+        ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderChanged)
+        self._onActiveExtruderChanged()
+
         Application.getInstance().stacksValidationFinished.connect(self._onStackErrorCheckFinished)
 
+        # A flag indicating if an error check was scheduled
+        # If so, we will stop the auto-slice timer and start upon the error check
+        self._is_error_check_scheduled = False
+
         # Listeners for receiving messages from the back-end.
         self._message_handlers["cura.proto.Layer"] = self._onLayerMessage
         self._message_handlers["cura.proto.LayerOptimized"] = self._onOptimizedLayerMessage
@@ -271,17 +290,16 @@ class CuraEngineBackend(QObject, Backend):
             return
 
         if job.getResult() == StartSliceJob.StartJobResult.SettingError:
-            global_container_stack = Application.getInstance().getGlobalContainerStack()
             if Application.getInstance().platformActivity:
-                extruders = list(ExtruderManager.getInstance().getMachineExtruders(global_container_stack.getId()))
+                extruders = list(ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId()))
                 error_keys = []
                 for extruder in extruders:
                     error_keys.extend(extruder.getErrorKeys())
                 if not extruders:
-                    error_keys = global_container_stack.getErrorKeys()
+                    error_keys = self._global_container_stack.getErrorKeys()
                 error_labels = set()
                 for key in error_keys:
-                    for stack in [global_container_stack] + extruders: #Search all container stacks for the definition of this setting. Some are only in an extruder stack.
+                    for stack in [self._global_container_stack] + extruders: #Search all container stacks for the definition of this setting. Some are only in an extruder stack.
                         definitions = stack.getBottom().findDefinitions(key = key)
                         if definitions:
                             break #Found it! No need to continue search.
@@ -420,7 +438,21 @@ class CuraEngineBackend(QObject, Backend):
             # With manually having to slice, we want to clear the old invalid layer data.
             self._clearLayerData()
 
+    ##  A setting has changed, so check if we must reslice.
+    # \param instance The setting instance that has changed.
+    # \param property The property of the setting instance that has changed.
+    def _onSettingChanged(self, instance, property):
+        if property == "value":  # Only reslice if the value has changed.
+            self.needsSlicing()
+            self._onChanged()
+
+        elif property == "validationState":
+            if self._use_timer:
+                self._is_error_check_scheduled = True
+                self._change_timer.stop()
+
     def _onStackErrorCheckFinished(self):
+        self._is_error_check_scheduled = False
         self.needsSlicing()
         self._onChanged()
 
@@ -515,7 +547,12 @@ class CuraEngineBackend(QObject, Backend):
     def _onChanged(self, *args, **kwargs):
         self.needsSlicing()
         if self._use_timer:
-            self._change_timer.start()
+            # if the error check is scheduled, wait for the error check finish signal to trigger auto-slice,
+            # otherwise business as usual
+            if self._is_error_check_scheduled:
+                self._change_timer.stop()
+            else:
+                self._change_timer.start()
 
     ##  Called when the back-end connects to the front-end.
     def _onBackendConnected(self):
@@ -574,6 +611,44 @@ class CuraEngineBackend(QObject, Backend):
             if self._process:
                 Logger.log("d", "Backend quit with return code %s. Resetting process and socket.", self._process.wait())
                 self._process = None
+                ##  Called when the global container stack changes
+
+    def _onGlobalStackChanged(self):
+        if self._global_container_stack:
+            self._global_container_stack.propertyChanged.disconnect(self._onSettingChanged)
+            self._global_container_stack.containersChanged.disconnect(self._onChanged)
+            extruders = list(ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId()))
+
+            if extruders:
+                for extruder in extruders:
+                    extruder.propertyChanged.disconnect(self._onSettingChanged)
+
+        self._global_container_stack = Application.getInstance().getGlobalContainerStack()
+
+        if self._global_container_stack:
+            self._global_container_stack.propertyChanged.connect(self._onSettingChanged)  # Note: Only starts slicing when the value changed.
+            self._global_container_stack.containersChanged.connect(self._onChanged)
+            extruders = list(ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId()))
+            if extruders:
+                for extruder in extruders:
+                    extruder.propertyChanged.connect(self._onSettingChanged)
+            self._onActiveExtruderChanged()
+            self._onChanged()
+
+    def _onActiveExtruderChanged(self):
+        if self._global_container_stack:
+            # Connect all extruders of the active machine. This might cause a few connects that have already happend,
+            # but that shouldn't cause issues as only new / unique connections are added.
+            extruders = list(ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId()))
+            if extruders:
+                for extruder in extruders:
+                    extruder.propertyChanged.connect(self._onSettingChanged)
+        if self._active_extruder_stack:
+            self._active_extruder_stack.containersChanged.disconnect(self._onChanged)
+
+        self._active_extruder_stack = ExtruderManager.getInstance().getActiveExtruderStack()
+        if self._active_extruder_stack:
+            self._active_extruder_stack.containersChanged.connect(self._onChanged)
 
     def _onProcessLayersFinished(self, job):
         self._process_layers_job = None