diff --git a/src/plugins/qmldesigner/libs/designercore/CMakeLists.txt b/src/plugins/qmldesigner/libs/designercore/CMakeLists.txt index e3bb78e8dd1..5cfc58be14a 100644 --- a/src/plugins/qmldesigner/libs/designercore/CMakeLists.txt +++ b/src/plugins/qmldesigner/libs/designercore/CMakeLists.txt @@ -391,6 +391,7 @@ extend_qtc_library(QmlDesignerCore projectstorageinfotypes.h projectstorageobserver.h projectstoragepathwatcher.h + projectstoragetriggerupdateinterface.h projectstoragepathwatcherinterface.h projectstoragepathwatchernotifierinterface.h projectstoragepathwatcher.h diff --git a/src/plugins/qmldesigner/libs/designercore/include/model.h b/src/plugins/qmldesigner/libs/designercore/include/model.h index 9ee93be5b09..ee80d1b5483 100644 --- a/src/plugins/qmldesigner/libs/designercore/include/model.h +++ b/src/plugins/qmldesigner/libs/designercore/include/model.h @@ -281,6 +281,7 @@ public: NotNullPointer projectStorage() const; const PathCacheType &pathCache() const; PathCacheType &pathCache(); + ProjectStorageTriggerUpdateInterface &projectStorageTriggerUpdate() const; void emitInstancePropertyChange(AbstractView *view, const QList> &propertyList); diff --git a/src/plugins/qmldesigner/libs/designercore/include/modelfwd.h b/src/plugins/qmldesigner/libs/designercore/include/modelfwd.h index 6557d8ebd5d..a886e2bb9dd 100644 --- a/src/plugins/qmldesigner/libs/designercore/include/modelfwd.h +++ b/src/plugins/qmldesigner/libs/designercore/include/modelfwd.h @@ -42,6 +42,7 @@ constexpr bool useProjectStorage() #endif } class SourcePathStorage; +class ProjectStorageTriggerUpdateInterface; using PathCache = SourcePathCache; #ifdef QDS_MODEL_USE_PROJECTSTORAGEINTERFACE @@ -52,11 +53,11 @@ using PathCacheType = SourcePathCacheInterface; using ProjectStorageType = ProjectStorage; using PathCacheType = SourcePathCache; #endif - struct ProjectStorageDependencies { ProjectStorageType &storage; PathCacheType &cache; + ProjectStorageTriggerUpdateInterface &triggerUpdate; }; enum class PropertyType { diff --git a/src/plugins/qmldesigner/libs/designercore/model/model.cpp b/src/plugins/qmldesigner/libs/designercore/model/model.cpp index b0636a9f0ca..28b847fdfa4 100644 --- a/src/plugins/qmldesigner/libs/designercore/model/model.cpp +++ b/src/plugins/qmldesigner/libs/designercore/model/model.cpp @@ -85,6 +85,7 @@ ModelPrivate::ModelPrivate(Model *model, std::unique_ptr resourceManagement) : projectStorage{&projectStorageDependencies.storage} , pathCache{&projectStorageDependencies.cache} + , projectStorageTriggerUpdate{&projectStorageDependencies.triggerUpdate} , m_model{model} , m_resourceManagement{std::move(resourceManagement)} { @@ -110,6 +111,7 @@ ModelPrivate::ModelPrivate(Model *model, std::unique_ptr resourceManagement) : projectStorage{&projectStorageDependencies.storage} , pathCache{&projectStorageDependencies.cache} + , projectStorageTriggerUpdate{&projectStorageDependencies.triggerUpdate} , m_model{model} , m_resourceManagement{std::move(resourceManagement)} { @@ -1771,7 +1773,7 @@ Model::Model(const TypeName &typeName, ModelPointer Model::createModel(const TypeName &typeName, std::unique_ptr resourceManagement) { - return Model::create({*d->projectStorage, *d->pathCache}, + return Model::create({*d->projectStorage, *d->pathCache, *d->projectStorageTriggerUpdate}, typeName, imports(), fileUrl(), @@ -2018,6 +2020,11 @@ PathCacheType &Model::pathCache() return *d->pathCache; } +ProjectStorageTriggerUpdateInterface &Model::projectStorageTriggerUpdate() const +{ + return *d->projectStorageTriggerUpdate; +} + void Model::emitInstancePropertyChange(AbstractView *view, const QList> &propertyList) { diff --git a/src/plugins/qmldesigner/libs/designercore/model/model_p.h b/src/plugins/qmldesigner/libs/designercore/model/model_p.h index d9591ccbf9e..b2a8a31d692 100644 --- a/src/plugins/qmldesigner/libs/designercore/model/model_p.h +++ b/src/plugins/qmldesigner/libs/designercore/model/model_p.h @@ -347,6 +347,7 @@ private: public: NotNullPointer projectStorage = nullptr; NotNullPointer pathCache = nullptr; + NotNullPointer projectStorageTriggerUpdate = nullptr; ModelTracing::AsynchronousToken traceToken = ModelTracing::category().beginAsynchronous("Model"); private: diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragepathwatcher.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragepathwatcher.h index 8fe2ba60e0a..6b86a4b5cf0 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragepathwatcher.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragepathwatcher.h @@ -8,6 +8,7 @@ #include "projectstoragepathwatcherinterface.h" #include "projectstoragepathwatchernotifierinterface.h" #include "projectstoragepathwatchertypes.h" +#include "projectstoragetriggerupdateinterface.h" #include @@ -34,7 +35,8 @@ void set_greedy_intersection_call( } template -class ProjectStoragePathWatcher : public ProjectStoragePathWatcherInterface +class ProjectStoragePathWatcher : public ProjectStoragePathWatcherInterface, + public ProjectStorageTriggerUpdateInterface { public: ProjectStoragePathWatcher(SourcePathCache &pathCache, @@ -83,6 +85,13 @@ public: removeUnusedEntries(entires, notContainsId); } + void checkForChangeInDirectory(SourceContextIds sourceContextIds) override + { + std::ranges::sort(sourceContextIds); + + addChangedPathForFilePath(sourceContextIds); + } + void removeIds(const ProjectPartIds &ids) override { auto removedEntries = removeIdsFromWatchedEntries(ids); @@ -279,10 +288,7 @@ public: return notWatchedPaths(uniquePaths(entries)); } - const WatcherEntries &watchedEntries() const - { - return m_watchedEntries; - } + const WatcherEntries &watchedEntries() const { return m_watchedEntries; } WatcherEntries removeIdsFromWatchedEntries(const ProjectPartIds &ids) { diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragetriggerupdateinterface.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragetriggerupdateinterface.h new file mode 100644 index 00000000000..f03e0ee4b2f --- /dev/null +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragetriggerupdateinterface.h @@ -0,0 +1,23 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "projectstorageids.h" + +namespace QmlDesigner { + +class ProjectStorageTriggerUpdateInterface +{ +public: + ProjectStorageTriggerUpdateInterface() = default; + ProjectStorageTriggerUpdateInterface(const ProjectStorageTriggerUpdateInterface &) = delete; + ProjectStorageTriggerUpdateInterface &operator=(const ProjectStorageTriggerUpdateInterface &) = delete; + + virtual void checkForChangeInDirectory(SourceContextIds sourceContextIds) = 0; + +protected: + ~ProjectStorageTriggerUpdateInterface() = default; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/project/qmldesignerprojectmanager.cpp b/src/plugins/qmldesigner/project/qmldesignerprojectmanager.cpp index 40d38afb62c..911a2508b65 100644 --- a/src/plugins/qmldesigner/project/qmldesignerprojectmanager.cpp +++ b/src/plugins/qmldesigner/project/qmldesignerprojectmanager.cpp @@ -366,14 +366,21 @@ namespace { return nullptr; } +[[maybe_unused]] ProjectStorageTriggerUpdateInterface *dummyTriggerUpdate() +{ + return nullptr; +} + } // namespace ProjectStorageDependencies QmlDesignerProjectManager::projectStorageDependencies() { if constexpr (useProjectStorage()) { - return {m_projectData->projectStorageData->storage, m_data->pathCache}; + return {m_projectData->projectStorageData->storage, + m_data->pathCache, + m_projectData->projectStorageData->pathWatcher}; } else { - return {*dummyProjectStorage(), *dummyPathCache()}; + return {*dummyProjectStorage(), *dummyPathCache(), *dummyTriggerUpdate()}; } } diff --git a/tests/unit/tests/mocks/CMakeLists.txt b/tests/unit/tests/mocks/CMakeLists.txt index 432a2ca2c54..a86e7a8f702 100644 --- a/tests/unit/tests/mocks/CMakeLists.txt +++ b/tests/unit/tests/mocks/CMakeLists.txt @@ -28,6 +28,7 @@ add_qtc_library(TestMocks OBJECT projectstorageobservermock.h projectstoragepathwatchermock.h projectstoragepathwatchernotifiermock.h + projectstoragetriggerupdatemock.h qmldocumentparsermock.h qmltypesparsermock.h sourcepathcachemock.h sourcepathcachemock.cpp diff --git a/tests/unit/tests/mocks/projectstoragetriggerupdatemock.h b/tests/unit/tests/mocks/projectstoragetriggerupdatemock.h new file mode 100644 index 00000000000..85f4afc2f50 --- /dev/null +++ b/tests/unit/tests/mocks/projectstoragetriggerupdatemock.h @@ -0,0 +1,19 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "../utils/googletest.h" + +#include + +class ProjectStorageTriggerUpdateMock : public QmlDesigner::ProjectStorageTriggerUpdateInterface +{ +public: + virtual ~ProjectStorageTriggerUpdateMock() = default; + + MOCK_METHOD(void, + checkForChangeInDirectory, + (QmlDesigner::SourceContextIds sourceContextIds), + (override)); +}; diff --git a/tests/unit/tests/testdesignercore/CMakeLists.txt b/tests/unit/tests/testdesignercore/CMakeLists.txt index 240c6b36390..dd9dad3bd30 100644 --- a/tests/unit/tests/testdesignercore/CMakeLists.txt +++ b/tests/unit/tests/testdesignercore/CMakeLists.txt @@ -342,6 +342,7 @@ extend_qtc_library(TestDesignerCore projectstorageinfotypes.h projectstorageobserver.h projectstoragepathwatcher.h + projectstoragetriggerupdateinterface.h projectstoragepathwatcherinterface.h projectstoragepathwatchernotifierinterface.h projectstoragepathwatcher.h diff --git a/tests/unit/tests/unittests/componentcore/propertycomponentgenerator-test.cpp b/tests/unit/tests/unittests/componentcore/propertycomponentgenerator-test.cpp index 4b398420082..2a5f5cd87e3 100644 --- a/tests/unit/tests/unittests/componentcore/propertycomponentgenerator-test.cpp +++ b/tests/unit/tests/unittests/componentcore/propertycomponentgenerator-test.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -173,10 +174,11 @@ protected: protected: inline static QSharedPointer simpleReaderNode; NiceMock viewMock; + NiceMock projectStorageTriggerUpdateMock; NiceMock pathCacheMock{"/path/foo.qml"}; NiceMock projectStorageMock{pathCacheMock.sourceId, "/path"}; NiceMock resourceManagementMock; - QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, + QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, "Item", -1, -1, diff --git a/tests/unit/tests/unittests/designercoreutils/modelutils-test.cpp b/tests/unit/tests/unittests/designercoreutils/modelutils-test.cpp index 24393accd04..c190585ab00 100644 --- a/tests/unit/tests/unittests/designercoreutils/modelutils-test.cpp +++ b/tests/unit/tests/unittests/designercoreutils/modelutils-test.cpp @@ -5,7 +5,9 @@ #include #include +#include #include + #include #include #include @@ -18,11 +20,12 @@ using QmlDesigner::Storage::ModuleKind; class ModelUtilsWithModel : public ::testing::Test { protected: + NiceMock projectStorageTriggerUpdateMock; NiceMock pathCacheMock{"/path/model.qml"}; QmlDesigner::SourceId sourceId = pathCacheMock.createSourceId("/path/foo.qml"); NiceMock projectStorageMock{pathCacheMock.sourceId, "/path"}; QmlDesigner::ModuleId moduleId = projectStorageMock.moduleId("QtQuick", ModuleKind::QmlLibrary); - QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, + QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, "Item", {QmlDesigner::Import::createLibraryImport("QML"), QmlDesigner::Import::createLibraryImport("QtQuick"), diff --git a/tests/unit/tests/unittests/designsystem/dsthemeqml-test.cpp b/tests/unit/tests/unittests/designsystem/dsthemeqml-test.cpp index 2fa8de50705..91205aeba18 100644 --- a/tests/unit/tests/unittests/designsystem/dsthemeqml-test.cpp +++ b/tests/unit/tests/unittests/designsystem/dsthemeqml-test.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -103,9 +104,10 @@ protected: const QmlDesigner::GroupType groupType = GetParam(); const QmlDesigner::PropertyName groupName = GroupId(groupType); QmlDesigner::DSThemeGroup group; + NiceMock projectStorageTriggerUpdateMock; NiceMock pathCacheMock{"/path/model.qm"}; NiceMock projectStorageMock{pathCacheMock.sourceId, "/path"}; - QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, + QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, "QtObject", {Import::createLibraryImport("QM"), Import::createLibraryImport("QtQuick")}, diff --git a/tests/unit/tests/unittests/listmodeleditor/listmodeleditor-test.cpp b/tests/unit/tests/unittests/listmodeleditor/listmodeleditor-test.cpp index 2e8de03cbd2..12013dfaeb9 100644 --- a/tests/unit/tests/unittests/listmodeleditor/listmodeleditor-test.cpp +++ b/tests/unit/tests/unittests/listmodeleditor/listmodeleditor-test.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -183,12 +184,14 @@ public: } protected: + NiceMock projectStorageTriggerUpdateMock; NiceMock pathCacheMock{"/path/foo.qml"}; NiceMock projectStorageMock{pathCacheMock.sourceId, "/path"}; NiceMock> goIntoComponentMock; QmlDesigner::ModelPointer designerModel{ QmlDesigner::Model::create(QmlDesigner::ProjectStorageDependencies{projectStorageMock, - pathCacheMock}, + pathCacheMock, + projectStorageTriggerUpdateMock}, "Item", {QmlDesigner::Import::createLibraryImport("QtQml.Models"), QmlDesigner::Import::createLibraryImport("QtQuick")}, @@ -204,7 +207,7 @@ protected: ModelNode element2; ModelNode element3; QmlDesigner::ModelPointer componentModel{ - QmlDesigner::Model::create({projectStorageMock, pathCacheMock}, + QmlDesigner::Model::create({projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, "ListModel", {QmlDesigner::Import::createLibraryImport("QtQml.Models"), QmlDesigner::Import::createLibraryImport("QtQuick")}, diff --git a/tests/unit/tests/unittests/metainfo/nodemetainfo-test.cpp b/tests/unit/tests/unittests/metainfo/nodemetainfo-test.cpp index 41ad91ee6e1..c315720c19e 100644 --- a/tests/unit/tests/unittests/metainfo/nodemetainfo-test.cpp +++ b/tests/unit/tests/unittests/metainfo/nodemetainfo-test.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -105,9 +106,10 @@ protected: } protected: + NiceMock projectStorageTriggerUpdateMock; NiceMock pathCache{"/path/foo.qml"}; NiceMock projectStorageMock{pathCache.sourceId, "/path"}; - QmlDesigner::Model model{{projectStorageMock, pathCache}, + QmlDesigner::Model model{{projectStorageMock, pathCache, projectStorageTriggerUpdateMock}, "Item", {QmlDesigner::Import::createLibraryImport("QML"), QmlDesigner::Import::createLibraryImport("QtQuick"), diff --git a/tests/unit/tests/unittests/metainfo/propertymetainfo-test.cpp b/tests/unit/tests/unittests/metainfo/propertymetainfo-test.cpp index b3e466de06c..820a580b1a7 100644 --- a/tests/unit/tests/unittests/metainfo/propertymetainfo-test.cpp +++ b/tests/unit/tests/unittests/metainfo/propertymetainfo-test.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -41,9 +42,10 @@ protected: } protected: + NiceMock projectStorageTriggerUpdateMock; NiceMock pathCache{"/path/foo.qml"}; NiceMock projectStorageMock{pathCache.sourceId, "/path"}; - QmlDesigner::Model model{{projectStorageMock, pathCache}, + QmlDesigner::Model model{{projectStorageMock, pathCache, projectStorageTriggerUpdateMock}, "Item", {QmlDesigner::Import::createLibraryImport("QML"), QmlDesigner::Import::createLibraryImport("QtQuick"), diff --git a/tests/unit/tests/unittests/model/auxiliarypropertystorageview-test.cpp b/tests/unit/tests/unittests/model/auxiliarypropertystorageview-test.cpp index 2021ca4f5c7..d6719f5be92 100644 --- a/tests/unit/tests/unittests/model/auxiliarypropertystorageview-test.cpp +++ b/tests/unit/tests/unittests/model/auxiliarypropertystorageview-test.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -40,17 +41,18 @@ protected: inline static std::unique_ptr staticData; Sqlite::Database &database = staticData->database; + NiceMock projectStorageTriggerUpdateMock; NiceMock pathCacheMock{"/path/foo.qml"}; NiceMock projectStorageMock{pathCacheMock.sourceId, "/path"}; NiceMock resourceManagementMock; QmlDesigner::Imports imports = {QmlDesigner::Import::createLibraryImport("QtQuick")}; - QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, + QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, "Item", imports, pathCacheMock.path.toQString(), std::make_unique( resourceManagementMock)}; - QmlDesigner::Model model2{{projectStorageMock, pathCacheMock}, + QmlDesigner::Model model2{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, "Item", imports, pathCacheMock.path.toQString(), diff --git a/tests/unit/tests/unittests/model/model-test.cpp b/tests/unit/tests/unittests/model/model-test.cpp index 31ce1a30d8e..dff3a7904bd 100644 --- a/tests/unit/tests/unittests/model/model-test.cpp +++ b/tests/unit/tests/unittests/model/model-test.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -119,13 +120,14 @@ protected: } protected: + NiceMock projectStorageTriggerUpdateMock; NiceMock pathCacheMock{"/path/foo.qml"}; NiceMock projectStorageMock{pathCacheMock.sourceId, "/path"}; NiceMock resourceManagementMock; QmlDesigner::Imports imports = {QmlDesigner::Import::createLibraryImport("QtQuick")}; NiceMock viewMock; QUrl fileUrl = QUrl::fromLocalFile(pathCacheMock.path.toQString()); - QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, + QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, "Item", imports, QUrl::fromLocalFile(pathCacheMock.path.toQString()), @@ -147,60 +149,60 @@ class Model_Creation : public Model TEST_F(Model_Creation, root_node_has_item_type_name) { - auto model = QmlDesigner::Model::create({projectStorageMock, pathCacheMock}, - "Item", - imports, - fileUrl, - std::make_unique( - resourceManagementMock)); + auto model = QmlDesigner::Model::create( + {projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, + "Item", + imports, + fileUrl, + std::make_unique(resourceManagementMock)); ASSERT_THAT(model->rootModelNode().type(), Eq("Item")); } TEST_F(Model_Creation, root_node_has_item_meta_info) { - auto model = QmlDesigner::Model::create({projectStorageMock, pathCacheMock}, - "Item", - imports, - fileUrl, - std::make_unique( - resourceManagementMock)); + auto model = QmlDesigner::Model::create( + {projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, + "Item", + imports, + fileUrl, + std::make_unique(resourceManagementMock)); ASSERT_THAT(model->rootModelNode().metaInfo(), model->qtQuickItemMetaInfo()); } TEST_F(Model_Creation, file_url) { - auto model = QmlDesigner::Model::create({projectStorageMock, pathCacheMock}, - "Item", - imports, - fileUrl, - std::make_unique( - resourceManagementMock)); + auto model = QmlDesigner::Model::create( + {projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, + "Item", + imports, + fileUrl, + std::make_unique(resourceManagementMock)); ASSERT_THAT(model->fileUrl().toLocalFile(), Eq(pathCacheMock.path.toQString())); } TEST_F(Model_Creation, file_url_source_id) { - auto model = QmlDesigner::Model::create({projectStorageMock, pathCacheMock}, - "Item", - imports, - fileUrl, - std::make_unique( - resourceManagementMock)); + auto model = QmlDesigner::Model::create( + {projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, + "Item", + imports, + fileUrl, + std::make_unique(resourceManagementMock)); ASSERT_THAT(model->fileUrlSourceId(), pathCacheMock.sourceId); } TEST_F(Model_Creation, imports) { - auto model = QmlDesigner::Model::create({projectStorageMock, pathCacheMock}, - "Item", - imports, - fileUrl, - std::make_unique( - resourceManagementMock)); + auto model = QmlDesigner::Model::create( + {projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, + "Item", + imports, + fileUrl, + std::make_unique(resourceManagementMock)); ASSERT_THAT(model->imports(), UnorderedElementsAreArray(imports)); } @@ -645,7 +647,8 @@ TEST_F(Model_ResourceManagment, TEST_F(Model_ResourceManagment, by_default_remove_model_node_removes_node) { - QmlDesigner::Model newModel{{projectStorageMock, pathCacheMock}, "QtQuick.Item"}; + QmlDesigner::Model newModel{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, + "QtQuick.Item"}; NiceMock viewMock; newModel.attachView(&viewMock); auto node = createNodeWithParent(viewMock.rootModelNode()); @@ -657,7 +660,8 @@ TEST_F(Model_ResourceManagment, by_default_remove_model_node_removes_node) TEST_F(Model_ResourceManagment, by_default_remove_properties_removes_property) { - QmlDesigner::Model newModel{{projectStorageMock, pathCacheMock}, "QtQuick.Item"}; + QmlDesigner::Model newModel{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, + "QtQuick.Item"}; NiceMock viewMock; newModel.attachView(&viewMock); rootNode = viewMock.rootModelNode(); @@ -671,7 +675,9 @@ TEST_F(Model_ResourceManagment, by_default_remove_properties_removes_property) TEST_F(Model_ResourceManagment, by_default_remove_model_node_in_factory_method_calls_removes_node) { model.detachView(&viewMock); - auto newModel = QmlDesigner::Model::create({projectStorageMock, pathCacheMock}, + auto newModel = QmlDesigner::Model::create({projectStorageMock, + pathCacheMock, + projectStorageTriggerUpdateMock}, "Item", imports, pathCacheMock.path.toQString()); @@ -686,7 +692,9 @@ TEST_F(Model_ResourceManagment, by_default_remove_model_node_in_factory_method_c TEST_F(Model_ResourceManagment, by_default_remove_properties_in_factory_method_calls_remove_property) { model.detachView(&viewMock); - auto newModel = QmlDesigner::Model::create({projectStorageMock, pathCacheMock}, + auto newModel = QmlDesigner::Model::create({projectStorageMock, + pathCacheMock, + projectStorageTriggerUpdateMock}, "Item", imports, pathCacheMock.path.toQString()); @@ -780,7 +788,8 @@ TEST_F(Model_ResourceManagment, remove_model_nodes_bypasses_model_resource_manag TEST_F(Model_ResourceManagment, by_default_remove_model_nodes_in_factory_method_calls_removes_node) { - QmlDesigner::Model newModel{{projectStorageMock, pathCacheMock}, "QtQuick.Item"}; + QmlDesigner::Model newModel{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, + "QtQuick.Item"}; NiceMock viewMock; newModel.attachView(&viewMock); rootNode = viewMock.rootModelNode(); @@ -874,7 +883,8 @@ TEST_F(Model_ResourceManagment, remove_properties_bypasses_model_resource_manage TEST_F(Model_ResourceManagment, by_default_remove_properties_in_factory_method_calls_removes_properties) { model.detachView(&viewMock); - QmlDesigner::Model newModel{{projectStorageMock, pathCacheMock}, "QtQuick.Item"}; + QmlDesigner::Model newModel{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, + "QtQuick.Item"}; newModel.attachView(&viewMock); rootNode = viewMock.rootModelNode(); auto property = createProperty(rootNode, "yi"); @@ -1131,14 +1141,24 @@ TEST_F(Model_MetaInfo, add_project_storage_observer_to_project_storage) { EXPECT_CALL(projectStorageMock, addObserver(_)); - QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, "Item", -1, -1, nullptr, {}}; + QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, + "Item", + -1, + -1, + nullptr, + {}}; } TEST_F(Model_MetaInfo, remove_project_storage_observer_from_project_storage) { EXPECT_CALL(projectStorageMock, removeObserver(_)).Times(2); // the fixture model is calling it too - QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, "Item", -1, -1, nullptr, {}}; + QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, + "Item", + -1, + -1, + nullptr, + {}}; } TEST_F(Model_MetaInfo, refresh_meta_infos_callback_is_calling_abstract_view) @@ -1148,7 +1168,12 @@ TEST_F(Model_MetaInfo, refresh_meta_infos_callback_is_calling_abstract_view) ProjectStorageObserverMock observerMock; QmlDesigner::ProjectStorageObserver *observer = nullptr; ON_CALL(projectStorageMock, addObserver(_)).WillByDefault([&](auto *o) { observer = o; }); - QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, "Item", -1, -1, nullptr, {}}; + QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, + "Item", + -1, + -1, + nullptr, + {}}; model.attachView(&viewMock); EXPECT_CALL(viewMock, refreshMetaInfos(typeIds)); @@ -1163,7 +1188,12 @@ TEST_F(Model_MetaInfo, added_exported_type_names_are_changed_callback_is_calling ProjectStorageObserverMock observerMock; QmlDesigner::ProjectStorageObserver *observer = nullptr; ON_CALL(projectStorageMock, addObserver(_)).WillByDefault([&](auto *o) { observer = o; }); - QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, "Item", -1, -1, nullptr, {}}; + QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, + "Item", + -1, + -1, + nullptr, + {}}; model.attachView(&viewMock); EXPECT_CALL(viewMock, exportedTypeNamesChanged(added, IsEmpty())); @@ -1178,7 +1208,12 @@ TEST_F(Model_MetaInfo, removed_exported_type_names_are_changed_callback_is_calli ProjectStorageObserverMock observerMock; QmlDesigner::ProjectStorageObserver *observer = nullptr; ON_CALL(projectStorageMock, addObserver(_)).WillByDefault([&](auto *o) { observer = o; }); - QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, "Item", -1, -1, nullptr, {}}; + QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, + "Item", + -1, + -1, + nullptr, + {}}; model.attachView(&viewMock); EXPECT_CALL(viewMock, exportedTypeNamesChanged(IsEmpty(), removed)); @@ -1355,7 +1390,7 @@ TEST_F(Model_ViewManagement, dont_call_modelAttached_if_node_instance_view_is_al TEST_F(Model_ViewManagement, detach_node_instance_view_from_other_model_before_attach_to_new_model) { InSequence s; - QmlDesigner::Model otherModel{{projectStorageMock, pathCacheMock}, + QmlDesigner::Model otherModel{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, "Item", imports, fileUrl, @@ -1401,7 +1436,7 @@ TEST_F(Model_ViewManagement, attach_view_is_not_calling_modelAttached_if_it_is_a TEST_F(Model_ViewManagement, view_is_detached_before_it_is_attached_ot_new_model) { InSequence s; - QmlDesigner::Model otherModel{{projectStorageMock, pathCacheMock}, + QmlDesigner::Model otherModel{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, "Item", imports, fileUrl, diff --git a/tests/unit/tests/unittests/model/modelnode-test.cpp b/tests/unit/tests/unittests/model/modelnode-test.cpp index 61d81f6178f..9214f24d4da 100644 --- a/tests/unit/tests/unittests/model/modelnode-test.cpp +++ b/tests/unit/tests/unittests/model/modelnode-test.cpp @@ -4,6 +4,7 @@ #include "../utils/googletest.h" #include "../mocks/projectstoragemock.h" +#include "../mocks/projectstoragetriggerupdatemock.h" #include "../mocks/sourcepathcachemock.h" #include @@ -15,9 +16,10 @@ namespace { class ModelNode : public testing::Test { protected: + NiceMock projectStorageTriggerUpdateMock; NiceMock pathCache{"/path/foo.qml"}; NiceMock projectStorageMock{pathCache.sourceId, "/path"}; - QmlDesigner::Model model{{projectStorageMock, pathCache}, "Item"}; + QmlDesigner::Model model{{projectStorageMock, pathCache, projectStorageTriggerUpdateMock}, "Item"}; QmlDesigner::ModelNode rootNode = model.rootModelNode(); }; diff --git a/tests/unit/tests/unittests/model/modelresourcemanagement-test.cpp b/tests/unit/tests/unittests/model/modelresourcemanagement-test.cpp index b020c7cfd0d..dea3501843e 100644 --- a/tests/unit/tests/unittests/model/modelresourcemanagement-test.cpp +++ b/tests/unit/tests/unittests/model/modelresourcemanagement-test.cpp @@ -6,6 +6,7 @@ #include "../mocks/abstractviewmock.h" #include "../mocks/modelresourcemanagementmock.h" #include "../mocks/projectstoragemock.h" +#include "../mocks/projectstoragetriggerupdatemock.h" #include "../mocks/sourcepathcachemock.h" #include @@ -71,10 +72,11 @@ protected: protected: NiceMock viewMock; + NiceMock projectStorageTriggerUpdateMock; NiceMock pathCacheMock{"/path/foo.qml"}; NiceMock projectStorageMock{pathCacheMock.sourceId, "/path"}; QmlDesigner::ModelResourceManagement management; - QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, + QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, "Item", {QmlDesigner::Import::createLibraryImport("QtQtuick")}, QUrl::fromLocalFile(pathCacheMock.path.toQString())}; diff --git a/tests/unit/tests/unittests/model/nodelistproperty-test.cpp b/tests/unit/tests/unittests/model/nodelistproperty-test.cpp index 023126f0f70..72df3f52365 100644 --- a/tests/unit/tests/unittests/model/nodelistproperty-test.cpp +++ b/tests/unit/tests/unittests/model/nodelistproperty-test.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -73,11 +74,13 @@ protected: } protected: + NiceMock projectStorageTriggerUpdateMock; NiceMock pathCache{"/path/foo.qml"}; NiceMock projectStorageMock{pathCache.sourceId, "/path"}; QmlDesigner::ModelPointer model{ QmlDesigner::Model::create(QmlDesigner::ProjectStorageDependencies{projectStorageMock, - pathCache}, + pathCache, + projectStorageTriggerUpdateMock}, "Item", {QmlDesigner::Import::createLibraryImport("QtQuick")}, QUrl::fromLocalFile(pathCache.path.toQString()))}; diff --git a/tests/unit/tests/unittests/model/rewriterview-test.cpp b/tests/unit/tests/unittests/model/rewriterview-test.cpp index 8c62accd1d8..f2dbd028123 100644 --- a/tests/unit/tests/unittests/model/rewriterview-test.cpp +++ b/tests/unit/tests/unittests/model/rewriterview-test.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -26,13 +27,14 @@ protected: ~RewriterView() { model.setRewriterView(nullptr); } protected: + NiceMock projectStorageTriggerUpdateMock; NiceMock externalDependenciesMock; NiceMock textModifierMock; NiceMock pathCacheMock{"/path/foo.qml"}; NiceMock projectStorageMock{pathCacheMock.sourceId, "/path"}; NiceMock resourceManagementMock; QmlDesigner::Imports imports = {QmlDesigner::Import::createLibraryImport("QtQuick")}; - QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, + QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, "Item", imports, QUrl::fromLocalFile(pathCacheMock.path.toQString()), diff --git a/tests/unit/tests/unittests/projectstorage/projectstoragepathwatcher-test.cpp b/tests/unit/tests/unittests/projectstorage/projectstoragepathwatcher-test.cpp index ac591b8c909..25c3895f818 100644 --- a/tests/unit/tests/unittests/projectstorage/projectstoragepathwatcher-test.cpp +++ b/tests/unit/tests/unittests/projectstorage/projectstoragepathwatcher-test.cpp @@ -415,6 +415,51 @@ TEST_F(ProjectStoragePathWatcher, no_duplicate_path_changes) mockQFileSytemWatcher.directoryChanged(sourceContextPath); } +TEST_F(ProjectStoragePathWatcher, trigger_manual_two_notify_file_changes) +{ + watcher.updateIdPaths( + {{projectChunkId1, {sourceIds[0], sourceIds[1], sourceIds[2]}}, + {projectChunkId2, {sourceIds[0], sourceIds[1], sourceIds[2], sourceIds[3], sourceIds[4]}}, + {projectChunkId3, {sourceIds[4]}}}); + ON_CALL(mockFileSystem, fileStatus(Eq(sourceIds[0]))) + .WillByDefault(Return(FileStatus{sourceIds[0], 1, 2})); + ON_CALL(mockFileSystem, fileStatus(Eq(sourceIds[1]))) + .WillByDefault(Return(FileStatus{sourceIds[1], 1, 2})); + ON_CALL(mockFileSystem, fileStatus(Eq(sourceIds[3]))) + .WillByDefault(Return(FileStatus{sourceIds[3], 1, 2})); + + EXPECT_CALL(notifier, + pathsWithIdsChanged( + ElementsAre(IdPaths{projectChunkId1, {sourceIds[0], sourceIds[1]}}, + IdPaths{projectChunkId2, {sourceIds[0], sourceIds[1], sourceIds[3]}}))); + + watcher.checkForChangeInDirectory({sourceIds[0].contextId(), sourceIds[1].contextId()}); +} + +TEST_F(ProjectStoragePathWatcher, trigger_manual_notify_for_path_changes) +{ + watcher.updateIdPaths({{projectChunkId1, {sourceIds[0], sourceIds[1], sourceIds[2]}}, + {projectChunkId2, {sourceIds[0], sourceIds[1], sourceIds[3]}}}); + ON_CALL(mockFileSystem, fileStatus(Eq(sourceIds[0]))) + .WillByDefault(Return(FileStatus{sourceIds[0], 1, 2})); + + ON_CALL(mockFileSystem, fileStatus(Eq(sourceIds[3]))) + .WillByDefault(Return(FileStatus{sourceIds[3], 1, 2})); + + EXPECT_CALL(notifier, pathsChanged(ElementsAre(sourceIds[0]))); + + watcher.checkForChangeInDirectory({sourceIds[0].contextId()}); +} + +TEST_F(ProjectStoragePathWatcher, trigger_manual_no_notify_for_unwatched_path_changes) +{ + watcher.updateIdPaths({{projectChunkId1, {sourceIds[3]}}, {projectChunkId2, {sourceIds[3]}}}); + + EXPECT_CALL(notifier, pathsChanged(IsEmpty())); + + watcher.checkForChangeInDirectory({sourceIds[0].contextId()}); +} + TEST_F(ProjectStoragePathWatcher, update_context_id_paths_adds_entry_in_new_directory) { watcher.updateIdPaths({