QmlDesigner: Recognize subfolders as modules at any depth

Fixes: QDS-4787
Change-Id: If4e474ba0bc5f23e8a3cbf7bc6b5c7715fe467dd
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Samuel Ghinet <samuel.ghinet@qt.io>
This commit is contained in:
Miikka Heikkinen
2021-10-12 17:15:50 +03:00
parent 74e29eaa26
commit a393bcec38
3 changed files with 45 additions and 14 deletions

View File

@@ -36,6 +36,7 @@
#include <QMultiHash>
#include <QPointer>
#include <QFileInfo>
#include <QDir>
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<QString,QString> m_dirToQualifier;
QUrl m_filePath;
QDir m_filePathDir;
QPointer<Model> m_model;
};

View File

@@ -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<Import> &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();

View File

@@ -914,16 +914,30 @@ static QList<QmlDesigner::Import> generatePossibleFileImports(const QString &pat
usedImportsSet.insert(i.info.path());
QList<QmlDesigner::Import> 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<void(const QString &)> 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;
}