From 5e3c0ffcc558f2971ce086e203c49b41b55faef7 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Wed, 23 Oct 2024 17:27:25 +0300 Subject: [PATCH] QmlDesigner: Add generated components when adding to content lib Also few relevant fixes and tweaks. Fixes: QDS-13746 Change-Id: I2a22d535591d6908ca3960145cb01682844aee38 Reviewed-by: Miikka Heikkinen Reviewed-by: Ali Kianian --- .../components/componentcore/bundlehelper.cpp | 36 ++++++++---------- .../components/componentcore/bundlehelper.h | 7 ++-- .../contentlibraryusermodel.cpp | 4 +- .../contentlibrary/contentlibraryview.cpp | 37 +++++++++++-------- .../contentlibrary/useritemcategory.cpp | 2 +- 5 files changed, 43 insertions(+), 43 deletions(-) diff --git a/src/plugins/qmldesigner/components/componentcore/bundlehelper.cpp b/src/plugins/qmldesigner/components/componentcore/bundlehelper.cpp index 1db2622e345..b7a17ce07f0 100644 --- a/src/plugins/qmldesigner/components/componentcore/bundlehelper.cpp +++ b/src/plugins/qmldesigner/components/componentcore/bundlehelper.cpp @@ -38,6 +38,11 @@ Utils::FilePath AssetPath::absFilPath() const return basePath.pathAppended(relativePath); } +QByteArray AssetPath::fileContent() const +{ + return absFilPath().fileContents().value_or(""); +} + BundleHelper::BundleHelper(AbstractView *view, QWidget *widget) : m_view(view) , m_widget(widget) @@ -186,7 +191,7 @@ void BundleHelper::importBundleToProject() } QString typePrefix = compUtils.userBundleType(bundleId); - TypeName type = QLatin1String("%1.%2").arg(typePrefix, qml.chopped(4)).toLatin1(); + TypeName type = QLatin1String("%1.%2").arg(typePrefix, qml.section('.', 0, 0)).toLatin1(); QString err = m_importer->importComponent(bundlePath.toFSPathString(), type, qml, files); @@ -211,12 +216,6 @@ void BundleHelper::exportComponent(const ModelNode &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); Utils::FilePath compFilePath = Utils::FilePath::fromString(ModelUtils::componentFilePath(node)); @@ -224,14 +223,14 @@ void BundleHelper::exportComponent(const ModelNode &node) QString compBaseName = compFilePath.completeBaseName(); QString compFileName = compFilePath.fileName(); - QString iconPath = QLatin1String("icons/%1").arg(UniqueName::generateId(compBaseName) + ".png"); + m_iconPath = QLatin1String("icons/%1").arg(UniqueName::generateId(compBaseName) + ".png"); const QSet compDependencies = getComponentDependencies(compFilePath, compDir); QStringList filesList; for (const AssetPath &asset : compDependencies) { Utils::FilePath assetAbsPath = asset.absFilPath(); - QByteArray assetContent = assetAbsPath.fileContents().value_or(""); + QByteArray assetContent = asset.fileContent(); // remove imports of sub components for (const QString &import : std::as_const(asset.importsToRemove)) { @@ -252,7 +251,7 @@ void BundleHelper::exportComponent(const ModelNode &node) itemsArr.append(QJsonObject { {"name", node.simplifiedTypeName()}, {"qml", compFileName}, - {"icon", iconPath}, + {"icon", m_iconPath}, {"files", QJsonArray::fromStringList(filesList)} }); @@ -262,12 +261,9 @@ void BundleHelper::exportComponent(const ModelNode &node) jsonObj["id"] = compUtils.user3DBundleId(); jsonObj["version"] = BUNDLE_VERSION; - Utils::FilePath jsonFilePath = targetPath.pathAppended(Constants::BUNDLE_JSON_FILENAME); - m_zipWriter->addFile(jsonFilePath.fileName(), QJsonDocument(jsonObj).toJson()); + m_zipWriter->addFile(Constants::BUNDLE_JSON_FILENAME, QJsonDocument(jsonObj).toJson()); // add icon - m_iconSavePath = targetPath.pathAppended(iconPath); - m_iconSavePath.parentDir().ensureWritableDir(); getImageFromCache(compFilePath.path(), [&](const QImage &image) { addIconAndCloseZip(image); }); @@ -293,6 +289,7 @@ void BundleHelper::exportNode(const ModelNode &node, const QPixmap &iconPixmap) QString qml = nodeNameToComponentFileName(name); QString iconBaseName = UniqueName::generateId(name); + m_iconPath = QLatin1String("icons/%1.png").arg(iconBaseName); // generate and save Qml file auto [qmlString, depAssets] = modelNodeToQmlString(node); @@ -307,15 +304,13 @@ void BundleHelper::exportNode(const ModelNode &node, const QPixmap &iconPixmap) QTC_ASSERT_EXPECTED(result, return); m_zipWriter->addFile(qmlFilePath.fileName(), qmlString.toUtf8()); - QString iconPath = QLatin1String("icons/%1.png").arg(iconBaseName); - // add the item to the bundle json QJsonObject jsonObj; QJsonArray itemsArr; itemsArr.append(QJsonObject { {"name", name}, {"qml", qml}, - {"icon", iconPath}, + {"icon", m_iconPath}, {"files", QJsonArray::fromStringList(depAssetsRelativePaths)} }); @@ -331,7 +326,7 @@ void BundleHelper::exportNode(const ModelNode &node, const QPixmap &iconPixmap) // add item's dependency assets to the bundle zip and target path (for icon generation) for (const AssetPath &assetPath : depAssetsList) { - auto assetContent = assetPath.absFilPath().fileContents().value_or(""); + QByteArray assetContent = assetPath.fileContent(); m_zipWriter->addFile(assetPath.relativePath, assetContent); Utils::FilePath assetTargetPath = targetPath.pathAppended(assetPath.relativePath); @@ -352,7 +347,6 @@ void BundleHelper::exportNode(const ModelNode &node, const QPixmap &iconPixmap) iconPixmapToSave = iconPixmap; } - m_iconSavePath = targetPath.pathAppended(iconPath); if (iconPixmapToSave.isNull()) { getImageFromCache(qmlFilePath.toFSPathString(), [&](const QImage &image) { addIconAndCloseZip(image); @@ -556,7 +550,7 @@ void BundleHelper::addIconAndCloseZip(const auto &image) { // auto: QImage or QP buffer.open(QIODevice::WriteOnly); image.save(&buffer, "PNG"); - m_zipWriter->addFile("icons/" + m_iconSavePath.fileName(), iconByteArray); + m_zipWriter->addFile(m_iconPath, iconByteArray); m_zipWriter->close(); }; @@ -664,7 +658,7 @@ Utils::FilePath getComponentFilePath(const QString &nodeType, const Utils::FileP } // namespace QSet BundleHelper::getComponentDependencies(const Utils::FilePath &filePath, - const Utils::FilePath &mainCompDir) + const Utils::FilePath &mainCompDir) const { QSet depList; AssetPath compAssetPath = {mainCompDir, filePath.relativePathFrom(mainCompDir).toFSPathString()}; diff --git a/src/plugins/qmldesigner/components/componentcore/bundlehelper.h b/src/plugins/qmldesigner/components/componentcore/bundlehelper.h index f853afea579..bb5da36bff0 100644 --- a/src/plugins/qmldesigner/components/componentcore/bundlehelper.h +++ b/src/plugins/qmldesigner/components/componentcore/bundlehelper.h @@ -32,6 +32,7 @@ public: {} Utils::FilePath absFilPath() const; + QByteArray fileContent() const; bool operator==(const AssetPath &other) const { @@ -62,6 +63,8 @@ public: QString nodeNameToComponentFileName(const QString &name) const; QPair> modelNodeToQmlString(const ModelNode &node, int depth = 0); QString getImportPath() const; + QSet getComponentDependencies(const Utils::FilePath &filePath, + const Utils::FilePath &mainCompDir) const; private: void createImporter(); @@ -71,8 +74,6 @@ private: void addIconAndCloseZip(const auto &image); Utils::FilePath componentPath(const NodeMetaInfo &metaInfo) const; QSet getBundleComponentDependencies(const ModelNode &node) const; - QSet getComponentDependencies(const Utils::FilePath &filePath, - const Utils::FilePath &mainCompDir); void exportComponent(const ModelNode &node); void exportNode(const ModelNode &node, const QPixmap &iconPixmap = QPixmap()); @@ -81,7 +82,7 @@ private: Utils::UniqueObjectPtr m_importer; std::unique_ptr m_zipWriter; std::unique_ptr m_tempDir; - Utils::FilePath m_iconSavePath; + QString m_iconPath; static constexpr char BUNDLE_VERSION[] = "1.0"; }; diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryusermodel.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryusermodel.cpp index 4c5161c3c2e..47b06781123 100644 --- a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryusermodel.cpp +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryusermodel.cpp @@ -84,7 +84,7 @@ void ContentLibraryUserModel::addItem(const QString &bundleId, const QString &na auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils(); QString typePrefix = compUtils.userBundleType(bundleId); - TypeName type = QLatin1String("%1.%2").arg(typePrefix, qml.chopped(4)).toLatin1(); + TypeName type = QLatin1String("%1.%2").arg(typePrefix, qml.section('.', 0, 0)).toLatin1(); SectionIndex sectionIndex = bundleIdToSectionIndex(bundleId); @@ -308,7 +308,7 @@ void ContentLibraryUserModel::updateImportedState(const QStringList &importedIte bool changed = false; for (QObject *item : items) { ContentLibraryItem *castedItem = qobject_cast(item); - changed |= castedItem->setImported(importedItems.contains(castedItem->qml().chopped(4))); + changed |= castedItem->setImported(importedItems.contains(castedItem->qml().section('.', 0, 0))); } if (changed) diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp index 55c96dd9b4b..dda4fa6b5fb 100644 --- a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp @@ -570,17 +570,18 @@ void ContentLibraryView::addLibAssets(const QStringList &paths) m_widget->userModel()->addTextures(targetPathsToAdd); } +// TODO: combine this method with BundleHelper::exportComponent() void ContentLibraryView::addLib3DComponent(const ModelNode &node) { auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils(); + auto bundlePath = Utils::FilePath::fromString(Paths::bundlesPathSetting() + "/User/3d/"); m_bundleId = compUtils.user3DBundleId(); - QString compBaseName = node.simplifiedTypeName(); - QString compFileName = compBaseName + ".qml"; - - auto compDir = Utils::FilePath::fromString(ModelUtils::componentFilePath(node)).parentDir(); - auto bundlePath = Utils::FilePath::fromString(Paths::bundlesPathSetting() + "/User/3d/"); + Utils::FilePath compFilePath = Utils::FilePath::fromString(ModelUtils::componentFilePath(node)); + Utils::FilePath compDir = compFilePath.parentDir(); + QString compBaseName = compFilePath.completeBaseName(); + QString compFileName = compFilePath.fileName(); // confirm overwrite if an item with same name exists if (bundlePath.pathAppended(compFileName).exists()) { @@ -599,24 +600,28 @@ void ContentLibraryView::addLib3DComponent(const ModelNode &node) m_iconSavePath = bundlePath.pathAppended(iconPath); m_iconSavePath.parentDir().ensureWritableDir(); - const Utils::FilePaths sourceFiles = compDir.dirEntries({{}, QDir::Files, QDirIterator::Subdirectories}); - const QStringList ignoreList {"_importdata.json", "qmldir", compBaseName + ".hints"}; + const QSet compDependencies = m_bundleHelper->getComponentDependencies(compFilePath, compDir); + QStringList filesList; // 3D component's assets (dependencies) + for (const AssetPath &asset : compDependencies) { + Utils::FilePath assetAbsPath = asset.absFilPath(); + QByteArray assetContent = asset.fileContent(); - for (const Utils::FilePath &sourcePath : sourceFiles) { - Utils::FilePath relativePath = sourcePath.relativePathFrom(compDir); - if (ignoreList.contains(sourcePath.fileName()) || relativePath.startsWith("source scene")) - continue; + // remove imports of sub components + for (const QString &import : std::as_const(asset.importsToRemove)) { + int removeIdx = assetContent.indexOf(QByteArray("import " + import.toLatin1())); + int removeLen = assetContent.indexOf('\n', removeIdx) - removeIdx; + assetContent.remove(removeIdx, removeLen); + } - Utils::FilePath targetPath = bundlePath.pathAppended(relativePath.path()); + Utils::FilePath targetPath = bundlePath.pathAppended(asset.relativePath); targetPath.parentDir().ensureWritableDir(); - // copy item from project to user bundle - auto result = sourcePath.copyFile(targetPath); + auto result = targetPath.writeFileContents(assetContent); QTC_ASSERT_EXPECTED(result,); - if (sourcePath.fileName() != compFileName) // skip component file (only collect dependencies) - filesList.append(relativePath.path()); + if (assetAbsPath.fileName() != compFileName) // skip component file (only collect dependencies) + filesList.append(asset.relativePath); } // add the item to the bundle json diff --git a/src/plugins/qmldesigner/components/contentlibrary/useritemcategory.cpp b/src/plugins/qmldesigner/components/contentlibrary/useritemcategory.cpp index c6983a92525..62851b33836 100644 --- a/src/plugins/qmldesigner/components/contentlibrary/useritemcategory.cpp +++ b/src/plugins/qmldesigner/components/contentlibrary/useritemcategory.cpp @@ -78,7 +78,7 @@ void UserItemCategory::loadBundle(bool force) QString name = itemObj.value("name").toString(); QString qml = itemObj.value("qml").toString(); - TypeName type = QLatin1String("%1.%2").arg(typePrefix, qml.chopped(4)).toLatin1(); + TypeName type = QLatin1String("%1.%2").arg(typePrefix, qml.section('.', 0, 0)).toLatin1(); QUrl icon = m_bundlePath.pathAppended(itemObj.value("icon").toString()).toUrl(); QStringList files = itemObj.value("files").toVariant().toStringList();