QmlDesigner: add directory import support to the item library

Also:
- fix removing used directory imports from possible imports.
- query imports from a hash for improved performance.

Fixes: QDS-3974
Change-Id: I69d072e24d39d3fa931493ab3cf2f821d5574c85
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Mahmoud Badri
2021-03-17 15:04:41 +02:00
parent 6d66b47b32
commit c11f5ebd42
7 changed files with 56 additions and 26 deletions

View File

@@ -58,16 +58,15 @@ QVariant ItemLibraryAddImportModel::data(const QModelIndex &index, int role) con
if (!index.isValid() || index.row() >= m_importList.count())
return {};
QString importUrl = m_importList[index.row()].url();
Import import = m_importList[index.row()];
if (m_roleNames[role] == "importUrl")
return importUrl;
return m_importList[index.row()].toString(true, true);
if (m_roleNames[role] == "importVisible")
return m_searchText.isEmpty() || importUrl.isEmpty() || m_importFilterList.contains(importUrl);
return m_searchText.isEmpty() || import.url().isEmpty() || m_importFilterList.contains(import.url());
if (m_roleNames[role] == "isSeparator")
return importUrl.isEmpty();
return import.isEmpty();
qWarning() << Q_FUNC_INFO << "invalid role requested";
@@ -132,14 +131,12 @@ void ItemLibraryAddImportModel::update(const QList<Import> &possibleImports)
// create import sections
bool previousIsPriority = false;
for (const Import &import : std::as_const(filteredImports)) {
if (import.isLibraryImport()) {
bool currentIsPriority = m_priorityImports.contains(import.url());
if (previousIsPriority && !currentIsPriority)
m_importList.append(Import::empty()); // empty import acts as a separator
m_importList.append(import);
previousIsPriority = currentIsPriority;
}
}
endResetModel();
}

View File

