forked from qt-creator/qt-creator
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:
@@ -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{};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -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,
|
||||||
|
@@ -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;
|
||||||
|
@@ -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,
|
||||||
|
@@ -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);
|
||||||
|
|
||||||
|
@@ -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()};
|
||||||
|
@@ -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));
|
||||||
};
|
};
|
||||||
|
@@ -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
|
||||||
|
Reference in New Issue
Block a user