mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-05-12 14:08:04 +08:00
Merge pull request #13102 from Ultimaker/CURA-9514_collapsable_printers_list
[CURA-9514] Collapsable printers list
This commit is contained in:
commit
197683c6c6
@ -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.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
|
||||||
from .SingleInstance import SingleInstance
|
from .SingleInstance import SingleInstance
|
||||||
@ -1194,6 +1195,7 @@ class CuraApplication(QtApplication):
|
|||||||
qmlRegisterType(InstanceContainer, "Cura", 1, 0, "InstanceContainer")
|
qmlRegisterType(InstanceContainer, "Cura", 1, 0, "InstanceContainer")
|
||||||
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")
|
||||||
|
|
||||||
self.processEvents()
|
self.processEvents()
|
||||||
qmlRegisterType(FavoriteMaterialsModel, "Cura", 1, 0, "FavoriteMaterialsModel")
|
qmlRegisterType(FavoriteMaterialsModel, "Cura", 1, 0, "FavoriteMaterialsModel")
|
||||||
|
92
cura/Machines/Models/MachineListModel.py
Normal file
92
cura/Machines/Models/MachineListModel.py
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
# Copyright (c) 2022 Ultimaker B.V.
|
||||||
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
|
from PyQt6.QtCore import Qt, QTimer
|
||||||
|
|
||||||
|
from UM.Qt.ListModel import ListModel
|
||||||
|
from UM.Settings.ContainerStack import ContainerStack
|
||||||
|
from UM.i18n import i18nCatalog
|
||||||
|
from UM.Util import parseBool
|
||||||
|
|
||||||
|
from cura.Settings.AbstractMachine import AbstractMachine
|
||||||
|
from cura.Settings.CuraContainerRegistry import CuraContainerRegistry
|
||||||
|
from cura.Settings.GlobalStack import GlobalStack
|
||||||
|
|
||||||
|
|
||||||
|
class MachineListModel(ListModel):
|
||||||
|
NameRole = Qt.ItemDataRole.UserRole + 1
|
||||||
|
IdRole = Qt.ItemDataRole.UserRole + 2
|
||||||
|
HasRemoteConnectionRole = Qt.ItemDataRole.UserRole + 3
|
||||||
|
MetaDataRole = Qt.ItemDataRole.UserRole + 4
|
||||||
|
IsOnlineRole = Qt.ItemDataRole.UserRole + 5
|
||||||
|
MachineTypeRole = Qt.ItemDataRole.UserRole + 6
|
||||||
|
MachineCountRole = Qt.ItemDataRole.UserRole + 7
|
||||||
|
|
||||||
|
def __init__(self, parent=None) -> None:
|
||||||
|
super().__init__(parent)
|
||||||
|
|
||||||
|
self._catalog = i18nCatalog("cura")
|
||||||
|
|
||||||
|
self.addRoleName(self.NameRole, "name")
|
||||||
|
self.addRoleName(self.IdRole, "id")
|
||||||
|
self.addRoleName(self.HasRemoteConnectionRole, "hasRemoteConnection")
|
||||||
|
self.addRoleName(self.MetaDataRole, "metadata")
|
||||||
|
self.addRoleName(self.IsOnlineRole, "isOnline")
|
||||||
|
self.addRoleName(self.MachineTypeRole, "machineType")
|
||||||
|
self.addRoleName(self.MachineCountRole, "machineCount")
|
||||||
|
|
||||||
|
self._change_timer = QTimer()
|
||||||
|
self._change_timer.setInterval(200)
|
||||||
|
self._change_timer.setSingleShot(True)
|
||||||
|
self._change_timer.timeout.connect(self._update)
|
||||||
|
|
||||||
|
# Listen to changes
|
||||||
|
CuraContainerRegistry.getInstance().containerAdded.connect(self._onContainerChanged)
|
||||||
|
CuraContainerRegistry.getInstance().containerMetaDataChanged.connect(self._onContainerChanged)
|
||||||
|
CuraContainerRegistry.getInstance().containerRemoved.connect(self._onContainerChanged)
|
||||||
|
self._updateDelayed()
|
||||||
|
|
||||||
|
def _onContainerChanged(self, container) -> None:
|
||||||
|
"""Handler for container added/removed events from registry"""
|
||||||
|
|
||||||
|
# We only need to update when the added / removed container GlobalStack
|
||||||
|
if isinstance(container, GlobalStack):
|
||||||
|
self._updateDelayed()
|
||||||
|
|
||||||
|
def _updateDelayed(self) -> None:
|
||||||
|
self._change_timer.start()
|
||||||
|
|
||||||
|
def _update(self) -> None:
|
||||||
|
self.setItems([]) # Clear items
|
||||||
|
|
||||||
|
other_machine_stacks = CuraContainerRegistry.getInstance().findContainerStacks(type="machine")
|
||||||
|
|
||||||
|
abstract_machine_stacks = CuraContainerRegistry.getInstance().findContainerStacks(type = "abstract_machine")
|
||||||
|
abstract_machine_stacks.sort(key = lambda machine: machine.getName(), reverse = True)
|
||||||
|
|
||||||
|
for abstract_machine in abstract_machine_stacks:
|
||||||
|
online_machine_stacks = AbstractMachine.getMachines(abstract_machine, online_only = True)
|
||||||
|
|
||||||
|
# Create a list item for abstract machine
|
||||||
|
self.addItem(abstract_machine, len(online_machine_stacks))
|
||||||
|
|
||||||
|
# Create list of machines that are children of the abstract machine
|
||||||
|
for stack in online_machine_stacks:
|
||||||
|
self.addItem(stack)
|
||||||
|
# Remove this machine from the other stack list
|
||||||
|
other_machine_stacks.remove(stack)
|
||||||
|
|
||||||
|
for stack in other_machine_stacks:
|
||||||
|
self.addItem(stack)
|
||||||
|
|
||||||
|
def addItem(self, container_stack: ContainerStack, machine_count: int = 0) -> None:
|
||||||
|
if parseBool(container_stack.getMetaDataEntry("hidden", False)):
|
||||||
|
return
|
||||||
|
|
||||||
|
self.appendItem({"name": container_stack.getName(),
|
||||||
|
"id": container_stack.getId(),
|
||||||
|
"metadata": container_stack.getMetaData().copy(),
|
||||||
|
"isOnline": parseBool(container_stack.getMetaDataEntry("is_online", False)),
|
||||||
|
"machineType": container_stack.getMetaDataEntry("type"),
|
||||||
|
"machineCount": machine_count,
|
||||||
|
})
|
@ -1,6 +1,7 @@
|
|||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from UM.Settings.ContainerStack import ContainerStack
|
from UM.Settings.ContainerStack import ContainerStack
|
||||||
|
from UM.Util import parseBool
|
||||||
from cura.PrinterOutput.PrinterOutputDevice import ConnectionType
|
from cura.PrinterOutput.PrinterOutputDevice import ConnectionType
|
||||||
from cura.Settings.GlobalStack import GlobalStack
|
from cura.Settings.GlobalStack import GlobalStack
|
||||||
from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase
|
from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase
|
||||||
@ -14,14 +15,30 @@ class AbstractMachine(GlobalStack):
|
|||||||
super().__init__(container_id)
|
super().__init__(container_id)
|
||||||
self.setMetaDataEntry("type", "abstract_machine")
|
self.setMetaDataEntry("type", "abstract_machine")
|
||||||
|
|
||||||
def getMachines(self) -> List[ContainerStack]:
|
@classmethod
|
||||||
from cura.CuraApplication import CuraApplication
|
def getMachines(cls, abstract_machine: ContainerStack, online_only = False) -> List[ContainerStack]:
|
||||||
|
""" Fetches all container stacks that match definition_id with an abstract machine.
|
||||||
|
|
||||||
|
:param abstractMachine: The abstract machine stack.
|
||||||
|
:return: A list of Containers or an empty list if abstract_machine is not an "abstract_machine"
|
||||||
|
"""
|
||||||
|
if not abstract_machine.getMetaDataEntry("type") == "abstract_machine":
|
||||||
|
return []
|
||||||
|
|
||||||
|
from cura.CuraApplication import CuraApplication # In function to avoid circular import
|
||||||
application = CuraApplication.getInstance()
|
application = CuraApplication.getInstance()
|
||||||
registry = application.getContainerRegistry()
|
registry = application.getContainerRegistry()
|
||||||
|
|
||||||
printer_type = self.definition.getId()
|
machines = registry.findContainerStacks(type="machine")
|
||||||
return [machine for machine in registry.findContainerStacks(type="machine") if machine.definition.id == printer_type and ConnectionType.CloudConnection in machine.configuredConnectionTypes]
|
# Filter machines that match definition
|
||||||
|
machines = filter(lambda machine: machine.definition.id == abstract_machine.definition.getId(), machines)
|
||||||
|
# Filter only LAN and Cloud printers
|
||||||
|
machines = filter(lambda machine: ConnectionType.CloudConnection in machine.configuredConnectionTypes or ConnectionType.NetworkConnection in machine.configuredConnectionTypes, machines)
|
||||||
|
if online_only:
|
||||||
|
# LAN printers have is_online = False but should still be included
|
||||||
|
machines = filter(lambda machine: parseBool(machine.getMetaDataEntry("is_online", False) or ConnectionType.NetworkConnection in machine.configuredConnectionTypes), machines)
|
||||||
|
|
||||||
|
return list(machines)
|
||||||
|
|
||||||
|
|
||||||
## private:
|
## private:
|
||||||
|
@ -297,6 +297,7 @@ class CuraStackBuilder:
|
|||||||
name = machine_definition.getName()
|
name = machine_definition.getName()
|
||||||
|
|
||||||
stack = AbstractMachine(abstract_machine_id)
|
stack = AbstractMachine(abstract_machine_id)
|
||||||
|
stack.setMetaDataEntry("is_online", True)
|
||||||
stack.setDefinition(machine_definition)
|
stack.setDefinition(machine_definition)
|
||||||
cls.createUserContainer(
|
cls.createUserContainer(
|
||||||
name,
|
name,
|
||||||
|
@ -232,6 +232,9 @@ class LocalClusterOutputDeviceManager:
|
|||||||
self._connectToOutputDevice(device, new_machine)
|
self._connectToOutputDevice(device, new_machine)
|
||||||
self._showCloudFlowMessage(device)
|
self._showCloudFlowMessage(device)
|
||||||
|
|
||||||
|
_abstract_machine = CuraStackBuilder.createAbstractMachine(device.printerType)
|
||||||
|
|
||||||
|
|
||||||
def _storeManualAddress(self, address: str) -> None:
|
def _storeManualAddress(self, address: str) -> None:
|
||||||
"""Add an address to the stored preferences."""
|
"""Add an address to the stored preferences."""
|
||||||
|
|
||||||
|
87
resources/qml/PrinterSelector/MachineListButton.qml
Normal file
87
resources/qml/PrinterSelector/MachineListButton.qml
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
// Copyright (c) 2022 Ultimaker B.V.
|
||||||
|
// Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
|
import QtQuick 2.10
|
||||||
|
import QtQuick.Controls 2.3
|
||||||
|
|
||||||
|
import UM 1.5 as UM
|
||||||
|
import Cura 1.0 as Cura
|
||||||
|
|
||||||
|
|
||||||
|
Button
|
||||||
|
{
|
||||||
|
id: machineListButton
|
||||||
|
|
||||||
|
width: parent.width
|
||||||
|
height: UM.Theme.getSize("large_button").height
|
||||||
|
leftPadding: UM.Theme.getSize("default_margin").width
|
||||||
|
rightPadding: UM.Theme.getSize("default_margin").width
|
||||||
|
checkable: true
|
||||||
|
hoverEnabled: true
|
||||||
|
|
||||||
|
contentItem: Item
|
||||||
|
{
|
||||||
|
width: machineListButton.width - machineListButton.leftPadding - machineListButton.rightPadding
|
||||||
|
height: UM.Theme.getSize("action_button").height
|
||||||
|
|
||||||
|
UM.ColorImage
|
||||||
|
{
|
||||||
|
id: printerIcon
|
||||||
|
height: UM.Theme.getSize("medium_button").height
|
||||||
|
width: UM.Theme.getSize("medium_button").width
|
||||||
|
color: UM.Theme.getColor("machine_selector_printer_icon")
|
||||||
|
visible: model.machineType == "abstract_machine" || !model.isOnline
|
||||||
|
source: model.machineType == "abstract_machine" ? UM.Theme.getIcon("PrinterTriple", "medium") : UM.Theme.getIcon("Printer", "medium")
|
||||||
|
|
||||||
|
anchors
|
||||||
|
{
|
||||||
|
left: parent.left
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UM.Label
|
||||||
|
{
|
||||||
|
id: buttonText
|
||||||
|
anchors
|
||||||
|
{
|
||||||
|
left: printerIcon.right
|
||||||
|
right: printerCount.left
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
|
leftMargin: UM.Theme.getSize("default_margin").width
|
||||||
|
}
|
||||||
|
text: machineListButton.text
|
||||||
|
font: model.machineType == "abstract_machine" ? UM.Theme.getFont("medium_bold") : UM.Theme.getFont("medium")
|
||||||
|
visible: text != ""
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
id: printerCount
|
||||||
|
color: UM.Theme.getColor("background_2")
|
||||||
|
radius: height
|
||||||
|
width: height
|
||||||
|
anchors
|
||||||
|
{
|
||||||
|
right: parent.right
|
||||||
|
top: buttonText.top
|
||||||
|
bottom: buttonText.bottom
|
||||||
|
}
|
||||||
|
visible: model.machineType == "abstract_machine"
|
||||||
|
|
||||||
|
UM.Label
|
||||||
|
{
|
||||||
|
text: model.machineCount
|
||||||
|
anchors.centerIn: parent
|
||||||
|
font: UM.Theme.getFont("default_bold")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
background: Rectangle
|
||||||
|
{
|
||||||
|
id: backgroundRect
|
||||||
|
color: machineListButton.hovered ? UM.Theme.getColor("action_button_hovered") : "transparent"
|
||||||
|
}
|
||||||
|
}
|
@ -192,7 +192,7 @@ Cura.ExpandablePopup
|
|||||||
contentItem: Item
|
contentItem: Item
|
||||||
{
|
{
|
||||||
id: popup
|
id: popup
|
||||||
implicitWidth: UM.Theme.getSize("machine_selector_widget_content").width
|
implicitWidth: Math.max(machineSelector.width, UM.Theme.getSize("machine_selector_widget_content").width)
|
||||||
implicitHeight: Math.min(machineSelectorList.contentHeight + separator.height + buttonRow.height, UM.Theme.getSize("machine_selector_widget_content").height) //Maximum height is the theme entry.
|
implicitHeight: Math.min(machineSelectorList.contentHeight + separator.height + buttonRow.height, UM.Theme.getSize("machine_selector_widget_content").height) //Maximum height is the theme entry.
|
||||||
MachineSelectorList
|
MachineSelectorList
|
||||||
{
|
{
|
||||||
@ -224,6 +224,9 @@ Cura.ExpandablePopup
|
|||||||
|
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
padding: UM.Theme.getSize("default_margin").width
|
padding: UM.Theme.getSize("default_margin").width
|
||||||
spacing: UM.Theme.getSize("default_margin").width
|
spacing: UM.Theme.getSize("default_margin").width
|
||||||
|
|
||||||
@ -236,7 +239,7 @@ Cura.ExpandablePopup
|
|||||||
// The maximum width of the button is half of the total space, minus the padding of the parent, the left
|
// The maximum width of the button is half of the total space, minus the padding of the parent, the left
|
||||||
// padding of the component and half the spacing because of the space between buttons.
|
// padding of the component and half the spacing because of the space between buttons.
|
||||||
fixedWidthMode: true
|
fixedWidthMode: true
|
||||||
width: UM.Theme.getSize("machine_selector_widget_content").width / 2 - leftPadding
|
width: buttonRow.width / 2 - leftPadding * 1.5
|
||||||
onClicked:
|
onClicked:
|
||||||
{
|
{
|
||||||
toggleContent()
|
toggleContent()
|
||||||
@ -253,7 +256,7 @@ Cura.ExpandablePopup
|
|||||||
fixedWidthMode: true
|
fixedWidthMode: true
|
||||||
// The maximum width of the button is half of the total space, minus the padding of the parent, the right
|
// The maximum width of the button is half of the total space, minus the padding of the parent, the right
|
||||||
// padding of the component and half the spacing because of the space between buttons.
|
// padding of the component and half the spacing because of the space between buttons.
|
||||||
width: UM.Theme.getSize("machine_selector_widget_content").width / 2 - leftPadding
|
width: buttonRow.width / 2 - rightPadding * 1.5
|
||||||
onClicked:
|
onClicked:
|
||||||
{
|
{
|
||||||
toggleContent()
|
toggleContent()
|
||||||
|
@ -10,8 +10,8 @@ import Cura 1.0 as Cura
|
|||||||
ListView
|
ListView
|
||||||
{
|
{
|
||||||
id: listView
|
id: listView
|
||||||
model: Cura.GlobalStacksModel {}
|
model: Cura.MachineListModel {}
|
||||||
section.property: "hasRemoteConnection"
|
section.property: "isOnline"
|
||||||
property real contentHeight: childrenRect.height
|
property real contentHeight: childrenRect.height
|
||||||
|
|
||||||
ScrollBar.vertical: UM.ScrollBar
|
ScrollBar.vertical: UM.ScrollBar
|
||||||
@ -21,7 +21,7 @@ ListView
|
|||||||
|
|
||||||
section.delegate: UM.Label
|
section.delegate: UM.Label
|
||||||
{
|
{
|
||||||
text: section == "true" ? catalog.i18nc("@label", "Connected printers") : catalog.i18nc("@label", "Preset printers")
|
text: section == "true" ? catalog.i18nc("@label", "Connected printers") : catalog.i18nc("@label", "Other printers")
|
||||||
width: parent.width - scrollBar.width
|
width: parent.width - scrollBar.width
|
||||||
height: UM.Theme.getSize("action_button").height
|
height: UM.Theme.getSize("action_button").height
|
||||||
leftPadding: UM.Theme.getSize("default_margin").width
|
leftPadding: UM.Theme.getSize("default_margin").width
|
||||||
@ -29,13 +29,10 @@ ListView
|
|||||||
color: UM.Theme.getColor("text_medium")
|
color: UM.Theme.getColor("text_medium")
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate: MachineSelectorButton
|
delegate: MachineListButton
|
||||||
{
|
{
|
||||||
text: model.name ? model.name : ""
|
text: model.name ? model.name : ""
|
||||||
width: listView.width - scrollBar.width
|
width: listView.width - scrollBar.width
|
||||||
outputDevice: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null
|
|
||||||
|
|
||||||
checked: Cura.MachineManager.activeMachine ? Cura.MachineManager.activeMachine.id == model.id : false
|
|
||||||
|
|
||||||
onClicked:
|
onClicked:
|
||||||
{
|
{
|
||||||
|
@ -2,6 +2,7 @@ module Cura
|
|||||||
|
|
||||||
MachineSelector 1.0 MachineSelector.qml
|
MachineSelector 1.0 MachineSelector.qml
|
||||||
MachineSelectorButton 1.0 MachineSelectorButton.qml
|
MachineSelectorButton 1.0 MachineSelectorButton.qml
|
||||||
|
MachineListButton 1.0 MachineListButton.qml
|
||||||
CustomConfigurationSelector 1.0 CustomConfigurationSelector.qml
|
CustomConfigurationSelector 1.0 CustomConfigurationSelector.qml
|
||||||
PrintSetupSelector 1.0 PrintSetupSelector.qml
|
PrintSetupSelector 1.0 PrintSetupSelector.qml
|
||||||
ProfileOverview 1.6 ProfileOverview.qml
|
ProfileOverview 1.6 ProfileOverview.qml
|
||||||
|
@ -564,6 +564,9 @@
|
|||||||
"medium_button": [2.5, 2.5],
|
"medium_button": [2.5, 2.5],
|
||||||
"medium_button_icon": [2, 2],
|
"medium_button_icon": [2, 2],
|
||||||
|
|
||||||
|
"large_button": [3.0, 3.0],
|
||||||
|
"large_button_icon": [2.8, 2.8],
|
||||||
|
|
||||||
"context_menu": [20, 2],
|
"context_menu": [20, 2],
|
||||||
|
|
||||||
"icon_indicator": [1, 1],
|
"icon_indicator": [1, 1],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user