1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qdeclarativecontext.h"
43 #include "private/qdeclarativecontext_p.h"
45 #include "private/qdeclarativecomponent_p.h"
46 #include "private/qdeclarativeexpression_p.h"
47 #include "private/qdeclarativeengine_p.h"
48 #include "qdeclarativeengine.h"
49 #include "qdeclarativeinfo.h"
50 #include "private/qdeclarativev4bindings_p.h"
51 #include "private/qv8bindings_p.h"
53 #include <qscriptengine.h>
54 #include <QtCore/qvarlengtharray.h>
55 #include <QtCore/qdebug.h>
57 #include <private/qscriptdeclarativeclass_p.h>
61 QDeclarativeContextPrivate::QDeclarativeContextPrivate()
62 : data(0), notifyIndex(-1)
67 \class QDeclarativeContext
69 \brief The QDeclarativeContext class defines a context within a QML engine.
72 Contexts allow data to be exposed to the QML components instantiated by the
75 Each QDeclarativeContext contains a set of properties, distinct from its QObject
76 properties, that allow data to be explicitly bound to a context by name. The
77 context properties are defined and updated by calling
78 QDeclarativeContext::setContextProperty(). The following example shows a Qt model
79 being bound to a context and then accessed from a QML file.
82 QDeclarativeEngine engine;
83 QStringListModel modelData;
84 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
85 context->setContextProperty("myModel", &modelData);
87 QDeclarativeComponent component(&engine);
88 component.setData("import QtQuick 1.0\nListView { model: myModel }", QUrl());
89 QObject *window = component.create(context);
92 Note it is the responsibility of the creator to delete any QDeclarativeContext it
93 constructs. If the \c context object in the example is no longer needed when the
94 \c window component instance is destroyed, the \c context must be destroyed explicitly.
95 The simplest way to ensure this is to set \c window as the parent of \c context.
97 To simplify binding and maintaining larger data sets, a context object can be set
98 on a QDeclarativeContext. All the properties of the context object are available
99 by name in the context, as though they were all individually added through calls
100 to QDeclarativeContext::setContextProperty(). Changes to the property's values are
101 detected through the property's notify signal. Setting a context object is both
102 faster and easier than manually adding and maintaing context property values.
104 The following example has the same effect as the previous one, but it uses a context
108 class MyDataSet : ... {
110 Q_PROPERTY(QAbstractItemModel *myModel READ model NOTIFY modelChanged)
115 QDeclarativeEngine engine;
116 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
117 context->setContextObject(&myDataSet);
119 QDeclarativeComponent component(&engine);
120 component.setData("import QtQuick 1.0\nListView { model: myModel }", QUrl());
121 component.create(context);
124 All properties added explicitly by QDeclarativeContext::setContextProperty() take
125 precedence over the context object's properties.
127 \section2 The Context Hierarchy
129 Contexts form a hierarchy. The root of this hierarchy is the QML engine's
130 \l {QDeclarativeEngine::rootContext()}{root context}. Child contexts inherit
131 the context properties of their parents; if a child context sets a context property
132 that already exists in its parent, the new context property overrides that of the
135 The following example defines two contexts - \c context1 and \c context2. The
136 second context overrides the "b" context property inherited from the first with a
140 QDeclarativeEngine engine;
141 QDeclarativeContext *context1 = new QDeclarativeContext(engine.rootContext());
142 QDeclarativeContext *context2 = new QDeclarativeContext(context1);
144 context1->setContextProperty("a", 12);
145 context1->setContextProperty("b", 12);
147 context2->setContextProperty("b", 15);
150 While QML objects instantiated in a context are not strictly owned by that
151 context, their bindings are. If a context is destroyed, the property bindings of
152 outstanding QML objects will stop evaluating.
154 \warning Setting the context object or adding new context properties after an object
155 has been created in that context is an expensive operation (essentially forcing all bindings
156 to reevaluate). Thus whenever possible you should complete "setup" of the context
157 before using it to create any objects.
159 \sa {Using QML Bindings in C++ Applications}
163 QDeclarativeContext::QDeclarativeContext(QDeclarativeEngine *e, bool)
164 : QObject(*(new QDeclarativeContextPrivate))
166 Q_D(QDeclarativeContext);
167 d->data = new QDeclarativeContextData(this);
173 Create a new QDeclarativeContext as a child of \a engine's root context, and the
176 QDeclarativeContext::QDeclarativeContext(QDeclarativeEngine *engine, QObject *parent)
177 : QObject(*(new QDeclarativeContextPrivate), parent)
179 Q_D(QDeclarativeContext);
180 d->data = new QDeclarativeContextData(this);
182 d->data->setParent(engine?QDeclarativeContextData::get(engine->rootContext()):0);
186 Create a new QDeclarativeContext with the given \a parentContext, and the
189 QDeclarativeContext::QDeclarativeContext(QDeclarativeContext *parentContext, QObject *parent)
190 : QObject(*(new QDeclarativeContextPrivate), parent)
192 Q_D(QDeclarativeContext);
193 d->data = new QDeclarativeContextData(this);
195 d->data->setParent(parentContext?QDeclarativeContextData::get(parentContext):0);
201 QDeclarativeContext::QDeclarativeContext(QDeclarativeContextData *data)
202 : QObject(*(new QDeclarativeContextPrivate), 0)
204 Q_D(QDeclarativeContext);
209 Destroys the QDeclarativeContext.
211 Any expressions, or sub-contexts dependent on this context will be
212 invalidated, but not destroyed (unless they are parented to the QDeclarativeContext
215 QDeclarativeContext::~QDeclarativeContext()
217 Q_D(QDeclarativeContext);
219 if (!d->data->isInternal)
224 Returns whether the context is valid.
226 To be valid, a context must have a engine, and it's contextObject(), if any,
227 must not have been deleted.
229 bool QDeclarativeContext::isValid() const
231 Q_D(const QDeclarativeContext);
232 return d->data && d->data->isValid();
236 Return the context's QDeclarativeEngine, or 0 if the context has no QDeclarativeEngine or the
237 QDeclarativeEngine was destroyed.
239 QDeclarativeEngine *QDeclarativeContext::engine() const
241 Q_D(const QDeclarativeContext);
242 return d->data->engine;
246 Return the context's parent QDeclarativeContext, or 0 if this context has no
247 parent or if the parent has been destroyed.
249 QDeclarativeContext *QDeclarativeContext::parentContext() const
251 Q_D(const QDeclarativeContext);
252 return d->data->parent?d->data->parent->asQDeclarativeContext():0;
256 Return the context object, or 0 if there is no context object.
258 QObject *QDeclarativeContext::contextObject() const
260 Q_D(const QDeclarativeContext);
261 return d->data->contextObject;
265 Set the context \a object.
267 void QDeclarativeContext::setContextObject(QObject *object)
269 Q_D(QDeclarativeContext);
271 QDeclarativeContextData *data = d->data;
273 if (data->isInternal) {
274 qWarning("QDeclarativeContext: Cannot set context object for internal context.");
279 qWarning("QDeclarativeContext: Cannot set context object on invalid context.");
283 data->contextObject = object;
287 Set a the \a value of the \a name property on this context.
289 void QDeclarativeContext::setContextProperty(const QString &name, const QVariant &value)
291 Q_D(QDeclarativeContext);
292 if (d->notifyIndex == -1)
293 d->notifyIndex = this->metaObject()->methodCount();
295 QDeclarativeContextData *data = d->data;
297 if (data->isInternal) {
298 qWarning("QDeclarativeContext: Cannot set property on internal context.");
303 qWarning("QDeclarativeContext: Cannot set property on invalid context.");
309 QObject *o = QDeclarativeEnginePrivate::get(data->engine)->toQObject(value, &ok);
311 setContextProperty(name, o);
316 if (!data->propertyNames) data->propertyNames = new QDeclarativeIntegerCache();
318 int idx = data->propertyNames->value(name);
320 data->propertyNames->add(name, data->idValueCount + d->propertyValues.count());
321 d->propertyValues.append(value);
323 data->refreshExpressions();
325 d->propertyValues[idx] = value;
326 QMetaObject::activate(this, idx + d->notifyIndex, 0);
331 Set the \a value of the \a name property on this context.
333 QDeclarativeContext does \bold not take ownership of \a value.
335 void QDeclarativeContext::setContextProperty(const QString &name, QObject *value)
337 Q_D(QDeclarativeContext);
338 if (d->notifyIndex == -1)
339 d->notifyIndex = this->metaObject()->methodCount();
341 QDeclarativeContextData *data = d->data;
343 if (data->isInternal) {
344 qWarning("QDeclarativeContext: Cannot set property on internal context.");
349 qWarning("QDeclarativeContext: Cannot set property on invalid context.");
353 if (!data->propertyNames) data->propertyNames = new QDeclarativeIntegerCache();
354 int idx = data->propertyNames->value(name);
357 data->propertyNames->add(name, data->idValueCount + d->propertyValues.count());
358 d->propertyValues.append(QVariant::fromValue(value));
360 data->refreshExpressions();
362 d->propertyValues[idx] = QVariant::fromValue(value);
363 QMetaObject::activate(this, idx + d->notifyIndex, 0);
368 Returns the value of the \a name property for this context
371 QVariant QDeclarativeContext::contextProperty(const QString &name) const
373 Q_D(const QDeclarativeContext);
377 QDeclarativeContextData *data = d->data;
379 if (data->propertyNames)
380 idx = data->propertyNames->value(name);
383 QByteArray utf8Name = name.toUtf8();
384 if (data->contextObject) {
385 QObject *obj = data->contextObject;
386 QDeclarativePropertyCache::Data local;
387 QDeclarativePropertyCache::Data *property =
388 QDeclarativePropertyCache::property(data->engine, obj, name, local);
390 if (property) value = obj->metaObject()->property(property->coreIndex).read(obj);
392 if (!value.isValid() && parentContext())
393 value = parentContext()->contextProperty(name);
395 if (idx >= d->propertyValues.count())
396 value = QVariant::fromValue(data->idValues[idx - d->propertyValues.count()].data());
398 value = d->propertyValues[idx];
405 Resolves the URL \a src relative to the URL of the
406 containing component.
408 \sa QDeclarativeEngine::baseUrl(), setBaseUrl()
410 QUrl QDeclarativeContext::resolvedUrl(const QUrl &src)
412 Q_D(QDeclarativeContext);
413 return d->data->resolvedUrl(src);
416 QUrl QDeclarativeContextData::resolvedUrl(const QUrl &src)
418 QDeclarativeContextData *ctxt = this;
420 if (src.isRelative() && !src.isEmpty()) {
423 if(ctxt->url.isValid())
430 return ctxt->url.resolved(src);
432 return engine->baseUrl().resolved(src);
442 Explicitly sets the url resolvedUrl() will use for relative references to \a baseUrl.
444 Calling this function will override the url of the containing
445 component used by default.
449 void QDeclarativeContext::setBaseUrl(const QUrl &baseUrl)
451 Q_D(QDeclarativeContext);
453 d->data->url = baseUrl;
457 Returns the base url of the component, or the containing component
460 QUrl QDeclarativeContext::baseUrl() const
462 Q_D(const QDeclarativeContext);
463 const QDeclarativeContextData* data = d->data;
464 while (data && data->url.isEmpty())
473 int QDeclarativeContextPrivate::context_count(QDeclarativeListProperty<QObject> *prop)
475 QDeclarativeContext *context = static_cast<QDeclarativeContext*>(prop->object);
476 QDeclarativeContextPrivate *d = QDeclarativeContextPrivate::get(context);
477 int contextProperty = (int)(quintptr)prop->data;
479 if (d->propertyValues.at(contextProperty).userType() != qMetaTypeId<QList<QObject*> >()) {
482 return ((const QList<QObject> *)d->propertyValues.at(contextProperty).constData())->count();
486 QObject *QDeclarativeContextPrivate::context_at(QDeclarativeListProperty<QObject> *prop, int index)
488 QDeclarativeContext *context = static_cast<QDeclarativeContext*>(prop->object);
489 QDeclarativeContextPrivate *d = QDeclarativeContextPrivate::get(context);
490 int contextProperty = (int)(quintptr)prop->data;
492 if (d->propertyValues.at(contextProperty).userType() != qMetaTypeId<QList<QObject*> >()) {
495 return ((const QList<QObject*> *)d->propertyValues.at(contextProperty).constData())->at(index);
500 QDeclarativeContextData::QDeclarativeContextData()
501 : parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false), isPragmaLibraryContext(false),
502 publicContext(0), propertyNames(0), contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0),
503 expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0),
504 componentAttached(0), v4bindings(0), v8bindings(0)
508 QDeclarativeContextData::QDeclarativeContextData(QDeclarativeContext *ctxt)
509 : parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false), isPragmaLibraryContext(false),
510 publicContext(ctxt), propertyNames(0), contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0),
511 expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0),
512 componentAttached(0), v4bindings(0), v8bindings(0)
516 void QDeclarativeContextData::invalidate()
518 while (childContexts) {
519 if (childContexts->ownedByParent) {
520 childContexts->destroy();
522 childContexts->invalidate();
526 while (componentAttached) {
527 QDeclarativeComponentAttached *a = componentAttached;
528 componentAttached = a->next;
529 if (componentAttached) componentAttached->prev = &componentAttached;
534 emit a->destruction();
538 *prevChild = nextChild;
539 if (nextChild) nextChild->prevChild = prevChild;
548 void QDeclarativeContextData::clearContext()
551 while (componentAttached) {
552 QDeclarativeComponentAttached *a = componentAttached;
553 componentAttached = a->next;
554 if (componentAttached) componentAttached->prev = &componentAttached;
559 emit a->destruction();
563 QDeclarativeAbstractExpression *expression = expressions;
565 QDeclarativeAbstractExpression *nextExpression = expression->m_nextExpression;
567 expression->m_context = 0;
568 expression->m_prevExpression = 0;
569 expression->m_nextExpression = 0;
571 expression = nextExpression;
576 void QDeclarativeContextData::destroy()
579 linkedContext->destroy();
581 if (engine) invalidate();
585 while (contextObjects) {
586 QDeclarativeData *co = contextObjects;
587 contextObjects = contextObjects->nextContextObject;
590 co->outerContext = 0;
591 co->nextContextObject = 0;
592 co->prevContextObject = 0;
595 QDeclarativeGuardedContextData *contextGuard = contextGuards;
596 while (contextGuard) {
597 QDeclarativeGuardedContextData *next = contextGuard->m_next;
598 contextGuard->m_next = 0;
599 contextGuard->m_prev = 0;
600 contextGuard->m_contextData = 0;
606 propertyNames->release();
612 v4bindings->release();
615 v8bindings->release();
617 for (int ii = 0; ii < importedScripts.count(); ++ii) {
618 qPersistentDispose(importedScripts[ii]);
624 delete publicContext;
629 void QDeclarativeContextData::setParent(QDeclarativeContextData *p, bool parentTakesOwnership)
634 nextChild = p->childContexts;
635 if (nextChild) nextChild->prevChild = &nextChild;
636 prevChild = &p->childContexts;
637 p->childContexts = this;
638 ownedByParent = parentTakesOwnership;
643 Refreshes all expressions that could possibly depend on this context. Refreshing flushes all
644 context-tree dependent caches in the expressions, and should occur every time the context tree
645 *structure* (not values) changes.
647 void QDeclarativeContextData::refreshExpressions()
649 QDeclarativeContextData *child = childContexts;
651 child->refreshExpressions();
652 child = child->nextChild;
655 QDeclarativeAbstractExpression *expression = expressions;
657 expression->refresh();
658 expression = expression->m_nextExpression;
662 void QDeclarativeContextData::addObject(QObject *o)
664 QDeclarativeData *data = QDeclarativeData::get(o, true);
666 Q_ASSERT(data->context == 0);
668 data->context = this;
669 data->outerContext = this;
671 data->nextContextObject = contextObjects;
672 if (data->nextContextObject)
673 data->nextContextObject->prevContextObject = &data->nextContextObject;
674 data->prevContextObject = &contextObjects;
675 contextObjects = data;
678 void QDeclarativeContextData::setIdProperty(int idx, QObject *obj)
681 idValues[idx].context = this;
684 void QDeclarativeContextData::setIdPropertyData(QDeclarativeIntegerCache *data)
686 Q_ASSERT(!propertyNames);
687 propertyNames = data;
688 propertyNames->addref();
690 idValueCount = data->count();
691 idValues = new ContextGuard[idValueCount];
694 QString QDeclarativeContextData::findObjectId(const QObject *obj) const
696 if (!idValues || !propertyNames)
699 for (int i=0; i<idValueCount; i++) {
700 if (idValues[i] == obj)
701 return propertyNames->findId(i);
705 return linkedContext->findObjectId(obj);
709 QDeclarativeContext *QDeclarativeContextData::asQDeclarativeContext()
712 publicContext = new QDeclarativeContext(this);
713 return publicContext;
716 QDeclarativeContextPrivate *QDeclarativeContextData::asQDeclarativeContextPrivate()
718 return QDeclarativeContextPrivate::get(asQDeclarativeContext());