Merge pull request #4975 from Ultimaker/CURA-6011_connection_types

[4.0] Every output device should define its connection type
This commit is contained in:
Lipu Fei 2018-12-18 13:23:02 +01:00 committed by GitHub
commit 71e71e0a4f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 183 additions and 104 deletions

View file

@ -51,6 +51,7 @@ from cura.Arranging.ArrangeObjectsJob import ArrangeObjectsJob
from cura.Arranging.ArrangeObjectsAllBuildPlatesJob import ArrangeObjectsAllBuildPlatesJob from cura.Arranging.ArrangeObjectsAllBuildPlatesJob import ArrangeObjectsAllBuildPlatesJob
from cura.Arranging.ShapeArray import ShapeArray from cura.Arranging.ShapeArray import ShapeArray
from cura.MultiplyObjectsJob import MultiplyObjectsJob from cura.MultiplyObjectsJob import MultiplyObjectsJob
from cura.PrintersModel import PrintersModel
from cura.Scene.ConvexHullDecorator import ConvexHullDecorator from cura.Scene.ConvexHullDecorator import ConvexHullDecorator
from cura.Operations.SetParentOperation import SetParentOperation from cura.Operations.SetParentOperation import SetParentOperation
from cura.Scene.SliceableObjectDecorator import SliceableObjectDecorator from cura.Scene.SliceableObjectDecorator import SliceableObjectDecorator
@ -113,6 +114,7 @@ from cura.Settings.CuraFormulaFunctions import CuraFormulaFunctions
from cura.ObjectsModel import ObjectsModel from cura.ObjectsModel import ObjectsModel
from cura.PrinterOutputDevice import PrinterOutputDevice
from cura.PrinterOutput.NetworkMJPGImage import NetworkMJPGImage from cura.PrinterOutput.NetworkMJPGImage import NetworkMJPGImage
from UM.FlameProfiler import pyqtSlot from UM.FlameProfiler import pyqtSlot
@ -969,6 +971,7 @@ class CuraApplication(QtApplication):
qmlRegisterType(MultiBuildPlateModel, "Cura", 1, 0, "MultiBuildPlateModel") qmlRegisterType(MultiBuildPlateModel, "Cura", 1, 0, "MultiBuildPlateModel")
qmlRegisterType(InstanceContainer, "Cura", 1, 0, "InstanceContainer") qmlRegisterType(InstanceContainer, "Cura", 1, 0, "InstanceContainer")
qmlRegisterType(ExtrudersModel, "Cura", 1, 0, "ExtrudersModel") qmlRegisterType(ExtrudersModel, "Cura", 1, 0, "ExtrudersModel")
qmlRegisterType(PrintersModel, "Cura", 1, 0, "PrintersModel")
qmlRegisterType(FavoriteMaterialsModel, "Cura", 1, 0, "FavoriteMaterialsModel") qmlRegisterType(FavoriteMaterialsModel, "Cura", 1, 0, "FavoriteMaterialsModel")
qmlRegisterType(GenericMaterialsModel, "Cura", 1, 0, "GenericMaterialsModel") qmlRegisterType(GenericMaterialsModel, "Cura", 1, 0, "GenericMaterialsModel")
@ -990,6 +993,8 @@ class CuraApplication(QtApplication):
qmlRegisterSingletonType(ContainerManager, "Cura", 1, 0, "ContainerManager", ContainerManager.getInstance) qmlRegisterSingletonType(ContainerManager, "Cura", 1, 0, "ContainerManager", ContainerManager.getInstance)
qmlRegisterType(SidebarCustomMenuItemsModel, "Cura", 1, 0, "SidebarCustomMenuItemsModel") qmlRegisterType(SidebarCustomMenuItemsModel, "Cura", 1, 0, "SidebarCustomMenuItemsModel")
qmlRegisterType(PrinterOutputDevice, "Cura", 1, 0, "PrinterOutputDevice")
from cura.API import CuraAPI from cura.API import CuraAPI
qmlRegisterSingletonType(CuraAPI, "Cura", 1, 1, "API", self.getCuraAPI) qmlRegisterSingletonType(CuraAPI, "Cura", 1, 1, "API", self.getCuraAPI)

View file

@ -6,7 +6,7 @@ from UM.Logger import Logger
from UM.Scene.SceneNode import SceneNode #For typing. from UM.Scene.SceneNode import SceneNode #For typing.
from cura.CuraApplication import CuraApplication from cura.CuraApplication import CuraApplication
from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState, ConnectionType
from PyQt5.QtNetwork import QHttpMultiPart, QHttpPart, QNetworkRequest, QNetworkAccessManager, QNetworkReply, QAuthenticator from PyQt5.QtNetwork import QHttpMultiPart, QHttpPart, QNetworkRequest, QNetworkAccessManager, QNetworkReply, QAuthenticator
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QUrl, QCoreApplication from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QUrl, QCoreApplication
@ -28,8 +28,8 @@ class AuthState(IntEnum):
class NetworkedPrinterOutputDevice(PrinterOutputDevice): class NetworkedPrinterOutputDevice(PrinterOutputDevice):
authenticationStateChanged = pyqtSignal() authenticationStateChanged = pyqtSignal()
def __init__(self, device_id, address: str, properties: Dict[bytes, bytes], parent: QObject = None) -> None: def __init__(self, device_id, address: str, properties: Dict[bytes, bytes], connection_type: ConnectionType = ConnectionType.NetworkConnection, parent: QObject = None) -> None:
super().__init__(device_id = device_id, parent = parent) super().__init__(device_id = device_id, connection_type = connection_type, parent = parent)
self._manager = None # type: Optional[QNetworkAccessManager] self._manager = None # type: Optional[QNetworkAccessManager]
self._last_manager_create_time = None # type: Optional[float] self._last_manager_create_time = None # type: Optional[float]
self._recreate_network_manager_time = 30 self._recreate_network_manager_time = 30
@ -125,7 +125,7 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice):
if self._connection_state_before_timeout is None: if self._connection_state_before_timeout is None:
self._connection_state_before_timeout = self._connection_state self._connection_state_before_timeout = self._connection_state
self.setConnectionState(ConnectionState.closed) self.setConnectionState(ConnectionState.Closed)
# We need to check if the manager needs to be re-created. If we don't, we get some issues when OSX goes to # We need to check if the manager needs to be re-created. If we don't, we get some issues when OSX goes to
# sleep. # sleep.
@ -133,7 +133,7 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice):
if self._last_manager_create_time is None or time() - self._last_manager_create_time > self._recreate_network_manager_time: if self._last_manager_create_time is None or time() - self._last_manager_create_time > self._recreate_network_manager_time:
self._createNetworkManager() self._createNetworkManager()
assert(self._manager is not None) assert(self._manager is not None)
elif self._connection_state == ConnectionState.closed: elif self._connection_state == ConnectionState.Closed:
# Go out of timeout. # Go out of timeout.
if self._connection_state_before_timeout is not None: # sanity check, but it should never be None here if self._connection_state_before_timeout is not None: # sanity check, but it should never be None here
self.setConnectionState(self._connection_state_before_timeout) self.setConnectionState(self._connection_state_before_timeout)
@ -285,8 +285,8 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice):
self._last_response_time = time() self._last_response_time = time()
if self._connection_state == ConnectionState.connecting: if self._connection_state == ConnectionState.Connecting:
self.setConnectionState(ConnectionState.connected) self.setConnectionState(ConnectionState.Connected)
callback_key = reply.url().toString() + str(reply.operation()) callback_key = reply.url().toString() + str(reply.operation())
try: try:

View file

@ -4,7 +4,7 @@
from UM.Decorators import deprecated from UM.Decorators import deprecated
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
from UM.OutputDevice.OutputDevice import OutputDevice from UM.OutputDevice.OutputDevice import OutputDevice
from PyQt5.QtCore import pyqtProperty, pyqtSignal, QObject, QTimer, QUrl from PyQt5.QtCore import pyqtProperty, pyqtSignal, QObject, QTimer, QUrl, Q_ENUMS
from PyQt5.QtWidgets import QMessageBox from PyQt5.QtWidgets import QMessageBox
from UM.Logger import Logger from UM.Logger import Logger
@ -28,11 +28,18 @@ i18n_catalog = i18nCatalog("cura")
## The current processing state of the backend. ## The current processing state of the backend.
class ConnectionState(IntEnum): class ConnectionState(IntEnum):
closed = 0 Closed = 0
connecting = 1 Connecting = 1
connected = 2 Connected = 2
busy = 3 Busy = 3
error = 4 Error = 4
class ConnectionType(IntEnum):
Unknown = 0
UsbConnection = 1
NetworkConnection = 2
CloudConnection = 3
## Printer output device adds extra interface options on top of output device. ## Printer output device adds extra interface options on top of output device.
@ -46,6 +53,11 @@ class ConnectionState(IntEnum):
# For all other uses it should be used in the same way as a "regular" OutputDevice. # For all other uses it should be used in the same way as a "regular" OutputDevice.
@signalemitter @signalemitter
class PrinterOutputDevice(QObject, OutputDevice): class PrinterOutputDevice(QObject, OutputDevice):
# Put ConnectionType here with Q_ENUMS() so it can be registered as a QML type and accessible via QML, and there is
# no need to remember what those Enum integer values mean.
Q_ENUMS(ConnectionType)
printersChanged = pyqtSignal() printersChanged = pyqtSignal()
connectionStateChanged = pyqtSignal(str) connectionStateChanged = pyqtSignal(str)
acceptsCommandsChanged = pyqtSignal() acceptsCommandsChanged = pyqtSignal()
@ -62,7 +74,7 @@ class PrinterOutputDevice(QObject, OutputDevice):
# Signal to indicate that the configuration of one of the printers has changed. # Signal to indicate that the configuration of one of the printers has changed.
uniqueConfigurationsChanged = pyqtSignal() uniqueConfigurationsChanged = pyqtSignal()
def __init__(self, device_id: str, parent: QObject = None) -> None: def __init__(self, device_id: str, connection_type: "ConnectionType" = ConnectionType.Unknown, parent: QObject = None) -> None:
super().__init__(device_id = device_id, parent = parent) # type: ignore # MyPy complains with the multiple inheritance super().__init__(device_id = device_id, parent = parent) # type: ignore # MyPy complains with the multiple inheritance
self._printers = [] # type: List[PrinterOutputModel] self._printers = [] # type: List[PrinterOutputModel]
@ -83,7 +95,8 @@ class PrinterOutputDevice(QObject, OutputDevice):
self._update_timer.setSingleShot(False) self._update_timer.setSingleShot(False)
self._update_timer.timeout.connect(self._update) self._update_timer.timeout.connect(self._update)
self._connection_state = ConnectionState.closed #type: ConnectionState self._connection_state = ConnectionState.Closed #type: ConnectionState
self._connection_type = connection_type
self._firmware_updater = None #type: Optional[FirmwareUpdater] self._firmware_updater = None #type: Optional[FirmwareUpdater]
self._firmware_name = None #type: Optional[str] self._firmware_name = None #type: Optional[str]
@ -110,15 +123,18 @@ class PrinterOutputDevice(QObject, OutputDevice):
callback(QMessageBox.Yes) callback(QMessageBox.Yes)
def isConnected(self) -> bool: def isConnected(self) -> bool:
return self._connection_state != ConnectionState.closed and self._connection_state != ConnectionState.error return self._connection_state != ConnectionState.Closed and self._connection_state != ConnectionState.Error
def setConnectionState(self, connection_state: ConnectionState) -> None: def setConnectionState(self, connection_state: "ConnectionState") -> None:
if self._connection_state != connection_state: if self._connection_state != connection_state:
self._connection_state = connection_state self._connection_state = connection_state
self.connectionStateChanged.emit(self._id) self.connectionStateChanged.emit(self._id)
def getConnectionType(self) -> "ConnectionType":
return self._connection_type
@pyqtProperty(str, notify = connectionStateChanged) @pyqtProperty(str, notify = connectionStateChanged)
def connectionState(self) -> ConnectionState: def connectionState(self) -> "ConnectionState":
return self._connection_state return self._connection_state
def _update(self) -> None: def _update(self) -> None:
@ -174,13 +190,13 @@ class PrinterOutputDevice(QObject, OutputDevice):
## Attempt to establish connection ## Attempt to establish connection
def connect(self) -> None: def connect(self) -> None:
self.setConnectionState(ConnectionState.connecting) self.setConnectionState(ConnectionState.Connecting)
self._update_timer.start() self._update_timer.start()
## Attempt to close the connection ## Attempt to close the connection
def close(self) -> None: def close(self) -> None:
self._update_timer.stop() self._update_timer.stop()
self.setConnectionState(ConnectionState.closed) self.setConnectionState(ConnectionState.Closed)
## Ensure that close gets called when object is destroyed ## Ensure that close gets called when object is destroyed
def __del__(self) -> None: def __del__(self) -> None:

69
cura/PrintersModel.py Normal file
View file

