123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 |
- # Copyright (c) 2017 Ultimaker B.V.
- # Cura is released under the terms of the AGPLv3 or higher.
- from typing import Any
- from PyQt5.QtCore import pyqtProperty, pyqtSlot, pyqtSignal
- from UM.Decorators import override
- from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase
- from UM.Settings.ContainerStack import ContainerStack, InvalidContainerStackError
- from UM.Settings.InstanceContainer import InstanceContainer
- from UM.Settings.DefinitionContainer import DefinitionContainer
- from UM.Settings.ContainerRegistry import ContainerRegistry
- from UM.Settings.Interfaces import ContainerInterface
- from . import Exceptions
- class CuraContainerStack(ContainerStack):
- def __init__(self, container_id: str, *args, **kwargs):
- super().__init__(container_id, *args, **kwargs)
- self._empty_instance_container = ContainerRegistry.getInstance().getEmptyInstanceContainer()
- self._containers = [self._empty_instance_container for i in range(len(_ContainerIndexes.IndexTypeMap))]
- self.containersChanged.connect(self._onContainersChanged)
- pyqtContainersChanged = pyqtSignal()
- def setUserChanges(self, new_user_changes: InstanceContainer) -> None:
- self.replaceContainer(_ContainerIndexes.UserChanges, new_user_changes)
- @pyqtProperty(InstanceContainer, fset = setUserChanges, notify = pyqtContainersChanged)
- def userChanges(self) -> InstanceContainer:
- return self._containers[_ContainerIndexes.UserChanges]
- def setQualityChanges(self, new_quality_changes: InstanceContainer) -> None:
- self.replaceContainer(_ContainerIndexes.QualityChanges, new_quality_changes)
- def setQualityChangesById(self, new_quality_changes_id: str) -> None:
- quality_changes = ContainerRegistry.getInstance().findInstanceContainers(id = new_quality_changes_id)
- if quality_changes:
- self.setQualityChanges(quality_changes[0])
- else:
- raise Exceptions.InvalidContainerError("Could not find container with id {id}".format(id = new_quality_changes_id))
- @pyqtProperty(InstanceContainer, fset = setQualityChanges, notify = pyqtContainersChanged)
- def qualityChanges(self) -> InstanceContainer:
- return self._containers[_ContainerIndexes.QualityChanges]
- def setQuality(self, new_quality: InstanceContainer) -> None:
- self.replaceContainer(_ContainerIndexes.Quality, new_quality)
- def setQualityById(self, new_quality_id: str) -> None:
- quality = ContainerRegistry.getInstance().findInstanceContainers(id = new_quality_id)
- if quality:
- self.setQuality(quality[0])
- else:
- raise Exceptions.InvalidContainerError("Could not find container with id {id}".format(id = new_quality_id))
- @pyqtProperty(InstanceContainer, fset = setQuality, notify = pyqtContainersChanged)
- def quality(self) -> InstanceContainer:
- return self._containers[_ContainerIndexes.Quality]
- def setMaterial(self, new_material: InstanceContainer) -> None:
- self.replaceContainer(_ContainerIndexes.Material, new_material)
- def setMaterialById(self, new_material_id: str) -> None:
- material = ContainerRegistry.getInstance().findInstanceContainers(id = new_material_id)
- if material:
- self.setMaterial(material[0])
- else:
- raise Exceptions.InvalidContainerError("Could not find container with id {id}".format(id = new_material_id))
- @pyqtProperty(InstanceContainer, fset = setMaterial, notify = pyqtContainersChanged)
- def material(self) -> InstanceContainer:
- return self._containers[_ContainerIndexes.Material]
- def setVariant(self, new_variant: InstanceContainer) -> None:
- self.replaceContainer(_ContainerIndexes.Variant, new_variant)
- def setVariantById(self, new_variant_id: str) -> None:
- variant = ContainerRegistry.getInstance().findInstanceContainers(id = new_variant_id)
- if variant:
- self.setVariant(variant[0])
- else:
- raise Exceptions.InvalidContainerError("Could not find container with id {id}".format(id = new_variant_id))
- @pyqtProperty(InstanceContainer, fset = setVariant, notify = pyqtContainersChanged)
- def variant(self) -> InstanceContainer:
- return self._containers[_ContainerIndexes.Variant]
- def setDefinitionChanges(self, new_definition_changes: InstanceContainer) -> None:
- self.replaceContainer(_ContainerIndexes.DefinitionChanges, new_definition_changes)
- def setDefinitionChangesById(self, new_definition_changes_id: str) -> None:
- new_definition_changes = ContainerRegistry.getInstance().findInstanceContainers(id = new_definition_changes_id)
- if new_definition_changes:
- self.setDefinitionChanges(new_definition_changes[0])
- else:
- raise Exceptions.InvalidContainerError("Could not find container with id {id}".format(id = new_definition_changes_id))
- @pyqtProperty(InstanceContainer, fset = setDefinitionChanges, notify = pyqtContainersChanged)
- def definitionChanges(self) -> InstanceContainer:
- return self._containers[_ContainerIndexes.DefinitionChanges]
- def setDefinition(self, new_definition: DefinitionContainer) -> None:
- self.replaceContainer(_ContainerIndexes.Definition, new_definition)
- def setDefinitionById(self, new_definition_id: str) -> None:
- new_definition = ContainerRegistry.getInstance().findDefinitionContainers(id = new_definition_id)
- if new_definition:
- self.setDefinition(new_definition[0])
- else:
- raise Exceptions.InvalidContainerError("Could not find container with id {id}".format(id = new_definition_id))
- @pyqtProperty(DefinitionContainer, fset = setDefinition, notify = pyqtContainersChanged)
- def definition(self) -> DefinitionContainer:
- return self._containers[_ContainerIndexes.Definition]
- ## Check whether the specified setting has a 'user' value.
- #
- # A user value here is defined as the setting having a value in either
- # the UserChanges or QualityChanges container.
- #
- # \return True if the setting has a user value, False if not.
- @pyqtSlot(str, result = bool)
- def hasUserValue(self, key: str) -> bool:
- if self._containers[_ContainerIndexes.UserChanges].hasProperty(key, "value"):
- return True
- if self._containers[_ContainerIndexes.QualityChanges].hasProperty(key, "value"):
- return True
- return False
- def setProperty(self, key: str, property_name: str, new_value: Any, target_container: str = "user") -> None:
- container_index = _ContainerIndexes.indexForType(target_container)
- if container_index != -1:
- self._containers[container_index].setProperty(key, property_name, new_value)
- else:
- raise IndexError("Invalid target container {type}".format(type = target_container))
- ## Overridden from ContainerStack
- #
- # Since we have a fixed order of containers in the stack, we want to enforce this.
- @override(ContainerStack)
- def addContainer(self, container: ContainerInterface) -> None:
- raise Exceptions.InvalidOperationError("Cannot add a container to Global stack")
- ## Overridden from ContainerStack
- @override(ContainerStack)
- def insertContainer(self, index: int, container: ContainerInterface) -> None:
- raise Exceptions.InvalidOperationError("Cannot insert a container into Global stack")
- ## Overridden from ContainerStack
- @override(ContainerStack)
- def removeContainer(self, index: int) -> None:
- raise Exceptions.InvalidOperationError("Cannot remove a container from Global stack")
- ## Overridden from ContainerStack
- @override(ContainerStack)
- def replaceContainer(self, index: int, container: ContainerInterface, postpone_emit: bool = False) -> None:
- expected_type = _ContainerIndexes.IndexTypeMap[index]
- if expected_type == "definition":
- if not isinstance(container, DefinitionContainer):
- raise Exceptions.InvalidContainerError("Cannot replace container at index {index} with a container that is not a DefinitionContainer".format(index = index))
- elif container != self._empty_instance_container and container.getMetaDataEntry("type") != expected_type:
- raise Exceptions.InvalidContainerError("Cannot replace container at index {index} with a container that is not of {type} type, but {actual_type} type.".format(index = index, type = expected_type, actual_type = container.getMetaDataEntry("type")))
- super().replaceContainer(index, container, postpone_emit)
- ## Overridden from ContainerStack
- @override(ContainerStack)
- def deserialize(self, contents: str) -> None:
- super().deserialize(contents)
- new_containers = self._containers.copy()
- while(len(new_containers) < len(_ContainerIndexes.IndexTypeMap)):
- new_containers.append(self._empty_instance_container)
- # Validate and ensure the list of containers matches with what we expect
- for index, type_name in _ContainerIndexes.IndexTypeMap.items():
- try:
- container = new_containers[index]
- except IndexError:
- container = None
- if type_name == "definition":
- if not container or not isinstance(container, DefinitionContainer):
- definition = self.findContainer(container_type = DefinitionContainer, category = "*")
- if not definition:
- raise InvalidContainerStackError("Stack {id} does not have a definition!".format(id = self._id))
- new_containers[index] = definition
- continue
- if not container or container.getMetaDataEntry("type") != type_name:
- actual_container = self.findContainer(type = type_name)
- if actual_container:
- new_containers[index] = actual_container
- else:
- new_containers[index] = self._empty_instance_container
- self._containers = new_containers
- def _onContainersChanged(self, container):
- self.pyqtContainersChanged.emit()
- ## private:
- class _ContainerIndexes:
- UserChanges = 0
- QualityChanges = 1
- Quality = 2
- Material = 3
- Variant = 4
- DefinitionChanges = 5
- Definition = 6
- # Simple hash map to map from index to "type" metadata entry
- IndexTypeMap = {
- UserChanges: "user",
- QualityChanges: "quality_changes",
- Quality: "quality",
- Material: "material",
- Variant: "variant",
- DefinitionChanges: "definition_changes",
- Definition: "definition",
- }
- @classmethod
- def indexForType(cls, type_name: str) -> int:
- for key, value in cls.IndexTypeMap.items():
- if value == type_name:
- return key
- return -1
|