mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-19 04:37:51 -06:00
Document CuraContainerStack
This commit is contained in:
parent
f1b5098a0a
commit
8682eb1486
1 changed files with 127 additions and 1 deletions
|
@ -16,6 +16,24 @@ from UM.Settings.Interfaces import ContainerInterface
|
||||||
|
|
||||||
from . import Exceptions
|
from . import Exceptions
|
||||||
|
|
||||||
|
## Base class for Cura related stacks that want to enforce certain containers are available.
|
||||||
|
#
|
||||||
|
# This class makes sure that the stack has the following containers set: user changes, quality
|
||||||
|
# changes, quality, material, variant, definition changes and finally definition. Initially,
|
||||||
|
# these will be equal to the empty instance container.
|
||||||
|
#
|
||||||
|
# The container types are determined based on the following criteria:
|
||||||
|
# - user: An InstanceContainer with the metadata entry "type" set to "user".
|
||||||
|
# - quality changes: An InstanceContainer with the metadata entry "type" set to "quality_changes".
|
||||||
|
# - quality: An InstanceContainer with the metadata entry "type" set to "quality".
|
||||||
|
# - material: An InstanceContainer with the metadata entry "type" set to "material".
|
||||||
|
# - variant: An InstanceContainer with the metadata entry "type" set to "variant".
|
||||||
|
# - definition changes: An InstanceContainer with the metadata entry "type" set to "definition_changes".
|
||||||
|
# - definition: A DefinitionContainer.
|
||||||
|
#
|
||||||
|
# Internally, this class ensures the mentioned containers are always there and kept in a specific order.
|
||||||
|
# This also means that operations on the stack that modifies the container ordering is prohibited and
|
||||||
|
# will raise an exception.
|
||||||
class CuraContainerStack(ContainerStack):
|
class CuraContainerStack(ContainerStack):
|
||||||
def __init__(self, container_id: str, *args, **kwargs):
|
def __init__(self, container_id: str, *args, **kwargs):
|
||||||
super().__init__(container_id, *args, **kwargs)
|
super().__init__(container_id, *args, **kwargs)
|
||||||
|
@ -26,18 +44,35 @@ class CuraContainerStack(ContainerStack):
|
||||||
|
|
||||||
self.containersChanged.connect(self._onContainersChanged)
|
self.containersChanged.connect(self._onContainersChanged)
|
||||||
|
|
||||||
|
# This is emitted whenever the containersChanged signal from the ContainerStack base class is emitted.
|
||||||
pyqtContainersChanged = pyqtSignal()
|
pyqtContainersChanged = pyqtSignal()
|
||||||
|
|
||||||
|
## Set the user changes container.
|
||||||
|
#
|
||||||
|
# \param new_user_changes The new user changes container. It is expected to have a "type" metadata entry with the value "user".
|
||||||
def setUserChanges(self, new_user_changes: InstanceContainer) -> None:
|
def setUserChanges(self, new_user_changes: InstanceContainer) -> None:
|
||||||
self.replaceContainer(_ContainerIndexes.UserChanges, new_user_changes)
|
self.replaceContainer(_ContainerIndexes.UserChanges, new_user_changes)
|
||||||
|
|
||||||
|
## Get the user changes container.
|
||||||
|
#
|
||||||
|
# \return The user changes container. Should always be a valid container, but can be equal to the empty InstanceContainer.
|
||||||
@pyqtProperty(InstanceContainer, fset = setUserChanges, notify = pyqtContainersChanged)
|
@pyqtProperty(InstanceContainer, fset = setUserChanges, notify = pyqtContainersChanged)
|
||||||
def userChanges(self) -> InstanceContainer:
|
def userChanges(self) -> InstanceContainer:
|
||||||
return self._containers[_ContainerIndexes.UserChanges]
|
return self._containers[_ContainerIndexes.UserChanges]
|
||||||
|
|
||||||
|
## Set the quality changes container.
|
||||||
|
#
|
||||||
|
# \param new_quality_changes The new quality changes container. It is expected to have a "type" metadata entry with the value "quality_changes".
|
||||||
def setQualityChanges(self, new_quality_changes: InstanceContainer) -> None:
|
def setQualityChanges(self, new_quality_changes: InstanceContainer) -> None:
|
||||||
self.replaceContainer(_ContainerIndexes.QualityChanges, new_quality_changes)
|
self.replaceContainer(_ContainerIndexes.QualityChanges, new_quality_changes)
|
||||||
|
|
||||||
|
## Set the quality changes container by an ID.
|
||||||
|
#
|
||||||
|
# This will search for the specified container and set it. If no container was found, an error will be raised.
|
||||||
|
#
|
||||||
|
# \param new_quality_changes_id The ID of the new quality changes container.
|
||||||
|
#
|
||||||
|
# \throws Exceptions.InvalidContainerError Raised when no container could be found with the specified ID.
|
||||||
def setQualityChangesById(self, new_quality_changes_id: str) -> None:
|
def setQualityChangesById(self, new_quality_changes_id: str) -> None:
|
||||||
quality_changes = ContainerRegistry.getInstance().findInstanceContainers(id = new_quality_changes_id)
|
quality_changes = ContainerRegistry.getInstance().findInstanceContainers(id = new_quality_changes_id)
|
||||||
if quality_changes:
|
if quality_changes:
|
||||||
|
@ -45,13 +80,24 @@ class CuraContainerStack(ContainerStack):
|
||||||
else:
|
else:
|
||||||
raise Exceptions.InvalidContainerError("Could not find container with id {id}".format(id = new_quality_changes_id))
|
raise Exceptions.InvalidContainerError("Could not find container with id {id}".format(id = new_quality_changes_id))
|
||||||
|
|
||||||
|
## Get the quality changes container.
|
||||||
|
#
|
||||||
|
# \return The quality changes container. Should always be a valid container, but can be equal to the empty InstanceContainer.
|
||||||
@pyqtProperty(InstanceContainer, fset = setQualityChanges, notify = pyqtContainersChanged)
|
@pyqtProperty(InstanceContainer, fset = setQualityChanges, notify = pyqtContainersChanged)
|
||||||
def qualityChanges(self) -> InstanceContainer:
|
def qualityChanges(self) -> InstanceContainer:
|
||||||
return self._containers[_ContainerIndexes.QualityChanges]
|
return self._containers[_ContainerIndexes.QualityChanges]
|
||||||
|
|
||||||
|
## Set the quality container.
|
||||||
|
#
|
||||||
|
# \param new_quality The new quality container. It is expected to have a "type" metadata entry with the value "quality".
|
||||||
def setQuality(self, new_quality: InstanceContainer) -> None:
|
def setQuality(self, new_quality: InstanceContainer) -> None:
|
||||||
self.replaceContainer(_ContainerIndexes.Quality, new_quality)
|
self.replaceContainer(_ContainerIndexes.Quality, new_quality)
|
||||||
|
|
||||||
|
## Set the quality container by an ID.
|
||||||
|
#
|
||||||
|
# \param new_quality_id The ID of the new quality container.
|
||||||
|
#
|
||||||
|
# \throws Exceptions.InvalidContainerError Raised when no container could be found with the specified ID.
|
||||||
def setQualityById(self, new_quality_id: str) -> None:
|
def setQualityById(self, new_quality_id: str) -> None:
|
||||||
quality = ContainerRegistry.getInstance().findInstanceContainers(id = new_quality_id)
|
quality = ContainerRegistry.getInstance().findInstanceContainers(id = new_quality_id)
|
||||||
if quality:
|
if quality:
|
||||||
|
@ -59,13 +105,24 @@ class CuraContainerStack(ContainerStack):
|
||||||
else:
|
else:
|
||||||
raise Exceptions.InvalidContainerError("Could not find container with id {id}".format(id = new_quality_id))
|
raise Exceptions.InvalidContainerError("Could not find container with id {id}".format(id = new_quality_id))
|
||||||
|
|
||||||
|
## Get the quality container.
|
||||||
|
#
|
||||||
|
# \return The quality container. Should always be a valid container, but can be equal to the empty InstanceContainer.
|
||||||
@pyqtProperty(InstanceContainer, fset = setQuality, notify = pyqtContainersChanged)
|
@pyqtProperty(InstanceContainer, fset = setQuality, notify = pyqtContainersChanged)
|
||||||
def quality(self) -> InstanceContainer:
|
def quality(self) -> InstanceContainer:
|
||||||
return self._containers[_ContainerIndexes.Quality]
|
return self._containers[_ContainerIndexes.Quality]
|
||||||
|
|
||||||
|
## Set the material container.
|
||||||
|
#
|
||||||
|
# \param new_quality_changes The new material container. It is expected to have a "type" metadata entry with the value "quality_changes".
|
||||||
def setMaterial(self, new_material: InstanceContainer) -> None:
|
def setMaterial(self, new_material: InstanceContainer) -> None:
|
||||||
self.replaceContainer(_ContainerIndexes.Material, new_material)
|
self.replaceContainer(_ContainerIndexes.Material, new_material)
|
||||||
|
|
||||||
|
## Set the material container by an ID.
|
||||||
|
#
|
||||||
|
# \param new_quality_changes_id The ID of the new material container.
|
||||||
|
#
|
||||||
|
# \throws Exceptions.InvalidContainerError Raised when no container could be found with the specified ID.
|
||||||
def setMaterialById(self, new_material_id: str) -> None:
|
def setMaterialById(self, new_material_id: str) -> None:
|
||||||
material = ContainerRegistry.getInstance().findInstanceContainers(id = new_material_id)
|
material = ContainerRegistry.getInstance().findInstanceContainers(id = new_material_id)
|
||||||
if material:
|
if material:
|
||||||
|
@ -73,13 +130,24 @@ class CuraContainerStack(ContainerStack):
|
||||||
else:
|
else:
|
||||||
raise Exceptions.InvalidContainerError("Could not find container with id {id}".format(id = new_material_id))
|
raise Exceptions.InvalidContainerError("Could not find container with id {id}".format(id = new_material_id))
|
||||||
|
|
||||||
|
## Get the material container.
|
||||||
|
#
|
||||||
|
# \return The material container. Should always be a valid container, but can be equal to the empty InstanceContainer.
|
||||||
@pyqtProperty(InstanceContainer, fset = setMaterial, notify = pyqtContainersChanged)
|
@pyqtProperty(InstanceContainer, fset = setMaterial, notify = pyqtContainersChanged)
|
||||||
def material(self) -> InstanceContainer:
|
def material(self) -> InstanceContainer:
|
||||||
return self._containers[_ContainerIndexes.Material]
|
return self._containers[_ContainerIndexes.Material]
|
||||||
|
|
||||||
|
## Set the variant container.
|
||||||
|
#
|
||||||
|
# \param new_quality_changes The new variant container. It is expected to have a "type" metadata entry with the value "quality_changes".
|
||||||
def setVariant(self, new_variant: InstanceContainer) -> None:
|
def setVariant(self, new_variant: InstanceContainer) -> None:
|
||||||
self.replaceContainer(_ContainerIndexes.Variant, new_variant)
|
self.replaceContainer(_ContainerIndexes.Variant, new_variant)
|
||||||
|
|
||||||
|
## Set the variant container by an ID.
|
||||||
|
#
|
||||||
|
# \param new_quality_changes_id The ID of the new variant container.
|
||||||
|
#
|
||||||
|
# \throws Exceptions.InvalidContainerError Raised when no container could be found with the specified ID.
|
||||||
def setVariantById(self, new_variant_id: str) -> None:
|
def setVariantById(self, new_variant_id: str) -> None:
|
||||||
variant = ContainerRegistry.getInstance().findInstanceContainers(id = new_variant_id)
|
variant = ContainerRegistry.getInstance().findInstanceContainers(id = new_variant_id)
|
||||||
if variant:
|
if variant:
|
||||||
|
@ -87,13 +155,25 @@ class CuraContainerStack(ContainerStack):
|
||||||
else:
|
else:
|
||||||
raise Exceptions.InvalidContainerError("Could not find container with id {id}".format(id = new_variant_id))
|
raise Exceptions.InvalidContainerError("Could not find container with id {id}".format(id = new_variant_id))
|
||||||
|
|
||||||
|
|
||||||
|
## Get the variant container.
|
||||||
|
#
|
||||||
|
# \return The variant container. Should always be a valid container, but can be equal to the empty InstanceContainer.
|
||||||
@pyqtProperty(InstanceContainer, fset = setVariant, notify = pyqtContainersChanged)
|
@pyqtProperty(InstanceContainer, fset = setVariant, notify = pyqtContainersChanged)
|
||||||
def variant(self) -> InstanceContainer:
|
def variant(self) -> InstanceContainer:
|
||||||
return self._containers[_ContainerIndexes.Variant]
|
return self._containers[_ContainerIndexes.Variant]
|
||||||
|
|
||||||
|
## Set the definition changes container.
|
||||||
|
#
|
||||||
|
# \param new_quality_changes The new definition changes container. It is expected to have a "type" metadata entry with the value "quality_changes".
|
||||||
def setDefinitionChanges(self, new_definition_changes: InstanceContainer) -> None:
|
def setDefinitionChanges(self, new_definition_changes: InstanceContainer) -> None:
|
||||||
self.replaceContainer(_ContainerIndexes.DefinitionChanges, new_definition_changes)
|
self.replaceContainer(_ContainerIndexes.DefinitionChanges, new_definition_changes)
|
||||||
|
|
||||||
|
## Set the definition changes container by an ID.
|
||||||
|
#
|
||||||
|
# \param new_quality_changes_id The ID of the new definition changes container.
|
||||||
|
#
|
||||||
|
# \throws Exceptions.InvalidContainerError Raised when no container could be found with the specified ID.
|
||||||
def setDefinitionChangesById(self, new_definition_changes_id: str) -> None:
|
def setDefinitionChangesById(self, new_definition_changes_id: str) -> None:
|
||||||
new_definition_changes = ContainerRegistry.getInstance().findInstanceContainers(id = new_definition_changes_id)
|
new_definition_changes = ContainerRegistry.getInstance().findInstanceContainers(id = new_definition_changes_id)
|
||||||
if new_definition_changes:
|
if new_definition_changes:
|
||||||
|
@ -101,13 +181,24 @@ class CuraContainerStack(ContainerStack):
|
||||||
else:
|
else:
|
||||||
raise Exceptions.InvalidContainerError("Could not find container with id {id}".format(id = new_definition_changes_id))
|
raise Exceptions.InvalidContainerError("Could not find container with id {id}".format(id = new_definition_changes_id))
|
||||||
|
|
||||||
|
## Get the definition changes container.
|
||||||
|
#
|
||||||
|
# \return The definition changes container. Should always be a valid container, but can be equal to the empty InstanceContainer.
|
||||||
@pyqtProperty(InstanceContainer, fset = setDefinitionChanges, notify = pyqtContainersChanged)
|
@pyqtProperty(InstanceContainer, fset = setDefinitionChanges, notify = pyqtContainersChanged)
|
||||||
def definitionChanges(self) -> InstanceContainer:
|
def definitionChanges(self) -> InstanceContainer:
|
||||||
return self._containers[_ContainerIndexes.DefinitionChanges]
|
return self._containers[_ContainerIndexes.DefinitionChanges]
|
||||||
|
|
||||||
|
## Set the definition container.
|
||||||
|
#
|
||||||
|
# \param new_quality_changes The new definition container. It is expected to have a "type" metadata entry with the value "quality_changes".
|
||||||
def setDefinition(self, new_definition: DefinitionContainer) -> None:
|
def setDefinition(self, new_definition: DefinitionContainer) -> None:
|
||||||
self.replaceContainer(_ContainerIndexes.Definition, new_definition)
|
self.replaceContainer(_ContainerIndexes.Definition, new_definition)
|
||||||
|
|
||||||
|
## Set the definition container by an ID.
|
||||||
|
#
|
||||||
|
# \param new_quality_changes_id The ID of the new definition container.
|
||||||
|
#
|
||||||
|
# \throws Exceptions.InvalidContainerError Raised when no container could be found with the specified ID.
|
||||||
def setDefinitionById(self, new_definition_id: str) -> None:
|
def setDefinitionById(self, new_definition_id: str) -> None:
|
||||||
new_definition = ContainerRegistry.getInstance().findDefinitionContainers(id = new_definition_id)
|
new_definition = ContainerRegistry.getInstance().findDefinitionContainers(id = new_definition_id)
|
||||||
if new_definition:
|
if new_definition:
|
||||||
|
@ -115,6 +206,9 @@ class CuraContainerStack(ContainerStack):
|
||||||
else:
|
else:
|
||||||
raise Exceptions.InvalidContainerError("Could not find container with id {id}".format(id = new_definition_id))
|
raise Exceptions.InvalidContainerError("Could not find container with id {id}".format(id = new_definition_id))
|
||||||
|
|
||||||
|
## Get the definition container.
|
||||||
|
#
|
||||||
|
# \return The definition container. Should always be a valid container, but can be equal to the empty InstanceContainer.
|
||||||
@pyqtProperty(DefinitionContainer, fset = setDefinition, notify = pyqtContainersChanged)
|
@pyqtProperty(DefinitionContainer, fset = setDefinition, notify = pyqtContainersChanged)
|
||||||
def definition(self) -> DefinitionContainer:
|
def definition(self) -> DefinitionContainer:
|
||||||
return self._containers[_ContainerIndexes.Definition]
|
return self._containers[_ContainerIndexes.Definition]
|
||||||
|
@ -135,6 +229,16 @@ class CuraContainerStack(ContainerStack):
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
## Set a property of a setting.
|
||||||
|
#
|
||||||
|
# This will set a property of a specified setting. Since the container stack does not contain
|
||||||
|
# any settings itself, it is required to specify a container to set the property on. The target
|
||||||
|
# container is matched by container type.
|
||||||
|
#
|
||||||
|
# \param key The key of the setting to set.
|
||||||
|
# \param property_name The name of the property to set.
|
||||||
|
# \param new_value The new value to set the property to.
|
||||||
|
# \param target_container The type of the container to set the property of. Defaults to "user".
|
||||||
def setProperty(self, key: str, property_name: str, new_value: Any, target_container: str = "user") -> None:
|
def setProperty(self, key: str, property_name: str, new_value: Any, target_container: str = "user") -> None:
|
||||||
container_index = _ContainerIndexes.indexForType(target_container)
|
container_index = _ContainerIndexes.indexForType(target_container)
|
||||||
if container_index != -1:
|
if container_index != -1:
|
||||||
|
@ -144,22 +248,34 @@ class CuraContainerStack(ContainerStack):
|
||||||
|
|
||||||
## Overridden from ContainerStack
|
## Overridden from ContainerStack
|
||||||
#
|
#
|
||||||
# Since we have a fixed order of containers in the stack, we want to enforce this.
|
# Since we have a fixed order of containers in the stack and this method would modify the container
|
||||||
|
# ordering, we disallow this operation.
|
||||||
@override(ContainerStack)
|
@override(ContainerStack)
|
||||||
def addContainer(self, container: ContainerInterface) -> None:
|
def addContainer(self, container: ContainerInterface) -> None:
|
||||||
raise Exceptions.InvalidOperationError("Cannot add a container to Global stack")
|
raise Exceptions.InvalidOperationError("Cannot add a container to Global stack")
|
||||||
|
|
||||||
## Overridden from ContainerStack
|
## Overridden from ContainerStack
|
||||||
|
#
|
||||||
|
# Since we have a fixed order of containers in the stack and this method would modify the container
|
||||||
|
# ordering, we disallow this operation.
|
||||||
@override(ContainerStack)
|
@override(ContainerStack)
|
||||||
def insertContainer(self, index: int, container: ContainerInterface) -> None:
|
def insertContainer(self, index: int, container: ContainerInterface) -> None:
|
||||||
raise Exceptions.InvalidOperationError("Cannot insert a container into Global stack")
|
raise Exceptions.InvalidOperationError("Cannot insert a container into Global stack")
|
||||||
|
|
||||||
## Overridden from ContainerStack
|
## Overridden from ContainerStack
|
||||||
|
#
|
||||||
|
# Since we have a fixed order of containers in the stack and this method would modify the container
|
||||||
|
# ordering, we disallow this operation.
|
||||||
@override(ContainerStack)
|
@override(ContainerStack)
|
||||||
def removeContainer(self, index: int) -> None:
|
def removeContainer(self, index: int) -> None:
|
||||||
raise Exceptions.InvalidOperationError("Cannot remove a container from Global stack")
|
raise Exceptions.InvalidOperationError("Cannot remove a container from Global stack")
|
||||||
|
|
||||||
## Overridden from ContainerStack
|
## Overridden from ContainerStack
|
||||||
|
#
|
||||||
|
# Replaces the container at the specified index with another container.
|
||||||
|
# This version performs checks to make sure the new container has the expected metadata and type.
|
||||||
|
#
|
||||||
|
# \throws Exception.InvalidContainerError Raised when trying to replace a container with a container that has an incorrect type.
|
||||||
@override(ContainerStack)
|
@override(ContainerStack)
|
||||||
def replaceContainer(self, index: int, container: ContainerInterface, postpone_emit: bool = False) -> None:
|
def replaceContainer(self, index: int, container: ContainerInterface, postpone_emit: bool = False) -> None:
|
||||||
expected_type = _ContainerIndexes.IndexTypeMap[index]
|
expected_type = _ContainerIndexes.IndexTypeMap[index]
|
||||||
|
@ -172,6 +288,13 @@ class CuraContainerStack(ContainerStack):
|
||||||
super().replaceContainer(index, container, postpone_emit)
|
super().replaceContainer(index, container, postpone_emit)
|
||||||
|
|
||||||
## Overridden from ContainerStack
|
## Overridden from ContainerStack
|
||||||
|
#
|
||||||
|
# This deserialize will make sure the internal list of containers matches with what we expect.
|
||||||
|
# It will first check to see if the container at a certain index already matches with what we
|
||||||
|
# expect. If it does not, it will search for a matching container with the correct type. Should
|
||||||
|
# no container with the correct type be found, it will use the empty container.
|
||||||
|
#
|
||||||
|
# \throws InvalidContainerStackError Raised when no definition can be found for the stack.
|
||||||
@override(ContainerStack)
|
@override(ContainerStack)
|
||||||
def deserialize(self, contents: str) -> None:
|
def deserialize(self, contents: str) -> None:
|
||||||
super().deserialize(contents)
|
super().deserialize(contents)
|
||||||
|
@ -209,6 +332,8 @@ class CuraContainerStack(ContainerStack):
|
||||||
self.pyqtContainersChanged.emit()
|
self.pyqtContainersChanged.emit()
|
||||||
|
|
||||||
## private:
|
## private:
|
||||||
|
|
||||||
|
# Private helper class to keep track of container positions and their types.
|
||||||
class _ContainerIndexes:
|
class _ContainerIndexes:
|
||||||
UserChanges = 0
|
UserChanges = 0
|
||||||
QualityChanges = 1
|
QualityChanges = 1
|
||||||
|
@ -229,6 +354,7 @@ class _ContainerIndexes:
|
||||||
Definition: "definition",
|
Definition: "definition",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Perform reverse lookup (type name -> index)
|
||||||
@classmethod
|
@classmethod
|
||||||
def indexForType(cls, type_name: str) -> int:
|
def indexForType(cls, type_name: str) -> int:
|
||||||
for key, value in cls.IndexTypeMap.items():
|
for key, value in cls.IndexTypeMap.items():
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue