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