diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index b90c23ac87..fce82212cd 100644 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -34,7 +34,7 @@ class MachineManager(QObject): self.globalContainerChanged.connect(self.activeVariantChanged) self.globalContainerChanged.connect(self.activeQualityChanged) - self._active_stack_valid = None + self._stacks_have_errors = None self._onGlobalContainerChanged() ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderStackChanged) @@ -85,6 +85,7 @@ class MachineManager(QObject): globalValueChanged = pyqtSignal() # Emitted whenever a value inside global container is changed. activeStackValueChanged = pyqtSignal() # Emitted whenever a value inside the active stack is changed. activeStackValidationChanged = pyqtSignal() # Emitted whenever a validation inside active container is changed + stacksValidationChanged = pyqtSignal() # Emitted whenever a validation is changed blurSettings = pyqtSignal() # Emitted to force fields in the advanced sidebar to un-focus, so they update properly @@ -246,6 +247,13 @@ class MachineManager(QObject): quality.nameChanged.connect(self._onQualityNameChanged) + ## Update self._stacks_valid according to _checkStacksForErrors and emit if change. + def _updateStacksHaveErrors(self): + old_stacks_have_errors = self._stacks_have_errors + self._stacks_have_errors = self._checkStacksHaveErrors() + if old_stacks_have_errors != self._stacks_have_errors: + self.stacksValidationChanged.emit() + def _onActiveExtruderStackChanged(self): self.blurSettings.emit() # Ensure no-one has focus. old_active_container_stack = self._active_container_stack @@ -260,10 +268,7 @@ class MachineManager(QObject): else: self._active_container_stack = self._global_container_stack - old_active_stack_valid = self._active_stack_valid - self._active_stack_valid = not self._checkStackForErrors(self._active_container_stack) - if old_active_stack_valid != self._active_stack_valid: - self.activeStackValidationChanged.emit() + self._updateStacksHaveErrors() if old_active_container_stack != self._active_container_stack: # Many methods and properties related to the active quality actually depend @@ -286,18 +291,18 @@ class MachineManager(QObject): self.activeStackValueChanged.emit() if property_name == "validationState": - if self._active_stack_valid: + if not self._stacks_have_errors: + # fast update, we only have to look at the current changed property if self._active_container_stack.getProperty(key, "settable_per_extruder"): changed_validation_state = self._active_container_stack.getProperty(key, property_name) else: changed_validation_state = self._global_container_stack.getProperty(key, property_name) if changed_validation_state in (UM.Settings.ValidatorState.Exception, UM.Settings.ValidatorState.MaximumError, UM.Settings.ValidatorState.MinimumError): - self._active_stack_valid = False - self.activeStackValidationChanged.emit() + self._stacks_have_errors = True + self.stacksValidationChanged.emit() else: - if not self._checkStackForErrors(self._active_container_stack) and not self._checkStackForErrors(self._global_container_stack): - self._active_stack_valid = True - self.activeStackValidationChanged.emit() + # Normal check + self._updateStacksHaveErrors() @pyqtSlot(str) def setActiveMachine(self, stack_id): @@ -351,15 +356,17 @@ class MachineManager(QObject): def _createUniqueName(self, container_type, current_name, new_name, fallback_name): return UM.Settings.ContainerRegistry.getInstance().createUniqueName(container_type, current_name, new_name, fallback_name) - ## Convenience function to check if a stack has errors. - def _checkStackForErrors(self, stack): - if stack is None: - return False + def _checkStacksHaveErrors(self): + if self._global_container_stack is not None and self._global_container_stack.hasErrors(): + return True - for key in stack.getAllKeys(): - validation_state = stack.getProperty(key, "validationState") - if validation_state in (UM.Settings.ValidatorState.Exception, UM.Settings.ValidatorState.MaximumError, UM.Settings.ValidatorState.MinimumError): + if self._global_container_stack is None: + return False + stacks = list(ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId())) + for stack in stacks: + if stack.hasErrors(): return True + return False ## Remove all instances from the top instanceContainer (effectively removing all user-changed settings) @@ -419,12 +426,12 @@ class MachineManager(QObject): for container in send_emits_containers: container.sendPostponedEmits() - ## Check if the global profile does not contain error states - # Note that the _active_stack_valid is cached due to performance issues - # Calling _checkStackForErrors on every change is simply too expensive - @pyqtProperty(bool, notify = activeStackValidationChanged) - def isActiveStackValid(self): - return bool(self._active_stack_valid) + ## Check if none of the stacks contain error states + # Note that the _stacks_have_errors is cached due to performance issues + # Calling _checkStack(s)ForErrors on every change is simply too expensive + @pyqtProperty(bool, notify = stacksValidationChanged) + def stacksHaveErrors(self): + return bool(self._stacks_have_errors) @pyqtProperty(str, notify = activeStackChanged) def activeUserProfileId(self): diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index 18c7fb1f5c..650bc9e45d 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -75,7 +75,7 @@ class StartSliceJob(Job): return # Don't slice if there is a setting with an error value. - if not Application.getInstance().getMachineManager().isActiveStackValid: + if Application.getInstance().getMachineManager().stacksHaveErrors: self.setResult(StartJobResult.SettingError) return diff --git a/resources/qml/Actions.qml b/resources/qml/Actions.qml index d7a0a87dbe..eebf8677b0 100644 --- a/resources/qml/Actions.qml +++ b/resources/qml/Actions.qml @@ -121,7 +121,7 @@ Item Action { id: updateProfileAction; - enabled: Cura.MachineManager.isActiveStackValid && Cura.MachineManager.hasUserSettings && !Cura.MachineManager.isReadOnly(Cura.MachineManager.activeQualityId) + enabled: !Cura.MachineManager.stacksHaveErrors && Cura.MachineManager.hasUserSettings && !Cura.MachineManager.isReadOnly(Cura.MachineManager.activeQualityId) text: catalog.i18nc("@action:inmenu menubar:profile","&Update profile with current settings"); onTriggered: Cura.ContainerManager.updateQualityChanges(); } @@ -141,7 +141,7 @@ Item Action { id: addProfileAction; - enabled: Cura.MachineManager.isActiveStackValid && Cura.MachineManager.hasUserSettings + enabled: !Cura.MachineManager.stacksHaveErrors && Cura.MachineManager.hasUserSettings text: catalog.i18nc("@action:inmenu menubar:profile","&Create profile from current settings..."); } diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 621ecb3184..47d49849b4 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -62,7 +62,7 @@ UM.ManagementPage Button { text: catalog.i18nc("@label", "Create") - enabled: base.canCreateProfile() + enabled: base.canCreateProfile() && !Cura.MachineManager.stacksHaveErrors visible: base.canCreateProfile() iconName: "list-add";