PrintJobOutputModel.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. # Copyright (c) 2018 Ultimaker B.V.
  2. # Cura is released under the terms of the LGPLv3 or higher.
  3. from typing import Optional, TYPE_CHECKING, List
  4. from PyQt5.QtCore import pyqtSignal, pyqtProperty, QObject, pyqtSlot, QUrl
  5. from PyQt5.QtGui import QImage
  6. if TYPE_CHECKING:
  7. from cura.PrinterOutput.PrinterOutputController import PrinterOutputController
  8. from cura.PrinterOutput.Models.PrinterOutputModel import PrinterOutputModel
  9. from cura.PrinterOutput.Models.PrinterConfigurationModel import PrinterConfigurationModel
  10. class PrintJobOutputModel(QObject):
  11. stateChanged = pyqtSignal()
  12. timeTotalChanged = pyqtSignal()
  13. timeElapsedChanged = pyqtSignal()
  14. nameChanged = pyqtSignal()
  15. keyChanged = pyqtSignal()
  16. assignedPrinterChanged = pyqtSignal()
  17. ownerChanged = pyqtSignal()
  18. configurationChanged = pyqtSignal()
  19. previewImageChanged = pyqtSignal()
  20. compatibleMachineFamiliesChanged = pyqtSignal()
  21. def __init__(self, output_controller: "PrinterOutputController", key: str = "", name: str = "", parent = None) -> None:
  22. super().__init__(parent)
  23. self._output_controller = output_controller
  24. self._state = ""
  25. self._time_total = 0
  26. self._time_elapsed = 0
  27. self._name = name # Human readable name
  28. self._key = key # Unique identifier
  29. self._assigned_printer = None # type: Optional[PrinterOutputModel]
  30. self._owner = "" # Who started/owns the print job?
  31. self._configuration = None # type: Optional[PrinterConfigurationModel]
  32. self._compatible_machine_families = [] # type: List[str]
  33. self._preview_image_id = 0
  34. self._preview_image = None # type: Optional[QImage]
  35. @pyqtProperty("QStringList", notify=compatibleMachineFamiliesChanged)
  36. def compatibleMachineFamilies(self) -> List[str]:
  37. # Hack; Some versions of cluster will return a family more than once...
  38. return list(set(self._compatible_machine_families))
  39. def setCompatibleMachineFamilies(self, compatible_machine_families: List[str]) -> None:
  40. if self._compatible_machine_families != compatible_machine_families:
  41. self._compatible_machine_families = compatible_machine_families
  42. self.compatibleMachineFamiliesChanged.emit()
  43. @pyqtProperty(QUrl, notify=previewImageChanged)
  44. def previewImageUrl(self):
  45. self._preview_image_id += 1
  46. # There is an image provider that is called "print_job_preview". In order to ensure that the image qml object, that
  47. # requires a QUrl to function, updates correctly we add an increasing number. This causes to see the QUrl
  48. # as new (instead of relying on cached version and thus forces an update.
  49. temp = "image://print_job_preview/" + str(self._preview_image_id) + "/" + self._key
  50. return QUrl(temp, QUrl.TolerantMode)
  51. def getPreviewImage(self) -> Optional[QImage]:
  52. return self._preview_image
  53. def updatePreviewImage(self, preview_image: Optional[QImage]) -> None:
  54. if self._preview_image != preview_image:
  55. self._preview_image = preview_image
  56. self.previewImageChanged.emit()
  57. @pyqtProperty(QObject, notify=configurationChanged)
  58. def configuration(self) -> Optional["PrinterConfigurationModel"]:
  59. return self._configuration
  60. def updateConfiguration(self, configuration: Optional["PrinterConfigurationModel"]) -> None:
  61. if self._configuration != configuration:
  62. self._configuration = configuration
  63. self.configurationChanged.emit()
  64. @pyqtProperty(str, notify = ownerChanged)
  65. def owner(self) -> str:
  66. return self._owner
  67. def updateOwner(self, owner: str) -> None:
  68. if self._owner != owner:
  69. self._owner = owner
  70. self.ownerChanged.emit()
  71. @pyqtProperty(QObject, notify=assignedPrinterChanged)
  72. def assignedPrinter(self):
  73. return self._assigned_printer
  74. def updateAssignedPrinter(self, assigned_printer: Optional["PrinterOutputModel"]) -> None:
  75. if self._assigned_printer != assigned_printer:
  76. old_printer = self._assigned_printer
  77. self._assigned_printer = assigned_printer
  78. if old_printer is not None:
  79. # If the previously assigned printer is set, this job is moved away from it.
  80. old_printer.updateActivePrintJob(None)
  81. self.assignedPrinterChanged.emit()
  82. @pyqtProperty(str, notify=keyChanged)
  83. def key(self):
  84. return self._key
  85. def updateKey(self, key: str):
  86. if self._key != key:
  87. self._key = key
  88. self.keyChanged.emit()
  89. @pyqtProperty(str, notify = nameChanged)
  90. def name(self):
  91. return self._name
  92. def updateName(self, name: str):
  93. if self._name != name:
  94. self._name = name
  95. self.nameChanged.emit()
  96. @pyqtProperty(int, notify = timeTotalChanged)
  97. def timeTotal(self) -> int:
  98. return self._time_total
  99. @pyqtProperty(int, notify = timeElapsedChanged)
  100. def timeElapsed(self) -> int:
  101. return self._time_elapsed
  102. @pyqtProperty(int, notify = timeElapsedChanged)
  103. def timeRemaining(self) -> int:
  104. # Never get a negative time remaining
  105. return max(self.timeTotal - self.timeElapsed, 0)
  106. @pyqtProperty(float, notify = timeElapsedChanged)
  107. def progress(self) -> float:
  108. result = float(self.timeElapsed) / max(self.timeTotal, 1.0) # Prevent a division by zero exception.
  109. return min(result, 1.0) # Never get a progress past 1.0
  110. @pyqtProperty(str, notify=stateChanged)
  111. def state(self) -> str:
  112. return self._state
  113. @pyqtProperty(bool, notify=stateChanged)
  114. def isActive(self) -> bool:
  115. inactive_states = [
  116. "pausing",
  117. "paused",
  118. "resuming",
  119. "wait_cleanup"
  120. ]
  121. if self.state in inactive_states and self.timeRemaining > 0:
  122. return False
  123. return True
  124. def updateTimeTotal(self, new_time_total: int) -> None:
  125. if self._time_total != new_time_total:
  126. self._time_total = new_time_total
  127. self.timeTotalChanged.emit()
  128. def updateTimeElapsed(self, new_time_elapsed: int) -> None:
  129. if self._time_elapsed != new_time_elapsed:
  130. self._time_elapsed = new_time_elapsed
  131. self.timeElapsedChanged.emit()
  132. def updateState(self, new_state: str) -> None:
  133. if self._state != new_state:
  134. self._state = new_state
  135. self.stateChanged.emit()
  136. @pyqtSlot(str)
  137. def setState(self, state):
  138. self._output_controller.setJobState(self, state)