From a393bcec38f5972724c01c15c682804981109cf8 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 12 Oct 2021 17:15:50 +0300 Subject: [PATCH] QmlDesigner: Recognize subfolders as modules at any depth Fixes: QDS-4787 Change-Id: If4e474ba0bc5f23e8a3cbf7bc6b5c7715fe467dd Reviewed-by: Thomas Hartmann Reviewed-by: Qt CI Bot Reviewed-by: Samuel Ghinet --- .../include/subcomponentmanager.h | 3 ++ .../metainfo/subcomponentmanager.cpp | 26 ++++++++++++---- .../designercore/model/texttomodelmerger.cpp | 30 ++++++++++++++----- 3 files changed, 45 insertions(+), 14 deletions(-) diff --git a/src/plugins/qmldesigner/designercore/include/subcomponentmanager.h b/src/plugins/qmldesigner/designercore/include/subcomponentmanager.h index f1b694c6880..66e93abda3a 100644 --- a/src/plugins/qmldesigner/designercore/include/subcomponentmanager.h +++ b/src/plugins/qmldesigner/designercore/include/subcomponentmanager.h @@ -36,6 +36,7 @@ #include #include #include +#include namespace QmlDesigner { @@ -69,6 +70,7 @@ private: // functions void parseQuick3DAssetsDir(const QString &quick3DAssetsPath); void parseQuick3DAssetsItem(const QString &importUrl, const QString &quick3DAssetsPath = {}); QStringList quick3DAssetPaths() const; + TypeName resolveDirQualifier(const QString &dirPath) const; private: // variables QFileSystemWatcher m_watcher; @@ -76,6 +78,7 @@ private: // variables // key: canonical directory path QMultiHash m_dirToQualifier; QUrl m_filePath; + QDir m_filePathDir; QPointer m_model; }; diff --git a/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp b/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp index 7466604d054..bb4e202c862 100644 --- a/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp +++ b/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp @@ -134,8 +134,11 @@ void SubComponentManager::parseDirectories() if (dirInfo.exists() && dirInfo.isDir()) parseDirectory(canonicalPath); - foreach (const QString &subDir, QDir(QFileInfo(file).path()).entryList(QDir::Dirs | QDir::NoDot | QDir::NoDotDot)) { - parseDirectory(canonicalPath + QLatin1Char('/') + subDir, true, subDir.toUtf8()); + const QStringList subDirs = QDir(QFileInfo(file).path()).entryList(QDir::Dirs | QDir::NoDot + | QDir::NoDotDot); + for (const QString &subDir : subDirs) { + const QString canSubPath = canonicalPath + QLatin1Char('/') + subDir; + parseDirectory(canSubPath, true, resolveDirQualifier(canSubPath)); } } @@ -146,8 +149,10 @@ void SubComponentManager::parseDirectories() foreach (const Import &import, m_imports) { if (import.isFileImport()) { QFileInfo dirInfo = QFileInfo(m_filePath.resolved(import.file()).toLocalFile()); - if (dirInfo.exists() && dirInfo.isDir()) - parseDirectory(dirInfo.canonicalFilePath(), true, dirInfo.baseName().toUtf8()); + if (dirInfo.exists() && dirInfo.isDir()) { + const QString canPath = dirInfo.canonicalFilePath(); + parseDirectory(canPath, true, resolveDirQualifier(canPath)); + } } else { QString url = import.url(); url.replace(QLatin1Char('.'), QLatin1Char('/')); @@ -445,6 +450,11 @@ QStringList SubComponentManager::quick3DAssetPaths() const return retPaths; } +TypeName SubComponentManager::resolveDirQualifier(const QString &dirPath) const +{ + return m_filePathDir.relativeFilePath(dirPath).toUtf8(); +} + /*! \class SubComponentManager @@ -472,10 +482,12 @@ void SubComponentManager::update(const QUrl &filePath, const QList &impo if (!m_filePath.isEmpty()) { const QString file = m_filePath.toLocalFile(); oldDir = QFileInfo(QFileInfo(file).path()); + m_filePathDir = {}; } if (!filePath.isEmpty()) { const QString file = filePath.toLocalFile(); newDir = QFileInfo(QFileInfo(file).path()); + m_filePathDir = {newDir.absoluteFilePath()}; } m_filePath = filePath; @@ -538,8 +550,10 @@ void SubComponentManager::updateImport(const Import &import) if (import.isFileImport()) { QFileInfo dirInfo = QFileInfo(m_filePath.resolved(import.file()).toLocalFile()); - if (dirInfo.exists() && dirInfo.isDir()) - parseDirectory(dirInfo.canonicalFilePath(), true, dirInfo.baseName().toUtf8()); + if (dirInfo.exists() && dirInfo.isDir()) { + const QString canPath = dirInfo.canonicalFilePath(); + parseDirectory(canPath, true, resolveDirQualifier(canPath)); + } } else { QString url = import.url(); diff --git a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp index 3c2ad6fc844..3f6a04fde47 100644 --- a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp +++ b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp @@ -914,16 +914,30 @@ static QList generatePossibleFileImports(const QString &pat usedImportsSet.insert(i.info.path()); QList possibleImports; + const QStringList qmlList("*.qml"); + const QStringList qmldirList("qmldir"); - foreach (const QString &subDir, QDir(path).entryList(QDir::Dirs | QDir::NoDot | QDir::NoDotDot)) { - QDir dir(path + "/" + subDir); - if (!dir.entryInfoList(QStringList("*.qml"), QDir::Files).isEmpty() - && dir.entryInfoList(QStringList("qmldir"), QDir::Files).isEmpty() - && !usedImportsSet.contains(dir.path())) { - QmlDesigner::Import import = QmlDesigner::Import::createFileImport(subDir); - possibleImports.append(import); + QStringList fileImportPaths; + const QChar delimeter('/'); + + std::function checkDir; + checkDir = [&](const QString &checkPath) { + const QStringList entries = QDir(checkPath).entryList(QDir::Dirs | QDir::NoDot | QDir::NoDotDot); + const QString checkPathDelim = checkPath + delimeter; + for (const QString &entry : entries) { + QDir dir(checkPathDelim + entry); + const QString dirPath = dir.path(); + if (!dir.entryInfoList(qmlList, QDir::Files).isEmpty() + && dir.entryInfoList(qmldirList, QDir::Files).isEmpty() + && !usedImportsSet.contains(dirPath)) { + const QString importName = dir.path().mid(path.size() + 1); + QmlDesigner::Import import = QmlDesigner::Import::createFileImport(importName); + possibleImports.append(import); + } + checkDir(dirPath); } - } + }; + checkDir(path); return possibleImports; }