summaryrefslogtreecommitdiffstats
path: root/src/core/nodes
diff options
context:
space:
mode:
authorPaul Lemire <paul.lemire@kdab.com>2019-04-25 15:27:11 +0200
committerPaul Lemire <paul.lemire@kdab.com>2019-04-26 07:14:12 +0200
commit06f41f15abaacc9f6f7acb8e51d2cfb68705a924 (patch)
tree210403f4bb9872940f8db4ab656238e9f14e1b98 /src/core/nodes
parent9b140ccba930f159443a70a81eb1d2585b6070f9 (diff)
parentfed848f7dcff99cf5adb3b7b45190826b3dcf898 (diff)
Merge remote-tracking branch 5.12 into 5.13
Diffstat (limited to 'src/core/nodes')
-rw-r--r--src/core/nodes/qentity.cpp15
-rw-r--r--src/core/nodes/qentity.h3
-rw-r--r--src/core/nodes/qnode.cpp79
-rw-r--r--src/core/nodes/qnode_p.h18
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