From 82f990558bec15e6292f8f1e7220b97dbf2a324d Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Mon, 21 Oct 2024 16:34:51 +0300 Subject: [PATCH] QmlDesigner: Add generated components when exporting a bundle When exporting a bundle of a component that has a dependency on another component loaded via a lib import from the Generated folder, those dependency components get properly added to the exported bundle. Also the generated imports are removed from the main component as they are not valid anymore. Task-number: QDS-13746 Change-Id: Ic3370fc62baa6b2a7cbbef432b1c2a3853170250 Reviewed-by: Miikka Heikkinen --- .../components/componentcore/bundlehelper.cpp | 71 ++++++++++++++++--- .../components/componentcore/bundlehelper.h | 11 ++- 2 files changed, 70 insertions(+), 12 deletions(-) diff --git a/src/plugins/qmldesigner/components/componentcore/bundlehelper.cpp b/src/plugins/qmldesigner/components/componentcore/bundlehelper.cpp index 347c08330f2..1db2622e345 100644 --- a/src/plugins/qmldesigner/components/componentcore/bundlehelper.cpp +++ b/src/plugins/qmldesigner/components/componentcore/bundlehelper.cpp @@ -231,7 +231,16 @@ void BundleHelper::exportComponent(const ModelNode &node) QStringList filesList; for (const AssetPath &asset : compDependencies) { Utils::FilePath assetAbsPath = asset.absFilPath(); - m_zipWriter->addFile(asset.relativePath, assetAbsPath.fileContents().value_or("")); + QByteArray assetContent = assetAbsPath.fileContents().value_or(""); + + // 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); + } + + m_zipWriter->addFile(asset.relativePath, assetContent); if (assetAbsPath.fileName() != compFileName) // skip component file (only collect dependencies) filesList.append(asset.relativePath); @@ -599,15 +608,45 @@ bool BundleHelper::isItemBundle(const QString &bundleId) const namespace { -// library imported Components won't be detected. TODO: find a feasible solution for detecting them -// and either add them as dependencies or warn the user Utils::FilePath getComponentFilePath(const QString &nodeType, const Utils::FilePath &compDir) { - Utils::FilePath compFilePath = compDir.pathAppended(QLatin1String("%1.qml").arg(nodeType)); - if (compFilePath.exists()) - return compFilePath; + QString compName = nodeType.split('.').last(); - compFilePath = compDir.pathAppended(QLatin1String("%1.ui.qml").arg(nodeType)); + auto findCompFilePath = [&](const Utils::FilePath &dir) -> Utils::FilePath { + Utils::FilePath compFP = dir.pathAppended(QLatin1String("%1.qml").arg(compName)); + if (compFP.exists()) + return compFP; + + compFP = dir.pathAppended(QLatin1String("%1.ui.qml").arg(compName)); + if (compFP.exists()) + return compFP; + + return {}; + }; + + Utils::FilePath compFilePath; + + // a component in "Generated" folder + if (nodeType.startsWith("Generated.")) { + Utils::FilePath projectPath = QmlDesignerPlugin::instance()->documentManager().currentProjectDirPath(); + QString nodeTypeSlashSep = nodeType; + nodeTypeSlashSep.replace('.', '/'); + Utils::FilePath genCompDir = projectPath.pathAppended(nodeTypeSlashSep); + + if (!genCompDir.exists()) + genCompDir = genCompDir.parentDir(); + + compFilePath = findCompFilePath(genCompDir); + if (compFilePath.exists()) + return compFilePath; + + + qWarning() << __FUNCTION__ << "Couldn't find Generated component path"; + return {}; + } + + // for components in the same dir as the main comp., search recursively for the comp. file + compFilePath = findCompFilePath(compDir); if (compFilePath.exists()) return compFilePath; @@ -618,6 +657,7 @@ Utils::FilePath getComponentFilePath(const QString &nodeType, const Utils::FileP return compFilePath; } + qWarning() << __FUNCTION__ << "Couldn't find component path"; return {}; } @@ -627,8 +667,7 @@ QSet BundleHelper::getComponentDependencies(const Utils::FilePath &fi const Utils::FilePath &mainCompDir) { QSet depList; - - depList.insert({mainCompDir, filePath.relativePathFrom(mainCompDir).toFSPathString()}); + AssetPath compAssetPath = {mainCompDir, filePath.relativePathFrom(mainCompDir).toFSPathString()}; #ifdef QDS_USE_PROJECTSTORAGE // TODO add model with ProjectStorageDependencies @@ -658,7 +697,16 @@ QSet BundleHelper::getComponentDependencies(const Utils::FilePath &fi if (!nodeType.startsWith("QtQuick")) { Utils::FilePath compFilPath = getComponentFilePath(nodeType, mainCompDir); if (!compFilPath.isEmpty()) { - depList.unite(getComponentDependencies(compFilPath, mainCompDir)); + Utils::FilePath compDir = compFilPath.isChildOf(mainCompDir) ? mainCompDir + : compFilPath.parentDir(); + depList.unite(getComponentDependencies(compFilPath, compDir)); + + // for sub components, mark their imports to be removed from their parent component + // as they will be moved to the same folder as the parent + QString import = nodeType.left(nodeType.lastIndexOf('.')); + if (model->hasImport(import)) + compAssetPath.importsToRemove.append(import); + return; } } @@ -687,6 +735,7 @@ QSet BundleHelper::getComponentDependencies(const Utils::FilePath &fi assetPathBase = mainCompDir; } + QTC_ASSERT(!assetPathRelative.isEmpty(), continue); depList.insert({assetPathBase, assetPathRelative}); } } @@ -701,6 +750,8 @@ QSet BundleHelper::getComponentDependencies(const Utils::FilePath &fi parseNode(rootNode); + depList.insert(compAssetPath); + return depList; } diff --git a/src/plugins/qmldesigner/components/componentcore/bundlehelper.h b/src/plugins/qmldesigner/components/componentcore/bundlehelper.h index 270109cd0b4..f853afea579 100644 --- a/src/plugins/qmldesigner/components/componentcore/bundlehelper.h +++ b/src/plugins/qmldesigner/components/componentcore/bundlehelper.h @@ -25,8 +25,11 @@ class NodeMetaInfo; class AssetPath { public: - Utils::FilePath basePath; - QString relativePath; + AssetPath(const Utils::FilePath &bsPath, const QString &relPath, const QStringList &imports = {}) + : basePath(bsPath) + , relativePath(relPath) + , importsToRemove(imports) + {} Utils::FilePath absFilPath() const; @@ -35,6 +38,10 @@ public: return basePath == other.basePath && relativePath == other.relativePath; } + Utils::FilePath basePath; + QString relativePath; + QStringList importsToRemove; + private: friend size_t qHash(const AssetPath &asset) {