Use static dispatch tables for QQmlAbstractBinding
[profile/ivi/qtdeclarative.git] / src / qml / qml / qqmlengine.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 "qqmlengine_p.h"
43 #include "qqmlengine.h"
44 #include "qqmlcomponentattached_p.h"
45
46 #include "qqmlcontext_p.h"
47 #include "qqmlcompiler_p.h"
48 #include "qqml.h"
49 #include "qqmlcontext.h"
50 #include "qqmlexpression.h"
51 #include "qqmlcomponent.h"
52 #include "qqmlvme_p.h"
53 #include <private/qqmlenginedebugservice_p.h>
54 #include "qqmlstringconverters_p.h"
55 #include "qqmlxmlhttprequest_p.h"
56 #include "qqmlscriptstring.h"
57 #include "qqmlglobal_p.h"
58 #include "qquicklistmodel_p.h"
59 #include "qquickworkerscript_p.h"
60 #include "qqmlcomponent_p.h"
61 #include "qqmlnetworkaccessmanagerfactory.h"
62 #include "qqmldirparser_p.h"
63 #include "qqmlextensioninterface.h"
64 #include "qqmllist_p.h"
65 #include "qqmltypenamecache_p.h"
66 #include "qqmlnotifier_p.h"
67 #include <private/qqmlprofilerservice_p.h>
68 #include <private/qv8debugservice_p.h>
69 #include <private/qdebugmessageservice_p.h>
70 #include "qqmlincubator.h"
71 #include <private/qv8profilerservice_p.h>
72 #include <private/qqmlboundsignal_p.h>
73
74 #include <QtCore/qstandardpaths.h>
75 #include <QtCore/qsettings.h>
76
77 #include <QtCore/qmetaobject.h>
78 #include <QNetworkAccessManager>
79 #include <QDebug>
80 #include <QtCore/qcoreapplication.h>
81 #include <QtCore/qdir.h>
82 #include <QtCore/qmutex.h>
83 #include <QtCore/qthread.h>
84 #include <private/qthread_p.h>
85 #include <QtNetwork/qnetworkconfigmanager.h>
86
87 #include <private/qobject_p.h>
88 #include <private/qmetaobject_p.h>
89
90 #include <private/qqmllocale_p.h>
91
92 #ifdef Q_OS_WIN // for %APPDATA%
93 #include <qt_windows.h>
94 #include <qlibrary.h>
95 #include <windows.h>
96
97 #define CSIDL_APPDATA           0x001a  // <username>\Application Data
98 #endif
99
100 Q_DECLARE_METATYPE(QQmlProperty)
101
102 QT_BEGIN_NAMESPACE
103
104 void qmlRegisterBaseTypes(const char *uri, int versionMajor, int versionMinor)
105 {
106     QQmlEnginePrivate::registerBaseTypes(uri, versionMajor, versionMinor);
107     QQmlValueTypeFactory::registerBaseTypes(uri, versionMajor, versionMinor);
108 }
109
110 /*!
111   \qmlclass QtObject QObject
112   \inqmlmodule QtQuick 2
113   \ingroup qml-utility-elements
114   \since 4.7
115   \brief A basic QML type
116
117   The QtObject element is a non-visual element which contains only the
118   objectName property.
119
120   It can be useful to create a QtObject if you need an extremely
121   lightweight element to enclose a set of custom properties:
122
123   \snippet doc/snippets/qml/qtobject.qml 0
124
125   It can also be useful for C++ integration, as it is just a plain
126   QObject. See the QObject documentation for further details.
127 */
128 /*!
129   \qmlproperty string QtObject::objectName
130   This property holds the QObject::objectName for this specific object instance.
131
132   This allows a C++ application to locate an item within a QML component
133   using the QObject::findChild() method. For example, the following C++
134   application locates the child \l Rectangle item and dynamically changes its
135   \c color value:
136
137     \qml
138     // MyRect.qml
139
140     import QtQuick 2.0
141
142     Item {
143         width: 200; height: 200
144
145         Rectangle {
146             anchors.fill: parent
147             color: "red"
148             objectName: "myRect"
149         }
150     }
151     \endqml
152
153     \code
154     // main.cpp
155
156     QQuickView view;
157     view.setSource(QUrl::fromLocalFile("MyRect.qml"));
158     view.show();
159
160     QQuickItem *item = view.rootObject()->findChild<QQuickItem*>("myRect");
161     if (item)
162         item->setProperty("color", QColor(Qt::yellow));
163     \endcode
164 */
165
166 bool QQmlEnginePrivate::qml_debugging_enabled = false;
167
168 void QQmlEnginePrivate::registerBaseTypes(const char *uri, int versionMajor, int versionMinor)
169 {
170     qmlRegisterType<QQmlComponent>(uri,versionMajor,versionMinor,"Component");
171     qmlRegisterType<QObject>(uri,versionMajor,versionMinor,"QtObject");
172     qmlRegisterType<QQuickListElement>(uri, versionMajor, versionMinor,"ListElement");
173     qmlRegisterCustomType<QQuickListModel>(uri, versionMajor, versionMinor,"ListModel", new QQuickListModelParser);
174     qmlRegisterType<QQuickWorkerScript>(uri,versionMajor,versionMinor,"WorkerScript");
175 }
176
177 void QQmlEnginePrivate::defineModule()
178 {
179     registerBaseTypes("QtQuick", 2, 0);
180     qmlRegisterUncreatableType<QQmlLocale>("QtQuick",2,0,"Locale",QQmlEngine::tr("Locale cannot be instantiated.  Use Qt.locale()"));
181 }
182
183
184 /*!
185     \class QQmlImageProviderBase
186     \brief The QQmlImageProviderBase class is used to register image providers in the QML engine.
187     \mainclass
188
189     Image providers must be registered with the QML engine.  The only information the QML
190     engine knows about image providers is the type of image data they provide.  To use an
191     image provider to acquire image data, you must cast the QQmlImageProviderBase pointer
192     to a QQuickImageProvider pointer.
193
194     \sa QQuickImageProvider, QQuickTextureFactory
195 */
196
197 /*!
198     \enum QQmlImageProviderBase::ImageType
199
200     Defines the type of image supported by this image provider.
201
202     \value Image The Image Provider provides QImage images.
203         The QQuickImageProvider::requestImage() method will be called for all image requests.
204     \value Pixmap The Image Provider provides QPixmap images.
205         The QQuickImageProvider::requestPixmap() method will be called for all image requests.
206     \value Texture The Image Provider provides QSGTextureProvider based images.
207         The QQuickImageProvider::requestTexture() method will be called for all image requests. \omitvalue
208 */
209
210 /*!
211     \enum QQmlImageProviderBase::Flag
212
213     Defines specific requirements or features of this image provider.
214
215     \value ForceAsynchronousImageLoading Ensures that image requests to the provider are
216         run in a separate thread, which allows the provider to spend as much time as needed
217         on producing the image without blocking the main thread.
218 */
219
220 /*! \internal */
221 QQmlImageProviderBase::QQmlImageProviderBase()
222 {
223 }
224
225 /*! \internal */
226 QQmlImageProviderBase::~QQmlImageProviderBase()
227 {
228 }
229
230
231 /*!
232 \qmlclass Qt QQmlEnginePrivate
233   \ingroup qml-utility-elements
234 \brief The QML global Qt object provides useful enums and functions from Qt.
235
236 \keyword QmlGlobalQtObject
237
238 \brief The \c Qt object provides useful enums and functions from Qt, for use in all QML files.
239
240 The \c Qt object is a global object with utility functions, properties and enums.
241
242 It is not instantiable; to use it, call the members of the global \c Qt object directly.
243 For example:
244
245 \qml
246 import QtQuick 2.0
247
248 Text {
249     color: Qt.rgba(1, 0, 0, 1)
250     text: Qt.md5("hello, world")
251 }
252 \endqml
253
254
255 \section1 Enums
256
257 The Qt object contains the enums available in the \l {Qt Namespace}. For example, you can access
258 the \l Qt::LeftButton and \l Qt::RightButton enum values as \c Qt.LeftButton and \c Qt.RightButton.
259
260
261 \section1 Types
262 The Qt object also contains helper functions for creating objects of specific
263 data types. This is primarily useful when setting the properties of an item
264 when the property has one of the following types:
265
266 \list
267 \li \c color - use \l{Qt::rgba()}{Qt.rgba()}, \l{Qt::hsla()}{Qt.hsla()}, \l{Qt::darker()}{Qt.darker()}, \l{Qt::lighter()}{Qt.lighter()} or \l{Qt::tint()}{Qt.tint()}
268 \li \c rect - use \l{Qt::rect()}{Qt.rect()}
269 \li \c point - use \l{Qt::point()}{Qt.point()}
270 \li \c size - use \l{Qt::size()}{Qt.size()}
271 \li \c vector3d - use \l{Qt::vector3d()}{Qt.vector3d()}
272 \endlist
273
274 There are also string based constructors for these types. See \l{qdeclarativebasictypes.html}{QML Basic Types} for more information.
275
276 \section1 Date/Time Formatters
277
278 The Qt object contains several functions for formatting QDateTime, QDate and QTime values.
279
280 \list
281     \li \l{Qt::formatDateTime}{string Qt.formatDateTime(datetime date, variant format)}
282     \li \l{Qt::formatDate}{string Qt.formatDate(datetime date, variant format)}
283     \li \l{Qt::formatTime}{string Qt.formatTime(datetime date, variant format)}
284 \endlist
285
286 The format specification is described at \l{Qt::formatDateTime}{Qt.formatDateTime}.
287
288
289 \section1 Dynamic Object Creation
290 The following functions on the global object allow you to dynamically create QML
291 items from files or strings. See \l{Dynamic Object Management in QML} for an overview
292 of their use.
293
294 \list
295     \li \l{Qt::createComponent()}{object Qt.createComponent(url)}
296     \li \l{Qt::createQmlObject()}{object Qt.createQmlObject(string qml, object parent, string filepath)}
297 \endlist
298
299
300 \section1 Other Functions
301
302 The following functions are also on the Qt object.
303
304 \list
305     \li \l{Qt::quit()}{Qt.quit()}
306     \li \l{Qt::md5()}{Qt.md5(string)}
307     \li \l{Qt::btoa()}{string Qt.btoa(string)}
308     \li \l{Qt::atob()}{string Qt.atob(string)}
309     \li \l{Qt::binding()}{object Qt.binding(function)}
310     \li \l{Qt::locale()}{object Qt.locale()}
311     \li \l{Qt::resolvedUrl()}{string Qt.resolvedUrl(string)}
312     \li \l{Qt::openUrlExternally()}{Qt.openUrlExternally(string)}
313     \li \l{Qt::fontFamilies()}{list<string> Qt.fontFamilies()}
314 \endlist
315 */
316
317 /*!
318     \qmlproperty object Qt::application
319     \since QtQuick 1.1
320
321     The \c application object provides access to global application state
322     properties shared by many QML components.
323
324     Its properties are:
325
326     \table
327     \row
328     \li \c application.active
329     \li
330     This read-only property indicates whether the application is the top-most and focused
331     application, and the user is able to interact with the application. The property
332     is false when the application is in the background, the device keylock or screen
333     saver is active, the screen backlight is turned off, or the global system dialog
334     is being displayed on top of the application. It can be used for stopping and
335     pausing animations, timers and active processing of data in order to save device
336     battery power and free device memory and processor load when the application is not
337     active.
338
339     \row
340     \li \c application.layoutDirection
341     \li
342     This read-only property can be used to query the default layout direction of the
343     application. On system start-up, the default layout direction depends on the
344     application's language. The property has a value of \c Qt.RightToLeft in locales
345     where text and graphic elements are read from right to left, and \c Qt.LeftToRight
346     where the reading direction flows from left to right. You can bind to this
347     property to customize your application layouts to support both layout directions.
348
349     Possible values are:
350
351     \list
352     \li Qt.LeftToRight - Text and graphics elements should be positioned
353                         from left to right.
354     \li Qt.RightToLeft - Text and graphics elements should be positioned
355                         from right to left.
356     \endlist
357
358     \endtable
359
360     The following example uses the \c application object to indicate
361     whether the application is currently active:
362
363     \snippet doc/snippets/qml/application.qml document
364 */
365
366 /*!
367     \qmlproperty object Qt::inputMethod
368     \since QtQuick 2.0
369
370     The \c inputMethod object allows access to application's QInputMethod object
371     and all its properties and slots. See the QInputMethod documentation for
372     further details.
373 */
374
375
376 /*!
377 \qmlmethod object Qt::include(string url, jsobject callback)
378
379 Includes another JavaScript file. This method can only be used from within JavaScript files,
380 and not regular QML files.
381
382 This imports all functions from \a url into the current script's namespace.
383
384 Qt.include() returns an object that describes the status of the operation.  The object has
385 a single property, \c {status}, that is set to one of the following values:
386
387 \table
388 \header \li Symbol \li Value \li Description
389 \row \li result.OK \li 0 \li The include completed successfully.
390 \row \li result.LOADING \li 1 \li Data is being loaded from the network.
391 \row \li result.NETWORK_ERROR \li 2 \li A network error occurred while fetching the url.
392 \row \li result.EXCEPTION \li 3 \li A JavaScript exception occurred while executing the included code.
393 An additional \c exception property will be set in this case.
394 \endtable
395
396 The \c status property will be updated as the operation progresses.
397
398 If provided, \a callback is invoked when the operation completes.  The callback is passed
399 the same object as is returned from the Qt.include() call.
400 */
401 // Qt.include() is implemented in qv8include.cpp
402
403
404 QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e)
405 : propertyCapture(0), rootContext(0), isDebugging(false),
406   outputWarningsToStdErr(true), sharedContext(0), sharedScope(0),
407   cleanup(0), erroredBindings(0), inProgressCreations(0),
408   workerScriptEngine(0), activeVME(0),
409   networkAccessManager(0), networkAccessManagerFactory(0),
410   scarceResourcesRefCount(0), typeLoader(e), importDatabase(e), uniqueId(1),
411   incubatorCount(0), incubationController(0), mutex(QMutex::Recursive)
412 {
413 }
414
415 QQmlEnginePrivate::~QQmlEnginePrivate()
416 {
417     if (inProgressCreations)
418         qWarning() << QQmlEngine::tr("There are still \"%1\" items in the process of being created at engine destruction.").arg(inProgressCreations);
419
420     while (cleanup) {
421         QQmlCleanup *c = cleanup;
422         cleanup = c->next;
423         if (cleanup) cleanup->prev = &cleanup;
424         c->next = 0;
425         c->prev = 0;
426         c->clear();
427     }
428
429     doDeleteInEngineThread();
430
431     if (incubationController) incubationController->d = 0;
432     incubationController = 0;
433
434     delete rootContext;
435     rootContext = 0;
436
437     for(QHash<const QMetaObject *, QQmlPropertyCache *>::Iterator iter = propertyCache.begin(); iter != propertyCache.end(); ++iter)
438         (*iter)->release();
439     for(QHash<QPair<QQmlType *, int>, QQmlPropertyCache *>::Iterator iter = typePropertyCache.begin(); iter != typePropertyCache.end(); ++iter)
440         (*iter)->release();
441     for(QHash<QQmlMetaType::ModuleApi, QQmlMetaType::ModuleApiInstance *>::Iterator iter = moduleApiInstances.begin(); iter != moduleApiInstances.end(); ++iter) {
442         delete (*iter)->qobjectApi;
443         delete *iter;
444     }
445     for (QHash<int, QQmlCompiledData *>::Iterator iter = m_compositeTypes.begin(); iter != m_compositeTypes.end(); ++iter)
446         iter.value()->isRegisteredWithEngine = false;
447 }
448
449 void QQmlPrivate::qdeclarativeelement_destructor(QObject *o)
450 {
451     QObjectPrivate *p = QObjectPrivate::get(o);
452     if (p->declarativeData) {
453         QQmlData *d = static_cast<QQmlData*>(p->declarativeData);
454         if (d->ownContext && d->context) {
455             d->context->destroy();
456             d->context = 0;
457         }
458
459         // Mark this object as in the process of deletion to
460         // prevent it resolving in bindings
461         QQmlData::markAsDeleted(o);
462     }
463 }
464
465 void QQmlData::destroyed(QAbstractDeclarativeData *d, QObject *o)
466 {
467     static_cast<QQmlData *>(d)->destroyed(o);
468 }
469
470 void QQmlData::parentChanged(QAbstractDeclarativeData *d, QObject *o, QObject *p)
471 {
472     static_cast<QQmlData *>(d)->parentChanged(o, p);
473 }
474
475 void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int index, void **a)
476 {
477     QQmlData *ddata = QQmlData::get(object, false);
478     if (!ddata) return; // Probably being deleted
479
480     // In general, QML only supports QObject's that live on the same thread as the QQmlEngine
481     // that they're exposed to.  However, to make writing "worker objects" that calculate data
482     // in a separate thread easier, QML allows a QObject that lives in the same thread as the
483     // QQmlEngine to emit signals from a different thread.  These signals are then automatically
484     // marshalled back onto the QObject's thread and handled by QML from there.  This is tested
485     // by the qqmlecmascript::threadSignal() autotest.
486     if (ddata->notifyList &&
487         QThread::currentThreadId() != QObjectPrivate::get(object)->threadData->threadId) {
488
489         QMetaMethod m = object->metaObject()->method(index);
490         QList<QByteArray> parameterTypes = m.parameterTypes();
491
492         int *types = (int *)malloc((parameterTypes.count() + 1) * sizeof(int));
493         void **args = (void **) malloc((parameterTypes.count() + 1) *sizeof(void *));
494
495         types[0] = 0; // return type
496         args[0] = 0; // return value
497
498         for (int ii = 0; ii < parameterTypes.count(); ++ii) {
499             const QByteArray &typeName = parameterTypes.at(ii);
500             if (typeName.endsWith('*'))
501                 types[ii + 1] = QMetaType::VoidStar;
502             else
503                 types[ii + 1] = QMetaType::type(typeName);
504
505             if (!types[ii + 1]) {
506                 qWarning("QObject::connect: Cannot queue arguments of type '%s'\n"
507                          "(Make sure '%s' is registered using qRegisterMetaType().)",
508                          typeName.constData(), typeName.constData());
509                 free(types);
510                 free(args);
511                 return;
512             }
513
514             args[ii + 1] = QMetaType::create(types[ii + 1], a[ii + 1]);
515         }
516
517         QMetaCallEvent *ev = new QMetaCallEvent(index, 0, 0, object, index,
518                                                 parameterTypes.count() + 1, types, args);
519         QCoreApplication::postEvent(object, ev);
520
521     } else {
522         QQmlNotifierEndpoint *ep = ddata->notify(index);
523         if (ep) QQmlNotifier::emitNotify(ep, a);
524     }
525 }
526
527 int QQmlData::receivers(QAbstractDeclarativeData *d, const QObject *, int index)
528 {
529     return static_cast<QQmlData *>(d)->endpointCount(index);
530 }
531
532 int QQmlData::endpointCount(int index)
533 {
534     int count = 0;
535     QQmlNotifierEndpoint *ep = notify(index);
536     if (!ep)
537         return count;
538     ++count;
539     while (ep->next) {
540         ++count;
541         ep = ep->next;
542     }
543     return count;
544 }
545
546 void QQmlData::markAsDeleted(QObject *o)
547 {
548     QQmlData::setQueuedForDeletion(o);
549
550     QObjectPrivate *p = QObjectPrivate::get(o);
551     for (QList<QObject *>::iterator it = p->children.begin(), end = p->children.end(); it != end; ++it) {
552         QQmlData::markAsDeleted(*it);
553     }
554 }
555
556 void QQmlData::setQueuedForDeletion(QObject *object)
557 {
558     if (object) {
559         if (QObjectPrivate *priv = QObjectPrivate::get(object)) {
560             if (!priv->wasDeleted && priv->declarativeData) {
561                 QQmlData *ddata = QQmlData::get(object, false);
562                 if (ddata->ownContext && ddata->context)
563                     ddata->context->emitDestruction();
564                 ddata->isQueuedForDeletion = true;
565             }
566         }
567     }
568 }
569
570 void QQmlEnginePrivate::init()
571 {
572     Q_Q(QQmlEngine);
573
574     static bool firstTime = true;
575     if (firstTime) {
576         qmlRegisterType<QQmlComponent>("QML", 1, 0, "Component");
577
578         QQmlData::init();
579         firstTime = false;
580     }
581
582     qRegisterMetaType<QVariant>("QVariant");
583     qRegisterMetaType<QQmlScriptString>("QQmlScriptString");
584     qRegisterMetaType<QJSValue>("QJSValue");
585     qRegisterMetaType<QQmlComponent::Status>("QQmlComponent::Status");
586     qRegisterMetaType<QList<QObject*> >("QList<QObject*>");
587     qRegisterMetaType<QList<int> >("QList<int>");
588     qRegisterMetaType<QQmlV8Handle>("QQmlV8Handle");
589
590     v8engine()->setEngine(q);
591
592     rootContext = new QQmlContext(q,true);
593
594     if (QCoreApplication::instance()->thread() == q->thread() &&
595         QQmlEngineDebugService::isDebuggingEnabled()) {
596         isDebugging = true;
597         QQmlEngineDebugService::instance()->addEngine(q);
598         QV8DebugService::initialize(v8engine());
599         QV8ProfilerService::initialize();
600         QQmlProfilerService::initialize();
601         QDebugMessageService::instance();
602     }
603
604     QString dataLocation = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
605     if (!dataLocation.isEmpty())
606         offlineStoragePath = dataLocation.replace(QLatin1Char('/'), QDir::separator())
607                            + QDir::separator() + QLatin1String("QML")
608                            + QDir::separator() + QLatin1String("OfflineStorage");
609 }
610
611 QQuickWorkerScriptEngine *QQmlEnginePrivate::getWorkerScriptEngine()
612 {
613     Q_Q(QQmlEngine);
614     if (!workerScriptEngine)
615         workerScriptEngine = new QQuickWorkerScriptEngine(q);
616     return workerScriptEngine;
617 }
618
619 /*!
620   \class QQmlEngine
621   \since 5.0
622   \inmodule QtQml
623   \brief The QQmlEngine class provides an environment for instantiating QML components.
624   \mainclass
625
626   Each QML component is instantiated in a QQmlContext.
627   QQmlContext's are essential for passing data to QML
628   components.  In QML, contexts are arranged hierarchically and this
629   hierarchy is managed by the QQmlEngine.
630
631   Prior to creating any QML components, an application must have
632   created a QQmlEngine to gain access to a QML context.  The
633   following example shows how to create a simple Text item.
634
635   \code
636   QQmlEngine engine;
637   QQmlComponent component(&engine);
638   component.setData("import QtQuick 2.0\nText { text: \"Hello world!\" }", QUrl());
639   QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
640
641   //add item to view, etc
642   ...
643   \endcode
644
645   In this case, the Text item will be created in the engine's
646   \l {QQmlEngine::rootContext()}{root context}.
647
648   Note that the QtQuick 1 version is called QDeclarativeEngine.
649
650   \sa QQmlComponent, QQmlContext
651 */
652
653 /*!
654   Create a new QQmlEngine with the given \a parent.
655 */
656 QQmlEngine::QQmlEngine(QObject *parent)
657 : QJSEngine(*new QQmlEnginePrivate(this), parent)
658 {
659     Q_D(QQmlEngine);
660     d->init();
661 }
662
663 /*!
664   Destroys the QQmlEngine.
665
666   Any QQmlContext's created on this engine will be
667   invalidated, but not destroyed (unless they are parented to the
668   QQmlEngine object).
669 */
670 QQmlEngine::~QQmlEngine()
671 {
672     Q_D(QQmlEngine);
673     if (d->isDebugging) {
674         QQmlEngineDebugService::instance()->remEngine(this);
675     }
676
677     // Emit onDestruction signals for the root context before
678     // we destroy the contexts, engine, Module APIs etc. that
679     // may be required to handle the destruction signal.
680     QQmlContextData::get(rootContext())->emitDestruction();
681
682     // if we are the parent of any of the qobject module api instances,
683     // we need to remove them from our internal list, in order to prevent
684     // a segfault in engine private dtor.
685     QList<QQmlMetaType::ModuleApi> keys = d->moduleApiInstances.keys();
686     QObject *currQObjectApi = 0;
687     QQmlMetaType::ModuleApiInstance *currInstance = 0;
688     foreach (const QQmlMetaType::ModuleApi &key, keys) {
689         currInstance = d->moduleApiInstances.value(key);
690         currQObjectApi = currInstance->qobjectApi;
691         if (this->children().contains(currQObjectApi)) {
692             delete currQObjectApi;
693             delete currInstance;
694             d->moduleApiInstances.remove(key);
695         }
696     }
697
698     if (d->incubationController)
699         d->incubationController->d = 0;
700 }
701
702 /*! \fn void QQmlEngine::quit()
703     This signal is emitted when the QML loaded by the engine would like to quit.
704  */
705
706 /*! \fn void QQmlEngine::warnings(const QList<QQmlError> &warnings)
707     This signal is emitted when \a warnings messages are generated by QML.
708  */
709
710 /*!
711   Clears the engine's internal component cache.
712
713   This function causes the property metadata of all components previously
714   loaded by the engine to be destroyed.  All previously loaded components and
715   the property bindings for all extant objects created from those components will
716   cease to function.
717
718   This function returns the engine to a state where it does not contain any loaded
719   component data.  This may be useful in order to reload a smaller subset of the
720   previous component set, or to load a new version of a previously loaded component.
721
722   Once the component cache has been cleared, components must be loaded before
723   any new objects can be created.
724
725   \sa trimComponentCache()
726  */
727 void QQmlEngine::clearComponentCache()
728 {
729     Q_D(QQmlEngine);
730     d->typeLoader.clearCache();
731 }
732
733 /*!
734   Trims the engine's internal component cache.
735
736   This function causes the property metadata of any loaded components which are
737   not currently in use to be destroyed.
738
739   A component is considered to be in use if there are any extant instances of
740   the component itself, any instances of other components that use the component,
741   or any objects instantiated by any of those components.
742
743   \sa clearComponentCache()
744  */
745 void QQmlEngine::trimComponentCache()
746 {
747     Q_D(QQmlEngine);
748     d->typeLoader.trimCache();
749 }
750
751 /*!
752   Returns the engine's root context.
753
754   The root context is automatically created by the QQmlEngine.
755   Data that should be available to all QML component instances
756   instantiated by the engine should be put in the root context.
757
758   Additional data that should only be available to a subset of
759   component instances should be added to sub-contexts parented to the
760   root context.
761 */
762 QQmlContext *QQmlEngine::rootContext() const
763 {
764     Q_D(const QQmlEngine);
765     return d->rootContext;
766 }
767
768 /*!
769   Sets the \a factory to use for creating QNetworkAccessManager(s).
770
771   QNetworkAccessManager is used for all network access by QML.  By
772   implementing a factory it is possible to create custom
773   QNetworkAccessManager with specialized caching, proxy and cookie
774   support.
775
776   The factory must be set before executing the engine.
777 */
778 void QQmlEngine::setNetworkAccessManagerFactory(QQmlNetworkAccessManagerFactory *factory)
779 {
780     Q_D(QQmlEngine);
781     QMutexLocker locker(&d->mutex);
782     d->networkAccessManagerFactory = factory;
783 }
784
785 /*!
786   Returns the current QQmlNetworkAccessManagerFactory.
787
788   \sa setNetworkAccessManagerFactory()
789 */
790 QQmlNetworkAccessManagerFactory *QQmlEngine::networkAccessManagerFactory() const
791 {
792     Q_D(const QQmlEngine);
793     return d->networkAccessManagerFactory;
794 }
795
796 void QQmlEnginePrivate::registerFinalizeCallback(QObject *obj, int index)
797 {
798     if (activeVME) {
799         activeVME->finalizeCallbacks.append(qMakePair(QQmlGuard<QObject>(obj), index));
800     } else {
801         void *args[] = { 0 };
802         QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, index, args);
803     }
804 }
805
806 QNetworkAccessManager *QQmlEnginePrivate::createNetworkAccessManager(QObject *parent) const
807 {
808     QMutexLocker locker(&mutex);
809     QNetworkAccessManager *nam;
810     if (networkAccessManagerFactory) {
811         nam = networkAccessManagerFactory->create(parent);
812     } else {
813         nam = new QNetworkAccessManager(parent);
814     }
815
816     return nam;
817 }
818
819 QNetworkAccessManager *QQmlEnginePrivate::getNetworkAccessManager() const
820 {
821     Q_Q(const QQmlEngine);
822     if (!networkAccessManager)
823         networkAccessManager = createNetworkAccessManager(const_cast<QQmlEngine*>(q));
824     return networkAccessManager;
825 }
826
827 /*!
828   Returns a common QNetworkAccessManager which can be used by any QML
829   element instantiated by this engine.
830
831   If a QQmlNetworkAccessManagerFactory has been set and a
832   QNetworkAccessManager has not yet been created, the
833   QQmlNetworkAccessManagerFactory will be used to create the
834   QNetworkAccessManager; otherwise the returned QNetworkAccessManager
835   will have no proxy or cache set.
836
837   \sa setNetworkAccessManagerFactory()
838 */
839 QNetworkAccessManager *QQmlEngine::networkAccessManager() const
840 {
841     Q_D(const QQmlEngine);
842     return d->getNetworkAccessManager();
843 }
844
845 /*!
846
847   Sets the \a provider to use for images requested via the \e
848   image: url scheme, with host \a providerId. The QQmlEngine
849   takes ownership of \a provider.
850
851   Image providers enable support for pixmap and threaded image
852   requests. See the QQuickImageProvider documentation for details on
853   implementing and using image providers.
854
855   All required image providers should be added to the engine before any
856   QML sources files are loaded.
857
858   \sa removeImageProvider(), QQuickImageProvider, QQmlImageProviderBase
859 */
860 void QQmlEngine::addImageProvider(const QString &providerId, QQmlImageProviderBase *provider)
861 {
862     Q_D(QQmlEngine);
863     QMutexLocker locker(&d->mutex);
864     d->imageProviders.insert(providerId.toLower(), QSharedPointer<QQmlImageProviderBase>(provider));
865 }
866
867 /*!
868   Returns the image provider set for \a providerId.
869
870   Returns the provider if it was found; otherwise returns 0.
871
872   \sa QQuickImageProvider
873 */
874 QQmlImageProviderBase *QQmlEngine::imageProvider(const QString &providerId) const
875 {
876     Q_D(const QQmlEngine);
877     QMutexLocker locker(&d->mutex);
878     return d->imageProviders.value(providerId).data();
879 }
880
881 /*!
882   Removes the image provider for \a providerId.
883
884   \sa addImageProvider(), QQuickImageProvider
885 */
886 void QQmlEngine::removeImageProvider(const QString &providerId)
887 {
888     Q_D(QQmlEngine);
889     QMutexLocker locker(&d->mutex);
890     d->imageProviders.take(providerId);
891 }
892
893 /*!
894   Return the base URL for this engine.  The base URL is only used to
895   resolve components when a relative URL is passed to the
896   QQmlComponent constructor.
897
898   If a base URL has not been explicitly set, this method returns the
899   application's current working directory.
900
901   \sa setBaseUrl()
902 */
903 QUrl QQmlEngine::baseUrl() const
904 {
905     Q_D(const QQmlEngine);
906     if (d->baseUrl.isEmpty()) {
907         return QUrl::fromLocalFile(QDir::currentPath() + QDir::separator());
908     } else {
909         return d->baseUrl;
910     }
911 }
912
913 /*!
914   Set the  base URL for this engine to \a url.
915
916   \sa baseUrl()
917 */
918 void QQmlEngine::setBaseUrl(const QUrl &url)
919 {
920     Q_D(QQmlEngine);
921     d->baseUrl = url;
922 }
923
924 /*!
925   Returns true if warning messages will be output to stderr in addition
926   to being emitted by the warnings() signal, otherwise false.
927
928   The default value is true.
929 */
930 bool QQmlEngine::outputWarningsToStandardError() const
931 {
932     Q_D(const QQmlEngine);
933     return d->outputWarningsToStdErr;
934 }
935
936 /*!
937   Set whether warning messages will be output to stderr to \a enabled.
938
939   If \a enabled is true, any warning messages generated by QML will be
940   output to stderr and emitted by the warnings() signal.  If \a enabled
941   is false, on the warnings() signal will be emitted.  This allows
942   applications to handle warning output themselves.
943
944   The default value is true.
945 */
946 void QQmlEngine::setOutputWarningsToStandardError(bool enabled)
947 {
948     Q_D(QQmlEngine);
949     d->outputWarningsToStdErr = enabled;
950 }
951
952 /*!
953   Returns the QQmlContext for the \a object, or 0 if no
954   context has been set.
955
956   When the QQmlEngine instantiates a QObject, the context is
957   set automatically.
958   */
959 QQmlContext *QQmlEngine::contextForObject(const QObject *object)
960 {
961     if(!object)
962         return 0;
963
964     QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object));
965
966     QQmlData *data =
967         static_cast<QQmlData *>(priv->declarativeData);
968
969     if (!data)
970         return 0;
971     else if (data->outerContext)
972         return data->outerContext->asQQmlContext();
973     else
974         return 0;
975 }
976
977 /*!
978   Sets the QQmlContext for the \a object to \a context.
979   If the \a object already has a context, a warning is
980   output, but the context is not changed.
981
982   When the QQmlEngine instantiates a QObject, the context is
983   set automatically.
984  */
985 void QQmlEngine::setContextForObject(QObject *object, QQmlContext *context)
986 {
987     if (!object || !context)
988         return;
989
990     QQmlData *data = QQmlData::get(object, true);
991     if (data->context) {
992         qWarning("QQmlEngine::setContextForObject(): Object already has a QQmlContext");
993         return;
994     }
995
996     QQmlContextData *contextData = QQmlContextData::get(context);
997     contextData->addObject(object);
998 }
999
1000 /*!
1001   \enum QQmlEngine::ObjectOwnership
1002
1003   Ownership controls whether or not QML automatically destroys the
1004   QObject when the object is garbage collected by the JavaScript
1005   engine.  The two ownership options are:
1006
1007   \value CppOwnership The object is owned by C++ code, and will
1008   never be deleted by QML.  The JavaScript destroy() method cannot be
1009   used on objects with CppOwnership.  This option is similar to
1010   QScriptEngine::QtOwnership.
1011
1012   \value JavaScriptOwnership The object is owned by JavaScript.
1013   When the object is returned to QML as the return value of a method
1014   call or property access, QML will track it, and delete the object
1015   if there are no remaining JavaScript references to it and it has no
1016   QObject::parent().  An object tracked by one QQmlEngine
1017   will be deleted during that QQmlEngine's destructor, and thus
1018   JavaScript references between objects with JavaScriptOwnership from
1019   two different engines will not be valid after the deletion of one of
1020   those engines.  This option is similar to QScriptEngine::ScriptOwnership.
1021
1022   Generally an application doesn't need to set an object's ownership
1023   explicitly.  QML uses a heuristic to set the default object
1024   ownership.  By default, an object that is created by QML has
1025   JavaScriptOwnership.  The exception to this are the root objects
1026   created by calling QQmlComponent::create() or
1027   QQmlComponent::beginCreate() which have CppOwnership by
1028   default.  The ownership of these root-level objects is considered to
1029   have been transferred to the C++ caller.
1030
1031   Objects not-created by QML have CppOwnership by default.  The
1032   exception to this is objects returned from a C++ method call.  The
1033   ownership of these objects is passed to JavaScript.
1034
1035   Calling setObjectOwnership() overrides the default ownership
1036   heuristic used by QML.
1037 */
1038
1039 /*!
1040   Sets the \a ownership of \a object.
1041 */
1042 void QQmlEngine::setObjectOwnership(QObject *object, ObjectOwnership ownership)
1043 {
1044     if (!object)
1045         return;
1046
1047     QQmlData *ddata = QQmlData::get(object, true);
1048     if (!ddata)
1049         return;
1050
1051     ddata->indestructible = (ownership == CppOwnership)?true:false;
1052     ddata->explicitIndestructibleSet = true;
1053 }
1054
1055 /*!
1056   Returns the ownership of \a object.
1057 */
1058 QQmlEngine::ObjectOwnership QQmlEngine::objectOwnership(QObject *object)
1059 {
1060     if (!object)
1061         return CppOwnership;
1062
1063     QQmlData *ddata = QQmlData::get(object, false);
1064     if (!ddata)
1065         return CppOwnership;
1066     else
1067         return ddata->indestructible?CppOwnership:JavaScriptOwnership;
1068 }
1069
1070 bool QQmlEngine::event(QEvent *e)
1071 {
1072     Q_D(QQmlEngine);
1073     if (e->type() == QEvent::User)
1074         d->doDeleteInEngineThread();
1075
1076     return QJSEngine::event(e);
1077 }
1078
1079 void QQmlEnginePrivate::doDeleteInEngineThread()
1080 {
1081     QFieldList<Deletable, &Deletable::next> list;
1082     mutex.lock();
1083     list.copyAndClear(toDeleteInEngineThread);
1084     mutex.unlock();
1085
1086     while (Deletable *d = list.takeFirst())
1087         delete d;
1088 }
1089
1090 Q_AUTOTEST_EXPORT void qmlExecuteDeferred(QObject *object)
1091 {
1092     QQmlData *data = QQmlData::get(object);
1093
1094     if (data && data->compiledData && data->deferredIdx) {
1095         QQmlObjectCreatingProfiler prof;
1096         if (prof.enabled) {
1097             QQmlType *type = QQmlMetaType::qmlType(object->metaObject());
1098             prof.setTypeName(type ? type->qmlTypeName()
1099                                   : QString::fromUtf8(object->metaObject()->className()));
1100             if (data->outerContext)
1101                 prof.setLocation(data->outerContext->url, data->lineNumber, data->columnNumber);
1102         }
1103         QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine);
1104
1105         QQmlComponentPrivate::ConstructionState state;
1106         QQmlComponentPrivate::beginDeferred(ep, object, &state);
1107
1108         // Release the reference for the deferral action (we still have one from construction)
1109         data->compiledData->release();
1110         data->compiledData = 0;
1111
1112         QQmlComponentPrivate::complete(ep, &state);
1113     }
1114 }
1115
1116 QQmlContext *qmlContext(const QObject *obj)
1117 {
1118     return QQmlEngine::contextForObject(obj);
1119 }
1120
1121 QQmlEngine *qmlEngine(const QObject *obj)
1122 {
1123     QQmlData *data = QQmlData::get(obj, false);
1124     if (!data || !data->context)
1125         return 0;
1126     return data->context->engine;
1127 }
1128
1129 QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create)
1130 {
1131     QQmlData *data = QQmlData::get(object);
1132     if (!data)
1133         return 0; // Attached properties are only on objects created by QML
1134
1135     QObject *rv = data->hasExtendedData()?data->attachedProperties()->value(id):0;
1136     if (rv || !create)
1137         return rv;
1138
1139     QQmlAttachedPropertiesFunc pf = QQmlMetaType::attachedPropertiesFuncById(id);
1140     if (!pf)
1141         return 0;
1142
1143     rv = pf(const_cast<QObject *>(object));
1144
1145     if (rv)
1146         data->attachedProperties()->insert(id, rv);
1147
1148     return rv;
1149 }
1150
1151 QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *object,
1152                                      const QMetaObject *attachedMetaObject, bool create)
1153 {
1154     if (*idCache == -1)
1155         *idCache = QQmlMetaType::attachedPropertiesFuncId(attachedMetaObject);
1156
1157     if (*idCache == -1 || !object)
1158         return 0;
1159
1160     return qmlAttachedPropertiesObjectById(*idCache, object, create);
1161 }
1162
1163 QQmlDebuggingEnabler::QQmlDebuggingEnabler(bool printWarning)
1164 {
1165 #ifndef QQML_NO_DEBUG_PROTOCOL
1166     if (!QQmlEnginePrivate::qml_debugging_enabled
1167             && printWarning) {
1168         qDebug("QML debugging is enabled. Only use this in a safe environment.");
1169     }
1170     QQmlEnginePrivate::qml_debugging_enabled = true;
1171 #endif
1172 }
1173
1174
1175 class QQmlDataExtended {
1176 public:
1177     QQmlDataExtended();
1178     ~QQmlDataExtended();
1179
1180     QHash<int, QObject *> attachedProperties;
1181 };
1182
1183 QQmlDataExtended::QQmlDataExtended()
1184 {
1185 }
1186
1187 QQmlDataExtended::~QQmlDataExtended()
1188 {
1189 }
1190
1191 void QQmlData::NotifyList::layout(QQmlNotifierEndpoint *endpoint)
1192 {
1193     if (endpoint->next)
1194         layout(endpoint->next);
1195
1196     int index = endpoint->sourceSignal;
1197     index = qMin(index, 0xFFFF - 1);
1198
1199     endpoint->next = notifies[index];
1200     if (endpoint->next) endpoint->next->prev = &endpoint->next;
1201     endpoint->prev = &notifies[index];
1202     notifies[index] = endpoint;
1203 }
1204
1205 void QQmlData::NotifyList::layout()
1206 {
1207     Q_ASSERT(maximumTodoIndex >= notifiesSize);
1208
1209     if (todo) {
1210         QQmlNotifierEndpoint **old = notifies;
1211         const int reallocSize = (maximumTodoIndex + 1) * sizeof(QQmlNotifierEndpoint*);
1212         notifies = (QQmlNotifierEndpoint**)realloc(notifies, reallocSize);
1213         const int memsetSize = (maximumTodoIndex - notifiesSize + 1) *
1214                                sizeof(QQmlNotifierEndpoint*);
1215         memset(notifies + notifiesSize, 0, memsetSize);
1216
1217         if (notifies != old) {
1218             for (int ii = 0; ii < notifiesSize; ++ii)
1219                 if (notifies[ii])
1220                     notifies[ii]->prev = &notifies[ii];
1221         }
1222
1223         notifiesSize = maximumTodoIndex + 1;
1224
1225         layout(todo);
1226     }
1227
1228     maximumTodoIndex = 0;
1229     todo = 0;
1230 }
1231
1232 void QQmlData::addNotify(int index, QQmlNotifierEndpoint *endpoint)
1233 {
1234     if (!notifyList) {
1235         notifyList = (NotifyList *)malloc(sizeof(NotifyList));
1236         notifyList->connectionMask = 0;
1237         notifyList->maximumTodoIndex = 0;
1238         notifyList->notifiesSize = 0;
1239         notifyList->todo = 0;
1240         notifyList->notifies = 0;
1241     }
1242
1243     Q_ASSERT(!endpoint->isConnected());
1244
1245     index = qMin(index, 0xFFFF - 1);
1246     notifyList->connectionMask |= (1ULL << quint64(index % 64));
1247
1248     if (index < notifyList->notifiesSize) {
1249
1250         endpoint->next = notifyList->notifies[index];
1251         if (endpoint->next) endpoint->next->prev = &endpoint->next;
1252         endpoint->prev = &notifyList->notifies[index];
1253         notifyList->notifies[index] = endpoint;
1254
1255     } else {
1256         notifyList->maximumTodoIndex = qMax(int(notifyList->maximumTodoIndex), index);
1257
1258         endpoint->next = notifyList->todo;
1259         if (endpoint->next) endpoint->next->prev = &endpoint->next;
1260         endpoint->prev = &notifyList->todo;
1261         notifyList->todo = endpoint;
1262     }
1263 }
1264
1265 bool QQml_isSignalConnected(QObject *obj, int signal_index, int index)
1266 {
1267     QQmlData *data = QQmlData::get(obj);
1268     return QObjectPrivate::get(obj)->isSignalConnected(signal_index) || (data && data->signalHasEndpoint(index));
1269 }
1270
1271 /*
1272     index MUST be the index returned by QMetaMethod::index()
1273     This is different than the index returned by QObjectPrivate::signalIndex()
1274 */
1275 bool QQmlData::signalHasEndpoint(int index)
1276 {
1277     return notifyList && (notifyList->connectionMask & (1ULL << quint64(index % 64)));
1278 }
1279
1280 QHash<int, QObject *> *QQmlData::attachedProperties() const
1281 {
1282     if (!extendedData) extendedData = new QQmlDataExtended;
1283     return &extendedData->attachedProperties;
1284 }
1285
1286 void QQmlData::destroyed(QObject *object)
1287 {
1288     if (nextContextObject)
1289         nextContextObject->prevContextObject = prevContextObject;
1290     if (prevContextObject)
1291         *prevContextObject = nextContextObject;
1292
1293     QQmlAbstractBinding *binding = bindings;
1294     while (binding) {
1295         QQmlAbstractBinding *next = binding->nextBinding();
1296         binding->setAddedToObject(false);
1297         binding->setNextBinding(0);
1298         binding->destroy();
1299         binding = next;
1300     }
1301
1302     if (compiledData) {
1303         compiledData->release();
1304         compiledData = 0;
1305     }
1306
1307     QQmlAbstractBoundSignal *signalHandler = signalHandlers;
1308     while (signalHandler) {
1309         if (signalHandler->isEvaluating()) {
1310             // The object is being deleted during signal handler evaluation.
1311             // This will cause a crash due to invalid memory access when the
1312             // evaluation has completed.
1313             // Abort with a friendly message instead.
1314             QString locationString;
1315             QQmlBoundSignalExpression *expr = signalHandler->expression();
1316             if (expr) {
1317                 QString fileName = expr->sourceFile();
1318                 if (fileName.isEmpty())
1319                     fileName = QStringLiteral("<Unknown File>");
1320                 locationString.append(fileName);
1321                 locationString.append(QString::fromLatin1(":%0: ").arg(expr->lineNumber()));
1322                 QString source = expr->expression();
1323                 if (source.size() > 100) {
1324                     source.truncate(96);
1325                     source.append(QStringLiteral(" ..."));
1326                 }
1327                 locationString.append(source);
1328             } else {
1329                 locationString = QStringLiteral("<Unknown Location>");
1330             }
1331             qFatal("Object %p destroyed while one of its QML signal handlers is in progress.\n"
1332                    "Most likely the object was deleted synchronously (use QObject::deleteLater() "
1333                    "instead), or the application is running a nested event loop.\n"
1334                    "This behavior is NOT supported!\n"
1335                    "%s", object, qPrintable(locationString));
1336         }
1337
1338         QQmlAbstractBoundSignal *next = signalHandler->m_nextSignal;
1339         signalHandler->m_prevSignal = 0;
1340         signalHandler->m_nextSignal = 0;
1341         delete signalHandler;
1342         signalHandler = next;
1343     }
1344
1345     if (bindingBits)
1346         free(bindingBits);
1347
1348     if (propertyCache)
1349         propertyCache->release();
1350
1351     if (ownContext && context)
1352         context->destroy();
1353
1354     while (guards) {
1355         QQmlGuard<QObject> *guard = static_cast<QQmlGuard<QObject> *>(guards);
1356         *guard = (QObject *)0;
1357         guard->objectDestroyed(object);
1358     }
1359
1360     if (notifyList) {
1361         while (notifyList->todo)
1362             notifyList->todo->disconnect();
1363         for (int ii = 0; ii < notifyList->notifiesSize; ++ii) {
1364             while (QQmlNotifierEndpoint *ep = notifyList->notifies[ii])
1365                 ep->disconnect();
1366         }
1367         free(notifyList->notifies);
1368         free(notifyList);
1369         notifyList = 0;
1370     }
1371
1372     if (extendedData)
1373         delete extendedData;
1374
1375     // Dispose the handle.
1376     // We don't simply clear it (and wait for next gc cycle to dispose
1377     // via the weak qobject reference callback) as this affects the
1378     // outcomes of v8's gc statistical analysis heuristics, which can
1379     // cause unnecessary growth of the old pointer space js heap area.
1380     qPersistentDispose(v8object);
1381
1382     if (ownMemory)
1383         delete this;
1384 }
1385
1386 void QQmlData::parentChanged(QObject *object, QObject *parent)
1387 {
1388     Q_UNUSED(object);
1389     Q_UNUSED(parent);
1390 }
1391
1392 bool QQmlData::hasBindingBit(int bit) const
1393 {
1394     if (bindingBitsSize > bit)
1395         return bindingBits[bit / 32] & (1 << (bit % 32));
1396     else
1397         return false;
1398 }
1399
1400 void QQmlData::clearBindingBit(int bit)
1401 {
1402     if (bindingBitsSize > bit)
1403         bindingBits[bit / 32] &= ~(1 << (bit % 32));
1404 }
1405
1406 void QQmlData::setBindingBit(QObject *obj, int bit)
1407 {
1408     if (bindingBitsSize <= bit) {
1409         int props = QQmlMetaObject(obj).propertyCount();
1410         Q_ASSERT(bit < props);
1411
1412         int arraySize = (props + 31) / 32;
1413         int oldArraySize = bindingBitsSize / 32;
1414
1415         bindingBits = (quint32 *)realloc(bindingBits,
1416                                          arraySize * sizeof(quint32));
1417
1418         memset(bindingBits + oldArraySize,
1419                0x00,
1420                sizeof(quint32) * (arraySize - oldArraySize));
1421
1422         bindingBitsSize = arraySize * 32;
1423     }
1424
1425     bindingBits[bit / 32] |= (1 << (bit % 32));
1426 }
1427
1428 void QQmlEnginePrivate::sendQuit()
1429 {
1430     Q_Q(QQmlEngine);
1431     emit q->quit();
1432     if (q->receivers(SIGNAL(quit())) == 0) {
1433         qWarning("Signal QQmlEngine::quit() emitted, but no receivers connected to handle it.");
1434     }
1435 }
1436
1437 static void dumpwarning(const QQmlError &error)
1438 {
1439     QMessageLogger(error.url().toString().toLatin1().constData(),
1440                    error.line(), 0).warning().nospace()
1441             << qPrintable(error.toString());
1442 }
1443
1444 static void dumpwarning(const QList<QQmlError> &errors)
1445 {
1446     for (int ii = 0; ii < errors.count(); ++ii)
1447         dumpwarning(errors.at(ii));
1448 }
1449
1450 void QQmlEnginePrivate::warning(const QQmlError &error)
1451 {
1452     Q_Q(QQmlEngine);
1453     q->warnings(QList<QQmlError>() << error);
1454     if (outputWarningsToStdErr)
1455         dumpwarning(error);
1456 }
1457
1458 void QQmlEnginePrivate::warning(const QList<QQmlError> &errors)
1459 {
1460     Q_Q(QQmlEngine);
1461     q->warnings(errors);
1462     if (outputWarningsToStdErr)
1463         dumpwarning(errors);
1464 }
1465
1466 void QQmlEnginePrivate::warning(QQmlEngine *engine, const QQmlError &error)
1467 {
1468     if (engine)
1469         QQmlEnginePrivate::get(engine)->warning(error);
1470     else
1471         dumpwarning(error);
1472 }
1473
1474 void QQmlEnginePrivate::warning(QQmlEngine *engine, const QList<QQmlError> &error)
1475 {
1476     if (engine)
1477         QQmlEnginePrivate::get(engine)->warning(error);
1478     else
1479         dumpwarning(error);
1480 }
1481
1482 void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QQmlError &error)
1483 {
1484     if (engine)
1485         engine->warning(error);
1486     else
1487         dumpwarning(error);
1488 }
1489
1490 void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QList<QQmlError> &error)
1491 {
1492     if (engine)
1493         engine->warning(error);
1494     else
1495         dumpwarning(error);
1496 }
1497
1498 /*
1499    This function should be called prior to evaluation of any js expression,
1500    so that scarce resources are not freed prematurely (eg, if there is a
1501    nested javascript expression).
1502  */
1503 void QQmlEnginePrivate::referenceScarceResources()
1504 {
1505     scarceResourcesRefCount += 1;
1506 }
1507
1508 /*
1509    This function should be called after evaluation of the js expression is
1510    complete, and so the scarce resources may be freed safely.
1511  */
1512 void QQmlEnginePrivate::dereferenceScarceResources()
1513 {
1514     Q_ASSERT(scarceResourcesRefCount > 0);
1515     scarceResourcesRefCount -= 1;
1516
1517     // if the refcount is zero, then evaluation of the "top level"
1518     // expression must have completed.  We can safely release the
1519     // scarce resources.
1520     if (scarceResourcesRefCount == 0) {
1521         // iterate through the list and release them all.
1522         // note that the actual SRD is owned by the JS engine,
1523         // so we cannot delete the SRD; but we can free the
1524         // memory used by the variant in the SRD.
1525         while (ScarceResourceData *sr = scarceResources.first()) {
1526             sr->data = QVariant();
1527             scarceResources.remove(sr);
1528         }
1529     }
1530 }
1531
1532 /*!
1533   Adds \a path as a directory where the engine searches for
1534   installed modules in a URL-based directory structure.
1535   The \a path may be a local filesystem directory or a URL.
1536
1537   The newly added \a path will be first in the importPathList().
1538
1539   \sa setImportPathList(), {QML Modules}
1540 */
1541 void QQmlEngine::addImportPath(const QString& path)
1542 {
1543     Q_D(QQmlEngine);
1544     d->importDatabase.addImportPath(path);
1545 }
1546
1547 /*!
1548   Returns the list of directories where the engine searches for
1549   installed modules in a URL-based directory structure.
1550
1551   For example, if \c /opt/MyApp/lib/imports is in the path, then QML that
1552   imports \c com.mycompany.Feature will cause the QQmlEngine to look
1553   in \c /opt/MyApp/lib/imports/com/mycompany/Feature/ for the components
1554   provided by that module. A \c qmldir file is required for defining the
1555   type version mapping and possibly QML extensions plugins.
1556
1557   By default, the list contains the directory of the application executable,
1558   paths specified in the \c QML_IMPORT_PATH environment variable,
1559   and the builtin \c ImportsPath from QLibraryInfo.
1560
1561   \sa addImportPath(), setImportPathList()
1562 */
1563 QStringList QQmlEngine::importPathList() const
1564 {
1565     Q_D(const QQmlEngine);
1566     return d->importDatabase.importPathList();
1567 }
1568
1569 /*!
1570   Sets \a paths as the list of directories where the engine searches for
1571   installed modules in a URL-based directory structure.
1572
1573   By default, the list contains the directory of the application executable,
1574   paths specified in the \c QML_IMPORT_PATH environment variable,
1575   and the builtin \c ImportsPath from QLibraryInfo.
1576
1577   \sa importPathList(), addImportPath()
1578   */
1579 void QQmlEngine::setImportPathList(const QStringList &paths)
1580 {
1581     Q_D(QQmlEngine);
1582     d->importDatabase.setImportPathList(paths);
1583 }
1584
1585
1586 /*!
1587   Adds \a path as a directory where the engine searches for
1588   native plugins for imported modules (referenced in the \c qmldir file).
1589
1590   By default, the list contains only \c .,  i.e. the engine searches
1591   in the directory of the \c qmldir file itself.
1592
1593   The newly added \a path will be first in the pluginPathList().
1594
1595   \sa setPluginPathList()
1596 */
1597 void QQmlEngine::addPluginPath(const QString& path)
1598 {
1599     Q_D(QQmlEngine);
1600     d->importDatabase.addPluginPath(path);
1601 }
1602
1603
1604 /*!
1605   Returns the list of directories where the engine searches for
1606   native plugins for imported modules (referenced in the \c qmldir file).
1607
1608   By default, the list contains only \c .,  i.e. the engine searches
1609   in the directory of the \c qmldir file itself.
1610
1611   \sa addPluginPath(), setPluginPathList()
1612 */
1613 QStringList QQmlEngine::pluginPathList() const
1614 {
1615     Q_D(const QQmlEngine);
1616     return d->importDatabase.pluginPathList();
1617 }
1618
1619 /*!
1620   Sets the list of directories where the engine searches for
1621   native plugins for imported modules (referenced in the \c qmldir file)
1622   to \a paths.
1623
1624   By default, the list contains only \c .,  i.e. the engine searches
1625   in the directory of the \c qmldir file itself.
1626
1627   \sa pluginPathList(), addPluginPath()
1628   */
1629 void QQmlEngine::setPluginPathList(const QStringList &paths)
1630 {
1631     Q_D(QQmlEngine);
1632     d->importDatabase.setPluginPathList(paths);
1633 }
1634
1635 /*!
1636   Imports the plugin named \a filePath with the \a uri provided.
1637   Returns true if the plugin was successfully imported; otherwise returns false.
1638
1639   On failure and if non-null, the \a errors list will have any errors which occurred prepended to it.
1640
1641   The plugin has to be a Qt plugin which implements the QQmlExtensionPlugin interface.
1642 */
1643 bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors)
1644 {
1645     Q_D(QQmlEngine);
1646     return d->importDatabase.importPlugin(filePath, uri, errors);
1647 }
1648
1649 /*!
1650   Imports the plugin named \a filePath with the \a uri provided.
1651   Returns true if the plugin was successfully imported; otherwise returns false.
1652
1653   On failure and if non-null, *\a errorString will be set to a message describing the failure.
1654
1655   The plugin has to be a Qt plugin which implements the QQmlExtensionPlugin interface.
1656 */
1657 bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QString *errorString)
1658 {
1659     Q_D(QQmlEngine);
1660     QList<QQmlError> errors;
1661     bool retn = d->importDatabase.importPlugin(filePath, uri, &errors);
1662     if (!errors.isEmpty()) {
1663         QString builtError;
1664         for (int i = 0; i < errors.size(); ++i) {
1665             builtError = QString(QLatin1String("%1\n        %2"))
1666                     .arg(builtError)
1667                     .arg(errors.at(i).toString());
1668         }
1669         *errorString = builtError;
1670     }
1671     return retn;
1672 }
1673
1674 /*!
1675   \property QQmlEngine::offlineStoragePath
1676   \brief the directory for storing offline user data
1677
1678   Returns the directory where SQL and other offline
1679   storage is placed.
1680
1681   QQuickWebView and the SQL databases created with openDatabase()
1682   are stored here.
1683
1684   The default is QML/OfflineStorage in the platform-standard
1685   user application data directory.
1686
1687   Note that the path may not currently exist on the filesystem, so
1688   callers wanting to \e create new files at this location should create
1689   it first - see QDir::mkpath().
1690 */
1691 void QQmlEngine::setOfflineStoragePath(const QString& dir)
1692 {
1693     Q_D(QQmlEngine);
1694     d->offlineStoragePath = dir;
1695 }
1696
1697 QString QQmlEngine::offlineStoragePath() const
1698 {
1699     Q_D(const QQmlEngine);
1700     return d->offlineStoragePath;
1701 }
1702
1703 QQmlPropertyCache *QQmlEnginePrivate::createCache(const QMetaObject *mo)
1704 {
1705     Q_Q(QQmlEngine);
1706
1707     if (!mo->superClass()) {
1708         QQmlPropertyCache *rv = new QQmlPropertyCache(q, mo);
1709         propertyCache.insert(mo, rv);
1710         return rv;
1711     } else {
1712         QQmlPropertyCache *super = cache(mo->superClass());
1713         QQmlPropertyCache *rv = super->copyAndAppend(q, mo);
1714         propertyCache.insert(mo, rv);
1715         return rv;
1716     }
1717 }
1718
1719 QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersion,
1720                                                                   QQmlError &error)
1721 {
1722     QList<QQmlType *> types;
1723
1724     int maxMinorVersion = 0;
1725
1726     const QMetaObject *metaObject = type->metaObject();
1727
1728     while (metaObject) {
1729         QQmlType *t = QQmlMetaType::qmlType(metaObject, type->module(),
1730                                                             type->majorVersion(), minorVersion);
1731         if (t) {
1732             maxMinorVersion = qMax(maxMinorVersion, t->minorVersion());
1733             types << t;
1734         } else {
1735             types << 0;
1736         }
1737
1738         metaObject = metaObject->superClass();
1739     }
1740
1741     if (QQmlPropertyCache *c = typePropertyCache.value(qMakePair(type, maxMinorVersion))) {
1742         c->addref();
1743         typePropertyCache.insert(qMakePair(type, minorVersion), c);
1744         return c;
1745     }
1746
1747     QQmlPropertyCache *raw = cache(type->metaObject());
1748
1749     bool hasCopied = false;
1750
1751     for (int ii = 0; ii < types.count(); ++ii) {
1752         QQmlType *currentType = types.at(ii);
1753         if (!currentType)
1754             continue;
1755
1756         int rev = currentType->metaObjectRevision();
1757         int moIndex = types.count() - 1 - ii;
1758
1759         if (raw->allowedRevisionCache[moIndex] != rev) {
1760             if (!hasCopied) {
1761                 raw = raw->copy();
1762                 hasCopied = true;
1763             }
1764             raw->allowedRevisionCache[moIndex] = rev;
1765         }
1766     }
1767
1768     // Test revision compatibility - the basic rule is:
1769     //    * Anything that is excluded, cannot overload something that is not excluded *
1770
1771     // Signals override:
1772     //    * other signals and methods of the same name.
1773     //    * properties named on<Signal Name>
1774     //    * automatic <property name>Changed notify signals
1775
1776     // Methods override:
1777     //    * other methods of the same name
1778
1779     // Properties override:
1780     //    * other elements of the same name
1781
1782     bool overloadError = false;
1783     QString overloadName;
1784
1785 #if 0
1786     for (QQmlPropertyCache::StringCache::ConstIterator iter = raw->stringCache.begin();
1787          !overloadError && iter != raw->stringCache.end();
1788          ++iter) {
1789
1790         QQmlPropertyData *d = *iter;
1791         if (raw->isAllowedInRevision(d))
1792             continue; // Not excluded - no problems
1793
1794         // check that a regular "name" overload isn't happening
1795         QQmlPropertyData *current = d;
1796         while (!overloadError && current) {
1797             current = d->overrideData(current);
1798             if (current && raw->isAllowedInRevision(current))
1799                 overloadError = true;
1800         }
1801     }
1802 #endif
1803
1804     if (overloadError) {
1805         if (hasCopied) raw->release();
1806
1807         error.setDescription(QLatin1String("Type ") + type->qmlTypeName() + QLatin1Char(' ') + QString::number(type->majorVersion()) + QLatin1Char('.') + QString::number(minorVersion) + QLatin1String(" contains an illegal property \"") + overloadName + QLatin1String("\".  This is an error in the type's implementation."));
1808         return 0;
1809     }
1810
1811     if (!hasCopied) raw->addref();
1812     typePropertyCache.insert(qMakePair(type, minorVersion), raw);
1813
1814     if (minorVersion != maxMinorVersion) {
1815         raw->addref();
1816         typePropertyCache.insert(qMakePair(type, maxMinorVersion), raw);
1817     }
1818
1819     return raw;
1820 }
1821
1822 QQmlMetaType::ModuleApiInstance *
1823 QQmlEnginePrivate::moduleApiInstance(const QQmlMetaType::ModuleApi &module)
1824 {
1825     Locker locker(this);
1826
1827     QQmlMetaType::ModuleApiInstance *a = moduleApiInstances.value(module);
1828     if (!a) {
1829         a = new QQmlMetaType::ModuleApiInstance;
1830         a->scriptCallback = module.script;
1831         a->qobjectCallback = module.qobject;
1832         a->instanceMetaObject = module.instanceMetaObject;
1833         moduleApiInstances.insert(module, a);
1834     }
1835
1836     return a;
1837 }
1838
1839 bool QQmlEnginePrivate::isQObject(int t)
1840 {
1841     Locker locker(this);
1842     return m_compositeTypes.contains(t) || QQmlMetaType::isQObject(t);
1843 }
1844
1845 QObject *QQmlEnginePrivate::toQObject(const QVariant &v, bool *ok) const
1846 {
1847     Locker locker(this);
1848     int t = v.userType();
1849     if (t == QMetaType::QObjectStar || m_compositeTypes.contains(t)) {
1850         if (ok) *ok = true;
1851         return *(QObject **)(v.constData());
1852     } else {
1853         return QQmlMetaType::toQObject(v, ok);
1854     }
1855 }
1856
1857 QQmlMetaType::TypeCategory QQmlEnginePrivate::typeCategory(int t) const
1858 {
1859     Locker locker(this);
1860     if (m_compositeTypes.contains(t))
1861         return QQmlMetaType::Object;
1862     else if (m_qmlLists.contains(t))
1863         return QQmlMetaType::List;
1864     else
1865         return QQmlMetaType::typeCategory(t);
1866 }
1867
1868 bool QQmlEnginePrivate::isList(int t) const
1869 {
1870     Locker locker(this);
1871     return m_qmlLists.contains(t) || QQmlMetaType::isList(t);
1872 }
1873
1874 int QQmlEnginePrivate::listType(int t) const
1875 {
1876     Locker locker(this);
1877     QHash<int, int>::ConstIterator iter = m_qmlLists.find(t);
1878     if (iter != m_qmlLists.end())
1879         return *iter;
1880     else
1881         return QQmlMetaType::listType(t);
1882 }
1883
1884 QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const
1885 {
1886     Locker locker(this);
1887     QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.find(t);
1888     if (iter != m_compositeTypes.end()) {
1889         return QQmlMetaObject((*iter)->rootPropertyCache);
1890     } else {
1891         QQmlType *type = QQmlMetaType::qmlType(t);
1892         return QQmlMetaObject(type?type->baseMetaObject():0);
1893     }
1894 }
1895
1896 QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const
1897 {
1898     Locker locker(this);
1899     QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.find(t);
1900     if (iter != m_compositeTypes.end()) {
1901         return QQmlMetaObject((*iter)->rootPropertyCache);
1902     } else {
1903         QQmlType *type = QQmlMetaType::qmlType(t);
1904         return QQmlMetaObject(type?type->metaObject():0);
1905     }
1906 }
1907
1908 QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t)
1909 {
1910     Locker locker(this);
1911     QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.find(t);
1912     if (iter != m_compositeTypes.end()) {
1913         return (*iter)->rootPropertyCache;
1914     } else {
1915         QQmlType *type = QQmlMetaType::qmlType(t);
1916         locker.unlock();
1917         return type?cache(type->metaObject()):0;
1918     }
1919 }
1920
1921 QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t)
1922 {
1923     Locker locker(this);
1924     QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.find(t);
1925     if (iter != m_compositeTypes.end()) {
1926         return (*iter)->rootPropertyCache;
1927     } else {
1928         QQmlType *type = QQmlMetaType::qmlType(t);
1929         locker.unlock();
1930         return type?cache(type->baseMetaObject()):0;
1931     }
1932 }
1933
1934 void QQmlEnginePrivate::registerCompositeType(QQmlCompiledData *data)
1935 {
1936     QByteArray name = data->rootPropertyCache->className();
1937
1938     QByteArray ptr = name + '*';
1939     QByteArray lst = "QQmlListProperty<" + name + '>';
1940
1941     int ptr_type = QMetaType::registerNormalizedType(ptr,
1942                                                      qMetaTypeDeleteHelper<QObject*>,
1943                                                      qMetaTypeCreateHelper<QObject*>,
1944                                                      qMetaTypeDestructHelper<QObject*>,
1945                                                      qMetaTypeConstructHelper<QObject*>,
1946                                                      sizeof(QObject*),
1947                                                      static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QObject*>::Flags),
1948                                                      0);
1949     int lst_type = QMetaType::registerNormalizedType(lst,
1950                                                      qMetaTypeDeleteHelper<QQmlListProperty<QObject> >,
1951                                                      qMetaTypeCreateHelper<QQmlListProperty<QObject> >,
1952                                                      qMetaTypeDestructHelper<QQmlListProperty<QObject> >,
1953                                                      qMetaTypeConstructHelper<QQmlListProperty<QObject> >,
1954                                                      sizeof(QQmlListProperty<QObject>),
1955                                                      static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QQmlListProperty<QObject> >::Flags),
1956                                                      static_cast<QMetaObject*>(0));
1957
1958     data->metaTypeId = ptr_type;
1959     data->listMetaTypeId = lst_type;
1960     data->isRegisteredWithEngine = true;
1961
1962     Locker locker(this);
1963     m_qmlLists.insert(lst_type, ptr_type);
1964     // The QQmlCompiledData is not referenced here, but it is removed from this
1965     // hash in the QQmlCompiledData destructor
1966     m_compositeTypes.insert(ptr_type, data);
1967 }
1968
1969 void QQmlEnginePrivate::unregisterCompositeType(QQmlCompiledData *data)
1970 {
1971     int ptr_type = data->metaTypeId;
1972     int lst_type = data->listMetaTypeId;
1973
1974     Locker locker(this);
1975     m_qmlLists.remove(lst_type);
1976     m_compositeTypes.remove(ptr_type);
1977 }
1978
1979 bool QQmlEnginePrivate::isTypeLoaded(const QUrl &url) const
1980 {
1981     return typeLoader.isTypeLoaded(url);
1982 }
1983
1984 bool QQmlEnginePrivate::isScriptLoaded(const QUrl &url) const
1985 {
1986     return typeLoader.isScriptLoaded(url);
1987 }
1988
1989 bool QQml_isFileCaseCorrect(const QString &fileName)
1990 {
1991 #if defined(Q_OS_MAC) || defined(Q_OS_WIN)
1992     QFileInfo info(fileName);
1993     const QString absolute = info.absoluteFilePath();
1994
1995 #if defined(Q_OS_MAC)
1996     const QString canonical = info.canonicalFilePath();
1997 #elif defined(Q_OS_WIN)
1998     wchar_t buffer[1024];
1999
2000     DWORD rv = ::GetShortPathName((wchar_t*)absolute.utf16(), buffer, 1024);
2001     if (rv == 0 || rv >= 1024) return true;
2002     rv = ::GetLongPathName(buffer, buffer, 1024);
2003     if (rv == 0 || rv >= 1024) return true;
2004
2005     const QString canonical = QString::fromWCharArray(buffer);
2006 #endif
2007
2008     const int absoluteLength = absolute.length();
2009     const int canonicalLength = canonical.length();
2010
2011     const int length = qMin(absoluteLength, canonicalLength);
2012     for (int ii = 0; ii < length; ++ii) {
2013         const QChar &a = absolute.at(absoluteLength - 1 - ii);
2014         const QChar &c = canonical.at(canonicalLength - 1 - ii);
2015
2016         if (a.toLower() != c.toLower())
2017             return true;
2018         if (a != c)
2019             return false;
2020     }
2021 #else
2022     Q_UNUSED(fileName)
2023 #endif
2024     return true;
2025 }
2026
2027 /*!
2028     \fn QQmlEngine *qmlEngine(const QObject *object)
2029     \relates QQmlEngine
2030
2031     Returns the QQmlEngine associated with \a object, if any.  This is equivalent to
2032     QQmlEngine::contextForObject(object)->engine(), but more efficient.
2033 */
2034
2035 /*!
2036     \fn QQmlContext *qmlContext(const QObject *object)
2037     \relates QQmlEngine
2038
2039     Returns the QQmlContext associated with \a object, if any.  This is equivalent to
2040     QQmlEngine::contextForObject(object).
2041 */
2042
2043 QT_END_NAMESPACE