From b855240b782395f94315f43ea3e7e182299fac48 Mon Sep 17 00:00:00 2001 From: Matthew Vogt Date: Thu, 16 Feb 2012 14:43:03 +1000 Subject: Rename QDeclarative symbols to QQuick and QQml Symbols beginning with QDeclarative are already exported by the quick1 module. Users can apply the bin/rename-qtdeclarative-symbols.sh script to modify client code using the previous names of the renamed symbols. Task-number: QTBUG-23737 Change-Id: Ifaa482663767634931e8711a8e9bf6e404859e66 Reviewed-by: Martin Jones --- src/qml/qml/qqmlengine.cpp | 1854 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1854 insertions(+) create mode 100644 src/qml/qml/qqmlengine.cpp (limited to 'src/qml/qml/qqmlengine.cpp') diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp new file mode 100644 index 0000000000..8cfe635543 --- /dev/null +++ b/src/qml/qml/qqmlengine.cpp @@ -0,0 +1,1854 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmlengine_p.h" +#include "qqmlengine.h" +#include "qqmlcomponentattached_p.h" + +#include "qqmlcontext_p.h" +#include "qqmlcompiler_p.h" +#include "qqml.h" +#include "qqmlcontext.h" +#include "qqmlexpression.h" +#include "qqmlcomponent.h" +#include "qqmlbinding_p_p.h" +#include "qqmlvme_p.h" +#include +#include "qqmlstringconverters_p.h" +#include "qqmlxmlhttprequest_p.h" +#include "qqmlscriptstring.h" +#include "qqmlglobal_p.h" +#include "qquicklistmodel_p.h" +#include "qquickworkerscript_p.h" +#include "qqmlcomponent_p.h" +#include "qqmlnetworkaccessmanagerfactory.h" +#include "qqmlimageprovider.h" +#include "qqmldirparser_p.h" +#include "qqmlextensioninterface.h" +#include "qqmllist_p.h" +#include "qqmltypenamecache_p.h" +#include "qqmlnotifier_p.h" +#include +#include +#include +#include +#include "qqmlincubator.h" +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#ifdef Q_OS_WIN // for %APPDATA% +#include +#include +#include + +#define CSIDL_APPDATA 0x001a // \Application Data +#endif + +Q_DECLARE_METATYPE(QQmlProperty) + +QT_BEGIN_NAMESPACE + +void qmlRegisterBaseTypes(const char *uri, int versionMajor, int versionMinor) +{ + QQmlEnginePrivate::registerBaseTypes(uri, versionMajor, versionMinor); + QQmlValueTypeFactory::registerBaseTypes(uri, versionMajor, versionMinor); +} + +/*! + \qmlclass QtObject QObject + \ingroup qml-utility-elements + \since 4.7 + \brief The QtObject element is the most basic element in QML. + + The QtObject element is a non-visual element which contains only the + objectName property. + + It can be useful to create a QtObject if you need an extremely + lightweight element to enclose a set of custom properties: + + \snippet doc/src/snippets/qml/qtobject.qml 0 + + It can also be useful for C++ integration, as it is just a plain + QObject. See the QObject documentation for further details. +*/ +/*! + \qmlproperty string QtObject::objectName + This property holds the QObject::objectName for this specific object instance. + + This allows a C++ application to locate an item within a QML component + using the QObject::findChild() method. For example, the following C++ + application locates the child \l Rectangle item and dynamically changes its + \c color value: + + \qml + // MyRect.qml + + import QtQuick 2.0 + + Item { + width: 200; height: 200 + + Rectangle { + anchors.fill: parent + color: "red" + objectName: "myRect" + } + } + \endqml + + \code + // main.cpp + + QQuickView view; + view.setSource(QUrl::fromLocalFile("MyRect.qml")); + view.show(); + + QQuickItem *item = view.rootObject()->findChild("myRect"); + if (item) + item->setProperty("color", QColor(Qt::yellow)); + \endcode +*/ + +bool QQmlEnginePrivate::qml_debugging_enabled = false; + +void QQmlEnginePrivate::registerBaseTypes(const char *uri, int versionMajor, int versionMinor) +{ + qmlRegisterType(uri,versionMajor,versionMinor,"Component"); + qmlRegisterType(uri,versionMajor,versionMinor,"QtObject"); + qmlRegisterType(uri, versionMajor, versionMinor,"ListElement"); + qmlRegisterCustomType(uri, versionMajor, versionMinor,"ListModel", new QQuickListModelParser); + qmlRegisterType(uri,versionMajor,versionMinor,"WorkerScript"); +} + +void QQmlEnginePrivate::defineModule() +{ + registerBaseTypes("QtQuick", 2, 0); + qmlRegisterType(); + qmlRegisterUncreatableType("QtQuick",2,0,"Application", QQuickApplication::tr("Application is an abstract class")); + qmlRegisterUncreatableType("QtQuick",2,0,"Locale",QQmlEngine::tr("Locale cannot be instantiated. Use Qt.locale()")); +} + +/*! +\qmlclass Qt QQmlEnginePrivate + \ingroup qml-utility-elements +\brief The QML global Qt object provides useful enums and functions from Qt. + +\keyword QmlGlobalQtObject + +\brief The \c Qt object provides useful enums and functions from Qt, for use in all QML files. + +The \c Qt object is a global object with utility functions, properties and enums. + +It is not instantiable; to use it, call the members of the global \c Qt object directly. +For example: + +\qml +import QtQuick 2.0 + +Text { + color: Qt.rgba(1, 0, 0, 1) + text: Qt.md5("hello, world") +} +\endqml + + +\section1 Enums + +The Qt object contains the enums available in the \l {Qt Namespace}. For example, you can access +the \l Qt::LeftButton and \l Qt::RightButton enum values as \c Qt.LeftButton and \c Qt.RightButton. + + +\section1 Types +The Qt object also contains helper functions for creating objects of specific +data types. This is primarily useful when setting the properties of an item +when the property has one of the following types: + +\list +\o \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()} +\o \c rect - use \l{Qt::rect()}{Qt.rect()} +\o \c point - use \l{Qt::point()}{Qt.point()} +\o \c size - use \l{Qt::size()}{Qt.size()} +\o \c vector3d - use \l{Qt::vector3d()}{Qt.vector3d()} +\endlist + +There are also string based constructors for these types. See \l{qdeclarativebasictypes.html}{QML Basic Types} for more information. + +\section1 Date/Time Formatters + +The Qt object contains several functions for formatting QDateTime, QDate and QTime values. + +\list + \o \l{Qt::formatDateTime}{string Qt.formatDateTime(datetime date, variant format)} + \o \l{Qt::formatDate}{string Qt.formatDate(datetime date, variant format)} + \o \l{Qt::formatTime}{string Qt.formatTime(datetime date, variant format)} +\endlist + +The format specification is described at \l{Qt::formatDateTime}{Qt.formatDateTime}. + + +\section1 Dynamic Object Creation +The following functions on the global object allow you to dynamically create QML +items from files or strings. See \l{Dynamic Object Management in QML} for an overview +of their use. + +\list + \o \l{Qt::createComponent()}{object Qt.createComponent(url)} + \o \l{Qt::createQmlObject()}{object Qt.createQmlObject(string qml, object parent, string filepath)} +\endlist +*/ + + +/*! + \qmlproperty object Qt::application + \since QtQuick 1.1 + + The \c application object provides access to global application state + properties shared by many QML components. + + Its properties are: + + \table + \row + \o \c application.active + \o + This read-only property indicates whether the application is the top-most and focused + application, and the user is able to interact with the application. The property + is false when the application is in the background, the device keylock or screen + saver is active, the screen backlight is turned off, or the global system dialog + is being displayed on top of the application. It can be used for stopping and + pausing animations, timers and active processing of data in order to save device + battery power and free device memory and processor load when the application is not + active. + + \row + \o \c application.layoutDirection + \o + This read-only property can be used to query the default layout direction of the + application. On system start-up, the default layout direction depends on the + application's language. The property has a value of \c Qt.RightToLeft in locales + where text and graphic elements are read from right to left, and \c Qt.LeftToRight + where the reading direction flows from left to right. You can bind to this + property to customize your application layouts to support both layout directions. + + Possible values are: + + \list + \o Qt.LeftToRight - Text and graphics elements should be positioned + from left to right. + \o Qt.RightToLeft - Text and graphics elements should be positioned + from right to left. + \endlist + + \row + \o \c application.inputPanel + \o + This read-only property allows access to application's QInputPanel object + and all its properties and slots. See the QInputPanel documentation for + further details. Deprecated in favor of Qt.InputMethod + \endtable + + The following example uses the \c application object to indicate + whether the application is currently active: + + \snippet doc/src/snippets/qml/application.qml document + + \qmlproperty object Qt::inputMethod + \since QtQuick 2.0 + + The \c inputMethod object allows access to application's QInputMethod object + and all its properties and slots. See the QInputMethod documentation for + further details. +*/ + + +/*! +\qmlmethod object Qt::include(string url, jsobject callback) + +Includes another JavaScript file. This method can only be used from within JavaScript files, +and not regular QML files. + +This imports all functions from \a url into the current script's namespace. + +Qt.include() returns an object that describes the status of the operation. The object has +a single property, \c {status}, that is set to one of the following values: + +\table +\header \o Symbol \o Value \o Description +\row \o result.OK \o 0 \o The include completed successfully. +\row \o result.LOADING \o 1 \o Data is being loaded from the network. +\row \o result.NETWORK_ERROR \o 2 \o A network error occurred while fetching the url. +\row \o result.EXCEPTION \o 3 \o A JavaScript exception occurred while executing the included code. +An additional \c exception property will be set in this case. +\endtable + +The \c status property will be updated as the operation progresses. + +If provided, \a callback is invoked when the operation completes. The callback is passed +the same object as is returned from the Qt.include() call. +*/ +// Qt.include() is implemented in qv8include.cpp + + +QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e) +: propertyCapture(0), rootContext(0), isDebugging(false), + outputWarningsToStdErr(true), sharedContext(0), sharedScope(0), + cleanup(0), erroredBindings(0), inProgressCreations(0), + workerScriptEngine(0), activeVME(0), + networkAccessManager(0), networkAccessManagerFactory(0), + scarceResourcesRefCount(0), typeLoader(e), importDatabase(e), uniqueId(1), + incubatorCount(0), incubationController(0), mutex(QMutex::Recursive) +{ +} + +QQmlEnginePrivate::~QQmlEnginePrivate() +{ + Q_ASSERT(inProgressCreations == 0); + + while (cleanup) { + QQmlCleanup *c = cleanup; + cleanup = c->next; + if (cleanup) cleanup->prev = &cleanup; + c->next = 0; + c->prev = 0; + c->clear(); + } + + doDeleteInEngineThread(); + + if (incubationController) incubationController->d = 0; + incubationController = 0; + + delete rootContext; + rootContext = 0; + + for(QHash::ConstIterator iter = m_compositeTypes.constBegin(); iter != m_compositeTypes.constEnd(); ++iter) + (*iter)->release(); + for(QHash::Iterator iter = propertyCache.begin(); iter != propertyCache.end(); ++iter) + (*iter)->release(); + for(QHash, QQmlPropertyCache *>::Iterator iter = typePropertyCache.begin(); iter != typePropertyCache.end(); ++iter) + (*iter)->release(); + for(QHash::Iterator iter = moduleApiInstances.begin(); iter != moduleApiInstances.end(); ++iter) { + delete (*iter)->qobjectApi; + delete *iter; + } +} + +void QQmlPrivate::qdeclarativeelement_destructor(QObject *o) +{ + QObjectPrivate *p = QObjectPrivate::get(o); + if (p->declarativeData) { + QQmlData *d = static_cast(p->declarativeData); + if (d->ownContext && d->context) { + d->context->destroy(); + d->context = 0; + } + } +} + +void QQmlData::destroyed(QAbstractDeclarativeData *d, QObject *o) +{ + static_cast(d)->destroyed(o); +} + +void QQmlData::parentChanged(QAbstractDeclarativeData *d, QObject *o, QObject *p) +{ + static_cast(d)->parentChanged(o, p); +} + +void QQmlData::objectNameChanged(QAbstractDeclarativeData *d, QObject *o) +{ + static_cast(d)->objectNameChanged(o); +} + +void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int index, void **) +{ + QQmlData *ddata = QQmlData::get(object, false); + if (!ddata) return; // Probably being deleted + + QQmlNotifierEndpoint *ep = ddata->notify(index); + if (ep) QQmlNotifier::emitNotify(ep); +} + +void QQmlEnginePrivate::init() +{ + Q_Q(QQmlEngine); + + static bool firstTime = true; + if (firstTime) { + qmlRegisterType("QML", 1, 0, "Component"); + + firstTime = false; + } + + qRegisterMetaType("QVariant"); + qRegisterMetaType("QQmlScriptString"); + qRegisterMetaType("QJSValue"); + qRegisterMetaType("QQmlComponent::Status"); + qRegisterMetaType >("QList"); + qRegisterMetaType >("QList"); + qRegisterMetaType("QQmlV8Handle"); + + QQmlData::init(); + + v8engine()->setEngine(q); + + rootContext = new QQmlContext(q,true); + + if (QCoreApplication::instance()->thread() == q->thread() && + QQmlEngineDebugService::isDebuggingEnabled()) { + isDebugging = true; + QQmlEngineDebugService::instance()->addEngine(q); + QV8DebugService::initialize(v8engine()); + QV8ProfilerService::initialize(); + QQmlProfilerService::initialize(); + QDebugMessageService::instance(); + } + + QString dataLocation = QStandardPaths::writableLocation(QStandardPaths::DataLocation); + offlineStoragePath = dataLocation.replace(QLatin1Char('/'), QDir::separator()) + + QDir::separator() + QLatin1String("QML") + + QDir::separator() + QLatin1String("OfflineStorage"); +} + +QQuickWorkerScriptEngine *QQmlEnginePrivate::getWorkerScriptEngine() +{ + Q_Q(QQmlEngine); + if (!workerScriptEngine) + workerScriptEngine = new QQuickWorkerScriptEngine(q); + return workerScriptEngine; +} + +/*! + \class QQmlEngine + \since 4.7 + \brief The QQmlEngine class provides an environment for instantiating QML components. + \mainclass + + Each QML component is instantiated in a QQmlContext. + QQmlContext's are essential for passing data to QML + components. In QML, contexts are arranged hierarchically and this + hierarchy is managed by the QQmlEngine. + + Prior to creating any QML components, an application must have + created a QQmlEngine to gain access to a QML context. The + following example shows how to create a simple Text item. + + \code + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData("import QtQuick 2.0\nText { text: \"Hello world!\" }", QUrl()); + QQuickItem *item = qobject_cast(component.create()); + + //add item to view, etc + ... + \endcode + + In this case, the Text item will be created in the engine's + \l {QQmlEngine::rootContext()}{root context}. + + \sa QQmlComponent QQmlContext +*/ + +/*! + Create a new QQmlEngine with the given \a parent. +*/ +QQmlEngine::QQmlEngine(QObject *parent) +: QJSEngine(*new QQmlEnginePrivate(this), parent) +{ + Q_D(QQmlEngine); + d->init(); +} + +/*! + Destroys the QQmlEngine. + + Any QQmlContext's created on this engine will be + invalidated, but not destroyed (unless they are parented to the + QQmlEngine object). +*/ +QQmlEngine::~QQmlEngine() +{ + Q_D(QQmlEngine); + if (d->isDebugging) { + QQmlEngineDebugService::instance()->remEngine(this); + } + + // if we are the parent of any of the qobject module api instances, + // we need to remove them from our internal list, in order to prevent + // a segfault in engine private dtor. + QList keys = d->moduleApiInstances.keys(); + QObject *currQObjectApi = 0; + QQmlMetaType::ModuleApiInstance *currInstance = 0; + foreach (const QQmlMetaType::ModuleApi &key, keys) { + currInstance = d->moduleApiInstances.value(key); + currQObjectApi = currInstance->qobjectApi; + if (this->children().contains(currQObjectApi)) { + delete currQObjectApi; + delete currInstance; + d->moduleApiInstances.remove(key); + } + } + + // ensure we clean up QObjects with JS ownership + d->v8engine()->gc(); + + if (d->incubationController) + d->incubationController->d = 0; +} + +/*! \fn void QQmlEngine::quit() + This signal is emitted when the QML loaded by the engine would like to quit. + */ + +/*! \fn void QQmlEngine::warnings(const QList &warnings) + This signal is emitted when \a warnings messages are generated by QML. + */ + +/*! + Clears the engine's internal component cache. + + Normally the QQmlEngine caches components loaded from qml + files. This method clears this cache and forces the component to be + reloaded. + */ +void QQmlEngine::clearComponentCache() +{ + Q_D(QQmlEngine); + d->typeLoader.clearCache(); +} + +/*! + Returns the engine's root context. + + The root context is automatically created by the QQmlEngine. + Data that should be available to all QML component instances + instantiated by the engine should be put in the root context. + + Additional data that should only be available to a subset of + component instances should be added to sub-contexts parented to the + root context. +*/ +QQmlContext *QQmlEngine::rootContext() const +{ + Q_D(const QQmlEngine); + return d->rootContext; +} + +/*! + Sets the \a factory to use for creating QNetworkAccessManager(s). + + QNetworkAccessManager is used for all network access by QML. By + implementing a factory it is possible to create custom + QNetworkAccessManager with specialized caching, proxy and cookie + support. + + The factory must be set before executing the engine. +*/ +void QQmlEngine::setNetworkAccessManagerFactory(QQmlNetworkAccessManagerFactory *factory) +{ + Q_D(QQmlEngine); + QMutexLocker locker(&d->mutex); + d->networkAccessManagerFactory = factory; +} + +/*! + Returns the current QQmlNetworkAccessManagerFactory. + + \sa setNetworkAccessManagerFactory() +*/ +QQmlNetworkAccessManagerFactory *QQmlEngine::networkAccessManagerFactory() const +{ + Q_D(const QQmlEngine); + return d->networkAccessManagerFactory; +} + +void QQmlEnginePrivate::registerFinalizeCallback(QObject *obj, int index) +{ + if (activeVME) { + activeVME->finalizeCallbacks.append(qMakePair(QQmlGuard(obj), index)); + } else { + void *args[] = { 0 }; + QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, index, args); + } +} + +QNetworkAccessManager *QQmlEnginePrivate::createNetworkAccessManager(QObject *parent) const +{ + QMutexLocker locker(&mutex); + QNetworkAccessManager *nam; + if (networkAccessManagerFactory) { + nam = networkAccessManagerFactory->create(parent); + } else { + nam = new QNetworkAccessManager(parent); + } + + return nam; +} + +QNetworkAccessManager *QQmlEnginePrivate::getNetworkAccessManager() const +{ + Q_Q(const QQmlEngine); + if (!networkAccessManager) + networkAccessManager = createNetworkAccessManager(const_cast(q)); + return networkAccessManager; +} + +/*! + Returns a common QNetworkAccessManager which can be used by any QML + element instantiated by this engine. + + If a QQmlNetworkAccessManagerFactory has been set and a + QNetworkAccessManager has not yet been created, the + QQmlNetworkAccessManagerFactory will be used to create the + QNetworkAccessManager; otherwise the returned QNetworkAccessManager + will have no proxy or cache set. + + \sa setNetworkAccessManagerFactory() +*/ +QNetworkAccessManager *QQmlEngine::networkAccessManager() const +{ + Q_D(const QQmlEngine); + return d->getNetworkAccessManager(); +} + +/*! + + Sets the \a provider to use for images requested via the \e + image: url scheme, with host \a providerId. The QQmlEngine + takes ownership of \a provider. + + Image providers enable support for pixmap and threaded image + requests. See the QQmlImageProvider documentation for details on + implementing and using image providers. + + All required image providers should be added to the engine before any + QML sources files are loaded. + + \sa removeImageProvider() +*/ +void QQmlEngine::addImageProvider(const QString &providerId, QQmlImageProvider *provider) +{ + Q_D(QQmlEngine); + QMutexLocker locker(&d->mutex); + d->imageProviders.insert(providerId.toLower(), QSharedPointer(provider)); +} + +/*! + Returns the QQmlImageProvider set for \a providerId. + + Returns the provider if it was found; otherwise returns 0. +*/ +QQmlImageProvider *QQmlEngine::imageProvider(const QString &providerId) const +{ + Q_D(const QQmlEngine); + QMutexLocker locker(&d->mutex); + return d->imageProviders.value(providerId).data(); +} + +/*! + Removes the QQmlImageProvider for \a providerId. + + \sa addImageProvider() +*/ +void QQmlEngine::removeImageProvider(const QString &providerId) +{ + Q_D(QQmlEngine); + QMutexLocker locker(&d->mutex); + d->imageProviders.take(providerId); +} + +QQmlImageProvider::ImageType QQmlEnginePrivate::getImageProviderType(const QUrl &url) +{ + QMutexLocker locker(&mutex); + QSharedPointer provider = imageProviders.value(url.host()); + locker.unlock(); + if (provider) + return provider->imageType(); + return QQmlImageProvider::Invalid; +} + +QQuickTextureFactory *QQmlEnginePrivate::getTextureFromProvider(const QUrl &url, QSize *size, const QSize& req_size) +{ + QMutexLocker locker(&mutex); + QSharedPointer provider = imageProviders.value(url.host()); + locker.unlock(); + if (provider) { + QString imageId = url.toString(QUrl::RemoveScheme | QUrl::RemoveAuthority).mid(1); + return provider->requestTexture(imageId, size, req_size); + } + return 0; +} + +QImage QQmlEnginePrivate::getImageFromProvider(const QUrl &url, QSize *size, const QSize& req_size) +{ + QMutexLocker locker(&mutex); + QImage image; + QSharedPointer provider = imageProviders.value(url.host()); + locker.unlock(); + if (provider) { + QString imageId = url.toString(QUrl::RemoveScheme | QUrl::RemoveAuthority).mid(1); + image = provider->requestImage(imageId, size, req_size); + } + return image; +} + +QPixmap QQmlEnginePrivate::getPixmapFromProvider(const QUrl &url, QSize *size, const QSize& req_size) +{ + QMutexLocker locker(&mutex); + QPixmap pixmap; + QSharedPointer provider = imageProviders.value(url.host()); + locker.unlock(); + if (provider) { + QString imageId = url.toString(QUrl::RemoveScheme | QUrl::RemoveAuthority).mid(1); + pixmap = provider->requestPixmap(imageId, size, req_size); + } + return pixmap; +} + +/*! + Return the base URL for this engine. The base URL is only used to + resolve components when a relative URL is passed to the + QQmlComponent constructor. + + If a base URL has not been explicitly set, this method returns the + application's current working directory. + + \sa setBaseUrl() +*/ +QUrl QQmlEngine::baseUrl() const +{ + Q_D(const QQmlEngine); + if (d->baseUrl.isEmpty()) { + return QUrl::fromLocalFile(QDir::currentPath() + QDir::separator()); + } else { + return d->baseUrl; + } +} + +/*! + Set the base URL for this engine to \a url. + + \sa baseUrl() +*/ +void QQmlEngine::setBaseUrl(const QUrl &url) +{ + Q_D(QQmlEngine); + d->baseUrl = url; +} + +/*! + Returns true if warning messages will be output to stderr in addition + to being emitted by the warnings() signal, otherwise false. + + The default value is true. +*/ +bool QQmlEngine::outputWarningsToStandardError() const +{ + Q_D(const QQmlEngine); + return d->outputWarningsToStdErr; +} + +/*! + Set whether warning messages will be output to stderr to \a enabled. + + If \a enabled is true, any warning messages generated by QML will be + output to stderr and emitted by the warnings() signal. If \a enabled + is false, on the warnings() signal will be emitted. This allows + applications to handle warning output themselves. + + The default value is true. +*/ +void QQmlEngine::setOutputWarningsToStandardError(bool enabled) +{ + Q_D(QQmlEngine); + d->outputWarningsToStdErr = enabled; +} + +/*! + Attempt to free unused memory. +*/ +void QQmlEngine::collectGarbage() +{ + QV8Engine::gc(); +} + +/*! + Returns the QQmlContext for the \a object, or 0 if no + context has been set. + + When the QQmlEngine instantiates a QObject, the context is + set automatically. + */ +QQmlContext *QQmlEngine::contextForObject(const QObject *object) +{ + if(!object) + return 0; + + QObjectPrivate *priv = QObjectPrivate::get(const_cast(object)); + + QQmlData *data = + static_cast(priv->declarativeData); + + if (!data) + return 0; + else if (data->outerContext) + return data->outerContext->asQQmlContext(); + else + return 0; +} + +/*! + Sets the QQmlContext for the \a object to \a context. + If the \a object already has a context, a warning is + output, but the context is not changed. + + When the QQmlEngine instantiates a QObject, the context is + set automatically. + */ +void QQmlEngine::setContextForObject(QObject *object, QQmlContext *context) +{ + if (!object || !context) + return; + + QQmlData *data = QQmlData::get(object, true); + if (data->context) { + qWarning("QQmlEngine::setContextForObject(): Object already has a QQmlContext"); + return; + } + + QQmlContextData *contextData = QQmlContextData::get(context); + contextData->addObject(object); +} + +/*! + \enum QQmlEngine::ObjectOwnership + + Ownership controls whether or not QML automatically destroys the + QObject when the object is garbage collected by the JavaScript + engine. The two ownership options are: + + \value CppOwnership The object is owned by C++ code, and will + never be deleted by QML. The JavaScript destroy() method cannot be + used on objects with CppOwnership. This option is similar to + QScriptEngine::QtOwnership. + + \value JavaScriptOwnership The object is owned by JavaScript. + When the object is returned to QML as the return value of a method + call or property access, QML will delete the object if there are no + remaining JavaScript references to it and it has no + QObject::parent(). This option is similar to + QScriptEngine::ScriptOwnership. + + Generally an application doesn't need to set an object's ownership + explicitly. QML uses a heuristic to set the default object + ownership. By default, an object that is created by QML has + JavaScriptOwnership. The exception to this are the root objects + created by calling QQmlComponent::create() or + QQmlComponent::beginCreate() which have CppOwnership by + default. The ownership of these root-level objects is considered to + have been transferred to the C++ caller. + + Objects not-created by QML have CppOwnership by default. The + exception to this is objects returned from a C++ method call. The + ownership of these objects is passed to JavaScript. + + Calling setObjectOwnership() overrides the default ownership + heuristic used by QML. +*/ + +/*! + Sets the \a ownership of \a object. +*/ +void QQmlEngine::setObjectOwnership(QObject *object, ObjectOwnership ownership) +{ + if (!object) + return; + + QQmlData *ddata = QQmlData::get(object, true); + if (!ddata) + return; + + ddata->indestructible = (ownership == CppOwnership)?true:false; + ddata->explicitIndestructibleSet = true; +} + +/*! + Returns the ownership of \a object. +*/ +QQmlEngine::ObjectOwnership QQmlEngine::objectOwnership(QObject *object) +{ + if (!object) + return CppOwnership; + + QQmlData *ddata = QQmlData::get(object, false); + if (!ddata) + return CppOwnership; + else + return ddata->indestructible?CppOwnership:JavaScriptOwnership; +} + +bool QQmlEngine::event(QEvent *e) +{ + Q_D(QQmlEngine); + if (e->type() == QEvent::User) + d->doDeleteInEngineThread(); + + return QJSEngine::event(e); +} + +void QQmlEnginePrivate::doDeleteInEngineThread() +{ + QFieldList list; + mutex.lock(); + list.copyAndClear(toDeleteInEngineThread); + mutex.unlock(); + + while (Deletable *d = list.takeFirst()) + delete d; +} + +Q_AUTOTEST_EXPORT void qmlExecuteDeferred(QObject *object) +{ + QQmlData *data = QQmlData::get(object); + + if (data && data->deferredComponent) { + if (QQmlDebugService::isDebuggingEnabled()) { + QQmlProfilerService::startRange(QQmlProfilerService::Creating); + QQmlType *type = QQmlMetaType::qmlType(object->metaObject()); + QString typeName = type ? type->qmlTypeName() : QString::fromUtf8(object->metaObject()->className()); + QQmlProfilerService::rangeData(QQmlProfilerService::Creating, typeName); + if (data->outerContext) + QQmlProfilerService::rangeLocation(QQmlProfilerService::Creating, data->outerContext->url, data->lineNumber, data->columnNumber); + } + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine); + + QQmlComponentPrivate::ConstructionState state; + QQmlComponentPrivate::beginDeferred(ep, object, &state); + + data->deferredComponent->release(); + data->deferredComponent = 0; + + QQmlComponentPrivate::complete(ep, &state); + QQmlProfilerService::endRange(QQmlProfilerService::Creating); + } +} + +QQmlContext *qmlContext(const QObject *obj) +{ + return QQmlEngine::contextForObject(obj); +} + +QQmlEngine *qmlEngine(const QObject *obj) +{ + QQmlData *data = QQmlData::get(obj, false); + if (!data || !data->context) + return 0; + return data->context->engine; +} + +QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create) +{ + QQmlData *data = QQmlData::get(object); + if (!data) + return 0; // Attached properties are only on objects created by QML + + QObject *rv = data->hasExtendedData()?data->attachedProperties()->value(id):0; + if (rv || !create) + return rv; + + QQmlAttachedPropertiesFunc pf = QQmlMetaType::attachedPropertiesFuncById(id); + if (!pf) + return 0; + + rv = pf(const_cast(object)); + + if (rv) + data->attachedProperties()->insert(id, rv); + + return rv; +} + +QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *object, + const QMetaObject *attachedMetaObject, bool create) +{ + if (*idCache == -1) + *idCache = QQmlMetaType::attachedPropertiesFuncId(attachedMetaObject); + + if (*idCache == -1 || !object) + return 0; + + return qmlAttachedPropertiesObjectById(*idCache, object, create); +} + +QQmlDebuggingEnabler::QQmlDebuggingEnabler() +{ +#ifndef QQML_NO_DEBUG_PROTOCOL + if (!QQmlEnginePrivate::qml_debugging_enabled) { + qWarning("Qml debugging is enabled. Only use this in a safe environment!"); + } + QQmlEnginePrivate::qml_debugging_enabled = true; +#endif +} + + +class QQmlDataExtended { +public: + QQmlDataExtended(); + ~QQmlDataExtended(); + + QHash attachedProperties; + QQmlNotifier objectNameNotifier; +}; + +QQmlDataExtended::QQmlDataExtended() +{ +} + +QQmlDataExtended::~QQmlDataExtended() +{ +} + +void QQmlData::NotifyList::layout(QQmlNotifierEndpoint *endpoint) +{ + if (endpoint->next) + layout(endpoint->next); + + int index = endpoint->sourceSignal; + index = qMin(index, 0xFFFF - 1); + + endpoint->next = notifies[index]; + if (endpoint->next) endpoint->next->prev = &endpoint->next; + endpoint->prev = ¬ifies[index]; + notifies[index] = endpoint; +} + +void QQmlData::NotifyList::layout() +{ + Q_ASSERT(maximumTodoIndex >= notifiesSize); + + if (todo) { + QQmlNotifierEndpoint **old = notifies; + const int reallocSize = (maximumTodoIndex + 1) * sizeof(QQmlNotifierEndpoint*); + notifies = (QQmlNotifierEndpoint**)realloc(notifies, reallocSize); + const int memsetSize = (maximumTodoIndex - notifiesSize + 1) * + sizeof(QQmlNotifierEndpoint*); + memset(notifies + notifiesSize, 0, memsetSize); + + if (notifies != old) { + for (int ii = 0; ii < notifiesSize; ++ii) + if (notifies[ii]) + notifies[ii]->prev = ¬ifies[ii]; + } + + notifiesSize = maximumTodoIndex + 1; + + layout(todo); + } + + maximumTodoIndex = 0; + todo = 0; +} + +void QQmlData::addNotify(int index, QQmlNotifierEndpoint *endpoint) +{ + if (!notifyList) { + notifyList = (NotifyList *)malloc(sizeof(NotifyList)); + notifyList->connectionMask = 0; + notifyList->maximumTodoIndex = 0; + notifyList->notifiesSize = 0; + notifyList->todo = 0; + notifyList->notifies = 0; + } + + Q_ASSERT(!endpoint->isConnected()); + + index = qMin(index, 0xFFFF - 1); + notifyList->connectionMask |= (1ULL << quint64(index % 64)); + + if (index < notifyList->notifiesSize) { + + endpoint->next = notifyList->notifies[index]; + if (endpoint->next) endpoint->next->prev = &endpoint->next; + endpoint->prev = ¬ifyList->notifies[index]; + notifyList->notifies[index] = endpoint; + + } else { + notifyList->maximumTodoIndex = qMax(int(notifyList->maximumTodoIndex), index); + + endpoint->next = notifyList->todo; + if (endpoint->next) endpoint->next->prev = &endpoint->next; + endpoint->prev = ¬ifyList->todo; + notifyList->todo = endpoint; + } +} + +QQmlNotifier *QQmlData::objectNameNotifier() const +{ + if (!extendedData) extendedData = new QQmlDataExtended; + return &extendedData->objectNameNotifier; +} + +QHash *QQmlData::attachedProperties() const +{ + if (!extendedData) extendedData = new QQmlDataExtended; + return &extendedData->attachedProperties; +} + +void QQmlData::destroyed(QObject *object) +{ + if (deferredComponent) + deferredComponent->release(); + + if (nextContextObject) + nextContextObject->prevContextObject = prevContextObject; + if (prevContextObject) + *prevContextObject = nextContextObject; + + QQmlAbstractBinding *binding = bindings; + while (binding) { + QQmlAbstractBinding *next = binding->m_nextBinding; + binding->m_prevBinding = 0; + binding->m_nextBinding = 0; + binding->destroy(); + binding = next; + } + + if (bindingBits) + free(bindingBits); + + if (propertyCache) + propertyCache->release(); + + if (ownContext && context) + context->destroy(); + + while (guards) { + QQmlGuard *guard = static_cast *>(guards); + *guard = (QObject *)0; + guard->objectDestroyed(object); + } + + if (notifyList) { + while (notifyList->todo) + notifyList->todo->disconnect(); + for (int ii = 0; ii < notifyList->notifiesSize; ++ii) { + while (QQmlNotifierEndpoint *ep = notifyList->notifies[ii]) + ep->disconnect(); + } + free(notifyList->notifies); + free(notifyList); + } + + if (extendedData) + delete extendedData; + + v8object.Clear(); // The WeakReference handler will clean the actual handle + + if (ownMemory) + delete this; +} + +void QQmlData::parentChanged(QObject *object, QObject *parent) +{ + Q_UNUSED(object); + Q_UNUSED(parent); +} + +void QQmlData::objectNameChanged(QObject *) +{ + if (extendedData) objectNameNotifier()->notify(); +} + +bool QQmlData::hasBindingBit(int bit) const +{ + if (bindingBitsSize > bit) + return bindingBits[bit / 32] & (1 << (bit % 32)); + else + return false; +} + +void QQmlData::clearBindingBit(int bit) +{ + if (bindingBitsSize > bit) + bindingBits[bit / 32] &= ~(1 << (bit % 32)); +} + +void QQmlData::setBindingBit(QObject *obj, int bit) +{ + if (bindingBitsSize <= bit) { + int props = obj->metaObject()->propertyCount(); + Q_ASSERT(bit < props); + + int arraySize = (props + 31) / 32; + int oldArraySize = bindingBitsSize / 32; + + bindingBits = (quint32 *)realloc(bindingBits, + arraySize * sizeof(quint32)); + + memset(bindingBits + oldArraySize, + 0x00, + sizeof(quint32) * (arraySize - oldArraySize)); + + bindingBitsSize = arraySize * 32; + } + + bindingBits[bit / 32] |= (1 << (bit % 32)); +} + +QString QQmlEnginePrivate::urlToLocalFileOrQrc(const QUrl& url) +{ + if (url.scheme().compare(QLatin1String("qrc"), Qt::CaseInsensitive) == 0) { + if (url.authority().isEmpty()) + return QLatin1Char(':') + url.path(); + return QString(); + } + return url.toLocalFile(); +} + + +static QString toLocalFile(const QString &url) +{ + if (!url.startsWith(QLatin1String("file://"), Qt::CaseInsensitive)) + return QString(); + + QString file = url.mid(7); + + //XXX TODO: handle windows hostnames: "//servername/path/to/file.txt" + + // magic for drives on windows + if (file.length() > 2 && file.at(0) == QLatin1Char('/') && file.at(2) == QLatin1Char(':')) + file.remove(0, 1); + + return file; +} + +QString QQmlEnginePrivate::urlToLocalFileOrQrc(const QString& url) +{ + if (url.startsWith(QLatin1String("qrc:"), Qt::CaseInsensitive)) { + if (url.length() > 4) + return QLatin1Char(':') + url.mid(4); + return QString(); + } + + return toLocalFile(url); +} + +void QQmlEnginePrivate::sendQuit() +{ + Q_Q(QQmlEngine); + emit q->quit(); + if (q->receivers(SIGNAL(quit())) == 0) { + qWarning("Signal QQmlEngine::quit() emitted, but no receivers connected to handle it."); + } +} + +static void dumpwarning(const QQmlError &error) +{ + qWarning().nospace() << qPrintable(error.toString()); +} + +static void dumpwarning(const QList &errors) +{ + for (int ii = 0; ii < errors.count(); ++ii) + dumpwarning(errors.at(ii)); +} + +void QQmlEnginePrivate::warning(const QQmlError &error) +{ + Q_Q(QQmlEngine); + q->warnings(QList() << error); + if (outputWarningsToStdErr) + dumpwarning(error); +} + +void QQmlEnginePrivate::warning(const QList &errors) +{ + Q_Q(QQmlEngine); + q->warnings(errors); + if (outputWarningsToStdErr) + dumpwarning(errors); +} + +void QQmlEnginePrivate::warning(QQmlEngine *engine, const QQmlError &error) +{ + if (engine) + QQmlEnginePrivate::get(engine)->warning(error); + else + dumpwarning(error); +} + +void QQmlEnginePrivate::warning(QQmlEngine *engine, const QList &error) +{ + if (engine) + QQmlEnginePrivate::get(engine)->warning(error); + else + dumpwarning(error); +} + +void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QQmlError &error) +{ + if (engine) + engine->warning(error); + else + dumpwarning(error); +} + +void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QList &error) +{ + if (engine) + engine->warning(error); + else + dumpwarning(error); +} + +/* + This function should be called prior to evaluation of any js expression, + so that scarce resources are not freed prematurely (eg, if there is a + nested javascript expression). + */ +void QQmlEnginePrivate::referenceScarceResources() +{ + scarceResourcesRefCount += 1; +} + +/* + This function should be called after evaluation of the js expression is + complete, and so the scarce resources may be freed safely. + */ +void QQmlEnginePrivate::dereferenceScarceResources() +{ + Q_ASSERT(scarceResourcesRefCount > 0); + scarceResourcesRefCount -= 1; + + // if the refcount is zero, then evaluation of the "top level" + // expression must have completed. We can safely release the + // scarce resources. + if (scarceResourcesRefCount == 0) { + // iterate through the list and release them all. + // note that the actual SRD is owned by the JS engine, + // so we cannot delete the SRD; but we can free the + // memory used by the variant in the SRD. + while (ScarceResourceData *sr = scarceResources.first()) { + sr->data = QVariant(); + scarceResources.remove(sr); + } + } +} + +/*! + Adds \a path as a directory where the engine searches for + installed modules in a URL-based directory structure. + The \a path may be a local filesystem directory or a URL. + + The newly added \a path will be first in the importPathList(). + + \sa setImportPathList(), {QML Modules} +*/ +void QQmlEngine::addImportPath(const QString& path) +{ + Q_D(QQmlEngine); + d->importDatabase.addImportPath(path); +} + +/*! + Returns the list of directories where the engine searches for + installed modules in a URL-based directory structure. + + For example, if \c /opt/MyApp/lib/imports is in the path, then QML that + imports \c com.mycompany.Feature will cause the QQmlEngine to look + in \c /opt/MyApp/lib/imports/com/mycompany/Feature/ for the components + provided by that module. A \c qmldir file is required for defining the + type version mapping and possibly declarative extensions plugins. + + By default, the list contains the directory of the application executable, + paths specified in the \c QML_IMPORT_PATH environment variable, + and the builtin \c ImportsPath from QLibraryInfo. + + \sa addImportPath() setImportPathList() +*/ +QStringList QQmlEngine::importPathList() const +{ + Q_D(const QQmlEngine); + return d->importDatabase.importPathList(); +} + +/*! + Sets \a paths as the list of directories where the engine searches for + installed modules in a URL-based directory structure. + + By default, the list contains the directory of the application executable, + paths specified in the \c QML_IMPORT_PATH environment variable, + and the builtin \c ImportsPath from QLibraryInfo. + + \sa importPathList() addImportPath() + */ +void QQmlEngine::setImportPathList(const QStringList &paths) +{ + Q_D(QQmlEngine); + d->importDatabase.setImportPathList(paths); +} + + +/*! + Adds \a path as a directory where the engine searches for + native plugins for imported modules (referenced in the \c qmldir file). + + By default, the list contains only \c ., i.e. the engine searches + in the directory of the \c qmldir file itself. + + The newly added \a path will be first in the pluginPathList(). + + \sa setPluginPathList() +*/ +void QQmlEngine::addPluginPath(const QString& path) +{ + Q_D(QQmlEngine); + d->importDatabase.addPluginPath(path); +} + + +/*! + Returns the list of directories where the engine searches for + native plugins for imported modules (referenced in the \c qmldir file). + + By default, the list contains only \c ., i.e. the engine searches + in the directory of the \c qmldir file itself. + + \sa addPluginPath() setPluginPathList() +*/ +QStringList QQmlEngine::pluginPathList() const +{ + Q_D(const QQmlEngine); + return d->importDatabase.pluginPathList(); +} + +/*! + Sets the list of directories where the engine searches for + native plugins for imported modules (referenced in the \c qmldir file) + to \a paths. + + By default, the list contains only \c ., i.e. the engine searches + in the directory of the \c qmldir file itself. + + \sa pluginPathList() addPluginPath() + */ +void QQmlEngine::setPluginPathList(const QStringList &paths) +{ + Q_D(QQmlEngine); + d->importDatabase.setPluginPathList(paths); +} + +/*! + Imports the plugin named \a filePath with the \a uri provided. + Returns true if the plugin was successfully imported; otherwise returns false. + + On failure and if non-null, the \a errors list will have any errors which occurred prepended to it. + + The plugin has to be a Qt plugin which implements the QQmlExtensionPlugin interface. +*/ +bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QList *errors) +{ + Q_D(QQmlEngine); + return d->importDatabase.importPlugin(filePath, uri, errors); +} + +/*! + Imports the plugin named \a filePath with the \a uri provided. + Returns true if the plugin was successfully imported; otherwise returns false. + + On failure and if non-null, *\a errorString will be set to a message describing the failure. + + The plugin has to be a Qt plugin which implements the QQmlExtensionPlugin interface. +*/ +bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QString *errorString) +{ + Q_D(QQmlEngine); + QList errors; + bool retn = d->importDatabase.importPlugin(filePath, uri, &errors); + if (!errors.isEmpty()) { + QString builtError; + for (int i = 0; i < errors.size(); ++i) { + builtError = QString(QLatin1String("%1\n %2")) + .arg(builtError) + .arg(errors.at(i).toString()); + } + *errorString = builtError; + } + return retn; +} + +/*! + \property QQmlEngine::offlineStoragePath + \brief the directory for storing offline user data + + Returns the directory where SQL and other offline + storage is placed. + + QQuickWebView and the SQL databases created with openDatabase() + are stored here. + + The default is QML/OfflineStorage in the platform-standard + user application data directory. + + Note that the path may not currently exist on the filesystem, so + callers wanting to \e create new files at this location should create + it first - see QDir::mkpath(). +*/ +void QQmlEngine::setOfflineStoragePath(const QString& dir) +{ + Q_D(QQmlEngine); + d->offlineStoragePath = dir; +} + +QString QQmlEngine::offlineStoragePath() const +{ + Q_D(const QQmlEngine); + return d->offlineStoragePath; +} + +static void voidptr_destructor(void *v) +{ + void **ptr = (void **)v; + delete ptr; +} + +static void *voidptr_constructor(const void *v) +{ + if (!v) { + return new void*; + } else { + return new void*(*(void **)v); + } +} + +QQmlPropertyCache *QQmlEnginePrivate::createCache(const QMetaObject *mo) +{ + Q_Q(QQmlEngine); + + if (!mo->superClass()) { + QQmlPropertyCache *rv = new QQmlPropertyCache(q, mo); + propertyCache.insert(mo, rv); + return rv; + } else { + QQmlPropertyCache *super = cache(mo->superClass()); + QQmlPropertyCache *rv = super->copyAndAppend(q, mo); + propertyCache.insert(mo, rv); + return rv; + } +} + +QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersion, + QQmlError &error) +{ + QList types; + + int maxMinorVersion = 0; + + const QMetaObject *metaObject = type->metaObject(); + + while (metaObject) { + QQmlType *t = QQmlMetaType::qmlType(metaObject, type->module(), + type->majorVersion(), minorVersion); + if (t) { + maxMinorVersion = qMax(maxMinorVersion, t->minorVersion()); + types << t; + } else { + types << 0; + } + + metaObject = metaObject->superClass(); + } + + if (QQmlPropertyCache *c = typePropertyCache.value(qMakePair(type, maxMinorVersion))) { + c->addref(); + typePropertyCache.insert(qMakePair(type, minorVersion), c); + return c; + } + + QQmlPropertyCache *raw = cache(type->metaObject()); + + bool hasCopied = false; + + for (int ii = 0; ii < types.count(); ++ii) { + QQmlType *currentType = types.at(ii); + if (!currentType) + continue; + + int rev = currentType->metaObjectRevision(); + int moIndex = types.count() - 1 - ii; + + if (raw->allowedRevisionCache[moIndex] != rev) { + if (!hasCopied) { + raw = raw->copy(); + hasCopied = true; + } + raw->allowedRevisionCache[moIndex] = rev; + } + } + + // Test revision compatibility - the basic rule is: + // * Anything that is excluded, cannot overload something that is not excluded * + + // Signals override: + // * other signals and methods of the same name. + // * properties named on + // * automatic Changed notify signals + + // Methods override: + // * other methods of the same name + + // Properties override: + // * other elements of the same name + + bool overloadError = false; + QString overloadName; + +#if 0 + for (QQmlPropertyCache::StringCache::ConstIterator iter = raw->stringCache.begin(); + !overloadError && iter != raw->stringCache.end(); + ++iter) { + + QQmlPropertyData *d = *iter; + if (raw->isAllowedInRevision(d)) + continue; // Not excluded - no problems + + // check that a regular "name" overload isn't happening + QQmlPropertyData *current = d; + while (!overloadError && current) { + current = d->overrideData(current); + if (current && raw->isAllowedInRevision(current)) + overloadError = true; + } + } +#endif + + if (overloadError) { + if (hasCopied) raw->release(); + + error.setDescription(QLatin1String("Type ") + type->qmlTypeName() + QLatin1String(" ") + QString::number(type->majorVersion()) + QLatin1String(".") + QString::number(minorVersion) + QLatin1String(" contains an illegal property \"") + overloadName + QLatin1String("\". This is an error in the type's implementation.")); + return 0; + } + + if (!hasCopied) raw->addref(); + typePropertyCache.insert(qMakePair(type, minorVersion), raw); + + if (minorVersion != maxMinorVersion) { + raw->addref(); + typePropertyCache.insert(qMakePair(type, maxMinorVersion), raw); + } + + return raw; +} + +QQmlMetaType::ModuleApiInstance * +QQmlEnginePrivate::moduleApiInstance(const QQmlMetaType::ModuleApi &module) +{ + Locker locker(this); + + QQmlMetaType::ModuleApiInstance *a = moduleApiInstances.value(module); + if (!a) { + a = new QQmlMetaType::ModuleApiInstance; + a->scriptCallback = module.script; + a->qobjectCallback = module.qobject; + moduleApiInstances.insert(module, a); + } + + return a; +} + +bool QQmlEnginePrivate::isQObject(int t) +{ + Locker locker(this); + return m_compositeTypes.contains(t) || QQmlMetaType::isQObject(t); +} + +QObject *QQmlEnginePrivate::toQObject(const QVariant &v, bool *ok) const +{ + Locker locker(this); + int t = v.userType(); + if (t == QMetaType::QObjectStar || m_compositeTypes.contains(t)) { + if (ok) *ok = true; + return *(QObject **)(v.constData()); + } else { + return QQmlMetaType::toQObject(v, ok); + } +} + +QQmlMetaType::TypeCategory QQmlEnginePrivate::typeCategory(int t) const +{ + Locker locker(this); + if (m_compositeTypes.contains(t)) + return QQmlMetaType::Object; + else if (m_qmlLists.contains(t)) + return QQmlMetaType::List; + else + return QQmlMetaType::typeCategory(t); +} + +bool QQmlEnginePrivate::isList(int t) const +{ + Locker locker(this); + return m_qmlLists.contains(t) || QQmlMetaType::isList(t); +} + +int QQmlEnginePrivate::listType(int t) const +{ + Locker locker(this); + QHash::ConstIterator iter = m_qmlLists.find(t); + if (iter != m_qmlLists.end()) + return *iter; + else + return QQmlMetaType::listType(t); +} + +const QMetaObject *QQmlEnginePrivate::rawMetaObjectForType(int t) const +{ + Locker locker(this); + QHash::ConstIterator iter = m_compositeTypes.find(t); + if (iter != m_compositeTypes.end()) { + return (*iter)->root; + } else { + QQmlType *type = QQmlMetaType::qmlType(t); + return type?type->baseMetaObject():0; + } +} + +const QMetaObject *QQmlEnginePrivate::metaObjectForType(int t) const +{ + Locker locker(this); + QHash::ConstIterator iter = m_compositeTypes.find(t); + if (iter != m_compositeTypes.end()) { + return (*iter)->root; + } else { + QQmlType *type = QQmlMetaType::qmlType(t); + return type?type->metaObject():0; + } +} + +void QQmlEnginePrivate::registerCompositeType(QQmlCompiledData *data) +{ + QByteArray name = data->root->className(); + + QByteArray ptr = name + '*'; + QByteArray lst = "QQmlListProperty<" + name + '>'; + + int ptr_type = QMetaType::registerType(ptr.constData(), voidptr_destructor, + voidptr_constructor); + int lst_type = QMetaType::registerType(lst.constData(), voidptr_destructor, + voidptr_constructor); + + data->addref(); + + Locker locker(this); + m_qmlLists.insert(lst_type, ptr_type); + m_compositeTypes.insert(ptr_type, data); +} + +bool QQml_isFileCaseCorrect(const QString &fileName) +{ +#if defined(Q_OS_MAC) || defined(Q_OS_WIN) + QFileInfo info(fileName); + const QString absolute = info.absoluteFilePath(); + +#if defined(Q_OS_MAC) + const QString canonical = info.canonicalFilePath(); +#elif defined(Q_OS_WIN) + wchar_t buffer[1024]; + + DWORD rv = ::GetShortPathName((wchar_t*)absolute.utf16(), buffer, 1024); + if (rv == 0 || rv >= 1024) return true; + rv = ::GetLongPathName(buffer, buffer, 1024); + if (rv == 0 || rv >= 1024) return true; + + const QString canonical = QString::fromWCharArray(buffer); +#endif + + const int absoluteLength = absolute.length(); + const int canonicalLength = canonical.length(); + + const int length = qMin(absoluteLength, canonicalLength); + for (int ii = 0; ii < length; ++ii) { + const QChar &a = absolute.at(absoluteLength - 1 - ii); + const QChar &c = canonical.at(canonicalLength - 1 - ii); + + if (a.toLower() != c.toLower()) + return true; + if (a != c) + return false; + } +#else + Q_UNUSED(fileName) +#endif + return true; +} + +/*! + \fn QQmlEngine *qmlEngine(const QObject *object) + \relates QQmlEngine + + Returns the QQmlEngine associated with \a object, if any. This is equivalent to + QQmlEngine::contextForObject(object)->engine(), but more efficient. +*/ + +/*! + \fn QQmlContext *qmlContext(const QObject *object) + \relates QQmlEngine + + Returns the QQmlContext associated with \a object, if any. This is equivalent to + QQmlEngine::contextForObject(object). +*/ + +QT_END_NAMESPACE -- cgit v1.2.3