def exportProfile(self, instance_id, file_url, file_type): if not file_url.isValid(): return path = file_url.toLocalFile() if not path: return ContainerRegistry.getInstance().exportProfile(instance_id, path, file_type)
def findDefaultVariant(self) -> Optional[ContainerInterface]: definition = self._getMachineDefinition() # has_variants can be overridden in other containers and stacks. # In the case of UM2, it is overridden in the GlobalStack if not self.getMetaDataEntry("has_variants"): # If the machine does not use variants, we should never set a variant. return None # First add any variant. Later, overwrite with preference if the preference is valid. variant = None definition_id = self._findInstanceContainerDefinitionId(definition) variants = ContainerRegistry.getInstance().findInstanceContainers(definition = definition_id, type = "variant") if variants: variant = variants[0] preferred_variant_id = definition.getMetaDataEntry("preferred_variant") if preferred_variant_id: preferred_variants = ContainerRegistry.getInstance().findInstanceContainers(id = preferred_variant_id, definition = definition_id, type = "variant") if preferred_variants: variant = preferred_variants[0] else: Logger.log("w", "The preferred variant \"{variant}\" of stack {stack} does not exist or is not a variant.", variant = preferred_variant_id, stack = self.id) # And leave it at the default variant. if variant: return variant Logger.log("w", "Could not find a valid default variant for stack {stack}", stack = self.id) return None
def container_registry(application): MimeTypeDatabase.addMimeType( MimeType( name = "application/x-uranium-definitioncontainer", comment = "Uranium Definition Container", suffixes = ["def.json"] ) ) MimeTypeDatabase.addMimeType( MimeType( name = "application/x-uranium-instancecontainer", comment = "Uranium Instance Container", suffixes = [ "inst.cfg" ] ) ) MimeTypeDatabase.addMimeType( MimeType( name = "application/x-uranium-containerstack", comment = "Uranium Container Stack", suffixes = [ "stack.cfg" ] ) ) Resources.addSearchPath(os.path.realpath(os.path.join(os.path.dirname(__file__), "..", "..", "Settings"))) ContainerRegistry._ContainerRegistry__instance = None # Reset the private instance variable every time PluginRegistry.getInstance().removeType("settings_container") ContainerRegistry.getInstance().load() return ContainerRegistry.getInstance()
def container_registry(application, test_containers_provider, plugin_registry: PluginRegistry): MimeTypeDatabase.addMimeType( MimeType( name = "application/x-uranium-definitioncontainer", comment = "Uranium Definition Container", suffixes = ["def.json"] ) ) MimeTypeDatabase.addMimeType( MimeType( name = "application/x-uranium-instancecontainer", comment = "Uranium Instance Container", suffixes = [ "inst.cfg" ] ) ) MimeTypeDatabase.addMimeType( MimeType( name = "application/x-uranium-containerstack", comment = "Uranium Container Stack", suffixes = [ "stack.cfg" ] ) ) ContainerRegistry._ContainerRegistry__instance = None # Reset the private instance variable every time registry = ContainerRegistry(application) #We need to mock the "priority" plug-in metadata field, but preferably without mocking an entire plug-in. with unittest.mock.patch("UM.PluginRegistry.PluginRegistry.getMetaData", unittest.mock.MagicMock(return_value = {"container_provider": {}})): registry.addProvider(test_containers_provider) UM.Settings.ContainerStack.setContainerRegistry(registry) UM.Settings.InstanceContainer.setContainerRegistry(registry) return registry
def _getBasicMaterialMetadatas(self, material_container: Dict[str, Any]) -> List[Dict[str, Any]]: if "definition" not in material_container: definition_id = "fdmprinter" else: material_container_definition = ContainerRegistry.getInstance().findDefinitionContainersMetadata(id = material_container["definition"]) if not material_container_definition: definition_id = "fdmprinter" else: material_container_definition = material_container_definition[0] if "has_machine_quality" not in material_container_definition: definition_id = "fdmprinter" else: definition_id = material_container_definition.get("quality_definition", material_container_definition["id"]) base_material = material_container.get("material") if base_material: # There is a basic material specified criteria = { "type": "material", "name": base_material, "definition": definition_id, "variant": material_container.get("variant") } containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(**criteria) return containers return []
def _writeContainerToArchive(container, archive): if type(container) == type(ContainerRegistry.getInstance().getEmptyInstanceContainer()): return # Empty file, do nothing. file_suffix = ContainerRegistry.getMimeTypeForContainer(type(container)).preferredSuffix # Some containers have a base file, which should then be the file to use. if "base_file" in container.getMetaData(): base_file = container.getMetaDataEntry("base_file") container = ContainerRegistry.getInstance().findContainers(id = base_file)[0] file_name = "Cura/%s.%s" % (container.getId(), file_suffix) if file_name in archive.namelist(): return # File was already saved, no need to do it again. Uranium guarantees unique ID's, so this should hold. file_in_archive = zipfile.ZipInfo(file_name) # For some reason we have to set the compress type of each file as well (it doesn't keep the type of the entire archive) file_in_archive.compress_type = zipfile.ZIP_DEFLATED if type(container) == ContainerStack and (container.getMetaDataEntry("network_authentication_id") or container.getMetaDataEntry("network_authentication_key")): # TODO: Hack # Create a shallow copy of the container, so we can filter out the network auth (if any) container_copy = copy.deepcopy(container) container_copy.removeMetaDataEntry("network_authentication_id") container_copy.removeMetaDataEntry("network_authentication_key") serialized_data = container_copy.serialize() else: serialized_data = container.serialize() archive.writestr(file_in_archive, serialized_data)
def createExtruderStack(cls, new_stack_id: str, extruder_definition: DefinitionContainerInterface, machine_definition_id: str, position: int, variant_container, material_container, quality_container, global_stack) -> ExtruderStack: from cura.CuraApplication import CuraApplication application = CuraApplication.getInstance() stack = ExtruderStack(new_stack_id, parent = global_stack) stack.setName(extruder_definition.getName()) stack.setDefinition(extruder_definition) stack.addMetaDataEntry("position", position) user_container = cls.createUserChangesContainer(new_stack_id + "_user", machine_definition_id, new_stack_id, is_global_stack = False) stack.definitionChanges = cls.createDefinitionChangesContainer(stack, new_stack_id + "_settings") stack.variant = variant_container stack.material = material_container stack.quality = quality_container stack.qualityChanges = application.empty_quality_changes_container stack.userChanges = user_container # Only add the created containers to the registry after we have set all the other # properties. This makes the create operation more transactional, since any problems # setting properties will not result in incomplete containers being added. ContainerRegistry.getInstance().addContainer(user_container) return stack
def setHasVariants(self, has_variants = True): global_container_stack = Application.getInstance().getGlobalContainerStack() if global_container_stack: variant_container = global_container_stack.extruders["0"].variant if has_variants: global_container_stack.setMetaDataEntry("has_variants", True) # Set the variant container to a sane default empty_container = ContainerRegistry.getInstance().getEmptyInstanceContainer() if type(variant_container) == type(empty_container): search_criteria = { "type": "variant", "definition": "ultimaker2", "id": "*0.4*" } containers = self._container_registry.findInstanceContainers(**search_criteria) if containers: global_container_stack.extruders["0"].variant = containers[0] else: # The metadata entry is stored in an ini, and ini files are parsed as strings only. # Because any non-empty string evaluates to a boolean True, we have to remove the entry to make it False. if "has_variants" in global_container_stack.getMetaData(): global_container_stack.removeMetaDataEntry("has_variants") # Set the variant container to an empty variant global_container_stack.extruders["0"].variant = ContainerRegistry.getInstance().getEmptyInstanceContainer() Application.getInstance().globalContainerStackChanged.emit() self._reset()
def __init__(self): super().__init__() self._settings = None self._stack = None setting_data = self.getSettingData() self._stack = ContainerStack(stack_id=id(self)) self._stack.setDirty(False) # This stack does not need to be saved. ## Check if the definition of this script already exists. If not, add it to the registry. if "key" in setting_data: definitions = ContainerRegistry.getInstance().findDefinitionContainers(id = setting_data["key"]) if definitions: # Definition was found self._definition = definitions[0] else: self._definition = DefinitionContainer(setting_data["key"]) self._definition.deserialize(json.dumps(setting_data)) ContainerRegistry.getInstance().addContainer(self._definition) self._stack.addContainer(self._definition) self._instance = InstanceContainer(container_id="ScriptInstanceContainer") self._instance.setDefinition(self._definition) self._stack.addContainer(self._instance) ContainerRegistry.getInstance().addContainer(self._stack)
def container_registry(application): MimeTypeDatabase.addMimeType( MimeType( name = "application/x-uranium-definitioncontainer", comment = "Uranium Definition Container", suffixes = ["def.json"] ) ) MimeTypeDatabase.addMimeType( MimeType( name = "application/x-uranium-instancecontainer", comment = "Uranium Instance Container", suffixes = [ "inst.cfg" ] ) ) MimeTypeDatabase.addMimeType( MimeType( name = "application/x-uranium-containerstack", comment = "Uranium Container Stack", suffixes = [ "stack.cfg" ] ) ) Resources.addSearchPath(os.path.dirname(os.path.abspath(__file__))) ContainerRegistry._ContainerRegistry__instance = None # Reset the private instance variable every time ContainerRegistry.setApplication(application) UM.Settings.ContainerStack.setContainerRegistry(ContainerRegistry.getInstance()) UM.Settings.InstanceContainer.setContainerRegistry(ContainerRegistry.getInstance()) return ContainerRegistry.getInstance()
def _reloadExtruders(self): self._extruderDefinitions = [] self._nozzles = {} self._extruderTrains = [] global_container_stack = Application.getInstance().getGlobalContainerStack() if not global_container_stack: #No machine has been added yet. return #Then leave them empty! #Fill the list of extruder trains. machine = global_container_stack.getBottom() extruder_train_ids = machine.getMetaData("machine_extruder_trains") for extruder_train_id in extruder_train_ids: extruders = ContainerRegistry.getInstance().findDefinitionContainers(id = extruder_train_id) #Should be only 1 definition if IDs are unique, but add the whole list anyway. if not extruders: #Empty list or error. Logger.log("w", "Machine definition %s refers to an extruder train \"%s\", but no such extruder was found.", machine.getId(), extruder_train_id) continue self._extruderDefinitions += extruders #Fill the nozzles for each of the extruder trains. for extruder in self._extruderDefinitions: self._nozzles[extruder.id] = [] all_nozzles = ContainerRegistry.getInstance().findInstanceContainers(type="nozzle") for nozzle in all_nozzles: extruders = nozzle.getMetaDataEntry("definitions").split(",").strip() for extruder_id in extruders: self._nozzles[extruder_id] = nozzle #Create the extruder train container stacks. for extruder in self._extruderDefinitions: self._extruderTrains.append(self._createContainerStack(extruder))
def _writeContainerToArchive(container, archive): if isinstance(container, type(ContainerRegistry.getInstance().getEmptyInstanceContainer())): return # Empty file, do nothing. file_suffix = ContainerRegistry.getMimeTypeForContainer(type(container)).preferredSuffix # Some containers have a base file, which should then be the file to use. if "base_file" in container.getMetaData(): base_file = container.getMetaDataEntry("base_file") container = ContainerRegistry.getInstance().findContainers(id = base_file)[0] file_name = "Cura/%s.%s" % (container.getId(), file_suffix) if file_name in archive.namelist(): return # File was already saved, no need to do it again. Uranium guarantees unique ID's, so this should hold. file_in_archive = zipfile.ZipInfo(file_name) # For some reason we have to set the compress type of each file as well (it doesn't keep the type of the entire archive) file_in_archive.compress_type = zipfile.ZIP_DEFLATED # Do not include the network authentication keys ignore_keys = {"network_authentication_id", "network_authentication_key"} serialized_data = container.serialize(ignored_metadata_keys = ignore_keys) archive.writestr(file_in_archive, serialized_data)
def initialize(self) -> None: setting_data = self.getSettingData() self._stack = ContainerStack(stack_id=str(id(self))) self._stack.setDirty(False) # This stack does not need to be saved. ## Check if the definition of this script already exists. If not, add it to the registry. if "key" in setting_data: definitions = ContainerRegistry.getInstance().findDefinitionContainers(id=setting_data["key"]) if definitions: # Definition was found self._definition = definitions[0] else: self._definition = DefinitionContainer(setting_data["key"]) try: self._definition.deserialize(json.dumps(setting_data)) ContainerRegistry.getInstance().addContainer(self._definition) except ContainerFormatError: self._definition = None return if self._definition is None: return self._stack.addContainer(self._definition) self._instance = InstanceContainer(container_id="ScriptInstanceContainer") self._instance.setDefinition(self._definition.getId()) self._instance.setMetaDataEntry("setting_version", self._definition.getMetaDataEntry("setting_version", default=0)) self._stack.addContainer(self._instance) self._stack.propertyChanged.connect(self._onPropertyChanged) ContainerRegistry.getInstance().addContainer(self._stack)
def importProfile(self, file_name): if not file_name: return { "status": "error", "message": catalog.i18nc("@info:status", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, "Invalid path")} plugin_registry = PluginRegistry.getInstance() for plugin_id, meta_data in self._getIOPlugins("profile_reader"): profile_reader = plugin_registry.getPluginObject(plugin_id) try: profile = profile_reader.read(file_name) #Try to open the file with the profile reader. except Exception as e: #Note that this will fail quickly. That is, if any profile reader throws an exception, it will stop reading. It will only continue reading if the reader returned None. Logger.log("e", "Failed to import profile from %s: %s", file_name, str(e)) return { "status": "error", "message": catalog.i18nc("@info:status", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, str(e))} if profile: #Success! profile.setReadOnly(False) new_name = self.createUniqueName("quality", "", os.path.splitext(os.path.basename(file_name))[0], catalog.i18nc("@label", "Custom profile")) profile.setName(new_name) profile._id = new_name if self._machineHasOwnQualities(): profile.setDefinition(self._activeDefinition()) if self._machineHasOwnMaterials(): profile.addMetaDataEntry("material", self._activeMaterialId()) else: profile.setDefinition(ContainerRegistry.getInstance().findDefinitionContainers(id="fdmprinter")[0]) ContainerRegistry.getInstance().addContainer(profile) return { "status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile.getName()) } #If it hasn't returned by now, none of the plugins loaded the profile successfully. return { "status": "error", "message": catalog.i18nc("@info:status", "Profile {0} has an unknown file type.", file_name)}
def saveSettings(self): if not self._started: # Do not do saving during application start return for instance in ContainerRegistry.getInstance().findInstanceContainers(): if not instance.isDirty(): continue try: data = instance.serialize() except NotImplementedError: continue except Exception: Logger.logException("e", "An exception occurred when serializing container %s", instance.getId()) continue mime_type = ContainerRegistry.getMimeTypeForContainer(type(instance)) file_name = urllib.parse.quote_plus(instance.getId()) + "." + mime_type.preferredSuffix instance_type = instance.getMetaDataEntry("type") path = None if instance_type == "material": path = Resources.getStoragePath(self.ResourceTypes.MaterialInstanceContainer, file_name) elif instance_type == "quality" or instance_type == "quality_changes": path = Resources.getStoragePath(self.ResourceTypes.QualityInstanceContainer, file_name) elif instance_type == "user": path = Resources.getStoragePath(self.ResourceTypes.UserInstanceContainer, file_name) elif instance_type == "variant": path = Resources.getStoragePath(self.ResourceTypes.VariantInstanceContainer, file_name) if path: instance.setPath(path) with SaveFile(path, "wt", -1, "utf-8") as f: f.write(data) for stack in ContainerRegistry.getInstance().findContainerStacks(): if not stack.isDirty(): continue try: data = stack.serialize() except NotImplementedError: continue except Exception: Logger.logException("e", "An exception occurred when serializing container %s", instance.getId()) continue mime_type = ContainerRegistry.getMimeTypeForContainer(type(stack)) file_name = urllib.parse.quote_plus(stack.getId()) + "." + mime_type.preferredSuffix stack_type = stack.getMetaDataEntry("type", None) path = None if not stack_type or stack_type == "machine": path = Resources.getStoragePath(self.ResourceTypes.MachineStack, file_name) elif stack_type == "extruder_train": path = Resources.getStoragePath(self.ResourceTypes.ExtruderStack, file_name) if path: stack.setPath(path) with SaveFile(path, "wt", -1, "utf-8") as f: f.write(data)
def __init__(self) -> None: super().__init__("UpgradeFirmware", catalog.i18nc("@action", "Update Firmware")) self._qml_url = "FirmwareUpdaterMachineAction.qml" ContainerRegistry.getInstance().containerAdded.connect(self._onContainerAdded) self._active_output_device = None # type: Optional[PrinterOutputDevice] self._active_firmware_updater = None # type: Optional[FirmwareUpdater] CuraApplication.getInstance().engineCreatedSignal.connect(self._onEngineCreated)
def exportProfile(self, instance_ids, file_name, file_type): # Parse the fileType to deduce what plugin can save the file format. # fileType has the format "<description> (*.<extension>)" split = file_type.rfind(" (*.") # Find where the description ends and the extension starts. if split < 0: # Not found. Invalid format. Logger.log("e", "Invalid file format identifier %s", file_type) return description = file_type[:split] extension = file_type[split + 4:-1] # Leave out the " (*." and ")". if not file_name.endswith("." + extension): # Auto-fill the extension if the user did not provide any. file_name += "." + extension # On Windows, QML FileDialog properly asks for overwrite confirm, but not on other platforms, so handle those ourself. if not Platform.isWindows(): if os.path.exists(file_name): result = QMessageBox.question(None, catalog.i18nc("@title:window", "File Already Exists"), catalog.i18nc("@label", "The file <filename>{0}</filename> already exists. Are you sure you want to overwrite it?").format(file_name)) if result == QMessageBox.No: return found_containers = [] extruder_positions = [] for instance_id in instance_ids: containers = ContainerRegistry.getInstance().findInstanceContainers(id=instance_id) if containers: found_containers.append(containers[0]) # Determine the position of the extruder of this container extruder_id = containers[0].getMetaDataEntry("extruder", "") if extruder_id == "": # Global stack extruder_positions.append(-1) else: extruder_containers = ContainerRegistry.getInstance().findDefinitionContainers(id=extruder_id) if extruder_containers: extruder_positions.append(int(extruder_containers[0].getMetaDataEntry("position", 0))) else: extruder_positions.append(0) # Ensure the profiles are always exported in order (global, extruder 0, extruder 1, ...) found_containers = [containers for (positions, containers) in sorted(zip(extruder_positions, found_containers))] profile_writer = self._findProfileWriter(extension, description) try: success = profile_writer.write(file_name, found_containers) except Exception as e: Logger.log("e", "Failed to export profile to %s: %s", file_name, str(e)) m = Message(catalog.i18nc("@info:status", "Failed to export profile to <filename>{0}</filename>: <message>{1}</message>", file_name, str(e)), lifetime = 0) m.show() return if not success: Logger.log("w", "Failed to export profile to %s: Writer plugin reported failure.", file_name) m = Message(catalog.i18nc("@info:status", "Failed to export profile to <filename>{0}</filename>: Writer plugin reported failure.", file_name), lifetime = 0) m.show() return m = Message(catalog.i18nc("@info:status", "Exported profile to <filename>{0}</filename>", file_name)) m.show()
def __init__(self): super().__init__() self._stack = ContainerStack(stack_id = id(self)) self._instance = InstanceContainer(container_id = "SettingOverrideInstanceContainer") self._stack.addContainer(self._instance) ContainerRegistry.getInstance().addContainer(self._stack) Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerStackChanged) self._onGlobalContainerStackChanged()
def _configureProfile(self, profile: InstanceContainer, id_seed: str, new_name: str) -> Optional[str]: profile.setDirty(True) # Ensure the profiles are correctly saved new_id = self.createUniqueName("quality_changes", "", id_seed, catalog.i18nc("@label", "Custom profile")) profile._id = new_id profile.setName(new_name) if "type" in profile.getMetaData(): profile.setMetaDataEntry("type", "quality_changes") else: profile.addMetaDataEntry("type", "quality_changes") quality_type = profile.getMetaDataEntry("quality_type") if not quality_type: return catalog.i18nc("@info:status", "Profile is missing a quality type.") quality_type_criteria = {"quality_type": quality_type} if self._machineHasOwnQualities(): profile.setDefinition(self._activeQualityDefinition().getId()) if self._machineHasOwnMaterials(): active_material_id = self._activeMaterialId() if active_material_id and active_material_id != "empty": # only update if there is an active material profile.addMetaDataEntry("material", active_material_id) quality_type_criteria["material"] = active_material_id quality_type_criteria["definition"] = profile.getDefinition().getId() else: profile.setDefinition(fdmprinter) quality_type_criteria["definition"] = "fdmprinter" machine_definition = Application.getInstance().getGlobalContainerStack().getBottom() del quality_type_criteria["definition"] # materials = None if "material" in quality_type_criteria: # materials = ContainerRegistry.getInstance().findInstanceContainers(id = quality_type_criteria["material"]) del quality_type_criteria["material"] # Do not filter quality containers here with materials because we are trying to import a profile, so it should # NOT be restricted by the active materials on the current machine. materials = None # Check to make sure the imported profile actually makes sense in context of the current configuration. # This prevents issues where importing a "draft" profile for a machine without "draft" qualities would report as # successfully imported but then fail to show up. from cura.QualityManager import QualityManager qualities = QualityManager.getInstance()._getFilteredContainersForStack(machine_definition, materials, **quality_type_criteria) if not qualities: return catalog.i18nc("@info:status", "Could not find a quality type {0} for the current configuration.", quality_type) ContainerRegistry.getInstance().addContainer(profile) return None
def _updatePrinter(self, printer: PrinterOutputModel, data: Dict) -> None: # For some unknown reason the cluster wants UUID for everything, except for sending a job directly to a printer. # Then we suddenly need the unique name. So in order to not have to mess up all the other code, we save a mapping. self._printer_uuid_to_unique_name_mapping[data["uuid"]] = data["unique_name"] definitions = ContainerRegistry.getInstance().findDefinitionContainers(name = data["machine_variant"]) if not definitions: Logger.log("w", "Unable to find definition for machine variant %s", data["machine_variant"]) return machine_definition = definitions[0] printer.updateName(data["friendly_name"]) printer.updateKey(data["uuid"]) printer.updateType(data["machine_variant"]) # Do not store the buildplate information that comes from connect if the current printer has not buildplate information if "build_plate" in data and machine_definition.getMetaDataEntry("has_variant_buildplates", False): printer.updateBuildplateName(data["build_plate"]["type"]) if not data["enabled"]: printer.updateState("disabled") else: printer.updateState(data["status"]) for index in range(0, self._number_of_extruders): extruder = printer.extruders[index] try: extruder_data = data["configuration"][index] except IndexError: break extruder.updateHotendID(extruder_data.get("print_core_id", "")) material_data = extruder_data["material"] if extruder.activeMaterial is None or extruder.activeMaterial.guid != material_data["guid"]: containers = ContainerRegistry.getInstance().findInstanceContainers(type="material", GUID=material_data["guid"]) if containers: color = containers[0].getMetaDataEntry("color_code") brand = containers[0].getMetaDataEntry("brand") material_type = containers[0].getMetaDataEntry("material") name = containers[0].getName() else: Logger.log("w", "Unable to find material with guid {guid}. Using data as provided by cluster".format( guid=material_data["guid"])) color = material_data["color"] brand = material_data["brand"] material_type = material_data["material"] name = "Empty" if material_data["material"] == "empty" else "Unknown" material = MaterialOutputModel(guid=material_data["guid"], type=material_type, brand=brand, color=color, name=name) extruder.updateActiveMaterial(material)
def __init__(self) -> None: super().__init__() # Listen to a Signal that indicates a change in the list of printers, just if the user has enabled the # "check for updates" option Application.getInstance().getPreferences().addPreference("info/automatic_update_check", True) if Application.getInstance().getPreferences().getValue("info/automatic_update_check"): ContainerRegistry.getInstance().containerAdded.connect(self._onContainerAdded) self._check_job = None self._checked_printer_names = set() # type: Set[str]
def __init__(self, parent = None): super().__init__(parent) self.addRoleName(self.NameRole, "name") self.addRoleName(self.IdRole, "id") self.addRoleName(self.MetaDataRole, "metadata") self._container_stacks = [] # Listen to changes ContainerRegistry.getInstance().containerAdded.connect(self._onContainerChanged) ContainerRegistry.getInstance().containerRemoved.connect(self._onContainerChanged) self._filter_dict = {} self._update()
def _recomputeItems(self): #Some globals that we can re-use. global_container_stack = Application.getInstance().getGlobalContainerStack() if global_container_stack is None: return container_registry = ContainerRegistry.getInstance() machine_manager = Application.getInstance().getMachineManager() unit = global_container_stack.getBottom().getProperty("layer_height", "unit") if not unit: unit = "" for item in super()._recomputeItems(): profile = container_registry.findContainers(id = item["id"]) if not profile: item["layer_height"] = "" #Can't update a profile that is unknown. yield item continue #Easy case: This profile defines its own layer height. profile = profile[0] if profile.hasProperty("layer_height", "value"): item["layer_height"] = str(profile.getProperty("layer_height", "value")) + unit yield item continue #Quality-changes profile that has no value for layer height. Get the corresponding quality profile and ask that profile. quality_type = profile.getMetaDataEntry("quality_type", None) if quality_type: quality_results = machine_manager.determineQualityAndQualityChangesForQualityType(quality_type) for quality_result in quality_results: if quality_result["stack"] is global_container_stack: quality = quality_result["quality"] break else: #No global container stack in the results: if quality_results: quality = quality_results[0]["quality"] #Take any of the extruders. else: quality = None if quality and quality.hasProperty("layer_height", "value"): item["layer_height"] = str(quality.getProperty("layer_height", "value")) + unit yield item continue #Quality has no value for layer height either. Get the layer height from somewhere lower in the stack. skip_until_container = global_container_stack.material if not skip_until_container or skip_until_container == ContainerRegistry.getInstance().getEmptyInstanceContainer(): #No material in stack. skip_until_container = global_container_stack.variant if not skip_until_container or skip_until_container == ContainerRegistry.getInstance().getEmptyInstanceContainer(): #No variant in stack. skip_until_container = global_container_stack.getBottom() item["layer_height"] = str(global_container_stack.getRawProperty("layer_height", "value", skip_until_container = skip_until_container.getId())) + unit #Fall through to the currently loaded material. yield item
def _getFilteredContainersForStack(self, machine_definition: "DefinitionContainerInterface" = None, material_containers: List[InstanceContainer] = None, **kwargs): # Fill in any default values. if machine_definition is None: machine_definition = Application.getInstance().getGlobalContainerStack().getBottom() quality_definition_id = machine_definition.getMetaDataEntry("quality_definition") if quality_definition_id is not None: machine_definition = ContainerRegistry.getInstance().findDefinitionContainers(id=quality_definition_id)[0] # for convenience if material_containers is None: material_containers = [] if not material_containers: active_stacks = ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks() if active_stacks: material_containers = [stack.material for stack in active_stacks] criteria = kwargs filter_by_material = False machine_definition = self.getParentMachineDefinition(machine_definition) criteria["definition"] = machine_definition.getId() found_containers_with_machine_definition = ContainerRegistry.getInstance().findInstanceContainers(**criteria) whole_machine_definition = self.getWholeMachineDefinition(machine_definition) if whole_machine_definition.getMetaDataEntry("has_machine_quality"): definition_id = machine_definition.getMetaDataEntry("quality_definition", whole_machine_definition.getId()) criteria["definition"] = definition_id filter_by_material = whole_machine_definition.getMetaDataEntry("has_materials") # only fall back to "fdmprinter" when there is no container for this machine elif not found_containers_with_machine_definition: criteria["definition"] = "fdmprinter" # Stick the material IDs in a set material_ids = set() for material_instance in material_containers: if material_instance is not None: # Add the parent material too. for basic_material in self._getBasicMaterials(material_instance): material_ids.add(basic_material.getId()) material_ids.add(material_instance.getId()) containers = ContainerRegistry.getInstance().findInstanceContainers(**criteria) result = [] for container in containers: # If the machine specifies we should filter by material, exclude containers that do not match any active material. if filter_by_material and container.getMetaDataEntry("material") not in material_ids and "global_quality" not in kwargs: continue result.append(container) return result
def __init__(self): super().__init__() self._stack = ContainerStack(stack_id = id(self)) self._stack.setDirty(False) # This stack does not need to be saved. self._instance = InstanceContainer(container_id = "SettingOverrideInstanceContainer") self._stack.addContainer(self._instance) self._stack.propertyChanged.connect(self._onSettingChanged) ContainerRegistry.getInstance().addContainer(self._stack) Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerStackChanged) self._onGlobalContainerStackChanged()
def __init__(self): super().__init__() self._stack = PerObjectContainerStack(stack_id = id(self)) self._stack.setDirty(False) # This stack does not need to be saved. self._stack.addContainer(InstanceContainer(container_id = "SettingOverrideInstanceContainer")) self._extruder_stack = ExtruderManager.getInstance().getExtruderStack(0).getId() self._stack.propertyChanged.connect(self._onSettingChanged) ContainerRegistry.getInstance().addContainer(self._stack) Application.getInstance().globalContainerStackChanged.connect(self._updateNextStack) self.activeExtruderChanged.connect(self._updateNextStack) self._updateNextStack()
def __init__(self): super().__init__() # Initialize the Preference called `latest_checked_firmware` that stores the last version # checked for the UM3. In the future if we need to check other printers' firmware Preferences.getInstance().addPreference("info/latest_checked_firmware", "") # Listen to a Signal that indicates a change in the list of printers, just if the user has enabled the # 'check for updates' option Preferences.getInstance().addPreference("info/automatic_update_check", True) if Preferences.getInstance().getValue("info/automatic_update_check"): ContainerRegistry.getInstance().containerAdded.connect(self._onContainerAdded) self._download_url = None
def createDefinitionChangesContainer(cls, container_stack, container_name): from cura.CuraApplication import CuraApplication unique_container_name = ContainerRegistry.getInstance().uniqueName(container_name) definition_changes_container = InstanceContainer(unique_container_name) definition_changes_container.setDefinition(container_stack.getBottom().getId()) definition_changes_container.addMetaDataEntry("type", "definition_changes") definition_changes_container.addMetaDataEntry("setting_version", CuraApplication.SettingVersion) ContainerRegistry.getInstance().addContainer(definition_changes_container) container_stack.definitionChanges = definition_changes_container return definition_changes_container
def _configureProfile(self, profile, name_seed): profile.setReadOnly(False) new_name = self.createUniqueName("quality", "", name_seed, catalog.i18nc("@label", "Custom profile")) profile.setName(new_name) profile._id = new_name if self._machineHasOwnQualities(): profile.setDefinition(self._activeDefinition()) if self._machineHasOwnMaterials(): profile.addMetaDataEntry("material", self._activeMaterialId()) else: profile.setDefinition(ContainerRegistry.getInstance().findDefinitionContainers(id="fdmprinter")[0]) ContainerRegistry.getInstance().addContainer(profile)
def __init__(self): super().__init__() self._supported_extensions = [".3mf"] self._dialog = WorkspaceDialog() self._3mf_mesh_reader = None self._container_registry = ContainerRegistry.getInstance() self._definition_container_suffix = ContainerRegistry.getMimeTypeForContainer(DefinitionContainer).preferredSuffix self._material_container_suffix = None # We have to wait until all other plugins are loaded before we can set it self._instance_container_suffix = ContainerRegistry.getMimeTypeForContainer(InstanceContainer).preferredSuffix self._container_stack_suffix = ContainerRegistry.getMimeTypeForContainer(ContainerStack).preferredSuffix self._resolve_strategies = {} self._id_mapping = {}
def __init__(self, parent=None): super().__init__(parent) self.addRoleName(self.NameRole, "name") self.addRoleName(self.IdRole, "id") self.addRoleName(self.HasRemoteConnectionRole, "hasRemoteConnection") self.addRoleName(self.ConnectionTypeRole, "connectionType") self.addRoleName(self.MetaDataRole, "metadata") self._container_stacks = [] # Listen to changes ContainerRegistry.getInstance().containerAdded.connect( self._onContainerChanged) ContainerRegistry.getInstance().containerMetaDataChanged.connect( self._onContainerChanged) ContainerRegistry.getInstance().containerRemoved.connect( self._onContainerChanged) self._filter_dict = {} self._update()
def _fixSingleExtrusionMachineExtruderDefinition( self, global_stack: "GlobalStack") -> None: container_registry = ContainerRegistry.getInstance() expected_extruder_definition_0_id = global_stack.getMetaDataEntry( "machine_extruder_trains")["0"] extruder_stack_0 = global_stack.extruders.get("0") # At this point, extruder stacks for this machine may not have been loaded yet. In this case, need to look in # the container registry as well. if not global_stack.extruders: extruder_trains = container_registry.findContainerStacks( type="extruder_train", machine=global_stack.getId()) if extruder_trains: for extruder in extruder_trains: if extruder.getMetaDataEntry("position") == "0": extruder_stack_0 = extruder break if extruder_stack_0 is None: Logger.log("i", "No extruder stack for global stack [%s], create one", global_stack.getId()) # Single extrusion machine without an ExtruderStack, create it from steslicer.Settings.SteSlicerStackBuilder import SteSlicerStackBuilder SteSlicerStackBuilder.createExtruderStackWithDefaultSetup( global_stack, 0) elif extruder_stack_0.definition.getId( ) != expected_extruder_definition_0_id: Logger.log( "e", "Single extruder printer [{printer}] expected extruder [{expected}], but got [{got}]. I'm making it [{expected}]." .format(printer=global_stack.getId(), expected=expected_extruder_definition_0_id, got=extruder_stack_0.definition.getId())) extruder_definition = container_registry.findDefinitionContainers( id=expected_extruder_definition_0_id)[0] extruder_stack_0.definition = extruder_definition
def _sendMaterialProfiles(self): Logger.log("i", "Sending material profiles to printer") # TODO: Might want to move this to a job... for container in ContainerRegistry.getInstance().findInstanceContainers(type="material"): try: xml_data = container.serialize() if xml_data == "" or xml_data is None: continue names = ContainerManager.getInstance().getLinkedMaterials(container.getId()) if names: # There are other materials that share this GUID. if not container.isReadOnly(): continue # If it's not readonly, it's created by user, so skip it. file_name = "none.xml" self.postForm("materials", "form-data; name=\"file\";filename=\"%s\"" % file_name, xml_data.encode(), onFinished=None) except NotImplementedError: # If the material container is not the most "generic" one it can't be serialized an will raise a # NotImplementedError. We can simply ignore these. pass
def getParentMachineDefinition(self, machine_definition: "DefinitionContainerInterface") -> "DefinitionContainerInterface": container_registry = ContainerRegistry.getInstance() machine_entry = machine_definition.getMetaDataEntry("machine") if machine_entry is None: # We have a normal (whole) machine defintion quality_definition = machine_definition.getMetaDataEntry("quality_definition") if quality_definition is not None: parent_machine_definition = container_registry.findDefinitionContainers(id=quality_definition)[0] return self.getParentMachineDefinition(parent_machine_definition) else: return machine_definition else: # This looks like an extruder. Find the rest of the machine. whole_machine = container_registry.findDefinitionContainers(id=machine_entry)[0] parent_machine = self.getParentMachineDefinition(whole_machine) if whole_machine is parent_machine: # This extruder already belongs to a 'parent' machine def. return machine_definition else: # Look up the corresponding extruder definition in the parent machine definition. extruder_position = machine_definition.getMetaDataEntry("position") parent_extruder_id = parent_machine.getMetaDataEntry("machine_extruder_trains")[extruder_position] return container_registry.findDefinitionContainers(id=parent_extruder_id)[0]
def importProfile(self, file_name): if not file_name: return { "status": "error", "message": catalog.i18nc("@info:status", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, "Invalid path")} plugin_registry = PluginRegistry.getInstance() container_registry = ContainerRegistry.getInstance() for plugin_id, meta_data in self._getIOPlugins("profile_reader"): profile_reader = plugin_registry.getPluginObject(plugin_id) try: profile_or_list = profile_reader.read(file_name) # Try to open the file with the profile reader. except Exception as e: #Note that this will fail quickly. That is, if any profile reader throws an exception, it will stop reading. It will only continue reading if the reader returned None. Logger.log("e", "Failed to import profile from %s: %s", file_name, str(e)) return { "status": "error", "message": catalog.i18nc("@info:status", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, str(e))} if profile_or_list: # Success! name_seed = os.path.splitext(os.path.basename(file_name))[0] if type(profile_or_list) is not list: profile = profile_or_list self._configureProfile(profile, name_seed) return { "status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile.getName()) } else: for profile in profile_or_list: profile.setDirty(True) # Ensure the profiles are correctly saved if profile.getId() != "": container_registry.addContainer(profile) else: self._configureProfile(profile, name_seed) if len(profile_or_list) == 1: return {"status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile_or_list[0].getName())} else: profile_names = ", ".join([profile.getName() for profile in profile_or_list]) return { "status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profiles {0}", profile_names) } #If it hasn't returned by now, none of the plugins loaded the profile successfully. return { "status": "error", "message": catalog.i18nc("@info:status", "Profile {0} has an unknown file type.", file_name)}
def _getSettingProperty(self, setting_key: str, prop: str = "value") -> Any: if self._global_stack is None or self._node is None: return None per_mesh_stack = self._node.callDecoration("getStack") if per_mesh_stack: return per_mesh_stack.getProperty(setting_key, prop) extruder_index = self._global_stack.getProperty( setting_key, "limit_to_extruder") if extruder_index == "-1": # No limit_to_extruder extruder_stack_id = self._node.callDecoration("getActiveExtruder") if not extruder_stack_id: # Decoration doesn't exist extruder_stack_id = ExtruderManager.getInstance( ).extruderIds["0"] extruder_stack = ContainerRegistry.getInstance( ).findContainerStacks(id=extruder_stack_id)[0] return extruder_stack.getProperty(setting_key, prop) else: # Limit_to_extruder is set. The global stack handles this then return self._global_stack.getProperty(setting_key, prop)
def _update(self) -> None: items = [] for container in self._container_stacks: container.nameChanged.disconnect(self._onContainerNameChanged) container_stacks = ContainerRegistry.getInstance().findContainerStacks( type="machine") for container_stack in container_stacks: connection_type = container_stack.getMetaDataEntry( "connection_type") has_remote_connection = connection_type in [ ConnectionType.NetworkConnection.value, ConnectionType.CloudConnection.value ] if container_stack.getMetaDataEntry("hidden", False) in ["True", True]: continue # TODO: Remove reference to connect group name. items.append({ "name": container_stack.getMetaDataEntry("connect_group_name", container_stack.getName()), "id": container_stack.getId(), "hasRemoteConnection": has_remote_connection, "connectionType": connection_type, "metadata": container_stack.getMetaData().copy() }) items.sort(key=lambda i: not i["hasRemoteConnection"]) self.setItems(items)
def _update(self): items = [] new_filter = copy.deepcopy(self._filter_dict) new_filter["base_machine"] = self._base_machine_property definition_containers = ContainerRegistry.getInstance( ).findDefinitionContainersMetadata(**new_filter) for metadata in definition_containers: metadata = metadata.copy() items.append({ "toolhead": metadata.get( "user_toolhead_name", metadata.get("firmware_toolhead_name", metadata["name"])), "id": metadata["id"], "name": metadata["name"], "priority": metadata.get("priority", "99") }) items = sorted(items, key=lambda x: x["priority"] + x["name"]) self.setItems(items)
def _onContainerLoadComplete(self, container_id: str) -> None: container = ContainerRegistry.getInstance().findContainers( id=container_id)[0] if not isinstance(container, DefinitionContainer): # skip containers that are not definitions return if container.getMetaDataEntry("type") == "extruder": # skip extruder definitions return try: material_category = container.findDefinitions(key="material")[0] except IndexError: Logger.log( "e", "Could not find parent category setting to add settings to") return setting_key = list(self._settings_dict.keys())[0] setting_definition = SettingDefinition(setting_key, container, material_category, self._i18n_catalog) setting_definition.deserialize(self._settings_dict[setting_key]) # add the setting to the already existing material settingdefinition # private member access is naughty, but the alternative is to serialise, nix and deserialise the whole thing, # which breaks stuff material_category._children.append(setting_definition) container._definition_cache[setting_key] = setting_definition container._updateRelations(setting_definition) self._expanded_categories = self._application.expandedCategories.copy() self._updateAddedChildren(container, setting_definition) self._application.setExpandedCategories(self._expanded_categories) self._expanded_categories = []
def loadContainer(self, container_id: str) -> "ContainerInterface": #First get the actual (base) ID of the path we're going to read. file_path = self._id_to_path[ container_id] #Raises KeyError if container ID does not exist in the (cache of the) files. base_id = self._pathToId(file_path) if not base_id: raise Exception( "The file where container {container_id} supposedly comes from is not a container file." .format(container_id=container_id)) Logger.log( "d", "Loading container {container_id}".format(container_id=base_id)) container_class = ContainerRegistry.mime_type_map[ self._id_to_mime[base_id].name] if issubclass(container_class, DefinitionContainer ): #We may need to load these from the definition cache. container = self._loadCachedDefinition(container_id) if container: #Yes, it was cached! return container #Not cached, so load by deserialising. container = container_class( base_id, parent=self._application) #Construct the container! with open(file_path, "r", encoding="utf-8") as f: container.deserialize(f.read()) container.setPath(file_path) if issubclass(container_class, DefinitionContainer): self._saveCachedDefinition(container) if base_id == container_id: return container #If we're not requesting the base ID, the sub-container must have been side loaded. return ContainerRegistry.getInstance().findContainers( id=container_id)[0]
def setPropertyValue(self, property_name, property_value): """Set the value of a property. :param property_name: The name of the property to set. :param property_value: The value of the property to set. """ if not self._container or not self._key: return if ContainerRegistry.getInstance().isReadOnly(self._container_id): return if property_name not in self._watched_properties: Logger.log("w", "Tried to set a property that is not being watched") return if self._property_values[property_name] == property_value: return if isinstance(self._container, DefinitionContainer): return self._container.setProperty(self._key, property_name, property_value)
def fixSingleExtrusionMachineExtruderDefinition(self, global_stack: "GlobalStack") -> None: container_registry = ContainerRegistry.getInstance() expected_extruder_definition_0_id = global_stack.getMetaDataEntry("machine_extruder_trains")["0"] try: extruder_stack_0 = global_stack.extruderList[0] except IndexError: extruder_stack_0 = None # At this point, extruder stacks for this machine may not have been loaded yet. In this case, need to look in # the container registry as well. if not global_stack.extruderList: extruder_trains = container_registry.findContainerStacks(type = "extruder_train", machine = global_stack.getId()) if extruder_trains: for extruder in extruder_trains: if extruder.getMetaDataEntry("position") == "0": extruder_stack_0 = extruder break if extruder_stack_0 is None: Logger.log("i", "No extruder stack for global stack [%s], create one", global_stack.getId()) # Single extrusion machine without an ExtruderStack, create it from cura.Settings.CuraStackBuilder import CuraStackBuilder CuraStackBuilder.createExtruderStackWithDefaultSetup(global_stack, 0) elif extruder_stack_0.definition.getId() != expected_extruder_definition_0_id: Logger.log("e", "Single extruder printer [{printer}] expected extruder [{expected}], but got [{got}]. I'm making it [{expected}].".format( printer = global_stack.getId(), expected = expected_extruder_definition_0_id, got = extruder_stack_0.definition.getId())) try: extruder_definition = container_registry.findDefinitionContainers(id = expected_extruder_definition_0_id)[0] except IndexError as e: # It still needs to break, but we want to know what extruder ID made it break. msg = "Unable to find extruder definition with the id [%s]" % expected_extruder_definition_0_id Logger.logException("e", msg) raise IndexError(msg) extruder_stack_0.definition = extruder_definition
def __init__(self, container_id: str) -> None: super().__init__(container_id) self.variants = { } # type: Dict[str, VariantNode] # Mapping variant names to their nodes. self.global_qualities = { } # type: Dict[str, QualityNode] # Mapping quality types to the global quality for those types. self.materialsChanged = Signal( ) # Emitted when one of the materials underneath this machine has been changed. container_registry = ContainerRegistry.getInstance() try: my_metadata = container_registry.findContainersMetadata( id=container_id)[0] except IndexError: Logger.log("Unable to find metadata for container %s", container_id) my_metadata = {} # Some of the metadata is cached upon construction here. # ONLY DO THAT FOR METADATA THAT DOESN'T CHANGE DURING RUNTIME! # Otherwise you need to keep it up-to-date during runtime. self.has_materials = parseBool(my_metadata.get("has_materials", "true")) self.has_variants = parseBool(my_metadata.get("has_variants", "false")) self.has_machine_quality = parseBool( my_metadata.get("has_machine_quality", "false")) self.quality_definition = my_metadata.get( "quality_definition", container_id) if self.has_machine_quality else "fdmprinter" self.exclude_materials = my_metadata.get("exclude_materials", []) self.preferred_variant_name = my_metadata.get("preferred_variant_name", "") self.preferred_material = my_metadata.get("preferred_material", "") self.preferred_quality_type = my_metadata.get("preferred_quality_type", "") self._loadAll()
def createOutputModel(self) -> MaterialOutputModel: """Creates a material output model based on this cloud printer material. A material is chosen that matches the current GUID. If multiple such materials are available, read-only materials are preferred and the material with the earliest alphabetical name will be selected. :return: A material output model that matches the current GUID. """ container_registry = ContainerRegistry.getInstance() same_guid = container_registry.findInstanceContainersMetadata( GUID=self.guid) if same_guid: read_only = sorted(filter( lambda metadata: container_registry.isReadOnly(metadata["id"]), same_guid), key=lambda metadata: metadata["name"]) if read_only: material_metadata = read_only[0] else: material_metadata = min(same_guid, key=lambda metadata: metadata["name"]) else: material_metadata = { "color_code": self.color, "brand": self.brand, "material": self.material, "name": "Empty" if self.material == "empty" else "Unknown" } return MaterialOutputModel(guid=self.guid, type=material_metadata["material"], brand=material_metadata["brand"], color=material_metadata.get( "color_code", "#ffc924"), name=material_metadata["name"])
def getUsedExtruderStacks(self) -> List["ExtruderStack"]: global_stack = self._application.getGlobalContainerStack() container_registry = ContainerRegistry.getInstance() used_extruder_stack_ids = set() # Get the extruders of all meshes in the scene support_enabled = False support_bottom_enabled = False support_roof_enabled = False scene_root = self._application.getController().getScene().getRoot() # If no extruders are registered in the extruder manager yet, return an empty array if len(self.extruderIds) == 0: return [] # Get the extruders of all printable meshes in the scene meshes = [node for node in DepthFirstIterator(scene_root) if isinstance(node, SceneNode) and node.isSelectable()] #type: ignore #Ignore type error because iter() should get called automatically by Python syntax. # Exclude anti-overhang meshes mesh_list = [] for mesh in meshes: stack = mesh.callDecoration("getStack") if stack is not None and (stack.getProperty("anti_overhang_mesh", "value") or stack.getProperty("support_mesh", "value")): continue mesh_list.append(mesh) for mesh in mesh_list: extruder_stack_id = mesh.callDecoration("getActiveExtruder") if not extruder_stack_id: # No per-object settings for this node extruder_stack_id = self.extruderIds["0"] used_extruder_stack_ids.add(extruder_stack_id) # Get whether any of them use support. stack_to_use = mesh.callDecoration("getStack") # if there is a per-mesh stack, we use it if not stack_to_use: # if there is no per-mesh stack, we use the build extruder for this mesh stack_to_use = container_registry.findContainerStacks(id = extruder_stack_id)[0] support_enabled |= stack_to_use.getProperty("support_enable", "value") support_bottom_enabled |= stack_to_use.getProperty("support_bottom_enable", "value") support_roof_enabled |= stack_to_use.getProperty("support_roof_enable", "value") # Check limit to extruders limit_to_extruder_feature_list = ["wall_0_extruder_nr", "wall_x_extruder_nr", "roofing_extruder_nr", "top_bottom_extruder_nr", "infill_extruder_nr", ] for extruder_nr_feature_name in limit_to_extruder_feature_list: extruder_nr = int(global_stack.getProperty(extruder_nr_feature_name, "value")) if extruder_nr == -1: continue used_extruder_stack_ids.add(self.extruderIds[str(extruder_nr)]) # Check support extruders if support_enabled: used_extruder_stack_ids.add(self.extruderIds[self.extruderValueWithDefault(str(global_stack.getProperty("support_infill_extruder_nr", "value")))]) used_extruder_stack_ids.add(self.extruderIds[self.extruderValueWithDefault(str(global_stack.getProperty("support_extruder_nr_layer_0", "value")))]) if support_bottom_enabled: used_extruder_stack_ids.add(self.extruderIds[self.extruderValueWithDefault(str(global_stack.getProperty("support_bottom_extruder_nr", "value")))]) if support_roof_enabled: used_extruder_stack_ids.add(self.extruderIds[self.extruderValueWithDefault(str(global_stack.getProperty("support_roof_extruder_nr", "value")))]) # The platform adhesion extruder. Not used if using none. if global_stack.getProperty("adhesion_type", "value") != "none" or ( global_stack.getProperty("prime_tower_brim_enable", "value") and global_stack.getProperty("adhesion_type", "value") != 'raft'): extruder_str_nr = str(global_stack.getProperty("adhesion_extruder_nr", "value")) if extruder_str_nr == "-1": extruder_str_nr = self._application.getMachineManager().defaultExtruderPosition if extruder_str_nr in self.extruderIds: used_extruder_stack_ids.add(self.extruderIds[extruder_str_nr]) try: return [container_registry.findContainerStacks(id = stack_id)[0] for stack_id in used_extruder_stack_ids] except IndexError: # One or more of the extruders was not found. Logger.log("e", "Unable to find one or more of the extruders in %s", used_extruder_stack_ids) return []
def getUsedExtruderStacks(self) -> List["ExtruderStack"]: """Gets the extruder stacks that are actually being used at the moment. An extruder stack is being used if it is the extruder to print any mesh with, or if it is the support infill extruder, the support interface extruder, or the bed adhesion extruder. If there are no extruders, this returns the global stack as a singleton list. :return: A list of extruder stacks. """ global_stack = self._application.getGlobalContainerStack() container_registry = ContainerRegistry.getInstance() used_extruder_stack_ids = set() # Get the extruders of all meshes in the scene support_enabled = False support_bottom_enabled = False support_roof_enabled = False scene_root = self._application.getController().getScene().getRoot() # If no extruders are registered in the extruder manager yet, return an empty array if len(self.extruderIds) == 0: return [] number_active_extruders = len([ extruder for extruder in self.getActiveExtruderStacks() if extruder.isEnabled ]) # Get the extruders of all printable meshes in the scene nodes = [ node for node in DepthFirstIterator(scene_root) if node.isSelectable() and not node.callDecoration("isAntiOverhangMesh") and not node.callDecoration("isSupportMesh") ] #type: ignore #Ignore type error because iter() should get called automatically by Python syntax. for node in nodes: extruder_stack_id = node.callDecoration("getActiveExtruder") if not extruder_stack_id: # No per-object settings for this node extruder_stack_id = self.extruderIds["0"] used_extruder_stack_ids.add(extruder_stack_id) if len(used_extruder_stack_ids) == number_active_extruders: # We're already done. Stop looking. # Especially with a lot of models on the buildplate, this will speed up things rather dramatically. break # Get whether any of them use support. stack_to_use = node.callDecoration( "getStack") # if there is a per-mesh stack, we use it if not stack_to_use: # if there is no per-mesh stack, we use the build extruder for this mesh stack_to_use = container_registry.findContainerStacks( id=extruder_stack_id)[0] if not support_enabled: support_enabled |= stack_to_use.getProperty( "support_enable", "value") if not support_bottom_enabled: support_bottom_enabled |= stack_to_use.getProperty( "support_bottom_enable", "value") if not support_roof_enabled: support_roof_enabled |= stack_to_use.getProperty( "support_roof_enable", "value") # Check limit to extruders limit_to_extruder_feature_list = [ "wall_0_extruder_nr", "wall_x_extruder_nr", "roofing_extruder_nr", "top_bottom_extruder_nr", "infill_extruder_nr", ] for extruder_nr_feature_name in limit_to_extruder_feature_list: extruder_nr = int( global_stack.getProperty(extruder_nr_feature_name, "value")) if extruder_nr == -1: continue if str(extruder_nr) not in self.extruderIds: extruder_nr = int(self._application.getMachineManager(). defaultExtruderPosition) used_extruder_stack_ids.add(self.extruderIds[str(extruder_nr)]) # Check support extruders if support_enabled: used_extruder_stack_ids.add( self.extruderIds[self.extruderValueWithDefault( str( global_stack.getProperty("support_infill_extruder_nr", "value")))]) used_extruder_stack_ids.add( self.extruderIds[self.extruderValueWithDefault( str( global_stack.getProperty("support_extruder_nr_layer_0", "value")))]) if support_bottom_enabled: used_extruder_stack_ids.add( self.extruderIds[self.extruderValueWithDefault( str( global_stack.getProperty( "support_bottom_extruder_nr", "value")))]) if support_roof_enabled: used_extruder_stack_ids.add( self.extruderIds[self.extruderValueWithDefault( str( global_stack.getProperty( "support_roof_extruder_nr", "value")))]) # The platform adhesion extruders. used_adhesion_extruders = set() adhesion_type = global_stack.getProperty("adhesion_type", "value") if adhesion_type == "skirt" and (global_stack.getProperty( "skirt_line_count", "value") > 0 or global_stack.getProperty( "skirt_brim_minimal_length", "value") > 0): used_adhesion_extruders.add( "skirt_brim_extruder_nr") # There's a skirt. if (adhesion_type == "brim" or global_stack.getProperty("prime_tower_brim_enable", "value") ) and (global_stack.getProperty("brim_line_count", "value") > 0 or global_stack.getProperty("skirt_brim_minimal_length", "value") > 0): used_adhesion_extruders.add( "skirt_brim_extruder_nr" ) # There's a brim or prime tower brim. if adhesion_type == "raft": used_adhesion_extruders.add("raft_base_extruder_nr") used_adhesion_extruders.add("raft_interface_extruder_nr") if global_stack.getProperty("raft_surface_layers", "value") > 0: used_adhesion_extruders.add("raft_surface_extruder_nr") for extruder_setting in used_adhesion_extruders: extruder_str_nr = str( global_stack.getProperty(extruder_setting, "value")) if extruder_str_nr == "-1": extruder_str_nr = self._application.getMachineManager( ).defaultExtruderPosition if extruder_str_nr in self.extruderIds: used_extruder_stack_ids.add(self.extruderIds[extruder_str_nr]) try: return [ container_registry.findContainerStacks(id=stack_id)[0] for stack_id in used_extruder_stack_ids ] except IndexError: # One or more of the extruders was not found. Logger.log("e", "Unable to find one or more of the extruders in %s", used_extruder_stack_ids) return []
def findDefaultQuality(self) -> Optional[ContainerInterface]: definition = self._getMachineDefinition() registry = ContainerRegistry.getInstance() material_container = self.material if self.material != self._empty_instance_container else None search_criteria = {"type": "quality"} if definition.getMetaDataEntry("has_machine_quality"): search_criteria["definition"] = self._findInstanceContainerDefinitionId(definition) if definition.getMetaDataEntry("has_materials") and material_container: search_criteria["material"] = material_container.id else: search_criteria["definition"] = "fdmprinter" if self.quality != self._empty_quality: search_criteria["name"] = self.quality.name else: preferred_quality = definition.getMetaDataEntry("preferred_quality") if preferred_quality: search_criteria["id"] = preferred_quality containers = registry.findInstanceContainers(**search_criteria) if containers: return containers[0] if "material" in search_criteria: # First check if we can solve our material not found problem by checking if we can find quality containers # that are assigned to the parents of this material profile. try: inherited_files = material_container.getInheritedFiles() except AttributeError: # Material_container does not support inheritance. inherited_files = [] if inherited_files: for inherited_file in inherited_files: # Extract the ID from the path we used to load the file. search_criteria["material"] = os.path.basename(inherited_file).split(".")[0] containers = registry.findInstanceContainers(**search_criteria) if containers: return containers[0] # We still weren't able to find a quality for this specific material. # Try to find qualities for a generic version of the material. material_search_criteria = {"type": "material", "material": material_container.getMetaDataEntry("material"), "color_name": "Generic"} if definition.getMetaDataEntry("has_machine_quality"): if self.material != self._empty_instance_container: material_search_criteria["definition"] = material_container.getDefinition().id if definition.getMetaDataEntry("has_variants"): material_search_criteria["variant"] = material_container.getMetaDataEntry("variant") else: material_search_criteria["definition"] = self._findInstanceContainerDefinitionId(definition) if definition.getMetaDataEntry("has_variants") and self.variant != self._empty_instance_container: material_search_criteria["variant"] = self.variant.id else: material_search_criteria["definition"] = "fdmprinter" material_containers = registry.findInstanceContainersMetadata(**material_search_criteria) # Try all materials to see if there is a quality profile available. for material_container in material_containers: search_criteria["material"] = material_container["id"] containers = registry.findInstanceContainers(**search_criteria) if containers: return containers[0] if "name" in search_criteria or "id" in search_criteria: # If a quality by this name can not be found, try a wider set of search criteria search_criteria.pop("name", None) search_criteria.pop("id", None) containers = registry.findInstanceContainers(**search_criteria) if containers: return containers[0] return None
property_name: str, context: Optional[PropertyEvaluationContext] = None) -> bool: if property_name is not "value": # Do not try to resolve anything but the "value" property return False if key in self._resolving_settings: # To prevent infinite recursion, if getProperty is called with the same key as # we are already trying to resolve, we should not try to resolve again. Since # this can happen multiple times when trying to resolve a value, we need to # track all settings that are being resolved. return False setting_state = super().getProperty(key, "state", context=context) if setting_state is not None and setting_state != InstanceState.Default: # When the user has explicitly set a value, we should ignore any resolve and # just return that value. return False return True ## private: global_stack_mime = MimeType(name="application/x-cura-globalstack", comment="Cura Global Stack", suffixes=["global.cfg"]) MimeTypeDatabase.addMimeType(global_stack_mime) ContainerRegistry.addContainerTypeByName(GlobalStack, "global_stack", global_stack_mime.name)
def __init__(self): super().__init__("UpgradeFirmware", catalog.i18nc("@action", "Upgrade Firmware")) self._qml_url = "UpgradeFirmwareMachineAction.qml" ContainerRegistry.getInstance().containerAdded.connect( self._onContainerAdded)
def exportProfile(self, instance_ids, file_name, file_type): # Parse the fileType to deduce what plugin can save the file format. # fileType has the format "<description> (*.<extension>)" split = file_type.rfind( " (*." ) # Find where the description ends and the extension starts. if split < 0: # Not found. Invalid format. Logger.log("e", "Invalid file format identifier %s", file_type) return description = file_type[:split] extension = file_type[split + 4:-1] # Leave out the " (*." and ")". if not file_name.endswith( "." + extension ): # Auto-fill the extension if the user did not provide any. file_name += "." + extension # On Windows, QML FileDialog properly asks for overwrite confirm, but not on other platforms, so handle those ourself. if not Platform.isWindows(): if os.path.exists(file_name): result = QMessageBox.question( None, catalog.i18nc("@title:window", "File Already Exists"), catalog.i18nc( "@label", "The file <filename>{0}</filename> already exists. Are you sure you want to overwrite it?" ).format(file_name)) if result == QMessageBox.No: return found_containers = [] extruder_positions = [] for instance_id in instance_ids: containers = ContainerRegistry.getInstance( ).findInstanceContainers(id=instance_id) if containers: found_containers.append(containers[0]) # Determine the position of the extruder of this container extruder_id = containers[0].getMetaDataEntry("extruder", "") if extruder_id == "": # Global stack extruder_positions.append(-1) else: extruder_containers = ContainerRegistry.getInstance( ).findDefinitionContainers(id=extruder_id) if extruder_containers: extruder_positions.append( int(extruder_containers[0].getMetaDataEntry( "position", 0))) else: extruder_positions.append(0) # Ensure the profiles are always exported in order (global, extruder 0, extruder 1, ...) found_containers = [ containers for (positions, containers ) in sorted(zip(extruder_positions, found_containers)) ] profile_writer = self._findProfileWriter(extension, description) try: success = profile_writer.write(file_name, found_containers) except Exception as e: Logger.log("e", "Failed to export profile to %s: %s", file_name, str(e)) m = Message(catalog.i18nc( "@info:status", "Failed to export profile to <filename>{0}</filename>: <message>{1}</message>", file_name, str(e)), lifetime=0) m.show() return if not success: Logger.log( "w", "Failed to export profile to %s: Writer plugin reported failure.", file_name) m = Message(catalog.i18nc( "@info:status", "Failed to export profile to <filename>{0}</filename>: Writer plugin reported failure.", file_name), lifetime=0) m.show() return m = Message( catalog.i18nc("@info:status", "Exported profile to <filename>{0}</filename>", file_name)) m.show()
def run(self) -> None: if self._build_plate_number is None: self.setResult(StartJobResult.Error) return stack = CuraApplication.getInstance().getGlobalContainerStack() if not stack: self.setResult(StartJobResult.Error) return # Don't slice if there is a setting with an error value. if CuraApplication.getInstance().getMachineManager().stacksHaveErrors: self.setResult(StartJobResult.SettingError) return if CuraApplication.getInstance().getBuildVolume().hasErrors(): self.setResult(StartJobResult.BuildPlateError) return # Don't slice if the buildplate or the nozzle type is incompatible with the materials if not CuraApplication.getInstance().getMachineManager().variantBuildplateCompatible and \ not CuraApplication.getInstance().getMachineManager().variantBuildplateUsable: self.setResult(StartJobResult.MaterialIncompatible) return for position, extruder_stack in stack.extruders.items(): material = extruder_stack.findContainer({"type": "material"}) if not extruder_stack.isEnabled: continue if material: if material.getMetaDataEntry("compatible") == False: self.setResult(StartJobResult.MaterialIncompatible) return # Don't slice if there is a per object setting with an error value. for node in DepthFirstIterator( self._scene.getRoot() ): #type: ignore #Ignore type error because iter() should get called automatically by Python syntax. if not isinstance(node, CuraSceneNode) or not node.isSelectable(): continue if self._checkStackForErrors(node.callDecoration("getStack")): self.setResult(StartJobResult.ObjectSettingError) return with self._scene.getSceneLock(): # Remove old layer data. for node in DepthFirstIterator( self._scene.getRoot() ): #type: ignore #Ignore type error because iter() should get called automatically by Python syntax. if node.callDecoration("getLayerData") and node.callDecoration( "getBuildPlateNumber") == self._build_plate_number: node.getParent().removeChild(node) break global_enable_support = stack.getProperty("support_enable", "value") # Get the objects in their groups to print. object_groups = [] if stack.getProperty("print_sequence", "value") == "one_at_a_time": # note that one_at_a_time printing is disabled on belt printers due to collission risk for node in OneAtATimeIterator( self._scene.getRoot() ): #type: ignore #Ignore type error because iter() should get called automatically by Python syntax. temp_list = [] # Node can't be printed, so don't bother sending it. if getattr(node, "_outside_buildarea", False): continue # Filter on current build plate build_plate_number = node.callDecoration( "getBuildPlateNumber") if build_plate_number is not None and build_plate_number != self._build_plate_number: continue children = node.getAllChildren() children.append(node) for child_node in children: if child_node.getMeshData() and child_node.getMeshData( ).getVertices() is not None: temp_list.append(child_node) if temp_list: object_groups.append(temp_list) Job.yieldThread() if len(object_groups) == 0: Logger.log( "w", "No objects suitable for one at a time found, or no correct order found" ) else: temp_list = [] has_printing_mesh = False # print convex hull nodes as "faux-raft" print_convex_hulls = self._preferences.getValue( "BeltPlugin/raft") for node in DepthFirstIterator( self._scene.getRoot() ): #type: ignore #Ignore type error because iter() should get called automatically by Python syntax. slice_node = (print_convex_hulls and type(node) is ConvexHullNode ) or node.callDecoration("isSliceable") if slice_node and node.getMeshData() and node.getMeshData( ).getVertices() is not None: per_object_stack = node.callDecoration("getStack") is_non_printing_mesh = False if per_object_stack: is_non_printing_mesh = any( per_object_stack.getProperty(key, "value") for key in NON_PRINTING_MESH_SETTINGS) # Find a reason not to add the node if node.callDecoration( "getBuildPlateNumber" ) != self._build_plate_number and type( node) is not ConvexHullNode: # NB: ConvexHullNodes get none of the usual decorators, so skip checking for them continue if getattr(node, "_outside_buildarea", False) and not is_non_printing_mesh: continue temp_list.append(node) if not is_non_printing_mesh: has_printing_mesh = True Job.yieldThread() #If the list doesn't have any model with suitable settings then clean the list # otherwise CuraEngine will crash if not has_printing_mesh: temp_list.clear() if temp_list: object_groups.append(temp_list) global_stack = CuraApplication.getInstance( ).getGlobalContainerStack() if not global_stack: return extruders_enabled = { position: stack.isEnabled for position, stack in global_stack.extruders.items() } filtered_object_groups = [] has_model_with_disabled_extruders = False associated_disabled_extruders = set() for group in object_groups: stack = global_stack skip_group = False for node in group: # Only check if the printing extruder is enabled for printing meshes is_non_printing_mesh = node.callDecoration( "evaluateIsNonPrintingMesh") extruder_position = node.callDecoration( "getActiveExtruderPosition") if extruder_position is None: # raft meshes may not have an extruder position (yet) extruder_position = "0" if not is_non_printing_mesh and not extruders_enabled[ extruder_position]: skip_group = True has_model_with_disabled_extruders = True associated_disabled_extruders.add(extruder_position) if not skip_group: filtered_object_groups.append(group) if has_model_with_disabled_extruders: self.setResult(StartJobResult.ObjectsWithDisabledExtruder) associated_disabled_extruders = { str(c) for c in sorted( [int(p) + 1 for p in associated_disabled_extruders]) } self.setMessage(", ".join(associated_disabled_extruders)) return # There are cases when there is nothing to slice. This can happen due to one at a time slicing not being # able to find a possible sequence or because there are no objects on the build plate (or they are outside # the build volume) if not filtered_object_groups: self.setResult(StartJobResult.NothingToSlice) return container_registry = ContainerRegistry.getInstance() stack_id = stack.getId() # Adapt layer_height and material_flow for a slanted gantry gantry_angle = self._scene.getRoot().callDecoration( "getGantryAngle") #gantry_angle = float(self._preferences.getValue("BeltPlugin/gantry_angle")) if gantry_angle: # not 0 or None # Act on a copy of the stack, so these changes don't cause a reslice _stack = CuraContainerStack(stack_id + "_temp") for index, container in enumerate(stack.getContainers()): if container_registry.isReadOnly(container.getId()): _stack.replaceContainer(index, container) else: _stack.replaceContainer(index, copy.deepcopy(container)) stack = _stack # Make sure CuraEngine does not create any supports # support_enable is set in the frontend so support options are settable, # but CuraEngine support structures don't work for slanted gantry stack.setProperty("support_enable", "value", False) # Make sure CuraEngine does not create a raft (we create one manually) # Adhesion type is used in the frontend to show the raft in the viewport stack.setProperty("adhesion_type", "value", "none") for key in ["layer_height", "layer_height_0"]: current_value = stack.getProperty(key, "value") stack.setProperty(key, "value", current_value / math.sin(gantry_angle)) self._buildGlobalSettingsMessage(stack) self._buildGlobalInheritsStackMessage(stack) # Build messages for extruder stacks # Send the extruder settings in the order of extruder positions. Somehow, if you send e.g. extruder 3 first, # then CuraEngine can slice with the wrong settings. This I think should be fixed in CuraEngine as well. extruder_stack_list = sorted(list(global_stack.extruders.items()), key=lambda item: int(item[0])) for _, extruder_stack in extruder_stack_list: if gantry_angle: # not 0 or None # Act on a copy of the stack, so these changes don't cause a reslice _extruder_stack = CuraContainerStack( extruder_stack.getId() + "_temp") for index, container in enumerate( extruder_stack.getContainers()): if container_registry.isReadOnly(container.getId()): _extruder_stack.replaceContainer(index, container) else: _extruder_stack.replaceContainer( index, copy.deepcopy(container)) extruder_stack = _extruder_stack extruder_stack.setNextStack(stack) for key in [ "material_flow", "prime_tower_flow", "spaghetti_flow" ]: if extruder_stack.hasProperty(key, "value"): current_value = extruder_stack.getProperty( key, "value") extruder_stack.setProperty( key, "value", current_value * math.sin(gantry_angle)) self._buildExtruderMessage(extruder_stack) bottom_cutting_meshes = [] raft_meshes = [] support_meshes = [] if gantry_angle: # not 0 or None for group in filtered_object_groups: added_meshes = [] for object in group: is_non_printing_mesh = False per_object_stack = object.callDecoration("getStack") # ConvexHullNodes get none of the usual decorators. If it made it here, it is meant to be printed if type(object) is ConvexHullNode: raft_thickness = self._preferences.getValue( "BeltPlugin/raft_thickness") raft_margin = self._preferences.getValue( "BeltPlugin/raft_margin") mb = MeshBuilder() hull_polygon = object.getHull() if raft_margin > 0: hull_polygon = hull_polygon.getMinkowskiHull( Polygon.approximatedCircle(raft_margin)) mb.addConvexPolygonExtrusion( hull_polygon.getPoints()[::-1], 0, raft_thickness) new_node = self._addMeshFromBuilder(mb, "raftMesh") added_meshes.append(new_node) raft_meshes.append(new_node.getName()) elif not is_non_printing_mesh: # add support mesh if needed belt_support_gantry_angle_bias = None belt_support_minimum_island_area = None if per_object_stack: is_non_printing_mesh = any( per_object_stack.getProperty(key, "value") for key in NON_PRINTING_MESH_SETTINGS) node_enable_support = per_object_stack.getProperty( "support_enable", "value") if per_object_stack.getProperty( "support_mesh", "value"): node_enable_support = node_enable_support or per_object_stack.getProperty( "support_mesh_drop_down", "value") add_support_mesh = node_enable_support if node_enable_support is not None else global_enable_support belt_support_gantry_angle_bias = self._preferences.getValue( "BeltPlugin/support_gantry_angle_bias") belt_support_minimum_island_area = self._preferences.getValue( "BeltPlugin/support_minimum_island_area") else: add_support_mesh = global_enable_support if add_support_mesh: #preferences = Application.getInstance().getPreferences() if belt_support_gantry_angle_bias is None: belt_support_gantry_angle_bias = self._preferences.getValue( "BeltPlugin/support_gantry_angle_bias") biased_down_angle = math.radians( belt_support_gantry_angle_bias) if belt_support_minimum_island_area is None: belt_support_minimum_island_area = self._preferences.getValue( "BeltPlugin/support_minimum_island_area" ) support_mesh_data = SupportMeshCreator( down_vector=numpy.array([ 0, -math.cos( math.radians(biased_down_angle)), -math.sin(biased_down_angle) ]), bottom_cut_off=stack.getProperty( "wall_line_width_0", "value") / 2, minimum_island_area= belt_support_minimum_island_area ).createSupportMeshForNode(object) if support_mesh_data: new_node = self._addMeshFromData( support_mesh_data, "generatedSupportMesh") added_meshes.append(new_node) support_meshes.append(new_node.getName()) # check if the bottom needs to be cut off aabb = object.getBoundingBox() if aabb.bottom < 0: # mesh extends below the belt; add a cutting mesh to cut off the part below the bottom height = -aabb.bottom center = Vector(aabb.center.x, -height / 2, aabb.center.z) mb = MeshBuilder() mb.addCube(width=aabb.width, height=height, depth=aabb.depth, center=center) new_node = self._addMeshFromBuilder( mb, "bottomCuttingMesh") added_meshes.append(new_node) bottom_cutting_meshes.append( new_node.getName()) if added_meshes: group += added_meshes transform_matrix = self._scene.getRoot().callDecoration( "getTransformMatrix") front_offset = None raft_offset = 0 raft_speed = None raft_flow = 1.0 if self._preferences.getValue("BeltPlugin/raft"): raft_offset = self._preferences.getValue( "BeltPlugin/raft_thickness") raft_speed = self._preferences.getValue( "BeltPlugin/raft_speed") raft_flow = self._preferences.getValue( "BeltPlugin/raft_flow") * math.sin(gantry_angle) adhesion_extruder_nr = stack.getProperty("adhesion_extruder_nr", "value") support_extruder_nr = stack.getProperty("support_extruder_nr", "value") for group in filtered_object_groups: group_message = self._slice_message.addRepeatedMessage( "object_lists") if group[0].getParent() is not None and group[0].getParent( ).callDecoration("isGroup"): self._handlePerObjectSettings(group[0].getParent(), group_message) if transform_matrix: scene_front = None for object in group: if type(object) is ConvexHullNode: continue is_non_printing_mesh = object.getName( ) in bottom_cutting_meshes or object.getName( ) in raft_meshes if not is_non_printing_mesh: per_object_stack = object.callDecoration( "getStack") if per_object_stack: is_non_printing_mesh = any( per_object_stack.getProperty(key, "value") for key in NON_PRINTING_MESH_SETTINGS) if not is_non_printing_mesh: _front = object.getBoundingBox().back if scene_front is None or _front < scene_front: scene_front = _front if scene_front is not None: front_offset = transformVertices( numpy.array([[0, 0, scene_front]]), transform_matrix)[0][1] for object in group: if type(object) is ConvexHullNode: continue mesh_data = object.getMeshData() rot_scale = object.getWorldTransformation().getTransposed( ).getData()[0:3, 0:3] translate = object.getWorldTransformation().getData()[:3, 3] # offset all non-raft objects if rafts are enabled # air gap is applied here to vertically offset objects from the raft if object.getName() not in raft_meshes: translate[1] += raft_offset if front_offset: translate[2] -= front_offset # This effectively performs a limited form of MeshData.getTransformed that ignores normals. verts = mesh_data.getVertices() verts = verts.dot(rot_scale) verts += translate if transform_matrix: verts = transformVertices(verts, transform_matrix) # Convert from Y up axes to Z up axes. Equals a 90 degree rotation. verts[:, [1, 2]] = verts[:, [2, 1]] verts[:, 1] *= -1 obj = group_message.addRepeatedMessage("objects") obj.id = id(object) obj.name = object.getName() indices = mesh_data.getIndices() if indices is not None: flat_verts = numpy.take(verts, indices.flatten(), axis=0) else: flat_verts = numpy.array(verts) obj.vertices = flat_verts if object.getName() in raft_meshes: self._addSettingsMessage( obj, { "wall_line_count": 99999999, "speed_wall_0": raft_speed, "speed_wall_x": raft_speed, "material_flow": raft_flow, "extruder_nr": adhesion_extruder_nr }) elif object.getName() in support_meshes: self._addSettingsMessage( obj, { "support_mesh": "True", "support_mesh_drop_down": "False", "extruder_nr": support_extruder_nr }) elif object.getName() in bottom_cutting_meshes: self._addSettingsMessage( obj, { "cutting_mesh": True, "wall_line_count": 0, "top_layers": 0, "bottom_layers": 0, "infill_line_distance": 0, "extruder_nr": 0 }) else: self._handlePerObjectSettings(object, obj) Job.yieldThread() # Store the front-most coordinate of the scene so the scene can be moved back into place post slicing # TODO: this should be handled per mesh-group instead of per scene # One-at-a-time printing should be disabled for slanted gantry printers for now self._scene.getRoot().callDecoration("setSceneFrontOffset", front_offset) self.setResult(StartJobResult.Finished)
super().deserialize(contents, file_name) if "enabled" not in self.getMetaData(): self.setMetaDataEntry("enabled", "True") def _onPropertiesChanged(self, key: str, properties: Dict[str, Any]) -> None: # When there is a setting that is not settable per extruder that depends on a value from a setting that is, # we do not always get properly informed that we should re-evaluate the setting. So make sure to indicate # something changed for those settings. if not self.getNextStack(): return #There are no global settings to depend on. definitions = self.getNextStack().definition.findDefinitions(key=key) if definitions: has_global_dependencies = False for relation in definitions[0].relations: if not getattr(relation.target, "settable_per_extruder", True): has_global_dependencies = True break if has_global_dependencies: self.getNextStack().propertiesChanged.emit(key, properties) extruder_stack_mime = MimeType(name="application/x-cura-extruderstack", comment="Cura Extruder Stack", suffixes=["extruder.cfg"]) MimeTypeDatabase.addMimeType(extruder_stack_mime) ContainerRegistry.addContainerTypeByName(ExtruderStack, "extruder_stack", extruder_stack_mime.name)
def __init__(self, parent=None): super().__init__(parent) self._container_registry = ContainerRegistry.getInstance() self._machine_manager = Application.getInstance().getMachineManager() self._container_name_filters = {}
def __init__(self): Resources.addSearchPath( os.path.join(QtApplication.getInstallPrefix(), "share", "cura", "resources")) if not hasattr(sys, "frozen"): Resources.addSearchPath( os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "resources")) self._open_file_queue = [] # Files to open when plug-ins are loaded. # Need to do this before ContainerRegistry tries to load the machines SettingDefinition.addSupportedProperty("settable_per_mesh", DefinitionPropertyType.Any, default=True, read_only=True) SettingDefinition.addSupportedProperty("settable_per_extruder", DefinitionPropertyType.Any, default=True, read_only=True) # this setting can be changed for each group in one-at-a-time mode SettingDefinition.addSupportedProperty("settable_per_meshgroup", DefinitionPropertyType.Any, default=True, read_only=True) SettingDefinition.addSupportedProperty("settable_globally", DefinitionPropertyType.Any, default=True, read_only=True) # From which stack the setting would inherit if not defined per object (handled in the engine) # AND for settings which are not settable_per_mesh: # which extruder is the only extruder this setting is obtained from SettingDefinition.addSupportedProperty("limit_to_extruder", DefinitionPropertyType.Function, default="-1") # For settings which are not settable_per_mesh and not settable_per_extruder: # A function which determines the glabel/meshgroup value by looking at the values of the setting in all (used) extruders SettingDefinition.addSupportedProperty("resolve", DefinitionPropertyType.Function, default=None) SettingDefinition.addSettingType("extruder", None, str, Validator) SettingFunction.registerOperator( "extruderValues", cura.Settings.ExtruderManager.getExtruderValues) SettingFunction.registerOperator( "extruderValue", cura.Settings.ExtruderManager.getExtruderValue) SettingFunction.registerOperator( "resolveOrValue", cura.Settings.ExtruderManager.getResolveOrValue) ## Add the 4 types of profiles to storage. Resources.addStorageType(self.ResourceTypes.QualityInstanceContainer, "quality") Resources.addStorageType(self.ResourceTypes.VariantInstanceContainer, "variants") Resources.addStorageType(self.ResourceTypes.MaterialInstanceContainer, "materials") Resources.addStorageType(self.ResourceTypes.UserInstanceContainer, "user") Resources.addStorageType(self.ResourceTypes.ExtruderStack, "extruders") Resources.addStorageType(self.ResourceTypes.MachineStack, "machine_instances") ContainerRegistry.getInstance().addResourceType( self.ResourceTypes.QualityInstanceContainer) ContainerRegistry.getInstance().addResourceType( self.ResourceTypes.VariantInstanceContainer) ContainerRegistry.getInstance().addResourceType( self.ResourceTypes.MaterialInstanceContainer) ContainerRegistry.getInstance().addResourceType( self.ResourceTypes.UserInstanceContainer) ContainerRegistry.getInstance().addResourceType( self.ResourceTypes.ExtruderStack) ContainerRegistry.getInstance().addResourceType( self.ResourceTypes.MachineStack) ## Initialise the version upgrade manager with Cura's storage paths. import UM.VersionUpgradeManager #Needs to be here to prevent circular dependencies. UM.VersionUpgradeManager.VersionUpgradeManager.getInstance( ).setCurrentVersions({ ("quality", UM.Settings.InstanceContainer.Version): (self.ResourceTypes.QualityInstanceContainer, "application/x-uranium-instancecontainer"), ("machine_stack", UM.Settings.ContainerStack.Version): (self.ResourceTypes.MachineStack, "application/x-uranium-containerstack"), ("preferences", UM.Preferences.Version): (Resources.Preferences, "application/x-uranium-preferences"), ("user", UM.Settings.InstanceContainer.Version): (self.ResourceTypes.UserInstanceContainer, "application/x-uranium-instancecontainer") }) self._machine_action_manager = MachineActionManager.MachineActionManager( ) self._machine_manager = None # This is initialized on demand. self._setting_inheritance_manager = None self._additional_components = { } # Components to add to certain areas in the interface super().__init__(name="cura", version=CuraVersion, buildtype=CuraBuildType) self.setWindowIcon( QIcon(Resources.getPath(Resources.Images, "cura-icon.png"))) self.setRequiredPlugins([ "CuraEngineBackend", "MeshView", "LayerView", "STLReader", "SelectionTool", "CameraTool", "GCodeWriter", "LocalFileOutputDevice" ]) self._physics = None self._volume = None self._output_devices = {} self._print_information = None self._previous_active_tool = None self._platform_activity = False self._scene_bounding_box = AxisAlignedBox.Null self._job_name = None self._center_after_select = False self._camera_animation = None self._cura_actions = None self._started = False self._message_box_callback = None self._message_box_callback_arguments = [] self._i18n_catalog = i18nCatalog("cura") self.getController().getScene().sceneChanged.connect( self.updatePlatformActivity) self.getController().toolOperationStopped.connect( self._onToolOperationStopped) Resources.addType(self.ResourceTypes.QmlFiles, "qml") Resources.addType(self.ResourceTypes.Firmware, "firmware") self.showSplashMessage( self._i18n_catalog.i18nc("@info:progress", "Loading machines...")) # Add empty variant, material and quality containers. # Since they are empty, they should never be serialized and instead just programmatically created. # We need them to simplify the switching between materials. empty_container = ContainerRegistry.getInstance( ).getEmptyInstanceContainer() empty_variant_container = copy.deepcopy(empty_container) empty_variant_container._id = "empty_variant" empty_variant_container.addMetaDataEntry("type", "variant") ContainerRegistry.getInstance().addContainer(empty_variant_container) empty_material_container = copy.deepcopy(empty_container) empty_material_container._id = "empty_material" empty_material_container.addMetaDataEntry("type", "material") ContainerRegistry.getInstance().addContainer(empty_material_container) empty_quality_container = copy.deepcopy(empty_container) empty_quality_container._id = "empty_quality" empty_quality_container.setName("Not supported") empty_quality_container.addMetaDataEntry("quality_type", "normal") empty_quality_container.addMetaDataEntry("type", "quality") ContainerRegistry.getInstance().addContainer(empty_quality_container) empty_quality_changes_container = copy.deepcopy(empty_container) empty_quality_changes_container._id = "empty_quality_changes" empty_quality_changes_container.addMetaDataEntry( "type", "quality_changes") ContainerRegistry.getInstance().addContainer( empty_quality_changes_container) # Set the filename to create if cura is writing in the config dir. self._config_lock_filename = os.path.join( Resources.getConfigStoragePath(), CONFIG_LOCK_FILENAME) self.waitConfigLockFile() ContainerRegistry.getInstance().load() Preferences.getInstance().addPreference("cura/active_mode", "simple") Preferences.getInstance().addPreference("cura/recent_files", "") Preferences.getInstance().addPreference("cura/categories_expanded", "") Preferences.getInstance().addPreference("cura/jobname_prefix", True) Preferences.getInstance().addPreference("view/center_on_select", True) Preferences.getInstance().addPreference("mesh/scale_to_fit", True) Preferences.getInstance().addPreference("mesh/scale_tiny_meshes", True) for key in [ "dialog_load_path", # dialog_save_path is in LocalFileOutputDevicePlugin "dialog_profile_path", "dialog_material_path" ]: Preferences.getInstance().addPreference("local_file/%s" % key, os.path.expanduser("~/")) Preferences.getInstance().setDefault("local_file/last_used_type", "text/x-gcode") Preferences.getInstance().setDefault( "general/visible_settings", """ machine_settings resolution layer_height shell wall_thickness top_bottom_thickness infill infill_sparse_density material material_print_temperature material_bed_temperature material_diameter material_flow retraction_enable speed speed_print speed_travel acceleration_print acceleration_travel jerk_print jerk_travel travel cooling cool_fan_enabled support support_enable support_extruder_nr support_type support_interface_density platform_adhesion adhesion_type adhesion_extruder_nr brim_width raft_airgap layer_0_z_overlap raft_surface_layers dual prime_tower_enable prime_tower_size prime_tower_position_x prime_tower_position_y meshfix blackmagic print_sequence infill_mesh experimental """.replace("\n", ";").replace(" ", "")) JobQueue.getInstance().jobFinished.connect(self._onJobFinished) self.applicationShuttingDown.connect(self.saveSettings) self.engineCreatedSignal.connect(self._onEngineCreated) self._recent_files = [] files = Preferences.getInstance().getValue("cura/recent_files").split( ";") for f in files: if not os.path.isfile(f): continue self._recent_files.append(QUrl.fromLocalFile(f))
def __init__(self, container_id: str, quality: "QualityNode") -> None: super().__init__(container_id) self.quality = quality self.intent_category = ContainerRegistry.getInstance().findContainersMetadata(id = container_id)[0].get("intent_category", "default")
def _update(self): item_dict = OrderedDict() item_list = [] global_stack = Application.getInstance().getGlobalContainerStack() if not global_stack: return stacks = [global_stack] stacks.extend(global_stack.extruders.values()) # Check if the definition container has a translation file and ensure it's loaded. definition = global_stack.getBottom() definition_suffix = ContainerRegistry.getMimeTypeForContainer( type(definition)).preferredSuffix catalog = i18nCatalog( os.path.basename(definition.getId() + "." + definition_suffix)) if catalog.hasTranslationLoaded(): self._i18n_catalog = catalog for file_name in definition.getInheritedFiles(): catalog = i18nCatalog(os.path.basename(file_name)) if catalog.hasTranslationLoaded(): self._i18n_catalog = catalog for stack in stacks: # Make a list of all containers in the stack. containers = [] latest_stack = stack while latest_stack: containers.extend(latest_stack.getContainers()) latest_stack = latest_stack.getNextStack() # Override "getExtruderValue" with "getDefaultExtruderValue" so we can get the default values user_changes = containers.pop(0) default_value_resolve_context = PropertyEvaluationContext(stack) default_value_resolve_context.context[ "evaluate_from_container_index"] = 1 # skip the user settings container default_value_resolve_context.context["override_operators"] = { "extruderValue": ExtruderManager.getDefaultExtruderValue, "extruderValues": ExtruderManager.getDefaultExtruderValues, "resolveOrValue": ExtruderManager.getDefaultResolveOrValue } for setting_key in user_changes.getAllKeys(): original_value = None # Find the category of the instance by moving up until we find a category. category = user_changes.getInstance(setting_key).definition while category.type != "category": category = category.parent # Handle translation (and fallback if we weren't able to find any translation files. if self._i18n_catalog: category_label = self._i18n_catalog.i18nc( category.key + " label", category.label) else: category_label = category.label if self._i18n_catalog: label = self._i18n_catalog.i18nc( setting_key + " label", stack.getProperty(setting_key, "label")) else: label = stack.getProperty(setting_key, "label") for container in containers: if stack == global_stack: resolve = global_stack.getProperty( setting_key, "resolve", default_value_resolve_context) if resolve is not None: original_value = resolve break original_value = container.getProperty( setting_key, "value", default_value_resolve_context) # If a value is a function, ensure it's called with the stack it's in. if isinstance(original_value, SettingFunction): original_value = original_value( stack, default_value_resolve_context) if original_value is not None: break item_to_add = { "key": setting_key, "label": label, "user_value": str(user_changes.getProperty(setting_key, "value")), "original_value": str(original_value), "extruder": "", "category": category_label } if stack != global_stack: item_to_add["extruder"] = stack.getName() if category_label not in item_dict: item_dict[category_label] = [] item_dict[category_label].append(item_to_add) for each_item_list in item_dict.values(): item_list += each_item_list self.setItems(item_list)
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: 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() # 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() 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: 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: raise RuntimeError( "Extruder position [%s] defined in extruder definition [%s] is not the same as in machine definition [%s] position [%s]" % (position_in_extruder_def, extruder_definition_id, definition_id, position)) 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) 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() for position, extruder_stack in new_global_stack.extruders.items(): if position in quality_group.nodes_for_extruders: 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 removeMachineExtruders(self, machine_id: str) -> None: for extruder in self.getMachineExtruders(machine_id): ContainerRegistry.getInstance().removeContainer(extruder.userChanges.getId()) ContainerRegistry.getInstance().removeContainer(extruder.getId()) if machine_id in self._extruder_trains: del self._extruder_trains[machine_id]
def totalNumberOfSettings(self): general_definition_containers = ContainerRegistry.getInstance( ).findDefinitionContainers(id="fdmprinter") if not general_definition_containers: return 0 return len(general_definition_containers[0].getAllKeys())
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))