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
This commit is contained in:
Arjen Hiemstra 2016-05-30 13:03:06 +02:00
parent cd2b853fff
commit 8039184c18
3 changed files with 56 additions and 38 deletions

View file

@ -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._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._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.backendQuit.connect(self._onBackendQuit)
self.backendConnected.connect(self._onBackendConnected) self.backendConnected.connect(self._onBackendConnected)
@ -134,26 +134,8 @@ class CuraEngineBackend(Backend):
self._process_layers_job.abort() self._process_layers_job.abort()
self._process_layers_job = None self._process_layers_job = None
# #Don't slice if there is a setting with an error value. if self._error_message:
# stack = Application.getInstance().getGlobalContainerStack() self._error_message.hide()
# 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
self.processingProgress.emit(0.0) self.processingProgress.emit(0.0)
self.backendStateChange.emit(BackendState.NotStarted) self.backendStateChange.emit(BackendState.NotStarted)
@ -200,12 +182,31 @@ class CuraEngineBackend(Backend):
# Note that cancelled slice jobs can still call this method. # Note that cancelled slice jobs can still call this method.
if self._start_slice_job is job: if self._start_slice_job is job:
self._start_slice_job = None 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 return
else:
# Preparation completed, send it to the backend. if job.getResult() == StartSliceJob.StartJobResult.SettingError:
self._socket.sendMessage(job.getSettingsMessage()) if Application.getInstance().getPlatformActivity:
self._socket.sendMessage(job.getSliceMessage()) 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. ## Listener for when the scene has changed.
# #

View file

@ -4,6 +4,7 @@
import numpy import numpy
from string import Formatter from string import Formatter
import traceback import traceback
from enum import IntEnum
from UM.Job import Job from UM.Job import Job
from UM.Application import Application from UM.Application import Application
@ -12,8 +13,15 @@ from UM.Logger import Logger
from UM.Scene.SceneNode import SceneNode from UM.Scene.SceneNode import SceneNode
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Settings.Validator import ValidatorState
from cura.OneAtATimeIterator import OneAtATimeIterator 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 ## Formatter class that handles token expansion in start/end gcod
class GcodeStartEndFormatter(Formatter): class GcodeStartEndFormatter(Formatter):
@ -48,9 +56,19 @@ class StartSliceJob(Job):
def run(self): def run(self):
stack = Application.getInstance().getGlobalContainerStack() stack = Application.getInstance().getGlobalContainerStack()
if not stack: if not stack:
self.setResult(False) self.setResult(StartJobResult.Error)
return 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(): with self._scene.getSceneLock():
# Remove old layer data. # Remove old layer data.
for node in DepthFirstIterator(self._scene.getRoot()): for node in DepthFirstIterator(self._scene.getRoot()):
@ -91,6 +109,7 @@ class StartSliceJob(Job):
object_groups.append(temp_list) object_groups.append(temp_list)
if not object_groups: if not object_groups:
self.setResult(StartJobResult.NothingToSlice)
return return
self._buildGlobalSettingsMessage(stack) self._buildGlobalSettingsMessage(stack)
@ -116,7 +135,7 @@ class StartSliceJob(Job):
Job.yieldThread() Job.yieldThread()
self.setResult(True) self.setResult(StartJobResult.Finished)
def cancel(self): def cancel(self):
super().cancel() super().cancel()
@ -131,7 +150,7 @@ class StartSliceJob(Job):
fmt = GcodeStartEndFormatter() fmt = GcodeStartEndFormatter()
return str(fmt.format(value, **settings)).encode("utf-8") return str(fmt.format(value, **settings)).encode("utf-8")
except: 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") return str(value).encode("utf-8")
## Sends all global settings to the engine. ## Sends all global settings to the engine.

View file

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