From 8b84db705943217072003bec7d97439506a91eb0 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Fri, 26 Aug 2022 10:45:45 +0200 Subject: [PATCH 1/3] Remove AbstractMachine Having a separate class for the AbstractMachine complicated things; it's behaviour was extremely similar to the GlobalStack so adding one more stack container type in addition to the many similar setting container types we already have adds complexity to the system. Having these different classes for machines and abstract machines also add complexity to the update script as the abstract machines were stored in a separate folder from the machine types. Because of these reasons we decided to replace the AbstractMachine by a GlobalStack where the is_abstract_machine property metadata property is set to True. CURA-9514, CURA-9277 Co-authored-by: joeydelarago --- cura/CuraApplication.py | 5 -- cura/Machines/Models/MachineListModel.py | 17 +++--- cura/Settings/AbstractMachine.py | 52 ------------------- cura/Settings/CuraStackBuilder.py | 10 ++-- cura/Settings/GlobalStack.py | 30 +++++++++-- .../qml/PrinterSelector/MachineListButton.qml | 8 +-- 6 files changed, 44 insertions(+), 78 deletions(-) delete mode 100644 cura/Settings/AbstractMachine.py diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 3cd0ecbf97..f690456913 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -146,8 +146,6 @@ class CuraApplication(QtApplication): DefinitionChangesContainer = Resources.UserType + 10 SettingVisibilityPreset = Resources.UserType + 11 IntentInstanceContainer = Resources.UserType + 12 - AbstractMachineStack = Resources.UserType + 13 - pyqtEnum(ResourceTypes) @@ -426,7 +424,6 @@ class CuraApplication(QtApplication): Resources.addStorageType(self.ResourceTypes.DefinitionChangesContainer, "definition_changes") Resources.addStorageType(self.ResourceTypes.SettingVisibilityPreset, "setting_visibility") Resources.addStorageType(self.ResourceTypes.IntentInstanceContainer, "intent") - Resources.addStorageType(self.ResourceTypes.AbstractMachineStack, "abstract_machine_instances") self._container_registry.addResourceType(self.ResourceTypes.QualityInstanceContainer, "quality") self._container_registry.addResourceType(self.ResourceTypes.QualityChangesInstanceContainer, "quality_changes") @@ -437,7 +434,6 @@ class CuraApplication(QtApplication): self._container_registry.addResourceType(self.ResourceTypes.MachineStack, "machine") self._container_registry.addResourceType(self.ResourceTypes.DefinitionChangesContainer, "definition_changes") self._container_registry.addResourceType(self.ResourceTypes.IntentInstanceContainer, "intent") - self._container_registry.addResourceType(self.ResourceTypes.AbstractMachineStack, "abstract_machine") Resources.addType(self.ResourceTypes.QmlFiles, "qml") Resources.addType(self.ResourceTypes.Firmware, "firmware") @@ -486,7 +482,6 @@ class CuraApplication(QtApplication): ("variant", InstanceContainer.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.VariantInstanceContainer, "application/x-uranium-instancecontainer"), ("setting_visibility", SettingVisibilityPresetsModel.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.SettingVisibilityPreset, "application/x-uranium-preferences"), ("machine", 2): (Resources.DefinitionContainers, "application/x-uranium-definitioncontainer"), - ("abstract_machine", 1): (Resources.DefinitionContainers, "application/x-uranium-definitioncontainer"), ("extruder", 2): (Resources.DefinitionContainers, "application/x-uranium-definitioncontainer") } ) diff --git a/cura/Machines/Models/MachineListModel.py b/cura/Machines/Models/MachineListModel.py index f3781cfd60..4b80410018 100644 --- a/cura/Machines/Models/MachineListModel.py +++ b/cura/Machines/Models/MachineListModel.py @@ -8,9 +8,8 @@ from UM.Settings.ContainerStack import ContainerStack from UM.i18n import i18nCatalog from UM.Util import parseBool -from cura.Settings.AbstractMachine import AbstractMachine from cura.Settings.CuraContainerRegistry import CuraContainerRegistry -from cura.Settings.GlobalStack import GlobalStack +from cura.Settings.GlobalStack import GlobalStack, getMachinesWithDefinition class MachineListModel(ListModel): @@ -19,8 +18,8 @@ class MachineListModel(ListModel): HasRemoteConnectionRole = Qt.ItemDataRole.UserRole + 3 MetaDataRole = Qt.ItemDataRole.UserRole + 4 IsOnlineRole = Qt.ItemDataRole.UserRole + 5 - MachineTypeRole = Qt.ItemDataRole.UserRole + 6 - MachineCountRole = Qt.ItemDataRole.UserRole + 7 + MachineCountRole = Qt.ItemDataRole.UserRole + 6 + IsAbstractMachine = Qt.ItemDataRole.UserRole + 7 def __init__(self, parent=None) -> None: super().__init__(parent) @@ -32,8 +31,8 @@ class MachineListModel(ListModel): self.addRoleName(self.HasRemoteConnectionRole, "hasRemoteConnection") self.addRoleName(self.MetaDataRole, "metadata") self.addRoleName(self.IsOnlineRole, "isOnline") - self.addRoleName(self.MachineTypeRole, "machineType") self.addRoleName(self.MachineCountRole, "machineCount") + self.addRoleName(self.IsAbstractMachine, "isAbstractMachine") self._change_timer = QTimer() self._change_timer.setInterval(200) @@ -61,14 +60,16 @@ class MachineListModel(ListModel): other_machine_stacks = CuraContainerRegistry.getInstance().findContainerStacks(type="machine") - abstract_machine_stacks = CuraContainerRegistry.getInstance().findContainerStacks(type = "abstract_machine") + abstract_machine_stacks = CuraContainerRegistry.getInstance().findContainerStacks(is_abstract_machine = "True") abstract_machine_stacks.sort(key = lambda machine: machine.getName(), reverse = True) for abstract_machine in abstract_machine_stacks: - online_machine_stacks = AbstractMachine.getMachines(abstract_machine, online_only = True) + definition_id = abstract_machine.definition.getId() + online_machine_stacks = getMachinesWithDefinition(definition_id, online_only = True) # Create a list item for abstract machine self.addItem(abstract_machine, len(online_machine_stacks)) + other_machine_stacks.remove(abstract_machine) # Create list of machines that are children of the abstract machine for stack in online_machine_stacks: @@ -87,6 +88,6 @@ class MachineListModel(ListModel): "id": container_stack.getId(), "metadata": container_stack.getMetaData().copy(), "isOnline": parseBool(container_stack.getMetaDataEntry("is_online", False)), - "machineType": container_stack.getMetaDataEntry("type"), + "isAbstractMachine": parseBool(container_stack.getMetaDataEntry("is_abstract_machine", False)), "machineCount": machine_count, }) diff --git a/cura/Settings/AbstractMachine.py b/cura/Settings/AbstractMachine.py deleted file mode 100644 index 86909b6e29..0000000000 --- a/cura/Settings/AbstractMachine.py +++ /dev/null @@ -1,52 +0,0 @@ -from typing import List - -from UM.Settings.ContainerStack import ContainerStack -from UM.Util import parseBool -from cura.PrinterOutput.PrinterOutputDevice import ConnectionType -from cura.Settings.GlobalStack import GlobalStack -from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase -from UM.Settings.ContainerRegistry import ContainerRegistry - - -class AbstractMachine(GlobalStack): - """ Represents a group of machines of the same type. This allows the user to select settings before selecting a printer. """ - - def __init__(self, container_id: str) -> None: - super().__init__(container_id) - self.setMetaDataEntry("type", "abstract_machine") - - @classmethod - def getMachines(cls, abstract_machine: ContainerStack, online_only = False) -> List[ContainerStack]: - """ Fetches all container stacks that match definition_id with an abstract machine. - - :param abstractMachine: The abstract machine stack. - :return: A list of Containers or an empty list if abstract_machine is not an "abstract_machine" - """ - if not abstract_machine.getMetaDataEntry("type") == "abstract_machine": - return [] - - from cura.CuraApplication import CuraApplication # In function to avoid circular import - application = CuraApplication.getInstance() - registry = application.getContainerRegistry() - - machines = registry.findContainerStacks(type="machine") - # Filter machines that match definition - machines = filter(lambda machine: machine.definition.id == abstract_machine.definition.getId(), machines) - # Filter only LAN and Cloud printers - machines = filter(lambda machine: ConnectionType.CloudConnection in machine.configuredConnectionTypes or ConnectionType.NetworkConnection in machine.configuredConnectionTypes, machines) - if online_only: - # LAN printers have is_online = False but should still be included - machines = filter(lambda machine: parseBool(machine.getMetaDataEntry("is_online", False) or ConnectionType.NetworkConnection in machine.configuredConnectionTypes), machines) - - return list(machines) - - -## private: -_abstract_machine_mime = MimeType( - name = "application/x-cura-abstract-machine", - comment = "Cura Abstract Machine", - suffixes = ["global.cfg"] -) - -MimeTypeDatabase.addMimeType(_abstract_machine_mime) -ContainerRegistry.addContainerTypeByName(AbstractMachine, "abstract_machine", _abstract_machine_mime.name) diff --git a/cura/Settings/CuraStackBuilder.py b/cura/Settings/CuraStackBuilder.py index d711a61243..5a745f8f0a 100644 --- a/cura/Settings/CuraStackBuilder.py +++ b/cura/Settings/CuraStackBuilder.py @@ -9,7 +9,6 @@ from UM.Settings.Interfaces import DefinitionContainerInterface from UM.Settings.InstanceContainer import InstanceContainer from cura.Machines.ContainerTree import ContainerTree -from .AbstractMachine import AbstractMachine from .GlobalStack import GlobalStack from .ExtruderStack import ExtruderStack @@ -268,21 +267,21 @@ class CuraStackBuilder: return definition_changes_container @classmethod - def createAbstractMachine(cls, definition_id: str) -> Optional[AbstractMachine]: + def createAbstractMachine(cls, definition_id: str) -> Optional[GlobalStack]: """Create a new instance of an abstract machine. :param definition_id: The ID of the machine definition to use. :return: The new Abstract Machine or None if an error occurred. """ - abstract_machine_id = definition_id + "_abstract_machine" + abstract_machine_id = f"{definition_id}_abstract_machine" from cura.CuraApplication import CuraApplication application = CuraApplication.getInstance() registry = application.getContainerRegistry() container_tree = ContainerTree.getInstance() - if registry.findContainerStacks(type = "abstract_machine", id = abstract_machine_id): + if registry.findContainerStacks(is_abstract_machine = "True", id = abstract_machine_id): # This abstract machine already exists return None @@ -296,7 +295,8 @@ class CuraStackBuilder: machine_node = container_tree.machines[machine_definition.getId()] name = machine_definition.getName() - stack = AbstractMachine(abstract_machine_id) + stack = GlobalStack(abstract_machine_id) + stack.setMetaDataEntry("is_abstract_machine", True) stack.setMetaDataEntry("is_online", True) stack.setDefinition(machine_definition) cls.createUserContainer( diff --git a/cura/Settings/GlobalStack.py b/cura/Settings/GlobalStack.py index f0a6946f88..6a14f10fe4 100755 --- a/cura/Settings/GlobalStack.py +++ b/cura/Settings/GlobalStack.py @@ -1,4 +1,4 @@ -# Copyright (c) 2019 Ultimaker B.V. +# Copyright (c) 2022 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. from collections import defaultdict @@ -8,10 +8,9 @@ import uuid from PyQt6.QtCore import pyqtProperty, pyqtSlot, pyqtSignal -from UM.Decorators import deprecated, override +from UM.Decorators import override from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase from UM.Settings.ContainerStack import ContainerStack -from UM.Settings.SettingInstance import InstanceState from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Settings.Interfaces import PropertyEvaluationContext from UM.Logger import Logger @@ -344,13 +343,36 @@ class GlobalStack(CuraContainerStack): def getName(self) -> str: return self._metadata.get("group_name", self._metadata.get("name", "")) - def setName(self, name: "str") -> None: + def setName(self, name: str) -> None: super().setName(name) nameChanged = pyqtSignal() name = pyqtProperty(str, fget=getName, fset=setName, notify=nameChanged) +def getMachinesWithDefinition(definition_id: str, online_only = False) -> List[ContainerStack]: + """ Fetches all container stacks that match definition_id. + + :param definition_id: The id of the machine definition. + :return: A list of Containers that match definition_id + """ + from cura.CuraApplication import CuraApplication # In function to avoid circular import + application = CuraApplication.getInstance() + registry = application.getContainerRegistry() + + machines = registry.findContainerStacks(type="machine") + # Filter machines that match definition + machines = filter(lambda machine: machine.definition.id == definition_id, machines) + # Filter only LAN and Cloud printers + machines = filter(lambda machine: ConnectionType.CloudConnection in machine.configuredConnectionTypes or + ConnectionType.NetworkConnection in machine.configuredConnectionTypes, machines) + if online_only: + # LAN printers can have is_online = False but should still be included, their online status is only checked when + # they are the active printer. + machines = filter(lambda machine: parseBool(machine.getMetaDataEntry("is_online", False) or + ConnectionType.NetworkConnection in machine.configuredConnectionTypes), machines) + + return list(machines) ## private: global_stack_mime = MimeType( diff --git a/resources/qml/PrinterSelector/MachineListButton.qml b/resources/qml/PrinterSelector/MachineListButton.qml index 4511c72b4c..55ae5497d9 100644 --- a/resources/qml/PrinterSelector/MachineListButton.qml +++ b/resources/qml/PrinterSelector/MachineListButton.qml @@ -30,8 +30,8 @@ Button height: UM.Theme.getSize("medium_button").height width: UM.Theme.getSize("medium_button").width color: UM.Theme.getColor("machine_selector_printer_icon") - visible: model.machineType == "abstract_machine" || !model.isOnline - source: model.machineType == "abstract_machine" ? UM.Theme.getIcon("PrinterTriple", "medium") : UM.Theme.getIcon("Printer", "medium") + visible: model.isAbstractMachine || !model.isOnline + source: model.isAbstractMachine ? UM.Theme.getIcon("PrinterTriple", "medium") : UM.Theme.getIcon("Printer", "medium") anchors { @@ -51,7 +51,7 @@ Button leftMargin: UM.Theme.getSize("default_margin").width } text: machineListButton.text - font: model.machineType == "abstract_machine" ? UM.Theme.getFont("medium_bold") : UM.Theme.getFont("medium") + font: model.isAbstractMachine ? UM.Theme.getFont("medium_bold") : UM.Theme.getFont("medium") visible: text != "" elide: Text.ElideRight } @@ -68,7 +68,7 @@ Button top: buttonText.top bottom: buttonText.bottom } - visible: model.machineType == "abstract_machine" + visible: model.isAbstractMachine UM.Label { From f000b75661765b3087a7e1fb53c4bd37c3d081e8 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Fri, 26 Aug 2022 11:16:10 +0200 Subject: [PATCH 2/3] Move `getMachinesWithDefinition` to `MachinesManager` CURA-9514, CURA-9277 --- cura/Machines/Models/MachineListModel.py | 6 ++++-- cura/Settings/GlobalStack.py | 25 ---------------------- cura/Settings/MachineManager.py | 27 ++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 27 deletions(-) diff --git a/cura/Machines/Models/MachineListModel.py b/cura/Machines/Models/MachineListModel.py index 4b80410018..c1796c5f3f 100644 --- a/cura/Machines/Models/MachineListModel.py +++ b/cura/Machines/Models/MachineListModel.py @@ -9,7 +9,7 @@ from UM.i18n import i18nCatalog from UM.Util import parseBool from cura.Settings.CuraContainerRegistry import CuraContainerRegistry -from cura.Settings.GlobalStack import GlobalStack, getMachinesWithDefinition +from cura.Settings.GlobalStack import GlobalStack class MachineListModel(ListModel): @@ -65,7 +65,9 @@ class MachineListModel(ListModel): for abstract_machine in abstract_machine_stacks: definition_id = abstract_machine.definition.getId() - online_machine_stacks = getMachinesWithDefinition(definition_id, online_only = True) + from cura.CuraApplication import CuraApplication + machines_manager = CuraApplication.getInstance().getMachineManager() + online_machine_stacks = machines_manager.getMachinesWithDefinition(definition_id, online_only = True) # Create a list item for abstract machine self.addItem(abstract_machine, len(online_machine_stacks)) diff --git a/cura/Settings/GlobalStack.py b/cura/Settings/GlobalStack.py index 6a14f10fe4..3c13f236ab 100755 --- a/cura/Settings/GlobalStack.py +++ b/cura/Settings/GlobalStack.py @@ -349,31 +349,6 @@ class GlobalStack(CuraContainerStack): nameChanged = pyqtSignal() name = pyqtProperty(str, fget=getName, fset=setName, notify=nameChanged) - -def getMachinesWithDefinition(definition_id: str, online_only = False) -> List[ContainerStack]: - """ Fetches all container stacks that match definition_id. - - :param definition_id: The id of the machine definition. - :return: A list of Containers that match definition_id - """ - from cura.CuraApplication import CuraApplication # In function to avoid circular import - application = CuraApplication.getInstance() - registry = application.getContainerRegistry() - - machines = registry.findContainerStacks(type="machine") - # Filter machines that match definition - machines = filter(lambda machine: machine.definition.id == definition_id, machines) - # Filter only LAN and Cloud printers - machines = filter(lambda machine: ConnectionType.CloudConnection in machine.configuredConnectionTypes or - ConnectionType.NetworkConnection in machine.configuredConnectionTypes, machines) - if online_only: - # LAN printers can have is_online = False but should still be included, their online status is only checked when - # they are the active printer. - machines = filter(lambda machine: parseBool(machine.getMetaDataEntry("is_online", False) or - ConnectionType.NetworkConnection in machine.configuredConnectionTypes), machines) - - return list(machines) - ## private: global_stack_mime = MimeType( name = "application/x-cura-globalstack", diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 64d34d6c3e..389c5ded75 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -19,6 +19,7 @@ from UM.Logger import Logger from UM.Message import Message from UM.Settings.SettingFunction import SettingFunction +from UM.Settings.ContainerStack import ContainerStack from UM.Signal import postponeSignals, CompressTechnique import cura.CuraApplication # Imported like this to prevent circular references. @@ -186,6 +187,32 @@ class MachineManager(QObject): self.outputDevicesChanged.emit() + def getMachinesWithDefinition(self, definition_id: str, online_only=False) -> List[ContainerStack]: + """ Fetches all container stacks that match definition_id. + + :param definition_id: The id of the machine definition. + :return: A list of Containers that match definition_id + """ + from cura.CuraApplication import CuraApplication # In function to avoid circular import + application = CuraApplication.getInstance() + registry = application.getContainerRegistry() + + machines = registry.findContainerStacks(type="machine") + # Filter machines that match definition + machines = filter(lambda machine: machine.definition.id == definition_id, machines) + # Filter only LAN and Cloud printers + machines = filter(lambda machine: ConnectionType.CloudConnection in machine.configuredConnectionTypes or + ConnectionType.NetworkConnection in machine.configuredConnectionTypes, + machines) + if online_only: + # LAN printers can have is_online = False but should still be included, + # their online status is only checked when they are the active printer. + machines = filter(lambda machine: parseBool(machine.getMetaDataEntry("is_online", False) or + ConnectionType.NetworkConnection in machine.configuredConnectionTypes), + machines) + + return list(machines) + @pyqtProperty(QObject, notify = currentConfigurationChanged) def currentConfiguration(self) -> PrinterConfigurationModel: return self._current_printer_configuration From ff7c9eddde5b4b6cfef560764c780ab12322e88a Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Fri, 26 Aug 2022 11:34:34 +0200 Subject: [PATCH 3/3] Add documentation CURA-9514, CURA-9277 --- cura/Machines/Models/MachineListModel.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cura/Machines/Models/MachineListModel.py b/cura/Machines/Models/MachineListModel.py index c1796c5f3f..a758060384 100644 --- a/cura/Machines/Models/MachineListModel.py +++ b/cura/Machines/Models/MachineListModel.py @@ -1,6 +1,10 @@ # Copyright (c) 2022 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +# The MachineListModel is used to display the connected printers in the interface. Both the abstract machines and all +# online cloud connected printers are represented within this ListModel. Additional information such as the number of +# connected printers for each printer type is gathered. + from PyQt6.QtCore import Qt, QTimer from UM.Qt.ListModel import ListModel