mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-05-08 08:49:01 +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 PrintJobPreviewImageProvider
|
||||
from .AutoSave import AutoSave
|
||||
from .Machines.Models.MachineListModel import MachineListModel
|
||||
from .Machines.Models.ActiveIntentQualitiesModel import ActiveIntentQualitiesModel
|
||||
from .Machines.Models.IntentSelectionModel import IntentSelectionModel
|
||||
from .SingleInstance import SingleInstance
|
||||
@ -1194,6 +1195,7 @@ class CuraApplication(QtApplication):
|
||||
qmlRegisterType(InstanceContainer, "Cura", 1, 0, "InstanceContainer")
|
||||
qmlRegisterType(ExtrudersModel, "Cura", 1, 0, "ExtrudersModel")
|
||||
qmlRegisterType(GlobalStacksModel, "Cura", 1, 0, "GlobalStacksModel")
|
||||
qmlRegisterType(MachineListModel, "Cura", 1, 0, "MachineListModel")
|
||||
|
||||
self.processEvents()
|
||||
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 UM.Settings.ContainerStack import ContainerStack
|
||||
from UM.Util import parseBool
|
||||
from cura.PrinterOutput.PrinterOutputDevice import ConnectionType
|
||||
from cura.Settings.GlobalStack import GlobalStack
|
||||
from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase
|
||||
@ -14,14 +15,30 @@ class AbstractMachine(GlobalStack):
|
||||
super().__init__(container_id)
|
||||
self.setMetaDataEntry("type", "abstract_machine")
|
||||
|
||||
def getMachines(self) -> List[ContainerStack]:
|
||||
from cura.CuraApplication import CuraApplication
|
||||
@classmethod
|
||||
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()
|
||||
registry = application.getContainerRegistry()
|
||||
|
||||
printer_type = self.definition.getId()
|
||||
return [machine for machine in registry.findContainerStacks(type="machine") if machine.definition.id == printer_type and ConnectionType.CloudConnection in machine.configuredConnectionTypes]
|
||||
machines = registry.findContainerStacks(type="machine")
|
||||
# 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:
|
||||
|
@ -297,6 +297,7 @@ class CuraStackBuilder:
|
||||
name = machine_definition.getName()
|
||||
|
||||
stack = AbstractMachine(abstract_machine_id)
|
||||
stack.setMetaDataEntry("is_online", True)
|
||||
stack.setDefinition(machine_definition)
|
||||
cls.createUserContainer(
|
||||
name,
|
||||
|
@ -232,6 +232,9 @@ class LocalClusterOutputDeviceManager:
|
||||
self._connectToOutputDevice(device, new_machine)
|
||||
self._showCloudFlowMessage(device)
|
||||
|
||||
_abstract_machine = CuraStackBuilder.createAbstractMachine(device.printerType)
|
||||
|
||||
|
||||
def _storeManualAddress(self, address: str) -> None:
|
||||
"""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
|
||||
{
|
||||
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.
|
||||
MachineSelectorList
|
||||
{
|
||||
@ -224,6 +224,9 @@ Cura.ExpandablePopup
|
||||
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
padding: 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
|
||||
// padding of the component and half the spacing because of the space between buttons.
|
||||
fixedWidthMode: true
|
||||
width: UM.Theme.getSize("machine_selector_widget_content").width / 2 - leftPadding
|
||||
width: buttonRow.width / 2 - leftPadding * 1.5
|
||||
onClicked:
|
||||
{
|
||||
toggleContent()
|
||||
@ -253,7 +256,7 @@ Cura.ExpandablePopup
|
||||
fixedWidthMode: true
|
||||
// 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.
|
||||
width: UM.Theme.getSize("machine_selector_widget_content").width / 2 - leftPadding
|
||||
width: buttonRow.width / 2 - rightPadding * 1.5
|
||||
onClicked:
|
||||
{
|
||||
toggleContent()
|
||||
|
@ -10,8 +10,8 @@ import Cura 1.0 as Cura
|
||||
ListView
|
||||
{
|
||||
id: listView
|
||||
model: Cura.GlobalStacksModel {}
|
||||
section.property: "hasRemoteConnection"
|
||||
model: Cura.MachineListModel {}
|
||||
section.property: "isOnline"
|
||||
property real contentHeight: childrenRect.height
|
||||
|
||||
ScrollBar.vertical: UM.ScrollBar
|
||||
@ -21,7 +21,7 @@ ListView
|
||||
|
||||
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
|
||||
height: UM.Theme.getSize("action_button").height
|
||||
leftPadding: UM.Theme.getSize("default_margin").width
|
||||
@ -29,13 +29,10 @@ ListView
|
||||
color: UM.Theme.getColor("text_medium")
|
||||
}
|
||||
|
||||
delegate: MachineSelectorButton
|
||||
delegate: MachineListButton
|
||||
{
|
||||
text: model.name ? model.name : ""
|
||||
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:
|
||||
{
|
||||
|
@ -2,6 +2,7 @@ module Cura
|
||||
|
||||
MachineSelector 1.0 MachineSelector.qml
|
||||
MachineSelectorButton 1.0 MachineSelectorButton.qml
|
||||
MachineListButton 1.0 MachineListButton.qml
|
||||
CustomConfigurationSelector 1.0 CustomConfigurationSelector.qml
|
||||
PrintSetupSelector 1.0 PrintSetupSelector.qml
|
||||
ProfileOverview 1.6 ProfileOverview.qml
|
||||
|
@ -564,6 +564,9 @@
|
||||
"medium_button": [2.5, 2.5],
|
||||
"medium_button_icon": [2, 2],
|
||||
|
||||
"large_button": [3.0, 3.0],
|
||||
"large_button_icon": [2.8, 2.8],
|
||||
|
||||
"context_menu": [20, 2],
|
||||
|
||||
"icon_indicator": [1, 1],
|
||||
|
Loading…
x
Reference in New Issue
Block a user