From 5c354eb6a36b77fb3fcb850fd8439a62f93f436f Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 26 Feb 2019 10:45:18 +0100 Subject: [PATCH 1/5] Switch the order of name & id in addMachine call This makes it possible for the name to not be set, in which case it will default to the name provided by the definition CURA-6179 --- cura/Settings/MachineManager.py | 8 +++++++- resources/qml/Dialogs/AddMachineDialog.qml | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 3416f0a321..a96a2c9443 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -386,8 +386,14 @@ class MachineManager(QObject): return machine return None + @pyqtSlot(str) @pyqtSlot(str, str) - def addMachine(self, name: str, definition_id: str) -> None: + def addMachine(self, definition_id: str, name: Optional[str] = None) -> None: + if name is None: + definitions = CuraContainerRegistry.getInstance().findDefinitionContainers(id = definition_id) + if definitions: + name = definitions[0].getName() + new_stack = CuraStackBuilder.createMachine(name, definition_id) if new_stack: # Instead of setting the global container stack here, we set the active machine and so the signals are emitted diff --git a/resources/qml/Dialogs/AddMachineDialog.qml b/resources/qml/Dialogs/AddMachineDialog.qml index f00359869c..dafe12693f 100644 --- a/resources/qml/Dialogs/AddMachineDialog.qml +++ b/resources/qml/Dialogs/AddMachineDialog.qml @@ -303,7 +303,7 @@ UM.Dialog { base.visible = false var item = machineList.model.getItem(machineList.currentIndex); - Cura.MachineManager.addMachine(machineName.text, item.id) + Cura.MachineManager.addMachine(item.id, machineName.text) base.machineAdded(item.id) // Emit signal that the user added a machine. } From 21c6bba1ce2eb18ed3ba055858eb1237305c5012 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 27 Feb 2019 11:05:54 +0100 Subject: [PATCH 2/5] Add the discovered printer functionality This can be used in the add machine wizard to short circuit the creation of a printer. So instead of first selecting a printer and then connecting it, it will be possible to have a list that contains all network discovered printers (from all plugins that can do this). This means we can select one of those printers and directly add it (thus no longer needing that step) CURA-6179 --- cura/CuraApplication.py | 2 ++ cura/Settings/MachineManager.py | 26 +++++++++++++++++-- .../src/UM3OutputDevicePlugin.py | 9 +++++-- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 4d3d2434ff..cb3a37ee69 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -745,6 +745,8 @@ class CuraApplication(QtApplication): # Initialize Cura API self._cura_API.initialize() + self._output_device_manager.start() + # Detect in which mode to run and execute that mode if self._is_headless: self.runWithoutGUI() diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index a96a2c9443..29a39fc461 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 +from typing import Any, List, Dict, TYPE_CHECKING, Optional, cast, NamedTuple, Callable from UM.ConfigurationErrorMessage import ConfigurationErrorMessage from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator @@ -49,6 +49,8 @@ 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: @@ -134,6 +136,9 @@ 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() @@ -171,7 +176,24 @@ class MachineManager(QObject): self._printer_output_devices.append(printer_output_device) self.outputDevicesChanged.emit() - self.printerConnectedStatusChanged.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) + 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] + + @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: diff --git a/plugins/UM3NetworkPrinting/src/UM3OutputDevicePlugin.py b/plugins/UM3NetworkPrinting/src/UM3OutputDevicePlugin.py index 723bcf2b7c..4529b31c45 100644 --- a/plugins/UM3NetworkPrinting/src/UM3OutputDevicePlugin.py +++ b/plugins/UM3NetworkPrinting/src/UM3OutputDevicePlugin.py @@ -213,6 +213,11 @@ class UM3OutputDevicePlugin(OutputDevicePlugin): self._checkManualDevice(address) + def _createMachineFromDiscoveredPrinter(self, key: str) -> None: + # TODO: This needs to be implemented. It's supposed to create a machine given a unique key as already discovered + # by this plugin. + pass + def _checkManualDevice(self, address): # Check if a UM3 family device exists at this address. # If a printer responds, it will replace the preliminary printer created above @@ -293,7 +298,7 @@ class UM3OutputDevicePlugin(OutputDevicePlugin): except TypeError: # Disconnect already happened. pass - + self._application.getMachineManager().removeDiscoveredPrinter(device.getId()) self.discoveredDevicesChanged.emit() def _onAddDevice(self, name, address, properties): @@ -318,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._discovered_devices[device.getId()] = device self.discoveredDevicesChanged.emit() From 17fdc86e500bf4547f7708a887c7236350f711e5 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 27 Feb 2019 11:59:50 +0100 Subject: [PATCH 3/5] Fix typing CURA-6179 --- cura/Settings/MachineManager.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 29a39fc461..7a06e8753c 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -415,8 +415,10 @@ class MachineManager(QObject): definitions = CuraContainerRegistry.getInstance().findDefinitionContainers(id = definition_id) if definitions: name = definitions[0].getName() + else: + name = definition_id - new_stack = CuraStackBuilder.createMachine(name, definition_id) + new_stack = CuraStackBuilder.createMachine(cast(str, name), definition_id) if new_stack: # Instead of setting the global container stack here, we set the active machine and so the signals are emitted self.setActiveMachine(new_stack.getId()) From bbe1b1590ac610254cecd57e7b6585369fc70e8d Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 28 Feb 2019 09:35:16 +0100 Subject: [PATCH 4/5] Added test for adding & creating machine with discovered printer CURA-6179 --- tests/TestMachineManager.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/TestMachineManager.py b/tests/TestMachineManager.py index b989a6ee79..ca0e203c8b 100644 --- a/tests/TestMachineManager.py +++ b/tests/TestMachineManager.py @@ -15,7 +15,10 @@ def container_registry() -> ContainerRegistry: def extruder_manager(application, container_registry) -> ExtruderManager: with patch("cura.CuraApplication.CuraApplication.getInstance", MagicMock(return_value=application)): with patch("UM.Settings.ContainerRegistry.ContainerRegistry.getInstance", MagicMock(return_value=container_registry)): + manager = ExtruderManager.getInstance() + if manager is None: manager = ExtruderManager() + return manager @pytest.fixture() @@ -41,3 +44,9 @@ def test_setActiveMachine(machine_manager): # Although we mocked the application away, we still want to know if it was notified about the attempted change. machine_manager._application.setGlobalContainerStack.assert_called_with(mocked_global_stack) + +def test_discoveredMachine(machine_manager): + mocked_callback = MagicMock() + machine_manager.addDiscoveredPrinter("test", "zomg", mocked_callback, "derp") + machine_manager.addMachineFromDiscoveredPrinter("test") + mocked_callback.assert_called_with("test") \ No newline at end of file From 1c7e047a3848851d14915037d5b0f59dfba56354 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 28 Feb 2019 09:47:25 +0100 Subject: [PATCH 5/5] Added tests for adding & removing discovered devices CURA-6179 --- cura/Settings/MachineManager.py | 7 +++++++ tests/TestMachineManager.py | 14 +++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 7a06e8753c..d19932a7a0 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -162,6 +162,7 @@ class MachineManager(QObject): printerConnectedStatusChanged = pyqtSignal() # Emitted every time the active machine change or the outputdevices change rootMaterialChanged = pyqtSignal() + discoveredPrintersChanged = pyqtSignal() def setInitialActiveMachine(self) -> None: active_machine_id = self._application.getPreferences().getValue("cura/active_machine") @@ -183,12 +184,18 @@ class MachineManager(QObject): 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: diff --git a/tests/TestMachineManager.py b/tests/TestMachineManager.py index ca0e203c8b..34a0bbc35c 100644 --- a/tests/TestMachineManager.py +++ b/tests/TestMachineManager.py @@ -11,6 +11,7 @@ from cura.Settings.MachineManager import MachineManager def container_registry() -> ContainerRegistry: return MagicMock() + @pytest.fixture() def extruder_manager(application, container_registry) -> ExtruderManager: with patch("cura.CuraApplication.CuraApplication.getInstance", MagicMock(return_value=application)): @@ -21,6 +22,7 @@ def extruder_manager(application, container_registry) -> ExtruderManager: return manager + @pytest.fixture() def machine_manager(application, extruder_manager, container_registry) -> MachineManager: application.getExtruderManager = MagicMock(return_value = extruder_manager) @@ -49,4 +51,14 @@ def test_discoveredMachine(machine_manager): mocked_callback = MagicMock() machine_manager.addDiscoveredPrinter("test", "zomg", mocked_callback, "derp") machine_manager.addMachineFromDiscoveredPrinter("test") - mocked_callback.assert_called_with("test") \ No newline at end of file + mocked_callback.assert_called_with("test") + + assert len(machine_manager.discoveredPrinters) == 1 + + # Test if removing it works + machine_manager.removeDiscoveredPrinter("test") + assert len(machine_manager.discoveredPrinters) == 0 + + # Just in case, nothing should happen. + machine_manager.addMachineFromDiscoveredPrinter("test") + assert mocked_callback.call_count == 1 \ No newline at end of file