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