Esempio n. 1
0
def test_getCurrentQualityChangesGroups(container_registry, application):
    with patch("UM.Settings.ContainerRegistry.ContainerRegistry.getInstance",
               MagicMock(return_value=container_registry)):
        container_tree = ContainerTree()
        container_tree.machines["current_global_stack"] = MagicMock(
        )  # Mock so that we can track whether the getQualityGroups function gets called with correct parameters.

        with patch("cura.CuraApplication.CuraApplication.getInstance",
                   MagicMock(return_value=application)):
            result = container_tree.getCurrentQualityChangesGroups()

    # As defined in the fixture for application.
    expected_variant_names = [
        "current_global_stack_left_variant_name",
        "current_global_stack_right_variant_name"
    ]
    expected_material_base_files = [
        "current_global_stack_left_material_base_file",
        "current_global_stack_right_material_base_file"
    ]
    expected_is_enabled = [True, True]

    container_tree.machines[
        "current_global_stack"].getQualityChangesGroups.assert_called_with(
            expected_variant_names, expected_material_base_files,
            expected_is_enabled)
    assert result == container_tree.machines[
        "current_global_stack"].getQualityChangesGroups.return_value
Esempio n. 2
0
def test_getCurrentQualityChangesGroupsNoGlobalStack(container_registry):
    with patch("UM.Settings.ContainerRegistry.ContainerRegistry.getInstance", MagicMock(return_value = container_registry)):
        with patch("cura.CuraApplication.CuraApplication.getInstance", MagicMock(return_value = MagicMock(getGlobalContainerStack = MagicMock(return_value = None)))):
            container_tree = ContainerTree()
            result = container_tree.getCurrentQualityChangesGroups()

    assert len(result) == 0
Esempio n. 3
0
    def __init__(self, parent=None):
        super().__init__(parent)
        from cura.CuraApplication import CuraApplication

        self._application = CuraApplication.getInstance()

        self._available_materials = {}  # type: Dict[str, MaterialNode]
        self._favorite_ids = set()  # type: Set[str]

        # Make these managers available to all material models
        self._container_registry = self._application.getInstance(
        ).getContainerRegistry()
        self._machine_manager = self._application.getMachineManager()

        self._extruder_position = 0
        self._extruder_stack = None
        self._enabled = True

        # CURA-6904
        # Updating the material model requires information from material nodes and containers. We use a timer here to
        # make sure that an update function call will not be directly invoked by an event. Because the triggered event
        # can be caused in the middle of a XMLMaterial loading, and the material container we try to find may not be
        # in the system yet. This will cause an infinite recursion of (1) trying to load a material, (2) trying to
        # update the material model, (3) cannot find the material container, load it, (4) repeat #1.
        self._update_timer = QTimer()
        self._update_timer.setInterval(100)
        self._update_timer.setSingleShot(True)
        self._update_timer.timeout.connect(self._update)

        # Update the stack and the model data when the machine changes
        self._machine_manager.globalContainerChanged.connect(
            self._updateExtruderStack)
        self._updateExtruderStack()

        # Update this model when switching machines or tabs, when adding materials or changing their metadata.
        self._machine_manager.activeStackChanged.connect(self._onChanged)
        ContainerTree.getInstance().materialsChanged.connect(
            self._materialsListChanged)
        self._application.getMaterialManagementModel(
        ).favoritesChanged.connect(self._onChanged)

        self.addRoleName(Qt.UserRole + 1, "root_material_id")
        self.addRoleName(Qt.UserRole + 2, "id")
        self.addRoleName(Qt.UserRole + 3, "GUID")
        self.addRoleName(Qt.UserRole + 4, "name")
        self.addRoleName(Qt.UserRole + 5, "brand")
        self.addRoleName(Qt.UserRole + 6, "description")
        self.addRoleName(Qt.UserRole + 7, "material")
        self.addRoleName(Qt.UserRole + 8, "color_name")
        self.addRoleName(Qt.UserRole + 9, "color_code")
        self.addRoleName(Qt.UserRole + 10, "density")
        self.addRoleName(Qt.UserRole + 11, "diameter")
        self.addRoleName(Qt.UserRole + 12, "approximate_diameter")
        self.addRoleName(Qt.UserRole + 13, "adhesion_info")
        self.addRoleName(Qt.UserRole + 14, "is_read_only")
        self.addRoleName(Qt.UserRole + 15, "container_node")
        self.addRoleName(Qt.UserRole + 16, "is_favorite")
Esempio n. 4
0
def test_alreadyKnownMachineAdded(container_registry):
    mocked_definition_container = MagicMock(spec=DefinitionContainer)
    mocked_definition_container.getId = MagicMock(return_value="machine_2")

    with patch("UM.Settings.ContainerRegistry.ContainerRegistry.getInstance",
               MagicMock(return_value=container_registry)):
        container_tree = ContainerTree()
        assert len(container_tree.machines) == 2

        # The ID is already there, so no machine should be added.
        container_tree._machineAdded(mocked_definition_container)
        assert len(container_tree.machines) == 2
Esempio n. 5
0
def test_containerTreeInit(container_registry):
    with patch("UM.Settings.ContainerRegistry.ContainerRegistry.getInstance",
               MagicMock(return_value=container_registry)):
        container_tree = ContainerTree()

    assert "machine_1" in container_tree.machines
    assert "machine_2" in container_tree.machines
Esempio n. 6
0
    def updateHasMaterialsMetadata(self):
        machine_manager = self._application.getMachineManager()
        global_stack = machine_manager.activeMachine

        definition = global_stack.definition
        if definition.getProperty("machine_gcode_flavor", "value") != "UltiGCode" or definition.getMetaDataEntry(
                "has_materials", False):
            # In other words: only continue for the UM2 (extended), but not for the UM2+
            return

        has_materials = global_stack.getProperty("machine_gcode_flavor", "value") != "UltiGCode"

        material_node = None
        if has_materials:
            global_stack.setMetaDataEntry("has_materials", True)
        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_materials" in global_stack.getMetaData():
                global_stack.removeMetaDataEntry("has_materials")

        # set materials
        for position, extruder in enumerate(global_stack.extruderList):
            if has_materials:
                approximate_diameter = extruder.getApproximateMaterialDiameter()
                variant_node = ContainerTree.getInstance().machines[global_stack.definition.getId()].variants[extruder.variant.getName()]
                material_node = variant_node.preferredMaterial(approximate_diameter)
            machine_manager.setMaterial(str(position), material_node)

        self.forceUpdate()
Esempio n. 7
0
    def getCurrentAvailableIntents(self) -> List[Tuple[str, str]]:
        application = cura.CuraApplication.CuraApplication.getInstance()
        global_stack = application.getGlobalContainerStack()
        if global_stack is None:
            return [("default", "normal")]
            # TODO: We now do this (return a default) if the global stack is missing, but not in the code below,
            #       even though there should always be defaults. The problem then is what to do with the quality_types.
            #       Currently _also_ inconsistent with 'currentAvailableIntentCategories', which _does_ return default.
        quality_groups = ContainerTree.getInstance().getCurrentQualityGroups()
        available_quality_types = {
            quality_group.quality_type
            for quality_group in quality_groups.values()
            if quality_group.node_for_global is not None
        }

        final_intent_ids = set()  # type: Set[str]
        current_definition_id = global_stack.definition.getId()
        for extruder_stack in global_stack.extruderList:
            nozzle_name = extruder_stack.variant.getMetaDataEntry("name")
            material_id = extruder_stack.material.getMetaDataEntry("base_file")
            final_intent_ids |= {
                metadata["id"]
                for metadata in self.intentMetadatas(current_definition_id,
                                                     nozzle_name, material_id)
                if metadata.get("quality_type") in available_quality_types
            }

        result = set()  # type: Set[Tuple[str, str]]
        for intent_id in final_intent_ids:
            intent_metadata = application.getContainerRegistry(
            ).findContainersMetadata(id=intent_id)[0]
            result.add((intent_metadata["intent_category"],
                        intent_metadata["quality_type"]))
        return list(result)
Esempio n. 8
0
    def _loadProfile(self, serialized: str,
                     profile_id: str) -> Optional[InstanceContainer]:
        """Load a profile from a serialized string.

        :param serialized: The profile data to read.
        :param profile_id: The name of the profile.
        :return: The profile that was stored in the string.
        """

        # Create an empty profile.
        profile = InstanceContainer(profile_id)
        profile.setMetaDataEntry("type", "quality_changes")
        try:
            profile.deserialize(serialized, file_name=profile_id)
        except ContainerFormatError as e:
            Logger.log("e", "Error in the format of a container: %s", str(e))
            return None
        except Exception as e:
            Logger.log("e", "Error while trying to parse profile: %s", str(e))
            return None

        global_stack = CuraApplication.getInstance().getGlobalContainerStack()
        if global_stack is None:
            return None

        active_quality_definition = ContainerTree.getInstance().machines[
            global_stack.definition.getId()].quality_definition
        if profile.getMetaDataEntry("definition") != active_quality_definition:
            profile.setMetaDataEntry("definition", active_quality_definition)
        return profile
Esempio n. 9
0
    def _createQualityChanges(
            self, quality_type: str, intent_category: Optional[str],
            new_name: str, machine: "GlobalStack",
            extruder_stack: Optional["ExtruderStack"]) -> "InstanceContainer":
        container_registry = cura.CuraApplication.CuraApplication.getInstance(
        ).getContainerRegistry()
        base_id = machine.definition.getId(
        ) if extruder_stack is None else extruder_stack.getId()
        new_id = base_id + "_" + new_name
        new_id = new_id.lower().replace(" ", "_")
        new_id = container_registry.uniqueName(new_id)

        # Create a new quality_changes container for the quality.
        quality_changes = InstanceContainer(new_id)
        quality_changes.setName(new_name)
        quality_changes.setMetaDataEntry("type", "quality_changes")
        quality_changes.setMetaDataEntry("quality_type", quality_type)
        if intent_category is not None:
            quality_changes.setMetaDataEntry("intent_category",
                                             intent_category)

        # If we are creating a container for an extruder, ensure we add that to the container.
        if extruder_stack is not None:
            quality_changes.setMetaDataEntry(
                "position", extruder_stack.getMetaDataEntry("position"))

        # If the machine specifies qualities should be filtered, ensure we match the current criteria.
        machine_definition_id = ContainerTree.getInstance().machines[
            machine.definition.getId()].quality_definition
        quality_changes.setDefinition(machine_definition_id)

        quality_changes.setMetaDataEntry(
            "setting_version",
            cura.CuraApplication.CuraApplication.getInstance().SettingVersion)
        return quality_changes
    def _update(self):
        Logger.log(
            "d", "Updating {model_class_name}.".format(
                model_class_name=self.__class__.__name__))

        # CURA-6836
        # LabelBar is a repeater that creates labels for quality layer heights. Because of an optimization in
        # UM.ListModel, the model will not remove all items and recreate new ones every time there's an update.
        # Because LabelBar uses Repeater with Labels anchoring to "undefined" in certain cases, the anchoring will be
        # kept the same as before.
        self.setItems([])

        global_stack = cura.CuraApplication.CuraApplication.getInstance(
        ).getGlobalContainerStack()
        if global_stack is None:
            self.setItems([])
            Logger.log(
                "d",
                "No active GlobalStack, set quality profile model as empty.")
            return

        if not self._layer_height_unit:
            unit = global_stack.definition.getProperty("layer_height", "unit")
            if not unit:
                unit = ""
            self._layer_height_unit = unit

        # Check for material compatibility
        if not cura.CuraApplication.CuraApplication.getInstance(
        ).getMachineManager().activeMaterialsCompatible():
            Logger.log(
                "d",
                "No active material compatibility, set quality profile model as empty."
            )
            self.setItems([])
            return

        quality_group_dict = ContainerTree.getInstance(
        ).getCurrentQualityGroups()

        item_list = []
        for quality_group in quality_group_dict.values():
            # layer_height = fetchLayerHeight(quality_group)

            item = {
                "name": quality_group.name,
                "quality_type": quality_group.quality_type,
                # "layer_height": layer_height,
                # "layer_height_unit": self._layer_height_unit,
                "available": quality_group.is_available,
                "quality_group": quality_group,
                "is_experimental": quality_group.is_experimental
            }

            item_list.append(item)

        # Sort items based on layer_height
        # item_list = sorted(item_list, key = lambda x: x["layer_height"])

        self.setItems(item_list)
    def _update(self) -> None:
        Logger.log(
            "d", "Updating {model_class_name}.".format(
                model_class_name=self.__class__.__name__))

        active_global_stack = cura.CuraApplication.CuraApplication.getInstance(
        ).getMachineManager().activeMachine
        if active_global_stack is None:
            self.setItems([])
            Logger.log("d", "No active GlobalStack, set %s as empty.",
                       self.__class__.__name__)
            return

        quality_changes_list = ContainerTree.getInstance(
        ).getCurrentQualityChangesGroups()

        item_list = []
        for quality_changes_group in sorted(quality_changes_list,
                                            key=lambda qgc: qgc.name.lower()):
            item = {
                "name": quality_changes_group.name,
                "layer_height": "",
                "layer_height_without_unit": "",
                "available": quality_changes_group.is_available,
                "quality_changes_group": quality_changes_group
            }

            item_list.append(item)

        self.setItems(item_list)
Esempio n. 12
0
    def resetMaterialsQualitiesAndUninstall(self) -> None:
        application = CuraApplication.getInstance()
        machine_manager = application.getMachineManager()
        container_tree = ContainerTree.getInstance()

        for global_stack, extruder_nr, container_id in self._package_used_materials:
            extruder = global_stack.extruderList[int(extruder_nr)]
            approximate_diameter = extruder.getApproximateMaterialDiameter()
            variant_node = container_tree.machines[global_stack.definition.getId()].variants[extruder.variant.getName()]
            default_material_node = variant_node.preferredMaterial(approximate_diameter)
            machine_manager.setMaterial(extruder_nr, default_material_node, global_stack = global_stack)
        for global_stack, extruder_nr, container_id in self._package_used_qualities:
            variant_names = [extruder.variant.getName() for extruder in global_stack.extruderList]
            material_bases = [extruder.material.getMetaDataEntry("base_file") for extruder in global_stack.extruderList]
            extruder_enabled = [extruder.isEnabled for extruder in global_stack.extruderList]
            definition_id = global_stack.definition.getId()
            machine_node = container_tree.machines[definition_id]
            default_quality_group = machine_node.getQualityGroups(variant_names, material_bases, extruder_enabled)[machine_node.preferred_quality_type]
            machine_manager.setQualityGroup(default_quality_group, global_stack = global_stack)

        if self._package_id_to_uninstall is not None:
            self._markPackageMaterialsAsToBeUninstalled(self._package_id_to_uninstall)
            self.uninstall(self._package_id_to_uninstall)
        self._resetUninstallVariables()
        self.closeConfirmResetDialog()
Esempio n. 13
0
    def intentMetadatas(self, definition_id: str, nozzle_name: str,
                        material_base_file: str) -> List[Dict[str, Any]]:
        """Gets the metadata dictionaries of all intent profiles for a given

        configuration.

        :param definition_id: ID of the printer.
        :param nozzle_name: Name of the nozzle.
        :param material_base_file: The base_file of the material.
        :return: A list of metadata dictionaries matching the search criteria, or
            an empty list if nothing was found.
        """
        intent_metadatas = []  # type: List[Dict[str, Any]]
        try:
            materials = ContainerTree.getInstance(
            ).machines[definition_id].variants[nozzle_name].materials
        except KeyError:
            Logger.log("w", "Unable to find the machine %s or the variant %s",
                       definition_id, nozzle_name)
            materials = {}
        if material_base_file not in materials:
            return intent_metadatas

        material_node = materials[material_base_file]
        for quality_node in material_node.qualities.values():
            for intent_node in quality_node.intents.values():
                intent_metadatas.append(intent_node.getMetadata())
        return intent_metadatas
Esempio n. 14
0
    def _update(self) -> None:
        new_items = []  # type: List[Dict[str, Any]]
        global_stack = cura.CuraApplication.CuraApplication.getInstance().getGlobalContainerStack()
        if not global_stack:
            self.setItems(new_items)
            return
        quality_groups = ContainerTree.getInstance().getCurrentQualityGroups()

        material_nodes = self._getActiveMaterials()

        added_quality_type_set = set()  # type: Set[str]
        for material_node in material_nodes:
            intents = self._getIntentsForMaterial(material_node, quality_groups)
            for intent in intents:
                if intent["quality_type"] not in added_quality_type_set:
                    new_items.append(intent)
                    added_quality_type_set.add(intent["quality_type"])

        # Now that we added all intents that we found something for, ensure that we set add ticks (and layer_heights)
        # for all groups that we don't have anything for (and set it to not available)
        for quality_type, quality_group in quality_groups.items():
            # Add the intents that are of the correct category
            if quality_type not in added_quality_type_set:
                layer_height = fetchLayerHeight(quality_group)
                new_items.append({"name": "Unavailable",
                                  "quality_type": quality_type,
                                  "layer_height": layer_height,
                                  "intent_category": self._intent_category,
                                  "available": False})
                added_quality_type_set.add(quality_type)

        new_items = sorted(new_items, key = lambda x: x["layer_height"])
        self.setItems(new_items)
Esempio n. 15
0
    def _update(self):
        """This is an abstract method that needs to be implemented by the specific models themselves. """

        self._favorite_ids = set(
            cura.CuraApplication.CuraApplication.getInstance().getPreferences(
            ).getValue("cura/favorite_materials").split(";"))

        # Update the available materials (ContainerNode) for the current active machine and extruder setup.
        global_stack = cura.CuraApplication.CuraApplication.getInstance(
        ).getGlobalContainerStack()
        if not global_stack or not global_stack.hasMaterials:
            return  # There are no materials for this machine, so nothing to do.
        extruder_list = global_stack.extruderList
        if self._extruder_position > len(extruder_list):
            return
        extruder_stack = extruder_list[self._extruder_position]
        nozzle_name = extruder_stack.variant.getName()
        machine_node = ContainerTree.getInstance().machines[
            global_stack.definition.getId()]
        if nozzle_name not in machine_node.variants:
            Logger.log("w", "Unable to find variant %s in container tree",
                       nozzle_name)
            self._available_materials = {}
            return
        materials = machine_node.variants[nozzle_name].materials
        approximate_material_diameter = extruder_stack.getApproximateMaterialDiameter(
        )
        self._available_materials = {
            key: material
            for key, material in materials.items()
            if float(material.getMetaDataEntry("approximate_diameter", -1)) ==
            approximate_material_diameter
        }
Esempio n. 16
0
    def getDefaultMaterial(
        self,
        global_stack: "GlobalStack",
        position: str,
        nozzle_name: Optional[str],
        extruder_definition: Optional["DefinitionContainer"] = None
    ) -> "MaterialNode":
        definition_id = global_stack.definition.getId()
        machine_node = ContainerTree.getInstance().machines[definition_id]
        if nozzle_name in machine_node.variants:
            nozzle_node = machine_node.variants[nozzle_name]
        else:
            Logger.log(
                "w",
                "Could not find variant {nozzle_name} for machine with definition {definition_id} in the container tree"
                .format(nozzle_name=nozzle_name, definition_id=definition_id))
            nozzle_node = next(iter(machine_node.variants))

        if not parseBool(global_stack.getMetaDataEntry("has_materials",
                                                       False)):
            return next(iter(nozzle_node.materials))

        if extruder_definition is not None:
            material_diameter = extruder_definition.getProperty(
                "material_diameter", "value")
        else:
            material_diameter = global_stack.extruders[
                position].getCompatibleMaterialDiameter()
        approximate_material_diameter = round(material_diameter)

        return nozzle_node.preferredMaterial(approximate_material_diameter)
Esempio n. 17
0
    def createMaterial(self) -> str:
        """Create a new material by cloning the preferred material for the current material diameter and generate a new
        GUID.

        The material type is explicitly left to be the one from the preferred material, since this allows the user to
        still have SOME profiles to work with.

        :return: The ID of the newly created material.
        """

        # Ensure all settings are saved.
        application = cura.CuraApplication.CuraApplication.getInstance()
        application.saveSettings()

        # Find the preferred material.
        extruder_stack = application.getMachineManager().activeStack
        active_variant_name = extruder_stack.variant.getName()
        approximate_diameter = int(extruder_stack.approximateMaterialDiameter)
        global_container_stack = application.getGlobalContainerStack()
        if not global_container_stack:
            return ""
        machine_node = ContainerTree.getInstance().machines[global_container_stack.definition.getId()]
        preferred_material_node = machine_node.variants[active_variant_name].preferredMaterial(approximate_diameter)

        # Create a new ID & new metadata for the new material.
        new_id = CuraContainerRegistry.getInstance().uniqueName("custom_material")
        new_metadata = {"name": catalog.i18nc("@label", "Custom Material"),
                        "brand": catalog.i18nc("@label", "Custom"),
                        "GUID": str(uuid.uuid4()),
                        }

        self.duplicateMaterial(preferred_material_node, new_base_id = new_id, new_metadata = new_metadata)
        return new_id
Esempio n. 18
0
    def getMaterialNode(self, machine_definition_id: str,
                        nozzle_name: Optional[str],
                        buildplate_name: Optional[str], diameter: float,
                        root_material_id: str) -> Optional["MaterialNode"]:
        container_tree = ContainerTree.getInstance()
        machine_node = container_tree.machines.get(machine_definition_id)
        if machine_node is None:
            Logger.log(
                "w",
                "Could not find machine with definition %s in the container tree",
                machine_definition_id)
            return None

        variant_node = machine_node.variants.get(nozzle_name)
        if variant_node is None:
            Logger.log(
                "w",
                "Could not find variant %s for machine with definition %s in the container tree",
                nozzle_name, machine_definition_id)
            return None

        material_node = variant_node.materials.get(root_material_id)

        if material_node is None:
            Logger.log(
                "w",
                "Could not find material %s for machine with definition %s and variant %s in the container tree",
                root_material_id, machine_definition_id, nozzle_name)
            return None

        return material_node
Esempio n. 19
0
    def _update(self):
        Logger.log(
            "d", "Updating {model_class_name}.".format(
                model_class_name=self.__class__.__name__))

        global_stack = self._machine_manager.activeMachine
        if global_stack is None:
            self.setItems([])
            return
        machine_node = ContainerTree.getInstance().machines[
            global_stack.definition.getId()]

        if not machine_node.has_variants:
            self.setItems([])
            return

        item_list = []
        for hotend_name, container_node in sorted(
                machine_node.variants.items(), key=lambda i: i[0].upper()):
            item = {
                "id": hotend_name,
                "hotend_name": hotend_name,
                "container_node": container_node
            }

            item_list.append(item)

        self.setItems(item_list)
Esempio n. 20
0
    def getExtruderHasQualityForMaterial(
            self, extruder_stack: "ExtruderStack") -> bool:
        """Checks if quality nodes exist for the variant/material combination."""
        application = cura.CuraApplication.CuraApplication.getInstance()
        global_stack = application.getGlobalContainerStack()
        if not global_stack or not extruder_stack:
            return False

        if not global_stack.getMetaDataEntry("has_materials"):
            return True

        machine_node = ContainerTree.getInstance().machines[
            global_stack.definition.getId()]

        active_variant_name = extruder_stack.variant.getMetaDataEntry("name")
        if active_variant_name not in machine_node.variants:
            Logger.log("w", "Could not find the variant %s",
                       active_variant_name)
            return True
        active_variant_node = machine_node.variants[active_variant_name]
        try:
            active_material_node = active_variant_node.materials[
                extruder_stack.material.getMetaDataEntry("base_file")]
        except KeyError:  # The material in this stack is not a supported material (e.g. wrong filament diameter, as loaded from a project file).
            return False

        active_material_node_qualities = active_material_node.qualities
        if not active_material_node_qualities:
            return False
        return list(
            active_material_node_qualities.keys())[0] != "empty_quality"
Esempio n. 21
0
    def _update(self):
        self._favorite_ids = set(
            cura.CuraApplication.CuraApplication.getInstance().getPreferences(
            ).getValue("cura/favorite_materials").split(";"))

        # Update the available materials (ContainerNode) for the current active machine and extruder setup.
        global_stack = cura.CuraApplication.CuraApplication.getInstance(
        ).getGlobalContainerStack()
        if not global_stack.hasMaterials:
            return  # There are no materials for this machine, so nothing to do.
        extruder_stack = global_stack.extruders.get(
            str(self._extruder_position))
        if not extruder_stack:
            return
        nozzle_name = extruder_stack.variant.getName()
        machine_node = ContainerTree.getInstance().machines[
            global_stack.definition.getId()]
        if nozzle_name not in machine_node.variants:
            Logger.log("w", "Unable to find variant %s in container tree",
                       nozzle_name)
            self._available_materials = {}
            return
        materials = machine_node.variants[nozzle_name].materials
        approximate_material_diameter = extruder_stack.getApproximateMaterialDiameter(
        )
        self._available_materials = {
            key: material
            for key, material in materials.items()
            if float(material.getMetaDataEntry("approximate_diameter", -1)) ==
            approximate_material_diameter
        }
Esempio n. 22
0
    def _getActiveMaterials(self) -> Set["MaterialNode"]:
        """Get the active materials for all extruders. No duplicates will be returned"""

        global_stack = cura.CuraApplication.CuraApplication.getInstance(
        ).getGlobalContainerStack()
        if global_stack is None:
            return set()

        container_tree = ContainerTree.getInstance()
        machine_node = container_tree.machines[global_stack.definition.getId()]
        nodes = set()  # type: Set[MaterialNode]

        for extruder in global_stack.extruderList:
            active_variant_name = extruder.variant.getMetaDataEntry("name")
            if active_variant_name not in machine_node.variants:
                Logger.log("w", "Could not find the variant %s",
                           active_variant_name)
                continue
            active_variant_node = machine_node.variants[active_variant_name]
            active_material_node = active_variant_node.materials.get(
                extruder.material.getMetaDataEntry("base_file"))
            if active_material_node is None:
                Logger.log("w", "Could not find the material %s",
                           extruder.material.getMetaDataEntry("base_file"))
                continue
            nodes.add(active_material_node)

        return nodes
Esempio n. 23
0
    def _configureProfile(self, profile: InstanceContainer, id_seed: str, new_name: str, machine_definition_id: str) -> Optional[str]:
        """Update an imported profile to match the current machine configuration.

        :param profile: The profile to configure.
        :param id_seed: The base ID for the profile. May be changed so it does not conflict with existing containers.
        :param new_name: The new name for the profile.

        :return: None if configuring was successful or an error message if an error occurred.
        """

        profile.setDirty(True)  # Ensure the profiles are correctly saved

        new_id = self.createUniqueName("quality_changes", "", id_seed, catalog.i18nc("@label", "Custom profile"))
        profile.setMetaDataEntry("id", new_id)
        profile.setName(new_name)

        # Set the unique Id to the profile, so it's generating a new one even if the user imports the same profile
        # It also solves an issue with importing profiles from G-Codes
        profile.setMetaDataEntry("id", new_id)
        profile.setMetaDataEntry("definition", machine_definition_id)

        if "type" in profile.getMetaData():
            profile.setMetaDataEntry("type", "quality_changes")
        else:
            profile.setMetaDataEntry("type", "quality_changes")

        quality_type = profile.getMetaDataEntry("quality_type")
        if not quality_type:
            return catalog.i18nc("@info:status", "Profile is missing a quality type.")

        global_stack = cura.CuraApplication.CuraApplication.getInstance().getGlobalContainerStack()
        if global_stack is None:
            return None
        definition_id = ContainerTree.getInstance().machines[global_stack.definition.getId()].quality_definition
        profile.setDefinition(definition_id)

        # 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.
        quality_group_dict = ContainerTree.getInstance().getCurrentQualityGroups()
        # "not_supported" profiles can be imported.
        if quality_type != empty_quality_container.getMetaDataEntry("quality_type") and quality_type not in quality_group_dict:
            return catalog.i18nc("@info:status", "Could not find a quality type {0} for the current configuration.", quality_type)

        ContainerRegistry.getInstance().addContainer(profile)

        return None
Esempio n. 24
0
    def __init__(self, parent=None):
        super().__init__(parent)
        from cura.CuraApplication import CuraApplication

        self._application = CuraApplication.getInstance()

        self._available_materials = {}  # type: Dict[str, MaterialNode]
        self._favorite_ids = set()  # type: Set[str]

        # Make these managers available to all material models
        self._container_registry = self._application.getInstance(
        ).getContainerRegistry()
        self._machine_manager = self._application.getMachineManager()

        self._extruder_position = 0
        self._extruder_stack = None
        self._enabled = True

        # Update the stack and the model data when the machine changes
        self._machine_manager.globalContainerChanged.connect(
            self._updateExtruderStack)
        self._updateExtruderStack()

        # Update this model when switching machines, when adding materials or changing their metadata.
        self._machine_manager.activeStackChanged.connect(self._update)
        ContainerTree.getInstance().materialsChanged.connect(
            self._materialsListChanged)
        self._application.getMaterialManagementModel(
        ).favoritesChanged.connect(self._update)

        self.addRoleName(Qt.UserRole + 1, "root_material_id")
        self.addRoleName(Qt.UserRole + 2, "id")
        self.addRoleName(Qt.UserRole + 3, "GUID")
        self.addRoleName(Qt.UserRole + 4, "name")
        self.addRoleName(Qt.UserRole + 5, "brand")
        self.addRoleName(Qt.UserRole + 6, "description")
        self.addRoleName(Qt.UserRole + 7, "material")
        self.addRoleName(Qt.UserRole + 8, "color_name")
        self.addRoleName(Qt.UserRole + 9, "color_code")
        self.addRoleName(Qt.UserRole + 10, "density")
        self.addRoleName(Qt.UserRole + 11, "diameter")
        self.addRoleName(Qt.UserRole + 12, "approximate_diameter")
        self.addRoleName(Qt.UserRole + 13, "adhesion_info")
        self.addRoleName(Qt.UserRole + 14, "is_read_only")
        self.addRoleName(Qt.UserRole + 15, "container_node")
        self.addRoleName(Qt.UserRole + 16, "is_favorite")
Esempio n. 25
0
    def updateQualityChanges(self) -> bool:
        application = cura.CuraApplication.CuraApplication.getInstance()
        global_stack = application.getMachineManager().activeMachine
        if not global_stack:
            return False

        application.getMachineManager().blurSettings.emit()

        current_quality_changes_name = global_stack.qualityChanges.getName()
        current_quality_type = global_stack.quality.getMetaDataEntry(
            "quality_type")
        extruder_stacks = list(global_stack.extruders.values())
        container_registry = cura.CuraApplication.CuraApplication.getInstance(
        ).getContainerRegistry()
        machine_definition_id = ContainerTree.getInstance().machines[
            global_stack.definition.getId()].quality_definition
        for stack in [global_stack] + extruder_stacks:
            # Find the quality_changes container for this stack and merge the contents of the top container into it.
            quality_changes = stack.qualityChanges

            if quality_changes.getId() == "empty_quality_changes":
                quality_changes = InstanceContainer(
                    container_registry.uniqueName(
                        (stack.getId() + "_" +
                         current_quality_changes_name).lower().replace(
                             " ", "_")))
                quality_changes.setName(current_quality_changes_name)
                quality_changes.setMetaDataEntry("type", "quality_changes")
                quality_changes.setMetaDataEntry("quality_type",
                                                 current_quality_type)
                if stack.getMetaDataEntry(
                        "position") is not None:  # Extruder stacks.
                    quality_changes.setMetaDataEntry(
                        "position", stack.getMetaDataEntry("position"))
                    quality_changes.setMetaDataEntry(
                        "intent_category",
                        stack.quality.getMetaDataEntry("intent_category",
                                                       "default"))
                quality_changes.setMetaDataEntry("setting_version",
                                                 application.SettingVersion)
                quality_changes.setDefinition(machine_definition_id)
                container_registry.addContainer(quality_changes)
                stack.qualityChanges = quality_changes

            if not quality_changes or container_registry.isReadOnly(
                    quality_changes.getId()):
                Logger.log(
                    "e",
                    "Could not update quality of a nonexistant or read only quality profile in stack %s",
                    stack.getId())
                continue

            self._performMerge(quality_changes, stack.getTop())

        cura.CuraApplication.CuraApplication.getInstance().getMachineManager(
        ).activeQualityChangesGroupChanged.emit()

        return True
Esempio n. 26
0
 def getDefaultQualityType(
         self, machine: "GlobalStack") -> Optional[QualityGroup]:
     machine_node = ContainerTree.getInstance().machines[
         machine.definition.getId()]
     quality_groups = self.getQualityGroups(machine)
     result = quality_groups.get(machine_node.preferred_quality_type)
     if result is not None and result.is_available:
         return result
     return None  # If preferred quality type is not available, leave it up for the caller.
Esempio n. 27
0
 def intentMetadatas(self, definition_id: str, nozzle_name: str,
                     material_base_file: str) -> List[Dict[str, Any]]:
     material_node = ContainerTree.getInstance().machines[
         definition_id].variants[nozzle_name].materials[material_base_file]
     intent_metadatas = []
     for quality_node in material_node.qualities.values():
         for intent_node in quality_node.intents.values():
             intent_metadatas.append(intent_node.getMetadata())
     return intent_metadatas
Esempio n. 28
0
    def createMachine(cls, name: str, definition_id: str) -> Optional[GlobalStack]:
        """Create a new instance of a machine.

        :param name: The name of the new machine.
        :param definition_id: The ID of the machine definition to use.

        :return: The new global stack or None if an error occurred.
        """

        from cura.CuraApplication import CuraApplication
        application = CuraApplication.getInstance()
        registry = application.getContainerRegistry()
        container_tree = ContainerTree.getInstance()

        definitions = registry.findDefinitionContainers(id = definition_id)
        if not definitions:
            ConfigurationErrorMessage.getInstance().addFaultyContainers(definition_id)
            Logger.log("w", "Definition {definition} was not found!", definition = definition_id)
            return None

        machine_definition = definitions[0]
        machine_node = container_tree.machines[machine_definition.getId()]

        generated_name = registry.createUniqueName("machine", "", name, machine_definition.getName())
        # Make sure the new name does not collide with any definition or (quality) profile
        # createUniqueName() only looks at other stacks, but not at definitions or quality profiles
        # Note that we don't go for uniqueName() immediately because that function matches with ignore_case set to true
        if registry.findContainersMetadata(id = generated_name):
            generated_name = registry.uniqueName(generated_name)

        new_global_stack = cls.createGlobalStack(
            new_stack_id = generated_name,
            definition = machine_definition,
            variant_container = application.empty_variant_container,
            material_container = application.empty_material_container,
            quality_container = machine_node.preferredGlobalQuality().container,
        )
        new_global_stack.setName(generated_name)

        # Create ExtruderStacks
        extruder_dict = machine_definition.getMetaDataEntry("machine_extruder_trains")
        for position in extruder_dict:
            try:
                cls.createExtruderStackWithDefaultSetup(new_global_stack, position)
            except IndexError:
                return None

        for new_extruder in new_global_stack.extruderList:  # Only register the extruders if we're sure that all of them are correct.
            registry.addContainer(new_extruder)

        # Register the global stack after the extruder stacks are created. This prevents the registry from adding another
        # extruder stack because the global stack didn't have one yet (which is enforced since Cura 3.1).
        registry.addContainer(new_global_stack)

        return new_global_stack
