From 940a833e734c533045858908b09973c0525b3f87 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Fri, 8 Mar 2019 11:02:30 +0100 Subject: [PATCH] WIP: Add printers via network --- cura/CuraApplication.py | 10 ++ .../Models/DiscoveredPrintersModel.py | 104 ++++++++++++++++++ cura/Settings/MachineManager.py | 31 +----- .../src/ClusterUM3OutputDevice.py | 3 + .../src/UM3OutputDevicePlugin.py | 4 +- .../PrinterSelector/MachineSelectorButton.qml | 8 +- .../PrinterSelector/MachineSelectorList.qml | 6 + .../AddPrinterBySelectionContent.qml | 23 +++- tests/TestMachineManager.py | 2 +- 9 files changed, 145 insertions(+), 46 deletions(-) create mode 100644 cura/Machines/Models/DiscoveredPrintersModel.py diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index f8b081bdcc..9ae43d4ee9 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -114,6 +114,8 @@ from cura.Settings.CuraFormulaFunctions import CuraFormulaFunctions from cura.ObjectsModel import ObjectsModel +from cura.Machines.Models.DiscoveredPrintersModel import DiscoveredPrinterModel + from cura.PrinterOutputDevice import PrinterOutputDevice from cura.PrinterOutput.NetworkMJPGImage import NetworkMJPGImage @@ -210,6 +212,8 @@ class CuraApplication(QtApplication): self._cura_scene_controller = None self._machine_error_checker = None + self._discovered_printer_model = DiscoveredPrinterModel(self) + self._welcome_pages_model = WelcomePagesModel(self) self._quality_profile_drop_down_menu_model = None @@ -846,6 +850,10 @@ class CuraApplication(QtApplication): # Hide the splash screen self.closeSplash() + @pyqtSlot(result = QObject) + def getDiscoveredPrinterModel(self, *args) -> "DiscoveredPrinterModel": + return self._discovered_printer_model + @pyqtSlot(result = QObject) def getSettingVisibilityPresetsModel(self, *args) -> SettingVisibilityPresetsModel: return self._setting_visibility_presets_model @@ -1003,6 +1011,8 @@ class CuraApplication(QtApplication): qmlRegisterType(QualityManagementModel, "Cura", 1, 0, "QualityManagementModel") qmlRegisterType(MachineManagementModel, "Cura", 1, 0, "MachineManagementModel") + qmlRegisterType(DiscoveredPrinterModel, "Cura", 1, 0, "DiscoveredPrinterModel") + qmlRegisterSingletonType(QualityProfilesDropDownMenuModel, "Cura", 1, 0, "QualityProfilesDropDownMenuModel", self.getQualityProfilesDropDownMenuModel) qmlRegisterSingletonType(CustomQualityProfilesDropDownMenuModel, "Cura", 1, 0, diff --git a/cura/Machines/Models/DiscoveredPrintersModel.py b/cura/Machines/Models/DiscoveredPrintersModel.py new file mode 100644 index 0000000000..d7e852629a --- /dev/null +++ b/cura/Machines/Models/DiscoveredPrintersModel.py @@ -0,0 +1,104 @@ +from typing import Callable, Optional, TYPE_CHECKING + +from PyQt5.QtCore import pyqtSlot, pyqtProperty, pyqtSignal, QObject + +from UM.Logger import Logger + +if TYPE_CHECKING: + from PyQt5.QtCore import QObject + + +class DiscoveredPrinter(QObject): + + def __init__(self, ip_address: str, key: str, name: str, create_callback: Callable[[str], None], machine_type: str, + device, parent = None) -> None: + super().__init__(parent) + self._ip_address = ip_address + self._key = key + self._name = name + self._create_callback = create_callback + self._machine_type = machine_type + self._device = device + + nameChanged = pyqtSignal() + + @pyqtProperty(str, notify = nameChanged) + def name(self) -> str: + return self._name + + def setName(self, name: str) -> None: + if self._name != name: + self._name = name + self.nameChanged.emit() + + machineTypeChanged = pyqtSignal() + + @pyqtProperty(str, notify = machineTypeChanged) + def machine_type(self) -> str: + return self._machine_type + + def setMachineType(self, machine_type: str) -> None: + if self._machine_type != machine_type: + self._machine_type = machine_type + self.machineTypeChanged.emit() + + @pyqtProperty(QObject, constant = True) + def device(self): + return self._device + + +# +# Discovered printers are all the printers that were found on the network, which provide a more convenient way +# to add networked printers (Plugin finds a bunch of printers, user can select one from the list, plugin can then +# add that printer to Cura as the active one). +# +class DiscoveredPrinterModel(QObject): + + def __init__(self, parent: Optional["QObject"]) -> None: + super().__init__(parent) + + self._discovered_printer_dict = dict() + + discoveredPrintersChanged = pyqtSignal() + + @pyqtProperty(list, notify = discoveredPrintersChanged) + def discovered_printers(self) -> "list": + item_list = list(x for x in self._discovered_printer_dict.values()) + item_list.sort(key = lambda x: x.name) + return item_list + + def addDiscoveredPrinter(self, ip_address: str, key: str, name: str, create_callback: Callable[[str], None], + machine_type: str, device) -> None: + if ip_address in self._discovered_printer_dict: + Logger.log("e", "+++++++++++++ printer with ip [%s] has already been added", ip_address) + return + + discovered_printer = DiscoveredPrinter(ip_address, key, name, create_callback, machine_type, device, parent = self) + self._discovered_printer_dict[ip_address] = discovered_printer + self.discoveredPrintersChanged.emit() + + def updateDiscoveredPrinter(self, ip_address: str, + name: Optional[str] = None, + machine_type: Optional[str] = None) -> None: + if ip_address not in self._discovered_printer_dict: + Logger.log("e", "+++++++++++++ printer with ip [%s] is not known", ip_address) + return + + item = self._discovered_printer_dict[ip_address] + + if name is not None: + item.setName(name) + if machine_type is not None: + item.setMachineType(machine_type) + + def removeDiscoveredPrinter(self, ip_address: str) -> None: + if ip_address not in self._discovered_printer_dict: + Logger.log("i", "Key [%s] does not exist in the discovered printers list.", ip_address) + return + + del self._discovered_printer_dict[ip_address] + self.discoveredPrintersChanged.emit() + + @pyqtSlot("QVariant") + def createMachineFromDiscoveredPrinter(self, discovered_printer: "DiscoveredPrinter") -> None: + discovered_printer.create_callback() diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index d19932a7a0..f2a50e3097 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -4,7 +4,7 @@ import time import re import unicodedata -from typing import Any, List, Dict, TYPE_CHECKING, Optional, cast, NamedTuple, Callable +from typing import Any, List, Dict, TYPE_CHECKING, Optional, cast from UM.ConfigurationErrorMessage import ConfigurationErrorMessage from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator @@ -49,8 +49,6 @@ if TYPE_CHECKING: from cura.Machines.QualityChangesGroup import QualityChangesGroup from cura.Machines.QualityGroup import QualityGroup -DiscoveredPrinter = NamedTuple("DiscoveredPrinter", [("key", str), ("name", str), ("create_callback", Callable[[str], None]), ("machine_type", "str")]) - class MachineManager(QObject): def __init__(self, application: "CuraApplication", parent: Optional["QObject"] = None) -> None: @@ -136,9 +134,6 @@ class MachineManager(QObject): self.globalContainerChanged.connect(self.printerConnectedStatusChanged) self.outputDevicesChanged.connect(self.printerConnectedStatusChanged) - # This will contain all discovered network printers - self._discovered_printers = {} # type: Dict[str, DiscoveredPrinter] - activeQualityGroupChanged = pyqtSignal() activeQualityChangesGroupChanged = pyqtSignal() @@ -178,30 +173,6 @@ class MachineManager(QObject): self.outputDevicesChanged.emit() - # Discovered printers are all the printers that were found on the network, which provide a more convenient way - # to add networked printers (Plugin finds a bunch of printers, user can select one from the list, plugin can then - # add that printer to Cura as the active one). - def addDiscoveredPrinter(self, key: str, name: str, create_callback: Callable[[str], None], machine_type: str) -> None: - if key not in self._discovered_printers: - self._discovered_printers[key] = DiscoveredPrinter(key, name, create_callback, machine_type) - self.discoveredPrintersChanged.emit() - else: - Logger.log("e", "Printer with the key %s was already in the discovered printer list", key) - - def removeDiscoveredPrinter(self, key: str) -> None: - if key in self._discovered_printers: - del self._discovered_printers[key] - self.discoveredPrintersChanged.emit() - - @pyqtProperty("QVariantList", notify = discoveredPrintersChanged) - def discoveredPrinters(self): - return list(self._discovered_printers.values()) - - @pyqtSlot(str) - def addMachineFromDiscoveredPrinter(self, key: str) -> None: - if key in self._discovered_printers: - self._discovered_printers[key].create_callback(key) - @pyqtProperty(QObject, notify = currentConfigurationChanged) def currentConfiguration(self) -> ConfigurationModel: return self._current_printer_configuration diff --git a/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py b/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py index c1a6362455..4b30514de1 100644 --- a/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py +++ b/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py @@ -624,6 +624,9 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): printer.updateName(data["friendly_name"]) printer.updateKey(data["uuid"]) printer.updateType(data["machine_variant"]) + self._application.getDiscoveredPrinterModel().updateDiscoveredPrinter(data["ip_address"], + name = data["friendly_name"], + machine_type = data["machine_variant"]) # Do not store the build plate information that comes from connect if the current printer has not build plate information if "build_plate" in data and machine_definition.getMetaDataEntry("has_variant_buildplates", False): diff --git a/plugins/UM3NetworkPrinting/src/UM3OutputDevicePlugin.py b/plugins/UM3NetworkPrinting/src/UM3OutputDevicePlugin.py index 4529b31c45..332af54abc 100644 --- a/plugins/UM3NetworkPrinting/src/UM3OutputDevicePlugin.py +++ b/plugins/UM3NetworkPrinting/src/UM3OutputDevicePlugin.py @@ -298,7 +298,7 @@ class UM3OutputDevicePlugin(OutputDevicePlugin): except TypeError: # Disconnect already happened. pass - self._application.getMachineManager().removeDiscoveredPrinter(device.getId()) + self._application.getDiscoveredPrinterModel().removeDiscoveredPrinter(device.getId()) self.discoveredDevicesChanged.emit() def _onAddDevice(self, name, address, properties): @@ -323,7 +323,7 @@ class UM3OutputDevicePlugin(OutputDevicePlugin): device = ClusterUM3OutputDevice.ClusterUM3OutputDevice(name, address, properties) else: device = LegacyUM3OutputDevice.LegacyUM3OutputDevice(name, address, properties) - self._application.getMachineManager().addDiscoveredPrinter(device.getId(), name, self._createMachineFromDiscoveredPrinter, properties[b"printer_type"].decode("utf-8")) + self._application.getDiscoveredPrinterModel().addDiscoveredPrinter(address, device.getId(), name, self._createMachineFromDiscoveredPrinter, properties[b"printer_type"].decode("utf-8"), device) self._discovered_devices[device.getId()] = device self.discoveredDevicesChanged.emit() diff --git a/resources/qml/PrinterSelector/MachineSelectorButton.qml b/resources/qml/PrinterSelector/MachineSelectorButton.qml index ec99dff6c9..abd9eea9e9 100644 --- a/resources/qml/PrinterSelector/MachineSelectorButton.qml +++ b/resources/qml/PrinterSelector/MachineSelectorButton.qml @@ -24,7 +24,7 @@ Button function updatePrinterTypesList() { - printerTypesList = (checked && (outputDevice != null)) ? outputDevice.uniquePrinterTypes : [] + printerTypesList = (outputDevice != null) ? outputDevice.uniquePrinterTypes : [] } contentItem: Item @@ -82,12 +82,6 @@ Button border.color: machineSelectorButton.checked ? UM.Theme.getColor("primary") : "transparent" } - onClicked: - { - toggleContent() - Cura.MachineManager.setActiveMachine(model.id) - } - Connections { target: outputDevice diff --git a/resources/qml/PrinterSelector/MachineSelectorList.qml b/resources/qml/PrinterSelector/MachineSelectorList.qml index 49d9d31f2b..1043339ae6 100644 --- a/resources/qml/PrinterSelector/MachineSelectorList.qml +++ b/resources/qml/PrinterSelector/MachineSelectorList.qml @@ -42,5 +42,11 @@ ListView } return result } + + onClicked: + { + toggleContent() + Cura.MachineManager.setActiveMachine(model.id) + } } } diff --git a/resources/qml/WelcomePages/AddPrinterBySelectionContent.qml b/resources/qml/WelcomePages/AddPrinterBySelectionContent.qml index 3e1c23ee8f..8ff058c615 100644 --- a/resources/qml/WelcomePages/AddPrinterBySelectionContent.qml +++ b/resources/qml/WelcomePages/AddPrinterBySelectionContent.qml @@ -57,10 +57,11 @@ Item ScrollView { - ScrollBar.horizontal.policy: ScrollBar.AlwaysOff + id: networkPrinterScrollView + ScrollBar.horizontal.policy: ScrollBar.AsNeeded ScrollBar.vertical.policy: ScrollBar.AlwaysOn - property int maxItemCountAtOnce: 5 // show at max 5 items at once, otherwise you need to scroll. + property int maxItemCountAtOnce: 8 // show at max 8 items at once, otherwise you need to scroll. height: maxItemCountAtOnce * (UM.Theme.getSize("action_button").height) clip: true @@ -69,15 +70,17 @@ Item { id: networkPrinterListView anchors.fill: parent - model: Cura.GlobalStacksModel {} // TODO: change this to the network printers + model: CuraApplication.getDiscoveredPrinterModel().discovered_printers + visible: len(model) > 0 delegate: MachineSelectorButton { - text: model.name + text: modelData.device.name + anchors.left: parent.left anchors.right: parent.right anchors.rightMargin: 10 - outputDevice: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null + outputDevice: modelData.device checked: ListView.view.currentIndex == index onClicked: @@ -86,6 +89,14 @@ Item } } } + + Label + { + id: noNetworkPrinterLabel + text: catalog.i18nc("@label", "There is no printer found over your network.") + renderType: Text.NativeRendering + visible: !networkPrinterListView.visible + } } } } @@ -109,7 +120,7 @@ Item } } - contentComponent: localPrinterListComponent + //contentComponent: localPrinterListComponent Component { diff --git a/tests/TestMachineManager.py b/tests/TestMachineManager.py index 34a0bbc35c..36ffe01b96 100644 --- a/tests/TestMachineManager.py +++ b/tests/TestMachineManager.py @@ -61,4 +61,4 @@ def test_discoveredMachine(machine_manager): # Just in case, nothing should happen. machine_manager.addMachineFromDiscoveredPrinter("test") - assert mocked_callback.call_count == 1 \ No newline at end of file + assert mocked_callback.call_count == 1