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.cpp
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#include "qqmlcontextdata_p.h"
5
6#include <QtQml/qqmlengine.h>
7#include <QtQml/private/qqmlcomponentattached_p.h>
8#include <QtQml/private/qqmljavascriptexpression_p.h>
9#include <QtQml/private/qqmlguardedcontextdata_p.h>
10
12
14{
15 Q_ASSERT(ddata);
17 if (ddata->context) {
18 Q_ASSERT(ddata->context != this);
19 Q_ASSERT(ddata->outerContext);
20 Q_ASSERT(ddata->outerContext != this);
21 QQmlRefPointer<QQmlContextData> c = ddata->context;
22 while (QQmlRefPointer<QQmlContextData> linked = c->linkedContext())
23 c = linked;
24 c->setLinkedContext(this);
25 } else {
26 ddata->context = this;
27 }
28 ddata->ownContext.reset(ddata->context);
29 } else if (!ddata->context) {
30 ddata->context = this;
31 }
32
33 addOwnedObject(ddata);
34}
35
37{
38 QUrl resolved;
39 if (src.isRelative() && !src.isEmpty()) {
40 const QUrl ownUrl = url();
41 if (ownUrl.isValid()) {
42 resolved = ownUrl.resolved(src);
43 } else {
44 for (QQmlRefPointer<QQmlContextData> ctxt = parent(); ctxt; ctxt = ctxt->parent()) {
45 const QUrl ctxtUrl = ctxt->url();
46 if (ctxtUrl.isValid()) {
47 resolved = ctxtUrl.resolved(src);
48 break;
49 }
50 }
51
52 if (m_engine && resolved.isEmpty())
53 resolved = m_engine->baseUrl().resolved(src);
54 }
55 } else {
56 resolved = src;
57 }
58
59 if (resolved.isEmpty()) //relative but no ctxt
60 return resolved;
61
62 return m_engine ? m_engine->interceptUrl(resolved, QQmlAbstractUrlInterceptor::UrlString)
63 : resolved;
64}
65
67{
68 if (!m_hasEmittedDestruction) {
69 m_hasEmittedDestruction = true;
70
71 // Emit the destruction signal - must be emitted before invalidate so that the
72 // context is still valid if bindings or resultant expression evaluation requires it
73 if (m_engine) {
74 while (m_componentAttacheds) {
75 QQmlComponentAttached *attached = m_componentAttacheds;
76 attached->removeFromList();
77 emit attached->destruction();
78 }
79
80 for (QQmlRefPointer<QQmlContextData> child = m_childContexts; !child.isNull(); child = child->m_nextChild)
81 child->emitDestruction();
82 }
83 }
84}
85
87{
89
90 while (m_childContexts) {
91 Q_ASSERT(m_childContexts != this);
92 m_childContexts->invalidate();
93 }
94
95 if (m_prevChild) {
96 *m_prevChild = m_nextChild;
97 if (m_nextChild) m_nextChild->m_prevChild = m_prevChild;
98 m_nextChild = nullptr;
99 m_prevChild = nullptr;
100 }
101
102 m_importedScripts.clear();
103
104 m_engine = nullptr;
105 clearParent();
106}
107
109{
110 clearContext();
111
112 for (auto ctxIt = m_childContexts; ctxIt; ctxIt = ctxIt->m_nextChild)
113 ctxIt->clearContextRecursively();
114}
115
117{
119
120 QQmlJavaScriptExpression *expression = m_expressions;
121 while (expression) {
122 QQmlJavaScriptExpression *nextExpression = expression->m_nextExpression;
123
124 expression->m_prevExpression = nullptr;
125 expression->m_nextExpression = nullptr;
126
127 expression->setContext(nullptr);
128
129 expression = nextExpression;
130 }
131 m_expressions = nullptr;
132}
133
134QQmlContextData::~QQmlContextData()
135{
136 Q_ASSERT(refCount() == 0);
137
138 // avoid recursion
139 addref();
140 if (m_engine)
141 invalidate();
142 m_linkedContext.reset();
143
144 Q_ASSERT(refCount() == 1);
145 clearContext();
146 Q_ASSERT(refCount() == 1);
147
148 while (m_ownedObjects) {
149 QQmlData *co = m_ownedObjects;
150 m_ownedObjects = m_ownedObjects->nextContextObject;
151
152 if (co->context == this)
153 co->context = nullptr;
154 co->outerContext = nullptr;
155 co->nextContextObject = nullptr;
156 co->prevContextObject = nullptr;
157 }
158 Q_ASSERT(refCount() == 1);
159
160 QQmlGuardedContextData *contextGuard = m_contextGuards;
161 while (contextGuard) {
162 // TODO: Is this dead code? Why?
163 QQmlGuardedContextData *next = contextGuard->next();
164 contextGuard->setContextData({});
165 contextGuard = next;
166 }
167 m_contextGuards = nullptr;
168 Q_ASSERT(refCount() == 1);
169
170 delete [] m_idValues;
171 m_idValues = nullptr;
172
173 Q_ASSERT(refCount() == 1);
174 if (m_publicContext)
175 delete m_publicContext;
176
177 Q_ASSERT(refCount() == 1);
178}
179
180void QQmlContextData::refreshExpressionsRecursive(QQmlJavaScriptExpression *expression)
181{
183
184 if (expression->m_nextExpression)
185 refreshExpressionsRecursive(expression->m_nextExpression);
186
187 if (!w.wasDeleted())
188 expression->refresh();
189}
190
191void QQmlContextData::refreshExpressionsRecursive(bool isGlobal)
192{
193 // For efficiency, we try and minimize the number of guards we have to create
194 if (hasExpressionsToRun(isGlobal) && (m_nextChild || m_childContexts)) {
195 QQmlGuardedContextData guard(this);
196
197 if (m_childContexts)
198 m_childContexts->refreshExpressionsRecursive(isGlobal);
199
200 if (guard.isNull()) return;
201
202 if (m_nextChild)
203 m_nextChild->refreshExpressionsRecursive(isGlobal);
204
205 if (guard.isNull()) return;
206
207 if (hasExpressionsToRun(isGlobal))
208 refreshExpressionsRecursive(m_expressions);
209
210 } else if (hasExpressionsToRun(isGlobal)) {
211 refreshExpressionsRecursive(m_expressions);
212 } else if (m_nextChild && m_childContexts) {
213 QQmlGuardedContextData guard(this);
214 m_childContexts->refreshExpressionsRecursive(isGlobal);
215 if (!guard.isNull() && m_nextChild)
216 m_nextChild->refreshExpressionsRecursive(isGlobal);
217 } else if (m_nextChild) {
218 m_nextChild->refreshExpressionsRecursive(isGlobal);
219 } else if (m_childContexts) {
220 m_childContexts->refreshExpressionsRecursive(isGlobal);
221 }
222}
223
224// Refreshes all expressions that could possibly depend on this context. Refreshing flushes all
225// context-tree dependent caches in the expressions, and should occur every time the context tree
226// *structure* (not values) changes.
228{
229 bool isGlobal = (m_parent == nullptr);
230
231 // For efficiency, we try and minimize the number of guards we have to create
232 if (hasExpressionsToRun(isGlobal) && m_childContexts) {
233 QQmlGuardedContextData guard(this);
234 m_childContexts->refreshExpressionsRecursive(isGlobal);
235 if (!guard.isNull() && hasExpressionsToRun(isGlobal))
236 refreshExpressionsRecursive(m_expressions);
237 } else if (hasExpressionsToRun(isGlobal)) {
238 refreshExpressionsRecursive(m_expressions);
239 } else if (m_childContexts) {
240 m_childContexts->refreshExpressionsRecursive(isGlobal);
241 }
242}
243
245{
246 if (data->outerContext) {
247 if (data->nextContextObject)
248 data->nextContextObject->prevContextObject = data->prevContextObject;
249 if (data->prevContextObject)
250 *data->prevContextObject = data->nextContextObject;
251 else if (data->outerContext->m_ownedObjects == data)
252 data->outerContext->m_ownedObjects = data->nextContextObject;
253 }
254
255 data->outerContext = this;
256
257 data->nextContextObject = m_ownedObjects;
258 if (data->nextContextObject)
260 data->prevContextObject = &m_ownedObjects;
261 m_ownedObjects = data;
262}
263
265{
266 m_idValues[idx] = obj;
267 m_idValues[idx].setContext(this);
268}
269
271{
272 for (int ii = 0; ii < m_idValueCount; ii++) {
273 if (m_idValues[ii] == obj)
274 return propertyName(ii);
275 }
276
277 const QVariant objVariant = QVariant::fromValue(obj);
278 if (m_publicContext) {
279 QQmlContextPrivate *p = QQmlContextPrivate::get(m_publicContext);
280 for (int ii = 0; ii < p->numPropertyValues(); ++ii)
281 if (p->propertyValue(ii) == objVariant)
282 return propertyName(ii);
283 }
284
285 if (m_contextObject) {
286 // This is expensive, but nameForObject should really mirror contextProperty()
287 for (const QMetaObject *metaObject = m_contextObject->metaObject();
288 metaObject; metaObject = metaObject->superClass()) {
289 for (int i = metaObject->propertyOffset(), end = metaObject->propertyCount();
290 i != end; ++i) {
291 const QMetaProperty prop = metaObject->property(i);
293 && prop.read(m_contextObject) == objVariant) {
294 return QString::fromUtf8(prop.name());
295 }
296 }
297 }
298 }
299
300 return QString();
301}
302
303void QQmlContextData::initFromTypeCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit, int subComponentIndex)
304{
305 m_typeCompilationUnit = unit;
306 m_componentObjectIndex = subComponentIndex == -1 ? /*root object*/0 : subComponentIndex;
307 Q_ASSERT(!m_idValues);
308 m_idValueCount = m_typeCompilationUnit->objectAt(m_componentObjectIndex)
310 m_idValues = new ContextGuard[m_idValueCount];
311}
312
314{
315 attached->insertIntoList(&m_componentAttacheds);
316}
317
319{
320 expression->insertIntoList(&m_expressions);
321}
322
323void QQmlContextData::initPropertyNames() const
324{
325 if (m_typeCompilationUnit)
326 m_propertyNameCache = m_typeCompilationUnit->namedObjectsPerComponent(m_componentObjectIndex);
327 else
328 m_propertyNameCache = QV4::IdentifierHash(m_engine->handle());
329 Q_ASSERT(!m_propertyNameCache.isEmpty());
330}
331
333{
334 if (m_typeCompilationUnit)
335 return m_typeCompilationUnit->finalUrl();
336 return m_baseUrl;
337}
338
340{
341 if (m_typeCompilationUnit)
342 return m_typeCompilationUnit->finalUrlString();
343 return m_baseUrlString;
344}
345
QV4::ExecutionEngine * handle() const
Definition qjsengine.h:298
\inmodule QtCore
QMetaType metaType() const
QVariant read(const QObject *obj) const
Reads the property's value from the given object.
const char * name() const
Returns this property's name.
constexpr TypeFlags flags() const
Definition qmetatype.h:2658
@ PointerToQObject
Definition qmetatype.h:406
\inmodule QtCore
Definition qobject.h:103
void insertIntoList(QQmlComponentAttached **listHead)
QString findObjectId(const QObject *obj) const
QUrl resolvedUrl(const QUrl &) const
void installContext(QQmlData *ddata, QmlObjectKind kind)
void initFromTypeCompilationUnit(const QQmlRefPointer< QV4::ExecutableCompilationUnit > &unit, int subComponentIndex)
void addExpression(QQmlJavaScriptExpression *expression)
void addComponentAttached(QQmlComponentAttached *attached)
void addOwnedObject(QQmlData *ownedObject)
void setIdValue(int index, QObject *idValue)
void addref() const
QString urlString() const
QQmlRefPointer< QQmlContextData > parent() const
QString propertyName(int index) const
static QQmlContextPrivate * get(QQmlContext *context)
QQmlContextData * context
Definition qqmldata_p.h:147
QQmlData ** prevContextObject
Definition qqmldata_p.h:158
QQmlData * nextContextObject
Definition qqmldata_p.h:157
QUrl baseUrl() const
Return the base URL for this engine.
QUrl interceptUrl(const QUrl &url, QQmlAbstractUrlInterceptor::DataType type) const
Run the current URL interceptors on the given url of the given type and return the result.
void insertIntoList(QQmlJavaScriptExpression **listHead)
void setContext(const QQmlRefPointer< QQmlContextData > &context)
void reset(T *t=nullptr)
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
\inmodule QtCore
Definition qurl.h:94
QString url(FormattingOptions options=FormattingOptions(PrettyDecoded)) const
Returns a string representation of the URL.
Definition qurl.cpp:2817
QUrl resolved(const QUrl &relative) const
Returns the result of the merge of this URL with relative.
Definition qurl.cpp:2725
bool isEmpty() const
Returns true if the URL has no data; otherwise returns false.
Definition qurl.cpp:1896
const CompiledObject * objectAt(int index) const
IdentifierHash namedObjectsPerComponent(int componentObjectIndex)
\inmodule QtCore
Definition qvariant.h:65
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
Definition qvariant.h:536
short next
Definition keywords.cpp:445
Combined button and popup list for selecting options.
GLfloat GLfloat GLfloat w
[0]
GLuint GLuint end
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum src
GLhandleARB obj
[2]
const GLubyte * c
GLfloat GLfloat p
[1]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define emit
obj metaObject() -> className()
QLayoutItem * child
[0]
\inmodule QtCore