Show Cura Connect alerts in the monitor tab

CL-897
This commit is contained in:
Simon Edwards 2018-09-18 16:27:22 +02:00
parent 942d20a8d8
commit b7673a7438
4 changed files with 268 additions and 5 deletions

View file

@ -12,6 +12,8 @@ if TYPE_CHECKING:
from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel
from cura.PrinterOutput.ConfigurationModel import ConfigurationModel
from cura.PrinterOutput.ConfigurationChangeModel import ConfigurationChangeModel
class PrintJobOutputModel(QObject):
stateChanged = pyqtSignal()
@ -24,6 +26,7 @@ class PrintJobOutputModel(QObject):
configurationChanged = pyqtSignal()
previewImageChanged = pyqtSignal()
compatibleMachineFamiliesChanged = pyqtSignal()
configurationChangesChanged = pyqtSignal()
def __init__(self, output_controller: "PrinterOutputController", key: str = "", name: str = "", parent=None) -> None:
super().__init__(parent)
@ -41,6 +44,7 @@ class PrintJobOutputModel(QObject):
self._preview_image_id = 0
self._preview_image = None # type: Optional[QImage]
self._configuration_changes = [] # type: List[ConfigurationChangeModel]
@pyqtProperty("QStringList", notify=compatibleMachineFamiliesChanged)
def compatibleMachineFamilies(self):
@ -148,3 +152,13 @@ class PrintJobOutputModel(QObject):
@pyqtSlot(str)
def setState(self, state):
self._output_controller.setJobState(self, state)
@pyqtProperty("QVariantList", notify=configurationChangesChanged)
def configurationChanges(self) -> List[ConfigurationChangeModel]:
return self._configuration_changes
def updateConfigurationChanges(self, changes: List[ConfigurationChangeModel]) -> None:
if len(self._configuration_changes) == 0 and len(changes) == 0:
return
self._configuration_changes = changes
self.configurationChangesChanged.emit()

View file

@ -85,7 +85,6 @@ Component
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("default_margin").height
anchors.leftMargin: UM.Theme.getSize("default_margin").height
height: 175 * screenScaleFactor
}
}
}

View file

