QmlDesigner: Add callbacks for model resource management

As a node or property is removed there are now callbacks to generate
node, properties and expressions which should removed or adapt too.

Task-number: QDS-9766
Change-Id: I6d842006a6282af00ff644ffaa0f3102e14f13fa
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
Marco Bubke
2023-05-04 19:01:58 +02:00
parent 90ea280b8e
commit 5eba056b73
25 changed files with 835 additions and 99 deletions

View File

@@ -341,6 +341,7 @@ extend_qtc_library(QmlDesignerCore
modelnodepositionrecalculator.cpp
modelnodepositionrecalculator.h
modelnodepositionstorage.cpp
modelresourcemanagementinterface.h
modeltotextmerger.cpp
modeltotextmerger.h
modelutils.cpp

View File

@@ -6,6 +6,7 @@
#include <qmldesignercorelib_global.h>
#include <documentmessage.h>
#include <model/modelresourcemanagementinterface.h>
#include <projectstorage/projectstoragefwd.h>
#include <QMimeData>
@@ -40,7 +41,7 @@ class RewriterView;
class NodeInstanceView;
class TextModifier;
using PropertyListType = QList<QPair<PropertyName, QVariant> >;
using PropertyListType = QList<QPair<PropertyName, QVariant>>;
class QMLDESIGNERCORE_EXPORT Model : public QObject
{
@@ -61,25 +62,34 @@ public:
const TypeName &type,
int major = 1,
int minor = 1,
Model *metaInfoProxyModel = nullptr);
Model(const TypeName &typeName, int major = 1, int minor = 1, Model *metaInfoProxyModel = nullptr);
Model *metaInfoProxyModel = nullptr,
std::unique_ptr<ModelResourceManagementInterface> resourceManagement = {});
Model(const TypeName &typeName,
int major = 1,
int minor = 1,
Model *metaInfoProxyModel = nullptr,
std::unique_ptr<ModelResourceManagementInterface> resourceManagement = {});
~Model();
static ModelPointer create(const TypeName &typeName,
int major = 1,
int minor = 1,
Model *metaInfoProxyModel = nullptr)
Model *metaInfoProxyModel = nullptr,
std::unique_ptr<ModelResourceManagementInterface> resourceManagement = {})
{
return ModelPointer(new Model(typeName, major, minor, metaInfoProxyModel));
return ModelPointer(
new Model(typeName, major, minor, metaInfoProxyModel, std::move(resourceManagement)));
}
static ModelPointer create(ProjectStorageType &projectStorage,
const TypeName &typeName,
int major = 1,
int minor = 1)
int minor = 1,
std::unique_ptr<ModelResourceManagementInterface> resourceManagement = {})
{
return ModelPointer(new Model(projectStorage, typeName, major, minor));
return ModelPointer(
new Model(projectStorage, typeName, major, minor, nullptr, std::move(resourceManagement)));
}
QUrl fileUrl() const;
@@ -120,6 +130,8 @@ public:
void attachView(AbstractView *view);
void detachView(AbstractView *view, ViewNotification emitDetachNotify = NotifyView);
QList<ModelNode> allModelNodes() const;
// Editing sub-components:
// Imports:
@@ -177,4 +189,4 @@ private:
std::unique_ptr<Internal::ModelPrivate> d;
};
}
} // namespace QmlDesigner

View File

@@ -270,6 +270,8 @@ QMLDESIGNERCORE_EXPORT bool operator !=(const ModelNode &firstNode, const ModelN
QMLDESIGNERCORE_EXPORT bool operator <(const ModelNode &firstNode, const ModelNode &secondNode);
QMLDESIGNERCORE_EXPORT QDebug operator<<(QDebug debug, const ModelNode &modelNode);
QMLDESIGNERCORE_EXPORT QTextStream& operator<<(QTextStream &stream, const ModelNode &modelNode);
using ModelNodes = QList<ModelNode>;
}
Q_DECLARE_METATYPE(QmlDesigner::ModelNode)

View File

@@ -1619,16 +1619,20 @@ TypeName NodeMetaInfo::simplifiedTypeName() const
int NodeMetaInfo::majorVersion() const
{
if (isValid())
return m_privateData->majorVersion();
if constexpr (!useProjectStorage()) {
if (isValid())
return m_privateData->majorVersion();
}
return -1;
}
int NodeMetaInfo::minorVersion() const
{
if (isValid())
return m_privateData->minorVersion();
if constexpr (!useProjectStorage()) {
if (isValid())
return m_privateData->minorVersion();
}
return -1;
}

View File

@@ -39,7 +39,6 @@ AbstractProperty::AbstractProperty(const Internal::InternalPropertyPointer &prop
m_model(model),
m_view(view)
{
Q_ASSERT(!m_model || m_view);
}
AbstractProperty::AbstractProperty(const AbstractProperty &property, AbstractView *view)

View File

@@ -64,8 +64,12 @@ RewriterTransaction AbstractView::beginRewriterTransaction(const QByteArray &ide
ModelNode AbstractView::createModelNode(const TypeName &typeName)
{
const NodeMetaInfo metaInfo = model()->metaInfo(typeName);
return createModelNode(typeName, metaInfo.majorVersion(), metaInfo.minorVersion());
if constexpr (useProjectStorage()) {
return createModelNode(typeName, -1, -1);
} else {
const NodeMetaInfo metaInfo = model()->metaInfo(typeName);
return createModelNode(typeName, metaInfo.majorVersion(), metaInfo.minorVersion());
}
}
ModelNode AbstractView::createModelNode(const TypeName &typeName,

View File

@@ -56,7 +56,7 @@ void BindingProperty::setExpression(const QString &expression)
}
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isBindingProperty())
privateModel()->removeProperty(internalNode()->property(name()));
privateModel()->removePropertyAndRelatedResources(internalNode()->property(name()));
privateModel()->setBindingProperty(internalNode(), name(), expression);
}
@@ -341,7 +341,7 @@ void BindingProperty::setDynamicTypeNameAndExpression(const TypeName &typeName,
}
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isBindingProperty())
privateModel()->removeProperty(internalNode()->property(name()));
privateModel()->removePropertyAndRelatedResources(internalNode()->property(name()));
privateModel()->setDynamicBindingProperty(internalNode(), name(), typeName, expression);
}

View File

