mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-09 07:56:22 -06:00
Start inheriting both output devices from a base device
This commit is contained in:
parent
bd4f0c4e25
commit
4268c011a7
5 changed files with 79 additions and 140 deletions
|
@ -3,7 +3,7 @@
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from time import time
|
from time import time
|
||||||
from typing import Dict, List, Optional, Set, cast
|
from typing import List, Optional, Set, cast
|
||||||
|
|
||||||
from PyQt5.QtCore import QObject, QUrl, pyqtProperty, pyqtSignal, pyqtSlot
|
from PyQt5.QtCore import QObject, QUrl, pyqtProperty, pyqtSignal, pyqtSlot
|
||||||
from PyQt5.QtGui import QDesktopServices
|
from PyQt5.QtGui import QDesktopServices
|
||||||
|
@ -14,14 +14,13 @@ from UM.FileHandler.FileHandler import FileHandler
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
from UM.Message import Message
|
from UM.Message import Message
|
||||||
from UM.PluginRegistry import PluginRegistry
|
from UM.PluginRegistry import PluginRegistry
|
||||||
from UM.Qt.Duration import Duration, DurationFormat
|
|
||||||
from UM.Scene.SceneNode import SceneNode
|
from UM.Scene.SceneNode import SceneNode
|
||||||
from UM.Version import Version
|
from UM.Version import Version
|
||||||
|
|
||||||
from cura.CuraApplication import CuraApplication
|
from cura.CuraApplication import CuraApplication
|
||||||
from cura.PrinterOutput.NetworkedPrinterOutputDevice import AuthState, NetworkedPrinterOutputDevice
|
from cura.PrinterOutput.NetworkedPrinterOutputDevice import AuthState
|
||||||
from cura.PrinterOutput.Models.PrinterOutputModel import PrinterOutputModel
|
|
||||||
from cura.PrinterOutput.PrinterOutputDevice import ConnectionType
|
from cura.PrinterOutput.PrinterOutputDevice import ConnectionType
|
||||||
|
from plugins.UM3NetworkPrinting.src.UltimakerNetworkedPrinterOutputDevice import UltimakerNetworkedPrinterOutputDevice
|
||||||
|
|
||||||
from .CloudOutputController import CloudOutputController
|
from .CloudOutputController import CloudOutputController
|
||||||
from ..MeshFormatHandler import MeshFormatHandler
|
from ..MeshFormatHandler import MeshFormatHandler
|
||||||
|
@ -35,7 +34,7 @@ from plugins.UM3NetworkPrinting.src.Models.CloudPrintResponse import CloudPrintR
|
||||||
from plugins.UM3NetworkPrinting.src.Models.CloudPrintJobResponse import CloudPrintJobResponse
|
from plugins.UM3NetworkPrinting.src.Models.CloudPrintJobResponse import CloudPrintJobResponse
|
||||||
from plugins.UM3NetworkPrinting.src.Models.CloudClusterPrinterStatus import CloudClusterPrinterStatus
|
from plugins.UM3NetworkPrinting.src.Models.CloudClusterPrinterStatus import CloudClusterPrinterStatus
|
||||||
from plugins.UM3NetworkPrinting.src.Models.CloudClusterPrintJobStatus import CloudClusterPrintJobStatus
|
from plugins.UM3NetworkPrinting.src.Models.CloudClusterPrintJobStatus import CloudClusterPrintJobStatus
|
||||||
from .Utils import formatDateCompleted, formatTimeCompleted
|
|
||||||
|
|
||||||
I18N_CATALOG = i18nCatalog("cura")
|
I18N_CATALOG = i18nCatalog("cura")
|
||||||
|
|
||||||
|
@ -44,7 +43,8 @@ I18N_CATALOG = i18nCatalog("cura")
|
||||||
# Currently it only supports viewing the printer and print job status and adding a new job to the queue.
|
# Currently it only supports viewing the printer and print job status and adding a new job to the queue.
|
||||||
# As such, those methods have been implemented here.
|
# As such, those methods have been implemented here.
|
||||||
# Note that this device represents a single remote cluster, not a list of multiple clusters.
|
# Note that this device represents a single remote cluster, not a list of multiple clusters.
|
||||||
class CloudOutputDevice(NetworkedPrinterOutputDevice):
|
class CloudOutputDevice(UltimakerNetworkedPrinterOutputDevice):
|
||||||
|
|
||||||
# The interval with which the remote clusters are checked
|
# The interval with which the remote clusters are checked
|
||||||
CHECK_CLUSTER_INTERVAL = 10.0 # seconds
|
CHECK_CLUSTER_INTERVAL = 10.0 # seconds
|
||||||
|
|
||||||
|
@ -81,12 +81,11 @@ class CloudOutputDevice(NetworkedPrinterOutputDevice):
|
||||||
super().__init__(device_id=cluster.cluster_id, address="",
|
super().__init__(device_id=cluster.cluster_id, address="",
|
||||||
connection_type=ConnectionType.CloudConnection, properties=properties, parent=parent)
|
connection_type=ConnectionType.CloudConnection, properties=properties, parent=parent)
|
||||||
self._api = api_client
|
self._api = api_client
|
||||||
|
self._account = api_client.account
|
||||||
self._cluster = cluster
|
self._cluster = cluster
|
||||||
|
|
||||||
self._setInterfaceElements()
|
self._setInterfaceElements()
|
||||||
|
|
||||||
self._account = api_client.account
|
|
||||||
|
|
||||||
# We use the Cura Connect monitor tab to get most functionality right away.
|
# We use the Cura Connect monitor tab to get most functionality right away.
|
||||||
if PluginRegistry.getInstance() is not None:
|
if PluginRegistry.getInstance() is not None:
|
||||||
plugin_path = PluginRegistry.getInstance().getPluginPath("UM3NetworkPrinting")
|
plugin_path = PluginRegistry.getInstance().getPluginPath("UM3NetworkPrinting")
|
||||||
|
@ -98,13 +97,6 @@ class CloudOutputDevice(NetworkedPrinterOutputDevice):
|
||||||
# Trigger the printersChanged signal when the private signal is triggered.
|
# Trigger the printersChanged signal when the private signal is triggered.
|
||||||
self.printersChanged.connect(self._clusterPrintersChanged)
|
self.printersChanged.connect(self._clusterPrintersChanged)
|
||||||
|
|
||||||
# We keep track of which printer is visible in the monitor page.
|
|
||||||
self._active_printer = None # type: Optional[PrinterOutputModel]
|
|
||||||
|
|
||||||
# Properties to populate later on with received cloud data.
|
|
||||||
self._print_jobs = [] # type: List[UM3PrintJobOutputModel]
|
|
||||||
self._number_of_extruders = 2 # All networked printers are dual-extrusion Ultimaker machines.
|
|
||||||
|
|
||||||
# We only allow a single upload at a time.
|
# We only allow a single upload at a time.
|
||||||
self._progress = CloudProgressMessage()
|
self._progress = CloudProgressMessage()
|
||||||
|
|
||||||
|
@ -382,98 +374,27 @@ class CloudOutputDevice(NetworkedPrinterOutputDevice):
|
||||||
firmware_version = Version([version_number[0], version_number[1], version_number[2]])
|
firmware_version = Version([version_number[0], version_number[1], version_number[2]])
|
||||||
return firmware_version >= self.PRINT_JOB_ACTIONS_MIN_VERSION
|
return firmware_version >= self.PRINT_JOB_ACTIONS_MIN_VERSION
|
||||||
|
|
||||||
## Gets the number of printers in the cluster.
|
|
||||||
# We use a minimum of 1 because cloud devices are always a cluster and printer discovery needs it.
|
|
||||||
@pyqtProperty(int, notify=_clusterPrintersChanged)
|
|
||||||
def clusterSize(self) -> int:
|
|
||||||
return max(1, len(self._printers))
|
|
||||||
|
|
||||||
## Gets the remote printers.
|
|
||||||
@pyqtProperty("QVariantList", notify=_clusterPrintersChanged)
|
|
||||||
def printers(self) -> List[PrinterOutputModel]:
|
|
||||||
return self._printers
|
|
||||||
|
|
||||||
## Get the active printer in the UI (monitor page).
|
|
||||||
@pyqtProperty(QObject, notify=activePrinterChanged)
|
|
||||||
def activePrinter(self) -> Optional[PrinterOutputModel]:
|
|
||||||
return self._active_printer
|
|
||||||
|
|
||||||
## Set the active printer in the UI (monitor page).
|
|
||||||
@pyqtSlot(QObject)
|
|
||||||
def setActivePrinter(self, printer: Optional[PrinterOutputModel] = None) -> None:
|
|
||||||
if printer != self._active_printer:
|
|
||||||
self._active_printer = printer
|
|
||||||
self.activePrinterChanged.emit()
|
|
||||||
|
|
||||||
## Get remote print jobs.
|
|
||||||
@pyqtProperty("QVariantList", notify=printJobsChanged)
|
|
||||||
def printJobs(self) -> List[UM3PrintJobOutputModel]:
|
|
||||||
return self._print_jobs
|
|
||||||
|
|
||||||
## Get remote print jobs that are still in the print queue.
|
|
||||||
@pyqtProperty("QVariantList", notify=printJobsChanged)
|
|
||||||
def queuedPrintJobs(self) -> List[UM3PrintJobOutputModel]:
|
|
||||||
return [print_job for print_job in self._print_jobs
|
|
||||||
if print_job.state == "queued" or print_job.state == "error"]
|
|
||||||
|
|
||||||
## Get remote print jobs that are assigned to a printer.
|
|
||||||
@pyqtProperty("QVariantList", notify=printJobsChanged)
|
|
||||||
def activePrintJobs(self) -> List[UM3PrintJobOutputModel]:
|
|
||||||
return [print_job for print_job in self._print_jobs if
|
|
||||||
print_job.assignedPrinter is not None and print_job.state != "queued"]
|
|
||||||
|
|
||||||
## Set the remote print job state.
|
## Set the remote print job state.
|
||||||
def setJobState(self, print_job_uuid: str, state: str) -> None:
|
def setJobState(self, print_job_uuid: str, state: str) -> None:
|
||||||
self._api.doPrintJobAction(self._cluster.cluster_id, print_job_uuid, state)
|
self._api.doPrintJobAction(self._cluster.cluster_id, print_job_uuid, state)
|
||||||
|
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(str, name="sendJobToTop")
|
||||||
def sendJobToTop(self, print_job_uuid: str) -> None:
|
def sendJobToTop(self, print_job_uuid: str) -> None:
|
||||||
self._api.doPrintJobAction(self._cluster.cluster_id, print_job_uuid, "move",
|
self._api.doPrintJobAction(self._cluster.cluster_id, print_job_uuid, "move",
|
||||||
{"list": "queued", "to_position": 0})
|
{"list": "queued", "to_position": 0})
|
||||||
|
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(str, name="deleteJobFromQueue")
|
||||||
def deleteJobFromQueue(self, print_job_uuid: str) -> None:
|
def deleteJobFromQueue(self, print_job_uuid: str) -> None:
|
||||||
self._api.doPrintJobAction(self._cluster.cluster_id, print_job_uuid, "remove")
|
self._api.doPrintJobAction(self._cluster.cluster_id, print_job_uuid, "remove")
|
||||||
|
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(str, name="forceSendJob")
|
||||||
def forceSendJob(self, print_job_uuid: str) -> None:
|
def forceSendJob(self, print_job_uuid: str) -> None:
|
||||||
self._api.doPrintJobAction(self._cluster.cluster_id, print_job_uuid, "force")
|
self._api.doPrintJobAction(self._cluster.cluster_id, print_job_uuid, "force")
|
||||||
|
|
||||||
@pyqtSlot(int, result=str)
|
@pyqtSlot(name="openPrintJobControlPanel")
|
||||||
def formatDuration(self, seconds: int) -> str:
|
|
||||||
return Duration(seconds).getDisplayString(DurationFormat.Format.Short)
|
|
||||||
|
|
||||||
@pyqtSlot(int, result=str)
|
|
||||||
def getTimeCompleted(self, time_remaining: int) -> str:
|
|
||||||
return formatTimeCompleted(time_remaining)
|
|
||||||
|
|
||||||
@pyqtSlot(int, result=str)
|
|
||||||
def getDateCompleted(self, time_remaining: int) -> str:
|
|
||||||
return formatDateCompleted(time_remaining)
|
|
||||||
|
|
||||||
@pyqtProperty(bool, notify=printJobsChanged)
|
|
||||||
def receivedPrintJobs(self) -> bool:
|
|
||||||
return bool(self._print_jobs)
|
|
||||||
|
|
||||||
@pyqtSlot()
|
|
||||||
def openPrintJobControlPanel(self) -> None:
|
def openPrintJobControlPanel(self) -> None:
|
||||||
QDesktopServices.openUrl(QUrl("https://mycloud.ultimaker.com"))
|
QDesktopServices.openUrl(QUrl("https://mycloud.ultimaker.com"))
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot(name="openPrinterControlPanel")
|
||||||
def openPrinterControlPanel(self) -> None:
|
def openPrinterControlPanel(self) -> None:
|
||||||
QDesktopServices.openUrl(QUrl("https://mycloud.ultimaker.com"))
|
QDesktopServices.openUrl(QUrl("https://mycloud.ultimaker.com"))
|
||||||
|
|
||||||
## TODO: The following methods are required by the monitor page QML, but are not actually available using cloud.
|
|
||||||
# TODO: We fake the methods here to not break the monitor page.
|
|
||||||
|
|
||||||
@pyqtProperty(QUrl, notify=_clusterPrintersChanged)
|
|
||||||
def activeCameraUrl(self) -> "QUrl":
|
|
||||||
return QUrl()
|
|
||||||
|
|
||||||
@pyqtSlot(QUrl)
|
|
||||||
def setActiveCameraUrl(self, camera_url: "QUrl") -> None:
|
|
||||||
pass
|
|
||||||
|
|
||||||
@pyqtProperty("QVariantList", notify=_clusterPrintersChanged)
|
|
||||||
def connectedPrintersTypeCount(self) -> List[Dict[str, str]]:
|
|
||||||
return []
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ from .CloudApiClient import CloudApiClient
|
||||||
from .CloudOutputDevice import CloudOutputDevice
|
from .CloudOutputDevice import CloudOutputDevice
|
||||||
from plugins.UM3NetworkPrinting.src.Models.CloudClusterResponse import CloudClusterResponse
|
from plugins.UM3NetworkPrinting.src.Models.CloudClusterResponse import CloudClusterResponse
|
||||||
from plugins.UM3NetworkPrinting.src.Models.CloudError import CloudError
|
from plugins.UM3NetworkPrinting.src.Models.CloudError import CloudError
|
||||||
from .Utils import findChanges
|
from plugins.UM3NetworkPrinting.src.Utils import findChanges
|
||||||
|
|
||||||
|
|
||||||
## The cloud output device manager is responsible for using the Ultimaker Cloud APIs to manage remote clusters.
|
## The cloud output device manager is responsible for using the Ultimaker Cloud APIs to manage remote clusters.
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
# Copyright (c) 2019 Ultimaker B.V.
|
# Copyright (c) 2019 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
from typing import Any, cast, Tuple, Union, Optional, Dict, List
|
from typing import Any, cast, Tuple, Union, Optional, Dict, List
|
||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
|
@ -14,7 +13,6 @@ from UM.i18n import i18nCatalog
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
from UM.Message import Message
|
from UM.Message import Message
|
||||||
from UM.PluginRegistry import PluginRegistry
|
from UM.PluginRegistry import PluginRegistry
|
||||||
from UM.Qt.Duration import Duration, DurationFormat
|
|
||||||
from UM.Scene.SceneNode import SceneNode # For typing.
|
from UM.Scene.SceneNode import SceneNode # For typing.
|
||||||
from UM.Settings.ContainerRegistry import ContainerRegistry
|
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||||
|
|
||||||
|
@ -27,7 +25,6 @@ from cura.PrinterOutput.PrinterOutputDevice import ConnectionType
|
||||||
from plugins.UM3NetworkPrinting.src.Factories.PrinterModelFactory import PrinterModelFactory
|
from plugins.UM3NetworkPrinting.src.Factories.PrinterModelFactory import PrinterModelFactory
|
||||||
from plugins.UM3NetworkPrinting.src.UltimakerNetworkedPrinterOutputDevice import UltimakerNetworkedPrinterOutputDevice
|
from plugins.UM3NetworkPrinting.src.UltimakerNetworkedPrinterOutputDevice import UltimakerNetworkedPrinterOutputDevice
|
||||||
|
|
||||||
from plugins.UM3NetworkPrinting.src.Cloud.Utils import formatTimeCompleted, formatDateCompleted
|
|
||||||
from plugins.UM3NetworkPrinting.src.Network.ClusterUM3PrinterOutputController import ClusterUM3PrinterOutputController
|
from plugins.UM3NetworkPrinting.src.Network.ClusterUM3PrinterOutputController import ClusterUM3PrinterOutputController
|
||||||
from plugins.UM3NetworkPrinting.src.MeshFormatHandler import MeshFormatHandler
|
from plugins.UM3NetworkPrinting.src.MeshFormatHandler import MeshFormatHandler
|
||||||
from plugins.UM3NetworkPrinting.src.SendMaterialJob import SendMaterialJob
|
from plugins.UM3NetworkPrinting.src.SendMaterialJob import SendMaterialJob
|
||||||
|
@ -43,7 +40,6 @@ i18n_catalog = i18nCatalog("cura")
|
||||||
class ClusterUM3OutputDevice(UltimakerNetworkedPrinterOutputDevice):
|
class ClusterUM3OutputDevice(UltimakerNetworkedPrinterOutputDevice):
|
||||||
|
|
||||||
activeCameraUrlChanged = pyqtSignal()
|
activeCameraUrlChanged = pyqtSignal()
|
||||||
receivedPrintJobsChanged = 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, connection_type = ConnectionType.NetworkConnection, parent = parent)
|
super().__init__(device_id = device_id, address = address, properties=properties, connection_type = ConnectionType.NetworkConnection, parent = parent)
|
||||||
|
@ -57,8 +53,6 @@ class ClusterUM3OutputDevice(UltimakerNetworkedPrinterOutputDevice):
|
||||||
"", {}, io.BytesIO()
|
"", {}, io.BytesIO()
|
||||||
) # type: Tuple[Optional[str], Dict[str, Union[str, int, bool]], Union[io.StringIO, io.BytesIO]]
|
) # type: Tuple[Optional[str], Dict[str, Union[str, int, bool]], Union[io.StringIO, io.BytesIO]]
|
||||||
|
|
||||||
self._received_print_jobs = False # type: bool
|
|
||||||
|
|
||||||
if PluginRegistry.getInstance() is not None:
|
if PluginRegistry.getInstance() is not None:
|
||||||
plugin_path = PluginRegistry.getInstance().getPluginPath("UM3NetworkPrinting")
|
plugin_path = PluginRegistry.getInstance().getPluginPath("UM3NetworkPrinting")
|
||||||
if plugin_path is None:
|
if plugin_path is None:
|
||||||
|
@ -113,10 +107,9 @@ class ClusterUM3OutputDevice(UltimakerNetworkedPrinterOutputDevice):
|
||||||
|
|
||||||
if len(self._printers) > 1: # We need to ask the user.
|
if len(self._printers) > 1: # We need to ask the user.
|
||||||
self._spawnPrinterSelectionDialog()
|
self._spawnPrinterSelectionDialog()
|
||||||
is_job_sent = True
|
|
||||||
else: # Just immediately continue.
|
else: # Just immediately continue.
|
||||||
self._sending_job.send("") # No specifically selected printer.
|
self._sending_job.send("") # No specifically selected printer.
|
||||||
is_job_sent = self._sending_job.send(None)
|
self._sending_job.send(None)
|
||||||
|
|
||||||
def _spawnPrinterSelectionDialog(self):
|
def _spawnPrinterSelectionDialog(self):
|
||||||
if self._printer_selection_dialog is None:
|
if self._printer_selection_dialog is None:
|
||||||
|
@ -129,11 +122,6 @@ class ClusterUM3OutputDevice(UltimakerNetworkedPrinterOutputDevice):
|
||||||
if self._printer_selection_dialog is not None:
|
if self._printer_selection_dialog is not None:
|
||||||
self._printer_selection_dialog.show()
|
self._printer_selection_dialog.show()
|
||||||
|
|
||||||
## Whether the printer that this output device represents supports print job actions via the local network.
|
|
||||||
@pyqtProperty(bool, constant=True)
|
|
||||||
def supportsPrintJobActions(self) -> bool:
|
|
||||||
return True
|
|
||||||
|
|
||||||
## Allows the user to choose a printer to print with from the printer
|
## Allows the user to choose a printer to print with from the printer
|
||||||
# selection dialogue.
|
# selection dialogue.
|
||||||
# \param target_printer The name of the printer to target.
|
# \param target_printer The name of the printer to target.
|
||||||
|
@ -226,26 +214,26 @@ class ClusterUM3OutputDevice(UltimakerNetworkedPrinterOutputDevice):
|
||||||
on_progress = self._onUploadPrintJobProgress)
|
on_progress = self._onUploadPrintJobProgress)
|
||||||
|
|
||||||
@pyqtProperty(QUrl, notify=activeCameraUrlChanged)
|
@pyqtProperty(QUrl, notify=activeCameraUrlChanged)
|
||||||
def activeCameraUrl(self) -> "QUrl":
|
def activeCameraUrl(self) -> QUrl:
|
||||||
return self._active_camera_url
|
return self._active_camera_url
|
||||||
|
|
||||||
@pyqtSlot(QUrl)
|
@pyqtSlot(QUrl, name="setActiveCameraUrl")
|
||||||
def setActiveCameraUrl(self, camera_url: "QUrl") -> None:
|
def setActiveCameraUrl(self, camera_url: QUrl) -> None:
|
||||||
if self._active_camera_url != camera_url:
|
if self._active_camera_url != camera_url:
|
||||||
self._active_camera_url = camera_url
|
self._active_camera_url = camera_url
|
||||||
self.activeCameraUrlChanged.emit()
|
self.activeCameraUrlChanged.emit()
|
||||||
|
|
||||||
|
## The IP address of the printer.
|
||||||
|
@pyqtProperty(str, constant = True)
|
||||||
|
def address(self) -> str:
|
||||||
|
return self._address
|
||||||
|
|
||||||
def _onPostPrintJobFinished(self, reply: QNetworkReply) -> None:
|
def _onPostPrintJobFinished(self, reply: QNetworkReply) -> None:
|
||||||
if self._progress_message:
|
if self._progress_message:
|
||||||
self._progress_message.hide()
|
self._progress_message.hide()
|
||||||
self._compressing_gcode = False
|
self._compressing_gcode = False
|
||||||
self._sending_gcode = False
|
self._sending_gcode = False
|
||||||
|
|
||||||
## The IP address of the printer.
|
|
||||||
@pyqtProperty(str, constant = True)
|
|
||||||
def address(self) -> str:
|
|
||||||
return self._address
|
|
||||||
|
|
||||||
def _onUploadPrintJobProgress(self, bytes_sent: int, bytes_total: int) -> None:
|
def _onUploadPrintJobProgress(self, bytes_sent: int, bytes_total: int) -> None:
|
||||||
if bytes_total > 0:
|
if bytes_total > 0:
|
||||||
new_progress = bytes_sent / bytes_total * 100
|
new_progress = bytes_sent / bytes_total * 100
|
||||||
|
@ -294,44 +282,26 @@ class ClusterUM3OutputDevice(UltimakerNetworkedPrinterOutputDevice):
|
||||||
|
|
||||||
@pyqtSlot(name="openPrintJobControlPanel")
|
@pyqtSlot(name="openPrintJobControlPanel")
|
||||||
def openPrintJobControlPanel(self) -> None:
|
def openPrintJobControlPanel(self) -> None:
|
||||||
Logger.log("d", "Opening print job control panel...")
|
|
||||||
QDesktopServices.openUrl(QUrl("http://" + self._address + "/print_jobs"))
|
QDesktopServices.openUrl(QUrl("http://" + self._address + "/print_jobs"))
|
||||||
|
|
||||||
@pyqtSlot(name="openPrinterControlPanel")
|
@pyqtSlot(name="openPrinterControlPanel")
|
||||||
def openPrinterControlPanel(self) -> None:
|
def openPrinterControlPanel(self) -> None:
|
||||||
Logger.log("d", "Opening printer control panel...")
|
|
||||||
QDesktopServices.openUrl(QUrl("http://" + self._address + "/printers"))
|
QDesktopServices.openUrl(QUrl("http://" + self._address + "/printers"))
|
||||||
|
|
||||||
@pyqtProperty(bool, notify = receivedPrintJobsChanged)
|
@pyqtSlot(str, name="sendJobToTop")
|
||||||
def receivedPrintJobs(self) -> bool:
|
|
||||||
return self._received_print_jobs
|
|
||||||
|
|
||||||
@pyqtSlot(int, result = str)
|
|
||||||
def getTimeCompleted(self, time_remaining: int) -> str:
|
|
||||||
return formatTimeCompleted(time_remaining)
|
|
||||||
|
|
||||||
@pyqtSlot(int, result = str)
|
|
||||||
def getDateCompleted(self, time_remaining: int) -> str:
|
|
||||||
return formatDateCompleted(time_remaining)
|
|
||||||
|
|
||||||
@pyqtSlot(int, result = str)
|
|
||||||
def formatDuration(self, seconds: int) -> str:
|
|
||||||
return Duration(seconds).getDisplayString(DurationFormat.Format.Short)
|
|
||||||
|
|
||||||
@pyqtSlot(str)
|
|
||||||
def sendJobToTop(self, print_job_uuid: str) -> None:
|
def sendJobToTop(self, print_job_uuid: str) -> None:
|
||||||
# This function is part of the output device (and not of the printjob output model) as this type of operation
|
# This function is part of the output device (and not of the printjob output model) as this type of operation
|
||||||
# is a modification of the cluster queue and not of the actual job.
|
# is a modification of the cluster queue and not of the actual job.
|
||||||
data = "{\"to_position\": 0}"
|
data = "{\"to_position\": 0}"
|
||||||
self.put("print_jobs/{uuid}/move_to_position".format(uuid = print_job_uuid), data, on_finished=None)
|
self.put("print_jobs/{uuid}/move_to_position".format(uuid = print_job_uuid), data, on_finished=None)
|
||||||
|
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(str, name="deleteJobFromQueue")
|
||||||
def deleteJobFromQueue(self, print_job_uuid: str) -> None:
|
def deleteJobFromQueue(self, print_job_uuid: str) -> None:
|
||||||
# This function is part of the output device (and not of the printjob output model) as this type of operation
|
# This function is part of the output device (and not of the printjob output model) as this type of operation
|
||||||
# is a modification of the cluster queue and not of the actual job.
|
# is a modification of the cluster queue and not of the actual job.
|
||||||
self.delete("print_jobs/{uuid}".format(uuid = print_job_uuid), on_finished=None)
|
self.delete("print_jobs/{uuid}".format(uuid = print_job_uuid), on_finished=None)
|
||||||
|
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(str, name="forceSendJob")
|
||||||
def forceSendJob(self, print_job_uuid: str) -> None:
|
def forceSendJob(self, print_job_uuid: str) -> None:
|
||||||
data = "{\"force\": true}"
|
data = "{\"force\": true}"
|
||||||
self.put("print_jobs/{uuid}".format(uuid=print_job_uuid), data, on_finished=None)
|
self.put("print_jobs/{uuid}".format(uuid=print_job_uuid), data, on_finished=None)
|
||||||
|
@ -392,9 +362,6 @@ class ClusterUM3OutputDevice(UltimakerNetworkedPrinterOutputDevice):
|
||||||
self.get("print_jobs/{uuid}/preview_image".format(uuid=print_job.key), on_finished=self._onGetPreviewImageFinished)
|
self.get("print_jobs/{uuid}/preview_image".format(uuid=print_job.key), on_finished=self._onGetPreviewImageFinished)
|
||||||
|
|
||||||
def _onGetPrintJobsFinished(self, reply: QNetworkReply) -> None:
|
def _onGetPrintJobsFinished(self, reply: QNetworkReply) -> None:
|
||||||
self._received_print_jobs = True
|
|
||||||
self.receivedPrintJobsChanged.emit()
|
|
||||||
|
|
||||||
if not checkValidGetReply(reply):
|
if not checkValidGetReply(reply):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -634,6 +601,7 @@ class ClusterUM3OutputDevice(UltimakerNetworkedPrinterOutputDevice):
|
||||||
job = SendMaterialJob(device = self)
|
job = SendMaterialJob(device = self)
|
||||||
job.run()
|
job.run()
|
||||||
|
|
||||||
|
|
||||||
def loadJsonFromReply(reply: QNetworkReply) -> Optional[List[Dict[str, Any]]]:
|
def loadJsonFromReply(reply: QNetworkReply) -> Optional[List[Dict[str, Any]]]:
|
||||||
try:
|
try:
|
||||||
result = json.loads(bytes(reply.readAll()).decode("utf-8"))
|
result = json.loads(bytes(reply.readAll()).decode("utf-8"))
|
||||||
|
|
|
@ -2,10 +2,12 @@
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
from typing import List, Optional, Dict
|
from typing import List, Optional, Dict
|
||||||
|
|
||||||
from PyQt5.QtCore import pyqtProperty, pyqtSignal, QObject, pyqtSlot
|
from PyQt5.QtCore import pyqtProperty, pyqtSignal, QObject, pyqtSlot, QUrl
|
||||||
|
|
||||||
|
from UM.Qt.Duration import Duration, DurationFormat
|
||||||
from cura.PrinterOutput.Models.PrinterOutputModel import PrinterOutputModel
|
from cura.PrinterOutput.Models.PrinterOutputModel import PrinterOutputModel
|
||||||
from cura.PrinterOutput.NetworkedPrinterOutputDevice import NetworkedPrinterOutputDevice, AuthState
|
from cura.PrinterOutput.NetworkedPrinterOutputDevice import NetworkedPrinterOutputDevice, AuthState
|
||||||
|
from plugins.UM3NetworkPrinting.src.Utils import formatTimeCompleted, formatDateCompleted
|
||||||
from plugins.UM3NetworkPrinting.src.Models.UM3PrintJobOutputModel import UM3PrintJobOutputModel
|
from plugins.UM3NetworkPrinting.src.Models.UM3PrintJobOutputModel import UM3PrintJobOutputModel
|
||||||
|
|
||||||
|
|
||||||
|
@ -31,6 +33,9 @@ class UltimakerNetworkedPrinterOutputDevice(NetworkedPrinterOutputDevice):
|
||||||
super().__init__(device_id=device_id, address=address, properties=properties, connection_type=connection_type,
|
super().__init__(device_id=device_id, address=address, properties=properties, connection_type=connection_type,
|
||||||
parent=parent)
|
parent=parent)
|
||||||
|
|
||||||
|
# Trigger the printersChanged signal when the private signal is triggered.
|
||||||
|
self.printersChanged.connect(self._clusterPrintersChanged)
|
||||||
|
|
||||||
# Keeps track of all print jobs in the cluster.
|
# Keeps track of all print jobs in the cluster.
|
||||||
self._print_jobs = [] # type: List[UM3PrintJobOutputModel]
|
self._print_jobs = [] # type: List[UM3PrintJobOutputModel]
|
||||||
|
|
||||||
|
@ -56,10 +61,14 @@ class UltimakerNetworkedPrinterOutputDevice(NetworkedPrinterOutputDevice):
|
||||||
return [print_job for print_job in self._print_jobs if
|
return [print_job for print_job in self._print_jobs if
|
||||||
print_job.assignedPrinter is not None and print_job.state not in self.QUEUED_PRINT_JOBS_STATES]
|
print_job.assignedPrinter is not None and print_job.state not in self.QUEUED_PRINT_JOBS_STATES]
|
||||||
|
|
||||||
|
@pyqtProperty(bool, notify=printJobsChanged)
|
||||||
|
def receivedPrintJobs(self) -> bool:
|
||||||
|
return bool(self._print_jobs)
|
||||||
|
|
||||||
# Get the amount of printers in the cluster.
|
# Get the amount of printers in the cluster.
|
||||||
@pyqtProperty(int, notify=_clusterPrintersChanged)
|
@pyqtProperty(int, notify=_clusterPrintersChanged)
|
||||||
def clusterSize(self) -> int:
|
def clusterSize(self) -> int:
|
||||||
return self._cluster_size
|
return max(1, len(self._printers))
|
||||||
|
|
||||||
# Get the amount of printer in the cluster per type.
|
# Get the amount of printer in the cluster per type.
|
||||||
@pyqtProperty("QVariantList", notify=_clusterPrintersChanged)
|
@pyqtProperty("QVariantList", notify=_clusterPrintersChanged)
|
||||||
|
@ -93,6 +102,27 @@ class UltimakerNetworkedPrinterOutputDevice(NetworkedPrinterOutputDevice):
|
||||||
self._active_printer = printer
|
self._active_printer = printer
|
||||||
self.activePrinterChanged.emit()
|
self.activePrinterChanged.emit()
|
||||||
|
|
||||||
|
## Whether the printer that this output device represents supports print job actions via the local network.
|
||||||
|
@pyqtProperty(bool, constant=True)
|
||||||
|
def supportsPrintJobActions(self) -> bool:
|
||||||
|
return True
|
||||||
|
|
||||||
|
## Set the remote print job state.
|
||||||
|
def setJobState(self, print_job_uuid: str, state: str) -> None:
|
||||||
|
raise NotImplementedError("setJobState must be implemented")
|
||||||
|
|
||||||
|
@pyqtSlot(str, name="sendJobToTop")
|
||||||
|
def sendJobToTop(self, print_job_uuid: str) -> None:
|
||||||
|
raise NotImplementedError("sendJobToTop must be implemented")
|
||||||
|
|
||||||
|
@pyqtSlot(str, name="deleteJobFromQueue")
|
||||||
|
def deleteJobFromQueue(self, print_job_uuid: str) -> None:
|
||||||
|
raise NotImplementedError("deleteJobFromQueue must be implemented")
|
||||||
|
|
||||||
|
@pyqtSlot(str, name="forceSendJob")
|
||||||
|
def forceSendJob(self, print_job_uuid: str) -> None:
|
||||||
|
raise NotImplementedError("forceSendJob must be implemented")
|
||||||
|
|
||||||
@pyqtSlot(name="openPrintJobControlPanel")
|
@pyqtSlot(name="openPrintJobControlPanel")
|
||||||
def openPrintJobControlPanel(self) -> None:
|
def openPrintJobControlPanel(self) -> None:
|
||||||
raise NotImplementedError("openPrintJobControlPanel must be implemented")
|
raise NotImplementedError("openPrintJobControlPanel must be implemented")
|
||||||
|
@ -100,3 +130,23 @@ class UltimakerNetworkedPrinterOutputDevice(NetworkedPrinterOutputDevice):
|
||||||
@pyqtSlot(name="openPrinterControlPanel")
|
@pyqtSlot(name="openPrinterControlPanel")
|
||||||
def openPrinterControlPanel(self) -> None:
|
def openPrinterControlPanel(self) -> None:
|
||||||
raise NotImplementedError("openPrinterControlPanel must be implemented")
|
raise NotImplementedError("openPrinterControlPanel must be implemented")
|
||||||
|
|
||||||
|
@pyqtProperty(QUrl, notify=_clusterPrintersChanged)
|
||||||
|
def activeCameraUrl(self) -> QUrl:
|
||||||
|
return QUrl()
|
||||||
|
|
||||||
|
@pyqtSlot(QUrl, name="setActiveCameraUrl")
|
||||||
|
def setActiveCameraUrl(self, camera_url: QUrl) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@pyqtSlot(int, result=str, name="getTimeCompleted")
|
||||||
|
def getTimeCompleted(self, time_remaining: int) -> str:
|
||||||
|
return formatTimeCompleted(time_remaining)
|
||||||
|
|
||||||
|
@pyqtSlot(int, result=str, name="getDateCompleted")
|
||||||
|
def getDateCompleted(self, time_remaining: int) -> str:
|
||||||
|
return formatDateCompleted(time_remaining)
|
||||||
|
|
||||||
|
@pyqtSlot(int, result=str, name="formatDuration")
|
||||||
|
def formatDuration(self, seconds: int) -> str:
|
||||||
|
return Duration(seconds).getDisplayString(DurationFormat.Format.Short)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue