mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-05-01 08:14:22 +08:00
W.I.P.: Press print on abstract cloud printer. User should see dialog.
Start of implementation. When printing on an abstract printer, a user should see a dialog with the matching concrete cloud printers to pick from to actually print. Names are not final. Very much a work in progress. Very not finished also. start of implementation for CURA-9278
This commit is contained in:
parent
ccdbc3e06f
commit
a56a21cf93
@ -115,6 +115,7 @@ from . import CuraActions
|
|||||||
from . import PlatformPhysics
|
from . import PlatformPhysics
|
||||||
from . import PrintJobPreviewImageProvider
|
from . import PrintJobPreviewImageProvider
|
||||||
from .AutoSave import AutoSave
|
from .AutoSave import AutoSave
|
||||||
|
from .Machines.Models.CompatibleMachineModel import CompatibleMachineModel
|
||||||
from .Machines.Models.MachineListModel import MachineListModel
|
from .Machines.Models.MachineListModel import MachineListModel
|
||||||
from .Machines.Models.ActiveIntentQualitiesModel import ActiveIntentQualitiesModel
|
from .Machines.Models.ActiveIntentQualitiesModel import ActiveIntentQualitiesModel
|
||||||
from .Machines.Models.IntentSelectionModel import IntentSelectionModel
|
from .Machines.Models.IntentSelectionModel import IntentSelectionModel
|
||||||
@ -1191,6 +1192,7 @@ class CuraApplication(QtApplication):
|
|||||||
qmlRegisterType(ExtrudersModel, "Cura", 1, 0, "ExtrudersModel")
|
qmlRegisterType(ExtrudersModel, "Cura", 1, 0, "ExtrudersModel")
|
||||||
qmlRegisterType(GlobalStacksModel, "Cura", 1, 0, "GlobalStacksModel")
|
qmlRegisterType(GlobalStacksModel, "Cura", 1, 0, "GlobalStacksModel")
|
||||||
qmlRegisterType(MachineListModel, "Cura", 1, 0, "MachineListModel")
|
qmlRegisterType(MachineListModel, "Cura", 1, 0, "MachineListModel")
|
||||||
|
qmlRegisterType(CompatibleMachineModel, "Cura", 1, 0, "CompatibleMachineModel")
|
||||||
|
|
||||||
self.processEvents()
|
self.processEvents()
|
||||||
qmlRegisterType(FavoriteMaterialsModel, "Cura", 1, 0, "FavoriteMaterialsModel")
|
qmlRegisterType(FavoriteMaterialsModel, "Cura", 1, 0, "FavoriteMaterialsModel")
|
||||||
|
73
cura/Machines/Models/CompatibleMachineModel.py
Normal file
73
cura/Machines/Models/CompatibleMachineModel.py
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
# Copyright (c) 2022 Ultimaker B.V.
|
||||||
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
|
# TODO?: documentation
|
||||||
|
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from PyQt6.QtCore import Qt, QTimer, QObject, pyqtSlot, pyqtProperty, pyqtSignal
|
||||||
|
|
||||||
|
from UM.Qt.ListModel import ListModel
|
||||||
|
from UM.Settings.ContainerStack import ContainerStack
|
||||||
|
from UM.i18n import i18nCatalog
|
||||||
|
from UM.Util import parseBool
|
||||||
|
|
||||||
|
from cura.PrinterOutput.PrinterOutputDevice import ConnectionType
|
||||||
|
from cura.Settings.CuraContainerRegistry import CuraContainerRegistry
|
||||||
|
|
||||||
|
|
||||||
|
class CompatibleMachineModel(ListModel):
|
||||||
|
NameRole = Qt.ItemDataRole.UserRole + 1
|
||||||
|
IdRole = Qt.ItemDataRole.UserRole + 2
|
||||||
|
ExtrudersRole = Qt.ItemDataRole.UserRole + 3
|
||||||
|
|
||||||
|
def __init__(self, parent: Optional[QObject] = None) -> None:
|
||||||
|
super().__init__(parent)
|
||||||
|
|
||||||
|
self._filter_on_definition_id: Optional[str] = None
|
||||||
|
|
||||||
|
self._catalog = i18nCatalog("cura")
|
||||||
|
|
||||||
|
self.addRoleName(self.NameRole, "name")
|
||||||
|
self.addRoleName(self.IdRole, "id")
|
||||||
|
self.addRoleName(self.ExtrudersRole, "extruders")
|
||||||
|
|
||||||
|
filterChanged = pyqtSignal(str)
|
||||||
|
|
||||||
|
@pyqtSlot(str)
|
||||||
|
def setFilter(self, abstract_machine_id: str) -> None:
|
||||||
|
# TODO??: defensive coding; check if machine is abstract & abort/log if not
|
||||||
|
self._filter_on_definition_id = abstract_machine_id
|
||||||
|
|
||||||
|
# Don't need a delayed update, since it's fire once on user click (either on 'print to cloud' or 'refresh').
|
||||||
|
# So, no signals that could come in (too) quickly.
|
||||||
|
self.filterChanged.emit(self._filter_on_definition_id)
|
||||||
|
self._update()
|
||||||
|
|
||||||
|
@pyqtProperty(str, fset=setFilter, notify=filterChanged)
|
||||||
|
def filter(self) -> str:
|
||||||
|
return self._filter_on_definition_id
|
||||||
|
|
||||||
|
def _update(self) -> None:
|
||||||
|
self.clear()
|
||||||
|
if not self._filter_on_definition_id or self._filter_on_definition_id == "":
|
||||||
|
# TODO?: log
|
||||||
|
return
|
||||||
|
|
||||||
|
from cura.CuraApplication import CuraApplication
|
||||||
|
machine_manager = CuraApplication.getInstance().getMachineManager()
|
||||||
|
compatible_machines = machine_manager.getMachinesWithDefinition(self._filter_on_definition_id, online_only = True)
|
||||||
|
# TODO: Handle 0 compatible machines -> option to close window? Message in card? (remember the design has a refresh button!)
|
||||||
|
|
||||||
|
for container_stack in compatible_machines:
|
||||||
|
if parseBool(container_stack.getMetaDataEntry("hidden", False)) or parseBool(container_stack.getMetaDataEntry("is_abstract_machine", False)):
|
||||||
|
continue
|
||||||
|
self.addItem(container_stack)
|
||||||
|
|
||||||
|
def addItem(self, container_stack: ContainerStack, machine_count: int = 0) -> None:
|
||||||
|
extruders = CuraContainerRegistry.getInstance().findContainerStacks(type="extruder_train", machine=container_stack.getId())
|
||||||
|
self.appendItem({
|
||||||
|
"name": container_stack.getName(),
|
||||||
|
"id": container_stack.getId(),
|
||||||
|
"extruders": [extruder.getMetaData().copy() for extruder in extruders]
|
||||||
|
})
|
@ -5,10 +5,13 @@
|
|||||||
# online cloud connected printers are represented within this ListModel. Additional information such as the number of
|
# online cloud connected printers are represented within this ListModel. Additional information such as the number of
|
||||||
# connected printers for each printer type is gathered.
|
# connected printers for each printer type is gathered.
|
||||||
|
|
||||||
from PyQt6.QtCore import Qt, QTimer, pyqtSlot, pyqtProperty, pyqtSignal
|
from typing import Optional
|
||||||
|
|
||||||
|
from PyQt6.QtCore import Qt, QTimer, QObject, pyqtSlot, pyqtProperty, pyqtSignal
|
||||||
|
|
||||||
from UM.Qt.ListModel import ListModel
|
from UM.Qt.ListModel import ListModel
|
||||||
from UM.Settings.ContainerStack import ContainerStack
|
from UM.Settings.ContainerStack import ContainerStack
|
||||||
|
from UM.Settings.Interfaces import ContainerInterface
|
||||||
from UM.i18n import i18nCatalog
|
from UM.i18n import i18nCatalog
|
||||||
from UM.Util import parseBool
|
from UM.Util import parseBool
|
||||||
from cura.PrinterOutput.PrinterOutputDevice import ConnectionType
|
from cura.PrinterOutput.PrinterOutputDevice import ConnectionType
|
||||||
@ -27,7 +30,7 @@ class MachineListModel(ListModel):
|
|||||||
IsAbstractMachineRole = Qt.ItemDataRole.UserRole + 7
|
IsAbstractMachineRole = Qt.ItemDataRole.UserRole + 7
|
||||||
ComponentTypeRole = Qt.ItemDataRole.UserRole + 8
|
ComponentTypeRole = Qt.ItemDataRole.UserRole + 8
|
||||||
|
|
||||||
def __init__(self, parent=None) -> None:
|
def __init__(self, parent: Optional[QObject] = None) -> None:
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
|
|
||||||
self._show_cloud_printers = False
|
self._show_cloud_printers = False
|
||||||
@ -66,7 +69,7 @@ class MachineListModel(ListModel):
|
|||||||
self._updateDelayed()
|
self._updateDelayed()
|
||||||
self.showCloudPrintersChanged.emit(show_cloud_printers)
|
self.showCloudPrintersChanged.emit(show_cloud_printers)
|
||||||
|
|
||||||
def _onContainerChanged(self, container) -> None:
|
def _onContainerChanged(self, container: ContainerInterface) -> None:
|
||||||
"""Handler for container added/removed events from registry"""
|
"""Handler for container added/removed events from registry"""
|
||||||
|
|
||||||
# We only need to update when the added / removed container GlobalStack
|
# We only need to update when the added / removed container GlobalStack
|
||||||
@ -79,14 +82,15 @@ class MachineListModel(ListModel):
|
|||||||
def _update(self) -> None:
|
def _update(self) -> None:
|
||||||
self.clear()
|
self.clear()
|
||||||
|
|
||||||
|
from cura.CuraApplication import CuraApplication
|
||||||
|
machines_manager = CuraApplication.getInstance().getMachineManager()
|
||||||
|
|
||||||
other_machine_stacks = CuraContainerRegistry.getInstance().findContainerStacks(type="machine")
|
other_machine_stacks = CuraContainerRegistry.getInstance().findContainerStacks(type="machine")
|
||||||
|
|
||||||
abstract_machine_stacks = CuraContainerRegistry.getInstance().findContainerStacks(is_abstract_machine = "True")
|
abstract_machine_stacks = CuraContainerRegistry.getInstance().findContainerStacks(is_abstract_machine = "True")
|
||||||
abstract_machine_stacks.sort(key = lambda machine: machine.getName(), reverse = True)
|
abstract_machine_stacks.sort(key = lambda machine: machine.getName(), reverse = True)
|
||||||
for abstract_machine in abstract_machine_stacks:
|
for abstract_machine in abstract_machine_stacks:
|
||||||
definition_id = abstract_machine.definition.getId()
|
definition_id = abstract_machine.definition.getId()
|
||||||
from cura.CuraApplication import CuraApplication
|
|
||||||
machines_manager = CuraApplication.getInstance().getMachineManager()
|
|
||||||
online_machine_stacks = machines_manager.getMachinesWithDefinition(definition_id, online_only = True)
|
online_machine_stacks = machines_manager.getMachinesWithDefinition(definition_id, online_only = True)
|
||||||
|
|
||||||
# Create a list item for abstract machine
|
# Create a list item for abstract machine
|
||||||
@ -132,11 +136,11 @@ class MachineListModel(ListModel):
|
|||||||
has_connection |= connection_type in container_stack.configuredConnectionTypes
|
has_connection |= connection_type in container_stack.configuredConnectionTypes
|
||||||
|
|
||||||
self.appendItem({
|
self.appendItem({
|
||||||
"componentType": "MACHINE",
|
"componentType": "MACHINE",
|
||||||
"name": container_stack.getName(),
|
"name": container_stack.getName(),
|
||||||
"id": container_stack.getId(),
|
"id": container_stack.getId(),
|
||||||
"metadata": container_stack.getMetaData().copy(),
|
"metadata": container_stack.getMetaData().copy(),
|
||||||
"isOnline": parseBool(container_stack.getMetaDataEntry("is_online", False)) and has_connection,
|
"isOnline": parseBool(container_stack.getMetaDataEntry("is_online", False)) and has_connection,
|
||||||
"isAbstractMachine": parseBool(container_stack.getMetaDataEntry("is_abstract_machine", False)),
|
"isAbstractMachine": parseBool(container_stack.getMetaDataEntry("is_abstract_machine", False)),
|
||||||
"machineCount": machine_count,
|
"machineCount": machine_count,
|
||||||
})
|
})
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
from time import time
|
from time import time
|
||||||
from typing import List
|
from typing import List, Optional
|
||||||
|
|
||||||
from PyQt6.QtCore import QObject
|
from PyQt6.QtCore import QObject
|
||||||
from PyQt6.QtNetwork import QNetworkReply
|
from PyQt6.QtNetwork import QNetworkReply
|
||||||
|
|
||||||
from UM import i18nCatalog
|
from UM import i18nCatalog
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
|
from UM.FileHandler.FileHandler import FileHandler
|
||||||
|
from UM.Resources import Resources
|
||||||
|
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
|
||||||
from .CloudApiClient import CloudApiClient
|
from .CloudApiClient import CloudApiClient
|
||||||
@ -31,6 +36,8 @@ class AbstractCloudOutputDevice(UltimakerNetworkedPrinterOutputDevice):
|
|||||||
parent=parent
|
parent=parent
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self._on_print_dialog: Optional[QObject] = None
|
||||||
|
|
||||||
self._setInterfaceElements()
|
self._setInterfaceElements()
|
||||||
|
|
||||||
def connect(self) -> None:
|
def connect(self) -> None:
|
||||||
@ -84,4 +91,26 @@ class AbstractCloudOutputDevice(UltimakerNetworkedPrinterOutputDevice):
|
|||||||
self._updatePrinters(all_configurations)
|
self._updatePrinters(all_configurations)
|
||||||
|
|
||||||
def _onError(self, reply: QNetworkReply, error: QNetworkReply.NetworkError) -> None:
|
def _onError(self, reply: QNetworkReply, error: QNetworkReply.NetworkError) -> None:
|
||||||
|
# TODO!
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def _openChoosePrinterDialog(self, machine_filter_id: str) -> None:
|
||||||
|
if self._on_print_dialog is None:
|
||||||
|
qml_path = Resources.getPath(CuraApplication.ResourceTypes.QmlFiles, "Dialogs", "ChoosePrinterDialog.qml")
|
||||||
|
self._on_print_dialog = CuraApplication.getInstance().createQmlComponent(qml_path, {})
|
||||||
|
if self._on_print_dialog is None: # Failed to load QML file.
|
||||||
|
return
|
||||||
|
self._on_print_dialog.setProperty("machine_id_filter", machine_filter_id)
|
||||||
|
self._on_print_dialog.show()
|
||||||
|
|
||||||
|
def requestWrite(self, nodes: List[SceneNode], file_name: Optional[str] = None, limit_mimetypes: bool = False, file_handler: Optional[FileHandler] = None, **kwargs) -> None:
|
||||||
|
|
||||||
|
# TODO:
|
||||||
|
# - Prettify (and make usable) dialog.
|
||||||
|
# (Including extruders... their metadata is already in the model. Is that enough though. Does that contain configurations as well?)
|
||||||
|
# - On button clicked, fetch/push to here selected printer, hide dialog
|
||||||
|
# - Find correct output-device for selected printer maybe via `CuraApplication.getInstance().getOutputDeviceManager().getOutputDevices()`
|
||||||
|
# Call 'requestWrite' of the selected output-device.
|
||||||
|
|
||||||
|
self._openChoosePrinterDialog(CuraApplication.getInstance().getGlobalContainerStack().definition.getId())
|
||||||
|
|
||||||
|
34
resources/qml/Dialogs/ChoosePrinterDialog.qml
Normal file
34
resources/qml/Dialogs/ChoosePrinterDialog.qml
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// Copyright (c) 2022 Ultimaker B.V.
|
||||||
|
// Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
|
import QtQuick 2.2
|
||||||
|
import QtQuick.Controls 2.9
|
||||||
|
|
||||||
|
import UM 1.5 as UM
|
||||||
|
import Cura 1.0 as Cura
|
||||||
|
|
||||||
|
UM.Dialog
|
||||||
|
{
|
||||||
|
id: base
|
||||||
|
|
||||||
|
property string machine_id_filter: ""
|
||||||
|
|
||||||
|
Column
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Repeater
|
||||||
|
{
|
||||||
|
id: contents
|
||||||
|
|
||||||
|
model: Cura.CompatibleMachineModel
|
||||||
|
{
|
||||||
|
filter: machine_id_filter
|
||||||
|
}
|
||||||
|
delegate: UM.Label
|
||||||
|
{
|
||||||
|
text: model.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user