@ -0,0 +1,69 @@
# Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from UM.Qt.ListModel import ListModel
from PyQt5.QtCore import pyqtProperty, Qt, pyqtSignal
from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Settings.ContainerStack import ContainerStack
from cura.PrinterOutputDevice import ConnectionType
from cura.Settings.GlobalStack import GlobalStack
class PrintersModel(ListModel):
NameRole = Qt.UserRole + 1
IdRole = Qt.UserRole + 2
HasRemoteConnectionRole = Qt.UserRole + 3
ConnectionTypeRole = Qt.UserRole + 4
MetaDataRole = Qt.UserRole + 5
def __init__(self, parent = None):
super().__init__(parent)
self.addRoleName(self.NameRole, "name")
self.addRoleName(self.IdRole, "id")
self.addRoleName(self.HasRemoteConnectionRole, "hasRemoteConnection")
self.addRoleName(self.ConnectionTypeRole, "connectionType")
self.addRoleName(self.MetaDataRole, "metadata")
self._container_stacks = []
# Listen to changes
ContainerRegistry.getInstance().containerAdded.connect(self._onContainerChanged)
ContainerRegistry.getInstance().containerMetaDataChanged.connect(self._onContainerChanged)
ContainerRegistry.getInstance().containerRemoved.connect(self._onContainerChanged)
self._filter_dict = {}
self._update()
## Handler for container added/removed events from registry
def _onContainerChanged(self, container):
# We only need to update when the added / removed container GlobalStack
if isinstance(container, GlobalStack):
self._update()
## Handler for container name change events.
def _onContainerNameChanged(self):
self._update()
def _update(self) -> None:
items = []
for container in self._container_stacks:
container.nameChanged.disconnect(self._onContainerNameChanged)
container_stacks = ContainerRegistry.getInstance().findContainerStacks(type = "machine")
for container_stack in container_stacks:
connection_type = container_stack.getMetaDataEntry("connection_type")
has_remote_connection = connection_type in [ConnectionType.NetworkConnection.value, ConnectionType.CloudConnection.value]
if container_stack.getMetaDataEntry("hidden", False) in ["True", True]:
continue
# TODO: Remove reference to connect group name.
items.append({"name": container_stack.getMetaDataEntry("connect_group_name", container_stack.getName()),
"id": container_stack.getId(),
"hasRemoteConnection": has_remote_connection,
"connectionType": connection_type,
"metadata": container_stack.getMetaData().copy()})
items.sort(key=lambda i: not i["hasRemoteConnection"])
self.setItems(items)

View file

@ -23,7 +23,7 @@ from UM.Settings.SettingFunction import SettingFunction
from UM.Signal import postponeSignals, CompressTechnique from UM.Signal import postponeSignals, CompressTechnique
from cura.Machines.QualityManager import getMachineDefinitionIDForQualitySearch from cura.Machines.QualityManager import getMachineDefinitionIDForQualitySearch
from cura.PrinterOutputDevice import PrinterOutputDevice from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionType
from cura.PrinterOutput.ConfigurationModel import ConfigurationModel from cura.PrinterOutput.ConfigurationModel import ConfigurationModel
from cura.PrinterOutput.ExtruderConfigurationModel import ExtruderConfigurationModel from cura.PrinterOutput.ExtruderConfigurationModel import ExtruderConfigurationModel
from cura.PrinterOutput.MaterialOutputModel import MaterialOutputModel from cura.PrinterOutput.MaterialOutputModel import MaterialOutputModel
@ -523,7 +523,13 @@ class MachineManager(QObject):
def printerConnected(self): def printerConnected(self):
return bool(self._printer_output_devices) return bool(self._printer_output_devices)
@pyqtProperty(str, notify = printerConnectedStatusChanged) @pyqtProperty(bool, notify = printerConnectedStatusChanged)
def activeMachineHasRemoteConnection(self) -> bool:
if self._global_container_stack:
connection_type = self._global_container_stack.getMetaDataEntry("connection_type")
return connection_type in [ConnectionType.NetworkConnection.value, ConnectionType.CloudConnection.value]
return False
def activeMachineNetworkKey(self) -> str: def activeMachineNetworkKey(self) -> str:
if self._global_container_stack: if self._global_container_stack:
return self._global_container_stack.getMetaDataEntry("um_network_key", "") return self._global_container_stack.getMetaDataEntry("um_network_key", "")
@ -751,7 +757,7 @@ class MachineManager(QObject):
self.setActiveMachine(other_machine_stacks[0]["id"]) self.setActiveMachine(other_machine_stacks[0]["id"])
metadata = CuraContainerRegistry.getInstance().findContainerStacksMetadata(id = machine_id)[0] metadata = CuraContainerRegistry.getInstance().findContainerStacksMetadata(id = machine_id)[0]
network_key = metadata["um_network_key"] if "um_network_key" in metadata else None network_key = metadata.get("um_network_key", None)
ExtruderManager.getInstance().removeMachineExtruders(machine_id) ExtruderManager.getInstance().removeMachineExtruders(machine_id)
containers = CuraContainerRegistry.getInstance().findInstanceContainersMetadata(type = "user", machine = machine_id) containers = CuraContainerRegistry.getInstance().findInstanceContainersMetadata(type = "user", machine = machine_id)
for container in containers: for container in containers:
@ -1317,17 +1323,18 @@ class MachineManager(QObject):
# Get the definition id corresponding to this machine name # Get the definition id corresponding to this machine name
machine_definition_id = CuraContainerRegistry.getInstance().findDefinitionContainers(name = machine_name)[0].getId() machine_definition_id = CuraContainerRegistry.getInstance().findDefinitionContainers(name = machine_name)[0].getId()
# Try to find a machine with the same network key # Try to find a machine with the same network key
new_machine = self.getMachine(machine_definition_id, metadata_filter = {"um_network_key": self.activeMachineNetworkKey}) new_machine = self.getMachine(machine_definition_id, metadata_filter = {"um_network_key": self.activeMachineNetworkKey()})
# If there is no machine, then create a new one and set it to the non-hidden instance # If there is no machine, then create a new one and set it to the non-hidden instance
if not new_machine: if not new_machine:
new_machine = CuraStackBuilder.createMachine(machine_definition_id + "_sync", machine_definition_id) new_machine = CuraStackBuilder.createMachine(machine_definition_id + "_sync", machine_definition_id)
if not new_machine: if not new_machine:
return return
new_machine.setMetaDataEntry("um_network_key", self.activeMachineNetworkKey) new_machine.setMetaDataEntry("um_network_key", self.activeMachineNetworkKey())
new_machine.setMetaDataEntry("connect_group_name", self.activeMachineNetworkGroupName) new_machine.setMetaDataEntry("connect_group_name", self.activeMachineNetworkGroupName)
new_machine.setMetaDataEntry("hidden", False) new_machine.setMetaDataEntry("hidden", False)
new_machine.setMetaDataEntry("connection_type", self._global_container_stack.getMetaDataEntry("connection_type"))
else: else:
Logger.log("i", "Found a %s with the key %s. Let's use it!", machine_name, self.activeMachineNetworkKey) Logger.log("i", "Found a %s with the key %s. Let's use it!", machine_name, self.activeMachineNetworkKey())
new_machine.setMetaDataEntry("hidden", False) new_machine.setMetaDataEntry("hidden", False)
# Set the current printer instance to hidden (the metadata entry must exist) # Set the current printer instance to hidden (the metadata entry must exist)
@ -1387,10 +1394,10 @@ class MachineManager(QObject):
# After updating from 3.2 to 3.3 some group names may be temporary. If there is a mismatch in the name of the group # After updating from 3.2 to 3.3 some group names may be temporary. If there is a mismatch in the name of the group
# then all the container stacks are updated, both the current and the hidden ones. # then all the container stacks are updated, both the current and the hidden ones.
def checkCorrectGroupName(self, device_id: str, group_name: str) -> None: def checkCorrectGroupName(self, device_id: str, group_name: str) -> None:
if self._global_container_stack and device_id == self.activeMachineNetworkKey: if self._global_container_stack and device_id == self.activeMachineNetworkKey():
# Check if the connect_group_name is correct. If not, update all the containers connected to the same printer # Check if the connect_group_name is correct. If not, update all the containers connected to the same printer
if self.activeMachineNetworkGroupName != group_name: if self.activeMachineNetworkGroupName != group_name:
metadata_filter = {"um_network_key": self.activeMachineNetworkKey} metadata_filter = {"um_network_key": self.activeMachineNetworkKey()}
containers = CuraContainerRegistry.getInstance().findContainerStacks(type = "machine", **metadata_filter) containers = CuraContainerRegistry.getInstance().findContainerStacks(type = "machine", **metadata_filter)
for container in containers: for container in containers:
container.setMetaDataEntry("connect_group_name", group_name) container.setMetaDataEntry("connect_group_name", group_name)

