Merge pull request #3404 from Ultimaker/CURA-4972_per_object_setting_validation

Cura 4972 per object setting validation
This commit is contained in:
Ian Paschal 2018-02-26 16:06:44 +01:00 committed by GitHub
commit 02c78faabc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 102 additions and 2 deletions

View File

@ -19,6 +19,8 @@ class ObjectsModel(ListModel):
self._build_plate_number = -1 self._build_plate_number = -1
self._stacks_have_errors = None # type:Optional[bool]
def setActiveBuildPlate(self, nr): def setActiveBuildPlate(self, nr):
self._build_plate_number = nr self._build_plate_number = nr
self._update() self._update()
@ -67,3 +69,11 @@ class ObjectsModel(ListModel):
@staticmethod @staticmethod
def createObjectsModel(): def createObjectsModel():
return ObjectsModel() return ObjectsModel()
## Check if none of the model's stacks contain error states
# The setting applied for the settings per model
def stacksHaveErrors(self) -> bool:
return bool(self._stacks_have_errors)
def setStacksHaveErrors(self, value):
self._stacks_have_errors = value

View File

@ -136,6 +136,11 @@ class StartSliceJob(Job):
self.setResult(StartJobResult.MaterialIncompatible) self.setResult(StartJobResult.MaterialIncompatible)
return return
# Validate settings per selectable model
if Application.getInstance().getObjectsModel().stacksHaveErrors():
self.setResult(StartJobResult.ObjectSettingError)
return
# Don't slice if there is a per object setting with an error value. # Don't slice if there is a per object setting with an error value.
for node in DepthFirstIterator(self._scene.getRoot()): for node in DepthFirstIterator(self._scene.getRoot()):
if node.isSelectable(): if node.isSelectable():

View File

@ -25,7 +25,20 @@ UM.TooltipArea
onClicked: onClicked:
{ {
addedSettingsModel.setVisible(model.key, checked); // Important first set visible and then subscribe
// otherwise the setting is not yet in list
// For unsubscribe is important first remove the subscription and then
// set as invisible
if(checked)
{
addedSettingsModel.setVisible(model.key, checked);
UM.ActiveTool.triggerAction("subscribeForSettingValidation", model.key)
}
else
{
UM.ActiveTool.triggerAction("unsubscribeForSettingValidation", model.key)
addedSettingsModel.setVisible(model.key, checked);
}
UM.ActiveTool.forceUpdate(); UM.ActiveTool.forceUpdate();
} }
} }

View File

@ -240,7 +240,10 @@ Item {
width: Math.round(UM.Theme.getSize("setting").height / 2) width: Math.round(UM.Theme.getSize("setting").height / 2)
height: UM.Theme.getSize("setting").height height: UM.Theme.getSize("setting").height
onClicked: addedSettingsModel.setVisible(model.key, false) onClicked: {
UM.ActiveTool.triggerAction("unsubscribeForSettingValidation", model.key)
addedSettingsModel.setVisible(model.key, false)
}
style: ButtonStyle style: ButtonStyle
{ {

View File

@ -10,7 +10,10 @@ from cura.Settings.SettingOverrideDecorator import SettingOverrideDecorator
from cura.Settings.ExtruderManager import ExtruderManager from cura.Settings.ExtruderManager import ExtruderManager
from UM.Settings.SettingInstance import SettingInstance from UM.Settings.SettingInstance import SettingInstance
from UM.Event import Event from UM.Event import Event
from UM.Settings.Validator import ValidatorState
from UM.Logger import Logger
from PyQt5.QtCore import QTimer
## This tool allows the user to add & change settings per node in the scene. ## This tool allows the user to add & change settings per node in the scene.
# The settings per object are kept in a ContainerStack, which is linked to a node by decorator. # The settings per object are kept in a ContainerStack, which is linked to a node by decorator.
@ -34,6 +37,13 @@ class PerObjectSettingsTool(Tool):
self._onGlobalContainerChanged() self._onGlobalContainerChanged()
Selection.selectionChanged.connect(self._updateEnabled) Selection.selectionChanged.connect(self._updateEnabled)
self._scene = Application.getInstance().getController().getScene()
self._error_check_timer = QTimer()
self._error_check_timer.setInterval(250)
self._error_check_timer.setSingleShot(True)
self._error_check_timer.timeout.connect(self._updateStacksHaveErrors)
def event(self, event): def event(self, event):
super().event(event) super().event(event)
@ -142,3 +152,62 @@ class PerObjectSettingsTool(Tool):
else: else:
self._single_model_selected = True self._single_model_selected = True
Application.getInstance().getController().toolEnabledChanged.emit(self._plugin_id, self._advanced_mode and self._single_model_selected) Application.getInstance().getController().toolEnabledChanged.emit(self._plugin_id, self._advanced_mode and self._single_model_selected)
def _onPropertyChanged(self, key: str, property_name: str) -> None:
if property_name == "validationState":
self._error_check_timer.start()
def _updateStacksHaveErrors(self) -> None:
self._checkStacksHaveErrors()
def _checkStacksHaveErrors(self):
for node in DepthFirstIterator(self._scene.getRoot()):
# valdiate only objects which can be selected because the settings per object
# can be applied only for them
if not node.isSelectable():
continue
hasErrors = self._checkStackForErrors(node.callDecoration("getStack"))
Application.getInstance().getObjectsModel().setStacksHaveErrors(hasErrors)
#If any of models has an error then no reason check next objects on the build plate
if hasErrors:
break
def _checkStackForErrors(self, stack):
if stack is None:
return False
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 Per Object %s is not valid.", key)
return True
return False
def subscribeForSettingValidation(self, setting_name):
selected_object = Selection.getSelectedObject(0)
stack = selected_object.callDecoration("getStack") # Don't try to get the active extruder since it may be None anyway.
if not stack:
return ""
settings = stack.getTop()
setting_instance = settings.getInstance(setting_name)
if setting_instance:
setting_instance.propertyChanged.connect(self._onPropertyChanged)
def unsubscribeForSettingValidation(self, setting_name):
selected_object = Selection.getSelectedObject(0)
stack = selected_object.callDecoration("getStack") # Don't try to get the active extruder since it may be None anyway.
if not stack:
return ""
settings = stack.getTop()
setting_instance = settings.getInstance(setting_name)
if setting_instance:
setting_instance.propertyChanged.disconnect(self._onPropertyChanged)