1# Copyright (c) 2018 Ultimaker B.V. 2# Cura is released under the terms of the LGPLv3 or higher. 3 4from PyQt5.QtCore import pyqtProperty, QObject, pyqtSignal 5from typing import List 6 7MYPY = False 8if MYPY: 9 from cura.PrinterOutput.Models.ExtruderConfigurationModel import ExtruderConfigurationModel 10 11 12class PrinterConfigurationModel(QObject): 13 14 configurationChanged = pyqtSignal() 15 16 def __init__(self) -> None: 17 super().__init__() 18 self._printer_type = "" 19 self._extruder_configurations = [] # type: List[ExtruderConfigurationModel] 20 self._buildplate_configuration = "" 21 22 def setPrinterType(self, printer_type: str) -> None: 23 self._printer_type = printer_type 24 25 @pyqtProperty(str, fset = setPrinterType, notify = configurationChanged) 26 def printerType(self) -> str: 27 return self._printer_type 28 29 def setExtruderConfigurations(self, extruder_configurations: List["ExtruderConfigurationModel"]) -> None: 30 if self._extruder_configurations != extruder_configurations: 31 self._extruder_configurations = extruder_configurations 32 33 for extruder_configuration in self._extruder_configurations: 34 extruder_configuration.extruderConfigurationChanged.connect(self.configurationChanged) 35 36 self.configurationChanged.emit() 37 38 @pyqtProperty("QVariantList", fset = setExtruderConfigurations, notify = configurationChanged) 39 def extruderConfigurations(self): 40 return self._extruder_configurations 41 42 def setBuildplateConfiguration(self, buildplate_configuration: str) -> None: 43 if self._buildplate_configuration != buildplate_configuration: 44 self._buildplate_configuration = buildplate_configuration 45 self.configurationChanged.emit() 46 47 @pyqtProperty(str, fset = setBuildplateConfiguration, notify = configurationChanged) 48 def buildplateConfiguration(self) -> str: 49 return self._buildplate_configuration 50 51 def isValid(self) -> bool: 52 """This method is intended to indicate whether the configuration is valid or not. 53 54 The method checks if the mandatory fields are or not set 55 """ 56 if not self._extruder_configurations: 57 return False 58 for configuration in self._extruder_configurations: 59 if configuration is None: 60 return False 61 return self._printer_type != "" 62 63 def hasAnyMaterialLoaded(self) -> bool: 64 if not self.isValid(): 65 return False 66 for configuration in self._extruder_configurations: 67 if configuration.activeMaterial and configuration.activeMaterial.type != "empty": 68 return True 69 return False 70 71 def __str__(self): 72 message_chunks = [] 73 message_chunks.append("Printer type: " + self._printer_type) 74 message_chunks.append("Extruders: [") 75 for configuration in self._extruder_configurations: 76 message_chunks.append(" " + str(configuration)) 77 message_chunks.append("]") 78 if self._buildplate_configuration is not None: 79 message_chunks.append("Buildplate: " + self._buildplate_configuration) 80 81 return "\n".join(message_chunks) 82 83 def __eq__(self, other): 84 if not isinstance(other, PrinterConfigurationModel): 85 return False 86 87 if self.printerType != other.printerType: 88 return False 89 90 if self.buildplateConfiguration != other.buildplateConfiguration: 91 return False 92 93 if len(self.extruderConfigurations) != len(other.extruderConfigurations): 94 return False 95 96 for self_extruder, other_extruder in zip(sorted(self._extruder_configurations, key=lambda x: x.position), sorted(other.extruderConfigurations, key=lambda x: x.position)): 97 if self_extruder != other_extruder: 98 return False 99 100 return True 101 102 def __hash__(self): 103 """The hash function is used to compare and create unique sets. The configuration is unique if the configuration 104 105 of the extruders is unique (the order of the extruders matters), and the type and buildplate is the same. 106 """ 107 extruder_hash = hash(0) 108 first_extruder = None 109 for configuration in self._extruder_configurations: 110 extruder_hash ^= hash(configuration) 111 if configuration.position == 0: 112 first_extruder = configuration 113 # To ensure the correct order of the extruders, we add an "and" operation using the first extruder hash value 114 if first_extruder: 115 extruder_hash &= hash(first_extruder) 116 117 return hash(self._printer_type) ^ extruder_hash ^ hash(self._buildplate_configuration) 118