Initial import from the monolithic Qt.
[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 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
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 "private/qdeclarativecompiledbindings_p.h"
50 #include "qdeclarativeinfo.h"
51 #include "private/qdeclarativeglobalscriptclass_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), 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), 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         childContexts->invalidate();
520
521     while (componentAttached) {
522         QDeclarativeComponentAttached *a = componentAttached;
523         componentAttached = a->next;
524         if (componentAttached) componentAttached->prev = &componentAttached;
525
526         a->next = 0;
527         a->prev = 0;
528
529         emit a->destruction();
530     }
531
532     if (prevChild) {
533         *prevChild = nextChild;
534         if (nextChild) nextChild->prevChild = prevChild;
535         nextChild = 0;
536         prevChild = 0;
537     }
538
539     engine = 0;
540     parent = 0;
541 }
542
543 void QDeclarativeContextData::clearContext()
544 {
545     if (engine) {
546         while (componentAttached) {
547             QDeclarativeComponentAttached *a = componentAttached;
548             componentAttached = a->next;
549             if (componentAttached) componentAttached->prev = &componentAttached;
550
551             a->next = 0;
552             a->prev = 0;
553
554             emit a->destruction();
555         }
556     }
557
558     QDeclarativeAbstractExpression *expression = expressions;
559     while (expression) {
560         QDeclarativeAbstractExpression *nextExpression = expression->m_nextExpression;
561
562         expression->m_context = 0;
563         expression->m_prevExpression = 0;
564         expression->m_nextExpression = 0;
565
566         expression = nextExpression;
567     }
568     expressions = 0;
569 }
570
571 void QDeclarativeContextData::destroy()
572 {
573     if (linkedContext)
574         linkedContext->destroy();
575
576     if (engine) invalidate();
577
578     clearContext();
579
580     while (contextObjects) {
581         QDeclarativeData *co = contextObjects;
582         contextObjects = contextObjects->nextContextObject;
583
584         co->context = 0;
585         co->outerContext = 0;
586         co->nextContextObject = 0;
587         co->prevContextObject = 0;
588     }
589
590     QDeclarativeGuardedContextData *contextGuard = contextGuards;
591     while (contextGuard) {
592         QDeclarativeGuardedContextData *next = contextGuard->m_next;
593         contextGuard->m_next = 0;
594         contextGuard->m_prev = 0;
595         contextGuard->m_contextData = 0;
596         contextGuard = next;
597     }
598     contextGuards = 0;
599
600     if (propertyNames)
601         propertyNames->release();
602
603     if (imports)
604         imports->release();
605
606     if (optimizedBindings)
607         optimizedBindings->release();
608
609     delete [] idValues;
610
611     if (isInternal)
612         delete publicContext;
613
614     delete this;
615 }
616
617 void QDeclarativeContextData::setParent(QDeclarativeContextData *p)
618 {
619     if (p) {
620         parent = p;
621         engine = p->engine;
622         nextChild = p->childContexts;
623         if (nextChild) nextChild->prevChild = &nextChild;
624         prevChild = &p->childContexts;
625         p->childContexts = this;
626     }
627 }
628
629 /*
630 Refreshes all expressions that could possibly depend on this context.  Refreshing flushes all
631 context-tree dependent caches in the expressions, and should occur every time the context tree
632  *structure* (not values) changes.
633 */
634 void QDeclarativeContextData::refreshExpressions()
635 {
636     QDeclarativeContextData *child = childContexts;
637     while (child) {
638         child->refreshExpressions();
639         child = child->nextChild;
640     }
641
642     QDeclarativeAbstractExpression *expression = expressions;
643     while (expression) {
644         expression->refresh();
645         expression = expression->m_nextExpression;
646     }
647 }
648
649 void QDeclarativeContextData::addObject(QObject *o)
650 {
651     QDeclarativeData *data = QDeclarativeData::get(o, true);
652
653     Q_ASSERT(data->context == 0);
654
655     data->context = this;
656     data->outerContext = this;
657
658     data->nextContextObject = contextObjects;
659     if (data->nextContextObject)
660         data->nextContextObject->prevContextObject = &data->nextContextObject;
661     data->prevContextObject = &contextObjects;
662     contextObjects = data;
663 }
664
665 void QDeclarativeContextData::addImportedScript(const QDeclarativeParser::Object::ScriptBlock &script)
666 {
667     if (!engine)
668         return;
669
670     QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine);
671     QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
672
673     const QString &code = script.code;
674     const QString &url = script.file;
675     const QDeclarativeParser::Object::ScriptBlock::Pragmas &pragmas = script.pragmas;
676
677     Q_ASSERT(!url.isEmpty());
678
679     if (pragmas & QDeclarativeParser::Object::ScriptBlock::Shared) {
680
681         QHash<QString, QScriptValue>::Iterator iter = enginePriv->m_sharedScriptImports.find(url);
682         if (iter == enginePriv->m_sharedScriptImports.end()) {
683             QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
684
685             scriptContext->pushScope(enginePriv->contextClass->newUrlContext(url));
686             scriptContext->pushScope(enginePriv->globalClass->staticGlobalObject());
687
688             QScriptValue scope = QScriptDeclarativeClass::newStaticScopeObject(scriptEngine);
689             scriptContext->pushScope(scope);
690
691             scriptEngine->evaluate(code, url, 1);
692
693             if (scriptEngine->hasUncaughtException()) {
694                 QDeclarativeError error;
695                 QDeclarativeExpressionPrivate::exceptionToError(scriptEngine, error);
696                 enginePriv->warning(error);
697             }
698
699             scriptEngine->popContext();
700
701             iter = enginePriv->m_sharedScriptImports.insert(url, scope);
702         }
703
704         importedScripts.append(*iter);
705
706     } else {
707
708         QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
709
710         scriptContext->pushScope(enginePriv->contextClass->newUrlContext(this, 0, url));
711         scriptContext->pushScope(enginePriv->globalClass->staticGlobalObject());
712
713         QScriptValue scope = QScriptDeclarativeClass::newStaticScopeObject(scriptEngine);
714         scriptContext->pushScope(scope);
715
716         scriptEngine->evaluate(code, url, 1);
717
718         if (scriptEngine->hasUncaughtException()) {
719             QDeclarativeError error;
720             QDeclarativeExpressionPrivate::exceptionToError(scriptEngine, error);
721             enginePriv->warning(error);
722         }
723
724         scriptEngine->popContext();
725
726         importedScripts.append(scope);
727
728     }
729 }
730
731 void QDeclarativeContextData::setIdProperty(int idx, QObject *obj)
732 {
733     idValues[idx] = obj;
734     idValues[idx].context = this;
735 }
736
737 void QDeclarativeContextData::setIdPropertyData(QDeclarativeIntegerCache *data)
738 {
739     Q_ASSERT(!propertyNames);
740     propertyNames = data;
741     propertyNames->addref();
742
743     idValueCount = data->count();
744     idValues = new ContextGuard[idValueCount];
745 }
746
747 QString QDeclarativeContextData::findObjectId(const QObject *obj) const
748 {
749     if (!idValues || !propertyNames)
750         return QString();
751
752     for (int i=0; i<idValueCount; i++) {
753         if (idValues[i] == obj)
754             return propertyNames->findId(i);
755     }
756
757     if (linkedContext)
758         return linkedContext->findObjectId(obj);
759     return QString();
760 }
761
762 QDeclarativeContext *QDeclarativeContextData::asQDeclarativeContext()
763 {
764     if (!publicContext)
765         publicContext = new QDeclarativeContext(this);
766     return publicContext;
767 }
768
769 QDeclarativeContextPrivate *QDeclarativeContextData::asQDeclarativeContextPrivate()
770 {
771     return QDeclarativeContextPrivate::get(asQDeclarativeContext());
772 }
773
774 QT_END_NAMESPACE