@@ -50,6 +50,9 @@ QString ItemLibraryImport::importName() const
if (importUrl() == "QtQuick")
return tr("Default Components");
if (m_import.isFileImport())
return m_import.toString(true, true);
return importUrl().replace('.', ' ');
}
@@ -64,6 +67,9 @@ QString ItemLibraryImport::importUrl() const
if (m_sectionType == SectionType::Unimported)
return unimportedComponentsTitle();
if (m_import.isFileImport())
return m_import.file();
return m_import.url();
}
@@ -168,6 +174,11 @@ bool ItemLibraryImport::hasCategories() const
return m_categoryModel.rowCount() > 0;
}
bool ItemLibraryImport::hasSingleCategory() const
{
return m_categoryModel.rowCount() == 1;
}
void ItemLibraryImport::sortCategorySections()
{
m_categoryModel.sortCategorySections();

View File

@@ -65,6 +65,7 @@ public:
bool importUsed() const;
bool importRemovable() const;
bool hasCategories() const;
bool hasSingleCategory() const;
ItemLibraryCategory *getCategorySection(const QString &categoryName) const;
void addCategory(ItemLibraryCategory *category);

View File

@@ -214,10 +214,15 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model)
// create import sections
QHash<QString, ItemLibraryImport *> importHash;
for (const Import &import : model->imports()) {
if (import.isLibraryImport() && import.url() != projectName) {
if (import.url() != projectName) {
bool addNew = true;
bool isQuick3DAsset = import.url().startsWith("Quick3DAssets.");
QString importUrl = isQuick3DAsset ? ItemLibraryImport::quick3DAssetsTitle() : import.url();
QString importUrl = import.url();
if (isQuick3DAsset)
importUrl = ItemLibraryImport::quick3DAssetsTitle();
else if (import.isFileImport())
importUrl = import.toString(true, true).remove("\"");
ItemLibraryImport *oldImport = importHash.value(importUrl);
if (oldImport && oldImport->sectionType() == ItemLibraryImport::SectionType::Quick3DAssets
&& isQuick3DAsset) {
@@ -280,28 +285,36 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model)
QString catName = entry.category();
if (isUsable) {
if (catName == ItemLibraryImport::userComponentsTitle()) {
// create an import section for user components
importSection = importByUrl(ItemLibraryImport::userComponentsTitle());
if (entry.requiredImport().isEmpty()) { // user components
importSection = importHash[ItemLibraryImport::userComponentsTitle()];
if (!importSection) {
importSection = new ItemLibraryImport(
{}, this, ItemLibraryImport::SectionType::User);
m_importList.append(importSection);
importHash.insert(ItemLibraryImport::userComponentsTitle(), importSection);
importSection->setImportExpanded(loadExpandedState(catName));
}
} else { // directory import
importSection = importHash[entry.requiredImport()];
}
} else if (catName == "My Quick3D Components") {
importSection = importByUrl(ItemLibraryImport::quick3DAssetsTitle());
importSection = importHash[ItemLibraryImport::quick3DAssetsTitle()];
} else {
if (catName.startsWith("Qt Quick - "))
catName = catName.mid(11); // remove "Qt Quick - "
importSection = importByUrl(entry.requiredImport());
importSection = importHash[entry.requiredImport().isEmpty() ? "QtQuick"
: entry.requiredImport()];
}
} else {
catName = ItemLibraryImport::unimportedComponentsTitle();
importSection = importByUrl(catName);
importSection = importHash[catName];
if (!importSection) {
importSection = new ItemLibraryImport(
{}, this, ItemLibraryImport::SectionType::Unimported);
m_importList.append(importSection);
importHash.insert(ItemLibraryImport::unimportedComponentsTitle(), importSection);
importSection->setImportExpanded(loadExpandedState(catName));
}
}
@@ -316,9 +329,11 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model)
if (!categorySection) {
categorySection = new ItemLibraryCategory(catName, importSection);
importSection->addCategory(categorySection);
if (importSection->sectionType() == ItemLibraryImport::SectionType::Default)
if (importSection->sectionType() == ItemLibraryImport::SectionType::Default
&& !importSection->hasSingleCategory()) {
categorySection->setExpanded(loadExpandedState(categorySection->categoryName()));
}
}
// create item
auto item = new ItemLibraryItem(entry, isUsable, categorySection);

View File

@@ -54,7 +54,7 @@ public:
QString alias() const { return m_alias; }
QStringList importPaths() const { return m_importPathList; }
QString toString(bool skipAlias = false) const;
QString toString(bool skipAlias = false, bool skipVersion = false) const;
QString toImportString() const;
bool operator==(const Import &other) const;

View File

@@ -64,7 +64,7 @@ Import::Import(const QString &url, const QString &file, const QString &version,
{
}
QString Import::toString(bool skipAlias) const
QString Import::toString(bool skipAlias, bool skipVersion) const
{
QString result;
@@ -75,7 +75,7 @@ QString Import::toString(bool skipAlias) const
else
return QString();
if (hasVersion())
if (hasVersion() && !skipVersion)
result += QLatin1Char(' ') + version();
if (hasAlias() && !skipAlias)

View File

@@ -870,14 +870,20 @@ static void removeUsedImports(QHash<QString, ImportKey> &filteredPossibleImportK
filteredPossibleImportKeys.remove(import.info.path());
}
static QList<QmlDesigner::Import> generatePossibleFileImports(const QString &path)
static QList<QmlDesigner::Import> generatePossibleFileImports(const QString &path,
const QList<QmlJS::Import> &usedImports)
{
QSet<QString> usedImportsSet;
for (const QmlJS::Import &i : usedImports)
usedImportsSet.insert(i.info.path());
QList<QmlDesigner::Import> possibleImports;
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()) {
&& dir.entryInfoList(QStringList("qmldir"), QDir::Files).isEmpty()
&& !usedImportsSet.contains(dir.path())) {
QmlDesigner::Import import = QmlDesigner::Import::createFileImport(subDir);
possibleImports.append(import);
}
@@ -914,7 +920,7 @@ void TextToModelMerger::setupPossibleImports(const QmlJS::Snapshot &snapshot, co
QList<QmlDesigner::Import> possibleImports = generatePossibleLibraryImports(filteredPossibleImportKeys);
possibleImports.append(generatePossibleFileImports(document()->path()));
possibleImports.append(generatePossibleFileImports(document()->path(), imports->all()));
if (m_rewriterView->isAttached())
m_rewriterView->model()->setPossibleImports(possibleImports);