Merge branch 'qtquick2' into v8
[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/qdeclarativev4bindings_p.h"
51 #include "private/qv8bindings_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();
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();
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), 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)
505 {
506 }
507
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)
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 (v4bindings)
612         v4bindings->release();
613
614     if (v8bindings)
615         v8bindings->release();
616
617     for (int ii = 0; ii < importedScripts.count(); ++ii) {
618         qPersistentDispose(importedScripts[ii]);
619     }
620
621     delete [] idValues;
622
623     if (isInternal)
624         delete publicContext;
625
626     delete this;
627 }
628
629 void QDeclarativeContextData::setParent(QDeclarativeContextData *p, bool parentTakesOwnership)
630 {
631     if (p) {
632         parent = p;
633         engine = p->engine;
634         nextChild = p->childContexts;
635         if (nextChild) nextChild->prevChild = &nextChild;
636         prevChild = &p->childContexts;
637         p->childContexts = this;
638         ownedByParent = parentTakesOwnership;
639     }
640 }
641
642 /*
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.
646 */
647 void QDeclarativeContextData::refreshExpressions()
648 {
649     QDeclarativeContextData *child = childContexts;
650     while (child) {
651         child->refreshExpressions();
652         child = child->nextChild;
653     }
654
655     QDeclarativeAbstractExpression *expression = expressions;
656     while (expression) {
657         expression->refresh();
658         expression = expression->m_nextExpression;
659     }
660 }
661
662 void QDeclarativeContextData::addObject(QObject *o)
663 {
664     QDeclarativeData *data = QDeclarativeData::get(o, true);
665
666     Q_ASSERT(data->context == 0);
667
668     data->context = this;
669     data->outerContext = this;
670
671     data->nextContextObject = contextObjects;
672     if (data->nextContextObject)
673         data->nextContextObject->prevContextObject = &data->nextContextObject;
674     data->prevContextObject = &contextObjects;
675     contextObjects = data;
676 }
677
678 void QDeclarativeContextData::setIdProperty(int idx, QObject *obj)
679 {
680     idValues[idx] = obj;
681     idValues[idx].context = this;
682 }
683
684 void QDeclarativeContextData::setIdPropertyData(QDeclarativeIntegerCache *data)
685 {
686     Q_ASSERT(!propertyNames);
687     propertyNames = data;
688     propertyNames->addref();
689
690     idValueCount = data->count();
691     idValues = new ContextGuard[idValueCount];
692 }
693
694 QString QDeclarativeContextData::findObjectId(const QObject *obj) const
695 {
696     if (!idValues || !propertyNames)
697         return QString();
698
699     for (int i=0; i<idValueCount; i++) {
700         if (idValues[i] == obj)
701             return propertyNames->findId(i);
702     }
703
704     if (linkedContext)
705         return linkedContext->findObjectId(obj);
706     return QString();
707 }
708
709 QDeclarativeContext *QDeclarativeContextData::asQDeclarativeContext()
710 {
711     if (!publicContext)
712         publicContext = new QDeclarativeContext(this);
713     return publicContext;
714 }
715
716 QDeclarativeContextPrivate *QDeclarativeContextData::asQDeclarativeContextPrivate()
717 {
718     return QDeclarativeContextPrivate::get(asQDeclarativeContext());
719 }
720
721 QT_END_NAMESPACE