View file

@ -28,7 +28,7 @@ Cura.MachineAction
// Check if there is another instance with the same key // Check if there is another instance with the same key
if (!manager.existsKey(printerKey)) if (!manager.existsKey(printerKey))
{ {
manager.setKey(printerKey) manager.associateActiveMachineWithPrinterDevice(base.selectedDevice)
manager.setGroupName(printerName) // TODO To change when the groups have a name manager.setGroupName(printerName) // TODO To change when the groups have a name
completed() completed()
} }

View file

@ -22,6 +22,7 @@ from cura.PrinterOutput.ExtruderConfigurationModel import ExtruderConfigurationM
from cura.PrinterOutput.NetworkedPrinterOutputDevice import NetworkedPrinterOutputDevice, AuthState from cura.PrinterOutput.NetworkedPrinterOutputDevice import NetworkedPrinterOutputDevice, AuthState
from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel
from cura.PrinterOutput.MaterialOutputModel import MaterialOutputModel from cura.PrinterOutput.MaterialOutputModel import MaterialOutputModel
from cura.PrinterOutputDevice import ConnectionType
from .ClusterUM3PrinterOutputController import ClusterUM3PrinterOutputController from .ClusterUM3PrinterOutputController import ClusterUM3PrinterOutputController
from .SendMaterialJob import SendMaterialJob from .SendMaterialJob import SendMaterialJob
@ -54,7 +55,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
clusterPrintersChanged = pyqtSignal() clusterPrintersChanged = pyqtSignal()
def __init__(self, device_id, address, properties, parent = None) -> None: def __init__(self, device_id, address, properties, parent = None) -> None:
super().__init__(device_id = device_id, address = address, properties=properties, parent = parent) super().__init__(device_id = device_id, address = address, properties=properties, connection_type = ConnectionType.NetworkConnection, parent = parent)
self._api_prefix = "/cluster-api/v1/" self._api_prefix = "/cluster-api/v1/"
self._number_of_extruders = 2 self._number_of_extruders = 2

