diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index f90b27bf5d..c5804f920f 100644 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/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 - else: - # Preparation completed, send it to the backend. - self._socket.sendMessage(job.getSettingsMessage()) - self._socket.sendMessage(job.getSliceMessage()) + + 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 + + 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. # diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index 6e0da0cb34..cf008e7b6f 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/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. diff --git a/resources/qml/SaveButton.qml b/resources/qml/SaveButton.qml index db147b3e69..1307e8f820 100644 --- a/resources/qml/SaveButton.qml +++ b/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") } }