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)
Example #2
0
    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()
Example #4
0
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
Example #5
0
    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 []
Example #6
0
    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)
Example #7
0
    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
Example #8
0
    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()
Example #9
0
    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)
Example #10
0
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))
Example #12
0
    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)
Example #13
0
    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)
Example #14
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()
        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)}
Example #15
0
    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)
Example #17
0
    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()
Example #19
0
    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
Example #20
0
    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)
Example #21
0
    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]
Example #22
0
    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()
Example #23
0
    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
Example #24
0
    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
Example #25
0
    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()
Example #26
0
    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()
Example #27
0
    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
Example #28
0
    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
Example #29
0
    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)
Example #30
0
    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 = {}
Example #31
0
    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()
Example #32
0
    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
Example #33
0
    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
Example #34
0
    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]
Example #35
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)}
Example #36
0
    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)
Example #37
0
    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 = []
Example #40
0
    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)
Example #42
0
    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
Example #43
0
    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"])
Example #45
0
    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 []
Example #46
0
    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 []
Example #47
0
    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
Example #48
0
            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)
Example #50
0
    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()
Example #51
0
    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)
Example #52
0
        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)
Example #53
0
    def __init__(self, parent=None):
        super().__init__(parent)

        self._container_registry = ContainerRegistry.getInstance()
        self._machine_manager = Application.getInstance().getMachineManager()
        self._container_name_filters = {}
Example #54
0
    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))
Example #55
0
 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")
Example #56
0
    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)
Example #57
0
    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
Example #58
0
 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())
Example #60
0
 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))