1 | // Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #ifndef QT3DCORE_QNODE_P_H |
5 | #define QT3DCORE_QNODE_P_H |
6 | |
7 | // |
8 | // W A R N I N G |
9 | // ------------- |
10 | // |
11 | // This file is not part of the Qt API. It exists for the convenience |
12 | // of other Qt classes. This header file may change from version to |
13 | // version without notice, or even be removed. |
14 | // |
15 | // We mean it. |
16 | // |
17 | |
18 | #include <Qt3DCore/qnode.h> |
19 | |
20 | #include <functional> |
21 | #include <vector> |
22 | |
23 | #include <Qt3DCore/private/propertychangehandler_p.h> |
24 | #include <Qt3DCore/private/qchangearbiter_p.h> |
25 | #include <Qt3DCore/private/qscene_p.h> |
26 | #include <Qt3DCore/private/qt3dcore_global_p.h> |
27 | #include <QtCore/private/qobject_p.h> |
28 | #include <QQueue> |
29 | |
30 | QT_BEGIN_NAMESPACE |
31 | |
32 | namespace Qt3DCore { |
33 | |
34 | class QNode; |
35 | class QAspectEngine; |
36 | |
37 | class Q_3DCORE_PRIVATE_EXPORT QNodePrivate : public QObjectPrivate |
38 | { |
39 | public: |
40 | QNodePrivate(); |
41 | ~QNodePrivate(); |
42 | |
43 | void init(QNode *parent); |
44 | |
45 | virtual void setScene(QScene *scene); |
46 | QScene *scene() const; |
47 | |
48 | void setArbiter(QChangeArbiter *arbiter); |
49 | |
50 | void notifyPropertyChange(const char *name, const QVariant &value); |
51 | void notifyDynamicPropertyChange(const QByteArray &name, const QVariant &value); |
52 | |
53 | void insertTree(QNode *treeRoot, int depth = 0); |
54 | void updatePropertyTrackMode(); |
55 | |
56 | virtual void update(); |
57 | void markDirty(QScene::DirtyNodeSet changes); |
58 | |
59 | Q_DECLARE_PUBLIC(QNode) |
60 | |
61 | // For now this just protects access to the m_changeArbiter. |
62 | // Later on we may decide to extend support for multiple observers. |
63 | QChangeArbiter *m_changeArbiter; |
64 | QMetaObject *m_typeInfo; |
65 | QScene *m_scene; |
66 | mutable QNodeId m_id; |
67 | QNodeId m_parentId; // Store this so we have it even in parent's QObject dtor |
68 | bool m_blockNotifications; |
69 | bool m_hasBackendNode; |
70 | bool m_enabled; |
71 | bool m_notifiedParent; |
72 | |
73 | static QNodePrivate *get(QNode *q); |
74 | static const QNodePrivate *get(const QNode *q); |
75 | static void nodePtrDeleter(QNode *q); |
76 | |
77 | template<typename Caller, typename NodeType> |
78 | using DestructionFunctionPointer = void (Caller::*)(NodeType *); |
79 | |
80 | template<typename Caller, typename NodeType, typename PropertyType> |
81 | void registerDestructionHelper(NodeType *, DestructionFunctionPointer<Caller, NodeType>, PropertyType); |
82 | |
83 | template<typename Caller, typename NodeType> |
84 | void registerDestructionHelper(NodeType *node, DestructionFunctionPointer<Caller, NodeType> func, NodeType *&) |
85 | { |
86 | // If the node is destoyed, we make sure not to keep a dangling pointer to it |
87 | Q_Q(QNode); |
88 | auto f = [q, func]() { (static_cast<Caller *>(q)->*func)(nullptr); }; |
89 | m_destructionConnections.push_back({node, QObject::connect(node, &QNode::nodeDestroyed, f)}); |
90 | } |
91 | |
92 | template<typename Caller, typename NodeType> |
93 | void registerDestructionHelper(NodeType *node, DestructionFunctionPointer<Caller, NodeType> func, QList<NodeType*> &) |
94 | { |
95 | // If the node is destoyed, we make sure not to keep a dangling pointer to it |
96 | Q_Q(QNode); |
97 | auto f = [q, func, node]() { (static_cast<Caller *>(q)->*func)(node); }; |
98 | m_destructionConnections.push_back({node, QObject::connect(node, &QNode::nodeDestroyed, f)}); |
99 | } |
100 | |
101 | template<typename Caller, typename NodeType> |
102 | void registerDestructionHelper(NodeType *node, DestructionFunctionPointer<Caller, NodeType> func, std::vector<NodeType*> &) |
103 | { |
104 | // If the node is destoyed, we make sure not to keep a dangling pointer to it |
105 | Q_Q(QNode); |
106 | auto f = [q, func, node]() { (static_cast<Caller *>(q)->*func)(node); }; |
107 | m_destructionConnections.push_back({node, QObject::connect(node, &QNode::nodeDestroyed, f)}); |
108 | } |
109 | |
110 | template<typename Caller, typename ValueType> |
111 | using DestructionFunctionValue = void (Caller::*)(const ValueType&); |
112 | |
113 | template<typename Caller, typename NodeType, typename ValueType> |
114 | void registerDestructionHelper(NodeType *node, DestructionFunctionValue<Caller, ValueType> func, NodeType *&, |
115 | const ValueType &resetValue) |
116 | { |
117 | // If the node is destoyed, we make sure not to keep a dangling pointer to it |
118 | Q_Q(QNode); |
119 | auto f = [q, func, resetValue]() { (static_cast<Caller *>(q)->*func)(resetValue); }; |
120 | m_destructionConnections.push_back({node, QObject::connect(node, &QNode::nodeDestroyed, f)}); |
121 | } |
122 | |
123 | template<typename Caller, typename NodeType> |
124 | void registerPrivateDestructionHelper(NodeType *node, DestructionFunctionPointer<Caller, NodeType> func) |
125 | { |
126 | // If the node is destoyed, we make sure not to keep a dangling pointer to it |
127 | auto f = [this, func, node]() { (static_cast<Caller *>(this)->*func)(node); }; |
128 | m_destructionConnections.push_back({node, QObject::connect(node, &QNode::nodeDestroyed, f)}); |
129 | } |
130 | |
131 | void unregisterDestructionHelper(QNode *node) |
132 | { |
133 | m_destructionConnections.erase(abegin: std::remove_if(first: m_destructionConnections.begin(), |
134 | last: m_destructionConnections.end(), |
135 | pred: [node] (const QPair<QNode *, QMetaObject::Connection> &nodeConnectionPair) { |
136 | if (nodeConnectionPair.first == node) { |
137 | QObject::disconnect(nodeConnectionPair.second); |
138 | return true; |
139 | } |
140 | return false; |
141 | }), |
142 | aend: m_destructionConnections.end()); |
143 | } |
144 | |
145 | static const QMetaObject *findStaticMetaObject(const QMetaObject *metaObject); |
146 | |
147 | void _q_postConstructorInit(); |
148 | void _q_ensureBackendNodeCreated(); |
149 | |
150 | private: |
151 | void createBackendNode(); |
152 | void notifyDestructionChangesAndRemoveFromScene(); |
153 | void _q_addChild(QNode *childNode); |
154 | void _q_removeChild(QNode *childNode); |
155 | void _q_setParentHelper(QNode *parent); |
156 | void registerNotifiedProperties(); |
157 | void unregisterNotifiedProperties(); |
158 | void propertyChanged(int propertyIndex); |
159 | |
160 | void setSceneHelper(QNode *root); |
161 | void unsetSceneHelper(QNode *root); |
162 | void addEntityComponentToScene(QNode *root); |
163 | |
164 | friend class PropertyChangeHandler<QNodePrivate>; |
165 | bool m_propertyChangesSetup; |
166 | PropertyChangeHandler<QNodePrivate> m_signals; |
167 | QList<QPair<QNode *, QMetaObject::Connection>> m_destructionConnections; |
168 | }; |
169 | |
170 | class NodePostConstructorInit : public QObject |
171 | { |
172 | Q_OBJECT |
173 | public: |
174 | NodePostConstructorInit(QObject *parent = nullptr); |
175 | virtual ~NodePostConstructorInit(); |
176 | void removeNode(QNode *node); |
177 | void addNode(QNode *node); |
178 | |
179 | public Q_SLOTS: |
180 | void processNodes(); |
181 | |
182 | private: |
183 | QQueue<QNodePrivate *> m_nodesToConstruct; |
184 | bool m_requestedProcessing; |
185 | }; |
186 | |
187 | } // namespace Qt3DCore |
188 | |
189 | QT_END_NAMESPACE |
190 | |
191 | #endif // QT3DCORE_NODE_P_H |
192 | |