Set ptr to zero after freeing memory
[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         QQmlData::init();
480         firstTime = false;
481     }
482
483     qRegisterMetaType<QVariant>("QVariant");
484     qRegisterMetaType<QQmlScriptString>("QQmlScriptString");
485     qRegisterMetaType<QJSValue>("QJSValue");
486     qRegisterMetaType<QQmlComponent::Status>("QQmlComponent::Status");
487     qRegisterMetaType<QList<QObject*> >("QList<QObject*>");
488     qRegisterMetaType<QList<int> >("QList<int>");
489     qRegisterMetaType<QQmlV8Handle>("QQmlV8Handle");
490
491     v8engine()->setEngine(q);
492
493     rootContext = new QQmlContext(q,true);
494
495     if (QCoreApplication::instance()->thread() == q->thread() &&
496         QQmlEngineDebugService::isDebuggingEnabled()) {
497         isDebugging = true;
498         QQmlEngineDebugService::instance()->addEngine(q);
499         QV8DebugService::initialize(v8engine());
500         QV8ProfilerService::initialize();
501         QQmlProfilerService::initialize();
502         QDebugMessageService::instance();
503     }
504
505     QString dataLocation = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
506     if (!dataLocation.isEmpty())
507         offlineStoragePath = dataLocation.replace(QLatin1Char('/'), QDir::separator())
508                            + QDir::separator() + QLatin1String("QML")
509                            + QDir::separator() + QLatin1String("OfflineStorage");
510 }
511
512 QQuickWorkerScriptEngine *QQmlEnginePrivate::getWorkerScriptEngine()
513 {
514     Q_Q(QQmlEngine);
515     if (!workerScriptEngine)
516         workerScriptEngine = new QQuickWorkerScriptEngine(q);
517     return workerScriptEngine;
518 }
519
520 /*!
521   \class QQmlEngine
522   \since 5.0
523   \inmodule QtQml
524   \brief The QQmlEngine class provides an environment for instantiating QML components.
525   \mainclass
526
527   Each QML component is instantiated in a QQmlContext.
528   QQmlContext's are essential for passing data to QML
529   components.  In QML, contexts are arranged hierarchically and this
530   hierarchy is managed by the QQmlEngine.
531
532   Prior to creating any QML components, an application must have
533   created a QQmlEngine to gain access to a QML context.  The
534   following example shows how to create a simple Text item.
535
536   \code
537   QQmlEngine engine;
538   QQmlComponent component(&engine);
539   component.setData("import QtQuick 2.0\nText { text: \"Hello world!\" }", QUrl());
540   QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
541
542   //add item to view, etc
543   ...
544   \endcode
545
546   In this case, the Text item will be created in the engine's
547   \l {QQmlEngine::rootContext()}{root context}.
548
549   Note that the QtQuick 1 version is called QDeclarativeEngine.
550
551   \sa QQmlComponent, QQmlContext
552 */
553
554 /*!
555   Create a new QQmlEngine with the given \a parent.
556 */
557 QQmlEngine::QQmlEngine(QObject *parent)
558 : QJSEngine(*new QQmlEnginePrivate(this), parent)
559 {
560     Q_D(QQmlEngine);
561     d->init();
562 }
563
564 /*!
565   Destroys the QQmlEngine.
566
567   Any QQmlContext's created on this engine will be
568   invalidated, but not destroyed (unless they are parented to the
569   QQmlEngine object).
570 */
571 QQmlEngine::~QQmlEngine()
572 {
573     Q_D(QQmlEngine);
574     if (d->isDebugging) {
575         QQmlEngineDebugService::instance()->remEngine(this);
576     }
577
578     // if we are the parent of any of the qobject module api instances,
579     // we need to remove them from our internal list, in order to prevent
580     // a segfault in engine private dtor.
581     QList<QQmlMetaType::ModuleApi> keys = d->moduleApiInstances.keys();
582     QObject *currQObjectApi = 0;
583     QQmlMetaType::ModuleApiInstance *currInstance = 0;
584     foreach (const QQmlMetaType::ModuleApi &key, keys) {
585         currInstance = d->moduleApiInstances.value(key);
586         currQObjectApi = currInstance->qobjectApi;
587         if (this->children().contains(currQObjectApi)) {
588             delete currQObjectApi;
589             delete currInstance;
590             d->moduleApiInstances.remove(key);
591         }
592     }
593
594     if (d->incubationController)
595         d->incubationController->d = 0;
596 }
597
598 /*! \fn void QQmlEngine::quit()
599     This signal is emitted when the QML loaded by the engine would like to quit.
600  */
601
602 /*! \fn void QQmlEngine::warnings(const QList<QQmlError> &warnings)
603     This signal is emitted when \a warnings messages are generated by QML.
604  */
605
606 /*!
607   Clears the engine's internal component cache.
608
609   This function causes the property metadata of all components previously
610   loaded by the engine to be destroyed.  All previously loaded components and
611   the property bindings for all extant objects created from those components will
612   cease to function.
613
614   This function returns the engine to a state where it does not contain any loaded
615   component data.  This may be useful in order to reload a smaller subset of the
616   previous component set, or to load a new version of a previously loaded component.
617
618   Once the component cache has been cleared, components must be loaded before
619   any new objects can be created.
620  */
621 void QQmlEngine::clearComponentCache()
622 {
623     Q_D(QQmlEngine);
624     d->typeLoader.clearCache();
625 }
626
627 /*!
628   Returns the engine's root context.
629
630   The root context is automatically created by the QQmlEngine.
631   Data that should be available to all QML component instances
632   instantiated by the engine should be put in the root context.
633
634   Additional data that should only be available to a subset of
635   component instances should be added to sub-contexts parented to the
636   root context.
637 */
638 QQmlContext *QQmlEngine::rootContext() const
639 {
640     Q_D(const QQmlEngine);
641     return d->rootContext;
642 }
643
644 /*!
645   Sets the \a factory to use for creating QNetworkAccessManager(s).
646
647   QNetworkAccessManager is used for all network access by QML.  By
648   implementing a factory it is possible to create custom
649   QNetworkAccessManager with specialized caching, proxy and cookie
650   support.
651
652   The factory must be set before executing the engine.
653 */
654 void QQmlEngine::setNetworkAccessManagerFactory(QQmlNetworkAccessManagerFactory *factory)
655 {
656     Q_D(QQmlEngine);
657     QMutexLocker locker(&d->mutex);
658     d->networkAccessManagerFactory = factory;
659 }
660
661 /*!
662   Returns the current QQmlNetworkAccessManagerFactory.
663
664   \sa setNetworkAccessManagerFactory()
665 */
666 QQmlNetworkAccessManagerFactory *QQmlEngine::networkAccessManagerFactory() const
667 {
668     Q_D(const QQmlEngine);
669     return d->networkAccessManagerFactory;
670 }
671
672 void QQmlEnginePrivate::registerFinalizeCallback(QObject *obj, int index)
673 {
674     if (activeVME) {
675         activeVME->finalizeCallbacks.append(qMakePair(QQmlGuard<QObject>(obj), index));
676     } else {
677         void *args[] = { 0 };
678         QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, index, args);
679     }
680 }
681
682 QNetworkAccessManager *QQmlEnginePrivate::createNetworkAccessManager(QObject *parent) const
683 {
684     QMutexLocker locker(&mutex);
685     QNetworkAccessManager *nam;
686     if (networkAccessManagerFactory) {
687         nam = networkAccessManagerFactory->create(parent);
688     } else {
689         nam = new QNetworkAccessManager(parent);
690     }
691
692     return nam;
693 }
694
695 QNetworkAccessManager *QQmlEnginePrivate::getNetworkAccessManager() const
696 {
697     Q_Q(const QQmlEngine);
698     if (!networkAccessManager)
699         networkAccessManager = createNetworkAccessManager(const_cast<QQmlEngine*>(q));
700     return networkAccessManager;
701 }
702
703 /*!
704   Returns a common QNetworkAccessManager which can be used by any QML
705   element instantiated by this engine.
706
707   If a QQmlNetworkAccessManagerFactory has been set and a
708   QNetworkAccessManager has not yet been created, the
709   QQmlNetworkAccessManagerFactory will be used to create the
710   QNetworkAccessManager; otherwise the returned QNetworkAccessManager
711   will have no proxy or cache set.
712
713   \sa setNetworkAccessManagerFactory()
714 */
715 QNetworkAccessManager *QQmlEngine::networkAccessManager() const
716 {
717     Q_D(const QQmlEngine);
718     return d->getNetworkAccessManager();
719 }
720
721 /*!
722
723   Sets the \a provider to use for images requested via the \e
724   image: url scheme, with host \a providerId. The QQmlEngine
725   takes ownership of \a provider.
726
727   Image providers enable support for pixmap and threaded image
728   requests. See the QQuickImageProvider documentation for details on
729   implementing and using image providers.
730
731   All required image providers should be added to the engine before any
732   QML sources files are loaded.
733
734   \sa removeImageProvider(), QQuickImageProvider, QQmlImageProviderBase
735 */
736 void QQmlEngine::addImageProvider(const QString &providerId, QQmlImageProviderBase *provider)
737 {
738     Q_D(QQmlEngine);
739     QMutexLocker locker(&d->mutex);
740     d->imageProviders.insert(providerId.toLower(), QSharedPointer<QQmlImageProviderBase>(provider));
741 }
742
743 /*!
744   Returns the image provider set for \a providerId.
745
746   Returns the provider if it was found; otherwise returns 0.
747
748   \sa QQuickImageProvider
749 */
750 QQmlImageProviderBase *QQmlEngine::imageProvider(const QString &providerId) const
751 {
752     Q_D(const QQmlEngine);
753     QMutexLocker locker(&d->mutex);
754     return d->imageProviders.value(providerId).data();
755 }
756
757 /*!
758   Removes the image provider for \a providerId.
759
760   \sa addImageProvider(), QQuickImageProvider
761 */
762 void QQmlEngine::removeImageProvider(const QString &providerId)
763 {
764     Q_D(QQmlEngine);
765     QMutexLocker locker(&d->mutex);
766     d->imageProviders.take(providerId);
767 }
768
769 /*!
770   Return the base URL for this engine.  The base URL is only used to
771   resolve components when a relative URL is passed to the
772   QQmlComponent constructor.
773
774   If a base URL has not been explicitly set, this method returns the
775   application's current working directory.
776
777   \sa setBaseUrl()
778 */
779 QUrl QQmlEngine::baseUrl() const
780 {
781     Q_D(const QQmlEngine);
782     if (d->baseUrl.isEmpty()) {
783         return QUrl::fromLocalFile(QDir::currentPath() + QDir::separator());
784     } else {
785         return d->baseUrl;
786     }
787 }
788
789 /*!
790   Set the  base URL for this engine to \a url.
791
792   \sa baseUrl()
793 */
794 void QQmlEngine::setBaseUrl(const QUrl &url)
795 {
796     Q_D(QQmlEngine);
797     d->baseUrl = url;
798 }
799
800 /*!
801   Returns true if warning messages will be output to stderr in addition
802   to being emitted by the warnings() signal, otherwise false.
803
804   The default value is true.
805 */
806 bool QQmlEngine::outputWarningsToStandardError() const
807 {
808     Q_D(const QQmlEngine);
809     return d->outputWarningsToStdErr;
810 }
811
812 /*!
813   Set whether warning messages will be output to stderr to \a enabled.
814
815   If \a enabled is true, any warning messages generated by QML will be
816   output to stderr and emitted by the warnings() signal.  If \a enabled
817   is false, on the warnings() signal will be emitted.  This allows
818   applications to handle warning output themselves.
819
820   The default value is true.
821 */
822 void QQmlEngine::setOutputWarningsToStandardError(bool enabled)
823 {
824     Q_D(QQmlEngine);
825     d->outputWarningsToStdErr = enabled;
826 }
827
828 /*!
829   Attempt to free unused memory.
830 */
831 void QQmlEngine::collectGarbage()
832 {
833     QV8Engine::gc();
834 }
835
836 /*!
837   Returns the QQmlContext for the \a object, or 0 if no
838   context has been set.
839
840   When the QQmlEngine instantiates a QObject, the context is
841   set automatically.
842   */
843 QQmlContext *QQmlEngine::contextForObject(const QObject *object)
844 {
845     if(!object)
846         return 0;
847
848     QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object));
849
850     QQmlData *data =
851         static_cast<QQmlData *>(priv->declarativeData);
852
853     if (!data)
854         return 0;
855     else if (data->outerContext)
856         return data->outerContext->asQQmlContext();
857     else
858         return 0;
859 }
860
861 /*!
862   Sets the QQmlContext for the \a object to \a context.
863   If the \a object already has a context, a warning is
864   output, but the context is not changed.
865
866   When the QQmlEngine instantiates a QObject, the context is
867   set automatically.
868  */
869 void QQmlEngine::setContextForObject(QObject *object, QQmlContext *context)
870 {
871     if (!object || !context)
872         return;
873
874     QQmlData *data = QQmlData::get(object, true);
875     if (data->context) {
876         qWarning("QQmlEngine::setContextForObject(): Object already has a QQmlContext");
877         return;
878     }
879
880     QQmlContextData *contextData = QQmlContextData::get(context);
881     contextData->addObject(object);
882 }
883
884 /*!
885   \enum QQmlEngine::ObjectOwnership
886
887   Ownership controls whether or not QML automatically destroys the
888   QObject when the object is garbage collected by the JavaScript
889   engine.  The two ownership options are:
890
891   \value CppOwnership The object is owned by C++ code, and will
892   never be deleted by QML.  The JavaScript destroy() method cannot be
893   used on objects with CppOwnership.  This option is similar to
894   QScriptEngine::QtOwnership.
895
896   \value JavaScriptOwnership The object is owned by JavaScript.
897   When the object is returned to QML as the return value of a method
898   call or property access, QML will track it, and delete the object
899   if there are no remaining JavaScript references to it and it has no
900   QObject::parent().  An object tracked by one QQmlEngine
901   will be deleted during that QQmlEngine's destructor, and thus
902   JavaScript references between objects with JavaScriptOwnership from
903   two different engines will not be valid after the deletion of one of
904   those engines.  This option is similar to QScriptEngine::ScriptOwnership.
905
906   Generally an application doesn't need to set an object's ownership
907   explicitly.  QML uses a heuristic to set the default object
908   ownership.  By default, an object that is created by QML has
909   JavaScriptOwnership.  The exception to this are the root objects
910   created by calling QQmlComponent::create() or
911   QQmlComponent::beginCreate() which have CppOwnership by
912   default.  The ownership of these root-level objects is considered to
913   have been transferred to the C++ caller.
914
915   Objects not-created by QML have CppOwnership by default.  The
916   exception to this is objects returned from a C++ method call.  The
917   ownership of these objects is passed to JavaScript.
918
919   Calling setObjectOwnership() overrides the default ownership
920   heuristic used by QML.
921 */
922
923 /*!
924   Sets the \a ownership of \a object.
925 */
926 void QQmlEngine::setObjectOwnership(QObject *object, ObjectOwnership ownership)
927 {
928     if (!object)
929         return;
930
931     QQmlData *ddata = QQmlData::get(object, true);
932     if (!ddata)
933         return;
934
935     ddata->indestructible = (ownership == CppOwnership)?true:false;
936     ddata->explicitIndestructibleSet = true;
937 }
938
939 /*!
940   Returns the ownership of \a object.
941 */
942 QQmlEngine::ObjectOwnership QQmlEngine::objectOwnership(QObject *object)
943 {
944     if (!object)
945         return CppOwnership;
946
947     QQmlData *ddata = QQmlData::get(object, false);
948     if (!ddata)
949         return CppOwnership;
950     else
951         return ddata->indestructible?CppOwnership:JavaScriptOwnership;
952 }
953
954 bool QQmlEngine::event(QEvent *e)
955 {
956     Q_D(QQmlEngine);
957     if (e->type() == QEvent::User)
958         d->doDeleteInEngineThread();
959
960     return QJSEngine::event(e);
961 }
962
963 void QQmlEnginePrivate::doDeleteInEngineThread()
964 {
965     QFieldList<Deletable, &Deletable::next> list;
966     mutex.lock();
967     list.copyAndClear(toDeleteInEngineThread);
968     mutex.unlock();
969
970     while (Deletable *d = list.takeFirst())
971         delete d;
972 }
973
974 Q_AUTOTEST_EXPORT void qmlExecuteDeferred(QObject *object)
975 {
976     QQmlData *data = QQmlData::get(object);
977
978     if (data && data->deferredComponent) {
979         QQmlObjectCreatingProfiler prof;
980         if (prof.enabled) {
981             QQmlType *type = QQmlMetaType::qmlType(object->metaObject());
982             prof.setTypeName(type ? type->qmlTypeName()
983                                   : QString::fromUtf8(object->metaObject()->className()));
984             if (data->outerContext)
985                 prof.setLocation(data->outerContext->url, data->lineNumber, data->columnNumber);
986         }
987         QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine);
988
989         QQmlComponentPrivate::ConstructionState state;
990         QQmlComponentPrivate::beginDeferred(ep, object, &state);
991
992         data->deferredComponent->release();
993         data->deferredComponent = 0;
994
995         QQmlComponentPrivate::complete(ep, &state);
996     }
997 }
998
999 QQmlContext *qmlContext(const QObject *obj)
1000 {
1001     return QQmlEngine::contextForObject(obj);
1002 }
1003
1004 QQmlEngine *qmlEngine(const QObject *obj)
1005 {
1006     QQmlData *data = QQmlData::get(obj, false);
1007     if (!data || !data->context)
1008         return 0;
1009     return data->context->engine;
1010 }
1011
1012 QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create)
1013 {
1014     QQmlData *data = QQmlData::get(object);
1015     if (!data)
1016         return 0; // Attached properties are only on objects created by QML
1017
1018     QObject *rv = data->hasExtendedData()?data->attachedProperties()->value(id):0;
1019     if (rv || !create)
1020         return rv;
1021
1022     QQmlAttachedPropertiesFunc pf = QQmlMetaType::attachedPropertiesFuncById(id);
1023     if (!pf)
1024         return 0;
1025
1026     rv = pf(const_cast<QObject *>(object));
1027
1028     if (rv)
1029         data->attachedProperties()->insert(id, rv);
1030
1031     return rv;
1032 }
1033
1034 QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *object,
1035                                      const QMetaObject *attachedMetaObject, bool create)
1036 {
1037     if (*idCache == -1)
1038         *idCache = QQmlMetaType::attachedPropertiesFuncId(attachedMetaObject);
1039
1040     if (*idCache == -1 || !object)
1041         return 0;
1042
1043     return qmlAttachedPropertiesObjectById(*idCache, object, create);
1044 }
1045
1046 QQmlDebuggingEnabler::QQmlDebuggingEnabler(bool printWarning)
1047 {
1048 #ifndef QQML_NO_DEBUG_PROTOCOL
1049     if (!QQmlEnginePrivate::qml_debugging_enabled
1050             && printWarning) {
1051         qDebug("QML debugging is enabled. Only use this in a safe environment.");
1052     }
1053     QQmlEnginePrivate::qml_debugging_enabled = true;
1054 #endif
1055 }
1056
1057
1058 class QQmlDataExtended {
1059 public:
1060     QQmlDataExtended();
1061     ~QQmlDataExtended();
1062
1063     QHash<int, QObject *> attachedProperties;
1064     QQmlNotifier objectNameNotifier;
1065 };
1066
1067 QQmlDataExtended::QQmlDataExtended()
1068 {
1069 }
1070
1071 QQmlDataExtended::~QQmlDataExtended()
1072 {
1073 }
1074
1075 void QQmlData::NotifyList::layout(QQmlNotifierEndpoint *endpoint)
1076 {
1077     if (endpoint->next)
1078         layout(endpoint->next);
1079
1080     int index = endpoint->sourceSignal;
1081     index = qMin(index, 0xFFFF - 1);
1082
1083     endpoint->next = notifies[index];
1084     if (endpoint->next) endpoint->next->prev = &endpoint->next;
1085     endpoint->prev = &notifies[index];
1086     notifies[index] = endpoint;
1087 }
1088
1089 void QQmlData::NotifyList::layout()
1090 {
1091     Q_ASSERT(maximumTodoIndex >= notifiesSize);
1092
1093     if (todo) {
1094         QQmlNotifierEndpoint **old = notifies;
1095         const int reallocSize = (maximumTodoIndex + 1) * sizeof(QQmlNotifierEndpoint*);
1096         notifies = (QQmlNotifierEndpoint**)realloc(notifies, reallocSize);
1097         const int memsetSize = (maximumTodoIndex - notifiesSize + 1) *
1098                                sizeof(QQmlNotifierEndpoint*);
1099         memset(notifies + notifiesSize, 0, memsetSize);
1100
1101         if (notifies != old) {
1102             for (int ii = 0; ii < notifiesSize; ++ii)
1103                 if (notifies[ii])
1104                     notifies[ii]->prev = &notifies[ii];
1105         }
1106
1107         notifiesSize = maximumTodoIndex + 1;
1108
1109         layout(todo);
1110     }
1111
1112     maximumTodoIndex = 0;
1113     todo = 0;
1114 }
1115
1116 void QQmlData::addNotify(int index, QQmlNotifierEndpoint *endpoint)
1117 {
1118     if (!notifyList) {
1119         notifyList = (NotifyList *)malloc(sizeof(NotifyList));
1120         notifyList->connectionMask = 0;
1121         notifyList->maximumTodoIndex = 0;
1122         notifyList->notifiesSize = 0;
1123         notifyList->todo = 0;
1124         notifyList->notifies = 0;
1125     }
1126
1127     Q_ASSERT(!endpoint->isConnected());
1128
1129     index = qMin(index, 0xFFFF - 1);
1130     notifyList->connectionMask |= (1ULL << quint64(index % 64));
1131
1132     if (index < notifyList->notifiesSize) {
1133
1134         endpoint->next = notifyList->notifies[index];
1135         if (endpoint->next) endpoint->next->prev = &endpoint->next;
1136         endpoint->prev = &notifyList->notifies[index];
1137         notifyList->notifies[index] = endpoint;
1138
1139     } else {
1140         notifyList->maximumTodoIndex = qMax(int(notifyList->maximumTodoIndex), index);
1141
1142         endpoint->next = notifyList->todo;
1143         if (endpoint->next) endpoint->next->prev = &endpoint->next;
1144         endpoint->prev = &notifyList->todo;
1145         notifyList->todo = endpoint;
1146     }
1147 }
1148
1149 bool QQml_isSignalConnected(QObject *obj, int signal_index, int index)
1150 {
1151     QQmlData *data = QQmlData::get(obj);
1152     return QObjectPrivate::get(obj)->isSignalConnected(signal_index) || (data && data->signalHasEndpoint(index));
1153 }
1154
1155 /*
1156     index MUST be the index returned by QMetaMethod::index()
1157     This is different than the index returned by QObjectPrivate::signalIndex()
1158 */
1159 bool QQmlData::signalHasEndpoint(int index)
1160 {
1161     return notifyList && (notifyList->connectionMask & (1ULL << quint64(index % 64)));
1162 }
1163
1164 QQmlNotifier *QQmlData::objectNameNotifier() const
1165 {
1166     if (!extendedData) extendedData = new QQmlDataExtended;
1167     return &extendedData->objectNameNotifier;
1168 }
1169
1170 QHash<int, QObject *> *QQmlData::attachedProperties() const
1171 {
1172     if (!extendedData) extendedData = new QQmlDataExtended;
1173     return &extendedData->attachedProperties;
1174 }
1175
1176 void QQmlData::destroyed(QObject *object)
1177 {
1178     if (deferredComponent)
1179         deferredComponent->release();
1180
1181     if (nextContextObject)
1182         nextContextObject->prevContextObject = prevContextObject;
1183     if (prevContextObject)
1184         *prevContextObject = nextContextObject;
1185
1186     QQmlAbstractBinding *binding = bindings;
1187     while (binding) {
1188         QQmlAbstractBinding *next = binding->m_nextBinding;
1189         binding->m_prevBinding = 0;
1190         binding->m_nextBinding = 0;
1191         binding->destroy();
1192         binding = next;
1193     }
1194
1195     QQmlAbstractBoundSignal *signalHandler = signalHandlers;
1196     while (signalHandler) {
1197         QQmlAbstractBoundSignal *next = signalHandler->m_nextSignal;
1198         signalHandler->m_prevSignal = 0;
1199         signalHandler->m_nextSignal = 0;
1200         delete signalHandler;
1201         signalHandler = next;
1202     }
1203
1204     if (bindingBits)
1205         free(bindingBits);
1206
1207     if (propertyCache)
1208         propertyCache->release();
1209
1210     if (ownContext && context)
1211         context->destroy();
1212
1213     while (guards) {
1214         QQmlGuard<QObject> *guard = static_cast<QQmlGuard<QObject> *>(guards);
1215         *guard = (QObject *)0;
1216         guard->objectDestroyed(object);
1217     }
1218
1219     if (notifyList) {
1220         while (notifyList->todo)
1221             notifyList->todo->disconnect();
1222         for (int ii = 0; ii < notifyList->notifiesSize; ++ii) {
1223             while (QQmlNotifierEndpoint *ep = notifyList->notifies[ii])
1224                 ep->disconnect();
1225         }
1226         free(notifyList->notifies);
1227         free(notifyList);
1228         notifyList = 0;
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