diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp index 39125c8f698..9dcc2d7abc8 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp @@ -920,19 +920,23 @@ void Edit3DView::addQuick3DImport() { DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument(); if (document && !document->inFileComponentModelActive() && model()) { - const Imports imports = model()->possibleImports(); - for (const auto &import : imports) { - if (import.url() == "QtQuick3D") { - if (!import.version().isEmpty() && import.majorVersion() >= 6) { - // Prefer empty version number in Qt6 and beyond - model()->changeImports({Import::createLibraryImport( - import.url(), {}, import.alias(), - import.importPaths())}, {}); - } else { - model()->changeImports({import}, {}); - } - return; + Import qtQuick3DImport; + differenceCall(model()->possibleImports(), model()->imports(), [&](const auto &import) { + if (import.url() == "QtQuick3D") + qtQuick3DImport = import; + }); + if (!qtQuick3DImport.isEmpty()) { + if (!qtQuick3DImport.version().isEmpty() && qtQuick3DImport.majorVersion() >= 6) { + // Prefer empty version number in Qt6 and beyond + model()->changeImports({Import::createLibraryImport(qtQuick3DImport.url(), + {}, + qtQuick3DImport.alias(), + qtQuick3DImport.importPaths())}, + {}); + } else { + model()->changeImports({qtQuick3DImport}, {}); } + return; } } Core::AsynchronousMessageBox::warning(tr("Failed to Add Import"), diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp index 89b16fcd8e5..4dd5be177f5 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp @@ -62,7 +62,7 @@ void ItemLibraryView::modelAttached(Model *model) m_widget->setModel(model); updateImports(); if (model) - m_widget->updatePossibleImports(model->possibleImports()); + m_widget->updatePossibleImports(difference(model->possibleImports(), model->imports())); m_hasErrors = !rewriterView()->errors().isEmpty(); m_widget->setFlowMode(QmlItemNode(rootModelNode()).isFlowView()); } diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp index 1fafc91ea6a..112453fb8d4 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp @@ -368,7 +368,7 @@ void ItemLibraryWidget::handlePriorityImportsChanged() { if (!m_itemLibraryInfo.isNull()) { m_addModuleModel->setPriorityImports(m_itemLibraryInfo->priorityImports()); - m_addModuleModel->update(m_model->possibleImports()); + m_addModuleModel->update(difference(m_model->possibleImports(), m_model->imports())); } } diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index 9dcf81a1738..9f664429039 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -901,7 +901,8 @@ void NavigatorTreeModel::addImport(const QString &importName) { Import import = Import::createLibraryImport(importName); if (!m_view->model()->hasImport(import, true, true)) { - const Imports possImports = m_view->model()->possibleImports(); + const Imports possImports = difference(m_view->model()->possibleImports(), + m_view->model()->imports()); for (const auto &possImport : possImports) { if (possImport.url() == import.url()) { import = possImport; diff --git a/src/plugins/qmldesigner/designercore/include/import.h b/src/plugins/qmldesigner/designercore/include/import.h index ff9e90f162f..be7c76f492d 100644 --- a/src/plugins/qmldesigner/designercore/include/import.h +++ b/src/plugins/qmldesigner/designercore/include/import.h @@ -3,6 +3,8 @@ #pragma once +#include + #include #include #include @@ -26,16 +28,15 @@ public: bool hasVersion() const { return !m_version.isEmpty(); } bool hasAlias() const { return !m_alias.isEmpty(); } - QString url() const { return m_url; } - QString file() const { return m_file; } - QString version() const { return m_version; } - QString alias() const { return m_alias; } - QStringList importPaths() const { return m_importPathList; } + const QString &url() const { return m_url; } + const QString &file() const { return m_file; } + const QString &version() const { return m_version; } + const QString &alias() const { return m_alias; } + const QStringList &importPaths() const { return m_importPathList; } QString toString(bool skipAlias = false, bool skipVersion = false) const; QString toImportString() const; - bool operator==(const Import &other) const; bool isSameModule(const Import &other) const; int majorVersion() const; @@ -43,6 +44,18 @@ public: static int majorFromVersion(const QString &version); static int minorFromVersion(const QString &version); + friend bool operator==(const Import &first, const Import &second) + { + return first.m_url == second.m_url && first.m_file == second.m_file + && (first.m_version == second.m_version || first.m_version.isEmpty() + || second.m_version.isEmpty()); + } + + friend bool operator<(const Import &first, const Import &second) + { + return std::tie(first.m_url, first.m_file) < std::tie(second.m_url, second.m_file); + } + private: Import(const QString &url, const QString &file, const QString &version, const QString &alias, const QStringList &importPaths); @@ -58,6 +71,21 @@ QMLDESIGNERCORE_EXPORT size_t qHash(const Import &import); using Imports = QList; +QMLDESIGNERCORE_EXPORT Imports difference(const Imports &first, const Imports &second); + +template +void differenceCall(const Imports &first, const Imports &second, Callable callable) +{ + Imports difference; + difference.reserve(first.size()); + + std::set_difference(first.begin(), + first.end(), + second.begin(), + second.end(), + Utils::make_iterator(callable)); +} + } // namespace QmlDesigner Q_DECLARE_METATYPE(QmlDesigner::Import) diff --git a/src/plugins/qmldesigner/designercore/include/model.h b/src/plugins/qmldesigner/designercore/include/model.h index d36086777d8..89391dfe9ed 100644 --- a/src/plugins/qmldesigner/designercore/include/model.h +++ b/src/plugins/qmldesigner/designercore/include/model.h @@ -119,8 +119,8 @@ public: const Imports &possibleImports() const; const Imports &usedImports() const; void changeImports(const Imports &importsToBeAdded, const Imports &importsToBeRemoved); - void setPossibleImports(const Imports &possibleImports); - void setUsedImports(const Imports &usedImports); + void setPossibleImports(Imports possibleImports); + void setUsedImports(Imports usedImports); bool hasImport(const Import &import, bool ignoreAlias = true, bool allowHigherVersion = false) const; bool isImportPossible(const Import &import, bool ignoreAlias = true, bool allowHigherVersion = false) const; QString pathForImport(const Import &import); diff --git a/src/plugins/qmldesigner/designercore/model/import.cpp b/src/plugins/qmldesigner/designercore/model/import.cpp index 3a6914d3258..b9e7a7a9e24 100644 --- a/src/plugins/qmldesigner/designercore/model/import.cpp +++ b/src/plugins/qmldesigner/designercore/model/import.cpp @@ -62,11 +62,6 @@ QString Import::toString(bool skipAlias, bool skipVersion) const return result; } -bool Import::operator==(const Import &other) const -{ - return url() == other.url() && file() == other.file() && (version() == other.version() || version().isEmpty() || other.version().isEmpty()); -} - bool Import::isSameModule(const Import &other) const { if (isLibraryImport()) @@ -107,4 +102,17 @@ size_t qHash(const Import &import) return ::qHash(import.url()) ^ ::qHash(import.file()) ^ ::qHash(import.version()) ^ ::qHash(import.alias()); } +Imports difference(const Imports &first, const Imports &second) +{ + Imports difference; + difference.reserve(first.size()); + + std::set_difference(first.begin(), + first.end(), + second.begin(), + second.end(), + std::back_inserter(difference)); + + return difference; +} } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/model/model.cpp b/src/plugins/qmldesigner/designercore/model/model.cpp index 33571cc3ce1..d410a3c87aa 100644 --- a/src/plugins/qmldesigner/designercore/model/model.cpp +++ b/src/plugins/qmldesigner/designercore/model/model.cpp @@ -127,6 +127,8 @@ void ModelPrivate::changeImports(const Imports &toBeAddedImportList, } } + std::sort(m_imports.begin(), m_imports.end()); + if (!removedImportList.isEmpty() || !addedImportList.isEmpty()) notifyImportsChanged(addedImportList, removedImportList); } @@ -1419,19 +1421,23 @@ void Model::changeImports(const Imports &importsToBeAdded, const Imports &import d->changeImports(importsToBeAdded, importsToBeRemoved); } -void Model::setPossibleImports(const Imports &possibleImports) +void Model::setPossibleImports(Imports possibleImports) { + std::sort(possibleImports.begin(), possibleImports.end()); + if (d->m_possibleImportList != possibleImports) { - d->m_possibleImportList = possibleImports; - d->notifyPossibleImportsChanged(possibleImports); + d->m_possibleImportList = std::move(possibleImports); + d->notifyPossibleImportsChanged(d->m_possibleImportList); } } -void Model::setUsedImports(const Imports &usedImports) +void Model::setUsedImports(Imports usedImports) { + std::sort(usedImports.begin(), usedImports.end()); + if (d->m_usedImportList != usedImports) { - d->m_usedImportList = usedImports; - d->notifyUsedImportsChanged(usedImports); + d->m_usedImportList = std::move(usedImports); + d->notifyUsedImportsChanged(d->m_usedImportList); } } diff --git a/src/plugins/qmldesigner/designercore/model/model_p.h b/src/plugins/qmldesigner/designercore/model/model_p.h index 95985482548..8cdaaac3ecb 100644 --- a/src/plugins/qmldesigner/designercore/model/model_p.h +++ b/src/plugins/qmldesigner/designercore/model/model_p.h @@ -203,8 +203,6 @@ public: // Imports: const Imports &imports() const { return m_imports; } - void addImport(const Import &import); - void removeImport(const Import &import); void changeImports(const Imports &importsToBeAdded, const Imports &importToBeRemoved); void notifyImportsChanged(const Imports &addedImports, const Imports &removedImports); void notifyPossibleImportsChanged(const Imports &possibleImports);