# Copyright (c) 2016 Ultimaker B.V. # Cura is released under the terms of the AGPLv3 or higher. from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot from cura.MachineAction import MachineAction import cura.Settings.CuraContainerRegistry import UM.Application import UM.Settings.InstanceContainer import UM.Settings.DefinitionContainer import UM.Logger import UM.i18n catalog = UM.i18n.i18nCatalog("cura") class MachineSettingsAction(MachineAction): def __init__(self, parent = None): super().__init__("MachineSettingsAction", catalog.i18nc("@action", "Machine Settings")) self._qml_url = "MachineSettingsAction.qml" self._container_index = 0 self._container_registry = UM.Settings.ContainerRegistry.getInstance() self._container_registry.containerAdded.connect(self._onContainerAdded) def _reset(self): global_container_stack = UM.Application.getInstance().getGlobalContainerStack() if not global_container_stack: return # First check if there is a variant previously generated by this machine machine_settings_variant = global_container_stack.findContainer({"type": "variant", "subtype": "machine_settings"}) if not machine_settings_variant: variant = global_container_stack.findContainer({"type": "variant"}) if variant: if variant.getId() == global_container_stack.getName() + "_variant": # There is a variant created by the UMOUpgradeSelection machine action machine_settings_variant = variant if variant.getId() == "empty_variant": # There is an empty variant that we can replace to store the machine settings container_index = global_container_stack.getContainerIndex(variant) machine_settings_variant = self._createMachineSettingsVariant(global_container_stack, container_index) if not machine_settings_variant: # Add a new variant to store the machine settings machine_settings_variant = self._createMachineSettingsVariant(global_container_stack) # Notify the UI in which container to store the machine settings data container_index = global_container_stack.getContainerIndex(machine_settings_variant) if container_index != self._container_index: self._container_index = container_index self.containerIndexChanged.emit() def _createMachineSettingsVariant(self, global_container_stack, container_index = None): machine_settings_variant = UM.Settings.InstanceContainer(global_container_stack.getName() + "_variant") if global_container_stack.getMetaDataEntry("has_variants", False): # If the current machine uses visible variants (eg for nozzle selection), make sure # not to add this variant to the list. definition = self._container_registry.findDefinitionContainers(id="fdmprinter")[0] else: definition = global_container_stack.getBottom() machine_settings_variant.setDefinition(definition) machine_settings_variant.addMetaDataEntry("type", "variant") machine_settings_variant.addMetaDataEntry("subtype", "machine_settings") self._container_registry.addContainer(machine_settings_variant) if container_index: global_container_stack.replaceContainer(container_index, machine_settings_variant) else: global_container_stack.insertContainer(-1, machine_settings_variant) return machine_settings_variant containerIndexChanged = pyqtSignal() @pyqtProperty(int, notify = containerIndexChanged) def containerIndex(self): return self._container_index def _onContainerAdded(self, container): # Add this action as a supported action to all machine definitions if isinstance(container, UM.Settings.DefinitionContainer) and container.getMetaDataEntry("type") == "machine": if container.getProperty("machine_extruder_count", "value") > 1: # Multiextruder printers are not currently supported UM.Logger.log("d", "Not attaching MachineSettingsAction to %s; Multi-extrusion printers are not supported", container.getId()) return UM.Application.getInstance().getMachineActionManager().addSupportedAction(container.getId(), self.getKey()) @pyqtSlot() def forceUpdate(self): # Force rebuilding the build volume by reloading the global container stack. # This is a bit of a hack, but it seems quick enough. UM.Application.getInstance().globalContainerStackChanged.emit() @pyqtSlot() def updateHasMaterialsMetadata(self): # Updates the has_materials metadata flag after switching gcode flavor global_container_stack = UM.Application.getInstance().getGlobalContainerStack() if global_container_stack: definition = global_container_stack.getBottom() if definition.getProperty("machine_gcode_flavor", "value") == "UltiGCode" and not definition.getMetaDataEntry("has_materials", False): has_materials = global_container_stack.getProperty("machine_gcode_flavor", "value") != "UltiGCode" material_container = global_container_stack.findContainer({"type": "material"}) material_index = global_container_stack.getContainerIndex(material_container) if has_materials: if "has_materials" in global_container_stack.getMetaData(): global_container_stack.setMetaDataEntry("has_materials", True) else: global_container_stack.addMetaDataEntry("has_materials", True) # Set the material container to a sane default if material_container.getId() == "empty_material": search_criteria = { "type": "material", "definition": "fdmprinter", "id": "*pla*" } containers = self._container_registry.findInstanceContainers(**search_criteria) if containers: global_container_stack.replaceContainer(material_index, containers[0]) else: # The metadata entry is stored in an ini, and ini files are parsed as strings only. # Because any non-empty string evaluates to a boolean True, we have to remove the entry to make it False. if "has_materials" in global_container_stack.getMetaData(): global_container_stack.removeMetaDataEntry("has_materials") empty_material = self._container_registry.findInstanceContainers(id = "empty_material")[0] global_container_stack.replaceContainer(material_index, empty_material) UM.Application.getInstance().globalContainerStackChanged.emit()