Rename QDeclarativeV4 -> QV4
[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/qv4bindings_p.h"
51 #include "private/qv8bindings_p.h"
52
53 #include <qjsengine.h>
54 #include <QtCore/qvarlengtharray.h>
55 #include <QtCore/qdebug.h>
56
57 QT_BEGIN_NAMESPACE
58
59 QDeclarativeContextPrivate::QDeclarativeContextPrivate()
60 : data(0), notifyIndex(-1)
61 {
62 }
63
64 /*!
65     \class QDeclarativeContext
66     \since 4.7
67     \brief The QDeclarativeContext class defines a context within a QML engine.
68     \mainclass
69
70     Contexts allow data to be exposed to the QML components instantiated by the
71     QML engine.
72
73     Each QDeclarativeContext contains a set of properties, distinct from its QObject
74     properties, that allow data to be explicitly bound to a context by name.  The
75     context properties are defined and updated by calling
76     QDeclarativeContext::setContextProperty().  The following example shows a Qt model
77     being bound to a context and then accessed from a QML file.
78
79     \code
80     QDeclarativeEngine engine;
81     QStringListModel modelData;
82     QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
83     context->setContextProperty("myModel", &modelData);
84
85     QDeclarativeComponent component(&engine);
86     component.setData("import QtQuick 1.0\nListView { model: myModel }", QUrl());
87     QObject *window = component.create(context);
88     \endcode
89
90     Note it is the responsibility of the creator to delete any QDeclarativeContext it
91     constructs. If the \c context object in the example is no longer needed when the
92     \c window component instance is destroyed, the \c context must be destroyed explicitly.
93     The simplest way to ensure this is to set \c window as the parent of \c context.
94
95     To simplify binding and maintaining larger data sets, a context object can be set
96     on a QDeclarativeContext.  All the properties of the context object are available
97     by name in the context, as though they were all individually added through calls
98     to QDeclarativeContext::setContextProperty().  Changes to the property's values are
99     detected through the property's notify signal.  Setting a context object is both
100     faster and easier than manually adding and maintaing context property values.
101
102     The following example has the same effect as the previous one, but it uses a context
103     object.
104
105     \code
106     class MyDataSet : ... {
107         ...
108         Q_PROPERTY(QAbstractItemModel *myModel READ model NOTIFY modelChanged)
109         ...
110     };
111
112     MyDataSet myDataSet;
113     QDeclarativeEngine engine;
114     QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
115     context->setContextObject(&myDataSet);
116
117     QDeclarativeComponent component(&engine);
118     component.setData("import QtQuick 1.0\nListView { model: myModel }", QUrl());
119     component.create(context);
120     \endcode
121
122     All properties added explicitly by QDeclarativeContext::setContextProperty() take
123     precedence over the context object's properties.
124
125     \section2 The Context Hierarchy
126
127     Contexts form a hierarchy. The root of this hierarchy is the QML engine's
128     \l {QDeclarativeEngine::rootContext()}{root context}. Child contexts inherit
129     the context properties of their parents; if a child context sets a context property
130     that already exists in its parent, the new context property overrides that of the
131     parent.
132
133     The following example defines two contexts - \c context1 and \c context2.  The
134     second context overrides the "b" context property inherited from the first with a
135     new value.
136
137     \code
138     QDeclarativeEngine engine;
139     QDeclarativeContext *context1 = new QDeclarativeContext(engine.rootContext());
140     QDeclarativeContext *context2 = new QDeclarativeContext(context1);
141
142     context1->setContextProperty("a", 12);
143     context1->setContextProperty("b", 12);
144
145     context2->setContextProperty("b", 15);
146     \endcode
147
148     While QML objects instantiated in a context are not strictly owned by that
149     context, their bindings are.  If a context is destroyed, the property bindings of
150     outstanding QML objects will stop evaluating.
151
152     \warning Setting the context object or adding new context properties after an object
153     has been created in that context is an expensive operation (essentially forcing all bindings
154     to reevaluate). Thus whenever possible you should complete "setup" of the context
155     before using it to create any objects.
156
157     \sa {Using QML Bindings in C++ Applications}
158 */
159
160 /*! \internal */
161 QDeclarativeContext::QDeclarativeContext(QDeclarativeEngine *e, bool)
162 : QObject(*(new QDeclarativeContextPrivate))
163 {
164     Q_D(QDeclarativeContext);
165     d->data = new QDeclarativeContextData(this);
166
167     d->data->engine = e;
168 }
169
170 /*!
171     Create a new QDeclarativeContext as a child of \a engine's root context, and the
172     QObject \a parent.
173 */
174 QDeclarativeContext::QDeclarativeContext(QDeclarativeEngine *engine, QObject *parent)
175 : QObject(*(new QDeclarativeContextPrivate), parent)
176 {
177     Q_D(QDeclarativeContext);
178     d->data = new QDeclarativeContextData(this);
179
180     d->data->setParent(engine?QDeclarativeContextData::get(engine->rootContext()):0);
181 }
182
183 /*!
184     Create a new QDeclarativeContext with the given \a parentContext, and the
185     QObject \a parent.
186 */
187 QDeclarativeContext::QDeclarativeContext(QDeclarativeContext *parentContext, QObject *parent)
188 : QObject(*(new QDeclarativeContextPrivate), parent)
189 {
190     Q_D(QDeclarativeContext);
191     d->data = new QDeclarativeContextData(this);
192
193     d->data->setParent(parentContext?QDeclarativeContextData::get(parentContext):0);
194 }
195
196 /*!
197     \internal
198 */
199 QDeclarativeContext::QDeclarativeContext(QDeclarativeContextData *data)
200 : QObject(*(new QDeclarativeContextPrivate), 0)
201 {
202     Q_D(QDeclarativeContext);
203     d->data = data;
204 }
205
206 /*!
207     Destroys the QDeclarativeContext.
208
209     Any expressions, or sub-contexts dependent on this context will be
210     invalidated, but not destroyed (unless they are parented to the QDeclarativeContext
211     object).
212  */
213 QDeclarativeContext::~QDeclarativeContext()
214 {
215     Q_D(QDeclarativeContext);
216
217     if (!d->data->isInternal)
218         d->data->destroy();
219 }
220
221 /*!
222     Returns whether the context is valid.
223
224     To be valid, a context must have a engine, and it's contextObject(), if any,
225     must not have been deleted.
226 */
227 bool QDeclarativeContext::isValid() const
228 {
229     Q_D(const QDeclarativeContext);
230     return d->data && d->data->isValid();
231 }
232
233 /*!
234     Return the context's QDeclarativeEngine, or 0 if the context has no QDeclarativeEngine or the
235     QDeclarativeEngine was destroyed.
236 */
237 QDeclarativeEngine *QDeclarativeContext::engine() const
238 {
239     Q_D(const QDeclarativeContext);
240     return d->data->engine;
241 }
242
243 /*!
244     Return the context's parent QDeclarativeContext, or 0 if this context has no
245     parent or if the parent has been destroyed.
246 */
247 QDeclarativeContext *QDeclarativeContext::parentContext() const
248 {
249     Q_D(const QDeclarativeContext);
250     return d->data->parent?d->data->parent->asQDeclarativeContext():0;
251 }
252
253 /*!
254     Return the context object, or 0 if there is no context object.
255 */
256 QObject *QDeclarativeContext::contextObject() const
257 {
258     Q_D(const QDeclarativeContext);
259     return d->data->contextObject;
260 }
261
262 /*!
263     Set the context \a object.
264 */
265 void QDeclarativeContext::setContextObject(QObject *object)
266 {
267     Q_D(QDeclarativeContext);
268
269     QDeclarativeContextData *data = d->data;
270
271     if (data->isInternal) {
272         qWarning("QDeclarativeContext: Cannot set context object for internal context.");
273         return;
274     }
275
276     if (!isValid()) {
277         qWarning("QDeclarativeContext: Cannot set context object on invalid context.");
278         return;
279     }
280
281     data->contextObject = object;
282 }
283
284 /*!
285     Set a the \a value of the \a name property on this context.
286 */
287 void QDeclarativeContext::setContextProperty(const QString &name, const QVariant &value)
288 {
289     Q_D(QDeclarativeContext);
290     if (d->notifyIndex == -1)
291         d->notifyIndex = this->metaObject()->methodCount();
292
293     QDeclarativeContextData *data = d->data;
294
295     if (data->isInternal) {
296         qWarning("QDeclarativeContext: Cannot set property on internal context.");
297         return;
298     }
299
300     if (!isValid()) {
301         qWarning("QDeclarativeContext: Cannot set property on invalid context.");
302         return;
303     }
304
305     if (data->engine) {
306         bool ok;
307         QObject *o = QDeclarativeEnginePrivate::get(data->engine)->toQObject(value, &ok);
308         if (ok) {
309             setContextProperty(name, o);
310             return;
311         }
312     }
313
314     if (!data->propertyNames) data->propertyNames = new QDeclarativeIntegerCache();
315
316     int idx = data->propertyNames->value(name);
317     if (idx == -1) {
318         data->propertyNames->add(name, data->idValueCount + d->propertyValues.count());
319         d->propertyValues.append(value);
320
321         data->refreshExpressions();
322     } else {
323         d->propertyValues[idx] = value;
324         QMetaObject::activate(this, idx + d->notifyIndex, 0);
325     }
326 }
327
328 /*!
329     Set the \a value of the \a name property on this context.
330
331     QDeclarativeContext does \bold not take ownership of \a value.
332 */
333 void QDeclarativeContext::setContextProperty(const QString &name, QObject *value)
334 {
335     Q_D(QDeclarativeContext);
336     if (d->notifyIndex == -1)
337         d->notifyIndex = this->metaObject()->methodCount();
338
339     QDeclarativeContextData *data = d->data;
340
341     if (data->isInternal) {
342         qWarning("QDeclarativeContext: Cannot set property on internal context.");
343         return;
344     }
345
346     if (!isValid()) {
347         qWarning("QDeclarativeContext: Cannot set property on invalid context.");
348         return;
349     }
350
351     if (!data->propertyNames) data->propertyNames = new QDeclarativeIntegerCache();
352     int idx = data->propertyNames->value(name);
353
354     if (idx == -1) {
355         data->propertyNames->add(name, data->idValueCount + d->propertyValues.count());
356         d->propertyValues.append(QVariant::fromValue(value));
357
358         data->refreshExpressions();
359     } else {
360         d->propertyValues[idx] = QVariant::fromValue(value);
361         QMetaObject::activate(this, idx + d->notifyIndex, 0);
362     }
363 }
364
365 /*!
366   Returns the value of the \a name property for this context
367   as a QVariant.
368  */
369 QVariant QDeclarativeContext::contextProperty(const QString &name) const
370 {
371     Q_D(const QDeclarativeContext);
372     QVariant value;
373     int idx = -1;
374
375     QDeclarativeContextData *data = d->data;
376
377     if (data->propertyNames)
378         idx = data->propertyNames->value(name);
379
380     if (idx == -1) {
381         QByteArray utf8Name = name.toUtf8();
382         if (data->contextObject) {
383             QObject *obj = data->contextObject;
384             QDeclarativePropertyCache::Data local;
385             QDeclarativePropertyCache::Data *property =
386                 QDeclarativePropertyCache::property(data->engine, obj, name, local);
387
388             if (property) value = obj->metaObject()->property(property->coreIndex).read(obj);
389         }
390         if (!value.isValid() && parentContext())
391             value = parentContext()->contextProperty(name);
392     } else {
393         if (idx >= d->propertyValues.count())
394             value = QVariant::fromValue(data->idValues[idx - d->propertyValues.count()].data());
395         else
396             value = d->propertyValues[idx];
397     }
398
399     return value;
400 }
401
402 /*!
403 Returns the name of \a object in this context, or an empty string if \a object 
404 is not named in the context.  Objects are named by setContextProperty(), or by ids in
405 the case of QML created contexts.
406
407 If the object has multiple names, the first is returned.
408 */
409 QString QDeclarativeContext::nameForObject(QObject *object) const
410 {
411     Q_D(const QDeclarativeContext);
412
413     return d->data->findObjectId(object);
414 }
415
416 /*!
417     Resolves the URL \a src relative to the URL of the
418     containing component.
419
420     \sa QDeclarativeEngine::baseUrl(), setBaseUrl()
421 */
422 QUrl QDeclarativeContext::resolvedUrl(const QUrl &src)
423 {
424     Q_D(QDeclarativeContext);
425     return d->data->resolvedUrl(src);
426 }
427
428 QUrl QDeclarativeContextData::resolvedUrl(const QUrl &src)
429 {
430     QDeclarativeContextData *ctxt = this;
431
432     if (src.isRelative() && !src.isEmpty()) {
433         if (ctxt) {
434             while(ctxt) {
435                 if(ctxt->url.isValid())
436                     break;
437                 else
438                     ctxt = ctxt->parent;
439             }
440
441             if (ctxt)
442                 return ctxt->url.resolved(src);
443             else if (engine)
444                 return engine->baseUrl().resolved(src);
445         }
446         return QUrl();
447     } else {
448         return src;
449     }
450 }
451
452
453 /*!
454     Explicitly sets the url resolvedUrl() will use for relative references to \a baseUrl.
455
456     Calling this function will override the url of the containing
457     component used by default.
458
459     \sa resolvedUrl()
460 */
461 void QDeclarativeContext::setBaseUrl(const QUrl &baseUrl)
462 {
463     Q_D(QDeclarativeContext);
464
465     d->data->url = baseUrl;
466 }
467
468 /*!
469     Returns the base url of the component, or the containing component
470     if none is set.
471 */
472 QUrl QDeclarativeContext::baseUrl() const
473 {
474     Q_D(const QDeclarativeContext);
475     const QDeclarativeContextData* data = d->data;
476     while (data && data->url.isEmpty())
477         data = data->parent;
478
479     if (data)
480         return data->url;
481     else
482         return QUrl();
483 }
484
485 int QDeclarativeContextPrivate::context_count(QDeclarativeListProperty<QObject> *prop)
486 {
487     QDeclarativeContext *context = static_cast<QDeclarativeContext*>(prop->object);
488     QDeclarativeContextPrivate *d = QDeclarativeContextPrivate::get(context);
489     int contextProperty = (int)(quintptr)prop->data;
490
491     if (d->propertyValues.at(contextProperty).userType() != qMetaTypeId<QList<QObject*> >()) {
492         return 0;
493     } else {
494         return ((const QList<QObject> *)d->propertyValues.at(contextProperty).constData())->count();
495     }
496 }
497
498 QObject *QDeclarativeContextPrivate::context_at(QDeclarativeListProperty<QObject> *prop, int index)
499 {
500     QDeclarativeContext *context = static_cast<QDeclarativeContext*>(prop->object);
501     QDeclarativeContextPrivate *d = QDeclarativeContextPrivate::get(context);
502     int contextProperty = (int)(quintptr)prop->data;
503
504     if (d->propertyValues.at(contextProperty).userType() != qMetaTypeId<QList<QObject*> >()) {
505         return 0;
506     } else {
507         return ((const QList<QObject*> *)d->propertyValues.at(contextProperty).constData())->at(index);
508     }
509 }
510
511
512 QDeclarativeContextData::QDeclarativeContextData()
513 : parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false), 
514   isPragmaLibraryContext(false), publicContext(0), activeVME(0), propertyNames(0), contextObject(0), 
515   imports(0), childContexts(0), nextChild(0), prevChild(0), expressions(0), contextObjects(0), 
516   contextGuards(0), idValues(0), idValueCount(0), linkedContext(0), componentAttached(0), 
517   v4bindings(0), v8bindings(0)
518 {
519 }
520
521 QDeclarativeContextData::QDeclarativeContextData(QDeclarativeContext *ctxt)
522 : parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false), 
523   isPragmaLibraryContext(false), publicContext(ctxt), activeVME(0), propertyNames(0), 
524   contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0), expressions(0), 
525   contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0), 
526   componentAttached(0), v4bindings(0), v8bindings(0)
527 {
528 }
529
530 void QDeclarativeContextData::invalidate()
531 {
532     while (childContexts) {
533         if (childContexts->ownedByParent) {
534             childContexts->destroy();
535         } else {
536             childContexts->invalidate();
537         }
538     }
539
540     while (componentAttached) {
541         QDeclarativeComponentAttached *a = componentAttached;
542         componentAttached = a->next;
543         if (componentAttached) componentAttached->prev = &componentAttached;
544
545         a->next = 0;
546         a->prev = 0;
547
548         emit a->destruction();
549     }
550
551     if (prevChild) {
552         *prevChild = nextChild;
553         if (nextChild) nextChild->prevChild = prevChild;
554         nextChild = 0;
555         prevChild = 0;
556     }
557
558     engine = 0;
559     parent = 0;
560 }
561
562 void QDeclarativeContextData::clearContext()
563 {
564     if (engine) {
565         while (componentAttached) {
566             QDeclarativeComponentAttached *a = componentAttached;
567             componentAttached = a->next;
568             if (componentAttached) componentAttached->prev = &componentAttached;
569
570             a->next = 0;
571             a->prev = 0;
572
573             emit a->destruction();
574         }
575     }
576
577     QDeclarativeAbstractExpression *expression = expressions;
578     while (expression) {
579         QDeclarativeAbstractExpression *nextExpression = expression->m_nextExpression;
580
581         expression->m_context = 0;
582         expression->m_prevExpression = 0;
583         expression->m_nextExpression = 0;
584
585         expression = nextExpression;
586     }
587     expressions = 0;
588 }
589
590 void QDeclarativeContextData::destroy()
591 {
592     if (linkedContext)
593         linkedContext->destroy();
594
595     if (engine) invalidate();
596
597     clearContext();
598
599     while (contextObjects) {
600         QDeclarativeData *co = contextObjects;
601         contextObjects = contextObjects->nextContextObject;
602
603         co->context = 0;
604         co->outerContext = 0;
605         co->nextContextObject = 0;
606         co->prevContextObject = 0;
607     }
608
609     QDeclarativeGuardedContextData *contextGuard = contextGuards;
610     while (contextGuard) {
611         QDeclarativeGuardedContextData *next = contextGuard->m_next;
612         contextGuard->m_next = 0;
613         contextGuard->m_prev = 0;
614         contextGuard->m_contextData = 0;
615         contextGuard = next;
616     }
617     contextGuards = 0;
618
619     if (propertyNames)
620         propertyNames->release();
621
622     if (imports)
623         imports->release();
624
625     if (v4bindings)
626         v4bindings->release();
627
628     if (v8bindings)
629         v8bindings->release();
630
631     for (int ii = 0; ii < importedScripts.count(); ++ii) {
632         qPersistentDispose(importedScripts[ii]);
633     }
634
635     delete [] idValues;
636
637     if (isInternal)
638         delete publicContext;
639
640     delete this;
641 }
642
643 void QDeclarativeContextData::setParent(QDeclarativeContextData *p, bool parentTakesOwnership)
644 {
645     if (p) {
646         parent = p;
647         engine = p->engine;
648         nextChild = p->childContexts;
649         if (nextChild) nextChild->prevChild = &nextChild;
650         prevChild = &p->childContexts;
651         p->childContexts = this;
652         ownedByParent = parentTakesOwnership;
653     }
654 }
655
656 /*
657 Refreshes all expressions that could possibly depend on this context.  Refreshing flushes all
658 context-tree dependent caches in the expressions, and should occur every time the context tree
659  *structure* (not values) changes.
660 */
661 void QDeclarativeContextData::refreshExpressions()
662 {
663     QDeclarativeContextData *child = childContexts;
664     while (child) {
665         child->refreshExpressions();
666         child = child->nextChild;
667     }
668
669     QDeclarativeAbstractExpression *expression = expressions;
670     while (expression) {
671         expression->refresh();
672         expression = expression->m_nextExpression;
673     }
674 }
675
676 void QDeclarativeContextData::addObject(QObject *o)
677 {
678     QDeclarativeData *data = QDeclarativeData::get(o, true);
679
680     Q_ASSERT(data->context == 0);
681
682     data->context = this;
683     data->outerContext = this;
684
685     data->nextContextObject = contextObjects;
686     if (data->nextContextObject)
687         data->nextContextObject->prevContextObject = &data->nextContextObject;
688     data->prevContextObject = &contextObjects;
689     contextObjects = data;
690 }
691
692 void QDeclarativeContextData::setIdProperty(int idx, QObject *obj)
693 {
694     idValues[idx] = obj;
695     idValues[idx].context = this;
696 }
697
698 void QDeclarativeContextData::setIdPropertyData(QDeclarativeIntegerCache *data)
699 {
700     Q_ASSERT(!propertyNames);
701     propertyNames = data;
702     propertyNames->addref();
703
704     idValueCount = data->count();
705     idValues = new ContextGuard[idValueCount];
706 }
707
708 QString QDeclarativeContextData::findObjectId(const QObject *obj) const
709 {
710     if (!propertyNames)
711         return QString();
712
713     for (int ii = 0; ii < idValueCount; ii++) {
714         if (idValues[ii] == obj)
715             return propertyNames->findId(ii);
716     }
717
718     if (publicContext) {
719         QDeclarativeContextPrivate *p = QDeclarativeContextPrivate::get(publicContext);
720         for (int ii = 0; ii < p->propertyValues.count(); ++ii)
721             if (p->propertyValues.at(ii) == QVariant::fromValue((QObject *)obj))
722                 return propertyNames->findId(ii);
723     }
724
725     if (linkedContext)
726         return linkedContext->findObjectId(obj);
727     return QString();
728 }
729
730 QDeclarativeContext *QDeclarativeContextData::asQDeclarativeContext()
731 {
732     if (!publicContext)
733         publicContext = new QDeclarativeContext(this);
734     return publicContext;
735 }
736
737 QDeclarativeContextPrivate *QDeclarativeContextData::asQDeclarativeContextPrivate()
738 {
739     return QDeclarativeContextPrivate::get(asQDeclarativeContext());
740 }
741
742 QT_END_NAMESPACE