diff options
author | Svenn-Arne Dragly <s@dragly.com> | 2019-02-22 13:50:30 +0100 |
---|---|---|
committer | Jani Heikkinen <jani.heikkinen@qt.io> | 2019-02-22 15:00:31 +0000 |
commit | 3de900a10c6fd051ba54727be2fd1fe47ed10481 (patch) | |
tree | de030e365dec53d02d6707601078dd9fc48ef773 | |
parent | 799bb8615c86b7713351851c6013821b523f8aa2 (diff) | |
download | qt3d-5.12.2.tar.gz |
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.cpp | 2 | ||||
-rw-r--r-- | src/core/nodes/qnode.cpp | 23 | ||||
-rw-r--r-- | src/core/nodes/qnode_p.h | 1 | ||||
-rw-r--r-- | tests/auto/core/nodes/tst_nodes.cpp | 84 |
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 |