summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSvenn-Arne Dragly <s@dragly.com>2019-02-22 13:50:30 +0100
committerJani Heikkinen <jani.heikkinen@qt.io>2019-02-22 15:00:31 +0000
commit3de900a10c6fd051ba54727be2fd1fe47ed10481 (patch)
treede030e365dec53d02d6707601078dd9fc48ef773
parent799bb8615c86b7713351851c6013821b523f8aa2 (diff)
Make sure backend node is created when component is added to Entityv5.12.2
In addition, the parent of the component and all further ancestors need to be registered on the backend. We do this by calling QNodePrivate::_q_postConstructorInit on all these nodes. Also add autotest that triggers the case referenced in QTBUG-72236 to avoid regressions. Change-Id: Ibf8f43654d145ea8b8082b2f30123ea65e42ff55 Fixes: QTBUG-72236 Reviewed-by: Paul Lemire <paul.lemire@kdab.com> Reviewed-by: James Turner <james.turner@kdab.com>
-rw-r--r--src/core/nodes/qentity.cpp2
-rw-r--r--src/core/nodes/qnode.cpp23
-rw-r--r--src/core/nodes/qnode_p.h1
-rw-r--r--tests/auto/core/nodes/tst_nodes.cpp84
4 files changed, 110 insertions, 0 deletions
diff --git a/src/core/nodes/qentity.cpp b/src/core/nodes/qentity.cpp
index 64ea65087..2ef78deb6 100644
--- a/src/core/nodes/qentity.cpp
+++ b/src/core/nodes/qentity.cpp
@@ -152,6 +152,8 @@ void QEntity::addComponent(QComponent *comp)
if (!comp->parent())
comp->setParent(this);
+ QNodePrivate::get(comp)->_q_ensureBackendNodeCreated();
+
d->m_components.append(comp);
// Ensures proper bookkeeping
diff --git a/src/core/nodes/qnode.cpp b/src/core/nodes/qnode.cpp
index 8143ccc75..c2373b805 100644
--- a/src/core/nodes/qnode.cpp
+++ b/src/core/nodes/qnode.cpp
@@ -506,6 +506,29 @@ void QNodePrivate::setArbiter(QLockableObserverInterface *arbiter)
}
/*!
+ * \internal
+ * Makes sure this node has a backend by traversing the tree up to the most distant ancestor
+ * without a backend node and initializing that node. This is done to make sure the parent nodes
+ * are always created before the child nodes, since child nodes reference parent nodes at creation
+ * time.
+ */
+void QNodePrivate::_q_ensureBackendNodeCreated()
+{
+ if (m_hasBackendNode)
+ return;
+
+ Q_Q(QNode);
+
+ QNode *nextNode = q;
+ QNode *topNodeWithoutBackend = nullptr;
+ while (nextNode != nullptr && !QNodePrivate::get(nextNode)->m_hasBackendNode) {
+ topNodeWithoutBackend = nextNode;
+ nextNode = nextNode->parentNode();
+ }
+ QNodePrivate::get(topNodeWithoutBackend)->_q_postConstructorInit();
+}
+
+/*!
\class Qt3DCore::QNode
\inherits QObject
diff --git a/src/core/nodes/qnode_p.h b/src/core/nodes/qnode_p.h
index 73893cc1e..6ffb19ce8 100644
--- a/src/core/nodes/qnode_p.h
+++ b/src/core/nodes/qnode_p.h
@@ -152,6 +152,7 @@ public:
static const QMetaObject *findStaticMetaObject(const QMetaObject *metaObject);
void _q_postConstructorInit();
+ void _q_ensureBackendNodeCreated();
private:
void notifyCreationChange();
diff --git a/tests/auto/core/nodes/tst_nodes.cpp b/tests/auto/core/nodes/tst_nodes.cpp
index 0106d2dc3..3f7fb4a75 100644
--- a/tests/auto/core/nodes/tst_nodes.cpp
+++ b/tests/auto/core/nodes/tst_nodes.cpp
@@ -89,6 +89,7 @@ private slots:
void appendingComponentToEntity();
void appendingParentlessComponentToEntityWithoutScene();
void appendingParentlessComponentToEntityWithScene();
+ void appendingParentlessComponentToNonRootEntity();
void removingComponentFromEntity();
void changeCustomProperty();
@@ -1322,6 +1323,89 @@ void tst_Nodes::appendingParentlessComponentToEntityWithoutScene()
}
}
+void tst_Nodes::appendingParentlessComponentToNonRootEntity()
+{
+ // GIVEN
+ ObserverSpy eventSpy;
+ Qt3DCore::QScene scene;
+
+ {
+ QScopedPointer<MyQEntity> root(new MyQEntity());
+ root->setArbiterAndScene(&eventSpy, &scene);
+ root->setSimulateBackendCreated(true);
+
+ QCoreApplication::processEvents();
+
+ QScopedPointer<MyQEntity> entity(new MyQEntity(root.data()));
+ MyQComponent *comp = new MyQComponent();
+
+ // THEN
+ QVERIFY(root->parentNode() == nullptr);
+ QVERIFY(root->children().count() == 1);
+ QVERIFY(root->components().empty());
+ QVERIFY(entity->parentNode() == root.data());
+ QVERIFY(entity->children().count() == 0);
+ QVERIFY(entity->components().empty());
+ QVERIFY(comp->parentNode() == nullptr);
+
+ // WHEN
+ entity->addComponent(comp);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QVERIFY(entity->components().count() == 1);
+ QVERIFY(entity->components().first() == comp);
+ QVERIFY(comp->parentNode() == entity.data());
+
+ QCOMPARE(eventSpy.events.size(), 5);
+ // - entity created
+ // - comp created
+ // - entity added as child to root
+ // - component added for entity
+ // - component added for compontent
+ QVERIFY(eventSpy.events.first().wasLocked());
+
+ {
+ const auto event = eventSpy.events.takeFirst().change().dynamicCast<Qt3DCore::QNodeCreatedChangeBase>();
+ QVERIFY(!event.isNull());
+ QCOMPARE(event->type(), Qt3DCore::NodeCreated);
+ QCOMPARE(event->subjectId(), entity->id());
+ }
+ {
+ const auto event = eventSpy.events.takeFirst().change().dynamicCast<Qt3DCore::QNodeCreatedChangeBase>();
+ QVERIFY(!event.isNull());
+ QCOMPARE(event->type(), Qt3DCore::NodeCreated);
+ QCOMPARE(event->subjectId(), comp->id());
+ }
+ {
+ const auto event = eventSpy.events.takeFirst().change().dynamicCast<Qt3DCore::QPropertyNodeAddedChange>();
+ QVERIFY(!event.isNull());
+ QCOMPARE(event->type(), Qt3DCore::PropertyValueAdded);
+ QCOMPARE(event->subjectId(), root->id());
+ QCOMPARE(event->propertyName(), QByteArrayLiteral("children"));
+ QCOMPARE(event->addedNodeId(), entity->id());
+ }
+ {
+ const auto event = eventSpy.events.takeFirst().change().dynamicCast<Qt3DCore::QComponentAddedChange>();
+ QVERIFY(!event.isNull());
+ QCOMPARE(event->type(), Qt3DCore::ComponentAdded);
+ QCOMPARE(event->subjectId(), entity->id());
+ QCOMPARE(event->entityId(), entity->id());
+ QCOMPARE(event->componentId(), comp->id());
+ QCOMPARE(event->componentMetaObject(), comp->metaObject());
+ }
+ {
+ const auto event = eventSpy.events.takeFirst().change().dynamicCast<Qt3DCore::QComponentAddedChange>();
+ QVERIFY(!event.isNull());
+ QCOMPARE(event->type(), Qt3DCore::ComponentAdded);
+ QCOMPARE(event->subjectId(), comp->id());
+ QCOMPARE(event->entityId(), entity->id());
+ QCOMPARE(event->componentId(), comp->id());
+ QCOMPARE(event->componentMetaObject(), comp->metaObject());
+ }
+ }
+}
+
void tst_Nodes::appendingParentlessComponentToEntityWithScene()
{
// GIVEN