From 5d2a9141809d201cc9d0db0a02abef617d2e59be Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Wed, 23 Jan 2019 15:54:11 +0100 Subject: [PATCH 01/15] Always show context menu for print jobs Contributes to CL-1175 --- .../resources/qml/MonitorPrintJobCard.qml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/plugins/UM3NetworkPrinting/resources/qml/MonitorPrintJobCard.qml b/plugins/UM3NetworkPrinting/resources/qml/MonitorPrintJobCard.qml index 3a724bb731..eadcc04329 100644 --- a/plugins/UM3NetworkPrinting/resources/qml/MonitorPrintJobCard.qml +++ b/plugins/UM3NetworkPrinting/resources/qml/MonitorPrintJobCard.qml @@ -217,14 +217,6 @@ Item height: 32 * screenScaleFactor // TODO: Theme! enabled: !cloudConnection onClicked: enabled ? contextMenu.switchPopupState() : {} - visible: - { - if (!printJob) { - return false - } - var states = ["queued", "sent_to_printer", "pre_print", "printing", "pausing", "paused", "resuming"] - return states.indexOf(printJob.state) !== -1 - } } MonitorContextMenu From 673734ee12d554058929b66593eb8bf92bb84e79 Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Thu, 24 Jan 2019 09:52:56 +0100 Subject: [PATCH 02/15] Show print job context menu if state == "error" Contributes to CL-1175 --- .../resources/qml/MonitorContextMenu.qml | 4 ++-- .../resources/qml/MonitorPrintJobCard.qml | 8 ++++++++ .../resources/qml/MonitorPrinterCard.qml | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/plugins/UM3NetworkPrinting/resources/qml/MonitorContextMenu.qml b/plugins/UM3NetworkPrinting/resources/qml/MonitorContextMenu.qml index 07eaa4f051..771bd4b8cf 100644 --- a/plugins/UM3NetworkPrinting/resources/qml/MonitorContextMenu.qml +++ b/plugins/UM3NetworkPrinting/resources/qml/MonitorContextMenu.qml @@ -53,7 +53,7 @@ Item } text: catalog.i18nc("@label", "Move to top"); visible: { - if (printJob && printJob.state == "queued" && !isAssigned(printJob)) { + if (printJob && (printJob.state == "queued" || printJob.state == "error") && !isAssigned(printJob)) { if (OutputDevice && OutputDevice.queuedPrintJobs[0]) { return OutputDevice.queuedPrintJobs[0].key != printJob.key; } @@ -72,7 +72,7 @@ Item if (!printJob) { return false; } - var states = ["queued", "sent_to_printer"]; + var states = ["queued", "error", "sent_to_printer"]; return states.indexOf(printJob.state) !== -1; } } diff --git a/plugins/UM3NetworkPrinting/resources/qml/MonitorPrintJobCard.qml b/plugins/UM3NetworkPrinting/resources/qml/MonitorPrintJobCard.qml index eadcc04329..c7588b83bc 100644 --- a/plugins/UM3NetworkPrinting/resources/qml/MonitorPrintJobCard.qml +++ b/plugins/UM3NetworkPrinting/resources/qml/MonitorPrintJobCard.qml @@ -217,6 +217,14 @@ Item height: 32 * screenScaleFactor // TODO: Theme! enabled: !cloudConnection onClicked: enabled ? contextMenu.switchPopupState() : {} + visible: + { + if (!printJob) { + return false + } + var states = ["queued", "error", "sent_to_printer", "pre_print", "printing", "pausing", "paused", "resuming"] + return states.indexOf(printJob.state) !== -1 + } } MonitorContextMenu diff --git a/plugins/UM3NetworkPrinting/resources/qml/MonitorPrinterCard.qml b/plugins/UM3NetworkPrinting/resources/qml/MonitorPrinterCard.qml index 085bf774b5..e56e22e40f 100644 --- a/plugins/UM3NetworkPrinting/resources/qml/MonitorPrinterCard.qml +++ b/plugins/UM3NetworkPrinting/resources/qml/MonitorPrinterCard.qml @@ -179,7 +179,7 @@ Item if (!printer || !printer.activePrintJob) { return false } - var states = ["queued", "sent_to_printer", "pre_print", "printing", "pausing", "paused", "resuming"] + var states = ["queued", "error", "sent_to_printer", "pre_print", "printing", "pausing", "paused", "resuming"] return states.indexOf(printer.activePrintJob.state) !== -1 } } From e7151390f7f8434c74e6898da5a3ea853f2524fb Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Thu, 24 Jan 2019 10:24:55 +0100 Subject: [PATCH 03/15] Label printers without connection to "unreachable" Contributes to CL-1188 --- .../UM3NetworkPrinting/resources/qml/MonitorPrinterCard.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/UM3NetworkPrinting/resources/qml/MonitorPrinterCard.qml b/plugins/UM3NetworkPrinting/resources/qml/MonitorPrinterCard.qml index 085bf774b5..5085e4de0d 100644 --- a/plugins/UM3NetworkPrinting/resources/qml/MonitorPrinterCard.qml +++ b/plugins/UM3NetworkPrinting/resources/qml/MonitorPrinterCard.qml @@ -306,7 +306,7 @@ Item } if (printer && printer.state == "unreachable") { - return catalog.i18nc("@label:status", "Unavailable") + return catalog.i18nc("@label:status", "Unreachable") } if (printer && !printer.activePrintJob && printer.state == "idle") { @@ -398,6 +398,7 @@ Item font: UM.Theme.getFont("default") text: catalog.i18nc("@label:status", "Requires configuration changes") visible: printer && printer.activePrintJob && printer.activePrintJob.configurationChanges.length > 0 && !printerStatus.visible + color: UM.Theme.getColor("monitor_text_primary") // FIXED-LINE-HEIGHT: height: 18 * screenScaleFactor // TODO: Theme! From 654cd8e645722e2cdcd2c45eb70acf1f8b7e3499 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Thu, 24 Jan 2019 18:08:02 +0100 Subject: [PATCH 04/15] MaterialInfo: Begin replace HTML-text with QML-elements for 'by material-type'. [CURA-6141] --- .../qml/ActionPanel/PrintJobInformation.qml | 65 +++++++++++-------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/resources/qml/ActionPanel/PrintJobInformation.qml b/resources/qml/ActionPanel/PrintJobInformation.qml index 8bd5d5a0d3..7b6d70d80b 100644 --- a/resources/qml/ActionPanel/PrintJobInformation.qml +++ b/resources/qml/ActionPanel/PrintJobInformation.qml @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Ultimaker B.V. +// Copyright (c) 2019 Ultimaker B.V. // Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.7 @@ -85,31 +85,18 @@ Column Label { + id: byMaterialType + property var printMaterialLengths: PrintInformation.materialLengths property var printMaterialWeights: PrintInformation.materialWeights property var printMaterialCosts: PrintInformation.materialCosts property var printMaterialNames: PrintInformation.materialNames + property var columnWidthMultipliers: [ 0.4, 0.2, 0.2, 0.2 ] - function formatRow(items) + function getMaterialTable() { - var rowHTML = "" - for(var item = 0; item < items.length; item++) - { - if (item == 0) - { - rowHTML += "%1".arg(items[item]) - } - else - { - rowHTML += "  %1".arg(items[item]) - } - } - rowHTML += "" - return rowHTML - } + var result = [] - text: - { var lengths = [] var weights = [] var costs = [] @@ -135,20 +122,42 @@ Column costs = ["0.00"] } - var text = "" for(var index = 0; index < lengths.length; index++) { - text += formatRow([ - "%1:".arg(names[index]), - catalog.i18nc("@label m for meter", "%1m").arg(lengths[index]), - catalog.i18nc("@label g for grams", "%1g").arg(weights[index]), - "%1 %2".arg(UM.Preferences.getValue("cura/currency")).arg(costs[index]), - ]) + var row = [] + row.push("%1:".arg(names[index])) + row.push(catalog.i18nc("@label m for meter", "%1m").arg(lengths[index])) + row.push(catalog.i18nc("@label g for grams", "%1g").arg(weights[index])) + row.push("%1 %2".arg(UM.Preferences.getValue("cura/currency")).arg(costs[index])) + result.push(row) } - text += "
" - return text + return result } + + Column + { + Repeater + { + model: byMaterialType.getMaterialTable() + + Row + { + //property var rowLength: modelData.length + Repeater + { + model: modelData + Text + { + width: Math.round(byMaterialType.width * byMaterialType.columnWidthMultipliers[index]) + wrapMode: Text.WrapAnywhere + text: modelData + } + } + } + } + } + width: parent.width - 2 * UM.Theme.getSize("default_margin").width color: UM.Theme.getColor("text") font: UM.Theme.getFont("default") From 7fdbb11f492e00ec75dfcf8037a00aad75b94799 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Thu, 24 Jan 2019 21:56:22 +0100 Subject: [PATCH 05/15] MaterialInfo: Put height and fonts by QML-elements for 'by material-type'. [CURA-6141] --- resources/qml/ActionPanel/PrintJobInformation.qml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/resources/qml/ActionPanel/PrintJobInformation.qml b/resources/qml/ActionPanel/PrintJobInformation.qml index 7b6d70d80b..daac6e0a19 100644 --- a/resources/qml/ActionPanel/PrintJobInformation.qml +++ b/resources/qml/ActionPanel/PrintJobInformation.qml @@ -140,16 +140,16 @@ Column Repeater { model: byMaterialType.getMaterialTable() - Row { - //property var rowLength: modelData.length Repeater { model: modelData Text { width: Math.round(byMaterialType.width * byMaterialType.columnWidthMultipliers[index]) + height: contentHeight + font: UM.Theme.getFont("default") wrapMode: Text.WrapAnywhere text: modelData } @@ -159,6 +159,7 @@ Column } width: parent.width - 2 * UM.Theme.getSize("default_margin").width + height: childrenRect.height color: UM.Theme.getColor("text") font: UM.Theme.getFont("default") renderType: Text.NativeRendering From 91dc3713ae6f5a5cab495084b33b6b9556d89fe3 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Fri, 25 Jan 2019 12:03:01 +0100 Subject: [PATCH 06/15] Initialise idle count properly This is a field so it should always get initialised in the __init__ function. Fixes #5218. --- plugins/USBPrinting/USBPrinterOutputDevice.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index 19a703e605..32203ffa6c 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -55,6 +55,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice): self._update_thread = Thread(target = self._update, daemon = True) self._last_temperature_request = None # type: Optional[int] + self._firmware_idle_count = 0 self._is_printing = False # A print is being sent. From e7ff70870f046df820c676791aec4aecc6daf78e Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Sat, 26 Jan 2019 11:25:38 +0100 Subject: [PATCH 07/15] MaterialInfo: Also replace HTML-text with QML-elements for 'by line-type'. [CURA-6141] --- .../qml/ActionPanel/PrintJobInformation.qml | 48 +++++++++++++++---- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/resources/qml/ActionPanel/PrintJobInformation.qml b/resources/qml/ActionPanel/PrintJobInformation.qml index daac6e0a19..50e4343626 100644 --- a/resources/qml/ActionPanel/PrintJobInformation.qml +++ b/resources/qml/ActionPanel/PrintJobInformation.qml @@ -36,30 +36,60 @@ Column Label { - property var printDuration: PrintInformation.currentPrintTime + id: byLineType - text: + property var printDuration: PrintInformation.currentPrintTime + property var columnWidthMultipliers: [ 0.4, 0.3, 0.3 ] + + function getMaterialTable() { + var result = [] + // All the time information for the different features is achieved var printTime = PrintInformation.getFeaturePrintTimes() var totalSeconds = parseInt(printDuration.getDisplayString(UM.DurationFormat.Seconds)) // A message is created and displayed when the user hover the time label - var text = "" for(var feature in printTime) { if(!printTime[feature].isTotalDurationZero) { - text += "" + - "".arg(printTime[feature].getDisplayString(UM.DurationFormat.ISO8601).slice(0,-3)) + - "".arg(Math.round(100 * parseInt(printTime[feature].getDisplayString(UM.DurationFormat.Seconds)) / totalSeconds)) + - "" + var row = [] + row.push(feature + ":") + row.push("%1".arg(printTime[feature].getDisplayString(UM.DurationFormat.ISO8601).slice(0,-3))) + row.push("%1%".arg(Math.round(100 * parseInt(printTime[feature].getDisplayString(UM.DurationFormat.Seconds)) / totalSeconds))) + result.push(row) } } - text += "
" + feature + ":  %1  %1%
" - return text + + return result } + + Column + { + Repeater + { + model: byLineType.getMaterialTable() + Row + { + Repeater + { + model: modelData + Text + { + width: Math.round(byLineType.width * byLineType.columnWidthMultipliers[index]) + height: contentHeight + font: UM.Theme.getFont("default") + wrapMode: Text.WrapAnywhere + text: modelData + } + } + } + } + } + width: parent.width - 2 * UM.Theme.getSize("default_margin").width + height: childrenRect.height color: UM.Theme.getColor("text") font: UM.Theme.getFont("default") renderType: Text.NativeRendering From 3d413ceb2c33dcea49287dcb9a258f7dc6eb78a5 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Sat, 26 Jan 2019 11:43:15 +0100 Subject: [PATCH 08/15] MaterialInfo: Tweak text-alignment/layout. [CURA-6141] --- resources/qml/ActionPanel/PrintJobInformation.qml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/resources/qml/ActionPanel/PrintJobInformation.qml b/resources/qml/ActionPanel/PrintJobInformation.qml index 50e4343626..483fe76812 100644 --- a/resources/qml/ActionPanel/PrintJobInformation.qml +++ b/resources/qml/ActionPanel/PrintJobInformation.qml @@ -40,6 +40,7 @@ Column property var printDuration: PrintInformation.currentPrintTime property var columnWidthMultipliers: [ 0.4, 0.3, 0.3 ] + property var columnHorizontalAligns: [ TextInput.AlignLeft, TextInput.AlignHCenter, TextInput.AlignHCenter ] function getMaterialTable() { @@ -55,7 +56,7 @@ Column if(!printTime[feature].isTotalDurationZero) { var row = [] - row.push(feature + ":") + row.push(feature + ": ") row.push("%1".arg(printTime[feature].getDisplayString(UM.DurationFormat.ISO8601).slice(0,-3))) row.push("%1%".arg(Math.round(100 * parseInt(printTime[feature].getDisplayString(UM.DurationFormat.Seconds)) / totalSeconds))) result.push(row) @@ -79,6 +80,7 @@ Column { width: Math.round(byLineType.width * byLineType.columnWidthMultipliers[index]) height: contentHeight + horizontalAlignment: byLineType.columnHorizontalAligns[index] font: UM.Theme.getFont("default") wrapMode: Text.WrapAnywhere text: modelData @@ -122,6 +124,7 @@ Column property var printMaterialCosts: PrintInformation.materialCosts property var printMaterialNames: PrintInformation.materialNames property var columnWidthMultipliers: [ 0.4, 0.2, 0.2, 0.2 ] + property var columnHorizontalAligns: [ TextInput.AlignLeft, TextInput.AlignHCenter, TextInput.AlignHCenter, TextInput.AlignHCenter ] function getMaterialTable() { @@ -155,7 +158,7 @@ Column for(var index = 0; index < lengths.length; index++) { var row = [] - row.push("%1:".arg(names[index])) + row.push("%1: ".arg(names[index])) row.push(catalog.i18nc("@label m for meter", "%1m").arg(lengths[index])) row.push(catalog.i18nc("@label g for grams", "%1g").arg(weights[index])) row.push("%1 %2".arg(UM.Preferences.getValue("cura/currency")).arg(costs[index])) @@ -179,6 +182,7 @@ Column { width: Math.round(byMaterialType.width * byMaterialType.columnWidthMultipliers[index]) height: contentHeight + horizontalAlignment: byLineType.columnHorizontalAligns[index] font: UM.Theme.getFont("default") wrapMode: Text.WrapAnywhere text: modelData From 71b2787d0de0ab18054109fc284f3b8b53271f47 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Mon, 28 Jan 2019 08:47:58 +0100 Subject: [PATCH 09/15] Use Label CURA-6141 --- resources/qml/ActionPanel/PrintJobInformation.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/qml/ActionPanel/PrintJobInformation.qml b/resources/qml/ActionPanel/PrintJobInformation.qml index 483fe76812..45b3846f38 100644 --- a/resources/qml/ActionPanel/PrintJobInformation.qml +++ b/resources/qml/ActionPanel/PrintJobInformation.qml @@ -76,7 +76,7 @@ Column Repeater { model: modelData - Text + Label { width: Math.round(byLineType.width * byLineType.columnWidthMultipliers[index]) height: contentHeight @@ -178,7 +178,7 @@ Column Repeater { model: modelData - Text + Label { width: Math.round(byMaterialType.width * byMaterialType.columnWidthMultipliers[index]) height: contentHeight From c6ff8149f6a6730e482f169908a323a4de5d1f1c Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Mon, 28 Jan 2019 09:04:04 +0100 Subject: [PATCH 10/15] Remove colon according to design CURA-6141 --- resources/qml/ActionPanel/PrintJobInformation.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/ActionPanel/PrintJobInformation.qml b/resources/qml/ActionPanel/PrintJobInformation.qml index 45b3846f38..a8d3dad164 100644 --- a/resources/qml/ActionPanel/PrintJobInformation.qml +++ b/resources/qml/ActionPanel/PrintJobInformation.qml @@ -158,7 +158,7 @@ Column for(var index = 0; index < lengths.length; index++) { var row = [] - row.push("%1: ".arg(names[index])) + row.push("%1".arg(names[index])) row.push(catalog.i18nc("@label m for meter", "%1m").arg(lengths[index])) row.push(catalog.i18nc("@label g for grams", "%1g").arg(weights[index])) row.push("%1 %2".arg(UM.Preferences.getValue("cura/currency")).arg(costs[index])) From 1f21eed14f5dae0383d353f96d1b17327b1f0d72 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Mon, 28 Jan 2019 09:05:40 +0100 Subject: [PATCH 11/15] Add Text.NativeRendering for Labels CURA-6141 --- resources/qml/ActionPanel/PrintJobInformation.qml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/resources/qml/ActionPanel/PrintJobInformation.qml b/resources/qml/ActionPanel/PrintJobInformation.qml index a8d3dad164..7cd466c33f 100644 --- a/resources/qml/ActionPanel/PrintJobInformation.qml +++ b/resources/qml/ActionPanel/PrintJobInformation.qml @@ -84,6 +84,7 @@ Column font: UM.Theme.getFont("default") wrapMode: Text.WrapAnywhere text: modelData + renderType: Text.NativeRendering } } } @@ -186,6 +187,7 @@ Column font: UM.Theme.getFont("default") wrapMode: Text.WrapAnywhere text: modelData + renderType: Text.NativeRendering } } } From 3774fdbd0209e5bfca735160ba7fc05a9324670d Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 28 Jan 2019 14:29:41 +0100 Subject: [PATCH 12/15] Refactored the "connection_type" metadata entry so it can support multiple types. After a lot of discussion and finding out what the hell was going on, we figured out we made a pretty big derp by only setting a single connection_type in the metadata of the machine. What it's actually doing is describing what connection types have been configured (and not just randomly displaying whatever output device set the value last) --- cura/GlobalStacksModel.py | 21 +++++------ cura/Settings/GlobalStack.py | 26 +++++++++++++ cura/Settings/MachineManager.py | 8 +++- .../src/DiscoverUM3Action.py | 37 +++++++++++-------- .../src/UM3OutputDevicePlugin.py | 20 +++++----- 5 files changed, 75 insertions(+), 37 deletions(-) diff --git a/cura/GlobalStacksModel.py b/cura/GlobalStacksModel.py index 289a03d1c4..406e7b6bb3 100644 --- a/cura/GlobalStacksModel.py +++ b/cura/GlobalStacksModel.py @@ -5,10 +5,8 @@ from UM.Qt.ListModel import ListModel from PyQt5.QtCore import pyqtProperty, Qt, pyqtSignal -from UM.Settings.ContainerRegistry import ContainerRegistry -from UM.Settings.ContainerStack import ContainerStack - from cura.PrinterOutputDevice import ConnectionType +from cura.Settings.CuraContainerRegistry import CuraContainerRegistry from cura.Settings.GlobalStack import GlobalStack @@ -25,14 +23,13 @@ class GlobalStacksModel(ListModel): self.addRoleName(self.NameRole, "name") self.addRoleName(self.IdRole, "id") self.addRoleName(self.HasRemoteConnectionRole, "hasRemoteConnection") - self.addRoleName(self.ConnectionTypeRole, "connectionType") self.addRoleName(self.MetaDataRole, "metadata") self._container_stacks = [] # Listen to changes - ContainerRegistry.getInstance().containerAdded.connect(self._onContainerChanged) - ContainerRegistry.getInstance().containerMetaDataChanged.connect(self._onContainerChanged) - ContainerRegistry.getInstance().containerRemoved.connect(self._onContainerChanged) + CuraContainerRegistry.getInstance().containerAdded.connect(self._onContainerChanged) + CuraContainerRegistry.getInstance().containerMetaDataChanged.connect(self._onContainerChanged) + CuraContainerRegistry.getInstance().containerRemoved.connect(self._onContainerChanged) self._filter_dict = {} self._update() @@ -45,11 +42,14 @@ class GlobalStacksModel(ListModel): def _update(self) -> None: items = [] - container_stacks = ContainerRegistry.getInstance().findContainerStacks(type = "machine") + container_stacks = CuraContainerRegistry.getInstance().findContainerStacks(type = "machine") for container_stack in container_stacks: - connection_type = int(container_stack.getMetaDataEntry("connection_type", ConnectionType.NotConnected.value)) - has_remote_connection = connection_type in [ConnectionType.NetworkConnection.value, ConnectionType.CloudConnection.value] + has_remote_connection = False + + for connection_type in container_stack.configuredConnectionTypes: + has_remote_connection |= connection_type in [ConnectionType.NetworkConnection.value, ConnectionType.CloudConnection.value] + if container_stack.getMetaDataEntry("hidden", False) in ["True", True]: continue @@ -57,7 +57,6 @@ class GlobalStacksModel(ListModel): items.append({"name": container_stack.getMetaDataEntry("connect_group_name", container_stack.getName()), "id": container_stack.getId(), "hasRemoteConnection": has_remote_connection, - "connectionType": connection_type, "metadata": container_stack.getMetaData().copy()}) items.sort(key=lambda i: not i["hasRemoteConnection"]) self.setItems(items) diff --git a/cura/Settings/GlobalStack.py b/cura/Settings/GlobalStack.py index 44ceee9511..b65b0fcbf4 100755 --- a/cura/Settings/GlobalStack.py +++ b/cura/Settings/GlobalStack.py @@ -42,7 +42,12 @@ class GlobalStack(CuraContainerStack): # Per thread we have our own resolving_settings, or strange things sometimes occur. self._resolving_settings = defaultdict(set) #type: Dict[str, Set[str]] # keys are thread names + # Since the metadatachanged is defined in container stack, we can't use it here as a notifier for pyqt + # properties. So we need to tie them together like this. + self.metaDataChanged.connect(self.configuredConnectionTypesChanged) + extrudersChanged = pyqtSignal() + configuredConnectionTypesChanged = pyqtSignal() ## Get the list of extruders of this stack. # @@ -63,6 +68,27 @@ class GlobalStack(CuraContainerStack): def getLoadingPriority(cls) -> int: return 2 + @pyqtProperty("QVariantList", notify=configuredConnectionTypesChanged) + def configuredConnectionTypes(self): + # Requesting it from the metadata actually gets them as strings (as that's what you get from serializing). + # But we do want them returned as a list of ints (so the rest of the code can directly compare) + connection_types = self.getMetaDataEntry("connection_type", "").split(",") + return [int(connection_type) for connection_type in connection_types if connection_type != ""] + + def addConfiguredConnectionType(self, connection_type): + configured_connection_types = self.configuredConnectionTypes + if connection_type not in configured_connection_types: + # Store the values as a string. + configured_connection_types.append(str(connection_type)) + self.setMetaDataEntry("connection_type", ",".join(configured_connection_types)) + + def removeConfiguredConnectionType(self, connection_type): + configured_connection_types = self.configuredConnectionTypes + if connection_type in self.configured_connection_types: + # Store the values as a string. + configured_connection_types.remove(str(connection_type)) + self.setMetaDataEntry("connection_type", ",".join(configured_connection_types)) + @classmethod def getConfigurationTypeFromSerialized(cls, serialized: str) -> Optional[str]: configuration_type = super().getConfigurationTypeFromSerialized(serialized) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 5f33be1c54..ae74d76734 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -528,8 +528,12 @@ class MachineManager(QObject): @pyqtProperty(bool, notify = printerConnectedStatusChanged) def activeMachineHasRemoteConnection(self) -> bool: if self._global_container_stack: - connection_type = int(self._global_container_stack.getMetaDataEntry("connection_type", ConnectionType.NotConnected.value)) - return connection_type in [ConnectionType.NetworkConnection.value, ConnectionType.CloudConnection.value] + has_remote_connection = False + + for connection_type in self._global_container_stack.configuredConnectionTypes: + has_remote_connection |= connection_type in [ConnectionType.NetworkConnection.value, + ConnectionType.CloudConnection.value] + return has_remote_connection return False @pyqtProperty(bool, notify = printerConnectedStatusChanged) diff --git a/plugins/UM3NetworkPrinting/src/DiscoverUM3Action.py b/plugins/UM3NetworkPrinting/src/DiscoverUM3Action.py index b688ee9d7d..7072aef4cc 100644 --- a/plugins/UM3NetworkPrinting/src/DiscoverUM3Action.py +++ b/plugins/UM3NetworkPrinting/src/DiscoverUM3Action.py @@ -13,6 +13,7 @@ from UM.i18n import i18nCatalog from cura.CuraApplication import CuraApplication from cura.MachineAction import MachineAction +from cura.Settings.CuraContainerRegistry import CuraContainerRegistry from .UM3OutputDevicePlugin import UM3OutputDevicePlugin @@ -133,23 +134,29 @@ class DiscoverUM3Action(MachineAction): return meta_data = global_container_stack.getMetaData() - if "um_network_key" in meta_data: - previous_network_key = meta_data["um_network_key"] - global_container_stack.setMetaDataEntry("um_network_key", printer_device.key) - # Delete old authentication data. - Logger.log("d", "Removing old authentication id %s for device %s", - global_container_stack.getMetaDataEntry("network_authentication_id", None), printer_device.key) - global_container_stack.removeMetaDataEntry("network_authentication_id") - global_container_stack.removeMetaDataEntry("network_authentication_key") - CuraApplication.getInstance().getMachineManager().replaceContainersMetadata(key = "um_network_key", value = previous_network_key, new_value = printer_device.key) - if "connection_type" in meta_data: - previous_connection_type = meta_data["connection_type"] - global_container_stack.setMetaDataEntry("connection_type", printer_device.connectionType.value) - CuraApplication.getInstance().getMachineManager().replaceContainersMetadata(key = "connection_type", value = previous_connection_type, new_value = printer_device.connectionType.value) - else: + if "um_network_key" in meta_data: # Global stack already had a connection, but it's changed. + old_network_key = meta_data["um_network_key"] + # Since we might have a bunch of hidden stacks, we also need to change it there. + metadata_filter = {"um_network_key": old_network_key} + containers = CuraContainerRegistry.getInstance().findContainerStacks(type="machine", **metadata_filter) + + for container in containers: + container.setMetaDataEntry("um_network_key", printer_device.key) + + # Delete old authentication data. + Logger.log("d", "Removing old authentication id %s for device %s", + global_container_stack.getMetaDataEntry("network_authentication_id", None), printer_device.key) + + container.removeMetaDataEntry("network_authentication_id") + container.removeMetaDataEntry("network_authentication_key") + + # Ensure that these containers do know that they are configured for network connection + container.addConfiguredConnectionType(printer_device.connectionType.value) + + else: # Global stack didn't have a connection yet, configure it. global_container_stack.setMetaDataEntry("um_network_key", printer_device.key) - global_container_stack.setMetaDataEntry("connection_type", printer_device.connectionType.value) + global_container_stack.addConfiguredConnectionType(printer_device.connectionType.value) if self._network_plugin: # Ensure that the connection states are refreshed. diff --git a/plugins/UM3NetworkPrinting/src/UM3OutputDevicePlugin.py b/plugins/UM3NetworkPrinting/src/UM3OutputDevicePlugin.py index 4a510903dd..74d2d87b3b 100644 --- a/plugins/UM3NetworkPrinting/src/UM3OutputDevicePlugin.py +++ b/plugins/UM3NetworkPrinting/src/UM3OutputDevicePlugin.py @@ -9,7 +9,7 @@ from zeroconf import Zeroconf, ServiceBrowser, ServiceStateChange, ServiceInfo from PyQt5.QtNetwork import QNetworkRequest, QNetworkAccessManager from PyQt5.QtCore import QUrl -from UM.Application import Application +from cura.CuraApplication import CuraApplication from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin from UM.Logger import Logger from UM.Signal import Signal, signalemitter @@ -41,7 +41,7 @@ class UM3OutputDevicePlugin(OutputDevicePlugin): self.addDeviceSignal.connect(self._onAddDevice) self.removeDeviceSignal.connect(self._onRemoveDevice) - Application.getInstance().globalContainerStackChanged.connect(self.reCheckConnections) + CuraApplication.getInstance().globalContainerStackChanged.connect(self.reCheckConnections) self._discovered_devices = {} @@ -56,7 +56,7 @@ class UM3OutputDevicePlugin(OutputDevicePlugin): self._cluster_api_prefix = "/cluster-api/v" + self._cluster_api_version + "/" # Get list of manual instances from preferences - self._preferences = Application.getInstance().getPreferences() + self._preferences = CuraApplication.getInstance().getPreferences() self._preferences.addPreference("um3networkprinting/manual_instances", "") # A comma-separated list of ip adresses or hostnames @@ -108,7 +108,7 @@ class UM3OutputDevicePlugin(OutputDevicePlugin): self.resetLastManualDevice() def reCheckConnections(self): - active_machine = Application.getInstance().getGlobalContainerStack() + active_machine = CuraApplication.getInstance().getGlobalContainerStack() if not active_machine: return @@ -118,7 +118,8 @@ class UM3OutputDevicePlugin(OutputDevicePlugin): if key == um_network_key: if not self._discovered_devices[key].isConnected(): Logger.log("d", "Attempting to connect with [%s]" % key) - active_machine.setMetaDataEntry("connection_type", self._discovered_devices[key].connectionType.value) + # It should already be set, but if it actually connects we know for sure it's supported! + active_machine.addConfiguredConnectionType(self._discovered_devices[key].connectionType.value) self._discovered_devices[key].connect() self._discovered_devices[key].connectionStateChanged.connect(self._onDeviceConnectionStateChanged) else: @@ -134,7 +135,7 @@ class UM3OutputDevicePlugin(OutputDevicePlugin): return if self._discovered_devices[key].isConnected(): # Sometimes the status changes after changing the global container and maybe the device doesn't belong to this machine - um_network_key = Application.getInstance().getGlobalContainerStack().getMetaDataEntry("um_network_key") + um_network_key = CuraApplication.getInstance().getGlobalContainerStack().getMetaDataEntry("um_network_key") if key == um_network_key: self.getOutputDeviceManager().addOutputDevice(self._discovered_devices[key]) else: @@ -287,9 +288,10 @@ class UM3OutputDevicePlugin(OutputDevicePlugin): self._discovered_devices[device.getId()] = device self.discoveredDevicesChanged.emit() - global_container_stack = Application.getInstance().getGlobalContainerStack() + global_container_stack = CuraApplication.getInstance().getGlobalContainerStack() if global_container_stack and device.getId() == global_container_stack.getMetaDataEntry("um_network_key"): - global_container_stack.setMetaDataEntry("connection_type", device.connectionType.value) + # Ensure that the configured connection type is set. + global_container_stack.addConfiguredConnectionType(device.connectionType.value) device.connect() device.connectionStateChanged.connect(self._onDeviceConnectionStateChanged) @@ -306,7 +308,7 @@ class UM3OutputDevicePlugin(OutputDevicePlugin): self._service_changed_request_event.wait(timeout = 5.0) # Stop if the application is shutting down - if Application.getInstance().isShuttingDown(): + if CuraApplication.getInstance().isShuttingDown(): return self._service_changed_request_event.clear() From f723cdc8a351d3aff0a408f5bad4af6055f04b87 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 28 Jan 2019 14:47:03 +0100 Subject: [PATCH 13/15] Fix typing issues --- plugins/CuraDrive/src/DrivePluginExtension.py | 4 ++-- plugins/Toolbox/src/Toolbox.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/CuraDrive/src/DrivePluginExtension.py b/plugins/CuraDrive/src/DrivePluginExtension.py index 060f1496f1..c1a3baf864 100644 --- a/plugins/CuraDrive/src/DrivePluginExtension.py +++ b/plugins/CuraDrive/src/DrivePluginExtension.py @@ -3,7 +3,7 @@ import os from datetime import datetime -from typing import Optional, List, Dict, Any +from typing import Optional, List, Dict, Any, cast from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty, pyqtSignal @@ -68,7 +68,7 @@ class DrivePluginExtension(QObject, Extension): def showDriveWindow(self) -> None: if not self._drive_window: - plugin_dir_path = CuraApplication.getInstance().getPluginRegistry().getPluginPath("CuraDrive") + plugin_dir_path = cast(str, CuraApplication.getInstance().getPluginRegistry().getPluginPath("CuraDrive")) path = os.path.join(plugin_dir_path, "src", "qml", "main.qml") self._drive_window = CuraApplication.getInstance().createQmlComponent(path, {"CuraDrive": self}) self.refreshBackups() diff --git a/plugins/Toolbox/src/Toolbox.py b/plugins/Toolbox/src/Toolbox.py index ccd181cdbc..3fea73f9a4 100644 --- a/plugins/Toolbox/src/Toolbox.py +++ b/plugins/Toolbox/src/Toolbox.py @@ -37,7 +37,7 @@ class Toolbox(QObject, Extension): self._application = application # type: CuraApplication self._sdk_version = ApplicationMetadata.CuraSDKVersion # type: Union[str, int] - self._cloud_api_version = UltimakerCloudAuthentication.CuraCloudAPIVersion # type: int + self._cloud_api_version = UltimakerCloudAuthentication.CuraCloudAPIVersion # type: str self._cloud_api_root = UltimakerCloudAuthentication.CuraCloudAPIRoot # type: str self._api_url = None # type: Optional[str] From bc8a08bb44b107ccfd1ed39a94d9cd631abb116f Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 28 Jan 2019 14:57:24 +0100 Subject: [PATCH 14/15] Add documentation to the configuredConnectionTypes --- cura/Settings/GlobalStack.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cura/Settings/GlobalStack.py b/cura/Settings/GlobalStack.py index b65b0fcbf4..2bb2cc7298 100755 --- a/cura/Settings/GlobalStack.py +++ b/cura/Settings/GlobalStack.py @@ -68,6 +68,11 @@ class GlobalStack(CuraContainerStack): def getLoadingPriority(cls) -> int: return 2 + # The configured connection types can be used to find out if the global stack is configured to be connected with + # a printer, without having to know all the details as to how this is exactly done (and without actually setting + # the stack to be active). This data can then in turn also be used when the global stack is active; If we can't + # get a network connection, but it is configured to have one, we can display a different icon to indicate the + # difference. @pyqtProperty("QVariantList", notify=configuredConnectionTypesChanged) def configuredConnectionTypes(self): # Requesting it from the metadata actually gets them as strings (as that's what you get from serializing). @@ -75,6 +80,7 @@ class GlobalStack(CuraContainerStack): connection_types = self.getMetaDataEntry("connection_type", "").split(",") return [int(connection_type) for connection_type in connection_types if connection_type != ""] + # \sa configuredConnectionTypes def addConfiguredConnectionType(self, connection_type): configured_connection_types = self.configuredConnectionTypes if connection_type not in configured_connection_types: @@ -82,6 +88,7 @@ class GlobalStack(CuraContainerStack): configured_connection_types.append(str(connection_type)) self.setMetaDataEntry("connection_type", ",".join(configured_connection_types)) + # \sa configuredConnectionTypes def removeConfiguredConnectionType(self, connection_type): configured_connection_types = self.configuredConnectionTypes if connection_type in self.configured_connection_types: From 9d8cf5ddde7d645ded51178f2b0596a178cc00bb Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 28 Jan 2019 16:40:45 +0100 Subject: [PATCH 15/15] Apply division by zero prevention to the denominator Rather than the numerator, which could not cause a division by zero exception. --- cura/PrinterOutput/PrintJobOutputModel.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cura/PrinterOutput/PrintJobOutputModel.py b/cura/PrinterOutput/PrintJobOutputModel.py index a77ac81909..eb0d846415 100644 --- a/cura/PrinterOutput/PrintJobOutputModel.py +++ b/cura/PrinterOutput/PrintJobOutputModel.py @@ -132,8 +132,7 @@ class PrintJobOutputModel(QObject): @pyqtProperty(float, notify = timeElapsedChanged) def progress(self) -> float: - time_elapsed = max(float(self.timeElapsed), 1.0) # Prevent a division by zero exception - result = time_elapsed / self.timeTotal + result = float(self.timeElapsed) / max(self.timeTotal, 1.0) # Prevent a division by zero exception. return min(result, 1.0) # Never get a progress past 1.0 @pyqtProperty(str, notify=stateChanged)