diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index d209b90909..7812024422 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -53,7 +53,7 @@ from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Settings.SettingFunction import SettingFunction from cura.Settings.MachineNameValidator import MachineNameValidator from cura.Settings.ProfilesModel import ProfilesModel -from cura.Settings.MaterialsModel import MaterialsModel +from cura.Settings.MaterialsModel import MaterialsModel, BrandMaterialsModel, GenericMaterialsModel from cura.Settings.QualityAndUserProfilesModel import QualityAndUserProfilesModel from cura.Settings.SettingInheritanceManager import SettingInheritanceManager from cura.Settings.UserProfilesModel import UserProfilesModel @@ -734,6 +734,10 @@ class CuraApplication(QtApplication): container_registry = ContainerRegistry.getInstance() self._variant_manager.initialize() + from cura.Machines.MaterialManager import MaterialManager + self._material_manager = MaterialManager(container_registry) + self._material_manager.initialize() + # Check if we should run as single instance or not self._setUpSingleInstanceServer() @@ -914,6 +918,10 @@ class CuraApplication(QtApplication): qmlRegisterType(ExtrudersModel, "Cura", 1, 0, "ExtrudersModel") qmlRegisterType(ContainerSettingsModel, "Cura", 1, 0, "ContainerSettingsModel") qmlRegisterSingletonType(ProfilesModel, "Cura", 1, 0, "ProfilesModel", ProfilesModel.createProfilesModel) + + qmlRegisterType(GenericMaterialsModel, "Cura", 1, 0, "GenericMaterialsModel") + qmlRegisterType(BrandMaterialsModel, "Cura", 1, 0, "BrandMaterialsModel") + qmlRegisterType(MaterialsModel, "Cura", 1, 0, "MaterialsModel") qmlRegisterType(QualityAndUserProfilesModel, "Cura", 1, 0, "QualityAndUserProfilesModel") qmlRegisterType(UserProfilesModel, "Cura", 1, 0, "UserProfilesModel") diff --git a/cura/Machines/MaterialManager.py b/cura/Machines/MaterialManager.py new file mode 100644 index 0000000000..596da50fb2 --- /dev/null +++ b/cura/Machines/MaterialManager.py @@ -0,0 +1,277 @@ +from typing import Optional + +from PyQt5.Qt import QTimer, QObject, pyqtSignal + +from UM.Logger import Logger +from UM.Settings import ContainerRegistry +from UM.Settings import InstanceContainer + +from cura.Machines.ContainerNode import ContainerNode + + +class MaterialGroup: + __slots__ = ("name", "root_material_node", "derived_material_node_list") + + def __init__(self, name: str): + self.name = name + self.root_material_node = None + self.derived_material_node_list = [] + + +class MaterialNode(ContainerNode): + __slots__ = ("material_map", "children_map") + + def __init__(self, metadata: Optional[dict] = None): + super().__init__(metadata = metadata) + self.material_map = {} + self.children_map = {} + + +class MaterialManager(QObject): + + materialsUpdated = pyqtSignal() # Emitted whenever the material lookup tables are updated. + + def __init__(self, container_registry, parent = None): + super().__init__(parent) + self._container_registry = container_registry # type: ContainerRegistry + + self._fallback_materials_map = dict() # material_type -> generic material metadata + self._material_group_map = dict() # root_material_id -> MaterialGroup + self._diameter_machine_variant_material_map = dict() # diameter -> dict(machine_definition_id -> MaterialNode) + + # The machine definition ID for the non-machine-specific materials. + # This is used as the last fallback option if the given machine-specific material(s) cannot be found. + self._default_machine_definition_id = "fdmprinter" + + self._update_timer = QTimer(self) + self._update_timer.setInterval(300) + self._update_timer.setSingleShot(True) + self._update_timer.timeout.connect(self._updateTables) + + self._container_registry.containerMetaDataChanged.connect(self._onContainerMetadataChanged) + self._container_registry.containerAdded.connect(self._onContainerMetadataChanged) + self._container_registry.containerRemoved.connect(self._onContainerMetadataChanged) + + def initialize(self): + # Find all materials and put them in a matrix for quick search. + material_metadata_list = self._container_registry.findContainersMetadata(type = "material") + + self._material_group_map = {} + self._diameter_machine_variant_material_map = {} + + # Table #1 + # root_material_id -> MaterialGroup + for material_metadata in material_metadata_list: + material_id = material_metadata["id"] + # We don't store empty material in the lookup tables + if material_id == "empty_material": + continue + + root_material_id = material_metadata.get("base_file") + if root_material_id not in self._material_group_map: + self._material_group_map[root_material_id] = MaterialGroup(root_material_id) + group = self._material_group_map[root_material_id] + + # We only add root materials here + if material_id == root_material_id: + group.root_material_node = MaterialNode(material_metadata) + else: + new_node = MaterialNode(material_metadata) + group.derived_material_node_list.append(new_node) + + # Table #2 + # Lookup table for material type -> fallback material metadata + grouped_by_type_dict = dict() + for root_material_id, material_node in self._material_group_map.items(): + material_type = material_node.root_material_node.metadata["material"] + if material_type not in grouped_by_type_dict: + grouped_by_type_dict[material_type] = {"generic": None, + "others": []} + brand = material_node.root_material_node.metadata["brand"] + if brand.lower() == "generic": + grouped_by_type_dict[material_type] = material_node.root_material_node.metadata + self._fallback_materials_map = grouped_by_type_dict + + # Table #3 + # "machine" -> "variant_name" -> "root material ID" -> specific material InstanceContainer + # Construct the "machine" -> "variant" -> "root material ID" -> specific material InstanceContainer + for material_metadata in material_metadata_list: + # We don't store empty material in the lookup tables + if material_metadata["id"] == "empty_material": + continue + + root_material_id = material_metadata["base_file"] + definition = material_metadata["definition"] + approximate_diameter = material_metadata["approximate_diameter"] + + if approximate_diameter not in self._diameter_machine_variant_material_map: + self._diameter_machine_variant_material_map[approximate_diameter] = {} + + machine_variant_material_map = self._diameter_machine_variant_material_map[approximate_diameter] + if definition not in machine_variant_material_map: + machine_variant_material_map[definition] = MaterialNode() + + machine_node = machine_variant_material_map[definition] + variant_name = material_metadata.get("variant_name") + if not variant_name: + # if there is no variant, this material is for the machine, so put its metadata in the machine node. + machine_node.material_map[root_material_id] = MaterialNode(material_metadata) + else: + # this material is variant-specific, so we save it in a variant-specific node under the + # machine-specific node + if variant_name not in machine_node.children_map: + machine_node.children_map[variant_name] = MaterialNode() + + variant_node = machine_node.children_map[variant_name] + if root_material_id not in variant_node.material_map: + variant_node.material_map[root_material_id] = MaterialNode(material_metadata) + else: + # Sanity check: make sure we don't have duplicated variant-specific materials for the same machine + raise RuntimeError("Found duplicate variant name [%s] for machine [%s] in material [%s]" % + (variant_name, definition, material_metadata["id"])) + + self.materialsUpdated.emit() + + def _updateTables(self): + self.initialize() + + def _onContainerMetadataChanged(self, container): + self._onContainerChanged(container) + + def _onContainerChanged(self, container): + container_type = container.getMetaDataEntry("type") + if container_type != "material": + return + + # TODO: update the cache table + self._update_timer.start() + + def getMaterialGroup(self, root_material_id: str) -> Optional[MaterialGroup]: + return self._material_group_map.get(root_material_id) + + def _test_metadata(self): + # print all metadata + import os + with open("c:/workspace/guid_map.txt", "w", encoding = "utf-8") as f: + for machine_id, node in self._guid_to_root_materials_map.items(): + f.write((" - %s -> %s" % (machine_id, node.metadata["id"])) + os.linesep) + + if False: + with open("c:/workspace/material_map.txt", "w", encoding = "utf-8") as f: + for machine_id in self._machine_variant_material_map: + f.write((" -> %s" % machine_id) + os.linesep) + + test_cases = [{"machine": "ultimaker3", "variant": "AA 0.4", "material": "generic_pla", "diameter": 2.85}, + {"machine": "ultimaker2_plus", "variant": None, "material": "generic_abs", "diameter": 2.85}, + {"machine": "fdmprinter", "variant": None, "material": "generic_cpe", "diameter": 2.85}, + {"machine": "fdmprinter", "variant": None, "material": "generic_abs_175", "diameter": 2.85}, + {"machine": "fdmprinter", "variant": None, "material": "generic_nylon", "diameter": 1.75}, + {"machine": "fdmprinter", "variant": None, "material": "generic_nylon_175", "diameter": 1.75}, + ] + for tc in test_cases: + result = self.getMaterialNode( + tc['machine'], + tc['variant'], + tc['diameter'], + tc['material']) + tc['result_id'] = result.getContainer().getId() if result else "None" + Logger.log("d", "!!!!!!!! MaterialManager test: %s", tc) + + # test available materials + with open("c:/workspace/test.txt", "w", encoding="utf-8") as f: + for tc in test_cases: + result = self.getAvailableMaterials(tc['machine'], + tc['variant'], + tc['diameter']) + f.write("--- [%s] [%s] [%s]:" % (tc['machine'], tc['variant'], tc['diameter']) + "\n") + for r, md in result.items(): + f.write(" - %s -> %s" % (r, md["id"]) + "\n") + + # + # Return a dict with all root material IDs (k) and ContainerNodes (v) that's suitable for the given setup. + # + def getAvailableMaterials(self, machine_definition_id: str, variant_name: Optional[str], diameter: float) -> dict: + # round the diameter to get the approximate diameter + rounded_diameter = str(round(diameter)) + if rounded_diameter not in self._diameter_machine_variant_material_map: + Logger.log("i", "Cannot find materials with diameter [%s] (rounded to [%s])", diameter, rounded_diameter) + return {} + + # If there are variant materials, get the variant material + machine_variant_material_map = self._diameter_machine_variant_material_map[rounded_diameter] + machine_node = machine_variant_material_map.get(machine_definition_id) + variant_node = None + if machine_node is None: + machine_node = machine_variant_material_map.get(self._default_machine_definition_id) + if variant_name is not None and machine_node is not None: + variant_node = machine_node.getChildNode(variant_name) + + # Fallback mechanism of finding materials: + # 1. variant-specific material + # 2. machine-specific material + # 3. generic material (for fdmprinter) + material_id_metadata_dict = {} + if variant_node is not None: + material_id_metadata_dict = {mid: node for mid, node in variant_node.material_map.items()} + + # Fallback: machine-specific materials, including "fdmprinter" + if not material_id_metadata_dict: + if machine_node is not None: + material_id_metadata_dict = {mid: node for mid, node in machine_node.material_map.items()} + + return material_id_metadata_dict + + # + # Gets MaterialNode for the given extruder and machine with the given material name. + # Returns None if: + # 1. the given machine doesn't have materials; + # 2. cannot find any material InstanceContainers with the given settings. + # + def getMaterial(self, machine_definition_id: str, variant_name: Optional[str], diameter: float, root_material_id: str) -> Optional["InstanceContainer"]: + # round the diameter to get the approximate diameter + rounded_diameter = str(round(diameter)) + if rounded_diameter not in self._diameter_machine_variant_material_map: + Logger.log("i", "Cannot find materials with diameter [%s] (rounded to [%s]) for root material id [%s]", + diameter, rounded_diameter, root_material_id) + return None + + # If there are variant materials, get the variant material + machine_variant_material_map = self._diameter_machine_variant_material_map[rounded_diameter] + machine_node = machine_variant_material_map.get(machine_definition_id) + variant_node = None + + # Fallback for "fdmprinter" if the machine-specific materials cannot be found + if machine_node is None: + machine_node = machine_variant_material_map.get(self._default_machine_definition_id) + if machine_node is not None and variant_name is not None: + variant_node = machine_node.getChildNode(variant_name) + + # Fallback mechanism of finding materials: + # 1. variant-specific material + # 2. machine-specific material + # 3. generic material (for fdmprinter) + material_node = None + if variant_node is not None: + if root_material_id in variant_node.material_map: + material_node = variant_node.material_map.get(root_material_id) + + # Fallback: machine-specific materials, including "fdmprinter" + if material_node is None: + if machine_node is not None: + material_node = machine_node.material_map.get(root_material_id) + + return material_node + + # + # Used by QualityManager. Built-in quality profiles may be based on generic material IDs such as "generic_pla". + # For materials such as ultimaker_pla_orange, no quality profiles may be found, so we should fall back to use + # the generic material IDs to search for qualities. + # + # This function returns the generic root material ID for the given material type, where material types are "PLA", + # "ABS", etc. + # + def getFallbackMaterialForType(self, material_type: str) -> dict: + # For safety + if material_type not in self._fallback_materials_map: + raise RuntimeError("Material type [%s] is not in the fallback materials table." % material_type) + return self._fallback_materials_map[material_type] diff --git a/cura/Settings/ContainerManager.py b/cura/Settings/ContainerManager.py index d2e8410dde..4c92eed845 100644 --- a/cura/Settings/ContainerManager.py +++ b/cura/Settings/ContainerManager.py @@ -766,22 +766,20 @@ class ContainerManager(QObject): # \return \type{str} the id of the newly created container. @pyqtSlot(str, result = str) def duplicateMaterial(self, material_id: str) -> str: - original = self._container_registry.findContainersMetadata(id = material_id) - if not original: + assert material_id + + from cura.CuraApplication import CuraApplication + material_manager = CuraApplication.getInstance()._material_manager + + material_group = material_manager.getMaterialGroup(material_id) + if not material_group: Logger.log("d", "Unable to duplicate the material with id %s, because it doesn't exist.", material_id) return "" - original = original[0] - base_container_id = original.get("base_file") - base_container = self._container_registry.findContainers(id = base_container_id) - if not base_container: - Logger.log("d", "Unable to duplicate the material with id {material_id}, because base_file {base_container_id} doesn't exist.".format(material_id = material_id, base_container_id = base_container_id)) - return "" - base_container = base_container[0] - - #We'll copy all containers with the same base. - #This way the correct variant and machine still gets assigned when loading the copy of the material. - containers_to_copy = self._container_registry.findInstanceContainers(base_file = base_container_id) + base_container = material_group.root_material_node.getContainer() + containers_to_copy = [] + for node in material_group.derived_material_node_list: + containers_to_copy.append(node.getContainer()) # Ensure all settings are saved. Application.getInstance().saveSettings() @@ -802,9 +800,9 @@ class ContainerManager(QObject): new_id = new_base_id if container_to_copy.getMetaDataEntry("definition") != "fdmprinter": new_id += "_" + container_to_copy.getMetaDataEntry("definition") - if container_to_copy.getMetaDataEntry("variant"): - variant = self._container_registry.findContainers(id = container_to_copy.getMetaDataEntry("variant"))[0] - new_id += "_" + variant.getName().replace(" ", "_") + if container_to_copy.getMetaDataEntry("variant_name"): + variant_name = container_to_copy.getMetaDataEntry("variant_name") + new_id += "_" + variant_name.replace(" ", "_") if current_id == material_id: clone_of_original = new_id @@ -826,13 +824,7 @@ class ContainerManager(QObject): # check if the given material has a base file (i.e. was shipped by default) base_file = self.getContainerMetaDataEntry(material_id, "base_file") - - if base_file == "": - # there is no base file, so duplicate by ID - return self.duplicateMaterial(material_id) - else: - # there is a base file, so duplicate the original material - return self.duplicateMaterial(base_file) + return self.duplicateMaterial(base_file) ## Create a new material by cloning Generic PLA for the current material diameter and setting the GUID to something unqiue # diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 719f90bdd1..1fa4a602bc 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -1237,6 +1237,14 @@ class MachineManager(QObject): return self.getQualityVariantId(self._global_container_stack.definition, variant) return "" + @pyqtProperty(str, notify = activeVariantChanged) + def activeQualityVariantName(self) -> str: + if self._active_container_stack: + variant = self._active_container_stack.variant + if variant.getId() != "empty_variant": + return variant.getName() + return "" + ## Get the Variant ID to use to select quality profiles for variants of the specified definitions # This is normally the id of the variant itself, but machines can specify a different definition # to inherit qualities from, which has consequences for the variant to use as well diff --git a/cura/Settings/MaterialsModel.py b/cura/Settings/MaterialsModel.py index c4b0329336..ad3256ba32 100644 --- a/cura/Settings/MaterialsModel.py +++ b/cura/Settings/MaterialsModel.py @@ -2,10 +2,189 @@ # Cura is released under the terms of the LGPLv3 or higher. from typing import Any, List +from PyQt5.QtCore import Qt + + +from UM.Logger import Logger +from UM.Qt.ListModel import ListModel from UM.Settings.ContainerRegistry import ContainerRegistry #To listen for changes to the materials. from UM.Settings.Models.InstanceContainersModel import InstanceContainersModel #We're extending this class. -## A model that shows a list of currently valid materials. + +def getAvailableMaterials(): + from cura.CuraApplication import CuraApplication + machine_manager = CuraApplication.getInstance().getMachineManager() + extruder_manager = CuraApplication.getInstance().getExtruderManager() + + material_manager = CuraApplication.getInstance()._material_manager + + active_global_stack = machine_manager._global_container_stack + active_extruder_stack = extruder_manager.getActiveExtruderStack() + + if active_global_stack is None or active_extruder_stack is None: + Logger.log("d", "Active global stack [%s] or extruder stack [%s] is None, setting material list to empty.", + active_global_stack, active_extruder_stack) + return + + machine_definition_id = active_global_stack.definition.getId() + variant_name = None + if active_extruder_stack.variant.getId() != "empty_variant": + variant_name = active_extruder_stack.variant.getName() + diameter = active_extruder_stack.getProperty("material_diameter", "value") + + # Fetch the available materials (ContainerNode) for the current active machine and extruder setup. + result_dict = material_manager.getAvailableMaterials(machine_definition_id, variant_name, diameter) + return result_dict + + +class BaseMaterialsModel(ListModel): + RootMaterialIdRole = Qt.UserRole + 1 + IdRole = Qt.UserRole + 2 + NameRole = Qt.UserRole + 3 + BrandRole = Qt.UserRole + 4 + MaterialRole = Qt.UserRole + 5 + ColorRole = Qt.UserRole + 6 + ContainerNodeRole = Qt.UserRole + 6 + + def __init__(self, parent = None): + super().__init__(parent) + + self.addRoleName(self.RootMaterialIdRole, "root_material_id") + self.addRoleName(self.IdRole, "id") + self.addRoleName(self.NameRole, "name") + self.addRoleName(self.BrandRole, "brand") + self.addRoleName(self.MaterialRole, "material") + self.addRoleName(self.ColorRole, "color_name") + self.addRoleName(self.ContainerNodeRole, "container_node") + + +class GenericMaterialsModel(BaseMaterialsModel): + + def __init__(self, parent = None): + super().__init__(parent) + + from cura.CuraApplication import CuraApplication + machine_manager = CuraApplication.getInstance().getMachineManager() + extruder_manager = CuraApplication.getInstance().getExtruderManager() + material_manager = CuraApplication.getInstance()._material_manager + + machine_manager.globalContainerChanged.connect(self._update) + extruder_manager.activeExtruderChanged.connect(self._update) + material_manager.materialsUpdated.connect(self._update) + + def _update(self): + item_list = [] + result_dict = getAvailableMaterials() + if result_dict is None: + self.setItems([]) + return + + for root_material_id, container_node in result_dict.items(): + metadata = container_node.metadata + # Only add results for generic materials + if metadata["brand"].lower() != "generic": + continue + + item = {"root_material_id": root_material_id, + "id": metadata["id"], + "name": metadata["name"], + "brand": metadata["brand"], + "material": metadata["material"], + "color_name": metadata["color_name"], + "container_node": container_node + } + item_list.append(item) + + # Sort the item list by material name alphabetically + item_list = sorted(item_list, key = lambda d: d["name"]) + + self.setItems(item_list) + + +class MaterialsModelGroupedByType(ListModel): + NameRole = Qt.UserRole + 1 + ColorsRole = Qt.UserRole + 2 + + def __init__(self, parent = None): + super().__init__(parent) + + self.addRoleName(self.NameRole, "name") + self.addRoleName(self.ColorsRole, "colors") + + +## Brand --> Material Type -> list of materials +class BrandMaterialsModel(ListModel): + NameRole = Qt.UserRole + 1 + MaterialsRole = Qt.UserRole + 2 + + def __init__(self, parent = None): + super().__init__(parent) + + self.addRoleName(self.NameRole, "name") + self.addRoleName(self.MaterialsRole, "materials") + + from cura.CuraApplication import CuraApplication + machine_manager = CuraApplication.getInstance().getMachineManager() + extruder_manager = CuraApplication.getInstance().getExtruderManager() + material_manager = CuraApplication.getInstance()._material_manager + + machine_manager.globalContainerChanged.connect(self._update) + extruder_manager.activeExtruderChanged.connect(self._update) + material_manager.materialsUpdated.connect(self._update) + + def _update(self): + brand_item_list = [] + result_dict = getAvailableMaterials() + if result_dict is None: + self.setItems([]) + return + + brand_group_dict = {} + for root_material_id, container_node in result_dict.items(): + metadata = container_node.metadata + brand = metadata["brand"] + # Only add results for generic materials + if brand.lower() == "generic": + continue + + if brand not in brand_group_dict: + brand_group_dict[brand] = {} + + material_type = metadata["material"] + if material_type not in brand_group_dict[brand]: + brand_group_dict[brand][material_type] = [] + + item = {"root_material_id": root_material_id, + "id": metadata["id"], + "name": metadata["name"], + "brand": metadata["brand"], + "material": metadata["material"], + "color_name": metadata["color_name"], + "container_node": container_node + } + brand_group_dict[brand][material_type].append(item) + + for brand, material_dict in brand_group_dict.items(): + brand_item = {"name": brand, + "materials": MaterialsModelGroupedByType(self)} # TODO + + material_type_item_list = [] + for material_type, material_list in material_dict.items(): + material_type_item = {"name": material_type, + "colors": BaseMaterialsModel(self)} + material_type_item["colors"].clear() + material_type_item["colors"].setItems(material_list) + + material_type_item_list.append(material_type_item) + + brand_item["materials"].setItems(material_type_item_list) + + brand_item_list.append(brand_item) + + self.setItems(brand_item_list) + + +## A model that shows a list of currently valid materials. Used by management page. class MaterialsModel(InstanceContainersModel): def __init__(self, parent = None): super().__init__(parent) diff --git a/resources/qml/Menus/MaterialMenu.qml b/resources/qml/Menus/MaterialMenu.qml index 3d04649f11..111e5ab6af 100644 --- a/resources/qml/Menus/MaterialMenu.qml +++ b/resources/qml/Menus/MaterialMenu.qml @@ -1,8 +1,8 @@ // Copyright (c) 2018 Ultimaker B.V. // Cura is released under the terms of the LGPLv3 or higher. -import QtQuick 2.2 -import QtQuick.Controls 1.1 +import QtQuick 2.8 +import QtQuick.Controls 1.4 import UM 1.2 as UM import Cura 1.0 as Cura @@ -29,16 +29,6 @@ Menu return true; } - UM.SettingPropertyProvider - { - id: materialDiameterProvider - - containerStackId: Cura.ExtruderManager.activeExtruderStackId - key: "material_diameter" - watchedProperties: [ "value" ] - storeIndex: 5 - } - MenuItem { id: automaticMaterial @@ -83,12 +73,16 @@ Menu exclusiveGroup: group onTriggered: { + + const container_id = model.id; // This workaround is done because of the application menus for materials and variants for multiextrusion printers. // The extruder menu would always act on the correspoding extruder only, instead of acting on the extruder selected in the UI. + var activeExtruderIndex = Cura.ExtruderManager.activeExtruderIndex; - Cura.ExtruderManager.setActiveExtruderIndex(extruderIndex); - Cura.MachineManager.setActiveMaterial(model.id); - Cura.ExtruderManager.setActiveExtruderIndex(activeExtruderIndex); + //Cura.ExtruderManager.setActiveExtruderIndex(extruderIndex); + //Cura.MachineManager.setActiveMaterial(container_id); + //Cura.ExtruderManager.setActiveExtruderIndex(activeExtruderIndex); + Cura.MachineManager.setMaterial(activeExtruderIndex, model.container_node); } } onObjectAdded: menu.insertItem(index, object) @@ -126,11 +120,12 @@ Menu exclusiveGroup: group onTriggered: { + const container_id = model.id; // This workaround is done because of the application menus for materials and variants for multiextrusion printers. // The extruder menu would always act on the correspoding extruder only, instead of acting on the extruder selected in the UI. var activeExtruderIndex = Cura.ExtruderManager.activeExtruderIndex; Cura.ExtruderManager.setActiveExtruderIndex(extruderIndex); - Cura.MachineManager.setActiveMaterial(model.id); + Cura.MachineManager.setActiveMaterial(container_id); Cura.ExtruderManager.setActiveExtruderIndex(activeExtruderIndex); } } @@ -146,105 +141,20 @@ Menu onObjectRemoved: menu.removeItem(object) } - ListModel + Cura.GenericMaterialsModel { id: genericMaterialsModel - Component.onCompleted: populateMenuModels() + //Component.onCompleted: populateMenuModels() } - ListModel + Cura.BrandMaterialsModel { id: brandModel } - //: Model used to populate the brandModel - Cura.MaterialsModel - { - id: materialsModel - filter: materialFilter() - onModelReset: populateMenuModels() - onDataChanged: populateMenuModels() - } - ExclusiveGroup { id: group } MenuSeparator { } MenuItem { action: Cura.Actions.manageMaterials } - - function materialFilter() - { - var result = { "type": "material", "approximate_diameter": Math.round(materialDiameterProvider.properties.value).toString() }; - if(Cura.MachineManager.filterMaterialsByMachine) - { - result.definition = Cura.MachineManager.activeQualityDefinitionId; - if(Cura.MachineManager.hasVariants) - { - result.variant = Cura.MachineManager.activeQualityVariantId; - } - } - else - { - result.definition = "fdmprinter"; - result.compatible = true; //NB: Only checks for compatibility in global version of material, but we don't have machine-specific materials anyway. - } - return result; - } - - function populateMenuModels() - { - // Create a structure of unique brands and their material-types - genericMaterialsModel.clear() - brandModel.clear(); - - var items = materialsModel.items; - var materialsByBrand = {}; - for (var i in items) { - var brandName = items[i]["metadata"]["brand"]; - var materialName = items[i]["metadata"]["material"]; - - if (brandName == "Generic") - { - // Add to top section - var materialId = items[i].id; - genericMaterialsModel.append({ - id: materialId, - name: items[i].name - }); - } - else - { - // Add to per-brand, per-material menu - if (!materialsByBrand.hasOwnProperty(brandName)) - { - materialsByBrand[brandName] = {}; - } - if (!materialsByBrand[brandName].hasOwnProperty(materialName)) - { - materialsByBrand[brandName][materialName] = []; - } - materialsByBrand[brandName][materialName].push({ - id: items[i].id, - name: items[i].name - }); - } - } - - for (var brand in materialsByBrand) - { - var materialsByBrandModel = []; - var materials = materialsByBrand[brand]; - for (var material in materials) - { - materialsByBrandModel.push({ - name: material, - colors: materials[material] - }) - } - brandModel.append({ - name: brand, - materials: materialsByBrandModel - }); - } - } } diff --git a/resources/qml/Preferences/MaterialsPage.qml b/resources/qml/Preferences/MaterialsPage.qml index 22814683ad..3a72f66cfc 100644 --- a/resources/qml/Preferences/MaterialsPage.qml +++ b/resources/qml/Preferences/MaterialsPage.qml @@ -30,7 +30,7 @@ UM.ManagementPage result.definition = Cura.MachineManager.activeQualityDefinitionId; if(Cura.MachineManager.hasVariants) { - result.variant = Cura.MachineManager.activeQualityVariantId; + result.variant_name = Cura.MachineManager.activeQualityVariantName; } } else