mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-06-04 11:14:21 +08:00
Merge pull request #3404 from Ultimaker/CURA-4972_per_object_setting_validation
Cura 4972 per object setting validation
This commit is contained in:
commit
02c78faabc
@ -19,6 +19,8 @@ class ObjectsModel(ListModel):
|
||||
|
||||
self._build_plate_number = -1
|
||||
|
||||
self._stacks_have_errors = None # type:Optional[bool]
|
||||
|
||||
def setActiveBuildPlate(self, nr):
|
||||
self._build_plate_number = nr
|
||||
self._update()
|
||||
@ -67,3 +69,11 @@ class ObjectsModel(ListModel):
|
||||
@staticmethod
|
||||
def createObjectsModel():
|
||||
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
|
@ -136,6 +136,11 @@ class StartSliceJob(Job):
|
||||
self.setResult(StartJobResult.MaterialIncompatible)
|
||||
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.
|
||||
for node in DepthFirstIterator(self._scene.getRoot()):
|
||||
if node.isSelectable():
|
||||
|
@ -25,7 +25,20 @@ UM.TooltipArea
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -240,7 +240,10 @@ Item {
|
||||
width: Math.round(UM.Theme.getSize("setting").height / 2)
|
||||
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
|
||||
{
|
||||
|
@ -10,7 +10,10 @@ from cura.Settings.SettingOverrideDecorator import SettingOverrideDecorator
|
||||
from cura.Settings.ExtruderManager import ExtruderManager
|
||||
from UM.Settings.SettingInstance import SettingInstance
|
||||
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.
|
||||
# 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()
|
||||
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):
|
||||
super().event(event)
|
||||
@ -142,3 +152,62 @@ class PerObjectSettingsTool(Tool):
|
||||
else:
|
||||
self._single_model_selected = True
|
||||
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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user