QmlDesigner: Add some useful iterator algorithms to NodeListProperty

Now there is iter_swap, rotate and reverse in the node list property. With
that methods we can implement slide too.

Task-number: QDS-4159
Change-Id: Ie7f80f64fd26e517ca696158a878262928dc82c4
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Marco Bubke
2021-04-15 15:10:18 +02:00
parent 2bf45ec998
commit 5203c478a5
8 changed files with 181 additions and 13 deletions

View File

@@ -42,6 +42,8 @@ using InternalNodeListPropertyPointer = QSharedPointer<InternalNodeListProperty>
class NodeListPropertyIterator class NodeListPropertyIterator
{ {
friend class QMLDESIGNERCORE_EXPORT NodeListProperty;
public: public:
using iterator_category = std::random_access_iterator_tag; using iterator_category = std::random_access_iterator_tag;
using difference_type = int; using difference_type = int;
@@ -49,6 +51,7 @@ public:
using pointer = InternalNodeListPropertyPointer; using pointer = InternalNodeListPropertyPointer;
using reference = ModelNode; using reference = ModelNode;
NodeListPropertyIterator() = default;
NodeListPropertyIterator(int currentIndex, NodeListPropertyIterator(int currentIndex,
class InternalNodeListProperty *nodeListProperty, class InternalNodeListProperty *nodeListProperty,
Model *model, Model *model,
@@ -191,6 +194,19 @@ public:
void swap(int, int) const; void swap(int, int) const;
void reparentHere(const ModelNode &modelNode); void reparentHere(const ModelNode &modelNode);
ModelNode at(int index) const; ModelNode at(int index) const;
void iterSwap(iterator &first, iterator &second);
iterator rotate(iterator first, iterator newFirst, iterator last);
template<typename Range>
iterator rotate(Range &range, iterator newFirst)
{
return rotate(range.begin(), newFirst, range.end());
}
void reverse(iterator first, iterator last);
template<typename Range>
void reverse(Range &range)
{
reverse(range.begin(), range.end());
}
static void reverseModelNodes(const QList<ModelNode> &nodes); static void reverseModelNodes(const QList<ModelNode> &nodes);
@@ -202,6 +218,13 @@ public:
protected: protected:
NodeListProperty(const PropertyName &propertyName, const Internal::InternalNodePointer &internalNode, Model* model, AbstractView *view); NodeListProperty(const PropertyName &propertyName, const Internal::InternalNodePointer &internalNode, Model* model, AbstractView *view);
NodeListProperty(const Internal::InternalNodeListPropertyPointer &internalNodeListProperty, Model* model, AbstractView *view); NodeListProperty(const Internal::InternalNodeListPropertyPointer &internalNodeListProperty,
Model *model,
AbstractView *view);
Internal::InternalNodeListPropertyPointer &internalNodeListProperty() const;
private:
mutable Internal::InternalNodeListPropertyPointer m_internalNodeListProperty{};
}; };
} }

View File

