mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-07 15:07:28 -06:00
LegacyUM3 now handles warnings & errors again
CL-541
This commit is contained in:
parent
96d5c7152b
commit
8b8d67b3a8
5 changed files with 166 additions and 11 deletions
|
@ -5,12 +5,13 @@ from PyQt5.QtCore import pyqtSignal, pyqtProperty, QObject, QVariant, pyqtSlot
|
||||||
|
|
||||||
|
|
||||||
class MaterialOutputModel(QObject):
|
class MaterialOutputModel(QObject):
|
||||||
def __init__(self, guid, type, color, brand, parent = None):
|
def __init__(self, guid, type, color, brand, name, parent = None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self._guid = guid
|
self._guid = guid
|
||||||
self._type = type
|
self._type = type
|
||||||
self._color = color
|
self._color = color
|
||||||
self._brand = brand
|
self._brand = brand
|
||||||
|
self._name = name
|
||||||
|
|
||||||
@pyqtProperty(str, constant = True)
|
@pyqtProperty(str, constant = True)
|
||||||
def guid(self):
|
def guid(self):
|
||||||
|
@ -27,3 +28,7 @@ class MaterialOutputModel(QObject):
|
||||||
@pyqtProperty(str, constant=True)
|
@pyqtProperty(str, constant=True)
|
||||||
def color(self):
|
def color(self):
|
||||||
return self._color
|
return self._color
|
||||||
|
|
||||||
|
@pyqtProperty(str, constant=True)
|
||||||
|
def name(self):
|
||||||
|
return self._name
|
|
@ -21,6 +21,7 @@ class AuthState(IntEnum):
|
||||||
|
|
||||||
class NetworkedPrinterOutputDevice(PrinterOutputDevice):
|
class NetworkedPrinterOutputDevice(PrinterOutputDevice):
|
||||||
authenticationStateChanged = pyqtSignal()
|
authenticationStateChanged = pyqtSignal()
|
||||||
|
|
||||||
def __init__(self, device_id, address: str, properties, parent = None):
|
def __init__(self, device_id, address: str, properties, parent = None):
|
||||||
super().__init__(device_id = device_id, parent = parent)
|
super().__init__(device_id = device_id, parent = parent)
|
||||||
self._manager = None
|
self._manager = None
|
||||||
|
@ -41,6 +42,9 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice):
|
||||||
|
|
||||||
self._cached_multiparts = {}
|
self._cached_multiparts = {}
|
||||||
|
|
||||||
|
def requestWrite(self, nodes, file_name=None, filter_by_machine=False, file_handler=None, **kwargs):
|
||||||
|
raise NotImplementedError("requestWrite needs to be implemented")
|
||||||
|
|
||||||
def setAuthenticationState(self, authentication_state):
|
def setAuthenticationState(self, authentication_state):
|
||||||
if self._authentication_state != authentication_state:
|
if self._authentication_state != authentication_state:
|
||||||
self._authentication_state = authentication_state
|
self._authentication_state = authentication_state
|
||||||
|
|
|
@ -11,6 +11,7 @@ MYPY = False
|
||||||
if MYPY:
|
if MYPY:
|
||||||
from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel
|
from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel
|
||||||
from cura.PrinterOutput.PrinterOutputController import PrinterOutputController
|
from cura.PrinterOutput.PrinterOutputController import PrinterOutputController
|
||||||
|
from cura.PrinterOutput.ExtruderOuputModel import ExtruderOutputModel
|
||||||
|
|
||||||
|
|
||||||
class PrinterOutputModel(QObject):
|
class PrinterOutputModel(QObject):
|
||||||
|
|
|
@ -5,13 +5,19 @@ from UM.i18n import i18nCatalog
|
||||||
from UM.OutputDevice.OutputDevice import OutputDevice
|
from UM.OutputDevice.OutputDevice import OutputDevice
|
||||||
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QTimer, pyqtSignal, QUrl
|
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QTimer, pyqtSignal, QUrl
|
||||||
from PyQt5.QtQml import QQmlComponent, QQmlContext
|
from PyQt5.QtQml import QQmlComponent, QQmlContext
|
||||||
from enum import IntEnum # For the connection state tracking.
|
|
||||||
|
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
from UM.Signal import signalemitter
|
from UM.Signal import signalemitter
|
||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
from enum import IntEnum # For the connection state tracking.
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
|
MYPY = False
|
||||||
|
if MYPY:
|
||||||
|
from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel
|
||||||
|
|
||||||
i18n_catalog = i18nCatalog("cura")
|
i18n_catalog = i18nCatalog("cura")
|
||||||
|
|
||||||
|
@ -32,7 +38,7 @@ class PrinterOutputDevice(QObject, OutputDevice):
|
||||||
def __init__(self, device_id, parent = None):
|
def __init__(self, device_id, parent = None):
|
||||||
super().__init__(device_id = device_id, parent = parent)
|
super().__init__(device_id = device_id, parent = parent)
|
||||||
|
|
||||||
self._printers = []
|
self._printers = [] # type: List[PrinterOutputModel]
|
||||||
|
|
||||||
self._monitor_view_qml_path = ""
|
self._monitor_view_qml_path = ""
|
||||||
self._monitor_component = None
|
self._monitor_component = None
|
||||||
|
@ -62,20 +68,19 @@ class PrinterOutputDevice(QObject, OutputDevice):
|
||||||
def _update(self):
|
def _update(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _getPrinterByKey(self, key):
|
def _getPrinterByKey(self, key) -> Optional["PrinterOutputModel"]:
|
||||||
for printer in self._printers:
|
for printer in self._printers:
|
||||||
if printer.key == key:
|
if printer.key == key:
|
||||||
return printer
|
return printer
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def requestWrite(self, nodes, file_name = None, filter_by_machine = False, file_handler = None):
|
def requestWrite(self, nodes, file_name = None, filter_by_machine = False, file_handler = None, **kwargs):
|
||||||
raise NotImplementedError("requestWrite needs to be implemented")
|
raise NotImplementedError("requestWrite needs to be implemented")
|
||||||
|
|
||||||
@pyqtProperty(QObject, notify = printersChanged)
|
@pyqtProperty(QObject, notify = printersChanged)
|
||||||
def activePrinter(self):
|
def activePrinter(self) -> Optional["PrinterOutputModel"]:
|
||||||
if len(self._printers):
|
if len(self._printers):
|
||||||
|
|
||||||
return self._printers[0]
|
return self._printers[0]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel
|
||||||
from cura.PrinterOutput.MaterialOutputModel import MaterialOutputModel
|
from cura.PrinterOutput.MaterialOutputModel import MaterialOutputModel
|
||||||
|
|
||||||
from cura.Settings.ContainerManager import ContainerManager
|
from cura.Settings.ContainerManager import ContainerManager
|
||||||
|
from cura.Settings.ExtruderManager import ExtruderManager
|
||||||
|
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
from UM.Settings.ContainerRegistry import ContainerRegistry
|
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||||
|
@ -13,6 +14,7 @@ from UM.Message import Message
|
||||||
|
|
||||||
from PyQt5.QtNetwork import QNetworkRequest
|
from PyQt5.QtNetwork import QNetworkRequest
|
||||||
from PyQt5.QtCore import QTimer
|
from PyQt5.QtCore import QTimer
|
||||||
|
from PyQt5.QtWidgets import QMessageBox
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import os # To get the username
|
import os # To get the username
|
||||||
|
@ -122,8 +124,144 @@ class LegacyUM3OutputDevice(NetworkedPrinterOutputDevice):
|
||||||
# NotImplementedError. We can simply ignore these.
|
# NotImplementedError. We can simply ignore these.
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# TODO
|
def requestWrite(self, nodes, file_name=None, filter_by_machine=False, file_handler=None, **kwargs):
|
||||||
pass
|
if not self.activePrinter:
|
||||||
|
# No active printer. Unable to write
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.activePrinter.printerState not in ["idle", ""]:
|
||||||
|
# Printer is not able to accept commands.
|
||||||
|
return
|
||||||
|
|
||||||
|
if self._authentication_state != AuthState.Authenticated:
|
||||||
|
# Not authenticated, so unable to send job.
|
||||||
|
return
|
||||||
|
|
||||||
|
# Notify the UI that a switch to the print monitor should happen
|
||||||
|
Application.getInstance().showPrintMonitor.emit(True)
|
||||||
|
self.writeStarted.emit(self)
|
||||||
|
|
||||||
|
gcode = getattr(Application.getInstance().getController().getScene(), "gcode_list", None)
|
||||||
|
if gcode is None:
|
||||||
|
# Unable to find g-code. Nothing to send
|
||||||
|
return
|
||||||
|
|
||||||
|
errors = self._checkForErrors()
|
||||||
|
if errors:
|
||||||
|
text = i18n_catalog.i18nc("@label", "Unable to start a new print job.")
|
||||||
|
informative_text = i18n_catalog.i18nc("@label",
|
||||||
|
"There is an issue with the configuration of your Ultimaker, which makes it impossible to start the print. "
|
||||||
|
"Please resolve this issues before continuing.")
|
||||||
|
detailed_text = ""
|
||||||
|
for error in errors:
|
||||||
|
detailed_text += error + "\n"
|
||||||
|
|
||||||
|
Application.getInstance().messageBox(i18n_catalog.i18nc("@window:title", "Mismatched configuration"),
|
||||||
|
text,
|
||||||
|
informative_text,
|
||||||
|
detailed_text,
|
||||||
|
buttons=QMessageBox.Ok,
|
||||||
|
icon=QMessageBox.Critical,
|
||||||
|
callback = self._messageBoxCallback
|
||||||
|
)
|
||||||
|
return # Don't continue; Errors must block sending the job to the printer.
|
||||||
|
|
||||||
|
# There might be multiple things wrong with the configuration. Check these before starting.
|
||||||
|
warnings = self._checkForWarnings()
|
||||||
|
|
||||||
|
if warnings:
|
||||||
|
text = i18n_catalog.i18nc("@label", "Are you sure you wish to print with the selected configuration?")
|
||||||
|
informative_text = i18n_catalog.i18nc("@label",
|
||||||
|
"There is a mismatch between the configuration or calibration of the printer and Cura. "
|
||||||
|
"For the best result, always slice for the PrintCores and materials that are inserted in your printer.")
|
||||||
|
detailed_text = ""
|
||||||
|
for warning in warnings:
|
||||||
|
detailed_text += warning + "\n"
|
||||||
|
|
||||||
|
Application.getInstance().messageBox(i18n_catalog.i18nc("@window:title", "Mismatched configuration"),
|
||||||
|
text,
|
||||||
|
informative_text,
|
||||||
|
detailed_text,
|
||||||
|
buttons=QMessageBox.Yes + QMessageBox.No,
|
||||||
|
icon=QMessageBox.Question,
|
||||||
|
callback=self._messageBoxCallback
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
# No warnings or errors, so we're good to go.
|
||||||
|
self._startPrint()
|
||||||
|
|
||||||
|
def _startPrint(self):
|
||||||
|
# TODO: Implement
|
||||||
|
Logger.log("i", "Sending print job to printer.")
|
||||||
|
return
|
||||||
|
|
||||||
|
def _messageBoxCallback(self, button):
|
||||||
|
def delayedCallback():
|
||||||
|
if button == QMessageBox.Yes:
|
||||||
|
self._startPrint()
|
||||||
|
else:
|
||||||
|
Application.getInstance().showPrintMonitor.emit(False)
|
||||||
|
# For some unknown reason Cura on OSX will hang if we do the call back code
|
||||||
|
# immediately without first returning and leaving QML's event system.
|
||||||
|
|
||||||
|
QTimer.singleShot(100, delayedCallback)
|
||||||
|
|
||||||
|
def _checkForErrors(self):
|
||||||
|
errors = []
|
||||||
|
print_information = Application.getInstance().getPrintInformation()
|
||||||
|
if not print_information.materialLengths:
|
||||||
|
Logger.log("w", "There is no material length information. Unable to check for errors.")
|
||||||
|
return errors
|
||||||
|
|
||||||
|
for index, extruder in enumerate(self.activePrinter.extruders):
|
||||||
|
# Due to airflow issues, both slots must be loaded, regardless if they are actually used or not.
|
||||||
|
if extruder.hotendID == "":
|
||||||
|
# No Printcore loaded.
|
||||||
|
errors.append(i18n_catalog.i18nc("@info:status", "No Printcore loaded in slot {slot_number}".format(slot_number=index + 1)))
|
||||||
|
|
||||||
|
if index < len(print_information.materialLengths) and print_information.materialLengths[index] != 0:
|
||||||
|
# The extruder is by this print.
|
||||||
|
if extruder.activeMaterial is None:
|
||||||
|
# No active material
|
||||||
|
errors.append(i18n_catalog.i18nc("@info:status", "No material loaded in slot {slot_number}".format(slot_number=index + 1)))
|
||||||
|
return errors
|
||||||
|
|
||||||
|
def _checkForWarnings(self):
|
||||||
|
warnings = []
|
||||||
|
print_information = Application.getInstance().getPrintInformation()
|
||||||
|
|
||||||
|
if not print_information.materialLengths:
|
||||||
|
Logger.log("w", "There is no material length information. Unable to check for warnings.")
|
||||||
|
return warnings
|
||||||
|
|
||||||
|
extruder_manager = ExtruderManager.getInstance()
|
||||||
|
|
||||||
|
for index, extruder in enumerate(self.activePrinter.extruders):
|
||||||
|
if index < len(print_information.materialLengths) and print_information.materialLengths[index] != 0:
|
||||||
|
# The extruder is by this print.
|
||||||
|
|
||||||
|
# TODO: material length check
|
||||||
|
|
||||||
|
# Check if the right Printcore is active.
|
||||||
|
variant = extruder_manager.getExtruderStack(index).findContainer({"type": "variant"})
|
||||||
|
if variant:
|
||||||
|
if variant.getName() != extruder.hotendID:
|
||||||
|
warnings.append(i18n_catalog.i18nc("@label", "Different PrintCore (Cura: {cura_printcore_name}, Printer: {remote_printcore_name}) selected for extruder {extruder_id}".format(cura_printcore_name = variant.getName(), remote_printcore_name = extruder.hotendID, extruder_id = index + 1)))
|
||||||
|
else:
|
||||||
|
Logger.log("w", "Unable to find variant.")
|
||||||
|
|
||||||
|
# Check if the right material is loaded.
|
||||||
|
local_material = extruder_manager.getExtruderStack(index).findContainer({"type": "material"})
|
||||||
|
if local_material:
|
||||||
|
if extruder.activeMaterial.guid != local_material.getMetaDataEntry("GUID"):
|
||||||
|
Logger.log("w", "Extruder %s has a different material (%s) as Cura (%s)", index + 1, extruder.activeMaterial.guid, local_material.getMetaDataEntry("GUID"))
|
||||||
|
warnings.append(i18n_catalog.i18nc("@label", "Different material (Cura: {0}, Printer: {1}) selected for extruder {2}").format(local_material.getName(), extruder.activeMaterial.name, index + 1))
|
||||||
|
else:
|
||||||
|
Logger.log("w", "Unable to find material.")
|
||||||
|
|
||||||
|
return warnings
|
||||||
|
|
||||||
|
|
||||||
def _update(self):
|
def _update(self):
|
||||||
if not super()._update():
|
if not super()._update():
|
||||||
|
@ -339,13 +477,15 @@ class LegacyUM3OutputDevice(NetworkedPrinterOutputDevice):
|
||||||
color = containers[0].getMetaDataEntry("color_code")
|
color = containers[0].getMetaDataEntry("color_code")
|
||||||
brand = containers[0].getMetaDataEntry("brand")
|
brand = containers[0].getMetaDataEntry("brand")
|
||||||
material_type = containers[0].getMetaDataEntry("material")
|
material_type = containers[0].getMetaDataEntry("material")
|
||||||
|
name = containers[0].getName()
|
||||||
else:
|
else:
|
||||||
# Unknown material.
|
# Unknown material.
|
||||||
color = "#00000000"
|
color = "#00000000"
|
||||||
brand = "Unknown"
|
brand = "Unknown"
|
||||||
material_type = "Unknown"
|
material_type = "Unknown"
|
||||||
|
name = "Unknown"
|
||||||
material = MaterialOutputModel(guid=material_guid, type=material_type,
|
material = MaterialOutputModel(guid=material_guid, type=material_type,
|
||||||
brand=brand, color=color)
|
brand=brand, color=color, name = name)
|
||||||
extruder.updateActiveMaterial(material)
|
extruder.updateActiveMaterial(material)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue