Merge branch 'master' of git://gitorious.org/qt/qtdeclarative into api_changes
[profile/ivi/qtdeclarative.git] / src / qml / qml / qqmlcontext.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qqmlcontext.h"
43 #include "qqmlcontext_p.h"
44 #include "qqmlcomponentattached_p.h"
45
46 #include "qqmlcomponent_p.h"
47 #include "qqmlexpression_p.h"
48 #include "qqmlengine_p.h"
49 #include "qqmlengine.h"
50 #include "qqmlinfo.h"
51 #include <private/qv4bindings_p.h>
52 #include <private/qv8bindings_p.h>
53
54 #include <qjsengine.h>
55 #include <QtCore/qvarlengtharray.h>
56 #include <QtCore/qdebug.h>
57
58 QT_BEGIN_NAMESPACE
59
60 QQmlContextPrivate::QQmlContextPrivate()
61 : data(0), notifyIndex(-1)
62 {
63 }
64
65 /*!
66     \class QQmlContext
67     \since 4.7
68     \brief The QQmlContext 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 QQmlContext 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     QQmlContext::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     QQmlEngine engine;
82     QStringListModel modelData;
83     QQmlContext *context = new QQmlContext(engine.rootContext());
84     context->setContextProperty("myModel", &modelData);
85
86     QQmlComponent component(&engine);
87     component.setData("import QtQuick 2.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 QQmlContext 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 QQmlContext.  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 QQmlContext::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     QQmlEngine engine;
115     QQmlContext *context = new QQmlContext(engine.rootContext());
116     context->setContextObject(&myDataSet);
117
118     QQmlComponent component(&engine);
119     component.setData("import QtQuick 2.0\nListView { model: myModel }", QUrl());
120     component.create(context);
121     \endcode
122
123     All properties added explicitly by QQmlContext::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 {QQmlEngine::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     QQmlEngine engine;
140     QQmlContext *context1 = new QQmlContext(engine.rootContext());
141     QQmlContext *context2 = new QQmlContext(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 QQmlContext::QQmlContext(QQmlEngine *e, bool)
163 : QObject(*(new QQmlContextPrivate))
164 {
165     Q_D(QQmlContext);
166     d->data = new QQmlContextData(this);
167
168     d->data->engine = e;
169 }
170
171 /*!
172     Create a new QQmlContext as a child of \a engine's root context, and the
173     QObject \a parent.
174 */
175 QQmlContext::QQmlContext(QQmlEngine *engine, QObject *parent)
176 : QObject(*(new QQmlContextPrivate), parent)
177 {
178     Q_D(QQmlContext);
179     d->data = new QQmlContextData(this);
180
181     d->data->setParent(engine?QQmlContextData::get(engine->rootContext()):0);
182 }
183
184 /*!
185     Create a new QQmlContext with the given \a parentContext, and the
186     QObject \a parent.
187 */
188 QQmlContext::QQmlContext(QQmlContext *parentContext, QObject *parent)
189 : QObject(*(new QQmlContextPrivate), parent)
190 {
191     Q_D(QQmlContext);
192     d->data = new QQmlContextData(this);
193
194     d->data->setParent(parentContext?QQmlContextData::get(parentContext):0);
195 }
196
197 /*!
198     \internal
199 */
200 QQmlContext::QQmlContext(QQmlContextData *data)
201 : QObject(*(new QQmlContextPrivate), 0)
202 {
203     Q_D(QQmlContext);
204     d->data = data;
205 }
206
207 /*!
208     Destroys the QQmlContext.
209
210     Any expressions, or sub-contexts dependent on this context will be
211     invalidated, but not destroyed (unless they are parented to the QQmlContext
212     object).
213  */
214 QQmlContext::~QQmlContext()
215 {
216     Q_D(QQmlContext);
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 QQmlContext::isValid() const
229 {
230     Q_D(const QQmlContext);
231     return d->data && d->data->isValid();
232 }
233
234 /*!
235     Return the context's QQmlEngine, or 0 if the context has no QQmlEngine or the
236     QQmlEngine was destroyed.
237 */
238 QQmlEngine *QQmlContext::engine() const
239 {
240     Q_D(const QQmlContext);
241     return d->data->engine;
242 }
243
244 /*!
245     Return the context's parent QQmlContext, or 0 if this context has no
246     parent or if the parent has been destroyed.
247 */
248 QQmlContext *QQmlContext::parentContext() const
249 {
250     Q_D(const QQmlContext);
251     return d->data->parent?d->data->parent->asQQmlContext():0;
252 }
253
254 /*!
255     Return the context object, or 0 if there is no context object.
256 */
257 QObject *QQmlContext::contextObject() const
258 {
259     Q_D(const QQmlContext);
260     return d->data->contextObject;
261 }
262
263 /*!
264     Set the context \a object.
265 */
266 void QQmlContext::setContextObject(QObject *object)
267 {
268     Q_D(QQmlContext);
269
270     QQmlContextData *data = d->data;
271
272     if (data->isInternal) {
273         qWarning("QQmlContext: Cannot set context object for internal context.");
274         return;
275     }
276
277     if (!isValid()) {
278         qWarning("QQmlContext: 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 QQmlContext::setContextProperty(const QString &name, const QVariant &value)
289 {
290     Q_D(QQmlContext);
291     if (d->notifyIndex == -1)
292         d->notifyIndex = this->metaObject()->methodCount();
293
294     QQmlContextData *data = d->data;
295
296     if (data->isInternal) {
297         qWarning("QQmlContext: Cannot set property on internal context.");
298         return;
299     }
300
301     if (!isValid()) {
302         qWarning("QQmlContext: Cannot set property on invalid context.");
303         return;
304     }
305
306     if (data->engine) {
307         bool ok;
308         QObject *o = QQmlEnginePrivate::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 QQmlIntegerCache();
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     QQmlContext does \bold not take ownership of \a value.
333 */
334 void QQmlContext::setContextProperty(const QString &name, QObject *value)
335 {
336     Q_D(QQmlContext);
337     if (d->notifyIndex == -1)
338         d->notifyIndex = this->metaObject()->methodCount();
339
340     QQmlContextData *data = d->data;
341
342     if (data->isInternal) {
343         qWarning("QQmlContext: Cannot set property on internal context.");
344         return;
345     }
346
347     if (!isValid()) {
348         qWarning("QQmlContext: Cannot set property on invalid context.");
349         return;
350     }
351
352     if (!data->propertyNames) data->propertyNames = new QQmlIntegerCache();
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 QQmlContext::contextProperty(const QString &name) const
371 {
372     Q_D(const QQmlContext);
373     QVariant value;
374     int idx = -1;
375
376     QQmlContextData *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             QQmlPropertyData local;
386             QQmlPropertyData *property =
387                 QQmlPropertyCache::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 Returns the name of \a object in this context, or an empty string if \a object 
405 is not named in the context.  Objects are named by setContextProperty(), or by ids in
406 the case of QML created contexts.
407
408 If the object has multiple names, the first is returned.
409 */
410 QString QQmlContext::nameForObject(QObject *object) const
411 {
412     Q_D(const QQmlContext);
413
414     return d->data->findObjectId(object);
415 }
416
417 /*!
418     Resolves the URL \a src relative to the URL of the
419     containing component.
420
421     \sa QQmlEngine::baseUrl(), setBaseUrl()
422 */
423 QUrl QQmlContext::resolvedUrl(const QUrl &src)
424 {
425     Q_D(QQmlContext);
426     return d->data->resolvedUrl(src);
427 }
428
429 QUrl QQmlContextData::resolvedUrl(const QUrl &src)
430 {
431     QQmlContextData *ctxt = this;
432
433     if (src.isRelative() && !src.isEmpty()) {
434         if (ctxt) {
435             while(ctxt) {
436                 if(ctxt->url.isValid())
437                     break;
438                 else
439                     ctxt = ctxt->parent;
440             }
441
442             if (ctxt)
443                 return ctxt->url.resolved(src);
444             else if (engine)
445                 return engine->baseUrl().resolved(src);
446         }
447         return QUrl();
448     } else {
449         return src;
450     }
451 }
452
453
454 /*!
455     Explicitly sets the url resolvedUrl() will use for relative references to \a baseUrl.
456
457     Calling this function will override the url of the containing
458     component used by default.
459
460     \sa resolvedUrl()
461 */
462 void QQmlContext::setBaseUrl(const QUrl &baseUrl)
463 {
464     Q_D(QQmlContext);
465
466     d->data->url = baseUrl;
467     d->data->urlString = baseUrl.toString();
468 }
469
470 /*!
471     Returns the base url of the component, or the containing component
472     if none is set.
473 */
474 QUrl QQmlContext::baseUrl() const
475 {
476     Q_D(const QQmlContext);
477     const QQmlContextData* data = d->data;
478     while (data && data->url.isEmpty())
479         data = data->parent;
480
481     if (data)
482         return data->url;
483     else
484         return QUrl();
485 }
486
487 int QQmlContextPrivate::context_count(QQmlListProperty<QObject> *prop)
488 {
489     QQmlContext *context = static_cast<QQmlContext*>(prop->object);
490     QQmlContextPrivate *d = QQmlContextPrivate::get(context);
491     int contextProperty = (int)(quintptr)prop->data;
492
493     if (d->propertyValues.at(contextProperty).userType() != qMetaTypeId<QList<QObject*> >()) {
494         return 0;
495     } else {
496         return ((const QList<QObject> *)d->propertyValues.at(contextProperty).constData())->count();
497     }
498 }
499
500 QObject *QQmlContextPrivate::context_at(QQmlListProperty<QObject> *prop, int index)
501 {
502     QQmlContext *context = static_cast<QQmlContext*>(prop->object);
503     QQmlContextPrivate *d = QQmlContextPrivate::get(context);
504     int contextProperty = (int)(quintptr)prop->data;
505
506     if (d->propertyValues.at(contextProperty).userType() != qMetaTypeId<QList<QObject*> >()) {
507         return 0;
508     } else {
509         return ((const QList<QObject*> *)d->propertyValues.at(contextProperty).constData())->at(index);
510     }
511 }
512
513
514 QQmlContextData::QQmlContextData()
515 : parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false), 
516   isPragmaLibraryContext(false), unresolvedNames(false), publicContext(0), activeVMEData(0),
517   propertyNames(0), contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0),
518   expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0),
519   componentAttached(0), v4bindings(0), v8bindings(0)
520 {
521 }
522
523 QQmlContextData::QQmlContextData(QQmlContext *ctxt)
524 : parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false), 
525   isPragmaLibraryContext(false), unresolvedNames(false), publicContext(ctxt), activeVMEData(0),
526   propertyNames(0), contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0),
527   expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0),
528   componentAttached(0), v4bindings(0), v8bindings(0)
529 {
530 }
531
532 void QQmlContextData::invalidate()
533 {
534     while (componentAttached) {
535         QQmlComponentAttached *a = componentAttached;
536         componentAttached = a->next;
537         if (componentAttached) componentAttached->prev = &componentAttached;
538
539         a->next = 0;
540         a->prev = 0;
541
542         emit a->destruction();
543     }
544
545     while (childContexts) {
546         if (childContexts->ownedByParent) {
547             childContexts->destroy();
548         } else {
549             childContexts->invalidate();
550         }
551     }
552
553     if (prevChild) {
554         *prevChild = nextChild;
555         if (nextChild) nextChild->prevChild = prevChild;
556         nextChild = 0;
557         prevChild = 0;
558     }
559
560     engine = 0;
561     parent = 0;
562 }
563
564 void QQmlContextData::clearContext()
565 {
566     if (engine) {
567         while (componentAttached) {
568             QQmlComponentAttached *a = componentAttached;
569             componentAttached = a->next;
570             if (componentAttached) componentAttached->prev = &componentAttached;
571
572             a->next = 0;
573             a->prev = 0;
574
575             emit a->destruction();
576         }
577     }
578
579     QQmlAbstractExpression *expression = expressions;
580     while (expression) {
581         QQmlAbstractExpression *nextExpression = expression->m_nextExpression;
582
583         expression->m_prevExpression = 0;
584         expression->m_nextExpression = 0;
585
586         expression->setContext(0);
587
588         expression = nextExpression;
589     }
590     expressions = 0;
591 }
592
593 void QQmlContextData::destroy()
594 {
595     if (linkedContext)
596         linkedContext->destroy();
597
598     if (engine) invalidate();
599
600     clearContext();
601
602     while (contextObjects) {
603         QQmlData *co = contextObjects;
604         contextObjects = contextObjects->nextContextObject;
605
606         co->context = 0;
607         co->outerContext = 0;
608         co->nextContextObject = 0;
609         co->prevContextObject = 0;
610     }
611
612     QQmlGuardedContextData *contextGuard = contextGuards;
613     while (contextGuard) {
614         QQmlGuardedContextData *next = contextGuard->m_next;
615         contextGuard->m_next = 0;
616         contextGuard->m_prev = 0;
617         contextGuard->m_contextData = 0;
618         contextGuard = next;
619     }
620     contextGuards = 0;
621
622     if (propertyNames)
623         propertyNames->release();
624
625     if (imports)
626         imports->release();
627
628     if (v4bindings)
629         v4bindings->release();
630
631     if (v8bindings)
632         v8bindings->release();
633
634     for (int ii = 0; ii < importedScripts.count(); ++ii) {
635         qPersistentDispose(importedScripts[ii]);
636     }
637
638     delete [] idValues;
639
640     if (isInternal)
641         delete publicContext;
642
643     delete this;
644 }
645
646 void QQmlContextData::setParent(QQmlContextData *p, bool parentTakesOwnership)
647 {
648     if (p) {
649         parent = p;
650         engine = p->engine;
651         nextChild = p->childContexts;
652         if (nextChild) nextChild->prevChild = &nextChild;
653         prevChild = &p->childContexts;
654         p->childContexts = this;
655         ownedByParent = parentTakesOwnership;
656     }
657 }
658
659 void QQmlContextData::refreshExpressionsRecursive(QQmlAbstractExpression *expression)
660 {
661     QQmlAbstractExpression::DeleteWatcher w(expression);
662
663     if (expression->m_nextExpression)
664         refreshExpressionsRecursive(expression->m_nextExpression);
665
666     if (!w.wasDeleted())
667         expression->refresh();
668 }
669
670 static inline bool expressions_to_run(QQmlContextData *ctxt, bool isGlobalRefresh)
671 {
672     return ctxt->expressions && (!isGlobalRefresh || ctxt->unresolvedNames);
673 }
674
675 void QQmlContextData::refreshExpressionsRecursive(bool isGlobal)
676 {
677     // For efficiency, we try and minimize the number of guards we have to create
678     if (expressions_to_run(this, isGlobal) && (nextChild || childContexts)) {
679         QQmlGuardedContextData guard(this);
680
681         if (childContexts)
682             childContexts->refreshExpressionsRecursive(isGlobal);
683
684         if (guard.isNull()) return;
685
686         if (nextChild)
687             nextChild->refreshExpressionsRecursive(isGlobal);
688
689         if (guard.isNull()) return;
690
691         if (expressions_to_run(this, isGlobal))
692             refreshExpressionsRecursive(expressions);
693
694     } else if (expressions_to_run(this, isGlobal)) {
695
696         refreshExpressionsRecursive(expressions);
697
698     } else if (nextChild && childContexts) {
699
700         QQmlGuardedContextData guard(this);
701
702         childContexts->refreshExpressionsRecursive(isGlobal);
703
704         if (!guard.isNull() && nextChild)
705             nextChild->refreshExpressionsRecursive(isGlobal);
706
707     } else if (nextChild) {
708
709         nextChild->refreshExpressionsRecursive(isGlobal);
710
711     } else if (childContexts) {
712
713         childContexts->refreshExpressionsRecursive(isGlobal);
714
715     }
716 }
717
718 // Refreshes all expressions that could possibly depend on this context.  Refreshing flushes all
719 // context-tree dependent caches in the expressions, and should occur every time the context tree
720 // *structure* (not values) changes.
721 void QQmlContextData::refreshExpressions()
722 {
723     bool isGlobal = (parent == 0);
724
725     // For efficiency, we try and minimize the number of guards we have to create
726     if (expressions_to_run(this, isGlobal) && childContexts) {
727         QQmlGuardedContextData guard(this);
728
729         childContexts->refreshExpressionsRecursive(isGlobal);
730
731         if (!guard.isNull() && expressions_to_run(this, isGlobal))
732             refreshExpressionsRecursive(expressions);
733
734     } else if (expressions_to_run(this, isGlobal)) {
735
736         refreshExpressionsRecursive(expressions);
737
738     } else if (childContexts) {
739
740         childContexts->refreshExpressionsRecursive(isGlobal);
741
742     }
743 }
744
745 void QQmlContextData::addObject(QObject *o)
746 {
747     QQmlData *data = QQmlData::get(o, true);
748
749     Q_ASSERT(data->context == 0);
750
751     data->context = this;
752     data->outerContext = this;
753
754     data->nextContextObject = contextObjects;
755     if (data->nextContextObject)
756         data->nextContextObject->prevContextObject = &data->nextContextObject;
757     data->prevContextObject = &contextObjects;
758     contextObjects = data;
759 }
760
761 void QQmlContextData::setIdProperty(int idx, QObject *obj)
762 {
763     idValues[idx] = obj;
764     idValues[idx].context = this;
765 }
766
767 void QQmlContextData::setIdPropertyData(QQmlIntegerCache *data)
768 {
769     Q_ASSERT(!propertyNames);
770     propertyNames = data;
771     propertyNames->addref();
772
773     idValueCount = data->count();
774     idValues = new ContextGuard[idValueCount];
775 }
776
777 QString QQmlContextData::findObjectId(const QObject *obj) const
778 {
779     if (!propertyNames)
780         return QString();
781
782     for (int ii = 0; ii < idValueCount; ii++) {
783         if (idValues[ii] == obj)
784             return propertyNames->findId(ii);
785     }
786
787     if (publicContext) {
788         QQmlContextPrivate *p = QQmlContextPrivate::get(publicContext);
789         for (int ii = 0; ii < p->propertyValues.count(); ++ii)
790             if (p->propertyValues.at(ii) == QVariant::fromValue((QObject *)obj))
791                 return propertyNames->findId(ii);
792     }
793
794     if (linkedContext)
795         return linkedContext->findObjectId(obj);
796     return QString();
797 }
798
799 QQmlContext *QQmlContextData::asQQmlContext()
800 {
801     if (!publicContext)
802         publicContext = new QQmlContext(this);
803     return publicContext;
804 }
805
806 QQmlContextPrivate *QQmlContextData::asQQmlContextPrivate()
807 {
808     return QQmlContextPrivate::get(asQQmlContext());
809 }
810
811 QT_END_NAMESPACE