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 <QMultiHash>
#include <QPointer> #include <QPointer>
#include <QFileInfo> #include <QFileInfo>
#include <QDir>
namespace QmlDesigner { namespace QmlDesigner {
@@ -69,6 +70,7 @@ private: // functions
void parseQuick3DAssetsDir(const QString &quick3DAssetsPath); void parseQuick3DAssetsDir(const QString &quick3DAssetsPath);
void parseQuick3DAssetsItem(const QString &importUrl, const QString &quick3DAssetsPath = {}); void parseQuick3DAssetsItem(const QString &importUrl, const QString &quick3DAssetsPath = {});
QStringList quick3DAssetPaths() const; QStringList quick3DAssetPaths() const;
TypeName resolveDirQualifier(const QString &dirPath) const;
private: // variables private: // variables
QFileSystemWatcher m_watcher; QFileSystemWatcher m_watcher;
@@ -76,6 +78,7 @@ private: // variables
// key: canonical directory path // key: canonical directory path
QMultiHash<QString,QString> m_dirToQualifier; QMultiHash<QString,QString> m_dirToQualifier;
QUrl m_filePath; QUrl m_filePath;
QDir m_filePathDir;
QPointer<Model> m_model; QPointer<Model> m_model;
}; };

View File

@@ -134,8 +134,11 @@ void SubComponentManager::parseDirectories()
if (dirInfo.exists() && dirInfo.isDir()) if (dirInfo.exists() && dirInfo.isDir())
parseDirectory(canonicalPath); parseDirectory(canonicalPath);
foreach (const QString &subDir, QDir(QFileInfo(file).path()).entryList(QDir::Dirs | QDir::NoDot | QDir::NoDotDot)) { const QStringList subDirs = QDir(QFileInfo(file).path()).entryList(QDir::Dirs | QDir::NoDot
parseDirectory(canonicalPath + QLatin1Char('/') + subDir, true, subDir.toUtf8()); | 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) { foreach (const Import &import, m_imports) {
if (import.isFileImport()) { if (import.isFileImport()) {
QFileInfo dirInfo = QFileInfo(m_filePath.resolved(import.file()).toLocalFile()); QFileInfo dirInfo = QFileInfo(m_filePath.resolved(import.file()).toLocalFile());
if (dirInfo.exists() && dirInfo.isDir()) if (dirInfo.exists() && dirInfo.isDir()) {
parseDirectory(dirInfo.canonicalFilePath(), true, dirInfo.baseName().toUtf8()); const QString canPath = dirInfo.canonicalFilePath();
parseDirectory(canPath, true, resolveDirQualifier(canPath));
}
} else { } else {
QString url = import.url(); QString url = import.url();
url.replace(QLatin1Char('.'), QLatin1Char('/')); url.replace(QLatin1Char('.'), QLatin1Char('/'));
@@ -445,6 +450,11 @@ QStringList SubComponentManager::quick3DAssetPaths() const
return retPaths; return retPaths;
} }
TypeName SubComponentManager::resolveDirQualifier(const QString &dirPath) const
{
return m_filePathDir.relativeFilePath(dirPath).toUtf8();
}
/*! /*!
\class SubComponentManager \class SubComponentManager
@@ -472,10 +482,12 @@ void SubComponentManager::update(const QUrl &filePath, const QList<Import> &impo
if (!m_filePath.isEmpty()) { if (!m_filePath.isEmpty()) {
const QString file = m_filePath.toLocalFile(); const QString file = m_filePath.toLocalFile();
oldDir = QFileInfo(QFileInfo(file).path()); oldDir = QFileInfo(QFileInfo(file).path());
m_filePathDir = {};
} }
if (!filePath.isEmpty()) { if (!filePath.isEmpty()) {
const QString file = filePath.toLocalFile(); const QString file = filePath.toLocalFile();
newDir = QFileInfo(QFileInfo(file).path()); newDir = QFileInfo(QFileInfo(file).path());
m_filePathDir = {newDir.absoluteFilePath()};
} }
m_filePath = filePath; m_filePath = filePath;
@@ -538,8 +550,10 @@ void SubComponentManager::updateImport(const Import &import)
if (import.isFileImport()) { if (import.isFileImport()) {
QFileInfo dirInfo = QFileInfo(m_filePath.resolved(import.file()).toLocalFile()); QFileInfo dirInfo = QFileInfo(m_filePath.resolved(import.file()).toLocalFile());
if (dirInfo.exists() && dirInfo.isDir()) if (dirInfo.exists() && dirInfo.isDir()) {
parseDirectory(dirInfo.canonicalFilePath(), true, dirInfo.baseName().toUtf8()); const QString canPath = dirInfo.canonicalFilePath();
parseDirectory(canPath, true, resolveDirQualifier(canPath));
}
} else { } else {
QString url = import.url(); QString url = import.url();

View File

@@ -914,16 +914,30 @@ static QList<QmlDesigner::Import> generatePossibleFileImports(const QString &pat
usedImportsSet.insert(i.info.path()); usedImportsSet.insert(i.info.path());
QList<QmlDesigner::Import> possibleImports; 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)) { QStringList fileImportPaths;
QDir dir(path + "/" + subDir); const QChar delimeter('/');
if (!dir.entryInfoList(QStringList("*.qml"), QDir::Files).isEmpty()
&& dir.entryInfoList(QStringList("qmldir"), QDir::Files).isEmpty() std::function<void(const QString &)> checkDir;
&& !usedImportsSet.contains(dir.path())) { checkDir = [&](const QString &checkPath) {
QmlDesigner::Import import = QmlDesigner::Import::createFileImport(subDir); 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); possibleImports.append(import);
} }
checkDir(dirPath);
} }
};
checkDir(path);
return possibleImports; return possibleImports;
} }