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