diff --git a/src/plugins/qmldesigner/libs/designercore/include/abstractview.h b/src/plugins/qmldesigner/libs/designercore/include/abstractview.h index c6f25e7bad1..79f6267162a 100644 --- a/src/plugins/qmldesigner/libs/designercore/include/abstractview.h +++ b/src/plugins/qmldesigner/libs/designercore/include/abstractview.h @@ -155,6 +155,9 @@ public: virtual void modelAboutToBeDetached(Model *model); virtual void refreshMetaInfos(const TypeIds &deletedTypeIds); + using ExportedTypeNames = Storage::Info::ExportedTypeNames; + virtual void exportedTypeNamesChanged(const ExportedTypeNames &added, + const ExportedTypeNames &removed); virtual void nodeCreated(const ModelNode &createdNode); virtual void nodeAboutToBeRemoved(const ModelNode &removedNode); diff --git a/src/plugins/qmldesigner/libs/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/libs/designercore/model/abstractview.cpp index acc8be0f9b0..c19ff88219e 100644 --- a/src/plugins/qmldesigner/libs/designercore/model/abstractview.cpp +++ b/src/plugins/qmldesigner/libs/designercore/model/abstractview.cpp @@ -177,6 +177,8 @@ void AbstractView::modelAboutToBeDetached(Model *) void AbstractView::refreshMetaInfos(const TypeIds &) {} +void AbstractView::exportedTypeNamesChanged(const ExportedTypeNames &, const ExportedTypeNames &) {} + /*! \enum QmlDesigner::AbstractView::PropertyChangeFlag diff --git a/src/plugins/qmldesigner/libs/designercore/model/model.cpp b/src/plugins/qmldesigner/libs/designercore/model/model.cpp index dc609493f98..b0636a9f0ca 100644 --- a/src/plugins/qmldesigner/libs/designercore/model/model.cpp +++ b/src/plugins/qmldesigner/libs/designercore/model/model.cpp @@ -474,6 +474,13 @@ void ModelPrivate::exportedTypesChanged() } } +void ModelPrivate::exportedTypeNamesChanged(const ExportedTypeNames &added, + const ExportedTypeNames &removed) +{ + notifyNodeInstanceViewLast( + [&](AbstractView *view) { view->exportedTypeNamesChanged(added, removed); }); +} + void ModelPrivate::removeAllSubNodes(const InternalNodePointer &node) { for (const InternalNodePointer &subNode : node->allSubNodes()) diff --git a/src/plugins/qmldesigner/libs/designercore/model/model_p.h b/src/plugins/qmldesigner/libs/designercore/model/model_p.h index 38384a416c5..d9591ccbf9e 100644 --- a/src/plugins/qmldesigner/libs/designercore/model/model_p.h +++ b/src/plugins/qmldesigner/libs/designercore/model/model_p.h @@ -326,6 +326,8 @@ public: protected: void removedTypeIds(const TypeIds &removedTypeIds) override; void exportedTypesChanged() override; + void exportedTypeNamesChanged(const ExportedTypeNames &added, + const ExportedTypeNames &removed) override; void removeNode(const InternalNodePointer &node); private: diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorage.cpp b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorage.cpp index 79c3749fe6e..f7dfa4bcaac 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorage.cpp +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorage.cpp @@ -107,14 +107,20 @@ struct ProjectStorage::Statements "defaultPropertyId=propertyDeclarationId " "WHERE t.typeId=?", database}; - mutable Sqlite::ReadStatement<4, 1> selectExportedTypesByTypeIdStatement{ - "SELECT moduleId, name, ifnull(majorVersion, -1), ifnull(minorVersion, -1) FROM " - "exportedTypeNames WHERE typeId=?", + mutable Sqlite::ReadStatement<5, 1> selectExportedTypesByTypeIdStatement{ + "SELECT moduleId, typeId, name, ifnull(majorVersion, -1), ifnull(minorVersion, -1) " + "FROM exportedTypeNames " + "WHERE typeId=?", database}; - mutable Sqlite::ReadStatement<4, 2> selectExportedTypesByTypeIdAndSourceIdStatement{ - "SELECT etn.moduleId, name, ifnull(etn.majorVersion, -1), ifnull(etn.minorVersion, -1) " - "FROM exportedTypeNames AS etn JOIN documentImports USING(moduleId) WHERE typeId=?1 AND " - "sourceId=?2", + mutable Sqlite::ReadStatement<5, 2> selectExportedTypesByTypeIdAndSourceIdStatement{ + "SELECT etn.moduleId, " + " typeId, " + " name, " + " ifnull(etn.majorVersion, -1), " + " ifnull(etn.minorVersion, -1) " + "FROM exportedTypeNames AS etn " + "JOIN documentImports USING(moduleId) " + "WHERE typeId=?1 AND sourceId=?2", database}; mutable Sqlite::ReadStatement<8> selectTypesStatement{ "SELECT sourceId, t.name, t.typeId, prototypeId, extensionId, traits, annotationTraits, " @@ -1298,6 +1304,8 @@ void ProjectStorage::synchronize(Storage::Synchronization::SynchronizationPackag NanotraceHR::Tracer tracer{"synchronize", projectStorageCategory()}; TypeIds deletedTypeIds; + Storage::Info::ExportedTypeNames removedExportedTypeNames; + Storage::Info::ExportedTypeNames addedExportedTypeNames; ExportedTypesChanged exportedTypesChanged = ExportedTypesChanged::No; Sqlite::withImmediateTransaction(database, [&] { @@ -1332,6 +1340,8 @@ void ProjectStorage::synchronize(Storage::Synchronization::SynchronizationPackag relinkablePrototypes, relinkableExtensions, exportedTypesChanged, + removedExportedTypeNames, + addedExportedTypeNames, package.updatedSourceIds); synchronizeTypeAnnotations(package.typeAnnotations, package.updatedTypeAnnotationSourceIds); synchronizePropertyEditorQmlPaths(package.propertyEditorQmlPaths, @@ -1361,7 +1371,10 @@ void ProjectStorage::synchronize(Storage::Synchronization::SynchronizationPackag commonTypeCache_.resetTypeIds(); }); - callRefreshMetaInfoCallback(deletedTypeIds, exportedTypesChanged); + callRefreshMetaInfoCallback(deletedTypeIds, + exportedTypesChanged, + removedExportedTypeNames, + addedExportedTypeNames); } void ProjectStorage::synchronizeDocumentImports(Storage::Imports imports, SourceId sourceId) @@ -2348,8 +2361,11 @@ ProjectStorage::ModuleCacheEntries ProjectStorage::fetchAllModules() const return s->selectAllModulesStatement.valuesWithTransaction(); } -void ProjectStorage::callRefreshMetaInfoCallback(TypeIds &deletedTypeIds, - ExportedTypesChanged &exportedTypesChanged) +void ProjectStorage::callRefreshMetaInfoCallback( + TypeIds &deletedTypeIds, + ExportedTypesChanged exportedTypesChanged, + const Storage::Info::ExportedTypeNames &removedExportedTypeNames, + const Storage::Info::ExportedTypeNames &addedExportedTypeNames) { using NanotraceHR::keyValue; NanotraceHR::Tracer tracer{"call refresh meta info callback", @@ -2364,8 +2380,10 @@ void ProjectStorage::callRefreshMetaInfoCallback(TypeIds &deletedTypeIds, } if (exportedTypesChanged == ExportedTypesChanged::Yes) { - for (ProjectStorageObserver *observer : observers) + for (ProjectStorageObserver *observer : observers) { observer->exportedTypesChanged(); + observer->exportedTypeNamesChanged(addedExportedTypeNames, removedExportedTypeNames); + } } } @@ -2428,7 +2446,6 @@ void ProjectStorage::synchronizeTypeAnnotations(Storage::Synchronization::TypeAn { NanotraceHR::Tracer tracer{"synchronize type annotations", projectStorageCategory()}; - updateTypeIdInTypeAnnotations(typeAnnotations); auto compareKey = [](auto &&first, auto &&second) { return first.typeId <=> second.typeId; }; @@ -2522,6 +2539,8 @@ void ProjectStorage::synchronizeTypes(Storage::Synchronization::Types &types, Prototypes &relinkablePrototypes, Prototypes &relinkableExtensions, ExportedTypesChanged &exportedTypesChanged, + Storage::Info::ExportedTypeNames &removedExportedTypeNames, + Storage::Info::ExportedTypeNames &addedExportedTypeNames, const SourceIds &updatedSourceIds) { NanotraceHR::Tracer tracer{"synchronize types", projectStorageCategory()}; @@ -2564,7 +2583,9 @@ void ProjectStorage::synchronizeTypes(Storage::Synchronization::Types &types, relinkablePropertyDeclarations, relinkablePrototypes, relinkableExtensions, - exportedTypesChanged); + exportedTypesChanged, + removedExportedTypeNames, + addedExportedTypeNames); syncPrototypesAndExtensions(types, relinkablePrototypes, relinkableExtensions); resetDefaultPropertiesIfChanged(types); @@ -3299,17 +3320,23 @@ void ProjectStorage::repairBrokenAliasPropertyDeclarations() linkAliases(brokenAliasPropertyDeclarations, RaiseError::No); } -void ProjectStorage::synchronizeExportedTypes(const TypeIds &updatedTypeIds, - Storage::Synchronization::ExportedTypes &exportedTypes, - AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, - PropertyDeclarations &relinkablePropertyDeclarations, - Prototypes &relinkablePrototypes, - Prototypes &relinkableExtensions, - ExportedTypesChanged &exportedTypesChanged) +void ProjectStorage::synchronizeExportedTypes( + const TypeIds &updatedTypeIds, + Storage::Synchronization::ExportedTypes &exportedTypes, + AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, + PropertyDeclarations &relinkablePropertyDeclarations, + Prototypes &relinkablePrototypes, + Prototypes &relinkableExtensions, + ExportedTypesChanged &exportedTypesChanged, + Storage::Info::ExportedTypeNames &removedExportedTypeNames, + Storage::Info::ExportedTypeNames &addedExportedTypeNames) { using NanotraceHR::keyValue; NanotraceHR::Tracer tracer{"synchronize exported types", projectStorageCategory()}; + removedExportedTypeNames.reserve(exportedTypes.size()); + addedExportedTypeNames.reserve(exportedTypes.size()); + std::ranges::sort(exportedTypes, [](auto &&first, auto &&second) { if (first.moduleId < second.moduleId) return true; @@ -3376,6 +3403,8 @@ void ProjectStorage::synchronizeExportedTypes(const TypeIds &updatedTypeIds, handlePrototypesWithExportedTypeNameAndTypeId(type.name, unresolvedTypeId, relinkablePrototypes); handleExtensionsWithExportedTypeNameAndTypeId(type.name, unresolvedTypeId, relinkableExtensions); + addedExportedTypeNames.emplace_back(type.moduleId, type.typeId, type.name, type.version); + exportedTypesChanged = ExportedTypesChanged::Yes; }; @@ -3397,6 +3426,9 @@ void ProjectStorage::synchronizeExportedTypes(const TypeIds &updatedTypeIds, s->updateExportedTypeNameTypeIdStatement.write(view.exportedTypeNameId, type.typeId); exportedTypesChanged = ExportedTypesChanged::Yes; + addedExportedTypeNames.emplace_back(type.moduleId, type.typeId, type.name, type.version); + removedExportedTypeNames.emplace_back(view.moduleId, view.typeId, view.name, view.version); + return Sqlite::UpdateChange::Update; } return Sqlite::UpdateChange::No; @@ -3417,6 +3449,8 @@ void ProjectStorage::synchronizeExportedTypes(const TypeIds &updatedTypeIds, s->deleteExportedTypeNameStatement.write(view.exportedTypeNameId); + removedExportedTypeNames.emplace_back(view.moduleId, view.typeId, view.name, view.version); + exportedTypesChanged = ExportedTypesChanged::Yes; }; diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorage.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorage.h index f11921330f3..1e6d287abe2 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorage.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorage.h @@ -325,7 +325,9 @@ private: enum class ExportedTypesChanged { No, Yes }; void callRefreshMetaInfoCallback(TypeIds &deletedTypeIds, - ExportedTypesChanged &exportedTypesChanged); + ExportedTypesChanged exportedTypesChanged, + const Storage::Info::ExportedTypeNames &removedExportedTypeNames, + const Storage::Info::ExportedTypeNames &addedExportedTypeNames); class AliasPropertyDeclaration { @@ -565,6 +567,8 @@ private: Prototypes &relinkablePrototypes, Prototypes &relinkableExtensions, ExportedTypesChanged &exportedTypesChanged, + Storage::Info::ExportedTypeNames &removedExportedTypeNames, + Storage::Info::ExportedTypeNames &addedExportedTypeNames, const SourceIds &updatedSourceIds); void synchronizeDirectoryInfos(Storage::Synchronization::DirectoryInfos &directoryInfos, @@ -666,7 +670,9 @@ private: PropertyDeclarations &relinkablePropertyDeclarations, Prototypes &relinkablePrototypes, Prototypes &relinkableExtensions, - ExportedTypesChanged &exportedTypesChanged); + ExportedTypesChanged &exportedTypesChanged, + Storage::Info::ExportedTypeNames &removedExportedTypeNames, + Storage::Info::ExportedTypeNames &addedExportedTypeNames); void synchronizePropertyDeclarationsInsertAlias( AliasPropertyDeclarations &insertedAliasPropertyDeclarations, diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageinfotypes.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageinfotypes.h index a23e2bd0212..025dc9de466 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageinfotypes.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageinfotypes.h @@ -257,20 +257,7 @@ public: explicit operator bool() const { return value >= 0; } - friend bool operator==(VersionNumber first, VersionNumber second) noexcept - { - return first.value == second.value; - } - - friend bool operator!=(VersionNumber first, VersionNumber second) noexcept - { - return !(first == second); - } - - friend bool operator<(VersionNumber first, VersionNumber second) noexcept - { - return first.value < second.value; - } + auto operator<=>(const VersionNumber &first) const noexcept = default; public: int value = -1; @@ -294,15 +281,7 @@ public: : major{major} {} - friend bool operator==(Version first, Version second) noexcept - { - return first.major == second.major && first.minor == second.minor; - } - - friend bool operator<(Version first, Version second) noexcept - { - return std::tie(first.major, first.minor) < std::tie(second.major, second.minor); - } + auto operator<=>(const Version &first) const noexcept = default; explicit operator bool() const { return major && minor; } @@ -470,32 +449,36 @@ public: ExportedTypeName() = default; ExportedTypeName(ModuleId moduleId, + TypeId typeId, ::Utils::SmallStringView name, Storage::Version version = Storage::Version{}) : name{name} , version{version} , moduleId{moduleId} + , typeId{typeId} {} ExportedTypeName(ModuleId moduleId, + TypeId typeId, ::Utils::SmallStringView name, int majorVersion, int minorVersion) : name{name} , version{majorVersion, minorVersion} , moduleId{moduleId} + , typeId{typeId} {} friend bool operator==(const ExportedTypeName &first, const ExportedTypeName &second) { - return first.moduleId == second.moduleId && first.version == second.version - && first.name == second.name; + return first.moduleId == second.moduleId && first.typeId == second.typeId + && first.version == second.version && first.name == second.name; } - friend bool operator<(const ExportedTypeName &first, const ExportedTypeName &second) + friend auto operator<=>(const ExportedTypeName &first, const ExportedTypeName &second) { - return std::tie(first.moduleId, first.name, first.version) - < std::tie(second.moduleId, second.name, second.version); + return std::tie(first.moduleId, first.name, first.version, second.typeId) + <=> std::tie(second.moduleId, second.name, second.version, second.typeId); } template @@ -505,7 +488,8 @@ public: using NanotraceHR::keyValue; auto dict = dictonary(keyValue("name", exportedTypeName.name), keyValue("version", exportedTypeName.version), - keyValue("module id", exportedTypeName.moduleId)); + keyValue("module id", exportedTypeName.moduleId), + keyValue("type id", exportedTypeName.typeId)); convertToString(string, dict); } @@ -514,6 +498,7 @@ public: ::Utils::SmallString name; Storage::Version version; ModuleId moduleId; + TypeId typeId; }; using ExportedTypeNames = std::vector; diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageobserver.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageobserver.h index 5beadc0472d..4fec677cb0a 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageobserver.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageobserver.h @@ -4,13 +4,17 @@ #pragma once #include "projectstorageids.h" +#include "projectstorageinfotypes.h" namespace QmlDesigner { class ProjectStorageObserver { public: + using ExportedTypeNames = Storage::Info::ExportedTypeNames; + virtual void removedTypeIds(const TypeIds &removedTypeIds) = 0; virtual void exportedTypesChanged() = 0; + virtual void exportedTypeNamesChanged(const ExportedTypeNames &added, const ExportedTypeNames &removed) = 0; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragetypes.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragetypes.h index a8f3d1d6e95..0331418568a 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragetypes.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragetypes.h @@ -393,11 +393,13 @@ public: {} explicit ExportedType(ModuleId moduleId, + TypeId typeId, ::Utils::SmallStringView name, int majorVersion, int minorVersion) : name{name} , version{majorVersion, minorVersion} + , typeId{typeId} , moduleId{moduleId} {} diff --git a/tests/unit/tests/matchers/info_exportedtypenames-matcher.h b/tests/unit/tests/matchers/info_exportedtypenames-matcher.h index 8ef86e53dec..f28008c7849 100644 --- a/tests/unit/tests/matchers/info_exportedtypenames-matcher.h +++ b/tests/unit/tests/matchers/info_exportedtypenames-matcher.h @@ -7,27 +7,43 @@ #include -template -auto IsInfoExportTypeNames(const ModuleIdMatcher &moduleIdMatcher, - const NameMatcher &nameMatcher, - const MajorVersionMatcher &majorVersionMatcher, - const MinorVersionMatcher &minorVersionMatcher) +template +auto IsInfoExportTypeName(const ModuleIdMatcher &moduleIdMatcher, + const TypeIdMatcher &typeIdMatcher, + const NameMatcher &nameMatcher, + const MajorVersionMatcher &majorVersionMatcher, + const MinorVersionMatcher &minorVersionMatcher) { - return AllOf(Field("QmlDesigner::Storage::Info::ExportedTypeName::moduleId", &QmlDesigner::Storage::Info::ExportedTypeName::moduleId, moduleIdMatcher), - Field("QmlDesigner::Storage::Info::ExportedTypeName::name", &QmlDesigner::Storage::Info::ExportedTypeName::name, nameMatcher), - Field("QmlDesigner::Storage::Info::ExportedTypeName::version", &QmlDesigner::Storage::Info::ExportedTypeName::version, + return AllOf(Field("QmlDesigner::Storage::Info::ExportedTypeName::moduleId", + &QmlDesigner::Storage::Info::ExportedTypeName::moduleId, + moduleIdMatcher), + Field("QmlDesigner::Storage::Info::ExportedTypeName::typeId", + &QmlDesigner::Storage::Info::ExportedTypeName::typeId, + typeIdMatcher), + Field("QmlDesigner::Storage::Info::ExportedTypeName::name", + &QmlDesigner::Storage::Info::ExportedTypeName::name, + nameMatcher), + Field("QmlDesigner::Storage::Info::ExportedTypeName::version", + &QmlDesigner::Storage::Info::ExportedTypeName::version, IsVersion(majorVersionMatcher, minorVersionMatcher))); } -template -auto IsInfoExportTypeNames(const ModuleIdMatcher &moduleIdMatcher, - const NameMatcher &nameMatcher, - const VersionMatcher &versionMatcher) +template +auto IsInfoExportTypeName(const ModuleIdMatcher &moduleIdMatcher, + const TypeIdMatcher &typeIdMatcher, + const NameMatcher &nameMatcher, + const VersionMatcher &versionMatcher) { - return AllOf(Field("QmlDesigner::Storage::Info::ExportedTypeName::moduleId", &QmlDesigner::Storage::Info::ExportedTypeName::moduleId, moduleIdMatcher), - Field("QmlDesigner::Storage::Info::ExportedTypeName::name", &QmlDesigner::Storage::Info::ExportedTypeName::name, nameMatcher), - Field("QmlDesigner::Storage::Info::ExportedTypeName::version", &QmlDesigner::Storage::Info::ExportedTypeName::version, versionMatcher)); + return AllOf(Field("QmlDesigner::Storage::Info::ExportedTypeName::moduleId", + &QmlDesigner::Storage::Info::ExportedTypeName::moduleId, + moduleIdMatcher), + Field("QmlDesigner::Storage::Info::ExportedTypeName::typeId", + &QmlDesigner::Storage::Info::ExportedTypeName::typeId, + typeIdMatcher), + Field("QmlDesigner::Storage::Info::ExportedTypeName::name", + &QmlDesigner::Storage::Info::ExportedTypeName::name, + nameMatcher), + Field("QmlDesigner::Storage::Info::ExportedTypeName::version", + &QmlDesigner::Storage::Info::ExportedTypeName::version, + versionMatcher)); } diff --git a/tests/unit/tests/mocks/abstractviewmock.h b/tests/unit/tests/mocks/abstractviewmock.h index 7a2ea1b48c2..941f6c2cb3d 100644 --- a/tests/unit/tests/mocks/abstractviewmock.h +++ b/tests/unit/tests/mocks/abstractviewmock.h @@ -65,6 +65,10 @@ public: (override)); MOCK_METHOD(void, nodeAboutToBeRemoved, (const QmlDesigner::ModelNode &removedNode), (override)); MOCK_METHOD(void, refreshMetaInfos, (const QmlDesigner::TypeIds &), (override)); + MOCK_METHOD(void, + exportedTypeNamesChanged, + (const ExportedTypeNames &added, const ExportedTypeNames &removed), + (override)); MOCK_METHOD(void, modelAttached, (QmlDesigner::Model *), (override)); MOCK_METHOD(void, modelAboutToBeDetached, (QmlDesigner::Model *), (override)); diff --git a/tests/unit/tests/mocks/projectstoragemock.cpp b/tests/unit/tests/mocks/projectstoragemock.cpp index 1d3a5f58cd2..150930db1ab 100644 --- a/tests/unit/tests/mocks/projectstoragemock.cpp +++ b/tests/unit/tests/mocks/projectstoragemock.cpp @@ -128,7 +128,7 @@ void ProjectStorageMock::addExportedTypeName(QmlDesigner::TypeId typeId, ON_CALL(*this, typeId(Eq(moduleId), Eq(typeName), _)).WillByDefault(Return(typeId)); ON_CALL(*this, fetchTypeIdByModuleIdAndExportedName(Eq(moduleId), Eq(typeName))) .WillByDefault(Return(typeId)); - exportedTypeName[typeId].emplace_back(moduleId, typeName); + exportedTypeName[typeId].emplace_back(moduleId, typeId, typeName); } void ProjectStorageMock::addExportedTypeNameBySourceId(QmlDesigner::TypeId typeId, @@ -136,7 +136,7 @@ void ProjectStorageMock::addExportedTypeNameBySourceId(QmlDesigner::TypeId typeI Utils::SmallStringView typeName, QmlDesigner::SourceId sourceId) { - exportedTypeNameBySourceId[{typeId, sourceId}].emplace_back(moduleId, typeName); + exportedTypeNameBySourceId[{typeId, sourceId}].emplace_back(moduleId, typeId, typeName); } void ProjectStorageMock::removeExportedTypeName(QmlDesigner::TypeId typeId, diff --git a/tests/unit/tests/mocks/projectstorageobservermock.h b/tests/unit/tests/mocks/projectstorageobservermock.h index 1f98ecae3bb..b1b6717026a 100644 --- a/tests/unit/tests/mocks/projectstorageobservermock.h +++ b/tests/unit/tests/mocks/projectstorageobservermock.h @@ -12,4 +12,8 @@ class ProjectStorageObserverMock : public QmlDesigner::ProjectStorageObserver public: MOCK_METHOD(void, removedTypeIds, (const QmlDesigner::TypeIds &), (override)); MOCK_METHOD(void, exportedTypesChanged, (), (override)); + MOCK_METHOD(void, + exportedTypeNamesChanged, + (const ExportedTypeNames &added, const ExportedTypeNames &removed), + (override)); }; diff --git a/tests/unit/tests/printers/gtest-creator-printing.cpp b/tests/unit/tests/printers/gtest-creator-printing.cpp index 40cc868edea..6d82128ab18 100644 --- a/tests/unit/tests/printers/gtest-creator-printing.cpp +++ b/tests/unit/tests/printers/gtest-creator-printing.cpp @@ -751,7 +751,8 @@ std::ostream &operator<<(std::ostream &out, const Type &type) std::ostream &operator<<(std::ostream &out, const ExportedTypeName &name) { - return out << "(\"" << name.name << "\", " << name.moduleId << ", " << name.version << ")"; + return out << "(\"" << name.name << "\", " << name.moduleId << ", " << name.version << ", " + << name.typeId << ")"; } std::ostream &operator<<(std::ostream &out, const TypeHint &hint) diff --git a/tests/unit/tests/unittests/metainfo/nodemetainfo-test.cpp b/tests/unit/tests/unittests/metainfo/nodemetainfo-test.cpp index ed28cb28544..41ad91ee6e1 100644 --- a/tests/unit/tests/unittests/metainfo/nodemetainfo-test.cpp +++ b/tests/unit/tests/unittests/metainfo/nodemetainfo-test.cpp @@ -2624,23 +2624,23 @@ TEST_F(NodeMetaInfo, default_is_not_enumeration) TEST_F(NodeMetaInfo, all_external_type_names) { - QmlDesigner::Storage::Info::ExportedTypeNames names{{qmlModuleId, "Object", 2, -1}, - {qmlModuleId, "Obj", 2, 1}}; auto metaInfo = createMetaInfo("QML", ModuleKind::QmlLibrary, "Foo"); + QmlDesigner::Storage::Info::ExportedTypeNames names{{qmlModuleId, metaInfo.id(), "Object", 2, -1}, + {qmlModuleId, metaInfo.id(), "Obj", 2, 1}}; ON_CALL(projectStorageMock, exportedTypeNames(metaInfo.id())).WillByDefault(Return(names)); auto exportedTypeNames = metaInfo.allExportedTypeNames(); ASSERT_THAT(exportedTypeNames, - UnorderedElementsAre(IsInfoExportTypeNames(qmlModuleId, "Object", 2, -1), - IsInfoExportTypeNames(qmlModuleId, "Obj", 2, 1))); + UnorderedElementsAre(IsInfoExportTypeName(qmlModuleId, metaInfo.id(), "Object", 2, -1), + IsInfoExportTypeName(qmlModuleId, metaInfo.id(), "Obj", 2, 1))); } TEST_F(NodeMetaInfo, default_has_no_external_type_names) { - QmlDesigner::Storage::Info::ExportedTypeNames names{{qmlModuleId, "Object", 2, -1}, - {qmlModuleId, "Obj", 2, 1}}; QmlDesigner::NodeMetaInfo metaInfo; + QmlDesigner::Storage::Info::ExportedTypeNames names{{qmlModuleId, metaInfo.id(), "Object", 2, -1}, + {qmlModuleId, metaInfo.id(), "Obj", 2, 1}}; ON_CALL(projectStorageMock, exportedTypeNames(_)).WillByDefault(Return(names)); auto exportedTypeNames = metaInfo.allExportedTypeNames(); @@ -2650,24 +2650,24 @@ TEST_F(NodeMetaInfo, default_has_no_external_type_names) TEST_F(NodeMetaInfo, external_type_names_for_source_id) { - QmlDesigner::Storage::Info::ExportedTypeNames names{{qmlModuleId, "Object", 2, -1}, - {qmlModuleId, "Obj", 2, 1}}; auto metaInfo = createMetaInfo("QML", ModuleKind::QmlLibrary, "Foo"); + QmlDesigner::Storage::Info::ExportedTypeNames names{{qmlModuleId, metaInfo.id(), "Object", 2, -1}, + {qmlModuleId, metaInfo.id(), "Obj", 2, 1}}; ON_CALL(projectStorageMock, exportedTypeNames(metaInfo.id(), model.fileUrlSourceId())) .WillByDefault(Return(names)); auto exportedTypeNames = metaInfo.exportedTypeNamesForSourceId(model.fileUrlSourceId()); ASSERT_THAT(exportedTypeNames, - UnorderedElementsAre(IsInfoExportTypeNames(qmlModuleId, "Object", 2, -1), - IsInfoExportTypeNames(qmlModuleId, "Obj", 2, 1))); + UnorderedElementsAre(IsInfoExportTypeName(qmlModuleId, metaInfo.id(), "Object", 2, -1), + IsInfoExportTypeName(qmlModuleId, metaInfo.id(), "Obj", 2, 1))); } TEST_F(NodeMetaInfo, default_has_no_external_type_names_for_source_id) { - QmlDesigner::Storage::Info::ExportedTypeNames names{{qmlModuleId, "Object", 2, -1}, - {qmlModuleId, "Obj", 2, 1}}; QmlDesigner::NodeMetaInfo metaInfo; + QmlDesigner::Storage::Info::ExportedTypeNames names{{qmlModuleId, metaInfo.id(), "Object", 2, -1}, + {qmlModuleId, metaInfo.id(), "Obj", 2, 1}}; ON_CALL(projectStorageMock, exportedTypeNames(metaInfo.id(), model.fileUrlSourceId())) .WillByDefault(Return(names)); @@ -2678,9 +2678,9 @@ TEST_F(NodeMetaInfo, default_has_no_external_type_names_for_source_id) TEST_F(NodeMetaInfo, invalid_source_id_has_no_external_type_names_for_source_id) { - QmlDesigner::Storage::Info::ExportedTypeNames names{{qmlModuleId, "Object", 2, -1}, - {qmlModuleId, "Obj", 2, 1}}; auto metaInfo = createMetaInfo("QML", ModuleKind::QmlLibrary, "Foo"); + QmlDesigner::Storage::Info::ExportedTypeNames names{{qmlModuleId, metaInfo.id(), "Object", 2, -1}, + {qmlModuleId, metaInfo.id(), "Obj", 2, 1}}; ON_CALL(projectStorageMock, exportedTypeNames(metaInfo.id(), model.fileUrlSourceId())) .WillByDefault(Return(names)); QmlDesigner::SourceId sourceId; diff --git a/tests/unit/tests/unittests/model/model-test.cpp b/tests/unit/tests/unittests/model/model-test.cpp index 88502e1d9ec..31ce1a30d8e 100644 --- a/tests/unit/tests/unittests/model/model-test.cpp +++ b/tests/unit/tests/unittests/model/model-test.cpp @@ -1141,14 +1141,13 @@ TEST_F(Model_MetaInfo, remove_project_storage_observer_from_project_storage) QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, "Item", -1, -1, nullptr, {}}; } -TEST_F(Model_MetaInfo, refresh_callback_is_calling_abstract_view) +TEST_F(Model_MetaInfo, refresh_meta_infos_callback_is_calling_abstract_view) { const QmlDesigner::TypeIds typeIds = {QmlDesigner::TypeId::create(3), QmlDesigner::TypeId::create(1)}; ProjectStorageObserverMock observerMock; QmlDesigner::ProjectStorageObserver *observer = nullptr; ON_CALL(projectStorageMock, addObserver(_)).WillByDefault([&](auto *o) { observer = o; }); - QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, "Item", -1, -1, nullptr, {}}; model.attachView(&viewMock); @@ -1157,6 +1156,36 @@ TEST_F(Model_MetaInfo, refresh_callback_is_calling_abstract_view) observer->removedTypeIds(typeIds); } +TEST_F(Model_MetaInfo, added_exported_type_names_are_changed_callback_is_calling_abstract_view) +{ + using QmlDesigner::Storage::Info::ExportedTypeNames; + ExportedTypeNames added = {{qtQuickModuleId, itemTypeId, "Foo", 1, 1}}; + ProjectStorageObserverMock observerMock; + QmlDesigner::ProjectStorageObserver *observer = nullptr; + ON_CALL(projectStorageMock, addObserver(_)).WillByDefault([&](auto *o) { observer = o; }); + QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, "Item", -1, -1, nullptr, {}}; + model.attachView(&viewMock); + + EXPECT_CALL(viewMock, exportedTypeNamesChanged(added, IsEmpty())); + + observer->exportedTypeNamesChanged(added, {}); +} + +TEST_F(Model_MetaInfo, removed_exported_type_names_are_changed_callback_is_calling_abstract_view) +{ + using QmlDesigner::Storage::Info::ExportedTypeNames; + ExportedTypeNames removed = {{qtQuickModuleId, itemTypeId, "Foo", 1, 1}}; + ProjectStorageObserverMock observerMock; + QmlDesigner::ProjectStorageObserver *observer = nullptr; + ON_CALL(projectStorageMock, addObserver(_)).WillByDefault([&](auto *o) { observer = o; }); + QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, "Item", -1, -1, nullptr, {}}; + model.attachView(&viewMock); + + EXPECT_CALL(viewMock, exportedTypeNamesChanged(IsEmpty(), removed)); + + observer->exportedTypeNamesChanged({}, removed); +} + TEST_F(Model_MetaInfo, meta_infos_for_mdoule) { projectStorageMock.createModule("Foo", ModuleKind::QmlLibrary); diff --git a/tests/unit/tests/unittests/projectstorage/projectstorage-test.cpp b/tests/unit/tests/unittests/projectstorage/projectstorage-test.cpp index 96aa0a6ede8..b948fb91ce1 100644 --- a/tests/unit/tests/unittests/projectstorage/projectstorage-test.cpp +++ b/tests/unit/tests/unittests/projectstorage/projectstorage-test.cpp @@ -8189,9 +8189,9 @@ TEST_F(ProjectStorage, get_exported_type_names) auto exportedTypeNames = storage.exportedTypeNames(typeId); ASSERT_THAT(exportedTypeNames, - UnorderedElementsAre(IsInfoExportTypeNames(qmlModuleId, "Object", 2, -1), - IsInfoExportTypeNames(qmlModuleId, "Obj", 2, -1), - IsInfoExportTypeNames(qmlNativeModuleId, "QObject", -1, -1))); + UnorderedElementsAre(IsInfoExportTypeName(qmlModuleId, typeId, "Object", 2, -1), + IsInfoExportTypeName(qmlModuleId, typeId, "Obj", 2, -1), + IsInfoExportTypeName(qmlNativeModuleId, typeId, "QObject", -1, -1))); } TEST_F(ProjectStorage, get_no_exported_type_names_if_type_id_is_invalid) @@ -8215,8 +8215,8 @@ TEST_F(ProjectStorage, get_exported_type_names_for_source_id) auto exportedTypeNames = storage.exportedTypeNames(typeId, sourceId3); ASSERT_THAT(exportedTypeNames, - UnorderedElementsAre(IsInfoExportTypeNames(qmlModuleId, "Object", 2, -1), - IsInfoExportTypeNames(qmlModuleId, "Obj", 2, -1))); + UnorderedElementsAre(IsInfoExportTypeName(qmlModuleId, typeId, "Object", 2, -1), + IsInfoExportTypeName(qmlModuleId, typeId, "Obj", 2, -1))); } TEST_F(ProjectStorage, get_no_exported_type_names_for_source_id_for_invalid_type_id) @@ -9075,7 +9075,7 @@ TEST_F(ProjectStorage, added_document_import_fixes_unresolved_extension) ASSERT_THAT(fetchType(sourceId1, "QQuickItem"), HasExtensionId(fetchTypeId(sourceId2, "QObject"))); } -TEST_F(ProjectStorage, added_export_is_notifing_changed_exported_types) +TEST_F(ProjectStorage, added_export_is_notifying_changed_exported_types) { auto package{createSimpleSynchronizationPackage()}; storage.synchronize(package); @@ -9088,7 +9088,7 @@ TEST_F(ProjectStorage, added_export_is_notifing_changed_exported_types) storage.synchronize(std::move(package)); } -TEST_F(ProjectStorage, removed_export_is_notifing_changed_exported_types) +TEST_F(ProjectStorage, removed_export_is_notifying_changed_exported_types) { auto package{createSimpleSynchronizationPackage()}; storage.synchronize(package); @@ -9101,7 +9101,7 @@ TEST_F(ProjectStorage, removed_export_is_notifing_changed_exported_types) storage.synchronize(std::move(package)); } -TEST_F(ProjectStorage, changed_export_is_notifing_changed_exported_types) +TEST_F(ProjectStorage, changed_export_is_notifying_changed_exported_types) { auto package{createSimpleSynchronizationPackage()}; storage.synchronize(package); @@ -9114,6 +9114,66 @@ TEST_F(ProjectStorage, changed_export_is_notifing_changed_exported_types) storage.synchronize(std::move(package)); } +TEST_F(ProjectStorage, added_export_is_notifying_changed_exported_type_names) +{ + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[1].exportedTypes.emplace_back(qmlNativeModuleId, "Objec"); + NiceMock observerMock; + storage.addObserver(&observerMock); + + EXPECT_CALL(observerMock, + exportedTypeNamesChanged(ElementsAre( + IsInfoExportTypeName(qmlNativeModuleId, + fetchTypeId(sourceId2, "QObject"), + Eq("Objec"), + A())), + IsEmpty())); + + storage.synchronize(std::move(package)); +} + +TEST_F(ProjectStorage, removed_export_is_notifying_changed_exported_type_names) +{ + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[1].exportedTypes.pop_back(); + NiceMock observerMock; + storage.addObserver(&observerMock); + + EXPECT_CALL(observerMock, + exportedTypeNamesChanged(IsEmpty(), + ElementsAre( + IsInfoExportTypeName(qmlNativeModuleId, + fetchTypeId(sourceId2, "QObject"), + Eq("QObject"), + A())))); + + storage.synchronize(std::move(package)); +} + +TEST_F(ProjectStorage, changed_export_is_notifying_changed_exported_type_names) +{ + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[1].exportedTypes[1].name = "Obj2"; + NiceMock observerMock; + storage.addObserver(&observerMock); + + EXPECT_CALL(observerMock, + exportedTypeNamesChanged( + ElementsAre(IsInfoExportTypeName(qmlModuleId, + fetchTypeId(sourceId2, "QObject"), + Eq("Obj2"), + A())), + ElementsAre(IsInfoExportTypeName(qmlModuleId, + fetchTypeId(sourceId2, "QObject"), + Eq("Obj"), + A())))); + + storage.synchronize(std::move(package)); +} + TEST_F(ProjectStorage, get_unqiue_singleton_type_ids) { auto package{createSimpleSynchronizationPackage()};