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