diff options
author | Paul Lemire <paul.lemire@kdab.com> | 2017-01-24 10:43:32 +0100 |
---|---|---|
committer | Paul Lemire <paul.lemire@kdab.com> | 2017-01-25 14:56:43 +0000 |
commit | 393ab950be4a622dc2616c061eeb4f2194991093 (patch) | |
tree | a8e83bb510c9cc58c1461eb2345f122925e09c34 | |
parent | 4f6bf6d53c50221977d3f6e2c04ced70d815e6ac (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>
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(); } |