View file

@ -3,7 +3,7 @@
import os.path import os.path
import time import time
from typing import cast, Optional from typing import Optional, TYPE_CHECKING
from PyQt5.QtCore import pyqtSignal, pyqtProperty, pyqtSlot, QObject from PyQt5.QtCore import pyqtSignal, pyqtProperty, pyqtSlot, QObject
@ -16,6 +16,9 @@ from cura.MachineAction import MachineAction
from .UM3OutputDevicePlugin import UM3OutputDevicePlugin from .UM3OutputDevicePlugin import UM3OutputDevicePlugin
if TYPE_CHECKING:
from cura.PrinterOutputDevice import PrinterOutputDevice
catalog = i18nCatalog("cura") catalog = i18nCatalog("cura")
@ -116,22 +119,30 @@ class DiscoverUM3Action(MachineAction):
# Ensure that the connection states are refreshed. # Ensure that the connection states are refreshed.
self._network_plugin.reCheckConnections() self._network_plugin.reCheckConnections()
@pyqtSlot(str) # Associates the currently active machine with the given printer device. The network connection information will be
def setKey(self, key: str) -> None: # stored into the metadata of the currently active machine.
Logger.log("d", "Attempting to set the network key of the active machine to %s", key) @pyqtSlot(QObject)
def associateActiveMachineWithPrinterDevice(self, printer_device: Optional["PrinterOutputDevice"]) -> None:
Logger.log("d", "Attempting to set the network key of the active machine to %s", printer_device.key)
global_container_stack = CuraApplication.getInstance().getGlobalContainerStack() global_container_stack = CuraApplication.getInstance().getGlobalContainerStack()
if global_container_stack: if global_container_stack:
meta_data = global_container_stack.getMetaData() meta_data = global_container_stack.getMetaData()
if "um_network_key" in meta_data: if "um_network_key" in meta_data:
previous_network_key= meta_data["um_network_key"] previous_network_key= meta_data["um_network_key"]
global_container_stack.setMetaDataEntry("um_network_key", key) global_container_stack.setMetaDataEntry("um_network_key", printer_device.key)
# Delete old authentication data. # Delete old authentication data.
Logger.log("d", "Removing old authentication id %s for device %s", global_container_stack.getMetaDataEntry("network_authentication_id", None), key) Logger.log("d", "Removing old authentication id %s for device %s", global_container_stack.getMetaDataEntry("network_authentication_id", None), printer_device.key)
global_container_stack.removeMetaDataEntry("network_authentication_id") global_container_stack.removeMetaDataEntry("network_authentication_id")
global_container_stack.removeMetaDataEntry("network_authentication_key") global_container_stack.removeMetaDataEntry("network_authentication_key")
CuraApplication.getInstance().getMachineManager().replaceContainersMetadata(key = "um_network_key", value = previous_network_key, new_value = key) CuraApplication.getInstance().getMachineManager().replaceContainersMetadata(key = "um_network_key", value = previous_network_key, new_value = printer_device.key)
if "connection_type" in meta_data:
previous_connection_type = meta_data["connection_type"]
global_container_stack.setMetaDataEntry("connection_type", printer_device.getConnectionType().value)
CuraApplication.getInstance().getMachineManager().replaceContainersMetadata(key = "connection_type", value = previous_connection_type, new_value = printer_device.getConnectionType().value)
else: else:
global_container_stack.setMetaDataEntry("um_network_key", key) global_container_stack.setMetaDataEntry("um_network_key", printer_device.key)
global_container_stack.setMetaDataEntry("connection_type", printer_device.getConnectionType().value)
if self._network_plugin: if self._network_plugin:
# Ensure that the connection states are refreshed. # Ensure that the connection states are refreshed.

View file

