diff options
author | Paul Lemire <paul.lemire@kdab.com> | 2019-04-25 15:27:11 +0200 |
---|---|---|
committer | Paul Lemire <paul.lemire@kdab.com> | 2019-04-26 07:14:12 +0200 |
commit | 06f41f15abaacc9f6f7acb8e51d2cfb68705a924 (patch) | |
tree | 210403f4bb9872940f8db4ab656238e9f14e1b98 /src/core/nodes | |
parent | 9b140ccba930f159443a70a81eb1d2585b6070f9 (diff) | |
parent | fed848f7dcff99cf5adb3b7b45190826b3dcf898 (diff) |
Merge remote-tracking branch 5.12 into 5.13
Change-Id: I42affdd02bddb5205b9f2455f0c5e5efbd414dd8
Diffstat (limited to 'src/core/nodes')
-rw-r--r-- | src/core/nodes/qentity.cpp | 15 | ||||
-rw-r--r-- | src/core/nodes/qentity.h | 3 | ||||
-rw-r--r-- | src/core/nodes/qnode.cpp | 79 | ||||
-rw-r--r-- | src/core/nodes/qnode_p.h | 18 |
4 files changed, 113 insertions, 2 deletions
diff --git a/src/core/nodes/qentity.cpp b/src/core/nodes/qentity.cpp index 69d774dd1..164e0feff 100644 --- a/src/core/nodes/qentity.cpp +++ b/src/core/nodes/qentity.cpp @@ -239,6 +239,10 @@ QNodeId QEntityPrivate::parentEntityId() const QNodeCreatedChangeBasePtr QEntity::createNodeCreationChange() const { + // connect to the parentChanged signal here rather than constructor because + // until now there's no backend node to notify when parent changes + connect(this, &QNode::parentChanged, this, &QEntity::onParentChanged); + auto creationChange = QNodeCreatedChangePtr<QEntityData>::create(this); auto &data = creationChange->data; @@ -268,6 +272,17 @@ QNodeCreatedChangeBasePtr QEntity::createNodeCreationChange() const return creationChange; } +void QEntity::onParentChanged(QObject *) +{ + const auto parentID = parentEntity() ? parentEntity()->id() : Qt3DCore::QNodeId(); + auto parentChange = Qt3DCore::QPropertyUpdatedChangePtr::create(id()); + parentChange->setPropertyName("parentEntityUpdated"); + parentChange->setValue(QVariant::fromValue(parentID)); + const bool blocked = blockNotifications(false); + notifyObservers(parentChange); + blockNotifications(blocked); +} + } // namespace Qt3DCore QT_END_NAMESPACE diff --git a/src/core/nodes/qentity.h b/src/core/nodes/qentity.h index bbf38efb4..f1a369c48 100644 --- a/src/core/nodes/qentity.h +++ b/src/core/nodes/qentity.h @@ -83,6 +83,9 @@ public: protected: explicit QEntity(QEntityPrivate &dd, QNode *parent = nullptr); +private Q_SLOTS: + void onParentChanged(QObject *); + private: Q_DECLARE_PRIVATE(QEntity) diff --git a/src/core/nodes/qnode.cpp b/src/core/nodes/qnode.cpp index c2373b805..900c3f8ce 100644 --- a/src/core/nodes/qnode.cpp +++ b/src/core/nodes/qnode.cpp @@ -101,7 +101,7 @@ void QNodePrivate::init(QNode *parent) Q_Q(QNode); if (m_scene) { // schedule the backend notification and scene registering -> set observers through scene - QMetaObject::invokeMethod(q, "_q_postConstructorInit", Qt::QueuedConnection); + m_scene->postConstructorInit()->addNode(q); } } @@ -165,7 +165,7 @@ void QNodePrivate::notifyDestructionChangesAndRemoveFromScene() * * Sends a QNodeCreatedChange event to the aspects and then also notifies the * parent backend node of its new child. This is called in a deferred manner - * by the QNodePrivate::init() method to notify the backend of newly created + * by NodePostConstructorInit::processNodes to notify the backend of newly created * nodes with a parent that is already part of the scene. * * Also notify the scene of this node, so it may set it's change arbiter. @@ -873,6 +873,12 @@ void QNode::setParent(QNode *parent) if (parentNode() == parent && ((parent != nullptr && d->m_parentId == parentNode()->id()) || parent == nullptr)) return; + + // remove ourself from postConstructorInit queue. The call to _q_setParentHelper + // will take care of creating the backend node if necessary depending on new parent. + if (d->m_scene) + d->m_scene->postConstructorInit()->removeNode(this); + d->_q_setParentHelper(parent); // Block notifications as we want to let the _q_setParentHelper @@ -1132,6 +1138,75 @@ const QMetaObject *QNodePrivate::findStaticMetaObject(const QMetaObject *metaObj return lastStaticMetaobject; } +/*! + * \internal + * + * NodePostConstructorInit handles calling QNode::_q_postConstructorInit for + * all nodes. By keeping track of nodes that need initialization we can + * create them all together ensuring they get sent to the backend in a single + * batch. + */ +NodePostConstructorInit::NodePostConstructorInit(QObject *parent) + : QObject(parent) + , m_requestedProcessing(false) +{ +} + +NodePostConstructorInit::~NodePostConstructorInit() {} + +/*! + * \internal + * + * Add a node to the list of nodes needing a call to _q_postConstructorInit + * We only add the node if it does not have an ancestor already in the queue + * because initializing the ancestor will initialize all it's children. + * This ensures that all backend nodes are created from the top-down, with + * all parents created before their children + * + */ +void NodePostConstructorInit::addNode(QNode *node) +{ + Q_ASSERT(node); + QNode *nextNode = node; + while (nextNode != nullptr && !m_nodesToConstruct.contains(QNodePrivate::get(nextNode))) + nextNode = nextNode->parentNode(); + + if (!nextNode) { + m_nodesToConstruct.append(QNodePrivate::get(node)); + if (!m_requestedProcessing){ + QMetaObject::invokeMethod(this, "processNodes", Qt::QueuedConnection); + m_requestedProcessing = true; + } + } +} + +/*! + * \internal + * + * Remove a node from the queue. This will ensure none of its + * children get initialized + */ +void NodePostConstructorInit::removeNode(QNode *node) +{ + Q_ASSERT(node); + m_nodesToConstruct.removeAll(QNodePrivate::get(node)); +} + +/*! + * \internal + * + * call _q_postConstructorInit for all nodes in the queue + * and clear the queue + */ +void NodePostConstructorInit::processNodes() +{ + m_requestedProcessing = false; + while (!m_nodesToConstruct.empty()) { + auto node = m_nodesToConstruct.takeFirst(); + node->_q_postConstructorInit(); + } +} + } // namespace Qt3DCore QT_END_NAMESPACE diff --git a/src/core/nodes/qnode_p.h b/src/core/nodes/qnode_p.h index fd3265870..506708762 100644 --- a/src/core/nodes/qnode_p.h +++ b/src/core/nodes/qnode_p.h @@ -60,6 +60,7 @@ #include <Qt3DCore/private/qobservableinterface_p.h> #include <Qt3DCore/private/qt3dcore_global_p.h> #include <QtCore/private/qobject_p.h> +#include <QQueue> QT_BEGIN_NAMESPACE @@ -174,6 +175,23 @@ private: QHash<QNode *, QMetaObject::Connection> m_destructionConnections; }; +class NodePostConstructorInit : public QObject +{ + Q_OBJECT +public: + NodePostConstructorInit(QObject *parent = nullptr); + virtual ~NodePostConstructorInit(); + void removeNode(QNode *node); + void addNode(QNode *node); + +private Q_SLOTS: + void processNodes(); + +private: + QQueue<QNodePrivate *> m_nodesToConstruct; + bool m_requestedProcessing; +}; + } // namespace Qt3DCore QT_END_NAMESPACE |