mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-05-07 14:19:01 +08:00

There were two singletons of this manager: One created by QML and managed by QML, and one created by us and managed by our own singleton pattern. That won't work! So we now manage just our own singleton type, and make it a context item for QML so it can use the manager too. Contributes to issues CURA-340 and CURA-1278.
197 lines
9.6 KiB
Python
197 lines
9.6 KiB
Python
# Copyright (c) 2016 Ultimaker B.V.
|
|
# Cura is released under the terms of the AGPLv3 or higher.
|
|
|
|
from PyQt5.QtCore import pyqtSignal, pyqtProperty, pyqtSlot, QObject #For communicating data and events to Qt.
|
|
|
|
import UM.Application #To get the global container stack to find the current machine.
|
|
import UM.Logger
|
|
import UM.Settings.ContainerRegistry #Finding containers by ID.
|
|
import re
|
|
|
|
|
|
## Manages all existing extruder stacks.
|
|
#
|
|
# This keeps a list of extruder stacks for each machine.
|
|
class ExtruderManager(QObject):
|
|
## Signal to notify other components when the list of extruders changes.
|
|
extrudersChanged = pyqtSignal()
|
|
|
|
## Notify when the user switches the currently active extruder.
|
|
activeExtruderChanged = pyqtSignal()
|
|
|
|
## Registers listeners and such to listen to changes to the extruders.
|
|
def __init__(self, parent = None):
|
|
super().__init__(parent)
|
|
self._extruder_trains = { } #Extruders for the current machine.
|
|
self._next_item = 0 #For when you use this class as iterator.
|
|
self._active_extruder_index = 0
|
|
|
|
self._repopulate()
|
|
|
|
## Creates an iterator over the extruders in this manager.
|
|
#
|
|
# \return An iterator over the extruders in this manager.
|
|
def __iter__(self):
|
|
return iter(self._extruders)
|
|
|
|
## Gets the unique identifier of the currently active extruder stack.
|
|
#
|
|
# The currently active extruder stack is the stack that is currently being
|
|
# edited.
|
|
#
|
|
# \return The unique ID of the currently active extruder stack.
|
|
@pyqtProperty(str, notify = activeExtruderChanged)
|
|
def activeExtruderStackId(self):
|
|
if not UM.Application.getInstance().getGlobalContainerStack():
|
|
return None #No active machine, so no active extruder.
|
|
try:
|
|
return self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getId()][str(self._active_extruder_index)]
|
|
except KeyError: #Extruder index could be -1 if the global tab is selected, or the entry doesn't exist if the machine definition is wrong.
|
|
return None
|
|
|
|
__instance = None
|
|
@classmethod
|
|
def getInstance(cls):
|
|
if not cls.__instance:
|
|
cls.__instance = ExtruderManager()
|
|
return cls.__instance
|
|
|
|
@pyqtSlot(int)
|
|
def setActiveExtruderIndex(self, index):
|
|
self._active_extruder_index = index
|
|
self.activeExtruderChanged.emit()
|
|
|
|
## Adds all extruders of a specific machine definition to the extruder
|
|
# manager.
|
|
#
|
|
# \param machine_definition The machine to add the extruders for.
|
|
def addMachineExtruders(self, machine_definition):
|
|
machine_id = machine_definition.getId()
|
|
if not self._extruder_trains[machine_id]:
|
|
self._extruder_trains[machine_id] = { }
|
|
|
|
container_registry = UM.Settings.ContainerRegistry.getInstance()
|
|
if not container_registry: #Then we shouldn't have any machine definition either. In any case, there are no extruder trains then so bye bye.
|
|
return
|
|
|
|
#Add the extruder trains that don't exist yet.
|
|
for position, extruder_definition_id in machine_definition.getMetaDataEntry("machine_extruder_trains", default = {}).items():
|
|
extruder_definition = container_registry.findDefinitionContainers(machine = machine_definition.getId())
|
|
if extruder_definition:
|
|
extruder_definition = extruder_definition[0]
|
|
else:
|
|
Logger.log("w", "Machine %s references an extruder with ID %s, which doesn't exist.", machine_definition.getName(), extruder_definition_id)
|
|
continue
|
|
name = self._uniqueName(extruder_definition_id) #Make a name based on the ID of the definition.
|
|
if not container_registry.findContainerStacks(id = name): #Doesn't exist yet.
|
|
self.createExtruderTrain(extruder_definition, machine_definition, name, position)
|
|
|
|
#Gets the extruder trains that we just created as well as any that still existed.
|
|
extruder_trains = container_registry.findContainerStacks(type = "extruder_train", machine = machine_definition.getId())
|
|
for extruder_train in extruder_trains:
|
|
self._extruder_trains[machine_id][extruder_train.getMetaDataEntry("position")] = extruder_train.getId()
|
|
if extruder_trains:
|
|
self.extrudersChanged.emit()
|
|
|
|
## (Re)populates the collections of extruders by machine.
|
|
def _repopulate(self):
|
|
self._extruder_trains = { }
|
|
if not UM.Application.getInstance().getGlobalContainerStack(): #No machine has been added yet.
|
|
self.extrudersChanged.emit() #Yes, we just cleared the _extruders list!
|
|
return #Then leave them empty!
|
|
|
|
extruder_trains = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(type = "extruder_train")
|
|
for extruder_train in extruder_trains:
|
|
machine_id = extruder_train.getMetaDataEntry("machine")
|
|
if not machine_id:
|
|
continue
|
|
if machine_id not in self._extruder_trains:
|
|
self._extruder_trains[machine_id] = { }
|
|
self._extruder_trains[machine_id][extruder_train.getMetaDataEntry("position")] = extruder_train.getId()
|
|
self.extrudersChanged.emit()
|
|
|
|
def createExtruderTrain(self, extruder_definition, machine_definition, extruder_train_id, position):
|
|
container_registry = UM.Settings.ContainerRegistry.getInstance()
|
|
|
|
#Create a container stack for this extruder.
|
|
container_stack = UM.Settings.ContainerStack(extruder_train_id)
|
|
container_stack.addMetaDataEntry("type", "extruder_train")
|
|
container_stack.addMetaDataEntry("machine", machine_definition.getId())
|
|
container_stack.addMetaDataEntry("position", position)
|
|
container_stack.addContainer(extruder_definition)
|
|
|
|
"""
|
|
Yes, I'm committing this code which needs to be transformed to work later.
|
|
#Find the nozzle to use for this extruder.
|
|
nozzle = container_registry.getEmptyInstanceContainer()
|
|
if definition.getMetaDataEntry("has_nozzles", default = "False") == "True":
|
|
if len(self._nozzles) >= 1: #First add any extruder. Later, overwrite with preference if the preference is valid.
|
|
self._nozzle = self._nozzles[0]
|
|
preferred_nozzle_id = definition.getMetaDataEntry("preferred_nozzle")
|
|
if preferred_nozzle_id:
|
|
for nozzle in self._nozzles:
|
|
if nozzle.getId() == preferred_nozzle_id:
|
|
self._nozzle = nozzle
|
|
break
|
|
self._container_stack.addContainer(self._nozzle)
|
|
|
|
#Find a material to use for this nozzle.
|
|
self._material = container_registry.getEmptyInstanceContainer()
|
|
if self._definition.getMetaDataEntry("has_materials", default = "False") == "True":
|
|
if self._definition.getMetaDataEntry("has_nozzle_materials", default = "False") == "True":
|
|
all_materials = container_registry.findInstanceContainers(type = "material", nozzle = self._nozzle.getId())
|
|
else:
|
|
all_materials = container_registry.findInstanceContainers(type = "material")
|
|
if len(all_materials) >= 1:
|
|
self._material = all_materials[0]
|
|
preferred_material_id = self._definition.getMetaDataEntry("preferred_material")
|
|
if preferred_material_id:
|
|
preferred_material = container_registry.findInstanceContainers(type = "material", id = preferred_material_id.lower())
|
|
if len(preferred_material) >= 1:
|
|
self._material = preferred_material[0]
|
|
self._container_stack.addContainer(self._material)
|
|
|
|
#Find a quality to use for this extruder.
|
|
self._quality = container_registry.getEmptyInstanceContainer()
|
|
if self._definition.getMetaDataEntry("has_machine_quality"):
|
|
all_qualities = container_registry.findInstanceContainers(type = "quality")
|
|
if len(all_qualities) >= 1:
|
|
self._quality = all_qualities[0]
|
|
preferred_quality_id = self._definition.getMetaDataEntry("preferred_quality")
|
|
if preferred_quality_id:
|
|
preferred_quality = container_registry.findInstanceContainers(type = "quality", id = preferred_quality_id.lower())
|
|
if len(preferred_quality) >= 1:
|
|
self._quality = preferred_quality[0]
|
|
self._container_stack.addContainer(self._quality)
|
|
"""
|
|
|
|
#Add an empty user profile.
|
|
user_profile = UM.Settings.InstanceContainer(extruder_train_id + "_current_settings")
|
|
user_profile.addMetaDataEntry("type", "user")
|
|
user_profile.setDefinition(machine_definition)
|
|
container_stack.addContainer(user_profile)
|
|
container_registry.addContainer(user_profile)
|
|
|
|
container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack())
|
|
|
|
container_registry.addContainer(container_stack)
|
|
|
|
|
|
def _uniqueName(self, original):
|
|
container_registry = UM.Settings.ContainerRegistry.getInstance()
|
|
|
|
name = original.strip()
|
|
num_check = re.compile("(.*?)\s*#\d$").match(name)
|
|
if num_check: # There is a number in the name.
|
|
name = num_check.group(1) # Filter out the number.
|
|
if name == "": # Wait, that deleted everything!
|
|
name = "Extruder"
|
|
unique_name = name
|
|
|
|
i = 1
|
|
while container_registry.findContainers(id=unique_name) or container_registry.findContainers(
|
|
name=unique_name): # A container already has this name.
|
|
i += 1 # Try next numbering.
|
|
unique_name = "%s #%d" % (name, i) # Fill name like this: "Extruder #2".
|
|
return unique_name
|