diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 14f4f5fc33..436f9814db 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -7,6 +7,8 @@ import time from typing import List, Dict, TYPE_CHECKING, Optional from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator +from UM.Settings.InstanceContainer import InstanceContainer +from UM.Settings.Interfaces import ContainerInterface from UM.Signal import Signal from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal, QTimer @@ -28,6 +30,7 @@ from cura.PrinterOutput.ConfigurationModel import ConfigurationModel from cura.PrinterOutput.ExtruderConfigurationModel import ExtruderConfigurationModel from cura.PrinterOutput.MaterialOutputModel import MaterialOutputModel from cura.Settings.ExtruderManager import ExtruderManager +from cura.Settings.ExtruderStack import ExtruderStack from .CuraStackBuilder import CuraStackBuilder @@ -38,16 +41,15 @@ if TYPE_CHECKING: from cura.Settings.CuraContainerStack import CuraContainerStack from cura.Settings.GlobalStack import GlobalStack - class MachineManager(QObject): def __init__(self, parent = None): super().__init__(parent) - self._active_container_stack = None # type: CuraContainerStack - self._global_container_stack = None # type: GlobalStack + self._active_container_stack = None # type: Optional[ExtruderManager] + self._global_container_stack = None # type: Optional[GlobalStack] - self._current_root_material_id = {} + self._current_root_material_id = {} # type: Dict[str, str] self._current_quality_group = None self._current_quality_changes_group = None @@ -62,7 +64,7 @@ class MachineManager(QObject): self._application = Application.getInstance() self._application.globalContainerStackChanged.connect(self._onGlobalContainerChanged) - self._application.getContainerRegistry().containerLoadComplete.connect(self._onInstanceContainersChanged) + self._application.getContainerRegistry().containerLoadComplete.connect(self._onContainersChanged) ## When the global container is changed, active material probably needs to be updated. self.globalContainerChanged.connect(self.activeMaterialChanged) @@ -99,7 +101,7 @@ class MachineManager(QObject): self._global_event_keys = set() - self._printer_output_devices = [] + self._printer_output_devices = [] # type: List[PrinterOutputDevice] Application.getInstance().getOutputDeviceManager().outputDevicesChanged.connect(self._onOutputDevicesChanged) # There might already be some output devices by the time the signal is connected self._onOutputDevicesChanged() @@ -160,7 +162,7 @@ class MachineManager(QObject): rootMaterialChanged = pyqtSignal() - def setInitialActiveMachine(self): + def setInitialActiveMachine(self) -> None: active_machine_id = Preferences.getInstance().getValue("cura/active_machine") if active_machine_id != "" and ContainerRegistry.getInstance().findContainerStacksMetadata(id = active_machine_id): # An active machine was saved, so restore it. @@ -177,7 +179,7 @@ class MachineManager(QObject): self.outputDevicesChanged.emit() @pyqtProperty(QObject, notify = currentConfigurationChanged) - def currentConfiguration(self): + def currentConfiguration(self) -> ConfigurationModel: return self._current_printer_configuration def _onCurrentConfigurationChanged(self) -> None: @@ -210,7 +212,7 @@ class MachineManager(QObject): return self._current_printer_configuration == configuration @pyqtProperty("QVariantList", notify = outputDevicesChanged) - def printerOutputDevices(self): + def printerOutputDevices(self) -> List[PrinterOutputDevice]: return self._printer_output_devices @pyqtProperty(int, constant=True) @@ -224,7 +226,7 @@ class MachineManager(QObject): except TypeError: # pyQtSignal gives a TypeError when disconnecting from something that was already disconnected. pass try: - self._global_container_stack.containersChanged.disconnect(self._onInstanceContainersChanged) + self._global_container_stack.containersChanged.disconnect(self._onContainersChanged) except TypeError: pass try: @@ -234,7 +236,7 @@ class MachineManager(QObject): for extruder_stack in ExtruderManager.getInstance().getActiveExtruderStacks(): extruder_stack.propertyChanged.disconnect(self._onPropertyChanged) - extruder_stack.containersChanged.disconnect(self._onInstanceContainersChanged) + extruder_stack.containersChanged.disconnect(self._onContainersChanged) # Update the local global container stack reference self._global_container_stack = Application.getInstance().getGlobalContainerStack() @@ -248,7 +250,7 @@ class MachineManager(QObject): Preferences.getInstance().setValue("cura/active_machine", self._global_container_stack.getId()) self._global_container_stack.nameChanged.connect(self._onMachineNameChanged) - self._global_container_stack.containersChanged.connect(self._onInstanceContainersChanged) + self._global_container_stack.containersChanged.connect(self._onContainersChanged) self._global_container_stack.propertyChanged.connect(self._onPropertyChanged) # Global stack can have only a variant if it is a buildplate @@ -265,7 +267,7 @@ class MachineManager(QObject): # Listen for changes on all extruder stacks for extruder_stack in ExtruderManager.getInstance().getActiveExtruderStacks(): extruder_stack.propertyChanged.connect(self._onPropertyChanged) - extruder_stack.containersChanged.connect(self._onInstanceContainersChanged) + extruder_stack.containersChanged.connect(self._onContainersChanged) if self._global_container_stack.getId() in self.machine_extruder_material_update_dict: for func in self.machine_extruder_material_update_dict[self._global_container_stack.getId()]: @@ -292,7 +294,7 @@ class MachineManager(QObject): self.rootMaterialChanged.emit() - def _onInstanceContainersChanged(self, container) -> None: + def _onContainersChanged(self, container: ContainerInterface) -> None: self._instance_container_timer.start() def _onPropertyChanged(self, key: str, property_name: str) -> None: @@ -301,7 +303,7 @@ class MachineManager(QObject): self.activeStackValueChanged.emit() ## Given a global_stack, make sure that it's all valid by searching for this quality group and applying it again - def _initMachineState(self, global_stack): + def _initMachineState(self, global_stack: "CuraContainerStack") -> None: material_dict = {} for position, extruder in global_stack.extruders.items(): material_dict[position] = extruder.material.getMetaDataEntry("base_file") @@ -620,7 +622,7 @@ class MachineManager(QObject): ## Copy the value of the setting of the current extruder to all other extruders as well as the global container. @pyqtSlot(str) - def copyValueToExtruders(self, key: str): + def copyValueToExtruders(self, key: str) -> None: new_value = self._active_container_stack.getProperty(key, "value") extruder_stacks = [stack for stack in ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId())] @@ -631,7 +633,7 @@ class MachineManager(QObject): ## Copy the value of all manually changed settings of the current extruder to all other extruders. @pyqtSlot() - def copyAllValuesToExtruders(self): + def copyAllValuesToExtruders(self) -> None: extruder_stacks = list(self._global_container_stack.extruders.values()) for extruder_stack in extruder_stacks: if extruder_stack != self._active_container_stack: @@ -685,7 +687,7 @@ class MachineManager(QObject): return fallback_title @pyqtSlot(str, str) - def renameMachine(self, machine_id: str, new_name: str): + def renameMachine(self, machine_id: str, new_name: str) -> None: container_registry = ContainerRegistry.getInstance() machine_stack = container_registry.findContainerStacks(id = machine_id) if machine_stack: @@ -694,7 +696,7 @@ class MachineManager(QObject): self.globalContainerChanged.emit() @pyqtSlot(str) - def removeMachine(self, machine_id: str): + def removeMachine(self, machine_id: str) -> None: # If the machine that is being removed is the currently active machine, set another machine as the active machine. activate_new_machine = (self._global_container_stack and self._global_container_stack.getId() == machine_id) @@ -791,9 +793,9 @@ class MachineManager(QObject): if containers: return containers[0].definition.getId() - def getIncompatibleSettingsOnEnabledExtruders(self, container): + def getIncompatibleSettingsOnEnabledExtruders(self, container: InstanceContainer) -> List[str]: extruder_count = self._global_container_stack.getProperty("machine_extruder_count", "value") - result = [] + result = [] # type: List[str] for setting_instance in container.findInstances(): setting_key = setting_instance.definition.key setting_enabled = self._global_container_stack.getProperty(setting_key, "enabled") @@ -815,7 +817,7 @@ class MachineManager(QObject): return result ## Update extruder number to a valid value when the number of extruders are changed, or when an extruder is changed - def correctExtruderSettings(self): + def correctExtruderSettings(self) -> None: for setting_key in self.getIncompatibleSettingsOnEnabledExtruders(self._global_container_stack.userChanges): self._global_container_stack.userChanges.removeInstance(setting_key) add_user_changes = self.getIncompatibleSettingsOnEnabledExtruders(self._global_container_stack.qualityChanges) @@ -832,7 +834,7 @@ class MachineManager(QObject): ## Set the amount of extruders on the active machine (global stack) # \param extruder_count int the number of extruders to set - def setActiveMachineExtruderCount(self, extruder_count): + def setActiveMachineExtruderCount(self, extruder_count: int) -> None: extruder_manager = Application.getInstance().getExtruderManager() definition_changes_container = self._global_container_stack.definitionChanges @@ -887,13 +889,13 @@ class MachineManager(QObject): self.forceUpdateAllSettings() @pyqtSlot(int, result = QObject) - def getExtruder(self, position: int): + def getExtruder(self, position: int) -> Optional[ExtruderStack]: extruder = None if self._global_container_stack: extruder = self._global_container_stack.extruders.get(str(position)) return extruder - def updateDefaultExtruder(self): + def updateDefaultExtruder(self) -> None: extruder_items = sorted(self._global_container_stack.extruders.items()) old_position = self._default_extruder_position new_default_position = "0" @@ -905,7 +907,7 @@ class MachineManager(QObject): self._default_extruder_position = new_default_position self.extruderChanged.emit() - def updateNumberExtrudersEnabled(self): + def updateNumberExtrudersEnabled(self) -> None: definition_changes_container = self._global_container_stack.definitionChanges machine_extruder_count = self._global_container_stack.getProperty("machine_extruder_count", "value") extruder_count = 0 @@ -917,16 +919,16 @@ class MachineManager(QObject): self.numberExtrudersEnabledChanged.emit() @pyqtProperty(int, notify = numberExtrudersEnabledChanged) - def numberExtrudersEnabled(self): + def numberExtrudersEnabled(self) -> int: return self._global_container_stack.definitionChanges.getProperty("extruders_enabled_count", "value") @pyqtProperty(str, notify = extruderChanged) - def defaultExtruderPosition(self): + def defaultExtruderPosition(self) -> str: return self._default_extruder_position ## This will fire the propertiesChanged for all settings so they will be updated in the front-end @pyqtSlot() - def forceUpdateAllSettings(self): + def forceUpdateAllSettings(self) -> None: with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): property_names = ["value", "resolve", "validationState"] for container in [self._global_container_stack] + list(self._global_container_stack.extruders.values()): @@ -934,8 +936,11 @@ class MachineManager(QObject): container.propertiesChanged.emit(setting_key, property_names) @pyqtSlot(int, bool) - def setExtruderEnabled(self, position: int, enabled) -> None: + def setExtruderEnabled(self, position: int, enabled: bool) -> None: extruder = self.getExtruder(position) + if not extruder: + Logger.log("w", "Could not find extruder on position %s", position) + extruder.setEnabled(enabled) self.updateDefaultExtruder() self.updateNumberExtrudersEnabled() @@ -952,13 +957,13 @@ class MachineManager(QObject): # Also trigger the build plate compatibility to update self.activeMaterialChanged.emit() - def _onMachineNameChanged(self): + def _onMachineNameChanged(self) -> None: self.globalContainerChanged.emit() - def _onMaterialNameChanged(self): + def _onMaterialNameChanged(self) -> None: self.activeMaterialChanged.emit() - def _onQualityNameChanged(self): + def _onQualityNameChanged(self) -> None: self.activeQualityChanged.emit() def _getContainerChangedSignals(self) -> List[Signal]: @@ -969,19 +974,19 @@ class MachineManager(QObject): return [ s.containersChanged for s in stacks ] @pyqtSlot(str, str, str) - def setSettingForAllExtruders(self, setting_name: str, property_name: str, property_value: str): + def setSettingForAllExtruders(self, setting_name: str, property_name: str, property_value: str) -> None: for key, extruder in self._global_container_stack.extruders.items(): container = extruder.userChanges container.setProperty(setting_name, property_name, property_value) @pyqtProperty("QVariantList", notify = globalContainerChanged) - def currentExtruderPositions(self): + def currentExtruderPositions(self) -> List[str]: if self._global_container_stack is None: return [] return sorted(list(self._global_container_stack.extruders.keys())) ## Update _current_root_material_id when the current root material was changed. - def _onRootMaterialChanged(self): + def _onRootMaterialChanged(self) -> None: self._current_root_material_id = {} if self._global_container_stack: @@ -989,13 +994,13 @@ class MachineManager(QObject): self._current_root_material_id[position] = self._global_container_stack.extruders[position].material.getMetaDataEntry("base_file") @pyqtProperty("QVariant", notify = rootMaterialChanged) - def currentRootMaterialId(self): + def currentRootMaterialId(self) -> Dict[str, str]: return self._current_root_material_id ## Return the variant names in the extruder stack(s). ## For the variant in the global stack, use activeVariantBuildplateName @pyqtProperty("QVariant", notify = activeVariantChanged) - def activeVariantNames(self): + def activeVariantNames(self) -> Dict[str, str]: result = {} active_stacks = ExtruderManager.getInstance().getActiveExtruderStacks() @@ -1011,7 +1016,7 @@ class MachineManager(QObject): # Sets all quality and quality_changes containers to empty_quality and empty_quality_changes containers # for all stacks in the currently active machine. # - def _setEmptyQuality(self): + def _setEmptyQuality(self) -> None: self._current_quality_group = None self._current_quality_changes_group = None self._global_container_stack.quality = self._empty_quality_container @@ -1023,7 +1028,7 @@ class MachineManager(QObject): self.activeQualityGroupChanged.emit() self.activeQualityChangesGroupChanged.emit() - def _setQualityGroup(self, quality_group, empty_quality_changes = True): + def _setQualityGroup(self, quality_group, empty_quality_changes: bool = True) -> None: if quality_group.node_for_global.getContainer() is None: return for node in quality_group.nodes_for_extruders.values(): @@ -1219,7 +1224,7 @@ class MachineManager(QObject): ## Given a printer definition name, select the right machine instance. In case it doesn't exist, create a new # instance with the same network key. @pyqtSlot(str) - def switchPrinterType(self, machine_name): + def switchPrinterType(self, machine_name: str): # Don't switch if the user tries to change to the same type of printer if self.activeMachineDefinitionName == machine_name: return @@ -1243,7 +1248,7 @@ class MachineManager(QObject): self.setActiveMachine(new_machine.getId()) @pyqtSlot(QObject) - def applyRemoteConfiguration(self, configuration: ConfigurationModel): + def applyRemoteConfiguration(self, configuration: ConfigurationModel) -> None: self.blurSettings.emit() with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): self.switchPrinterType(configuration.printerType) @@ -1273,7 +1278,7 @@ class MachineManager(QObject): self._updateQualityWithMaterial() ## Find all container stacks that has the pair 'key = value' in its metadata and replaces the value with 'new_value' - def replaceContainersMetadata(self, key: str, value: str, new_value: str): + def replaceContainersMetadata(self, key: str, value: str, new_value: str) -> None: machines = ContainerRegistry.getInstance().findContainerStacks(type = "machine") for machine in machines: if machine.getMetaDataEntry(key) == value: @@ -1282,7 +1287,7 @@ class MachineManager(QObject): ## This method checks if the name of the group stored in the definition container is correct. # After updating from 3.2 to 3.3 some group names may be temporary. If there is a mismatch in the name of the group # then all the container stacks are updated, both the current and the hidden ones. - def checkCorrectGroupName(self, device_id: str, group_name: str): + def checkCorrectGroupName(self, device_id: str, group_name: str) -> None: if self._global_container_stack and device_id == self.activeMachineNetworkKey: # Check if the connect_group_name is correct. If not, update all the containers connected to the same printer if self.activeMachineNetworkGroupName != group_name: @@ -1316,7 +1321,7 @@ class MachineManager(QObject): self.setMaterial(position, material_node) @pyqtSlot(str, "QVariant") - def setMaterial(self, position, container_node): + def setMaterial(self, position: str, container_node) -> None: position = str(position) self.blurSettings.emit() with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): @@ -1324,13 +1329,13 @@ class MachineManager(QObject): self._updateQualityWithMaterial() @pyqtSlot(str, str) - def setVariantByName(self, position, variant_name): + def setVariantByName(self, position: str, variant_name: str) -> None: machine_definition_id = self._global_container_stack.definition.id variant_node = self._variant_manager.getVariantNode(machine_definition_id, variant_name) self.setVariant(position, variant_node) @pyqtSlot(str, "QVariant") - def setVariant(self, position, container_node): + def setVariant(self, position: str, container_node): position = str(position) self.blurSettings.emit() with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): @@ -1339,7 +1344,7 @@ class MachineManager(QObject): self._updateQualityWithMaterial() @pyqtSlot(str) - def setQualityGroupByQualityType(self, quality_type): + def setQualityGroupByQualityType(self, quality_type: str) -> None: if self._global_container_stack is None: return # Get all the quality groups for this global stack and filter out by quality_type @@ -1391,7 +1396,7 @@ class MachineManager(QObject): name = self._current_quality_group.name return name - def _updateUponMaterialMetadataChange(self): + def _updateUponMaterialMetadataChange(self) -> None: if self._global_container_stack is None: return with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue):