Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qqmlcontextdata_p.h
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
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 QQMLCONTEXTDATA_P_H
5#define QQMLCONTEXTDATA_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 purely as an
12// implementation detail. 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 <QtQml/private/qtqmlglobal_p.h>
19#include <QtQml/private/qqmlcontext_p.h>
20#include <QtQml/private/qqmlguard_p.h>
21#include <QtQml/private/qqmltypenamecache_p.h>
22#include <QtQml/private/qqmlnotifier_p.h>
23#include <QtQml/private/qv4identifierhash_p.h>
24#include <QtQml/private/qv4executablecompilationunit_p.h>
25
27
32
33class Q_QML_EXPORT QQmlContextData
34{
35public:
36 static QQmlRefPointer<QQmlContextData> createRefCounted(
37 const QQmlRefPointer<QQmlContextData> &parent)
38 {
39 return QQmlRefPointer<QQmlContextData>(new QQmlContextData(RefCounted, nullptr, parent),
41 }
42
43 // Owned by the parent. When the parent is reset to nullptr, it will be deref'd.
44 static QQmlRefPointer<QQmlContextData> createChild(
45 const QQmlRefPointer<QQmlContextData> &parent)
46 {
47 Q_ASSERT(!parent.isNull());
48 return QQmlRefPointer<QQmlContextData>(new QQmlContextData(OwnedByParent, nullptr, parent));
49 }
50
51 void addref() const { ++m_refCount; }
52 void release() const { if (--m_refCount == 0) delete this; }
53 int count() const { return m_refCount; }
54 int refCount() const { return m_refCount; }
55
56 QQmlRefPointer<QV4::ExecutableCompilationUnit> typeCompilationUnit() const
57 {
58 return m_typeCompilationUnit;
59 }
60 void initFromTypeCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit,
61 int subComponentIndex);
62
63 static QQmlRefPointer<QQmlContextData> get(QQmlContext *context) {
64 return QQmlContextPrivate::get(context)->m_data;
65 }
66
67 void emitDestruction();
68 void clearContext();
69 void clearContextRecursively();
70 void invalidate();
71
72 bool isValid() const
73 {
74 return m_engine && (!m_isInternal || !m_contextObject
75 || !QObjectPrivate::get(m_contextObject)->wasDeleted);
76 }
77
78 bool isInternal() const { return m_isInternal; }
79 void setInternal(bool isInternal) { m_isInternal = isInternal; }
80
81 bool isJSContext() const { return m_isJSContext; }
82 void setJSContext(bool isJSContext) { m_isJSContext = isJSContext; }
83
84 bool isPragmaLibraryContext() const { return m_isPragmaLibraryContext; }
85 void setPragmaLibraryContext(bool library) { m_isPragmaLibraryContext = library; }
86
87 QQmlRefPointer<QQmlContextData> parent() const { return m_parent; }
89 {
90 if (!m_parent)
91 return;
92
93 m_parent = nullptr;
94 if (m_ownedByParent) {
95 m_ownedByParent = false;
96 release();
97 }
98 }
99
100 void refreshExpressions();
101
102 void addOwnedObject(QQmlData *ownedObject);
103 QQmlData *ownedObjects() const { return m_ownedObjects; }
104 void setOwnedObjects(QQmlData *ownedObjects) { m_ownedObjects = ownedObjects; }
105
110 void installContext(QQmlData *ddata, QmlObjectKind kind);
111
112 QUrl resolvedUrl(const QUrl &) const;
113
114 // My containing QQmlContext. If isInternal is true this owns publicContext.
115 // If internal is false publicContext owns this.
117 {
118 if (!m_publicContext)
119 m_publicContext = new QQmlContext(*new QQmlContextPrivate(this));
120 return m_publicContext;
121 }
122
124 {
125 return QQmlContextPrivate::get(asQQmlContext());
126 }
127
128 QObject *contextObject() const { return m_contextObject; }
129 void setContextObject(QObject *contextObject) { m_contextObject = contextObject; }
130
131 template<typename HandleSelf, typename HandleLinked>
133 QObject *contextObject, HandleSelf &&handleSelf, HandleLinked &&handleLinked) {
134 for (QQmlContextData *lc = m_linkedContext.data(); lc; lc = lc->m_linkedContext.data()) {
135 handleLinked(lc);
136 if (lc->m_contextObject == contextObject)
137 lc->m_contextObject = nullptr;
138 }
139
140 handleSelf(this);
141 if (m_contextObject == contextObject)
142 m_contextObject = nullptr;
143 }
144
145 void deepClearContextObject(QObject *contextObject)
146 {
147 deepClearContextObject(
148 contextObject,
149 [](QQmlContextData *self) { self->emitDestruction(); },
150 [](QQmlContextData *){});
151 }
152
153 QQmlEngine *engine() const { return m_engine; }
154 void setEngine(QQmlEngine *engine) { m_engine = engine; }
155
156 QQmlContext *publicContext() const { return m_publicContext; }
158 {
159 if (!m_publicContext)
160 return;
161
162 m_publicContext = nullptr;
163 if (m_ownedByPublicContext) {
164 m_ownedByPublicContext = false;
165 release();
166 }
167 }
168
169 int propertyIndex(const QString &name) const
170 {
171 ensurePropertyNames();
172 return m_propertyNameCache.value(name);
173 }
174
176 {
177 ensurePropertyNames();
178 return m_propertyNameCache.value(name);
179 }
180
182 {
183 ensurePropertyNames();
184 return m_propertyNameCache.findId(index);
185 }
186
188 {
189 Q_ASSERT(!m_propertyNameCache.isEmpty());
190 m_propertyNameCache.add(name, index);
191 }
192
193 void setExpressions(QQmlJavaScriptExpression *expressions) { m_expressions = expressions; }
195 {
196 QQmlJavaScriptExpression *expressions = m_expressions;
197 m_expressions = nullptr;
198 return expressions;
199 }
200
201 void setChildContexts(const QQmlRefPointer<QQmlContextData> &childContexts)
202 {
203 m_childContexts = childContexts.data();
204 }
205 QQmlRefPointer<QQmlContextData> childContexts() const { return m_childContexts; }
206 QQmlRefPointer<QQmlContextData> takeChildContexts()
207 {
208 QQmlRefPointer<QQmlContextData> childContexts = m_childContexts;
209 m_childContexts = nullptr;
210 return childContexts;
211 }
212 QQmlRefPointer<QQmlContextData> nextChild() const { return m_nextChild; }
213
214 int numIdValues() const { return m_idValueCount; }
215 void setIdValue(int index, QObject *idValue);
216 bool isIdValueSet(int index) const { return m_idValues[index].wasSet(); }
217 QQmlNotifier *idValueBindings(int index) const { return m_idValues[index].bindings(); }
218 QObject *idValue(int index) const { return m_idValues[index].data(); }
219
220 // Return the outermost id for obj, if any.
221 QString findObjectId(const QObject *obj) const;
222
223 // url() and urlString() prefer the CU's URL over explicitly set baseUrls. They
224 // don't search the context hierarchy.
225 // baseUrl() and baseUrlString() search the context hierarchy and prefer explicit
226 // base URLs over CU Urls.
227
228 QUrl url() const;
229 QString urlString() const;
230
231 void setBaseUrlString(const QString &baseUrlString) { m_baseUrlString = baseUrlString; }
233 {
234 for (const QQmlContextData *data = this; data; data = data->m_parent) {
235 if (!data->m_baseUrlString.isEmpty())
236 return data->m_baseUrlString;
237 if (data->m_typeCompilationUnit)
238 return data->m_typeCompilationUnit->finalUrlString();
239 }
240 return QString();
241 }
242
243 void setBaseUrl(const QUrl &baseUrl) { m_baseUrl = baseUrl; }
244 QUrl baseUrl() const
245 {
246 for (const QQmlContextData *data = this; data; data = data->m_parent) {
247 if (!data->m_baseUrl.isEmpty())
248 return data->m_baseUrl;
249 if (data->m_typeCompilationUnit)
250 return data->m_typeCompilationUnit->finalUrl();
251 }
252 return QUrl();
253 }
254
255 QQmlRefPointer<QQmlTypeNameCache> imports() const { return m_imports; }
256 void setImports(const QQmlRefPointer<QQmlTypeNameCache> &imports) { m_imports = imports; }
257
258 QQmlIncubatorPrivate *incubator() const { return m_hasExtraObject ? nullptr : m_incubator; }
260 {
261 Q_ASSERT(!m_hasExtraObject || m_extraObject == nullptr);
262 m_hasExtraObject = false;
263 m_incubator = incubator;
264 }
265
266 QObject *extraObject() const { return m_hasExtraObject ? m_extraObject : nullptr; }
267 void setExtraObject(QObject *extraObject)
268 {
269 Q_ASSERT(m_hasExtraObject || m_incubator == nullptr);
270 m_hasExtraObject = true;
271 m_extraObject = extraObject;
272 }
273
274 bool isRootObjectInCreation() const { return m_isRootObjectInCreation; }
275 void setRootObjectInCreation(bool rootInCreation) { m_isRootObjectInCreation = rootInCreation; }
276
277 QV4::PersistentValue importedScripts() const { return m_importedScripts; }
278 void setImportedScripts(const QV4::PersistentValue &scripts) { m_importedScripts = scripts; }
279
280 QQmlRefPointer<QQmlContextData> linkedContext() const { return m_linkedContext; }
281 void setLinkedContext(const QQmlRefPointer<QQmlContextData> &context) { m_linkedContext = context; }
282
283 bool hasUnresolvedNames() const { return m_unresolvedNames; }
284 void setUnresolvedNames(bool hasUnresolvedNames) { m_unresolvedNames = hasUnresolvedNames; }
285
286 QQmlComponentAttached *componentAttacheds() const { return m_componentAttacheds; }
287 void addComponentAttached(QQmlComponentAttached *attached);
288
289 void addExpression(QQmlJavaScriptExpression *expression);
290
292 return m_typeCompilationUnit && m_typeCompilationUnit->valueTypesAreAddressable();
293 }
294
295private:
297 friend class QQmlContextPrivate;
298
299 enum Ownership {
300 RefCounted,
301 OwnedByParent,
302 OwnedByPublicContext
303 };
304
305 // id guards
306 struct ContextGuard : public QQmlGuard<QObject>
307 {
308 enum Tag {
309 NoTag,
310 ObjectWasSet
311 };
312
313 inline ContextGuard() : QQmlGuard<QObject>(&ContextGuard::objectDestroyedImpl, nullptr), m_context(nullptr) {}
314 inline ContextGuard &operator=(QObject *obj);
315
316 inline bool wasSet() const;
317
318 QQmlNotifier *bindings() { return &m_bindings; }
319 void setContext(const QQmlRefPointer<QQmlContextData> &context)
320 {
321 m_context = context.data();
322 }
323
324 private:
325 inline static void objectDestroyedImpl(QQmlGuardImpl *);
326 // Not refcounted, as it always belongs to the QQmlContextData.
327 QTaggedPointer<QQmlContextData, Tag> m_context;
328 QQmlNotifier m_bindings;
329 };
330
331 // It's OK to pass a half-created publicContext here. We will not dereference it during
332 // construction.
334 Ownership ownership, QQmlContext *publicContext,
335 const QQmlRefPointer<QQmlContextData> &parent, QQmlEngine *engine = nullptr)
336 : m_parent(parent.data()),
337 m_engine(engine ? engine : (parent.isNull() ? nullptr : parent->engine())),
338 m_isInternal(false), m_isJSContext(false), m_isPragmaLibraryContext(false),
339 m_unresolvedNames(false), m_hasEmittedDestruction(false), m_isRootObjectInCreation(false),
340 m_ownedByParent(ownership == OwnedByParent),
341 m_ownedByPublicContext(ownership == OwnedByPublicContext), m_hasExtraObject(false),
342 m_dummy(0), m_publicContext(publicContext), m_incubator(nullptr)
343 {
344 Q_ASSERT(!m_ownedByParent || !m_ownedByPublicContext);
345 if (!m_parent)
346 return;
347
348 m_nextChild = m_parent->m_childContexts;
349 if (m_nextChild)
350 m_nextChild->m_prevChild = &m_nextChild;
351 m_prevChild = &m_parent->m_childContexts;
352 m_parent->m_childContexts = this;
353 }
354
356
357 bool hasExpressionsToRun(bool isGlobalRefresh) const
358 {
359 return m_expressions && (!isGlobalRefresh || m_unresolvedNames);
360 }
361
362 void refreshExpressionsRecursive(bool isGlobal);
363 void refreshExpressionsRecursive(QQmlJavaScriptExpression *);
364 void initPropertyNames() const;
365
366 void ensurePropertyNames() const
367 {
368 if (m_propertyNameCache.isEmpty())
369 initPropertyNames();
370 Q_ASSERT(!m_propertyNameCache.isEmpty());
371 }
372
373 // My parent context and engine
374 QQmlContextData *m_parent = nullptr;
375 QQmlEngine *m_engine = nullptr;
376
377 mutable quint32 m_refCount = 1;
378 quint32 m_isInternal:1;
379 quint32 m_isJSContext:1;
380 quint32 m_isPragmaLibraryContext:1;
381 quint32 m_unresolvedNames:1; // True if expressions in this context failed to resolve a toplevel name
382 quint32 m_hasEmittedDestruction:1;
383 quint32 m_isRootObjectInCreation:1;
384 quint32 m_ownedByParent:1;
385 quint32 m_ownedByPublicContext:1;
386 quint32 m_hasExtraObject:1; // used in QQmlDelegateModelItem::dataForObject to find the corresponding QQmlDelegateModelItem of an object
387 Q_DECL_UNUSED_MEMBER quint32 m_dummy:23;
388 QQmlContext *m_publicContext = nullptr;
389
390 union {
391 // The incubator that is constructing this context if any
393 // a pointer to extra data, currently only used in QQmlDelegateModel
395 };
396
397 // Compilation unit for contexts that belong to a compiled type.
398 QQmlRefPointer<QV4::ExecutableCompilationUnit> m_typeCompilationUnit;
399
400 // object index in CompiledData::Unit to component that created this context
401 int m_componentObjectIndex = -1;
402
403 // flag indicates whether the context owns the cache (after mutation) or not.
404 mutable QV4::IdentifierHash m_propertyNameCache;
405
406 // Context object
407 QObject *m_contextObject = nullptr;
408
409 // Any script blocks that exist on this context
410 QV4::PersistentValue m_importedScripts; // This is a JS Array
411
412 QUrl m_baseUrl;
413 QString m_baseUrlString;
414
415 // List of imports that apply to this context
416 QQmlRefPointer<QQmlTypeNameCache> m_imports;
417
418 // My children, not refcounted as that would create cyclic references
419 QQmlContextData *m_childContexts = nullptr;
420
421 // My peers in parent's childContexts list; not refcounted
422 QQmlContextData *m_nextChild = nullptr;
423 QQmlContextData **m_prevChild = nullptr;
424
425 // Expressions that use this context
426 QQmlJavaScriptExpression *m_expressions = nullptr;
427
428 // Doubly-linked list of objects that are owned by this context
429 QQmlData *m_ownedObjects = nullptr;
430
431 // Doubly-linked list of context guards (XXX merge with contextObjects)
432 QQmlGuardedContextData *m_contextGuards = nullptr;
433
434 ContextGuard *m_idValues = nullptr;
435 int m_idValueCount = 0;
436
437 // Linked contexts. this owns linkedContext.
438 QQmlRefPointer<QQmlContextData> m_linkedContext;
439
440 // Linked list of uses of the Component attached property in this context
441 QQmlComponentAttached *m_componentAttacheds = nullptr;
442};
443
444QQmlContextData::ContextGuard &QQmlContextData::ContextGuard::operator=(QObject *obj)
445{
447 m_context.setTag(ObjectWasSet);
448 m_bindings.notify(); // For alias connections
449 return *this;
450}
451
452 void QQmlContextData::ContextGuard::objectDestroyedImpl(QQmlGuardImpl *impl)
453{
454 auto This = static_cast<QQmlContextData::ContextGuard *>(impl);
455 if (QObject *contextObject = This->m_context->contextObject()) {
456 if (!QObjectPrivate::get(contextObject)->wasDeleted)
457 This->m_bindings.notify();
458 }
459}
460
461bool QQmlContextData::ContextGuard::wasSet() const
462{
463 return m_context.tag() == ObjectWasSet;
464}
465
467
468#endif // QQMLCONTEXTDATA_P_H
static QObjectPrivate * get(QObject *o)
Definition qobject_p.h:150
\inmodule QtCore
Definition qobject.h:103
QObject * idValue(int index) const
void setContextObject(QObject *contextObject)
bool hasUnresolvedNames() const
void setRootObjectInCreation(bool rootInCreation)
void deepClearContextObject(QObject *contextObject, HandleSelf &&handleSelf, HandleLinked &&handleLinked)
int propertyIndex(const QString &name) const
void setOwnedObjects(QQmlData *ownedObjects)
void deepClearContextObject(QObject *contextObject)
QQmlContext * asQQmlContext()
void setInternal(bool isInternal)
QQmlRefPointer< QQmlTypeNameCache > imports() const
bool isJSContext() const
void setExtraObject(QObject *extraObject)
static QQmlRefPointer< QQmlContextData > get(QQmlContext *context)
bool valueTypesAreAddressable() const
int numIdValues() const
QQmlData * ownedObjects() const
QV4::PersistentValue importedScripts() const
void setEngine(QQmlEngine *engine)
QObject * contextObject() const
QQmlRefPointer< QQmlContextData > nextChild() const
bool isValid() const
QQmlIncubatorPrivate * incubator() const
bool isInternal() const
void setUnresolvedNames(bool hasUnresolvedNames)
QQmlRefPointer< QQmlContextData > takeChildContexts()
QQmlIncubatorPrivate * m_incubator
void setPragmaLibraryContext(bool library)
void setImportedScripts(const QV4::PersistentValue &scripts)
QString baseUrlString() const
QQmlNotifier * idValueBindings(int index) const
void setLinkedContext(const QQmlRefPointer< QQmlContextData > &context)
void release() const
static QQmlRefPointer< QQmlContextData > createChild(const QQmlRefPointer< QQmlContextData > &parent)
void setBaseUrl(const QUrl &baseUrl)
QQmlComponentAttached * componentAttacheds() const
QObject * extraObject() const
void setImports(const QQmlRefPointer< QQmlTypeNameCache > &imports)
void setIncubator(QQmlIncubatorPrivate *incubator)
QQmlRefPointer< QQmlContextData > childContexts() const
void setExpressions(QQmlJavaScriptExpression *expressions)
void addPropertyNameAndIndex(const QString &name, int index)
void setBaseUrlString(const QString &baseUrlString)
static QQmlRefPointer< QQmlContextData > createRefCounted(const QQmlRefPointer< QQmlContextData > &parent)
int propertyIndex(QV4::String *name) const
bool isIdValueSet(int index) const
QQmlRefPointer< QV4::ExecutableCompilationUnit > typeCompilationUnit() const
void addref() const
QQmlRefPointer< QQmlContextData > linkedContext() const
QQmlContext * publicContext() const
QQmlJavaScriptExpression * takeExpressions()
bool isPragmaLibraryContext() const
QQmlRefPointer< QQmlContextData > parent() const
void setChildContexts(const QQmlRefPointer< QQmlContextData > &childContexts)
void setJSContext(bool isJSContext)
QQmlEngine * engine() const
QQmlContextPrivate * asQQmlContextPrivate()
bool isRootObjectInCreation() const
QString propertyName(int index) const
static QQmlContextPrivate * get(QQmlContext *context)
The QQmlContext class defines a context within a QML engine.
Definition qqmlcontext.h:25
The QQmlEngine class provides an environment for instantiating QML components.
Definition qqmlengine.h:57
QQmlGuard< T > & operator=(const QQmlGuard< T > &o)
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
void setTag(Tag tag)
\inmodule QtCore
Definition qurl.h:94
Combined button and popup list for selecting options.
bool isNull(const T &t)
static void * context
#define Q_DECL_UNUSED_MEMBER
quint32 Tag
GLuint index
[2]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint name
GLhandleARB obj
[2]
static QUrl resolvedUrl(const QUrl &url, const QQmlRefPointer< QQmlContextData > &context)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
unsigned int quint32
Definition qtypes.h:50
QUrl url("example.com")
[constructor-url-reference]
QUrl baseUrl
QObject::connect nullptr
sem release()
QJSEngine engine
[0]