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#include "qqmlcontext.h"
41#include "qqmlcontext_p.h"
42#include "qqmlcomponentattached_p.h"
43
44#include "qqmlcomponent_p.h"
45#include "qqmlexpression_p.h"
46#include "qqmlengine_p.h"
47#include "qqmlengine.h"
48#include "qqmlinfo.h"
49#include "qqmlabstracturlinterceptor.h"
50
51#include <qjsengine.h>
52#include <QtCore/qvarlengtharray.h>
53#include <private/qmetaobject_p.h>
54#include <QtCore/qdebug.h>
55
56QT_BEGIN_NAMESPACE
57
58QQmlContextPrivate::QQmlContextPrivate()
59: data(nullptr), notifyIndex(-1)
60{
61}
62
63/*!
64 \class QQmlContext
65 \brief The QQmlContext class defines a context within a QML engine.
66 \inmodule QtQml
67
68 Contexts allow data to be exposed to the QML components instantiated by the
69 QML engine.
70
71 Each QQmlContext contains a set of properties, distinct from its QObject
72 properties, that allow data to be explicitly bound to a context by name. The
73 context properties are defined and updated by calling
74 QQmlContext::setContextProperty(). The following example shows a Qt model
75 being bound to a context and then accessed from a QML file.
76
77 \code
78 QQmlEngine engine;
79 QStringListModel modelData;
80 QQmlContext *context = new QQmlContext(engine.rootContext());
81 context->setContextProperty("myModel", &modelData);
82
83 QQmlComponent component(&engine);
84 component.setData("import QtQuick 2.0\nListView { model: myModel }", QUrl());
85 QObject *window = component.create(context);
86 \endcode
87
88 Note it is the responsibility of the creator to delete any QQmlContext it
89 constructs. If the \c context object in the example is no longer needed when the
90 \c window component instance is destroyed, the \c context must be destroyed explicitly.
91 The simplest way to ensure this is to set \c window as the parent of \c context.
92
93 To simplify binding and maintaining larger data sets, a context object can be set
94 on a QQmlContext. All the properties of the context object are available
95 by name in the context, as though they were all individually added through calls
96 to QQmlContext::setContextProperty(). Changes to the property's values are
97 detected through the property's notify signal. Setting a context object is both
98 faster and easier than manually adding and maintaining context property values.
99
100 The following example has the same effect as the previous one, but it uses a context
101 object.
102
103 \code
104 class MyDataSet : ... {
105 ...
106 Q_PROPERTY(QAbstractItemModel *myModel READ model NOTIFY modelChanged)
107 ...
108 };
109
110 MyDataSet myDataSet;
111 QQmlEngine engine;
112 QQmlContext *context = new QQmlContext(engine.rootContext());
113 context->setContextObject(&myDataSet);
114
115 QQmlComponent component(&engine);
116 component.setData("import QtQuick 2.0\nListView { model: myModel }", QUrl());
117 component.create(context);
118 \endcode
119
120 All properties added explicitly by QQmlContext::setContextProperty() take
121 precedence over the context object's properties.
122
123 \section2 The Context Hierarchy
124
125 Contexts form a hierarchy. The root of this hierarchy is the QML engine's
126 \l {QQmlEngine::rootContext()}{root context}. Child contexts inherit
127 the context properties of their parents; if a child context sets a context property
128 that already exists in its parent, the new context property overrides that of the
129 parent.
130
131 The following example defines two contexts - \c context1 and \c context2. The
132 second context overrides the "b" context property inherited from the first with a
133 new value.
134
135 \code
136 QQmlEngine engine;
137 QQmlContext *context1 = new QQmlContext(engine.rootContext());
138 QQmlContext *context2 = new QQmlContext(context1);
139
140 context1->setContextProperty("a", 12);
141 context1->setContextProperty("b", 12);
142
143 context2->setContextProperty("b", 15);
144 \endcode
145
146 While QML objects instantiated in a context are not strictly owned by that
147 context, their bindings are. If a context is destroyed, the property bindings of
148 outstanding QML objects will stop evaluating.
149
150 \warning Setting the context object or adding new context properties after an object
151 has been created in that context is an expensive operation (essentially forcing all bindings
152 to reevaluate). Thus whenever possible you should complete "setup" of the context
153 before using it to create any objects.
154
155 \sa {qtqml-cppintegration-exposecppattributes.html}{Exposing Attributes of C++ Types to QML}
156*/
157
158/*! \internal */
159QQmlContext::QQmlContext(QQmlEngine *e, bool)
160: QObject(*(new QQmlContextPrivate))
161{
162 Q_D(QQmlContext);
163 d->data = new QQmlContextData(this);
164 ++d->data->refCount;
165
166 d->data->engine = e;
167}
168
169/*!
170 Create a new QQmlContext as a child of \a engine's root context, and the
171 QObject \a parent.
172*/
173QQmlContext::QQmlContext(QQmlEngine *engine, QObject *parent)
174: QObject(*(new QQmlContextPrivate), parent)
175{
176 Q_D(QQmlContext);
177 d->data = new QQmlContextData(this);
178 ++d->data->refCount;
179
180 d->data->setParent(engine?QQmlContextData::get(engine->rootContext()):nullptr);
181}
182
183/*!
184 Create a new QQmlContext with the given \a parentContext, and the
185 QObject \a parent.
186*/
187QQmlContext::QQmlContext(QQmlContext *parentContext, QObject *parent)
188: QObject(*(new QQmlContextPrivate), parent)
189{
190 Q_D(QQmlContext);
191 d->data = new QQmlContextData(this);
192 ++d->data->refCount;
193
194 d->data->setParent(parentContext?QQmlContextData::get(parentContext):nullptr);
195}
196
197/*!
198 \internal
199*/
200QQmlContext::QQmlContext(QQmlContextData *data)
201: QObject(*(new QQmlContextPrivate), nullptr)
202{
203 Q_D(QQmlContext);
204 d->data = data;
205 // don't add a refcount here, as the data owns this context
206}
207
208/*!
209 Destroys the QQmlContext.
210
211 Any expressions, or sub-contexts dependent on this context will be
212 invalidated, but not destroyed (unless they are parented to the QQmlContext
213 object).
214 */
215QQmlContext::~QQmlContext()
216{
217 Q_D(QQmlContext);
218
219 d->data->publicContext = nullptr;
220 if (!--d->data->refCount)
221 d->data->destroy();
222}
223
224/*!
225 Returns whether the context is valid.
226
227 To be valid, a context must have a engine, and it's contextObject(), if any,
228 must not have been deleted.
229*/
230bool QQmlContext::isValid() const
231{
232 Q_D(const QQmlContext);
233 return d->data && d->data->isValid();
234}
235
236/*!
237 Return the context's QQmlEngine, or 0 if the context has no QQmlEngine or the
238 QQmlEngine was destroyed.
239*/
240QQmlEngine *QQmlContext::engine() const
241{
242 Q_D(const QQmlContext);
243 return d->data->engine;
244}
245
246/*!
247 Return the context's parent QQmlContext, or 0 if this context has no
248 parent or if the parent has been destroyed.
249*/
250QQmlContext *QQmlContext::parentContext() const
251{
252 Q_D(const QQmlContext);
253 return d->data->parent?d->data->parent->asQQmlContext():nullptr;
254}
255
256/*!
257 Return the context object, or 0 if there is no context object.
258*/
259QObject *QQmlContext::contextObject() const
260{
261 Q_D(const QQmlContext);
262 return d->data->contextObject;
263}
264
265/*!
266 Set the context \a object.
267*/
268void QQmlContext::setContextObject(QObject *object)
269{
270 Q_D(QQmlContext);
271
272 QQmlContextData *data = d->data;
273
274 if (data->isInternal) {
275 qWarning("QQmlContext: Cannot set context object for internal context.");
276 return;
277 }
278
279 if (!isValid()) {
280 qWarning("QQmlContext: Cannot set context object on invalid context.");
281 return;
282 }
283
284 data->contextObject = object;
285 data->refreshExpressions();
286}
287
288/*!
289 Set a the \a value of the \a name property on this context.
290*/
291void QQmlContext::setContextProperty(const QString &name, const QVariant &value)
292{
293 Q_D(QQmlContext);
294 if (d->notifyIndex == -1)
295 d->notifyIndex = QMetaObjectPrivate::absoluteSignalCount(&QQmlContext::staticMetaObject);
296
297 QQmlContextData *data = d->data;
298
299 if (data->isInternal) {
300 qWarning("QQmlContext: Cannot set property on internal context.");
301 return;
302 }
303
304 if (!isValid()) {
305 qWarning("QQmlContext: Cannot set property on invalid context.");
306 return;
307 }
308
309 QV4::IdentifierHash &properties = data->detachedPropertyNames();
310 int idx = properties.value(name);
311 if (idx == -1) {
312 properties.add(name, data->idValueCount + d->propertyValues.count());
313 d->propertyValues.append(value);
314
315 data->refreshExpressions();
316 } else {
317 d->propertyValues[idx] = value;
318 QMetaObject::activate(this, d->notifyIndex, idx, nullptr);
319 }
320
321 if (auto *obj = qvariant_cast<QObject *>(value)) {
322 connect(obj, &QObject::destroyed, this, [d, name](QObject *destroyed) {
323 d->dropDestroyedQObject(name, destroyed);
324 });
325 }
326}
327
328/*!
329 Set the \a value of the \a name property on this context.
330
331 QQmlContext does \b not take ownership of \a value.
332*/
333void QQmlContext::setContextProperty(const QString &name, QObject *value)
334{
335 setContextProperty(name, QVariant::fromValue(value));
336}
337
338/*!
339 \since 5.11
340
341 Set a batch of \a properties on this context.
342
343 Setting all properties in one batch avoids unnecessary
344 refreshing expressions, and is therefore recommended
345 instead of calling \l setContextProperty() for each individual property.
346
347 \sa QQmlContext::setContextProperty()
348*/
349void QQmlContext::setContextProperties(const QVector<PropertyPair> &properties)
350{
351 Q_D(const QQmlContext);
352
353 QQmlContextData *data = d->data;
354
355 QQmlJavaScriptExpression *expressions = data->expressions;
356 QQmlContextData *childContexts = data->childContexts;
357
358 data->expressions = nullptr;
359 data->childContexts = nullptr;
360
361 for (auto property : properties)
362 setContextProperty(property.name, property.value);
363
364 data->expressions = expressions;
365 data->childContexts = childContexts;
366
367 data->refreshExpressions();
368}
369
370/*!
371 \since 5.11
372
373 \class QQmlContext::PropertyPair
374 \inmodule QtQml
375
376 This struct contains a property name and a property value.
377 It is used as a parameter for the \c setContextProperties function.
378
379 \sa QQmlContext::setContextProperties()
380*/
381
382/*!
383 Returns the value of the \a name property for this context
384 as a QVariant.
385 */
386QVariant QQmlContext::contextProperty(const QString &name) const
387{
388 Q_D(const QQmlContext);
389 QVariant value;
390 int idx = -1;
391
392 QQmlContextData *data = d->data;
393
394 const QV4::IdentifierHash &properties = data->propertyNames();
395 if (properties.count())
396 idx = properties.value(name);
397
398 if (idx == -1) {
399 if (data->contextObject) {
400 QObject *obj = data->contextObject;
401 QQmlPropertyData local;
402 QQmlPropertyData *property =
403 QQmlPropertyCache::property(data->engine, obj, name, data, local);
404
405 if (property) value = obj->metaObject()->property(property->coreIndex()).read(obj);
406 }
407 if (!value.isValid() && parentContext())
408 value = parentContext()->contextProperty(name);
409 } else {
410 if (idx >= d->propertyValues.count())
411 value = QVariant::fromValue(data->idValues[idx - d->propertyValues.count()].data());
412 else
413 value = d->propertyValues[idx];
414 }
415
416 return value;
417}
418
419/*!
420Returns the name of \a object in this context, or an empty string if \a object
421is not named in the context. Objects are named by setContextProperty(), or by ids in
422the case of QML created contexts.
423
424If the object has multiple names, the first is returned.
425*/
426QString QQmlContext::nameForObject(QObject *object) const
427{
428 Q_D(const QQmlContext);
429
430 return d->data->findObjectId(object);
431}
432
433/*!
434 Resolves the URL \a src relative to the URL of the
435 containing component.
436
437 \sa QQmlEngine::baseUrl(), setBaseUrl()
438*/
439QUrl QQmlContext::resolvedUrl(const QUrl &src)
440{
441 Q_D(QQmlContext);
442 return d->data->resolvedUrl(src);
443}
444
445QUrl QQmlContextData::resolvedUrl(const QUrl &src)
446{
447 QUrl resolved;
448 if (src.isRelative() && !src.isEmpty()) {
449 QQmlContextData *ctxt = this;
450 do {
451 if (ctxt->url().isValid())
452 break;
453 else
454 ctxt = ctxt->parent;
455 } while (ctxt);
456
457 if (ctxt)
458 resolved = ctxt->url().resolved(src);
459 else if (engine)
460 resolved = engine->baseUrl().resolved(src);
461 } else {
462 resolved = src;
463 }
464
465 if (resolved.isEmpty()) //relative but no ctxt
466 return resolved;
467
468 if (engine && engine->urlInterceptor())
469 resolved = engine->urlInterceptor()->intercept(resolved, QQmlAbstractUrlInterceptor::UrlString);
470 return resolved;
471}
472
473
474/*!
475 Explicitly sets the url resolvedUrl() will use for relative references to \a baseUrl.
476
477 Calling this function will override the url of the containing
478 component used by default.
479
480 \sa resolvedUrl()
481*/
482void QQmlContext::setBaseUrl(const QUrl &baseUrl)
483{
484 Q_D(QQmlContext);
485
486 d->data->baseUrl = baseUrl;
487 d->data->baseUrlString = baseUrl.toString();
488}
489
490/*!
491 Returns the base url of the component, or the containing component
492 if none is set.
493*/
494QUrl QQmlContext::baseUrl() const
495{
496 Q_D(const QQmlContext);
497 const QQmlContextData* data = d->data;
498 while (data && data->url().isEmpty())
499 data = data->parent;
500
501 if (data)
502 return data->url();
503 else
504 return QUrl();
505}
506
507int QQmlContextPrivate::context_count(QQmlListProperty<QObject> *prop)
508{
509 QQmlContext *context = static_cast<QQmlContext*>(prop->object);
510 QQmlContextPrivate *d = QQmlContextPrivate::get(context);
511 int contextProperty = (int)(quintptr)prop->data;
512
513 if (d->propertyValues.at(contextProperty).userType() != qMetaTypeId<QList<QObject*> >()) {
514 return 0;
515 } else {
516 return ((const QList<QObject> *)d->propertyValues.at(contextProperty).constData())->count();
517 }
518}
519
520QObject *QQmlContextPrivate::context_at(QQmlListProperty<QObject> *prop, int index)
521{
522 QQmlContext *context = static_cast<QQmlContext*>(prop->object);
523 QQmlContextPrivate *d = QQmlContextPrivate::get(context);
524 int contextProperty = (int)(quintptr)prop->data;
525
526 if (d->propertyValues.at(contextProperty).userType() != qMetaTypeId<QList<QObject*> >()) {
527 return nullptr;
528 } else {
529 return ((const QList<QObject*> *)d->propertyValues.at(contextProperty).constData())->at(index);
530 }
531}
532
533void QQmlContextPrivate::dropDestroyedQObject(const QString &name, QObject *destroyed)
534{
535 const int idx = data->propertyNames().value(name);
536 Q_ASSERT(idx >= 0);
537 if (qvariant_cast<QObject *>(propertyValues[idx]) != destroyed)
538 return;
539
540 propertyValues[idx] = QVariant::fromValue<QObject *>(nullptr);
541 QMetaObject::activate(q_func(), notifyIndex, idx, nullptr);
542}
543
544
545QQmlContextData::QQmlContextData()
546 : QQmlContextData(nullptr)
547{
548}
549
550QQmlContextData::QQmlContextData(QQmlContext *ctxt)
551 : engine(nullptr), isInternal(false), isJSContext(false),
552 isPragmaLibraryContext(false), unresolvedNames(false), hasEmittedDestruction(false), isRootObjectInCreation(false),
553 stronglyReferencedByParent(false), publicContext(ctxt), incubator(nullptr), componentObjectIndex(-1),
554 contextObject(nullptr), nextChild(nullptr), prevChild(nullptr),
555 expressions(nullptr), contextObjects(nullptr), idValues(nullptr), idValueCount(0),
556 componentAttached(nullptr)
557{
558}
559
560void QQmlContextData::emitDestruction()
561{
562 if (!hasEmittedDestruction) {
563 hasEmittedDestruction = true;
564
565 // Emit the destruction signal - must be emitted before invalidate so that the
566 // context is still valid if bindings or resultant expression evaluation requires it
567 if (engine) {
568 while (componentAttached) {
569 QQmlComponentAttached *a = componentAttached;
570 componentAttached = a->next;
571 if (componentAttached) componentAttached->prev = &componentAttached;
572
573 a->next = nullptr;
574 a->prev = nullptr;
575
576 emit a->destruction();
577 }
578
579 QQmlContextData * child = childContexts;
580 while (child) {
581 child->emitDestruction();
582 child = child->nextChild;
583 }
584 }
585 }
586}
587
588void QQmlContextData::invalidate()
589{
590 emitDestruction();
591
592 while (childContexts) {
593 Q_ASSERT(childContexts != this);
594 if (childContexts->stronglyReferencedByParent && !--childContexts->refCount)
595 childContexts->destroy();
596 else
597 childContexts->invalidate();
598 }
599
600 if (prevChild) {
601 *prevChild = nextChild;
602 if (nextChild) nextChild->prevChild = prevChild;
603 nextChild = nullptr;
604 prevChild = nullptr;
605 }
606
607 importedScripts.clear();
608
609 engine = nullptr;
610 parent = nullptr;
611}
612
613void QQmlContextData::clearContextRecursively()
614{
615 clearContext();
616
617 for (auto ctxIt = childContexts; ctxIt; ctxIt = ctxIt->nextChild)
618 ctxIt->clearContextRecursively();
619}
620
621void QQmlContextData::clearContext()
622{
623 emitDestruction();
624
625 QQmlJavaScriptExpression *expression = expressions;
626 while (expression) {
627 QQmlJavaScriptExpression *nextExpression = expression->m_nextExpression;
628
629 expression->m_prevExpression = nullptr;
630 expression->m_nextExpression = nullptr;
631
632 expression->setContext(nullptr);
633
634 expression = nextExpression;
635 }
636 expressions = nullptr;
637}
638
639void QQmlContextData::destroy()
640{
641 Q_ASSERT(refCount == 0);
642 linkedContext = nullptr;
643
644 // avoid recursion
645 ++refCount;
646 if (engine)
647 invalidate();
648
649 Q_ASSERT(refCount == 1);
650 clearContext();
651 Q_ASSERT(refCount == 1);
652
653 while (contextObjects) {
654 QQmlData *co = contextObjects;
655 contextObjects = contextObjects->nextContextObject;
656
657 if (co->context == this)
658 co->context = nullptr;
659 co->outerContext = nullptr;
660 co->nextContextObject = nullptr;
661 co->prevContextObject = nullptr;
662 }
663 Q_ASSERT(refCount == 1);
664
665 QQmlGuardedContextData *contextGuard = contextGuards;
666 while (contextGuard) {
667 QQmlGuardedContextData *next = contextGuard->m_next;
668 contextGuard->m_next = nullptr;
669 contextGuard->m_prev = nullptr;
670 contextGuard->m_contextData = nullptr;
671 contextGuard = next;
672 }
673 contextGuards = nullptr;
674 Q_ASSERT(refCount == 1);
675
676 delete [] idValues;
677 idValues = nullptr;
678
679 Q_ASSERT(refCount == 1);
680 if (publicContext) {
681 // the QQmlContext destructor will remove one ref again
682 ++refCount;
683 delete publicContext;
684 }
685
686 Q_ASSERT(refCount == 1);
687 --refCount;
688 Q_ASSERT(refCount == 0);
689
690 delete this;
691}
692
693void QQmlContextData::setParent(QQmlContextData *p, bool stronglyReferencedByParent)
694{
695 if (p == parent)
696 return;
697 if (p) {
698 Q_ASSERT(!parent);
699 parent = p;
700 this->stronglyReferencedByParent = stronglyReferencedByParent;
701 if (stronglyReferencedByParent)
702 ++refCount; // balanced in QQmlContextData::invalidate()
703 engine = p->engine;
704 nextChild = p->childContexts;
705 if (nextChild) nextChild->prevChild = &nextChild;
706 prevChild = &p->childContexts;
707 p->childContexts = this;
708 }
709}
710
711void QQmlContextData::refreshExpressionsRecursive(QQmlJavaScriptExpression *expression)
712{
713 QQmlJavaScriptExpression::DeleteWatcher w(expression);
714
715 if (expression->m_nextExpression)
716 refreshExpressionsRecursive(expression->m_nextExpression);
717
718 if (!w.wasDeleted())
719 expression->refresh();
720}
721
722QQmlContextData::~QQmlContextData()
723{
724}
725
726static inline bool expressions_to_run(QQmlContextData *ctxt, bool isGlobalRefresh)
727{
728 return ctxt->expressions && (!isGlobalRefresh || ctxt->unresolvedNames);
729}
730
731void QQmlContextData::refreshExpressionsRecursive(bool isGlobal)
732{
733 // For efficiency, we try and minimize the number of guards we have to create
734 if (expressions_to_run(this, isGlobal) && (nextChild || childContexts)) {
735 QQmlGuardedContextData guard(this);
736
737 if (childContexts)
738 childContexts->refreshExpressionsRecursive(isGlobal);
739
740 if (guard.isNull()) return;
741
742 if (nextChild)
743 nextChild->refreshExpressionsRecursive(isGlobal);
744
745 if (guard.isNull()) return;
746
747 if (expressions_to_run(this, isGlobal))
748 refreshExpressionsRecursive(expressions);
749
750 } else if (expressions_to_run(this, isGlobal)) {
751
752 refreshExpressionsRecursive(expressions);
753
754 } else if (nextChild && childContexts) {
755
756 QQmlGuardedContextData guard(this);
757
758 childContexts->refreshExpressionsRecursive(isGlobal);
759
760 if (!guard.isNull() && nextChild)
761 nextChild->refreshExpressionsRecursive(isGlobal);
762
763 } else if (nextChild) {
764
765 nextChild->refreshExpressionsRecursive(isGlobal);
766
767 } else if (childContexts) {
768
769 childContexts->refreshExpressionsRecursive(isGlobal);
770
771 }
772}
773
774// Refreshes all expressions that could possibly depend on this context. Refreshing flushes all
775// context-tree dependent caches in the expressions, and should occur every time the context tree
776// *structure* (not values) changes.
777void QQmlContextData::refreshExpressions()
778{
779 bool isGlobal = (parent == nullptr);
780
781 // For efficiency, we try and minimize the number of guards we have to create
782 if (expressions_to_run(this, isGlobal) && childContexts) {
783 QQmlGuardedContextData guard(this);
784
785 childContexts->refreshExpressionsRecursive(isGlobal);
786
787 if (!guard.isNull() && expressions_to_run(this, isGlobal))
788 refreshExpressionsRecursive(expressions);
789
790 } else if (expressions_to_run(this, isGlobal)) {
791
792 refreshExpressionsRecursive(expressions);
793
794 } else if (childContexts) {
795
796 childContexts->refreshExpressionsRecursive(isGlobal);
797
798 }
799}
800
801void QQmlContextData::addObject(QQmlData *data)
802{
803 if (data->outerContext) {
804 if (data->nextContextObject)
805 data->nextContextObject->prevContextObject = data->prevContextObject;
806 if (data->prevContextObject)
807 *data->prevContextObject = data->nextContextObject;
808 else if (data->outerContext->contextObjects == data)
809 data->outerContext->contextObjects = data->nextContextObject;
810 }
811
812 data->outerContext = this;
813
814 data->nextContextObject = contextObjects;
815 if (data->nextContextObject)
816 data->nextContextObject->prevContextObject = &data->nextContextObject;
817 data->prevContextObject = &contextObjects;
818 contextObjects = data;
819}
820
821void QQmlContextData::setIdProperty(int idx, QObject *obj)
822{
823 idValues[idx] = obj;
824 idValues[idx].context = this;
825}
826
827QString QQmlContextData::findObjectId(const QObject *obj) const
828{
829 const QV4::IdentifierHash &properties = propertyNames();
830 if (propertyNameCache.isEmpty())
831 return QString();
832
833 for (int ii = 0; ii < idValueCount; ii++) {
834 if (idValues[ii] == obj)
835 return properties.findId(ii);
836 }
837
838 if (publicContext) {
839 QQmlContextPrivate *p = QQmlContextPrivate::get(publicContext);
840 for (int ii = 0; ii < p->propertyValues.count(); ++ii)
841 if (p->propertyValues.at(ii) == QVariant::fromValue(const_cast<QObject *>(obj)))
842 return properties.findId(ii);
843 }
844
845 if (linkedContext)
846 return linkedContext->findObjectId(obj);
847 return QString();
848}
849
850QQmlContext *QQmlContextData::asQQmlContext()
851{
852 if (!publicContext)
853 publicContext = new QQmlContext(this);
854 return publicContext;
855}
856
857QQmlContextPrivate *QQmlContextData::asQQmlContextPrivate()
858{
859 return QQmlContextPrivate::get(asQQmlContext());
860}
861
862void QQmlContextData::initFromTypeCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit, int subComponentIndex)
863{
864 typeCompilationUnit = unit;
865 componentObjectIndex = subComponentIndex == -1 ? /*root object*/0 : subComponentIndex;
866 Q_ASSERT(!idValues);
867 idValueCount = typeCompilationUnit->objectAt(componentObjectIndex)->nNamedObjectsInComponent;
868 idValues = new ContextGuard[idValueCount];
869}
870
871const QV4::IdentifierHash &QQmlContextData::propertyNames() const
872{
873 if (propertyNameCache.isEmpty()) {
874 if (typeCompilationUnit)
875 propertyNameCache = typeCompilationUnit->namedObjectsPerComponent(componentObjectIndex);
876 else
877 propertyNameCache = QV4::IdentifierHash(engine->handle());
878 }
879 return propertyNameCache;
880}
881
882QV4::IdentifierHash &QQmlContextData::detachedPropertyNames()
883{
884 propertyNames();
885 propertyNameCache.detach();
886 return propertyNameCache;
887}
888
889QUrl QQmlContextData::url() const
890{
891 if (typeCompilationUnit)
892 return typeCompilationUnit->finalUrl();
893 return baseUrl;
894}
895
896QString QQmlContextData::urlString() const
897{
898 if (typeCompilationUnit)
899 return typeCompilationUnit->finalUrlString();
900 return baseUrlString;
901}
902
903QT_END_NAMESPACE
904
905#include "moc_qqmlcontext.cpp"
906