From b9f2d498b4ddfc0d02f36b8d109180abf90a42a7 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 11:25:38 +0200 Subject: [PATCH 01/12] Fix typo in documentation --- 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 9dabbaee98..6a11136966 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -48,7 +48,7 @@ ScrollView //Qt5.4.2 and earlier has a bug where this causes a crash: https://bugreports.qt.io/browse/QTBUG-35989 //In addition, while it works for 5.5 and higher, the ordering of the actual combo box drop down changes, - //causing nasty issues when selecting differnt options. So disable asynchronous loading of enum type completely. + //causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely. asynchronous: model.type != "enum" active: model.type != undefined From 1f9805a73c0b7cdfba3b57405062703e0e6b9d97 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 11:43:02 +0200 Subject: [PATCH 02/12] Remove unused imports These are unused because the code was moved to Extruder.py Contributes to issues CURA-1278 and CURA-351. --- cura/ExtruderManager.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 71b636ad6f..60d452ae73 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -1,12 +1,9 @@ # Copyright (c) 2016 Ultimaker B.V. # Cura is released under the terms of the AGPLv3 or higher. -import re - from cura.Extruder import Extruder #The individual extruders managed by this manager. from UM.Application import Application #To get the global container stack to find the current machine. from UM.Logger import Logger -from UM.Settings.ContainerStack import ContainerStack #To create container stacks for each extruder. from UM.Settings.ContainerRegistry import ContainerRegistry #Finding containers by ID. From 06f7f90bb08c5a5dea6e216a670cf05d112125a9 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 12:04:19 +0200 Subject: [PATCH 03/12] Make ExtruderManager into a singleton This way we don't need to load it in CuraApplication but we can just load it whenever it is first needed. ExtruderManager should be robust against initialising it at any point in Cura's runtime. Contributes to issues CURA-1278 and CURA-351. --- cura/CuraApplication.py | 2 -- cura/ExtruderManager.py | 13 +++++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 49fcbbf405..b8cef52d0c 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -327,8 +327,6 @@ class CuraApplication(QtApplication): qmlRegisterSingletonType(MachineManagerModel.MachineManagerModel, "Cura", 1, 0, "MachineManager", MachineManagerModel.createMachineManagerModel) - self._extruder_manager = ExtruderManager.ExtruderManager() - self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml")) self._qml_import_paths.append(Resources.getPath(self.ResourceTypes.QmlFiles)) self.initializeEngine() diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 60d452ae73..34dbfd7c0c 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -13,6 +13,9 @@ from UM.Settings.ContainerRegistry import ContainerRegistry #Finding containers # and makes sure that whenever the machine is swapped, this list is kept up to # date. It also contains and updates the setting stacks for the extruders. class ExtruderManager: + ## The singleton instance of this manager. + __instance = None + ## Registers listeners and such to listen to changes to the extruders. def __init__(self): self._extruders = [] #Extruders for the current machine. @@ -20,6 +23,16 @@ class ExtruderManager: Application.getInstance().globalContainerStackChanged.connect(self._reconnectExtruderReload) #When the current machine changes, we need to reload all extruders belonging to the new machine. + ## Gets an instance of this extruder manager. + # + # If an instance was already created, the old instance is returned. This + # implements the singleton pattern. + @classmethod + def getInstance(cls): + if not cls.__instance: + cls.__instance = ExtruderManager() + return cls.__instance + ## When the global container stack changes, this reconnects to the new # signal for containers changing. def _reconnectExtruderReload(self): From 8a8b0016ba314fbf7167710f24cf139beb0ce8ce Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 12:55:01 +0200 Subject: [PATCH 04/12] Add signal for when extruder list changes The ExtrudersModel will need to listen to this. Contributes to issues CURA-1278 and CURA-351. --- cura/ExtruderManager.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 34dbfd7c0c..3477a3175f 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -5,6 +5,7 @@ from cura.Extruder import Extruder #The individual extruders managed by this man from UM.Application import Application #To get the global container stack to find the current machine. from UM.Logger import Logger from UM.Settings.ContainerRegistry import ContainerRegistry #Finding containers by ID. +import UM.Signal #To notify other components of changes in the extruders. ## Class that handles the current extruder stack. @@ -16,6 +17,9 @@ class ExtruderManager: ## The singleton instance of this manager. __instance = None + ## Signal to notify other components when the list of extruders changes. + extrudersChanged = UM.Signal() + ## Registers listeners and such to listen to changes to the extruders. def __init__(self): self._extruders = [] #Extruders for the current machine. @@ -49,6 +53,7 @@ class ExtruderManager: def _reloadExtruders(self): self._extruders = [] if not self._global_container_stack: #No machine has been added yet. + self.extrudersChanged.emit() #Yes, we just cleared the _extruders list! return #Then leave them empty! #Get the extruder definitions belonging to the current machine. @@ -60,4 +65,5 @@ class ExtruderManager: Logger.log("w", "Machine definition %s refers to an extruder train \"%s\", but no such extruder was found.", machine.getId(), extruder_train_id) continue for extruder_definition in extruder_definitions: - self._extruders.append(Extruder(extruder_definition)) \ No newline at end of file + self._extruders.append(Extruder(extruder_definition)) + self.extrudersChanged.emit() \ No newline at end of file From 83693162369851aff7f287de64095066205edcd3 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 12:56:55 +0200 Subject: [PATCH 05/12] Use modern import method This is more robust to cyclic dependencies, and also the intended way of importing these classes in Python in general. Contributes to issues CURA-1278 and CURA-351. --- cura/ExtruderManager.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 3477a3175f..51faa0a5e2 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -2,9 +2,9 @@ # Cura is released under the terms of the AGPLv3 or higher. from cura.Extruder import Extruder #The individual extruders managed by this manager. -from UM.Application import Application #To get the global container stack to find the current machine. -from UM.Logger import Logger -from UM.Settings.ContainerRegistry import ContainerRegistry #Finding containers by ID. +import UM.Application #To get the global container stack to find the current machine. +import UM.Logger +import UM.Settings.ContainerRegistry #Finding containers by ID. import UM.Signal #To notify other components of changes in the extruders. @@ -25,7 +25,7 @@ class ExtruderManager: self._extruders = [] #Extruders for the current machine. self._global_container_stack = None - Application.getInstance().globalContainerStackChanged.connect(self._reconnectExtruderReload) #When the current machine changes, we need to reload all extruders belonging to the new machine. + UM.Application.getInstance().globalContainerStackChanged.connect(self._reconnectExtruderReload) #When the current machine changes, we need to reload all extruders belonging to the new machine. ## Gets an instance of this extruder manager. # @@ -42,7 +42,7 @@ class ExtruderManager: def _reconnectExtruderReload(self): if self._global_container_stack: self._global_container_stack.containersChanged.disconnect(self._reloadExtruders) #Disconnect from the old global container stack. - self._global_container_stack = Application.getInstance().getGlobalContainerStack() + self._global_container_stack = UM.Application.getInstance().getGlobalContainerStack() self._global_container_stack.containersChanged.connect(self._reloadExtruders) #When the current machine changes, we need to reload all extruders belonging to the new machine. ## (Re)loads all extruders of the currently active machine. @@ -60,9 +60,9 @@ class ExtruderManager: machine = self._global_container_stack.getBottom() extruder_train_ids = machine.getMetaData("machine_extruder_trains") for extruder_train_id in extruder_train_ids: - extruder_definitions = ContainerRegistry.getInstance().findDefinitionContainers(id = extruder_train_id) #Should be only 1 definition if IDs are unique, but add the whole list anyway. + extruder_definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id = extruder_train_id) #Should be only 1 definition if IDs are unique, but add the whole list anyway. if not extruder_definitions: #Empty list or error. - Logger.log("w", "Machine definition %s refers to an extruder train \"%s\", but no such extruder was found.", machine.getId(), extruder_train_id) + UM.Logger.log("w", "Machine definition %s refers to an extruder train \"%s\", but no such extruder was found.", machine.getId(), extruder_train_id) continue for extruder_definition in extruder_definitions: self._extruders.append(Extruder(extruder_definition)) From 8a8de959692e4ea65135166de3ad4c2bba84d585 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 13:11:02 +0200 Subject: [PATCH 06/12] Add iteration over extruder manager This iteration iterates over the extruders. Contributes to issues CURA-1278 and CURA-351. --- cura/ExtruderManager.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 51faa0a5e2..3c1e50d9bd 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -24,6 +24,7 @@ class ExtruderManager: def __init__(self): self._extruders = [] #Extruders for the current machine. self._global_container_stack = None + self._next_item = 0 #For when you use this class as iterator. UM.Application.getInstance().globalContainerStackChanged.connect(self._reconnectExtruderReload) #When the current machine changes, we need to reload all extruders belonging to the new machine. @@ -37,6 +38,12 @@ class ExtruderManager: cls.__instance = ExtruderManager() return cls.__instance + ## Creates an iterator over the extruders in this manager. + # + # \return An iterator over the extruders in this manager. + def __iter__(self): + return iter(self._extruders) + ## When the global container stack changes, this reconnects to the new # signal for containers changing. def _reconnectExtruderReload(self): From 25a6a992869e7f84511e838211f951e17df2ab61 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 13:15:33 +0200 Subject: [PATCH 07/12] Make name of extruder a property This stores the name for later use, for instance when displaying the extruder. Contributes to issues CURA-1278 and CURA-351. --- cura/Extruder.py | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/cura/Extruder.py b/cura/Extruder.py index 5be05c713c..cff5f3e6d0 100644 --- a/cura/Extruder.py +++ b/cura/Extruder.py @@ -25,8 +25,8 @@ class Extruder: self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = self._definition.getId()) #Create a container stack for this extruder. - name = self._uniqueName(self._definition.getId()) - self._container_stack = UM.Settings.ContainerStack(name) + self._name = self._uniqueName(self._definition.getId()) + self._container_stack = UM.Settings.ContainerStack(self._name) self._container_stack.addMetaDataEntry("type", "extruder_train") self._container_stack.addContainer(self._definition) @@ -73,15 +73,16 @@ class Extruder: self._container_stack.addContainer(self._quality) #Add an empty user profile. - self._user_profile = UM.Settings.InstanceContainer(name + "_current_settings") + self._user_profile = UM.Settings.InstanceContainer(self._name + "_current_settings") self._user_profile.addMetaDataEntry("type", "user") self._container_stack.addContainer(self._user_profile) self._container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack()) - nozzle_changed = UM.Signal.Signal() - material_changed = UM.Signal.Signal() - quality_changed = UM.Signal.Signal() + material_changed = UM.Signal() + name_changed = UM.Signal() + nozzle_changed = UM.Signal() + quality_changed = UM.Signal() ## Gets the currently active material on this extruder. # @@ -104,6 +105,19 @@ class Extruder: self._material = value self.material_changed.emit() + ## Gets the name of this extruder. + # + # \return The name of this extruder. + @property + def name(self): + return self._name + + ## Changes the name of this extruder. + @name.setter + def name(self, value): + self._name = value + self.name_changed.emit() + ## Gets the currently active nozzle on this extruder. # # \return The currently active nozzle on this extruder. From df363a024a7a9e3c31ee9dfbc629da180e71b40d Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 13:24:53 +0200 Subject: [PATCH 08/12] Expose definition container of extruders This contains important metadata which we'll need. It's also more consistent with the rest. Contributes to issues CURA-1278 and CURA-351. --- cura/Extruder.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/cura/Extruder.py b/cura/Extruder.py index cff5f3e6d0..9f2a8ab493 100644 --- a/cura/Extruder.py +++ b/cura/Extruder.py @@ -79,11 +79,33 @@ class Extruder: self._container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack()) + definition_changed = UM.Signal() material_changed = UM.Signal() name_changed = UM.Signal() nozzle_changed = UM.Signal() quality_changed = UM.Signal() + ## Gets the definition container of this extruder. + # + # \return The definition container of this extruder. + @property + def definition(self): + return self._definition + + ## Changes the definition container of this extruder. + # + # \param value The new definition for this extruder. + @definition.setter + def definition(self, value): + try: + position = self._container_stack.index(self._definition) + except ValueError: #Definition is not in the list. Big trouble! + UM.Logger.log("e", "I've lost my old extruder definition, so I can't find where to insert the new definition.") + return + self._container_stack.replaceContainer(position, value) + self._definition = value + self.definition_changed.emit() + ## Gets the currently active material on this extruder. # # \return The currently active material on this extruder. From e16fedf2d8640146fa4059b28a1a0fea51b2e68e Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 13:27:11 +0200 Subject: [PATCH 09/12] Changing name of extruder also changes name in container stack This name may be used to get a unique human-readable name. Just for consistency really. Contributes to issues CURA-1278 and CURA-351. --- cura/Extruder.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cura/Extruder.py b/cura/Extruder.py index 9f2a8ab493..4bbe24183d 100644 --- a/cura/Extruder.py +++ b/cura/Extruder.py @@ -135,9 +135,12 @@ class Extruder: return self._name ## Changes the name of this extruder. + # + # \param value The new name for this extruder. @name.setter def name(self, value): self._name = value + self._container_stack.setName(value) #Also update in container stack, being defensive. self.name_changed.emit() ## Gets the currently active nozzle on this extruder. From c24f4be8ae3403223141d991d29fe4ca085c8d3f Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 13:42:02 +0200 Subject: [PATCH 10/12] Add extruders model Hasn't been tested much because there is no display for this in the front-end yet. It needs a setting data type to go with in order to display it. This model is for the drop-down boxes to select an extruder to print, for instance, the support with. Contributes to issues CURA-1278 and CURA-351. --- cura/ExtrudersModel.py | 55 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 cura/ExtrudersModel.py diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py new file mode 100644 index 0000000000..08f349c1ff --- /dev/null +++ b/cura/ExtrudersModel.py @@ -0,0 +1,55 @@ +# Copyright (c) 2016 Ultimaker B.V. +# Cura is released under the terms of the AGPLv3 or higher. + +from PyQt5.QtCore import Qt + +import cura.ExtruderManager +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. +class ExtrudersModel(UM.Qt.ListModel): + ## Human-readable name of the extruder. + NameRole = Qt.UserRole + 1 + + ## Colour of the material loaded in the extruder. + ColourRole = Qt.UserRole + 2 + + ## Index of the extruder, which is also the value of the setting itself. + # + # An index of 0 indicates the first extruder, an index of 1 the second + # one, and so on. This is the value that will be saved in instance + # containers. + IndexRole = Qt.UserRole + 3 + + ## Initialises the extruders model, defining the roles and listening for + # changes in the data. + # + # \param parent Parent QtObject of this list. + def __init__(self, parent = None): + super().__init__(parent) + + self.addRoleName(self.NameRole, "name") + self.addRoleName(self.ColourRole, "colour") + self.addRoleName(self.IndexRole, "index") + + #Listen to changes. + manager = cura.ExtruderManager.ExtruderManager.getInstance() + manager.extrudersChanged.connect(self._updateExtruders()) + + ## Update the list of extruders. + # + # This should be called whenever the list of extruders changes. + def _updateExtruders(self): + self.clear() + manager = cura.ExtruderManager.ExtruderManager.getInstance() + for index, extruder in enumerate(manager): + item = { #Construct an item with only the relevant information. + "name": extruder.name, + "colour": extruder.material.getMetaDataEntry("color_code", default = "#FFFF00"), + "index": index + } + self.appendItem(item) + self.sort(lambda item: item["index"]) \ No newline at end of file From f18eeba793e148088f9d34fad2455fbb126fa374 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 14:02:44 +0200 Subject: [PATCH 11/12] Add extruder setting type This is a new data type. It behaves and saves just like an integer, but it's actually just an index of the extruder to use. Contributes to issues CURA-1278 and CURA-351. --- cura/CuraApplication.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index b8cef52d0c..a5357b10d7 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -18,6 +18,7 @@ from UM.JobQueue import JobQueue from UM.SaveFile import SaveFile from UM.Scene.Selection import Selection from UM.Scene.GroupDecorator import GroupDecorator +import UM.Settings.Validator from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation @@ -89,6 +90,7 @@ class CuraApplication(QtApplication): # Need to do this before ContainerRegistry tries to load the machines SettingDefinition.addSupportedProperty("global_only", DefinitionPropertyType.Function, default = False) + SettingDefinition.addSettingType("extruder", int, str, UM.Settings.Validator) super().__init__(name = "cura", version = CuraVersion) From 45d01bf37186c065f73eb16ce793cfb2c43cb619 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 14:03:33 +0200 Subject: [PATCH 12/12] Remove unused import This was no longer needed since ExtruderManager is now a singleton. It's no longer in CuraApplication. Contributes to issues CURA-1278 and CURA-351. --- cura/CuraApplication.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index a5357b10d7..3c3415aefe 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -31,7 +31,6 @@ from UM.Settings.ContainerRegistry import ContainerRegistry from UM.i18n import i18nCatalog -from . import ExtruderManager from . import PlatformPhysics from . import BuildVolume from . import CameraAnimation