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
|
||||
{
|
||||
friend class QMLDESIGNERCORE_EXPORT NodeListProperty;
|
||||
|
||||
public:
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
using difference_type = int;
|
||||
@@ -49,6 +51,7 @@ public:
|
||||
using pointer = InternalNodeListPropertyPointer;
|
||||
using reference = ModelNode;
|
||||
|
||||
NodeListPropertyIterator() = default;
|
||||
NodeListPropertyIterator(int currentIndex,
|
||||
class InternalNodeListProperty *nodeListProperty,
|
||||
Model *model,
|
||||
@@ -191,6 +194,19 @@ public:
|
||||
void swap(int, int) const;
|
||||
void reparentHere(const ModelNode &modelNode);
|
||||
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);
|
||||
|
||||
@@ -202,6 +218,13 @@ public:
|
||||
|
||||
protected:
|
||||
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,
|
||||
const ModelNode &movedNode,
|
||||
int /*oldIndex*/) override;
|
||||
void nodeOrderChanged(const NodeListProperty &listProperty) 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 customNotification(const AbstractView *view, const QString &identifier,
|
||||
|
@@ -72,6 +72,9 @@ public:
|
||||
const QList<InternalNodePointer> &nodeList() const;
|
||||
void slide(int from, int to);
|
||||
|
||||
QList<InternalNodePointer>::iterator begin() { return m_nodeList.begin(); }
|
||||
QList<InternalNodePointer>::iterator end() { return m_nodeList.end(); }
|
||||
|
||||
protected:
|
||||
InternalNodeListProperty(const PropertyName &name, const InternalNodePointer &propertyOwner);
|
||||
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)
|
||||
{
|
||||
QList<InternalNodePointer> sortedSelectedList = Utils::filtered(selectedNodeList,
|
||||
|
@@ -159,6 +159,7 @@ public:
|
||||
void notifyNodeOrderChanged(const InternalNodeListPropertyPointer &internalListProperty,
|
||||
const InternalNodePointer &node,
|
||||
int oldIndex);
|
||||
void notifyNodeOrderChanged(const InternalNodeListPropertyPointer &internalListProperty);
|
||||
void notifyAuxiliaryDataChanged(const InternalNodePointer &node, const PropertyName &name, const QVariant &data);
|
||||
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)
|
||||
{
|
||||
QList<ModelNode> modelNodeList;
|
||||
@@ -73,11 +87,10 @@ QList<ModelNode> NodeListProperty::toModelNodeList() const
|
||||
if (!isValid())
|
||||
throw InvalidPropertyException(__LINE__, __FUNCTION__, __FILE__, "<invalid node list property>");
|
||||
|
||||
if (internalNode()->hasProperty(name())) {
|
||||
Internal::InternalProperty::Pointer internalProperty = internalNode()->property(name());
|
||||
if (internalProperty->isNodeListProperty())
|
||||
return internalNodesToModelNodes(internalProperty->toNodeListProperty()->nodeList(), model(), view());
|
||||
}
|
||||
if (internalNodeListProperty())
|
||||
return internalNodesToModelNodes(m_internalNodeListProperty->toNodeListProperty()->nodeList(),
|
||||
model(),
|
||||
view());
|
||||
|
||||
return QList<ModelNode>();
|
||||
}
|
||||
@@ -134,14 +147,51 @@ ModelNode NodeListProperty::at(int index) const
|
||||
if (!isValid())
|
||||
throw InvalidPropertyException(__LINE__, __FUNCTION__, __FILE__, "<invalid node list property>");
|
||||
|
||||
Internal::InternalNodeListProperty::Pointer internalProperty = internalNode()->nodeListProperty(name());
|
||||
if (internalProperty)
|
||||
return ModelNode(internalProperty->at(index), model(), view());
|
||||
|
||||
if (internalNodeListProperty())
|
||||
return ModelNode(m_internalNodeListProperty->at(index), model(), view());
|
||||
|
||||
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)
|
||||
{
|
||||
ModelNode firstNode = nodes.first();
|
||||
@@ -174,12 +224,12 @@ Internal::NodeListPropertyIterator NodeListProperty::end()
|
||||
|
||||
Internal::NodeListPropertyIterator NodeListProperty::begin() const
|
||||
{
|
||||
return {0, internalNode()->nodeListProperty(name()).data(), model(), view()};
|
||||
return {0, internalNodeListProperty().data(), model(), view()};
|
||||
}
|
||||
|
||||
Internal::NodeListPropertyIterator NodeListProperty::end() const
|
||||
{
|
||||
auto nodeListProperty = internalNode()->nodeListProperty(name());
|
||||
auto nodeListProperty = internalNodeListProperty();
|
||||
auto size = nodeListProperty ? nodeListProperty->size() : 0;
|
||||
|
||||
return {size, nodeListProperty.data(), model(), view()};
|
||||
|
@@ -32,4 +32,5 @@
|
||||
class AbstractViewMock : public QmlDesigner::AbstractView
|
||||
{
|
||||
public:
|
||||
MOCK_METHOD(void, nodeOrderChanged, (const QmlDesigner::NodeListProperty &listProperty), (override));
|
||||
};
|
||||
|
@@ -70,7 +70,7 @@ protected:
|
||||
|
||||
protected:
|
||||
std::unique_ptr<QmlDesigner::Model> model{QmlDesigner::Model::create("QtQuick.Item")};
|
||||
AbstractViewMock abstractViewMock;
|
||||
NiceMock<AbstractViewMock> abstractViewMock;
|
||||
QmlDesigner::NodeListProperty nodeListProperty;
|
||||
ModelNode node1;
|
||||
ModelNode node2;
|
||||
@@ -436,4 +436,85 @@ TEST_F(NodeListProperty, DereferenceIterator)
|
||||
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
|
||||
|
Reference in New Issue
Block a user