QParameter: add bookkeeping of QNode values

Change-Id: I0a7334907e4b34df6955fb24832958b674d7b62b
Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
This commit is contained in:
Paul Lemire 2018-01-19 15:34:58 +01:00
parent ba3c6bc0ff
commit 0fd16cf43f
3 changed files with 48 additions and 4 deletions

View File

@ -108,13 +108,13 @@ public:
static void nodePtrDeleter(QNode *q);
template<typename Caller, typename NodeType>
using DestructionFunction = void (Caller::*)(NodeType *);
using DestructionFunctionPointer = void (Caller::*)(NodeType *);
template<typename Caller, typename NodeType, typename PropertyType>
void registerDestructionHelper(NodeType *, DestructionFunction<Caller, NodeType>, PropertyType);
void registerDestructionHelper(NodeType *, DestructionFunctionPointer<Caller, NodeType>, PropertyType);
template<typename Caller, typename NodeType>
void registerDestructionHelper(NodeType *node, DestructionFunction<Caller, NodeType> func, NodeType *&)
void registerDestructionHelper(NodeType *node, DestructionFunctionPointer<Caller, NodeType> func, NodeType *&)
{
// If the node is destoyed, we make sure not to keep a dangling pointer to it
Q_Q(QNode);
@ -123,7 +123,7 @@ public:
}
template<typename Caller, typename NodeType>
void registerDestructionHelper(NodeType *node, DestructionFunction<Caller, NodeType> func, QVector<NodeType*> &)
void registerDestructionHelper(NodeType *node, DestructionFunctionPointer<Caller, NodeType> func, QVector<NodeType*> &)
{
// If the node is destoyed, we make sure not to keep a dangling pointer to it
Q_Q(QNode);
@ -131,6 +131,19 @@ public:
m_destructionConnections.insert(node, QObject::connect(node, &QNode::nodeDestroyed, f));
}
template<typename Caller, typename ValueType>
using DestructionFunctionValue = void (Caller::*)(const ValueType&);
template<typename Caller, typename NodeType, typename ValueType>
void registerDestructionHelper(NodeType *node, DestructionFunctionValue<Caller, ValueType> func, NodeType *&,
const ValueType &resetValue)
{
// If the node is destoyed, we make sure not to keep a dangling pointer to it
Q_Q(QNode);
auto f = [q, func, resetValue]() { (static_cast<Caller *>(q)->*func)(resetValue); };
m_destructionConnections.insert(node, QObject::connect(node, &QNode::nodeDestroyed, f));
}
void unregisterDestructionHelper(QNode *node)
{
QObject::disconnect(m_destructionConnections.take(node));

View File

@ -288,12 +288,21 @@ void QParameter::setValue(const QVariant &dv)
Q_D(QParameter);
if (d->m_value != dv) {
QNode *oldNodeValue = d->m_value.value<QNode *>();
if (oldNodeValue != nullptr)
d->unregisterDestructionHelper(oldNodeValue);
// In case node values are declared inline
QNode *nodeValue = dv.value<QNode *>();
if (nodeValue != nullptr && !nodeValue->parent())
nodeValue->setParent(this);
d->setValue(dv);
// Ensures proper bookkeeping
if (nodeValue != nullptr)
d->registerDestructionHelper(nodeValue, &QParameter::setValue, nodeValue, QVariant());
emit valueChanged(dv);
}
}

View File

@ -249,6 +249,28 @@ private Q_SLOTS:
}
void checkBookeeping()
{
// GIVEN
Qt3DRender::QParameter parameter;
QSignalSpy spy(&parameter, SIGNAL(valueChanged(QVariant)));
{
// WHEN
QScopedPointer<Qt3DCore::QNode> node(new Qt3DCore::QNode());
parameter.setValue(QVariant::fromValue(node.data()));
// THEN
QCOMPARE(spy.count(), 1);
QCOMPARE(parameter.value(), QVariant::fromValue(node.data()));
spy.clear();
}
// THEN
QCOMPARE(spy.count(), 1);
QCOMPARE(parameter.value(), QVariant());
}
};
QTEST_MAIN(tst_QParameter)