Update to 5.0.0-beta1
[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 <private/qmetaobject_p.h>
57 #include <QtCore/qdebug.h>
58
59 QT_BEGIN_NAMESPACE
60
61 QQmlContextPrivate::QQmlContextPrivate()
62 : data(0), notifyIndex(-1)
63 {
64 }
65
66 /*!
67     \class QQmlContext
68     \brief The QQmlContext class defines a context within a QML engine.
69     \mainclass
70     \inmodule QtQml
71
72     Contexts allow data to be exposed to the QML components instantiated by the
73     QML engine.
74
75     Each QQmlContext 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     QQmlContext::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     QQmlEngine engine;
83     QStringListModel modelData;
84     QQmlContext *context = new QQmlContext(engine.rootContext());
85     context->setContextProperty("myModel", &modelData);
86
87     QQmlComponent component(&engine);
88     component.setData("import QtQuick 2.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 QQmlContext 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 QQmlContext.  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 QQmlContext::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     QQmlEngine engine;
116     QQmlContext *context = new QQmlContext(engine.rootContext());
117     context->setContextObject(&myDataSet);
118
119     QQmlComponent component(&engine);
120     component.setData("import QtQuick 2.0\nListView { model: myModel }", QUrl());
121     component.create(context);
122     \endcode
123
124     All properties added explicitly by QQmlContext::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 {QQmlEngine::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     QQmlEngine engine;
141     QQmlContext *context1 = new QQmlContext(engine.rootContext());
142     QQmlContext *context2 = new QQmlContext(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 {qtqml-cppintegration-exposecppattributes.html}{Exposing Attributes of C++ Types to QML}
160 */
161
162 /*! \internal */
163 QQmlContext::QQmlContext(QQmlEngine *e, bool)
164 : QObject(*(new QQmlContextPrivate))
165 {
166     Q_D(QQmlContext);
167     d->data = new QQmlContextData(this);
168
169     d->data->engine = e;
170 }
171
172 /*!
173     Create a new QQmlContext as a child of \a engine's root context, and the
174     QObject \a parent.
175 */
176 QQmlContext::QQmlContext(QQmlEngine *engine, QObject *parent)
177 : QObject(*(new QQmlContextPrivate), parent)
178 {
179     Q_D(QQmlContext);
180     d->data = new QQmlContextData(this);
181
182     d->data->setParent(engine?QQmlContextData::get(engine->rootContext()):0);
183 }
184
185 /*!
186     Create a new QQmlContext with the given \a parentContext, and the
187     QObject \a parent.
188 */
189 QQmlContext::QQmlContext(QQmlContext *parentContext, QObject *parent)
190 : QObject(*(new QQmlContextPrivate), parent)
191 {
192     Q_D(QQmlContext);
193     d->data = new QQmlContextData(this);
194
195     d->data->setParent(parentContext?QQmlContextData::get(parentContext):0);
196 }
197
198 /*!
199     \internal
200 */
201 QQmlContext::QQmlContext(QQmlContextData *data)
202 : QObject(*(new QQmlContextPrivate), 0)
203 {
204     Q_D(QQmlContext);
205     d->data = data;
206 }
207
208 /*!
209     Destroys the QQmlContext.
210
211     Any expressions, or sub-contexts dependent on this context will be
212     invalidated, but not destroyed (unless they are parented to the QQmlContext
213     object).
214  */
215 QQmlContext::~QQmlContext()
216 {
217     Q_D(QQmlContext);
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 QQmlContext::isValid() const
230 {
231     Q_D(const QQmlContext);
232     return d->data && d->data->isValid();
233 }
234
235 /*!
236     Return the context's QQmlEngine, or 0 if the context has no QQmlEngine or the
237     QQmlEngine was destroyed.
238 */
239 QQmlEngine *QQmlContext::engine() const
240 {
241     Q_D(const QQmlContext);
242     return d->data->engine;
243 }
244
245 /*!
246     Return the context's parent QQmlContext, or 0 if this context has no
247     parent or if the parent has been destroyed.
248 */
249 QQmlContext *QQmlContext::parentContext() const
250 {
251     Q_D(const QQmlContext);
252     return d->data->parent?d->data->parent->asQQmlContext():0;
253 }
254
255 /*!
256     Return the context object, or 0 if there is no context object.
257 */
258 QObject *QQmlContext::contextObject() const
259 {
260     Q_D(const QQmlContext);
261     return d->data->contextObject;
262 }
263
264 /*!
265     Set the context \a object.
266 */
267 void QQmlContext::setContextObject(QObject *object)
268 {
269     Q_D(QQmlContext);
270
271     QQmlContextData *data = d->data;
272
273     if (data->isInternal) {
274         qWarning("QQmlContext: Cannot set context object for internal context.");
275         return;
276     }
277
278     if (!isValid()) {
279         qWarning("QQmlContext: 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 QQmlContext::setContextProperty(const QString &name, const QVariant &value)
290 {
291     Q_D(QQmlContext);
292     if (d->notifyIndex == -1)
293         d->notifyIndex = QMetaObjectPrivate::absoluteSignalCount(&QQmlContext::staticMetaObject);
294
295     QQmlContextData *data = d->data;
296
297     if (data->isInternal) {
298         qWarning("QQmlContext: Cannot set property on internal context.");
299         return;
300     }
301
302     if (!isValid()) {
303         qWarning("QQmlContext: Cannot set property on invalid context.");
304         return;
305     }
306
307     if (data->engine) {
308         bool ok;
309         QObject *o = QQmlEnginePrivate::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 QQmlIntegerCache();
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, d->notifyIndex, idx, 0);
327     }
328 }
329
330 /*!
331     Set the \a value of the \a name property on this context.
332
333     QQmlContext does \b not take ownership of \a value.
334 */
335 void QQmlContext::setContextProperty(const QString &name, QObject *value)
336 {
337     Q_D(QQmlContext);
338     if (d->notifyIndex == -1)
339         d->notifyIndex = QMetaObjectPrivate::absoluteSignalCount(&QQmlContext::staticMetaObject);
340
341     QQmlContextData *data = d->data;
342
343     if (data->isInternal) {
344         qWarning("QQmlContext: Cannot set property on internal context.");
345         return;
346     }
347
348     if (!isValid()) {
349         qWarning("QQmlContext: Cannot set property on invalid context.");
350         return;
351     }
352
353     if (!data->propertyNames) data->propertyNames = new QQmlIntegerCache();
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, d->notifyIndex, idx, 0);
364     }
365 }
366
367 /*!
368   Returns the value of the \a name property for this context
369   as a QVariant.
370  */
371 QVariant QQmlContext::contextProperty(const QString &name) const
372 {
373     Q_D(const QQmlContext);
374     QVariant value;
375     int idx = -1;
376
377     QQmlContextData *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             QQmlPropertyData local;
387             QQmlPropertyData *property =
388                 QQmlPropertyCache::property(data->engine, obj, name, data, 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 Returns the name of \a object in this context, or an empty string if \a object 
406 is not named in the context.  Objects are named by setContextProperty(), or by ids in
407 the case of QML created contexts.
408
409 If the object has multiple names, the first is returned.
410 */
411 QString QQmlContext::nameForObject(QObject *object) const
412 {
413     Q_D(const QQmlContext);
414
415     return d->data->findObjectId(object);
416 }
417
418 /*!
419     Resolves the URL \a src relative to the URL of the
420     containing component.
421
422     \sa QQmlEngine::baseUrl(), setBaseUrl()
423 */
424 QUrl QQmlContext::resolvedUrl(const QUrl &src)
425 {
426     Q_D(QQmlContext);
427     return d->data->resolvedUrl(src);
428 }
429
430 QUrl QQmlContextData::resolvedUrl(const QUrl &src)
431 {
432     QQmlContextData *ctxt = this;
433
434     if (src.isRelative() && !src.isEmpty()) {
435         if (ctxt) {
436             while(ctxt) {
437                 if(ctxt->url.isValid())
438                     break;
439                 else
440                     ctxt = ctxt->parent;
441             }
442
443             if (ctxt)
444                 return ctxt->url.resolved(src);
445             else if (engine)
446                 return engine->baseUrl().resolved(src);
447         }
448         return QUrl();
449     } else {
450         return src;
451     }
452 }
453
454
455 /*!
456     Explicitly sets the url resolvedUrl() will use for relative references to \a baseUrl.
457
458     Calling this function will override the url of the containing
459     component used by default.
460
461     \sa resolvedUrl()
462 */
463 void QQmlContext::setBaseUrl(const QUrl &baseUrl)
464 {
465     Q_D(QQmlContext);
466
467     d->data->url = baseUrl;
468     d->data->urlString = baseUrl.toString();
469 }
470
471 /*!
472     Returns the base url of the component, or the containing component
473     if none is set.
474 */
475 QUrl QQmlContext::baseUrl() const
476 {
477     Q_D(const QQmlContext);
478     const QQmlContextData* data = d->data;
479     while (data && data->url.isEmpty())
480         data = data->parent;
481
482     if (data)
483         return data->url;
484     else
485         return QUrl();
486 }
487
488 int QQmlContextPrivate::context_count(QQmlListProperty<QObject> *prop)
489 {
490     QQmlContext *context = static_cast<QQmlContext*>(prop->object);
491     QQmlContextPrivate *d = QQmlContextPrivate::get(context);
492     int contextProperty = (int)(quintptr)prop->data;
493
494     if (d->propertyValues.at(contextProperty).userType() != qMetaTypeId<QList<QObject*> >()) {
495         return 0;
496     } else {
497         return ((const QList<QObject> *)d->propertyValues.at(contextProperty).constData())->count();
498     }
499 }
500
501 QObject *QQmlContextPrivate::context_at(QQmlListProperty<QObject> *prop, int index)
502 {
503     QQmlContext *context = static_cast<QQmlContext*>(prop->object);
504     QQmlContextPrivate *d = QQmlContextPrivate::get(context);
505     int contextProperty = (int)(quintptr)prop->data;
506
507     if (d->propertyValues.at(contextProperty).userType() != qMetaTypeId<QList<QObject*> >()) {
508         return 0;
509     } else {
510         return ((const QList<QObject*> *)d->propertyValues.at(contextProperty).constData())->at(index);
511     }
512 }
513
514
515 QQmlContextData::QQmlContextData()
516 : parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false), 
517   isPragmaLibraryContext(false), unresolvedNames(false), hasEmittedDestruction(false), isRootObjectInCreation(false),
518   publicContext(0), activeVMEData(0),
519   propertyNames(0), contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0),
520   expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0),
521   componentAttached(0), v4bindings(0), v8bindings(0)
522 {
523 }
524
525 QQmlContextData::QQmlContextData(QQmlContext *ctxt)
526 : parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false), 
527   isPragmaLibraryContext(false), unresolvedNames(false), hasEmittedDestruction(false), isRootObjectInCreation(false),
528   publicContext(ctxt), activeVMEData(0),
529   propertyNames(0), contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0),
530   expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0),
531   componentAttached(0), v4bindings(0), v8bindings(0)
532 {
533 }
534
535 void QQmlContextData::emitDestruction()
536 {
537     if (!hasEmittedDestruction) {
538         hasEmittedDestruction = true;
539
540         // Emit the destruction signal - must be emitted before invalidate so that the
541         // context is still valid if bindings or resultant expression evaluation requires it
542         if (engine) {
543             while (componentAttached) {
544                 QQmlComponentAttached *a = componentAttached;
545                 componentAttached = a->next;
546                 if (componentAttached) componentAttached->prev = &componentAttached;
547
548                 a->next = 0;
549                 a->prev = 0;
550
551                 emit a->destruction();
552             }
553
554             QQmlContextData * child = childContexts;
555             while (child) {
556                 child->emitDestruction();
557                 child = child->nextChild;
558             }
559         }
560     }
561 }
562
563 void QQmlContextData::invalidate()
564 {
565     emitDestruction();
566
567     while (childContexts) {
568         if (childContexts->ownedByParent) {
569             childContexts->destroy();
570         } else {
571             childContexts->invalidate();
572         }
573     }
574
575     if (prevChild) {
576         *prevChild = nextChild;
577         if (nextChild) nextChild->prevChild = prevChild;
578         nextChild = 0;
579         prevChild = 0;
580     }
581
582     engine = 0;
583     parent = 0;
584 }
585
586 void QQmlContextData::clearContext()
587 {
588     emitDestruction();
589
590     QQmlAbstractExpression *expression = expressions;
591     while (expression) {
592         QQmlAbstractExpression *nextExpression = expression->m_nextExpression;
593
594         expression->m_prevExpression = 0;
595         expression->m_nextExpression = 0;
596
597         expression->setContext(0);
598
599         expression = nextExpression;
600     }
601     expressions = 0;
602 }
603
604 void QQmlContextData::destroy()
605 {
606     if (linkedContext)
607         linkedContext->destroy();
608
609     if (engine) invalidate();
610
611     clearContext();
612
613     while (contextObjects) {
614         QQmlData *co = contextObjects;
615         contextObjects = contextObjects->nextContextObject;
616
617         co->context = 0;
618         co->outerContext = 0;
619         co->nextContextObject = 0;
620         co->prevContextObject = 0;
621     }
622
623     QQmlGuardedContextData *contextGuard = contextGuards;
624     while (contextGuard) {
625         QQmlGuardedContextData *next = contextGuard->m_next;
626         contextGuard->m_next = 0;
627         contextGuard->m_prev = 0;
628         contextGuard->m_contextData = 0;
629         contextGuard = next;
630     }
631     contextGuards = 0;
632
633     if (propertyNames)
634         propertyNames->release();
635
636     if (imports)
637         imports->release();
638
639     if (v4bindings)
640         v4bindings->release();
641
642     if (v8bindings)
643         v8bindings->release();
644
645     for (int ii = 0; ii < importedScripts.count(); ++ii) {
646         qPersistentDispose(importedScripts[ii]);
647     }
648
649     delete [] idValues;
650
651     if (isInternal)
652         delete publicContext;
653
654     delete this;
655 }
656
657 void QQmlContextData::setParent(QQmlContextData *p, bool parentTakesOwnership)
658 {
659     if (p) {
660         parent = p;
661         engine = p->engine;
662         nextChild = p->childContexts;
663         if (nextChild) nextChild->prevChild = &nextChild;
664         prevChild = &p->childContexts;
665         p->childContexts = this;
666         ownedByParent = parentTakesOwnership;
667     }
668 }
669
670 void QQmlContextData::refreshExpressionsRecursive(QQmlAbstractExpression *expression)
671 {
672     QQmlAbstractExpression::DeleteWatcher w(expression);
673
674     if (expression->m_nextExpression)
675         refreshExpressionsRecursive(expression->m_nextExpression);
676
677     if (!w.wasDeleted())
678         expression->refresh();
679 }
680
681 static inline bool expressions_to_run(QQmlContextData *ctxt, bool isGlobalRefresh)
682 {
683     return ctxt->expressions && (!isGlobalRefresh || ctxt->unresolvedNames);
684 }
685
686 void QQmlContextData::refreshExpressionsRecursive(bool isGlobal)
687 {
688     // For efficiency, we try and minimize the number of guards we have to create
689     if (expressions_to_run(this, isGlobal) && (nextChild || childContexts)) {
690         QQmlGuardedContextData guard(this);
691
692         if (childContexts)
693             childContexts->refreshExpressionsRecursive(isGlobal);
694
695         if (guard.isNull()) return;
696
697         if (nextChild)
698             nextChild->refreshExpressionsRecursive(isGlobal);
699
700         if (guard.isNull()) return;
701
702         if (expressions_to_run(this, isGlobal))
703             refreshExpressionsRecursive(expressions);
704
705     } else if (expressions_to_run(this, isGlobal)) {
706
707         refreshExpressionsRecursive(expressions);
708
709     } else if (nextChild && childContexts) {
710
711         QQmlGuardedContextData guard(this);
712
713         childContexts->refreshExpressionsRecursive(isGlobal);
714
715         if (!guard.isNull() && nextChild)
716             nextChild->refreshExpressionsRecursive(isGlobal);
717
718     } else if (nextChild) {
719
720         nextChild->refreshExpressionsRecursive(isGlobal);
721
722     } else if (childContexts) {
723
724         childContexts->refreshExpressionsRecursive(isGlobal);
725
726     }
727 }
728
729 // Refreshes all expressions that could possibly depend on this context.  Refreshing flushes all
730 // context-tree dependent caches in the expressions, and should occur every time the context tree
731 // *structure* (not values) changes.
732 void QQmlContextData::refreshExpressions()
733 {
734     bool isGlobal = (parent == 0);
735
736     // For efficiency, we try and minimize the number of guards we have to create
737     if (expressions_to_run(this, isGlobal) && childContexts) {
738         QQmlGuardedContextData guard(this);
739
740         childContexts->refreshExpressionsRecursive(isGlobal);
741
742         if (!guard.isNull() && expressions_to_run(this, isGlobal))
743             refreshExpressionsRecursive(expressions);
744
745     } else if (expressions_to_run(this, isGlobal)) {
746
747         refreshExpressionsRecursive(expressions);
748
749     } else if (childContexts) {
750
751         childContexts->refreshExpressionsRecursive(isGlobal);
752
753     }
754 }
755
756 void QQmlContextData::addObject(QObject *o)
757 {
758     QQmlData *data = QQmlData::get(o, true);
759
760     Q_ASSERT(data->context == 0);
761
762     data->context = this;
763     data->outerContext = this;
764
765     data->nextContextObject = contextObjects;
766     if (data->nextContextObject)
767         data->nextContextObject->prevContextObject = &data->nextContextObject;
768     data->prevContextObject = &contextObjects;
769     contextObjects = data;
770 }
771
772 void QQmlContextData::setIdProperty(int idx, QObject *obj)
773 {
774     idValues[idx] = obj;
775     idValues[idx].context = this;
776 }
777
778 void QQmlContextData::setIdPropertyData(QQmlIntegerCache *data)
779 {
780     Q_ASSERT(!propertyNames);
781     propertyNames = data;
782     propertyNames->addref();
783
784     idValueCount = data->count();
785     idValues = new ContextGuard[idValueCount];
786 }
787
788 QString QQmlContextData::findObjectId(const QObject *obj) const
789 {
790     if (!propertyNames)
791         return QString();
792
793     for (int ii = 0; ii < idValueCount; ii++) {
794         if (idValues[ii] == obj)
795             return propertyNames->findId(ii);
796     }
797
798     if (publicContext) {
799         QQmlContextPrivate *p = QQmlContextPrivate::get(publicContext);
800         for (int ii = 0; ii < p->propertyValues.count(); ++ii)
801             if (p->propertyValues.at(ii) == QVariant::fromValue((QObject *)obj))
802                 return propertyNames->findId(ii);
803     }
804
805     if (linkedContext)
806         return linkedContext->findObjectId(obj);
807     return QString();
808 }
809
810 QQmlContext *QQmlContextData::asQQmlContext()
811 {
812     if (!publicContext)
813         publicContext = new QQmlContext(this);
814     return publicContext;
815 }
816
817 QQmlContextPrivate *QQmlContextData::asQQmlContextPrivate()
818 {
819     return QQmlContextPrivate::get(asQQmlContext());
820 }
821
822 QT_END_NAMESPACE