From ddbb9937a1a92cf189511a68a90ec2dc65961f55 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Thu, 6 Jun 2024 13:49:01 +0300 Subject: [PATCH] QmlDesigner: Implement exporting an imported 3D component Fixes: QDS-12904 Change-Id: If8c597f00864a08a4ce47d7c09239a5c70a5026a Reviewed-by: Miikka Heikkinen --- .../contentlibrary/contentlibraryview.cpp | 93 ++++++++++++++++--- .../contentlibrary/contentlibraryview.h | 2 + 2 files changed, 83 insertions(+), 12 deletions(-) diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp index ca410dee11a..feb648665ef 100644 --- a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -26,7 +27,6 @@ #include #include #include - #include #include @@ -379,7 +379,11 @@ void ContentLibraryView::customNotification(const AbstractView *view, else addLib3DItem(nodeList.first()); } else if (identifier == "export_item_as_bundle") { - exportLib3DItem(nodeList.first()); + // TODO: support exporting 2D items + if (nodeList.first().isComponent()) + exportLib3DComponent(nodeList.first()); + else + exportLib3DItem(nodeList.first()); } else if (identifier == "export_material_as_bundle") { exportLib3DItem(nodeList.first(), data.first().value()); } @@ -676,14 +680,10 @@ void ContentLibraryView::addLibAssets(const QStringList &paths) void ContentLibraryView::addLib3DComponent(const ModelNode &node) { - auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils(); - QString compBaseName = node.simplifiedTypeName(); QString compFileName = compBaseName + ".qml"; - Utils::FilePath compDir = DocumentManager::currentProjectDirPath() - .pathAppended(compUtils.import3dTypePath() + '/' + compBaseName); - + auto compDir = Utils::FilePath::fromString(ModelUtils::componentFilePath(node)).parentDir(); auto bundlePath = Utils::FilePath::fromString(Paths::bundlesPathSetting() + "/User/3d/"); // confirm overwrite if an item with same name exists @@ -750,6 +750,71 @@ void ContentLibraryView::addLib3DComponent(const ModelNode &node) m_widget->userModel()->add3DItem(compBaseName, compFileName, m_iconSavePath.toUrl(), filesList); } +void ContentLibraryView::exportLib3DComponent(const ModelNode &node) +{ + QString exportPath = getExportPath(node); + if (exportPath.isEmpty()) + return; + + // targetPath is a temp path for collecting and zipping assets, actual export target is where + // the user chose to export (i.e. exportPath) + QTemporaryDir tempDir; + QTC_ASSERT(tempDir.isValid(), return); + auto targetPath = Utils::FilePath::fromString(tempDir.path()); + + m_zipWriter = std::make_unique(exportPath); + + QString compBaseName = node.simplifiedTypeName(); + QString compFileName = compBaseName + ".qml"; + + auto compDir = Utils::FilePath::fromString(ModelUtils::componentFilePath(node)).parentDir(); + + QString iconPath = QLatin1String("icons/%1").arg(UniqueName::generateId(compBaseName) + ".png"); + + const Utils::FilePaths sourceFiles = compDir.dirEntries({{}, QDir::Files, QDirIterator::Subdirectories}); + const QStringList ignoreList {"_importdata.json", "qmldir", compBaseName + ".hints"}; + QStringList filesList; // 3D component's assets (dependencies) + + for (const Utils::FilePath &sourcePath : sourceFiles) { + Utils::FilePath relativePath = sourcePath.relativePathFrom(compDir); + if (ignoreList.contains(sourcePath.fileName()) || relativePath.startsWith("source scene")) + continue; + + m_zipWriter->addFile(relativePath.toFSPathString(), sourcePath.fileContents().value_or("")); + + if (sourcePath.fileName() != compFileName) // skip component file (only collect dependencies) + filesList.append(relativePath.path()); + } + + // add the item to the bundle json + QJsonObject jsonObj; + QJsonArray itemsArr; + itemsArr.append(QJsonObject { + {"name", node.simplifiedTypeName()}, + {"qml", compFileName}, + {"icon", iconPath}, + {"files", QJsonArray::fromStringList(filesList)} + }); + + jsonObj["items"] = itemsArr; + + Utils::FilePath jsonFilePath = targetPath.pathAppended(Constants::BUNDLE_JSON_FILENAME); + m_zipWriter->addFile(jsonFilePath.fileName(), QJsonDocument(jsonObj).toJson()); + + // add icon + m_iconSavePath = targetPath.pathAppended(iconPath); + m_iconSavePath.parentDir().ensureWritableDir(); + getImageFromCache(compDir.pathAppended(compFileName).path(), [&](const QImage &image) { + QByteArray iconByteArray; + QBuffer buffer(&iconByteArray); + buffer.open(QIODevice::WriteOnly); + image.save(&buffer, "PNG"); + + m_zipWriter->addFile("icons/" + m_iconSavePath.fileName(), iconByteArray); + m_zipWriter->close(); + }); +} + void ContentLibraryView::addLib3DItem(const ModelNode &node) { auto bundlePath = Utils::FilePath::fromString(Paths::bundlesPathSetting() + "/User/3d/"); @@ -810,9 +875,8 @@ void ContentLibraryView::addLib3DItem(const ModelNode &node) m_widget->userModel()->add3DItem(name, qml, m_iconSavePath.toUrl(), depAssetsList); } -void ContentLibraryView::exportLib3DItem(const ModelNode &node, const QPixmap &iconPixmap) +QString ContentLibraryView::getExportPath(const ModelNode &node) { - // prompt and get the exported bundle path QString defaultExportFileName = QLatin1String("%1.%2").arg(node.id(), Constants::BUNDLE_SUFFIX); Utils::FilePath projectFP = DocumentManager::currentProjectDirPath(); if (projectFP.isEmpty()) { @@ -822,9 +886,14 @@ void ContentLibraryView::exportLib3DItem(const ModelNode &node, const QPixmap &i QString dialogTitle = node.metaInfo().isQtQuick3DMaterial() ? tr("Export Material") : tr("Export Component"); - QString exportPath = QFileDialog::getSaveFileName(m_widget, dialogTitle, - projectFP.pathAppended(defaultExportFileName).toFSPathString(), - tr("Qt Design Studio Bundle Files (*.%1)").arg(Constants::BUNDLE_SUFFIX)); + return QFileDialog::getSaveFileName(m_widget, dialogTitle, + projectFP.pathAppended(defaultExportFileName).toFSPathString(), + tr("Qt Design Studio Bundle Files (*.%1)").arg(Constants::BUNDLE_SUFFIX)); +} + +void ContentLibraryView::exportLib3DItem(const ModelNode &node, const QPixmap &iconPixmap) +{ + QString exportPath = getExportPath(node); if (exportPath.isEmpty()) return; diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h index 93840a20ed6..c109aace134 100644 --- a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h @@ -62,10 +62,12 @@ private: void addLibMaterial(const ModelNode &node, const QPixmap &iconPixmap); void addLibAssets(const QStringList &paths); void addLib3DComponent(const ModelNode &node); + void exportLib3DComponent(const ModelNode &node); void addLib3DItem(const ModelNode &node); void exportLib3DItem(const ModelNode &node, const QPixmap &iconPixmap = {}); void getImageFromCache(const QString &qmlPath, std::function successCallback); + QString getExportPath(const ModelNode &node); QPair> modelNodeToQmlString(const ModelNode &node, int depth = 0); #ifdef QDS_USE_PROJECTSTORAGE