forked from qt-creator/qt-creator
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:
@@ -341,6 +341,7 @@ extend_qtc_library(QmlDesignerCore
|
|||||||
modelnodepositionrecalculator.cpp
|
modelnodepositionrecalculator.cpp
|
||||||
modelnodepositionrecalculator.h
|
modelnodepositionrecalculator.h
|
||||||
modelnodepositionstorage.cpp
|
modelnodepositionstorage.cpp
|
||||||
|
modelresourcemanagementinterface.h
|
||||||
modeltotextmerger.cpp
|
modeltotextmerger.cpp
|
||||||
modeltotextmerger.h
|
modeltotextmerger.h
|
||||||
modelutils.cpp
|
modelutils.cpp
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <qmldesignercorelib_global.h>
|
#include <qmldesignercorelib_global.h>
|
||||||
|
|
||||||
#include <documentmessage.h>
|
#include <documentmessage.h>
|
||||||
|
#include <model/modelresourcemanagementinterface.h>
|
||||||
#include <projectstorage/projectstoragefwd.h>
|
#include <projectstorage/projectstoragefwd.h>
|
||||||
|
|
||||||
#include <QMimeData>
|
#include <QMimeData>
|
||||||
@@ -61,25 +62,34 @@ public:
|
|||||||
const TypeName &type,
|
const TypeName &type,
|
||||||
int major = 1,
|
int major = 1,
|
||||||
int minor = 1,
|
int minor = 1,
|
||||||
Model *metaInfoProxyModel = nullptr);
|
Model *metaInfoProxyModel = nullptr,
|
||||||
Model(const TypeName &typeName, int major = 1, int minor = 1, 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();
|
~Model();
|
||||||
|
|
||||||
static ModelPointer create(const TypeName &typeName,
|
static ModelPointer create(const TypeName &typeName,
|
||||||
int major = 1,
|
int major = 1,
|
||||||
int minor = 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,
|
static ModelPointer create(ProjectStorageType &projectStorage,
|
||||||
const TypeName &typeName,
|
const TypeName &typeName,
|
||||||
int major = 1,
|
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;
|
QUrl fileUrl() const;
|
||||||
@@ -120,6 +130,8 @@ public:
|
|||||||
void attachView(AbstractView *view);
|
void attachView(AbstractView *view);
|
||||||
void detachView(AbstractView *view, ViewNotification emitDetachNotify = NotifyView);
|
void detachView(AbstractView *view, ViewNotification emitDetachNotify = NotifyView);
|
||||||
|
|
||||||
|
QList<ModelNode> allModelNodes() const;
|
||||||
|
|
||||||
// Editing sub-components:
|
// Editing sub-components:
|
||||||
|
|
||||||
// Imports:
|
// Imports:
|
||||||
@@ -177,4 +189,4 @@ private:
|
|||||||
std::unique_ptr<Internal::ModelPrivate> d;
|
std::unique_ptr<Internal::ModelPrivate> d;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace QmlDesigner
|
||||||
|
|||||||
@@ -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 bool operator <(const ModelNode &firstNode, const ModelNode &secondNode);
|
||||||
QMLDESIGNERCORE_EXPORT QDebug operator<<(QDebug debug, const ModelNode &modelNode);
|
QMLDESIGNERCORE_EXPORT QDebug operator<<(QDebug debug, const ModelNode &modelNode);
|
||||||
QMLDESIGNERCORE_EXPORT QTextStream& operator<<(QTextStream &stream, const ModelNode &modelNode);
|
QMLDESIGNERCORE_EXPORT QTextStream& operator<<(QTextStream &stream, const ModelNode &modelNode);
|
||||||
|
|
||||||
|
using ModelNodes = QList<ModelNode>;
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(QmlDesigner::ModelNode)
|
Q_DECLARE_METATYPE(QmlDesigner::ModelNode)
|
||||||
|
|||||||
@@ -1619,16 +1619,20 @@ TypeName NodeMetaInfo::simplifiedTypeName() const
|
|||||||
|
|
||||||
int NodeMetaInfo::majorVersion() const
|
int NodeMetaInfo::majorVersion() const
|
||||||
{
|
{
|
||||||
|
if constexpr (!useProjectStorage()) {
|
||||||
if (isValid())
|
if (isValid())
|
||||||
return m_privateData->majorVersion();
|
return m_privateData->majorVersion();
|
||||||
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int NodeMetaInfo::minorVersion() const
|
int NodeMetaInfo::minorVersion() const
|
||||||
{
|
{
|
||||||
|
if constexpr (!useProjectStorage()) {
|
||||||
if (isValid())
|
if (isValid())
|
||||||
return m_privateData->minorVersion();
|
return m_privateData->minorVersion();
|
||||||
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ AbstractProperty::AbstractProperty(const Internal::InternalPropertyPointer &prop
|
|||||||
m_model(model),
|
m_model(model),
|
||||||
m_view(view)
|
m_view(view)
|
||||||
{
|
{
|
||||||
Q_ASSERT(!m_model || m_view);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractProperty::AbstractProperty(const AbstractProperty &property, AbstractView *view)
|
AbstractProperty::AbstractProperty(const AbstractProperty &property, AbstractView *view)
|
||||||
|
|||||||
@@ -64,9 +64,13 @@ RewriterTransaction AbstractView::beginRewriterTransaction(const QByteArray &ide
|
|||||||
|
|
||||||
ModelNode AbstractView::createModelNode(const TypeName &typeName)
|
ModelNode AbstractView::createModelNode(const TypeName &typeName)
|
||||||
{
|
{
|
||||||
|
if constexpr (useProjectStorage()) {
|
||||||
|
return createModelNode(typeName, -1, -1);
|
||||||
|
} else {
|
||||||
const NodeMetaInfo metaInfo = model()->metaInfo(typeName);
|
const NodeMetaInfo metaInfo = model()->metaInfo(typeName);
|
||||||
return createModelNode(typeName, metaInfo.majorVersion(), metaInfo.minorVersion());
|
return createModelNode(typeName, metaInfo.majorVersion(), metaInfo.minorVersion());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ModelNode AbstractView::createModelNode(const TypeName &typeName,
|
ModelNode AbstractView::createModelNode(const TypeName &typeName,
|
||||||
int majorVersion,
|
int majorVersion,
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ void BindingProperty::setExpression(const QString &expression)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isBindingProperty())
|
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isBindingProperty())
|
||||||
privateModel()->removeProperty(internalNode()->property(name()));
|
privateModel()->removePropertyAndRelatedResources(internalNode()->property(name()));
|
||||||
|
|
||||||
privateModel()->setBindingProperty(internalNode(), name(), expression);
|
privateModel()->setBindingProperty(internalNode(), name(), expression);
|
||||||
}
|
}
|
||||||
@@ -341,7 +341,7 @@ void BindingProperty::setDynamicTypeNameAndExpression(const TypeName &typeName,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isBindingProperty())
|
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isBindingProperty())
|
||||||
privateModel()->removeProperty(internalNode()->property(name()));
|
privateModel()->removePropertyAndRelatedResources(internalNode()->property(name()));
|
||||||
|
|
||||||
privateModel()->setDynamicBindingProperty(internalNode(), name(), typeName, expression);
|
privateModel()->setDynamicBindingProperty(internalNode(), name(), typeName, expression);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,9 +62,11 @@ ModelPrivate::ModelPrivate(Model *model,
|
|||||||
const TypeName &typeName,
|
const TypeName &typeName,
|
||||||
int major,
|
int major,
|
||||||
int minor,
|
int minor,
|
||||||
Model *metaInfoProxyModel)
|
Model *metaInfoProxyModel,
|
||||||
|
std::unique_ptr<ModelResourceManagementInterface> resourceManagement)
|
||||||
: projectStorage{&projectStorage}
|
: projectStorage{&projectStorage}
|
||||||
, m_model{model}
|
, m_model{model}
|
||||||
|
, m_resourceManagement{std::move(resourceManagement)}
|
||||||
{
|
{
|
||||||
m_metaInfoProxyModel = metaInfoProxyModel;
|
m_metaInfoProxyModel = metaInfoProxyModel;
|
||||||
|
|
||||||
@@ -75,9 +77,14 @@ ModelPrivate::ModelPrivate(Model *model,
|
|||||||
m_currentTimelineNode = m_rootInternalNode;
|
m_currentTimelineNode = m_rootInternalNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelPrivate::ModelPrivate(
|
ModelPrivate::ModelPrivate(Model *model,
|
||||||
Model *model, const TypeName &typeName, int major, int minor, Model *metaInfoProxyModel)
|
const TypeName &typeName,
|
||||||
|
int major,
|
||||||
|
int minor,
|
||||||
|
Model *metaInfoProxyModel,
|
||||||
|
std::unique_ptr<ModelResourceManagementInterface> resourceManagement)
|
||||||
: m_model(model)
|
: m_model(model)
|
||||||
|
, m_resourceManagement{std::move(resourceManagement)}
|
||||||
{
|
{
|
||||||
m_metaInfoProxyModel = metaInfoProxyModel;
|
m_metaInfoProxyModel = metaInfoProxyModel;
|
||||||
|
|
||||||
@@ -279,7 +286,9 @@ InternalNodePointer ModelPrivate::createNode(const TypeName &typeName,
|
|||||||
notifyNodeCreated(newNode);
|
notifyNodeCreated(newNode);
|
||||||
|
|
||||||
if (!newNode->propertyNameList().isEmpty())
|
if (!newNode->propertyNameList().isEmpty())
|
||||||
notifyVariantPropertiesChanged(newNode, newNode->propertyNameList(), AbstractView::PropertiesAdded);
|
notifyVariantPropertiesChanged(newNode,
|
||||||
|
newNode->propertyNameList(),
|
||||||
|
AbstractView::PropertiesAdded);
|
||||||
|
|
||||||
return newNode;
|
return newNode;
|
||||||
}
|
}
|
||||||
@@ -303,16 +312,40 @@ EnabledViewRange ModelPrivate::enabledViews() const
|
|||||||
return EnabledViewRange{m_viewList};
|
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)
|
void ModelPrivate::removeAllSubNodes(const InternalNodePointer &node)
|
||||||
{
|
{
|
||||||
for (const InternalNodePointer &subNode : node->allSubNodes())
|
for (const InternalNodePointer &subNode : node->allSubNodes())
|
||||||
removeNodeFromModel(subNode);
|
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)
|
void ModelPrivate::removeNode(const InternalNodePointer &node)
|
||||||
{
|
{
|
||||||
Q_ASSERT(node);
|
|
||||||
|
|
||||||
AbstractView::PropertyChangeFlags propertyChangeFlags = AbstractView::NoAdditionalChanges;
|
AbstractView::PropertyChangeFlags propertyChangeFlags = AbstractView::NoAdditionalChanges;
|
||||||
|
|
||||||
notifyNodeAboutToBeRemoved(node);
|
notifyNodeAboutToBeRemoved(node);
|
||||||
@@ -1088,6 +1121,15 @@ static QList<PropertyPair> toPropertyPairList(const QList<InternalPropertyPointe
|
|||||||
return propertyPairList;
|
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)
|
void ModelPrivate::removeProperty(const InternalPropertyPointer &property)
|
||||||
{
|
{
|
||||||
notifyPropertiesAboutToBeRemoved({property});
|
notifyPropertiesAboutToBeRemoved({property});
|
||||||
@@ -1408,13 +1450,19 @@ Model::Model(ProjectStorageType &projectStorage,
|
|||||||
const TypeName &typeName,
|
const TypeName &typeName,
|
||||||
int major,
|
int major,
|
||||||
int minor,
|
int minor,
|
||||||
Model *metaInfoProxyModel)
|
Model *metaInfoProxyModel,
|
||||||
|
std::unique_ptr<ModelResourceManagementInterface> resourceManagement)
|
||||||
: d(std::make_unique<Internal::ModelPrivate>(
|
: 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)
|
Model::Model(const TypeName &typeName,
|
||||||
: d(std::make_unique<Internal::ModelPrivate>(this, typeName, major, minor, metaInfoProxyModel))
|
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;
|
Model::~Model() = default;
|
||||||
@@ -2156,4 +2204,9 @@ void Model::detachView(AbstractView *view, ViewNotification emitDetachNotify)
|
|||||||
d->detachView(view, emitNotify);
|
d->detachView(view, emitNotify);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<ModelNode> Model::allModelNodes() const
|
||||||
|
{
|
||||||
|
return QmlDesigner::toModelNodeList(d->allNodes(), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
|||||||
@@ -101,8 +101,14 @@ public:
|
|||||||
const TypeName &type,
|
const TypeName &type,
|
||||||
int major,
|
int major,
|
||||||
int minor,
|
int minor,
|
||||||
Model *metaInfoProxyModel);
|
Model *metaInfoProxyModel,
|
||||||
ModelPrivate(Model *model, const TypeName &type, int major, int minor, 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;
|
~ModelPrivate() override;
|
||||||
|
|
||||||
@@ -120,6 +126,7 @@ public:
|
|||||||
bool isRootNode = false);
|
bool isRootNode = false);
|
||||||
|
|
||||||
/*factory methods for internal use in model and rewriter*/
|
/*factory methods for internal use in model and rewriter*/
|
||||||
|
void removeNodeAndRelatedResources(const InternalNodePointer &node);
|
||||||
void removeNode(const InternalNodePointer &node);
|
void removeNode(const InternalNodePointer &node);
|
||||||
void changeNodeId(const InternalNodePointer &node, const QString &id);
|
void changeNodeId(const InternalNodePointer &node, const QString &id);
|
||||||
void changeNodeType(const InternalNodePointer &node, const TypeName &typeName, int majorVersion, int minorVersion);
|
void changeNodeType(const InternalNodePointer &node, const TypeName &typeName, int majorVersion, int minorVersion);
|
||||||
@@ -235,6 +242,7 @@ public:
|
|||||||
//node state property manipulation
|
//node state property manipulation
|
||||||
void addProperty(const InternalNodePointer &node, const PropertyName &name);
|
void addProperty(const InternalNodePointer &node, const PropertyName &name);
|
||||||
void setPropertyValue(const InternalNodePointer &node,const PropertyName &name, const QVariant &value);
|
void setPropertyValue(const InternalNodePointer &node,const PropertyName &name, const QVariant &value);
|
||||||
|
void removePropertyAndRelatedResources(const InternalPropertyPointer &property);
|
||||||
void removeProperty(const InternalPropertyPointer &property);
|
void removeProperty(const InternalPropertyPointer &property);
|
||||||
|
|
||||||
void setBindingProperty(const InternalNodePointer &node, const PropertyName &name, const QString &expression);
|
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<ModelNode> toModelNodeVector(const QVector<InternalNodePointer> &nodeVector, AbstractView *view) const;
|
||||||
QVector<InternalNodePointer> toInternalNodeVector(const QVector<ModelNode> &modelNodeVector) const;
|
QVector<InternalNodePointer> toInternalNodeVector(const QVector<ModelNode> &modelNodeVector) const;
|
||||||
EnabledViewRange enabledViews() const;
|
EnabledViewRange enabledViews() const;
|
||||||
|
void handleResourceSet(const ModelResourceSet &resourceSet);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NotNullPointer<ProjectStorageType> projectStorage = nullptr;
|
NotNullPointer<ProjectStorageType> projectStorage = nullptr;
|
||||||
@@ -300,6 +309,7 @@ private:
|
|||||||
InternalNodePointer m_currentStateNode;
|
InternalNodePointer m_currentStateNode;
|
||||||
InternalNodePointer m_rootInternalNode;
|
InternalNodePointer m_rootInternalNode;
|
||||||
InternalNodePointer m_currentTimelineNode;
|
InternalNodePointer m_currentTimelineNode;
|
||||||
|
std::unique_ptr<ModelResourceManagementInterface> m_resourceManagement;
|
||||||
QUrl m_fileUrl;
|
QUrl m_fileUrl;
|
||||||
QPointer<RewriterView> m_rewriterView;
|
QPointer<RewriterView> m_rewriterView;
|
||||||
QPointer<NodeInstanceView> m_nodeInstanceView;
|
QPointer<NodeInstanceView> m_nodeInstanceView;
|
||||||
|
|||||||
@@ -290,7 +290,7 @@ A node might become invalid if e.g. it or one of its ancestors is deleted.
|
|||||||
*/
|
*/
|
||||||
bool ModelNode::isValid() const
|
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;
|
return;
|
||||||
|
|
||||||
if (m_internalNode->hasProperty(name))
|
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
|
/*! \brief removes this node from the node tree
|
||||||
@@ -692,7 +692,7 @@ void ModelNode::destroy()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
removeModelNodeFromSelection(*this);
|
removeModelNodeFromSelection(*this);
|
||||||
model()->d->removeNode(m_internalNode);
|
model()->d->removeNodeAndRelatedResources(m_internalNode);
|
||||||
}
|
}
|
||||||
//\}
|
//\}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -71,7 +71,7 @@ void NodeAbstractProperty::reparentHere(const ModelNode &modelNode, bool isNode
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isNodeAbstractProperty())
|
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isNodeAbstractProperty())
|
||||||
privateModel()->removeProperty(internalNode()->property(name()));
|
privateModel()->removePropertyAndRelatedResources(internalNode()->property(name()));
|
||||||
|
|
||||||
if (modelNode.hasParentProperty()) {
|
if (modelNode.hasParentProperty()) {
|
||||||
Internal::InternalNodeAbstractProperty::Pointer oldParentProperty = modelNode.internalNode()->parentProperty();
|
Internal::InternalNodeAbstractProperty::Pointer oldParentProperty = modelNode.internalNode()->parentProperty();
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ void NodeProperty::setModelNode(const ModelNode &modelNode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isNodeProperty())
|
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
|
privateModel()->reparentNode(internalNode(), name(), modelNode.internalNode(), false); //### we have to add a flag that this is not a list
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ void SignalHandlerProperty::setSource(const QString &source)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isSignalHandlerProperty())
|
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isSignalHandlerProperty())
|
||||||
privateModel()->removeProperty(internalNode()->property(name()));
|
privateModel()->removePropertyAndRelatedResources(internalNode()->property(name()));
|
||||||
|
|
||||||
privateModel()->setSignalHandlerProperty(internalNode(), name(), source);
|
privateModel()->setSignalHandlerProperty(internalNode(), name(), source);
|
||||||
}
|
}
|
||||||
@@ -118,7 +118,7 @@ void SignalDeclarationProperty::setSignature(const QString &signature)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isSignalDeclarationProperty())
|
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isSignalDeclarationProperty())
|
||||||
privateModel()->removeProperty(internalNode()->property(name()));
|
privateModel()->removePropertyAndRelatedResources(internalNode()->property(name()));
|
||||||
|
|
||||||
privateModel()->setSignalDeclarationProperty(internalNode(), name(), signature);
|
privateModel()->setSignalDeclarationProperty(internalNode(), name(), signature);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ void VariantProperty::setValue(const QVariant &value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isVariantProperty())
|
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isVariantProperty())
|
||||||
privateModel()->removeProperty(internalNode()->property(name()));
|
privateModel()->removePropertyAndRelatedResources(internalNode()->property(name()));
|
||||||
|
|
||||||
privateModel()->setVariantProperty(internalNode(), name(), value);
|
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())
|
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isVariantProperty())
|
||||||
privateModel()->removeProperty(internalNode()->property(name()));
|
privateModel()->removePropertyAndRelatedResources(internalNode()->property(name()));
|
||||||
|
|
||||||
privateModel()->setDynamicVariantProperty(internalNode(), name(), type, value);
|
privateModel()->setDynamicVariantProperty(internalNode(), name(), type, value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -242,36 +242,37 @@ public:
|
|||||||
return false;
|
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 id1,
|
||||||
TypeId id2,
|
TypeId id2,
|
||||||
TypeId id3,
|
TypeId id3,
|
||||||
@@ -280,7 +281,7 @@ public:
|
|||||||
TypeId id6,
|
TypeId id6,
|
||||||
TypeId id7) const override
|
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
|
TypeId fetchTypeIdByExportedName(Utils::SmallStringView name) const
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ public:
|
|||||||
propertyName(PropertyDeclarationId propertyDeclarationId) const = 0;
|
propertyName(PropertyDeclarationId propertyDeclarationId) const = 0;
|
||||||
virtual TypeIds prototypeAndSelfIds(TypeId type) const = 0;
|
virtual TypeIds prototypeAndSelfIds(TypeId type) const = 0;
|
||||||
virtual TypeIds prototypeIds(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) const = 0;
|
||||||
virtual bool isBasedOn(TypeId, TypeId, TypeId) const = 0;
|
virtual bool isBasedOn(TypeId, TypeId, TypeId) const = 0;
|
||||||
virtual bool isBasedOn(TypeId, TypeId, TypeId, TypeId) const = 0;
|
virtual bool isBasedOn(TypeId, TypeId, TypeId, TypeId) const = 0;
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ add_qtc_test(unittest GTEST
|
|||||||
gtest-std-printing.h
|
gtest-std-printing.h
|
||||||
lastchangedrowid-test.cpp
|
lastchangedrowid-test.cpp
|
||||||
import-test.cpp
|
import-test.cpp
|
||||||
|
model-test.cpp
|
||||||
|
modelresourcemanagementmock.h
|
||||||
matchingtext-test.cpp
|
matchingtext-test.cpp
|
||||||
mockfutureinterface.h
|
mockfutureinterface.h
|
||||||
mockmutex.h
|
mockmutex.h
|
||||||
@@ -66,6 +68,7 @@ add_qtc_test(unittest GTEST
|
|||||||
mocktimer.cpp mocktimer.h
|
mocktimer.cpp mocktimer.h
|
||||||
nodelistproperty-test.cpp
|
nodelistproperty-test.cpp
|
||||||
processevents-utilities.cpp processevents-utilities.h
|
processevents-utilities.cpp processevents-utilities.h
|
||||||
|
projectstoragemock.cpp projectstoragemock.h
|
||||||
sizedarray-test.cpp
|
sizedarray-test.cpp
|
||||||
smallstring-test.cpp
|
smallstring-test.cpp
|
||||||
spydummy.cpp spydummy.h
|
spydummy.cpp spydummy.h
|
||||||
@@ -258,6 +261,7 @@ extend_qtc_test(unittest
|
|||||||
model/model.cpp
|
model/model.cpp
|
||||||
model/model_p.h
|
model/model_p.h
|
||||||
model/modelnode.cpp
|
model/modelnode.cpp
|
||||||
|
model/modelresourcemanagementinterface.h
|
||||||
model/propertycontainer.cpp
|
model/propertycontainer.cpp
|
||||||
model/propertyparser.cpp
|
model/propertyparser.cpp
|
||||||
model/nodeabstractproperty.cpp
|
model/nodeabstractproperty.cpp
|
||||||
|
|||||||
@@ -73,19 +73,10 @@ class ListModelEditor : public testing::Test
|
|||||||
public:
|
public:
|
||||||
ListModelEditor()
|
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);
|
designerModel->attachView(&mockView);
|
||||||
|
|
||||||
emptyListModelNode = mockView.createModelNode("QtQml.Models.ListModel", 2, 15);
|
emptyListModelNode = mockView.createModelNode("QtQml.Models.ListModel", 2, 15);
|
||||||
|
|
||||||
setType(modelId_QtQuick, "ListView", "data");
|
|
||||||
listViewNode = mockView.createModelNode("QtQuick.ListView", 2, 15);
|
listViewNode = mockView.createModelNode("QtQuick.ListView", 2, 15);
|
||||||
listModelNode = mockView.createModelNode("QtQml.Models.ListModel", 2, 15);
|
listModelNode = mockView.createModelNode("QtQml.Models.ListModel", 2, 15);
|
||||||
mockView.rootModelNode().defaultNodeListProperty().reparentHere(listModelNode);
|
mockView.rootModelNode().defaultNodeListProperty().reparentHere(listModelNode);
|
||||||
@@ -108,29 +99,6 @@ public:
|
|||||||
ON_CALL(goIntoComponentMock, Call(_)).WillByDefault([](ModelNode node) { return node; });
|
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>;
|
using Entry = std::pair<QmlDesigner::PropertyName, QVariant>;
|
||||||
|
|
||||||
ModelNode createElement(std::initializer_list<Entry> entries, AbstractView &view, ModelNode listModel)
|
ModelNode createElement(std::initializer_list<Entry> entries, AbstractView &view, ModelNode listModel)
|
||||||
@@ -211,9 +179,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
NiceMock<ProjectStorageMock> projectStorageMock;
|
NiceMock<ProjectStorageMockWithQtQtuick> projectStorageMock;
|
||||||
NiceMock<MockFunction<ModelNode(const ModelNode &)>> goIntoComponentMock;
|
NiceMock<MockFunction<ModelNode(const ModelNode &)>> goIntoComponentMock;
|
||||||
QmlDesigner::ModelPointer designerModel;
|
QmlDesigner::ModelPointer designerModel{
|
||||||
|
QmlDesigner::Model::create(projectStorageMock, "QtQuick.Item", 1, 1)};
|
||||||
NiceMock<MockListModelEditorView> mockView;
|
NiceMock<MockListModelEditorView> mockView;
|
||||||
QmlDesigner::ListModelEditorModel model{
|
QmlDesigner::ListModelEditorModel model{
|
||||||
[&] { return mockView.createModelNode("QtQml.Models.ListModel", 2, 15); },
|
[&] { return mockView.createModelNode("QtQml.Models.ListModel", 2, 15); },
|
||||||
@@ -225,11 +194,10 @@ protected:
|
|||||||
ModelNode element1;
|
ModelNode element1;
|
||||||
ModelNode element2;
|
ModelNode element2;
|
||||||
ModelNode element3;
|
ModelNode element3;
|
||||||
QmlDesigner::ModelPointer componentModel;
|
QmlDesigner::ModelPointer componentModel{
|
||||||
|
QmlDesigner::Model::create(projectStorageMock, "QtQml.Models.ListModel", 1, 1)};
|
||||||
NiceMock<MockListModelEditorView> mockComponentView;
|
NiceMock<MockListModelEditorView> mockComponentView;
|
||||||
ModelNode componentElement;
|
ModelNode componentElement;
|
||||||
ModuleId modelId_QtQuick = ModuleId::create(1);
|
|
||||||
ModuleId modelId_QtQml_Models = ModuleId::create(2);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(ListModelEditor, CreatePropertyNameSet)
|
TEST_F(ListModelEditor, CreatePropertyNameSet)
|
||||||
|
|||||||
@@ -26,10 +26,25 @@ public:
|
|||||||
const QmlDesigner::NodeAbstractProperty &oldPropertyParent,
|
const QmlDesigner::NodeAbstractProperty &oldPropertyParent,
|
||||||
AbstractView::PropertyChangeFlags propertyChange),
|
AbstractView::PropertyChangeFlags propertyChange),
|
||||||
(override));
|
(override));
|
||||||
|
|
||||||
MOCK_METHOD(void,
|
MOCK_METHOD(void,
|
||||||
propertiesRemoved,
|
propertiesRemoved,
|
||||||
(const QList<QmlDesigner::AbstractProperty> &propertyList),
|
(const QList<QmlDesigner::AbstractProperty> &propertyList),
|
||||||
(override));
|
(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,
|
MOCK_METHOD(void,
|
||||||
nodeRemoved,
|
nodeRemoved,
|
||||||
@@ -37,4 +52,5 @@ public:
|
|||||||
const QmlDesigner::NodeAbstractProperty &parentProperty,
|
const QmlDesigner::NodeAbstractProperty &parentProperty,
|
||||||
AbstractView::PropertyChangeFlags propertyChange),
|
AbstractView::PropertyChangeFlags propertyChange),
|
||||||
(override));
|
(override));
|
||||||
|
MOCK_METHOD(void, nodeAboutToBeRemoved, (const QmlDesigner::ModelNode &removedNode), (override));
|
||||||
};
|
};
|
||||||
|
|||||||
491
tests/unit/unittest/model-test.cpp
Normal file
491
tests/unit/unittest/model-test.cpp
Normal 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
|
||||||
42
tests/unit/unittest/modelresourcemanagementmock.h
Normal file
42
tests/unit/unittest/modelresourcemanagementmock.h
Normal 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;
|
||||||
|
};
|
||||||
@@ -25,11 +25,6 @@ protected:
|
|||||||
using iterator = QmlDesigner::NodeListProperty::iterator;
|
using iterator = QmlDesigner::NodeListProperty::iterator;
|
||||||
NodeListProperty()
|
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);
|
model->attachView(&abstractViewMock);
|
||||||
nodeListProperty = abstractViewMock.rootModelNode().nodeListProperty("foo");
|
nodeListProperty = abstractViewMock.rootModelNode().nodeListProperty("foo");
|
||||||
|
|
||||||
@@ -82,8 +77,9 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
NiceMock<ProjectStorageMock> projectStorageMock;
|
NiceMock<ProjectStorageMockWithQtQtuick> projectStorageMock;
|
||||||
std::unique_ptr<QmlDesigner::Model> model;
|
std::unique_ptr<QmlDesigner::Model> model{
|
||||||
|
std::make_unique<QmlDesigner::Model>(projectStorageMock, "QtQuick.Item")};
|
||||||
NiceMock<AbstractViewMock> abstractViewMock;
|
NiceMock<AbstractViewMock> abstractViewMock;
|
||||||
QmlDesigner::NodeListProperty nodeListProperty;
|
QmlDesigner::NodeListProperty nodeListProperty;
|
||||||
ModelNode node1;
|
ModelNode node1;
|
||||||
|
|||||||
89
tests/unit/unittest/projectstoragemock.cpp
Normal file
89
tests/unit/unittest/projectstoragemock.cpp
Normal 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);
|
||||||
|
}
|
||||||
@@ -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
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -14,6 +14,8 @@
|
|||||||
class ProjectStorageMock : public QmlDesigner::ProjectStorageInterface
|
class ProjectStorageMock : public QmlDesigner::ProjectStorageInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
void setupQtQtuick();
|
||||||
|
|
||||||
MOCK_METHOD(void,
|
MOCK_METHOD(void,
|
||||||
synchronize,
|
synchronize,
|
||||||
(QmlDesigner::Storage::Synchronization::SynchronizationPackage package),
|
(QmlDesigner::Storage::Synchronization::SynchronizationPackage package),
|
||||||
@@ -63,7 +65,6 @@ public:
|
|||||||
(const, override));
|
(const, override));
|
||||||
MOCK_METHOD(QmlDesigner::TypeIds, prototypeAndSelfIds, (QmlDesigner::TypeId type), (const, override));
|
MOCK_METHOD(QmlDesigner::TypeIds, prototypeAndSelfIds, (QmlDesigner::TypeId type), (const, override));
|
||||||
MOCK_METHOD(QmlDesigner::TypeIds, prototypeIds, (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, (QmlDesigner::TypeId typeId, QmlDesigner::TypeId), (const, override));
|
||||||
MOCK_METHOD(bool,
|
MOCK_METHOD(bool,
|
||||||
isBasedOn,
|
isBasedOn,
|
||||||
@@ -158,3 +159,8 @@ public:
|
|||||||
MOCK_METHOD(std::vector<QmlDesigner::Cache::Source>, fetchAllSources, (), ());
|
MOCK_METHOD(std::vector<QmlDesigner::Cache::Source>, fetchAllSources, (), ());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ProjectStorageMockWithQtQtuick : public ProjectStorageMock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ProjectStorageMockWithQtQtuick() { setupQtQtuick(); }
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user