mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-11 16:57:51 -06:00
Merge more stuff, re-use models for local networking as well
This commit is contained in:
parent
8f37c83b9c
commit
4b212d6c05
31 changed files with 688 additions and 975 deletions
|
@ -1,7 +1,5 @@
|
|||
# Copyright (c) 2018 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
import os
|
||||
|
||||
from time import time
|
||||
from typing import List, Optional, Set, cast
|
||||
|
||||
|
@ -13,27 +11,24 @@ from UM.Backend.Backend import BackendState
|
|||
from UM.FileHandler.FileHandler import FileHandler
|
||||
from UM.Logger import Logger
|
||||
from UM.Message import Message
|
||||
from UM.PluginRegistry import PluginRegistry
|
||||
from UM.Scene.SceneNode import SceneNode
|
||||
from UM.Version import Version
|
||||
|
||||
from cura.CuraApplication import CuraApplication
|
||||
from cura.PrinterOutput.NetworkedPrinterOutputDevice import AuthState
|
||||
from cura.PrinterOutput.PrinterOutputDevice import ConnectionType
|
||||
from plugins.UM3NetworkPrinting.src.UltimakerNetworkedPrinterOutputDevice import UltimakerNetworkedPrinterOutputDevice
|
||||
|
||||
from .CloudOutputController import CloudOutputController
|
||||
from ..MeshFormatHandler import MeshFormatHandler
|
||||
from plugins.UM3NetworkPrinting.src.Models.UM3PrintJobOutputModel import UM3PrintJobOutputModel
|
||||
from .CloudProgressMessage import CloudProgressMessage
|
||||
from .CloudApiClient import CloudApiClient
|
||||
from plugins.UM3NetworkPrinting.src.Models.CloudClusterResponse import CloudClusterResponse
|
||||
from plugins.UM3NetworkPrinting.src.Models.CloudClusterStatus import CloudClusterStatus
|
||||
from plugins.UM3NetworkPrinting.src.Models.CloudPrintJobUploadRequest import CloudPrintJobUploadRequest
|
||||
from plugins.UM3NetworkPrinting.src.Models.CloudPrintResponse import CloudPrintResponse
|
||||
from plugins.UM3NetworkPrinting.src.Models.CloudPrintJobResponse import CloudPrintJobResponse
|
||||
from plugins.UM3NetworkPrinting.src.Models.CloudClusterPrinterStatus import CloudClusterPrinterStatus
|
||||
from plugins.UM3NetworkPrinting.src.Models.CloudClusterPrintJobStatus import CloudClusterPrintJobStatus
|
||||
from ..UltimakerNetworkedPrinterOutputDevice import UltimakerNetworkedPrinterOutputDevice
|
||||
from ..MeshFormatHandler import MeshFormatHandler
|
||||
from ..Models.Http.CloudClusterResponse import CloudClusterResponse
|
||||
from ..Models.Http.CloudClusterStatus import CloudClusterStatus
|
||||
from ..Models.Http.CloudPrintJobUploadRequest import CloudPrintJobUploadRequest
|
||||
from ..Models.Http.CloudPrintResponse import CloudPrintResponse
|
||||
from ..Models.Http.CloudPrintJobResponse import CloudPrintJobResponse
|
||||
from ..Models.Http.ClusterPrinterStatus import ClusterPrinterStatus
|
||||
from ..Models.Http.ClusterPrintJobStatus import ClusterPrintJobStatus
|
||||
|
||||
|
||||
I18N_CATALOG = i18nCatalog("cura")
|
||||
|
@ -78,22 +73,21 @@ class CloudOutputDevice(UltimakerNetworkedPrinterOutputDevice):
|
|||
b"cluster_size": b"1" # cloud devices are always clusters of at least one
|
||||
}
|
||||
|
||||
super().__init__(device_id=cluster.cluster_id, address="",
|
||||
connection_type=ConnectionType.CloudConnection, properties=properties, parent=parent)
|
||||
super().__init__(
|
||||
device_id=cluster.cluster_id,
|
||||
address="",
|
||||
connection_type=ConnectionType.CloudConnection,
|
||||
properties=properties,
|
||||
parent=parent
|
||||
)
|
||||
|
||||
self._api = api_client
|
||||
self._account = api_client.account
|
||||
self._cluster = cluster
|
||||
self.setAuthenticationState(AuthState.NotAuthenticated)
|
||||
|
||||
self._setInterfaceElements()
|
||||
|
||||
# We use the Cura Connect monitor tab to get most functionality right away.
|
||||
if PluginRegistry.getInstance() is not None:
|
||||
plugin_path = PluginRegistry.getInstance().getPluginPath("UM3NetworkPrinting")
|
||||
if plugin_path is None:
|
||||
Logger.log("e", "Cloud not find plugin path for plugin UM3NetworkPrnting")
|
||||
raise RuntimeError("Cloud not find plugin path for plugin UM3NetworkPrnting")
|
||||
self._monitor_view_qml_path = os.path.join(plugin_path, "resources", "qml", "MonitorStage.qml")
|
||||
|
||||
# Trigger the printersChanged signal when the private signal is triggered.
|
||||
self.printersChanged.connect(self._clusterPrintersChanged)
|
||||
|
||||
|
@ -101,11 +95,8 @@ class CloudOutputDevice(UltimakerNetworkedPrinterOutputDevice):
|
|||
self._progress = CloudProgressMessage()
|
||||
|
||||
# Keep server string of the last generated time to avoid updating models more than once for the same response
|
||||
self._received_printers = None # type: Optional[List[CloudClusterPrinterStatus]]
|
||||
self._received_print_jobs = None # type: Optional[List[CloudClusterPrintJobStatus]]
|
||||
|
||||
# A set of the user's job IDs that have finished
|
||||
self._finished_jobs = set() # type: Set[str]
|
||||
self._received_printers = None # type: Optional[List[ClusterPrinterStatus]]
|
||||
self._received_print_jobs = None # type: Optional[List[ClusterPrintJobStatus]]
|
||||
|
||||
# Reference to the uploaded print job / mesh
|
||||
self._tool_path = None # type: Optional[bytes]
|
||||
|
@ -130,33 +121,21 @@ class CloudOutputDevice(UltimakerNetworkedPrinterOutputDevice):
|
|||
self._tool_path = None
|
||||
self._uploaded_print_job = None
|
||||
|
||||
## Gets the cluster response from which this device was created.
|
||||
@property
|
||||
def clusterData(self) -> CloudClusterResponse:
|
||||
return self._cluster
|
||||
|
||||
## Updates the cluster data from the cloud.
|
||||
@clusterData.setter
|
||||
def clusterData(self, value: CloudClusterResponse) -> None:
|
||||
self._cluster = value
|
||||
|
||||
## Checks whether the given network key is found in the cloud's host name
|
||||
def matchesNetworkKey(self, network_key: str) -> bool:
|
||||
# Typically, a network key looks like "ultimakersystem-aabbccdd0011._ultimaker._tcp.local."
|
||||
# the host name should then be "ultimakersystem-aabbccdd0011"
|
||||
if network_key.startswith(self.clusterData.host_name):
|
||||
return True
|
||||
|
||||
# However, for manually added printers, the local IP address is used in lieu of a proper
|
||||
# network key, so check for that as well
|
||||
if self.clusterData.host_internal_ip is not None and network_key.find(self.clusterData.host_internal_ip):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
## Set all the interface elements and texts for this output device.
|
||||
def _setInterfaceElements(self) -> None:
|
||||
self.setPriority(2) # Make sure we end up below the local networking and above 'save to file'
|
||||
self.setPriority(2) # Make sure we end up below the local networking and above 'save to file'.
|
||||
self.setName(self._id)
|
||||
self.setShortDescription(I18N_CATALOG.i18nc("@action:button", "Print via Cloud"))
|
||||
self.setDescription(I18N_CATALOG.i18nc("@properties:tooltip", "Print via Cloud"))
|
||||
|
@ -227,105 +206,6 @@ class CloudOutputDevice(UltimakerNetworkedPrinterOutputDevice):
|
|||
self._received_print_jobs = status.print_jobs
|
||||
self._updatePrintJobs(status.print_jobs)
|
||||
|
||||
## Updates the local list of printers with the list received from the cloud.
|
||||
# \param remote_printers: The printers received from the cloud.
|
||||
def _updatePrinters(self, remote_printers: List[CloudClusterPrinterStatus]) -> None:
|
||||
|
||||
# Keep track of the new printers to show.
|
||||
# We create a new list instead of changing the existing one to get the correct order.
|
||||
new_printers = []
|
||||
|
||||
# Check which printers need to be created or updated.
|
||||
for index, printer_data in enumerate(remote_printers):
|
||||
printer = next(iter(printer for printer in self._printers if printer.key == printer_data.uuid), None)
|
||||
if not printer:
|
||||
new_printers.append(printer_data.createOutputModel(CloudOutputController(self)))
|
||||
else:
|
||||
printer_data.updateOutputModel(printer)
|
||||
new_printers.append(printer)
|
||||
|
||||
# Check which printers need to be removed (de-referenced).
|
||||
remote_printers_keys = [printer_data.uuid for printer_data in remote_printers]
|
||||
removed_printers = [printer for printer in self._printers if printer.key not in remote_printers_keys]
|
||||
for removed_printer in removed_printers:
|
||||
if self._active_printer and self._active_printer.key == removed_printer.key:
|
||||
self.setActivePrinter(None)
|
||||
|
||||
self._printers = new_printers
|
||||
if self._printers and not self.activePrinter:
|
||||
self.setActivePrinter(self._printers[0])
|
||||
|
||||
self.printersChanged.emit()
|
||||
|
||||
## Updates the local list of print jobs with the list received from the cloud.
|
||||
# \param remote_jobs: The print jobs received from the cloud.
|
||||
def _updatePrintJobs(self, remote_jobs: List[CloudClusterPrintJobStatus]) -> None:
|
||||
|
||||
# Keep track of the new print jobs to show.
|
||||
# We create a new list instead of changing the existing one to get the correct order.
|
||||
new_print_jobs = []
|
||||
|
||||
# Check which print jobs need to be created or updated.
|
||||
for index, print_job_data in enumerate(remote_jobs):
|
||||
print_job = next(
|
||||
iter(print_job for print_job in self._print_jobs if print_job.key == print_job_data.uuid), None)
|
||||
if not print_job:
|
||||
new_print_jobs.append(self._createPrintJobModel(print_job_data))
|
||||
else:
|
||||
print_job_data.updateOutputModel(print_job)
|
||||
if print_job_data.printer_uuid:
|
||||
self._updateAssignedPrinter(print_job, print_job_data.printer_uuid)
|
||||
new_print_jobs.append(print_job)
|
||||
|
||||
# Check which print job need to be removed (de-referenced).
|
||||
remote_job_keys = [print_job_data.uuid for print_job_data in remote_jobs]
|
||||
removed_jobs = [print_job for print_job in self._print_jobs if print_job.key not in remote_job_keys]
|
||||
for removed_job in removed_jobs:
|
||||
if removed_job.assignedPrinter:
|
||||
removed_job.assignedPrinter.updateActivePrintJob(None)
|
||||
removed_job.stateChanged.disconnect(self._onPrintJobStateChanged)
|
||||
|
||||
self._print_jobs = new_print_jobs
|
||||
self.printJobsChanged.emit()
|
||||
|
||||
## Create a new print job model based on the remote status of the job.
|
||||
# \param remote_job: The remote print job data.
|
||||
def _createPrintJobModel(self, remote_job: CloudClusterPrintJobStatus) -> UM3PrintJobOutputModel:
|
||||
model = remote_job.createOutputModel(CloudOutputController(self))
|
||||
model.stateChanged.connect(self._onPrintJobStateChanged)
|
||||
if remote_job.printer_uuid:
|
||||
self._updateAssignedPrinter(model, remote_job.printer_uuid)
|
||||
return model
|
||||
|
||||
## Handles the event of a change in a print job state
|
||||
def _onPrintJobStateChanged(self) -> None:
|
||||
user_name = self._getUserName()
|
||||
# TODO: confirm that notifications in Cura are still required
|
||||
for job in self._print_jobs:
|
||||
if job.state == "wait_cleanup" and job.key not in self._finished_jobs and job.owner == user_name:
|
||||
self._finished_jobs.add(job.key)
|
||||
Message(
|
||||
title=I18N_CATALOG.i18nc("@info:status", "Print finished"),
|
||||
text=(I18N_CATALOG.i18nc("@info:status",
|
||||
"Printer '{printer_name}' has finished printing '{job_name}'.").format(
|
||||
printer_name=job.assignedPrinter.name,
|
||||
job_name=job.name
|
||||
) if job.assignedPrinter else
|
||||
I18N_CATALOG.i18nc("@info:status", "The print job '{job_name}' was finished.").format(
|
||||
job_name=job.name
|
||||
)),
|
||||
).show()
|
||||
|
||||
## Updates the printer assignment for the given print job model.
|
||||
def _updateAssignedPrinter(self, model: UM3PrintJobOutputModel, printer_uuid: str) -> None:
|
||||
printer = next((p for p in self._printers if printer_uuid == p.key), None)
|
||||
if not printer:
|
||||
Logger.log("w", "Missing printer %s for job %s in %s", model.assignedPrinter, model.key,
|
||||
[p.key for p in self._printers])
|
||||
return
|
||||
printer.updateActivePrintJob(model)
|
||||
model.updateAssignedPrinter(printer)
|
||||
|
||||
## Uploads the mesh when the print job was registered with the cloud API.
|
||||
# \param job_response: The response received from the cloud API.
|
||||
def _onPrintJobCreated(self, job_response: CloudPrintJobResponse) -> None:
|
||||
|
@ -398,3 +278,13 @@ class CloudOutputDevice(UltimakerNetworkedPrinterOutputDevice):
|
|||
@pyqtSlot(name="openPrinterControlPanel")
|
||||
def openPrinterControlPanel(self) -> None:
|
||||
QDesktopServices.openUrl(QUrl("https://mycloud.ultimaker.com"))
|
||||
|
||||
## Gets the cluster response from which this device was created.
|
||||
@property
|
||||
def clusterData(self) -> CloudClusterResponse:
|
||||
return self._cluster
|
||||
|
||||
## Updates the cluster data from the cloud.
|
||||
@clusterData.setter
|
||||
def clusterData(self, value: CloudClusterResponse) -> None:
|
||||
self._cluster = value
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue