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