Merge branch 'master' of git://scm.dev.nokia.troll.no/qt/qtdeclarative
[profile/ivi/qtdeclarative.git] / src / declarative / qml / qdeclarativecontext.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
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.
17 **
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.
21 **
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.
29 **
30 ** Other Usage
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.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qdeclarativecontext.h"
43 #include "private/qdeclarativecontext_p.h"
44
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/qdeclarativeglobalscriptclass_p.h"
51 #include "private/qdeclarativev4bindings_p.h"
52
53 #include <qscriptengine.h>
54 #include <QtCore/qvarlengtharray.h>
55 #include <QtCore/qdebug.h>
56
57 #include <private/qscriptdeclarativeclass_p.h>
58
59 QT_BEGIN_NAMESPACE
60
61 QDeclarativeContextPrivate::QDeclarativeContextPrivate()
62 : data(0), notifyIndex(-1)
63 {
64 }
65
66 /*!
67     \class QDeclarativeContext
68     \since 4.7
69     \brief The QDeclarativeContext class defines a context within a QML engine.
70     \mainclass
71
72     Contexts allow data to be exposed to the QML components instantiated by the
73     QML engine.
74
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.
80
81     \code
82     QDeclarativeEngine engine;
83     QStringListModel modelData;
84     QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
85     context->setContextProperty("myModel", &modelData);
86
87     QDeclarativeComponent component(&engine);
88     component.setData("import QtQuick 1.0\nListView { model: myModel }", QUrl());
89     QObject *window = component.create(context);
90     \endcode
91
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.
96
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.
103
104     The following example has the same effect as the previous one, but it uses a context
105     object.
106
107     \code
108     class MyDataSet : ... {
109         ...
110         Q_PROPERTY(QAbstractItemModel *myModel READ model NOTIFY modelChanged)
111         ...
112     };
113
114     MyDataSet myDataSet;
115     QDeclarativeEngine engine;
116     QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
117     context->setContextObject(&myDataSet);
118
119     QDeclarativeComponent component(&engine);
120     component.setData("import QtQuick 1.0\nListView { model: myModel }", QUrl());
121     component.create(context);
122     \endcode
123
124     All properties added explicitly by QDeclarativeContext::setContextProperty() take
125     precedence over the context object's properties.
126
127     \section2 The Context Hierarchy
128
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
133     parent.
134
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
137     new value.
138
139     \code
140     QDeclarativeEngine engine;
141     QDeclarativeContext *context1 = new QDeclarativeContext(engine.rootContext());
142     QDeclarativeContext *context2 = new QDeclarativeContext(context1);
143
144     context1->setContextProperty("a", 12);
145     context1->setContextProperty("b", 12);
146
147     context2->setContextProperty("b", 15);
148     \endcode
149
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.
153
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.
158
159     \sa {Using QML Bindings in C++ Applications}
160 */
161
162 /*! \internal */
163 QDeclarativeContext::QDeclarativeContext(QDeclarativeEngine *e, bool)
164 : QObject(*(new QDeclarativeContextPrivate))
165 {
166     Q_D(QDeclarativeContext);
167     d->data = new QDeclarativeContextData(this);
168
169     d->data->engine = e;
170 }
171
172 /*!
173     Create a new QDeclarativeContext as a child of \a engine's root context, and the
174     QObject \a parent.
175 */
176 QDeclarativeContext::QDeclarativeContext(QDeclarativeEngine *engine, QObject *parent)
177 : QObject(*(new QDeclarativeContextPrivate), parent)
178 {
179     Q_D(QDeclarativeContext);
180     d->data = new QDeclarativeContextData(this);
181
182     d->data->setParent(engine?QDeclarativeContextData::get(engine->rootContext()):0);
183 }
184
185 /*!
186     Create a new QDeclarativeContext with the given \a parentContext, and the
187     QObject \a parent.
188 */
189 QDeclarativeContext::QDeclarativeContext(QDeclarativeContext *parentContext, QObject *parent)
190 : QObject(*(new QDeclarativeContextPrivate), parent)
191 {
192     Q_D(QDeclarativeContext);
193     d->data = new QDeclarativeContextData(this);
194
195     d->data->setParent(parentContext?QDeclarativeContextData::get(parentContext):0);
196 }
197
198 /*!
199     \internal
200 */
201 QDeclarativeContext::QDeclarativeContext(QDeclarativeContextData *data)
202 : QObject(*(new QDeclarativeContextPrivate), 0)
203 {
204     Q_D(QDeclarativeContext);
205     d->data = data;
206 }
207
208 /*!
209     Destroys the QDeclarativeContext.
210
211     Any expressions, or sub-contexts dependent on this context will be
212     invalidated, but not destroyed (unless they are parented to the QDeclarativeContext
213     object).
214  */
215 QDeclarativeContext::~QDeclarativeContext()
216 {
217     Q_D(QDeclarativeContext);
218
219     if (!d->data->isInternal)
220         d->data->destroy();
221 }
222
223 /*!
224     Returns whether the context is valid.
225
226     To be valid, a context must have a engine, and it's contextObject(), if any,
227     must not have been deleted.
228 */
229 bool QDeclarativeContext::isValid() const
230 {
231     Q_D(const QDeclarativeContext);
232     return d->data && d->data->isValid();
233 }
234
235 /*!
236     Return the context's QDeclarativeEngine, or 0 if the context has no QDeclarativeEngine or the
237     QDeclarativeEngine was destroyed.
238 */
239 QDeclarativeEngine *QDeclarativeContext::engine() const
240 {
241     Q_D(const QDeclarativeContext);
242     return d->data->engine;
243 }
244
245 /*!
246     Return the context's parent QDeclarativeContext, or 0 if this context has no
247     parent or if the parent has been destroyed.
248 */
249 QDeclarativeContext *QDeclarativeContext::parentContext() const
250 {
251     Q_D(const QDeclarativeContext);
252     return d->data->parent?d->data->parent->asQDeclarativeContext():0;
253 }
254
255 /*!
256     Return the context object, or 0 if there is no context object.
257 */
258 QObject *QDeclarativeContext::contextObject() const
259 {
260     Q_D(const QDeclarativeContext);
261     return d->data->contextObject;
262 }
263
264 /*!
265     Set the context \a object.
266 */
267 void QDeclarativeContext::setContextObject(QObject *object)
268 {
269     Q_D(QDeclarativeContext);
270
271     QDeclarativeContextData *data = d->data;
272
273     if (data->isInternal) {
274         qWarning("QDeclarativeContext: Cannot set context object for internal context.");
275         return;
276     }
277
278     if (!isValid()) {
279         qWarning("QDeclarativeContext: Cannot set context object on invalid context.");
280         return;
281     }
282
283     data->contextObject = object;
284 }
285
286 /*!
287     Set a the \a value of the \a name property on this context.
288 */
289 void QDeclarativeContext::setContextProperty(const QString &name, const QVariant &value)
290 {
291     Q_D(QDeclarativeContext);
292     if (d->notifyIndex == -1)
293         d->notifyIndex = this->metaObject()->methodCount();
294
295     QDeclarativeContextData *data = d->data;
296
297     if (data->isInternal) {
298         qWarning("QDeclarativeContext: Cannot set property on internal context.");
299         return;
300     }
301
302     if (!isValid()) {
303         qWarning("QDeclarativeContext: Cannot set property on invalid context.");
304         return;
305     }
306
307     if (data->engine) {
308         bool ok;
309         QObject *o = QDeclarativeEnginePrivate::get(data->engine)->toQObject(value, &ok);
310         if (ok) {
311             setContextProperty(name, o);
312             return;
313         }
314     }
315
316     if (!data->propertyNames) data->propertyNames = new QDeclarativeIntegerCache(data->engine);
317
318     int idx = data->propertyNames->value(name);
319     if (idx == -1) {
320         data->propertyNames->add(name, data->idValueCount + d->propertyValues.count());
321         d->propertyValues.append(value);
322
323         data->refreshExpressions();
324     } else {
325         d->propertyValues[idx] = value;
326         QMetaObject::activate(this, idx + d->notifyIndex, 0);
327     }
328 }
329
330 /*!
331     Set the \a value of the \a name property on this context.
332
333     QDeclarativeContext does \bold not take ownership of \a value.
334 */
335 void QDeclarativeContext::setContextProperty(const QString &name, QObject *value)
336 {
337     Q_D(QDeclarativeContext);
338     if (d->notifyIndex == -1)
339         d->notifyIndex = this->metaObject()->methodCount();
340
341     QDeclarativeContextData *data = d->data;
342
343     if (data->isInternal) {
344         qWarning("QDeclarativeContext: Cannot set property on internal context.");
345         return;
346     }
347
348     if (!isValid()) {
349         qWarning("QDeclarativeContext: Cannot set property on invalid context.");
350         return;
351     }
352
353     if (!data->propertyNames) data->propertyNames = new QDeclarativeIntegerCache(data->engine);
354     int idx = data->propertyNames->value(name);
355
356     if (idx == -1) {
357         data->propertyNames->add(name, data->idValueCount + d->propertyValues.count());
358         d->propertyValues.append(QVariant::fromValue(value));
359
360         data->refreshExpressions();
361     } else {
362         d->propertyValues[idx] = QVariant::fromValue(value);
363         QMetaObject::activate(this, idx + d->notifyIndex, 0);
364     }
365 }
366
367 /*!
368   Returns the value of the \a name property for this context
369   as a QVariant.
370  */
371 QVariant QDeclarativeContext::contextProperty(const QString &name) const
372 {
373     Q_D(const QDeclarativeContext);
374     QVariant value;
375     int idx = -1;
376
377     QDeclarativeContextData *data = d->data;
378
379     if (data->propertyNames)
380         idx = data->propertyNames->value(name);
381
382     if (idx == -1) {
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);
389
390             if (property) value = obj->metaObject()->property(property->coreIndex).read(obj);
391         }
392         if (!value.isValid() && parentContext())
393             value = parentContext()->contextProperty(name);
394     } else {
395         if (idx >= d->propertyValues.count())
396             value = QVariant::fromValue(data->idValues[idx - d->propertyValues.count()].data());
397         else
398             value = d->propertyValues[idx];
399     }
400
401     return value;
402 }
403
404 /*!
405     Resolves the URL \a src relative to the URL of the
406     containing component.
407
408     \sa QDeclarativeEngine::baseUrl(), setBaseUrl()
409 */
410 QUrl QDeclarativeContext::resolvedUrl(const QUrl &src)
411 {
412     Q_D(QDeclarativeContext);
413     return d->data->resolvedUrl(src);
414 }
415
416 QUrl QDeclarativeContextData::resolvedUrl(const QUrl &src)
417 {
418     QDeclarativeContextData *ctxt = this;
419
420     if (src.isRelative() && !src.isEmpty()) {
421         if (ctxt) {
422             while(ctxt) {
423                 if(ctxt->url.isValid())
424                     break;
425                 else
426                     ctxt = ctxt->parent;
427             }
428
429             if (ctxt)
430                 return ctxt->url.resolved(src);
431             else if (engine)
432                 return engine->baseUrl().resolved(src);
433         }
434         return QUrl();
435     } else {
436         return src;
437     }
438 }
439
440
441 /*!
442     Explicitly sets the url resolvedUrl() will use for relative references to \a baseUrl.
443
444     Calling this function will override the url of the containing
445     component used by default.
446
447     \sa resolvedUrl()
448 */
449 void QDeclarativeContext::setBaseUrl(const QUrl &baseUrl)
450 {
451     Q_D(QDeclarativeContext);
452
453     d->data->url = baseUrl;
454 }
455
456 /*!
457     Returns the base url of the component, or the containing component
458     if none is set.
459 */
460 QUrl QDeclarativeContext::baseUrl() const
461 {
462     Q_D(const QDeclarativeContext);
463     const QDeclarativeContextData* data = d->data;
464     while (data && data->url.isEmpty())
465         data = data->parent;
466
467     if (data)
468         return data->url;
469     else
470         return QUrl();
471 }
472
473 int QDeclarativeContextPrivate::context_count(QDeclarativeListProperty<QObject> *prop)
474 {
475     QDeclarativeContext *context = static_cast<QDeclarativeContext*>(prop->object);
476     QDeclarativeContextPrivate *d = QDeclarativeContextPrivate::get(context);
477     int contextProperty = (int)(quintptr)prop->data;
478
479     if (d->propertyValues.at(contextProperty).userType() != qMetaTypeId<QList<QObject*> >()) {
480         return 0;
481     } else {
482         return ((const QList<QObject> *)d->propertyValues.at(contextProperty).constData())->count();
483     }
484 }
485
486 QObject *QDeclarativeContextPrivate::context_at(QDeclarativeListProperty<QObject> *prop, int index)
487 {
488     QDeclarativeContext *context = static_cast<QDeclarativeContext*>(prop->object);
489     QDeclarativeContextPrivate *d = QDeclarativeContextPrivate::get(context);
490     int contextProperty = (int)(quintptr)prop->data;
491
492     if (d->propertyValues.at(contextProperty).userType() != qMetaTypeId<QList<QObject*> >()) {
493         return 0;
494     } else {
495         return ((const QList<QObject*> *)d->propertyValues.at(contextProperty).constData())->at(index);
496     }
497 }
498
499
500 QDeclarativeContextData::QDeclarativeContextData()
501 : parent(0), engine(0), isInternal(false), ownedByParent(false), publicContext(0), propertyNames(0), contextObject(0),
502   imports(0), childContexts(0), nextChild(0), prevChild(0), expressions(0), contextObjects(0),
503   contextGuards(0), idValues(0), idValueCount(0), optimizedBindings(0), linkedContext(0),
504   componentAttached(0)
505 {
506 }
507
508 QDeclarativeContextData::QDeclarativeContextData(QDeclarativeContext *ctxt)
509 : parent(0), engine(0), isInternal(false), ownedByParent(false), publicContext(ctxt), propertyNames(0), contextObject(0),
510   imports(0), childContexts(0), nextChild(0), prevChild(0), expressions(0), contextObjects(0),
511   contextGuards(0), idValues(0), idValueCount(0), optimizedBindings(0), linkedContext(0),
512   componentAttached(0)
513 {
514 }
515
516 void QDeclarativeContextData::invalidate()
517 {
518     while (childContexts) {
519         if (childContexts->ownedByParent) {
520             childContexts->destroy();
521         } else {
522             childContexts->invalidate();
523         }
524     }
525
526     while (componentAttached) {
527         QDeclarativeComponentAttached *a = componentAttached;
528         componentAttached = a->next;
529         if (componentAttached) componentAttached->prev = &componentAttached;
530
531         a->next = 0;
532         a->prev = 0;
533
534         emit a->destruction();
535     }
536
537     if (prevChild) {
538         *prevChild = nextChild;
539         if (nextChild) nextChild->prevChild = prevChild;
540         nextChild = 0;
541         prevChild = 0;
542     }
543
544     engine = 0;
545     parent = 0;
546 }
547
548 void QDeclarativeContextData::clearContext()
549 {
550     if (engine) {
551         while (componentAttached) {
552             QDeclarativeComponentAttached *a = componentAttached;
553             componentAttached = a->next;
554             if (componentAttached) componentAttached->prev = &componentAttached;
555
556             a->next = 0;
557             a->prev = 0;
558
559             emit a->destruction();
560         }
561     }
562
563     QDeclarativeAbstractExpression *expression = expressions;
564     while (expression) {
565         QDeclarativeAbstractExpression *nextExpression = expression->m_nextExpression;
566
567         expression->m_context = 0;
568         expression->m_prevExpression = 0;
569         expression->m_nextExpression = 0;
570
571         expression = nextExpression;
572     }
573     expressions = 0;
574 }
575
576 void QDeclarativeContextData::destroy()
577 {
578     if (linkedContext)
579         linkedContext->destroy();
580
581     if (engine) invalidate();
582
583     clearContext();
584
585     while (contextObjects) {
586         QDeclarativeData *co = contextObjects;
587         contextObjects = contextObjects->nextContextObject;
588
589         co->context = 0;
590         co->outerContext = 0;
591         co->nextContextObject = 0;
592         co->prevContextObject = 0;
593     }
594
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;
601         contextGuard = next;
602     }
603     contextGuards = 0;
604
605     if (propertyNames)
606         propertyNames->release();
607
608     if (imports)
609         imports->release();
610
611     if (optimizedBindings)
612         optimizedBindings->release();
613
614     delete [] idValues;
615
616     if (isInternal)
617         delete publicContext;
618
619     delete this;
620 }
621
622 void QDeclarativeContextData::setParent(QDeclarativeContextData *p, bool parentTakesOwnership)
623 {
624     if (p) {
625         parent = p;
626         engine = p->engine;
627         nextChild = p->childContexts;
628         if (nextChild) nextChild->prevChild = &nextChild;
629         prevChild = &p->childContexts;
630         p->childContexts = this;
631         ownedByParent = parentTakesOwnership;
632     }
633 }
634
635 /*
636 Refreshes all expressions that could possibly depend on this context.  Refreshing flushes all
637 context-tree dependent caches in the expressions, and should occur every time the context tree
638  *structure* (not values) changes.
639 */
640 void QDeclarativeContextData::refreshExpressions()
641 {
642     QDeclarativeContextData *child = childContexts;
643     while (child) {
644         child->refreshExpressions();
645         child = child->nextChild;
646     }
647
648     QDeclarativeAbstractExpression *expression = expressions;
649     while (expression) {
650         expression->refresh();
651         expression = expression->m_nextExpression;
652     }
653 }
654
655 void QDeclarativeContextData::addObject(QObject *o)
656 {
657     QDeclarativeData *data = QDeclarativeData::get(o, true);
658
659     Q_ASSERT(data->context == 0);
660
661     data->context = this;
662     data->outerContext = this;
663
664     data->nextContextObject = contextObjects;
665     if (data->nextContextObject)
666         data->nextContextObject->prevContextObject = &data->nextContextObject;
667     data->prevContextObject = &contextObjects;
668     contextObjects = data;
669 }
670
671 void QDeclarativeContextData::setIdProperty(int idx, QObject *obj)
672 {
673     idValues[idx] = obj;
674     idValues[idx].context = this;
675 }
676
677 void QDeclarativeContextData::setIdPropertyData(QDeclarativeIntegerCache *data)
678 {
679     Q_ASSERT(!propertyNames);
680     propertyNames = data;
681     propertyNames->addref();
682
683     idValueCount = data->count();
684     idValues = new ContextGuard[idValueCount];
685 }
686
687 QString QDeclarativeContextData::findObjectId(const QObject *obj) const
688 {
689     if (!idValues || !propertyNames)
690         return QString();
691
692     for (int i=0; i<idValueCount; i++) {
693         if (idValues[i] == obj)
694             return propertyNames->findId(i);
695     }
696
697     if (linkedContext)
698         return linkedContext->findObjectId(obj);
699     return QString();
700 }
701
702 QDeclarativeContext *QDeclarativeContextData::asQDeclarativeContext()
703 {
704     if (!publicContext)
705         publicContext = new QDeclarativeContext(this);
706     return publicContext;
707 }
708
709 QDeclarativeContextPrivate *QDeclarativeContextData::asQDeclarativeContextPrivate()
710 {
711     return QDeclarativeContextPrivate::get(asQDeclarativeContext());
712 }
713
714 QT_END_NAMESPACE