@ -7,6 +7,7 @@ from cura.PrinterOutput.NetworkedPrinterOutputDevice import NetworkedPrinterOutp
from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel
from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel
from cura.PrinterOutput.MaterialOutputModel import MaterialOutputModel from cura.PrinterOutput.MaterialOutputModel import MaterialOutputModel
from cura.PrinterOutputDevice import ConnectionType
from cura.Settings.ContainerManager import ContainerManager from cura.Settings.ContainerManager import ContainerManager
from cura.Settings.ExtruderManager import ExtruderManager from cura.Settings.ExtruderManager import ExtruderManager
@ -43,7 +44,7 @@ i18n_catalog = i18nCatalog("cura")
# 5. As a final step, we verify the authentication, as this forces the QT manager to setup the authenticator. # 5. As a final step, we verify the authentication, as this forces the QT manager to setup the authenticator.
class LegacyUM3OutputDevice(NetworkedPrinterOutputDevice): class LegacyUM3OutputDevice(NetworkedPrinterOutputDevice):
def __init__(self, device_id, address: str, properties, parent = None) -> None: def __init__(self, device_id, address: str, properties, parent = None) -> None:
super().__init__(device_id = device_id, address = address, properties = properties, parent = parent) super().__init__(device_id = device_id, address = address, properties = properties, connection_type = ConnectionType.NetworkConnection, parent = parent)
self._api_prefix = "/api/v1/" self._api_prefix = "/api/v1/"
self._number_of_extruders = 2 self._number_of_extruders = 2

View file

@ -283,6 +283,7 @@ class UM3OutputDevicePlugin(OutputDevicePlugin):
global_container_stack = Application.getInstance().getGlobalContainerStack() global_container_stack = Application.getInstance().getGlobalContainerStack()
if global_container_stack and device.getId() == global_container_stack.getMetaDataEntry("um_network_key"): if global_container_stack and device.getId() == global_container_stack.getMetaDataEntry("um_network_key"):
global_container_stack.setMetaDataEntry("connection_type", device.getConnectionType().value)
device.connect() device.connect()
device.connectionStateChanged.connect(self._onDeviceConnectionStateChanged) device.connectionStateChanged.connect(self._onDeviceConnectionStateChanged)

View file

@ -7,7 +7,7 @@ from UM.i18n import i18nCatalog
from UM.Qt.Duration import DurationFormat from UM.Qt.Duration import DurationFormat
from cura.CuraApplication import CuraApplication from cura.CuraApplication import CuraApplication
from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState, ConnectionType
from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel
from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel
from cura.PrinterOutput.GenericOutputController import GenericOutputController from cura.PrinterOutput.GenericOutputController import GenericOutputController
@ -29,7 +29,7 @@ catalog = i18nCatalog("cura")
class USBPrinterOutputDevice(PrinterOutputDevice): class USBPrinterOutputDevice(PrinterOutputDevice):
def __init__(self, serial_port: str, baud_rate: Optional[int] = None) -> None: def __init__(self, serial_port: str, baud_rate: Optional[int] = None) -> None:
super().__init__(serial_port) super().__init__(serial_port, connection_type = ConnectionType.UsbConnection)
self.setName(catalog.i18nc("@item:inmenu", "USB printing")) self.setName(catalog.i18nc("@item:inmenu", "USB printing"))
self.setShortDescription(catalog.i18nc("@action:button Preceded by 'Ready to'.", "Print via USB")) self.setShortDescription(catalog.i18nc("@action:button Preceded by 'Ready to'.", "Print via USB"))
self.setDescription(catalog.i18nc("@info:tooltip", "Print via USB")) self.setDescription(catalog.i18nc("@info:tooltip", "Print via USB"))
@ -179,7 +179,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
return return
CuraApplication.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerStackChanged) CuraApplication.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerStackChanged)
self._onGlobalContainerStackChanged() self._onGlobalContainerStackChanged()
self.setConnectionState(ConnectionState.connected) self.setConnectionState(ConnectionState.Connected)
self._update_thread.start() self._update_thread.start()
def _onGlobalContainerStackChanged(self): def _onGlobalContainerStackChanged(self):
@ -208,7 +208,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
self._sendCommand(command) self._sendCommand(command)
def _sendCommand(self, command: Union[str, bytes]): def _sendCommand(self, command: Union[str, bytes]):
if self._serial is None or self._connection_state != ConnectionState.connected: if self._serial is None or self._connection_state != ConnectionState.Connected:
return return
new_command = cast(bytes, command) if type(command) is bytes else cast(str, command).encode() # type: bytes new_command = cast(bytes, command) if type(command) is bytes else cast(str, command).encode() # type: bytes
@ -222,7 +222,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
self._command_received.set() self._command_received.set()
def _update(self): def _update(self):
while self._connection_state == ConnectionState.connected and self._serial is not None: while self._connection_state == ConnectionState.Connected and self._serial is not None:
try: try:
line = self._serial.readline() line = self._serial.readline()
except: except:

View file

@ -66,7 +66,7 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin):
return return
changed_device = self._usb_output_devices[serial_port] changed_device = self._usb_output_devices[serial_port]
if changed_device.connectionState == ConnectionState.connected: if changed_device.connectionState == ConnectionState.Connected:
self.getOutputDeviceManager().addOutputDevice(changed_device) self.getOutputDeviceManager().addOutputDevice(changed_device)
else: else:
self.getOutputDeviceManager().removeOutputDevice(serial_port) self.getOutputDeviceManager().removeOutputDevice(serial_port)

