QmlDesigner: Add exported type name notification

If an exported type name will be updated, the notifier will put it into
removed and added. That can anyway happen if the module is moved with a time difference.

Task-number: QDS-14669
Change-Id: I5ede7ce8edc8c02056bea35f27d266379bae044c
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Marco Bubke
2025-03-31 18:06:23 +02:00
committed by Thomas Hartmann
parent 5abeb01ca2
commit 4fdf1522ff
17 changed files with 255 additions and 96 deletions

View File

@@ -155,6 +155,9 @@ public:
virtual void modelAboutToBeDetached(Model *model); virtual void modelAboutToBeDetached(Model *model);
virtual void refreshMetaInfos(const TypeIds &deletedTypeIds); 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 nodeCreated(const ModelNode &createdNode);
virtual void nodeAboutToBeRemoved(const ModelNode &removedNode); virtual void nodeAboutToBeRemoved(const ModelNode &removedNode);

View File

@@ -177,6 +177,8 @@ void AbstractView::modelAboutToBeDetached(Model *)
void AbstractView::refreshMetaInfos(const TypeIds &) {} void AbstractView::refreshMetaInfos(const TypeIds &) {}
void AbstractView::exportedTypeNamesChanged(const ExportedTypeNames &, const ExportedTypeNames &) {}
/*! /*!
\enum QmlDesigner::AbstractView::PropertyChangeFlag \enum QmlDesigner::AbstractView::PropertyChangeFlag

View File

@@ -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) void ModelPrivate::removeAllSubNodes(const InternalNodePointer &node)
{ {
for (const InternalNodePointer &subNode : node->allSubNodes()) for (const InternalNodePointer &subNode : node->allSubNodes())

View File

@@ -326,6 +326,8 @@ public:
protected: protected:
void removedTypeIds(const TypeIds &removedTypeIds) override; void removedTypeIds(const TypeIds &removedTypeIds) override;
void exportedTypesChanged() override; void exportedTypesChanged() override;
void exportedTypeNamesChanged(const ExportedTypeNames &added,
const ExportedTypeNames &removed) override;
void removeNode(const InternalNodePointer &node); void removeNode(const InternalNodePointer &node);
private: private:

View File

@@ -107,14 +107,20 @@ struct ProjectStorage::Statements
"defaultPropertyId=propertyDeclarationId " "defaultPropertyId=propertyDeclarationId "
"WHERE t.typeId=?", "WHERE t.typeId=?",
database}; database};
mutable Sqlite::ReadStatement<4, 1> selectExportedTypesByTypeIdStatement{ mutable Sqlite::ReadStatement<5, 1> selectExportedTypesByTypeIdStatement{
"SELECT moduleId, name, ifnull(majorVersion, -1), ifnull(minorVersion, -1) FROM " "SELECT moduleId, typeId, name, ifnull(majorVersion, -1), ifnull(minorVersion, -1) "
"exportedTypeNames WHERE typeId=?", "FROM exportedTypeNames "
"WHERE typeId=?",
database}; database};
mutable Sqlite::ReadStatement<4, 2> selectExportedTypesByTypeIdAndSourceIdStatement{ mutable Sqlite::ReadStatement<5, 2> selectExportedTypesByTypeIdAndSourceIdStatement{
"SELECT etn.moduleId, name, ifnull(etn.majorVersion, -1), ifnull(etn.minorVersion, -1) " "SELECT etn.moduleId, "
"FROM exportedTypeNames AS etn JOIN documentImports USING(moduleId) WHERE typeId=?1 AND " " typeId, "
"sourceId=?2", " name, "
" ifnull(etn.majorVersion, -1), "
" ifnull(etn.minorVersion, -1) "
"FROM exportedTypeNames AS etn "
"JOIN documentImports USING(moduleId) "
"WHERE typeId=?1 AND sourceId=?2",
database}; database};
mutable Sqlite::ReadStatement<8> selectTypesStatement{ mutable Sqlite::ReadStatement<8> selectTypesStatement{
"SELECT sourceId, t.name, t.typeId, prototypeId, extensionId, traits, annotationTraits, " "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()}; NanotraceHR::Tracer tracer{"synchronize", projectStorageCategory()};
TypeIds deletedTypeIds; TypeIds deletedTypeIds;
Storage::Info::ExportedTypeNames removedExportedTypeNames;
Storage::Info::ExportedTypeNames addedExportedTypeNames;
ExportedTypesChanged exportedTypesChanged = ExportedTypesChanged::No; ExportedTypesChanged exportedTypesChanged = ExportedTypesChanged::No;
Sqlite::withImmediateTransaction(database, [&] { Sqlite::withImmediateTransaction(database, [&] {
@@ -1332,6 +1340,8 @@ void ProjectStorage::synchronize(Storage::Synchronization::SynchronizationPackag
relinkablePrototypes, relinkablePrototypes,
relinkableExtensions, relinkableExtensions,
exportedTypesChanged, exportedTypesChanged,
removedExportedTypeNames,
addedExportedTypeNames,
package.updatedSourceIds); package.updatedSourceIds);
synchronizeTypeAnnotations(package.typeAnnotations, package.updatedTypeAnnotationSourceIds); synchronizeTypeAnnotations(package.typeAnnotations, package.updatedTypeAnnotationSourceIds);
synchronizePropertyEditorQmlPaths(package.propertyEditorQmlPaths, synchronizePropertyEditorQmlPaths(package.propertyEditorQmlPaths,
@@ -1361,7 +1371,10 @@ void ProjectStorage::synchronize(Storage::Synchronization::SynchronizationPackag
commonTypeCache_.resetTypeIds(); commonTypeCache_.resetTypeIds();
}); });
callRefreshMetaInfoCallback(deletedTypeIds, exportedTypesChanged); callRefreshMetaInfoCallback(deletedTypeIds,
exportedTypesChanged,
removedExportedTypeNames,
addedExportedTypeNames);
} }
void ProjectStorage::synchronizeDocumentImports(Storage::Imports imports, SourceId sourceId) void ProjectStorage::synchronizeDocumentImports(Storage::Imports imports, SourceId sourceId)
@@ -2348,8 +2361,11 @@ ProjectStorage::ModuleCacheEntries ProjectStorage::fetchAllModules() const
return s->selectAllModulesStatement.valuesWithTransaction<ModuleCacheEntry, 128>(); return s->selectAllModulesStatement.valuesWithTransaction<ModuleCacheEntry, 128>();
} }
void ProjectStorage::callRefreshMetaInfoCallback(TypeIds &deletedTypeIds, void ProjectStorage::callRefreshMetaInfoCallback(
ExportedTypesChanged &exportedTypesChanged) TypeIds &deletedTypeIds,
ExportedTypesChanged exportedTypesChanged,
const Storage::Info::ExportedTypeNames &removedExportedTypeNames,
const Storage::Info::ExportedTypeNames &addedExportedTypeNames)
{ {
using NanotraceHR::keyValue; using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"call refresh meta info callback", NanotraceHR::Tracer tracer{"call refresh meta info callback",
@@ -2364,8 +2380,10 @@ void ProjectStorage::callRefreshMetaInfoCallback(TypeIds &deletedTypeIds,
} }
if (exportedTypesChanged == ExportedTypesChanged::Yes) { if (exportedTypesChanged == ExportedTypesChanged::Yes) {
for (ProjectStorageObserver *observer : observers) for (ProjectStorageObserver *observer : observers) {
observer->exportedTypesChanged(); observer->exportedTypesChanged();
observer->exportedTypeNamesChanged(addedExportedTypeNames, removedExportedTypeNames);
}
} }
} }
@@ -2428,7 +2446,6 @@ void ProjectStorage::synchronizeTypeAnnotations(Storage::Synchronization::TypeAn
{ {
NanotraceHR::Tracer tracer{"synchronize type annotations", projectStorageCategory()}; NanotraceHR::Tracer tracer{"synchronize type annotations", projectStorageCategory()};
updateTypeIdInTypeAnnotations(typeAnnotations); updateTypeIdInTypeAnnotations(typeAnnotations);
auto compareKey = [](auto &&first, auto &&second) { return first.typeId <=> second.typeId; }; 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 &relinkablePrototypes,
Prototypes &relinkableExtensions, Prototypes &relinkableExtensions,
ExportedTypesChanged &exportedTypesChanged, ExportedTypesChanged &exportedTypesChanged,
Storage::Info::ExportedTypeNames &removedExportedTypeNames,
Storage::Info::ExportedTypeNames &addedExportedTypeNames,
const SourceIds &updatedSourceIds) const SourceIds &updatedSourceIds)
{ {
NanotraceHR::Tracer tracer{"synchronize types", projectStorageCategory()}; NanotraceHR::Tracer tracer{"synchronize types", projectStorageCategory()};
@@ -2564,7 +2583,9 @@ void ProjectStorage::synchronizeTypes(Storage::Synchronization::Types &types,
relinkablePropertyDeclarations, relinkablePropertyDeclarations,
relinkablePrototypes, relinkablePrototypes,
relinkableExtensions, relinkableExtensions,
exportedTypesChanged); exportedTypesChanged,
removedExportedTypeNames,
addedExportedTypeNames);
syncPrototypesAndExtensions(types, relinkablePrototypes, relinkableExtensions); syncPrototypesAndExtensions(types, relinkablePrototypes, relinkableExtensions);
resetDefaultPropertiesIfChanged(types); resetDefaultPropertiesIfChanged(types);
@@ -3299,17 +3320,23 @@ void ProjectStorage::repairBrokenAliasPropertyDeclarations()
linkAliases(brokenAliasPropertyDeclarations, RaiseError::No); linkAliases(brokenAliasPropertyDeclarations, RaiseError::No);
} }
void ProjectStorage::synchronizeExportedTypes(const TypeIds &updatedTypeIds, void ProjectStorage::synchronizeExportedTypes(
Storage::Synchronization::ExportedTypes &exportedTypes, const TypeIds &updatedTypeIds,
AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, Storage::Synchronization::ExportedTypes &exportedTypes,
PropertyDeclarations &relinkablePropertyDeclarations, AliasPropertyDeclarations &relinkableAliasPropertyDeclarations,
Prototypes &relinkablePrototypes, PropertyDeclarations &relinkablePropertyDeclarations,
Prototypes &relinkableExtensions, Prototypes &relinkablePrototypes,
ExportedTypesChanged &exportedTypesChanged) Prototypes &relinkableExtensions,
ExportedTypesChanged &exportedTypesChanged,
Storage::Info::ExportedTypeNames &removedExportedTypeNames,
Storage::Info::ExportedTypeNames &addedExportedTypeNames)
{ {
using NanotraceHR::keyValue; using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"synchronize exported types", projectStorageCategory()}; NanotraceHR::Tracer tracer{"synchronize exported types", projectStorageCategory()};
removedExportedTypeNames.reserve(exportedTypes.size());
addedExportedTypeNames.reserve(exportedTypes.size());
std::ranges::sort(exportedTypes, [](auto &&first, auto &&second) { std::ranges::sort(exportedTypes, [](auto &&first, auto &&second) {
if (first.moduleId < second.moduleId) if (first.moduleId < second.moduleId)
return true; return true;
@@ -3376,6 +3403,8 @@ void ProjectStorage::synchronizeExportedTypes(const TypeIds &updatedTypeIds,
handlePrototypesWithExportedTypeNameAndTypeId(type.name, unresolvedTypeId, relinkablePrototypes); handlePrototypesWithExportedTypeNameAndTypeId(type.name, unresolvedTypeId, relinkablePrototypes);
handleExtensionsWithExportedTypeNameAndTypeId(type.name, unresolvedTypeId, relinkableExtensions); handleExtensionsWithExportedTypeNameAndTypeId(type.name, unresolvedTypeId, relinkableExtensions);
addedExportedTypeNames.emplace_back(type.moduleId, type.typeId, type.name, type.version);
exportedTypesChanged = ExportedTypesChanged::Yes; exportedTypesChanged = ExportedTypesChanged::Yes;
}; };
@@ -3397,6 +3426,9 @@ void ProjectStorage::synchronizeExportedTypes(const TypeIds &updatedTypeIds,
s->updateExportedTypeNameTypeIdStatement.write(view.exportedTypeNameId, type.typeId); s->updateExportedTypeNameTypeIdStatement.write(view.exportedTypeNameId, type.typeId);
exportedTypesChanged = ExportedTypesChanged::Yes; 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::Update;
} }
return Sqlite::UpdateChange::No; return Sqlite::UpdateChange::No;
@@ -3417,6 +3449,8 @@ void ProjectStorage::synchronizeExportedTypes(const TypeIds &updatedTypeIds,
s->deleteExportedTypeNameStatement.write(view.exportedTypeNameId); s->deleteExportedTypeNameStatement.write(view.exportedTypeNameId);
removedExportedTypeNames.emplace_back(view.moduleId, view.typeId, view.name, view.version);
exportedTypesChanged = ExportedTypesChanged::Yes; exportedTypesChanged = ExportedTypesChanged::Yes;
}; };

View File

@@ -325,7 +325,9 @@ private:
enum class ExportedTypesChanged { No, Yes }; enum class ExportedTypesChanged { No, Yes };
void callRefreshMetaInfoCallback(TypeIds &deletedTypeIds, void callRefreshMetaInfoCallback(TypeIds &deletedTypeIds,
ExportedTypesChanged &exportedTypesChanged); ExportedTypesChanged exportedTypesChanged,
const Storage::Info::ExportedTypeNames &removedExportedTypeNames,
const Storage::Info::ExportedTypeNames &addedExportedTypeNames);
class AliasPropertyDeclaration class AliasPropertyDeclaration
{ {
@@ -565,6 +567,8 @@ private:
Prototypes &relinkablePrototypes, Prototypes &relinkablePrototypes,
Prototypes &relinkableExtensions, Prototypes &relinkableExtensions,
ExportedTypesChanged &exportedTypesChanged, ExportedTypesChanged &exportedTypesChanged,
Storage::Info::ExportedTypeNames &removedExportedTypeNames,
Storage::Info::ExportedTypeNames &addedExportedTypeNames,
const SourceIds &updatedSourceIds); const SourceIds &updatedSourceIds);
void synchronizeDirectoryInfos(Storage::Synchronization::DirectoryInfos &directoryInfos, void synchronizeDirectoryInfos(Storage::Synchronization::DirectoryInfos &directoryInfos,
@@ -666,7 +670,9 @@ private:
PropertyDeclarations &relinkablePropertyDeclarations, PropertyDeclarations &relinkablePropertyDeclarations,
Prototypes &relinkablePrototypes, Prototypes &relinkablePrototypes,
Prototypes &relinkableExtensions, Prototypes &relinkableExtensions,
ExportedTypesChanged &exportedTypesChanged); ExportedTypesChanged &exportedTypesChanged,
Storage::Info::ExportedTypeNames &removedExportedTypeNames,
Storage::Info::ExportedTypeNames &addedExportedTypeNames);
void synchronizePropertyDeclarationsInsertAlias( void synchronizePropertyDeclarationsInsertAlias(
AliasPropertyDeclarations &insertedAliasPropertyDeclarations, AliasPropertyDeclarations &insertedAliasPropertyDeclarations,

View File

@@ -257,20 +257,7 @@ public:
explicit operator bool() const { return value >= 0; } explicit operator bool() const { return value >= 0; }
friend bool operator==(VersionNumber first, VersionNumber second) noexcept auto operator<=>(const VersionNumber &first) const noexcept = default;
{
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;
}
public: public:
int value = -1; int value = -1;
@@ -294,15 +281,7 @@ public:
: major{major} : major{major}
{} {}
friend bool operator==(Version first, Version second) noexcept auto operator<=>(const Version &first) const noexcept = default;
{
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);
}
explicit operator bool() const { return major && minor; } explicit operator bool() const { return major && minor; }
@@ -470,32 +449,36 @@ public:
ExportedTypeName() = default; ExportedTypeName() = default;
ExportedTypeName(ModuleId moduleId, ExportedTypeName(ModuleId moduleId,
TypeId typeId,
::Utils::SmallStringView name, ::Utils::SmallStringView name,
Storage::Version version = Storage::Version{}) Storage::Version version = Storage::Version{})
: name{name} : name{name}
, version{version} , version{version}
, moduleId{moduleId} , moduleId{moduleId}
, typeId{typeId}
{} {}
ExportedTypeName(ModuleId moduleId, ExportedTypeName(ModuleId moduleId,
TypeId typeId,
::Utils::SmallStringView name, ::Utils::SmallStringView name,
int majorVersion, int majorVersion,
int minorVersion) int minorVersion)
: name{name} : name{name}
, version{majorVersion, minorVersion} , version{majorVersion, minorVersion}
, moduleId{moduleId} , moduleId{moduleId}
, typeId{typeId}
{} {}
friend bool operator==(const ExportedTypeName &first, const ExportedTypeName &second) friend bool operator==(const ExportedTypeName &first, const ExportedTypeName &second)
{ {
return first.moduleId == second.moduleId && first.version == second.version return first.moduleId == second.moduleId && first.typeId == second.typeId
&& first.name == second.name; && 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) return std::tie(first.moduleId, first.name, first.version, second.typeId)
< std::tie(second.moduleId, second.name, second.version); <=> std::tie(second.moduleId, second.name, second.version, second.typeId);
} }
template<typename String> template<typename String>
@@ -505,7 +488,8 @@ public:
using NanotraceHR::keyValue; using NanotraceHR::keyValue;
auto dict = dictonary(keyValue("name", exportedTypeName.name), auto dict = dictonary(keyValue("name", exportedTypeName.name),
keyValue("version", exportedTypeName.version), keyValue("version", exportedTypeName.version),
keyValue("module id", exportedTypeName.moduleId)); keyValue("module id", exportedTypeName.moduleId),
keyValue("type id", exportedTypeName.typeId));
convertToString(string, dict); convertToString(string, dict);
} }
@@ -514,6 +498,7 @@ public:
::Utils::SmallString name; ::Utils::SmallString name;
Storage::Version version; Storage::Version version;
ModuleId moduleId; ModuleId moduleId;
TypeId typeId;
}; };
using ExportedTypeNames = std::vector<ExportedTypeName>; using ExportedTypeNames = std::vector<ExportedTypeName>;

View File

@@ -4,13 +4,17 @@
#pragma once #pragma once
#include "projectstorageids.h" #include "projectstorageids.h"
#include "projectstorageinfotypes.h"
namespace QmlDesigner { namespace QmlDesigner {
class ProjectStorageObserver class ProjectStorageObserver
{ {
public: public:
using ExportedTypeNames = Storage::Info::ExportedTypeNames;
virtual void removedTypeIds(const TypeIds &removedTypeIds) = 0; virtual void removedTypeIds(const TypeIds &removedTypeIds) = 0;
virtual void exportedTypesChanged() = 0; virtual void exportedTypesChanged() = 0;
virtual void exportedTypeNamesChanged(const ExportedTypeNames &added, const ExportedTypeNames &removed) = 0;
}; };
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -393,11 +393,13 @@ public:
{} {}
explicit ExportedType(ModuleId moduleId, explicit ExportedType(ModuleId moduleId,
TypeId typeId,
::Utils::SmallStringView name, ::Utils::SmallStringView name,
int majorVersion, int majorVersion,
int minorVersion) int minorVersion)
: name{name} : name{name}
, version{majorVersion, minorVersion} , version{majorVersion, minorVersion}
, typeId{typeId}
, moduleId{moduleId} , moduleId{moduleId}
{} {}

View File

@@ -7,27 +7,43 @@
#include <projectstorage/projectstorageinfotypes.h> #include <projectstorage/projectstorageinfotypes.h>
template<typename ModuleIdMatcher, template<typename ModuleIdMatcher, typename TypeIdMatcher, typename NameMatcher, typename MajorVersionMatcher, typename MinorVersionMatcher>
typename NameMatcher, auto IsInfoExportTypeName(const ModuleIdMatcher &moduleIdMatcher,
typename MajorVersionMatcher, const TypeIdMatcher &typeIdMatcher,
typename MinorVersionMatcher> const NameMatcher &nameMatcher,
auto IsInfoExportTypeNames(const ModuleIdMatcher &moduleIdMatcher, const MajorVersionMatcher &majorVersionMatcher,
const NameMatcher &nameMatcher, const MinorVersionMatcher &minorVersionMatcher)
const MajorVersionMatcher &majorVersionMatcher,
const MinorVersionMatcher &minorVersionMatcher)
{ {
return AllOf(Field("QmlDesigner::Storage::Info::ExportedTypeName::moduleId", &QmlDesigner::Storage::Info::ExportedTypeName::moduleId, moduleIdMatcher), return AllOf(Field("QmlDesigner::Storage::Info::ExportedTypeName::moduleId",
Field("QmlDesigner::Storage::Info::ExportedTypeName::name", &QmlDesigner::Storage::Info::ExportedTypeName::name, nameMatcher), &QmlDesigner::Storage::Info::ExportedTypeName::moduleId,
Field("QmlDesigner::Storage::Info::ExportedTypeName::version", &QmlDesigner::Storage::Info::ExportedTypeName::version, 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))); IsVersion(majorVersionMatcher, minorVersionMatcher)));
} }
template<typename ModuleIdMatcher, typename NameMatcher, typename VersionMatcher> template<typename ModuleIdMatcher, typename TypeIdMatcher, typename NameMatcher, typename VersionMatcher>
auto IsInfoExportTypeNames(const ModuleIdMatcher &moduleIdMatcher, auto IsInfoExportTypeName(const ModuleIdMatcher &moduleIdMatcher,
const NameMatcher &nameMatcher, const TypeIdMatcher &typeIdMatcher,
const VersionMatcher &versionMatcher) const NameMatcher &nameMatcher,
const VersionMatcher &versionMatcher)
{ {
return AllOf(Field("QmlDesigner::Storage::Info::ExportedTypeName::moduleId", &QmlDesigner::Storage::Info::ExportedTypeName::moduleId, moduleIdMatcher), return AllOf(Field("QmlDesigner::Storage::Info::ExportedTypeName::moduleId",
Field("QmlDesigner::Storage::Info::ExportedTypeName::name", &QmlDesigner::Storage::Info::ExportedTypeName::name, nameMatcher), &QmlDesigner::Storage::Info::ExportedTypeName::moduleId,
Field("QmlDesigner::Storage::Info::ExportedTypeName::version", &QmlDesigner::Storage::Info::ExportedTypeName::version, versionMatcher)); 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));
} }

View File

@@ -65,6 +65,10 @@ public:
(override)); (override));
MOCK_METHOD(void, nodeAboutToBeRemoved, (const QmlDesigner::ModelNode &removedNode), (override)); MOCK_METHOD(void, nodeAboutToBeRemoved, (const QmlDesigner::ModelNode &removedNode), (override));
MOCK_METHOD(void, refreshMetaInfos, (const QmlDesigner::TypeIds &), (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, modelAttached, (QmlDesigner::Model *), (override));
MOCK_METHOD(void, modelAboutToBeDetached, (QmlDesigner::Model *), (override)); MOCK_METHOD(void, modelAboutToBeDetached, (QmlDesigner::Model *), (override));

View File

@@ -128,7 +128,7 @@ void ProjectStorageMock::addExportedTypeName(QmlDesigner::TypeId typeId,
ON_CALL(*this, typeId(Eq(moduleId), Eq(typeName), _)).WillByDefault(Return(typeId)); ON_CALL(*this, typeId(Eq(moduleId), Eq(typeName), _)).WillByDefault(Return(typeId));
ON_CALL(*this, fetchTypeIdByModuleIdAndExportedName(Eq(moduleId), Eq(typeName))) ON_CALL(*this, fetchTypeIdByModuleIdAndExportedName(Eq(moduleId), Eq(typeName)))
.WillByDefault(Return(typeId)); .WillByDefault(Return(typeId));
exportedTypeName[typeId].emplace_back(moduleId, typeName); exportedTypeName[typeId].emplace_back(moduleId, typeId, typeName);
} }
void ProjectStorageMock::addExportedTypeNameBySourceId(QmlDesigner::TypeId typeId, void ProjectStorageMock::addExportedTypeNameBySourceId(QmlDesigner::TypeId typeId,
@@ -136,7 +136,7 @@ void ProjectStorageMock::addExportedTypeNameBySourceId(QmlDesigner::TypeId typeI
Utils::SmallStringView typeName, Utils::SmallStringView typeName,
QmlDesigner::SourceId sourceId) QmlDesigner::SourceId sourceId)
{ {
exportedTypeNameBySourceId[{typeId, sourceId}].emplace_back(moduleId, typeName); exportedTypeNameBySourceId[{typeId, sourceId}].emplace_back(moduleId, typeId, typeName);
} }
void ProjectStorageMock::removeExportedTypeName(QmlDesigner::TypeId typeId, void ProjectStorageMock::removeExportedTypeName(QmlDesigner::TypeId typeId,

View File

@@ -12,4 +12,8 @@ class ProjectStorageObserverMock : public QmlDesigner::ProjectStorageObserver
public: public:
MOCK_METHOD(void, removedTypeIds, (const QmlDesigner::TypeIds &), (override)); MOCK_METHOD(void, removedTypeIds, (const QmlDesigner::TypeIds &), (override));
MOCK_METHOD(void, exportedTypesChanged, (), (override)); MOCK_METHOD(void, exportedTypesChanged, (), (override));
MOCK_METHOD(void,
exportedTypeNamesChanged,
(const ExportedTypeNames &added, const ExportedTypeNames &removed),
(override));
}; };

View File

@@ -751,7 +751,8 @@ std::ostream &operator<<(std::ostream &out, const Type &type)
std::ostream &operator<<(std::ostream &out, const ExportedTypeName &name) 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) std::ostream &operator<<(std::ostream &out, const TypeHint &hint)

View File

@@ -2624,23 +2624,23 @@ TEST_F(NodeMetaInfo, default_is_not_enumeration)
TEST_F(NodeMetaInfo, all_external_type_names) 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"); 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)); ON_CALL(projectStorageMock, exportedTypeNames(metaInfo.id())).WillByDefault(Return(names));
auto exportedTypeNames = metaInfo.allExportedTypeNames(); auto exportedTypeNames = metaInfo.allExportedTypeNames();
ASSERT_THAT(exportedTypeNames, ASSERT_THAT(exportedTypeNames,
UnorderedElementsAre(IsInfoExportTypeNames(qmlModuleId, "Object", 2, -1), UnorderedElementsAre(IsInfoExportTypeName(qmlModuleId, metaInfo.id(), "Object", 2, -1),
IsInfoExportTypeNames(qmlModuleId, "Obj", 2, 1))); IsInfoExportTypeName(qmlModuleId, metaInfo.id(), "Obj", 2, 1)));
} }
TEST_F(NodeMetaInfo, default_has_no_external_type_names) 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::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)); ON_CALL(projectStorageMock, exportedTypeNames(_)).WillByDefault(Return(names));
auto exportedTypeNames = metaInfo.allExportedTypeNames(); 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) 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"); 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())) ON_CALL(projectStorageMock, exportedTypeNames(metaInfo.id(), model.fileUrlSourceId()))
.WillByDefault(Return(names)); .WillByDefault(Return(names));
auto exportedTypeNames = metaInfo.exportedTypeNamesForSourceId(model.fileUrlSourceId()); auto exportedTypeNames = metaInfo.exportedTypeNamesForSourceId(model.fileUrlSourceId());
ASSERT_THAT(exportedTypeNames, ASSERT_THAT(exportedTypeNames,
UnorderedElementsAre(IsInfoExportTypeNames(qmlModuleId, "Object", 2, -1), UnorderedElementsAre(IsInfoExportTypeName(qmlModuleId, metaInfo.id(), "Object", 2, -1),
IsInfoExportTypeNames(qmlModuleId, "Obj", 2, 1))); IsInfoExportTypeName(qmlModuleId, metaInfo.id(), "Obj", 2, 1)));
} }
TEST_F(NodeMetaInfo, default_has_no_external_type_names_for_source_id) 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::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())) ON_CALL(projectStorageMock, exportedTypeNames(metaInfo.id(), model.fileUrlSourceId()))
.WillByDefault(Return(names)); .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) 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"); 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())) ON_CALL(projectStorageMock, exportedTypeNames(metaInfo.id(), model.fileUrlSourceId()))
.WillByDefault(Return(names)); .WillByDefault(Return(names));
QmlDesigner::SourceId sourceId; QmlDesigner::SourceId sourceId;

View File

@@ -1141,14 +1141,13 @@ TEST_F(Model_MetaInfo, remove_project_storage_observer_from_project_storage)
QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, "Item", -1, -1, nullptr, {}}; 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), const QmlDesigner::TypeIds typeIds = {QmlDesigner::TypeId::create(3),
QmlDesigner::TypeId::create(1)}; QmlDesigner::TypeId::create(1)};
ProjectStorageObserverMock observerMock; ProjectStorageObserverMock observerMock;
QmlDesigner::ProjectStorageObserver *observer = nullptr; QmlDesigner::ProjectStorageObserver *observer = nullptr;
ON_CALL(projectStorageMock, addObserver(_)).WillByDefault([&](auto *o) { observer = o; }); ON_CALL(projectStorageMock, addObserver(_)).WillByDefault([&](auto *o) { observer = o; });
QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, "Item", -1, -1, nullptr, {}}; QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, "Item", -1, -1, nullptr, {}};
model.attachView(&viewMock); model.attachView(&viewMock);
@@ -1157,6 +1156,36 @@ TEST_F(Model_MetaInfo, refresh_callback_is_calling_abstract_view)
observer->removedTypeIds(typeIds); 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) TEST_F(Model_MetaInfo, meta_infos_for_mdoule)
{ {
projectStorageMock.createModule("Foo", ModuleKind::QmlLibrary); projectStorageMock.createModule("Foo", ModuleKind::QmlLibrary);

View File

@@ -8189,9 +8189,9 @@ TEST_F(ProjectStorage, get_exported_type_names)
auto exportedTypeNames = storage.exportedTypeNames(typeId); auto exportedTypeNames = storage.exportedTypeNames(typeId);
ASSERT_THAT(exportedTypeNames, ASSERT_THAT(exportedTypeNames,
UnorderedElementsAre(IsInfoExportTypeNames(qmlModuleId, "Object", 2, -1), UnorderedElementsAre(IsInfoExportTypeName(qmlModuleId, typeId, "Object", 2, -1),
IsInfoExportTypeNames(qmlModuleId, "Obj", 2, -1), IsInfoExportTypeName(qmlModuleId, typeId, "Obj", 2, -1),
IsInfoExportTypeNames(qmlNativeModuleId, "QObject", -1, -1))); IsInfoExportTypeName(qmlNativeModuleId, typeId, "QObject", -1, -1)));
} }
TEST_F(ProjectStorage, get_no_exported_type_names_if_type_id_is_invalid) 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); auto exportedTypeNames = storage.exportedTypeNames(typeId, sourceId3);
ASSERT_THAT(exportedTypeNames, ASSERT_THAT(exportedTypeNames,
UnorderedElementsAre(IsInfoExportTypeNames(qmlModuleId, "Object", 2, -1), UnorderedElementsAre(IsInfoExportTypeName(qmlModuleId, typeId, "Object", 2, -1),
IsInfoExportTypeNames(qmlModuleId, "Obj", 2, -1))); IsInfoExportTypeName(qmlModuleId, typeId, "Obj", 2, -1)));
} }
TEST_F(ProjectStorage, get_no_exported_type_names_for_source_id_for_invalid_type_id) 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"))); 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()}; auto package{createSimpleSynchronizationPackage()};
storage.synchronize(package); storage.synchronize(package);
@@ -9088,7 +9088,7 @@ TEST_F(ProjectStorage, added_export_is_notifing_changed_exported_types)
storage.synchronize(std::move(package)); 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()}; auto package{createSimpleSynchronizationPackage()};
storage.synchronize(package); storage.synchronize(package);
@@ -9101,7 +9101,7 @@ TEST_F(ProjectStorage, removed_export_is_notifing_changed_exported_types)
storage.synchronize(std::move(package)); 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()}; auto package{createSimpleSynchronizationPackage()};
storage.synchronize(package); storage.synchronize(package);
@@ -9114,6 +9114,66 @@ TEST_F(ProjectStorage, changed_export_is_notifing_changed_exported_types)
storage.synchronize(std::move(package)); 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<ProjectStorageObserverMock> observerMock;
storage.addObserver(&observerMock);
EXPECT_CALL(observerMock,
exportedTypeNamesChanged(ElementsAre(
IsInfoExportTypeName(qmlNativeModuleId,
fetchTypeId(sourceId2, "QObject"),
Eq("Objec"),
A<QmlDesigner::Storage::Version>())),
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<ProjectStorageObserverMock> observerMock;
storage.addObserver(&observerMock);
EXPECT_CALL(observerMock,
exportedTypeNamesChanged(IsEmpty(),
ElementsAre(
IsInfoExportTypeName(qmlNativeModuleId,
fetchTypeId(sourceId2, "QObject"),
Eq("QObject"),
A<QmlDesigner::Storage::Version>()))));
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<ProjectStorageObserverMock> observerMock;
storage.addObserver(&observerMock);
EXPECT_CALL(observerMock,
exportedTypeNamesChanged(
ElementsAre(IsInfoExportTypeName(qmlModuleId,
fetchTypeId(sourceId2, "QObject"),
Eq("Obj2"),
A<QmlDesigner::Storage::Version>())),
ElementsAre(IsInfoExportTypeName(qmlModuleId,
fetchTypeId(sourceId2, "QObject"),
Eq("Obj"),
A<QmlDesigner::Storage::Version>()))));
storage.synchronize(std::move(package));
}
TEST_F(ProjectStorage, get_unqiue_singleton_type_ids) TEST_F(ProjectStorage, get_unqiue_singleton_type_ids)
{ {
auto package{createSimpleSynchronizationPackage()}; auto package{createSimpleSynchronizationPackage()};