summaryrefslogtreecommitdiffstats
path: root/src/declarative/qml/qmlengine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative/qml/qmlengine.cpp')
-rw-r--r--src/declarative/qml/qmlengine.cpp1623
1 files changed, 1623 insertions, 0 deletions
diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp
new file mode 100644
index 0000000..ea0c054
--- /dev/null
+++ b/src/declarative/qml/qmlengine.cpp
@@ -0,0 +1,1623 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmlengine_p.h"
+#include "qmlengine.h"
+
+#include "qmlcontext_p.h"
+#include "qmlcompiler_p.h"
+#include "qmlglobalscriptclass_p.h"
+#include "qml.h"
+#include "qmlcontext.h"
+#include "qmlexpression.h"
+#include "qmlcomponent.h"
+#include "qmlmetaproperty_p.h"
+#include "qmlmoduleplugin.h"
+#include "qmlbinding_p.h"
+#include "qmlvme_p.h"
+#include "qmlenginedebug_p.h"
+#include "qmlstringconverters_p.h"
+#include "qmlxmlhttprequest_p.h"
+#include "qmlsqldatabase_p.h"
+#include "qmltypenamescriptclass_p.h"
+#include "qmllistscriptclass_p.h"
+#include "qmlscriptstring.h"
+#include "qmlglobal_p.h"
+#include "qmlworkerscript_p.h"
+#include "qmlcomponent_p.h"
+#include "qmlscriptclass_p.h"
+#include "qmlnetworkaccessmanagerfactory.h"
+
+#include <qfxperf_p_p.h>
+
+#include <QtCore/qmetaobject.h>
+#include <QScriptClass>
+#include <QNetworkReply>
+#include <QNetworkRequest>
+#include <QNetworkAccessManager>
+#include <QDesktopServices>
+#include <QTimer>
+#include <QList>
+#include <QPair>
+#include <QDebug>
+#include <QMetaObject>
+#include <QStack>
+#include <QtCore/qlibraryinfo.h>
+#include <QtCore/qthreadstorage.h>
+#include <QtCore/qthread.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qdir.h>
+#include <QtGui/qcolor.h>
+#include <QtGui/qvector3d.h>
+#include <QtGui/qsound.h>
+#include <QGraphicsObject>
+#include <QtCore/qcryptographichash.h>
+
+#include <private/qfactoryloader_p.h>
+#include <private/qobject_p.h>
+#include <private/qscriptdeclarativeclass_p.h>
+
+#ifdef Q_OS_WIN // for %APPDATA%
+#include <qt_windows.h>
+#include <qlibrary.h>
+
+#define CSIDL_APPDATA 0x001a // <username>\Application Data
+#endif
+
+Q_DECLARE_METATYPE(QmlMetaProperty)
+Q_DECLARE_METATYPE(QList<QObject *>);
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(qmlImportTrace, QML_IMPORT_TRACE)
+
+QML_DEFINE_TYPE(Qt,4,6,QtObject,QObject)
+
+struct StaticQtMetaObject : public QObject
+{
+ static const QMetaObject *get()
+ { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
+};
+
+QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e)
+: captureProperties(false), rootContext(0), currentExpression(0), isDebugging(false),
+ contextClass(0), sharedContext(0), sharedScope(0), objectClass(0), valueTypeClass(0),
+ globalClass(0), cleanup(0), erroredBindings(0), inProgressCreations(0),
+ scriptEngine(this), workerScriptEngine(0), componentAttacheds(0), inBeginCreate(false),
+ networkAccessManager(0), networkAccessManagerFactory(0),
+ typeManager(e), uniqueId(1)
+{
+ globalClass = new QmlGlobalScriptClass(&scriptEngine);
+ fileImportPath.append(QLibraryInfo::location(QLibraryInfo::DataPath)+QDir::separator()+QLatin1String("qml"));
+}
+
+QUrl QmlScriptEngine::resolvedUrl(QScriptContext *context, const QUrl& url)
+{
+ if (p) {
+ QmlContext *ctxt = QmlEnginePrivate::get(this)->getContext(context);
+ Q_ASSERT(ctxt);
+ return ctxt->resolvedUrl(url);
+ }
+ return baseUrl.resolved(url);
+}
+
+QmlScriptEngine::QmlScriptEngine(QmlEnginePrivate *priv)
+: p(priv), sqlQueryClass(0), namedNodeMapClass(0), nodeListClass(0)
+{
+ // Note that all documentation for stuff put on the global object goes in
+ // doc/src/declarative/globalobject.qdoc
+
+ bool mainthread = priv != 0;
+
+ QScriptValue qtObject =
+ newQMetaObject(StaticQtMetaObject::get());
+ globalObject().setProperty(QLatin1String("Qt"), qtObject);
+
+ offlineStoragePath = QDesktopServices::storageLocation(QDesktopServices::DataLocation).replace(QLatin1Char('/'), QDir::separator())
+ + QDir::separator() + QLatin1String("QML")
+ + QDir::separator() + QLatin1String("OfflineStorage");
+
+
+ qt_add_qmlxmlhttprequest(this);
+ qt_add_qmlsqldatabase(this);
+ // XXX A Multimedia "Qt.Sound" class also needs to be made available,
+ // XXX but we don't want a dependency in that cirection.
+ // XXX When the above a done some better way, that way should also be
+ // XXX used to add Qt.Sound class.
+
+
+ //types
+ qtObject.setProperty(QLatin1String("rgba"), newFunction(QmlEnginePrivate::rgba, 4));
+ qtObject.setProperty(QLatin1String("hsla"), newFunction(QmlEnginePrivate::hsla, 4));
+ qtObject.setProperty(QLatin1String("rect"), newFunction(QmlEnginePrivate::rect, 4));
+ qtObject.setProperty(QLatin1String("point"), newFunction(QmlEnginePrivate::point, 2));
+ qtObject.setProperty(QLatin1String("size"), newFunction(QmlEnginePrivate::size, 2));
+ qtObject.setProperty(QLatin1String("vector3d"), newFunction(QmlEnginePrivate::vector, 3));
+
+ if (mainthread) {
+ //color helpers
+ qtObject.setProperty(QLatin1String("lighter"), newFunction(QmlEnginePrivate::lighter, 1));
+ qtObject.setProperty(QLatin1String("darker"), newFunction(QmlEnginePrivate::darker, 1));
+ qtObject.setProperty(QLatin1String("tint"), newFunction(QmlEnginePrivate::tint, 2));
+ }
+
+ //misc methods
+ qtObject.setProperty(QLatin1String("closestAngle"), newFunction(QmlEnginePrivate::closestAngle, 2));
+ qtObject.setProperty(QLatin1String("playSound"), newFunction(QmlEnginePrivate::playSound, 1));
+ qtObject.setProperty(QLatin1String("openUrlExternally"),newFunction(QmlEnginePrivate::desktopOpenUrl, 1));
+ qtObject.setProperty(QLatin1String("md5"),newFunction(QmlEnginePrivate::md5, 1));
+ qtObject.setProperty(QLatin1String("btoa"),newFunction(QmlEnginePrivate::btoa, 1));
+ qtObject.setProperty(QLatin1String("atob"),newFunction(QmlEnginePrivate::atob, 1));
+ qtObject.setProperty(QLatin1String("quit"), newFunction(QmlEnginePrivate::quit, 0));
+ qtObject.setProperty(QLatin1String("resolvedUrl"),newFunction(QmlScriptEngine::resolvedUrl, 1));
+
+ //firebug/webkit compat
+ QScriptValue consoleObject = newObject();
+ consoleObject.setProperty(QLatin1String("log"),newFunction(QmlEnginePrivate::consoleLog, 1));
+ consoleObject.setProperty(QLatin1String("debug"),newFunction(QmlEnginePrivate::consoleLog, 1));
+ globalObject().setProperty(QLatin1String("console"), consoleObject);
+
+ if (mainthread) {
+ globalObject().setProperty(QLatin1String("createQmlObject"),
+ newFunction(QmlEnginePrivate::createQmlObject, 1));
+ globalObject().setProperty(QLatin1String("createComponent"),
+ newFunction(QmlEnginePrivate::createComponent, 1));
+ }
+
+ // translation functions need to be installed
+ // before the global script class is constructed (QTBUG-6437)
+ installTranslatorFunctions();
+}
+
+QmlScriptEngine::~QmlScriptEngine()
+{
+ delete sqlQueryClass;
+ delete nodeListClass;
+ delete namedNodeMapClass;
+}
+
+QScriptValue QmlScriptEngine::resolvedUrl(QScriptContext *ctxt, QScriptEngine *engine)
+{
+ QString arg = ctxt->argument(0).toString();
+ QUrl r = QmlScriptEngine::get(engine)->resolvedUrl(ctxt,QUrl(arg));
+ return QScriptValue(r.toString());
+}
+
+QNetworkAccessManager *QmlScriptEngine::networkAccessManager()
+{
+ return p->getNetworkAccessManager();
+}
+
+QmlEnginePrivate::~QmlEnginePrivate()
+{
+ while (cleanup) {
+ QmlCleanup *c = cleanup;
+ cleanup = c->next;
+ if (cleanup) cleanup->prev = &cleanup;
+ c->next = 0;
+ c->prev = 0;
+ c->clear();
+ }
+
+ delete rootContext;
+ rootContext = 0;
+ delete contextClass;
+ contextClass = 0;
+ delete objectClass;
+ objectClass = 0;
+ delete valueTypeClass;
+ valueTypeClass = 0;
+ delete typeNameClass;
+ typeNameClass = 0;
+ delete listClass;
+ listClass = 0;
+ delete globalClass;
+ globalClass = 0;
+
+ for(int ii = 0; ii < bindValues.count(); ++ii)
+ clear(bindValues[ii]);
+ for(int ii = 0; ii < parserStatus.count(); ++ii)
+ clear(parserStatus[ii]);
+ for(QHash<int, QmlCompiledData*>::ConstIterator iter = m_compositeTypes.constBegin(); iter != m_compositeTypes.constEnd(); ++iter)
+ (*iter)->release();
+ for(QHash<const QMetaObject *, QmlPropertyCache *>::Iterator iter = propertyCache.begin(); iter != propertyCache.end(); ++iter)
+ (*iter)->release();
+
+}
+
+void QmlEnginePrivate::clear(SimpleList<QmlAbstractBinding> &bvs)
+{
+ bvs.clear();
+}
+
+void QmlEnginePrivate::clear(SimpleList<QmlParserStatus> &pss)
+{
+ for (int ii = 0; ii < pss.count; ++ii) {
+ QmlParserStatus *ps = pss.at(ii);
+ if(ps)
+ ps->d = 0;
+ }
+ pss.clear();
+}
+
+Q_GLOBAL_STATIC(QmlEngineDebugServer, qmlEngineDebugServer);
+
+void QmlEnginePrivate::init()
+{
+ Q_Q(QmlEngine);
+ qRegisterMetaType<QVariant>("QVariant");
+ qRegisterMetaType<QmlScriptString>("QmlScriptString");
+ qRegisterMetaType<QScriptValue>("QScriptValue");
+
+ contextClass = new QmlContextScriptClass(q);
+ objectClass = new QmlObjectScriptClass(q);
+ valueTypeClass = new QmlValueTypeScriptClass(q);
+ typeNameClass = new QmlTypeNameScriptClass(q);
+ listClass = new QmlListScriptClass(q);
+ rootContext = new QmlContext(q,true);
+
+ if (QCoreApplication::instance()->thread() == q->thread() &&
+ QmlEngineDebugServer::isDebuggingEnabled()) {
+ qmlEngineDebugServer();
+ isDebugging = true;
+ QmlEngineDebugServer::addEngine(q);
+
+ qmlEngineDebugServer()->waitForClients();
+ }
+}
+
+QmlWorkerScriptEngine *QmlEnginePrivate::getWorkerScriptEngine()
+{
+ Q_Q(QmlEngine);
+ if (!workerScriptEngine)
+ workerScriptEngine = new QmlWorkerScriptEngine(q);
+ return workerScriptEngine;
+}
+
+/*!
+ \class QmlEngine
+ \brief The QmlEngine class provides an environment for instantiating QML components.
+ \mainclass
+
+ Each QML component is instantiated in a QmlContext. QmlContext's are
+ essential for passing data to QML components. In QML, contexts are arranged
+ hierarchically and this hierarchy is managed by the QmlEngine.
+
+ Prior to creating any QML components, an application must have created a
+ QmlEngine to gain access to a QML context. The following example shows how
+ to create a simple Text item.
+
+ \code
+ QmlEngine engine;
+ QmlComponent component(&engine);
+ component.setData("import Qt 4.6\nText { text: \"Hello world!\" }", QUrl());
+ QmlGraphicsItem *item = qobject_cast<QmlGraphicsItem *>(component.create());
+
+ //add item to view, etc
+ ...
+ \endcode
+
+ In this case, the Text item will be created in the engine's
+ \l {QmlEngine::rootContext()}{root context}.
+
+ \sa QmlComponent QmlContext
+*/
+
+/*!
+ Create a new QmlEngine with the given \a parent.
+*/
+QmlEngine::QmlEngine(QObject *parent)
+: QObject(*new QmlEnginePrivate(this), parent)
+{
+ Q_D(QmlEngine);
+ d->init();
+}
+
+/*!
+ Destroys the QmlEngine.
+
+ Any QmlContext's created on this engine will be invalidated, but not
+ destroyed (unless they are parented to the QmlEngine object).
+*/
+QmlEngine::~QmlEngine()
+{
+ Q_D(QmlEngine);
+ if (d->isDebugging)
+ QmlEngineDebugServer::remEngine(this);
+}
+
+/*!
+ Clears the engine's internal component cache.
+
+ Normally the QmlEngine caches components loaded from qml files. This method
+ clears this cache and forces the component to be reloaded.
+ */
+void QmlEngine::clearComponentCache()
+{
+ Q_D(QmlEngine);
+ d->typeManager.clearCache();
+}
+
+/*!
+ Returns the engine's root context.
+
+ The root context is automatically created by the QmlEngine. 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.
+*/
+QmlContext *QmlEngine::rootContext()
+{
+ Q_D(QmlEngine);
+ 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.
+*/
+void QmlEngine::setNetworkAccessManagerFactory(QmlNetworkAccessManagerFactory *factory)
+{
+ Q_D(QmlEngine);
+ d->networkAccessManagerFactory = factory;
+}
+
+/*!
+ Returns the current QmlNetworkAccessManagerFactory.
+
+ \sa setNetworkAccessManagerFactory()
+*/
+QmlNetworkAccessManagerFactory *QmlEngine::networkAccessManagerFactory() const
+{
+ Q_D(const QmlEngine);
+ return d->networkAccessManagerFactory;
+}
+
+QNetworkAccessManager *QmlEnginePrivate::getNetworkAccessManager() const
+{
+ Q_Q(const QmlEngine);
+
+ if (!networkAccessManager) {
+ if (networkAccessManagerFactory) {
+ networkAccessManager = networkAccessManagerFactory->create(const_cast<QmlEngine*>(q));
+ } else {
+ networkAccessManager = new QNetworkAccessManager(const_cast<QmlEngine*>(q));
+ }
+ }
+ return networkAccessManager;
+}
+
+/*!
+ Returns a common QNetworkAccessManager which can be used by any QML element
+ instantiated by this engine.
+
+ If a QmlNetworkAccessManagerFactory has been set and a QNetworkAccessManager
+ has not yet been created, the QmlNetworkAccessManagerFactory will be used
+ to create the QNetworkAccessManager; otherwise the returned QNetworkAccessManager
+ will have no proxy or cache set.
+
+ \sa setNetworkAccessManagerFactory()
+*/
+QNetworkAccessManager *QmlEngine::networkAccessManager() const
+{
+ Q_D(const QmlEngine);
+ return d->getNetworkAccessManager();
+}
+
+/*!
+ Return the base URL for this engine. The base URL is only used to resolve
+ components when a relative URL is passed to the QmlComponent constructor.
+
+ If a base URL has not been explicitly set, this method returns the
+ application's current working directory.
+
+ \sa setBaseUrl()
+*/
+QUrl QmlEngine::baseUrl() const
+{
+ Q_D(const QmlEngine);
+ 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 QmlEngine::setBaseUrl(const QUrl &url)
+{
+ Q_D(QmlEngine);
+ d->baseUrl = url;
+}
+
+/*!
+ Returns the QmlContext for the \a object, or 0 if no context has been set.
+
+ When the QmlEngine instantiates a QObject, the context is set automatically.
+ */
+QmlContext *QmlEngine::contextForObject(const QObject *object)
+{
+ if(!object)
+ return 0;
+
+ QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object));
+
+ QmlDeclarativeData *data =
+ static_cast<QmlDeclarativeData *>(priv->declarativeData);
+
+ if (!data)
+ return 0;
+ else if (data->outerContext)
+ return data->outerContext;
+ else
+ return data->context;
+}
+
+/*!
+ Sets the QmlContext 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 QmlEngine instantiates a QObject, the context is set automatically.
+ */
+void QmlEngine::setContextForObject(QObject *object, QmlContext *context)
+{
+ if (!object || !context)
+ return;
+
+ QmlDeclarativeData *data = QmlDeclarativeData::get(object, true);
+ if (data->context) {
+ qWarning("QmlEngine::setContextForObject(): Object already has a QmlContext");
+ return;
+ }
+
+ data->context = context;
+ data->nextContextObject = context->d_func()->contextObjects;
+ data->prevContextObject = &context->d_func()->contextObjects;
+}
+
+void qmlExecuteDeferred(QObject *object)
+{
+ QmlDeclarativeData *data = QmlDeclarativeData::get(object);
+
+ if (data && data->deferredComponent) {
+
+ QmlEnginePrivate *ep = QmlEnginePrivate::get(data->context->engine());
+
+ QmlComponentPrivate::ConstructionState state;
+ QmlComponentPrivate::beginDeferred(data->context, ep, object, &state);
+
+ data->deferredComponent->release();
+ data->deferredComponent = 0;
+
+ QmlComponentPrivate::complete(ep, &state);
+
+ if (!state.errors.isEmpty())
+ qWarning() << state.errors;
+
+ }
+}
+
+QmlContext *qmlContext(const QObject *obj)
+{
+ return QmlEngine::contextForObject(obj);
+}
+
+QmlEngine *qmlEngine(const QObject *obj)
+{
+ QmlContext *context = QmlEngine::contextForObject(obj);
+ return context?context->engine():0;
+}
+
+QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create)
+{
+ QmlDeclarativeData *data = QmlDeclarativeData::get(object);
+ if (!data)
+ return 0; // Attached properties are only on objects created by QML
+
+ QObject *rv = data->attachedProperties?data->attachedProperties->value(id):0;
+ if (rv || !create)
+ return rv;
+
+ QmlAttachedPropertiesFunc pf = QmlMetaType::attachedPropertiesFuncById(id);
+ if (!pf)
+ return 0;
+
+ rv = pf(const_cast<QObject *>(object));
+
+ if (rv) {
+ if (!data->attachedProperties)
+ data->attachedProperties = new QHash<int, QObject *>();
+ data->attachedProperties->insert(id, rv);
+ }
+
+ return rv;
+}
+
+void QmlDeclarativeData::destroyed(QObject *object)
+{
+ if (deferredComponent)
+ deferredComponent->release();
+ if (attachedProperties)
+ delete attachedProperties;
+
+ if (nextContextObject)
+ nextContextObject->prevContextObject = prevContextObject;
+ if (prevContextObject)
+ *prevContextObject = nextContextObject;
+
+ QmlAbstractBinding *binding = bindings;
+ while (binding) {
+ QmlAbstractBinding *next = binding->m_nextBinding;
+ binding->m_prevBinding = 0;
+ binding->m_nextBinding = 0;
+ binding->destroy();
+ binding = next;
+ }
+
+ if (bindingBits)
+ free(bindingBits);
+
+ if (propertyCache)
+ propertyCache->release();
+
+ QmlGuard<QObject> *guard = guards;
+ while (guard) {
+ QmlGuard<QObject> *g = guard;
+ guard = guard->next;
+ g->o = 0;
+ g->prev = 0;
+ g->next = 0;
+ g->objectDestroyed(object);
+ }
+
+ delete this;
+}
+
+bool QmlDeclarativeData::hasBindingBit(int bit) const
+{
+ if (bindingBitsSize > bit)
+ return bindingBits[bit / 32] & (1 << (bit % 32));
+ else
+ return false;
+}
+
+void QmlDeclarativeData::clearBindingBit(int bit)
+{
+ if (bindingBitsSize > bit)
+ bindingBits[bit / 32] &= ~(1 << (bit % 32));
+}
+
+void QmlDeclarativeData::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));
+}
+
+/*!
+ Creates a QScriptValue allowing you to use \a object in QML script.
+ \a engine is the QmlEngine it is to be created in.
+
+ The QScriptValue returned is a QtScript Object, not a QtScript QObject, due
+ to the special needs of QML requiring more functionality than a standard
+ QtScript QObject.
+*/
+QScriptValue QmlEnginePrivate::qmlScriptObject(QObject* object,
+ QmlEngine* engine)
+{
+ QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine);
+ return enginePriv->objectClass->newQObject(object);
+}
+
+/*!
+ Returns the QmlContext for the executing QScript \a ctxt.
+*/
+QmlContext *QmlEnginePrivate::getContext(QScriptContext *ctxt)
+{
+ QScriptValue scopeNode = QScriptDeclarativeClass::scopeChainValue(ctxt, -3);
+ Q_ASSERT(scopeNode.isValid());
+ Q_ASSERT(QScriptDeclarativeClass::scriptClass(scopeNode) == contextClass);
+ return contextClass->contextFromValue(scopeNode);
+}
+
+QScriptValue QmlEnginePrivate::createComponent(QScriptContext *ctxt,
+ QScriptEngine *engine)
+{
+ QmlEnginePrivate *activeEnginePriv =
+ static_cast<QmlScriptEngine*>(engine)->p;
+ QmlEngine* activeEngine = activeEnginePriv->q_func();
+
+ QmlContext* context = activeEnginePriv->getContext(ctxt);
+ Q_ASSERT(context);
+ if(ctxt->argumentCount() != 1) {
+ return engine->nullValue();
+ }else{
+ QString arg = ctxt->argument(0).toString();
+ if (arg.isEmpty())
+ return engine->nullValue();
+ QUrl url = QUrl(context->resolvedUrl(QUrl(arg)));
+ QmlComponent *c = new QmlComponent(activeEngine, url, activeEngine);
+ c->setCreationContext(context);
+ return activeEnginePriv->objectClass->newQObject(c, qMetaTypeId<QmlComponent*>());
+ }
+}
+
+QScriptValue QmlEnginePrivate::createQmlObject(QScriptContext *ctxt, QScriptEngine *engine)
+{
+ QmlEnginePrivate *activeEnginePriv =
+ static_cast<QmlScriptEngine*>(engine)->p;
+ QmlEngine* activeEngine = activeEnginePriv->q_func();
+
+ if(ctxt->argumentCount() < 2 || ctxt->argumentCount() > 3)
+ return engine->nullValue();
+
+ QmlContext* context = activeEnginePriv->getContext(ctxt);
+ Q_ASSERT(context);
+
+ QString qml = ctxt->argument(0).toString();
+ if (qml.isEmpty())
+ return engine->nullValue();
+
+ QUrl url;
+ if(ctxt->argumentCount() > 2)
+ url = QUrl(ctxt->argument(2).toString());
+ else
+ url = QUrl(QLatin1String("inline"));
+
+ if (url.isValid() && url.isRelative())
+ url = context->resolvedUrl(url);
+
+ QObject *parentArg = activeEnginePriv->objectClass->toQObject(ctxt->argument(1));
+ if(!parentArg)
+ return engine->nullValue();
+
+ QmlComponent component(activeEngine);
+ component.setData(qml.toUtf8(), url);
+
+ if(component.isError()) {
+ QList<QmlError> errors = component.errors();
+ qWarning().nospace() << "QmlEngine::createQmlObject():";
+ foreach (const QmlError &error, errors)
+ qWarning().nospace() << " " << error;
+
+ return engine->nullValue();
+ }
+
+ if (!component.isReady()) {
+ qWarning().nospace() << "QmlEngine::createQmlObject(): Component is not ready";
+
+ return engine->nullValue();
+ }
+
+ QObject *obj = component.create(context);
+
+ if(component.isError()) {
+ QList<QmlError> errors = component.errors();
+ qWarning().nospace() << "QmlEngine::createQmlObject():";
+ foreach (const QmlError &error, errors)
+ qWarning().nospace() << " " << error;
+
+ return engine->nullValue();
+ }
+
+ Q_ASSERT(obj);
+
+ obj->setParent(parentArg);
+ QGraphicsObject* gobj = qobject_cast<QGraphicsObject*>(obj);
+ QGraphicsObject* gparent = qobject_cast<QGraphicsObject*>(parentArg);
+ if(gobj && gparent)
+ gobj->setParentItem(gparent);
+
+ return qmlScriptObject(obj, activeEngine);
+}
+
+QScriptValue QmlEnginePrivate::vector(QScriptContext *ctxt, QScriptEngine *engine)
+{
+ if(ctxt->argumentCount() != 3)
+ return engine->nullValue();
+ qsreal x = ctxt->argument(0).toNumber();
+ qsreal y = ctxt->argument(1).toNumber();
+ qsreal z = ctxt->argument(2).toNumber();
+ return engine->newVariant(qVariantFromValue(QVector3D(x, y, z)));
+}
+
+QScriptValue QmlEnginePrivate::rgba(QScriptContext *ctxt, QScriptEngine *engine)
+{
+ int argCount = ctxt->argumentCount();
+ if(argCount < 3 || argCount > 4)
+ return engine->nullValue();
+ qsreal r = ctxt->argument(0).toNumber();
+ qsreal g = ctxt->argument(1).toNumber();
+ qsreal b = ctxt->argument(2).toNumber();
+ qsreal a = (argCount == 4) ? ctxt->argument(3).toNumber() : 1;
+
+ if (r < 0 || r > 1 || g < 0 || g > 1 || b < 0 || b > 1 || a < 0 || a > 1)
+ return engine->nullValue();
+
+ return qScriptValueFromValue(engine, qVariantFromValue(QColor::fromRgbF(r, g, b, a)));
+}
+
+QScriptValue QmlEnginePrivate::hsla(QScriptContext *ctxt, QScriptEngine *engine)
+{
+ int argCount = ctxt->argumentCount();
+ if(argCount < 3 || argCount > 4)
+ return engine->nullValue();
+ qsreal h = ctxt->argument(0).toNumber();
+ qsreal s = ctxt->argument(1).toNumber();
+ qsreal l = ctxt->argument(2).toNumber();
+ qsreal a = (argCount == 4) ? ctxt->argument(3).toNumber() : 1;
+
+ if (h < 0 || h > 1 || s < 0 || s > 1 || l < 0 || l > 1 || a < 0 || a > 1)
+ return engine->nullValue();
+
+ return qScriptValueFromValue(engine, qVariantFromValue(QColor::fromHslF(h, s, l, a)));
+}
+
+QScriptValue QmlEnginePrivate::rect(QScriptContext *ctxt, QScriptEngine *engine)
+{
+ if(ctxt->argumentCount() != 4)
+ return engine->nullValue();
+
+ qsreal x = ctxt->argument(0).toNumber();
+ qsreal y = ctxt->argument(1).toNumber();
+ qsreal w = ctxt->argument(2).toNumber();
+ qsreal h = ctxt->argument(3).toNumber();
+
+ if (w < 0 || h < 0)
+ return engine->nullValue();
+
+ return qScriptValueFromValue(engine, qVariantFromValue(QRectF(x, y, w, h)));
+}
+
+QScriptValue QmlEnginePrivate::point(QScriptContext *ctxt, QScriptEngine *engine)
+{
+ if(ctxt->argumentCount() != 2)
+ return engine->nullValue();
+ qsreal x = ctxt->argument(0).toNumber();
+ qsreal y = ctxt->argument(1).toNumber();
+ return qScriptValueFromValue(engine, qVariantFromValue(QPointF(x, y)));
+}
+
+QScriptValue QmlEnginePrivate::size(QScriptContext *ctxt, QScriptEngine *engine)
+{
+ if(ctxt->argumentCount() != 2)
+ return engine->nullValue();
+ qsreal w = ctxt->argument(0).toNumber();
+ qsreal h = ctxt->argument(1).toNumber();
+ return qScriptValueFromValue(engine, qVariantFromValue(QSizeF(w, h)));
+}
+
+QScriptValue QmlEnginePrivate::lighter(QScriptContext *ctxt, QScriptEngine *engine)
+{
+ if(ctxt->argumentCount() != 1)
+ return engine->nullValue();
+ QVariant v = ctxt->argument(0).toVariant();
+ QColor color;
+ if (v.userType() == QVariant::Color)
+ color = v.value<QColor>();
+ else if (v.userType() == QVariant::String) {
+ bool ok;
+ color = QmlStringConverters::colorFromString(v.toString(), &ok);
+ if (!ok)
+ return engine->nullValue();
+ } else
+ return engine->nullValue();
+ color = color.lighter();
+ return qScriptValueFromValue(engine, qVariantFromValue(color));
+}
+
+QScriptValue QmlEnginePrivate::darker(QScriptContext *ctxt, QScriptEngine *engine)
+{
+ if(ctxt->argumentCount() != 1)
+ return engine->nullValue();
+ QVariant v = ctxt->argument(0).toVariant();
+ QColor color;
+ if (v.userType() == QVariant::Color)
+ color = v.value<QColor>();
+ else if (v.userType() == QVariant::String) {
+ bool ok;
+ color = QmlStringConverters::colorFromString(v.toString(), &ok);
+ if (!ok)
+ return engine->nullValue();
+ } else
+ return engine->nullValue();
+ color = color.darker();
+ return qScriptValueFromValue(engine, qVariantFromValue(color));
+}
+
+QScriptValue QmlEnginePrivate::playSound(QScriptContext *ctxt, QScriptEngine *engine)
+{
+ if (ctxt->argumentCount() != 1)
+ return engine->undefinedValue();
+
+ QUrl url(ctxt->argument(0).toString());
+
+ QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine);
+ if (url.isRelative()) {
+ QmlContext *context = enginePriv->getContext(ctxt);
+ if (!context)
+ return engine->undefinedValue();
+
+ url = context->resolvedUrl(url);
+ }
+
+ if (url.scheme() == QLatin1String("file")) {
+
+ QSound::play(url.toLocalFile());
+
+ }
+ return engine->undefinedValue();
+}
+
+QScriptValue QmlEnginePrivate::desktopOpenUrl(QScriptContext *ctxt, QScriptEngine *e)
+{
+ if(ctxt->argumentCount() < 1)
+ return e->newVariant(QVariant(false));
+ bool ret = QDesktopServices::openUrl(QUrl(ctxt->argument(0).toString()));
+ return e->newVariant(QVariant(ret));
+}
+
+QScriptValue QmlEnginePrivate::md5(QScriptContext *ctxt, QScriptEngine *)
+{
+ QByteArray data;
+
+ if (ctxt->argumentCount() >= 1)
+ data = ctxt->argument(0).toString().toUtf8();
+
+ QByteArray result = QCryptographicHash::hash(data, QCryptographicHash::Md5);
+
+ return QScriptValue(QLatin1String(result.toHex()));
+}
+
+QScriptValue QmlEnginePrivate::btoa(QScriptContext *ctxt, QScriptEngine *)
+{
+ QByteArray data;
+
+ if (ctxt->argumentCount() >= 1)
+ data = ctxt->argument(0).toString().toUtf8();
+
+ return QScriptValue(QLatin1String(data.toBase64()));
+}
+
+QScriptValue QmlEnginePrivate::atob(QScriptContext *ctxt, QScriptEngine *)
+{
+ QByteArray data;
+
+ if (ctxt->argumentCount() >= 1)
+ data = ctxt->argument(0).toString().toUtf8();
+
+ return QScriptValue(QLatin1String(QByteArray::fromBase64(data)));
+}
+
+QScriptValue QmlEnginePrivate::consoleLog(QScriptContext *ctxt, QScriptEngine *e)
+{
+ if(ctxt->argumentCount() < 1)
+ return e->newVariant(QVariant(false));
+
+ QByteArray msg;
+
+ for (int i=0; i<ctxt->argumentCount(); ++i) {
+ if (!msg.isEmpty()) msg += ' ';
+ msg += ctxt->argument(i).toString().toLocal8Bit();
+ // does not support firebug "%[a-z]" formatting, since firebug really
+ // does just ignore the format letter, which makes it pointless.
+ }
+
+ qDebug("%s",msg.constData());
+
+ return e->newVariant(QVariant(true));
+}
+
+void QmlEnginePrivate::sendQuit ()
+{
+ Q_Q(QmlEngine);
+ emit q->quit ();
+}
+
+QScriptValue QmlEnginePrivate::quit(QScriptContext * /*ctxt*/, QScriptEngine *e)
+{
+ QmlEnginePrivate *qe = get (e);
+ qe->sendQuit ();
+ return QScriptValue();
+}
+
+QScriptValue QmlEnginePrivate::closestAngle(QScriptContext *ctxt, QScriptEngine *e)
+{
+ if(ctxt->argumentCount() < 2)
+ return e->newVariant(QVariant(0.0));
+ qreal a = ctxt->argument(0).toNumber();
+ qreal b = ctxt->argument(1).toNumber();
+ qreal ret = b;
+ qreal diff = b-a;
+ while(diff > 180.0){
+ ret -= 360.0;
+ diff -= 360.0;
+ }
+ while(diff < -180.0){
+ ret += 360.0;
+ diff += 360.0;
+ }
+ return e->newVariant(QVariant(ret));
+}
+
+QScriptValue QmlEnginePrivate::tint(QScriptContext *ctxt, QScriptEngine *engine)
+{
+ if(ctxt->argumentCount() != 2)
+ return engine->nullValue();
+ //get color
+ QVariant v = ctxt->argument(0).toVariant();
+ QColor color;
+ if (v.userType() == QVariant::Color)
+ color = v.value<QColor>();
+ else if (v.userType() == QVariant::String) {
+ bool ok;
+ color = QmlStringConverters::colorFromString(v.toString(), &ok);
+ if (!ok)
+ return engine->nullValue();
+ } else
+ return engine->nullValue();
+
+ //get tint color
+ v = ctxt->argument(1).toVariant();
+ QColor tintColor;
+ if (v.userType() == QVariant::Color)
+ tintColor = v.value<QColor>();
+ else if (v.userType() == QVariant::String) {
+ bool ok;
+ tintColor = QmlStringConverters::colorFromString(v.toString(), &ok);
+ if (!ok)
+ return engine->nullValue();
+ } else
+ return engine->nullValue();
+
+ //tint
+ QColor finalColor;
+ int a = tintColor.alpha();
+ if (a == 0xFF)
+ finalColor = tintColor;
+ else if (a == 0x00)
+ finalColor = color;
+ else {
+ uint src = tintColor.rgba();
+ uint dest = color.rgba();
+
+ uint res = (((a * (src & 0xFF00FF)) +
+ ((0xFF - a) * (dest & 0xFF00FF))) >> 8) & 0xFF00FF;
+ res |= (((a * ((src >> 8) & 0xFF00FF)) +
+ ((0xFF - a) * ((dest >> 8) & 0xFF00FF)))) & 0xFF00FF00;
+ if ((src & 0xFF000000) == 0xFF000000)
+ res |= 0xFF000000;
+
+ finalColor = QColor::fromRgba(res);
+ }
+
+ return qScriptValueFromValue(engine, qVariantFromValue(finalColor));
+}
+
+
+QScriptValue QmlEnginePrivate::scriptValueFromVariant(const QVariant &val)
+{
+ if (QmlMetaType::isObject(val.userType())) {
+ QObject *rv = *(QObject **)val.constData();
+ return objectClass->newQObject(rv);
+ } else {
+ return qScriptValueFromValue(&scriptEngine, val);
+ }
+}
+
+QVariant QmlEnginePrivate::scriptValueToVariant(const QScriptValue &val)
+{
+ QScriptDeclarativeClass *dc = QScriptDeclarativeClass::scriptClass(val);
+ if (dc == objectClass)
+ return QVariant::fromValue(objectClass->toQObject(val));
+ else if (dc == contextClass)
+ return QVariant();
+
+ QScriptDeclarativeClass *sc = QScriptDeclarativeClass::scriptClass(val);
+ if (!sc) {
+ return val.toVariant();
+ } else if (sc == valueTypeClass) {
+ return valueTypeClass->toVariant(val);
+ } else {
+ return QVariant();
+ }
+}
+
+QmlScriptClass::QmlScriptClass(QScriptEngine *engine)
+: QScriptDeclarativeClass(engine)
+{
+}
+
+QVariant QmlScriptClass::toVariant(QmlEngine *engine, const QScriptValue &val)
+{
+ QmlEnginePrivate *ep =
+ static_cast<QmlEnginePrivate *>(QObjectPrivate::get(engine));
+
+ return ep->scriptValueToVariant(val);
+}
+
+// XXX this beyonds in QUrl::toLocalFile()
+static QString toLocalFileOrQrc(const QUrl& url)
+{
+ QString r = url.toLocalFile();
+ if (r.isEmpty() && url.scheme() == QLatin1String("qrc"))
+ r = QLatin1Char(':') + url.path();
+ return r;
+}
+
+/////////////////////////////////////////////////////////////
+struct QmlEnginePrivate::ImportedNamespace {
+ QStringList uris;
+ QStringList urls;
+ QList<int> majversions;
+ QList<int> minversions;
+ QList<bool> isLibrary;
+ QList<bool> isBuiltin; // Types provided by C++ code (including plugins)
+ QList<QString> qmlDirContent;
+
+ bool find(const QByteArray& type, int *vmajor, int *vminor, QmlType** type_return, QUrl* url_return) const
+ {
+ for (int i=0; i<urls.count(); ++i) {
+ int vmaj = majversions.at(i);
+ int vmin = minversions.at(i);
+
+ if (isBuiltin.at(i)) {
+ QByteArray qt = uris.at(i).toUtf8();
+ qt += '/';
+ qt += type;
+ if (qmlImportTrace())
+ qDebug() << "Look in" << qt;
+ QmlType *t = QmlMetaType::qmlType(qt,vmaj,vmin);
+ if (vmajor) *vmajor = vmaj;
+ if (vminor) *vminor = vmin;
+ if (t) {
+ if (qmlImportTrace())
+ qDebug() << "Found" << qt;
+ if (type_return)
+ *type_return = t;
+ return true;
+ }
+ }
+ QUrl url = QUrl(urls.at(i) + QLatin1Char('/') + QString::fromUtf8(type) + QLatin1String(".qml"));
+ QString qmldircontent = qmlDirContent.at(i);
+ if (vmaj>=0 || !qmldircontent.isEmpty()) {
+ // Check version file - XXX cache these in QmlEngine!
+ if (qmldircontent.isEmpty()) {
+ QFile qmldir(toLocalFileOrQrc(QUrl(urls.at(i)+QLatin1String("/qmldir"))));
+ if (qmldir.open(QIODevice::ReadOnly)) {
+ qmldircontent = QString::fromUtf8(qmldir.readAll());
+ }
+ }
+ QString typespace = QString::fromUtf8(type)+QLatin1Char(' ');
+ QStringList lines = qmldircontent.split(QLatin1Char('\n'));
+ foreach (QString line, lines) {
+ if (line.isEmpty() || line.at(0) == QLatin1Char('#'))
+ continue;
+ if (line.startsWith(typespace)) {
+ int space1 = line.indexOf(QLatin1Char(' '));
+ int space2 = space1 >=0 ? line.indexOf(QLatin1Char(' '),space1+1) : -1;
+ QString mapversions = line.mid(space1+1,space2<0?line.length()-space1-1:space2-space1-1);
+ int dot = mapversions.indexOf(QLatin1Char('.'));
+ int mapvmaj = mapversions.left(dot).toInt();
+ if (mapvmaj<=vmaj) {
+ if (mapvmaj<vmaj || vmin >= mapversions.mid(dot+1).toInt()) {
+ QStringRef mapfile = space2<0 ? QStringRef() : line.midRef(space2+1,line.length()-space2-1);
+ if (url_return)
+ *url_return = url.resolved(QUrl(mapfile.toString()));
+ return true;
+ }
+ }
+ }
+ }
+ } else {
+ // XXX search non-files too! (eg. zip files, see QT-524)
+ QFileInfo f(toLocalFileOrQrc(url));
+ if (f.exists()) {
+ if (url_return)
+ *url_return = url;
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+};
+
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+ (QmlModuleFactoryInterface_iid, QLatin1String("/qmlmodules")))
+
+class QmlImportsPrivate {
+public:
+ QmlImportsPrivate() : ref(1)
+ {
+ }
+
+ ~QmlImportsPrivate()
+ {
+ foreach (QmlEnginePrivate::ImportedNamespace* s, set.values())
+ delete s;
+ }
+
+ bool add(const QUrl& base, const QString& qmldircontent, const QString& uri, const QString& prefix, int vmaj, int vmin, QmlScriptParser::Import::Type importType, const QStringList& importPath)
+ {
+ QmlEnginePrivate::ImportedNamespace *s;
+ if (prefix.isEmpty()) {
+ s = &unqualifiedset;
+ } else {
+ s = set.value(prefix);
+ if (!s)
+ set.insert(prefix,(s=new QmlEnginePrivate::ImportedNamespace));
+ }
+ QString url = uri;
+ bool isbuiltin = false;
+ if (importType == QmlScriptParser::Import::Library) {
+ url.replace(QLatin1Char('.'),QLatin1Char('/'));
+ bool found = false;
+ foreach (QString p, importPath) {
+ QString dir = p+QLatin1Char('/')+url;
+ QFileInfo fi(dir+QLatin1String("/qmldir"));
+ if (fi.isFile()) {
+ url = QUrl::fromLocalFile(fi.absolutePath()).toString();
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ // XXX assume it is a built-in type qualifier
+ isbuiltin = true;
+ }
+ QFactoryLoader *l = loader();
+ QmlModuleFactoryInterface *factory =
+ qobject_cast<QmlModuleFactoryInterface*>(l->instance(uri));
+ if (factory) {
+ factory->defineModuleOnce(uri);
+ isbuiltin = true;
+ }
+ } else {
+ url = base.resolved(QUrl(url)).toString();
+ }
+ s->uris.prepend(uri);
+ s->urls.prepend(url);
+ s->majversions.prepend(vmaj);
+ s->minversions.prepend(vmin);
+ s->isLibrary.prepend(importType == QmlScriptParser::Import::Library);
+ s->isBuiltin.prepend(isbuiltin);
+ s->qmlDirContent.prepend(qmldircontent);
+ return true;
+ }
+
+ bool find(const QByteArray& type, int *vmajor, int *vminor, QmlType** type_return, QUrl* url_return)
+ {
+ QmlEnginePrivate::ImportedNamespace *s = 0;
+ int slash = type.indexOf('/');
+ if (slash >= 0) {
+ while (!s) {
+ s = set.value(QString::fromUtf8(type.left(slash)));
+ int nslash = type.indexOf('/',slash+1);
+ if (nslash > 0)
+ slash = nslash;
+ else
+ break;
+ }
+ } else {
+ s = &unqualifiedset;
+ }
+ QByteArray unqualifiedtype = slash < 0 ? type : type.mid(slash+1); // common-case opt (QString::mid works fine, but slower)
+ if (s) {
+ if (s->find(unqualifiedtype,vmajor,vminor,type_return,url_return))
+ return true;
+ if (s->urls.count() == 1 && !s->isBuiltin[0] && !s->isLibrary[0] && url_return) {
+ *url_return = QUrl(s->urls[0]+QLatin1Char('/')).resolved(QUrl(QString::fromUtf8(unqualifiedtype) + QLatin1String(".qml")));
+ return true;
+ }
+ }
+ if (url_return) {
+ *url_return = base.resolved(QUrl(QString::fromUtf8(type + ".qml")));
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ QmlEnginePrivate::ImportedNamespace *findNamespace(const QString& type)
+ {
+ return set.value(type);
+ }
+
+ QUrl base;
+ int ref;
+
+private:
+ friend struct QmlEnginePrivate::Imports;
+ QmlEnginePrivate::ImportedNamespace unqualifiedset;
+ QHash<QString,QmlEnginePrivate::ImportedNamespace* > set;
+};
+
+QmlEnginePrivate::Imports::Imports(const Imports &copy) :
+ d(copy.d)
+{
+ ++d->ref;
+}
+
+QmlEnginePrivate::Imports &QmlEnginePrivate::Imports::operator =(const Imports &copy)
+{
+ ++copy.d->ref;
+ if (--d->ref == 0)
+ delete d;
+ d = copy.d;
+ return *this;
+}
+
+QmlEnginePrivate::Imports::Imports() :
+ d(new QmlImportsPrivate)
+{
+}
+
+QmlEnginePrivate::Imports::~Imports()
+{
+ if (--d->ref == 0)
+ delete d;
+}
+
+#include "qmlmetatype.h"
+#include "qmltypenamecache_p.h"
+
+static QmlTypeNameCache *cacheForNamespace(QmlEngine *engine, const QmlEnginePrivate::ImportedNamespace &set, QmlTypeNameCache *cache)
+{
+ if (!cache)
+ cache = new QmlTypeNameCache(engine);
+
+ QList<QmlType *> types = QmlMetaType::qmlTypes();
+
+ for (int ii = 0; ii < set.uris.count(); ++ii) {
+ if (!set.isBuiltin.at(ii))
+ continue;
+
+ QByteArray base = set.uris.at(ii).toUtf8() + '/';
+ int major = set.majversions.at(ii);
+ int minor = set.minversions.at(ii);
+
+ foreach (QmlType *type, types) {
+ if (type->qmlTypeName().startsWith(base) &&
+ type->qmlTypeName().lastIndexOf('/') == (base.length() - 1) &&
+ type->availableInVersion(major,minor))
+ {
+ QString name = QString::fromUtf8(type->qmlTypeName().mid(base.length()));
+
+ cache->add(name, type);
+ }
+ }
+ }
+
+ return cache;
+}
+
+QmlTypeNameCache *QmlEnginePrivate::Imports::cache(QmlEngine *engine) const
+{
+ const QmlEnginePrivate::ImportedNamespace &set = d->unqualifiedset;
+
+ QmlTypeNameCache *cache = new QmlTypeNameCache(engine);
+
+ for (QHash<QString,QmlEnginePrivate::ImportedNamespace* >::ConstIterator iter = d->set.begin();
+ iter != d->set.end(); ++iter) {
+
+ QmlTypeNameCache::Data *d = cache->data(iter.key());
+ if (d) {
+ if (!d->typeNamespace)
+ cacheForNamespace(engine, *(*iter), d->typeNamespace);
+ } else {
+ QmlTypeNameCache *nc = cacheForNamespace(engine, *(*iter), 0);
+ cache->add(iter.key(), nc);
+ nc->release();
+ }
+ }
+
+ cacheForNamespace(engine, set, cache);
+
+ return cache;
+}
+
+/*
+QStringList QmlEnginePrivate::Imports::unqualifiedSet() const
+{
+ QStringList rv;
+
+ const QmlEnginePrivate::ImportedNamespace &set = d->unqualifiedset;
+
+ for (int ii = 0; ii < set.urls.count(); ++ii) {
+ if (set.isBuiltin.at(ii))
+ rv << set.urls.at(ii);
+ }
+
+ return rv;
+}
+*/
+
+/*!
+ Sets the base URL to be used for all relative file imports added.
+*/
+void QmlEnginePrivate::Imports::setBaseUrl(const QUrl& url)
+{
+ d->base = url;
+}
+
+/*!
+ Returns the base URL to be used for all relative file imports added.
+*/
+QUrl QmlEnginePrivate::Imports::baseUrl() const
+{
+ return d->base;
+}
+
+/*!
+ Adds \a path as a directory where installed QML components are
+ defined in a URL-based directory structure.
+
+ For example, if you add \c /opt/MyApp/lib/qml and then load QML
+ that imports \c com.mycompany.Feature, then QmlEngine will look
+ in \c /opt/MyApp/lib/qml/com/mycompany/Feature/ for the components
+ provided by that module (and in the case of versioned imports,
+ for the \c qmldir file definiting the type version mapping.
+
+ By default, only the "qml" subdirectory of QLibraryInfo::location(QLibraryInfo::DataPath)
+ is included on the import path.
+*/
+void QmlEngine::addImportPath(const QString& path)
+{
+ if (qmlImportTrace())
+ qDebug() << "QmlEngine::addImportPath" << path;
+ Q_D(QmlEngine);
+ d->fileImportPath.prepend(path);
+}
+
+/*!
+ \property QmlEngine::offlineStoragePath
+ \brief the directory for storing offline user data
+
+ Returns the directory where SQL and other offline
+ storage is placed.
+
+ QmlGraphicsWebView 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 QmlEngine::setOfflineStoragePath(const QString& dir)
+{
+ Q_D(QmlEngine);
+ d->scriptEngine.offlineStoragePath = dir;
+}
+
+QString QmlEngine::offlineStoragePath() const
+{
+ Q_D(const QmlEngine);
+ return d->scriptEngine.offlineStoragePath;
+}
+
+
+/*!
+ \internal
+
+ Adds information to \a imports such that subsequent calls to resolveType()
+ will resolve types qualified by \a prefix by considering types found at the given \a uri.
+
+ The uri is either a directory (if importType is FileImport), or a URI resolved using paths
+ added via addImportPath() (if importType is LibraryImport).
+
+ The \a prefix may be empty, in which case the import location is considered for
+ unqualified types.
+
+ The base URL must already have been set with Import::setBaseUrl().
+*/
+bool QmlEnginePrivate::addToImport(Imports* imports, const QString& qmldircontent, const QString& uri, const QString& prefix, int vmaj, int vmin, QmlScriptParser::Import::Type importType) const
+{
+ bool ok = imports->d->add(imports->d->base,qmldircontent,uri,prefix,vmaj,vmin,importType,fileImportPath);
+ if (qmlImportTrace())
+ qDebug() << "QmlEngine::addToImport(" << imports << uri << prefix << vmaj << '.' << vmin << (importType==QmlScriptParser::Import::Library? "Library" : "File") << ": " << ok;
+ return ok;
+}
+
+/*!
+ \internal
+
+ Using the given \a imports, the given (namespace qualified) \a type is resolved to either
+ an ImportedNamespace stored at \a ns_return,
+ a QmlType stored at \a type_return, or
+ a component located at \a url_return.
+
+ If any return pointer is 0, the corresponding search is not done.
+
+ \sa addToImport()
+*/
+bool QmlEnginePrivate::resolveType(const Imports& imports, const QByteArray& type, QmlType** type_return, QUrl* url_return, int *vmaj, int *vmin, ImportedNamespace** ns_return) const
+{
+ ImportedNamespace* ns = imports.d->findNamespace(QString::fromUtf8(type));
+ if (ns) {
+ if (qmlImportTrace())
+ qDebug() << "QmlEngine::resolveType" << type << "is namespace for" << ns->urls;
+ if (ns_return)
+ *ns_return = ns;
+ return true;
+ }
+ if (type_return || url_return) {
+ if (imports.d->find(type,vmaj,vmin,type_return,url_return)) {
+ if (qmlImportTrace()) {
+ if (type_return && *type_return)
+ qDebug() << "QmlEngine::resolveType" << type << '=' << (*type_return)->typeName();
+ if (url_return)
+ qDebug() << "QmlEngine::resolveType" << type << '=' << *url_return;
+ }
+ return true;
+ }
+ if (qmlImportTrace())
+ qDebug() << "QmlEngine::resolveType" << type << "not found";
+ }
+ return false;
+}
+
+/*!
+ \internal
+
+ Searching \e only in the namespace \a ns (previously returned in a call to
+ resolveType(), \a type is found and returned to either
+ a QmlType stored at \a type_return, or
+ a component located at \a url_return.
+
+ If either return pointer is 0, the corresponding search is not done.
+*/
+void QmlEnginePrivate::resolveTypeInNamespace(ImportedNamespace* ns, const QByteArray& type, QmlType** type_return, QUrl* url_return, int *vmaj, int *vmin ) const
+{
+ ns->find(type,vmaj,vmin,type_return,url_return);
+}
+
+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);
+ }
+}
+
+void QmlEnginePrivate::registerCompositeType(QmlCompiledData *data)
+{
+ QByteArray name = data->root->className();
+
+ QByteArray ptr = name + '*';
+ QByteArray lst = "QmlList<" + ptr + ">*";
+
+ int ptr_type = QMetaType::registerType(ptr.constData(), voidptr_destructor,
+ voidptr_constructor);
+ int lst_type = QMetaType::registerType(lst.constData(), voidptr_destructor,
+ voidptr_constructor);
+
+ m_qmlLists.insert(lst_type, ptr_type);
+ m_compositeTypes.insert(ptr_type, data);
+ data->addref();
+}
+
+bool QmlEnginePrivate::isQmlList(int t) const
+{
+ return m_qmlLists.contains(t) || QmlMetaType::isQmlList(t);
+}
+
+bool QmlEnginePrivate::isObject(int t)
+{
+ return m_compositeTypes.contains(t) || QmlMetaType::isObject(t);
+}
+
+int QmlEnginePrivate::qmlListType(int t) const
+{
+ QHash<int, int>::ConstIterator iter = m_qmlLists.find(t);
+ if (iter != m_qmlLists.end())
+ return *iter;
+ else
+ return QmlMetaType::qmlListType(t);
+}
+
+QmlMetaType::TypeCategory QmlEnginePrivate::typeCategory(int t) const
+{
+ if (m_compositeTypes.contains(t))
+ return QmlMetaType::Object;
+ else if (m_qmlLists.contains(t))
+ return QmlMetaType::QmlList;
+ else
+ return QmlMetaType::typeCategory(t);
+}
+
+const QMetaObject *QmlEnginePrivate::rawMetaObjectForType(int t) const
+{
+ QHash<int, QmlCompiledData*>::ConstIterator iter = m_compositeTypes.find(t);
+ if (iter != m_compositeTypes.end()) {
+ return (*iter)->root;
+ } else {
+ return QmlMetaType::rawMetaObjectForType(t);
+ }
+}
+
+const QMetaObject *QmlEnginePrivate::metaObjectForType(int t) const
+{
+ QHash<int, QmlCompiledData*>::ConstIterator iter = m_compositeTypes.find(t);
+ if (iter != m_compositeTypes.end()) {
+ return (*iter)->root;
+ } else {
+ return QmlMetaType::metaObjectForType(t);
+ }
+}
+
+QT_END_NAMESPACE