@@ -62,9 +62,11 @@ ModelPrivate::ModelPrivate(Model *model,
const TypeName &typeName,
int major,
int minor,
Model *metaInfoProxyModel)
Model *metaInfoProxyModel,
std::unique_ptr<ModelResourceManagementInterface> resourceManagement)
: projectStorage{&projectStorage}
, m_model{model}
, m_resourceManagement{std::move(resourceManagement)}
{
m_metaInfoProxyModel = metaInfoProxyModel;
@@ -75,9 +77,14 @@ ModelPrivate::ModelPrivate(Model *model,
m_currentTimelineNode = m_rootInternalNode;
}
ModelPrivate::ModelPrivate(
Model *model, const TypeName &typeName, int major, int minor, Model *metaInfoProxyModel)
ModelPrivate::ModelPrivate(Model *model,
const TypeName &typeName,
int major,
int minor,
Model *metaInfoProxyModel,
std::unique_ptr<ModelResourceManagementInterface> resourceManagement)
: m_model(model)
, m_resourceManagement{std::move(resourceManagement)}
{
m_metaInfoProxyModel = metaInfoProxyModel;
@@ -279,7 +286,9 @@ InternalNodePointer ModelPrivate::createNode(const TypeName &typeName,
notifyNodeCreated(newNode);
if (!newNode->propertyNameList().isEmpty())
notifyVariantPropertiesChanged(newNode, newNode->propertyNameList(), AbstractView::PropertiesAdded);
notifyVariantPropertiesChanged(newNode,
newNode->propertyNameList(),
AbstractView::PropertiesAdded);
return newNode;
}
@@ -303,16 +312,40 @@ EnabledViewRange ModelPrivate::enabledViews() const
return EnabledViewRange{m_viewList};
}
void ModelPrivate::handleResourceSet(const ModelResourceSet &resourceSet)
{
for (const ModelNode &node : resourceSet.removeModelNodes) {
if (node)
removeNode(node.m_internalNode);
}
for (const AbstractProperty &property : resourceSet.removeProperties) {
if (property)
removeProperty(property.m_internalNode->property(property.m_propertyName));
}
for (const auto &[property, expression] : resourceSet.setExpressions) {
if (property)
setBindingProperty(property.m_internalNode, property.m_propertyName, expression);
}
}
void ModelPrivate::removeAllSubNodes(const InternalNodePointer &node)
{
for (const InternalNodePointer &subNode : node->allSubNodes())
removeNodeFromModel(subNode);
}
void ModelPrivate::removeNodeAndRelatedResources(const InternalNodePointer &node)
{
if (m_resourceManagement)
handleResourceSet(m_resourceManagement->removeNode(ModelNode{node, m_model, nullptr}));
else
removeNode(node);
}
void ModelPrivate::removeNode(const InternalNodePointer &node)
{
Q_ASSERT(node);
AbstractView::PropertyChangeFlags propertyChangeFlags = AbstractView::NoAdditionalChanges;
notifyNodeAboutToBeRemoved(node);
@@ -1088,6 +1121,15 @@ static QList<PropertyPair> toPropertyPairList(const QList<InternalPropertyPointe
return propertyPairList;
}
void ModelPrivate::removePropertyAndRelatedResources(const InternalPropertyPointer &property)
{
if (m_resourceManagement)
handleResourceSet(
m_resourceManagement->removeProperty(AbstractProperty{property, m_model, nullptr}));
else
removeProperty(property);
}
void ModelPrivate::removeProperty(const InternalPropertyPointer &property)
{
notifyPropertiesAboutToBeRemoved({property});
@@ -1408,13 +1450,19 @@ Model::Model(ProjectStorageType &projectStorage,
const TypeName &typeName,
int major,
int minor,
Model *metaInfoProxyModel)
Model *metaInfoProxyModel,
std::unique_ptr<ModelResourceManagementInterface> resourceManagement)
: d(std::make_unique<Internal::ModelPrivate>(
this, projectStorage, typeName, major, minor, metaInfoProxyModel))
this, projectStorage, typeName, major, minor, metaInfoProxyModel, std::move(resourceManagement)))
{}
Model::Model(const TypeName &typeName, int major, int minor, Model *metaInfoProxyModel)
: d(std::make_unique<Internal::ModelPrivate>(this, typeName, major, minor, metaInfoProxyModel))
Model::Model(const TypeName &typeName,
int major,
int minor,
Model *metaInfoProxyModel,
std::unique_ptr<ModelResourceManagementInterface> resourceManagement)
: d(std::make_unique<Internal::ModelPrivate>(
this, typeName, major, minor, metaInfoProxyModel, std::move(resourceManagement)))
{}
Model::~Model() = default;
@@ -2156,4 +2204,9 @@ void Model::detachView(AbstractView *view, ViewNotification emitDetachNotify)
d->detachView(view, emitNotify);
}
QList<ModelNode> Model::allModelNodes() const
{
return QmlDesigner::toModelNodeList(d->allNodes(), nullptr);
}
} // namespace QmlDesigner

View File

@@ -101,8 +101,14 @@ public:
const TypeName &type,
int major,
int minor,
Model *metaInfoProxyModel);
ModelPrivate(Model *model, const TypeName &type, int major, int minor, Model *metaInfoProxyModel);
Model *metaInfoProxyModel,
std::unique_ptr<ModelResourceManagementInterface> resourceManagement);
ModelPrivate(Model *model,
const TypeName &type,
int major,
int minor,
Model *metaInfoProxyModel,
std::unique_ptr<ModelResourceManagementInterface> resourceManagement);
~ModelPrivate() override;
@@ -120,6 +126,7 @@ public:
bool isRootNode = false);
/*factory methods for internal use in model and rewriter*/
void removeNodeAndRelatedResources(const InternalNodePointer &node);
void removeNode(const InternalNodePointer &node);
void changeNodeId(const InternalNodePointer &node, const QString &id);
void changeNodeType(const InternalNodePointer &node, const TypeName &typeName, int majorVersion, int minorVersion);
@@ -235,6 +242,7 @@ public:
//node state property manipulation
void addProperty(const InternalNodePointer &node, const PropertyName &name);
void setPropertyValue(const InternalNodePointer &node,const PropertyName &name, const QVariant &value);
void removePropertyAndRelatedResources(const InternalPropertyPointer &property);
void removeProperty(const InternalPropertyPointer &property);
void setBindingProperty(const InternalNodePointer &node, const PropertyName &name, const QString &expression);
@@ -282,6 +290,7 @@ private:
QVector<ModelNode> toModelNodeVector(const QVector<InternalNodePointer> &nodeVector, AbstractView *view) const;
QVector<InternalNodePointer> toInternalNodeVector(const QVector<ModelNode> &modelNodeVector) const;
EnabledViewRange enabledViews() const;
void handleResourceSet(const ModelResourceSet &resourceSet);
public:
NotNullPointer<ProjectStorageType> projectStorage = nullptr;
@@ -300,6 +309,7 @@ private:
InternalNodePointer m_currentStateNode;
InternalNodePointer m_rootInternalNode;
InternalNodePointer m_currentTimelineNode;
std::unique_ptr<ModelResourceManagementInterface> m_resourceManagement;
QUrl m_fileUrl;
QPointer<RewriterView> m_rewriterView;
QPointer<NodeInstanceView> m_nodeInstanceView;

