Don't double emit threaded signals
[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 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 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 class QQmlThreadNotifierProxyObject : public QObject
476 {
477 public:
478     QPointer<QObject> target;
479
480     virtual int qt_metacall(QMetaObject::Call, int id, void **a) {
481         if (!target)
482             return -1;
483
484         QQmlData *ddata = QQmlData::get(target, false);
485         QQmlNotifierEndpoint *ep = ddata->notify(id);
486         if (ep) QQmlNotifier::emitNotify(ep, a);
487
488         delete this;
489
490         return -1;
491     }
492 };
493
494 void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int index, void **a)
495 {
496     QQmlData *ddata = QQmlData::get(object, false);
497     if (!ddata) return; // Probably being deleted
498
499     // In general, QML only supports QObject's that live on the same thread as the QQmlEngine
500     // that they're exposed to.  However, to make writing "worker objects" that calculate data
501     // in a separate thread easier, QML allows a QObject that lives in the same thread as the
502     // QQmlEngine to emit signals from a different thread.  These signals are then automatically
503     // marshalled back onto the QObject's thread and handled by QML from there.  This is tested
504     // by the qqmlecmascript::threadSignal() autotest.
505     if (ddata->notifyList &&
506         QThread::currentThreadId() != QObjectPrivate::get(object)->threadData->threadId) {
507
508         if (!QObjectPrivate::get(object)->threadData->thread)
509             return;
510
511         QMetaMethod m = object->metaObject()->method(index);
512         QList<QByteArray> parameterTypes = m.parameterTypes();
513
514         int *types = (int *)malloc((parameterTypes.count() + 1) * sizeof(int));
515         void **args = (void **) malloc((parameterTypes.count() + 1) *sizeof(void *));
516
517         types[0] = 0; // return type
518         args[0] = 0; // return value
519
520         for (int ii = 0; ii < parameterTypes.count(); ++ii) {
521             const QByteArray &typeName = parameterTypes.at(ii);
522             if (typeName.endsWith('*'))
523                 types[ii + 1] = QMetaType::VoidStar;
524             else
525                 types[ii + 1] = QMetaType::type(typeName);
526
527             if (!types[ii + 1]) {
528                 qWarning("QObject::connect: Cannot queue arguments of type '%s'\n"
529                          "(Make sure '%s' is registered using qRegisterMetaType().)",
530                          typeName.constData(), typeName.constData());
531                 free(types);
532                 free(args);
533                 return;
534             }
535
536             args[ii + 1] = QMetaType::create(types[ii + 1], a[ii + 1]);
537         }
538
539         QMetaCallEvent *ev = new QMetaCallEvent(index, 0, 0, object, index,
540                                                 parameterTypes.count() + 1, types, args);
541
542         QQmlThreadNotifierProxyObject *mpo = new QQmlThreadNotifierProxyObject;
543         mpo->target = object;
544         mpo->moveToThread(QObjectPrivate::get(object)->threadData->thread);
545         QCoreApplication::postEvent(mpo, ev);
546
547     } else {
548         QQmlNotifierEndpoint *ep = ddata->notify(index);
549         if (ep) QQmlNotifier::emitNotify(ep, a);
550     }
551 }
552
553 int QQmlData::receivers(QAbstractDeclarativeData *d, const QObject *, int index)
554 {
555     return static_cast<QQmlData *>(d)->endpointCount(index);
556 }
557
558 int QQmlData::endpointCount(int index)
559 {
560     int count = 0;
561     QQmlNotifierEndpoint *ep = notify(index);
562     if (!ep)
563         return count;
564     ++count;
565     while (ep->next) {
566         ++count;
567         ep = ep->next;
568     }
569     return count;
570 }
571
572 void QQmlData::markAsDeleted(QObject *o)
573 {
574     QQmlData::setQueuedForDeletion(o);
575
576     QObjectPrivate *p = QObjectPrivate::get(o);
577     for (QList<QObject *>::iterator it = p->children.begin(), end = p->children.end(); it != end; ++it) {
578         QQmlData::markAsDeleted(*it);
579     }
580 }
581
582 void QQmlData::setQueuedForDeletion(QObject *object)
583 {
584     if (object) {
585         if (QObjectPrivate *priv = QObjectPrivate::get(object)) {
586             if (!priv->wasDeleted && priv->declarativeData) {
587                 QQmlData *ddata = QQmlData::get(object, false);
588                 if (ddata->ownContext && ddata->context)
589                     ddata->context->emitDestruction();
590                 ddata->isQueuedForDeletion = true;
591             }
592         }
593     }
594 }
595
596 void QQmlEnginePrivate::init()
597 {
598     Q_Q(QQmlEngine);
599
600     static bool firstTime = true;
601     if (firstTime) {
602         qmlRegisterType<QQmlComponent>("QML", 1, 0, "Component");
603
604         QQmlData::init();
605         firstTime = false;
606     }
607
608     qRegisterMetaType<QVariant>("QVariant");
609     qRegisterMetaType<QQmlScriptString>("QQmlScriptString");
610     qRegisterMetaType<QJSValue>("QJSValue");
611     qRegisterMetaType<QQmlComponent::Status>("QQmlComponent::Status");
612     qRegisterMetaType<QList<QObject*> >("QList<QObject*>");
613     qRegisterMetaType<QList<int> >("QList<int>");
614     qRegisterMetaType<QQmlV8Handle>("QQmlV8Handle");
615
616     v8engine()->setEngine(q);
617
618     rootContext = new QQmlContext(q,true);
619
620     if (QCoreApplication::instance()->thread() == q->thread() &&
621         QQmlEngineDebugService::isDebuggingEnabled()) {
622         isDebugging = true;
623         QQmlEngineDebugService::instance()->addEngine(q);
624         QV8DebugService::initialize(v8engine());
625         QV8ProfilerService::initialize();
626         QQmlProfilerService::initialize();
627         QDebugMessageService::instance();
628     }
629
630     QString dataLocation = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
631     if (!dataLocation.isEmpty())
632         offlineStoragePath = dataLocation.replace(QLatin1Char('/'), QDir::separator())
633                            + QDir::separator() + QLatin1String("QML")
634                            + QDir::separator() + QLatin1String("OfflineStorage");
635 }
636
637 QQuickWorkerScriptEngine *QQmlEnginePrivate::getWorkerScriptEngine()
638 {
639     Q_Q(QQmlEngine);
640     if (!workerScriptEngine)
641         workerScriptEngine = new QQuickWorkerScriptEngine(q);
642     return workerScriptEngine;
643 }
644
645 /*!
646   \class QQmlEngine
647   \since 5.0
648   \inmodule QtQml
649   \brief The QQmlEngine class provides an environment for instantiating QML components.
650   \mainclass
651
652   Each QML component is instantiated in a QQmlContext.
653   QQmlContext's are essential for passing data to QML
654   components.  In QML, contexts are arranged hierarchically and this
655   hierarchy is managed by the QQmlEngine.
656
657   Prior to creating any QML components, an application must have
658   created a QQmlEngine to gain access to a QML context.  The
659   following example shows how to create a simple Text item.
660
661   \code
662   QQmlEngine engine;
663   QQmlComponent component(&engine);
664   component.setData("import QtQuick 2.0\nText { text: \"Hello world!\" }", QUrl());
665   QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
666
667   //add item to view, etc
668   ...
669   \endcode
670
671   In this case, the Text item will be created in the engine's
672   \l {QQmlEngine::rootContext()}{root context}.
673
674   Note that the QtQuick 1 version is called QDeclarativeEngine.
675
676   \sa QQmlComponent, QQmlContext
677 */
678
679 /*!
680   Create a new QQmlEngine with the given \a parent.
681 */
682 QQmlEngine::QQmlEngine(QObject *parent)
683 : QJSEngine(*new QQmlEnginePrivate(this), parent)
684 {
685     Q_D(QQmlEngine);
686     d->init();
687 }
688
689 /*!
690   Destroys the QQmlEngine.
691
692   Any QQmlContext's created on this engine will be
693   invalidated, but not destroyed (unless they are parented to the
694   QQmlEngine object).
695 */
696 QQmlEngine::~QQmlEngine()
697 {
698     Q_D(QQmlEngine);
699     if (d->isDebugging) {
700         QQmlEngineDebugService::instance()->remEngine(this);
701     }
702
703     // Emit onDestruction signals for the root context before
704     // we destroy the contexts, engine, Module APIs etc. that
705     // may be required to handle the destruction signal.
706     QQmlContextData::get(rootContext())->emitDestruction();
707
708     // if we are the parent of any of the qobject module api instances,
709     // we need to remove them from our internal list, in order to prevent
710     // a segfault in engine private dtor.
711     QList<QQmlMetaType::ModuleApi> keys = d->moduleApiInstances.keys();
712     QObject *currQObjectApi = 0;
713     QQmlMetaType::ModuleApiInstance *currInstance = 0;
714     foreach (const QQmlMetaType::ModuleApi &key, keys) {
715         currInstance = d->moduleApiInstances.value(key);
716         currQObjectApi = currInstance->qobjectApi;
717         if (this->children().contains(currQObjectApi)) {
718             delete currQObjectApi;
719             delete currInstance;
720             d->moduleApiInstances.remove(key);
721         }
722     }
723
724     if (d->incubationController)
725         d->incubationController->d = 0;
726 }
727
728 /*! \fn void QQmlEngine::quit()
729     This signal is emitted when the QML loaded by the engine would like to quit.
730  */
731
732 /*! \fn void QQmlEngine::warnings(const QList<QQmlError> &warnings)
733     This signal is emitted when \a warnings messages are generated by QML.
734  */
735
736 /*!
737   Clears the engine's internal component cache.
738
739   This function causes the property metadata of all components previously
740   loaded by the engine to be destroyed.  All previously loaded components and
741   the property bindings for all extant objects created from those components will
742   cease to function.
743
744   This function returns the engine to a state where it does not contain any loaded
745   component data.  This may be useful in order to reload a smaller subset of the
746   previous component set, or to load a new version of a previously loaded component.
747
748   Once the component cache has been cleared, components must be loaded before
749   any new objects can be created.
750
751   \sa trimComponentCache()
752  */
753 void QQmlEngine::clearComponentCache()
754 {
755     Q_D(QQmlEngine);
756     d->typeLoader.clearCache();
757 }
758
759 /*!
760   Trims the engine's internal component cache.
761
762   This function causes the property metadata of any loaded components which are
763   not currently in use to be destroyed.
764
765   A component is considered to be in use if there are any extant instances of
766   the component itself, any instances of other components that use the component,
767   or any objects instantiated by any of those components.
768
769   \sa clearComponentCache()
770  */
771 void QQmlEngine::trimComponentCache()
772 {
773     Q_D(QQmlEngine);
774     d->typeLoader.trimCache();
775 }
776
777 /*!
778   Returns the engine's root context.
779
780   The root context is automatically created by the QQmlEngine.
781   Data that should be available to all QML component instances
782   instantiated by the engine should be put in the root context.
783
784   Additional data that should only be available to a subset of
785   component instances should be added to sub-contexts parented to the
786   root context.
787 */
788 QQmlContext *QQmlEngine::rootContext() const
789 {
790     Q_D(const QQmlEngine);
791     return d->rootContext;
792 }
793
794 /*!
795   Sets the \a factory to use for creating QNetworkAccessManager(s).
796
797   QNetworkAccessManager is used for all network access by QML.  By
798   implementing a factory it is possible to create custom
799   QNetworkAccessManager with specialized caching, proxy and cookie
800   support.
801
802   The factory must be set before executing the engine.
803 */
804 void QQmlEngine::setNetworkAccessManagerFactory(QQmlNetworkAccessManagerFactory *factory)
805 {
806     Q_D(QQmlEngine);
807     QMutexLocker locker(&d->mutex);
808     d->networkAccessManagerFactory = factory;
809 }
810
811 /*!
812   Returns the current QQmlNetworkAccessManagerFactory.
813
814   \sa setNetworkAccessManagerFactory()
815 */
816 QQmlNetworkAccessManagerFactory *QQmlEngine::networkAccessManagerFactory() const
817 {
818     Q_D(const QQmlEngine);
819     return d->networkAccessManagerFactory;
820 }
821
822 void QQmlEnginePrivate::registerFinalizeCallback(QObject *obj, int index)
823 {
824     if (activeVME) {
825         activeVME->finalizeCallbacks.append(qMakePair(QQmlGuard<QObject>(obj), index));
826     } else {
827         void *args[] = { 0 };
828         QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, index, args);
829     }
830 }
831
832 QNetworkAccessManager *QQmlEnginePrivate::createNetworkAccessManager(QObject *parent) const
833 {
834     QMutexLocker locker(&mutex);
835     QNetworkAccessManager *nam;
836     if (networkAccessManagerFactory) {
837         nam = networkAccessManagerFactory->create(parent);
838     } else {
839         nam = new QNetworkAccessManager(parent);
840     }
841
842     return nam;
843 }
844
845 QNetworkAccessManager *QQmlEnginePrivate::getNetworkAccessManager() const
846 {
847     Q_Q(const QQmlEngine);
848     if (!networkAccessManager)
849         networkAccessManager = createNetworkAccessManager(const_cast<QQmlEngine*>(q));
850     return networkAccessManager;
851 }
852
853 /*!
854   Returns a common QNetworkAccessManager which can be used by any QML
855   element instantiated by this engine.
856
857   If a QQmlNetworkAccessManagerFactory has been set and a
858   QNetworkAccessManager has not yet been created, the
859   QQmlNetworkAccessManagerFactory will be used to create the
860   QNetworkAccessManager; otherwise the returned QNetworkAccessManager
861   will have no proxy or cache set.
862
863   \sa setNetworkAccessManagerFactory()
864 */
865 QNetworkAccessManager *QQmlEngine::networkAccessManager() const
866 {
867     Q_D(const QQmlEngine);
868     return d->getNetworkAccessManager();
869 }
870
871 /*!
872
873   Sets the \a provider to use for images requested via the \e
874   image: url scheme, with host \a providerId. The QQmlEngine
875   takes ownership of \a provider.
876
877   Image providers enable support for pixmap and threaded image
878   requests. See the QQuickImageProvider documentation for details on
879   implementing and using image providers.
880
881   All required image providers should be added to the engine before any
882   QML sources files are loaded.
883
884   \sa removeImageProvider(), QQuickImageProvider, QQmlImageProviderBase
885 */
886 void QQmlEngine::addImageProvider(const QString &providerId, QQmlImageProviderBase *provider)
887 {
888     Q_D(QQmlEngine);
889     QMutexLocker locker(&d->mutex);
890     d->imageProviders.insert(providerId.toLower(), QSharedPointer<QQmlImageProviderBase>(provider));
891 }
892
893 /*!
894   Returns the image provider set for \a providerId.
895
896   Returns the provider if it was found; otherwise returns 0.
897
898   \sa QQuickImageProvider
899 */
900 QQmlImageProviderBase *QQmlEngine::imageProvider(const QString &providerId) const
901 {
902     Q_D(const QQmlEngine);
903     QMutexLocker locker(&d->mutex);
904     return d->imageProviders.value(providerId).data();
905 }
906
907 /*!
908   Removes the image provider for \a providerId.
909
910   \sa addImageProvider(), QQuickImageProvider
911 */
912 void QQmlEngine::removeImageProvider(const QString &providerId)
913 {
914     Q_D(QQmlEngine);
915     QMutexLocker locker(&d->mutex);
916     d->imageProviders.take(providerId);
917 }
918
919 /*!
920   Return the base URL for this engine.  The base URL is only used to
921   resolve components when a relative URL is passed to the
922   QQmlComponent constructor.
923
924   If a base URL has not been explicitly set, this method returns the
925   application's current working directory.
926
927   \sa setBaseUrl()
928 */
929 QUrl QQmlEngine::baseUrl() const
930 {
931     Q_D(const QQmlEngine);
932     if (d->baseUrl.isEmpty()) {
933         return QUrl::fromLocalFile(QDir::currentPath() + QDir::separator());
934     } else {
935         return d->baseUrl;
936     }
937 }
938
939 /*!
940   Set the  base URL for this engine to \a url.
941
942   \sa baseUrl()
943 */
944 void QQmlEngine::setBaseUrl(const QUrl &url)
945 {
946     Q_D(QQmlEngine);
947     d->baseUrl = url;
948 }
949
950 /*!
951   Returns true if warning messages will be output to stderr in addition
952   to being emitted by the warnings() signal, otherwise false.
953
954   The default value is true.
955 */
956 bool QQmlEngine::outputWarningsToStandardError() const
957 {
958     Q_D(const QQmlEngine);
959     return d->outputWarningsToStdErr;
960 }
961
962 /*!
963   Set whether warning messages will be output to stderr to \a enabled.
964
965   If \a enabled is true, any warning messages generated by QML will be
966   output to stderr and emitted by the warnings() signal.  If \a enabled
967   is false, on the warnings() signal will be emitted.  This allows
968   applications to handle warning output themselves.
969
970   The default value is true.
971 */
972 void QQmlEngine::setOutputWarningsToStandardError(bool enabled)
973 {
974     Q_D(QQmlEngine);
975     d->outputWarningsToStdErr = enabled;
976 }
977
978 /*!
979   Returns the QQmlContext for the \a object, or 0 if no
980   context has been set.
981
982   When the QQmlEngine instantiates a QObject, the context is
983   set automatically.
984   */
985 QQmlContext *QQmlEngine::contextForObject(const QObject *object)
986 {
987     if(!object)
988         return 0;
989
990     QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object));
991
992     QQmlData *data =
993         static_cast<QQmlData *>(priv->declarativeData);
994
995     if (!data)
996         return 0;
997     else if (data->outerContext)
998         return data->outerContext->asQQmlContext();
999     else
1000         return 0;
1001 }
1002
1003 /*!
1004   Sets the QQmlContext for the \a object to \a context.
1005   If the \a object already has a context, a warning is
1006   output, but the context is not changed.
1007
1008   When the QQmlEngine instantiates a QObject, the context is
1009   set automatically.
1010  */
1011 void QQmlEngine::setContextForObject(QObject *object, QQmlContext *context)
1012 {
1013     if (!object || !context)
1014         return;
1015
1016     QQmlData *data = QQmlData::get(object, true);
1017     if (data->context) {
1018         qWarning("QQmlEngine::setContextForObject(): Object already has a QQmlContext");
1019         return;
1020     }
1021
1022     QQmlContextData *contextData = QQmlContextData::get(context);
1023     contextData->addObject(object);
1024 }
1025
1026 /*!
1027   \enum QQmlEngine::ObjectOwnership
1028
1029   Ownership controls whether or not QML automatically destroys the
1030   QObject when the object is garbage collected by the JavaScript
1031   engine.  The two ownership options are:
1032
1033   \value CppOwnership The object is owned by C++ code, and will
1034   never be deleted by QML.  The JavaScript destroy() method cannot be
1035   used on objects with CppOwnership.  This option is similar to
1036   QScriptEngine::QtOwnership.
1037
1038   \value JavaScriptOwnership The object is owned by JavaScript.
1039   When the object is returned to QML as the return value of a method
1040   call or property access, QML will track it, and delete the object
1041   if there are no remaining JavaScript references to it and it has no
1042   QObject::parent().  An object tracked by one QQmlEngine
1043   will be deleted during that QQmlEngine's destructor, and thus
1044   JavaScript references between objects with JavaScriptOwnership from
1045   two different engines will not be valid after the deletion of one of
1046   those engines.  This option is similar to QScriptEngine::ScriptOwnership.
1047
1048   Generally an application doesn't need to set an object's ownership
1049   explicitly.  QML uses a heuristic to set the default object
1050   ownership.  By default, an object that is created by QML has
1051   JavaScriptOwnership.  The exception to this are the root objects
1052   created by calling QQmlComponent::create() or
1053   QQmlComponent::beginCreate() which have CppOwnership by
1054   default.  The ownership of these root-level objects is considered to
1055   have been transferred to the C++ caller.
1056
1057   Objects not-created by QML have CppOwnership by default.  The
1058   exception to this is objects returned from a C++ method call.  The
1059   ownership of these objects is passed to JavaScript.
1060
1061   Calling setObjectOwnership() overrides the default ownership
1062   heuristic used by QML.
1063 */
1064
1065 /*!
1066   Sets the \a ownership of \a object.
1067 */
1068 void QQmlEngine::setObjectOwnership(QObject *object, ObjectOwnership ownership)
1069 {
1070     if (!object)
1071         return;
1072
1073     QQmlData *ddata = QQmlData::get(object, true);
1074     if (!ddata)
1075         return;
1076
1077     ddata->indestructible = (ownership == CppOwnership)?true:false;
1078     ddata->explicitIndestructibleSet = true;
1079 }
1080
1081 /*!
1082   Returns the ownership of \a object.
1083 */
1084 QQmlEngine::ObjectOwnership QQmlEngine::objectOwnership(QObject *object)
1085 {
1086     if (!object)
1087         return CppOwnership;
1088
1089     QQmlData *ddata = QQmlData::get(object, false);
1090     if (!ddata)
1091         return CppOwnership;
1092     else
1093         return ddata->indestructible?CppOwnership:JavaScriptOwnership;
1094 }
1095
1096 bool QQmlEngine::event(QEvent *e)
1097 {
1098     Q_D(QQmlEngine);
1099     if (e->type() == QEvent::User)
1100         d->doDeleteInEngineThread();
1101
1102     return QJSEngine::event(e);
1103 }
1104
1105 void QQmlEnginePrivate::doDeleteInEngineThread()
1106 {
1107     QFieldList<Deletable, &Deletable::next> list;
1108     mutex.lock();
1109     list.copyAndClear(toDeleteInEngineThread);
1110     mutex.unlock();
1111
1112     while (Deletable *d = list.takeFirst())
1113         delete d;
1114 }
1115
1116 Q_AUTOTEST_EXPORT void qmlExecuteDeferred(QObject *object)
1117 {
1118     QQmlData *data = QQmlData::get(object);
1119
1120     if (data && data->compiledData && data->deferredIdx) {
1121         QQmlObjectCreatingProfiler prof;
1122         if (prof.enabled) {
1123             QQmlType *type = QQmlMetaType::qmlType(object->metaObject());
1124             prof.setTypeName(type ? type->qmlTypeName()
1125                                   : QString::fromUtf8(object->metaObject()->className()));
1126             if (data->outerContext)
1127                 prof.setLocation(data->outerContext->url, data->lineNumber, data->columnNumber);
1128         }
1129         QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine);
1130
1131         QQmlComponentPrivate::ConstructionState state;
1132         QQmlComponentPrivate::beginDeferred(ep, object, &state);
1133
1134         // Release the reference for the deferral action (we still have one from construction)
1135         data->compiledData->release();
1136         data->compiledData = 0;
1137
1138         QQmlComponentPrivate::complete(ep, &state);
1139     }
1140 }
1141
1142 QQmlContext *qmlContext(const QObject *obj)
1143 {
1144     return QQmlEngine::contextForObject(obj);
1145 }
1146
1147 QQmlEngine *qmlEngine(const QObject *obj)
1148 {
1149     QQmlData *data = QQmlData::get(obj, false);
1150     if (!data || !data->context)
1151         return 0;
1152     return data->context->engine;
1153 }
1154
1155 QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create)
1156 {
1157     QQmlData *data = QQmlData::get(object);
1158     if (!data)
1159         return 0; // Attached properties are only on objects created by QML
1160
1161     QObject *rv = data->hasExtendedData()?data->attachedProperties()->value(id):0;
1162     if (rv || !create)
1163         return rv;
1164
1165     QQmlAttachedPropertiesFunc pf = QQmlMetaType::attachedPropertiesFuncById(id);
1166     if (!pf)
1167         return 0;
1168
1169     rv = pf(const_cast<QObject *>(object));
1170
1171     if (rv)
1172         data->attachedProperties()->insert(id, rv);
1173
1174     return rv;
1175 }
1176
1177 QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *object,
1178                                      const QMetaObject *attachedMetaObject, bool create)
1179 {
1180     if (*idCache == -1)
1181         *idCache = QQmlMetaType::attachedPropertiesFuncId(attachedMetaObject);
1182
1183     if (*idCache == -1 || !object)
1184         return 0;
1185
1186     return qmlAttachedPropertiesObjectById(*idCache, object, create);
1187 }
1188
1189 QQmlDebuggingEnabler::QQmlDebuggingEnabler(bool printWarning)
1190 {
1191 #ifndef QQML_NO_DEBUG_PROTOCOL
1192     if (!QQmlEnginePrivate::qml_debugging_enabled
1193             && printWarning) {
1194         qDebug("QML debugging is enabled. Only use this in a safe environment.");
1195     }
1196     QQmlEnginePrivate::qml_debugging_enabled = true;
1197 #endif
1198 }
1199
1200
1201 class QQmlDataExtended {
1202 public:
1203     QQmlDataExtended();
1204     ~QQmlDataExtended();
1205
1206     QHash<int, QObject *> attachedProperties;
1207 };
1208
1209 QQmlDataExtended::QQmlDataExtended()
1210 {
1211 }
1212
1213 QQmlDataExtended::~QQmlDataExtended()
1214 {
1215 }
1216
1217 void QQmlData::NotifyList::layout(QQmlNotifierEndpoint *endpoint)
1218 {
1219     if (endpoint->next)
1220         layout(endpoint->next);
1221
1222     int index = endpoint->sourceSignal;
1223     index = qMin(index, 0xFFFF - 1);
1224
1225     endpoint->next = notifies[index];
1226     if (endpoint->next) endpoint->next->prev = &endpoint->next;
1227     endpoint->prev = &notifies[index];
1228     notifies[index] = endpoint;
1229 }
1230
1231 void QQmlData::NotifyList::layout()
1232 {
1233     Q_ASSERT(maximumTodoIndex >= notifiesSize);
1234
1235     if (todo) {
1236         QQmlNotifierEndpoint **old = notifies;
1237         const int reallocSize = (maximumTodoIndex + 1) * sizeof(QQmlNotifierEndpoint*);
1238         notifies = (QQmlNotifierEndpoint**)realloc(notifies, reallocSize);
1239         const int memsetSize = (maximumTodoIndex - notifiesSize + 1) *
1240                                sizeof(QQmlNotifierEndpoint*);
1241         memset(notifies + notifiesSize, 0, memsetSize);
1242
1243         if (notifies != old) {
1244             for (int ii = 0; ii < notifiesSize; ++ii)
1245                 if (notifies[ii])
1246                     notifies[ii]->prev = &notifies[ii];
1247         }
1248
1249         notifiesSize = maximumTodoIndex + 1;
1250
1251         layout(todo);
1252     }
1253
1254     maximumTodoIndex = 0;
1255     todo = 0;
1256 }
1257
1258 void QQmlData::addNotify(int index, QQmlNotifierEndpoint *endpoint)
1259 {
1260     if (!notifyList) {
1261         notifyList = (NotifyList *)malloc(sizeof(NotifyList));
1262         notifyList->connectionMask = 0;
1263         notifyList->maximumTodoIndex = 0;
1264         notifyList->notifiesSize = 0;
1265         notifyList->todo = 0;
1266         notifyList->notifies = 0;
1267     }
1268
1269     Q_ASSERT(!endpoint->isConnected());
1270
1271     index = qMin(index, 0xFFFF - 1);
1272     notifyList->connectionMask |= (1ULL << quint64(index % 64));
1273
1274     if (index < notifyList->notifiesSize) {
1275
1276         endpoint->next = notifyList->notifies[index];
1277         if (endpoint->next) endpoint->next->prev = &endpoint->next;
1278         endpoint->prev = &notifyList->notifies[index];
1279         notifyList->notifies[index] = endpoint;
1280
1281     } else {
1282         notifyList->maximumTodoIndex = qMax(int(notifyList->maximumTodoIndex), index);
1283
1284         endpoint->next = notifyList->todo;
1285         if (endpoint->next) endpoint->next->prev = &endpoint->next;
1286         endpoint->prev = &notifyList->todo;
1287         notifyList->todo = endpoint;
1288     }
1289 }
1290
1291 bool QQml_isSignalConnected(QObject *obj, int signal_index, int index)
1292 {
1293     QQmlData *data = QQmlData::get(obj);
1294     return QObjectPrivate::get(obj)->isSignalConnected(signal_index) || (data && data->signalHasEndpoint(index));
1295 }
1296
1297 /*
1298     index MUST be the index returned by QMetaMethod::index()
1299     This is different than the index returned by QObjectPrivate::signalIndex()
1300 */
1301 bool QQmlData::signalHasEndpoint(int index)
1302 {
1303     return notifyList && (notifyList->connectionMask & (1ULL << quint64(index % 64)));
1304 }
1305
1306 QHash<int, QObject *> *QQmlData::attachedProperties() const
1307 {
1308     if (!extendedData) extendedData = new QQmlDataExtended;
1309     return &extendedData->attachedProperties;
1310 }
1311
1312 void QQmlData::destroyed(QObject *object)
1313 {
1314     if (nextContextObject)
1315         nextContextObject->prevContextObject = prevContextObject;
1316     if (prevContextObject)
1317         *prevContextObject = nextContextObject;
1318
1319     QQmlAbstractBinding *binding = bindings;
1320     while (binding) {
1321         QQmlAbstractBinding *next = binding->nextBinding();
1322         binding->setAddedToObject(false);
1323         binding->setNextBinding(0);
1324         binding->destroy();
1325         binding = next;
1326     }
1327
1328     if (compiledData) {
1329         compiledData->release();
1330         compiledData = 0;
1331     }
1332
1333     QQmlAbstractBoundSignal *signalHandler = signalHandlers;
1334     while (signalHandler) {
1335         if (signalHandler->isEvaluating()) {
1336             // The object is being deleted during signal handler evaluation.
1337             // This will cause a crash due to invalid memory access when the
1338             // evaluation has completed.
1339             // Abort with a friendly message instead.
1340             QString locationString;
1341             QQmlBoundSignalExpression *expr = signalHandler->expression();
1342             if (expr) {
1343                 QString fileName = expr->sourceFile();
1344                 if (fileName.isEmpty())
1345                     fileName = QStringLiteral("<Unknown File>");
1346                 locationString.append(fileName);
1347                 locationString.append(QString::fromLatin1(":%0: ").arg(expr->lineNumber()));
1348                 QString source = expr->expression();
1349                 if (source.size() > 100) {
1350                     source.truncate(96);
1351                     source.append(QStringLiteral(" ..."));
1352                 }
1353                 locationString.append(source);
1354             } else {
1355                 locationString = QStringLiteral("<Unknown Location>");
1356             }
1357             qFatal("Object %p destroyed while one of its QML signal handlers is in progress.\n"
1358                    "Most likely the object was deleted synchronously (use QObject::deleteLater() "
1359                    "instead), or the application is running a nested event loop.\n"
1360                    "This behavior is NOT supported!\n"
1361                    "%s", object, qPrintable(locationString));
1362         }
1363
1364         QQmlAbstractBoundSignal *next = signalHandler->m_nextSignal;
1365         signalHandler->m_prevSignal = 0;
1366         signalHandler->m_nextSignal = 0;
1367         delete signalHandler;
1368         signalHandler = next;
1369     }
1370
1371     if (bindingBits)
1372         free(bindingBits);
1373
1374     if (propertyCache)
1375         propertyCache->release();
1376
1377     if (ownContext && context)
1378         context->destroy();
1379
1380     while (guards) {
1381         QQmlGuard<QObject> *guard = static_cast<QQmlGuard<QObject> *>(guards);
1382         *guard = (QObject *)0;
1383         guard->objectDestroyed(object);
1384     }
1385
1386     if (notifyList) {
1387         while (notifyList->todo)
1388             notifyList->todo->disconnect();
1389         for (int ii = 0; ii < notifyList->notifiesSize; ++ii) {
1390             while (QQmlNotifierEndpoint *ep = notifyList->notifies[ii])
1391                 ep->disconnect();
1392         }
1393         free(notifyList->notifies);
1394         free(notifyList);
1395         notifyList = 0;
1396     }
1397
1398     if (extendedData)
1399         delete extendedData;
1400
1401     // Dispose the handle.
1402     // We don't simply clear it (and wait for next gc cycle to dispose
1403     // via the weak qobject reference callback) as this affects the
1404     // outcomes of v8's gc statistical analysis heuristics, which can
1405     // cause unnecessary growth of the old pointer space js heap area.
1406     qPersistentDispose(v8object);
1407
1408     if (ownMemory)
1409         delete this;
1410 }
1411
1412 DEFINE_BOOL_CONFIG_OPTION(parentTest, QML_PARENT_TEST);
1413
1414 void QQmlData::parentChanged(QObject *object, QObject *parent)
1415 {
1416     if (parentTest()) {
1417         if (parentFrozen && !QObjectPrivate::get(object)->wasDeleted) {
1418             QString on;
1419             QString pn;
1420
1421             { QDebug dbg(&on); dbg << object; on = on.left(on.length() - 1); }
1422             { QDebug dbg(&pn); dbg << parent; pn = pn.left(pn.length() - 1); }
1423
1424             qFatal("Object %s has had its parent frozen by QML and cannot be changed.\n"
1425                    "User code is attempting to change it to %s.\n"
1426                    "This behavior is NOT supported!", qPrintable(on), qPrintable(pn));
1427         }
1428     }
1429 }
1430
1431 bool QQmlData::hasBindingBit(int bit) const
1432 {
1433     if (bindingBitsSize > bit)
1434         return bindingBits[bit / 32] & (1 << (bit % 32));
1435     else
1436         return false;
1437 }
1438
1439 void QQmlData::clearBindingBit(int bit)
1440 {
1441     if (bindingBitsSize > bit)
1442         bindingBits[bit / 32] &= ~(1 << (bit % 32));
1443 }
1444
1445 void QQmlData::setBindingBit(QObject *obj, int bit)
1446 {
1447     if (bindingBitsSize <= bit) {
1448         int props = QQmlMetaObject(obj).propertyCount();
1449         Q_ASSERT(bit < props);
1450
1451         int arraySize = (props + 31) / 32;
1452         int oldArraySize = bindingBitsSize / 32;
1453
1454         bindingBits = (quint32 *)realloc(bindingBits,
1455                                          arraySize * sizeof(quint32));
1456
1457         memset(bindingBits + oldArraySize,
1458                0x00,
1459                sizeof(quint32) * (arraySize - oldArraySize));
1460
1461         bindingBitsSize = arraySize * 32;
1462     }
1463
1464     bindingBits[bit / 32] |= (1 << (bit % 32));
1465 }
1466
1467 void QQmlEnginePrivate::sendQuit()
1468 {
1469     Q_Q(QQmlEngine);
1470     emit q->quit();
1471     if (q->receivers(SIGNAL(quit())) == 0) {
1472         qWarning("Signal QQmlEngine::quit() emitted, but no receivers connected to handle it.");
1473     }
1474 }
1475
1476 static void dumpwarning(const QQmlError &error)
1477 {
1478     QMessageLogger(error.url().toString().toLatin1().constData(),
1479                    error.line(), 0).warning().nospace()
1480             << qPrintable(error.toString());
1481 }
1482
1483 static void dumpwarning(const QList<QQmlError> &errors)
1484 {
1485     for (int ii = 0; ii < errors.count(); ++ii)
1486         dumpwarning(errors.at(ii));
1487 }
1488
1489 void QQmlEnginePrivate::warning(const QQmlError &error)
1490 {
1491     Q_Q(QQmlEngine);
1492     q->warnings(QList<QQmlError>() << error);
1493     if (outputWarningsToStdErr)
1494         dumpwarning(error);
1495 }
1496
1497 void QQmlEnginePrivate::warning(const QList<QQmlError> &errors)
1498 {
1499     Q_Q(QQmlEngine);
1500     q->warnings(errors);
1501     if (outputWarningsToStdErr)
1502         dumpwarning(errors);
1503 }
1504
1505 void QQmlEnginePrivate::warning(QQmlDelayedError *error)
1506 {
1507     Q_Q(QQmlEngine);
1508     warning(error->error(q));
1509 }
1510
1511 void QQmlEnginePrivate::warning(QQmlEngine *engine, const QQmlError &error)
1512 {
1513     if (engine)
1514         QQmlEnginePrivate::get(engine)->warning(error);
1515     else
1516         dumpwarning(error);
1517 }
1518
1519 void QQmlEnginePrivate::warning(QQmlEngine *engine, const QList<QQmlError> &error)
1520 {
1521     if (engine)
1522         QQmlEnginePrivate::get(engine)->warning(error);
1523     else
1524         dumpwarning(error);
1525 }
1526
1527 void QQmlEnginePrivate::warning(QQmlEngine *engine, QQmlDelayedError *error)
1528 {
1529     if (engine)
1530         QQmlEnginePrivate::get(engine)->warning(error);
1531     else
1532         dumpwarning(error->error(0));
1533 }
1534
1535 void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QQmlError &error)
1536 {
1537     if (engine)
1538         engine->warning(error);
1539     else
1540         dumpwarning(error);
1541 }
1542
1543 void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QList<QQmlError> &error)
1544 {
1545     if (engine)
1546         engine->warning(error);
1547     else
1548         dumpwarning(error);
1549 }
1550
1551 /*
1552    This function should be called prior to evaluation of any js expression,
1553    so that scarce resources are not freed prematurely (eg, if there is a
1554    nested javascript expression).
1555  */
1556 void QQmlEnginePrivate::referenceScarceResources()
1557 {
1558     scarceResourcesRefCount += 1;
1559 }
1560
1561 /*
1562    This function should be called after evaluation of the js expression is
1563    complete, and so the scarce resources may be freed safely.
1564  */
1565 void QQmlEnginePrivate::dereferenceScarceResources()
1566 {
1567     Q_ASSERT(scarceResourcesRefCount > 0);
1568     scarceResourcesRefCount -= 1;
1569
1570     // if the refcount is zero, then evaluation of the "top level"
1571     // expression must have completed.  We can safely release the
1572     // scarce resources.
1573     if (scarceResourcesRefCount == 0) {
1574         // iterate through the list and release them all.
1575         // note that the actual SRD is owned by the JS engine,
1576         // so we cannot delete the SRD; but we can free the
1577         // memory used by the variant in the SRD.
1578         while (ScarceResourceData *sr = scarceResources.first()) {
1579             sr->data = QVariant();
1580             scarceResources.remove(sr);
1581         }
1582     }
1583 }
1584
1585 /*!
1586   Adds \a path as a directory where the engine searches for
1587   installed modules in a URL-based directory structure.
1588   The \a path may be a local filesystem directory or a URL.
1589
1590   The newly added \a path will be first in the importPathList().
1591
1592   \sa setImportPathList(), {QML Modules}
1593 */
1594 void QQmlEngine::addImportPath(const QString& path)
1595 {
1596     Q_D(QQmlEngine);
1597     d->importDatabase.addImportPath(path);
1598 }
1599
1600 /*!
1601   Returns the list of directories where the engine searches for
1602   installed modules in a URL-based directory structure.
1603
1604   For example, if \c /opt/MyApp/lib/imports is in the path, then QML that
1605   imports \c com.mycompany.Feature will cause the QQmlEngine to look
1606   in \c /opt/MyApp/lib/imports/com/mycompany/Feature/ for the components
1607   provided by that module. A \c qmldir file is required for defining the
1608   type version mapping and possibly QML extensions plugins.
1609
1610   By default, the list contains the directory of the application executable,
1611   paths specified in the \c QML_IMPORT_PATH environment variable,
1612   and the builtin \c ImportsPath from QLibraryInfo.
1613
1614   \sa addImportPath(), setImportPathList()
1615 */
1616 QStringList QQmlEngine::importPathList() const
1617 {
1618     Q_D(const QQmlEngine);
1619     return d->importDatabase.importPathList();
1620 }
1621
1622 /*!
1623   Sets \a paths as the list of directories where the engine searches for
1624   installed modules in a URL-based directory structure.
1625
1626   By default, the list contains the directory of the application executable,
1627   paths specified in the \c QML_IMPORT_PATH environment variable,
1628   and the builtin \c ImportsPath from QLibraryInfo.
1629
1630   \sa importPathList(), addImportPath()
1631   */
1632 void QQmlEngine::setImportPathList(const QStringList &paths)
1633 {
1634     Q_D(QQmlEngine);
1635     d->importDatabase.setImportPathList(paths);
1636 }
1637
1638
1639 /*!
1640   Adds \a path as a directory where the engine searches for
1641   native plugins for imported modules (referenced in the \c qmldir file).
1642
1643   By default, the list contains only \c .,  i.e. the engine searches
1644   in the directory of the \c qmldir file itself.
1645
1646   The newly added \a path will be first in the pluginPathList().
1647
1648   \sa setPluginPathList()
1649 */
1650 void QQmlEngine::addPluginPath(const QString& path)
1651 {
1652     Q_D(QQmlEngine);
1653     d->importDatabase.addPluginPath(path);
1654 }
1655
1656
1657 /*!
1658   Returns the list of directories where the engine searches for
1659   native plugins for imported modules (referenced in the \c qmldir file).
1660
1661   By default, the list contains only \c .,  i.e. the engine searches
1662   in the directory of the \c qmldir file itself.
1663
1664   \sa addPluginPath(), setPluginPathList()
1665 */
1666 QStringList QQmlEngine::pluginPathList() const
1667 {
1668     Q_D(const QQmlEngine);
1669     return d->importDatabase.pluginPathList();
1670 }
1671
1672 /*!
1673   Sets the list of directories where the engine searches for
1674   native plugins for imported modules (referenced in the \c qmldir file)
1675   to \a paths.
1676
1677   By default, the list contains only \c .,  i.e. the engine searches
1678   in the directory of the \c qmldir file itself.
1679
1680   \sa pluginPathList(), addPluginPath()
1681   */
1682 void QQmlEngine::setPluginPathList(const QStringList &paths)
1683 {
1684     Q_D(QQmlEngine);
1685     d->importDatabase.setPluginPathList(paths);
1686 }
1687
1688 /*!
1689   Imports the plugin named \a filePath with the \a uri provided.
1690   Returns true if the plugin was successfully imported; otherwise returns false.
1691
1692   On failure and if non-null, the \a errors list will have any errors which occurred prepended to it.
1693
1694   The plugin has to be a Qt plugin which implements the QQmlExtensionPlugin interface.
1695 */
1696 bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors)
1697 {
1698     Q_D(QQmlEngine);
1699     return d->importDatabase.importPlugin(filePath, uri, errors);
1700 }
1701
1702 /*!
1703   \property QQmlEngine::offlineStoragePath
1704   \brief the directory for storing offline user data
1705
1706   Returns the directory where SQL and other offline
1707   storage is placed.
1708
1709   QQuickWebView and the SQL databases created with openDatabase()
1710   are stored here.
1711
1712   The default is QML/OfflineStorage in the platform-standard
1713   user application data directory.
1714
1715   Note that the path may not currently exist on the filesystem, so
1716   callers wanting to \e create new files at this location should create
1717   it first - see QDir::mkpath().
1718 */
1719 void QQmlEngine::setOfflineStoragePath(const QString& dir)
1720 {
1721     Q_D(QQmlEngine);
1722     d->offlineStoragePath = dir;
1723 }
1724
1725 QString QQmlEngine::offlineStoragePath() const
1726 {
1727     Q_D(const QQmlEngine);
1728     return d->offlineStoragePath;
1729 }
1730
1731 QQmlPropertyCache *QQmlEnginePrivate::createCache(const QMetaObject *mo)
1732 {
1733     Q_Q(QQmlEngine);
1734
1735     if (!mo->superClass()) {
1736         QQmlPropertyCache *rv = new QQmlPropertyCache(q, mo);
1737         propertyCache.insert(mo, rv);
1738         return rv;
1739     } else {
1740         QQmlPropertyCache *super = cache(mo->superClass());
1741         QQmlPropertyCache *rv = super->copyAndAppend(q, mo);
1742         propertyCache.insert(mo, rv);
1743         return rv;
1744     }
1745 }
1746
1747 QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersion,
1748                                                                   QQmlError &error)
1749 {
1750     QList<QQmlType *> types;
1751
1752     int maxMinorVersion = 0;
1753
1754     const QMetaObject *metaObject = type->metaObject();
1755
1756     while (metaObject) {
1757         QQmlType *t = QQmlMetaType::qmlType(metaObject, type->module(),
1758                                                             type->majorVersion(), minorVersion);
1759         if (t) {
1760             maxMinorVersion = qMax(maxMinorVersion, t->minorVersion());
1761             types << t;
1762         } else {
1763             types << 0;
1764         }
1765
1766         metaObject = metaObject->superClass();
1767     }
1768
1769     if (QQmlPropertyCache *c = typePropertyCache.value(qMakePair(type, maxMinorVersion))) {
1770         c->addref();
1771         typePropertyCache.insert(qMakePair(type, minorVersion), c);
1772         return c;
1773     }
1774
1775     QQmlPropertyCache *raw = cache(type->metaObject());
1776
1777     bool hasCopied = false;
1778
1779     for (int ii = 0; ii < types.count(); ++ii) {
1780         QQmlType *currentType = types.at(ii);
1781         if (!currentType)
1782             continue;
1783
1784         int rev = currentType->metaObjectRevision();
1785         int moIndex = types.count() - 1 - ii;
1786
1787         if (raw->allowedRevisionCache[moIndex] != rev) {
1788             if (!hasCopied) {
1789                 raw = raw->copy();
1790                 hasCopied = true;
1791             }
1792             raw->allowedRevisionCache[moIndex] = rev;
1793         }
1794     }
1795
1796     // Test revision compatibility - the basic rule is:
1797     //    * Anything that is excluded, cannot overload something that is not excluded *
1798
1799     // Signals override:
1800     //    * other signals and methods of the same name.
1801     //    * properties named on<Signal Name>
1802     //    * automatic <property name>Changed notify signals
1803
1804     // Methods override:
1805     //    * other methods of the same name
1806
1807     // Properties override:
1808     //    * other elements of the same name
1809
1810     bool overloadError = false;
1811     QString overloadName;
1812
1813 #if 0
1814     for (QQmlPropertyCache::StringCache::ConstIterator iter = raw->stringCache.begin();
1815          !overloadError && iter != raw->stringCache.end();
1816          ++iter) {
1817
1818         QQmlPropertyData *d = *iter;
1819         if (raw->isAllowedInRevision(d))
1820             continue; // Not excluded - no problems
1821
1822         // check that a regular "name" overload isn't happening
1823         QQmlPropertyData *current = d;
1824         while (!overloadError && current) {
1825             current = d->overrideData(current);
1826             if (current && raw->isAllowedInRevision(current))
1827                 overloadError = true;
1828         }
1829     }
1830 #endif
1831
1832     if (overloadError) {
1833         if (hasCopied) raw->release();
1834
1835         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."));
1836         return 0;
1837     }
1838
1839     if (!hasCopied) raw->addref();
1840     typePropertyCache.insert(qMakePair(type, minorVersion), raw);
1841
1842     if (minorVersion != maxMinorVersion) {
1843         raw->addref();
1844         typePropertyCache.insert(qMakePair(type, maxMinorVersion), raw);
1845     }
1846
1847     return raw;
1848 }
1849
1850 QQmlMetaType::ModuleApiInstance *
1851 QQmlEnginePrivate::moduleApiInstance(const QQmlMetaType::ModuleApi &module)
1852 {
1853     Locker locker(this);
1854
1855     QQmlMetaType::ModuleApiInstance *a = moduleApiInstances.value(module);
1856     if (!a) {
1857         a = new QQmlMetaType::ModuleApiInstance;
1858         a->scriptCallback = module.script;
1859         a->qobjectCallback = module.qobject;
1860         a->instanceMetaObject = module.instanceMetaObject;
1861         moduleApiInstances.insert(module, a);
1862     }
1863
1864     return a;
1865 }
1866
1867 bool QQmlEnginePrivate::isQObject(int t)
1868 {
1869     Locker locker(this);
1870     return m_compositeTypes.contains(t) || QQmlMetaType::isQObject(t);
1871 }
1872
1873 QObject *QQmlEnginePrivate::toQObject(const QVariant &v, bool *ok) const
1874 {
1875     Locker locker(this);
1876     int t = v.userType();
1877     if (t == QMetaType::QObjectStar || m_compositeTypes.contains(t)) {
1878         if (ok) *ok = true;
1879         return *(QObject **)(v.constData());
1880     } else {
1881         return QQmlMetaType::toQObject(v, ok);
1882     }
1883 }
1884
1885 QQmlMetaType::TypeCategory QQmlEnginePrivate::typeCategory(int t) const
1886 {
1887     Locker locker(this);
1888     if (m_compositeTypes.contains(t))
1889         return QQmlMetaType::Object;
1890     else if (m_qmlLists.contains(t))
1891         return QQmlMetaType::List;
1892     else
1893         return QQmlMetaType::typeCategory(t);
1894 }
1895
1896 bool QQmlEnginePrivate::isList(int t) const
1897 {
1898     Locker locker(this);
1899     return m_qmlLists.contains(t) || QQmlMetaType::isList(t);
1900 }
1901
1902 int QQmlEnginePrivate::listType(int t) const
1903 {
1904     Locker locker(this);
1905     QHash<int, int>::ConstIterator iter = m_qmlLists.find(t);
1906     if (iter != m_qmlLists.end())
1907         return *iter;
1908     else
1909         return QQmlMetaType::listType(t);
1910 }
1911
1912 QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const
1913 {
1914     Locker locker(this);
1915     QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.find(t);
1916     if (iter != m_compositeTypes.end()) {
1917         return QQmlMetaObject((*iter)->rootPropertyCache);
1918     } else {
1919         QQmlType *type = QQmlMetaType::qmlType(t);
1920         return QQmlMetaObject(type?type->baseMetaObject():0);
1921     }
1922 }
1923
1924 QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const
1925 {
1926     Locker locker(this);
1927     QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.find(t);
1928     if (iter != m_compositeTypes.end()) {
1929         return QQmlMetaObject((*iter)->rootPropertyCache);
1930     } else {
1931         QQmlType *type = QQmlMetaType::qmlType(t);
1932         return QQmlMetaObject(type?type->metaObject():0);
1933     }
1934 }
1935
1936 QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t)
1937 {
1938     Locker locker(this);
1939     QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.find(t);
1940     if (iter != m_compositeTypes.end()) {
1941         return (*iter)->rootPropertyCache;
1942     } else {
1943         QQmlType *type = QQmlMetaType::qmlType(t);
1944         locker.unlock();
1945         return type?cache(type->metaObject()):0;
1946     }
1947 }
1948
1949 QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t)
1950 {
1951     Locker locker(this);
1952     QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.find(t);
1953     if (iter != m_compositeTypes.end()) {
1954         return (*iter)->rootPropertyCache;
1955     } else {
1956         QQmlType *type = QQmlMetaType::qmlType(t);
1957         locker.unlock();
1958         return type?cache(type->baseMetaObject()):0;
1959     }
1960 }
1961
1962 void QQmlEnginePrivate::registerCompositeType(QQmlCompiledData *data)
1963 {
1964     QByteArray name = data->rootPropertyCache->className();
1965
1966     QByteArray ptr = name + '*';
1967     QByteArray lst = "QQmlListProperty<" + name + '>';
1968
1969     int ptr_type = QMetaType::registerNormalizedType(ptr,
1970                                                      qMetaTypeDeleteHelper<QObject*>,
1971                                                      qMetaTypeCreateHelper<QObject*>,
1972                                                      qMetaTypeDestructHelper<QObject*>,
1973                                                      qMetaTypeConstructHelper<QObject*>,
1974                                                      sizeof(QObject*),
1975                                                      static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QObject*>::Flags),
1976                                                      0);
1977     int lst_type = QMetaType::registerNormalizedType(lst,
1978                                                      qMetaTypeDeleteHelper<QQmlListProperty<QObject> >,
1979                                                      qMetaTypeCreateHelper<QQmlListProperty<QObject> >,
1980                                                      qMetaTypeDestructHelper<QQmlListProperty<QObject> >,
1981                                                      qMetaTypeConstructHelper<QQmlListProperty<QObject> >,
1982                                                      sizeof(QQmlListProperty<QObject>),
1983                                                      static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QQmlListProperty<QObject> >::Flags),
1984                                                      static_cast<QMetaObject*>(0));
1985
1986     data->metaTypeId = ptr_type;
1987     data->listMetaTypeId = lst_type;
1988     data->isRegisteredWithEngine = true;
1989
1990     Locker locker(this);
1991     m_qmlLists.insert(lst_type, ptr_type);
1992     // The QQmlCompiledData is not referenced here, but it is removed from this
1993     // hash in the QQmlCompiledData destructor
1994     m_compositeTypes.insert(ptr_type, data);
1995 }
1996
1997 void QQmlEnginePrivate::unregisterCompositeType(QQmlCompiledData *data)
1998 {
1999     int ptr_type = data->metaTypeId;
2000     int lst_type = data->listMetaTypeId;
2001
2002     Locker locker(this);
2003     m_qmlLists.remove(lst_type);
2004     m_compositeTypes.remove(ptr_type);
2005 }
2006
2007 bool QQmlEnginePrivate::isTypeLoaded(const QUrl &url) const
2008 {
2009     return typeLoader.isTypeLoaded(url);
2010 }
2011
2012 bool QQmlEnginePrivate::isScriptLoaded(const QUrl &url) const
2013 {
2014     return typeLoader.isScriptLoaded(url);
2015 }
2016
2017 bool QQml_isFileCaseCorrect(const QString &fileName)
2018 {
2019 #if defined(Q_OS_MAC) || defined(Q_OS_WIN)
2020     QFileInfo info(fileName);
2021     const QString absolute = info.absoluteFilePath();
2022
2023 #if defined(Q_OS_MAC)
2024     const QString canonical = info.canonicalFilePath();
2025 #elif defined(Q_OS_WIN)
2026     wchar_t buffer[1024];
2027
2028     DWORD rv = ::GetShortPathName((wchar_t*)absolute.utf16(), buffer, 1024);
2029     if (rv == 0 || rv >= 1024) return true;
2030     rv = ::GetLongPathName(buffer, buffer, 1024);
2031     if (rv == 0 || rv >= 1024) return true;
2032
2033     const QString canonical = QString::fromWCharArray(buffer);
2034 #endif
2035
2036     const int absoluteLength = absolute.length();
2037     const int canonicalLength = canonical.length();
2038
2039     const int length = qMin(absoluteLength, canonicalLength);
2040     for (int ii = 0; ii < length; ++ii) {
2041         const QChar &a = absolute.at(absoluteLength - 1 - ii);
2042         const QChar &c = canonical.at(canonicalLength - 1 - ii);
2043
2044         if (a.toLower() != c.toLower())
2045             return true;
2046         if (a != c)
2047             return false;
2048     }
2049 #else
2050     Q_UNUSED(fileName)
2051 #endif
2052     return true;
2053 }
2054
2055 /*!
2056     \fn QQmlEngine *qmlEngine(const QObject *object)
2057     \relates QQmlEngine
2058
2059     Returns the QQmlEngine associated with \a object, if any.  This is equivalent to
2060     QQmlEngine::contextForObject(object)->engine(), but more efficient.
2061 */
2062
2063 /*!
2064     \fn QQmlContext *qmlContext(const QObject *object)
2065     \relates QQmlEngine
2066
2067     Returns the QQmlContext associated with \a object, if any.  This is equivalent to
2068     QQmlEngine::contextForObject(object).
2069 */
2070
2071 QT_END_NAMESPACE