1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
42 #include "qqmlengine_p.h"
43 #include "qqmlengine.h"
44 #include "qqmlcomponentattached_p.h"
46 #include "qqmlcontext_p.h"
47 #include "qqmlcompiler_p.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>
74 #include <QtCore/qstandardpaths.h>
75 #include <QtCore/qsettings.h>
77 #include <QtCore/qmetaobject.h>
78 #include <QNetworkAccessManager>
80 #include <QtCore/qcoreapplication.h>
81 #include <QtCore/qdir.h>
82 #include <QtCore/qmutex.h>
83 #include <QtCore/qthread.h>
84 #include <private/qthread_p.h>
85 #include <QtNetwork/qnetworkconfigmanager.h>
87 #include <private/qobject_p.h>
88 #include <private/qmetaobject_p.h>
90 #include <private/qqmllocale_p.h>
92 #ifdef Q_OS_WIN // for %APPDATA%
93 #include <qt_windows.h>
97 #define CSIDL_APPDATA 0x001a // <username>\Application Data
100 Q_DECLARE_METATYPE(QQmlProperty)
104 void qmlRegisterBaseTypes(const char *uri, int versionMajor, int versionMinor)
106 QQmlEnginePrivate::registerBaseTypes(uri, versionMajor, versionMinor);
107 QQmlEnginePrivate::registerQtQuick2Types(uri, versionMajor, versionMinor);
108 QQmlValueTypeFactory::registerValueTypes(uri, versionMajor, versionMinor);
113 \instantiates QObject
114 \inqmlmodule QtQuick 2
115 \ingroup qml-utility-elements
116 \brief A basic QML type
118 The QtObject type is a non-visual element which contains only the
121 It can be useful to create a QtObject if you need an extremely
122 lightweight type to enclose a set of custom properties:
124 \snippet qml/qtobject.qml 0
126 It can also be useful for C++ integration, as it is just a plain
127 QObject. See the QObject documentation for further details.
130 \qmlproperty string QtObject::objectName
131 This property holds the QObject::objectName for this specific object instance.
133 This allows a C++ application to locate an item within a QML component
134 using the QObject::findChild() method. For example, the following C++
135 application locates the child \l Rectangle item and dynamically changes its
144 width: 200; height: 200
158 view.setSource(QUrl::fromLocalFile("MyRect.qml"));
161 QQuickItem *item = view.rootObject()->findChild<QQuickItem*>("myRect");
163 item->setProperty("color", QColor(Qt::yellow));
167 bool QQmlEnginePrivate::qml_debugging_enabled = false;
169 // these types are part of the QML language
170 void QQmlEnginePrivate::registerBaseTypes(const char *uri, int versionMajor, int versionMinor)
172 qmlRegisterType<QQmlComponent>(uri,versionMajor,versionMinor,"Component");
173 qmlRegisterType<QObject>(uri,versionMajor,versionMinor,"QtObject");
177 // These QtQuick types' implementation resides in the QtQml module
178 void QQmlEnginePrivate::registerQtQuick2Types(const char *uri, int versionMajor, int versionMinor)
180 qmlRegisterType<QQuickListElement>(uri, versionMajor, versionMinor, "ListElement");
181 qmlRegisterCustomType<QQuickListModel>(uri, versionMajor, versionMinor, "ListModel", new QQuickListModelParser);
182 qmlRegisterType<QQuickWorkerScript>(uri, versionMajor, versionMinor, "WorkerScript");
185 void QQmlEnginePrivate::defineQtQuick2Module()
187 // register the base types into the QtQuick namespace
188 registerBaseTypes("QtQuick",2,0);
190 // register the QtQuick2 types which are implemented in the QtQml module.
191 registerQtQuick2Types("QtQuick",2,0);
192 qmlRegisterUncreatableType<QQmlLocale>("QtQuick", 2, 0, "Locale", QQmlEngine::tr("Locale cannot be instantiated. Use Qt.locale()"));
197 \class QQmlImageProviderBase
198 \brief The QQmlImageProviderBase class is used to register image providers in the QML engine.
202 Image providers must be registered with the QML engine. The only information the QML
203 engine knows about image providers is the type of image data they provide. To use an
204 image provider to acquire image data, you must cast the QQmlImageProviderBase pointer
205 to a QQuickImageProvider pointer.
207 \sa QQuickImageProvider, QQuickTextureFactory
211 \enum QQmlImageProviderBase::ImageType
213 Defines the type of image supported by this image provider.
215 \value Image The Image Provider provides QImage images.
216 The QQuickImageProvider::requestImage() method will be called for all image requests.
217 \value Pixmap The Image Provider provides QPixmap images.
218 The QQuickImageProvider::requestPixmap() method will be called for all image requests.
219 \value Texture The Image Provider provides QSGTextureProvider based images.
220 The QQuickImageProvider::requestTexture() method will be called for all image requests.
225 \enum QQmlImageProviderBase::Flag
227 Defines specific requirements or features of this image provider.
229 \value ForceAsynchronousImageLoading Ensures that image requests to the provider are
230 run in a separate thread, which allows the provider to spend as much time as needed
231 on producing the image without blocking the main thread.
235 QQmlImageProviderBase::QQmlImageProviderBase()
240 QQmlImageProviderBase::~QQmlImageProviderBase()
247 \instantiates QQmlEnginePrivate
248 \ingroup qml-utility-elements
249 \brief The QML global Qt object provides useful enums and functions from Qt.
251 \keyword QmlGlobalQtObject
253 \brief The \c Qt object provides useful enums and functions from Qt, for use in all QML files.
255 The \c Qt object is a global object with utility functions, properties and enums.
257 It is not instantiable; to use it, call the members of the global \c Qt object directly.
264 color: Qt.rgba(1, 0, 0, 1)
265 text: Qt.md5("hello, world")
272 The Qt object contains the enums available in the \l {Qt Namespace}. For example, you can access
273 the \l Qt::LeftButton and \l Qt::RightButton enumeration values as \c Qt.LeftButton and \c Qt.RightButton.
278 The Qt object also contains helper functions for creating objects of specific
279 data types. This is primarily useful when setting the properties of an item
280 when the property has one of the following types:
282 \li \c rect - use \l{Qt::rect()}{Qt.rect()}
283 \li \c point - use \l{Qt::point()}{Qt.point()}
284 \li \c size - use \l{Qt::size()}{Qt.size()}
287 If the QtQuick module has been imported, the following helper functions for
288 creating objects of specific data types are also available for clients to use:
290 \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()}
291 \li \c font - use \l{Qt::font()}{Qt.font()}
292 \li \c vector2d - use \l{Qt::vector2d()}{Qt.vector2d()}
293 \li \c vector3d - use \l{Qt::vector3d()}{Qt.vector3d()}
294 \li \c vector4d - use \l{Qt::vector4d()}{Qt.vector4d()}
295 \li \c quaternion - use \l{Qt::quaternion()}{Qt.quaternion()}
296 \li \c matrix4x4 - use \l{Qt::matrix4x4()}{Qt.matrix4x4()}
299 There are also string based constructors for these types. See \l{qtqml-typesystem-basictypes.html}{QML Basic Types} for more information.
301 \section1 Date/Time Formatters
303 The Qt object contains several functions for formatting QDateTime, QDate and QTime values.
306 \li \l{Qt::formatDateTime}{string Qt.formatDateTime(datetime date, variant format)}
307 \li \l{Qt::formatDate}{string Qt.formatDate(datetime date, variant format)}
308 \li \l{Qt::formatTime}{string Qt.formatTime(datetime date, variant format)}
311 The format specification is described at \l{Qt::formatDateTime}{Qt.formatDateTime}.
314 \section1 Dynamic Object Creation
315 The following functions on the global object allow you to dynamically create QML
316 items from files or strings. See \l{Dynamic QML Object Creation from JavaScript} for an overview
320 \li \l{Qt::createComponent()}{object Qt.createComponent(url)}
321 \li \l{Qt::createQmlObject()}{object Qt.createQmlObject(string qml, object parent, string filepath)}
325 \section1 Other Functions
327 The following functions are also on the Qt object.
330 \li \l{Qt::quit()}{Qt.quit()}
331 \li \l{Qt::md5()}{Qt.md5(string)}
332 \li \l{Qt::btoa()}{string Qt.btoa(string)}
333 \li \l{Qt::atob()}{string Qt.atob(string)}
334 \li \l{Qt::binding()}{object Qt.binding(function)}
335 \li \l{Qt::locale()}{object Qt.locale()}
336 \li \l{Qt::resolvedUrl()}{string Qt.resolvedUrl(string)}
337 \li \l{Qt::openUrlExternally()}{Qt.openUrlExternally(string)}
338 \li \l{Qt::fontFamilies()}{list<string> Qt.fontFamilies()}
343 \qmlproperty object Qt::application
346 The \c application object provides access to global application state
347 properties shared by many QML components.
353 \li \c application.active
355 This read-only property indicates whether the application is the top-most and focused
356 application, and the user is able to interact with the application. The property
357 is false when the application is in the background, the device keylock or screen
358 saver is active, the screen backlight is turned off, or the global system dialog
359 is being displayed on top of the application. It can be used for stopping and
360 pausing animations, timers and active processing of data in order to save device
361 battery power and free device memory and processor load when the application is not
365 \li \c application.layoutDirection
367 This read-only property can be used to query the default layout direction of the
368 application. On system start-up, the default layout direction depends on the
369 application's language. The property has a value of \c Qt.RightToLeft in locales
370 where text and graphic elements are read from right to left, and \c Qt.LeftToRight
371 where the reading direction flows from left to right. You can bind to this
372 property to customize your application layouts to support both layout directions.
377 \li Qt.LeftToRight - Text and graphics elements should be positioned
379 \li Qt.RightToLeft - Text and graphics elements should be positioned
385 The following example uses the \c application object to indicate
386 whether the application is currently active:
388 \snippet qml/application.qml document
392 \qmlproperty object Qt::inputMethod
395 The \c inputMethod object allows access to application's QInputMethod object
396 and all its properties and slots. See the QInputMethod documentation for
402 \qmlmethod object Qt::include(string url, jsobject callback)
404 Includes another JavaScript file. This method can only be used from within JavaScript files,
405 and not regular QML files.
407 This imports all functions from \a url into the current script's namespace.
409 Qt.include() returns an object that describes the status of the operation. The object has
410 a single property, \c {status}, that is set to one of the following values:
413 \header \li Symbol \li Value \li Description
414 \row \li result.OK \li 0 \li The include completed successfully.
415 \row \li result.LOADING \li 1 \li Data is being loaded from the network.
416 \row \li result.NETWORK_ERROR \li 2 \li A network error occurred while fetching the url.
417 \row \li result.EXCEPTION \li 3 \li A JavaScript exception occurred while executing the included code.
418 An additional \c exception property will be set in this case.
421 The \c status property will be updated as the operation progresses.
423 If provided, \a callback is invoked when the operation completes. The callback is passed
424 the same object as is returned from the Qt.include() call.
426 // Qt.include() is implemented in qv8include.cpp
429 QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e)
430 : propertyCapture(0), rootContext(0), isDebugging(false),
431 outputWarningsToStdErr(true), sharedContext(0), sharedScope(0),
432 cleanup(0), erroredBindings(0), inProgressCreations(0),
433 workerScriptEngine(0), activeVME(0),
434 networkAccessManager(0), networkAccessManagerFactory(0),
435 scarceResourcesRefCount(0), typeLoader(e), importDatabase(e), uniqueId(1),
436 incubatorCount(0), incubationController(0), mutex(QMutex::Recursive)
440 QQmlEnginePrivate::~QQmlEnginePrivate()
442 if (inProgressCreations)
443 qWarning() << QQmlEngine::tr("There are still \"%1\" items in the process of being created at engine destruction.").arg(inProgressCreations);
446 QQmlCleanup *c = cleanup;
448 if (cleanup) cleanup->prev = &cleanup;
454 doDeleteInEngineThread();
456 if (incubationController) incubationController->d = 0;
457 incubationController = 0;
462 for(QHash<const QMetaObject *, QQmlPropertyCache *>::Iterator iter = propertyCache.begin(); iter != propertyCache.end(); ++iter)
464 for(QHash<QPair<QQmlType *, int>, QQmlPropertyCache *>::Iterator iter = typePropertyCache.begin(); iter != typePropertyCache.end(); ++iter)
466 for (QHash<int, QQmlCompiledData *>::Iterator iter = m_compositeTypes.begin(); iter != m_compositeTypes.end(); ++iter)
467 iter.value()->isRegisteredWithEngine = false;
470 void QQmlPrivate::qdeclarativeelement_destructor(QObject *o)
472 QObjectPrivate *p = QObjectPrivate::get(o);
473 if (p->declarativeData) {
474 QQmlData *d = static_cast<QQmlData*>(p->declarativeData);
475 if (d->ownContext && d->context) {
476 d->context->destroy();
480 // Mark this object as in the process of deletion to
481 // prevent it resolving in bindings
482 QQmlData::markAsDeleted(o);
484 // Disconnect the notifiers now - during object destruction this would be too late, since
485 // the disconnect call wouldn't be able to call disconnectNotify(), as it isn't possible to
486 // get the metaobject anymore.
487 d->disconnectNotifiers();
491 void QQmlData::destroyed(QAbstractDeclarativeData *d, QObject *o)
493 static_cast<QQmlData *>(d)->destroyed(o);
496 void QQmlData::parentChanged(QAbstractDeclarativeData *d, QObject *o, QObject *p)
498 static_cast<QQmlData *>(d)->parentChanged(o, p);
501 class QQmlThreadNotifierProxyObject : public QObject
504 QPointer<QObject> target;
506 virtual int qt_metacall(QMetaObject::Call, int methodIndex, void **a) {
510 QMetaMethod method = target->metaObject()->method(methodIndex);
511 Q_ASSERT(method.methodType() == QMetaMethod::Signal);
512 int signalIndex = QMetaObjectPrivate::signalIndex(method);
513 QQmlData *ddata = QQmlData::get(target, false);
514 QQmlNotifierEndpoint *ep = ddata->notify(signalIndex);
515 if (ep) QQmlNotifier::emitNotify(ep, a);
523 void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int index, void **a)
525 QQmlData *ddata = QQmlData::get(object, false);
526 if (!ddata) return; // Probably being deleted
528 // In general, QML only supports QObject's that live on the same thread as the QQmlEngine
529 // that they're exposed to. However, to make writing "worker objects" that calculate data
530 // in a separate thread easier, QML allows a QObject that lives in the same thread as the
531 // QQmlEngine to emit signals from a different thread. These signals are then automatically
532 // marshalled back onto the QObject's thread and handled by QML from there. This is tested
533 // by the qqmlecmascript::threadSignal() autotest.
534 if (ddata->notifyList &&
535 QThread::currentThreadId() != QObjectPrivate::get(object)->threadData->threadId) {
537 if (!QObjectPrivate::get(object)->threadData->thread)
540 QMetaMethod m = QMetaObjectPrivate::signal(object->metaObject(), index);
541 QList<QByteArray> parameterTypes = m.parameterTypes();
543 int *types = (int *)malloc((parameterTypes.count() + 1) * sizeof(int));
544 void **args = (void **) malloc((parameterTypes.count() + 1) *sizeof(void *));
546 types[0] = 0; // return type
547 args[0] = 0; // return value
549 for (int ii = 0; ii < parameterTypes.count(); ++ii) {
550 const QByteArray &typeName = parameterTypes.at(ii);
551 if (typeName.endsWith('*'))
552 types[ii + 1] = QMetaType::VoidStar;
554 types[ii + 1] = QMetaType::type(typeName);
556 if (!types[ii + 1]) {
557 qWarning("QObject::connect: Cannot queue arguments of type '%s'\n"
558 "(Make sure '%s' is registered using qRegisterMetaType().)",
559 typeName.constData(), typeName.constData());
565 args[ii + 1] = QMetaType::create(types[ii + 1], a[ii + 1]);
568 QMetaCallEvent *ev = new QMetaCallEvent(m.methodIndex(), 0, 0, object, index,
569 parameterTypes.count() + 1, types, args);
571 QQmlThreadNotifierProxyObject *mpo = new QQmlThreadNotifierProxyObject;
572 mpo->target = object;
573 mpo->moveToThread(QObjectPrivate::get(object)->threadData->thread);
574 QCoreApplication::postEvent(mpo, ev);
577 QQmlNotifierEndpoint *ep = ddata->notify(index);
578 if (ep) QQmlNotifier::emitNotify(ep, a);
582 int QQmlData::receivers(QAbstractDeclarativeData *d, const QObject *, int index)
584 return static_cast<QQmlData *>(d)->endpointCount(index);
587 bool QQmlData::isSignalConnected(QAbstractDeclarativeData *d, const QObject *, int index)
589 return static_cast<QQmlData *>(d)->signalHasEndpoint(index);
592 int QQmlData::endpointCount(int index)
595 QQmlNotifierEndpoint *ep = notify(index);
606 void QQmlData::markAsDeleted(QObject *o)
608 QQmlData::setQueuedForDeletion(o);
610 QObjectPrivate *p = QObjectPrivate::get(o);
611 for (QList<QObject *>::iterator it = p->children.begin(), end = p->children.end(); it != end; ++it) {
612 QQmlData::markAsDeleted(*it);
616 void QQmlData::setQueuedForDeletion(QObject *object)
619 if (QObjectPrivate *priv = QObjectPrivate::get(object)) {
620 if (!priv->wasDeleted && priv->declarativeData) {
621 QQmlData *ddata = QQmlData::get(object, false);
622 if (ddata->ownContext && ddata->context)
623 ddata->context->emitDestruction();
624 ddata->isQueuedForDeletion = true;
630 void QQmlData::flushPendingBindingImpl(int coreIndex)
632 clearPendingBindingBit(coreIndex);
635 QQmlAbstractBinding *b = bindings;
636 while (b && *b->m_mePtr && b->propertyIndex() != coreIndex)
637 b = b->nextBinding();
641 b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor |
642 QQmlPropertyPrivate::DontRemoveBinding);
646 void QQmlEnginePrivate::init()
650 static bool firstTime = true;
652 qmlRegisterType<QQmlComponent>("QML", 1, 0, "Component"); // required for the Compiler.
653 registerBaseTypes("QtQml", 2, 0); // import which provides language building blocks.
659 qRegisterMetaType<QVariant>("QVariant");
660 qRegisterMetaType<QQmlScriptString>("QQmlScriptString");
661 qRegisterMetaType<QJSValue>("QJSValue");
662 qRegisterMetaType<QQmlComponent::Status>("QQmlComponent::Status");
663 qRegisterMetaType<QList<QObject*> >("QList<QObject*>");
664 qRegisterMetaType<QList<int> >("QList<int>");
665 qRegisterMetaType<QQmlV8Handle>("QQmlV8Handle");
667 v8engine()->setEngine(q);
669 rootContext = new QQmlContext(q,true);
671 if (QCoreApplication::instance()->thread() == q->thread() &&
672 QQmlEngineDebugService::isDebuggingEnabled()) {
674 QQmlEngineDebugService::instance()->addEngine(q);
675 QV8DebugService::initialize(v8engine());
676 QV8ProfilerService::initialize();
677 QQmlProfilerService::initialize();
678 QDebugMessageService::instance();
681 QString dataLocation = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
682 if (!dataLocation.isEmpty())
683 offlineStoragePath = dataLocation.replace(QLatin1Char('/'), QDir::separator())
684 + QDir::separator() + QLatin1String("QML")
685 + QDir::separator() + QLatin1String("OfflineStorage");
688 QQuickWorkerScriptEngine *QQmlEnginePrivate::getWorkerScriptEngine()
691 if (!workerScriptEngine)
692 workerScriptEngine = new QQuickWorkerScriptEngine(q);
693 return workerScriptEngine;
700 \brief The QQmlEngine class provides an environment for instantiating QML components.
703 Each QML component is instantiated in a QQmlContext.
704 QQmlContext's are essential for passing data to QML
705 components. In QML, contexts are arranged hierarchically and this
706 hierarchy is managed by the QQmlEngine.
708 Prior to creating any QML components, an application must have
709 created a QQmlEngine to gain access to a QML context. The
710 following example shows how to create a simple Text item.
714 QQmlComponent component(&engine);
715 component.setData("import QtQuick 2.0\nText { text: \"Hello world!\" }", QUrl());
716 QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
718 //add item to view, etc
722 In this case, the Text item will be created in the engine's
723 \l {QQmlEngine::rootContext()}{root context}.
725 Note that the QtQuick 1 version is called QDeclarativeEngine.
727 \sa QQmlComponent, QQmlContext
731 Create a new QQmlEngine with the given \a parent.
733 QQmlEngine::QQmlEngine(QObject *parent)
734 : QJSEngine(*new QQmlEnginePrivate(this), parent)
741 Destroys the QQmlEngine.
743 Any QQmlContext's created on this engine will be
744 invalidated, but not destroyed (unless they are parented to the
747 QQmlEngine::~QQmlEngine()
750 if (d->isDebugging) {
751 QQmlEngineDebugService::instance()->remEngine(this);
754 // Emit onDestruction signals for the root context before
755 // we destroy the contexts, engine, Singleton Types etc. that
756 // may be required to handle the destruction signal.
757 QQmlContextData::get(rootContext())->emitDestruction();
759 // clean up all singleton type instances which we own.
760 // we do this here and not in the private dtor since otherwise a crash can
761 // occur (if we are the QObject parent of the QObject singleton instance)
762 // XXX TODO: performance -- store list of singleton types separately?
763 QList<QQmlType*> singletonTypes = QQmlMetaType::qmlSingletonTypes();
764 foreach (QQmlType *currType, singletonTypes)
765 currType->singletonInstanceInfo()->destroy(this);
767 if (d->incubationController)
768 d->incubationController->d = 0;
771 /*! \fn void QQmlEngine::quit()
772 This signal is emitted when the QML loaded by the engine would like to quit.
775 /*! \fn void QQmlEngine::warnings(const QList<QQmlError> &warnings)
776 This signal is emitted when \a warnings messages are generated by QML.
780 Clears the engine's internal component cache.
782 This function causes the property metadata of all components previously
783 loaded by the engine to be destroyed. All previously loaded components and
784 the property bindings for all extant objects created from those components will
787 This function returns the engine to a state where it does not contain any loaded
788 component data. This may be useful in order to reload a smaller subset of the
789 previous component set, or to load a new version of a previously loaded component.
791 Once the component cache has been cleared, components must be loaded before
792 any new objects can be created.
794 \sa trimComponentCache()
796 void QQmlEngine::clearComponentCache()
799 d->typeLoader.clearCache();
803 Trims the engine's internal component cache.
805 This function causes the property metadata of any loaded components which are
806 not currently in use to be destroyed.
808 A component is considered to be in use if there are any extant instances of
809 the component itself, any instances of other components that use the component,
810 or any objects instantiated by any of those components.
812 \sa clearComponentCache()
814 void QQmlEngine::trimComponentCache()
817 d->typeLoader.trimCache();
821 Returns the engine's root context.
823 The root context is automatically created by the QQmlEngine.
824 Data that should be available to all QML component instances
825 instantiated by the engine should be put in the root context.
827 Additional data that should only be available to a subset of
828 component instances should be added to sub-contexts parented to the
831 QQmlContext *QQmlEngine::rootContext() const
833 Q_D(const QQmlEngine);
834 return d->rootContext;
838 Sets the \a factory to use for creating QNetworkAccessManager(s).
840 QNetworkAccessManager is used for all network access by QML. By
841 implementing a factory it is possible to create custom
842 QNetworkAccessManager with specialized caching, proxy and cookie
845 The factory must be set before executing the engine.
847 void QQmlEngine::setNetworkAccessManagerFactory(QQmlNetworkAccessManagerFactory *factory)
850 QMutexLocker locker(&d->mutex);
851 d->networkAccessManagerFactory = factory;
855 Returns the current QQmlNetworkAccessManagerFactory.
857 \sa setNetworkAccessManagerFactory()
859 QQmlNetworkAccessManagerFactory *QQmlEngine::networkAccessManagerFactory() const
861 Q_D(const QQmlEngine);
862 return d->networkAccessManagerFactory;
865 void QQmlEnginePrivate::registerFinalizeCallback(QObject *obj, int index)
868 activeVME->finalizeCallbacks.append(qMakePair(QQmlGuard<QObject>(obj), index));
870 void *args[] = { 0 };
871 QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, index, args);
875 QNetworkAccessManager *QQmlEnginePrivate::createNetworkAccessManager(QObject *parent) const
877 QMutexLocker locker(&mutex);
878 QNetworkAccessManager *nam;
879 if (networkAccessManagerFactory) {
880 nam = networkAccessManagerFactory->create(parent);
882 nam = new QNetworkAccessManager(parent);
888 QNetworkAccessManager *QQmlEnginePrivate::getNetworkAccessManager() const
890 Q_Q(const QQmlEngine);
891 if (!networkAccessManager)
892 networkAccessManager = createNetworkAccessManager(const_cast<QQmlEngine*>(q));
893 return networkAccessManager;
897 Returns a common QNetworkAccessManager which can be used by any QML
898 type instantiated by this engine.
900 If a QQmlNetworkAccessManagerFactory has been set and a
901 QNetworkAccessManager has not yet been created, the
902 QQmlNetworkAccessManagerFactory will be used to create the
903 QNetworkAccessManager; otherwise the returned QNetworkAccessManager
904 will have no proxy or cache set.
906 \sa setNetworkAccessManagerFactory()
908 QNetworkAccessManager *QQmlEngine::networkAccessManager() const
910 Q_D(const QQmlEngine);
911 return d->getNetworkAccessManager();
916 Sets the \a provider to use for images requested via the \e
917 image: url scheme, with host \a providerId. The QQmlEngine
918 takes ownership of \a provider.
920 Image providers enable support for pixmap and threaded image
921 requests. See the QQuickImageProvider documentation for details on
922 implementing and using image providers.
924 All required image providers should be added to the engine before any
925 QML sources files are loaded.
927 \sa removeImageProvider(), QQuickImageProvider, QQmlImageProviderBase
929 void QQmlEngine::addImageProvider(const QString &providerId, QQmlImageProviderBase *provider)
932 QMutexLocker locker(&d->mutex);
933 d->imageProviders.insert(providerId.toLower(), QSharedPointer<QQmlImageProviderBase>(provider));
937 Returns the image provider set for \a providerId.
939 Returns the provider if it was found; otherwise returns 0.
941 \sa QQuickImageProvider
943 QQmlImageProviderBase *QQmlEngine::imageProvider(const QString &providerId) const
945 Q_D(const QQmlEngine);
946 QMutexLocker locker(&d->mutex);
947 return d->imageProviders.value(providerId).data();
951 Removes the image provider for \a providerId.
953 \sa addImageProvider(), QQuickImageProvider
955 void QQmlEngine::removeImageProvider(const QString &providerId)
958 QMutexLocker locker(&d->mutex);
959 d->imageProviders.take(providerId);
963 Return the base URL for this engine. The base URL is only used to
964 resolve components when a relative URL is passed to the
965 QQmlComponent constructor.
967 If a base URL has not been explicitly set, this method returns the
968 application's current working directory.
972 QUrl QQmlEngine::baseUrl() const
974 Q_D(const QQmlEngine);
975 if (d->baseUrl.isEmpty()) {
976 return QUrl::fromLocalFile(QDir::currentPath() + QDir::separator());
983 Set the base URL for this engine to \a url.
987 void QQmlEngine::setBaseUrl(const QUrl &url)
994 Returns true if warning messages will be output to stderr in addition
995 to being emitted by the warnings() signal, otherwise false.
997 The default value is true.
999 bool QQmlEngine::outputWarningsToStandardError() const
1001 Q_D(const QQmlEngine);
1002 return d->outputWarningsToStdErr;
1006 Set whether warning messages will be output to stderr to \a enabled.
1008 If \a enabled is true, any warning messages generated by QML will be
1009 output to stderr and emitted by the warnings() signal. If \a enabled
1010 is false, on the warnings() signal will be emitted. This allows
1011 applications to handle warning output themselves.
1013 The default value is true.
1015 void QQmlEngine::setOutputWarningsToStandardError(bool enabled)
1018 d->outputWarningsToStdErr = enabled;
1022 Returns the QQmlContext for the \a object, or 0 if no
1023 context has been set.
1025 When the QQmlEngine instantiates a QObject, the context is
1028 QQmlContext *QQmlEngine::contextForObject(const QObject *object)
1033 QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object));
1036 static_cast<QQmlData *>(priv->declarativeData);
1040 else if (data->outerContext)
1041 return data->outerContext->asQQmlContext();
1047 Sets the QQmlContext for the \a object to \a context.
1048 If the \a object already has a context, a warning is
1049 output, but the context is not changed.
1051 When the QQmlEngine instantiates a QObject, the context is
1054 void QQmlEngine::setContextForObject(QObject *object, QQmlContext *context)
1056 if (!object || !context)
1059 QQmlData *data = QQmlData::get(object, true);
1060 if (data->context) {
1061 qWarning("QQmlEngine::setContextForObject(): Object already has a QQmlContext");
1065 QQmlContextData *contextData = QQmlContextData::get(context);
1066 contextData->addObject(object);
1070 \enum QQmlEngine::ObjectOwnership
1072 Ownership controls whether or not QML automatically destroys the
1073 QObject when the object is garbage collected by the JavaScript
1074 engine. The two ownership options are:
1076 \value CppOwnership The object is owned by C++ code, and will
1077 never be deleted by QML. The JavaScript destroy() method cannot be
1078 used on objects with CppOwnership. This option is similar to
1079 QScriptEngine::QtOwnership.
1081 \value JavaScriptOwnership The object is owned by JavaScript.
1082 When the object is returned to QML as the return value of a method
1083 call or property access, QML will track it, and delete the object
1084 if there are no remaining JavaScript references to it and it has no
1085 QObject::parent(). An object tracked by one QQmlEngine
1086 will be deleted during that QQmlEngine's destructor, and thus
1087 JavaScript references between objects with JavaScriptOwnership from
1088 two different engines will not be valid after the deletion of one of
1089 those engines. This option is similar to QScriptEngine::ScriptOwnership.
1091 Generally an application doesn't need to set an object's ownership
1092 explicitly. QML uses a heuristic to set the default object
1093 ownership. By default, an object that is created by QML has
1094 JavaScriptOwnership. The exception to this are the root objects
1095 created by calling QQmlComponent::create() or
1096 QQmlComponent::beginCreate() which have CppOwnership by
1097 default. The ownership of these root-level objects is considered to
1098 have been transferred to the C++ caller.
1100 Objects not-created by QML have CppOwnership by default. The
1101 exception to this is objects returned from C++ method calls; in these cases,
1102 the ownership of the returned objects will be set to JavaScriptOwnerShip.
1103 Note this applies only to explicit invocations of Q_INVOKABLE methods or slots,
1104 and not to property getter invocations.
1106 Calling setObjectOwnership() overrides the default ownership
1107 heuristic used by QML.
1111 Sets the \a ownership of \a object.
1113 void QQmlEngine::setObjectOwnership(QObject *object, ObjectOwnership ownership)
1118 QQmlData *ddata = QQmlData::get(object, true);
1122 ddata->indestructible = (ownership == CppOwnership)?true:false;
1123 ddata->explicitIndestructibleSet = true;
1127 Returns the ownership of \a object.
1129 QQmlEngine::ObjectOwnership QQmlEngine::objectOwnership(QObject *object)
1132 return CppOwnership;
1134 QQmlData *ddata = QQmlData::get(object, false);
1136 return CppOwnership;
1138 return ddata->indestructible?CppOwnership:JavaScriptOwnership;
1141 bool QQmlEngine::event(QEvent *e)
1144 if (e->type() == QEvent::User)
1145 d->doDeleteInEngineThread();
1147 return QJSEngine::event(e);
1150 void QQmlEnginePrivate::doDeleteInEngineThread()
1152 QFieldList<Deletable, &Deletable::next> list;
1154 list.copyAndClear(toDeleteInEngineThread);
1157 while (Deletable *d = list.takeFirst())
1161 Q_AUTOTEST_EXPORT void qmlExecuteDeferred(QObject *object)
1163 QQmlData *data = QQmlData::get(object);
1165 if (data && data->compiledData && data->deferredIdx) {
1166 QQmlObjectCreatingProfiler prof;
1168 QQmlType *type = QQmlMetaType::qmlType(object->metaObject());
1169 prof.setTypeName(type ? type->qmlTypeName()
1170 : QString::fromUtf8(object->metaObject()->className()));
1171 if (data->outerContext)
1172 prof.setLocation(data->outerContext->url, data->lineNumber, data->columnNumber);
1174 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine);
1176 QQmlComponentPrivate::ConstructionState state;
1177 QQmlComponentPrivate::beginDeferred(ep, object, &state);
1179 // Release the reference for the deferral action (we still have one from construction)
1180 data->compiledData->release();
1181 data->compiledData = 0;
1183 QQmlComponentPrivate::complete(ep, &state);
1187 QQmlContext *qmlContext(const QObject *obj)
1189 return QQmlEngine::contextForObject(obj);
1192 QQmlEngine *qmlEngine(const QObject *obj)
1194 QQmlData *data = QQmlData::get(obj, false);
1195 if (!data || !data->context)
1197 return data->context->engine;
1200 QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create)
1202 QQmlData *data = QQmlData::get(object);
1204 return 0; // Attached properties are only on objects created by QML
1206 QObject *rv = data->hasExtendedData()?data->attachedProperties()->value(id):0;
1210 QQmlAttachedPropertiesFunc pf = QQmlMetaType::attachedPropertiesFuncById(id);
1214 rv = pf(const_cast<QObject *>(object));
1217 data->attachedProperties()->insert(id, rv);
1222 QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *object,
1223 const QMetaObject *attachedMetaObject, bool create)
1226 *idCache = QQmlMetaType::attachedPropertiesFuncId(attachedMetaObject);
1228 if (*idCache == -1 || !object)
1231 return qmlAttachedPropertiesObjectById(*idCache, object, create);
1234 QQmlDebuggingEnabler::QQmlDebuggingEnabler(bool printWarning)
1236 #ifndef QQML_NO_DEBUG_PROTOCOL
1237 if (!QQmlEnginePrivate::qml_debugging_enabled
1239 qDebug("QML debugging is enabled. Only use this in a safe environment.");
1241 QQmlEnginePrivate::qml_debugging_enabled = true;
1246 class QQmlDataExtended {
1249 ~QQmlDataExtended();
1251 QHash<int, QObject *> attachedProperties;
1254 QQmlDataExtended::QQmlDataExtended()
1258 QQmlDataExtended::~QQmlDataExtended()
1262 void QQmlData::NotifyList::layout(QQmlNotifierEndpoint *endpoint)
1265 layout(endpoint->next);
1267 int index = endpoint->sourceSignal;
1268 index = qMin(index, 0xFFFF - 1);
1270 endpoint->next = notifies[index];
1271 if (endpoint->next) endpoint->next->prev = &endpoint->next;
1272 endpoint->prev = ¬ifies[index];
1273 notifies[index] = endpoint;
1276 void QQmlData::NotifyList::layout()
1278 Q_ASSERT(maximumTodoIndex >= notifiesSize);
1281 QQmlNotifierEndpoint **old = notifies;
1282 const int reallocSize = (maximumTodoIndex + 1) * sizeof(QQmlNotifierEndpoint*);
1283 notifies = (QQmlNotifierEndpoint**)realloc(notifies, reallocSize);
1284 const int memsetSize = (maximumTodoIndex - notifiesSize + 1) *
1285 sizeof(QQmlNotifierEndpoint*);
1286 memset(notifies + notifiesSize, 0, memsetSize);
1288 if (notifies != old) {
1289 for (int ii = 0; ii < notifiesSize; ++ii)
1291 notifies[ii]->prev = ¬ifies[ii];
1294 notifiesSize = maximumTodoIndex + 1;
1299 maximumTodoIndex = 0;
1303 void QQmlData::addNotify(int index, QQmlNotifierEndpoint *endpoint)
1306 notifyList = (NotifyList *)malloc(sizeof(NotifyList));
1307 notifyList->connectionMask = 0;
1308 notifyList->maximumTodoIndex = 0;
1309 notifyList->notifiesSize = 0;
1310 notifyList->todo = 0;
1311 notifyList->notifies = 0;
1314 Q_ASSERT(!endpoint->isConnected());
1316 index = qMin(index, 0xFFFF - 1);
1317 notifyList->connectionMask |= (1ULL << quint64(index % 64));
1319 if (index < notifyList->notifiesSize) {
1321 endpoint->next = notifyList->notifies[index];
1322 if (endpoint->next) endpoint->next->prev = &endpoint->next;
1323 endpoint->prev = ¬ifyList->notifies[index];
1324 notifyList->notifies[index] = endpoint;
1327 notifyList->maximumTodoIndex = qMax(int(notifyList->maximumTodoIndex), index);
1329 endpoint->next = notifyList->todo;
1330 if (endpoint->next) endpoint->next->prev = &endpoint->next;
1331 endpoint->prev = ¬ifyList->todo;
1332 notifyList->todo = endpoint;
1337 index MUST in the range returned by QObjectPrivate::signalIndex()
1338 This is different than the index returned by QMetaMethod::methodIndex()
1340 bool QQmlData::signalHasEndpoint(int index)
1342 return notifyList && (notifyList->connectionMask & (1ULL << quint64(index % 64)));
1345 void QQmlData::disconnectNotifiers()
1348 while (notifyList->todo)
1349 notifyList->todo->disconnect();
1350 for (int ii = 0; ii < notifyList->notifiesSize; ++ii) {
1351 while (QQmlNotifierEndpoint *ep = notifyList->notifies[ii])
1354 free(notifyList->notifies);
1360 QHash<int, QObject *> *QQmlData::attachedProperties() const
1362 if (!extendedData) extendedData = new QQmlDataExtended;
1363 return &extendedData->attachedProperties;
1366 void QQmlData::destroyed(QObject *object)
1368 if (nextContextObject)
1369 nextContextObject->prevContextObject = prevContextObject;
1370 if (prevContextObject)
1371 *prevContextObject = nextContextObject;
1373 QQmlAbstractBinding *binding = bindings;
1375 QQmlAbstractBinding *next = binding->nextBinding();
1376 binding->setAddedToObject(false);
1377 binding->setNextBinding(0);
1383 compiledData->release();
1387 QQmlAbstractBoundSignal *signalHandler = signalHandlers;
1388 while (signalHandler) {
1389 if (signalHandler->isEvaluating()) {
1390 // The object is being deleted during signal handler evaluation.
1391 // This will cause a crash due to invalid memory access when the
1392 // evaluation has completed.
1393 // Abort with a friendly message instead.
1394 QString locationString;
1395 QQmlBoundSignalExpression *expr = signalHandler->expression();
1397 QString fileName = expr->sourceFile();
1398 if (fileName.isEmpty())
1399 fileName = QStringLiteral("<Unknown File>");
1400 locationString.append(fileName);
1401 locationString.append(QString::fromLatin1(":%0: ").arg(expr->lineNumber()));
1402 QString source = expr->expression();
1403 if (source.size() > 100) {
1404 source.truncate(96);
1405 source.append(QStringLiteral(" ..."));
1407 locationString.append(source);
1409 locationString = QStringLiteral("<Unknown Location>");
1411 qFatal("Object %p destroyed while one of its QML signal handlers is in progress.\n"
1412 "Most likely the object was deleted synchronously (use QObject::deleteLater() "
1413 "instead), or the application is running a nested event loop.\n"
1414 "This behavior is NOT supported!\n"
1415 "%s", object, qPrintable(locationString));
1418 QQmlAbstractBoundSignal *next = signalHandler->m_nextSignal;
1419 signalHandler->m_prevSignal = 0;
1420 signalHandler->m_nextSignal = 0;
1421 delete signalHandler;
1422 signalHandler = next;
1429 propertyCache->release();
1431 if (ownContext && context)
1435 QQmlGuard<QObject> *guard = static_cast<QQmlGuard<QObject> *>(guards);
1436 *guard = (QObject *)0;
1437 guard->objectDestroyed(object);
1440 disconnectNotifiers();
1443 delete extendedData;
1445 // Dispose the handle.
1446 // We don't simply clear it (and wait for next gc cycle to dispose
1447 // via the weak qobject reference callback) as this affects the
1448 // outcomes of v8's gc statistical analysis heuristics, which can
1449 // cause unnecessary growth of the old pointer space js heap area.
1450 qPersistentDispose(v8object);
1456 DEFINE_BOOL_CONFIG_OPTION(parentTest, QML_PARENT_TEST);
1458 void QQmlData::parentChanged(QObject *object, QObject *parent)
1461 if (parentFrozen && !QObjectPrivate::get(object)->wasDeleted) {
1465 { QDebug dbg(&on); dbg << object; on = on.left(on.length() - 1); }
1466 { QDebug dbg(&pn); dbg << parent; pn = pn.left(pn.length() - 1); }
1468 qFatal("Object %s has had its parent frozen by QML and cannot be changed.\n"
1469 "User code is attempting to change it to %s.\n"
1470 "This behavior is NOT supported!", qPrintable(on), qPrintable(pn));
1475 static void QQmlData_setBit(QQmlData *data, QObject *obj, int bit)
1477 if (data->bindingBitsSize <= bit) {
1478 int props = QQmlMetaObject(obj).propertyCount();
1479 Q_ASSERT(bit < 2 * props);
1481 int arraySize = (2 * props + 31) / 32;
1482 int oldArraySize = data->bindingBitsSize / 32;
1484 data->bindingBits = (quint32 *)realloc(data->bindingBits,
1485 arraySize * sizeof(quint32));
1487 memset(data->bindingBits + oldArraySize,
1489 sizeof(quint32) * (arraySize - oldArraySize));
1491 data->bindingBitsSize = arraySize * 32;
1494 data->bindingBits[bit / 32] |= (1 << (bit % 32));
1497 static void QQmlData_clearBit(QQmlData *data, int bit)
1499 if (data->bindingBitsSize > bit)
1500 data->bindingBits[bit / 32] &= ~(1 << (bit % 32));
1503 void QQmlData::clearBindingBit(int coreIndex)
1505 QQmlData_clearBit(this, coreIndex * 2);
1508 void QQmlData::setBindingBit(QObject *obj, int coreIndex)
1510 QQmlData_setBit(this, obj, coreIndex * 2);
1513 void QQmlData::clearPendingBindingBit(int coreIndex)
1515 QQmlData_clearBit(this, coreIndex * 2 + 1);
1518 void QQmlData::setPendingBindingBit(QObject *obj, int coreIndex)
1520 QQmlData_setBit(this, obj, coreIndex * 2 + 1);
1523 void QQmlEnginePrivate::sendQuit()
1527 if (q->receivers(SIGNAL(quit())) == 0) {
1528 qWarning("Signal QQmlEngine::quit() emitted, but no receivers connected to handle it.");
1532 static void dumpwarning(const QQmlError &error)
1534 QMessageLogger(error.url().toString().toLatin1().constData(),
1535 error.line(), 0).warning().nospace()
1536 << qPrintable(error.toString());
1539 static void dumpwarning(const QList<QQmlError> &errors)
1541 for (int ii = 0; ii < errors.count(); ++ii)
1542 dumpwarning(errors.at(ii));
1545 void QQmlEnginePrivate::warning(const QQmlError &error)
1548 q->warnings(QList<QQmlError>() << error);
1549 if (outputWarningsToStdErr)
1553 void QQmlEnginePrivate::warning(const QList<QQmlError> &errors)
1556 q->warnings(errors);
1557 if (outputWarningsToStdErr)
1558 dumpwarning(errors);
1561 void QQmlEnginePrivate::warning(QQmlDelayedError *error)
1564 warning(error->error(q));
1567 void QQmlEnginePrivate::warning(QQmlEngine *engine, const QQmlError &error)
1570 QQmlEnginePrivate::get(engine)->warning(error);
1575 void QQmlEnginePrivate::warning(QQmlEngine *engine, const QList<QQmlError> &error)
1578 QQmlEnginePrivate::get(engine)->warning(error);
1583 void QQmlEnginePrivate::warning(QQmlEngine *engine, QQmlDelayedError *error)
1586 QQmlEnginePrivate::get(engine)->warning(error);
1588 dumpwarning(error->error(0));
1591 void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QQmlError &error)
1594 engine->warning(error);
1599 void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QList<QQmlError> &error)
1602 engine->warning(error);
1608 This function should be called prior to evaluation of any js expression,
1609 so that scarce resources are not freed prematurely (eg, if there is a
1610 nested javascript expression).
1612 void QQmlEnginePrivate::referenceScarceResources()
1614 scarceResourcesRefCount += 1;
1618 This function should be called after evaluation of the js expression is
1619 complete, and so the scarce resources may be freed safely.
1621 void QQmlEnginePrivate::dereferenceScarceResources()
1623 Q_ASSERT(scarceResourcesRefCount > 0);
1624 scarceResourcesRefCount -= 1;
1626 // if the refcount is zero, then evaluation of the "top level"
1627 // expression must have completed. We can safely release the
1628 // scarce resources.
1629 if (scarceResourcesRefCount == 0) {
1630 // iterate through the list and release them all.
1631 // note that the actual SRD is owned by the JS engine,
1632 // so we cannot delete the SRD; but we can free the
1633 // memory used by the variant in the SRD.
1634 while (ScarceResourceData *sr = scarceResources.first()) {
1635 sr->data = QVariant();
1636 scarceResources.remove(sr);
1642 Adds \a path as a directory where the engine searches for
1643 installed modules in a URL-based directory structure.
1645 The \a path may be a local filesystem directory, a
1646 \l {The Qt Resource System}{Qt Resource} path (\c {:/imports}), a
1647 \l {The Qt Resource System}{Qt Resource} url (\c {qrc:/imports}) or a URL.
1649 The \a path will be converted into canonical form before it
1650 is added to the import path list.
1652 The newly added \a path will be first in the importPathList().
1654 \sa setImportPathList(), {QML Modules}
1656 void QQmlEngine::addImportPath(const QString& path)
1659 d->importDatabase.addImportPath(path);
1663 Returns the list of directories where the engine searches for
1664 installed modules in a URL-based directory structure.
1666 For example, if \c /opt/MyApp/lib/imports is in the path, then QML that
1667 imports \c com.mycompany.Feature will cause the QQmlEngine to look
1668 in \c /opt/MyApp/lib/imports/com/mycompany/Feature/ for the components
1669 provided by that module. A \c qmldir file is required for defining the
1670 type version mapping and possibly QML extensions plugins.
1672 By default, the list contains the directory of the application executable,
1673 paths specified in the \c QML_IMPORT_PATH environment variable,
1674 and the builtin \c ImportsPath from QLibraryInfo.
1676 \sa addImportPath(), setImportPathList()
1678 QStringList QQmlEngine::importPathList() const
1680 Q_D(const QQmlEngine);
1681 return d->importDatabase.importPathList();
1685 Sets \a paths as the list of directories where the engine searches for
1686 installed modules in a URL-based directory structure.
1688 By default, the list contains the directory of the application executable,
1689 paths specified in the \c QML_IMPORT_PATH environment variable,
1690 and the builtin \c ImportsPath from QLibraryInfo.
1692 \sa importPathList(), addImportPath()
1694 void QQmlEngine::setImportPathList(const QStringList &paths)
1697 d->importDatabase.setImportPathList(paths);
1702 Adds \a path as a directory where the engine searches for
1703 native plugins for imported modules (referenced in the \c qmldir file).
1705 By default, the list contains only \c ., i.e. the engine searches
1706 in the directory of the \c qmldir file itself.
1708 The newly added \a path will be first in the pluginPathList().
1710 \sa setPluginPathList()
1712 void QQmlEngine::addPluginPath(const QString& path)
1715 d->importDatabase.addPluginPath(path);
1720 Returns the list of directories where the engine searches for
1721 native plugins for imported modules (referenced in the \c qmldir file).
1723 By default, the list contains only \c ., i.e. the engine searches
1724 in the directory of the \c qmldir file itself.
1726 \sa addPluginPath(), setPluginPathList()
1728 QStringList QQmlEngine::pluginPathList() const
1730 Q_D(const QQmlEngine);
1731 return d->importDatabase.pluginPathList();
1735 Sets the list of directories where the engine searches for
1736 native plugins for imported modules (referenced in the \c qmldir file)
1739 By default, the list contains only \c ., i.e. the engine searches
1740 in the directory of the \c qmldir file itself.
1742 \sa pluginPathList(), addPluginPath()
1744 void QQmlEngine::setPluginPathList(const QStringList &paths)
1747 d->importDatabase.setPluginPathList(paths);
1751 Imports the plugin named \a filePath with the \a uri provided.
1752 Returns true if the plugin was successfully imported; otherwise returns false.
1754 On failure and if non-null, the \a errors list will have any errors which occurred prepended to it.
1756 The plugin has to be a Qt plugin which implements the QQmlExtensionPlugin interface.
1758 bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors)
1761 return d->importDatabase.importPlugin(filePath, uri, QString(), errors);
1765 \property QQmlEngine::offlineStoragePath
1766 \brief the directory for storing offline user data
1768 Returns the directory where SQL and other offline
1771 QQuickWebView and the SQL databases created with openDatabase()
1774 The default is QML/OfflineStorage in the platform-standard
1775 user application data directory.
1777 Note that the path may not currently exist on the filesystem, so
1778 callers wanting to \e create new files at this location should create
1779 it first - see QDir::mkpath().
1781 void QQmlEngine::setOfflineStoragePath(const QString& dir)
1784 d->offlineStoragePath = dir;
1787 QString QQmlEngine::offlineStoragePath() const
1789 Q_D(const QQmlEngine);
1790 return d->offlineStoragePath;
1793 QQmlPropertyCache *QQmlEnginePrivate::createCache(const QMetaObject *mo)
1797 if (!mo->superClass()) {
1798 QQmlPropertyCache *rv = new QQmlPropertyCache(q, mo);
1799 propertyCache.insert(mo, rv);
1802 QQmlPropertyCache *super = cache(mo->superClass());
1803 QQmlPropertyCache *rv = super->copyAndAppend(q, mo);
1804 propertyCache.insert(mo, rv);
1809 QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersion,
1812 QList<QQmlType *> types;
1814 int maxMinorVersion = 0;
1816 const QMetaObject *metaObject = type->metaObject();
1818 while (metaObject) {
1819 QQmlType *t = QQmlMetaType::qmlType(metaObject, type->module(),
1820 type->majorVersion(), minorVersion);
1822 maxMinorVersion = qMax(maxMinorVersion, t->minorVersion());
1828 metaObject = metaObject->superClass();
1831 if (QQmlPropertyCache *c = typePropertyCache.value(qMakePair(type, maxMinorVersion))) {
1833 typePropertyCache.insert(qMakePair(type, minorVersion), c);
1837 QQmlPropertyCache *raw = cache(type->metaObject());
1839 bool hasCopied = false;
1841 for (int ii = 0; ii < types.count(); ++ii) {
1842 QQmlType *currentType = types.at(ii);
1846 int rev = currentType->metaObjectRevision();
1847 int moIndex = types.count() - 1 - ii;
1849 if (raw->allowedRevisionCache[moIndex] != rev) {
1854 raw->allowedRevisionCache[moIndex] = rev;
1858 // Test revision compatibility - the basic rule is:
1859 // * Anything that is excluded, cannot overload something that is not excluded *
1861 // Signals override:
1862 // * other signals and methods of the same name.
1863 // * properties named on<Signal Name>
1864 // * automatic <property name>Changed notify signals
1866 // Methods override:
1867 // * other methods of the same name
1869 // Properties override:
1870 // * other elements of the same name
1872 bool overloadError = false;
1873 QString overloadName;
1876 for (QQmlPropertyCache::StringCache::ConstIterator iter = raw->stringCache.begin();
1877 !overloadError && iter != raw->stringCache.end();
1880 QQmlPropertyData *d = *iter;
1881 if (raw->isAllowedInRevision(d))
1882 continue; // Not excluded - no problems
1884 // check that a regular "name" overload isn't happening
1885 QQmlPropertyData *current = d;
1886 while (!overloadError && current) {
1887 current = d->overrideData(current);
1888 if (current && raw->isAllowedInRevision(current))
1889 overloadError = true;
1894 if (overloadError) {
1895 if (hasCopied) raw->release();
1897 error.setDescription(QLatin1String("Type ") + type->qmlTypeName() + QLatin1Char(' ') + QString::number(type->majorVersion()) + QLatin1Char('.') + QString::number(minorVersion) + QLatin1String(" contains an illegal property \"") + overloadName + QLatin1String("\". This is an error in the type's implementation."));
1901 if (!hasCopied) raw->addref();
1902 typePropertyCache.insert(qMakePair(type, minorVersion), raw);
1904 if (minorVersion != maxMinorVersion) {
1906 typePropertyCache.insert(qMakePair(type, maxMinorVersion), raw);
1912 bool QQmlEnginePrivate::isQObject(int t)
1914 Locker locker(this);
1915 return m_compositeTypes.contains(t) || QQmlMetaType::isQObject(t);
1918 QObject *QQmlEnginePrivate::toQObject(const QVariant &v, bool *ok) const
1920 Locker locker(this);
1921 int t = v.userType();
1922 if (t == QMetaType::QObjectStar || m_compositeTypes.contains(t)) {
1924 return *(QObject **)(v.constData());
1926 return QQmlMetaType::toQObject(v, ok);
1930 QQmlMetaType::TypeCategory QQmlEnginePrivate::typeCategory(int t) const
1932 Locker locker(this);
1933 if (m_compositeTypes.contains(t))
1934 return QQmlMetaType::Object;
1935 else if (m_qmlLists.contains(t))
1936 return QQmlMetaType::List;
1938 return QQmlMetaType::typeCategory(t);
1941 bool QQmlEnginePrivate::isList(int t) const
1943 Locker locker(this);
1944 return m_qmlLists.contains(t) || QQmlMetaType::isList(t);
1947 int QQmlEnginePrivate::listType(int t) const
1949 Locker locker(this);
1950 QHash<int, int>::ConstIterator iter = m_qmlLists.find(t);
1951 if (iter != m_qmlLists.end())
1954 return QQmlMetaType::listType(t);
1957 QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const
1959 Locker locker(this);
1960 QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.find(t);
1961 if (iter != m_compositeTypes.end()) {
1962 return QQmlMetaObject((*iter)->rootPropertyCache);
1964 QQmlType *type = QQmlMetaType::qmlType(t);
1965 return QQmlMetaObject(type?type->baseMetaObject():0);
1969 QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const
1971 Locker locker(this);
1972 QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.find(t);
1973 if (iter != m_compositeTypes.end()) {
1974 return QQmlMetaObject((*iter)->rootPropertyCache);
1976 QQmlType *type = QQmlMetaType::qmlType(t);
1977 return QQmlMetaObject(type?type->metaObject():0);
1981 QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t)
1983 Locker locker(this);
1984 QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.find(t);
1985 if (iter != m_compositeTypes.end()) {
1986 return (*iter)->rootPropertyCache;
1988 QQmlType *type = QQmlMetaType::qmlType(t);
1990 return type?cache(type->metaObject()):0;
1994 QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t)
1996 Locker locker(this);
1997 QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.find(t);
1998 if (iter != m_compositeTypes.end()) {
1999 return (*iter)->rootPropertyCache;
2001 QQmlType *type = QQmlMetaType::qmlType(t);
2003 return type?cache(type->baseMetaObject()):0;
2007 void QQmlEnginePrivate::registerCompositeType(QQmlCompiledData *data)
2009 QByteArray name = data->rootPropertyCache->className();
2011 QByteArray ptr = name + '*';
2012 QByteArray lst = "QQmlListProperty<" + name + '>';
2014 int ptr_type = QMetaType::registerNormalizedType(ptr,
2015 QtMetaTypePrivate::QMetaTypeFunctionHelper<QObject*>::Delete,
2016 QtMetaTypePrivate::QMetaTypeFunctionHelper<QObject*>::Create,
2017 QtMetaTypePrivate::QMetaTypeFunctionHelper<QObject*>::Destruct,
2018 QtMetaTypePrivate::QMetaTypeFunctionHelper<QObject*>::Construct,
2020 static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QObject*>::Flags),
2022 int lst_type = QMetaType::registerNormalizedType(lst,
2023 QtMetaTypePrivate::QMetaTypeFunctionHelper<QQmlListProperty<QObject> >::Delete,
2024 QtMetaTypePrivate::QMetaTypeFunctionHelper<QQmlListProperty<QObject> >::Create,
2025 QtMetaTypePrivate::QMetaTypeFunctionHelper<QQmlListProperty<QObject> >::Destruct,
2026 QtMetaTypePrivate::QMetaTypeFunctionHelper<QQmlListProperty<QObject> >::Construct,
2027 sizeof(QQmlListProperty<QObject>),
2028 static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QQmlListProperty<QObject> >::Flags),
2029 static_cast<QMetaObject*>(0));
2031 data->metaTypeId = ptr_type;
2032 data->listMetaTypeId = lst_type;
2033 data->isRegisteredWithEngine = true;
2035 Locker locker(this);
2036 m_qmlLists.insert(lst_type, ptr_type);
2037 // The QQmlCompiledData is not referenced here, but it is removed from this
2038 // hash in the QQmlCompiledData destructor
2039 m_compositeTypes.insert(ptr_type, data);
2042 void QQmlEnginePrivate::unregisterCompositeType(QQmlCompiledData *data)
2044 int ptr_type = data->metaTypeId;
2045 int lst_type = data->listMetaTypeId;
2047 Locker locker(this);
2048 m_qmlLists.remove(lst_type);
2049 m_compositeTypes.remove(ptr_type);
2052 bool QQmlEnginePrivate::isTypeLoaded(const QUrl &url) const
2054 return typeLoader.isTypeLoaded(url);
2057 bool QQmlEnginePrivate::isScriptLoaded(const QUrl &url) const
2059 return typeLoader.isScriptLoaded(url);
2062 bool QQml_isFileCaseCorrect(const QString &fileName)
2064 #if defined(Q_OS_MAC) || defined(Q_OS_WIN)
2065 QFileInfo info(fileName);
2066 const QString absolute = info.absoluteFilePath();
2068 #if defined(Q_OS_MAC) || defined(Q_OS_WINCE)
2069 const QString canonical = info.canonicalFilePath();
2070 #elif defined(Q_OS_WIN)
2071 wchar_t buffer[1024];
2073 DWORD rv = ::GetShortPathName((wchar_t*)absolute.utf16(), buffer, 1024);
2074 if (rv == 0 || rv >= 1024) return true;
2075 rv = ::GetLongPathName(buffer, buffer, 1024);
2076 if (rv == 0 || rv >= 1024) return true;
2078 const QString canonical = QString::fromWCharArray(buffer);
2081 const int absoluteLength = absolute.length();
2082 const int canonicalLength = canonical.length();
2084 const int length = qMin(absoluteLength, canonicalLength);
2085 for (int ii = 0; ii < length; ++ii) {
2086 const QChar &a = absolute.at(absoluteLength - 1 - ii);
2087 const QChar &c = canonical.at(canonicalLength - 1 - ii);
2089 if (a.toLower() != c.toLower())
2101 \fn QQmlEngine *qmlEngine(const QObject *object)
2104 Returns the QQmlEngine associated with \a object, if any. This is equivalent to
2105 QQmlEngine::contextForObject(object)->engine(), but more efficient.
2109 \fn QQmlContext *qmlContext(const QObject *object)
2112 Returns the QQmlContext associated with \a object, if any. This is equivalent to
2113 QQmlEngine::contextForObject(object).