1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQml 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#ifndef QQMLCONTEXT_P_H
41#define QQMLCONTEXT_P_H
42
43//
44// W A R N I N G
45// -------------
46//
47// This file is not part of the Qt API. It exists purely as an
48// implementation detail. This header file may change from version to
49// version without notice, or even be removed.
50//
51// We mean it.
52//
53
54#include "qqmlcontext.h"
55
56#include "qqmldata_p.h"
57#include "qqmltypenamecache_p.h"
58#include "qqmlnotifier_p.h"
59#include "qqmllist.h"
60
61#include <QtCore/qhash.h>
62#include <QtQml/qjsvalue.h>
63#include <QtCore/qset.h>
64
65#include <private/qobject_p.h>
66#include <private/qflagpointer_p.h>
67#include <private/qqmlguard_p.h>
68
69#include <private/qv4executablecompilationunit_p.h>
70#include <private/qv4identifier_p.h>
71
72QT_BEGIN_NAMESPACE
73
74class QQmlContext;
75class QQmlExpression;
76class QQmlEngine;
77class QQmlExpression;
78class QQmlExpressionPrivate;
79class QQmlJavaScriptExpression;
80class QQmlContextData;
81class QQmlGuardedContextData;
82class QQmlIncubatorPrivate;
83
84class QQmlContextPrivate : public QObjectPrivate
85{
86 Q_DECLARE_PUBLIC(QQmlContext)
87public:
88 QQmlContextPrivate();
89
90 QQmlContextData *data;
91
92 QList<QVariant> propertyValues;
93 int notifyIndex;
94
95 static QQmlContextPrivate *get(QQmlContext *context) {
96 return static_cast<QQmlContextPrivate *>(QObjectPrivate::get(o: context));
97 }
98 static QQmlContext *get(QQmlContextPrivate *context) {
99 return static_cast<QQmlContext *>(context->q_func());
100 }
101
102 // Only used for debugging
103 QList<QPointer<QObject> > instances;
104
105 static int context_count(QQmlListProperty<QObject> *);
106 static QObject *context_at(QQmlListProperty<QObject> *, int);
107
108 void dropDestroyedQObject(const QString &name, QObject *destroyed);
109};
110
111class QQmlComponentAttached;
112
113class Q_QML_PRIVATE_EXPORT QQmlContextData
114{
115public:
116 QQmlContextData();
117 QQmlContextData(QQmlContext *);
118 void emitDestruction();
119 void clearContext();
120 void clearContextRecursively();
121 void invalidate();
122
123 inline bool isValid() const {
124 return engine && (!isInternal || !contextObject || !QObjectPrivate::get(o: contextObject)->wasDeleted);
125 }
126
127 // My parent context and engine
128 QQmlContextData *parent = nullptr;
129 QQmlEngine *engine;
130
131 void setParent(QQmlContextData *, bool stronglyReferencedByParent = false);
132 void refreshExpressions();
133
134 void addObject(QQmlData *data);
135
136 QUrl resolvedUrl(const QUrl &);
137
138 // My containing QQmlContext. If isInternal is true this owns publicContext.
139 // If internal is false publicContext owns this.
140 QQmlContext *asQQmlContext();
141 QQmlContextPrivate *asQQmlContextPrivate();
142 quint32 refCount = 0;
143 quint32 isInternal:1;
144 quint32 isJSContext:1;
145 quint32 isPragmaLibraryContext:1;
146 quint32 unresolvedNames:1; // True if expressions in this context failed to resolve a toplevel name
147 quint32 hasEmittedDestruction:1;
148 quint32 isRootObjectInCreation:1;
149 quint32 stronglyReferencedByParent:1;
150 quint32 hasExtraObject:1; // used in QQmlDelegateModelItem::dataForObject to find the corresponding QQmlDelegateModelItem of an object
151 quint32 dummy:24;
152 QQmlContext *publicContext;
153
154 union {
155 // The incubator that is constructing this context if any
156 QQmlIncubatorPrivate *incubator;
157 // a pointer to extra data, currently only used in QQmlDelegateModel
158 QObject *extraObject;
159 };
160
161 // Compilation unit for contexts that belong to a compiled type.
162 QQmlRefPointer<QV4::ExecutableCompilationUnit> typeCompilationUnit;
163
164 // object index in CompiledData::Unit to component that created this context
165 int componentObjectIndex;
166
167 void initFromTypeCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit, int subComponentIndex);
168
169 // flag indicates whether the context owns the cache (after mutation) or not.
170 mutable QV4::IdentifierHash propertyNameCache;
171 const QV4::IdentifierHash &propertyNames() const;
172 QV4::IdentifierHash &detachedPropertyNames();
173
174 // Context object
175 QObject *contextObject;
176
177 // Any script blocks that exist on this context
178 QV4::PersistentValue importedScripts; // This is a JS Array
179
180 QUrl baseUrl;
181 QString baseUrlString;
182
183 QUrl url() const;
184 QString urlString() const;
185
186 // List of imports that apply to this context
187 QQmlRefPointer<QQmlTypeNameCache> imports;
188
189 // My children
190 QQmlContextData *childContexts = nullptr;
191
192 // My peers in parent's childContexts list
193 QQmlContextData *nextChild;
194 QQmlContextData **prevChild;
195
196 // Expressions that use this context
197 QQmlJavaScriptExpression *expressions;
198
199 // Doubly-linked list of objects that are owned by this context
200 QQmlData *contextObjects;
201
202 // Doubly-linked list of context guards (XXX merge with contextObjects)
203 QQmlGuardedContextData *contextGuards = nullptr;
204
205 // id guards
206 struct ContextGuard : public QQmlGuard<QObject>
207 {
208 inline ContextGuard();
209 inline ContextGuard &operator=(QObject *obj);
210 inline void objectDestroyed(QObject *) override;
211
212 inline bool wasSet() const;
213
214 QFlagPointer<QQmlContextData> context;
215 QQmlNotifier bindings;
216 };
217 ContextGuard *idValues;
218 int idValueCount;
219 void setIdProperty(int, QObject *);
220
221 // Linked contexts. this owns linkedContext.
222 QQmlContextDataRef linkedContext;
223
224 // Linked list of uses of the Component attached property in this
225 // context
226 QQmlComponentAttached *componentAttached;
227
228 // Return the outermost id for obj, if any.
229 QString findObjectId(const QObject *obj) const;
230
231 static QQmlContextData *get(QQmlContext *context) {
232 return QQmlContextPrivate::get(context)->data;
233 }
234
235private:
236 friend class QQmlContextDataRef;
237 friend class QQmlContext; // needs to do manual refcounting :/
238 void refreshExpressionsRecursive(bool isGlobal);
239 void refreshExpressionsRecursive(QQmlJavaScriptExpression *);
240 ~QQmlContextData();
241 void destroy();
242};
243
244
245class QQmlGuardedContextData
246{
247public:
248 inline QQmlGuardedContextData() = default;
249 inline QQmlGuardedContextData(QQmlContextData *data)
250 { setContextData(data); }
251 inline ~QQmlGuardedContextData()
252 { clear(); }
253
254 inline QQmlContextData *contextData() const
255 { return m_contextData; }
256 inline void setContextData(QQmlContextData *);
257
258 inline bool isNull() const { return !m_contextData; }
259
260 inline operator QQmlContextData*() const { return m_contextData; }
261 inline QQmlContextData* operator->() const { return m_contextData; }
262 inline QQmlGuardedContextData &operator=(QQmlContextData *d) {
263 setContextData(d); return *this;
264 }
265
266private:
267 QQmlGuardedContextData &operator=(const QQmlGuardedContextData &) = delete;
268 QQmlGuardedContextData(const QQmlGuardedContextData &) = delete;
269 friend class QQmlContextData;
270
271 inline void clear();
272
273 QQmlContextData *m_contextData = nullptr;
274 QQmlGuardedContextData *m_next = nullptr;
275 QQmlGuardedContextData **m_prev = nullptr;
276};
277
278
279void QQmlGuardedContextData::setContextData(QQmlContextData *contextData)
280 {
281 if (m_contextData == contextData)
282 return;
283 clear();
284
285 if (contextData) {
286 m_contextData = contextData;
287 m_next = contextData->contextGuards;
288 if (m_next) m_next->m_prev = &m_next;
289 m_prev = &contextData->contextGuards;
290 contextData->contextGuards = this;
291 }
292}
293
294void QQmlGuardedContextData::clear()
295{
296 if (m_prev) {
297 *m_prev = m_next;
298 if (m_next) m_next->m_prev = m_prev;
299 m_contextData = nullptr;
300 m_next = nullptr;
301 m_prev = nullptr;
302 }
303}
304
305QQmlContextDataRef::QQmlContextDataRef()
306 : m_contextData(nullptr)
307{
308}
309
310QQmlContextDataRef::QQmlContextDataRef(const QQmlContextDataRef &other)
311 : m_contextData(other.m_contextData)
312{
313 if (m_contextData)
314 ++m_contextData->refCount;
315}
316
317QQmlContextDataRef::QQmlContextDataRef(QQmlContextData *data)
318 : m_contextData(data)
319{
320 if (m_contextData)
321 ++m_contextData->refCount;
322}
323
324QQmlContextDataRef::~QQmlContextDataRef()
325{
326 clear();
327}
328
329void QQmlContextDataRef::setContextData(QQmlContextData *contextData)
330{
331 if (m_contextData == contextData)
332 return;
333 clear();
334
335 if (contextData) {
336 m_contextData = contextData;
337 ++m_contextData->refCount;
338 }
339}
340
341QQmlContextData *QQmlContextDataRef::contextData() const
342{
343 return m_contextData;
344}
345
346void QQmlContextDataRef::clear()
347{
348 if (m_contextData && !--m_contextData->refCount)
349 m_contextData->destroy();
350 m_contextData = nullptr;
351}
352
353QQmlContextDataRef &
354QQmlContextDataRef::operator=(QQmlContextData *d)
355{
356 setContextData(d);
357 return *this;
358}
359
360QQmlContextDataRef &
361QQmlContextDataRef::operator=(const QQmlContextDataRef &other)
362{
363 setContextData(other.m_contextData);
364 return *this;
365}
366
367QQmlContextData::ContextGuard::ContextGuard()
368: context(nullptr)
369{
370}
371
372QQmlContextData::ContextGuard &QQmlContextData::ContextGuard::operator=(QObject *obj)
373{
374 QQmlGuard<QObject>::operator=(obj);
375 context.setFlag();
376 bindings.notify(); // For alias connections
377 return *this;
378}
379
380void QQmlContextData::ContextGuard::objectDestroyed(QObject *)
381{
382 if (context->contextObject && !QObjectPrivate::get(o: context->contextObject)->wasDeleted)
383 bindings.notify();
384}
385
386bool QQmlContextData::ContextGuard::wasSet() const
387{
388 return context.flag();
389}
390
391QT_END_NAMESPACE
392
393#endif // QQMLCONTEXT_P_H
394

source code of qtdeclarative/src/qml/qml/qqmlcontext_p.h