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