@@ -94,6 +94,7 @@ public:
void nodeOrderChanged(const NodeListProperty &listProperty, void nodeOrderChanged(const NodeListProperty &listProperty,
const ModelNode &movedNode, const ModelNode &movedNode,
int /*oldIndex*/) override; int /*oldIndex*/) override;
void nodeOrderChanged(const NodeListProperty &listProperty) override;
void rootNodeTypeChanged(const QString &type, int majorVersion, int minorVersion) override; void rootNodeTypeChanged(const QString &type, int majorVersion, int minorVersion) override;
void nodeTypeChanged(const ModelNode& node, const TypeName &type, int majorVersion, int minorVersion) override; void nodeTypeChanged(const ModelNode& node, const TypeName &type, int majorVersion, int minorVersion) override;
void customNotification(const AbstractView *view, const QString &identifier, void customNotification(const AbstractView *view, const QString &identifier,

View File

@@ -72,6 +72,9 @@ public:
const QList<InternalNodePointer> &nodeList() const; const QList<InternalNodePointer> &nodeList() const;
void slide(int from, int to); void slide(int from, int to);
QList<InternalNodePointer>::iterator begin() { return m_nodeList.begin(); }
QList<InternalNodePointer>::iterator end() { return m_nodeList.end(); }
protected: protected:
InternalNodeListProperty(const PropertyName &name, const InternalNodePointer &propertyOwner); InternalNodeListProperty(const PropertyName &name, const InternalNodePointer &propertyOwner);
void add(const InternalNodePointer &node) override; void add(const InternalNodePointer &node) override;

View File

@@ -889,6 +889,14 @@ void ModelPrivate::notifyNodeOrderChanged(const InternalNodeListPropertyPointer
}); });
} }
void ModelPrivate::notifyNodeOrderChanged(const InternalNodeListPropertyPointer &internalListProperty)
{
notifyNodeInstanceViewLast([&](AbstractView *view) {
NodeListProperty nodeListProperty(internalListProperty, m_model, view);
view->nodeOrderChanged(nodeListProperty);
});
}
void ModelPrivate::setSelectedNodes(const QList<InternalNodePointer> &selectedNodeList) void ModelPrivate::setSelectedNodes(const QList<InternalNodePointer> &selectedNodeList)
{ {
QList<InternalNodePointer> sortedSelectedList = Utils::filtered(selectedNodeList, QList<InternalNodePointer> sortedSelectedList = Utils::filtered(selectedNodeList,

View File

@@ -159,6 +159,7 @@ public:
void notifyNodeOrderChanged(const InternalNodeListPropertyPointer &internalListProperty, void notifyNodeOrderChanged(const InternalNodeListPropertyPointer &internalListProperty,
const InternalNodePointer &node, const InternalNodePointer &node,
int oldIndex); int oldIndex);
void notifyNodeOrderChanged(const InternalNodeListPropertyPointer &internalListProperty);
void notifyAuxiliaryDataChanged(const InternalNodePointer &node, const PropertyName &name, const QVariant &data); void notifyAuxiliaryDataChanged(const InternalNodePointer &node, const PropertyName &name, const QVariant &data);
void notifyNodeSourceChanged(const InternalNodePointer &node, const QString &newNodeSource); void notifyNodeSourceChanged(const InternalNodePointer &node, const QString &newNodeSource);

View File

@@ -59,6 +59,20 @@ NodeListProperty::NodeListProperty(const Internal::InternalNodeListProperty::Poi
{ {
} }
Internal::InternalNodeListPropertyPointer &NodeListProperty::internalNodeListProperty() const
{
if (m_internalNodeListProperty)
return m_internalNodeListProperty;
if (internalNode()->hasProperty(name())) {
Internal::InternalProperty::Pointer internalProperty = internalNode()->property(name());
if (internalProperty->isNodeListProperty())
m_internalNodeListProperty = internalProperty->toNodeListProperty();
}
return m_internalNodeListProperty;
}
static QList<ModelNode> internalNodesToModelNodes(const QList<Internal::InternalNode::Pointer> &inputList, Model* model, AbstractView *view) static QList<ModelNode> internalNodesToModelNodes(const QList<Internal::InternalNode::Pointer> &inputList, Model* model, AbstractView *view)
{ {
QList<ModelNode> modelNodeList; QList<ModelNode> modelNodeList;
@@ -73,11 +87,10 @@ QList<ModelNode> NodeListProperty::toModelNodeList() const
if (!isValid()) if (!isValid())
throw InvalidPropertyException(__LINE__, __FUNCTION__, __FILE__, "<invalid node list property>"); throw InvalidPropertyException(__LINE__, __FUNCTION__, __FILE__, "<invalid node list property>");
if (internalNode()->hasProperty(name())) { if (internalNodeListProperty())
Internal::InternalProperty::Pointer internalProperty = internalNode()->property(name()); return internalNodesToModelNodes(m_internalNodeListProperty->toNodeListProperty()->nodeList(),
if (internalProperty->isNodeListProperty()) model(),
return internalNodesToModelNodes(internalProperty->toNodeListProperty()->nodeList(), model(), view()); view());
}
return QList<ModelNode>(); return QList<ModelNode>();
} }
@@ -134,14 +147,51 @@ ModelNode NodeListProperty::at(int index) const
if (!isValid()) if (!isValid())
throw InvalidPropertyException(__LINE__, __FUNCTION__, __FILE__, "<invalid node list property>"); throw InvalidPropertyException(__LINE__, __FUNCTION__, __FILE__, "<invalid node list property>");
Internal::InternalNodeListProperty::Pointer internalProperty = internalNode()->nodeListProperty(name()); if (internalNodeListProperty())
if (internalProperty) return ModelNode(m_internalNodeListProperty->at(index), model(), view());
return ModelNode(internalProperty->at(index), model(), view());
return ModelNode(); return ModelNode();
} }
void NodeListProperty::iterSwap(NodeListProperty::iterator &first, NodeListProperty::iterator &second)
{
if (!internalNodeListProperty())
return;
std::swap(m_internalNodeListProperty->at(first.m_currentIndex),
m_internalNodeListProperty->at(second.m_currentIndex));
}
NodeListProperty::iterator NodeListProperty::rotate(NodeListProperty::iterator first,
NodeListProperty::iterator newFirst,
NodeListProperty::iterator last)
{
if (!internalNodeListProperty())
return {};
auto begin = m_internalNodeListProperty->begin();
auto iter = std::rotate(std::next(begin, first.m_currentIndex),
std::next(begin, newFirst.m_currentIndex),
std::next(begin, last.m_currentIndex));
privateModel()->notifyNodeOrderChanged(m_internalNodeListProperty);
return {iter - begin, internalNodeListProperty().data(), model(), view()};
}
void NodeListProperty::reverse(NodeListProperty::iterator first, NodeListProperty::iterator last)
{
if (!internalNodeListProperty())
return;
auto begin = m_internalNodeListProperty->begin();
std::reverse(std::next(begin, first.m_currentIndex), std::next(begin, last.m_currentIndex));
privateModel()->notifyNodeOrderChanged(m_internalNodeListProperty);
}
void NodeListProperty::reverseModelNodes(const QList<ModelNode> &nodes) void NodeListProperty::reverseModelNodes(const QList<ModelNode> &nodes)
{ {
ModelNode firstNode = nodes.first(); ModelNode firstNode = nodes.first();
@@ -174,12 +224,12 @@ Internal::NodeListPropertyIterator NodeListProperty::end()
Internal::NodeListPropertyIterator NodeListProperty::begin() const Internal::NodeListPropertyIterator NodeListProperty::begin() const
{ {
return {0, internalNode()->nodeListProperty(name()).data(), model(), view()}; return {0, internalNodeListProperty().data(), model(), view()};
} }
Internal::NodeListPropertyIterator NodeListProperty::end() const Internal::NodeListPropertyIterator NodeListProperty::end() const
{ {
auto nodeListProperty = internalNode()->nodeListProperty(name()); auto nodeListProperty = internalNodeListProperty();
auto size = nodeListProperty ? nodeListProperty->size() : 0; auto size = nodeListProperty ? nodeListProperty->size() : 0;
return {size, nodeListProperty.data(), model(), view()}; return {size, nodeListProperty.data(), model(), view()};

View File

@@ -32,4 +32,5 @@
class AbstractViewMock : public QmlDesigner::AbstractView class AbstractViewMock : public QmlDesigner::AbstractView
{ {
public: public:
MOCK_METHOD(void, nodeOrderChanged, (const QmlDesigner::NodeListProperty &listProperty), (override));
}; };

View File

@@ -70,7 +70,7 @@ protected:
protected: protected:
std::unique_ptr<QmlDesigner::Model> model{QmlDesigner::Model::create("QtQuick.Item")}; std::unique_ptr<QmlDesigner::Model> model{QmlDesigner::Model::create("QtQuick.Item")};
AbstractViewMock abstractViewMock; NiceMock<AbstractViewMock> abstractViewMock;
QmlDesigner::NodeListProperty nodeListProperty; QmlDesigner::NodeListProperty nodeListProperty;
ModelNode node1; ModelNode node1;
ModelNode node2; ModelNode node2;
@@ -436,4 +436,85 @@ TEST_F(NodeListProperty, DereferenceIterator)
ASSERT_THAT(node, Eq(node2)); ASSERT_THAT(node, Eq(node2));
} }
TEST_F(NodeListProperty, IterSwap)
{
auto first = std::next(nodeListProperty.begin(), 2);
auto second = nodeListProperty.begin();
nodeListProperty.iterSwap(first, second);
ASSERT_THAT(nodes(), ElementsAre(node3, node2, node1, node4, node5));
}
TEST_F(NodeListProperty, Rotate)
{
auto first = std::next(nodeListProperty.begin());
auto newFirst = std::next(nodeListProperty.begin(), 2);
auto last = std::prev(nodeListProperty.end());
nodeListProperty.rotate(first, newFirst, last);
ASSERT_THAT(nodes(), ElementsAre(node1, node3, node4, node2, node5));
}
TEST_F(NodeListProperty, RotateCallsNodeOrderedChanged)
{
auto first = std::next(nodeListProperty.begin());
auto newFirst = std::next(nodeListProperty.begin(), 2);
auto last = std::prev(nodeListProperty.end());
EXPECT_CALL(abstractViewMock, nodeOrderChanged(ElementsAre(node1, node3, node4, node2, node5)));
nodeListProperty.rotate(first, newFirst, last);
}
TEST_F(NodeListProperty, RotateRange)
{
auto newFirst = std::prev(nodeListProperty.end(), 2);
nodeListProperty.rotate(nodeListProperty, newFirst);
ASSERT_THAT(nodes(), ElementsAre(node4, node5, node1, node2, node3));
}
TEST_F(NodeListProperty, RotateReturnsIterator)
{
auto first = std::next(nodeListProperty.begin());
auto newFirst = std::next(nodeListProperty.begin(), 2);
auto last = std::prev(nodeListProperty.end());
auto iterator = nodeListProperty.rotate(first, newFirst, last);
ASSERT_THAT(iterator, Eq(first + (last - newFirst)));
}
TEST_F(NodeListProperty, RotateRangeReturnsIterator)
{
auto newFirst = std::prev(nodeListProperty.end(), 2);
auto iterator = nodeListProperty.rotate(nodeListProperty, newFirst);
ASSERT_THAT(iterator, Eq(nodeListProperty.begin() + (nodeListProperty.end() - newFirst)));
}
TEST_F(NodeListProperty, Reverse)
{
auto first = std::next(nodeListProperty.begin());
auto last = std::prev(nodeListProperty.end());
nodeListProperty.reverse(first, last);
ASSERT_THAT(nodes(), ElementsAre(node1, node4, node3, node2, node5));
}
TEST_F(NodeListProperty, ReverseCallsNodeOrderedChanged)
{
auto first = std::next(nodeListProperty.begin());
auto last = std::prev(nodeListProperty.end());
EXPECT_CALL(abstractViewMock, nodeOrderChanged(ElementsAre(node1, node4, node3, node2, node5)));
nodeListProperty.reverse(first, last);
}
} // namespace } // namespace