diff options
Diffstat (limited to 'src/core/nodes/qnode.cpp')
-rw-r--r-- | src/core/nodes/qnode.cpp | 70 |
1 files changed, 54 insertions, 16 deletions
diff --git a/src/core/nodes/qnode.cpp b/src/core/nodes/qnode.cpp index e56d4bd81..6f19e7217 100644 --- a/src/core/nodes/qnode.cpp +++ b/src/core/nodes/qnode.cpp @@ -91,6 +91,7 @@ void QNodePrivate::init(QNode *parent) // in a deferred way when the object is fully constructed. This is delayed // until the object is fully constructed as it involves calling a virtual // function of QNode. + m_parentId = parent->id(); const auto parentPrivate = get(parent); m_scene = parentPrivate->m_scene; Q_Q(QNode); @@ -119,6 +120,43 @@ void QNodePrivate::notifyCreationChange() /*! * \internal * + * Notify the backend that the parent lost this node as a child and + * that this node is being destroyed. We only send the node removed + * change for the parent's children property iff we have an id for + * a parent node. This is set/unset in the _q_addChild()/_q_removeChild() + * functions (and initialized in init() if there is a parent at + * construction time). + * + * Likewise, we only send the node destroyed change, iff we have + * previously sent a node created change. This is tracked via the + * m_hasBackendNode member. + */ +void QNodePrivate::notifyDestructionChangesAndRemoveFromScene() +{ + Q_Q(QNode); + +// // We notify the backend that the parent lost us as a child + if (m_changeArbiter != nullptr && !m_parentId.isNull()) { + const auto change = QPropertyNodeRemovedChangePtr::create(m_parentId, q); + change->setPropertyName("children"); + notifyObservers(change); + } + + // Tell the backend we are about to be destroyed + if (m_hasBackendNode) { + const QDestructionIdAndTypeCollector collector(q); + const auto destroyedChange = QNodeDestroyedChangePtr::create(q, collector.subtreeIdsAndTypes()); + notifyObservers(destroyedChange); + } + + // We unset the scene from the node as its backend node was/is about to be destroyed + QNodeVisitor visitor; + visitor.traverse(q, this, &QNodePrivate::unsetSceneHelper); +} + +/*! + * \internal + * * 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 @@ -152,6 +190,14 @@ void QNodePrivate::_q_addChild(QNode *childNode) Q_ASSERT(childNode); Q_ASSERT_X(childNode->parent() == q_func(), Q_FUNC_INFO, "not a child of this node"); + // Store our id as the parentId in the child so that even if the child gets + // removed from the scene as part of the destruction of the parent, when the + // parent's children are deleted in the QObject dtor, we still have access to + // the parentId. If we didn't store this, we wouldn't have access at that time + // because the parent woudl then only be a QObject, the QNode part would have + // been destroyed already. + QNodePrivate::get(childNode)->m_parentId = m_id; + if (!m_scene) return; @@ -180,6 +226,8 @@ void QNodePrivate::_q_removeChild(QNode *childNode) Q_ASSERT(childNode); Q_ASSERT_X(childNode->parent() == q_func(), Q_FUNC_INFO, "not a child of this node"); + QNodePrivate::get(childNode)->m_parentId = QNodeId(); + // We notify the backend that we lost a child if (m_changeArbiter != nullptr) { const auto change = QPropertyNodeRemovedChangePtr::create(m_id, childNode); @@ -220,18 +268,8 @@ void QNodePrivate::_q_setParentHelper(QNode *parent) // If we have an old parent but the new parent is null // the backend node needs to be destroyed - if (!parent) { - // Tell the backend we are about to be destroyed - if (m_hasBackendNode) { - const QDestructionIdAndTypeCollector collector(q); - const auto destroyedChange = QNodeDestroyedChangePtr::create(q, collector.subtreeIdsAndTypes()); - notifyObservers(destroyedChange); - } - - // We unset the scene from the node as its backend node was/is about to be destroyed - QNodeVisitor visitor; - visitor.traverse(q, oldParentNode->d_func(), &QNodePrivate::unsetSceneHelper); - } + if (!parent) + notifyDestructionChangesAndRemoveFromScene(); } // Basically QObject::setParent but for QObjectPrivate @@ -586,10 +624,10 @@ QNode::QNode(QNodePrivate &dd, QNode *parent) QNode::~QNode() { - // If we have a parent it makes sense to let it know we are about to be destroyed. - // This in turn triggers the deletion of the corresponding backend nodes for the - // subtree rooted at this QNode. - setParent(Q_NODE_NULLPTR); + // Notify the backend that the parent lost this node as a child and + // that this node is being destroyed. + Q_D(QNode); + d->notifyDestructionChangesAndRemoveFromScene(); } /*! |