From 81f3422e36b22c9465780d099a6e73b6e407af5a Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 4 Aug 2016 02:02:14 +0200 Subject: [PATCH 01/23] Make settable_per_* properties read-only Contributes to CURA-2006 --- cura/CuraApplication.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 5e78aeeed1..b08325b2dc 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -93,10 +93,10 @@ class CuraApplication(QtApplication): self._open_file_queue = [] # Files to open when plug-ins are loaded. # Need to do this before ContainerRegistry tries to load the machines - SettingDefinition.addSupportedProperty("settable_per_mesh", DefinitionPropertyType.Any, default = True) - SettingDefinition.addSupportedProperty("settable_per_extruder", DefinitionPropertyType.Any, default = True) - SettingDefinition.addSupportedProperty("settable_per_meshgroup", DefinitionPropertyType.Any, default = True) - SettingDefinition.addSupportedProperty("settable_globally", DefinitionPropertyType.Any, default = True) + SettingDefinition.addSupportedProperty("settable_per_mesh", DefinitionPropertyType.Any, default = True, read_only = True) + SettingDefinition.addSupportedProperty("settable_per_extruder", DefinitionPropertyType.Any, default = True, read_only = True) + SettingDefinition.addSupportedProperty("settable_per_meshgroup", DefinitionPropertyType.Any, default = True, read_only = True) + SettingDefinition.addSupportedProperty("settable_globally", DefinitionPropertyType.Any, default = True, read_only = True) SettingDefinition.addSupportedProperty("global_inherits_stack", DefinitionPropertyType.Function, default = "-1") SettingDefinition.addSettingType("extruder", None, str, Validator) From ab99100c5671a60b76ecf1d748db09dedf8af9b7 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 4 Aug 2016 02:02:47 +0200 Subject: [PATCH 02/23] Introduce an empty quality_changes container Contributes to CURA-2006 --- cura/CuraApplication.py | 4 ++++ cura/Settings/MachineManager.py | 1 + 2 files changed, 5 insertions(+) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index b08325b2dc..fcd4eae829 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -190,6 +190,10 @@ class CuraApplication(QtApplication): empty_quality_container._id = "empty_quality" empty_quality_container.addMetaDataEntry("type", "quality") ContainerRegistry.getInstance().addContainer(empty_quality_container) + empty_quality_changes_container = copy.deepcopy(empty_container) + empty_quality_changes_container._id = "empty_quality_changes" + empty_quality_changes_container.addMetaDataEntry("type", "quality_changes") + ContainerRegistry.getInstance().addContainer(empty_quality_changes_container) ContainerRegistry.getInstance().load() diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 6a180593c5..de7b72bc84 100644 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -47,6 +47,7 @@ class MachineManager(QObject): self._empty_variant_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = "empty_variant")[0] self._empty_material_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = "empty_material")[0] self._empty_quality_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = "empty_quality")[0] + self._empty_quality_changes_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = "empty_quality_changes")[0] Preferences.getInstance().addPreference("cura/active_machine", "") From d42f390ed6f93d3df77db1b7ae443d6eb404c980 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 4 Aug 2016 02:03:57 +0200 Subject: [PATCH 03/23] Add the new empty quality_changes container to new machines Contributes to CURA-2006 --- cura/Settings/MachineManager.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index de7b72bc84..936e73b63d 100644 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -383,7 +383,6 @@ class MachineManager(QObject): current_settings_instance_container.setDefinition(definitions[0]) container_registry.addContainer(current_settings_instance_container) - # If a definition is found, its a list. Should only have one item. new_global_stack.addContainer(definition) if variant_instance_container: new_global_stack.addContainer(variant_instance_container) @@ -391,6 +390,8 @@ class MachineManager(QObject): new_global_stack.addContainer(material_instance_container) if quality_instance_container: new_global_stack.addContainer(quality_instance_container) + + new_global_stack.addContainer(self._empty_quality_changes_container) new_global_stack.addContainer(current_settings_instance_container) ExtruderManager.getInstance().addMachineExtruders(definition, new_global_stack.getId()) From aa8561fec7aeb9a09b93c78ff8c2fb28b9686593 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 4 Aug 2016 02:05:12 +0200 Subject: [PATCH 04/23] Remove globalPropertyChanged There should be no need for this if we properly store settings where they should be stored. Contributes to CURA-2006 --- cura/Settings/MachineManager.py | 100 ++------------------------------ 1 file changed, 5 insertions(+), 95 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 936e73b63d..0b97ffe00c 100644 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -26,6 +26,10 @@ class MachineManager(QObject): self._global_container_stack = None Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged) + self.globalContainerChanged.connect(self.activeMaterialChanged) + self.globalContainerChanged.connect(self.activeVariantChanged) + self.globalContainerChanged.connect(self.activeQualityChanged) + self._active_stack_valid = None self._onGlobalContainerChanged() @@ -33,9 +37,7 @@ class MachineManager(QObject): self._onActiveExtruderStackChanged() ## When the global container is changed, active material probably needs to be updated. - self.globalContainerChanged.connect(self.activeMaterialChanged) - self.globalContainerChanged.connect(self.activeVariantChanged) - self.globalContainerChanged.connect(self.activeQualityChanged) + ExtruderManager.getInstance().activeExtruderChanged.connect(self.activeMaterialChanged) ExtruderManager.getInstance().activeExtruderChanged.connect(self.activeVariantChanged) ExtruderManager.getInstance().activeExtruderChanged.connect(self.activeQualityChanged) @@ -197,107 +199,18 @@ class MachineManager(QObject): if old_index is not None: extruder_manager.setActiveExtruderIndex(old_index) - def _onGlobalPropertyChanged(self, key, property_name): - if property_name == "value": - ## We can get recursion issues. So we store a list of keys that we are still handling to prevent this. - if key in self._global_event_keys: - return - self._global_event_keys.add(key) - self.globalValueChanged.emit() - if self._active_container_stack and self._active_container_stack != self._global_container_stack: - # Make the global current settings mirror the stack values appropriate for this setting - if self._active_container_stack.getProperty("extruder_nr", "value") == int(self._active_container_stack.getProperty(key, "global_inherits_stack")): - new_value = self._active_container_stack.getProperty(key, "value") - self._global_container_stack.getTop().setProperty(key, "value", new_value) - # Global-only setting values should be set on all extruders and the global stack - if not self._global_container_stack.getProperty(key, "settable_per_extruder"): - extruder_stacks = list(ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId())) - target_stack_position = int(self._active_container_stack.getProperty(key, "global_inherits_stack")) - if target_stack_position == -1: # Prevent -1 from selecting wrong stack. - target_stack = self._active_container_stack - else: - target_stack = extruder_stacks[target_stack_position] - new_value = target_stack.getProperty(key, "value") - target_stack_has_user_value = target_stack.getTop().getInstance(key) != None - for extruder_stack in extruder_stacks: - if extruder_stack != target_stack: - if target_stack_has_user_value: - extruder_stack.getTop().setProperty(key, "value", new_value) - else: - # Remove from the value from the other stacks as well, unless the - # top value from the other stacklevels is different than the new value - for container in extruder_stack.getContainers(): - if container.__class__ == UM.Settings.InstanceContainer and container.getInstance(key) != None: - if container.getProperty(key, "value") != new_value: - # It could be that the setting needs to be removed instead of updated. - temp = extruder_stack - containers = extruder_stack.getContainers() - # Ensure we have the entire 'chain' - while temp.getNextStack(): - temp = temp.getNextStack() - containers.extend(temp.getContainers()) - instance_needs_removal = False - if len(containers) > 1: - for index in range(1, len(containers)): - deeper_container = containers[index] - if deeper_container.getProperty(key, "value") is None: - continue # Deeper container does not have the value, so continue. - if deeper_container.getProperty(key, "value") == new_value: - # Removal will result in correct value, so do that. - # We do this to prevent the reset from showing up unneeded. - instance_needs_removal = True - break - else: - # Container has the value, but it's not the same. Stop looking. - break - if instance_needs_removal: - extruder_stack.getTop().removeInstance(key) - else: - extruder_stack.getTop().setProperty(key, "value", new_value) - else: - # Check if we really need to remove something. - if extruder_stack.getProperty(key, "value") != new_value: - extruder_stack.getTop().removeInstance(key) - break - if self._global_container_stack.getProperty(key, "value") != new_value: - self._global_container_stack.getTop().setProperty(key, "value", new_value) - self._global_event_keys.remove(key) - if property_name == "global_inherits_stack": - if self._active_container_stack and self._active_container_stack != self._global_container_stack: - # Update the global user value when the "global_inherits_stack" function points to a different stack - extruder_stacks = list(ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId())) - target_stack_position = int(self._active_container_stack.getProperty(key, "global_inherits_stack")) - if target_stack_position == -1: # Prevent -1 from selecting wrong stack. - target_stack = self._active_container_stack - else: - target_stack = extruder_stacks[target_stack_position] - new_value = target_stack.getProperty(key, "value") - if self._global_container_stack.getProperty(key, "value") != new_value: - self._global_container_stack.getTop().setProperty(key, "value", new_value) - if property_name == "validationState": - if self._active_stack_valid: - changed_validation_state = self._active_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.activeValidationChanged.emit() - else: - has_errors = self._checkStackForErrors(self._active_container_stack) - if not has_errors: - self._active_stack_valid = True - self.activeValidationChanged.emit() def _onGlobalContainerChanged(self): if self._global_container_stack: self._global_container_stack.nameChanged.disconnect(self._onMachineNameChanged) self._global_container_stack.containersChanged.disconnect(self._onInstanceContainersChanged) - self._global_container_stack.propertyChanged.disconnect(self._onGlobalPropertyChanged) material = self._global_container_stack.findContainer({"type": "material"}) material.nameChanged.disconnect(self._onMaterialNameChanged) @@ -314,7 +227,6 @@ class MachineManager(QObject): Preferences.getInstance().setValue("cura/active_machine", self._global_container_stack.getId()) self._global_container_stack.nameChanged.connect(self._onMachineNameChanged) self._global_container_stack.containersChanged.connect(self._onInstanceContainersChanged) - self._global_container_stack.propertyChanged.connect(self._onGlobalPropertyChanged) material = self._global_container_stack.findContainer({"type": "material"}) material.nameChanged.connect(self._onMaterialNameChanged) @@ -325,11 +237,9 @@ class MachineManager(QObject): self.blurSettings.emit() # Ensure no-one has focus. if self._active_container_stack and self._active_container_stack != self._global_container_stack: self._active_container_stack.containersChanged.disconnect(self._onInstanceContainersChanged) - self._active_container_stack.propertyChanged.disconnect(self._onGlobalPropertyChanged) self._active_container_stack = ExtruderManager.getInstance().getActiveExtruderStack() if self._active_container_stack: self._active_container_stack.containersChanged.connect(self._onInstanceContainersChanged) - self._active_container_stack.propertyChanged.connect(self._onGlobalPropertyChanged) else: self._active_container_stack = self._global_container_stack self._active_stack_valid = not self._checkStackForErrors(self._active_container_stack) From 4de40534909efb0321d287414009226799604865 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 4 Aug 2016 02:08:06 +0200 Subject: [PATCH 05/23] Properly implement "set as active extruder" menu entry Contributes to CURA-2006 --- resources/qml/Cura.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index 5f45a062b8..7633b14239 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -150,7 +150,7 @@ UM.MainWindow MenuSeparator { } - MenuItem { text: "Set as Active Extruder" } + MenuItem { text: catalog.i18nc("@action:inmenu", "Set as Active Extruder"); onTriggered: Cura.ExtruderManager.setActiveExtruderIndex(model.index) } } onObjectAdded: settingsMenu.insertItem(index, object) onObjectRemoved: settingsMenu.removeItem(object) From 6eed25f145862c0e76fc07ff3cfa1e980ed46a72 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 4 Aug 2016 02:09:02 +0200 Subject: [PATCH 06/23] Only write property changes to extruder stack if we actually should Now global settings are once again stored in the global stack Contributes to CURA-2006 --- resources/qml/Settings/SettingView.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 978e2dcaed..f79f074400 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -94,6 +94,7 @@ ScrollView { target: provider property: "containerStackId" + when: model.settable_per_extruder || (inheritStackProvider.properties.global_inherits_stack == -1 || inheritStackProvider.properties.global_inherits_stack == null) value: { if(inheritStackProvider.properties.global_inherits_stack == -1 || inheritStackProvider.properties.global_inherits_stack == null) @@ -127,7 +128,7 @@ ScrollView containerStackId: Cura.MachineManager.activeMachineId key: model.key ? model.key : "" - watchedProperties: [ "value", "enabled", "state", "validationState", "settable_per_extruder" ] + watchedProperties: [ "value", "enabled", "state", "validationState" ] storeIndex: 0 } From 95c3aa8251bbc6c166c1c87decbbb85111c25dce Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 4 Aug 2016 02:10:28 +0200 Subject: [PATCH 07/23] Split ContainerManager::mergeContainer into a checking bit and a function that does the actual work Contributes to CURA-2006 --- cura/Settings/ContainerManager.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/cura/Settings/ContainerManager.py b/cura/Settings/ContainerManager.py index 82be7c480f..a93c7ae96c 100644 --- a/cura/Settings/ContainerManager.py +++ b/cura/Settings/ContainerManager.py @@ -135,12 +135,11 @@ class ContainerManager(QObject): merge = containers[0] - if type(merge) != type(merge_into): + if not isinstance(merge, type(merge_into)): UM.Logger.log("w", "Cannot merge two containers of different types") return False - for key in merge.getAllKeys(): - merge_into.setProperty(key, "value", merge.getProperty(key, "value")) + self._performMerge(merge_into, merge) return True @@ -350,6 +349,22 @@ class ContainerManager(QObject): return { "status": "success", "message": "Successfully imported container {0}".format(container.getName()) } + # Factory function, used by QML + @staticmethod + def createContainerManager(engine, js_engine): + return ContainerManager() + + def _performMerge(self, merge_into, merge): + assert isinstance(merge, type(merge_into)) + + if merge == merge_into: + return + + for key in merge.getAllKeys(): + merge_into.setProperty(key, "value", merge.getProperty(key, "value")) + + merge.clear() + def _updateContainerNameFilters(self): self._container_name_filters = {} for plugin_id, container_type in UM.Settings.ContainerRegistry.getContainerTypes(): @@ -393,8 +408,3 @@ class ContainerManager(QObject): name_filter = "{0} ({1})".format(mime_type.comment, suffix_list) self._container_name_filters[name_filter] = entry - - # Factory function, used by QML - @staticmethod - def createContainerManager(engine, js_engine): - return ContainerManager() From 0934ae70a8533765b03e34b92b9cdec78a50117a Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 4 Aug 2016 02:11:35 +0200 Subject: [PATCH 08/23] Introduce clearUserContainers and updateQualityChanges methods in ContainerManager They are moved from MachineManager which is really getting too large and complicated. Contributes to CURA-2006 --- cura/Settings/ContainerManager.py | 32 +++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/cura/Settings/ContainerManager.py b/cura/Settings/ContainerManager.py index a93c7ae96c..ad9c61366f 100644 --- a/cura/Settings/ContainerManager.py +++ b/cura/Settings/ContainerManager.py @@ -14,6 +14,8 @@ import UM.Platform import UM.MimeTypeDatabase import UM.Logger +from .ExtruderManager import ExtruderManager + from UM.MimeTypeDatabase import MimeTypeNotFoundError from UM.i18n import i18nCatalog @@ -349,6 +351,36 @@ class ContainerManager(QObject): return { "status": "success", "message": "Successfully imported container {0}".format(container.getName()) } + @pyqtSlot(result = bool) + def updateQualityChanges(self): + global_stack = UM.Application.getInstance().getGlobalContainerStack() + + containers_to_merge = [] + + global_quality_changes = global_stack.findContainer(type = "quality_changes") + if not global_quality_changes or global_quality_changes.isReadOnly(): + return False + + containers_to_merge.append((global_quality_changes, global_stack.getTop())) + + for extruder in ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()): + quality_changes = extruder.findContainer(type = "quality_changes") + if not quality_changes or quality_changes.isReadOnly(): + return False + + containers_to_merge.append((quality_changes, extruder.getTop())) + + for merge_into, merge in containers_to_merge: + self._performMerge(merge_into, merge) + + @pyqtSlot() + def clearUserContainers(self): + global_stack = UM.Application.getInstance().getGlobalContainerStack() + + for extruder in ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()): + extruder.getTop().clear() + + global_stack.getTop().clear() # Factory function, used by QML @staticmethod def createContainerManager(engine, js_engine): From 9ef709962ff3239261ca42bc26334d61f797cf83 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 4 Aug 2016 02:12:32 +0200 Subject: [PATCH 09/23] Start implementing a createQualityChanges method in ContainerManager It will be used to create the quality change containers from the existing user containers. Contributes to CURA-2006 --- cura/Settings/ContainerManager.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/cura/Settings/ContainerManager.py b/cura/Settings/ContainerManager.py index ad9c61366f..7a6d5b8184 100644 --- a/cura/Settings/ContainerManager.py +++ b/cura/Settings/ContainerManager.py @@ -381,6 +381,28 @@ class ContainerManager(QObject): extruder.getTop().clear() global_stack.getTop().clear() + + @pyqtSlot() + def createQualityChanges(self): + global_stack = UM.Application.getInstance().getGlobalContainerStack() + + user_container = global_stack.getTop() + quality_container = global_stack.findContainer(type = "quality") + if not quality_container: + return + + unique_name = UM.Settings.ContainerRegistry.getInstance().uniqueName(quality_container.getName()) + unique_id = unique_name.lower() + unique_id.replace(" ", "_") + + quality_changes = user_container.duplicate() + quality_changes.setMetaDataEntry("type", "quality_changes") + quality_changes.setMetaDataEntry("quality_base", quality_container.getId()) + + UM.Settings.ContainerRegistry.getInstance().addContainer(quality_changes) + + + # Factory function, used by QML @staticmethod def createContainerManager(engine, js_engine): From 4eb4a90ded2d629b40f64b771924e13cfcd00a1d Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 4 Aug 2016 02:13:24 +0200 Subject: [PATCH 10/23] Call the new clearUserContainers/updateQualityChanges from the relevant actions Contributes to CURA-2006 --- resources/qml/Actions.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/qml/Actions.qml b/resources/qml/Actions.qml index ed88433e33..3d08b133cc 100644 --- a/resources/qml/Actions.qml +++ b/resources/qml/Actions.qml @@ -122,7 +122,7 @@ Item id: updateProfileAction; enabled: Cura.MachineManager.isActiveStackValid && Cura.MachineManager.hasUserSettings && !Cura.MachineManager.isReadOnly(Cura.MachineManager.activeQualityId) text: catalog.i18nc("@action:inmenu menubar:profile","&Update profile with current settings"); - onTriggered: Cura.MachineManager.updateQualityContainerFromUserContainer() + onTriggered: Cura.ContainerManager.updateQualityChanges(); } Action @@ -130,7 +130,7 @@ Item id: resetProfileAction; enabled: Cura.MachineManager.hasUserSettings text: catalog.i18nc("@action:inmenu menubar:profile","&Discard current settings"); - onTriggered: Cura.MachineManager.clearUserSettings(); + onTriggered: Cura.ContainerManager.clearUserContainers(); } Action From b6d0c40852a54bc11c5c829cca5319e39e173c9b Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 4 Aug 2016 17:32:38 +0200 Subject: [PATCH 11/23] Store "quality_changes" type containers in the quality directory Contributes to CURA-2006 --- cura/CuraApplication.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index fcd4eae829..091b8fe269 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -314,7 +314,7 @@ class CuraApplication(QtApplication): path = None if instance_type == "material": path = Resources.getStoragePath(self.ResourceTypes.MaterialInstanceContainer, file_name) - elif instance_type == "quality": + elif instance_type == "quality" or instance_type == "quality_changes": path = Resources.getStoragePath(self.ResourceTypes.QualityInstanceContainer, file_name) elif instance_type == "user": path = Resources.getStoragePath(self.ResourceTypes.UserInstanceContainer, file_name) From ec383b46b95ddee10b7b4b843395bb76255574f4 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 4 Aug 2016 17:33:35 +0200 Subject: [PATCH 12/23] Emit blurSettings for ContainerManager::merge/clear user containers Contributes to CURA-2006 --- cura/Settings/ContainerManager.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cura/Settings/ContainerManager.py b/cura/Settings/ContainerManager.py index 7a6d5b8184..bec04af92e 100644 --- a/cura/Settings/ContainerManager.py +++ b/cura/Settings/ContainerManager.py @@ -15,6 +15,7 @@ import UM.MimeTypeDatabase import UM.Logger from .ExtruderManager import ExtruderManager +from .MachineManager import MachineManager from UM.MimeTypeDatabase import MimeTypeNotFoundError @@ -359,13 +360,17 @@ class ContainerManager(QObject): global_quality_changes = global_stack.findContainer(type = "quality_changes") if not global_quality_changes or global_quality_changes.isReadOnly(): + UM.Logger.log("e", "Could not update quality of a nonexistant or read only quality profile") return False + MachineManager.getInstance().blurSettings.emit() + containers_to_merge.append((global_quality_changes, global_stack.getTop())) for extruder in ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()): quality_changes = extruder.findContainer(type = "quality_changes") if not quality_changes or quality_changes.isReadOnly(): + UM.Logger.log("e", "Could not update quality of a nonexistant or read only quality profile") return False containers_to_merge.append((quality_changes, extruder.getTop())) @@ -377,6 +382,8 @@ class ContainerManager(QObject): def clearUserContainers(self): global_stack = UM.Application.getInstance().getGlobalContainerStack() + MachineManager.getInstance().blurSettings.emit() + for extruder in ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()): extruder.getTop().clear() From 7613274686adeff933db8d791bbf47c14f18306e Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 4 Aug 2016 17:34:41 +0200 Subject: [PATCH 13/23] Properly hide link icon if setting is not settable per extruder Contributes to CURA-2006 --- resources/qml/Settings/SettingItem.qml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/resources/qml/Settings/SettingItem.qml b/resources/qml/Settings/SettingItem.qml index dae9953690..a091b55c8b 100644 --- a/resources/qml/Settings/SettingItem.qml +++ b/resources/qml/Settings/SettingItem.qml @@ -27,7 +27,6 @@ Item { // Create properties to put property provider stuff in (bindings break in qt 5.5.1 otherwise) property var state: propertyProvider.properties.state - property var settablePerExtruder: propertyProvider.properties.settable_per_extruder property var stackLevels: propertyProvider.stackLevels property var stackLevel: stackLevels[0] @@ -138,7 +137,7 @@ Item { { id: linkedSettingIcon; - visible: Cura.MachineManager.activeStackId != Cura.MachineManager.activeMachineId && base.settablePerExtruder != "True" && base.showLinkedSettingIcon + visible: Cura.MachineManager.activeStackId != Cura.MachineManager.activeMachineId && !definition.settable_per_extruder && base.showLinkedSettingIcon height: parent.height; width: height; From 9d0acf5b036ee4749af0034969c683e39cc547d3 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 4 Aug 2016 17:35:01 +0200 Subject: [PATCH 14/23] Properly send global settings to the global stack Contributes to CURA-2006 --- resources/qml/Settings/SettingView.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index f79f074400..79925e629f 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -94,7 +94,7 @@ ScrollView { target: provider property: "containerStackId" - when: model.settable_per_extruder || (inheritStackProvider.properties.global_inherits_stack == -1 || inheritStackProvider.properties.global_inherits_stack == null) + when: model.settable_per_extruder || (inheritStackProvider.properties.global_inherits_stack != -1 && inheritStackProvider.properties.global_inherits_stack != null) value: { if(inheritStackProvider.properties.global_inherits_stack == -1 || inheritStackProvider.properties.global_inherits_stack == null) From 70dee38c959db4a772f6ccf7277e02b33d1afe3d Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 4 Aug 2016 17:35:33 +0200 Subject: [PATCH 15/23] Show quality_changes instance containers for custom containers in the profile menu Contributes to CURA-2006 --- resources/qml/Menus/ProfileMenu.qml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/resources/qml/Menus/ProfileMenu.qml b/resources/qml/Menus/ProfileMenu.qml index 68f83305d7..c99d6a181d 100644 --- a/resources/qml/Menus/ProfileMenu.qml +++ b/resources/qml/Menus/ProfileMenu.qml @@ -7,7 +7,7 @@ import QtQuick.Controls 1.1 import UM 1.2 as UM import Cura 1.0 as Cura - Menu +Menu { id: menu @@ -15,7 +15,7 @@ import Cura 1.0 as Cura { model: UM.InstanceContainersModel { - filter: menu.getFilter({ "read_only": true }); + filter: menu.getFilter({ "type": "quality" }); } MenuItem @@ -38,7 +38,7 @@ import Cura 1.0 as Cura id: customProfileInstantiator model: UM.InstanceContainersModel { - filter: menu.getFilter({ "read_only": false }); + filter: menu.getFilter({ "type": "quality_changes", "extruder": null }); onModelReset: customSeparator.visible = rowCount() > 0 } @@ -76,7 +76,6 @@ import Cura 1.0 as Cura function getFilter(initial_conditions) { var result = initial_conditions; - result.type = "quality" if(Cura.MachineManager.filterQualityByMachine) { From b76ebbb8508d58a5b8aa07917e3953c6ea21f4b5 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 4 Aug 2016 17:36:39 +0200 Subject: [PATCH 16/23] Ensure we have an empty quality changes container in the extruder stack Contributes to CURA-2006 --- cura/Settings/ExtruderManager.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cura/Settings/ExtruderManager.py b/cura/Settings/ExtruderManager.py index 71bd58ded5..8861334237 100644 --- a/cura/Settings/ExtruderManager.py +++ b/cura/Settings/ExtruderManager.py @@ -235,6 +235,9 @@ class ExtruderManager(QObject): container_stack.addContainer(quality) + empty_quality_changes = container_registry.findInstanceContainers(id = "empty_quality_changes")[0] + container_stack.addContainer(empty_quality_changes) + user_profile = container_registry.findInstanceContainers(type = "user", extruder = extruder_stack_id) if user_profile: # There was already a user profile, loaded from settings. user_profile = user_profile[0] From 2ee2bc734831eeefcec6c48da3f7ddc04d928be2 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 4 Aug 2016 17:37:15 +0200 Subject: [PATCH 17/23] Properly implement ContainerManager::createQualityChanges Contributes to CURA-2006 --- cura/Settings/ContainerManager.py | 39 +++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/cura/Settings/ContainerManager.py b/cura/Settings/ContainerManager.py index bec04af92e..d58b111be9 100644 --- a/cura/Settings/ContainerManager.py +++ b/cura/Settings/ContainerManager.py @@ -389,26 +389,51 @@ class ContainerManager(QObject): global_stack.getTop().clear() - @pyqtSlot() + @pyqtSlot(result = bool) def createQualityChanges(self): global_stack = UM.Application.getInstance().getGlobalContainerStack() + if not global_stack: + return False - user_container = global_stack.getTop() quality_container = global_stack.findContainer(type = "quality") if not quality_container: - return + UM.Logger.log("w", "No quality container found in stack %s, cannot create profile", global_stack.getId()) + return False + + MachineManager.getInstance().blurSettings.emit() unique_name = UM.Settings.ContainerRegistry.getInstance().uniqueName(quality_container.getName()) unique_id = unique_name.lower() unique_id.replace(" ", "_") - quality_changes = user_container.duplicate() - quality_changes.setMetaDataEntry("type", "quality_changes") - quality_changes.setMetaDataEntry("quality_base", quality_container.getId()) + stacks = [ s for s in ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()) ] + stacks.insert(0, global_stack) - UM.Settings.ContainerRegistry.getInstance().addContainer(quality_changes) + for stack in stacks: + user_container = stack.getTop() + quality_container = stack.findContainer(type = "quality") + quality_changes_container = stack.findContainer(type = "quality_changes") + if not quality_container or not quality_changes_container: + UM.Logger.log("w", "No quality or quality changes container found in stack %s, ignoring it", stack.getId()) + return False + new_quality_changes = user_container.duplicate(stack.getId() + "_" + unique_id, unique_name) + new_quality_changes.setMetaDataEntry("type", "quality_changes") + new_quality_changes.addMetaDataEntry("quality", quality_container.getId()) + if not global_stack.getMetaDataEntry("has_machine_quality"): + new_quality_changes.setDefinition(UM.Settings.ContainerRegistry.getInstance().findContainers(id = "fdmprinter")[0]) + + if global_stack.getMetaDataEntry("has_materials"): + material = stack.findContainer(type = "material") + new_quality_changes.addMetaDataEntry("material", material.getId()) + + UM.Settings.ContainerRegistry.getInstance().addContainer(new_quality_changes) + + stack.replaceContainer(stack.getContainerIndex(quality_changes_container), new_quality_changes) + stack.getTop().clear() + + return True # Factory function, used by QML @staticmethod From 6d49fb87afe9420edb60b4fa79454705a627f381 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 4 Aug 2016 17:38:19 +0200 Subject: [PATCH 18/23] Use ContainerManager::createQualityChanges when creating a quality from current settings Contributes to CURA-2006 --- resources/qml/Cura.qml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index 7633b14239..02dcd10897 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -459,7 +459,8 @@ UM.MainWindow target: Cura.Actions.addProfile onTriggered: { - Cura.MachineManager.newQualityContainerFromQualityAndUser(); +// Cura.MachineManager.newQualityContainerFromQualityAndUser(); + Cura.ContainerManager.createQualityChanges(); preferences.setPage(4); preferences.show(); @@ -764,6 +765,10 @@ UM.MainWindow addMachineDialog.visible = true addMachineDialog.firstRun = false } + onClearAllFocus: + { + contentItem.focus = true + } } Timer From 10de07c08ec2494227dc56d2e00b96d9d82d91a8 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 4 Aug 2016 17:39:09 +0200 Subject: [PATCH 19/23] Remove some code that was moved to ContainerManager Contributes to CURA-2006 --- cura/Settings/MachineManager.py | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 0b97ffe00c..265e3d0bc1 100644 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -438,16 +438,6 @@ class MachineManager(QObject): if extruder_stack != self._active_container_stack and extruder_stack.getProperty(key, "value") != new_value: extruder_stack.getTop().setProperty(key, "value", new_value) - @pyqtSlot(result = str) - def newQualityContainerFromQualityAndUser(self): - new_container_id = self.duplicateContainer(self.activeQualityId) - if new_container_id == "": - return - self.blurSettings.emit() - self.updateQualityContainerFromUserContainer(new_container_id) - self.setActiveQuality(new_container_id) - return new_container_id - @pyqtSlot(str, result=str) def duplicateContainer(self, container_id): if not self._active_container_stack: @@ -513,29 +503,6 @@ class MachineManager(QObject): self.setActiveQuality(containers[0].getId()) self.activeQualityChanged.emit() - @pyqtSlot(str) - @pyqtSlot() - def updateQualityContainerFromUserContainer(self, quality_id = None): - if not self._active_container_stack: - return - - if quality_id: - quality = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = quality_id, type = "quality") - if quality: - quality = quality[0] - else: - quality = self._active_container_stack.findContainer({"type": "quality"}) - - if not quality: - return - - user_settings = self._active_container_stack.getTop() - - for key in user_settings.getAllKeys(): - quality.setProperty(key, "value", user_settings.getProperty(key, "value")) - self.clearUserSettings() # As all users settings are noq a quality, remove them. - - @pyqtSlot(str) def setActiveMaterial(self, material_id): containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = material_id) From 5361efcf2c335791f9e5d403ec0a872e4ff0d114 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 4 Aug 2016 17:39:52 +0200 Subject: [PATCH 20/23] Return the name/id of the quality changes container if it is set for activeQuality Contributes to CURA-2006 --- cura/Settings/MachineManager.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 265e3d0bc1..6a3c50b53b 100644 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -404,6 +404,9 @@ class MachineManager(QObject): @pyqtProperty(str, notify=activeQualityChanged) def activeQualityName(self): if self._active_container_stack: + quality = self._active_container_stack.findContainer({"type": "quality_changes"}) + if quality and quality != self._empty_quality_changes_container: + return quality.getName() quality = self._active_container_stack.findContainer({"type": "quality"}) if quality: return quality.getName() @@ -411,8 +414,11 @@ class MachineManager(QObject): @pyqtProperty(str, notify=activeQualityChanged) def activeQualityId(self): - if self._active_container_stack: - quality = self._active_container_stack.findContainer({"type": "quality"}) + if self._global_container_stack: + quality = self._global_container_stack.findContainer({"type": "quality_changes"}) + if quality and quality != self._empty_quality_changes_container: + return quality.getId() + quality = self._global_container_stack.findContainer({"type": "quality"}) if quality: return quality.getId() return "" From e2045cdb7f7ec58730bf6f2b1ef2233847637dda Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 4 Aug 2016 17:40:16 +0200 Subject: [PATCH 21/23] Remove obsolete container switcheroo Contributes to CURA-2006 --- cura/Settings/MachineManager.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 6a3c50b53b..38b4e80e80 100644 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -248,16 +248,7 @@ class MachineManager(QObject): def _onInstanceContainersChanged(self, container): container_type = container.getMetaDataEntry("type") - if self._active_container_stack and self._active_container_stack != self._global_container_stack: - if int(self._active_container_stack.getProperty("extruder_nr", "value")) == 0: - global_container = self._global_container_stack.findContainer({"type": container_type}) - if global_container and global_container != container: - container_index = self._global_container_stack.getContainerIndex(global_container) - self._global_container_stack.replaceContainer(container_index, container) - for key in container.getAllKeys(): - # Make sure the values in this profile are distributed to other stacks if necessary - self._onGlobalPropertyChanged(key, "value") if container_type == "material": self.activeMaterialChanged.emit() From d150acb79c95122384a197b847e11b34333db9b5 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 4 Aug 2016 17:41:01 +0200 Subject: [PATCH 22/23] Change setActiveQuality to set quality of extruders & global and also set change containers Contributes to CURA-2006 --- cura/Settings/MachineManager.py | 75 ++++++++++++++++++++++++--------- 1 file changed, 54 insertions(+), 21 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 38b4e80e80..3b239ce770 100644 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -545,32 +545,65 @@ class MachineManager(QObject): @pyqtSlot(str) def setActiveQuality(self, quality_id): containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = quality_id) - if not containers or not self._active_container_stack: + if not containers or not self._global_container_stack: return - old_quality = self._active_container_stack.findContainer({"type": "quality"}) - if old_quality and old_quality != containers[0]: - old_quality.nameChanged.disconnect(self._onQualityNameChanged) + quality_container = None + quality_changes_container = self._empty_quality_changes_container - quality_index = self._active_container_stack.getContainerIndex(old_quality) + container_type = containers[0].getMetaDataEntry("type") - self._active_container_stack.replaceContainer(quality_index, containers[0]) - - containers[0].nameChanged.connect(self._onQualityNameChanged) - - if self.hasUserSettings and Preferences.getInstance().getValue("cura/active_mode") == 1: - # Ask the user if the user profile should be cleared or not (discarding the current settings) - # In Simple Mode we assume the user always wants to keep the (limited) current settings - details = catalog.i18nc("@label", "You made changes to the following setting(s):") - user_settings = self._active_container_stack.getTop().findInstances(**{}) - for setting in user_settings: - details = details + "\n " + setting.definition.label - - Application.getInstance().messageBox(catalog.i18nc("@window:title", "Switched profiles"), catalog.i18nc("@label", "Do you want to transfer your changed settings to this profile?"), - catalog.i18nc("@label", "If you transfer your settings they will override settings in the profile."), details, - buttons = QMessageBox.Yes + QMessageBox.No, icon = QMessageBox.Question, callback = self._keepUserSettingsDialogCallback) + if container_type == "quality": + quality_container = containers[0] + elif container_type == "quality_changes": + quality_changes_container = containers[0] + containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = quality_changes_container.getMetaDataEntry("quality")) + if not containers: + Logger.log("e", "Could not find quality %s for changes %s, not changing quality", quality_changes_container.getMetaDataEntry("quality"), quality_changes_container.getId()) + return + quality_container = containers[0] else: - Logger.log("w", "While trying to set the active quality, no quality was found to replace.") + Logger.log("e", "Tried to set quality to a container that is not of the right type") + return + + stacks = [ s for s in ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId()) ] + stacks.insert(0, self._global_container_stack) + + for stack in stacks: + extruder_id = stack.getId() if stack != self._global_container_stack else None + stack_quality = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(name = quality_container.getName(), extruder = extruder_id) + if not stack_quality: + stack_quality = quality_container + else: + stack_quality = stack_quality[0] + + if quality_changes_container != self._empty_quality_changes_container: + stack_quality_changes = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(name = quality_changes_container.getName(), extruder = extruder_id)[0] + else: + stack_quality_changes = self._empty_quality_changes_container + + old_quality = stack.findContainer(type = "quality") + old_quality.nameChanged.disconnect(self._onQualityNameChanged) + old_changes = stack.findContainer(type = "quality_changes") + old_changes.nameChanged.disconnect(self._onQualityNameChanged) + + stack.replaceContainer(stack.getContainerIndex(old_quality), stack_quality) + stack.replaceContainer(stack.getContainerIndex(old_changes), stack_quality_changes) + + stack_quality.nameChanged.connect(self._onQualityNameChanged) + stack_quality_changes.nameChanged.connect(self._onQualityNameChanged) + + if self.hasUserSettings and Preferences.getInstance().getValue("cura/active_mode") == 1: + # Ask the user if the user profile should be cleared or not (discarding the current settings) + # In Simple Mode we assume the user always wants to keep the (limited) current settings + details = catalog.i18nc("@label", "You made changes to the following setting(s):") + user_settings = self._active_container_stack.getTop().findInstances(**{}) + for setting in user_settings: + details = details + "\n " + setting.definition.label + + Application.getInstance().messageBox(catalog.i18nc("@window:title", "Switched profiles"), catalog.i18nc("@label", "Do you want to transfer your changed settings to this profile?"), + catalog.i18nc("@label", "If you transfer your settings they will override settings in the profile."), details, + buttons = QMessageBox.Yes + QMessageBox.No, icon = QMessageBox.Question, callback = self._keepUserSettingsDialogCallback) def _keepUserSettingsDialogCallback(self, button): if button == QMessageBox.Yes: From 354a467d8ef0c948533b9da35e3b62a3bcc0700c Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 4 Aug 2016 17:51:43 +0200 Subject: [PATCH 23/23] Fix circular import bullcrap Contributes to CURA-2006 --- cura/Settings/ContainerManager.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/cura/Settings/ContainerManager.py b/cura/Settings/ContainerManager.py index d58b111be9..528248f7ae 100644 --- a/cura/Settings/ContainerManager.py +++ b/cura/Settings/ContainerManager.py @@ -14,8 +14,7 @@ import UM.Platform import UM.MimeTypeDatabase import UM.Logger -from .ExtruderManager import ExtruderManager -from .MachineManager import MachineManager +import cura.Settings from UM.MimeTypeDatabase import MimeTypeNotFoundError @@ -363,11 +362,11 @@ class ContainerManager(QObject): UM.Logger.log("e", "Could not update quality of a nonexistant or read only quality profile") return False - MachineManager.getInstance().blurSettings.emit() + cura.Settings.MachineManager.getInstance().blurSettings.emit() containers_to_merge.append((global_quality_changes, global_stack.getTop())) - for extruder in ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()): + for extruder in cura.Settings.ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()): quality_changes = extruder.findContainer(type = "quality_changes") if not quality_changes or quality_changes.isReadOnly(): UM.Logger.log("e", "Could not update quality of a nonexistant or read only quality profile") @@ -382,9 +381,9 @@ class ContainerManager(QObject): def clearUserContainers(self): global_stack = UM.Application.getInstance().getGlobalContainerStack() - MachineManager.getInstance().blurSettings.emit() + cura.Settings.MachineManager.getInstance().blurSettings.emit() - for extruder in ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()): + for extruder in cura.Settings.ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()): extruder.getTop().clear() global_stack.getTop().clear() @@ -400,13 +399,13 @@ class ContainerManager(QObject): UM.Logger.log("w", "No quality container found in stack %s, cannot create profile", global_stack.getId()) return False - MachineManager.getInstance().blurSettings.emit() + cura.Settings.MachineManager.getInstance().blurSettings.emit() unique_name = UM.Settings.ContainerRegistry.getInstance().uniqueName(quality_container.getName()) unique_id = unique_name.lower() unique_id.replace(" ", "_") - stacks = [ s for s in ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()) ] + stacks = [ s for s in cura.Settings.ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()) ] stacks.insert(0, global_stack) for stack in stacks: