1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
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 QQmlValueTypeFactory::registerBaseTypes(uri, versionMajor, versionMinor);
111 \qmlclass QtObject QObject
112 \inqmlmodule QtQuick 2
113 \ingroup qml-utility-elements
115 \brief A basic QML type
117 The QtObject element is a non-visual element which contains only the
120 It can be useful to create a QtObject if you need an extremely
121 lightweight element to enclose a set of custom properties:
123 \snippet qml/qtobject.qml 0
125 It can also be useful for C++ integration, as it is just a plain
126 QObject. See the QObject documentation for further details.
129 \qmlproperty string QtObject::objectName
130 This property holds the QObject::objectName for this specific object instance.
132 This allows a C++ application to locate an item within a QML component
133 using the QObject::findChild() method. For example, the following C++
134 application locates the child \l Rectangle item and dynamically changes its
143 width: 200; height: 200
157 view.setSource(QUrl::fromLocalFile("MyRect.qml"));
160 QQuickItem *item = view.rootObject()->findChild<QQuickItem*>("myRect");
162 item->setProperty("color", QColor(Qt::yellow));
166 bool QQmlEnginePrivate::qml_debugging_enabled = false;
168 void QQmlEnginePrivate::registerBaseTypes(const char *uri, int versionMajor, int versionMinor)
170 qmlRegisterType<QQmlComponent>(uri,versionMajor,versionMinor,"Component");
171 qmlRegisterType<QObject>(uri,versionMajor,versionMinor,"QtObject");
172 qmlRegisterType<QQuickListElement>(uri, versionMajor, versionMinor,"ListElement");
173 qmlRegisterCustomType<QQuickListModel>(uri, versionMajor, versionMinor,"ListModel", new QQuickListModelParser);
174 qmlRegisterType<QQuickWorkerScript>(uri,versionMajor,versionMinor,"WorkerScript");
177 void QQmlEnginePrivate::defineModule()
179 registerBaseTypes("QtQuick", 2, 0);
180 qmlRegisterUncreatableType<QQmlLocale>("QtQuick",2,0,"Locale",QQmlEngine::tr("Locale cannot be instantiated. Use Qt.locale()"));
185 \class QQmlImageProviderBase
186 \brief The QQmlImageProviderBase class is used to register image providers in the QML engine.
189 Image providers must be registered with the QML engine. The only information the QML
190 engine knows about image providers is the type of image data they provide. To use an
191 image provider to acquire image data, you must cast the QQmlImageProviderBase pointer
192 to a QQuickImageProvider pointer.
194 \sa QQuickImageProvider, QQuickTextureFactory
198 \enum QQmlImageProviderBase::ImageType
200 Defines the type of image supported by this image provider.
202 \value Image The Image Provider provides QImage images.
203 The QQuickImageProvider::requestImage() method will be called for all image requests.
204 \value Pixmap The Image Provider provides QPixmap images.
205 The QQuickImageProvider::requestPixmap() method will be called for all image requests.
206 \value Texture The Image Provider provides QSGTextureProvider based images.
207 The QQuickImageProvider::requestTexture() method will be called for all image requests. \omitvalue
211 \enum QQmlImageProviderBase::Flag
213 Defines specific requirements or features of this image provider.
215 \value ForceAsynchronousImageLoading Ensures that image requests to the provider are
216 run in a separate thread, which allows the provider to spend as much time as needed
217 on producing the image without blocking the main thread.
221 QQmlImageProviderBase::QQmlImageProviderBase()
226 QQmlImageProviderBase::~QQmlImageProviderBase()
232 \qmlclass Qt QQmlEnginePrivate
233 \ingroup qml-utility-elements
234 \brief The QML global Qt object provides useful enums and functions from Qt.
236 \keyword QmlGlobalQtObject
238 \brief The \c Qt object provides useful enums and functions from Qt, for use in all QML files.
240 The \c Qt object is a global object with utility functions, properties and enums.
242 It is not instantiable; to use it, call the members of the global \c Qt object directly.
249 color: Qt.rgba(1, 0, 0, 1)
250 text: Qt.md5("hello, world")
257 The Qt object contains the enums available in the \l {Qt Namespace}. For example, you can access
258 the \l Qt::LeftButton and \l Qt::RightButton enum values as \c Qt.LeftButton and \c Qt.RightButton.
262 The Qt object also contains helper functions for creating objects of specific
263 data types. This is primarily useful when setting the properties of an item
264 when the property has one of the following types:
267 \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()}
268 \li \c rect - use \l{Qt::rect()}{Qt.rect()}
269 \li \c point - use \l{Qt::point()}{Qt.point()}
270 \li \c size - use \l{Qt::size()}{Qt.size()}
271 \li \c vector3d - use \l{Qt::vector3d()}{Qt.vector3d()}
274 There are also string based constructors for these types. See \l{qdeclarativebasictypes.html}{QML Basic Types} for more information.
276 \section1 Date/Time Formatters
278 The Qt object contains several functions for formatting QDateTime, QDate and QTime values.
281 \li \l{Qt::formatDateTime}{string Qt.formatDateTime(datetime date, variant format)}
282 \li \l{Qt::formatDate}{string Qt.formatDate(datetime date, variant format)}
283 \li \l{Qt::formatTime}{string Qt.formatTime(datetime date, variant format)}
286 The format specification is described at \l{Qt::formatDateTime}{Qt.formatDateTime}.
289 \section1 Dynamic Object Creation
290 The following functions on the global object allow you to dynamically create QML
291 items from files or strings. See \l{Dynamic Object Management in QML} for an overview
295 \li \l{Qt::createComponent()}{object Qt.createComponent(url)}
296 \li \l{Qt::createQmlObject()}{object Qt.createQmlObject(string qml, object parent, string filepath)}
300 \section1 Other Functions
302 The following functions are also on the Qt object.
305 \li \l{Qt::quit()}{Qt.quit()}
306 \li \l{Qt::md5()}{Qt.md5(string)}
307 \li \l{Qt::btoa()}{string Qt.btoa(string)}
308 \li \l{Qt::atob()}{string Qt.atob(string)}
309 \li \l{Qt::binding()}{object Qt.binding(function)}
310 \li \l{Qt::locale()}{object Qt.locale()}
311 \li \l{Qt::resolvedUrl()}{string Qt.resolvedUrl(string)}
312 \li \l{Qt::openUrlExternally()}{Qt.openUrlExternally(string)}
313 \li \l{Qt::fontFamilies()}{list<string> Qt.fontFamilies()}
318 \qmlproperty object Qt::application
321 The \c application object provides access to global application state
322 properties shared by many QML components.
328 \li \c application.active
330 This read-only property indicates whether the application is the top-most and focused
331 application, and the user is able to interact with the application. The property
332 is false when the application is in the background, the device keylock or screen
333 saver is active, the screen backlight is turned off, or the global system dialog
334 is being displayed on top of the application. It can be used for stopping and
335 pausing animations, timers and active processing of data in order to save device
336 battery power and free device memory and processor load when the application is not
340 \li \c application.layoutDirection
342 This read-only property can be used to query the default layout direction of the
343 application. On system start-up, the default layout direction depends on the
344 application's language. The property has a value of \c Qt.RightToLeft in locales
345 where text and graphic elements are read from right to left, and \c Qt.LeftToRight
346 where the reading direction flows from left to right. You can bind to this
347 property to customize your application layouts to support both layout directions.
352 \li Qt.LeftToRight - Text and graphics elements should be positioned
354 \li Qt.RightToLeft - Text and graphics elements should be positioned
360 The following example uses the \c application object to indicate
361 whether the application is currently active:
363 \snippet qml/application.qml document
367 \qmlproperty object Qt::inputMethod
370 The \c inputMethod object allows access to application's QInputMethod object
371 and all its properties and slots. See the QInputMethod documentation for
377 \qmlmethod object Qt::include(string url, jsobject callback)
379 Includes another JavaScript file. This method can only be used from within JavaScript files,
380 and not regular QML files.
382 This imports all functions from \a url into the current script's namespace.
384 Qt.include() returns an object that describes the status of the operation. The object has
385 a single property, \c {status}, that is set to one of the following values:
388 \header \li Symbol \li Value \li Description
389 \row \li result.OK \li 0 \li The include completed successfully.
390 \row \li result.LOADING \li 1 \li Data is being loaded from the network.
391 \row \li result.NETWORK_ERROR \li 2 \li A network error occurred while fetching the url.
392 \row \li result.EXCEPTION \li 3 \li A JavaScript exception occurred while executing the included code.
393 An additional \c exception property will be set in this case.
396 The \c status property will be updated as the operation progresses.
398 If provided, \a callback is invoked when the operation completes. The callback is passed
399 the same object as is returned from the Qt.include() call.
401 // Qt.include() is implemented in qv8include.cpp
404 QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e)
405 : propertyCapture(0), rootContext(0), isDebugging(false),
406 outputWarningsToStdErr(true), sharedContext(0), sharedScope(0),
407 cleanup(0), erroredBindings(0), inProgressCreations(0),
408 workerScriptEngine(0), activeVME(0),
409 networkAccessManager(0), networkAccessManagerFactory(0),
410 scarceResourcesRefCount(0), typeLoader(e), importDatabase(e), uniqueId(1),
411 incubatorCount(0), incubationController(0), mutex(QMutex::Recursive)
415 QQmlEnginePrivate::~QQmlEnginePrivate()
417 if (inProgressCreations)
418 qWarning() << QQmlEngine::tr("There are still \"%1\" items in the process of being created at engine destruction.").arg(inProgressCreations);
421 QQmlCleanup *c = cleanup;
423 if (cleanup) cleanup->prev = &cleanup;
429 doDeleteInEngineThread();
431 if (incubationController) incubationController->d = 0;
432 incubationController = 0;
437 for(QHash<const QMetaObject *, QQmlPropertyCache *>::Iterator iter = propertyCache.begin(); iter != propertyCache.end(); ++iter)
439 for(QHash<QPair<QQmlType *, int>, QQmlPropertyCache *>::Iterator iter = typePropertyCache.begin(); iter != typePropertyCache.end(); ++iter)
441 for(QHash<QQmlMetaType::ModuleApi, QQmlMetaType::ModuleApiInstance *>::Iterator iter = moduleApiInstances.begin(); iter != moduleApiInstances.end(); ++iter) {
442 delete (*iter)->qobjectApi;
445 for (QHash<int, QQmlCompiledData *>::Iterator iter = m_compositeTypes.begin(); iter != m_compositeTypes.end(); ++iter)
446 iter.value()->isRegisteredWithEngine = false;
449 void QQmlPrivate::qdeclarativeelement_destructor(QObject *o)
451 QObjectPrivate *p = QObjectPrivate::get(o);
452 if (p->declarativeData) {
453 QQmlData *d = static_cast<QQmlData*>(p->declarativeData);
454 if (d->ownContext && d->context) {
455 d->context->destroy();
459 // Mark this object as in the process of deletion to
460 // prevent it resolving in bindings
461 QQmlData::markAsDeleted(o);
465 void QQmlData::destroyed(QAbstractDeclarativeData *d, QObject *o)
467 static_cast<QQmlData *>(d)->destroyed(o);
470 void QQmlData::parentChanged(QAbstractDeclarativeData *d, QObject *o, QObject *p)
472 static_cast<QQmlData *>(d)->parentChanged(o, p);
475 class QQmlThreadNotifierProxyObject : public QObject
478 QPointer<QObject> target;
480 virtual int qt_metacall(QMetaObject::Call, int methodIndex, void **a) {
484 QMetaMethod method = target->metaObject()->method(methodIndex);
485 Q_ASSERT(method.methodType() == QMetaMethod::Signal);
486 int signalIndex = QMetaObjectPrivate::signalIndex(method);
487 QQmlData *ddata = QQmlData::get(target, false);
488 QQmlNotifierEndpoint *ep = ddata->notify(signalIndex);
489 if (ep) QQmlNotifier::emitNotify(ep, a);
497 void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int index, void **a)
499 QQmlData *ddata = QQmlData::get(object, false);
500 if (!ddata) return; // Probably being deleted
502 // In general, QML only supports QObject's that live on the same thread as the QQmlEngine
503 // that they're exposed to. However, to make writing "worker objects" that calculate data
504 // in a separate thread easier, QML allows a QObject that lives in the same thread as the
505 // QQmlEngine to emit signals from a different thread. These signals are then automatically
506 // marshalled back onto the QObject's thread and handled by QML from there. This is tested
507 // by the qqmlecmascript::threadSignal() autotest.
508 if (ddata->notifyList &&
509 QThread::currentThreadId() != QObjectPrivate::get(object)->threadData->threadId) {
511 if (!QObjectPrivate::get(object)->threadData->thread)
514 QMetaMethod m = QMetaObjectPrivate::signal(object->metaObject(), index);
515 QList<QByteArray> parameterTypes = m.parameterTypes();
517 int *types = (int *)malloc((parameterTypes.count() + 1) * sizeof(int));
518 void **args = (void **) malloc((parameterTypes.count() + 1) *sizeof(void *));
520 types[0] = 0; // return type
521 args[0] = 0; // return value
523 for (int ii = 0; ii < parameterTypes.count(); ++ii) {
524 const QByteArray &typeName = parameterTypes.at(ii);
525 if (typeName.endsWith('*'))
526 types[ii + 1] = QMetaType::VoidStar;
528 types[ii + 1] = QMetaType::type(typeName);
530 if (!types[ii + 1]) {
531 qWarning("QObject::connect: Cannot queue arguments of type '%s'\n"
532 "(Make sure '%s' is registered using qRegisterMetaType().)",
533 typeName.constData(), typeName.constData());
539 args[ii + 1] = QMetaType::create(types[ii + 1], a[ii + 1]);
542 QMetaCallEvent *ev = new QMetaCallEvent(m.methodIndex(), 0, 0, object, index,
543 parameterTypes.count() + 1, types, args);
545 QQmlThreadNotifierProxyObject *mpo = new QQmlThreadNotifierProxyObject;
546 mpo->target = object;
547 mpo->moveToThread(QObjectPrivate::get(object)->threadData->thread);
548 QCoreApplication::postEvent(mpo, ev);
551 QQmlNotifierEndpoint *ep = ddata->notify(index);
552 if (ep) QQmlNotifier::emitNotify(ep, a);
556 int QQmlData::receivers(QAbstractDeclarativeData *d, const QObject *, int index)
558 return static_cast<QQmlData *>(d)->endpointCount(index);
561 int QQmlData::endpointCount(int index)
564 QQmlNotifierEndpoint *ep = notify(index);
575 void QQmlData::markAsDeleted(QObject *o)
577 QQmlData::setQueuedForDeletion(o);
579 QObjectPrivate *p = QObjectPrivate::get(o);
580 for (QList<QObject *>::iterator it = p->children.begin(), end = p->children.end(); it != end; ++it) {
581 QQmlData::markAsDeleted(*it);
585 void QQmlData::setQueuedForDeletion(QObject *object)
588 if (QObjectPrivate *priv = QObjectPrivate::get(object)) {
589 if (!priv->wasDeleted && priv->declarativeData) {
590 QQmlData *ddata = QQmlData::get(object, false);
591 if (ddata->ownContext && ddata->context)
592 ddata->context->emitDestruction();
593 ddata->isQueuedForDeletion = true;
599 void QQmlEnginePrivate::init()
603 static bool firstTime = true;
605 qmlRegisterType<QQmlComponent>("QML", 1, 0, "Component");
611 qRegisterMetaType<QVariant>("QVariant");
612 qRegisterMetaType<QQmlScriptString>("QQmlScriptString");
613 qRegisterMetaType<QJSValue>("QJSValue");
614 qRegisterMetaType<QQmlComponent::Status>("QQmlComponent::Status");
615 qRegisterMetaType<QList<QObject*> >("QList<QObject*>");
616 qRegisterMetaType<QList<int> >("QList<int>");
617 qRegisterMetaType<QQmlV8Handle>("QQmlV8Handle");
619 v8engine()->setEngine(q);
621 rootContext = new QQmlContext(q,true);
623 if (QCoreApplication::instance()->thread() == q->thread() &&
624 QQmlEngineDebugService::isDebuggingEnabled()) {
626 QQmlEngineDebugService::instance()->addEngine(q);
627 QV8DebugService::initialize(v8engine());
628 QV8ProfilerService::initialize();
629 QQmlProfilerService::initialize();
630 QDebugMessageService::instance();
633 QString dataLocation = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
634 if (!dataLocation.isEmpty())
635 offlineStoragePath = dataLocation.replace(QLatin1Char('/'), QDir::separator())
636 + QDir::separator() + QLatin1String("QML")
637 + QDir::separator() + QLatin1String("OfflineStorage");
640 QQuickWorkerScriptEngine *QQmlEnginePrivate::getWorkerScriptEngine()
643 if (!workerScriptEngine)
644 workerScriptEngine = new QQuickWorkerScriptEngine(q);
645 return workerScriptEngine;
652 \brief The QQmlEngine class provides an environment for instantiating QML components.
655 Each QML component is instantiated in a QQmlContext.
656 QQmlContext's are essential for passing data to QML
657 components. In QML, contexts are arranged hierarchically and this
658 hierarchy is managed by the QQmlEngine.
660 Prior to creating any QML components, an application must have
661 created a QQmlEngine to gain access to a QML context. The
662 following example shows how to create a simple Text item.
666 QQmlComponent component(&engine);
667 component.setData("import QtQuick 2.0\nText { text: \"Hello world!\" }", QUrl());
668 QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
670 //add item to view, etc
674 In this case, the Text item will be created in the engine's
675 \l {QQmlEngine::rootContext()}{root context}.
677 Note that the QtQuick 1 version is called QDeclarativeEngine.
679 \sa QQmlComponent, QQmlContext
683 Create a new QQmlEngine with the given \a parent.
685 QQmlEngine::QQmlEngine(QObject *parent)
686 : QJSEngine(*new QQmlEnginePrivate(this), parent)
693 Destroys the QQmlEngine.
695 Any QQmlContext's created on this engine will be
696 invalidated, but not destroyed (unless they are parented to the
699 QQmlEngine::~QQmlEngine()
702 if (d->isDebugging) {
703 QQmlEngineDebugService::instance()->remEngine(this);
706 // Emit onDestruction signals for the root context before
707 // we destroy the contexts, engine, Module APIs etc. that
708 // may be required to handle the destruction signal.
709 QQmlContextData::get(rootContext())->emitDestruction();
711 // if we are the parent of any of the qobject module api instances,
712 // we need to remove them from our internal list, in order to prevent
713 // a segfault in engine private dtor.
714 QList<QQmlMetaType::ModuleApi> keys = d->moduleApiInstances.keys();
715 QObject *currQObjectApi = 0;
716 QQmlMetaType::ModuleApiInstance *currInstance = 0;
717 foreach (const QQmlMetaType::ModuleApi &key, keys) {
718 currInstance = d->moduleApiInstances.value(key);
719 currQObjectApi = currInstance->qobjectApi;
720 if (this->children().contains(currQObjectApi)) {
721 delete currQObjectApi;
723 d->moduleApiInstances.remove(key);
727 if (d->incubationController)
728 d->incubationController->d = 0;
731 /*! \fn void QQmlEngine::quit()
732 This signal is emitted when the QML loaded by the engine would like to quit.
735 /*! \fn void QQmlEngine::warnings(const QList<QQmlError> &warnings)
736 This signal is emitted when \a warnings messages are generated by QML.
740 Clears the engine's internal component cache.
742 This function causes the property metadata of all components previously
743 loaded by the engine to be destroyed. All previously loaded components and
744 the property bindings for all extant objects created from those components will
747 This function returns the engine to a state where it does not contain any loaded
748 component data. This may be useful in order to reload a smaller subset of the
749 previous component set, or to load a new version of a previously loaded component.
751 Once the component cache has been cleared, components must be loaded before
752 any new objects can be created.
754 \sa trimComponentCache()
756 void QQmlEngine::clearComponentCache()
759 d->typeLoader.clearCache();
763 Trims the engine's internal component cache.
765 This function causes the property metadata of any loaded components which are
766 not currently in use to be destroyed.
768 A component is considered to be in use if there are any extant instances of
769 the component itself, any instances of other components that use the component,
770 or any objects instantiated by any of those components.
772 \sa clearComponentCache()
774 void QQmlEngine::trimComponentCache()
777 d->typeLoader.trimCache();
781 Returns the engine's root context.
783 The root context is automatically created by the QQmlEngine.
784 Data that should be available to all QML component instances
785 instantiated by the engine should be put in the root context.
787 Additional data that should only be available to a subset of
788 component instances should be added to sub-contexts parented to the
791 QQmlContext *QQmlEngine::rootContext() const
793 Q_D(const QQmlEngine);
794 return d->rootContext;
798 Sets the \a factory to use for creating QNetworkAccessManager(s).
800 QNetworkAccessManager is used for all network access by QML. By
801 implementing a factory it is possible to create custom
802 QNetworkAccessManager with specialized caching, proxy and cookie
805 The factory must be set before executing the engine.
807 void QQmlEngine::setNetworkAccessManagerFactory(QQmlNetworkAccessManagerFactory *factory)
810 QMutexLocker locker(&d->mutex);
811 d->networkAccessManagerFactory = factory;
815 Returns the current QQmlNetworkAccessManagerFactory.
817 \sa setNetworkAccessManagerFactory()
819 QQmlNetworkAccessManagerFactory *QQmlEngine::networkAccessManagerFactory() const
821 Q_D(const QQmlEngine);
822 return d->networkAccessManagerFactory;
825 void QQmlEnginePrivate::registerFinalizeCallback(QObject *obj, int index)
828 activeVME->finalizeCallbacks.append(qMakePair(QQmlGuard<QObject>(obj), index));
830 void *args[] = { 0 };
831 QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, index, args);
835 QNetworkAccessManager *QQmlEnginePrivate::createNetworkAccessManager(QObject *parent) const
837 QMutexLocker locker(&mutex);
838 QNetworkAccessManager *nam;
839 if (networkAccessManagerFactory) {
840 nam = networkAccessManagerFactory->create(parent);
842 nam = new QNetworkAccessManager(parent);
848 QNetworkAccessManager *QQmlEnginePrivate::getNetworkAccessManager() const
850 Q_Q(const QQmlEngine);
851 if (!networkAccessManager)
852 networkAccessManager = createNetworkAccessManager(const_cast<QQmlEngine*>(q));
853 return networkAccessManager;
857 Returns a common QNetworkAccessManager which can be used by any QML
858 element instantiated by this engine.
860 If a QQmlNetworkAccessManagerFactory has been set and a
861 QNetworkAccessManager has not yet been created, the
862 QQmlNetworkAccessManagerFactory will be used to create the
863 QNetworkAccessManager; otherwise the returned QNetworkAccessManager
864 will have no proxy or cache set.
866 \sa setNetworkAccessManagerFactory()
868 QNetworkAccessManager *QQmlEngine::networkAccessManager() const
870 Q_D(const QQmlEngine);
871 return d->getNetworkAccessManager();
876 Sets the \a provider to use for images requested via the \e
877 image: url scheme, with host \a providerId. The QQmlEngine
878 takes ownership of \a provider.
880 Image providers enable support for pixmap and threaded image
881 requests. See the QQuickImageProvider documentation for details on
882 implementing and using image providers.
884 All required image providers should be added to the engine before any
885 QML sources files are loaded.
887 \sa removeImageProvider(), QQuickImageProvider, QQmlImageProviderBase
889 void QQmlEngine::addImageProvider(const QString &providerId, QQmlImageProviderBase *provider)
892 QMutexLocker locker(&d->mutex);
893 d->imageProviders.insert(providerId.toLower(), QSharedPointer<QQmlImageProviderBase>(provider));
897 Returns the image provider set for \a providerId.
899 Returns the provider if it was found; otherwise returns 0.
901 \sa QQuickImageProvider
903 QQmlImageProviderBase *QQmlEngine::imageProvider(const QString &providerId) const
905 Q_D(const QQmlEngine);
906 QMutexLocker locker(&d->mutex);
907 return d->imageProviders.value(providerId).data();
911 Removes the image provider for \a providerId.
913 \sa addImageProvider(), QQuickImageProvider
915 void QQmlEngine::removeImageProvider(const QString &providerId)
918 QMutexLocker locker(&d->mutex);
919 d->imageProviders.take(providerId);
923 Return the base URL for this engine. The base URL is only used to
924 resolve components when a relative URL is passed to the
925 QQmlComponent constructor.
927 If a base URL has not been explicitly set, this method returns the
928 application's current working directory.
932 QUrl QQmlEngine::baseUrl() const
934 Q_D(const QQmlEngine);
935 if (d->baseUrl.isEmpty()) {
936 return QUrl::fromLocalFile(QDir::currentPath() + QDir::separator());
943 Set the base URL for this engine to \a url.
947 void QQmlEngine::setBaseUrl(const QUrl &url)
954 Returns true if warning messages will be output to stderr in addition
955 to being emitted by the warnings() signal, otherwise false.
957 The default value is true.
959 bool QQmlEngine::outputWarningsToStandardError() const
961 Q_D(const QQmlEngine);
962 return d->outputWarningsToStdErr;
966 Set whether warning messages will be output to stderr to \a enabled.
968 If \a enabled is true, any warning messages generated by QML will be
969 output to stderr and emitted by the warnings() signal. If \a enabled
970 is false, on the warnings() signal will be emitted. This allows
971 applications to handle warning output themselves.
973 The default value is true.
975 void QQmlEngine::setOutputWarningsToStandardError(bool enabled)
978 d->outputWarningsToStdErr = enabled;
982 Returns the QQmlContext for the \a object, or 0 if no
983 context has been set.
985 When the QQmlEngine instantiates a QObject, the context is
988 QQmlContext *QQmlEngine::contextForObject(const QObject *object)
993 QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object));
996 static_cast<QQmlData *>(priv->declarativeData);
1000 else if (data->outerContext)
1001 return data->outerContext->asQQmlContext();
1007 Sets the QQmlContext for the \a object to \a context.
1008 If the \a object already has a context, a warning is
1009 output, but the context is not changed.
1011 When the QQmlEngine instantiates a QObject, the context is
1014 void QQmlEngine::setContextForObject(QObject *object, QQmlContext *context)
1016 if (!object || !context)
1019 QQmlData *data = QQmlData::get(object, true);
1020 if (data->context) {
1021 qWarning("QQmlEngine::setContextForObject(): Object already has a QQmlContext");
1025 QQmlContextData *contextData = QQmlContextData::get(context);
1026 contextData->addObject(object);
1030 \enum QQmlEngine::ObjectOwnership
1032 Ownership controls whether or not QML automatically destroys the
1033 QObject when the object is garbage collected by the JavaScript
1034 engine. The two ownership options are:
1036 \value CppOwnership The object is owned by C++ code, and will
1037 never be deleted by QML. The JavaScript destroy() method cannot be
1038 used on objects with CppOwnership. This option is similar to
1039 QScriptEngine::QtOwnership.
1041 \value JavaScriptOwnership The object is owned by JavaScript.
1042 When the object is returned to QML as the return value of a method
1043 call or property access, QML will track it, and delete the object
1044 if there are no remaining JavaScript references to it and it has no
1045 QObject::parent(). An object tracked by one QQmlEngine
1046 will be deleted during that QQmlEngine's destructor, and thus
1047 JavaScript references between objects with JavaScriptOwnership from
1048 two different engines will not be valid after the deletion of one of
1049 those engines. This option is similar to QScriptEngine::ScriptOwnership.
1051 Generally an application doesn't need to set an object's ownership
1052 explicitly. QML uses a heuristic to set the default object
1053 ownership. By default, an object that is created by QML has
1054 JavaScriptOwnership. The exception to this are the root objects
1055 created by calling QQmlComponent::create() or
1056 QQmlComponent::beginCreate() which have CppOwnership by
1057 default. The ownership of these root-level objects is considered to
1058 have been transferred to the C++ caller.
1060 Objects not-created by QML have CppOwnership by default. The
1061 exception to this is objects returned from a C++ method call. The
1062 ownership of these objects is passed to JavaScript.
1064 Calling setObjectOwnership() overrides the default ownership
1065 heuristic used by QML.
1069 Sets the \a ownership of \a object.
1071 void QQmlEngine::setObjectOwnership(QObject *object, ObjectOwnership ownership)
1076 QQmlData *ddata = QQmlData::get(object, true);
1080 ddata->indestructible = (ownership == CppOwnership)?true:false;
1081 ddata->explicitIndestructibleSet = true;
1085 Returns the ownership of \a object.
1087 QQmlEngine::ObjectOwnership QQmlEngine::objectOwnership(QObject *object)
1090 return CppOwnership;
1092 QQmlData *ddata = QQmlData::get(object, false);
1094 return CppOwnership;
1096 return ddata->indestructible?CppOwnership:JavaScriptOwnership;
1099 bool QQmlEngine::event(QEvent *e)
1102 if (e->type() == QEvent::User)
1103 d->doDeleteInEngineThread();
1105 return QJSEngine::event(e);
1108 void QQmlEnginePrivate::doDeleteInEngineThread()
1110 QFieldList<Deletable, &Deletable::next> list;
1112 list.copyAndClear(toDeleteInEngineThread);
1115 while (Deletable *d = list.takeFirst())
1119 Q_AUTOTEST_EXPORT void qmlExecuteDeferred(QObject *object)
1121 QQmlData *data = QQmlData::get(object);
1123 if (data && data->compiledData && data->deferredIdx) {
1124 QQmlObjectCreatingProfiler prof;
1126 QQmlType *type = QQmlMetaType::qmlType(object->metaObject());
1127 prof.setTypeName(type ? type->qmlTypeName()
1128 : QString::fromUtf8(object->metaObject()->className()));
1129 if (data->outerContext)
1130 prof.setLocation(data->outerContext->url, data->lineNumber, data->columnNumber);
1132 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine);
1134 QQmlComponentPrivate::ConstructionState state;
1135 QQmlComponentPrivate::beginDeferred(ep, object, &state);
1137 // Release the reference for the deferral action (we still have one from construction)
1138 data->compiledData->release();
1139 data->compiledData = 0;
1141 QQmlComponentPrivate::complete(ep, &state);
1145 QQmlContext *qmlContext(const QObject *obj)
1147 return QQmlEngine::contextForObject(obj);
1150 QQmlEngine *qmlEngine(const QObject *obj)
1152 QQmlData *data = QQmlData::get(obj, false);
1153 if (!data || !data->context)
1155 return data->context->engine;
1158 QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create)
1160 QQmlData *data = QQmlData::get(object);
1162 return 0; // Attached properties are only on objects created by QML
1164 QObject *rv = data->hasExtendedData()?data->attachedProperties()->value(id):0;
1168 QQmlAttachedPropertiesFunc pf = QQmlMetaType::attachedPropertiesFuncById(id);
1172 rv = pf(const_cast<QObject *>(object));
1175 data->attachedProperties()->insert(id, rv);
1180 QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *object,
1181 const QMetaObject *attachedMetaObject, bool create)
1184 *idCache = QQmlMetaType::attachedPropertiesFuncId(attachedMetaObject);
1186 if (*idCache == -1 || !object)
1189 return qmlAttachedPropertiesObjectById(*idCache, object, create);
1192 QQmlDebuggingEnabler::QQmlDebuggingEnabler(bool printWarning)
1194 #ifndef QQML_NO_DEBUG_PROTOCOL
1195 if (!QQmlEnginePrivate::qml_debugging_enabled
1197 qDebug("QML debugging is enabled. Only use this in a safe environment.");
1199 QQmlEnginePrivate::qml_debugging_enabled = true;
1204 class QQmlDataExtended {
1207 ~QQmlDataExtended();
1209 QHash<int, QObject *> attachedProperties;
1212 QQmlDataExtended::QQmlDataExtended()
1216 QQmlDataExtended::~QQmlDataExtended()
1220 void QQmlData::NotifyList::layout(QQmlNotifierEndpoint *endpoint)
1223 layout(endpoint->next);
1225 int index = endpoint->sourceSignal;
1226 index = qMin(index, 0xFFFF - 1);
1228 endpoint->next = notifies[index];
1229 if (endpoint->next) endpoint->next->prev = &endpoint->next;
1230 endpoint->prev = ¬ifies[index];
1231 notifies[index] = endpoint;
1234 void QQmlData::NotifyList::layout()
1236 Q_ASSERT(maximumTodoIndex >= notifiesSize);
1239 QQmlNotifierEndpoint **old = notifies;
1240 const int reallocSize = (maximumTodoIndex + 1) * sizeof(QQmlNotifierEndpoint*);
1241 notifies = (QQmlNotifierEndpoint**)realloc(notifies, reallocSize);
1242 const int memsetSize = (maximumTodoIndex - notifiesSize + 1) *
1243 sizeof(QQmlNotifierEndpoint*);
1244 memset(notifies + notifiesSize, 0, memsetSize);
1246 if (notifies != old) {
1247 for (int ii = 0; ii < notifiesSize; ++ii)
1249 notifies[ii]->prev = ¬ifies[ii];
1252 notifiesSize = maximumTodoIndex + 1;
1257 maximumTodoIndex = 0;
1261 void QQmlData::addNotify(int index, QQmlNotifierEndpoint *endpoint)
1264 notifyList = (NotifyList *)malloc(sizeof(NotifyList));
1265 notifyList->connectionMask = 0;
1266 notifyList->maximumTodoIndex = 0;
1267 notifyList->notifiesSize = 0;
1268 notifyList->todo = 0;
1269 notifyList->notifies = 0;
1272 Q_ASSERT(!endpoint->isConnected());
1274 index = qMin(index, 0xFFFF - 1);
1275 notifyList->connectionMask |= (1ULL << quint64(index % 64));
1277 if (index < notifyList->notifiesSize) {
1279 endpoint->next = notifyList->notifies[index];
1280 if (endpoint->next) endpoint->next->prev = &endpoint->next;
1281 endpoint->prev = ¬ifyList->notifies[index];
1282 notifyList->notifies[index] = endpoint;
1285 notifyList->maximumTodoIndex = qMax(int(notifyList->maximumTodoIndex), index);
1287 endpoint->next = notifyList->todo;
1288 if (endpoint->next) endpoint->next->prev = &endpoint->next;
1289 endpoint->prev = ¬ifyList->todo;
1290 notifyList->todo = endpoint;
1294 bool QQml_isSignalConnected(QObject *obj, int signal_index)
1296 QQmlData *data = QQmlData::get(obj);
1297 return QObjectPrivate::get(obj)->isSignalConnected(signal_index) || (data && data->signalHasEndpoint(signal_index));
1301 index MUST in the range returned by QObjectPrivate::signalIndex()
1302 This is different than the index returned by QMetaMethod::methodIndex()
1304 bool QQmlData::signalHasEndpoint(int index)
1306 return notifyList && (notifyList->connectionMask & (1ULL << quint64(index % 64)));
1309 QHash<int, QObject *> *QQmlData::attachedProperties() const
1311 if (!extendedData) extendedData = new QQmlDataExtended;
1312 return &extendedData->attachedProperties;
1315 void QQmlData::destroyed(QObject *object)
1317 if (nextContextObject)
1318 nextContextObject->prevContextObject = prevContextObject;
1319 if (prevContextObject)
1320 *prevContextObject = nextContextObject;
1322 QQmlAbstractBinding *binding = bindings;
1324 QQmlAbstractBinding *next = binding->nextBinding();
1325 binding->setAddedToObject(false);
1326 binding->setNextBinding(0);
1332 compiledData->release();
1336 QQmlAbstractBoundSignal *signalHandler = signalHandlers;
1337 while (signalHandler) {
1338 if (signalHandler->isEvaluating()) {
1339 // The object is being deleted during signal handler evaluation.
1340 // This will cause a crash due to invalid memory access when the
1341 // evaluation has completed.
1342 // Abort with a friendly message instead.
1343 QString locationString;
1344 QQmlBoundSignalExpression *expr = signalHandler->expression();
1346 QString fileName = expr->sourceFile();
1347 if (fileName.isEmpty())
1348 fileName = QStringLiteral("<Unknown File>");
1349 locationString.append(fileName);
1350 locationString.append(QString::fromLatin1(":%0: ").arg(expr->lineNumber()));
1351 QString source = expr->expression();
1352 if (source.size() > 100) {
1353 source.truncate(96);
1354 source.append(QStringLiteral(" ..."));
1356 locationString.append(source);
1358 locationString = QStringLiteral("<Unknown Location>");
1360 qFatal("Object %p destroyed while one of its QML signal handlers is in progress.\n"
1361 "Most likely the object was deleted synchronously (use QObject::deleteLater() "
1362 "instead), or the application is running a nested event loop.\n"
1363 "This behavior is NOT supported!\n"
1364 "%s", object, qPrintable(locationString));
1367 QQmlAbstractBoundSignal *next = signalHandler->m_nextSignal;
1368 signalHandler->m_prevSignal = 0;
1369 signalHandler->m_nextSignal = 0;
1370 delete signalHandler;
1371 signalHandler = next;
1378 propertyCache->release();
1380 if (ownContext && context)
1384 QQmlGuard<QObject> *guard = static_cast<QQmlGuard<QObject> *>(guards);
1385 *guard = (QObject *)0;
1386 guard->objectDestroyed(object);
1390 while (notifyList->todo)
1391 notifyList->todo->disconnect();
1392 for (int ii = 0; ii < notifyList->notifiesSize; ++ii) {
1393 while (QQmlNotifierEndpoint *ep = notifyList->notifies[ii])
1396 free(notifyList->notifies);
1402 delete extendedData;
1404 // Dispose the handle.
1405 // We don't simply clear it (and wait for next gc cycle to dispose
1406 // via the weak qobject reference callback) as this affects the
1407 // outcomes of v8's gc statistical analysis heuristics, which can
1408 // cause unnecessary growth of the old pointer space js heap area.
1409 qPersistentDispose(v8object);
1415 DEFINE_BOOL_CONFIG_OPTION(parentTest, QML_PARENT_TEST);
1417 void QQmlData::parentChanged(QObject *object, QObject *parent)
1420 if (parentFrozen && !QObjectPrivate::get(object)->wasDeleted) {
1424 { QDebug dbg(&on); dbg << object; on = on.left(on.length() - 1); }
1425 { QDebug dbg(&pn); dbg << parent; pn = pn.left(pn.length() - 1); }
1427 qFatal("Object %s has had its parent frozen by QML and cannot be changed.\n"
1428 "User code is attempting to change it to %s.\n"
1429 "This behavior is NOT supported!", qPrintable(on), qPrintable(pn));
1434 bool QQmlData::hasBindingBit(int bit) const
1436 if (bindingBitsSize > bit)
1437 return bindingBits[bit / 32] & (1 << (bit % 32));
1442 void QQmlData::clearBindingBit(int bit)
1444 if (bindingBitsSize > bit)
1445 bindingBits[bit / 32] &= ~(1 << (bit % 32));
1448 void QQmlData::setBindingBit(QObject *obj, int bit)
1450 if (bindingBitsSize <= bit) {
1451 int props = QQmlMetaObject(obj).propertyCount();
1452 Q_ASSERT(bit < props);
1454 int arraySize = (props + 31) / 32;
1455 int oldArraySize = bindingBitsSize / 32;
1457 bindingBits = (quint32 *)realloc(bindingBits,
1458 arraySize * sizeof(quint32));
1460 memset(bindingBits + oldArraySize,
1462 sizeof(quint32) * (arraySize - oldArraySize));
1464 bindingBitsSize = arraySize * 32;
1467 bindingBits[bit / 32] |= (1 << (bit % 32));
1470 void QQmlEnginePrivate::sendQuit()
1474 if (q->receivers(SIGNAL(quit())) == 0) {
1475 qWarning("Signal QQmlEngine::quit() emitted, but no receivers connected to handle it.");
1479 static void dumpwarning(const QQmlError &error)
1481 QMessageLogger(error.url().toString().toLatin1().constData(),
1482 error.line(), 0).warning().nospace()
1483 << qPrintable(error.toString());
1486 static void dumpwarning(const QList<QQmlError> &errors)
1488 for (int ii = 0; ii < errors.count(); ++ii)
1489 dumpwarning(errors.at(ii));
1492 void QQmlEnginePrivate::warning(const QQmlError &error)
1495 q->warnings(QList<QQmlError>() << error);
1496 if (outputWarningsToStdErr)
1500 void QQmlEnginePrivate::warning(const QList<QQmlError> &errors)
1503 q->warnings(errors);
1504 if (outputWarningsToStdErr)
1505 dumpwarning(errors);
1508 void QQmlEnginePrivate::warning(QQmlDelayedError *error)
1511 warning(error->error(q));
1514 void QQmlEnginePrivate::warning(QQmlEngine *engine, const QQmlError &error)
1517 QQmlEnginePrivate::get(engine)->warning(error);
1522 void QQmlEnginePrivate::warning(QQmlEngine *engine, const QList<QQmlError> &error)
1525 QQmlEnginePrivate::get(engine)->warning(error);
1530 void QQmlEnginePrivate::warning(QQmlEngine *engine, QQmlDelayedError *error)
1533 QQmlEnginePrivate::get(engine)->warning(error);
1535 dumpwarning(error->error(0));
1538 void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QQmlError &error)
1541 engine->warning(error);
1546 void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QList<QQmlError> &error)
1549 engine->warning(error);
1555 This function should be called prior to evaluation of any js expression,
1556 so that scarce resources are not freed prematurely (eg, if there is a
1557 nested javascript expression).
1559 void QQmlEnginePrivate::referenceScarceResources()
1561 scarceResourcesRefCount += 1;
1565 This function should be called after evaluation of the js expression is
1566 complete, and so the scarce resources may be freed safely.
1568 void QQmlEnginePrivate::dereferenceScarceResources()
1570 Q_ASSERT(scarceResourcesRefCount > 0);
1571 scarceResourcesRefCount -= 1;
1573 // if the refcount is zero, then evaluation of the "top level"
1574 // expression must have completed. We can safely release the
1575 // scarce resources.
1576 if (scarceResourcesRefCount == 0) {
1577 // iterate through the list and release them all.
1578 // note that the actual SRD is owned by the JS engine,
1579 // so we cannot delete the SRD; but we can free the
1580 // memory used by the variant in the SRD.
1581 while (ScarceResourceData *sr = scarceResources.first()) {
1582 sr->data = QVariant();
1583 scarceResources.remove(sr);
1589 Adds \a path as a directory where the engine searches for
1590 installed modules in a URL-based directory structure.
1591 The \a path may be a local filesystem directory or a URL.
1593 The newly added \a path will be first in the importPathList().
1595 \sa setImportPathList(), {QML Modules}
1597 void QQmlEngine::addImportPath(const QString& path)
1600 d->importDatabase.addImportPath(path);
1604 Returns the list of directories where the engine searches for
1605 installed modules in a URL-based directory structure.
1607 For example, if \c /opt/MyApp/lib/imports is in the path, then QML that
1608 imports \c com.mycompany.Feature will cause the QQmlEngine to look
1609 in \c /opt/MyApp/lib/imports/com/mycompany/Feature/ for the components
1610 provided by that module. A \c qmldir file is required for defining the
1611 type version mapping and possibly QML extensions plugins.
1613 By default, the list contains the directory of the application executable,
1614 paths specified in the \c QML_IMPORT_PATH environment variable,
1615 and the builtin \c ImportsPath from QLibraryInfo.
1617 \sa addImportPath(), setImportPathList()
1619 QStringList QQmlEngine::importPathList() const
1621 Q_D(const QQmlEngine);
1622 return d->importDatabase.importPathList();
1626 Sets \a paths as the list of directories where the engine searches for
1627 installed modules in a URL-based directory structure.
1629 By default, the list contains the directory of the application executable,
1630 paths specified in the \c QML_IMPORT_PATH environment variable,
1631 and the builtin \c ImportsPath from QLibraryInfo.
1633 \sa importPathList(), addImportPath()
1635 void QQmlEngine::setImportPathList(const QStringList &paths)
1638 d->importDatabase.setImportPathList(paths);
1643 Adds \a path as a directory where the engine searches for
1644 native plugins for imported modules (referenced in the \c qmldir file).
1646 By default, the list contains only \c ., i.e. the engine searches
1647 in the directory of the \c qmldir file itself.
1649 The newly added \a path will be first in the pluginPathList().
1651 \sa setPluginPathList()
1653 void QQmlEngine::addPluginPath(const QString& path)
1656 d->importDatabase.addPluginPath(path);
1661 Returns the list of directories where the engine searches for
1662 native plugins for imported modules (referenced in the \c qmldir file).
1664 By default, the list contains only \c ., i.e. the engine searches
1665 in the directory of the \c qmldir file itself.
1667 \sa addPluginPath(), setPluginPathList()
1669 QStringList QQmlEngine::pluginPathList() const
1671 Q_D(const QQmlEngine);
1672 return d->importDatabase.pluginPathList();
1676 Sets the list of directories where the engine searches for
1677 native plugins for imported modules (referenced in the \c qmldir file)
1680 By default, the list contains only \c ., i.e. the engine searches
1681 in the directory of the \c qmldir file itself.
1683 \sa pluginPathList(), addPluginPath()
1685 void QQmlEngine::setPluginPathList(const QStringList &paths)
1688 d->importDatabase.setPluginPathList(paths);
1692 Imports the plugin named \a filePath with the \a uri provided.
1693 Returns true if the plugin was successfully imported; otherwise returns false.
1695 On failure and if non-null, the \a errors list will have any errors which occurred prepended to it.
1697 The plugin has to be a Qt plugin which implements the QQmlExtensionPlugin interface.
1699 bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors)
1702 return d->importDatabase.importPlugin(filePath, uri, errors);
1706 \property QQmlEngine::offlineStoragePath
1707 \brief the directory for storing offline user data
1709 Returns the directory where SQL and other offline
1712 QQuickWebView and the SQL databases created with openDatabase()
1715 The default is QML/OfflineStorage in the platform-standard
1716 user application data directory.
1718 Note that the path may not currently exist on the filesystem, so
1719 callers wanting to \e create new files at this location should create
1720 it first - see QDir::mkpath().
1722 void QQmlEngine::setOfflineStoragePath(const QString& dir)
1725 d->offlineStoragePath = dir;
1728 QString QQmlEngine::offlineStoragePath() const
1730 Q_D(const QQmlEngine);
1731 return d->offlineStoragePath;
1734 QQmlPropertyCache *QQmlEnginePrivate::createCache(const QMetaObject *mo)
1738 if (!mo->superClass()) {
1739 QQmlPropertyCache *rv = new QQmlPropertyCache(q, mo);
1740 propertyCache.insert(mo, rv);
1743 QQmlPropertyCache *super = cache(mo->superClass());
1744 QQmlPropertyCache *rv = super->copyAndAppend(q, mo);
1745 propertyCache.insert(mo, rv);
1750 QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersion,
1753 QList<QQmlType *> types;
1755 int maxMinorVersion = 0;
1757 const QMetaObject *metaObject = type->metaObject();
1759 while (metaObject) {
1760 QQmlType *t = QQmlMetaType::qmlType(metaObject, type->module(),
1761 type->majorVersion(), minorVersion);
1763 maxMinorVersion = qMax(maxMinorVersion, t->minorVersion());
1769 metaObject = metaObject->superClass();
1772 if (QQmlPropertyCache *c = typePropertyCache.value(qMakePair(type, maxMinorVersion))) {
1774 typePropertyCache.insert(qMakePair(type, minorVersion), c);
1778 QQmlPropertyCache *raw = cache(type->metaObject());
1780 bool hasCopied = false;
1782 for (int ii = 0; ii < types.count(); ++ii) {
1783 QQmlType *currentType = types.at(ii);
1787 int rev = currentType->metaObjectRevision();
1788 int moIndex = types.count() - 1 - ii;
1790 if (raw->allowedRevisionCache[moIndex] != rev) {
1795 raw->allowedRevisionCache[moIndex] = rev;
1799 // Test revision compatibility - the basic rule is:
1800 // * Anything that is excluded, cannot overload something that is not excluded *
1802 // Signals override:
1803 // * other signals and methods of the same name.
1804 // * properties named on<Signal Name>
1805 // * automatic <property name>Changed notify signals
1807 // Methods override:
1808 // * other methods of the same name
1810 // Properties override:
1811 // * other elements of the same name
1813 bool overloadError = false;
1814 QString overloadName;
1817 for (QQmlPropertyCache::StringCache::ConstIterator iter = raw->stringCache.begin();
1818 !overloadError && iter != raw->stringCache.end();
1821 QQmlPropertyData *d = *iter;
1822 if (raw->isAllowedInRevision(d))
1823 continue; // Not excluded - no problems
1825 // check that a regular "name" overload isn't happening
1826 QQmlPropertyData *current = d;
1827 while (!overloadError && current) {
1828 current = d->overrideData(current);
1829 if (current && raw->isAllowedInRevision(current))
1830 overloadError = true;
1835 if (overloadError) {
1836 if (hasCopied) raw->release();
1838 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."));
1842 if (!hasCopied) raw->addref();
1843 typePropertyCache.insert(qMakePair(type, minorVersion), raw);
1845 if (minorVersion != maxMinorVersion) {
1847 typePropertyCache.insert(qMakePair(type, maxMinorVersion), raw);
1853 QQmlMetaType::ModuleApiInstance *
1854 QQmlEnginePrivate::moduleApiInstance(const QQmlMetaType::ModuleApi &module)
1856 Locker locker(this);
1858 QQmlMetaType::ModuleApiInstance *a = moduleApiInstances.value(module);
1860 a = new QQmlMetaType::ModuleApiInstance;
1861 a->scriptCallback = module.script;
1862 a->qobjectCallback = module.qobject;
1863 a->instanceMetaObject = module.instanceMetaObject;
1864 moduleApiInstances.insert(module, a);
1870 bool QQmlEnginePrivate::isQObject(int t)
1872 Locker locker(this);
1873 return m_compositeTypes.contains(t) || QQmlMetaType::isQObject(t);
1876 QObject *QQmlEnginePrivate::toQObject(const QVariant &v, bool *ok) const
1878 Locker locker(this);
1879 int t = v.userType();
1880 if (t == QMetaType::QObjectStar || m_compositeTypes.contains(t)) {
1882 return *(QObject **)(v.constData());
1884 return QQmlMetaType::toQObject(v, ok);
1888 QQmlMetaType::TypeCategory QQmlEnginePrivate::typeCategory(int t) const
1890 Locker locker(this);
1891 if (m_compositeTypes.contains(t))
1892 return QQmlMetaType::Object;
1893 else if (m_qmlLists.contains(t))
1894 return QQmlMetaType::List;
1896 return QQmlMetaType::typeCategory(t);
1899 bool QQmlEnginePrivate::isList(int t) const
1901 Locker locker(this);
1902 return m_qmlLists.contains(t) || QQmlMetaType::isList(t);
1905 int QQmlEnginePrivate::listType(int t) const
1907 Locker locker(this);
1908 QHash<int, int>::ConstIterator iter = m_qmlLists.find(t);
1909 if (iter != m_qmlLists.end())
1912 return QQmlMetaType::listType(t);
1915 QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const
1917 Locker locker(this);
1918 QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.find(t);
1919 if (iter != m_compositeTypes.end()) {
1920 return QQmlMetaObject((*iter)->rootPropertyCache);
1922 QQmlType *type = QQmlMetaType::qmlType(t);
1923 return QQmlMetaObject(type?type->baseMetaObject():0);
1927 QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const
1929 Locker locker(this);
1930 QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.find(t);
1931 if (iter != m_compositeTypes.end()) {
1932 return QQmlMetaObject((*iter)->rootPropertyCache);
1934 QQmlType *type = QQmlMetaType::qmlType(t);
1935 return QQmlMetaObject(type?type->metaObject():0);
1939 QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t)
1941 Locker locker(this);
1942 QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.find(t);
1943 if (iter != m_compositeTypes.end()) {
1944 return (*iter)->rootPropertyCache;
1946 QQmlType *type = QQmlMetaType::qmlType(t);
1948 return type?cache(type->metaObject()):0;
1952 QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t)
1954 Locker locker(this);
1955 QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.find(t);
1956 if (iter != m_compositeTypes.end()) {
1957 return (*iter)->rootPropertyCache;
1959 QQmlType *type = QQmlMetaType::qmlType(t);
1961 return type?cache(type->baseMetaObject()):0;
1965 void QQmlEnginePrivate::registerCompositeType(QQmlCompiledData *data)
1967 QByteArray name = data->rootPropertyCache->className();
1969 QByteArray ptr = name + '*';
1970 QByteArray lst = "QQmlListProperty<" + name + '>';
1972 int ptr_type = QMetaType::registerNormalizedType(ptr,
1973 qMetaTypeDeleteHelper<QObject*>,
1974 qMetaTypeCreateHelper<QObject*>,
1975 qMetaTypeDestructHelper<QObject*>,
1976 qMetaTypeConstructHelper<QObject*>,
1978 static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QObject*>::Flags),
1980 int lst_type = QMetaType::registerNormalizedType(lst,
1981 qMetaTypeDeleteHelper<QQmlListProperty<QObject> >,
1982 qMetaTypeCreateHelper<QQmlListProperty<QObject> >,
1983 qMetaTypeDestructHelper<QQmlListProperty<QObject> >,
1984 qMetaTypeConstructHelper<QQmlListProperty<QObject> >,
1985 sizeof(QQmlListProperty<QObject>),
1986 static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QQmlListProperty<QObject> >::Flags),
1987 static_cast<QMetaObject*>(0));
1989 data->metaTypeId = ptr_type;
1990 data->listMetaTypeId = lst_type;
1991 data->isRegisteredWithEngine = true;
1993 Locker locker(this);
1994 m_qmlLists.insert(lst_type, ptr_type);
1995 // The QQmlCompiledData is not referenced here, but it is removed from this
1996 // hash in the QQmlCompiledData destructor
1997 m_compositeTypes.insert(ptr_type, data);
2000 void QQmlEnginePrivate::unregisterCompositeType(QQmlCompiledData *data)
2002 int ptr_type = data->metaTypeId;
2003 int lst_type = data->listMetaTypeId;
2005 Locker locker(this);
2006 m_qmlLists.remove(lst_type);
2007 m_compositeTypes.remove(ptr_type);
2010 bool QQmlEnginePrivate::isTypeLoaded(const QUrl &url) const
2012 return typeLoader.isTypeLoaded(url);
2015 bool QQmlEnginePrivate::isScriptLoaded(const QUrl &url) const
2017 return typeLoader.isScriptLoaded(url);
2020 bool QQml_isFileCaseCorrect(const QString &fileName)
2022 #if defined(Q_OS_MAC) || defined(Q_OS_WIN)
2023 QFileInfo info(fileName);
2024 const QString absolute = info.absoluteFilePath();
2026 #if defined(Q_OS_MAC)
2027 const QString canonical = info.canonicalFilePath();
2028 #elif defined(Q_OS_WIN)
2029 wchar_t buffer[1024];
2031 DWORD rv = ::GetShortPathName((wchar_t*)absolute.utf16(), buffer, 1024);
2032 if (rv == 0 || rv >= 1024) return true;
2033 rv = ::GetLongPathName(buffer, buffer, 1024);
2034 if (rv == 0 || rv >= 1024) return true;
2036 const QString canonical = QString::fromWCharArray(buffer);
2039 const int absoluteLength = absolute.length();
2040 const int canonicalLength = canonical.length();
2042 const int length = qMin(absoluteLength, canonicalLength);
2043 for (int ii = 0; ii < length; ++ii) {
2044 const QChar &a = absolute.at(absoluteLength - 1 - ii);
2045 const QChar &c = canonical.at(canonicalLength - 1 - ii);
2047 if (a.toLower() != c.toLower())
2059 \fn QQmlEngine *qmlEngine(const QObject *object)
2062 Returns the QQmlEngine associated with \a object, if any. This is equivalent to
2063 QQmlEngine::contextForObject(object)->engine(), but more efficient.
2067 \fn QQmlContext *qmlContext(const QObject *object)
2070 Returns the QQmlContext associated with \a object, if any. This is equivalent to
2071 QQmlEngine::contextForObject(object).