mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-19 12:47:49 -06:00
Bring back the printer selection dialog for networked printers
This commit is contained in:
parent
d905b8b8cc
commit
9a3ff527ac
4 changed files with 80 additions and 42 deletions
|
@ -35,6 +35,7 @@ class PrinterOutputModel(QObject):
|
||||||
self._target_bed_temperature = 0 # type: float
|
self._target_bed_temperature = 0 # type: float
|
||||||
self._name = ""
|
self._name = ""
|
||||||
self._key = "" # Unique identifier
|
self._key = "" # Unique identifier
|
||||||
|
self._unique_name = "" # Unique name (used in Connect)
|
||||||
self._controller = output_controller
|
self._controller = output_controller
|
||||||
self._controller.canUpdateFirmwareChanged.connect(self._onControllerCanUpdateFirmwareChanged)
|
self._controller.canUpdateFirmwareChanged.connect(self._onControllerCanUpdateFirmwareChanged)
|
||||||
self._extruders = [ExtruderOutputModel(printer = self, position = i) for i in range(number_of_extruders)]
|
self._extruders = [ExtruderOutputModel(printer = self, position = i) for i in range(number_of_extruders)]
|
||||||
|
@ -190,6 +191,15 @@ class PrinterOutputModel(QObject):
|
||||||
self._name = name
|
self._name = name
|
||||||
self.nameChanged.emit()
|
self.nameChanged.emit()
|
||||||
|
|
||||||
|
@pyqtProperty(str, notify = nameChanged)
|
||||||
|
def uniqueName(self) -> str:
|
||||||
|
return self._unique_name
|
||||||
|
|
||||||
|
def updateUniqueName(self, unique_name: str) -> None:
|
||||||
|
if self._unique_name != unique_name:
|
||||||
|
self._unique_name = unique_name
|
||||||
|
self.nameChanged.emit()
|
||||||
|
|
||||||
## Update the bed temperature. This only changes it locally.
|
## Update the bed temperature. This only changes it locally.
|
||||||
def updateBedTemperature(self, temperature: float) -> None:
|
def updateBedTemperature(self, temperature: float) -> None:
|
||||||
if self._bed_temperature != temperature:
|
if self._bed_temperature != temperature:
|
||||||
|
|
|
@ -1,52 +1,57 @@
|
||||||
// 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.
|
||||||
|
|
||||||
import QtQuick 2.2
|
import QtQuick 2.2
|
||||||
import QtQuick.Window 2.2
|
import QtQuick.Window 2.2
|
||||||
import QtQuick.Controls 1.2
|
import QtQuick.Controls 1.2
|
||||||
import UM 1.1 as UM
|
import UM 1.1 as UM
|
||||||
|
|
||||||
UM.Dialog {
|
UM.Dialog {
|
||||||
|
|
||||||
id: base;
|
id: base;
|
||||||
|
title: catalog.i18nc("@title:window", "Print over network");
|
||||||
|
width: minimumWidth;
|
||||||
height: minimumHeight;
|
height: minimumHeight;
|
||||||
leftButtons: [
|
|
||||||
Button {
|
|
||||||
enabled: true;
|
|
||||||
onClicked: {
|
|
||||||
base.visible = false;
|
|
||||||
printerSelectionCombobox.currentIndex = 0;
|
|
||||||
OutputDevice.cancelPrintSelection();
|
|
||||||
}
|
|
||||||
text: catalog.i18nc("@action:button","Cancel");
|
|
||||||
}
|
|
||||||
]
|
|
||||||
maximumHeight: minimumHeight;
|
maximumHeight: minimumHeight;
|
||||||
maximumWidth: minimumWidth;
|
maximumWidth: minimumWidth;
|
||||||
minimumHeight: 140 * screenScaleFactor;
|
minimumHeight: 140 * screenScaleFactor;
|
||||||
minimumWidth: 500 * screenScaleFactor;
|
minimumWidth: 500 * screenScaleFactor;
|
||||||
modality: Qt.ApplicationModal;
|
modality: Qt.ApplicationModal;
|
||||||
onVisibleChanged: {
|
|
||||||
if (visible) {
|
Component.onCompleted: {
|
||||||
resetPrintersModel();
|
populateComboBox()
|
||||||
} else {
|
}
|
||||||
OutputDevice.cancelPrintSelection();
|
|
||||||
|
// populates the combo box with the correct printer values
|
||||||
|
function populateComboBox() {
|
||||||
|
comboBoxPrintersModel.clear();
|
||||||
|
comboBoxPrintersModel.append({ name: "Automatic", key: "" }); // Connect will just do it's thing
|
||||||
|
for (var i in OutputDevice.printers) {
|
||||||
|
comboBoxPrintersModel.append({
|
||||||
|
name: OutputDevice.printers[i].name,
|
||||||
|
key: OutputDevice.printers[i].uniqueName
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
leftButtons: [
|
||||||
|
Button {
|
||||||
|
enabled: true;
|
||||||
|
onClicked: {
|
||||||
|
base.close();
|
||||||
|
}
|
||||||
|
text: catalog.i18nc("@action:button","Cancel");
|
||||||
|
}
|
||||||
|
]
|
||||||
rightButtons: [
|
rightButtons: [
|
||||||
Button {
|
Button {
|
||||||
enabled: true;
|
enabled: true;
|
||||||
onClicked: {
|
onClicked: {
|
||||||
base.visible = false;
|
OutputDevice.selectTargetPrinter(printerComboBox.model.get(printerComboBox.currentIndex).key);
|
||||||
OutputDevice.selectPrinter(printerSelectionCombobox.model.get(printerSelectionCombobox.currentIndex).key);
|
base.close();
|
||||||
// reset to defaults
|
|
||||||
printerSelectionCombobox.currentIndex = 0;
|
|
||||||
}
|
}
|
||||||
text: catalog.i18nc("@action:button","Print");
|
text: catalog.i18nc("@action:button","Print");
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
title: catalog.i18nc("@title:window", "Print over network");
|
|
||||||
visible: true;
|
|
||||||
width: minimumWidth;
|
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: printerSelection;
|
id: printerSelection;
|
||||||
|
@ -59,10 +64,6 @@ UM.Dialog {
|
||||||
}
|
}
|
||||||
height: 50 * screenScaleFactor;
|
height: 50 * screenScaleFactor;
|
||||||
|
|
||||||
SystemPalette {
|
|
||||||
id: palette;
|
|
||||||
}
|
|
||||||
|
|
||||||
UM.I18nCatalog {
|
UM.I18nCatalog {
|
||||||
id: catalog;
|
id: catalog;
|
||||||
name: "cura";
|
name: "cura";
|
||||||
|
@ -82,23 +83,14 @@ UM.Dialog {
|
||||||
}
|
}
|
||||||
|
|
||||||
ComboBox {
|
ComboBox {
|
||||||
id: printerSelectionCombobox;
|
id: printerComboBox;
|
||||||
Behavior on height { NumberAnimation { duration: 100 } }
|
Behavior on height { NumberAnimation { duration: 100 } }
|
||||||
height: 40 * screenScaleFactor;
|
height: 40 * screenScaleFactor;
|
||||||
model: ListModel {
|
model: ListModel {
|
||||||
id: printersModel;
|
id: comboBoxPrintersModel;
|
||||||
}
|
}
|
||||||
textRole: "name";
|
textRole: "name";
|
||||||
width: parent.width;
|
width: parent.width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Utils
|
|
||||||
function resetPrintersModel() {
|
|
||||||
printersModel.clear();
|
|
||||||
printersModel.append({ name: "Automatic", key: ""});
|
|
||||||
for (var index in OutputDevice.printers) {
|
|
||||||
printersModel.append({name: OutputDevice.printers[index].name, key: OutputDevice.printers[index].key});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,6 +79,7 @@ class ClusterPrinterStatus(BaseModel):
|
||||||
def updateOutputModel(self, model: PrinterOutputModel) -> None:
|
def updateOutputModel(self, model: PrinterOutputModel) -> None:
|
||||||
model.updateKey(self.uuid)
|
model.updateKey(self.uuid)
|
||||||
model.updateName(self.friendly_name)
|
model.updateName(self.friendly_name)
|
||||||
|
model.updateUniqueName(self.unique_name)
|
||||||
model.updateType(self.machine_variant)
|
model.updateType(self.machine_variant)
|
||||||
model.updateState(self.status if self.enabled else "disabled")
|
model.updateState(self.status if self.enabled else "disabled")
|
||||||
model.updateBuildplate(self.build_plate.type if self.build_plate else "glass")
|
model.updateBuildplate(self.build_plate.type if self.build_plate else "glass")
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
# 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.
|
||||||
|
import os
|
||||||
from typing import Optional, Dict, List, Callable, Any
|
from typing import Optional, Dict, List, Callable, Any
|
||||||
|
|
||||||
from PyQt5.QtGui import QDesktopServices
|
from PyQt5.QtGui import QDesktopServices
|
||||||
from PyQt5.QtCore import pyqtSlot, QUrl, pyqtSignal, pyqtProperty
|
from PyQt5.QtCore import pyqtSlot, QUrl, pyqtSignal, pyqtProperty, QObject
|
||||||
from PyQt5.QtNetwork import QNetworkReply
|
from PyQt5.QtNetwork import QNetworkReply
|
||||||
|
|
||||||
from UM.FileHandler.FileHandler import FileHandler
|
from UM.FileHandler.FileHandler import FileHandler
|
||||||
from UM.i18n import i18nCatalog
|
from UM.i18n import i18nCatalog
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
from UM.Scene.SceneNode import SceneNode
|
from UM.Scene.SceneNode import SceneNode
|
||||||
|
from cura.CuraApplication import CuraApplication
|
||||||
from cura.PrinterOutput.NetworkedPrinterOutputDevice import AuthState
|
from cura.PrinterOutput.NetworkedPrinterOutputDevice import AuthState
|
||||||
from cura.PrinterOutput.PrinterOutputDevice import ConnectionType
|
from cura.PrinterOutput.PrinterOutputDevice import ConnectionType
|
||||||
|
|
||||||
|
@ -42,6 +43,8 @@ class LocalClusterOutputDevice(UltimakerNetworkedPrinterOutputDevice):
|
||||||
)
|
)
|
||||||
|
|
||||||
self._cluster_api = None # type: Optional[ClusterApiClient]
|
self._cluster_api = None # type: Optional[ClusterApiClient]
|
||||||
|
self._active_exported_job = None # type: Optional[ExportFileJob]
|
||||||
|
self._printer_select_dialog = None # type: Optional[QObject]
|
||||||
|
|
||||||
# We don't have authentication over local networking, so we're always authenticated.
|
# We don't have authentication over local networking, so we're always authenticated.
|
||||||
self.setAuthenticationState(AuthState.Authenticated)
|
self.setAuthenticationState(AuthState.Authenticated)
|
||||||
|
@ -129,17 +132,49 @@ class LocalClusterOutputDevice(UltimakerNetworkedPrinterOutputDevice):
|
||||||
job.finished.connect(self._onPrintJobCreated)
|
job.finished.connect(self._onPrintJobCreated)
|
||||||
job.start()
|
job.start()
|
||||||
|
|
||||||
|
## Allows the user to choose a printer to print with from the printer selection dialogue.
|
||||||
|
# \param unique_name: The unique name of the printer to target.
|
||||||
|
@pyqtSlot(str, name="selectTargetPrinter")
|
||||||
|
def selectTargetPrinter(self, unique_name: str = "") -> None:
|
||||||
|
self._startPrintJobUpload(unique_name if unique_name != "" else None)
|
||||||
|
|
||||||
## Handler for when the print job was created locally.
|
## Handler for when the print job was created locally.
|
||||||
# It can now be sent over the network.
|
# It can now be sent over the network.
|
||||||
def _onPrintJobCreated(self, job: ExportFileJob) -> None:
|
def _onPrintJobCreated(self, job: ExportFileJob) -> None:
|
||||||
|
self._active_exported_job = job
|
||||||
|
# TODO: add preference to enable/disable this feature?
|
||||||
|
if self.clusterSize > 1:
|
||||||
|
self._showPrinterSelectionDialog() # self._startPrintJobUpload will be triggered from this dialog
|
||||||
|
return
|
||||||
|
self._startPrintJobUpload()
|
||||||
|
|
||||||
|
## Shows a dialog allowing the user to select which printer in a group to send a job to.
|
||||||
|
def _showPrinterSelectionDialog(self) -> None:
|
||||||
|
if not self._printer_select_dialog:
|
||||||
|
path = os.path.join(CuraApplication.getInstance().getPluginRegistry().getPluginPath("UM3NetworkPrinting"),
|
||||||
|
"resources", "qml", "PrintWindow.qml")
|
||||||
|
self._printer_select_dialog = CuraApplication.getInstance().createQmlComponent(path, {"OutputDevice": self})
|
||||||
|
self._printer_select_dialog.show()
|
||||||
|
|
||||||
|
## Upload the print job to the group.
|
||||||
|
def _startPrintJobUpload(self, unique_name: str = None) -> None:
|
||||||
|
if not self._active_exported_job:
|
||||||
|
Logger.log("e", "No active exported job to upload!")
|
||||||
|
return
|
||||||
self._progress.show()
|
self._progress.show()
|
||||||
parts = [
|
parts = [
|
||||||
self._createFormPart("name=owner", bytes(self._getUserName(), "utf-8"), "text/plain"),
|
self._createFormPart("name=owner", bytes(self._getUserName(), "utf-8"), "text/plain"),
|
||||||
self._createFormPart("name=\"file\"; filename=\"%s\"" % job.getFileName(), job.getOutput())
|
self._createFormPart("name=\"file\"; filename=\"%s\"" % self._active_exported_job.getFileName(),
|
||||||
|
self._active_exported_job.getOutput())
|
||||||
]
|
]
|
||||||
|
# If a specific printer was selected we include the name in the request.
|
||||||
|
# FIXME: Connect should allow the printer UUID here instead of the 'unique_name'.
|
||||||
|
if unique_name is not None:
|
||||||
|
parts.append(self._createFormPart("name=require_printer_name", bytes(unique_name, "utf-8"), "text/plain"))
|
||||||
# FIXME: move form posting to API client
|
# FIXME: move form posting to API client
|
||||||
self.postFormWithParts("/cluster-api/v1/print_jobs/", parts, on_finished=self._onPrintUploadCompleted,
|
self.postFormWithParts("/cluster-api/v1/print_jobs/", parts, on_finished=self._onPrintUploadCompleted,
|
||||||
on_progress=self._onPrintJobUploadProgress)
|
on_progress=self._onPrintJobUploadProgress)
|
||||||
|
self._active_exported_job = None
|
||||||
|
|
||||||
## Handler for print job upload progress.
|
## Handler for print job upload progress.
|
||||||
def _onPrintJobUploadProgress(self, bytes_sent: int, bytes_total: int) -> None:
|
def _onPrintJobUploadProgress(self, bytes_sent: int, bytes_total: int) -> None:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue