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