1/****************************************************************************
2**
3** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt3D module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qpostman_p.h"
41#include "qpostman_p_p.h"
42
43#include <Qt3DCore/qnode.h>
44#include <Qt3DCore/qpropertyupdatedchange.h>
45
46#include <Qt3DCore/private/qlockableobserverinterface_p.h>
47#include <Qt3DCore/private/qnode_p.h>
48#include <Qt3DCore/private/qpropertyupdatedchangebase_p.h>
49#include <Qt3DCore/private/qscene_p.h>
50#include <QtCore/private/qobject_p.h>
51
52QT_BEGIN_NAMESPACE
53
54namespace Qt3DCore {
55
56QPostmanPrivate *QPostmanPrivate::get(QPostman *q)
57{
58 return q->d_func();
59}
60
61QPostman::QPostman(QObject *parent)
62 : QObject(*new QPostmanPrivate, parent)
63{
64 qRegisterMetaType<QSceneChangePtr >("QSceneChangePtr");
65}
66
67QPostman::~QPostman()
68{
69}
70
71void QPostman::setScene(QScene *scene)
72{
73 Q_D(QPostman);
74 d->m_scene = scene;
75}
76
77static inline QMetaMethod notifyFrontendNodeMethod()
78{
79 int idx = QPostman::staticMetaObject.indexOfMethod("notifyFrontendNode(QSceneChangePtr)");
80 Q_ASSERT(idx != -1);
81 return QPostman::staticMetaObject.method(idx);
82}
83
84void QPostman::sceneChangeEvent(const QSceneChangePtr &e)
85{
86 static const QMetaMethod notifyFrontendNode = notifyFrontendNodeMethod();
87 notifyFrontendNode.invoke(this, Q_ARG(QSceneChangePtr, e));
88}
89
90static inline QMetaMethod submitChangeBatchMethod()
91{
92 int idx = QPostman::staticMetaObject.indexOfMethod("submitChangeBatch()");
93 Q_ASSERT(idx != -1);
94 return QPostman::staticMetaObject.method(idx);
95}
96
97/*
98 * \internal
99 * This will start or append \a change to a batch of changes from frontend
100 * nodes. Once the batch is complete, when the event loop returns, the batch is
101 * sent to the QChangeArbiter to notify the backend aspects.
102 */
103void QPostman::notifyBackend(const QSceneChangePtr &change)
104{
105 // If batch in progress
106 // add change
107 // otherwise start batch
108 // by calling a queued slot
109 Q_D(QPostman);
110 if (d->m_batch.empty()) {
111 static const QMetaMethod submitChangeBatch = submitChangeBatchMethod();
112 submitChangeBatch.invoke(this, Qt::QueuedConnection);
113 }
114 d->m_batch.push_back(change);
115}
116
117// AspectThread
118bool QPostman::shouldNotifyFrontend(const QSceneChangePtr &e)
119{
120 Q_D(QPostman);
121 const QPropertyUpdatedChangePtr propertyChange = qSharedPointerDynamicCast<QPropertyUpdatedChange>(e);
122 if (Q_LIKELY(d->m_scene != nullptr) && !propertyChange.isNull()) {
123 const QScene::NodePropertyTrackData propertyTrackData
124 = d->m_scene->lookupNodePropertyTrackData(e->subjectId());
125
126 const QNode::PropertyTrackingMode trackMode = propertyTrackData.trackedPropertiesOverrides.value(QLatin1String(propertyChange->propertyName()),
127 propertyTrackData.defaultTrackMode);
128
129 switch (trackMode) {
130 case QNode::TrackAllValues:
131 return true;
132
133 case QNode::DontTrackValues:
134 return false;
135
136 case QNode::TrackFinalValues: {
137 const bool isIntermediate
138 = QPropertyUpdatedChangeBasePrivate::get(propertyChange.data())->m_isIntermediate;
139 return !isIntermediate;
140 }
141
142 default:
143 Q_UNREACHABLE();
144 return false;
145 }
146 }
147 return true;
148}
149
150// Main Thread
151void QPostman::notifyFrontendNode(const QSceneChangePtr &e)
152{
153 Q_D(QPostman);
154 if (!e.isNull() && d->m_scene != nullptr) {
155 QNode *n = d->m_scene->lookupNode(e->subjectId());
156 if (n != nullptr)
157 n->sceneChangeEvent(e);
158 }
159}
160
161void QPostman::submitChangeBatch()
162{
163 Q_D(QPostman);
164 QLockableObserverInterface *arbiter = nullptr;
165 if (d->m_scene && (arbiter = d->m_scene->arbiter()) != nullptr) {
166 arbiter->sceneChangeEventWithLock(d->m_batch);
167 d->m_batch.clear();
168 }
169}
170
171} //Qt3D
172
173QT_END_NAMESPACE
174