@ -2,6 +2,8 @@ import QtQuick 2.2
import QtQuick.Controls 2.0
import QtQuick.Controls.Styles 1.4
import QtGraphicalEffects 1.0
import QtQuick.Layouts 1.1
import QtQuick.Dialogs 1.1
import UM 1.3 as UM
@ -9,6 +11,110 @@ import UM 1.3 as UM
Item
{
id: base
function haveAlert() {
return printJob.configurationChanges.length !== 0;
}
function alertHeight() {
return haveAlert() ? 230 : 0;
}
function alertText() {
if (printJob.configurationChanges.length === 0) {
return "";
}
var topLine;
if (materialsAreKnown(printJob)) {
topLine = catalog.i18nc("@label", "The assigned printer, %1, requires the following configuration change(s):").arg(printJob.assignedPrinter.name);
} else {
topLine = catalog.i18nc("@label", "The printer %1 is assigned, but the job contains an unknown material configuration.").arg(printJob.assignedPrinter.name);
}
var result = "<p>" + topLine +"</p>";
for (var i=0; i<printJob.configurationChanges.length; i++) {
var change = printJob.configurationChanges[i];
var text = "";
if (change.typeOfChange === 'material_change') {
text = catalog.i18nc("@label", "Change material %1 from %2 to %3.").arg(change.index + 1).arg(change.originName).arg(change.targetName);
} else if (change.typeOfChange === 'material_insert') {
text = catalog.i18nc("@label", "Load %3 as material %1 (This cannot be overridden).").arg(change.index + 1).arg(change.targetName);
} else if (change.typeOfChange === 'print_core_change') {
text = catalog.i18nc("@label", "Change print core %1 from %2 to %3.").arg(change.index + 1).arg(change.originName).arg(change.targetName);
} else if (change.typeOfChange === 'buildplate_change') {
var target_name = formatBuildPlateType(change.target_name);
text = catalog.i18nc("@label", "Change build plate to %1 (This cannot be overridden).").arg(target_name);
}
result += "<p><b>" + text + "</b></p>";
}
return result;
}
function materialsAreKnown(printJob) {
var conf0 = printJob.configuration[0];
if (conf0 && !conf0.material.material) {
return false;
}
var conf1 = printJob.configuration[1];
if (conf1 && !conf1.material.material) {
return false;
}
return true;
}
function formatBuildPlateType(buildPlateType) {
var translationText = "";
switch (buildPlateType) {
case 'glass':
translationText = catalog.i18nc("@label", "Glass");
break;
case 'aluminum':
translationText = catalog.i18nc("@label", "Aluminum");
break;
default:
translationText = null;
}
return translationText;
}
function formatPrintJobName(name) {
var extensionsToRemove = [
'.gz',
'.gcode',
'.ufp'
];
for (var i = 0; i < extensionsToRemove.length; i++) {
var extension = extensionsToRemove[i];
if (name.slice(-extension.length) === extension) {
name = name.substring(0, name.length - extension.length);
}
}
return name;
}
function isPrintJobForcable(printJob) {
var forcable = true;
for (var i = 0; i < printJob.configurationChanges.length; i++) {
var typeOfChange = printJob.configurationChanges[i].typeOfChange;
if (typeOfChange === 'material_insert' || typeOfChange === 'buildplate_change') {
forcable = false;
}
}
return forcable;
}
property var cardHeight: 175
height: (cardHeight + alertHeight()) * screenScaleFactor
property var printJob: null
property var shadowRadius: 5 * screenScaleFactor
function getPrettyTime(time)
@ -27,6 +133,9 @@ Item
Rectangle
{
id: background
height: (cardHeight + alertHeight()) * screenScaleFactor
anchors
{
top: parent.top
@ -35,7 +144,7 @@ Item
leftMargin: base.shadowRadius
rightMargin: base.shadowRadius
right: parent.right
bottom: parent.bottom
//bottom: parent.bottom - alertHeight() * screenScaleFactor
bottomMargin: base.shadowRadius
}
@ -47,6 +156,18 @@ Item
color: "#3F000000" // 25% shadow
}
Rectangle
{
height: cardHeight * screenScaleFactor
anchors
{
top: parent.top
left: parent.left
right: parent.right
// bottom: parent.bottom
}
Item
{
// Content on the left of the infobox
@ -392,15 +513,128 @@ Item
}
}
}
Rectangle
{
height: cardHeight * screenScaleFactor
color: UM.Theme.getColor("viewport_background")
width: 2 * screenScaleFactor
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.margins: UM.Theme.getSize("default_margin").height
anchors.horizontalCenter: parent.horizontalCenter
}
// Alert / Configuration change box
Rectangle
{
height: alertHeight() * screenScaleFactor
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
color: "#ff00ff"
ColumnLayout
{
anchors.fill: parent
RowLayout
{
Item
{
Layout.fillWidth: true
}
Label
{
font: UM.Theme.getFont("default_bold")
text: "Configuration change"
}
UM.RecolorImage
{
id: collapseIcon
width: 15
height: 15
sourceSize.width: width
sourceSize.height: height
// FIXME
source: base.collapsed ? UM.Theme.getIcon("arrow_left") : UM.Theme.getIcon("arrow_bottom")
color: "black"
}
Item
{
Layout.fillWidth: true
}
}
Rectangle
{
Layout.fillHeight: true
Layout.fillWidth: true
color: "red"
Rectangle
{
color: "green"
width: childrenRect.width
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.bottom: parent.bottom
ColumnLayout
{
width: childrenRect.width
anchors.top: parent.top
anchors.bottom: parent.bottom
Text
{
Layout.alignment: Qt.AlignTop
textFormat: Text.StyledText
font: UM.Theme.getFont("default_bold")
text: alertText()
}
Button
{
visible: isPrintJobForcable(printJob)
text: catalog.i18nc("@label", "Override")
onClicked: {
overrideConfirmationDialog.visible = true;
}
}
// Spacer
Item
{
Layout.fillHeight: true
}
}
}
}
}
}
MessageDialog
{
id: overrideConfirmationDialog
title: catalog.i18nc("@window:title", "Override configuration")
icon: StandardIcon.Warning
text: {
var printJobName = formatPrintJobName(printJob.name);
var confirmText = catalog.i18nc("@label", "Starting a print job with an incompatible configuration could damage your 3D printer. Are you sure you want to override the configuration and print %1?").arg(printJobName);
return confirmText;
}
standardButtons: StandardButton.Yes | StandardButton.No
Component.onCompleted: visible = false
onYes: OutputDevice.forceSendJob(printJob.key)
}
}
}

View file

@ -17,6 +17,7 @@ from UM.Scene.SceneNode import SceneNode # For typing.
from UM.Version import Version # To check against firmware versions for support.
from cura.CuraApplication import CuraApplication
from cura.PrinterOutput.ConfigurationChangeModel import ConfigurationChangeModel
from cura.PrinterOutput.ConfigurationModel import ConfigurationModel
from cura.PrinterOutput.ExtruderConfigurationModel import ExtruderConfigurationModel
from cura.PrinterOutput.NetworkedPrinterOutputDevice import NetworkedPrinterOutputDevice, AuthState
@ -406,6 +407,11 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
# 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)
@pyqtSlot(str)
def forceSendJob(self, print_job_uuid: str) -> None:
data = "{\"force\": true}"
self.put("print_jobs/{uuid}".format(uuid=print_job_uuid), data, on_finished=None)
def _printJobStateChanged(self) -> None:
username = self._getUserName()
@ -574,6 +580,16 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
if not status_set_by_impediment:
print_job.updateState(data["status"])
print_job.updateConfigurationChanges(self._createConfigurationChanges(data["configuration_changes_required"]))
def _createConfigurationChanges(self, data: List[Dict[str, Any]]) -> List[ConfigurationChangeModel]:
result = []
for change in data:
result.append(ConfigurationChangeModel(type_of_change=change["type_of_change"],
index=change["index"],
target_name=change["target_name"],
origin_name=change["origin_name"]))
return result
def _createMaterialOutputModel(self, material_data) -> MaterialOutputModel:
containers = ContainerRegistry.getInstance().findInstanceContainers(type="material", GUID=material_data["guid"])