a02b2b7dd474d0d7b2831ec8c1d1a5fbdc568c27
[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 \b 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), hasEmittedDestruction(false), isRootObjectInCreation(false),
517   publicContext(0), activeVMEData(0),
518   propertyNames(0), contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0),
519   expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0),
520   componentAttached(0), v4bindings(0), v8bindings(0)
521 {
522 }
523
524 QQmlContextData::QQmlContextData(QQmlContext *ctxt)
525 : parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false), 
526   isPragmaLibraryContext(false), unresolvedNames(false), hasEmittedDestruction(false), isRootObjectInCreation(false),
527   publicContext(ctxt), activeVMEData(0),
528   propertyNames(0), contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0),
529   expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0),
530   componentAttached(0), v4bindings(0), v8bindings(0)
531 {
532 }
533
534 void QQmlContextData::emitDestruction()
535 {
536     if (!hasEmittedDestruction) {
537         hasEmittedDestruction = true;
538
539         // Emit the destruction signal - must be emitted before invalidate so that the
540         // context is still valid if bindings or resultant expression evaluation requires it
541         if (engine) {
542             while (componentAttached) {
543                 QQmlComponentAttached *a = componentAttached;
544                 componentAttached = a->next;
545                 if (componentAttached) componentAttached->prev = &componentAttached;
546
547                 a->next = 0;
548                 a->prev = 0;
549
550                 emit a->destruction();
551             }
552
553             QQmlContextData * child = childContexts;
554             while (child) {
555                 child->emitDestruction();
556                 child = child->nextChild;
557             }
558         }
559     }
560 }
561
562 void QQmlContextData::invalidate()
563 {
564     emitDestruction();
565
566     while (childContexts) {
567         if (childContexts->ownedByParent) {
568             childContexts->destroy();
569         } else {
570             childContexts->invalidate();
571         }
572     }
573
574     if (prevChild) {
575         *prevChild = nextChild;
576         if (nextChild) nextChild->prevChild = prevChild;
577         nextChild = 0;
578         prevChild = 0;
579     }
580
581     engine = 0;
582     parent = 0;
583 }
584
585 void QQmlContextData::clearContext()
586 {
587     emitDestruction();
588
589     QQmlAbstractExpression *expression = expressions;
590     while (expression) {
591         QQmlAbstractExpression *nextExpression = expression->m_nextExpression;
592
593         expression->m_prevExpression = 0;
594         expression->m_nextExpression = 0;
595
596         expression->setContext(0);
597
598         expression = nextExpression;
599     }
600     expressions = 0;
601 }
602
603 void QQmlContextData::destroy()
604 {
605     if (linkedContext)
606         linkedContext->destroy();
607
608     if (engine) invalidate();
609
610     clearContext();
611
612     while (contextObjects) {
613         QQmlData *co = contextObjects;
614         contextObjects = contextObjects->nextContextObject;
615
616         co->context = 0;
617         co->outerContext = 0;
618         co->nextContextObject = 0;
619         co->prevContextObject = 0;
620     }
621
622     QQmlGuardedContextData *contextGuard = contextGuards;
623     while (contextGuard) {
624         QQmlGuardedContextData *next = contextGuard->m_next;
625         contextGuard->m_next = 0;
626         contextGuard->m_prev = 0;
627         contextGuard->m_contextData = 0;
628         contextGuard = next;
629     }
630     contextGuards = 0;
631
632     if (propertyNames)
633         propertyNames->release();
634
635     if (imports)
636         imports->release();
637
638     if (v4bindings)
639         v4bindings->release();
640
641     if (v8bindings)
642         v8bindings->release();
643
644     for (int ii = 0; ii < importedScripts.count(); ++ii) {
645         qPersistentDispose(importedScripts[ii]);
646     }
647
648     delete [] idValues;
649
650     if (isInternal)
651         delete publicContext;
652
653     delete this;
654 }
655
656 void QQmlContextData::setParent(QQmlContextData *p, bool parentTakesOwnership)
657 {
658     if (p) {
659         parent = p;
660         engine = p->engine;
661         nextChild = p->childContexts;
662         if (nextChild) nextChild->prevChild = &nextChild;
663         prevChild = &p->childContexts;
664         p->childContexts = this;
665         ownedByParent = parentTakesOwnership;
666     }
667 }
668
669 void QQmlContextData::refreshExpressionsRecursive(QQmlAbstractExpression *expression)
670 {
671     QQmlAbstractExpression::DeleteWatcher w(expression);
672
673     if (expression->m_nextExpression)
674         refreshExpressionsRecursive(expression->m_nextExpression);
675
676     if (!w.wasDeleted())
677         expression->refresh();
678 }
679
680 static inline bool expressions_to_run(QQmlContextData *ctxt, bool isGlobalRefresh)
681 {
682     return ctxt->expressions && (!isGlobalRefresh || ctxt->unresolvedNames);
683 }
684
685 void QQmlContextData::refreshExpressionsRecursive(bool isGlobal)
686 {
687     // For efficiency, we try and minimize the number of guards we have to create
688     if (expressions_to_run(this, isGlobal) && (nextChild || childContexts)) {
689         QQmlGuardedContextData guard(this);
690
691         if (childContexts)
692             childContexts->refreshExpressionsRecursive(isGlobal);
693
694         if (guard.isNull()) return;
695
696         if (nextChild)
697             nextChild->refreshExpressionsRecursive(isGlobal);
698
699         if (guard.isNull()) return;
700
701         if (expressions_to_run(this, isGlobal))
702             refreshExpressionsRecursive(expressions);
703
704     } else if (expressions_to_run(this, isGlobal)) {
705
706         refreshExpressionsRecursive(expressions);
707
708     } else if (nextChild && childContexts) {
709
710         QQmlGuardedContextData guard(this);
711
712         childContexts->refreshExpressionsRecursive(isGlobal);
713
714         if (!guard.isNull() && nextChild)
715             nextChild->refreshExpressionsRecursive(isGlobal);
716
717     } else if (nextChild) {
718
719         nextChild->refreshExpressionsRecursive(isGlobal);
720
721     } else if (childContexts) {
722
723         childContexts->refreshExpressionsRecursive(isGlobal);
724
725     }
726 }
727
728 // Refreshes all expressions that could possibly depend on this context.  Refreshing flushes all
729 // context-tree dependent caches in the expressions, and should occur every time the context tree
730 // *structure* (not values) changes.
731 void QQmlContextData::refreshExpressions()
732 {
733     bool isGlobal = (parent == 0);
734
735     // For efficiency, we try and minimize the number of guards we have to create
736     if (expressions_to_run(this, isGlobal) && childContexts) {
737         QQmlGuardedContextData guard(this);
738
739         childContexts->refreshExpressionsRecursive(isGlobal);
740
741         if (!guard.isNull() && expressions_to_run(this, isGlobal))
742             refreshExpressionsRecursive(expressions);
743
744     } else if (expressions_to_run(this, isGlobal)) {
745
746         refreshExpressionsRecursive(expressions);
747
748     } else if (childContexts) {
749
750         childContexts->refreshExpressionsRecursive(isGlobal);
751
752     }
753 }
754
755 void QQmlContextData::addObject(QObject *o)
756 {
757     QQmlData *data = QQmlData::get(o, true);
758
759     Q_ASSERT(data->context == 0);
760
761     data->context = this;
762     data->outerContext = this;
763
764     data->nextContextObject = contextObjects;
765     if (data->nextContextObject)
766         data->nextContextObject->prevContextObject = &data->nextContextObject;
767     data->prevContextObject = &contextObjects;
768     contextObjects = data;
769 }
770
771 void QQmlContextData::setIdProperty(int idx, QObject *obj)
772 {
773     idValues[idx] = obj;
774     idValues[idx].context = this;
775 }
776
777 void QQmlContextData::setIdPropertyData(QQmlIntegerCache *data)
778 {
779     Q_ASSERT(!propertyNames);
780     propertyNames = data;
781     propertyNames->addref();
782
783     idValueCount = data->count();
784     idValues = new ContextGuard[idValueCount];
785 }
786
787 QString QQmlContextData::findObjectId(const QObject *obj) const
788 {
789     if (!propertyNames)
790         return QString();
791
792     for (int ii = 0; ii < idValueCount; ii++) {
793         if (idValues[ii] == obj)
794             return propertyNames->findId(ii);
795     }
796
797     if (publicContext) {
798         QQmlContextPrivate *p = QQmlContextPrivate::get(publicContext);
799         for (int ii = 0; ii < p->propertyValues.count(); ++ii)
800             if (p->propertyValues.at(ii) == QVariant::fromValue((QObject *)obj))
801                 return propertyNames->findId(ii);
802     }
803
804     if (linkedContext)
805         return linkedContext->findObjectId(obj);
806     return QString();
807 }
808
809 QQmlContext *QQmlContextData::asQQmlContext()
810 {
811     if (!publicContext)
812         publicContext = new QQmlContext(this);
813     return publicContext;
814 }
815
816 QQmlContextPrivate *QQmlContextData::asQQmlContextPrivate()
817 {
818     return QQmlContextPrivate::get(asQQmlContext());
819 }
820
821 QT_END_NAMESPACE