def loadMetadata(self, container_id: str) -> Optional[Dict[str, Any]]: registry = ContainerRegistry.getInstance() if container_id in registry.metadata: return registry.metadata[container_id] filename = self._id_to_path[container_id] #Raises KeyError if container ID does not exist in the (cache of the) files! clazz = ContainerRegistry.mime_type_map[self._id_to_mime[container_id].name] requested_metadata = None try: with open(filename, "r", encoding = "utf-8") as f: result_metadatas = clazz.deserializeMetadata(f.read(), container_id) #pylint: disable=no-member except IOError as e: Logger.log("e", "Unable to load metadata from file {filename}: {error_msg}".format(filename = filename, error_msg = str(e))) ConfigurationErrorMessage.getInstance().addFaultyContainers(container_id) return None except Exception as e: Logger.logException("e", "Unable to deserialize metadata for container {filename}: {container_id}: {error_msg}".format(filename = filename, container_id = container_id, error_msg = str(e))) ConfigurationErrorMessage.getInstance().addFaultyContainers(container_id) return None for metadata in result_metadatas: if "id" not in metadata: Logger.log("w", "Metadata obtained from deserializeMetadata of {class_name} didn't contain an ID.".format(class_name = clazz.__name__)) continue if metadata["id"] == container_id: requested_metadata = metadata #Side-load the metadata into the registry if we get multiple containers. if metadata["id"] not in registry.metadata: #This wouldn't get loaded normally. self._id_to_path[metadata["id"]] = filename self._id_to_mime[metadata["id"]] = self._id_to_mime[container_id] #Assume that they only return one MIME type. registry.metadata[metadata["id"]] = metadata registry.source_provider[metadata["id"]] = self return requested_metadata
def loadMetadata(self, container_id: str) -> Dict[str, Any]: registry = ContainerRegistry.getInstance() if container_id in registry.metadata: return registry.metadata[container_id] filename = self._id_to_path[container_id] #Raises KeyError if container ID does not exist in the (cache of the) files! clazz = ContainerRegistry.mime_type_map[self._id_to_mime[container_id].name] requested_metadata = {} # type: Dict[str, Any] try: with open(filename, "r", encoding = "utf-8") as f: result_metadatas = clazz.deserializeMetadata(f.read(), container_id) #pylint: disable=no-member except IOError as e: Logger.log("e", "Unable to load metadata from file {filename}: {error_msg}".format(filename = filename, error_msg = str(e))) ConfigurationErrorMessage.getInstance().addFaultyContainers(container_id) return {} except Exception as e: Logger.logException("e", "Unable to deserialize metadata for container {filename}: {container_id}: {error_msg}".format(filename = filename, container_id = container_id, error_msg = str(e))) ConfigurationErrorMessage.getInstance().addFaultyContainers(container_id) return {} for metadata in result_metadatas: if "id" not in metadata: Logger.log("w", "Metadata obtained from deserializeMetadata of {class_name} didn't contain an ID.".format(class_name = clazz.__name__)) continue if metadata["id"] == container_id: requested_metadata = metadata #Side-load the metadata into the registry if we get multiple containers. if metadata["id"] not in registry.metadata: #This wouldn't get loaded normally. self._id_to_path[metadata["id"]] = filename self._id_to_mime[metadata["id"]] = self._id_to_mime[container_id] #Assume that they only return one MIME type. registry.metadata[metadata["id"]] = metadata registry.source_provider[metadata["id"]] = self return requested_metadata
def initialize(self): self._machine_to_variant_dict_map = OrderedDict() self._machine_to_buildplate_dict_map = OrderedDict() # Cache all variants from the container registry to a variant map for better searching and organization. variant_metadata_list = self._container_registry.findContainersMetadata( type="variant") for variant_metadata in variant_metadata_list: if variant_metadata["id"] in self._exclude_variant_id_list: Logger.log("d", "Exclude variant [%s]", variant_metadata["id"]) continue variant_name = variant_metadata["name"] variant_definition = variant_metadata["definition"] if variant_definition not in self._machine_to_variant_dict_map: self._machine_to_variant_dict_map[ variant_definition] = OrderedDict() for variant_type in ALL_VARIANT_TYPES: self._machine_to_variant_dict_map[variant_definition][ variant_type] = dict() try: variant_type = variant_metadata["hardware_type"] except KeyError: Logger.log( "w", "Variant %s does not specify a hardware_type; assuming 'nozzle'", variant_metadata["id"]) variant_type = VariantType.NOZZLE variant_type = VariantType(variant_type) variant_dict = self._machine_to_variant_dict_map[ variant_definition][variant_type] if variant_name in variant_dict: # ERROR: duplicated variant name. ConfigurationErrorMessage.getInstance().addFaultyContainers( variant_metadata["id"]) continue #Then ignore this variant. This now chooses one of the two variants arbitrarily and deletes the other one! No guarantees! variant_dict[variant_name] = ContainerNode( metadata=variant_metadata) # If the variant is a buildplate then fill also the buildplate map if variant_type == VariantType.BUILD_PLATE: if variant_definition not in self._machine_to_buildplate_dict_map: self._machine_to_buildplate_dict_map[ variant_definition] = OrderedDict() variant_container = self._container_registry.findContainers( type="variant", id=variant_metadata["id"])[0] buildplate_type = variant_container.getProperty( "machine_buildplate_type", "value") if buildplate_type not in self._machine_to_buildplate_dict_map[ variant_definition]: self._machine_to_variant_dict_map[variant_definition][ buildplate_type] = dict() self._machine_to_buildplate_dict_map[variant_definition][ buildplate_type] = variant_dict[variant_name]
def createMachine(cls, name: str, definition_id: str) -> Optional[GlobalStack]: from cura.CuraApplication import CuraApplication application = CuraApplication.getInstance() registry = application.getContainerRegistry() container_tree = ContainerTree.getInstance() definitions = registry.findDefinitionContainers(id=definition_id) if not definitions: ConfigurationErrorMessage.getInstance().addFaultyContainers( definition_id) Logger.log("w", "Definition {definition} was not found!", definition=definition_id) return None machine_definition = definitions[0] # The container tree listens to the containerAdded signal to add the definition and build the tree, # but that signal is emitted with a delay which might not have passed yet. # Therefore we must make sure that it's manually added here. container_tree.addMachineNodeByDefinitionId(machine_definition.getId()) machine_node = container_tree.machines[machine_definition.getId()] generated_name = registry.createUniqueName( "machine", "", name, machine_definition.getName()) # Make sure the new name does not collide with any definition or (quality) profile # createUniqueName() only looks at other stacks, but not at definitions or quality profiles # Note that we don't go for uniqueName() immediately because that function matches with ignore_case set to true if registry.findContainersMetadata(id=generated_name): generated_name = registry.uniqueName(generated_name) new_global_stack = cls.createGlobalStack( new_stack_id=generated_name, definition=machine_definition, variant_container=application.empty_variant_container, material_container=application.empty_material_container, quality_container=machine_node.preferredGlobalQuality().container, ) new_global_stack.setName(generated_name) # Create ExtruderStacks extruder_dict = machine_definition.getMetaDataEntry( "machine_extruder_trains") for position in extruder_dict: cls.createExtruderStackWithDefaultSetup(new_global_stack, position) for new_extruder in new_global_stack.extruders.values( ): # Only register the extruders if we're sure that all of them are correct. registry.addContainer(new_extruder) # Register the global stack after the extruder stacks are created. This prevents the registry from adding another # extruder stack because the global stack didn't have one yet (which is enforced since Cura 3.1). registry.addContainer(new_global_stack) return new_global_stack
def createMachine(cls, name: str, definition_id: str) -> Optional[GlobalStack]: """Create a new instance of a machine. :param name: The name of the new machine. :param definition_id: The ID of the machine definition to use. :return: The new global stack or None if an error occurred. """ from cura.CuraApplication import CuraApplication application = CuraApplication.getInstance() registry = application.getContainerRegistry() container_tree = ContainerTree.getInstance() definitions = registry.findDefinitionContainers(id = definition_id) if not definitions: ConfigurationErrorMessage.getInstance().addFaultyContainers(definition_id) Logger.log("w", "Definition {definition} was not found!", definition = definition_id) return None machine_definition = definitions[0] machine_node = container_tree.machines[machine_definition.getId()] generated_name = registry.createUniqueName("machine", "", name, machine_definition.getName()) # Make sure the new name does not collide with any definition or (quality) profile # createUniqueName() only looks at other stacks, but not at definitions or quality profiles # Note that we don't go for uniqueName() immediately because that function matches with ignore_case set to true if registry.findContainersMetadata(id = generated_name): generated_name = registry.uniqueName(generated_name) new_global_stack = cls.createGlobalStack( new_stack_id = generated_name, definition = machine_definition, variant_container = application.empty_variant_container, material_container = application.empty_material_container, quality_container = machine_node.preferredGlobalQuality().container, ) new_global_stack.setName(generated_name) # Create ExtruderStacks extruder_dict = machine_definition.getMetaDataEntry("machine_extruder_trains") for position in extruder_dict: try: cls.createExtruderStackWithDefaultSetup(new_global_stack, position) except IndexError: return None for new_extruder in new_global_stack.extruderList: # Only register the extruders if we're sure that all of them are correct. registry.addContainer(new_extruder) # Register the global stack after the extruder stacks are created. This prevents the registry from adding another # extruder stack because the global stack didn't have one yet (which is enforced since Cura 3.1). registry.addContainer(new_global_stack) return new_global_stack
def deserialize(self, serialized: str, file_name: Optional[str] = None) -> str: # Update the serialized data first serialized = super().deserialize(serialized, file_name) parser = self._readAndValidateSerialized(serialized) if parser.getint("general", "version") != self.Version: raise IncorrectVersionError() # Clear all data before starting. for container in self._containers: container.propertyChanged.disconnect(self._collectPropertyChanges) self._containers = [] self._metadata = {} if "metadata" in parser: self._metadata = dict(parser["metadata"]) self._metadata["id"] = parser["general"]["id"] self._metadata["name"] = parser["general"].get("name", self.getId()) self._metadata["version"] = self.Version # Guaranteed to be equal to what's in the container. See above. self._metadata["container_type"] = ContainerStack if "containers" in parser: for index, container_id in parser.items("containers"): containers = _containerRegistry.findContainers(id = container_id) if containers: containers[0].propertyChanged.connect(self._collectPropertyChanges) self._containers.append(containers[0]) else: self._containers.append(_containerRegistry.getEmptyInstanceContainer()) ConfigurationErrorMessage.getInstance().addFaultyContainers(container_id, self.getId()) Logger.log("e", "When trying to deserialize %s, we received an unknown container ID (%s)" % (self.getId(), container_id)) raise ContainerFormatError("When trying to deserialize %s, we received an unknown container ID (%s)" % (self.getId(), container_id)) elif parser.has_option("general", "containers"): # Backward compatibility with 2.3.1: The containers used to be saved in a single comma-separated list. container_string = parser["general"].get("containers", "") Logger.log("d", "While deserializing, we got the following container string: %s", container_string) container_id_list = container_string.split(",") for container_id in container_id_list: if container_id != "": containers = _containerRegistry.findContainers(id = container_id) if containers: containers[0].propertyChanged.connect(self._collectPropertyChanges) self._containers.append(containers[0]) else: self._containers.append(_containerRegistry.getEmptyInstanceContainer()) ConfigurationErrorMessage.getInstance().addFaultyContainers(container_id, self.getId()) Logger.log("e", "When trying to deserialize %s, we received an unknown container ID (%s)" % (self.getId(), container_id)) raise ContainerFormatError("When trying to deserialize %s, we received an unknown container ID (%s)" % (self.getId(), container_id)) ## TODO; Deserialize the containers. return serialized
def addNode(self, node: "QualityNode"): extruder_position = node.metadata.get("position") if extruder_position is None and self.node_for_global is not None or extruder_position in self.nodes_for_extruders: #We would be overwriting another node. ConfigurationErrorMessage.getInstance().addFaultyContainers(node.metadata["id"]) return if extruder_position is None: #Then we're a global quality changes profile. self.node_for_global = node else: #This is an extruder's quality changes profile. self.nodes_for_extruders[extruder_position] = node
def addNode(self, node: "QualityNode") -> None: extruder_position = node.getMetaDataEntry("position") if extruder_position is None and self.node_for_global is not None or extruder_position in self.nodes_for_extruders: #We would be overwriting another node. ConfigurationErrorMessage.getInstance().addFaultyContainers(node.getMetaDataEntry("id")) return if extruder_position is None: # Then we're a global quality changes profile. self.node_for_global = node else: # This is an extruder's quality changes profile. self.nodes_for_extruders[extruder_position] = node
def _configurationErrorMessageActionTriggered(self, _, action_id): if action_id == "startoptimiser_clean": configuration_error_message = ConfigurationErrorMessage.getInstance( ) configuration_error_message.hide() self._addToBlackList( configuration_error_message._faulty_containers)
def container(self) -> Optional[InstanceContainer]: if not self._container: container_list = ContainerRegistry.getInstance().findInstanceContainers(id = self.container_id) if len(container_list) == 0: Logger.log("e", "Failed to lazy-load container [{container_id}]. Cannot find it.".format(container_id = self.container_id)) error_message = ConfigurationErrorMessage.getInstance() error_message.addFaultyContainers(self.container_id) return None self._container = container_list[0] return self._container
def initialize(self) -> None: self._machine_to_variant_dict_map = OrderedDict() self._machine_to_buildplate_dict_map = OrderedDict() # Cache all variants from the container registry to a variant map for better searching and organization. variant_metadata_list = self._container_registry.findContainersMetadata(type = "variant") for variant_metadata in variant_metadata_list: if variant_metadata["id"] in self._exclude_variant_id_list: Logger.log("d", "Exclude variant [%s]", variant_metadata["id"]) continue variant_name = variant_metadata["name"] variant_definition = variant_metadata["definition"] if variant_definition not in self._machine_to_variant_dict_map: self._machine_to_variant_dict_map[variant_definition] = OrderedDict() for variant_type in ALL_VARIANT_TYPES: self._machine_to_variant_dict_map[variant_definition][variant_type] = dict() try: variant_type = variant_metadata["hardware_type"] except KeyError: Logger.log("w", "Variant %s does not specify a hardware_type; assuming 'nozzle'", variant_metadata["id"]) variant_type = VariantType.NOZZLE variant_type = VariantType(variant_type) variant_dict = self._machine_to_variant_dict_map[variant_definition][variant_type] if variant_name in variant_dict: # ERROR: duplicated variant name. ConfigurationErrorMessage.getInstance().addFaultyContainers(variant_metadata["id"]) continue #Then ignore this variant. This now chooses one of the two variants arbitrarily and deletes the other one! No guarantees! variant_dict[variant_name] = ContainerNode(metadata = variant_metadata) # If the variant is a buildplate then fill also the buildplate map if variant_type == VariantType.BUILD_PLATE: if variant_definition not in self._machine_to_buildplate_dict_map: self._machine_to_buildplate_dict_map[variant_definition] = OrderedDict() variant_container = self._container_registry.findContainers(type = "variant", id = variant_metadata["id"])[0] buildplate_type = variant_container.getProperty("machine_buildplate_type", "value") if buildplate_type not in self._machine_to_buildplate_dict_map[variant_definition]: self._machine_to_variant_dict_map[variant_definition][buildplate_type] = dict() self._machine_to_buildplate_dict_map[variant_definition][buildplate_type] = variant_dict[variant_name]
def getContainer(self) -> Optional["InstanceContainer"]: if self._metadata is None: Logger.log("e", "Cannot get container for a ContainerNode without metadata.") return None if self._container is None: container_id = self._metadata["id"] from UM.Settings.ContainerRegistry import ContainerRegistry container_list = ContainerRegistry.getInstance().findInstanceContainers(id = container_id) if not container_list: Logger.log("e", "Failed to lazy-load container [{container_id}]. Cannot find it.".format(container_id = container_id)) error_message = ConfigurationErrorMessage.getInstance() error_message.addFaultyContainers(container_id) return None self._container = container_list[0] return self._container
def _onPluginsLoaded(self) -> None: local_container_provider = self._application.getPluginRegistry( ).getPluginObject("LocalContainerProvider") self._local_container_provider_patches = LocalContainerProviderPatches.LocalContainerProviderPatches( local_container_provider) configuration_error_message = ConfigurationErrorMessage.getInstance() configuration_error_message.addAction( action_id="startoptimiser_clean", name=catalog.i18nc("@action:button", "Disable affected profiles"), icon="", description=catalog.i18nc( "@action:tooltip", "Disable loading the corrupted configuration files but attempt to leave the rest intact." )) configuration_error_message.actionTriggered.connect( self._configurationErrorMessageActionTriggered)
def container(self) -> Optional[InstanceContainer]: """The container that this node's container ID refers to. This can be used to finally instantiate the container in order to put it in the container stack. :return: A container. """ if not self._container: container_list = ContainerRegistry.getInstance().findInstanceContainers(id = self.container_id) if len(container_list) == 0: Logger.log("e", "Failed to lazy-load container [{container_id}]. Cannot find it.".format(container_id = self.container_id)) error_message = ConfigurationErrorMessage.getInstance() error_message.addFaultyContainers(self.container_id) return None self._container = container_list[0] return self._container
def getContainer(self) -> Optional["InstanceContainer"]: if self.metadata is None: Logger.log("e", "Cannot get container for a ContainerNode without metadata.") return None if self.container is None: container_id = self.metadata["id"] from UM.Settings.ContainerRegistry import ContainerRegistry container_list = ContainerRegistry.getInstance().findInstanceContainers(id = container_id) if not container_list: Logger.log("e", "Failed to lazy-load container [{container_id}]. Cannot find it.".format(container_id = container_id)) error_message = ConfigurationErrorMessage.getInstance() error_message.addFaultyContainers(container_id) return None self.container = container_list[0] return self.container
def createMachine(cls, name: str, definition_id: str) -> Optional[GlobalStack]: from cura.CuraApplication import CuraApplication application = CuraApplication.getInstance() variant_manager = application.getVariantManager() material_manager = application.getMaterialManager() quality_manager = application.getQualityManager() registry = ContainerRegistry.getInstance() definitions = registry.findDefinitionContainers(id = definition_id) if not definitions: ConfigurationErrorMessage.getInstance().addFaultyContainers(definition_id) Logger.log("w", "Definition {definition} was not found!", definition = definition_id) return None machine_definition = definitions[0] # get variant container for the global stack global_variant_container = application.empty_variant_container global_variant_node = variant_manager.getDefaultVariantNode(machine_definition, VariantType.BUILD_PLATE) if global_variant_node: global_variant_container = global_variant_node.getContainer() if not global_variant_container: global_variant_container = application.empty_variant_container # get variant container for extruders extruder_variant_container = application.empty_variant_container extruder_variant_node = variant_manager.getDefaultVariantNode(machine_definition, VariantType.NOZZLE) extruder_variant_name = None if extruder_variant_node: extruder_variant_container = extruder_variant_node.getContainer() if not extruder_variant_container: extruder_variant_container = application.empty_variant_container extruder_variant_name = extruder_variant_container.getName() generated_name = registry.createUniqueName("machine", "", name, machine_definition.getName()) # Make sure the new name does not collide with any definition or (quality) profile # createUniqueName() only looks at other stacks, but not at definitions or quality profiles # Note that we don't go for uniqueName() immediately because that function matches with ignore_case set to true if registry.findContainersMetadata(id = generated_name): generated_name = registry.uniqueName(generated_name) new_global_stack = cls.createGlobalStack( new_stack_id = generated_name, definition = machine_definition, variant_container = global_variant_container, material_container = application.empty_material_container, quality_container = application.empty_quality_container, ) new_global_stack.setName(generated_name) # get material container for extruders material_container = application.empty_material_container material_node = material_manager.getDefaultMaterial(new_global_stack, extruder_variant_name) if material_node and material_node.getContainer(): material_container = material_node.getContainer() # Create ExtruderStacks extruder_dict = machine_definition.getMetaDataEntry("machine_extruder_trains") for position, extruder_definition_id in extruder_dict.items(): # Sanity check: make sure that the positions in the extruder definitions are same as in the machine # definition extruder_definition = registry.findDefinitionContainers(id = extruder_definition_id)[0] position_in_extruder_def = extruder_definition.getMetaDataEntry("position") if position_in_extruder_def != position: ConfigurationErrorMessage.getInstance().addFaultyContainers(extruder_definition_id) return None #Don't return any container stack then, not the rest of the extruders either. new_extruder_id = registry.uniqueName(extruder_definition_id) new_extruder = cls.createExtruderStack( new_extruder_id, extruder_definition = extruder_definition, machine_definition_id = definition_id, position = position, variant_container = extruder_variant_container, material_container = material_container, quality_container = application.empty_quality_container, global_stack = new_global_stack, ) new_extruder.setNextStack(new_global_stack) new_global_stack.addExtruder(new_extruder) for new_extruder in new_global_stack.extruders.values(): #Only register the extruders if we're sure that all of them are correct. registry.addContainer(new_extruder) preferred_quality_type = machine_definition.getMetaDataEntry("preferred_quality_type") quality_group_dict = quality_manager.getQualityGroups(new_global_stack) quality_group = quality_group_dict.get(preferred_quality_type) new_global_stack.quality = quality_group.node_for_global.getContainer() if not new_global_stack.quality: new_global_stack.quality = application.empty_quality_container for position, extruder_stack in new_global_stack.extruders.items(): if position in quality_group.nodes_for_extruders and quality_group.nodes_for_extruders[position].getContainer(): extruder_stack.quality = quality_group.nodes_for_extruders[position].getContainer() else: extruder_stack.quality = application.empty_quality_container # Register the global stack after the extruder stacks are created. This prevents the registry from adding another # extruder stack because the global stack didn't have one yet (which is enforced since Cura 3.1). registry.addContainer(new_global_stack) return new_global_stack
def createMachine(cls, name: str, definition_id: str) -> Optional[GlobalStack]: from cura.CuraApplication import CuraApplication application = CuraApplication.getInstance() variant_manager = application.getVariantManager() material_manager = application.getMaterialManager() quality_manager = application.getQualityManager() registry = application.getContainerRegistry() definitions = registry.findDefinitionContainers(id=definition_id) if not definitions: ConfigurationErrorMessage.getInstance().addFaultyContainers( definition_id) Logger.log("w", "Definition {definition} was not found!", definition=definition_id) return None machine_definition = definitions[0] # get variant container for the global stack global_variant_container = application.empty_variant_container global_variant_node = variant_manager.getDefaultVariantNode( machine_definition, VariantType.BUILD_PLATE) if global_variant_node: global_variant_container = global_variant_node.getContainer() if not global_variant_container: global_variant_container = application.empty_variant_container # get variant container for extruders extruder_variant_container = application.empty_variant_container extruder_variant_node = variant_manager.getDefaultVariantNode( machine_definition, VariantType.NOZZLE) extruder_variant_name = None if extruder_variant_node: extruder_variant_container = extruder_variant_node.getContainer() if not extruder_variant_container: extruder_variant_container = application.empty_variant_container extruder_variant_name = extruder_variant_container.getName() generated_name = registry.createUniqueName( "machine", "", name, machine_definition.getName()) # Make sure the new name does not collide with any definition or (quality) profile # createUniqueName() only looks at other stacks, but not at definitions or quality profiles # Note that we don't go for uniqueName() immediately because that function matches with ignore_case set to true if registry.findContainersMetadata(id=generated_name): generated_name = registry.uniqueName(generated_name) new_global_stack = cls.createGlobalStack( new_stack_id=generated_name, definition=machine_definition, variant_container=global_variant_container, material_container=application.empty_material_container, quality_container=application.empty_quality_container, ) new_global_stack.setName(generated_name) # Create ExtruderStacks extruder_dict = machine_definition.getMetaDataEntry( "machine_extruder_trains") for position, extruder_definition_id in extruder_dict.items(): # Sanity check: make sure that the positions in the extruder definitions are same as in the machine # definition extruder_definition = registry.findDefinitionContainers( id=extruder_definition_id)[0] position_in_extruder_def = extruder_definition.getMetaDataEntry( "position") if position_in_extruder_def != position: ConfigurationErrorMessage.getInstance().addFaultyContainers( extruder_definition_id) return None #Don't return any container stack then, not the rest of the extruders either. # get material container for extruders material_container = application.empty_material_container material_node = material_manager.getDefaultMaterial( new_global_stack, position, extruder_variant_name, extruder_definition=extruder_definition) if material_node and material_node.getContainer(): material_container = material_node.getContainer() new_extruder_id = registry.uniqueName(extruder_definition_id) new_extruder = cls.createExtruderStack( new_extruder_id, extruder_definition=extruder_definition, machine_definition_id=definition_id, position=position, variant_container=extruder_variant_container, material_container=material_container, quality_container=application.empty_quality_container) new_extruder.setNextStack(new_global_stack) new_global_stack.addExtruder(new_extruder) for new_extruder in new_global_stack.extruders.values( ): #Only register the extruders if we're sure that all of them are correct. registry.addContainer(new_extruder) preferred_quality_type = machine_definition.getMetaDataEntry( "preferred_quality_type") quality_group_dict = quality_manager.getQualityGroups(new_global_stack) quality_group = quality_group_dict.get(preferred_quality_type) new_global_stack.quality = quality_group.node_for_global.getContainer() if not new_global_stack.quality: new_global_stack.quality = application.empty_quality_container for position, extruder_stack in new_global_stack.extruders.items(): if position in quality_group.nodes_for_extruders and quality_group.nodes_for_extruders[ position].getContainer(): extruder_stack.quality = quality_group.nodes_for_extruders[ position].getContainer() else: extruder_stack.quality = application.empty_quality_container # Register the global stack after the extruder stacks are created. This prevents the registry from adding another # extruder stack because the global stack didn't have one yet (which is enforced since Cura 3.1). registry.addContainer(new_global_stack) return new_global_stack
def initialize(self): # Initialize the lookup tree for quality profiles with following structure: # <machine> -> <variant> -> <material> # -> <material> self._machine_variant_material_quality_type_to_quality_dict = { } # for quality lookup self._machine_quality_type_to_quality_changes_dict = { } # for quality_changes lookup quality_metadata_list = self._container_registry.findContainersMetadata( type="quality") for metadata in quality_metadata_list: if metadata["id"] == "empty_quality": continue definition_id = metadata["definition"] quality_type = metadata["quality_type"] root_material_id = metadata.get("material") variant_name = metadata.get("variant") is_global_quality = metadata.get("global_quality", False) is_global_quality = is_global_quality or (root_material_id is None and variant_name is None) # Sanity check: material+variant and is_global_quality cannot be present at the same time if is_global_quality and (root_material_id or variant_name): ConfigurationErrorMessage.getInstance().addFaultyContainers( metadata["id"]) continue if definition_id not in self._machine_variant_material_quality_type_to_quality_dict: self._machine_variant_material_quality_type_to_quality_dict[ definition_id] = QualityNode() machine_node = self._machine_variant_material_quality_type_to_quality_dict[ definition_id] if is_global_quality: # For global qualities, save data in the machine node machine_node.addQualityMetadata(quality_type, metadata) continue if variant_name is not None: # If variant_name is specified in the quality/quality_changes profile, check if material is specified, # too. if variant_name not in machine_node.children_map: machine_node.children_map[variant_name] = QualityNode() variant_node = machine_node.children_map[variant_name] if root_material_id is None: # If only variant_name is specified but material is not, add the quality/quality_changes metadata # into the current variant node. variant_node.addQualityMetadata(quality_type, metadata) else: # If only variant_name and material are both specified, go one level deeper: create a material node # under the current variant node, and then add the quality/quality_changes metadata into the # material node. if root_material_id not in variant_node.children_map: variant_node.children_map[ root_material_id] = QualityNode() material_node = variant_node.children_map[root_material_id] material_node.addQualityMetadata(quality_type, metadata) else: # If variant_name is not specified, check if material is specified. if root_material_id is not None: if root_material_id not in machine_node.children_map: machine_node.children_map[ root_material_id] = QualityNode() material_node = machine_node.children_map[root_material_id] material_node.addQualityMetadata(quality_type, metadata) # Initialize the lookup tree for quality_changes profiles with following structure: # <machine> -> <quality_type> -> <name> quality_changes_metadata_list = self._container_registry.findContainersMetadata( type="quality_changes") for metadata in quality_changes_metadata_list: if metadata["id"] == "empty_quality_changes": continue machine_definition_id = metadata["definition"] quality_type = metadata["quality_type"] if machine_definition_id not in self._machine_quality_type_to_quality_changes_dict: self._machine_quality_type_to_quality_changes_dict[ machine_definition_id] = QualityNode() machine_node = self._machine_quality_type_to_quality_changes_dict[ machine_definition_id] machine_node.addQualityChangesMetadata(quality_type, metadata) Logger.log("d", "Lookup tables updated.") self.qualitiesUpdated.emit()
def __addMaterialMetadataIntoLookupTree(self, material_metadata: Dict[str, Any]) -> None: material_id = material_metadata["id"] # We don't store empty material in the lookup tables if material_id == "empty_material": return root_material_id = material_metadata["base_file"] definition = material_metadata["definition"] approximate_diameter = material_metadata["approximate_diameter"] if approximate_diameter not in self._diameter_machine_nozzle_buildplate_material_map: self._diameter_machine_nozzle_buildplate_material_map[approximate_diameter] = {} machine_nozzle_buildplate_material_map = self._diameter_machine_nozzle_buildplate_material_map[ approximate_diameter] if definition not in machine_nozzle_buildplate_material_map: machine_nozzle_buildplate_material_map[definition] = MaterialNode() # This is a list of information regarding the intermediate nodes: # nozzle -> buildplate nozzle_name = material_metadata.get("variant_name") buildplate_name = material_metadata.get("buildplate_name") intermediate_node_info_list = [(nozzle_name, VariantType.NOZZLE), (buildplate_name, VariantType.BUILD_PLATE), ] variant_manager = self._application.getVariantManager() machine_node = machine_nozzle_buildplate_material_map[definition] current_node = machine_node current_intermediate_node_info_idx = 0 error_message = None # type: Optional[str] while current_intermediate_node_info_idx < len(intermediate_node_info_list): variant_name, variant_type = intermediate_node_info_list[current_intermediate_node_info_idx] if variant_name is not None: # The new material has a specific variant, so it needs to be added to that specific branch in the tree. variant = variant_manager.getVariantNode(definition, variant_name, variant_type) if variant is None: error_message = "Material {id} contains a variant {name} that does not exist.".format( id = material_metadata["id"], name = variant_name) break # Update the current node to advance to a more specific branch if variant_name not in current_node.children_map: current_node.children_map[variant_name] = MaterialNode() current_node = current_node.children_map[variant_name] current_intermediate_node_info_idx += 1 if error_message is not None: Logger.log("e", "%s It will not be added into the material lookup tree.", error_message) self._container_registry.addWrongContainerId(material_metadata["id"]) return # Add the material to the current tree node, which is the deepest (the most specific) branch we can find. # Sanity check: Make sure that there is no duplicated materials. if root_material_id in current_node.material_map: Logger.log("e", "Duplicated material [%s] with root ID [%s]. It has already been added.", material_id, root_material_id) ConfigurationErrorMessage.getInstance().addFaultyContainers(root_material_id) return current_node.material_map[root_material_id] = MaterialNode(material_metadata)
def createMachine(cls, name: str, definition_id: str) -> Optional[GlobalStack]: from cura.CuraApplication import CuraApplication application = CuraApplication.getInstance() variant_manager = application.getVariantManager() quality_manager = application.getQualityManager() registry = application.getContainerRegistry() definitions = registry.findDefinitionContainers(id=definition_id) if not definitions: ConfigurationErrorMessage.getInstance().addFaultyContainers( definition_id) Logger.log("w", "Definition {definition} was not found!", definition=definition_id) return None machine_definition = definitions[0] # get variant container for the global stack global_variant_container = application.empty_variant_container global_variant_node = variant_manager.getDefaultVariantNode( machine_definition, VariantType.BUILD_PLATE) if global_variant_node: global_variant_container = global_variant_node.getContainer() if not global_variant_container: global_variant_container = application.empty_variant_container generated_name = registry.createUniqueName( "machine", "", name, machine_definition.getName()) # Make sure the new name does not collide with any definition or (quality) profile # createUniqueName() only looks at other stacks, but not at definitions or quality profiles # Note that we don't go for uniqueName() immediately because that function matches with ignore_case set to true if registry.findContainersMetadata(id=generated_name): generated_name = registry.uniqueName(generated_name) new_global_stack = cls.createGlobalStack( new_stack_id=generated_name, definition=machine_definition, variant_container=global_variant_container, material_container=application.empty_material_container, quality_container=application.empty_quality_container, ) new_global_stack.setName(generated_name) # Create ExtruderStacks extruder_dict = machine_definition.getMetaDataEntry( "machine_extruder_trains") for position in extruder_dict: cls.createExtruderStackWithDefaultSetup(new_global_stack, position) for new_extruder in new_global_stack.extruders.values( ): #Only register the extruders if we're sure that all of them are correct. registry.addContainer(new_extruder) preferred_quality_type = machine_definition.getMetaDataEntry( "preferred_quality_type") quality_group_dict = quality_manager.getQualityGroups(new_global_stack) if not quality_group_dict: # There is no available quality group, set all quality containers to empty. new_global_stack.quality = application.empty_quality_container for extruder_stack in new_global_stack.extruders.values(): extruder_stack.quality = application.empty_quality_container else: # Set the quality containers to the preferred quality type if available, otherwise use the first quality # type that's available. if preferred_quality_type not in quality_group_dict: Logger.log( "w", "The preferred quality {quality_type} doesn't exist for this set-up. Choosing a random one." .format(quality_type=preferred_quality_type)) preferred_quality_type = next(iter(quality_group_dict)) quality_group = quality_group_dict.get(preferred_quality_type) new_global_stack.quality = quality_group.node_for_global.getContainer( ) if not new_global_stack.quality: new_global_stack.quality = application.empty_quality_container for position, extruder_stack in new_global_stack.extruders.items(): if position in quality_group.nodes_for_extruders and quality_group.nodes_for_extruders[ position].getContainer(): extruder_stack.quality = quality_group.nodes_for_extruders[ position].getContainer() else: extruder_stack.quality = application.empty_quality_container # Register the global stack after the extruder stacks are created. This prevents the registry from adding another # extruder stack because the global stack didn't have one yet (which is enforced since Cura 3.1). registry.addContainer(new_global_stack) return new_global_stack
def createMachine(cls, name: str, definition_id: str) -> Optional[GlobalStack]: from cura.CuraApplication import CuraApplication application = CuraApplication.getInstance() variant_manager = application.getVariantManager() quality_manager = application.getQualityManager() registry = application.getContainerRegistry() definitions = registry.findDefinitionContainers(id = definition_id) if not definitions: ConfigurationErrorMessage.getInstance().addFaultyContainers(definition_id) Logger.log("w", "Definition {definition} was not found!", definition = definition_id) return None machine_definition = definitions[0] # get variant container for the global stack global_variant_container = application.empty_variant_container global_variant_node = variant_manager.getDefaultVariantNode(machine_definition, VariantType.BUILD_PLATE) if global_variant_node: global_variant_container = global_variant_node.getContainer() if not global_variant_container: global_variant_container = application.empty_variant_container generated_name = registry.createUniqueName("machine", "", name, machine_definition.getName()) # Make sure the new name does not collide with any definition or (quality) profile # createUniqueName() only looks at other stacks, but not at definitions or quality profiles # Note that we don't go for uniqueName() immediately because that function matches with ignore_case set to true if registry.findContainersMetadata(id = generated_name): generated_name = registry.uniqueName(generated_name) new_global_stack = cls.createGlobalStack( new_stack_id = generated_name, definition = machine_definition, variant_container = global_variant_container, material_container = application.empty_material_container, quality_container = application.empty_quality_container, ) new_global_stack.setName(generated_name) # Create ExtruderStacks extruder_dict = machine_definition.getMetaDataEntry("machine_extruder_trains") for position in extruder_dict: cls.createExtruderStackWithDefaultSetup(new_global_stack, position) for new_extruder in new_global_stack.extruders.values(): #Only register the extruders if we're sure that all of them are correct. registry.addContainer(new_extruder) preferred_quality_type = machine_definition.getMetaDataEntry("preferred_quality_type") quality_group_dict = quality_manager.getQualityGroups(new_global_stack) if not quality_group_dict: # There is no available quality group, set all quality containers to empty. new_global_stack.quality = application.empty_quality_container for extruder_stack in new_global_stack.extruders.values(): extruder_stack.quality = application.empty_quality_container else: # Set the quality containers to the preferred quality type if available, otherwise use the first quality # type that's available. if preferred_quality_type not in quality_group_dict: Logger.log("w", "The preferred quality {quality_type} doesn't exist for this set-up. Choosing a random one.".format(quality_type = preferred_quality_type)) preferred_quality_type = next(iter(quality_group_dict)) quality_group = quality_group_dict.get(preferred_quality_type) new_global_stack.quality = quality_group.node_for_global.getContainer() if not new_global_stack.quality: new_global_stack.quality = application.empty_quality_container for position, extruder_stack in new_global_stack.extruders.items(): if position in quality_group.nodes_for_extruders and quality_group.nodes_for_extruders[position].getContainer(): extruder_stack.quality = quality_group.nodes_for_extruders[position].getContainer() else: extruder_stack.quality = application.empty_quality_container # Register the global stack after the extruder stacks are created. This prevents the registry from adding another # extruder stack because the global stack didn't have one yet (which is enforced since Cura 3.1). registry.addContainer(new_global_stack) return new_global_stack
def initialize(self): # Find all materials and put them in a matrix for quick search. material_metadatas = {metadata["id"]: metadata for metadata in self._container_registry.findContainersMetadata(type = "material") if metadata.get("GUID")} self._material_group_map = dict() # Map #1 # root_material_id -> MaterialGroup for material_id, material_metadata in material_metadatas.items(): # We don't store empty material in the lookup tables if material_id == "empty_material": continue root_material_id = material_metadata.get("base_file") if root_material_id not in self._material_group_map: self._material_group_map[root_material_id] = MaterialGroup(root_material_id, MaterialNode(material_metadatas[root_material_id])) self._material_group_map[root_material_id].is_read_only = self._container_registry.isReadOnly(root_material_id) group = self._material_group_map[root_material_id] # Store this material in the group of the appropriate root material. if material_id != root_material_id: new_node = MaterialNode(material_metadata) group.derived_material_node_list.append(new_node) # Order this map alphabetically so it's easier to navigate in a debugger self._material_group_map = OrderedDict(sorted(self._material_group_map.items(), key = lambda x: x[0])) # Map #1.5 # GUID -> material group list self._guid_material_groups_map = defaultdict(list) for root_material_id, material_group in self._material_group_map.items(): guid = material_group.root_material_node.metadata["GUID"] self._guid_material_groups_map[guid].append(material_group) # Map #2 # Lookup table for material type -> fallback material metadata, only for read-only materials grouped_by_type_dict = dict() material_types_without_fallback = set() for root_material_id, material_node in self._material_group_map.items(): material_type = material_node.root_material_node.metadata["material"] if material_type not in grouped_by_type_dict: grouped_by_type_dict[material_type] = {"generic": None, "others": []} material_types_without_fallback.add(material_type) brand = material_node.root_material_node.metadata["brand"] if brand.lower() == "generic": to_add = True if material_type in grouped_by_type_dict: diameter = material_node.root_material_node.metadata.get("approximate_diameter") if diameter != self._default_approximate_diameter_for_quality_search: to_add = False # don't add if it's not the default diameter if to_add: # Checking this first allow us to differentiate between not read only materials: # - if it's in the list, it means that is a new material without fallback # - if it is not, then it is a custom material with a fallback material (parent) if material_type in material_types_without_fallback: grouped_by_type_dict[material_type] = material_node.root_material_node.metadata material_types_without_fallback.remove(material_type) # Remove the materials that have no fallback materials for material_type in material_types_without_fallback: del grouped_by_type_dict[material_type] self._fallback_materials_map = grouped_by_type_dict # Map #3 # There can be multiple material profiles for the same material with different diameters, such as "generic_pla" # and "generic_pla_175". This is inconvenient when we do material-specific quality lookup because a quality can # be for either "generic_pla" or "generic_pla_175", but not both. This map helps to get the correct material ID # for quality search. self._material_diameter_map = defaultdict(dict) self._diameter_material_map = dict() # Group the material IDs by the same name, material, brand, and color but with different diameters. material_group_dict = dict() keys_to_fetch = ("name", "material", "brand", "color") for root_material_id, machine_node in self._material_group_map.items(): root_material_metadata = machine_node.root_material_node.metadata key_data = [] for key in keys_to_fetch: key_data.append(root_material_metadata.get(key)) key_data = tuple(key_data) # If the key_data doesn't exist, it doesn't matter if the material is read only... if key_data not in material_group_dict: material_group_dict[key_data] = dict() else: # ...but if key_data exists, we just overwrite it if the material is read only, otherwise we skip it if not machine_node.is_read_only: continue approximate_diameter = root_material_metadata.get("approximate_diameter") material_group_dict[key_data][approximate_diameter] = root_material_metadata["id"] # Map [root_material_id][diameter] -> root_material_id for this diameter for data_dict in material_group_dict.values(): for root_material_id1 in data_dict.values(): if root_material_id1 in self._material_diameter_map: continue diameter_map = data_dict for root_material_id2 in data_dict.values(): self._material_diameter_map[root_material_id2] = diameter_map default_root_material_id = data_dict.get(self._default_approximate_diameter_for_quality_search) if default_root_material_id is None: default_root_material_id = list(data_dict.values())[0] # no default diameter present, just take "the" only one for root_material_id in data_dict.values(): self._diameter_material_map[root_material_id] = default_root_material_id # Map #4 # "machine" -> "variant_name" -> "root material ID" -> specific material InstanceContainer # Construct the "machine" -> "variant" -> "root material ID" -> specific material InstanceContainer self._diameter_machine_variant_material_map = dict() for material_metadata in material_metadatas.values(): # We don't store empty material in the lookup tables if material_metadata["id"] == "empty_material": continue root_material_id = material_metadata["base_file"] definition = material_metadata["definition"] approximate_diameter = material_metadata["approximate_diameter"] if approximate_diameter not in self._diameter_machine_variant_material_map: self._diameter_machine_variant_material_map[approximate_diameter] = {} machine_variant_material_map = self._diameter_machine_variant_material_map[approximate_diameter] if definition not in machine_variant_material_map: machine_variant_material_map[definition] = MaterialNode() machine_node = machine_variant_material_map[definition] variant_name = material_metadata.get("variant_name") if not variant_name: # if there is no variant, this material is for the machine, so put its metadata in the machine node. machine_node.material_map[root_material_id] = MaterialNode(material_metadata) else: # this material is variant-specific, so we save it in a variant-specific node under the # machine-specific node # Check first if the variant exist in the manager existing_variant = self._application.getVariantManager().getVariantNode(definition, variant_name) if existing_variant is not None: if variant_name not in machine_node.children_map: machine_node.children_map[variant_name] = MaterialNode() variant_node = machine_node.children_map[variant_name] if root_material_id in variant_node.material_map: # We shouldn't have duplicated variant-specific materials for the same machine. ConfigurationErrorMessage.getInstance().addFaultyContainers(root_material_id) continue variant_node.material_map[root_material_id] = MaterialNode(material_metadata) else: # Add this container id to the wrong containers list in the registry Logger.log("w", "Not adding {id} to the material manager because the variant does not exist.".format(id = material_metadata["id"])) self._container_registry.addWrongContainerId(material_metadata["id"]) self.materialsUpdated.emit()
def __addMaterialMetadataIntoLookupTree( self, material_metadata: Dict[str, Any]) -> None: material_id = material_metadata["id"] # We don't store empty material in the lookup tables if material_id == "empty_material": return root_material_id = material_metadata["base_file"] definition = material_metadata["definition"] approximate_diameter = material_metadata["approximate_diameter"] if approximate_diameter not in self._diameter_machine_nozzle_buildplate_material_map: self._diameter_machine_nozzle_buildplate_material_map[ approximate_diameter] = {} machine_nozzle_buildplate_material_map = self._diameter_machine_nozzle_buildplate_material_map[ approximate_diameter] if definition not in machine_nozzle_buildplate_material_map: machine_nozzle_buildplate_material_map[definition] = MaterialNode() # This is a list of information regarding the intermediate nodes: # nozzle -> buildplate nozzle_name = material_metadata.get("variant_name") buildplate_name = material_metadata.get("buildplate_name") intermediate_node_info_list = [ (nozzle_name, VariantType.NOZZLE), (buildplate_name, VariantType.BUILD_PLATE), ] variant_manager = self._application.getVariantManager() machine_node = machine_nozzle_buildplate_material_map[definition] current_node = machine_node current_intermediate_node_info_idx = 0 error_message = None # type: Optional[str] while current_intermediate_node_info_idx < len( intermediate_node_info_list): variant_name, variant_type = intermediate_node_info_list[ current_intermediate_node_info_idx] if variant_name is not None: # The new material has a specific variant, so it needs to be added to that specific branch in the tree. variant = variant_manager.getVariantNode( definition, variant_name, variant_type) if variant is None: error_message = "Material {id} contains a variant {name} that does not exist.".format( id=material_metadata["id"], name=variant_name) break # Update the current node to advance to a more specific branch if variant_name not in current_node.children_map: current_node.children_map[variant_name] = MaterialNode() current_node = current_node.children_map[variant_name] current_intermediate_node_info_idx += 1 if error_message is not None: Logger.log( "e", "%s It will not be added into the material lookup tree.", error_message) self._container_registry.addWrongContainerId( material_metadata["id"]) return # Add the material to the current tree node, which is the deepest (the most specific) branch we can find. # Sanity check: Make sure that there is no duplicated materials. if root_material_id in current_node.material_map: Logger.log( "e", "Duplicated material [%s] with root ID [%s]. It has already been added.", material_id, root_material_id) ConfigurationErrorMessage.getInstance().addFaultyContainers( root_material_id) return current_node.material_map[root_material_id] = MaterialNode( material_metadata)
def startSplashWindowPhase(self) -> None: super().startSplashWindowPhase() i18n_catalog = i18nCatalog("uranium") self.showSplashMessage( i18n_catalog.i18nc("@info:progress", "Initializing package manager...")) self._package_manager.initialize() # Read preferences here (upgrade won't work) to get the language in use, so the splash window can be shown in # the correct language. try: preferences_filename = Resources.getPath(Resources.Preferences, self._app_name + ".cfg") self._preferences.readFromFile(preferences_filename) except FileNotFoundError: Logger.log( "i", "Preferences file not found, ignore and use default language '%s'", self._default_language) signal.signal(signal.SIGINT, signal.SIG_DFL) # This is done here as a lot of plugins require a correct gl context. If you want to change the framework, # these checks need to be done in your <framework>Application.py class __init__(). self._configuration_error_message = ConfigurationErrorMessage( self, i18n_catalog.i18nc("@info:status", "Your configuration seems to be corrupt."), lifetime=0, title=i18n_catalog.i18nc("@info:title", "Configuration errors")) # Remove, install, and then loading plugins self.showSplashMessage( i18n_catalog.i18nc("@info:progress", "Loading plugins...")) # Remove and install the plugins that have been scheduled self._plugin_registry.initializeBeforePluginsAreLoaded() self._loadPlugins() self._plugin_registry.checkRequiredPlugins(self.getRequiredPlugins()) self.pluginsLoaded.emit() self.showSplashMessage( i18n_catalog.i18nc("@info:progress", "Updating configuration...")) with self._container_registry.lockFile(): VersionUpgradeManager.getInstance().upgrade() # Load preferences again because before we have loaded the plugins, we don't have the upgrade routine for # the preferences file. Now that we have, load the preferences file again so it can be upgraded and loaded. self.showSplashMessage( i18n_catalog.i18nc("@info:progress", "Loading preferences...")) try: preferences_filename = Resources.getPath(Resources.Preferences, self._app_name + ".cfg") with open(preferences_filename, "r", encoding="utf-8") as f: serialized = f.read() # This performs the upgrade for Preferences self._preferences.deserialize(serialized) self._preferences.setValue("general/plugins_to_remove", "") self._preferences.writeToFile(preferences_filename) except (FileNotFoundError, UnicodeDecodeError): Logger.log( "i", "The preferences file cannot be found or it is corrupted, so we will use default values" ) self.processEvents() # Force the configuration file to be written again since the list of plugins to remove maybe changed try: self._preferences_filename = Resources.getPath( Resources.Preferences, self._app_name + ".cfg") self._preferences.readFromFile(self._preferences_filename) except FileNotFoundError: Logger.log( "i", "The preferences file '%s' cannot be found, will use default values", self._preferences_filename) self._preferences_filename = Resources.getStoragePath( Resources.Preferences, self._app_name + ".cfg") # FIXME: This is done here because we now use "plugins.json" to manage plugins instead of the Preferences file, # but the PluginRegistry will still import data from the Preferences files if present, such as disabled plugins, # so we need to reset those values AFTER the Preferences file is loaded. self._plugin_registry.initializeAfterPluginsAreLoaded() # Check if we have just updated from an older version self._preferences.addPreference("general/last_run_version", "") last_run_version_str = self._preferences.getValue( "general/last_run_version") if not last_run_version_str: last_run_version_str = self._version last_run_version = Version(last_run_version_str) current_version = Version(self._version) if last_run_version < current_version: self._just_updated_from_old_version = True self._preferences.setValue("general/last_run_version", str(current_version)) self._preferences.writeToFile(self._preferences_filename) # Preferences: recent files self._preferences.addPreference("%s/recent_files" % self._app_name, "") file_names = self._preferences.getValue("%s/recent_files" % self._app_name).split(";") for file_name in file_names: if not os.path.isfile(file_name): continue self._recent_files.append(QUrl.fromLocalFile(file_name)) if not self.getIsHeadLess(): # Initialize System tray icon and make it invisible because it is used only to show pop up messages self._tray_icon = None if self._tray_icon_name: self._tray_icon = QIcon( Resources.getPath(Resources.Images, self._tray_icon_name)) self._tray_icon_widget = QSystemTrayIcon(self._tray_icon) self._tray_icon_widget.setVisible(False)
def initialize(self) -> None: # Initialize the lookup tree for quality profiles with following structure: # <machine> -> <nozzle> -> <buildplate> -> <material> # <machine> -> <material> self._machine_nozzle_buildplate_material_quality_type_to_quality_dict = { } # for quality lookup self._machine_quality_type_to_quality_changes_dict = { } # for quality_changes lookup quality_metadata_list = self._container_registry.findContainersMetadata( type="quality") for metadata in quality_metadata_list: if metadata["id"] == "empty_quality": continue definition_id = metadata["definition"] quality_type = metadata["quality_type"] root_material_id = metadata.get("material") nozzle_name = metadata.get("variant") buildplate_name = metadata.get("buildplate") is_global_quality = metadata.get("global_quality", False) is_global_quality = is_global_quality or ( root_material_id is None and nozzle_name is None and buildplate_name is None) # Sanity check: material+variant and is_global_quality cannot be present at the same time if is_global_quality and (root_material_id or nozzle_name): ConfigurationErrorMessage.getInstance().addFaultyContainers( metadata["id"]) continue if definition_id not in self._machine_nozzle_buildplate_material_quality_type_to_quality_dict: self._machine_nozzle_buildplate_material_quality_type_to_quality_dict[ definition_id] = QualityNode() machine_node = cast( QualityNode, self. _machine_nozzle_buildplate_material_quality_type_to_quality_dict[ definition_id]) if is_global_quality: # For global qualities, save data in the machine node machine_node.addQualityMetadata(quality_type, metadata) continue current_node = machine_node intermediate_node_info_list = [ nozzle_name, buildplate_name, root_material_id ] current_intermediate_node_info_idx = 0 while current_intermediate_node_info_idx < len( intermediate_node_info_list): node_name = intermediate_node_info_list[ current_intermediate_node_info_idx] if node_name is not None: # There is specific information, update the current node to go deeper so we can add this quality # at the most specific branch in the lookup tree. if node_name not in current_node.children_map: current_node.children_map[node_name] = QualityNode() current_node = cast(QualityNode, current_node.children_map[node_name]) current_intermediate_node_info_idx += 1 current_node.addQualityMetadata(quality_type, metadata) # Initialize the lookup tree for quality_changes profiles with following structure: # <machine> -> <quality_type> -> <name> quality_changes_metadata_list = self._container_registry.findContainersMetadata( type="quality_changes") for metadata in quality_changes_metadata_list: if metadata["id"] == "empty_quality_changes": continue machine_definition_id = metadata["definition"] quality_type = metadata["quality_type"] if machine_definition_id not in self._machine_quality_type_to_quality_changes_dict: self._machine_quality_type_to_quality_changes_dict[ machine_definition_id] = QualityNode() machine_node = self._machine_quality_type_to_quality_changes_dict[ machine_definition_id] machine_node.addQualityChangesMetadata(quality_type, metadata) Logger.log("d", "Lookup tables updated.") self.qualitiesUpdated.emit()
def initialize(self): # Find all materials and put them in a matrix for quick search. material_metadatas = { metadata["id"]: metadata for metadata in self._container_registry.findContainersMetadata( type="material") if metadata.get("GUID") } self._material_group_map = dict() # Map #1 # root_material_id -> MaterialGroup for material_id, material_metadata in material_metadatas.items(): # We don't store empty material in the lookup tables if material_id == "empty_material": continue root_material_id = material_metadata.get("base_file") if root_material_id not in self._material_group_map: self._material_group_map[root_material_id] = MaterialGroup( root_material_id, MaterialNode(material_metadatas[root_material_id])) self._material_group_map[ root_material_id].is_read_only = self._container_registry.isReadOnly( root_material_id) group = self._material_group_map[root_material_id] # Store this material in the group of the appropriate root material. if material_id != root_material_id: new_node = MaterialNode(material_metadata) group.derived_material_node_list.append(new_node) # Order this map alphabetically so it's easier to navigate in a debugger self._material_group_map = OrderedDict( sorted(self._material_group_map.items(), key=lambda x: x[0])) # Map #1.5 # GUID -> material group list self._guid_material_groups_map = defaultdict(list) for root_material_id, material_group in self._material_group_map.items( ): guid = material_group.root_material_node.metadata["GUID"] self._guid_material_groups_map[guid].append(material_group) # Map #2 # Lookup table for material type -> fallback material metadata, only for read-only materials grouped_by_type_dict = dict() material_types_without_fallback = set() for root_material_id, material_node in self._material_group_map.items( ): material_type = material_node.root_material_node.metadata[ "material"] if material_type not in grouped_by_type_dict: grouped_by_type_dict[material_type] = { "generic": None, "others": [] } material_types_without_fallback.add(material_type) brand = material_node.root_material_node.metadata["brand"] if brand.lower() == "generic": to_add = True if material_type in grouped_by_type_dict: diameter = material_node.root_material_node.metadata.get( "approximate_diameter") if diameter != self._default_approximate_diameter_for_quality_search: to_add = False # don't add if it's not the default diameter if to_add: # Checking this first allow us to differentiate between not read only materials: # - if it's in the list, it means that is a new material without fallback # - if it is not, then it is a custom material with a fallback material (parent) if material_type in material_types_without_fallback: grouped_by_type_dict[ material_type] = material_node.root_material_node.metadata material_types_without_fallback.remove(material_type) # Remove the materials that have no fallback materials for material_type in material_types_without_fallback: del grouped_by_type_dict[material_type] self._fallback_materials_map = grouped_by_type_dict # Map #3 # There can be multiple material profiles for the same material with different diameters, such as "generic_pla" # and "generic_pla_175". This is inconvenient when we do material-specific quality lookup because a quality can # be for either "generic_pla" or "generic_pla_175", but not both. This map helps to get the correct material ID # for quality search. self._material_diameter_map = defaultdict(dict) self._diameter_material_map = dict() # Group the material IDs by the same name, material, brand, and color but with different diameters. material_group_dict = dict() keys_to_fetch = ("name", "material", "brand", "color") for root_material_id, machine_node in self._material_group_map.items(): root_material_metadata = machine_node.root_material_node.metadata key_data = [] for key in keys_to_fetch: key_data.append(root_material_metadata.get(key)) key_data = tuple(key_data) # If the key_data doesn't exist, it doesn't matter if the material is read only... if key_data not in material_group_dict: material_group_dict[key_data] = dict() else: # ...but if key_data exists, we just overwrite it if the material is read only, otherwise we skip it if not machine_node.is_read_only: continue approximate_diameter = root_material_metadata.get( "approximate_diameter") material_group_dict[key_data][ approximate_diameter] = root_material_metadata["id"] # Map [root_material_id][diameter] -> root_material_id for this diameter for data_dict in material_group_dict.values(): for root_material_id1 in data_dict.values(): if root_material_id1 in self._material_diameter_map: continue diameter_map = data_dict for root_material_id2 in data_dict.values(): self._material_diameter_map[ root_material_id2] = diameter_map default_root_material_id = data_dict.get( self._default_approximate_diameter_for_quality_search) if default_root_material_id is None: default_root_material_id = list(data_dict.values())[ 0] # no default diameter present, just take "the" only one for root_material_id in data_dict.values(): self._diameter_material_map[ root_material_id] = default_root_material_id # Map #4 # "machine" -> "variant_name" -> "root material ID" -> specific material InstanceContainer # Construct the "machine" -> "variant" -> "root material ID" -> specific material InstanceContainer self._diameter_machine_variant_material_map = dict() for material_metadata in material_metadatas.values(): # We don't store empty material in the lookup tables if material_metadata["id"] == "empty_material": continue root_material_id = material_metadata["base_file"] definition = material_metadata["definition"] approximate_diameter = material_metadata["approximate_diameter"] if approximate_diameter not in self._diameter_machine_variant_material_map: self._diameter_machine_variant_material_map[ approximate_diameter] = {} machine_variant_material_map = self._diameter_machine_variant_material_map[ approximate_diameter] if definition not in machine_variant_material_map: machine_variant_material_map[definition] = MaterialNode() machine_node = machine_variant_material_map[definition] variant_name = material_metadata.get("variant_name") if not variant_name: # if there is no variant, this material is for the machine, so put its metadata in the machine node. machine_node.material_map[root_material_id] = MaterialNode( material_metadata) else: # this material is variant-specific, so we save it in a variant-specific node under the # machine-specific node # Check first if the variant exist in the manager existing_variant = self._application.getVariantManager( ).getVariantNode(definition, variant_name) if existing_variant is not None: if variant_name not in machine_node.children_map: machine_node.children_map[variant_name] = MaterialNode( ) variant_node = machine_node.children_map[variant_name] if root_material_id in variant_node.material_map: # We shouldn't have duplicated variant-specific materials for the same machine. ConfigurationErrorMessage.getInstance( ).addFaultyContainers(root_material_id) continue variant_node.material_map[root_material_id] = MaterialNode( material_metadata) else: # Add this container id to the wrong containers list in the registry Logger.log( "w", "Not adding {id} to the material manager because the variant does not exist." .format(id=material_metadata["id"])) self._container_registry.addWrongContainerId( material_metadata["id"]) self.materialsUpdated.emit()
def initialize(self) -> None: # Initialize the lookup tree for quality profiles with following structure: # <machine> -> <nozzle> -> <buildplate> -> <material> # <machine> -> <material> self._machine_nozzle_buildplate_material_quality_type_to_quality_dict = {} # for quality lookup self._machine_quality_type_to_quality_changes_dict = {} # for quality_changes lookup quality_metadata_list = self._container_registry.findContainersMetadata(type = "quality") for metadata in quality_metadata_list: if metadata["id"] == "empty_quality": continue definition_id = metadata["definition"] quality_type = metadata["quality_type"] root_material_id = metadata.get("material") nozzle_name = metadata.get("variant") buildplate_name = metadata.get("buildplate") is_global_quality = metadata.get("global_quality", False) is_global_quality = is_global_quality or (root_material_id is None and nozzle_name is None and buildplate_name is None) # Sanity check: material+variant and is_global_quality cannot be present at the same time if is_global_quality and (root_material_id or nozzle_name): ConfigurationErrorMessage.getInstance().addFaultyContainers(metadata["id"]) continue if definition_id not in self._machine_nozzle_buildplate_material_quality_type_to_quality_dict: self._machine_nozzle_buildplate_material_quality_type_to_quality_dict[definition_id] = QualityNode() machine_node = cast(QualityNode, self._machine_nozzle_buildplate_material_quality_type_to_quality_dict[definition_id]) if is_global_quality: # For global qualities, save data in the machine node machine_node.addQualityMetadata(quality_type, metadata) continue current_node = machine_node intermediate_node_info_list = [nozzle_name, buildplate_name, root_material_id] current_intermediate_node_info_idx = 0 while current_intermediate_node_info_idx < len(intermediate_node_info_list): node_name = intermediate_node_info_list[current_intermediate_node_info_idx] if node_name is not None: # There is specific information, update the current node to go deeper so we can add this quality # at the most specific branch in the lookup tree. if node_name not in current_node.children_map: current_node.children_map[node_name] = QualityNode() current_node = cast(QualityNode, current_node.children_map[node_name]) current_intermediate_node_info_idx += 1 current_node.addQualityMetadata(quality_type, metadata) # Initialize the lookup tree for quality_changes profiles with following structure: # <machine> -> <quality_type> -> <name> quality_changes_metadata_list = self._container_registry.findContainersMetadata(type = "quality_changes") for metadata in quality_changes_metadata_list: if metadata["id"] == "empty_quality_changes": continue machine_definition_id = metadata["definition"] quality_type = metadata["quality_type"] if machine_definition_id not in self._machine_quality_type_to_quality_changes_dict: self._machine_quality_type_to_quality_changes_dict[machine_definition_id] = QualityNode() machine_node = self._machine_quality_type_to_quality_changes_dict[machine_definition_id] machine_node.addQualityChangesMetadata(quality_type, metadata) Logger.log("d", "Lookup tables updated.") self.qualitiesUpdated.emit()