Просмотр исходного кода

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

Remco Burema 5 лет назад
Родитель
Сommit
c333e980dc

+ 7 - 0
cura/CuraApplication.py

@@ -85,6 +85,7 @@ from cura.Machines.Models.FirstStartMachineActionsModel import FirstStartMachine
 from cura.Machines.Models.GenericMaterialsModel import GenericMaterialsModel
 from cura.Machines.Models.GlobalStacksModel import GlobalStacksModel
 from cura.Machines.Models.MaterialBrandsModel import MaterialBrandsModel
+from cura.Machines.Models.MaterialManagementModel import MaterialManagementModel
 from cura.Machines.Models.MultiBuildPlateModel import MultiBuildPlateModel
 from cura.Machines.Models.NozzleModel import NozzleModel
 from cura.Machines.Models.QualityManagementModel import QualityManagementModel
@@ -221,6 +222,7 @@ class CuraApplication(QtApplication):
         self._machine_error_checker = None
 
         self._machine_settings_manager = MachineSettingsManager(self, parent = self)
+        self._material_management_model = MaterialManagementModel()
 
         self._discovered_printer_model = DiscoveredPrintersModel(self, parent = self)
         self._first_start_machine_actions_model = FirstStartMachineActionsModel(self, parent = self)
@@ -975,6 +977,10 @@ class CuraApplication(QtApplication):
     def getMachineActionManager(self, *args):
         return self._machine_action_manager
 
+    @pyqtSlot(result = QObject)
+    def getMaterialManagementModel(self):
+        return self._material_management_model
+
     def getSimpleModeSettingsManager(self, *args):
         if self._simple_mode_settings_manager is None:
             self._simple_mode_settings_manager = SimpleModeSettingsManager()
@@ -1054,6 +1060,7 @@ class CuraApplication(QtApplication):
         qmlRegisterType(GenericMaterialsModel, "Cura", 1, 0, "GenericMaterialsModel")
         qmlRegisterType(MaterialBrandsModel, "Cura", 1, 0, "MaterialBrandsModel")
         qmlRegisterType(QualityManagementModel, "Cura", 1, 0, "QualityManagementModel")
+        qmlRegisterSingletonType(MaterialManagementModel, "Cura", 1, 5, "MaterialManagementModel", self.getMaterialManagementModel)
 
         qmlRegisterType(DiscoveredPrintersModel, "Cura", 1, 0, "DiscoveredPrintersModel")
 

+ 5 - 7
cura/Machines/MaterialManager.py

@@ -1,5 +1,6 @@
 # Copyright (c) 2019 Ultimaker B.V.
 # Cura is released under the terms of the LGPLv3 or higher.
+
 from collections import defaultdict
 import copy
 import uuid
@@ -7,19 +8,16 @@ from typing import Dict, Optional, TYPE_CHECKING, Any, List, cast
 
 from PyQt5.Qt import QTimer, QObject, pyqtSignal, pyqtSlot
 
-from UM.ConfigurationErrorMessage import ConfigurationErrorMessage
 from UM.Decorators import deprecated
 from UM.Logger import Logger
 from UM.Settings.ContainerRegistry import ContainerRegistry
-from UM.Settings.SettingFunction import SettingFunction
 from UM.Util import parseBool
-import cura.CuraApplication #Imported like this to prevent circular imports.
+import cura.CuraApplication  # Imported like this to prevent circular imports.
 from cura.Machines.ContainerTree import ContainerTree
 from cura.Settings.CuraContainerRegistry import CuraContainerRegistry
 
 from .MaterialNode import MaterialNode
 from .MaterialGroup import MaterialGroup
-from .VariantType import VariantType
 
 if TYPE_CHECKING:
     from UM.Settings.DefinitionContainer import DefinitionContainer
@@ -248,7 +246,7 @@ class MaterialManager(QObject):
 
     def removeMaterialByRootId(self, root_material_id: str):
         container_registry = CuraContainerRegistry.getInstance()
-        results = container_registry.findContainers(id=root_material_id)
+        results = container_registry.findContainers(id = root_material_id)
         if not results:
             container_registry.addWrongContainerId(root_material_id)
 
@@ -260,8 +258,8 @@ class MaterialManager(QObject):
         # Check if the material is active in any extruder train. In that case, the material shouldn't be removed!
         # In the future we might enable this again, but right now, it's causing a ton of issues if we do (since it
         # corrupts the configuration)
-        root_material_id = material_node.container.getMetaDataEntry("base_file")
-        ids_to_remove = [metadata.get("id", "") for metadata in CuraContainerRegistry.getInstance().findInstanceContainersMetadata(base_file=root_material_id)]
+        root_material_id = material_node.base_file
+        ids_to_remove = {metadata.get("id", "") for metadata in CuraContainerRegistry.getInstance().findInstanceContainersMetadata(base_file = root_material_id)}
 
         for extruder_stack in CuraContainerRegistry.getInstance().findContainerStacks(type = "extruder_train"):
             if extruder_stack.material.getId() in ids_to_remove:

+ 5 - 4
cura/Machines/Models/BaseMaterialsModel.py

@@ -31,8 +31,13 @@ class BaseMaterialsModel(ListModel):
         self._container_registry = self._application.getInstance().getContainerRegistry()
         self._machine_manager = self._application.getMachineManager()
 
+        self._extruder_position = 0
+        self._extruder_stack = None
+        self._enabled = True
+
         # Update the stack and the model data when the machine changes
         self._machine_manager.globalContainerChanged.connect(self._updateExtruderStack)
+        self._updateExtruderStack()
 
         # Update this model when switching machines, when adding materials or changing their metadata.
         self._machine_manager.activeStackChanged.connect(self._update)
@@ -55,12 +60,8 @@ class BaseMaterialsModel(ListModel):
         self.addRoleName(Qt.UserRole + 15, "container_node")
         self.addRoleName(Qt.UserRole + 16, "is_favorite")
 
-        self._extruder_position = 0
-        self._extruder_stack = None
-
         self._available_materials = None  # type: Optional[Dict[str, MaterialNode]]
         self._favorite_ids = set()  # type: Set[str]
-        self._enabled = True
 
     def _updateExtruderStack(self):
         global_stack = self._machine_manager.activeMachine

+ 65 - 0
cura/Machines/Models/MaterialManagementModel.py

@@ -0,0 +1,65 @@
+# Copyright (c) 2019 Ultimaker B.V.
+# Cura is released under the terms of the LGPLv3 or higher.
+
+from PyQt5.QtCore import QObject, pyqtSlot  # To allow the preference page proxy to be used from the actual preferences page.
+from typing import TYPE_CHECKING
+
+from UM.Logger import Logger
+
+from cura.Settings.CuraContainerRegistry import CuraContainerRegistry  # To find the sets of materials belonging to each other, and currently loaded extruder stacks.
+
+if TYPE_CHECKING:
+    from cura.Machines.MaterialNode import MaterialNode
+
+##  Proxy class to the materials page in the preferences.
+#
+#   This class handles the actions in that page, such as creating new materials,
+#   renaming them, etc.
+class MaterialManagementModel(QObject):
+    ##  Can a certain material be deleted, or is it still in use in one of the
+    #   container stacks anywhere?
+    #
+    #   We forbid the user from deleting a material if it's in use in any stack.
+    #   Deleting it while it's in use can lead to corrupted stacks. In the
+    #   future we might enable this functionality again (deleting the material
+    #   from those stacks) but for now it is easier to prevent the user from
+    #   doing this.
+    #   \param material_node The ContainerTree node of the material to check.
+    #   \return Whether or not the material can be removed.
+    @pyqtSlot("QVariant", result = bool)
+    def canMaterialBeRemoved(self, material_node: "MaterialNode"):
+        container_registry = CuraContainerRegistry.getInstance()
+        ids_to_remove = {metadata.get("id", "") for metadata in container_registry.findInstanceContainersMetadata(base_file = material_node.base_file)}
+        for extruder_stack in container_registry.findContainerStacks(type = "extruder_train"):
+            if extruder_stack.material.getId() in ids_to_remove:
+                return False
+        return True
+
+    ##  Change the user-visible name of a material.
+    #   \param material_node The ContainerTree node of the material to rename.
+    #   \param name The new name for the material.
+    @pyqtSlot("QVariant", str)
+    def setMaterialName(self, material_node: "MaterialNode", name: str) -> None:
+        container_registry = CuraContainerRegistry.getInstance()
+        root_material_id = material_node.base_file
+        if container_registry.isReadOnly(root_material_id):
+            Logger.log("w", "Cannot set name of read-only container %s.", root_material_id)
+            return
+        return container_registry.findContainers(id = root_material_id)[0].setName(name)
+
+    ##  Deletes a material from Cura.
+    #
+    #   This function does not do any safety checking any more. Please call this
+    #   function only if:
+    #   - The material is not read-only.
+    #   - The material is not used in any stacks.
+    #   If the material was not lazy-loaded yet, this will fully load the
+    #   container. When removing this material node, all other materials with
+    #   the same base fill will also be removed.
+    #   \param material_node The material to remove.
+    @pyqtSlot("QVariant")
+    def removeMaterial(self, material_node: "MaterialNode") -> None:
+        container_registry = CuraContainerRegistry.getInstance()
+        materials_this_base_file = container_registry.findContainersMetadata(base_file = material_node.base_file)
+        for material_metadata in materials_this_base_file:
+            container_registry.removeContainer(material_metadata["id"])

+ 9 - 14
plugins/XmlMaterialProfile/XmlMaterialProfile.py

