Cura/cura/PrinterOutput/Models/PrinterConfigurationModel.py
Remco Burema 767b1f6c19 Early-out when printer-type hasn't any printers.
This would otherwise search in, and process the result of, _all_ variants, since the 'id' would be empty.
This could actually happen w.r.t. searching dealing with abstract printers, which could slow down the process enough that the entire UI becomes very stuttery for users. (But mostly only for the old Makerbot Method-series printers ... somehow.)

1st (and hopefully last) attempt at fixing CURA-12835 (and if we're lucky, some other seemingly related issues).
2026-01-21 13:55:56 +01:00

131 lines
5.3 KiB
Python

# Copyright (c) 2025 UltiMaker
# Cura is released under the terms of the LGPLv3 or higher.
from PyQt6.QtCore import pyqtProperty, QObject, pyqtSignal
from typing import List
from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Settings.DefinitionContainer import DefinitionContainer
MYPY = False
if MYPY:
from cura.PrinterOutput.Models.ExtruderConfigurationModel import ExtruderConfigurationModel
class PrinterConfigurationModel(QObject):
configurationChanged = pyqtSignal()
def __init__(self) -> None:
super().__init__()
self._printer_type = ""
self._extruder_configurations = [] # type: List[ExtruderConfigurationModel]
self._buildplate_configuration = ""
def setPrinterType(self, printer_type: str) -> None:
self._printer_type = printer_type
@pyqtProperty(str, fset = setPrinterType, notify = configurationChanged)
def printerType(self) -> str:
return self._printer_type
def setExtruderConfigurations(self, extruder_configurations: List["ExtruderConfigurationModel"]) -> None:
if self._extruder_configurations != extruder_configurations:
self._extruder_configurations = extruder_configurations
for extruder_configuration in self._extruder_configurations:
extruder_configuration.extruderConfigurationChanged.connect(self.configurationChanged)
self.configurationChanged.emit()
@pyqtProperty("QVariantList", fset = setExtruderConfigurations, notify = configurationChanged)
def extruderConfigurations(self):
return self._extruder_configurations
def setBuildplateConfiguration(self, buildplate_configuration: str) -> None:
if self._buildplate_configuration != buildplate_configuration:
self._buildplate_configuration = buildplate_configuration
self.configurationChanged.emit()
@pyqtProperty(str, fset = setBuildplateConfiguration, notify = configurationChanged)
def buildplateConfiguration(self) -> str:
return self._buildplate_configuration
def isValid(self) -> bool:
"""This method is intended to indicate whether the configuration is valid or not.
The method checks if the mandatory fields are or not set
"""
if not self._extruder_configurations:
return False
for configuration in self._extruder_configurations:
if configuration is None:
return False
return self._printer_type != ""
def hasAnyMaterialLoaded(self) -> bool:
if not self.isValid():
return False
for configuration in self._extruder_configurations:
if configuration.activeMaterial and configuration.activeMaterial.type != "empty":
return True
return False
@pyqtProperty("QStringList", constant=True)
def validCoresForPrinterType(self) -> List[str]:
printers = ContainerRegistry.getInstance().findContainersMetadata(
ignore_case=True, type="machine", name=self._printer_type, container_type=DefinitionContainer)
id = printers[0]["id"] if len(printers) > 0 and "id" in printers[0] else ""
if id == "":
return []
definitions = ContainerRegistry.getInstance().findContainersMetadata(
ignore_case=True, type="variant", definition=id+"*")
return [x["name"] for x in definitions]
def __str__(self):
message_chunks = []
message_chunks.append("Printer type: " + self._printer_type)
message_chunks.append("Extruders: [")
for configuration in self._extruder_configurations:
message_chunks.append(" " + str(configuration))
message_chunks.append("]")
if self._buildplate_configuration is not None:
message_chunks.append("Buildplate: " + self._buildplate_configuration)
return "\n".join(message_chunks)
def __eq__(self, other):
if not isinstance(other, PrinterConfigurationModel):
return False
if self.printerType != other.printerType:
return False
if self.buildplateConfiguration != other.buildplateConfiguration:
return False
if len(self.extruderConfigurations) != len(other.extruderConfigurations):
return False
for self_extruder, other_extruder in zip(sorted(self._extruder_configurations, key=lambda x: x.position), sorted(other.extruderConfigurations, key=lambda x: x.position)):
if self_extruder != other_extruder:
return False
return True
def __hash__(self):
"""The hash function is used to compare and create unique sets. The configuration is unique if the configuration
of the extruders is unique (the order of the extruders matters), and the type and buildplate is the same.
"""
extruder_hash = hash(0)
first_extruder = None
for configuration in self._extruder_configurations:
extruder_hash ^= hash(configuration)
if configuration.position == 0:
first_extruder = configuration
# To ensure the correct order of the extruders, we add an "and" operation using the first extruder hash value
if first_extruder:
extruder_hash &= hash(first_extruder)
return hash(self._printer_type) ^ extruder_hash ^ hash(self._buildplate_configuration)