summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Lemire <paul.lemire@kdab.com>2017-01-24 10:43:32 +0100
committerPaul Lemire <paul.lemire@kdab.com>2017-01-25 14:56:43 +0000
commit393ab950be4a622dc2616c061eeb4f2194991093 (patch)
treea8e83bb510c9cc58c1461eb2345f122925e09c34
parent4f6bf6d53c50221977d3f6e2c04ced70d815e6ac (diff)
Allow to filter change events based on a track property
* QNode now has a PropertyTrackMode property * QScene contains a table of PropertyTrakcMode data * QPostman checks if a QNode is supposed to receive a change based on the information available in the QScene property track mode table * Unit tests updated and added for QPostman Change-Id: I3b88037a949020a917c81817f1451ef532065982 Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
-rw-r--r--src/core/changes/qpropertyupdatedchangebase.cpp6
-rw-r--r--src/core/changes/qpropertyupdatedchangebase_p.h3
-rw-r--r--src/core/core.pri3
-rw-r--r--src/core/nodes/qnode.cpp73
-rw-r--r--src/core/nodes/qnode.h16
-rw-r--r--src/core/nodes/qnode_p.h3
-rw-r--r--src/core/qchangearbiter.cpp6
-rw-r--r--src/core/qchangearbiter_p.h8
-rw-r--r--src/core/qpostman.cpp44
-rw-r--r--src/core/qpostman_p.h4
-rw-r--r--src/core/qpostman_p_p.h85
-rw-r--r--src/core/qscene.cpp23
-rw-r--r--src/core/qscene_p.h12
-rw-r--r--src/render/geometry/buffer.cpp2
-rw-r--r--src/render/io/scene.cpp3
-rw-r--r--tests/auto/core/common/testpostmanarbiter.cpp5
-rw-r--r--tests/auto/core/common/testpostmanarbiter.h1
-rw-r--r--tests/auto/core/core.pro3
-rw-r--r--tests/auto/core/nodes/nodes.pro2
-rw-r--r--tests/auto/core/nodes/tst_nodes.cpp254
-rw-r--r--tests/auto/core/qchangearbiter/tst_qchangearbiter.cpp136
-rw-r--r--tests/auto/core/qpostman/qpostman.pro11
-rw-r--r--tests/auto/core/qpostman/tst_qpostman.cpp300
-rw-r--r--tests/auto/core/qscene/tst_qscene.cpp155
-rw-r--r--tests/auto/render/buffer/tst_buffer.cpp2
-rw-r--r--tests/auto/render/sceneloader/tst_sceneloader.cpp3
26 files changed, 1096 insertions, 67 deletions
diff --git a/src/core/changes/qpropertyupdatedchangebase.cpp b/src/core/changes/qpropertyupdatedchangebase.cpp
index 18f2039fc..d33c737e5 100644
--- a/src/core/changes/qpropertyupdatedchangebase.cpp
+++ b/src/core/changes/qpropertyupdatedchangebase.cpp
@@ -46,6 +46,7 @@ namespace Qt3DCore {
QPropertyUpdatedChangeBasePrivate::QPropertyUpdatedChangeBasePrivate()
: QSceneChangePrivate()
+ , m_isFinal(false)
{
}
@@ -53,6 +54,11 @@ QPropertyUpdatedChangeBasePrivate::~QPropertyUpdatedChangeBasePrivate()
{
}
+QPropertyUpdatedChangeBasePrivate *QPropertyUpdatedChangeBasePrivate::get(QPropertyUpdatedChangeBase *q)
+{
+ return q->d_func();
+}
+
/*!
* \class Qt3DCore::QPropertyUpdatedChangeBase
* \inheaderfile Qt3DCore/QPropertyUpdatedChangeBase
diff --git a/src/core/changes/qpropertyupdatedchangebase_p.h b/src/core/changes/qpropertyupdatedchangebase_p.h
index 314b1ea15..3c32b2237 100644
--- a/src/core/changes/qpropertyupdatedchangebase_p.h
+++ b/src/core/changes/qpropertyupdatedchangebase_p.h
@@ -66,7 +66,10 @@ public:
QPropertyUpdatedChangeBasePrivate();
virtual ~QPropertyUpdatedChangeBasePrivate();
+ static QPropertyUpdatedChangeBasePrivate *get(QPropertyUpdatedChangeBase *q);
+
Q_DECLARE_PUBLIC(QPropertyUpdatedChangeBase)
+ bool m_isFinal;
};
} // namespace Qt3DCore
diff --git a/src/core/core.pri b/src/core/core.pri
index becdbb282..458a0328d 100644
--- a/src/core/core.pri
+++ b/src/core/core.pri
@@ -13,7 +13,8 @@ HEADERS += \
$$PWD/qchangearbiter_p.h \
$$PWD/qbackendnodefactory_p.h \
$$PWD/qt3dcore_global_p.h \
- $$PWD/qscene_p.h
+ $$PWD/qscene_p.h \
+ $$PWD/qpostman_p_p.h
SOURCES += \
$$PWD/qtickclock.cpp \
diff --git a/src/core/nodes/qnode.cpp b/src/core/nodes/qnode.cpp
index e4bb5d4a3..77d7c0a6b 100644
--- a/src/core/nodes/qnode.cpp
+++ b/src/core/nodes/qnode.cpp
@@ -73,6 +73,7 @@ QNodePrivate::QNodePrivate()
, m_blockNotifications(false)
, m_hasBackendNode(false)
, m_enabled(true)
+ , m_propertyTrackMode(QNode::DefaultTrackMode)
, m_propertyChangesSetup(false)
, m_signals(this)
{
@@ -402,7 +403,6 @@ void QNodePrivate::unsetSceneHelper(QNode *root)
m_scene->removeEntityForComponent(c->id(), entity->id());
}
}
-
if (m_scene != nullptr)
m_scene->removeObservable(root);
root->d_func()->setScene(nullptr);
@@ -495,8 +495,13 @@ void QNode::sceneChangeEvent(const QSceneChangePtr &change)
*/
void QNodePrivate::setScene(QScene *scene)
{
- if (m_scene != scene)
+ if (m_scene != scene) {
+ if (m_scene != nullptr)
+ m_scene->removePropertyTrackDataForNode(m_id);
m_scene = scene;
+ // set PropertyTrackData in the scene
+ updatePropertyTrackMode();
+ }
}
/*!
@@ -580,6 +585,16 @@ void QNodePrivate::insertTree(QNode *treeRoot, int depth)
treeRoot->setParent(q_func());
}
+void QNodePrivate::updatePropertyTrackMode()
+{
+ if (m_scene != nullptr) {
+ QScene::NodePropertyTrackData trackData;
+ trackData.updateMode = m_propertyTrackMode;
+ trackData.namedProperties = m_trackedProperties;
+ m_scene->setPropertyTrackDataForNode(m_id,trackData);
+ }
+}
+
/*!
\internal
*/
@@ -769,6 +784,34 @@ void QNode::setEnabled(bool isEnabled)
emit enabledChanged(isEnabled);
}
+void QNode::setPropertyTrackMode(QNode::PropertyTrackMode mode)
+{
+ Q_D(QNode);
+ if (d->m_propertyTrackMode == mode)
+ return;
+
+ d->m_propertyTrackMode = mode;
+ // The backend doesn't care about such notification
+ const bool blocked = blockNotifications(true);
+ emit propertyUpdateModeChanged(mode);
+ blockNotifications(blocked);
+ d->updatePropertyTrackMode();
+}
+
+void QNode::setTrackedProperties(const QStringList &trackedProperties)
+{
+ Q_D(QNode);
+ if (d->m_trackedProperties == trackedProperties)
+ return;
+
+ d->m_trackedProperties = trackedProperties;
+ // The backend doesn't care about such notification
+ const bool blocked = blockNotifications(true);
+ emit trackedPropertiesChanged(trackedProperties);
+ blockNotifications(blocked);
+ d->updatePropertyTrackMode();
+}
+
/*!
\property Qt3DCore::QNode::enabled
@@ -785,6 +828,32 @@ bool QNode::isEnabled() const
return d->m_enabled;
}
+/*!
+ \property Qt3DCore::QNode::propertyTrackMode
+
+ Holds the property track mode which determines whether a QNode should
+ be listening for property updates
+
+ By default it is set to QNode::DontTrackProperties
+*/
+QNode::PropertyTrackMode QNode::propertyTrackMode() const
+{
+ Q_D(const QNode);
+ return d->m_propertyTrackMode;
+}
+
+/*!
+ \property Qt3DCore::QNode::trackedProperties
+
+ Holds the names of the properties to be tracked when propertyTrackMode is
+ set to TrackNamedProperties.
+*/
+QStringList QNode::trackedProperties() const
+{
+ Q_D(const QNode);
+ return d->m_trackedProperties;
+}
+
QNodeCreatedChangeBasePtr QNode::createNodeCreationChange() const
{
// Uncomment this when implementing new frontend and backend types.
diff --git a/src/core/nodes/qnode.h b/src/core/nodes/qnode.h
index cadcc7d5c..75ea61cc7 100644
--- a/src/core/nodes/qnode.h
+++ b/src/core/nodes/qnode.h
@@ -69,7 +69,17 @@ class QT3DCORESHARED_EXPORT QNode : public QObject
Q_OBJECT
Q_PROPERTY(Qt3DCore::QNode *parent READ parentNode WRITE setParent NOTIFY parentChanged)
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged)
+ Q_PROPERTY(PropertyTrackMode propertyTrackMode READ propertyTrackMode WRITE setPropertyTrackMode NOTIFY propertyUpdateModeChanged)
+ Q_PROPERTY(QStringList trackedProperties READ trackedProperties WRITE setTrackedProperties NOTIFY trackedPropertiesChanged)
public:
+
+ enum PropertyTrackMode {
+ DefaultTrackMode,
+ TrackNamedPropertiesMode,
+ TrackAllPropertiesMode
+ };
+ Q_ENUM(PropertyTrackMode)
+
explicit QNode(QNode *parent = nullptr);
virtual ~QNode();
@@ -82,14 +92,20 @@ public:
QNodeVector childNodes() const;
bool isEnabled() const;
+ PropertyTrackMode propertyTrackMode() const;
+ QStringList trackedProperties() const;
public Q_SLOTS:
void setParent(QNode *parent);
void setEnabled(bool isEnabled);
+ void setPropertyTrackMode(PropertyTrackMode mode);
+ void setTrackedProperties(const QStringList &trackedProperties);
Q_SIGNALS:
void parentChanged(QObject *parent);
void enabledChanged(bool enabled);
+ void propertyUpdateModeChanged(PropertyTrackMode mode);
+ void trackedPropertiesChanged(const QStringList &trackedProperties);
void nodeDestroyed();
protected:
diff --git a/src/core/nodes/qnode_p.h b/src/core/nodes/qnode_p.h
index a90011128..5d6329e62 100644
--- a/src/core/nodes/qnode_p.h
+++ b/src/core/nodes/qnode_p.h
@@ -84,6 +84,7 @@ public:
void notifyObservers(const QSceneChangePtr &change) Q_DECL_OVERRIDE;
void insertTree(QNode *treeRoot, int depth = 0);
+ void updatePropertyTrackMode();
Q_DECLARE_PUBLIC(QNode)
@@ -97,6 +98,8 @@ public:
bool m_blockNotifications;
bool m_hasBackendNode;
bool m_enabled;
+ QNode::PropertyTrackMode m_propertyTrackMode;
+ QStringList m_trackedProperties;
static QNodePrivate *get(QNode *q);
static void nodePtrDeleter(QNode *q);
diff --git a/src/core/qchangearbiter.cpp b/src/core/qchangearbiter.cpp
index 3bd3f69e8..a7ca3ed40 100644
--- a/src/core/qchangearbiter.cpp
+++ b/src/core/qchangearbiter.cpp
@@ -132,9 +132,11 @@ void QChangeArbiter::distributeQueueChanges(QChangeQueue *changeQueue)
(change->deliveryFlags() & QSceneChange::BackendNodes))
observer.second->sceneChangeEvent(change);
}
+ // Also send change to the postman
if (change->deliveryFlags() & QSceneChange::Nodes) {
- // Also send change to the postman
- m_postman->sceneChangeEvent(change);
+ // Check if QNode actually cares about the change
+ if (m_postman->shouldNotifyFrontend(change))
+ m_postman->sceneChangeEvent(change);
}
}
}
diff --git a/src/core/qchangearbiter_p.h b/src/core/qchangearbiter_p.h
index e3fdcad9b..e381abc65 100644
--- a/src/core/qchangearbiter_p.h
+++ b/src/core/qchangearbiter_p.h
@@ -136,14 +136,8 @@ private:
QMutex m_mutex;
QAbstractAspectJobManager *m_jobManager;
- // The lists of observers indexed by observable. We maintain two
- // distinct hashes:
- //
- // m_aspectObservations is for observables owned by aspects
+ // The lists of observers indexed by observable (QNodeId).
// m_nodeObservations is for observables in the main thread's object tree
- //
- // We keep these distinct because we do not manage the main thread which means
- // the mechanisms for working with objects there is different.
QHash<QNodeId, QObserverList> m_nodeObservations;
QList<QSceneObserverInterface *> m_sceneObservers;
diff --git a/src/core/qpostman.cpp b/src/core/qpostman.cpp
index ac78450c6..2b8e6c3a8 100644
--- a/src/core/qpostman.cpp
+++ b/src/core/qpostman.cpp
@@ -38,30 +38,22 @@
****************************************************************************/
#include "qpostman_p.h"
-#include <private/qobject_p.h>
+#include "qpostman_p_p.h"
#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DCore/private/qscene_p.h>
#include <Qt3DCore/private/qlockableobserverinterface_p.h>
#include <Qt3DCore/qnode.h>
#include <Qt3DCore/private/qnode_p.h>
+#include <Qt3DCore/private/qpropertyupdatedchangebase_p.h>
QT_BEGIN_NAMESPACE
namespace Qt3DCore {
-class QPostmanPrivate : public QObjectPrivate
+QPostmanPrivate *QPostmanPrivate::get(QPostman *q)
{
-public:
- QPostmanPrivate()
- : QObjectPrivate()
- , m_scene(nullptr)
- {
- }
-
- Q_DECLARE_PUBLIC(QPostman)
- QScene *m_scene;
- std::vector<QSceneChangePtr> m_batch;
-};
+ return q->d_func();
+}
QPostman::QPostman(QObject *parent)
: QObject(*new QPostmanPrivate, parent)
@@ -118,6 +110,32 @@ void QPostman::notifyBackend(const QSceneChangePtr &change)
d->m_batch.push_back(change);
}
+// AspectThread
+bool QPostman::shouldNotifyFrontend(const QSceneChangePtr &e)
+{
+ Q_D(QPostman);
+ const QPropertyUpdatedChangePtr propertyChange = qSharedPointerDynamicCast<QPropertyUpdatedChange>(e);
+ if (Q_LIKELY(d->m_scene != nullptr) && !propertyChange.isNull()) {
+ const bool isFinal = QPropertyUpdatedChangeBasePrivate::get(propertyChange.data())->m_isFinal;
+ if (isFinal)
+ return true;
+ const QScene::NodePropertyTrackData propertyTrackData = d->m_scene->lookupNodePropertyTrackData(e->subjectId());
+ switch (propertyTrackData.updateMode) {
+ case QNode::TrackAllPropertiesMode:
+ return true;
+ case QNode::TrackNamedPropertiesMode:
+ return propertyTrackData.namedProperties.contains(QLatin1String(propertyChange->propertyName()));
+ case QNode::DefaultTrackMode:
+ return false;
+ default:
+ Q_UNREACHABLE();
+ return false;
+ }
+ }
+ return true;
+}
+
+// Main Thread
void QPostman::notifyFrontendNode(const QSceneChangePtr &e)
{
Q_D(QPostman);
diff --git a/src/core/qpostman_p.h b/src/core/qpostman_p.h
index 4fe788960..cbc4048ce 100644
--- a/src/core/qpostman_p.h
+++ b/src/core/qpostman_p.h
@@ -66,9 +66,10 @@ class QT3DCORE_PRIVATE_EXPORT QAbstractPostman : public QObserverInterface
public:
virtual void setScene(QScene *sceneLookup) = 0;
virtual void notifyBackend(const QSceneChangePtr &change) = 0;
+ virtual bool shouldNotifyFrontend(const QSceneChangePtr &change) = 0;
};
-class QPostman Q_DECL_FINAL
+class Q_AUTOTEST_EXPORT QPostman Q_DECL_FINAL
: public QObject
, public QAbstractPostman
{
@@ -80,6 +81,7 @@ public:
void setScene(QScene *sceneLookup) Q_DECL_FINAL;
void sceneChangeEvent(const QSceneChangePtr &e) Q_DECL_FINAL;
void notifyBackend(const QSceneChangePtr &change) Q_DECL_FINAL;
+ bool shouldNotifyFrontend(const QSceneChangePtr &e) Q_DECL_FINAL;
public Q_SLOTS:
void submitChangeBatch();
diff --git a/src/core/qpostman_p_p.h b/src/core/qpostman_p_p.h
new file mode 100644
index 000000000..1b5cca3c9
--- /dev/null
+++ b/src/core/qpostman_p_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DCORE_QPOSTMAN_P_P_H
+#define QT3DCORE_QPOSTMAN_P_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <Qt3DCore/qscenechange.h>
+#include <private/qobject_p.h>
+#include <Qt3DCore/private/qt3dcore_global_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+class QScene;
+class QPostman;
+
+class QT3DCORE_PRIVATE_EXPORT QPostmanPrivate : public QObjectPrivate
+{
+public:
+ QPostmanPrivate()
+ : QObjectPrivate()
+ , m_scene(nullptr)
+ {
+ }
+
+ static QPostmanPrivate *get(QPostman *q);
+
+ Q_DECLARE_PUBLIC(QPostman)
+ QScene *m_scene;
+ std::vector<QSceneChangePtr> m_batch;
+};
+
+} // Qt3DCore
+
+QT_END_NAMESPACE
+
+#endif // QT3DCORE_QPOSTMAN_P_P_H
diff --git a/src/core/qscene.cpp b/src/core/qscene.cpp
index 42c3a2bc8..972659131 100644
--- a/src/core/qscene.cpp
+++ b/src/core/qscene.cpp
@@ -63,8 +63,10 @@ public:
QMultiHash<QNodeId, QNodeId> m_componentToEntities;
QMultiHash<QNodeId, QObservableInterface *> m_observablesLookupTable;
QHash<QObservableInterface *, QNodeId> m_observableToUuid;
+ QHash<QNodeId, QScene::NodePropertyTrackData> m_nodePropertyTrackModeLookupTable;
QLockableObserverInterface *m_arbiter;
mutable QReadWriteLock m_lock;
+ mutable QReadWriteLock m_nodePropertyTrackModeLock;
};
@@ -213,6 +215,27 @@ bool QScene::hasEntityForComponent(QNodeId componentUuid, QNodeId entityUuid)
return d->m_componentToEntities.values(componentUuid).contains(entityUuid);
}
+QScene::NodePropertyTrackData QScene::lookupNodePropertyTrackData(QNodeId id) const
+{
+ Q_D(const QScene);
+ QReadLocker lock(&d->m_nodePropertyTrackModeLock);
+ return d->m_nodePropertyTrackModeLookupTable.value(id);
+}
+
+void QScene::setPropertyTrackDataForNode(QNodeId nodeId, const QScene::NodePropertyTrackData &data)
+{
+ Q_D(QScene);
+ QWriteLocker lock(&d->m_nodePropertyTrackModeLock);
+ d->m_nodePropertyTrackModeLookupTable.insert(nodeId, data);
+}
+
+void QScene::removePropertyTrackDataForNode(QNodeId nodeId)
+{
+ Q_D(QScene);
+ QWriteLocker lock(&d->m_nodePropertyTrackModeLock);
+ d->m_nodePropertyTrackModeLookupTable.remove(nodeId);
+}
+
} // Qt3D
QT_END_NAMESPACE
diff --git a/src/core/qscene_p.h b/src/core/qscene_p.h
index 6b4009538..1a313c249 100644
--- a/src/core/qscene_p.h
+++ b/src/core/qscene_p.h
@@ -53,13 +53,13 @@
#include <Qt3DCore/private/qt3dcore_global_p.h>
#include <Qt3DCore/private/qobservableinterface_p.h>
+#include <Qt3DCore/qnode.h>
#include <QScopedPointer>
QT_BEGIN_NAMESPACE
namespace Qt3DCore {
-class QNode;
class QScenePrivate;
class QAspectEngine;
@@ -92,6 +92,16 @@ public:
void removeEntityForComponent(QNodeId componentUuid, QNodeId entityUuid);
bool hasEntityForComponent(QNodeId componentUuid, QNodeId entityUuid);
+ // Node -> Property Update Data
+ struct NodePropertyTrackData
+ {
+ QNode::PropertyTrackMode updateMode = QNode::DefaultTrackMode;
+ QStringList namedProperties;
+ };
+ NodePropertyTrackData lookupNodePropertyTrackData(QNodeId id) const;
+ void setPropertyTrackDataForNode(QNodeId id, const NodePropertyTrackData &data);
+ void removePropertyTrackDataForNode(QNodeId id);
+
private:
Q_DECLARE_PRIVATE(QScene)
QScopedPointer<QScenePrivate> d_ptr;
diff --git a/src/render/geometry/buffer.cpp b/src/render/geometry/buffer.cpp
index aaae9825f..df0bc3c92 100644
--- a/src/render/geometry/buffer.cpp
+++ b/src/render/geometry/buffer.cpp
@@ -41,6 +41,7 @@
#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DRender/private/buffermanager_p.h>
#include <Qt3DRender/private/qbuffer_p.h>
+#include <Qt3DCore/private/qpropertyupdatedchangebase_p.h>
QT_BEGIN_NAMESPACE
@@ -92,6 +93,7 @@ void Buffer::executeFunctor()
e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
e->setPropertyName("data");
e->setValue(QVariant::fromValue(m_data));
+ Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true;
notifyObservers(e);
}
}
diff --git a/src/render/io/scene.cpp b/src/render/io/scene.cpp
index cf1ca4736..2057ffd3d 100644
--- a/src/render/io/scene.cpp
+++ b/src/render/io/scene.cpp
@@ -46,6 +46,7 @@
#include <Qt3DRender/private/qsceneloader_p.h>
#include <Qt3DRender/private/scenemanager_p.h>
#include <QtCore/qcoreapplication.h>
+#include <Qt3DCore/private/qpropertyupdatedchangebase_p.h>
QT_BEGIN_NAMESPACE
@@ -72,6 +73,7 @@ void Scene::setStatus(QSceneLoader::Status status)
e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
e->setPropertyName("status");
e->setValue(QVariant::fromValue(status));
+ Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true;
notifyObservers(e);
}
@@ -114,6 +116,7 @@ void Scene::setSceneSubtree(Qt3DCore::QEntity *subTree)
e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
e->setPropertyName("scene");
e->setValue(QVariant::fromValue(subTree));
+ Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true;
notifyObservers(e);
}
diff --git a/tests/auto/core/common/testpostmanarbiter.cpp b/tests/auto/core/common/testpostmanarbiter.cpp
index 6c3ca025b..59c59f5ab 100644
--- a/tests/auto/core/common/testpostmanarbiter.cpp
+++ b/tests/auto/core/common/testpostmanarbiter.cpp
@@ -46,6 +46,11 @@ void TestPostman::notifyBackend(const Qt3DCore::QSceneChangePtr &e)
m_arbiter->sceneChangeEventWithLock(e);
}
+bool TestPostman::shouldNotifyFrontend(const Qt3DCore::QSceneChangePtr &)
+{
+ return false;
+}
+
TestArbiter::TestArbiter()
: m_postman(new TestPostman(this))
{
diff --git a/tests/auto/core/common/testpostmanarbiter.h b/tests/auto/core/common/testpostmanarbiter.h
index cb2b87afd..731f16f0f 100644
--- a/tests/auto/core/common/testpostmanarbiter.h
+++ b/tests/auto/core/common/testpostmanarbiter.h
@@ -45,6 +45,7 @@ public:
void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &) Q_DECL_FINAL;
void setScene(Qt3DCore::QScene *) Q_DECL_FINAL;
void notifyBackend(const Qt3DCore::QSceneChangePtr &e) Q_DECL_FINAL;
+ bool shouldNotifyFrontend(const Qt3DCore::QSceneChangePtr &e) Q_DECL_FINAL;
private:
TestArbiter *m_arbiter;
diff --git a/tests/auto/core/core.pro b/tests/auto/core/core.pro
index 339e9d5a4..637ee086e 100644
--- a/tests/auto/core/core.pro
+++ b/tests/auto/core/core.pro
@@ -20,5 +20,6 @@ qtConfig(private_tests) {
qframeallocator \
qtransform \
threadpooler \
- aspectcommanddebugger
+ aspectcommanddebugger \
+ qpostman
}
diff --git a/tests/auto/core/nodes/nodes.pro b/tests/auto/core/nodes/nodes.pro
index 15e34bb6c..b2c43f5e6 100644
--- a/tests/auto/core/nodes/nodes.pro
+++ b/tests/auto/core/nodes/nodes.pro
@@ -5,3 +5,5 @@ TEMPLATE = app
SOURCES += tst_nodes.cpp
QT += testlib 3dcore 3dcore-private core-private
+
+include(../common/common.pri)
diff --git a/tests/auto/core/nodes/tst_nodes.cpp b/tests/auto/core/nodes/tst_nodes.cpp
index f33c0f117..407e8d816 100644
--- a/tests/auto/core/nodes/tst_nodes.cpp
+++ b/tests/auto/core/nodes/tst_nodes.cpp
@@ -37,11 +37,14 @@
#include <Qt3DCore/qnodedestroyedchange.h>
#include <Qt3DCore/qpropertynodeaddedchange.h>
#include <Qt3DCore/qpropertynoderemovedchange.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
#include <private/qpostman_p.h>
#include <Qt3DCore/private/qlockableobserverinterface_p.h>
#include <Qt3DCore/private/qnode_p.h>
#include <Qt3DCore/private/qcomponent_p.h>
+#include <QSignalSpy>
+#include "testpostmanarbiter.h"
class tst_Nodes : public QObject
{
@@ -54,6 +57,7 @@ public:
~tst_Nodes() {}
private slots:
+ void initTestCase();
void defaultNodeConstruction();
void defaultComponentConstruction();
void defaultEntityConstrution();
@@ -81,6 +85,13 @@ private slots:
void changeCustomProperty();
void checkDestruction();
+
+ void checkDefaultConstruction();
+ void checkPropertyChanges();
+ void checkCreationData();
+ void checkEnabledUpdate();
+ void checkPropertyTrackModeUpdate();
+ void checkTrackedPropertyNamesUpdate();
};
class ObserverSpy;
@@ -94,6 +105,7 @@ public:
void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &) Q_DECL_FINAL {};
void setScene(Qt3DCore::QScene *) Q_DECL_FINAL {};
void notifyBackend(const Qt3DCore::QSceneChangePtr &change) Q_DECL_FINAL;
+ bool shouldNotifyFrontend(const Qt3DCore::QSceneChangePtr &changee) Q_DECL_FINAL { return false; }
private:
ObserverSpy *m_spy;
@@ -236,6 +248,11 @@ public:
};
+void tst_Nodes::initTestCase()
+{
+ qRegisterMetaType<Qt3DCore::QNode::PropertyTrackMode>("PropertyTrackMode");
+}
+
void tst_Nodes::defaultNodeConstruction()
{
// GIVEN
@@ -944,6 +961,243 @@ void tst_Nodes::checkDestruction()
QVERIFY(root->children().isEmpty());
}
+void tst_Nodes::checkDefaultConstruction()
+{
+ // GIVEN
+ Qt3DCore::QNode node;
+
+ // THEN
+ QCOMPARE(node.parentNode(), nullptr);
+ QCOMPARE(node.isEnabled(), true);
+ QCOMPARE(node.propertyTrackMode(), Qt3DCore::QNode::DefaultTrackMode);
+ QCOMPARE(node.trackedProperties(), QStringList());
+}
+
+void tst_Nodes::checkPropertyChanges()
+{
+ // GIVEN
+ Qt3DCore::QNode parentNode;
+ Qt3DCore::QNode node;
+
+ {
+ // WHEN
+ QSignalSpy spy(&node, SIGNAL(parentChanged(QObject *)));
+ Qt3DCore::QNode *newValue = &parentNode;
+ node.setParent(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(node.parentNode(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ node.setParent(newValue);
+
+ // THEN
+ QCOMPARE(node.parentNode(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&node, SIGNAL(enabledChanged(bool)));
+ const bool newValue = false;
+ node.setEnabled(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(node.isEnabled(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ node.setEnabled(newValue);
+
+ // THEN
+ QCOMPARE(node.isEnabled(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&node, SIGNAL(propertyUpdateModeChanged(PropertyTrackMode)));
+ const Qt3DCore::QNode::PropertyTrackMode newValue = Qt3DCore::QNode::TrackAllPropertiesMode;
+ node.setPropertyTrackMode(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(node.propertyTrackMode(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ node.setPropertyTrackMode(newValue);
+
+ // THEN
+ QCOMPARE(node.propertyTrackMode(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&node, SIGNAL(trackedPropertiesChanged(const QStringList &)));
+ const QStringList newValue = QStringList() << QStringLiteral("C1") << QStringLiteral("C2") << QStringLiteral("C3");
+ node.setTrackedProperties(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(node.trackedProperties(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ node.setTrackedProperties(newValue);
+
+ // THEN
+ QCOMPARE(node.trackedProperties(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+}
+
+void tst_Nodes::checkCreationData()
+{
+ // GIVEN
+ Qt3DCore::QNode root;
+ Qt3DCore::QNode node;
+
+ node.setParent(&root);
+ node.setEnabled(true);
+ node.setPropertyTrackMode(Qt3DCore::QNode::TrackNamedPropertiesMode);
+ const QStringList trackedPropertyNames = QStringList() << QStringLiteral("327");
+ node.setTrackedProperties(trackedPropertyNames);
+
+ // WHEN
+ QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges;
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&node);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 1);
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChangeBase>(creationChanges.first());
+
+ QCOMPARE(node.id(), creationChangeData->subjectId());
+ QCOMPARE(node.isEnabled(), true);
+ QCOMPARE(node.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(node.metaObject(), creationChangeData->metaObject());
+ }
+
+ // WHEN
+ node.setEnabled(false);
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&node);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 1);
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChangeBase>(creationChanges.first());
+
+ QCOMPARE(node.id(), creationChangeData->subjectId());
+ QCOMPARE(node.isEnabled(), false);
+ QCOMPARE(node.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(node.metaObject(), creationChangeData->metaObject());
+ }
+}
+
+void tst_Nodes::checkEnabledUpdate()
+{
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DCore::QNode node;
+ arbiter.setArbiterOnNode(&node);
+
+ {
+ // WHEN
+ node.setEnabled(false);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "enabled");
+ QCOMPARE(change->value().value<bool>(), node.isEnabled());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ node.setEnabled(false);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+}
+
+void tst_Nodes::checkPropertyTrackModeUpdate()
+{
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DCore::QNode node;
+ arbiter.setArbiterOnNode(&node);
+
+ {
+ // WHEN
+ node.setPropertyTrackMode(Qt3DCore::QNode::TrackAllPropertiesMode);
+ QCoreApplication::processEvents();
+
+ // THEN -> this properties is non notifying
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ {
+ // WHEN
+ node.setPropertyTrackMode(Qt3DCore::QNode::TrackAllPropertiesMode);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+}
+
+void tst_Nodes::checkTrackedPropertyNamesUpdate()
+{
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DCore::QNode node;
+ arbiter.setArbiterOnNode(&node);
+ const QStringList newValue = QStringList() << QStringLiteral("883") << QStringLiteral("454");
+
+ {
+ // WHEN
+ node.setTrackedProperties(newValue);
+ QCoreApplication::processEvents();
+
+ // THEN -> this properties is non notifying
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ {
+ // WHEN
+ node.setTrackedProperties(newValue);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+}
+
QTEST_MAIN(tst_Nodes)
#include "tst_nodes.moc"
diff --git a/tests/auto/core/qchangearbiter/tst_qchangearbiter.cpp b/tests/auto/core/qchangearbiter/tst_qchangearbiter.cpp
index d98cd5e91..061de06fa 100644
--- a/tests/auto/core/qchangearbiter/tst_qchangearbiter.cpp
+++ b/tests/auto/core/qchangearbiter/tst_qchangearbiter.cpp
@@ -200,6 +200,11 @@ public:
return m_lastChanges;
}
+ void clear()
+ {
+ m_lastChanges.clear();
+ }
+
private:
QList<Qt3DCore::QSceneChangePtr> m_lastChanges;
};
@@ -217,17 +222,17 @@ public:
{
QVERIFY(!e.isNull());
m_lastChanges << e;
- // Save reply to be sent to the frontend
- m_reply.reset(new Qt3DCore::QPropertyUpdatedChange(e->subjectId()));
- m_reply->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
- m_reply->setPropertyName("Reply");
+ m_targetId = e->subjectId();
}
// should be called in thread
void sendReply()
{
- QVERIFY(!m_reply.isNull());
- notifyObservers(m_reply);
+ Qt3DCore::QPropertyUpdatedChangePtr reply;
+ reply.reset(new Qt3DCore::QPropertyUpdatedChange(m_targetId));
+ reply->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
+ reply->setPropertyName("Reply");
+ notifyObservers(reply);
qDebug() << Q_FUNC_INFO;
}
@@ -243,14 +248,17 @@ public:
return m_lastChanges;
}
+ void clear()
+ {
+ m_lastChanges.clear();
+ }
+
private:
QList<Qt3DCore::QSceneChangePtr> m_lastChanges;
- Qt3DCore::QPropertyUpdatedChangePtr m_reply;
+ Qt3DCore::QNodeId m_targetId;
};
-QWaitCondition waitingForBackendReplyCondition;
-
class ThreadedAnswer : public QThread
{
Q_OBJECT
@@ -261,6 +269,8 @@ public:
, m_backendObs(backend)
{}
+ ~ThreadedAnswer() { qDebug() << this; }
+
void run() Q_DECL_OVERRIDE
{
// create backend change queue on QChangeArbiter
@@ -269,10 +279,13 @@ public:
// gives time for other threads to start waiting
QThread::currentThread()->sleep(1);
// wake waiting condition
- waitingForBackendReplyCondition.wakeOne();
+ m_waitingForReplyToBeSent.wakeOne();
exec();
+ Qt3DCore::QChangeArbiter::destroyThreadLocalChangeQueue(m_arbiter);
}
+ QWaitCondition *waitingCondition() { return &m_waitingForReplyToBeSent; }
+
private:
Qt3DCore::QChangeArbiter *m_arbiter;
tst_BackendObserverObservable *m_backendObs;
@@ -283,7 +296,9 @@ class tst_PostManObserver : public Qt3DCore::QAbstractPostman
{
public:
- tst_PostManObserver() : m_sceneInterface(nullptr)
+ tst_PostManObserver()
+ : m_sceneInterface(nullptr)
+ , m_allowFrontendNotifications(false)
{}
void setScene(Qt3DCore::QScene *scene) Q_DECL_FINAL
@@ -291,6 +306,11 @@ public:
m_sceneInterface = scene;
}
+ void setAllowFrontendNotifications(bool allow)
+ {
+ m_allowFrontendNotifications = allow;
+ }
+
// QObserverInterface interface
void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
{
@@ -319,9 +339,15 @@ public:
m_sceneInterface->arbiter()->sceneChangeEventWithLock(e);
}
+ bool shouldNotifyFrontend(const Qt3DCore::QSceneChangePtr &)
+ {
+ return m_allowFrontendNotifications;
+ }
+
private:
Qt3DCore::QScene *m_sceneInterface;
QList<Qt3DCore::QSceneChangePtr> m_lastChanges;
+ bool m_allowFrontendNotifications;
};
class tst_SceneObserver : public Qt3DCore::QSceneObserverInterface
@@ -888,39 +914,71 @@ void tst_QChangeArbiter::distributeBackendChanges()
QCOMPARE(postman->lastChanges().count(), 0);
QCOMPARE(backenObserverObservable->lastChanges().count(), 1);
- // WHEN
- // simulate a worker thread
- QScopedPointer<ThreadedAnswer> answer(new ThreadedAnswer(arbiter.data(), backenObserverObservable));
+ backenObserverObservable->clear();
- QMutex mutex;
- // sends reply from another thread (simulates job thread)
- answer->start();
- mutex.lock();
- waitingForBackendReplyCondition.wait(&mutex);
- mutex.unlock();
+ {
+ // WHEN
+ // simulate a worker thread
+ QScopedPointer<ThreadedAnswer> answer(new ThreadedAnswer(arbiter.data(), backenObserverObservable));
+ postman->setAllowFrontendNotifications(false);
+ QWaitCondition *waitingForBackendReplyCondition = answer->waitingCondition();
+
+ QMutex mutex;
+ // sends reply from another thread (simulates job thread)
+ answer->start();
+ mutex.lock();
+ waitingForBackendReplyCondition->wait(&mutex);
+ mutex.unlock();
+
+ // To verify that backendObserver sent a reply
+ arbiter->syncChanges();
+
+ // THEN
+ // the repliers should receive it's reply
+ QCOMPARE(backenObserverObservable->lastChanges().count(), 1);
+ // verify that postMan has received the change
+ QCOMPARE(postman->lastChanges().count(), 0);
+ answer->exit();
+ answer->wait();
+ backenObserverObservable->clear();
+ }
- // To verify that backendObserver sent a reply
- arbiter->syncChanges();
+ {
+ // WHEN
+ // simulate a worker thread
+ QScopedPointer<ThreadedAnswer> answer(new ThreadedAnswer(arbiter.data(), backenObserverObservable));
+ postman->setAllowFrontendNotifications(true);
+ QWaitCondition *waitingForBackendReplyCondition = answer->waitingCondition();
+ QMutex mutex;
+ // sends reply from another thread (simulates job thread)
+ answer->start();
+ mutex.lock();
+ waitingForBackendReplyCondition->wait(&mutex);
+ mutex.unlock();
+
+ // To verify that backendObserver sent a reply
+ arbiter->syncChanges();
+
+ // THEN
+ // the repliers should receive it's reply
+ QCOMPARE(backenObserverObservable->lastChanges().count(), 1);
+ // verify that postMan has received the change
+ QCOMPARE(postman->lastChanges().count(), 1);
+
+ // verify correctness of the reply
+ Qt3DCore::QPropertyUpdatedChangePtr c = qSharedPointerDynamicCast<Qt3DCore::QPropertyUpdatedChange>(postman->lastChange());
+ QVERIFY(!c.isNull());
+ QVERIFY(c->subjectId() == root->id());
+ qDebug() << c->propertyName();
+ QVERIFY(strcmp(c->propertyName(), "Reply") == 0);
+ QVERIFY(c->type() == Qt3DCore::PropertyUpdated);
+ answer->exit();
+ answer->wait();
+ }
- // THEN
- // the repliers should receive it's reply
- QCOMPARE(backenObserverObservable->lastChanges().count(), 2);
- // verify that postMan has received the change
- QCOMPARE(postman->lastChanges().count(), 1);
-
- // verify correctness of the reply
- Qt3DCore::QPropertyUpdatedChangePtr c = qSharedPointerDynamicCast<Qt3DCore::QPropertyUpdatedChange>(postman->lastChange());
- QVERIFY(!c.isNull());
- QVERIFY(c->subjectId() == root->id());
- qDebug() << c->propertyName();
- QVERIFY(strcmp(c->propertyName(), "Reply") == 0);
- QVERIFY(c->type() == Qt3DCore::PropertyUpdated);
-
- answer->exit();
- answer->wait();
Qt3DCore::QChangeArbiter::destroyThreadLocalChangeQueue(arbiter.data());
}
-QTEST_GUILESS_MAIN(tst_QChangeArbiter)
+QTEST_MAIN(tst_QChangeArbiter)
#include "tst_qchangearbiter.moc"
diff --git a/tests/auto/core/qpostman/qpostman.pro b/tests/auto/core/qpostman/qpostman.pro
new file mode 100644
index 000000000..fee342f74
--- /dev/null
+++ b/tests/auto/core/qpostman/qpostman.pro
@@ -0,0 +1,11 @@
+TEMPLATE = app
+
+TARGET = tst_qpostman
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_qpostman.cpp
+
+include(../common/common.pri)
diff --git a/tests/auto/core/qpostman/tst_qpostman.cpp b/tests/auto/core/qpostman/tst_qpostman.cpp
new file mode 100644
index 000000000..e51c21b59
--- /dev/null
+++ b/tests/auto/core/qpostman/tst_qpostman.cpp
@@ -0,0 +1,300 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DCore/private/qpostman_p.h>
+#include <Qt3DCore/private/qpostman_p_p.h>
+#include <Qt3DCore/private/qscene_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/qpropertynodeaddedchange.h>
+#include <Qt3DCore/qpropertynoderemovedchange.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include <Qt3DCore/private/qpropertyupdatedchangebase_p.h>
+#include "testpostmanarbiter.h"
+
+
+namespace {
+
+class NodeChangeReceiver: public Qt3DCore::QNode
+{
+public:
+ NodeChangeReceiver(Qt3DCore::QNode *parent = nullptr)
+ : Qt3DCore::QNode(parent)
+ , m_hasReceivedChange(false)
+ {}
+
+ inline bool hasReceivedChange() const { return m_hasReceivedChange; }
+
+protected:
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &) Q_DECL_OVERRIDE
+ {
+ m_hasReceivedChange = true;
+ }
+
+private:
+ bool m_hasReceivedChange;
+};
+
+} // anonymous
+
+class tst_QPostman : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkSetScene()
+ {
+ // GIVEN
+ Qt3DCore::QPostman postman;
+
+ // THEN
+ QVERIFY(Qt3DCore::QPostmanPrivate::get(&postman)->m_scene == nullptr);
+
+ // WHEN
+ Qt3DCore::QScene scene;
+ postman.setScene(&scene);
+
+ // THEN
+ QCOMPARE(Qt3DCore::QPostmanPrivate::get(&postman)->m_scene, &scene);
+ }
+
+ void checkSceneChangeEvent()
+ {
+ // GIVEN
+ QScopedPointer<Qt3DCore::QScene> scene(new Qt3DCore::QScene);
+ Qt3DCore::QPostman postman;
+ TestArbiter arbiter;
+ Qt3DCore::QNode rootNode;
+ NodeChangeReceiver *receiverNode = new NodeChangeReceiver();
+
+ Qt3DCore::QNodePrivate::get(&rootNode)->m_scene = scene.data();
+ scene->setArbiter(&arbiter);
+ postman.setScene(scene.data());
+ // Setting the parent (which has a scene) adds the node into the observable lookup
+ // table of the scene which is needed by the postman to distribute changes
+ static_cast<Qt3DCore::QNode *>(receiverNode)->setParent(&rootNode);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(receiverNode->hasReceivedChange(), false);
+ QCOMPARE(Qt3DCore::QNodePrivate::get(receiverNode)->m_scene, scene.data());
+
+ // WHEN
+ Qt3DCore::QPropertyUpdatedChangePtr updateChange(new Qt3DCore::QPropertyUpdatedChange(receiverNode->id()));
+ updateChange->setValue(1584);
+ updateChange->setPropertyName("someName");
+ postman.sceneChangeEvent(updateChange);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(receiverNode->hasReceivedChange(), true);
+ }
+
+ void checkNotifyBackend()
+ {
+ // GIVEN
+ QScopedPointer<Qt3DCore::QScene> scene(new Qt3DCore::QScene);
+ Qt3DCore::QPostman postman;
+ TestArbiter arbiter;
+
+ scene->setArbiter(&arbiter);
+ postman.setScene(scene.data());
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+
+ // WHEN
+ Qt3DCore::QPropertyUpdatedChangePtr updateChange(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId()));
+ updateChange->setValue(1584);
+ updateChange->setPropertyName("someName");
+ postman.notifyBackend(updateChange);
+
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ }
+
+ void checkShouldNotifyFrontend()
+ {
+ // GIVEN
+ QScopedPointer<Qt3DCore::QScene> scene(new Qt3DCore::QScene);
+ Qt3DCore::QPostman postman;
+ TestArbiter arbiter;
+ Qt3DCore::QNode rootNode;
+ NodeChangeReceiver *receiverNode = new NodeChangeReceiver();
+
+ Qt3DCore::QNodePrivate::get(&rootNode)->m_scene = scene.data();
+ scene->setArbiter(&arbiter);
+ postman.setScene(scene.data());
+ // Setting the parent (which has a scene) adds the node into the observable lookup
+ // table of the scene which is needed by the postman to distribute changes
+ static_cast<Qt3DCore::QNode *>(receiverNode)->setParent(&rootNode);
+ QCoreApplication::processEvents();
+
+ {
+ // WHEN
+ Qt3DCore::QPropertyUpdatedChangePtr updateChange(new Qt3DCore::QPropertyUpdatedChange(receiverNode->id()));
+ updateChange->setValue(1584);
+ updateChange->setPropertyName("someName");
+
+ // THEN -> we don't track properties by default Qt3DCore::QNode::DontTrackProperties
+ QCOMPARE(postman.shouldNotifyFrontend(updateChange), false);
+ }
+
+ {
+ // WHEN
+ receiverNode->setPropertyTrackMode(Qt3DCore::QNode::TrackAllPropertiesMode);
+
+ Qt3DCore::QPropertyUpdatedChangePtr updateChange(new Qt3DCore::QPropertyUpdatedChange(receiverNode->id()));
+ updateChange->setValue(1584);
+ updateChange->setPropertyName("someName");
+
+ // THEN -> we don't track properties by default
+ QCOMPARE(postman.shouldNotifyFrontend(updateChange), true);
+ }
+
+ {
+ // GIVEN
+ receiverNode->setPropertyTrackMode(Qt3DCore::QNode::TrackNamedPropertiesMode);
+ receiverNode->setTrackedProperties(QStringList() << QStringLiteral("vette"));
+
+ {
+ // WHEN
+ Qt3DCore::QPropertyUpdatedChangePtr updateChange(new Qt3DCore::QPropertyUpdatedChange(receiverNode->id()));
+ updateChange->setValue(1584);
+ updateChange->setPropertyName("someName");
+
+ // THEN -> we don't track properties by default
+ QCOMPARE(postman.shouldNotifyFrontend(updateChange), false);
+ }
+
+ {
+ // WHEN
+ Qt3DCore::QPropertyUpdatedChangePtr updateChange(new Qt3DCore::QPropertyUpdatedChange(receiverNode->id()));
+ updateChange->setValue(1584);
+ updateChange->setPropertyName("vette");
+
+ // THEN
+ QCOMPARE(postman.shouldNotifyFrontend(updateChange), true);
+ }
+ }
+
+ {
+ // GIVEN
+ receiverNode->setTrackedProperties(QStringList() << QStringLiteral("vette"));
+ receiverNode->setPropertyTrackMode(Qt3DCore::QNode::TrackAllPropertiesMode);
+
+ {
+ // WHEN
+ Qt3DCore::QPropertyUpdatedChangePtr updateChange(new Qt3DCore::QPropertyUpdatedChange(receiverNode->id()));
+ updateChange->setValue(1584);
+ updateChange->setPropertyName("someName");
+
+ // THEN -> we don't track properties by default
+ QCOMPARE(postman.shouldNotifyFrontend(updateChange), true);
+ }
+
+ {
+ // WHEN
+ Qt3DCore::QPropertyUpdatedChangePtr updateChange(new Qt3DCore::QPropertyUpdatedChange(receiverNode->id()));
+ updateChange->setValue(1584);
+ updateChange->setPropertyName("vette");
+
+ // THEN -> we don't track properties by default
+ QCOMPARE(postman.shouldNotifyFrontend(updateChange), true);
+ }
+ }
+
+ {
+ // GIVEN
+ receiverNode->setTrackedProperties(QStringList());
+ receiverNode->setPropertyTrackMode(Qt3DCore::QNode::DefaultTrackMode);
+
+ {
+ // WHEN
+ Qt3DCore::QPropertyUpdatedChangePtr updateChange(new Qt3DCore::QPropertyUpdatedChange(receiverNode->id()));
+ updateChange->setValue(1584);
+ updateChange->setPropertyName("someName");
+
+ // THEN -> we don't track properties by default
+ QCOMPARE(postman.shouldNotifyFrontend(updateChange), false);
+ }
+
+ {
+ // WHEN
+ Qt3DCore::QPropertyNodeAddedChangePtr addedChange(new Qt3DCore::QPropertyNodeAddedChange(receiverNode->id(), receiverNode));
+
+ // THEN -> only QPropertyUpdatedChangePtr are filtered
+ QCOMPARE(postman.shouldNotifyFrontend(addedChange), true);
+ }
+ {
+ // WHEN
+ Qt3DCore::QPropertyNodeRemovedChangePtr removedChange(new Qt3DCore::QPropertyNodeRemovedChange(receiverNode->id(), receiverNode));
+
+ // THEN -> only QPropertyUpdatedChangePtr are filtered
+ QCOMPARE(postman.shouldNotifyFrontend(removedChange), true);
+ }
+ }
+
+ {
+ // GIVEN
+ receiverNode->setTrackedProperties(QStringList());
+ receiverNode->setPropertyTrackMode(Qt3DCore::QNode::DefaultTrackMode);
+
+ {
+ // WHEN
+ Qt3DCore::QPropertyUpdatedChangePtr updateChange(new Qt3DCore::QPropertyUpdatedChange(receiverNode->id()));
+ updateChange->setValue(1584);
+ updateChange->setPropertyName("someName");
+
+ // THEN -> we don't track properties by default
+ QCOMPARE(postman.shouldNotifyFrontend(updateChange), false);
+ }
+
+ {
+ // WHEN
+ Qt3DCore::QPropertyUpdatedChangePtr updateChange(new Qt3DCore::QPropertyUpdatedChange(receiverNode->id()));
+ updateChange->setValue(1584);
+ updateChange->setPropertyName("someName");
+ Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(updateChange.data())->m_isFinal = true;
+
+ // THEN
+ QCOMPARE(postman.shouldNotifyFrontend(updateChange), true);
+ }
+
+ }
+ }
+
+};
+
+QTEST_MAIN(tst_QPostman)
+
+#include "tst_qpostman.moc"
diff --git a/tests/auto/core/qscene/tst_qscene.cpp b/tests/auto/core/qscene/tst_qscene.cpp
index eabcc96fb..9ee4d126e 100644
--- a/tests/auto/core/qscene/tst_qscene.cpp
+++ b/tests/auto/core/qscene/tst_qscene.cpp
@@ -52,6 +52,11 @@ private slots:
void addEntityForComponent();
void removeEntityForComponent();
void hasEntityForComponent();
+ void setPropertyTrackData();
+ void lookupNodePropertyTrackData();
+ void removePropertyTrackData();
+ void nodeSetAndUnsetPropertyTrackData();
+ void nodeUpdatePropertyTrackData();
};
class tst_LockableObserver : public Qt3DCore::QLockableObserverInterface
@@ -413,6 +418,156 @@ void tst_QScene::hasEntityForComponent()
QVERIFY(scene->hasEntityForComponent(components.at(i)->id(), entities.at(i)->id()));
}
+void tst_QScene::setPropertyTrackData()
+{
+ // GIVEN
+ Qt3DCore::QNodeId fakeNodeId = Qt3DCore::QNodeId::createId();
+ QScopedPointer<Qt3DCore::QScene> scene(new Qt3DCore::QScene);
+ const QStringList propertyNamesList = QStringList() << QStringLiteral("1340");
+
+ // WHEN
+ {
+ Qt3DCore::QScene::NodePropertyTrackData trackData;
+ trackData.namedProperties = propertyNamesList;
+ trackData.updateMode = Qt3DCore::QNode::TrackNamedPropertiesMode;
+ scene->setPropertyTrackDataForNode(fakeNodeId, trackData);
+ }
+
+ // THEN
+ {
+ Qt3DCore::QScene::NodePropertyTrackData trackData = scene->lookupNodePropertyTrackData(fakeNodeId);
+ QCOMPARE(trackData.namedProperties, propertyNamesList);
+ QCOMPARE(trackData.updateMode, Qt3DCore::QNode::TrackNamedPropertiesMode);
+ }
+
+ // WHEN
+ {
+ Qt3DCore::QScene::NodePropertyTrackData trackData;
+ trackData.namedProperties = propertyNamesList;
+ trackData.updateMode = Qt3DCore::QNode::DefaultTrackMode;
+ scene->setPropertyTrackDataForNode(fakeNodeId, trackData);
+ }
+
+ // THEN
+ {
+ Qt3DCore::QScene::NodePropertyTrackData trackData = scene->lookupNodePropertyTrackData(fakeNodeId);
+ QCOMPARE(trackData.namedProperties, propertyNamesList);
+ QCOMPARE(trackData.updateMode, Qt3DCore::QNode::DefaultTrackMode);
+ }
+}
+
+void tst_QScene::lookupNodePropertyTrackData()
+{
+ // GIVEN
+ QScopedPointer<Qt3DCore::QScene> scene(new Qt3DCore::QScene);
+ Qt3DCore::QNodeId fakeNodeId = Qt3DCore::QNodeId::createId();
+ const QStringList propertyNamesList = QStringList() << QStringLiteral("383");
+
+ // THEN -> default value for non existent id
+ Qt3DCore::QScene::NodePropertyTrackData trackData = scene->lookupNodePropertyTrackData(fakeNodeId);
+ QCOMPARE(trackData.namedProperties, QStringList());
+ QCOMPARE(trackData.updateMode, Qt3DCore::QNode::DefaultTrackMode);
+
+ // WHEN
+ trackData.namedProperties = propertyNamesList;
+ trackData.updateMode = Qt3DCore::QNode::TrackNamedPropertiesMode;
+ scene->setPropertyTrackDataForNode(fakeNodeId, trackData);
+
+ trackData = scene->lookupNodePropertyTrackData(fakeNodeId);
+ QCOMPARE(trackData.namedProperties, propertyNamesList);
+ QCOMPARE(trackData.updateMode, Qt3DCore::QNode::TrackNamedPropertiesMode);
+}
+
+void tst_QScene::removePropertyTrackData()
+{
+ // GIVEN
+ QScopedPointer<Qt3DCore::QScene> scene(new Qt3DCore::QScene);
+ Qt3DCore::QNodeId fakeNodeId = Qt3DCore::QNodeId::createId();
+
+ // WHEN
+ Qt3DCore::QScene::NodePropertyTrackData trackData;
+ trackData.namedProperties = QStringList() << QStringLiteral("1584");
+ trackData.updateMode = Qt3DCore::QNode::TrackNamedPropertiesMode;
+ scene->setPropertyTrackDataForNode(fakeNodeId, trackData);
+ scene->removePropertyTrackDataForNode(fakeNodeId);
+
+ // THEN -> default value for non existent id
+ trackData = scene->lookupNodePropertyTrackData(fakeNodeId);
+ QCOMPARE(trackData.namedProperties, QStringList());
+ QCOMPARE(trackData.updateMode, Qt3DCore::QNode::DefaultTrackMode);
+}
+
+void tst_QScene::nodeSetAndUnsetPropertyTrackData()
+{
+ // GIVEN
+ QScopedPointer<Qt3DCore::QScene> scene(new Qt3DCore::QScene);
+ Qt3DCore::QNode parentNode;
+ Qt3DCore::QNodePrivate::get(&parentNode)->setScene(scene.data());
+
+ Qt3DCore::QNode *childNode = new Qt3DCore::QNode();
+ const QStringList propertyNamesList = QStringList() << QStringLiteral("883");
+ childNode->setTrackedProperties(propertyNamesList);
+ childNode->setPropertyTrackMode(Qt3DCore::QNode::TrackNamedPropertiesMode);
+
+ // WHEN
+ childNode->setParent(&parentNode);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(Qt3DCore::QNodePrivate::get(childNode)->m_scene, scene.data());
+ Qt3DCore::QScene::NodePropertyTrackData trackData = scene->lookupNodePropertyTrackData(childNode->id());
+ QCOMPARE(trackData.updateMode, Qt3DCore::QNode::TrackNamedPropertiesMode);
+ QCOMPARE(trackData.namedProperties, propertyNamesList);
+
+ // WHEN
+ const Qt3DCore::QNodeId childNodeId = childNode->id();
+ delete childNode;
+ QCoreApplication::processEvents();
+
+ // THEN -> default value for non existent id
+ trackData = scene->lookupNodePropertyTrackData(childNodeId);
+ QCOMPARE(trackData.namedProperties, QStringList());
+ QCOMPARE(trackData.updateMode, Qt3DCore::QNode::DefaultTrackMode);
+}
+
+void tst_QScene::nodeUpdatePropertyTrackData()
+{
+ // GIVEN
+ QScopedPointer<Qt3DCore::QScene> scene(new Qt3DCore::QScene);
+ Qt3DCore::QNode parentNode;
+ Qt3DCore::QNodePrivate::get(&parentNode)->setScene(scene.data());
+
+ Qt3DCore::QNode *childNode = new Qt3DCore::QNode();
+ const QStringList propertyNamesList = QStringList() << QStringLiteral("883");
+ childNode->setTrackedProperties(propertyNamesList);
+ childNode->setPropertyTrackMode(Qt3DCore::QNode::TrackNamedPropertiesMode);
+
+ // WHEN
+ childNode->setParent(&parentNode);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(Qt3DCore::QNodePrivate::get(childNode)->m_scene, scene.data());
+ Qt3DCore::QScene::NodePropertyTrackData trackData = scene->lookupNodePropertyTrackData(childNode->id());
+ QCOMPARE(trackData.updateMode, Qt3DCore::QNode::TrackNamedPropertiesMode);
+ QCOMPARE(trackData.namedProperties, propertyNamesList);
+
+ // WHEN
+ childNode->setPropertyTrackMode(Qt3DCore::QNode::TrackAllPropertiesMode);
+
+ // THEN
+ trackData = scene->lookupNodePropertyTrackData(childNode->id());
+ QCOMPARE(trackData.updateMode, Qt3DCore::QNode::TrackAllPropertiesMode);
+
+ // WHEN
+ const QStringList propertyNamesList2 = QStringList() << QStringLiteral("Viper");
+ childNode->setTrackedProperties(propertyNamesList2);
+
+ // THEN
+ trackData = scene->lookupNodePropertyTrackData(childNode->id());
+ QCOMPARE(trackData.namedProperties, propertyNamesList2);
+}
+
QTEST_MAIN(tst_QScene)
#include "tst_qscene.moc"
diff --git a/tests/auto/render/buffer/tst_buffer.cpp b/tests/auto/render/buffer/tst_buffer.cpp
index b06425bd7..da5f74dd6 100644
--- a/tests/auto/render/buffer/tst_buffer.cpp
+++ b/tests/auto/render/buffer/tst_buffer.cpp
@@ -33,6 +33,7 @@
#include <Qt3DRender/private/buffermanager_p.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DCore/private/qbackendnode_p.h>
+#include <Qt3DCore/private/qpropertyupdatedchangebase_p.h>
#include "testpostmanarbiter.h"
#include "testrenderer.h"
@@ -233,6 +234,7 @@ private Q_SLOTS:
Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
QCOMPARE(change->propertyName(), "data");
QCOMPARE(change->value().toByteArray(), QByteArrayLiteral("454"));
+ QCOMPARE(Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(change.data())->m_isFinal, true);
arbiter.events.clear();
diff --git a/tests/auto/render/sceneloader/tst_sceneloader.cpp b/tests/auto/render/sceneloader/tst_sceneloader.cpp
index 05f4f08b6..edd6fabda 100644
--- a/tests/auto/render/sceneloader/tst_sceneloader.cpp
+++ b/tests/auto/render/sceneloader/tst_sceneloader.cpp
@@ -34,6 +34,7 @@
#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DCore/private/qbackendnode_p.h>
#include <Qt3DCore/private/qentity_p.h>
+#include <Qt3DCore/private/qpropertyupdatedchangebase_p.h>
#include "testpostmanarbiter.h"
#include "testrenderer.h"
@@ -146,6 +147,7 @@ private Q_SLOTS:
QCOMPARE(arbiter.events.count(), 1);
QCOMPARE(change->propertyName(), "scene");
QCOMPARE(change->value().value<Qt3DCore::QEntity *>(), &subtree);
+ QCOMPARE(Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(change.data())->m_isFinal, true);
arbiter.events.clear();
}
@@ -168,6 +170,7 @@ private Q_SLOTS:
QCOMPARE(arbiter.events.count(), 1);
QCOMPARE(change->propertyName(), "status");
QCOMPARE(change->value().value<Qt3DRender::QSceneLoader::Status>(), Qt3DRender::QSceneLoader::Ready);
+ QCOMPARE(Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(change.data())->m_isFinal, true);
arbiter.events.clear();
}