Browse Source

Fix: per model settings validation
CURA-4972

Aleksei S 7 years ago
parent
commit
ed7dec0cae

+ 10 - 0
cura/ObjectsModel.py

@@ -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

+ 5 - 0
plugins/CuraEngineBackend/StartSliceJob.py

@@ -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():

+ 14 - 1
plugins/PerObjectSettingsTool/PerObjectItem.qml

@@ -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();
         }
     }

+ 10 - 1
plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml

@@ -54,6 +54,12 @@ Item {
                 id: meshTypeSelection
                 style: UM.Theme.styles.combobox
                 onActivated: {
+
+                    console.log("!!!!!!!!!!!!!!!!!!!")
+
+                    if(model.get(index).type == "anti_overhang_mesh")
+                         console.log("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
+
                     UM.ActiveTool.setProperty("MeshType", model.get(index).type)
                 }
                 model: ListModel
@@ -240,7 +246,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
                             {

+ 69 - 0
plugins/PerObjectSettingsTool/PerObjectSettingsTool.py

@@ -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)