View File

@@ -290,7 +290,7 @@ A node might become invalid if e.g. it or one of its ancestors is deleted.
*/
bool ModelNode::isValid() const
{
return !m_model.isNull() && !m_view.isNull() && m_internalNode && m_internalNode->isValid;
return !m_model.isNull() && m_internalNode && m_internalNode->isValid;
}
/*!
@@ -652,7 +652,7 @@ void ModelNode::removeProperty(const PropertyName &name) const
return;
if (m_internalNode->hasProperty(name))
model()->d->removeProperty(m_internalNode->property(name));
model()->d->removePropertyAndRelatedResources(m_internalNode->property(name));
}
/*! \brief removes this node from the node tree
@@ -692,7 +692,7 @@ void ModelNode::destroy()
return;
removeModelNodeFromSelection(*this);
model()->d->removeNode(m_internalNode);
model()->d->removeNodeAndRelatedResources(m_internalNode);
}
//\}

View File

@@ -0,0 +1,39 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include <qmldesignercorelib_exports.h>
#include <bindingproperty.h>
namespace QmlDesigner {
struct ModelResourceSet
{
struct SetExpression
{
BindingProperty property;
QString expression;
};
QList<ModelNode> removeModelNodes;
QList<AbstractProperty> removeProperties;
QList<SetExpression> setExpressions;
};
class QMLDESIGNERCORE_EXPORT ModelResourceManagementInterface
{
public:
ModelResourceManagementInterface() = default;
virtual ~ModelResourceManagementInterface() = default;
ModelResourceManagementInterface(const ModelResourceManagementInterface &) = delete;
ModelResourceManagementInterface &operator=(const ModelResourceManagementInterface &) = delete;
ModelResourceManagementInterface(ModelResourceManagementInterface &&) = default;
ModelResourceManagementInterface &operator=(ModelResourceManagementInterface &&) = default;
virtual ModelResourceSet removeNode(const ModelNode &node) const = 0;
virtual ModelResourceSet removeProperty(const AbstractProperty &property) const = 0;
};
} // namespace QmlDesigner

View File

@@ -71,7 +71,7 @@ void NodeAbstractProperty::reparentHere(const ModelNode &modelNode, bool isNode
return;
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isNodeAbstractProperty())
privateModel()->removeProperty(internalNode()->property(name()));
privateModel()->removePropertyAndRelatedResources(internalNode()->property(name()));
if (modelNode.hasParentProperty()) {
Internal::InternalNodeAbstractProperty::Pointer oldParentProperty = modelNode.internalNode()->parentProperty();

View File

@@ -32,7 +32,7 @@ void NodeProperty::setModelNode(const ModelNode &modelNode)
}
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isNodeProperty())
privateModel()->removeProperty(internalNode()->property(name()));
privateModel()->removePropertyAndRelatedResources(internalNode()->property(name()));
privateModel()->reparentNode(internalNode(), name(), modelNode.internalNode(), false); //### we have to add a flag that this is not a list
}

View File

@@ -41,7 +41,7 @@ void SignalHandlerProperty::setSource(const QString &source)
}
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isSignalHandlerProperty())
privateModel()->removeProperty(internalNode()->property(name()));
privateModel()->removePropertyAndRelatedResources(internalNode()->property(name()));
privateModel()->setSignalHandlerProperty(internalNode(), name(), source);
}
@@ -118,7 +118,7 @@ void SignalDeclarationProperty::setSignature(const QString &signature)
}
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isSignalDeclarationProperty())
privateModel()->removeProperty(internalNode()->property(name()));
privateModel()->removePropertyAndRelatedResources(internalNode()->property(name()));
privateModel()->setSignalDeclarationProperty(internalNode(), name(), signature);
}

View File

@@ -47,7 +47,7 @@ void VariantProperty::setValue(const QVariant &value)
}
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isVariantProperty())
privateModel()->removeProperty(internalNode()->property(name()));
privateModel()->removePropertyAndRelatedResources(internalNode()->property(name()));
privateModel()->setVariantProperty(internalNode(), name(), value);
}
@@ -96,7 +96,7 @@ void VariantProperty::setDynamicTypeNameAndValue(const TypeName &type, const QVa
}
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isVariantProperty())
privateModel()->removeProperty(internalNode()->property(name()));
privateModel()->removePropertyAndRelatedResources(internalNode()->property(name()));
privateModel()->setDynamicVariantProperty(internalNode(), name(), type, value);
}

View File

@@ -242,36 +242,37 @@ public:
return false;
}
bool isBasedOn(TypeId id0) const override { return isBasedOn_(id0); }
bool isBasedOn(TypeId typeId) const { return isBasedOn_(typeId); }
bool isBasedOn(TypeId id0, TypeId id1) const override { return isBasedOn_(id0, id1); }
bool isBasedOn(TypeId typeId, TypeId id1) const override { return isBasedOn_(typeId, id1); }
bool isBasedOn(TypeId id0, TypeId id1, TypeId id2) const override
bool isBasedOn(TypeId typeId, TypeId id1, TypeId id2) const override
{
return isBasedOn_(id0, id1, id2);
return isBasedOn_(typeId, id1, id2);
}
bool isBasedOn(TypeId id0, TypeId id1, TypeId id2, TypeId id3) const override
bool isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3) const override
{
return isBasedOn_(id0, id1, id2, id3);
return isBasedOn_(typeId, id1, id2, id3);
}
bool isBasedOn(TypeId id0, TypeId id1, TypeId id2, TypeId id3, TypeId id4) const override
bool isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4) const override
{
return isBasedOn_(id0, id1, id2, id3, id4);
return isBasedOn_(typeId, id1, id2, id3, id4);
}
bool isBasedOn(TypeId id0, TypeId id1, TypeId id2, TypeId id3, TypeId id4, TypeId id5) const override
bool isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4, TypeId id5) const override
{
return isBasedOn_(id0, id1, id2, id3, id4, id5);
return isBasedOn_(typeId, id1, id2, id3, id4, id5);
}
bool isBasedOn(TypeId id0, TypeId id1, TypeId id2, TypeId id3, TypeId id4, TypeId id5, TypeId id6) const override
bool isBasedOn(
TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4, TypeId id5, TypeId id6) const override
{
return isBasedOn_(id0, id1, id2, id3, id4, id5, id6);
return isBasedOn_(typeId, id1, id2, id3, id4, id5, id6);
}
bool isBasedOn(TypeId id0,
bool isBasedOn(TypeId typeId,
TypeId id1,
TypeId id2,
TypeId id3,
@@ -280,7 +281,7 @@ public:
TypeId id6,
TypeId id7) const override
{
return isBasedOn_(id0, id1, id2, id3, id4, id5, id6, id7);
return isBasedOn_(typeId, id1, id2, id3, id4, id5, id6, id7);
}
TypeId fetchTypeIdByExportedName(Utils::SmallStringView name) const

View File

@@ -36,7 +36,6 @@ public:
propertyName(PropertyDeclarationId propertyDeclarationId) const = 0;
virtual TypeIds prototypeAndSelfIds(TypeId type) const = 0;
virtual TypeIds prototypeIds(TypeId type) const = 0;
virtual bool isBasedOn(TypeId) const = 0;
virtual bool isBasedOn(TypeId, TypeId) const = 0;
virtual bool isBasedOn(TypeId, TypeId, TypeId) const = 0;
virtual bool isBasedOn(TypeId, TypeId, TypeId, TypeId) const = 0;

View File

@@ -56,6 +56,8 @@ add_qtc_test(unittest GTEST
gtest-std-printing.h
lastchangedrowid-test.cpp
import-test.cpp
model-test.cpp
modelresourcemanagementmock.h
matchingtext-test.cpp
mockfutureinterface.h
mockmutex.h
@@ -66,6 +68,7 @@ add_qtc_test(unittest GTEST
mocktimer.cpp mocktimer.h
nodelistproperty-test.cpp
processevents-utilities.cpp processevents-utilities.h
projectstoragemock.cpp projectstoragemock.h
sizedarray-test.cpp
smallstring-test.cpp
spydummy.cpp spydummy.h
@@ -258,6 +261,7 @@ extend_qtc_test(unittest
model/model.cpp
model/model_p.h
model/modelnode.cpp
model/modelresourcemanagementinterface.h
model/propertycontainer.cpp
model/propertyparser.cpp
model/nodeabstractproperty.cpp

View File

@@ -73,19 +73,10 @@ class ListModelEditor : public testing::Test
public:
ListModelEditor()
{
setModuleId("QtQuick", modelId_QtQuick);
setType(modelId_QtQuick, "Item", "data");
designerModel = QmlDesigner::Model::create(projectStorageMock, "QtQuick.Item", 1, 1);
setModuleId("QtQml.Models", modelId_QtQml_Models);
setType(modelId_QtQml_Models, "ListModel", "children");
setType(modelId_QtQml_Models, "ListElement", "children");
componentModel = QmlDesigner::Model::create(projectStorageMock, "QtQml.Models.ListModel", 1, 1);
designerModel->attachView(&mockView);
emptyListModelNode = mockView.createModelNode("QtQml.Models.ListModel", 2, 15);
setType(modelId_QtQuick, "ListView", "data");
listViewNode = mockView.createModelNode("QtQuick.ListView", 2, 15);
listModelNode = mockView.createModelNode("QtQml.Models.ListModel", 2, 15);
mockView.rootModelNode().defaultNodeListProperty().reparentHere(listModelNode);
@@ -108,29 +99,6 @@ public:
ON_CALL(goIntoComponentMock, Call(_)).WillByDefault([](ModelNode node) { return node; });
}
void setModuleId(Utils::SmallStringView moduleName, ModuleId moduleId)
{
ON_CALL(projectStorageMock, moduleId(Eq(moduleName))).WillByDefault(Return(moduleId));
}
void setType(ModuleId moduleId,
Utils::SmallStringView typeName,
Utils::SmallString defaultPeopertyName)
{
static int typeIdNumber = 0;
TypeId typeId = TypeId::create(++typeIdNumber);
static int defaultPropertyIdNumber = 0;
PropertyDeclarationId defaultPropertyId = PropertyDeclarationId::create(
++defaultPropertyIdNumber);
ON_CALL(projectStorageMock, typeId(Eq(moduleId), Eq(typeName), _)).WillByDefault(Return(typeId));
ON_CALL(projectStorageMock, type(Eq(typeId)))
.WillByDefault(Return(Info::Type{defaultPropertyId, {}}));
ON_CALL(projectStorageMock, propertyName(Eq(defaultPropertyId)))
.WillByDefault(Return(defaultPeopertyName));
}
using Entry = std::pair<QmlDesigner::PropertyName, QVariant>;
ModelNode createElement(std::initializer_list<Entry> entries, AbstractView &view, ModelNode listModel)
@@ -211,9 +179,10 @@ public:
}
protected:
NiceMock<ProjectStorageMock> projectStorageMock;
NiceMock<ProjectStorageMockWithQtQtuick> projectStorageMock;
NiceMock<MockFunction<ModelNode(const ModelNode &)>> goIntoComponentMock;
QmlDesigner::ModelPointer designerModel;
QmlDesigner::ModelPointer designerModel{
QmlDesigner::Model::create(projectStorageMock, "QtQuick.Item", 1, 1)};
NiceMock<MockListModelEditorView> mockView;
QmlDesigner::ListModelEditorModel model{
[&] { return mockView.createModelNode("QtQml.Models.ListModel", 2, 15); },
@@ -225,11 +194,10 @@ protected:
ModelNode element1;
ModelNode element2;
ModelNode element3;
QmlDesigner::ModelPointer componentModel;
QmlDesigner::ModelPointer componentModel{
QmlDesigner::Model::create(projectStorageMock, "QtQml.Models.ListModel", 1, 1)};
NiceMock<MockListModelEditorView> mockComponentView;
ModelNode componentElement;
ModuleId modelId_QtQuick = ModuleId::create(1);
ModuleId modelId_QtQml_Models = ModuleId::create(2);
};
TEST_F(ListModelEditor, CreatePropertyNameSet)

View File

@@ -26,10 +26,25 @@ public:
const QmlDesigner::NodeAbstractProperty &oldPropertyParent,
AbstractView::PropertyChangeFlags propertyChange),
(override));
MOCK_METHOD(void,
propertiesRemoved,
(const QList<QmlDesigner::AbstractProperty> &propertyList),
(override));
MOCK_METHOD(void,
propertiesAboutToBeRemoved,
(const QList<QmlDesigner::AbstractProperty> &propertyList),
(override));
MOCK_METHOD(void,
bindingPropertiesChanged,
(const QList<QmlDesigner::BindingProperty> &propertyList,
PropertyChangeFlags propertyChange),
(override));
MOCK_METHOD(void,
bindingPropertiesAboutToBeChanged,
(const QList<QmlDesigner::BindingProperty> &propertyList),
(override));
MOCK_METHOD(void,
nodeRemoved,
@@ -37,4 +52,5 @@ public:
const QmlDesigner::NodeAbstractProperty &parentProperty,
AbstractView::PropertyChangeFlags propertyChange),
(override));
MOCK_METHOD(void, nodeAboutToBeRemoved, (const QmlDesigner::ModelNode &removedNode), (override));
};

View File

@@ -0,0 +1,491 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "googletest.h"
#include "mocklistmodeleditorview.h"
#include "modelresourcemanagementmock.h"
#include "projectstoragemock.h"
#include <designercore/include/bindingproperty.h>
#include <designercore/include/model.h>
#include <designercore/include/modelnode.h>
#include <designercore/include/nodeabstractproperty.h>
#include <designercore/include/nodelistproperty.h>
#include <designercore/include/nodeproperty.h>
#include <designercore/include/signalhandlerproperty.h>
#include <designercore/include/variantproperty.h>
namespace {
using QmlDesigner::AbstractProperty;
using QmlDesigner::ModelNode;
using QmlDesigner::ModelNodes;
using QmlDesigner::ModelResourceSet;
template<typename Matcher>
auto HasPropertyName(const Matcher &matcher)
{
return Property(&AbstractProperty::name, matcher);
}
class Model : public ::testing::Test
{
protected:
Model()
{
model.attachView(&viewMock);
rootNode = viewMock.rootModelNode();
ON_CALL(resourceManagementMock, removeNode(_)).WillByDefault([](const auto &node) {
return ModelResourceSet{{node}, {}, {}};
});
ON_CALL(resourceManagementMock, removeProperty(_)).WillByDefault([](const auto &property) {
return ModelResourceSet{{}, {property}, {}};
});
}
~Model() { model.detachView(&viewMock); }
auto createNodeWithParent(const ModelNode &parentNode)
{
auto node = viewMock.createModelNode("QtQuick.Item");
parentNode.defaultNodeAbstractProperty().reparentHere(node);
return node;
}
auto createProperty(const ModelNode &parentNode, QmlDesigner::PropertyName name)
{
auto property = parentNode.variantProperty(name);
property.setValue(4);
return property;
}
protected:
NiceMock<MockListModelEditorView> viewMock;
NiceMock<ProjectStorageMockWithQtQtuick> projectStorageMock;
NiceMock<ModelResourceManagementMock> resourceManagementMock;
QmlDesigner::Model model{projectStorageMock,
"QtQuick.Item",
-1,
-1,
nullptr,
std::make_unique<ModelResourceManagementMockWrapper>(
resourceManagementMock)};
ModelNode rootNode;
};
TEST_F(Model, ModelNodeDestroyIsCallingModelResourceManagementRemoveNode)
{
auto node = createNodeWithParent(rootNode);
EXPECT_CALL(resourceManagementMock, removeNode(node));
node.destroy();
}
TEST_F(Model, ModelNodeRemoveProperyIsCallingModelResourceManagementRemoveProperty)
{
auto property = rootNode.variantProperty("foo");
property.setValue(4);
EXPECT_CALL(resourceManagementMock, removeProperty(Eq(property)));
rootNode.removeProperty("foo");
}
TEST_F(Model, NodeAbstractPropertyReparentHereIsCallingModelResourceManagementRemoveProperty)
{
auto node = createNodeWithParent(rootNode);
auto property = rootNode.variantProperty("foo");
property.setValue(4);
EXPECT_CALL(resourceManagementMock, removeProperty(Eq(property)));
rootNode.nodeListProperty("foo").reparentHere(node);
}
TEST_F(Model, NodePropertySetModelNodeIsCallingModelResourceManagementRemoveProperty)
{
auto node = createNodeWithParent(rootNode);
auto property = rootNode.variantProperty("foo");
property.setValue(4);
EXPECT_CALL(resourceManagementMock, removeProperty(Eq(property)));
rootNode.nodeProperty("foo").setModelNode(node);
}
TEST_F(Model, VariantPropertySetValueIsCallingModelResourceManagementRemoveProperty)
{
auto property = rootNode.bindingProperty("foo");
property.setExpression("blah");
EXPECT_CALL(resourceManagementMock, removeProperty(Eq(property)));
rootNode.variantProperty("foo").setValue(7);
}
TEST_F(Model,
VariantPropertySetDynamicTypeNameAndEnumerationIsCallingModelResourceManagementRemoveProperty)
{
auto property = rootNode.bindingProperty("foo");
property.setExpression("blah");
EXPECT_CALL(resourceManagementMock, removeProperty(Eq(property)));
rootNode.variantProperty("foo").setDynamicTypeNameAndEnumeration("int", "Ha");
}
TEST_F(Model, VariantPropertySetDynamicTypeNameAndValueIsCallingModelResourceManagementRemoveProperty)
{
auto property = rootNode.bindingProperty("foo");
property.setExpression("blah");
EXPECT_CALL(resourceManagementMock, removeProperty(Eq(property)));
rootNode.variantProperty("foo").setDynamicTypeNameAndValue("int", 7);
}
TEST_F(Model, BindingPropertySetExpressionIsCallingModelResourceManagementRemoveProperty)
{
auto property = rootNode.variantProperty("foo");
property.setValue(4);
EXPECT_CALL(resourceManagementMock, removeProperty(Eq(property)));
rootNode.bindingProperty("foo").setExpression("blah");
}
TEST_F(Model,
BindingPropertySetDynamicTypeNameAndExpressionIsCallingModelResourceManagementRemoveProperty)
{
auto property = rootNode.variantProperty("foo");
property.setValue(4);
EXPECT_CALL(resourceManagementMock, removeProperty(Eq(property)));
rootNode.bindingProperty("foo").setDynamicTypeNameAndExpression("int", "blah");
}
TEST_F(Model, SignalHandlerPropertySetSourceIsCallingModelResourceManagementRemoveProperty)
{
auto property = rootNode.bindingProperty("foo");
property.setExpression("blah");
EXPECT_CALL(resourceManagementMock, removeProperty(Eq(property)));
rootNode.signalHandlerProperty("foo").setSource("blah");
}
TEST_F(Model, SignalDeclarationPropertySetSignatureIsCallingModelResourceManagementRemoveProperty)
{
auto property = rootNode.bindingProperty("foo");
property.setExpression("blah");
EXPECT_CALL(resourceManagementMock, removeProperty(Eq(property)));
rootNode.signalDeclarationProperty("foo").setSignature("blah");
}
TEST_F(Model, ModelNodeDestroyIsCallingAbstractViewNodeAboutToBeRemoved)
{
auto node = createNodeWithParent(rootNode);
auto node2 = createNodeWithParent(rootNode);
ON_CALL(resourceManagementMock, removeNode(node))
.WillByDefault(Return(ModelResourceSet{{node, node2}, {}, {}}));
EXPECT_CALL(viewMock, nodeAboutToBeRemoved(Eq(node)));
EXPECT_CALL(viewMock, nodeAboutToBeRemoved(Eq(node2)));
node.destroy();
}
TEST_F(Model, ModelNodeDestroyIsCallingAbstractViewNodeRemoved)
{
auto node = createNodeWithParent(rootNode);
auto node2 = createNodeWithParent(rootNode);
ON_CALL(resourceManagementMock, removeNode(node))
.WillByDefault(Return(ModelResourceSet{{node, node2}, {}, {}}));
EXPECT_CALL(viewMock, nodeRemoved(Eq(node), _, _));
EXPECT_CALL(viewMock, nodeRemoved(Eq(node2), _, _));
node.destroy();
}
TEST_F(Model, ModelNodeDestroyIsCallingAbstractViewNodeRemovedWithValidNodes)
{
auto node = createNodeWithParent(rootNode);
auto node2 = createNodeWithParent(rootNode);
ON_CALL(resourceManagementMock, removeNode(node))
.WillByDefault(Return(ModelResourceSet{{node, node2, ModelNode{}}, {}, {}}));
EXPECT_CALL(viewMock, nodeRemoved(Eq(node), _, _));
EXPECT_CALL(viewMock, nodeRemoved(Eq(node2), _, _));
node.destroy();
}
TEST_F(Model, ModelNodeDestroyIsCallingAbstractViewPropertiesAboutToBeRemoved)
{
auto node = createNodeWithParent(rootNode);
auto property = createProperty(rootNode, "foo");
auto property2 = createProperty(rootNode, "bar");
ON_CALL(resourceManagementMock, removeNode(node))
.WillByDefault(Return(ModelResourceSet{{node}, {property, property2}, {}}));
EXPECT_CALL(viewMock, propertiesAboutToBeRemoved(ElementsAre(Eq(property))));
EXPECT_CALL(viewMock, propertiesAboutToBeRemoved(ElementsAre(Eq(property2))));
node.destroy();
}
TEST_F(Model, ModelNodeDestroyIsCallingAbstractViewPropertiesRemoved)
{
auto node = createNodeWithParent(rootNode);
auto property = createProperty(rootNode, "foo");
auto property2 = createProperty(rootNode, "bar");
ON_CALL(resourceManagementMock, removeNode(node))
.WillByDefault(Return(ModelResourceSet{{node}, {property, property2}, {}}));
EXPECT_CALL(viewMock, propertiesRemoved(ElementsAre(Eq(property))));
EXPECT_CALL(viewMock, propertiesRemoved(ElementsAre(Eq(property2))));
node.destroy();
}
TEST_F(Model, ModelNodeDestroyIsCallingAbstractViewPropertiesRemovedOnlyWithValidProperties)
{
auto node = createNodeWithParent(rootNode);
auto property = createProperty(rootNode, "foo");
auto property2 = createProperty(rootNode, "bar");
ON_CALL(resourceManagementMock, removeNode(node))
.WillByDefault(Return(ModelResourceSet{{node}, {property, property2, {}}, {}}));
EXPECT_CALL(viewMock, propertiesRemoved(ElementsAre(Eq(property))));
EXPECT_CALL(viewMock, propertiesRemoved(ElementsAre(Eq(property2))));
node.destroy();
}
TEST_F(Model, ModelNodeDestroyIsCallingAbstractViewBindingPropertiesAboutToBeChanged)
{
auto node = createNodeWithParent(rootNode);
auto property = rootNode.bindingProperty("foo");
auto property2 = rootNode.bindingProperty("bar");
ON_CALL(resourceManagementMock, removeNode(node))
.WillByDefault(Return(ModelResourceSet{{node}, {}, {{property, "yi"}, {property2, "er"}}}));
EXPECT_CALL(viewMock, bindingPropertiesAboutToBeChanged(ElementsAre(Eq(property))));
EXPECT_CALL(viewMock, bindingPropertiesAboutToBeChanged(ElementsAre(Eq(property2))));
node.destroy();
}
TEST_F(Model, ModelNodeDestroyIsCallingAbstractViewBindingPropertiesChanged)
{
auto node = createNodeWithParent(rootNode);
auto property = rootNode.bindingProperty("foo");
auto property2 = rootNode.bindingProperty("bar");
ON_CALL(resourceManagementMock, removeNode(node))
.WillByDefault(Return(ModelResourceSet{{node}, {}, {{property, "yi"}, {property2, "er"}}}));
EXPECT_CALL(viewMock, bindingPropertiesChanged(ElementsAre(Eq(property)), _));
EXPECT_CALL(viewMock, bindingPropertiesChanged(ElementsAre(Eq(property2)), _));
node.destroy();
}
TEST_F(Model, ModelNodeDestroyIsCallingAbstractViewBindingPropertiesChangedOnlyWithValidProperties)
{
auto node = createNodeWithParent(rootNode);
auto property = rootNode.bindingProperty("foo");
auto property2 = rootNode.bindingProperty("bar");
ON_CALL(resourceManagementMock, removeNode(node))
.WillByDefault(Return(
ModelResourceSet{{node}, {}, {{property, "yi"}, {property2, "er"}, {{}, "san"}}}));
EXPECT_CALL(viewMock, bindingPropertiesChanged(ElementsAre(Eq(property)), _));
EXPECT_CALL(viewMock, bindingPropertiesChanged(ElementsAre(Eq(property2)), _));
node.destroy();
}
TEST_F(Model, ModelNodeRemovePropertyIsCallingAbstractViewNodeAboutToBeRemoved)
{
auto property = createProperty(rootNode, "foo");
auto node = createNodeWithParent(rootNode);
auto node2 = createNodeWithParent(rootNode);
ON_CALL(resourceManagementMock, removeProperty(property))
.WillByDefault(Return(ModelResourceSet{{node, node2}, {property}, {}}));
EXPECT_CALL(viewMock, nodeAboutToBeRemoved(Eq(node)));
EXPECT_CALL(viewMock, nodeAboutToBeRemoved(Eq(node2)));
rootNode.removeProperty("foo");
}
TEST_F(Model, ModelNodeRemovePropertyIsCallingAbstractViewNodeRemoved)
{
auto property = createProperty(rootNode, "foo");
auto node = createNodeWithParent(rootNode);
auto node2 = createNodeWithParent(rootNode);
ON_CALL(resourceManagementMock, removeProperty(property))
.WillByDefault(Return(ModelResourceSet{{node, node2}, {property}, {}}));
EXPECT_CALL(viewMock, nodeRemoved(Eq(node), _, _));
EXPECT_CALL(viewMock, nodeRemoved(Eq(node2), _, _));
rootNode.removeProperty("foo");
}
TEST_F(Model, ModelNodeRemovePropertyIsCallingAbstractViewNodeRemovedWithValidNodes)
{
auto property = createProperty(rootNode, "foo");
auto node = createNodeWithParent(rootNode);
auto node2 = createNodeWithParent(rootNode);
ON_CALL(resourceManagementMock, removeProperty(property))
.WillByDefault(Return(ModelResourceSet{{node, node2, ModelNode{}}, {property}, {}}));
EXPECT_CALL(viewMock, nodeRemoved(Eq(node), _, _));
EXPECT_CALL(viewMock, nodeRemoved(Eq(node2), _, _));
rootNode.removeProperty("foo");
}
TEST_F(Model, ModelNodeRemovePropertyIsCallingAbstractViewPropertiesAboutToBeRemoved)
{
auto property = createProperty(rootNode, "yi");
auto property2 = createProperty(rootNode, "er");
ON_CALL(resourceManagementMock, removeProperty(property))
.WillByDefault(Return(ModelResourceSet{{}, {property, property2}, {}}));
EXPECT_CALL(viewMock, propertiesAboutToBeRemoved(ElementsAre(Eq(property))));
EXPECT_CALL(viewMock, propertiesAboutToBeRemoved(ElementsAre(Eq(property2))));
rootNode.removeProperty("yi");
}
TEST_F(Model, ModelNodeRemovePropertyIsCallingAbstractViewPropertiesRemoved)
{
auto property = createProperty(rootNode, "yi");
auto property2 = createProperty(rootNode, "er");
ON_CALL(resourceManagementMock, removeProperty(property))
.WillByDefault(Return(ModelResourceSet{{}, {property, property2}, {}}));
EXPECT_CALL(viewMock, propertiesRemoved(ElementsAre(Eq(property))));
EXPECT_CALL(viewMock, propertiesRemoved(ElementsAre(Eq(property2))));
rootNode.removeProperty("yi");
}
TEST_F(Model, ModelNodeRemovePropertyIsCallingAbstractViewPropertiesRemovedOnlyWithValidProperties)
{
auto property = createProperty(rootNode, "yi");
auto property2 = createProperty(rootNode, "er");
ON_CALL(resourceManagementMock, removeProperty(property))
.WillByDefault(Return(ModelResourceSet{{}, {property, property2, {}}, {}}));
EXPECT_CALL(viewMock, propertiesRemoved(ElementsAre(Eq(property))));
EXPECT_CALL(viewMock, propertiesRemoved(ElementsAre(Eq(property2))));
rootNode.removeProperty("yi");
}
TEST_F(Model, ModelNodeRemovePropertyIsCallingAbstractViewBindingPropertiesAboutToBeChanged)
{
auto property = createProperty(rootNode, "yi");
auto property1 = rootNode.bindingProperty("foo");
auto property2 = rootNode.bindingProperty("bar");
ON_CALL(resourceManagementMock, removeProperty(property))
.WillByDefault(
Return(ModelResourceSet{{}, {property}, {{property1, "yi"}, {property2, "er"}}}));
EXPECT_CALL(viewMock, bindingPropertiesAboutToBeChanged(ElementsAre(Eq(property1))));
EXPECT_CALL(viewMock, bindingPropertiesAboutToBeChanged(ElementsAre(Eq(property2))));
rootNode.removeProperty("yi");
}
TEST_F(Model, ModelNodeRemovePropertyIsCallingAbstractViewBindingPropertiesChanged)
{
auto property = createProperty(rootNode, "yi");
auto property1 = rootNode.bindingProperty("foo");
auto property2 = rootNode.bindingProperty("bar");
ON_CALL(resourceManagementMock, removeProperty(property))
.WillByDefault(
Return(ModelResourceSet{{}, {property}, {{property1, "yi"}, {property2, "er"}}}));
EXPECT_CALL(viewMock, bindingPropertiesChanged(ElementsAre(Eq(property1)), _));
EXPECT_CALL(viewMock, bindingPropertiesChanged(ElementsAre(Eq(property2)), _));
rootNode.removeProperty("yi");
}
TEST_F(Model,
ModelNodeRemovePropertyIsCallingAbstractViewBindingPropertiesChangedOnlyWithValidProperties)
{
auto property = createProperty(rootNode, "yi");
auto property1 = rootNode.bindingProperty("foo");
auto property2 = rootNode.bindingProperty("bar");
ON_CALL(resourceManagementMock, removeProperty(property))
.WillByDefault(
Return(ModelResourceSet{{}, {property}, {{property1, "yi"}, {property2, "er"}, {}}}));
EXPECT_CALL(viewMock, bindingPropertiesChanged(ElementsAre(Eq(property1)), _));
EXPECT_CALL(viewMock, bindingPropertiesChanged(ElementsAre(Eq(property2)), _));
rootNode.removeProperty("yi");
}
TEST_F(Model, ByDefaultRemoveModelNodeRemovesNode)
{
model.detachView(&viewMock);
QmlDesigner::Model newModel{projectStorageMock, "QtQuick.Item"};
newModel.attachView(&viewMock);
auto node = createNodeWithParent(viewMock.rootModelNode());
EXPECT_CALL(viewMock, nodeAboutToBeRemoved(Eq(node)));
node.destroy();
}
TEST_F(Model, ByDefaultRemovePropertiesRemovesProperty)
{
model.detachView(&viewMock);
QmlDesigner::Model newModel{projectStorageMock, "QtQuick.Item"};
newModel.attachView(&viewMock);
rootNode = viewMock.rootModelNode();
auto property = createProperty(rootNode, "yi");
EXPECT_CALL(viewMock, propertiesAboutToBeRemoved(ElementsAre(Eq(property))));
rootNode.removeProperty("yi");
}
TEST_F(Model, ByDefaultRemoveModelNodeInFactoryMethodCallsRemovesNode)
{
model.detachView(&viewMock);
auto newModel = QmlDesigner::Model::create(projectStorageMock, "QtQuick.Item");
newModel->attachView(&viewMock);
auto node = createNodeWithParent(viewMock.rootModelNode());
EXPECT_CALL(viewMock, nodeAboutToBeRemoved(Eq(node)));
node.destroy();
}
TEST_F(Model, ByDefaultRemovePropertiesInFactoryMethodCallsRemoveProperty)
{
model.detachView(&viewMock);
auto newModel = QmlDesigner::Model::create(projectStorageMock, "QtQuick.Item");
newModel->attachView(&viewMock);
rootNode = viewMock.rootModelNode();
auto property = createProperty(rootNode, "yi");
EXPECT_CALL(viewMock, propertiesAboutToBeRemoved(ElementsAre(Eq(property))));
rootNode.removeProperty("yi");
}
} // namespace

View File

@@ -0,0 +1,42 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include "googletest.h"
#include <model/modelresourcemanagementinterface.h>
#include <modelnode.h>
class ModelResourceManagementMock : public QmlDesigner::ModelResourceManagementInterface
{
public:
MOCK_METHOD(QmlDesigner::ModelResourceSet,
removeNode,
(const QmlDesigner::ModelNode &),
(const, override));
MOCK_METHOD(QmlDesigner::ModelResourceSet,
removeProperty,
(const QmlDesigner::AbstractProperty &),
(const, override));
};
class ModelResourceManagementMockWrapper : public QmlDesigner::ModelResourceManagementInterface
{
public:
ModelResourceManagementMockWrapper(ModelResourceManagementMock &mock)
: mock{mock}
{}
QmlDesigner::ModelResourceSet removeNode(const QmlDesigner::ModelNode &node) const override
{
return mock.removeNode(node);
}
QmlDesigner::ModelResourceSet removeProperty(const QmlDesigner::AbstractProperty &property) const override
{
return mock.removeProperty(property);
}
ModelResourceManagementMock &mock;
};

View File

@@ -25,11 +25,6 @@ protected:
using iterator = QmlDesigner::NodeListProperty::iterator;
NodeListProperty()
{
ModuleId modelId_QtQuick = ModuleId::create(1);
setModuleId("QtQuick", modelId_QtQuick);
setType(modelId_QtQuick, "Item", "data");
model = std::make_unique<QmlDesigner::Model>(projectStorageMock, "QtQuick.Item");
model->attachView(&abstractViewMock);
nodeListProperty = abstractViewMock.rootModelNode().nodeListProperty("foo");
@@ -82,8 +77,9 @@ protected:
}
protected:
NiceMock<ProjectStorageMock> projectStorageMock;
std::unique_ptr<QmlDesigner::Model> model;
NiceMock<ProjectStorageMockWithQtQtuick> projectStorageMock;
std::unique_ptr<QmlDesigner::Model> model{
std::make_unique<QmlDesigner::Model>(projectStorageMock, "QtQuick.Item")};
NiceMock<AbstractViewMock> abstractViewMock;
QmlDesigner::NodeListProperty nodeListProperty;
ModelNode node1;

View File

@@ -0,0 +1,89 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "projectstoragemock.h"
namespace QmlDesigner {
namespace {
template<typename BasicId>
void incrementBasicId(BasicId &id)
{
id = BasicId::create(id.internalId() + 1);
}
ModuleId createModule(ProjectStorageMock &mock, Utils::SmallStringView moduleName)
{
static ModuleId moduleId;
incrementBasicId(moduleId);
ON_CALL(mock, moduleId(Eq(moduleName))).WillByDefault(Return(moduleId));
return moduleId;
}
TypeId createType(ProjectStorageMock &mock,
ModuleId moduleId,
Utils::SmallStringView typeName,
Utils::SmallString defaultPropertyName,
Storage::TypeTraits typeTraits,
TypeId baseTypeId = TypeId{})
{
static TypeId typeId;
incrementBasicId(typeId);
static PropertyDeclarationId defaultPropertyId;
incrementBasicId(defaultPropertyId);
ON_CALL(mock, typeId(Eq(moduleId), Eq(typeName), _)).WillByDefault(Return(typeId));
ON_CALL(mock, type(Eq(typeId)))
.WillByDefault(Return(Storage::Info::Type{defaultPropertyId, typeTraits}));
ON_CALL(mock, propertyName(Eq(defaultPropertyId))).WillByDefault(Return(defaultPropertyName));
if (baseTypeId)
ON_CALL(mock, isBasedOn(Eq(typeId), Eq(baseTypeId))).WillByDefault(Return(true));
return typeId;
}
TypeId createObject(ProjectStorageMock &mock,
ModuleId moduleId,
Utils::SmallStringView typeName,
Utils::SmallString defaultPropertyName,
TypeId baseTypeId = TypeId{})
{
return createType(
mock, moduleId, typeName, defaultPropertyName, Storage::TypeTraits::Reference, baseTypeId);
}
void setupIsBasedOn(ProjectStorageMock &mock)
{
auto call = [&](TypeId typeId, auto... ids) -> bool {
return (mock.isBasedOn(typeId, ids) || ...);
};
ON_CALL(mock, isBasedOn(_, _, _)).WillByDefault(call);
ON_CALL(mock, isBasedOn(_, _, _, _)).WillByDefault(call);
ON_CALL(mock, isBasedOn(_, _, _, _, _)).WillByDefault(call);
ON_CALL(mock, isBasedOn(_, _, _, _, _, _)).WillByDefault(call);
ON_CALL(mock, isBasedOn(_, _, _, _, _, _, _)).WillByDefault(call);
ON_CALL(mock, isBasedOn(_, _, _, _, _, _, _, _)).WillByDefault(call);
}
} // namespace
} // namespace QmlDesigner
void ProjectStorageMock::setupQtQtuick()
{
QmlDesigner::setupIsBasedOn(*this);
auto qmlModuleId = QmlDesigner::createModule(*this, "QML");
auto qtQmlModelsModuleId = QmlDesigner::createModule(*this, "QtQml.Models");
auto qtQuickModuleId = QmlDesigner::createModule(*this, "QtQuick");
auto qtObjectId = QmlDesigner::createObject(*this, qmlModuleId, "QtObject", "children");
QmlDesigner::createObject(*this, qtQmlModelsModuleId, "ListModel", "children", qtObjectId);
QmlDesigner::createObject(*this, qtQmlModelsModuleId, "ListElement", "children", qtObjectId);
auto itemId = QmlDesigner::createObject(*this, qtQuickModuleId, "Item", "data", qtObjectId);
QmlDesigner::createObject(*this, qtQuickModuleId, "ListView", "data", itemId);
}

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2017 The Qt Company Ltd.
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
@@ -14,6 +14,8 @@
class ProjectStorageMock : public QmlDesigner::ProjectStorageInterface
{
public:
void setupQtQtuick();
MOCK_METHOD(void,
synchronize,
(QmlDesigner::Storage::Synchronization::SynchronizationPackage package),
@@ -63,7 +65,6 @@ public:
(const, override));
MOCK_METHOD(QmlDesigner::TypeIds, prototypeAndSelfIds, (QmlDesigner::TypeId type), (const, override));
MOCK_METHOD(QmlDesigner::TypeIds, prototypeIds, (QmlDesigner::TypeId type), (const, override));
MOCK_METHOD(bool, isBasedOn, (QmlDesigner::TypeId typeId), (const, override));
MOCK_METHOD(bool, isBasedOn, (QmlDesigner::TypeId typeId, QmlDesigner::TypeId), (const, override));
MOCK_METHOD(bool,
isBasedOn,
@@ -158,3 +159,8 @@ public:
MOCK_METHOD(std::vector<QmlDesigner::Cache::Source>, fetchAllSources, (), ());
};
class ProjectStorageMockWithQtQtuick : public ProjectStorageMock
{
public:
ProjectStorageMockWithQtQtuick() { setupQtQtuick(); }
};