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