From d2405a24d26f0c23b1be3349438232142234e842 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 7 Jun 2016 14:56:29 +0200 Subject: [PATCH 01/26] Perobject stacks are no longer saved CURA-1278 --- cura/SettingOverrideDecorator.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cura/SettingOverrideDecorator.py b/cura/SettingOverrideDecorator.py index 04e77b0d3f..10a14007f3 100644 --- a/cura/SettingOverrideDecorator.py +++ b/cura/SettingOverrideDecorator.py @@ -15,6 +15,7 @@ class SettingOverrideDecorator(SceneNodeDecorator): def __init__(self): super().__init__() self._stack = ContainerStack(stack_id = id(self)) + self._stack.setDirty(False) # This stack does not need to be saved. self._instance = InstanceContainer(container_id = "SettingOverrideInstanceContainer") self._stack.addContainer(self._instance) From 5761307b336c5dcdea2c8d162a78d04f4ac39863 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 7 Jun 2016 15:45:51 +0200 Subject: [PATCH 02/26] Updated deepcopy to correctly copy the instance container CURA-1636 --- cura/SettingOverrideDecorator.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cura/SettingOverrideDecorator.py b/cura/SettingOverrideDecorator.py index 10a14007f3..f9878e436c 100644 --- a/cura/SettingOverrideDecorator.py +++ b/cura/SettingOverrideDecorator.py @@ -29,10 +29,10 @@ class SettingOverrideDecorator(SceneNodeDecorator): def __deepcopy__(self, memo): ## Create a fresh decorator object deep_copy = SettingOverrideDecorator() - ## Copy the stack - deep_copy._stack = copy.deepcopy(self._stack, memo) - ## Ensure that the id is unique. - deep_copy._stack._id = id(deep_copy) + ## Copy the instance + deep_copy._instance = copy.deepcopy(self._instance, memo) + ## Set the copied instance as the first (and only) instance container of the stack. + deep_copy._stack.replaceContainer(0, deep_copy._instance) return deep_copy def _onSettingChanged(self, instance, property): From 9a14a3e8b755bb9f85015670d0fb85bf2c90f50f Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 7 Jun 2016 15:46:37 +0200 Subject: [PATCH 03/26] Per object settings no longer watches "state" property CURA-1278 --- plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml index c89485517e..9565b0e345 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml @@ -120,7 +120,7 @@ Item { containerStackId: UM.ActiveTool.properties.getValue("ContainerID") key: model.key - watchedProperties: [ "value", "enabled", "state", "validationState" ] + watchedProperties: [ "value", "enabled", "validationState" ] storeIndex: 0 } } From b2782ced0a088274b2f483cc7502fc53abc70ab2 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 7 Jun 2016 15:56:59 +0200 Subject: [PATCH 04/26] Fix "renaming" profiles/machines to their current name without adding an increment CURA-1585 --- cura/MachineManagerModel.py | 66 ++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index c764296a68..7d8403afdd 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -9,6 +9,7 @@ from UM.Logger import Logger import UM.Settings from UM.Settings.Validator import ValidatorState from UM.Settings.InstanceContainer import InstanceContainer +from UM.Settings.ContainerStack import ContainerStack from . import ExtruderManager from UM.i18n import i18nCatalog catalog = i18nCatalog("cura") @@ -109,7 +110,7 @@ class MachineManagerModel(QObject): definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id=definition_id) if definitions: definition = definitions[0] - name = self._createUniqueName("machine", name, definition.getName()) + name = self._createUniqueName(containers[0], "machine", name, definition.getName()) new_global_stack = UM.Settings.ContainerStack(name) new_global_stack.addMetaDataEntry("type", "machine") @@ -139,31 +140,42 @@ class MachineManagerModel(QObject): Application.getInstance().setGlobalContainerStack(new_global_stack) - # Create a name that is not empty and unique - def _createUniqueName(self, object_type, name, fallback_name): - name = name.strip() - num_check = re.compile("(.*?)\s*#\d+$").match(name) - if(num_check): - name = num_check.group(1) - if name == "": - name = fallback_name - unique_name = name - i = 1 + ## Create a name that is not empty and unique + # \param container \type{} container to create a unique name for + # \param container_type \type{string} Type of the container (machine, quality, ...) + # \param new_name \type{string} Name base name, which may not be unique + # \param fallback_name \type{string} Name to use when (stripped) new_name is empty + # \return \type{string} Name that is unique for the specified type and name/id + def _createUniqueName(self, container, object_type, new_name, fallback_name): + new_name = new_name.strip() + num_check = re.compile("(.*?)\s*#\d+$").match(new_name) + if num_check: + new_name = num_check.group(1) + if new_name == "": + new_name = fallback_name - # Check both the id and the name, because they may not be the same and it is better if they are both unique - if object_type == "machine": - while UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = unique_name, type = "machine") or \ - UM.Settings.ContainerRegistry.getInstance().findContainerStacks(name = unique_name, type = "machine"): - i += 1 - unique_name = "%s #%d" % (name, i) - else: - while UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = unique_name, type = object_type) or \ - UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(name = unique_name, type = object_type): - i += 1 - unique_name = "%s #%d" % (name, i) + unique_name = new_name + i = 1 + while self._containerWithIdOrNameExists(unique_name, object_type, container): + i += 1 + unique_name = "%s #%d" % (new_name, i) return unique_name + ## Check if a container with of a certain type and a certain name or id exists + # Both the id and the name are checked, because they may not be the same and it is better if they are both unique + def _containerWithIdOrNameExists(self, id_or_name, container_type, exclude_container = None): + container_class = ContainerStack if container_type == "machine" else InstanceContainer + + containers = UM.Settings.ContainerRegistry.getInstance().findContainers(container_class, id = id_or_name, type = container_type) + if containers and containers[0] != exclude_container: + return True + containers = UM.Settings.ContainerRegistry.getInstance().findContainers(container_class, name = id_or_name, type = container_type) + if containers and containers[0] != exclude_container: + return True + + return False + ## Convenience function to check if a stack has errors. def _checkStackForErrors(self, stack): if stack is None: @@ -260,9 +272,9 @@ class MachineManagerModel(QObject): if not self._global_container_stack: return - name = self._createUniqueName("quality", self.activeQualityName, catalog.i18nc("@label", "Custom profile")) - user_settings = self._global_container_stack.getTop() new_quality_container = InstanceContainer("") + name = self._createUniqueName(new_quality_container, "quality", self.activeQualityName, catalog.i18nc("@label", "Custom profile")) + user_settings = self._global_container_stack.getTop() ## Copy all values new_quality_container.deserialize(user_settings.serialize()) @@ -290,7 +302,7 @@ class MachineManagerModel(QObject): return containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=container_id) if containers: - new_name = self._createUniqueName("quality", containers[0].getName(), catalog.i18nc("@label", "Custom profile")) + new_name = self._createUniqueName(containers[0], "quality", containers[0].getName(), catalog.i18nc("@label", "Custom profile")) new_container = InstanceContainer("") @@ -310,7 +322,7 @@ class MachineManagerModel(QObject): def renameQualityContainer(self, container_id, new_name): containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = container_id, type = "quality") if containers: - new_name = self._createUniqueName("machine", new_name, catalog.i18nc("@label", "Custom profile")) + new_name = self._createUniqueName(containers[0], "quality", new_name, catalog.i18nc("@label", "Custom profile")) containers[0].setName(new_name) UM.Settings.ContainerRegistry.getInstance().containerChanged.emit(containers[0]) @@ -413,7 +425,7 @@ class MachineManagerModel(QObject): def renameMachine(self, machine_id, new_name): containers = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = machine_id) if containers: - new_name = self._createUniqueName("machine", new_name, containers[0].getBottom().getName()) + new_name = self._createUniqueName(containers[0], "machine", new_name, containers[0].getBottom().getName()) containers[0].setName(new_name) self.globalContainerChanged.emit() From 44d9fefd5d622bc5a3edaeb553173627fb9705f4 Mon Sep 17 00:00:00 2001 From: Simon Edwards Date: Tue, 7 Jun 2016 16:11:44 +0200 Subject: [PATCH 05/26] Profile export from the Profiles window. Contributed to CURA-1667 Profile import/export --- resources/qml/Preferences/ProfilesPage.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 28248b23f4..ed9c20f65f 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -237,7 +237,7 @@ UM.ManagementPage folder: base.model.getDefaultPath() onAccepted: { - var result = base.model.exportProfile(base.currentItem.id, base.currentItem.name, fileUrl, selectedNameFilter) + var result = base.model.exportProfile(base.currentItem.id, fileUrl) if(result && result.status == "error") { messageDialog.icon = StandardIcon.Critical From cca432742b124f3103cad5fd8b52cf077a67050b Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 7 Jun 2016 17:01:08 +0200 Subject: [PATCH 06/26] Fix creating a name for a new MachineManagerModel CURA-1585 --- cura/MachineManagerModel.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 7d8403afdd..c0ac74abe4 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -110,9 +110,10 @@ class MachineManagerModel(QObject): definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id=definition_id) if definitions: definition = definitions[0] - name = self._createUniqueName(containers[0], "machine", name, definition.getName()) - new_global_stack = UM.Settings.ContainerStack(name) + name = self._createUniqueName(new_global_stack, "machine", name, definition.getName()) + new_global_stack._id = name + new_global_stack.setName(name) new_global_stack.addMetaDataEntry("type", "machine") UM.Settings.ContainerRegistry.getInstance().addContainer(new_global_stack) From e33eb52e936dab1cffa98e6568a41ca0dea3782a Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 7 Jun 2016 17:32:28 +0200 Subject: [PATCH 07/26] Hide Support Extruder in advanced mode when support is disabled CURA-1663 --- resources/definitions/fdmprinter.def.json | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index ec27abd9f5..79bdf4399a 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -2139,6 +2139,7 @@ "default_value": 0, "minimum_value": "0", "maximum_value": "machine_extruder_count - 1", + "enabled": "support_enable", "global_only": "True", "children": { "support_infill_extruder_nr": From 4d0bb217af1d7f35c75576e44b1b4e0d61967fb9 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 7 Jun 2016 18:13:19 +0200 Subject: [PATCH 08/26] Fix crash when enabling setting visibility for adhesion_extruder_nr or support_extruder_nr The fix is likely not what was intended by the author of the offending code (and does not seem to be functional), but at least it fixes the hard crash outlined in CURA-1666 --- cura/ExtrudersModel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py index eb63bc4257..7e00611742 100644 --- a/cura/ExtrudersModel.py +++ b/cura/ExtrudersModel.py @@ -46,7 +46,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): def _updateExtruders(self): self.clear() manager = cura.ExtruderManager.ExtruderManager.getInstance() - for index, extruder in enumerate(manager): + for index, extruder in enumerate(manager._extruder_trains): item = { #Construct an item with only the relevant information. "name": extruder.name, "colour": extruder.material.getMetaDataEntry("color_code", default = "#FFFF00"), From 21b1891c0ee72afa44a6d606fe40ff5a11bc8776 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 7 Jun 2016 18:55:27 +0200 Subject: [PATCH 09/26] Make unique name generation more robust and simpler CURA-1585 --- cura/MachineManagerModel.py | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index c0ac74abe4..202ca3611c 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -106,14 +106,12 @@ class MachineManagerModel(QObject): Application.getInstance().setGlobalContainerStack(containers[0]) @pyqtSlot(str, str) - def addMachine(self,name, definition_id): + def addMachine(self, name, definition_id): definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id=definition_id) if definitions: definition = definitions[0] + name = self._createUniqueName("machine", "", name, definition.getName()) new_global_stack = UM.Settings.ContainerStack(name) - name = self._createUniqueName(new_global_stack, "machine", name, definition.getName()) - new_global_stack._id = name - new_global_stack.setName(name) new_global_stack.addMetaDataEntry("type", "machine") UM.Settings.ContainerRegistry.getInstance().addContainer(new_global_stack) @@ -142,12 +140,12 @@ class MachineManagerModel(QObject): Application.getInstance().setGlobalContainerStack(new_global_stack) ## Create a name that is not empty and unique - # \param container \type{} container to create a unique name for # \param container_type \type{string} Type of the container (machine, quality, ...) - # \param new_name \type{string} Name base name, which may not be unique + # \param current_name \type{} Current name of the container, which may be an acceptable option + # \param new_name \type{string} Base name, which may not be unique # \param fallback_name \type{string} Name to use when (stripped) new_name is empty # \return \type{string} Name that is unique for the specified type and name/id - def _createUniqueName(self, container, object_type, new_name, fallback_name): + def _createUniqueName(self, container_type, current_name, new_name, fallback_name): new_name = new_name.strip() num_check = re.compile("(.*?)\s*#\d+$").match(new_name) if num_check: @@ -157,7 +155,8 @@ class MachineManagerModel(QObject): unique_name = new_name i = 1 - while self._containerWithIdOrNameExists(unique_name, object_type, container): + # In case we are renaming, the current name of the container is also a valid end-result + while self._containerExists(container_type, unique_name) and unique_name != current_name: i += 1 unique_name = "%s #%d" % (new_name, i) @@ -165,17 +164,13 @@ class MachineManagerModel(QObject): ## Check if a container with of a certain type and a certain name or id exists # Both the id and the name are checked, because they may not be the same and it is better if they are both unique - def _containerWithIdOrNameExists(self, id_or_name, container_type, exclude_container = None): + # \param container_type \type{string} Type of the container (machine, quality, ...) + # \param container_name \type{string} Name to check + def _containerExists(self, container_type, container_name): container_class = ContainerStack if container_type == "machine" else InstanceContainer - containers = UM.Settings.ContainerRegistry.getInstance().findContainers(container_class, id = id_or_name, type = container_type) - if containers and containers[0] != exclude_container: - return True - containers = UM.Settings.ContainerRegistry.getInstance().findContainers(container_class, name = id_or_name, type = container_type) - if containers and containers[0] != exclude_container: - return True - - return False + return UM.Settings.ContainerRegistry.getInstance().findContainers(container_class, id = container_name, type = container_type) or \ + UM.Settings.ContainerRegistry.getInstance().findContainers(container_class, name = container_name, type = container_type) ## Convenience function to check if a stack has errors. def _checkStackForErrors(self, stack): @@ -274,7 +269,7 @@ class MachineManagerModel(QObject): return new_quality_container = InstanceContainer("") - name = self._createUniqueName(new_quality_container, "quality", self.activeQualityName, catalog.i18nc("@label", "Custom profile")) + name = self._createUniqueName("quality", "", self.activeQualityName, catalog.i18nc("@label", "Custom profile")) user_settings = self._global_container_stack.getTop() ## Copy all values @@ -303,7 +298,7 @@ class MachineManagerModel(QObject): return containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=container_id) if containers: - new_name = self._createUniqueName(containers[0], "quality", containers[0].getName(), catalog.i18nc("@label", "Custom profile")) + new_name = self._createUniqueName("quality", "", containers[0].getName(), catalog.i18nc("@label", "Custom profile")) new_container = InstanceContainer("") @@ -323,7 +318,7 @@ class MachineManagerModel(QObject): def renameQualityContainer(self, container_id, new_name): containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = container_id, type = "quality") if containers: - new_name = self._createUniqueName(containers[0], "quality", new_name, catalog.i18nc("@label", "Custom profile")) + new_name = self._createUniqueName("quality", containers[0].getName(), new_name, catalog.i18nc("@label", "Custom profile")) containers[0].setName(new_name) UM.Settings.ContainerRegistry.getInstance().containerChanged.emit(containers[0]) @@ -426,7 +421,7 @@ class MachineManagerModel(QObject): def renameMachine(self, machine_id, new_name): containers = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = machine_id) if containers: - new_name = self._createUniqueName(containers[0], "machine", new_name, containers[0].getBottom().getName()) + new_name = self._createUniqueName("machine", containers[0].getName(), new_name, containers[0].getBottom().getName()) containers[0].setName(new_name) self.globalContainerChanged.emit() From f7480baca2c7f1648571fbf8bb9d1e9a892cddc1 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 7 Jun 2016 19:25:12 +0200 Subject: [PATCH 10/26] Fix selecting another quality when the currently active quality is removed CURA-1585 --- cura/MachineManagerModel.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 202ca3611c..5f3ca0b7af 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -335,11 +335,11 @@ class MachineManagerModel(QObject): UM.Settings.ContainerRegistry.getInstance().removeContainer(container_id) if activate_new_container: - old_container = self._global_container_stack.findInstanceContainers({"type": "quality"}) - containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = container_type) - if containers and old_container: - container_index = self._global_container_stack.getContainerIndex(old_container) - self._global_container_stack.replaceContainer(container_index, containers[0]) + definition_id = "fdmprinter" if not self.filterQualityByMachine else self.activeDefinitionId + containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "quality", definition = definition_id) + if containers: + self.setActiveQuality(containers[0].getId()) + self.activeQualityChanged.emit() @pyqtSlot() From b452af5dbf5997c92e47ea09a4366d7f876c538d Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 7 Jun 2016 19:31:35 +0200 Subject: [PATCH 11/26] Update Profile dropdown when renaming a quality profile CURA-1585 --- cura/MachineManagerModel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 5f3ca0b7af..02d8db8290 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -320,7 +320,7 @@ class MachineManagerModel(QObject): if containers: new_name = self._createUniqueName("quality", containers[0].getName(), new_name, catalog.i18nc("@label", "Custom profile")) containers[0].setName(new_name) - UM.Settings.ContainerRegistry.getInstance().containerChanged.emit(containers[0]) + self.activeQualityChanged.emit() @pyqtSlot(str) From ec2657947345c7b76f59bbec4ab0898b658c26cc Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 7 Jun 2016 14:59:32 +0200 Subject: [PATCH 12/26] Remove unused _repopulate function It is replaced by the addMachineExtruders function. Contributes to issues CURA-340 and CURA-1278. --- cura/ExtruderManager.py | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index df31cbacdf..23a72b2c3b 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -80,23 +80,6 @@ class ExtruderManager(QObject): if extruder_trains: self.extrudersChanged.emit() - ## (Re)populates the collections of extruders by machine. - def _repopulate(self): - self._extruder_trains = { } - if not UM.Application.getInstance().getGlobalContainerStack(): #No machine has been added yet. - self.extrudersChanged.emit() #Yes, we just cleared the _extruders list! - return #Then leave them empty! - - extruder_trains = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(type = "extruder_train") - for extruder_train in extruder_trains: - machine_id = extruder_train.getMetaDataEntry("machine") - if not machine_id: - continue - if machine_id not in self._extruder_trains: - self._extruder_trains[machine_id] = { } - self._extruder_trains[machine_id][extruder_train.getMetaDataEntry("position")] = extruder_train.getId() - self.extrudersChanged.emit() - def createExtruderTrain(self, extruder_definition, machine_definition, extruder_train_id, position): container_registry = UM.Settings.ContainerRegistry.getInstance() From f461ed0f5f62f2cbf556c32037298bb5c7052514 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 7 Jun 2016 15:26:51 +0200 Subject: [PATCH 13/26] Document singleton Contributes to issues CURA-340 and CURA-1278. --- cura/ExtruderManager.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 23a72b2c3b..b40bb0f664 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -39,7 +39,18 @@ class ExtruderManager(QObject): except KeyError: #Extruder index could be -1 if the global tab is selected, or the entry doesn't exist if the machine definition is wrong. return None + ## The instance of the singleton pattern. + # + # It's None if the extruder manager hasn't been created yet. __instance = None + + ## Gets an instance of the extruder manager, or creates one if no instance + # exists yet. + # + # This is an implementation of singleton. If an extruder manager already + # exists, it is re-used. + # + # \return The extruder manager. @classmethod def getInstance(cls): if not cls.__instance: From 98a0f90dae4764bfb77ca6feaf92412e7716aaf3 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 7 Jun 2016 16:56:55 +0200 Subject: [PATCH 14/26] Remove unused variable _active_extruder_index This index is managed by ExtruderManager. Contributes to issues CURA-340 and CURA-1278. --- cura/MachineManagerModel.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 02d8db8290..e7034412f5 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -36,8 +36,6 @@ class MachineManagerModel(QObject): active_machine_id = Preferences.getInstance().getValue("cura/active_machine") - self._active_extruder_index = 0 - if active_machine_id != "": # An active machine was saved, so restore it. self.setActiveMachine(active_machine_id) From 8b1c36393261608ade3257386d613cb72d5e32cd Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 7 Jun 2016 17:37:25 +0200 Subject: [PATCH 15/26] Load current machine's extruders upon creation, start and switch of machines This requires some trickery of initialising the extruder manager before the machine manager is initialised, so that it properly listens to global container stack changes. Contributes to issues CURA-340 and CURA-1278. --- cura/CuraApplication.py | 1 + cura/ExtruderManager.py | 29 ++++++++++++++++++++++++----- cura/ExtrudersModel.py | 11 ++++++++--- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 7edb0bf8bd..37ba6cf7ad 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -351,6 +351,7 @@ class CuraApplication(QtApplication): self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Loading interface...")) + ExtruderManager.ExtruderManager.getInstance() #Initialise extruder so as to listen to global container stack changes before the first global container stack is set. qmlRegisterSingletonType(MachineManagerModel.MachineManagerModel, "Cura", 1, 0, "MachineManager", MachineManagerModel.createMachineManagerModel) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index b40bb0f664..c71dd27414 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -1,7 +1,7 @@ # Copyright (c) 2016 Ultimaker B.V. # Cura is released under the terms of the AGPLv3 or higher. -from PyQt5.QtCore import pyqtSignal, pyqtProperty, pyqtSlot, QObject #For communicating data and events to Qt. +from PyQt5.QtCore import pyqtSignal, pyqtProperty, pyqtSlot, QObject, QVariant #For communicating data and events to Qt. import UM.Application #To get the global container stack to find the current machine. import UM.Logger @@ -13,7 +13,7 @@ import UM.Settings.ContainerRegistry #Finding containers by ID. # This keeps a list of extruder stacks for each machine. class ExtruderManager(QObject): ## Signal to notify other components when the list of extruders changes. - extrudersChanged = pyqtSignal() + extrudersChanged = pyqtSignal(QVariant) ## Notify when the user switches the currently active extruder. activeExtruderChanged = pyqtSignal() @@ -21,8 +21,9 @@ class ExtruderManager(QObject): ## Registers listeners and such to listen to changes to the extruders. def __init__(self, parent = None): super().__init__(parent) - self._extruder_trains = { } #Extruders for the current machine. + self._extruder_trains = { } #Per machine, a dictionary of extruder container stack IDs. self._active_extruder_index = 0 + UM.Application.getInstance().globalContainerStackChanged.connect(self._addCurrentMachineExtruders) ## Gets the unique identifier of the currently active extruder stack. # @@ -79,7 +80,7 @@ class ExtruderManager(QObject): for extruder_definition in container_registry.findDefinitionContainers(machine = machine_definition.getId()): position = extruder_definition.getMetaDataEntry("position", None) if not position: - UM.Logger.Log("w", "Extruder definition %s specifies no position metadata entry.", extruder_definition.getId()) + UM.Logger.log("w", "Extruder definition %s specifies no position metadata entry.", extruder_definition.getId()) if not container_registry.findContainerStacks(machine = machine_id, position = position): #Doesn't exist yet. name = container_registry.uniqueName(extruder_definition.getId()) #Make a name based on the ID of the definition. self.createExtruderTrain(extruder_definition, machine_definition, name, position) @@ -89,7 +90,7 @@ class ExtruderManager(QObject): for extruder_train in extruder_trains: self._extruder_trains[machine_id][extruder_train.getMetaDataEntry("position")] = extruder_train.getId() if extruder_trains: - self.extrudersChanged.emit() + self.extrudersChanged.emit(machine_definition) def createExtruderTrain(self, extruder_definition, machine_definition, extruder_train_id, position): container_registry = UM.Settings.ContainerRegistry.getInstance() @@ -156,3 +157,21 @@ class ExtruderManager(QObject): container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack()) container_registry.addContainer(container_stack) + + ## Generates extruders for a specific machine. + def getMachineExtruders(self, machine_definition): + container_registry = UM.Settings.ContainerRegistry.getInstance() + machine_id = machine_definition.getId() + if not machine_id in self._extruder_trains: + UM.Logger.log("w", "Tried to get the extruder trains for machine %s, which doesn't exist.", machine_id) + return + for extruder_train_id in self._extruder_trains[machine_id]: + extruder_train = container_registry.findContainerStacks(id = extruder_train_id) + if extruder_train: + yield extruder_train[0] + + ## Adds the extruders of the currently active machine. + def _addCurrentMachineExtruders(self): + global_stack = UM.Application.getInstance().getGlobalContainerStack() + if global_stack and global_stack.getBottom(): + self.addMachineExtruders(global_stack.getBottom()) \ No newline at end of file diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py index 7e00611742..691a5c7690 100644 --- a/cura/ExtrudersModel.py +++ b/cura/ExtrudersModel.py @@ -9,7 +9,8 @@ import UM.Qt.ListModel ## Model that holds extruders. # # This model is designed for use by any list of extruders, but specifically -# intended for drop-down lists of extruders in place of settings. +# intended for drop-down lists of the current machine's extruders in place of +# settings. class ExtrudersModel(UM.Qt.ListModel.ListModel): ## Human-readable name of the extruder. NameRole = Qt.UserRole + 1 @@ -37,7 +38,8 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): #Listen to changes. manager = cura.ExtruderManager.ExtruderManager.getInstance() - manager.extrudersChanged.connect(self._updateExtruders) + manager.extrudersChanged.connect(self._updateExtruders) #When the list of extruders changes in general. + UM.Application.globalContainerStackChanged.connect(self._updateExtruders) #When the current machine changes. self._updateExtruders() ## Update the list of extruders. @@ -46,7 +48,10 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): def _updateExtruders(self): self.clear() manager = cura.ExtruderManager.ExtruderManager.getInstance() - for index, extruder in enumerate(manager._extruder_trains): + global_container_stack = UM.Application.getInstance().getGlobalContainerStack() + if not global_container_stack: + return #There is no machine to get the extruders of. + for index, extruder in manager.getMachineExtruders(global_container_stack.getBottom()): item = { #Construct an item with only the relevant information. "name": extruder.name, "colour": extruder.material.getMetaDataEntry("color_code", default = "#FFFF00"), From 1a8fe6aa1fb7dd22034f02d61338d1e8d1faab04 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 8 Jun 2016 10:55:48 +0200 Subject: [PATCH 16/26] Fix customised settings indicator CURA-1585 --- resources/qml/ProfileSetup.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/ProfileSetup.qml b/resources/qml/ProfileSetup.qml index c6291c8c85..48d52c539a 100644 --- a/resources/qml/ProfileSetup.qml +++ b/resources/qml/ProfileSetup.qml @@ -143,7 +143,7 @@ Item{ UM.SimpleButton { id: customisedSettings - visible: UM.ActiveProfile.hasCustomisedValues + visible: Cura.MachineManager.hasUserSettings height: parent.height * 0.6 width: parent.height * 0.6 From 77431b01a3ddb88952c6d2283e420386cb92d19e Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 8 Jun 2016 11:02:04 +0200 Subject: [PATCH 17/26] Inherit button now has the same behaviour as 2.1 again CURA-1278 --- resources/qml/Settings/SettingItem.qml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/resources/qml/Settings/SettingItem.qml b/resources/qml/Settings/SettingItem.qml index e4edc267ef..eb8fabec28 100644 --- a/resources/qml/Settings/SettingItem.qml +++ b/resources/qml/Settings/SettingItem.qml @@ -24,7 +24,7 @@ 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 stackLevel: propertyProvider.stackLevel + property var stackLevel: propertyProvider.stackLevels[0] signal contextMenuRequested() signal showTooltip(string text); @@ -166,7 +166,15 @@ Item { onClicked: { focus = true; - propertyProvider.removeFromContainer(base.stackLevel) + // Get the deepest entry of this setting that we can find. TODO: This is a bit naive, in some cases + // there might be multiple profiles saying something about the same setting. There is no strategy + // how to handle this as of yet. + var last_entry = propertyProvider.stackLevels.slice(-1)[0] + // Put that entry into the "top" instance container. + // This ensures that the value in any of the deeper containers need not be removed, which is + // needed for the reset button (which deletes the top value) to correctly go back to profile + // defaults. + propertyProvider.setPropertyValue("value", propertyProvider.getPropertyValue("value", last_entry)) } backgroundColor: UM.Theme.getColor("setting_control"); From af484b03d80a5379c5eebd38b1a26f3e89a66cfd Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 8 Jun 2016 10:45:32 +0200 Subject: [PATCH 18/26] Fix typo in variable name --- plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml | 2 +- resources/qml/Settings/SettingItem.qml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml index 9565b0e345..667f842469 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml @@ -61,7 +61,7 @@ Item { onLoaded: { settingLoader.item.showRevertButton = false settingLoader.item.showInheritButton = false - settingLoader.item.doDepthIdentation = false + settingLoader.item.doDepthIndentation = false } sourceComponent: diff --git a/resources/qml/Settings/SettingItem.qml b/resources/qml/Settings/SettingItem.qml index eb8fabec28..4fa615134b 100644 --- a/resources/qml/Settings/SettingItem.qml +++ b/resources/qml/Settings/SettingItem.qml @@ -20,7 +20,7 @@ Item { property var showRevertButton: true property var showInheritButton: true - property var doDepthIdentation: true + property var doDepthIndentation: true // Create properties to put property provider stuff in (bindings break in qt 5.5.1 otherwise) property var state: propertyProvider.properties.state @@ -101,7 +101,7 @@ Item { id: label; anchors.left: parent.left; - anchors.leftMargin: doDepthIdentation ? (UM.Theme.getSize("section_icon_column").width + 5) + ((definition.depth - 1) * UM.Theme.getSize("setting_control_depth_margin").width) : 0 + anchors.leftMargin: doDepthIndentation ? (UM.Theme.getSize("section_icon_column").width + 5) + ((definition.depth - 1) * UM.Theme.getSize("setting_control_depth_margin").width) : 0 anchors.right: settingControls.left; anchors.verticalCenter: parent.verticalCenter From 4aa495f9efa8dba6120c129f193186502c6d802b Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 8 Jun 2016 10:56:51 +0200 Subject: [PATCH 19/26] Fix getting name and colour from extruder There used to be an extruder object from which we could ask these properties. But now we have a container stack in its place, so we need to get the properties in a slightly different way. Contributes to issues CURA-1278 and CURA-340. --- cura/ExtrudersModel.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py index 691a5c7690..cd85181787 100644 --- a/cura/ExtrudersModel.py +++ b/cura/ExtrudersModel.py @@ -53,8 +53,8 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): return #There is no machine to get the extruders of. for index, extruder in manager.getMachineExtruders(global_container_stack.getBottom()): item = { #Construct an item with only the relevant information. - "name": extruder.name, - "colour": extruder.material.getMetaDataEntry("color_code", default = "#FFFF00"), + "name": extruder.getName(), + "colour": extruder.findContainer(type = "material").getMetaDataEntry("color_code", default = "#FFFF00"), "index": index } self.appendItem(item) From 675a8c140e1bf22ed9c396298ff150d66f9d7e69 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 8 Jun 2016 11:00:50 +0200 Subject: [PATCH 20/26] Give default colour if there is no material Otherwise it would try to call getMetaDataEntry on None. Contributes to issues CURA-340 and CURA-1278. --- cura/ExtrudersModel.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py index cd85181787..a915a21506 100644 --- a/cura/ExtrudersModel.py +++ b/cura/ExtrudersModel.py @@ -52,9 +52,11 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): if not global_container_stack: return #There is no machine to get the extruders of. for index, extruder in manager.getMachineExtruders(global_container_stack.getBottom()): + material = extruder.findContainer(type = "material") + colour = material.getMetaDataEntry("color_code", default = "#FFFF00") if material else "#FFFF00" item = { #Construct an item with only the relevant information. "name": extruder.getName(), - "colour": extruder.findContainer(type = "material").getMetaDataEntry("color_code", default = "#FFFF00"), + "colour": colour, "index": index } self.appendItem(item) From 91797c3944c24e41b16883bb55f48d4294c046c1 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 8 Jun 2016 11:09:08 +0200 Subject: [PATCH 21/26] Log error if the machine refers to invalid extruder train ID This helped mostly for debugging but it should be a genuine warning. Contributes to issues CURA-1278 and CURA-340. --- cura/ExtruderManager.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index c71dd27414..3be0694440 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -169,6 +169,8 @@ class ExtruderManager(QObject): extruder_train = container_registry.findContainerStacks(id = extruder_train_id) if extruder_train: yield extruder_train[0] + else: + UM.Logger.log("w", "Machine %s refers to an extruder train with ID %s, which doesn't exist.", machine_id, extruder_train_id) ## Adds the extruders of the currently active machine. def _addCurrentMachineExtruders(self): From 21545af5c8eb425faee88caf1ca703ea8ea9ef1a Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 8 Jun 2016 11:10:41 +0200 Subject: [PATCH 22/26] Get only values from extruder trains dictionary Instead of getting the keys, which are labeled '0' and '1', we'd like to get the values, which are the extruder train IDs themselves. Contributes to issues CURA-340 and CURA-1278. --- cura/ExtruderManager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 3be0694440..8219066eca 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -165,7 +165,7 @@ class ExtruderManager(QObject): if not machine_id in self._extruder_trains: UM.Logger.log("w", "Tried to get the extruder trains for machine %s, which doesn't exist.", machine_id) return - for extruder_train_id in self._extruder_trains[machine_id]: + for _,extruder_train_id in self._extruder_trains[machine_id].items(): extruder_train = container_registry.findContainerStacks(id = extruder_train_id) if extruder_train: yield extruder_train[0] From 8c7b3a05b654e2eea12cf6a2a6525e6e97950bfc Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 8 Jun 2016 11:22:03 +0200 Subject: [PATCH 23/26] Enumerate again over the machine's extruders We needed to get the index, after all. Contributes to issues CURA-340 and CURA-1278. --- cura/ExtrudersModel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py index a915a21506..a95f9f8a99 100644 --- a/cura/ExtrudersModel.py +++ b/cura/ExtrudersModel.py @@ -51,7 +51,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): global_container_stack = UM.Application.getInstance().getGlobalContainerStack() if not global_container_stack: return #There is no machine to get the extruders of. - for index, extruder in manager.getMachineExtruders(global_container_stack.getBottom()): + for index, extruder in enumerate(manager.getMachineExtruders(global_container_stack.getBottom())): material = extruder.findContainer(type = "material") colour = material.getMetaDataEntry("color_code", default = "#FFFF00") if material else "#FFFF00" item = { #Construct an item with only the relevant information. From 8b75a230a0adad455787278683863bd70c63df41 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 8 Jun 2016 11:24:41 +0200 Subject: [PATCH 24/26] Fix findContainer call without kwargs It has no kwargs. This needs to be provided as dictionary. Contributes to issues CURA-340 and CURA-1278. --- cura/ExtrudersModel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py index a95f9f8a99..60bd60abab 100644 --- a/cura/ExtrudersModel.py +++ b/cura/ExtrudersModel.py @@ -52,7 +52,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): if not global_container_stack: return #There is no machine to get the extruders of. for index, extruder in enumerate(manager.getMachineExtruders(global_container_stack.getBottom())): - material = extruder.findContainer(type = "material") + material = extruder.findContainer({ "type": "material" }) colour = material.getMetaDataEntry("color_code", default = "#FFFF00") if material else "#FFFF00" item = { #Construct an item with only the relevant information. "name": extruder.getName(), From b53926b9de53abc85b2bd8a6345a34563c1acc9f Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Wed, 8 Jun 2016 13:29:36 +0200 Subject: [PATCH 25/26] Exclude machine_settings from the settings visible in the sidebar Contrivbutes to CURA-1645 --- 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 6261496c84..a6bb60f865 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -29,7 +29,8 @@ ScrollView model: UM.SettingDefinitionsModel { id: definitionsModel; containerId: Cura.MachineManager.activeDefinitionId - visibilityHandler: UM.SettingPreferenceVisibilityHandler {} + exclude: ["machine_settings"] + visibilityHandler: UM.SettingPreferenceVisibilityHandler { } } delegate: Loader From 2cedc69ed19c309f9c348a6ca597ba5b1761d22b Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Wed, 8 Jun 2016 13:46:30 +0200 Subject: [PATCH 26/26] Remove all special floating point handling code from SettingTextField Since we now always send setting values as string and the conversion from float to string already does the rounding, there is no need to also do it here. Contributes to CURA-1278 Contributes to CURA-389 --- resources/qml/Settings/SettingTextField.qml | 36 +-------------------- 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/resources/qml/Settings/SettingTextField.qml b/resources/qml/Settings/SettingTextField.qml index 2a1fb96330..bf6fc34c93 100644 --- a/resources/qml/Settings/SettingTextField.qml +++ b/resources/qml/Settings/SettingTextField.qml @@ -90,21 +90,11 @@ SettingItem Keys.onReleased: { -// text = text.replace(",", ".") // User convenience. We use dots for decimal values -// if(parseFloat(text) != base.parentValue) -// { -// base.valueChanged(parseFloat(text)); -// } - propertyProvider.setPropertyValue("value", text) } onEditingFinished: { -// if(parseFloat(text) != base.parentValue) -// { -// base.valueChanged(parseFloat(text)); -// } propertyProvider.setPropertyValue("value", text) } @@ -121,33 +111,9 @@ SettingItem { target: input property: "text" - value: control.format(propertyProvider.properties.value) + value: propertyProvider.properties.value when: !input.activeFocus } } - - //Rounds a floating point number to 4 decimals. This prevents floating - //point rounding errors. - // - //input: The number to round. - //decimals: The number of decimals (digits after the radix) to round to. - //return: The rounded number. - function roundFloat(input, decimals) - { - //First convert to fixed-point notation to round the number to 4 decimals and not introduce new floating point errors. - //Then convert to a string (is implicit). The fixed-point notation will be something like "3.200". - //Then remove any trailing zeroes and the radix. - return input.toFixed(decimals).replace(/\.?0*$/, ""); //Match on periods, if any ( \.? ), followed by any number of zeros ( 0* ), then the end of string ( $ ). - } - - //Formats a value for display in the text field. - // - //This correctly handles formatting of float values. - // - //input: The string value to format. - //return: The formatted string. - function format(inputValue) { - return parseFloat(inputValue) ? roundFloat(parseFloat(inputValue), 4) : inputValue //If it's a float, round to four decimals. - } } }