Esempio n. 29
0
    def createMachine(cls, name: str,
                      definition_id: str) -> Optional[GlobalStack]:
        from cura.CuraApplication import CuraApplication
        application = CuraApplication.getInstance()
        registry = application.getContainerRegistry()
        container_tree = ContainerTree.getInstance()

        definitions = registry.findDefinitionContainers(id=definition_id)
        if not definitions:
            ConfigurationErrorMessage.getInstance().addFaultyContainers(
                definition_id)
            Logger.log("w",
                       "Definition {definition} was not found!",
                       definition=definition_id)
            return None

        machine_definition = definitions[0]
        # The container tree listens to the containerAdded signal to add the definition and build the tree,
        # but that signal is emitted with a delay which might not have passed yet.
        # Therefore we must make sure that it's manually added here.
        container_tree.addMachineNodeByDefinitionId(machine_definition.getId())
        machine_node = container_tree.machines[machine_definition.getId()]

        generated_name = registry.createUniqueName(
            "machine", "", name, machine_definition.getName())
        # Make sure the new name does not collide with any definition or (quality) profile
        # createUniqueName() only looks at other stacks, but not at definitions or quality profiles
        # Note that we don't go for uniqueName() immediately because that function matches with ignore_case set to true
        if registry.findContainersMetadata(id=generated_name):
            generated_name = registry.uniqueName(generated_name)

        new_global_stack = cls.createGlobalStack(
            new_stack_id=generated_name,
            definition=machine_definition,
            variant_container=application.empty_variant_container,
            material_container=application.empty_material_container,
            quality_container=machine_node.preferredGlobalQuality().container,
        )
        new_global_stack.setName(generated_name)

        # Create ExtruderStacks
        extruder_dict = machine_definition.getMetaDataEntry(
            "machine_extruder_trains")
        for position in extruder_dict:
            cls.createExtruderStackWithDefaultSetup(new_global_stack, position)

        for new_extruder in new_global_stack.extruders.values(
        ):  # Only register the extruders if we're sure that all of them are correct.
            registry.addContainer(new_extruder)

        # Register the global stack after the extruder stacks are created. This prevents the registry from adding another
        # extruder stack because the global stack didn't have one yet (which is enforced since Cura 3.1).
        registry.addContainer(new_global_stack)

        return new_global_stack
Esempio n. 30
0
    def createExtruderStackWithDefaultSetup(cls, global_stack: "GlobalStack",
                                            extruder_position: int) -> None:
        from cura.CuraApplication import CuraApplication
        application = CuraApplication.getInstance()
        registry = application.getContainerRegistry()

        # Get the extruder definition.
        extruder_definition_dict = global_stack.getMetaDataEntry(
            "machine_extruder_trains")
        extruder_definition_id = extruder_definition_dict[str(
            extruder_position)]
        try:
            extruder_definition = registry.findDefinitionContainers(
                id=extruder_definition_id)[0]
        except IndexError:
            # 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]" % extruder_definition_id
            Logger.logException("e", msg)
            raise IndexError(msg)

        # Find out what filament diameter we need.
        approximate_diameter = round(
            extruder_definition.getProperty("material_diameter", "value")
        )  # Can't be modified by definition changes since we are just initialising the stack here.

        # Find the preferred containers.
        machine_node = ContainerTree.getInstance().machines[
            global_stack.definition.getId()]
        extruder_variant_node = machine_node.variants.get(
            machine_node.preferred_variant_name)
        if not extruder_variant_node:
            Logger.log(
                "w",
                "Could not find preferred nozzle {nozzle_name}. Falling back to {fallback}."
                .format(nozzle_name=machine_node.preferred_variant_name,
                        fallback=next(iter(machine_node.variants))))
            extruder_variant_node = next(iter(machine_node.variants.values()))
        extruder_variant_container = extruder_variant_node.container
        material_node = extruder_variant_node.preferredMaterial(
            approximate_diameter)
        material_container = material_node.container
        quality_node = material_node.preferredQuality()

        new_extruder_id = registry.uniqueName(extruder_definition_id)
        new_extruder = cls.createExtruderStack(
            new_extruder_id,
            extruder_definition=extruder_definition,
            machine_definition_id=global_stack.definition.getId(),
            position=extruder_position,
            variant_container=extruder_variant_container,
            material_container=material_container,
            quality_container=quality_node.container)
        new_extruder.setNextStack(global_stack)

        registry.addContainer(new_extruder)