View file

@ -136,7 +136,7 @@ Cura.ExpandablePopup
onVisibleChanged: onVisibleChanged:
{ {
is_connected = Cura.MachineManager.activeMachineNetworkKey !== "" && Cura.MachineManager.printerConnected // Re-evaluate. is_connected = Cura.MachineManager.activeMachineHasRemoteConnection && Cura.MachineManager.printerConnected //Re-evaluate.
// If the printer is not connected, we switch always to the custom mode. If is connected instead, the auto mode // If the printer is not connected, we switch always to the custom mode. If is connected instead, the auto mode
// or the previous state is selected // or the previous state is selected

View file

@ -11,7 +11,7 @@ Cura.ExpandablePopup
{ {
id: machineSelector id: machineSelector
property bool isNetworkPrinter: Cura.MachineManager.activeMachineNetworkKey != "" property bool isNetworkPrinter: Cura.MachineManager.activeMachineHasRemoteConnection
property bool isPrinterConnected: Cura.MachineManager.printerConnected property bool isPrinterConnected: Cura.MachineManager.printerConnected
property var outputDevice: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null property var outputDevice: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null
@ -98,6 +98,12 @@ Cura.ExpandablePopup
scroll.height = Math.min(height, maximumHeight) scroll.height = Math.min(height, maximumHeight)
popup.height = scroll.height + buttonRow.height popup.height = scroll.height + buttonRow.height
} }
Component.onCompleted:
{
scroll.height = Math.min(height, maximumHeight)
popup.height = scroll.height + buttonRow.height
}
} }
} }

View file

@ -7,78 +7,40 @@ import QtQuick.Controls 2.3
import UM 1.2 as UM import UM 1.2 as UM
import Cura 1.0 as Cura import Cura 1.0 as Cura
Column ListView
{ {
id: machineSelectorList id: listView
height: childrenRect.height
model: Cura.PrintersModel {}
section.property: "hasRemoteConnection"
Label section.delegate: Label
{ {
text: catalog.i18nc("@label", "Connected printers") text: section == "true" ? catalog.i18nc("@label", "Connected printers") : catalog.i18nc("@label", "Preset printers")
visible: networkedPrintersModel.items.length > 0 width: parent.width
leftPadding: UM.Theme.getSize("default_margin").width
height: visible ? contentHeight + 2 * UM.Theme.getSize("default_margin").height : 0 height: visible ? contentHeight + 2 * UM.Theme.getSize("default_margin").height : 0
leftPadding: UM.Theme.getSize("default_margin").width
renderType: Text.NativeRendering renderType: Text.NativeRendering
font: UM.Theme.getFont("medium") font: UM.Theme.getFont("medium")
color: UM.Theme.getColor("text_medium") color: UM.Theme.getColor("text_medium")
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
} }
Repeater delegate: MachineSelectorButton
{ {
id: networkedPrinters text: model.name
width: listView.width
outputDevice: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null
model: UM.ContainerStacksModel checked:
{ {
id: networkedPrintersModel // If the machine has a remote connection
filter: var result = Cura.MachineManager.activeMachineId == model.id
if (Cura.MachineManager.activeMachineHasRemoteConnection)
{ {
"type": "machine", "um_network_key": "*", "hidden": "False" result |= Cura.MachineManager.activeMachineNetworkGroupName == model.metadata["connect_group_name"]
} }
} return result
delegate: MachineSelectorButton
{
text: model.metadata["connect_group_name"]
checked: Cura.MachineManager.activeMachineNetworkGroupName == model.metadata["connect_group_name"]
outputDevice: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null
Connections
{
target: Cura.MachineManager
onActiveMachineNetworkGroupNameChanged: checked = Cura.MachineManager.activeMachineNetworkGroupName == model.metadata["connect_group_name"]
}
}
}
Label
{
text: catalog.i18nc("@label", "Preset printers")
visible: virtualPrintersModel.items.length > 0
leftPadding: UM.Theme.getSize("default_margin").width
height: visible ? contentHeight + 2 * UM.Theme.getSize("default_margin").height : 0
renderType: Text.NativeRendering
font: UM.Theme.getFont("medium")
color: UM.Theme.getColor("text_medium")
verticalAlignment: Text.AlignVCenter
}
Repeater
{
id: virtualPrinters
model: UM.ContainerStacksModel
{
id: virtualPrintersModel
filter:
{
"type": "machine", "um_network_key": null
}
}
delegate: MachineSelectorButton
{
text: model.name
checked: Cura.MachineManager.activeMachineId == model.id
} }
} }
} }