Browse Source

Move setting error checking to StartSliceJob and allow the job to return a proper response

Now the job can determine if we can continue with slicing or not and if
not, why not.

This also means we can now show a message when we cannot find any
slicable objects.

Contributes to CURA-1278
Arjen Hiemstra 8 years ago
parent
commit
8039184c18

+ 27 - 26
plugins/CuraEngineBackend/CuraEngineBackend.py

@@ -82,7 +82,7 @@ class CuraEngineBackend(Backend):
         self._always_restart = True #Always restart the engine when starting a new slice. Don't keep the process running. TODO: Fix engine statelessness.
         self._process_layers_job = None #The currently active job to process layers, or None if it is not processing layers.
 
-        self._message = None #Pop-up message that shows the slicing progress bar (or an error message).
+        self._error_message = None #Pop-up message that shows errors.
 
         self.backendQuit.connect(self._onBackendQuit)
         self.backendConnected.connect(self._onBackendConnected)
@@ -134,26 +134,8 @@ class CuraEngineBackend(Backend):
             self._process_layers_job.abort()
             self._process_layers_job = None
 
-        # #Don't slice if there is a setting with an error value.
-        # stack = Application.getInstance().getGlobalContainerStack()
-        # for key in stack.getAllKeys():
-        #     validation_state = stack.getProperty(key, "validationState")
-        #     #Only setting instances have a validation state, so settings which
-        #     #are not overwritten by any instance will have none. The property
-        #     #then, and only then, evaluates to None. We make the assumption that
-        #     #the definition defines the setting with a default value that is
-        #     #valid. Therefore we can allow both ValidatorState.Valid and None as
-        #     #allowable validation states.
-        #     #TODO: This assumption is wrong! If the definition defines an inheritance function that through inheritance evaluates to a disallowed value, a setting is still invalid even though it's default!
-        #     #TODO: Therefore we must also validate setting definitions.
-        #     if validation_state != None and validation_state != ValidatorState.Valid:
-        #         Logger.log("w", "Setting %s is not valid, but %s. Aborting slicing.", key, validation_state)
-        #         if self._message: #Hide any old message before creating a new one.
-        #             self._message.hide()
-        #             self._message = None
-        #         self._message = Message(catalog.i18nc("@info:status", "Unable to slice. Please check your setting values for errors."))
-        #         self._message.show()
-        #         return
+        if self._error_message:
+            self._error_message.hide()
 
         self.processingProgress.emit(0.0)
         self.backendStateChange.emit(BackendState.NotStarted)
@@ -200,12 +182,31 @@ class CuraEngineBackend(Backend):
         # Note that cancelled slice jobs can still call this method.
         if self._start_slice_job is job:
             self._start_slice_job = None
-        if job.isCancelled() or job.getError() or job.getResult() != True:
+
+        if job.isCancelled() or job.getError() or job.getResult() == StartSliceJob.StartJobResult.Error:
+            return
+
+        if job.getResult() == StartSliceJob.StartJobResult.SettingError:
+            if Application.getInstance().getPlatformActivity:
+                self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice. Please check your setting values for errors."), lifetime = 10)
+                self._error_message.show()
+                self.backendStateChange.emit(BackendState.Error)
+            else:
+                self.backendStateChange.emit(BackendState.NotStarted)
             return
-        else:
-            # Preparation completed, send it to the backend.
-            self._socket.sendMessage(job.getSettingsMessage())
-            self._socket.sendMessage(job.getSliceMessage())
+
+        if job.getResult() == StartSliceJob.StartJobResult.NothingToSlice:
+            if Application.getInstance().getPlatformActivity:
+                self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice. No suitable objects found."), lifetime = 10)
+                self._error_message.show()
+                self.backendStateChange.emit(BackendState.Error)
+            else:
+                self.backendStateChange.emit(BackendState.NotStarted)
+            return
+
+        # Preparation completed, send it to the backend.
+        self._socket.sendMessage(job.getSettingsMessage())
+        self._socket.sendMessage(job.getSliceMessage())
 
     ##  Listener for when the scene has changed.
     #

+ 22 - 3
plugins/CuraEngineBackend/StartSliceJob.py

@@ -4,6 +4,7 @@
 import numpy
 from string import Formatter
 import traceback
+from enum import IntEnum
 
 from UM.Job import Job
 from UM.Application import Application
@@ -12,8 +13,15 @@ from UM.Logger import Logger
 from UM.Scene.SceneNode import SceneNode
 from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
 
+from UM.Settings.Validator import ValidatorState
+
 from cura.OneAtATimeIterator import OneAtATimeIterator
 
+class StartJobResult(IntEnum):
+    Finished = 1
+    Error = 2
+    SettingError = 3
+    NothingToSlice = 4
 
 ##  Formatter class that handles token expansion in start/end gcod
 class GcodeStartEndFormatter(Formatter):
@@ -48,9 +56,19 @@ class StartSliceJob(Job):
     def run(self):
         stack = Application.getInstance().getGlobalContainerStack()
         if not stack:
-            self.setResult(False)
+            self.setResult(StartJobResult.Error)
             return
 
+        #Don't slice if there is a setting with an error value.
+        for key in stack.getAllKeys():
+            validation_state = stack.getProperty(key, "validationState")
+            if validation_state in (ValidatorState.Exception, ValidatorState.MaximumError, ValidatorState.MinimumError):
+                Logger.log("w", "Setting %s is not valid, but %s. Aborting slicing.", key, validation_state)
+                self.setResult(StartJobResult.SettingError)
+                return
+
+            Job.yieldThread()
+
         with self._scene.getSceneLock():
             # Remove old layer data.
             for node in DepthFirstIterator(self._scene.getRoot()):
@@ -91,6 +109,7 @@ class StartSliceJob(Job):
                     object_groups.append(temp_list)
 
             if not object_groups:
+                self.setResult(StartJobResult.NothingToSlice)
                 return
 
             self._buildGlobalSettingsMessage(stack)
@@ -116,7 +135,7 @@ class StartSliceJob(Job):
 
                     Job.yieldThread()
 
-        self.setResult(True)
+        self.setResult(StartJobResult.Finished)
 
     def cancel(self):
         super().cancel()
@@ -131,7 +150,7 @@ class StartSliceJob(Job):
             fmt = GcodeStartEndFormatter()
             return str(fmt.format(value, **settings)).encode("utf-8")
         except:
-            Logger.log("w", "Unabled to do token replacement on start/end gcode %s", traceback.format_exc())
+            Logger.logException("w", "Unable to do token replacement on start/end gcode")
             return str(value).encode("utf-8")
 
     ##  Sends all global settings to the engine.

+ 7 - 9
resources/qml/SaveButton.qml

@@ -21,16 +21,14 @@ Rectangle {
     property string fileBaseName
     property string statusText:
     {
+        if(!activity)
+        {
+            return catalog.i18nc("@label:PrintjobStatus", "Please load a 3d model");
+        }
+
         if(base.backendState == 1)
         {
-            if(!activity)
-            {
-                return catalog.i18nc("@label:PrintjobStatus", "Please load a 3d model");
-            }
-            else
-            {
-                return catalog.i18nc("@label:PrintjobStatus", "Preparing to slice...");
-            }
+            return catalog.i18nc("@label:PrintjobStatus", "Preparing to slice...");
         }
         else if(base.backendState == 2)
         {
@@ -42,7 +40,7 @@ Rectangle {
         }
         else if(base.backendState == 4)
         {
-            return catalog.i18nc("@label:PrintjobStatus", "Unable to slice due to errors")
+            return catalog.i18nc("@label:PrintjobStatus", "Unable to Slice")
         }
     }