diff options
author | j.delarago <joeydelarago@gmail.com> | 2022-05-30 18:29:59 +0300 |
---|---|---|
committer | j.delarago <joeydelarago@gmail.com> | 2022-05-30 18:29:59 +0300 |
commit | 21d59e93492dc66198312bdd8dd17d91bc44d252 (patch) | |
tree | f5544f4323eebfd3423d068d9253d5574d26ffa5 | |
parent | 596c24657d39804c8bc94e6e8f99436115d7e411 (diff) |
Write active material metadata to ufp when saving.CURA-8610_save_package_metadata
Add function to fetch package_id using only information from XmlMaterialProfile material container.
The only piece of information associating the material container and the package together is the file_name. To find the package that owns a material we have to search each of the material package paths.
It would be great to find a cleaner solution (preferable one that doesn't require invalidating the cached containers).
CURA-8610
-rw-r--r-- | cura/CuraPackageManager.py | 20 | ||||
-rw-r--r-- | plugins/UFPWriter/UFPWriter.py | 61 | ||||
-rw-r--r-- | plugins/XmlMaterialProfile/XmlMaterialProfile.py | 3 |
3 files changed, 67 insertions, 17 deletions
diff --git a/cura/CuraPackageManager.py b/cura/CuraPackageManager.py index 17d6832ac6..b23422fbbd 100644 --- a/cura/CuraPackageManager.py +++ b/cura/CuraPackageManager.py @@ -1,5 +1,6 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +import os from typing import Any, cast, Dict, List, Set, Tuple, TYPE_CHECKING, Optional @@ -51,6 +52,25 @@ class CuraPackageManager(PackageManager): super().initialize() + def getMaterialFilePackageId(self, file_name: str, guid: str) -> str: + """Get the id of the material package that contains file_name""" + for material_package in [f for f in os.scandir(self._installation_dirs_dict["materials"]) if f.is_dir()]: + package_id = material_package.name + + for root, _, file_names in os.walk(material_package.path): + if file_name not in file_names: + #File with the name we are looking for is not in this directory + continue + + with open(root + "/" + file_name, encoding="utf-8") as f: + # Make sure the file we found has the same guid as our material + # Parsing this xml would be better but the namespace is needed to search it. + if guid in f.read(): + return package_id + continue + + + def getMachinesUsingPackage(self, package_id: str) -> Tuple[List[Tuple[GlobalStack, str, str]], List[Tuple[GlobalStack, str, str]]]: """Returns a list of where the package is used diff --git a/plugins/UFPWriter/UFPWriter.py b/plugins/UFPWriter/UFPWriter.py index 52dab1efc7..59067b1932 100644 --- a/plugins/UFPWriter/UFPWriter.py +++ b/plugins/UFPWriter/UFPWriter.py @@ -16,13 +16,14 @@ from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType from UM.PluginRegistry import PluginRegistry # To get the g-code writer. from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator -from UM.Scene.SceneNode import SceneNode from cura.CuraApplication import CuraApplication +from cura.CuraPackageManager import CuraPackageManager from cura.Utils.Threading import call_on_qt_thread from UM.i18n import i18nCatalog METADATA_OBJECTS_PATH = "metadata/objects" +METADATA_MATERIALS_PATH = "metadata/packages" catalog = i18nCatalog("cura") @@ -49,7 +50,7 @@ class UFPWriter(MeshWriter): archive.openStream(stream, "application/x-ufp", OpenMode.WriteOnly) try: - self._writeObjectList(archive) + self._writeMetadata(archive) # Store the g-code from the scene. archive.addContentType(extension = "gcode", mime_type = "text/x-gcode") @@ -163,30 +164,56 @@ class UFPWriter(MeshWriter): return True @staticmethod - def _writeObjectList(archive): - """Write a json list of object names to the METADATA_OBJECTS_PATH metadata field + def _writeMetadata(archive: VirtualFile): + material_metadata = UFPWriter._getMaterialPackageMetadata() + object_metadata = UFPWriter._getObjectMetadata() - To retrieve, use: `archive.getMetadata(METADATA_OBJECTS_PATH)` + data = {METADATA_MATERIALS_PATH: material_metadata, + METADATA_OBJECTS_PATH: object_metadata} + + archive.setMetadata(data) + + @staticmethod + def _getObjectMetadata() -> List[Dict[str, str]]: + """Get object metadata to write for a Node. + + :return: List of object metadata dictionaries. """ + metadata = [] objects_model = CuraApplication.getInstance().getObjectsModel() - object_metas = [] for item in objects_model.items: - object_metas.extend(UFPWriter._getObjectMetadata(item["node"])) + for node in DepthFirstIterator(item["node"]): + if node.getMeshData() is not None and not node.callDecoration("isNonPrintingMesh"): + metadata.extend({"name": node.getName()}) - data = {METADATA_OBJECTS_PATH: object_metas} - archive.setMetadata(data) + return metadata @staticmethod - def _getObjectMetadata(node: SceneNode) -> List[Dict[str, str]]: - """Get object metadata to write for a Node. + def _getMaterialPackageMetadata() -> List[Dict[str, str]]: + """Get metadata for installed materials in active extruder stack, this does not include bundled materials. - :return: List of object metadata dictionaries. - Might contain > 1 element in case of a group node. - Might be empty in case of nonPrintingMesh + :return: List of material metadata dictionaries. """ + metadata = [] + + package_manager = cast(CuraPackageManager, CuraApplication.getInstance().getPackageManager()) + + for extruder in CuraApplication.getInstance().getExtruderManager().getActiveExtruderStacks(): + package_id = package_manager.getMaterialFilePackageId(extruder.material.getFileName(), extruder.material.getMetaDataEntry("GUID")) + package_data = package_manager.getInstalledPackageInfo(package_id) + + if package_data.get("is_bundled"): + continue + + material_metadata = {"id": package_id, + "display_name": package_data.get("display_name"), + "website": package_data.get("website"), + "package_version": package_data.get("package_version"), + "sdk_version_semver": package_data.get("package_version_semver")} + + metadata.append(material_metadata) + + return metadata - return [{"name": item.getName()} - for item in DepthFirstIterator(node) - if item.getMeshData() is not None and not item.callDecoration("isNonPrintingMesh")] diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index 1b88272d49..d1da10399a 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -343,6 +343,9 @@ class XmlMaterialProfile(InstanceContainer): return stream.getvalue().decode("utf-8") + def getFileName(self): + return self.getMetaDataEntry("base_file") + ".xml.fdm_material" + # Recursively resolve loading inherited files def _resolveInheritance(self, file_name): xml = self._loadFile(file_name) |