Browse Source

Merge branch 'master' of https://github.com/Ultimaker/Cura

Tim Kuipers 8 years ago
parent
commit
482bc21a9f

+ 1 - 0
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)
 

+ 37 - 22
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.
     #
@@ -39,7 +40,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:
@@ -68,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)
@@ -78,24 +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()
-
-    ##  (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()
+            self.extrudersChanged.emit(machine_definition)
 
     def createExtruderTrain(self, extruder_definition, machine_definition, extruder_train_id, position):
         container_registry = UM.Settings.ContainerRegistry.getInstance()
@@ -162,3 +157,23 @@ 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].items():
+            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):
+        global_stack = UM.Application.getInstance().getGlobalContainerStack()
+        if global_stack and global_stack.getBottom():
+            self.addMachineExtruders(global_stack.getBottom())

+ 12 - 5
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,10 +48,15 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
     def _updateExtruders(self):
         self.clear()
         manager = cura.ExtruderManager.ExtruderManager.getInstance()
-        for index, extruder in enumerate(manager):
+        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 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.
-                "name": extruder.name,
-                "colour": extruder.material.getMetaDataEntry("color_code", default = "#FFFF00"),
+                "name": extruder.getName(),
+                "colour": colour,
                 "index": index
             }
             self.appendItem(item)

+ 43 - 37
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")
@@ -35,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)
@@ -105,12 +104,11 @@ 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())
-
+            name = self._createUniqueName("machine", "", name, definition.getName())
             new_global_stack = UM.Settings.ContainerStack(name)
             new_global_stack.addMetaDataEntry("type", "machine")
             UM.Settings.ContainerRegistry.getInstance().addContainer(new_global_stack)
@@ -139,31 +137,39 @@ 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
+    ##  Create a name that is not empty and unique
+    #   \param container_type \type{string} Type of the container (machine, quality, ...)
+    #   \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_type, current_name, 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
+
+        unique_name = new_name
         i = 1
-
-        # 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)
+        # 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)
 
         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
+    #   \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
+
+        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):
         if stack is None:
@@ -260,9 +266,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("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 +296,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("quality", "", containers[0].getName(), catalog.i18nc("@label", "Custom profile"))
 
             new_container = InstanceContainer("")
 
@@ -310,9 +316,9 @@ 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("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)
@@ -327,11 +333,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()
@@ -413,7 +419,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("machine", containers[0].getName(), new_name, containers[0].getBottom().getName())
             containers[0].setName(new_name)
             self.globalContainerChanged.emit()
 

+ 5 - 4
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)
 
@@ -28,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):

+ 2 - 2
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:
@@ -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
                 }
             }

+ 1 - 0
resources/definitions/fdmprinter.def.json

@@ -2138,6 +2138,7 @@
                     "default_value": 0,
                     "minimum_value": "0",
                     "maximum_value": "machine_extruder_count - 1",
+                    "enabled": "support_enable",
                     "global_only": "True",
                     "children": {
                         "support_infill_extruder_nr":

+ 1 - 1
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

+ 1 - 1
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
 

+ 12 - 4
resources/qml/Settings/SettingItem.qml

@@ -20,11 +20,11 @@ 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
-    property var stackLevel: propertyProvider.stackLevel
+    property var stackLevel: propertyProvider.stackLevels[0]
 
     signal contextMenuRequested()
     signal showTooltip(string text);
@@ -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
 
@@ -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");

Some files were not shown because too many files changed in this diff