@@ -223,10 +223,10 @@ class XmlMaterialProfile(InstanceContainer):
             for instance in self.findInstances():
                 self._addSettingElement(builder, instance)
 
-        machine_container_map = {} # type: Dict[str, InstanceContainer]
-        machine_variant_map = {} # type: Dict[str, Dict[str, Any]]
+        machine_container_map = {}  # type: Dict[str, InstanceContainer]
+        machine_variant_map = {}  # type: Dict[str, Dict[str, Any]]
 
-        variant_manager = CuraApplication.getInstance().getVariantManager()
+        container_tree = ContainerTree.getInstance()
 
         root_material_id = self.getMetaDataEntry("base_file")  # if basefile is self.getId, this is a basefile.
         all_containers = registry.findInstanceContainers(base_file = root_material_id)
@@ -243,16 +243,12 @@ class XmlMaterialProfile(InstanceContainer):
                 machine_variant_map[definition_id] = {}
 
             variant_name = container.getMetaDataEntry("variant_name")
-            if variant_name:
-                variant_node = variant_manager.getVariantNode(definition_id, variant_name)
-                if variant_node is None:
-                    continue
-                variant_dict = {"variant_node":variant_node ,
-                                "material_container": container}
-                machine_variant_map[definition_id][variant_name] = variant_dict
-                continue
+            if not variant_name:
+                machine_container_map[definition_id] = container
 
-            machine_container_map[definition_id] = container
+            variant_dict = {"variant_type": container.getMetaDataEntry("hardware_type", str(VariantType.NOZZLE)),
+                            "material_container": container}
+            machine_variant_map[definition_id][variant_name] = variant_dict
 
         # Map machine human-readable names to IDs
         product_id_map = self.getProductIdMap()
@@ -285,8 +281,7 @@ class XmlMaterialProfile(InstanceContainer):
             # Find all hotend sub-profiles corresponding to this material and machine and add them to this profile.
             buildplate_dict = {} # type: Dict[str, Any]
             for variant_name, variant_dict in machine_variant_map[definition_id].items():
-                variant_type = variant_dict["variant_node"].getMetaDataEntry("hardware_type", str(VariantType.NOZZLE))
-                variant_type = VariantType(variant_type)
+                variant_type = VariantType(variant_dict["variant_type"])
                 if variant_type == VariantType.NOZZLE:
                     # The hotend identifier is not the containers name, but its "name".
                     builder.start("hotend", {"id": variant_name})

+ 4 - 3
resources/qml/Preferences/Materials/MaterialsPage.qml

@@ -7,7 +7,7 @@ import QtQuick.Layouts 1.3
 import QtQuick.Dialogs 1.2
 
 import UM 1.2 as UM
-import Cura 1.0 as Cura
+import Cura 1.5 as Cura
 
 Item
 {
@@ -18,6 +18,7 @@ Item
     property var currentItem: null
 
     property var materialManager: CuraApplication.getMaterialManager()
+    property var materialManagementModel: CuraApplication.getMaterialManagementModel()
 
     property var hasCurrentItem: base.currentItem != null
     property var isCurrentItemActivated:
@@ -147,7 +148,7 @@ Item
             id: removeMenuButton
             text: catalog.i18nc("@action:button", "Remove")
             iconName: "list-remove"
-            enabled: base.hasCurrentItem && !base.currentItem.is_read_only && !base.isCurrentItemActivated && base.materialManager.canMaterialBeRemoved(base.currentItem.container_node)
+            enabled: base.hasCurrentItem && !base.currentItem.is_read_only && !base.isCurrentItemActivated && base.materialManagementModel.canMaterialBeRemoved(base.currentItem.container_node)
 
             onClicked:
             {
@@ -297,7 +298,7 @@ Item
         {
             // Set the active material as the fallback. It will be selected when the current material is deleted
             base.newRootMaterialIdToSwitchTo = base.active_root_material_id
-            base.materialManager.removeMaterial(base.currentItem.container_node);
+            base.materialManagementModel.removeMaterial(base.currentItem.container_node);
         }
     }
 

+ 2 - 1
resources/qml/Preferences/Materials/MaterialsView.qml

@@ -23,6 +23,7 @@ TabView
     property real secondColumnWidth: (width * 0.40) | 0
     property string containerId: ""
     property var materialPreferenceValues: UM.Preferences.getValue("cura/material_settings") ? JSON.parse(UM.Preferences.getValue("cura/material_settings")) : {}
+    property var materialManagementModel: CuraApplication.getMaterialManagementModel()
 
     property double spoolLength: calculateSpoolLength()
     property real costPerMeter: calculateCostPerMeter()
@@ -565,7 +566,7 @@ TabView
         }
 
         // update the values
-        CuraApplication.getMaterialManager().setMaterialName(base.currentMaterialNode, new_name)
+        base.materialManagementModel.setMaterialName(base.currentMaterialNode, new_name)
         properties.name = new_name
     }