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;
168 bool QQmlEnginePrivate::s_designerMode = false;
170 // these types are part of the QML language
171 void QQmlEnginePrivate::registerBaseTypes(const char *uri, int versionMajor, int versionMinor)
173 qmlRegisterType<QQmlComponent>(uri,versionMajor,versionMinor,"Component");
174 qmlRegisterType<QObject>(uri,versionMajor,versionMinor,"QtObject");
178 // These QtQuick types' implementation resides in the QtQml module
179 void QQmlEnginePrivate::registerQtQuick2Types(const char *uri, int versionMajor, int versionMinor)
181 qmlRegisterType<QQuickListElement>(uri, versionMajor, versionMinor, "ListElement");
182 qmlRegisterCustomType<QQuickListModel>(uri, versionMajor, versionMinor, "ListModel", new QQuickListModelParser);
183 qmlRegisterType<QQuickWorkerScript>(uri, versionMajor, versionMinor, "WorkerScript");
186 void QQmlEnginePrivate::defineQtQuick2Module()
188 // register the base types into the QtQuick namespace
189 registerBaseTypes("QtQuick",2,0);
191 // register the QtQuick2 types which are implemented in the QtQml module.
192 registerQtQuick2Types("QtQuick",2,0);
193 qmlRegisterUncreatableType<QQmlLocale>("QtQuick", 2, 0, "Locale", QQmlEngine::tr("Locale cannot be instantiated. Use Qt.locale()"));
196 bool QQmlEnginePrivate::designerMode()
198 return s_designerMode;
201 void QQmlEnginePrivate::activateDesignerMode()
203 s_designerMode = true;
208 \class QQmlImageProviderBase
209 \brief The QQmlImageProviderBase class is used to register image providers in the QML engine.
213 Image providers must be registered with the QML engine. The only information the QML
214 engine knows about image providers is the type of image data they provide. To use an
215 image provider to acquire image data, you must cast the QQmlImageProviderBase pointer
216 to a QQuickImageProvider pointer.
218 \sa QQuickImageProvider, QQuickTextureFactory
222 \enum QQmlImageProviderBase::ImageType
224 Defines the type of image supported by this image provider.
226 \value Image The Image Provider provides QImage images.
227 The QQuickImageProvider::requestImage() method will be called for all image requests.
228 \value Pixmap The Image Provider provides QPixmap images.
229 The QQuickImageProvider::requestPixmap() method will be called for all image requests.
230 \value Texture The Image Provider provides QSGTextureProvider based images.
231 The QQuickImageProvider::requestTexture() method will be called for all image requests.
236 \enum QQmlImageProviderBase::Flag
238 Defines specific requirements or features of this image provider.
240 \value ForceAsynchronousImageLoading Ensures that image requests to the provider are
241 run in a separate thread, which allows the provider to spend as much time as needed
242 on producing the image without blocking the main thread.
246 QQmlImageProviderBase::QQmlImageProviderBase()
251 QQmlImageProviderBase::~QQmlImageProviderBase()
258 \instantiates QQmlEnginePrivate
259 \ingroup qml-utility-elements
260 \brief The QML global Qt object provides useful enums and functions from Qt.
262 \keyword QmlGlobalQtObject
264 \brief The \c Qt object provides useful enums and functions from Qt, for use in all QML files.
266 The \c Qt object is a global object with utility functions, properties and enums.
268 It is not instantiable; to use it, call the members of the global \c Qt object directly.
275 color: Qt.rgba(1, 0, 0, 1)
276 text: Qt.md5("hello, world")
283 The Qt object contains the enums available in the \l {Qt Namespace}. For example, you can access
284 the \l Qt::LeftButton and \l Qt::RightButton enumeration values as \c Qt.LeftButton and \c Qt.RightButton.
289 The Qt object also contains helper functions for creating objects of specific
290 data types. This is primarily useful when setting the properties of an item
291 when the property has one of the following types:
293 \li \c rect - use \l{Qt::rect()}{Qt.rect()}
294 \li \c point - use \l{Qt::point()}{Qt.point()}
295 \li \c size - use \l{Qt::size()}{Qt.size()}
298 If the QtQuick module has been imported, the following helper functions for
299 creating objects of specific data types are also available for clients to use:
301 \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()}
302 \li \c font - use \l{Qt::font()}{Qt.font()}
303 \li \c vector2d - use \l{Qt::vector2d()}{Qt.vector2d()}
304 \li \c vector3d - use \l{Qt::vector3d()}{Qt.vector3d()}
305 \li \c vector4d - use \l{Qt::vector4d()}{Qt.vector4d()}
306 \li \c quaternion - use \l{Qt::quaternion()}{Qt.quaternion()}
307 \li \c matrix4x4 - use \l{Qt::matrix4x4()}{Qt.matrix4x4()}
310 There are also string based constructors for these types. See \l{qtqml-typesystem-basictypes.html}{QML Basic Types} for more information.
312 \section1 Date/Time Formatters
314 The Qt object contains several functions for formatting QDateTime, QDate and QTime values.
317 \li \l{Qt::formatDateTime}{string Qt.formatDateTime(datetime date, variant format)}
318 \li \l{Qt::formatDate}{string Qt.formatDate(datetime date, variant format)}
319 \li \l{Qt::formatTime}{string Qt.formatTime(datetime date, variant format)}
322 The format specification is described at \l{Qt::formatDateTime}{Qt.formatDateTime}.
325 \section1 Dynamic Object Creation
326 The following functions on the global object allow you to dynamically create QML
327 items from files or strings. See \l{Dynamic QML Object Creation from JavaScript} for an overview
331 \li \l{Qt::createComponent()}{object Qt.createComponent(url)}
332 \li \l{Qt::createQmlObject()}{object Qt.createQmlObject(string qml, object parent, string filepath)}
336 \section1 Other Functions
338 The following functions are also on the Qt object.
341 \li \l{Qt::quit()}{Qt.quit()}
342 \li \l{Qt::md5()}{Qt.md5(string)}
343 \li \l{Qt::btoa()}{string Qt.btoa(string)}
344 \li \l{Qt::atob()}{string Qt.atob(string)}
345 \li \l{Qt::binding()}{object Qt.binding(function)}
346 \li \l{Qt::locale()}{object Qt.locale()}
347 \li \l{Qt::resolvedUrl()}{string Qt.resolvedUrl(string)}
348 \li \l{Qt::openUrlExternally()}{Qt.openUrlExternally(string)}
349 \li \l{Qt::fontFamilies()}{list<string> Qt.fontFamilies()}
354 \qmlproperty object Qt::application
357 The \c application object provides access to global application state
358 properties shared by many QML components.
364 \li \c application.active
366 This read-only property indicates whether the application is the top-most and focused
367 application, and the user is able to interact with the application. The property
368 is false when the application is in the background, the device keylock or screen
369 saver is active, the screen backlight is turned off, or the global system dialog
370 is being displayed on top of the application. It can be used for stopping and
371 pausing animations, timers and active processing of data in order to save device
372 battery power and free device memory and processor load when the application is not
376 \li \c application.layoutDirection
378 This read-only property can be used to query the default layout direction of the
379 application. On system start-up, the default layout direction depends on the
380 application's language. The property has a value of \c Qt.RightToLeft in locales
381 where text and graphic elements are read from right to left, and \c Qt.LeftToRight
382 where the reading direction flows from left to right. You can bind to this
383 property to customize your application layouts to support both layout directions.
388 \li Qt.LeftToRight - Text and graphics elements should be positioned
390 \li Qt.RightToLeft - Text and graphics elements should be positioned
396 The following example uses the \c application object to indicate
397 whether the application is currently active:
399 \snippet qml/application.qml document
403 \qmlproperty object Qt::inputMethod
406 The \c inputMethod object allows access to application's QInputMethod object
407 and all its properties and slots. See the QInputMethod documentation for
413 \qmlmethod object Qt::include(string url, jsobject callback)
415 Includes another JavaScript file. This method can only be used from within JavaScript files,
416 and not regular QML files.
418 This imports all functions from \a url into the current script's namespace.
420 Qt.include() returns an object that describes the status of the operation. The object has
421 a single property, \c {status}, that is set to one of the following values:
424 \header \li Symbol \li Value \li Description
425 \row \li result.OK \li 0 \li The include completed successfully.
426 \row \li result.LOADING \li 1 \li Data is being loaded from the network.
427 \row \li result.NETWORK_ERROR \li 2 \li A network error occurred while fetching the url.
428 \row \li result.EXCEPTION \li 3 \li A JavaScript exception occurred while executing the included code.
429 An additional \c exception property will be set in this case.
432 The \c status property will be updated as the operation progresses.
434 If provided, \a callback is invoked when the operation completes. The callback is passed
435 the same object as is returned from the Qt.include() call.
437 // Qt.include() is implemented in qv8include.cpp
440 QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e)
441 : propertyCapture(0), rootContext(0), isDebugging(false),
442 outputWarningsToStdErr(true), sharedContext(0), sharedScope(0),
443 cleanup(0), erroredBindings(0), inProgressCreations(0),
444 workerScriptEngine(0), activeVME(0),
445 networkAccessManager(0), networkAccessManagerFactory(0),
446 scarceResourcesRefCount(0), typeLoader(e), importDatabase(e), uniqueId(1),
447 incubatorCount(0), incubationController(0), mutex(QMutex::Recursive)
451 QQmlEnginePrivate::~QQmlEnginePrivate()
453 if (inProgressCreations)
454 qWarning() << QQmlEngine::tr("There are still \"%1\" items in the process of being created at engine destruction.").arg(inProgressCreations);
457 QQmlCleanup *c = cleanup;
459 if (cleanup) cleanup->prev = &cleanup;
465 doDeleteInEngineThread();
467 if (incubationController) incubationController->d = 0;
468 incubationController = 0;
473 for(QHash<const QMetaObject *, QQmlPropertyCache *>::Iterator iter = propertyCache.begin(); iter != propertyCache.end(); ++iter)
475 for(QHash<QPair<QQmlType *, int>, QQmlPropertyCache *>::Iterator iter = typePropertyCache.begin(); iter != typePropertyCache.end(); ++iter)
477 for (QHash<int, QQmlCompiledData *>::Iterator iter = m_compositeTypes.begin(); iter != m_compositeTypes.end(); ++iter)
478 iter.value()->isRegisteredWithEngine = false;
481 void QQmlPrivate::qdeclarativeelement_destructor(QObject *o)
483 QObjectPrivate *p = QObjectPrivate::get(o);
484 if (p->declarativeData) {
485 QQmlData *d = static_cast<QQmlData*>(p->declarativeData);
486 if (d->ownContext && d->context) {
487 d->context->destroy();
491 // Mark this object as in the process of deletion to
492 // prevent it resolving in bindings
493 QQmlData::markAsDeleted(o);
495 // Disconnect the notifiers now - during object destruction this would be too late, since
496 // the disconnect call wouldn't be able to call disconnectNotify(), as it isn't possible to
497 // get the metaobject anymore.
498 d->disconnectNotifiers();
502 void QQmlData::destroyed(QAbstractDeclarativeData *d, QObject *o)
504 static_cast<QQmlData *>(d)->destroyed(o);
507 void QQmlData::parentChanged(QAbstractDeclarativeData *d, QObject *o, QObject *p)
509 static_cast<QQmlData *>(d)->parentChanged(o, p);
512 class QQmlThreadNotifierProxyObject : public QObject
515 QPointer<QObject> target;
517 virtual int qt_metacall(QMetaObject::Call, int methodIndex, void **a) {
521 QMetaMethod method = target->metaObject()->method(methodIndex);
522 Q_ASSERT(method.methodType() == QMetaMethod::Signal);
523 int signalIndex = QMetaObjectPrivate::signalIndex(method);
524 QQmlData *ddata = QQmlData::get(target, false);
525 QQmlNotifierEndpoint *ep = ddata->notify(signalIndex);
526 if (ep) QQmlNotifier::emitNotify(ep, a);
534 void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int index, void **a)
536 QQmlData *ddata = QQmlData::get(object, false);
537 if (!ddata) return; // Probably being deleted
539 // In general, QML only supports QObject's that live on the same thread as the QQmlEngine
540 // that they're exposed to. However, to make writing "worker objects" that calculate data
541 // in a separate thread easier, QML allows a QObject that lives in the same thread as the
542 // QQmlEngine to emit signals from a different thread. These signals are then automatically
543 // marshalled back onto the QObject's thread and handled by QML from there. This is tested
544 // by the qqmlecmascript::threadSignal() autotest.
545 if (ddata->notifyList &&
546 QThread::currentThreadId() != QObjectPrivate::get(object)->threadData->threadId) {
548 if (!QObjectPrivate::get(object)->threadData->thread)
551 QMetaMethod m = QMetaObjectPrivate::signal(object->metaObject(), index);
552 QList<QByteArray> parameterTypes = m.parameterTypes();
554 int *types = (int *)malloc((parameterTypes.count() + 1) * sizeof(int));
555 void **args = (void **) malloc((parameterTypes.count() + 1) *sizeof(void *));
557 types[0] = 0; // return type
558 args[0] = 0; // return value
560 for (int ii = 0; ii < parameterTypes.count(); ++ii) {
561 const QByteArray &typeName = parameterTypes.at(ii);
562 if (typeName.endsWith('*'))
563 types[ii + 1] = QMetaType::VoidStar;
565 types[ii + 1] = QMetaType::type(typeName);
567 if (!types[ii + 1]) {
568 qWarning("QObject::connect: Cannot queue arguments of type '%s'\n"
569 "(Make sure '%s' is registered using qRegisterMetaType().)",
570 typeName.constData(), typeName.constData());
576 args[ii + 1] = QMetaType::create(types[ii + 1], a[ii + 1]);
579 QMetaCallEvent *ev = new QMetaCallEvent(m.methodIndex(), 0, 0, object, index,
580 parameterTypes.count() + 1, types, args);
582 QQmlThreadNotifierProxyObject *mpo = new QQmlThreadNotifierProxyObject;
583 mpo->target = object;
584 mpo->moveToThread(QObjectPrivate::get(object)->threadData->thread);
585 QCoreApplication::postEvent(mpo, ev);
588 QQmlNotifierEndpoint *ep = ddata->notify(index);
589 if (ep) QQmlNotifier::emitNotify(ep, a);
593 int QQmlData::receivers(QAbstractDeclarativeData *d, const QObject *, int index)
595 return static_cast<QQmlData *>(d)->endpointCount(index);
598 bool QQmlData::isSignalConnected(QAbstractDeclarativeData *d, const QObject *, int index)
600 return static_cast<QQmlData *>(d)->signalHasEndpoint(index);
603 int QQmlData::endpointCount(int index)
606 QQmlNotifierEndpoint *ep = notify(index);
617 void QQmlData::markAsDeleted(QObject *o)
619 QQmlData::setQueuedForDeletion(o);
621 QObjectPrivate *p = QObjectPrivate::get(o);
622 for (QList<QObject *>::iterator it = p->children.begin(), end = p->children.end(); it != end; ++it) {
623 QQmlData::markAsDeleted(*it);
627 void QQmlData::setQueuedForDeletion(QObject *object)
630 if (QObjectPrivate *priv = QObjectPrivate::get(object)) {
631 if (!priv->wasDeleted && priv->declarativeData) {
632 QQmlData *ddata = QQmlData::get(object, false);
633 if (ddata->ownContext && ddata->context)
634 ddata->context->emitDestruction();
635 ddata->isQueuedForDeletion = true;
641 void QQmlData::flushPendingBindingImpl(int coreIndex)
643 clearPendingBindingBit(coreIndex);
646 QQmlAbstractBinding *b = bindings;
647 while (b && *b->m_mePtr && b->propertyIndex() != coreIndex)
648 b = b->nextBinding();
652 b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor |
653 QQmlPropertyPrivate::DontRemoveBinding);
657 void QQmlEnginePrivate::init()
661 static bool firstTime = true;
663 qmlRegisterType<QQmlComponent>("QML", 1, 0, "Component"); // required for the Compiler.
664 registerBaseTypes("QtQml", 2, 0); // import which provides language building blocks.
670 qRegisterMetaType<QVariant>("QVariant");
671 qRegisterMetaType<QQmlScriptString>("QQmlScriptString");
672 qRegisterMetaType<QJSValue>("QJSValue");
673 qRegisterMetaType<QQmlComponent::Status>("QQmlComponent::Status");
674 qRegisterMetaType<QList<QObject*> >("QList<QObject*>");
675 qRegisterMetaType<QList<int> >("QList<int>");
676 qRegisterMetaType<QQmlV8Handle>("QQmlV8Handle");
678 v8engine()->setEngine(q);
680 rootContext = new QQmlContext(q,true);
682 if (QCoreApplication::instance()->thread() == q->thread() &&
683 QQmlEngineDebugService::isDebuggingEnabled()) {
685 QQmlEngineDebugService::instance()->addEngine(q);
686 QV8DebugService::initialize(v8engine());
687 QV8ProfilerService::initialize();
688 QQmlProfilerService::initialize();
689 QDebugMessageService::instance();
692 QString dataLocation = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
693 if (!dataLocation.isEmpty())
694 offlineStoragePath = dataLocation.replace(QLatin1Char('/'), QDir::separator())
695 + QDir::separator() + QLatin1String("QML")
696 + QDir::separator() + QLatin1String("OfflineStorage");
699 QQuickWorkerScriptEngine *QQmlEnginePrivate::getWorkerScriptEngine()
702 if (!workerScriptEngine)
703 workerScriptEngine = new QQuickWorkerScriptEngine(q);
704 return workerScriptEngine;
711 \brief The QQmlEngine class provides an environment for instantiating QML components.
714 Each QML component is instantiated in a QQmlContext.
715 QQmlContext's are essential for passing data to QML
716 components. In QML, contexts are arranged hierarchically and this
717 hierarchy is managed by the QQmlEngine.
719 Prior to creating any QML components, an application must have
720 created a QQmlEngine to gain access to a QML context. The
721 following example shows how to create a simple Text item.
725 QQmlComponent component(&engine);
726 component.setData("import QtQuick 2.0\nText { text: \"Hello world!\" }", QUrl());
727 QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
729 //add item to view, etc
733 In this case, the Text item will be created in the engine's
734 \l {QQmlEngine::rootContext()}{root context}.
736 Note that the QtQuick 1 version is called QDeclarativeEngine.
738 \sa QQmlComponent, QQmlContext
742 Create a new QQmlEngine with the given \a parent.
744 QQmlEngine::QQmlEngine(QObject *parent)
745 : QJSEngine(*new QQmlEnginePrivate(this), parent)
752 Destroys the QQmlEngine.
754 Any QQmlContext's created on this engine will be
755 invalidated, but not destroyed (unless they are parented to the
758 QQmlEngine::~QQmlEngine()
761 if (d->isDebugging) {
762 QQmlEngineDebugService::instance()->remEngine(this);
765 // Emit onDestruction signals for the root context before
766 // we destroy the contexts, engine, Singleton Types etc. that
767 // may be required to handle the destruction signal.
768 QQmlContextData::get(rootContext())->emitDestruction();
770 // clean up all singleton type instances which we own.
771 // we do this here and not in the private dtor since otherwise a crash can
772 // occur (if we are the QObject parent of the QObject singleton instance)
773 // XXX TODO: performance -- store list of singleton types separately?
774 QList<QQmlType*> singletonTypes = QQmlMetaType::qmlSingletonTypes();
775 foreach (QQmlType *currType, singletonTypes)
776 currType->singletonInstanceInfo()->destroy(this);
778 if (d->incubationController)
779 d->incubationController->d = 0;
782 /*! \fn void QQmlEngine::quit()
783 This signal is emitted when the QML loaded by the engine would like to quit.
786 /*! \fn void QQmlEngine::warnings(const QList<QQmlError> &warnings)
787 This signal is emitted when \a warnings messages are generated by QML.
791 Clears the engine's internal component cache.
793 This function causes the property metadata of all components previously
794 loaded by the engine to be destroyed. All previously loaded components and
795 the property bindings for all extant objects created from those components will
798 This function returns the engine to a state where it does not contain any loaded
799 component data. This may be useful in order to reload a smaller subset of the
800 previous component set, or to load a new version of a previously loaded component.
802 Once the component cache has been cleared, components must be loaded before
803 any new objects can be created.
805 \sa trimComponentCache()
807 void QQmlEngine::clearComponentCache()
810 d->typeLoader.clearCache();
814 Trims the engine's internal component cache.
816 This function causes the property metadata of any loaded components which are
817 not currently in use to be destroyed.
819 A component is considered to be in use if there are any extant instances of
820 the component itself, any instances of other components that use the component,
821 or any objects instantiated by any of those components.
823 \sa clearComponentCache()
825 void QQmlEngine::trimComponentCache()
828 d->typeLoader.trimCache();
832 Returns the engine's root context.
834 The root context is automatically created by the QQmlEngine.
835 Data that should be available to all QML component instances
836 instantiated by the engine should be put in the root context.
838 Additional data that should only be available to a subset of
839 component instances should be added to sub-contexts parented to the
842 QQmlContext *QQmlEngine::rootContext() const
844 Q_D(const QQmlEngine);
845 return d->rootContext;
849 Sets the \a factory to use for creating QNetworkAccessManager(s).
851 QNetworkAccessManager is used for all network access by QML. By
852 implementing a factory it is possible to create custom
853 QNetworkAccessManager with specialized caching, proxy and cookie
856 The factory must be set before executing the engine.
858 void QQmlEngine::setNetworkAccessManagerFactory(QQmlNetworkAccessManagerFactory *factory)
861 QMutexLocker locker(&d->mutex);
862 d->networkAccessManagerFactory = factory;
866 Returns the current QQmlNetworkAccessManagerFactory.
868 \sa setNetworkAccessManagerFactory()
870 QQmlNetworkAccessManagerFactory *QQmlEngine::networkAccessManagerFactory() const
872 Q_D(const QQmlEngine);
873 return d->networkAccessManagerFactory;
876 void QQmlEnginePrivate::registerFinalizeCallback(QObject *obj, int index)
879 activeVME->finalizeCallbacks.append(qMakePair(QQmlGuard<QObject>(obj), index));
881 void *args[] = { 0 };
882 QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, index, args);
886 QNetworkAccessManager *QQmlEnginePrivate::createNetworkAccessManager(QObject *parent) const
888 QMutexLocker locker(&mutex);
889 QNetworkAccessManager *nam;
890 if (networkAccessManagerFactory) {
891 nam = networkAccessManagerFactory->create(parent);
893 nam = new QNetworkAccessManager(parent);
899 QNetworkAccessManager *QQmlEnginePrivate::getNetworkAccessManager() const
901 Q_Q(const QQmlEngine);
902 if (!networkAccessManager)
903 networkAccessManager = createNetworkAccessManager(const_cast<QQmlEngine*>(q));
904 return networkAccessManager;
908 Returns a common QNetworkAccessManager which can be used by any QML
909 type instantiated by this engine.
911 If a QQmlNetworkAccessManagerFactory has been set and a
912 QNetworkAccessManager has not yet been created, the
913 QQmlNetworkAccessManagerFactory will be used to create the
914 QNetworkAccessManager; otherwise the returned QNetworkAccessManager
915 will have no proxy or cache set.
917 \sa setNetworkAccessManagerFactory()
919 QNetworkAccessManager *QQmlEngine::networkAccessManager() const
921 Q_D(const QQmlEngine);
922 return d->getNetworkAccessManager();
927 Sets the \a provider to use for images requested via the \e
928 image: url scheme, with host \a providerId. The QQmlEngine
929 takes ownership of \a provider.
931 Image providers enable support for pixmap and threaded image
932 requests. See the QQuickImageProvider documentation for details on
933 implementing and using image providers.
935 All required image providers should be added to the engine before any
936 QML sources files are loaded.
938 \sa removeImageProvider(), QQuickImageProvider, QQmlImageProviderBase
940 void QQmlEngine::addImageProvider(const QString &providerId, QQmlImageProviderBase *provider)
943 QMutexLocker locker(&d->mutex);
944 d->imageProviders.insert(providerId.toLower(), QSharedPointer<QQmlImageProviderBase>(provider));
948 Returns the image provider set for \a providerId.
950 Returns the provider if it was found; otherwise returns 0.
952 \sa QQuickImageProvider
954 QQmlImageProviderBase *QQmlEngine::imageProvider(const QString &providerId) const
956 Q_D(const QQmlEngine);
957 QMutexLocker locker(&d->mutex);
958 return d->imageProviders.value(providerId).data();
962 Removes the image provider for \a providerId.
964 \sa addImageProvider(), QQuickImageProvider
966 void QQmlEngine::removeImageProvider(const QString &providerId)
969 QMutexLocker locker(&d->mutex);
970 d->imageProviders.take(providerId);
974 Return the base URL for this engine. The base URL is only used to
975 resolve components when a relative URL is passed to the
976 QQmlComponent constructor.
978 If a base URL has not been explicitly set, this method returns the
979 application's current working directory.
983 QUrl QQmlEngine::baseUrl() const
985 Q_D(const QQmlEngine);
986 if (d->baseUrl.isEmpty()) {
987 return QUrl::fromLocalFile(QDir::currentPath() + QDir::separator());
994 Set the base URL for this engine to \a url.
998 void QQmlEngine::setBaseUrl(const QUrl &url)
1005 Returns true if warning messages will be output to stderr in addition
1006 to being emitted by the warnings() signal, otherwise false.
1008 The default value is true.
1010 bool QQmlEngine::outputWarningsToStandardError() const
1012 Q_D(const QQmlEngine);
1013 return d->outputWarningsToStdErr;
1017 Set whether warning messages will be output to stderr to \a enabled.
1019 If \a enabled is true, any warning messages generated by QML will be
1020 output to stderr and emitted by the warnings() signal. If \a enabled
1021 is false, on the warnings() signal will be emitted. This allows
1022 applications to handle warning output themselves.
1024 The default value is true.
1026 void QQmlEngine::setOutputWarningsToStandardError(bool enabled)
1029 d->outputWarningsToStdErr = enabled;
1033 Returns the QQmlContext for the \a object, or 0 if no
1034 context has been set.
1036 When the QQmlEngine instantiates a QObject, the context is
1039 QQmlContext *QQmlEngine::contextForObject(const QObject *object)
1044 QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object));
1047 static_cast<QQmlData *>(priv->declarativeData);
1051 else if (data->outerContext)
1052 return data->outerContext->asQQmlContext();
1058 Sets the QQmlContext for the \a object to \a context.
1059 If the \a object already has a context, a warning is
1060 output, but the context is not changed.
1062 When the QQmlEngine instantiates a QObject, the context is
1065 void QQmlEngine::setContextForObject(QObject *object, QQmlContext *context)
1067 if (!object || !context)
1070 QQmlData *data = QQmlData::get(object, true);
1071 if (data->context) {
1072 qWarning("QQmlEngine::setContextForObject(): Object already has a QQmlContext");
1076 QQmlContextData *contextData = QQmlContextData::get(context);
1077 contextData->addObject(object);
1081 \enum QQmlEngine::ObjectOwnership
1083 Ownership controls whether or not QML automatically destroys the
1084 QObject when the object is garbage collected by the JavaScript
1085 engine. The two ownership options are:
1087 \value CppOwnership The object is owned by C++ code, and will
1088 never be deleted by QML. The JavaScript destroy() method cannot be
1089 used on objects with CppOwnership. This option is similar to
1090 QScriptEngine::QtOwnership.
1092 \value JavaScriptOwnership The object is owned by JavaScript.
1093 When the object is returned to QML as the return value of a method
1094 call or property access, QML will track it, and delete the object
1095 if there are no remaining JavaScript references to it and it has no
1096 QObject::parent(). An object tracked by one QQmlEngine
1097 will be deleted during that QQmlEngine's destructor, and thus
1098 JavaScript references between objects with JavaScriptOwnership from
1099 two different engines will not be valid after the deletion of one of
1100 those engines. This option is similar to QScriptEngine::ScriptOwnership.
1102 Generally an application doesn't need to set an object's ownership
1103 explicitly. QML uses a heuristic to set the default object
1104 ownership. By default, an object that is created by QML has
1105 JavaScriptOwnership. The exception to this are the root objects
1106 created by calling QQmlComponent::create() or
1107 QQmlComponent::beginCreate() which have CppOwnership by
1108 default. The ownership of these root-level objects is considered to
1109 have been transferred to the C++ caller.
1111 Objects not-created by QML have CppOwnership by default. The
1112 exception to this is objects returned from C++ method calls; in these cases,
1113 the ownership of the returned objects will be set to JavaScriptOwnerShip.
1114 Note this applies only to explicit invocations of Q_INVOKABLE methods or slots,
1115 and not to property getter invocations.
1117 Calling setObjectOwnership() overrides the default ownership
1118 heuristic used by QML.
1122 Sets the \a ownership of \a object.
1124 void QQmlEngine::setObjectOwnership(QObject *object, ObjectOwnership ownership)
1129 QQmlData *ddata = QQmlData::get(object, true);
1133 ddata->indestructible = (ownership == CppOwnership)?true:false;
1134 ddata->explicitIndestructibleSet = true;
1138 Returns the ownership of \a object.
1140 QQmlEngine::ObjectOwnership QQmlEngine::objectOwnership(QObject *object)
1143 return CppOwnership;
1145 QQmlData *ddata = QQmlData::get(object, false);
1147 return CppOwnership;
1149 return ddata->indestructible?CppOwnership:JavaScriptOwnership;
1152 bool QQmlEngine::event(QEvent *e)
1155 if (e->type() == QEvent::User)
1156 d->doDeleteInEngineThread();
1158 return QJSEngine::event(e);
1161 void QQmlEnginePrivate::doDeleteInEngineThread()
1163 QFieldList<Deletable, &Deletable::next> list;
1165 list.copyAndClear(toDeleteInEngineThread);
1168 while (Deletable *d = list.takeFirst())
1172 Q_AUTOTEST_EXPORT void qmlExecuteDeferred(QObject *object)
1174 QQmlData *data = QQmlData::get(object);
1176 if (data && data->compiledData && data->deferredIdx) {
1177 QQmlObjectCreatingProfiler prof;
1179 QQmlType *type = QQmlMetaType::qmlType(object->metaObject());
1180 prof.setTypeName(type ? type->qmlTypeName()
1181 : QString::fromUtf8(object->metaObject()->className()));
1182 if (data->outerContext)
1183 prof.setLocation(data->outerContext->url, data->lineNumber, data->columnNumber);
1185 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine);
1187 QQmlComponentPrivate::ConstructionState state;
1188 QQmlComponentPrivate::beginDeferred(ep, object, &state);
1190 // Release the reference for the deferral action (we still have one from construction)
1191 data->compiledData->release();
1192 data->compiledData = 0;
1194 QQmlComponentPrivate::complete(ep, &state);
1198 QQmlContext *qmlContext(const QObject *obj)
1200 return QQmlEngine::contextForObject(obj);
1203 QQmlEngine *qmlEngine(const QObject *obj)
1205 QQmlData *data = QQmlData::get(obj, false);
1206 if (!data || !data->context)
1208 return data->context->engine;
1211 QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create)
1213 QQmlData *data = QQmlData::get(object);
1215 return 0; // Attached properties are only on objects created by QML
1217 QObject *rv = data->hasExtendedData()?data->attachedProperties()->value(id):0;
1221 QQmlAttachedPropertiesFunc pf = QQmlMetaType::attachedPropertiesFuncById(id);
1225 rv = pf(const_cast<QObject *>(object));
1228 data->attachedProperties()->insert(id, rv);
1233 QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *object,
1234 const QMetaObject *attachedMetaObject, bool create)
1237 *idCache = QQmlMetaType::attachedPropertiesFuncId(attachedMetaObject);
1239 if (*idCache == -1 || !object)
1242 return qmlAttachedPropertiesObjectById(*idCache, object, create);
1245 QQmlDebuggingEnabler::QQmlDebuggingEnabler(bool printWarning)
1247 #ifndef QQML_NO_DEBUG_PROTOCOL
1248 if (!QQmlEnginePrivate::qml_debugging_enabled
1250 qDebug("QML debugging is enabled. Only use this in a safe environment.");
1252 QQmlEnginePrivate::qml_debugging_enabled = true;
1257 class QQmlDataExtended {
1260 ~QQmlDataExtended();
1262 QHash<int, QObject *> attachedProperties;
1265 QQmlDataExtended::QQmlDataExtended()
1269 QQmlDataExtended::~QQmlDataExtended()
1273 void QQmlData::NotifyList::layout(QQmlNotifierEndpoint *endpoint)
1276 layout(endpoint->next);
1278 int index = endpoint->sourceSignal;
1279 index = qMin(index, 0xFFFF - 1);
1281 endpoint->next = notifies[index];
1282 if (endpoint->next) endpoint->next->prev = &endpoint->next;
1283 endpoint->prev = ¬ifies[index];
1284 notifies[index] = endpoint;
1287 void QQmlData::NotifyList::layout()
1289 Q_ASSERT(maximumTodoIndex >= notifiesSize);
1292 QQmlNotifierEndpoint **old = notifies;
1293 const int reallocSize = (maximumTodoIndex + 1) * sizeof(QQmlNotifierEndpoint*);
1294 notifies = (QQmlNotifierEndpoint**)realloc(notifies, reallocSize);
1295 const int memsetSize = (maximumTodoIndex - notifiesSize + 1) *
1296 sizeof(QQmlNotifierEndpoint*);
1297 memset(notifies + notifiesSize, 0, memsetSize);
1299 if (notifies != old) {
1300 for (int ii = 0; ii < notifiesSize; ++ii)
1302 notifies[ii]->prev = ¬ifies[ii];
1305 notifiesSize = maximumTodoIndex + 1;
1310 maximumTodoIndex = 0;
1314 void QQmlData::addNotify(int index, QQmlNotifierEndpoint *endpoint)
1317 notifyList = (NotifyList *)malloc(sizeof(NotifyList));
1318 notifyList->connectionMask = 0;
1319 notifyList->maximumTodoIndex = 0;
1320 notifyList->notifiesSize = 0;
1321 notifyList->todo = 0;
1322 notifyList->notifies = 0;
1325 Q_ASSERT(!endpoint->isConnected());
1327 index = qMin(index, 0xFFFF - 1);
1328 notifyList->connectionMask |= (1ULL << quint64(index % 64));
1330 if (index < notifyList->notifiesSize) {
1332 endpoint->next = notifyList->notifies[index];
1333 if (endpoint->next) endpoint->next->prev = &endpoint->next;
1334 endpoint->prev = ¬ifyList->notifies[index];
1335 notifyList->notifies[index] = endpoint;
1338 notifyList->maximumTodoIndex = qMax(int(notifyList->maximumTodoIndex), index);
1340 endpoint->next = notifyList->todo;
1341 if (endpoint->next) endpoint->next->prev = &endpoint->next;
1342 endpoint->prev = ¬ifyList->todo;
1343 notifyList->todo = endpoint;
1348 index MUST in the range returned by QObjectPrivate::signalIndex()
1349 This is different than the index returned by QMetaMethod::methodIndex()
1351 bool QQmlData::signalHasEndpoint(int index)
1353 return notifyList && (notifyList->connectionMask & (1ULL << quint64(index % 64)));
1356 void QQmlData::disconnectNotifiers()
1359 while (notifyList->todo)
1360 notifyList->todo->disconnect();
1361 for (int ii = 0; ii < notifyList->notifiesSize; ++ii) {
1362 while (QQmlNotifierEndpoint *ep = notifyList->notifies[ii])
1365 free(notifyList->notifies);
1371 QHash<int, QObject *> *QQmlData::attachedProperties() const
1373 if (!extendedData) extendedData = new QQmlDataExtended;
1374 return &extendedData->attachedProperties;
1377 void QQmlData::destroyed(QObject *object)
1379 if (nextContextObject)
1380 nextContextObject->prevContextObject = prevContextObject;
1381 if (prevContextObject)
1382 *prevContextObject = nextContextObject;
1384 QQmlAbstractBinding *binding = bindings;
1386 QQmlAbstractBinding *next = binding->nextBinding();
1387 binding->setAddedToObject(false);
1388 binding->setNextBinding(0);
1394 compiledData->release();
1398 QQmlAbstractBoundSignal *signalHandler = signalHandlers;
1399 while (signalHandler) {
1400 if (signalHandler->isEvaluating()) {
1401 // The object is being deleted during signal handler evaluation.
1402 // This will cause a crash due to invalid memory access when the
1403 // evaluation has completed.
1404 // Abort with a friendly message instead.
1405 QString locationString;
1406 QQmlBoundSignalExpression *expr = signalHandler->expression();
1408 QString fileName = expr->sourceFile();
1409 if (fileName.isEmpty())
1410 fileName = QStringLiteral("<Unknown File>");
1411 locationString.append(fileName);
1412 locationString.append(QString::fromLatin1(":%0: ").arg(expr->lineNumber()));
1413 QString source = expr->expression();
1414 if (source.size() > 100) {
1415 source.truncate(96);
1416 source.append(QStringLiteral(" ..."));
1418 locationString.append(source);
1420 locationString = QStringLiteral("<Unknown Location>");
1422 qFatal("Object %p destroyed while one of its QML signal handlers is in progress.\n"
1423 "Most likely the object was deleted synchronously (use QObject::deleteLater() "
1424 "instead), or the application is running a nested event loop.\n"
1425 "This behavior is NOT supported!\n"
1426 "%s", object, qPrintable(locationString));
1429 QQmlAbstractBoundSignal *next = signalHandler->m_nextSignal;
1430 signalHandler->m_prevSignal = 0;
1431 signalHandler->m_nextSignal = 0;
1432 delete signalHandler;
1433 signalHandler = next;
1440 propertyCache->release();
1442 if (ownContext && context)
1446 QQmlGuard<QObject> *guard = static_cast<QQmlGuard<QObject> *>(guards);
1447 *guard = (QObject *)0;
1448 guard->objectDestroyed(object);
1451 disconnectNotifiers();
1454 delete extendedData;
1456 // Dispose the handle.
1457 // We don't simply clear it (and wait for next gc cycle to dispose
1458 // via the weak qobject reference callback) as this affects the
1459 // outcomes of v8's gc statistical analysis heuristics, which can
1460 // cause unnecessary growth of the old pointer space js heap area.
1461 qPersistentDispose(v8object);
1467 DEFINE_BOOL_CONFIG_OPTION(parentTest, QML_PARENT_TEST);
1469 void QQmlData::parentChanged(QObject *object, QObject *parent)
1472 if (parentFrozen && !QObjectPrivate::get(object)->wasDeleted) {
1476 { QDebug dbg(&on); dbg << object; on = on.left(on.length() - 1); }
1477 { QDebug dbg(&pn); dbg << parent; pn = pn.left(pn.length() - 1); }
1479 qFatal("Object %s has had its parent frozen by QML and cannot be changed.\n"
1480 "User code is attempting to change it to %s.\n"
1481 "This behavior is NOT supported!", qPrintable(on), qPrintable(pn));
1486 static void QQmlData_setBit(QQmlData *data, QObject *obj, int bit)
1488 if (data->bindingBitsSize <= bit) {
1489 int props = QQmlMetaObject(obj).propertyCount();
1490 Q_ASSERT(bit < 2 * props);
1492 int arraySize = (2 * props + 31) / 32;
1493 int oldArraySize = data->bindingBitsSize / 32;
1495 data->bindingBits = (quint32 *)realloc(data->bindingBits,
1496 arraySize * sizeof(quint32));
1498 memset(data->bindingBits + oldArraySize,
1500 sizeof(quint32) * (arraySize - oldArraySize));
1502 data->bindingBitsSize = arraySize * 32;
1505 data->bindingBits[bit / 32] |= (1 << (bit % 32));
1508 static void QQmlData_clearBit(QQmlData *data, int bit)
1510 if (data->bindingBitsSize > bit)
1511 data->bindingBits[bit / 32] &= ~(1 << (bit % 32));
1514 void QQmlData::clearBindingBit(int coreIndex)
1516 QQmlData_clearBit(this, coreIndex * 2);
1519 void QQmlData::setBindingBit(QObject *obj, int coreIndex)
1521 QQmlData_setBit(this, obj, coreIndex * 2);
1524 void QQmlData::clearPendingBindingBit(int coreIndex)
1526 QQmlData_clearBit(this, coreIndex * 2 + 1);
1529 void QQmlData::setPendingBindingBit(QObject *obj, int coreIndex)
1531 QQmlData_setBit(this, obj, coreIndex * 2 + 1);
1534 void QQmlEnginePrivate::sendQuit()
1538 if (q->receivers(SIGNAL(quit())) == 0) {
1539 qWarning("Signal QQmlEngine::quit() emitted, but no receivers connected to handle it.");
1543 static void dumpwarning(const QQmlError &error)
1545 QMessageLogger(error.url().toString().toLatin1().constData(),
1546 error.line(), 0).warning().nospace()
1547 << qPrintable(error.toString());
1550 static void dumpwarning(const QList<QQmlError> &errors)
1552 for (int ii = 0; ii < errors.count(); ++ii)
1553 dumpwarning(errors.at(ii));
1556 void QQmlEnginePrivate::warning(const QQmlError &error)
1559 q->warnings(QList<QQmlError>() << error);
1560 if (outputWarningsToStdErr)
1564 void QQmlEnginePrivate::warning(const QList<QQmlError> &errors)
1567 q->warnings(errors);
1568 if (outputWarningsToStdErr)
1569 dumpwarning(errors);
1572 void QQmlEnginePrivate::warning(QQmlDelayedError *error)
1575 warning(error->error(q));
1578 void QQmlEnginePrivate::warning(QQmlEngine *engine, const QQmlError &error)
1581 QQmlEnginePrivate::get(engine)->warning(error);
1586 void QQmlEnginePrivate::warning(QQmlEngine *engine, const QList<QQmlError> &error)
1589 QQmlEnginePrivate::get(engine)->warning(error);
1594 void QQmlEnginePrivate::warning(QQmlEngine *engine, QQmlDelayedError *error)
1597 QQmlEnginePrivate::get(engine)->warning(error);
1599 dumpwarning(error->error(0));
1602 void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QQmlError &error)
1605 engine->warning(error);
1610 void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QList<QQmlError> &error)
1613 engine->warning(error);
1619 This function should be called prior to evaluation of any js expression,
1620 so that scarce resources are not freed prematurely (eg, if there is a
1621 nested javascript expression).
1623 void QQmlEnginePrivate::referenceScarceResources()
1625 scarceResourcesRefCount += 1;
1629 This function should be called after evaluation of the js expression is
1630 complete, and so the scarce resources may be freed safely.
1632 void QQmlEnginePrivate::dereferenceScarceResources()
1634 Q_ASSERT(scarceResourcesRefCount > 0);
1635 scarceResourcesRefCount -= 1;
1637 // if the refcount is zero, then evaluation of the "top level"
1638 // expression must have completed. We can safely release the
1639 // scarce resources.
1640 if (scarceResourcesRefCount == 0) {
1641 // iterate through the list and release them all.
1642 // note that the actual SRD is owned by the JS engine,
1643 // so we cannot delete the SRD; but we can free the
1644 // memory used by the variant in the SRD.
1645 while (ScarceResourceData *sr = scarceResources.first()) {
1646 sr->data = QVariant();
1647 scarceResources.remove(sr);
1653 Adds \a path as a directory where the engine searches for
1654 installed modules in a URL-based directory structure.
1656 The \a path may be a local filesystem directory, a
1657 \l {The Qt Resource System}{Qt Resource} path (\c {:/imports}), a
1658 \l {The Qt Resource System}{Qt Resource} url (\c {qrc:/imports}) or a URL.
1660 The \a path will be converted into canonical form before it
1661 is added to the import path list.
1663 The newly added \a path will be first in the importPathList().
1665 \sa setImportPathList(), {QML Modules}
1667 void QQmlEngine::addImportPath(const QString& path)
1670 d->importDatabase.addImportPath(path);
1674 Returns the list of directories where the engine searches for
1675 installed modules in a URL-based directory structure.
1677 For example, if \c /opt/MyApp/lib/imports is in the path, then QML that
1678 imports \c com.mycompany.Feature will cause the QQmlEngine to look
1679 in \c /opt/MyApp/lib/imports/com/mycompany/Feature/ for the components
1680 provided by that module. A \c qmldir file is required for defining the
1681 type version mapping and possibly QML extensions plugins.
1683 By default, the list contains the directory of the application executable,
1684 paths specified in the \c QML2_IMPORT_PATH environment variable,
1685 and the builtin \c Qml2ImportsPath from QLibraryInfo.
1687 \sa addImportPath(), setImportPathList()
1689 QStringList QQmlEngine::importPathList() const
1691 Q_D(const QQmlEngine);
1692 return d->importDatabase.importPathList();
1696 Sets \a paths as the list of directories where the engine searches for
1697 installed modules in a URL-based directory structure.
1699 By default, the list contains the directory of the application executable,
1700 paths specified in the \c QML2_IMPORT_PATH environment variable,
1701 and the builtin \c Qml2ImportsPath from QLibraryInfo.
1703 \sa importPathList(), addImportPath()
1705 void QQmlEngine::setImportPathList(const QStringList &paths)
1708 d->importDatabase.setImportPathList(paths);
1713 Adds \a path as a directory where the engine searches for
1714 native plugins for imported modules (referenced in the \c qmldir file).
1716 By default, the list contains only \c ., i.e. the engine searches
1717 in the directory of the \c qmldir file itself.
1719 The newly added \a path will be first in the pluginPathList().
1721 \sa setPluginPathList()
1723 void QQmlEngine::addPluginPath(const QString& path)
1726 d->importDatabase.addPluginPath(path);
1731 Returns the list of directories where the engine searches for
1732 native plugins for imported modules (referenced in the \c qmldir file).
1734 By default, the list contains only \c ., i.e. the engine searches
1735 in the directory of the \c qmldir file itself.
1737 \sa addPluginPath(), setPluginPathList()
1739 QStringList QQmlEngine::pluginPathList() const
1741 Q_D(const QQmlEngine);
1742 return d->importDatabase.pluginPathList();
1746 Sets the list of directories where the engine searches for
1747 native plugins for imported modules (referenced in the \c qmldir file)
1750 By default, the list contains only \c ., i.e. the engine searches
1751 in the directory of the \c qmldir file itself.
1753 \sa pluginPathList(), addPluginPath()
1755 void QQmlEngine::setPluginPathList(const QStringList &paths)
1758 d->importDatabase.setPluginPathList(paths);
1762 Imports the plugin named \a filePath with the \a uri provided.
1763 Returns true if the plugin was successfully imported; otherwise returns false.
1765 On failure and if non-null, the \a errors list will have any errors which occurred prepended to it.
1767 The plugin has to be a Qt plugin which implements the QQmlExtensionPlugin interface.
1769 bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors)
1772 return d->importDatabase.importPlugin(filePath, uri, QString(), errors);
1776 \property QQmlEngine::offlineStoragePath
1777 \brief the directory for storing offline user data
1779 Returns the directory where SQL and other offline
1782 QQuickWebView and the SQL databases created with openDatabase()
1785 The default is QML/OfflineStorage in the platform-standard
1786 user application data directory.
1788 Note that the path may not currently exist on the filesystem, so
1789 callers wanting to \e create new files at this location should create
1790 it first - see QDir::mkpath().
1792 void QQmlEngine::setOfflineStoragePath(const QString& dir)
1795 d->offlineStoragePath = dir;
1798 QString QQmlEngine::offlineStoragePath() const
1800 Q_D(const QQmlEngine);
1801 return d->offlineStoragePath;
1804 QQmlPropertyCache *QQmlEnginePrivate::createCache(const QMetaObject *mo)
1808 if (!mo->superClass()) {
1809 QQmlPropertyCache *rv = new QQmlPropertyCache(q, mo);
1810 propertyCache.insert(mo, rv);
1813 QQmlPropertyCache *super = cache(mo->superClass());
1814 QQmlPropertyCache *rv = super->copyAndAppend(q, mo);
1815 propertyCache.insert(mo, rv);
1820 QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersion,
1823 QList<QQmlType *> types;
1825 int maxMinorVersion = 0;
1827 const QMetaObject *metaObject = type->metaObject();
1829 while (metaObject) {
1830 QQmlType *t = QQmlMetaType::qmlType(metaObject, type->module(),
1831 type->majorVersion(), minorVersion);
1833 maxMinorVersion = qMax(maxMinorVersion, t->minorVersion());
1839 metaObject = metaObject->superClass();
1842 if (QQmlPropertyCache *c = typePropertyCache.value(qMakePair(type, maxMinorVersion))) {
1844 typePropertyCache.insert(qMakePair(type, minorVersion), c);
1848 QQmlPropertyCache *raw = cache(type->metaObject());
1850 bool hasCopied = false;
1852 for (int ii = 0; ii < types.count(); ++ii) {
1853 QQmlType *currentType = types.at(ii);
1857 int rev = currentType->metaObjectRevision();
1858 int moIndex = types.count() - 1 - ii;
1860 if (raw->allowedRevisionCache[moIndex] != rev) {
1865 raw->allowedRevisionCache[moIndex] = rev;
1869 // Test revision compatibility - the basic rule is:
1870 // * Anything that is excluded, cannot overload something that is not excluded *
1872 // Signals override:
1873 // * other signals and methods of the same name.
1874 // * properties named on<Signal Name>
1875 // * automatic <property name>Changed notify signals
1877 // Methods override:
1878 // * other methods of the same name
1880 // Properties override:
1881 // * other elements of the same name
1883 bool overloadError = false;
1884 QString overloadName;
1887 for (QQmlPropertyCache::StringCache::ConstIterator iter = raw->stringCache.begin();
1888 !overloadError && iter != raw->stringCache.end();
1891 QQmlPropertyData *d = *iter;
1892 if (raw->isAllowedInRevision(d))
1893 continue; // Not excluded - no problems
1895 // check that a regular "name" overload isn't happening
1896 QQmlPropertyData *current = d;
1897 while (!overloadError && current) {
1898 current = d->overrideData(current);
1899 if (current && raw->isAllowedInRevision(current))
1900 overloadError = true;
1905 if (overloadError) {
1906 if (hasCopied) raw->release();
1908 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."));
1912 if (!hasCopied) raw->addref();
1913 typePropertyCache.insert(qMakePair(type, minorVersion), raw);
1915 if (minorVersion != maxMinorVersion) {
1917 typePropertyCache.insert(qMakePair(type, maxMinorVersion), raw);
1923 bool QQmlEnginePrivate::isQObject(int t)
1925 Locker locker(this);
1926 return m_compositeTypes.contains(t) || QQmlMetaType::isQObject(t);
1929 QObject *QQmlEnginePrivate::toQObject(const QVariant &v, bool *ok) const
1931 Locker locker(this);
1932 int t = v.userType();
1933 if (t == QMetaType::QObjectStar || m_compositeTypes.contains(t)) {
1935 return *(QObject **)(v.constData());
1937 return QQmlMetaType::toQObject(v, ok);
1941 QQmlMetaType::TypeCategory QQmlEnginePrivate::typeCategory(int t) const
1943 Locker locker(this);
1944 if (m_compositeTypes.contains(t))
1945 return QQmlMetaType::Object;
1946 else if (m_qmlLists.contains(t))
1947 return QQmlMetaType::List;
1949 return QQmlMetaType::typeCategory(t);
1952 bool QQmlEnginePrivate::isList(int t) const
1954 Locker locker(this);
1955 return m_qmlLists.contains(t) || QQmlMetaType::isList(t);
1958 int QQmlEnginePrivate::listType(int t) const
1960 Locker locker(this);
1961 QHash<int, int>::ConstIterator iter = m_qmlLists.find(t);
1962 if (iter != m_qmlLists.end())
1965 return QQmlMetaType::listType(t);
1968 QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const
1970 Locker locker(this);
1971 QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.find(t);
1972 if (iter != m_compositeTypes.end()) {
1973 return QQmlMetaObject((*iter)->rootPropertyCache);
1975 QQmlType *type = QQmlMetaType::qmlType(t);
1976 return QQmlMetaObject(type?type->baseMetaObject():0);
1980 QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const
1982 Locker locker(this);
1983 QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.find(t);
1984 if (iter != m_compositeTypes.end()) {
1985 return QQmlMetaObject((*iter)->rootPropertyCache);
1987 QQmlType *type = QQmlMetaType::qmlType(t);
1988 return QQmlMetaObject(type?type->metaObject():0);
1992 QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t)
1994 Locker locker(this);
1995 QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.find(t);
1996 if (iter != m_compositeTypes.end()) {
1997 return (*iter)->rootPropertyCache;
1999 QQmlType *type = QQmlMetaType::qmlType(t);
2001 return type?cache(type->metaObject()):0;
2005 QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t)
2007 Locker locker(this);
2008 QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.find(t);
2009 if (iter != m_compositeTypes.end()) {
2010 return (*iter)->rootPropertyCache;
2012 QQmlType *type = QQmlMetaType::qmlType(t);
2014 return type?cache(type->baseMetaObject()):0;
2018 void QQmlEnginePrivate::registerCompositeType(QQmlCompiledData *data)
2020 QByteArray name = data->rootPropertyCache->className();
2022 QByteArray ptr = name + '*';
2023 QByteArray lst = "QQmlListProperty<" + name + '>';
2025 int ptr_type = QMetaType::registerNormalizedType(ptr,
2026 QtMetaTypePrivate::QMetaTypeFunctionHelper<QObject*>::Delete,
2027 QtMetaTypePrivate::QMetaTypeFunctionHelper<QObject*>::Create,
2028 QtMetaTypePrivate::QMetaTypeFunctionHelper<QObject*>::Destruct,
2029 QtMetaTypePrivate::QMetaTypeFunctionHelper<QObject*>::Construct,
2031 static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QObject*>::Flags),
2033 int lst_type = QMetaType::registerNormalizedType(lst,
2034 QtMetaTypePrivate::QMetaTypeFunctionHelper<QQmlListProperty<QObject> >::Delete,
2035 QtMetaTypePrivate::QMetaTypeFunctionHelper<QQmlListProperty<QObject> >::Create,
2036 QtMetaTypePrivate::QMetaTypeFunctionHelper<QQmlListProperty<QObject> >::Destruct,
2037 QtMetaTypePrivate::QMetaTypeFunctionHelper<QQmlListProperty<QObject> >::Construct,
2038 sizeof(QQmlListProperty<QObject>),
2039 static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QQmlListProperty<QObject> >::Flags),
2040 static_cast<QMetaObject*>(0));
2042 data->metaTypeId = ptr_type;
2043 data->listMetaTypeId = lst_type;
2044 data->isRegisteredWithEngine = true;
2046 Locker locker(this);
2047 m_qmlLists.insert(lst_type, ptr_type);
2048 // The QQmlCompiledData is not referenced here, but it is removed from this
2049 // hash in the QQmlCompiledData destructor
2050 m_compositeTypes.insert(ptr_type, data);
2053 void QQmlEnginePrivate::unregisterCompositeType(QQmlCompiledData *data)
2055 int ptr_type = data->metaTypeId;
2056 int lst_type = data->listMetaTypeId;
2058 Locker locker(this);
2059 m_qmlLists.remove(lst_type);
2060 m_compositeTypes.remove(ptr_type);
2063 bool QQmlEnginePrivate::isTypeLoaded(const QUrl &url) const
2065 return typeLoader.isTypeLoaded(url);
2068 bool QQmlEnginePrivate::isScriptLoaded(const QUrl &url) const
2070 return typeLoader.isScriptLoaded(url);
2073 bool QQml_isFileCaseCorrect(const QString &fileName)
2075 #if defined(Q_OS_MAC) || defined(Q_OS_WIN)
2076 QFileInfo info(fileName);
2077 const QString absolute = info.absoluteFilePath();
2079 #if defined(Q_OS_MAC) || defined(Q_OS_WINCE)
2080 const QString canonical = info.canonicalFilePath();
2081 #elif defined(Q_OS_WIN)
2082 wchar_t buffer[1024];
2084 DWORD rv = ::GetShortPathName((wchar_t*)absolute.utf16(), buffer, 1024);
2085 if (rv == 0 || rv >= 1024) return true;
2086 rv = ::GetLongPathName(buffer, buffer, 1024);
2087 if (rv == 0 || rv >= 1024) return true;
2089 const QString canonical = QString::fromWCharArray(buffer);
2092 const int absoluteLength = absolute.length();
2093 const int canonicalLength = canonical.length();
2095 const int length = qMin(absoluteLength, canonicalLength);
2096 for (int ii = 0; ii < length; ++ii) {
2097 const QChar &a = absolute.at(absoluteLength - 1 - ii);
2098 const QChar &c = canonical.at(canonicalLength - 1 - ii);
2100 if (a.toLower() != c.toLower())
2112 \fn QQmlEngine *qmlEngine(const QObject *object)
2115 Returns the QQmlEngine associated with \a object, if any. This is equivalent to
2116 QQmlEngine::contextForObject(object)->engine(), but more efficient.
2120 \fn QQmlContext *qmlContext(const QObject *object)
2123 Returns the QQmlContext associated with \a object, if any. This is equivalent to
2124 QQmlEngine::contextForObject(object).