From 35ab04c907a1cefa23eff2d7c853350fb5d27178 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 30 May 2013 13:16:44 +0200 Subject: Port the type wrapper over to v4 Change-Id: Id442281a366914be818b068f70ebe5200c527254 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmltypewrapper.cpp | 276 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 276 insertions(+) create mode 100644 src/qml/qml/qqmltypewrapper.cpp (limited to 'src/qml/qml/qqmltypewrapper.cpp') diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp new file mode 100644 index 0000000000..322a7e31c4 --- /dev/null +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -0,0 +1,276 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmltypewrapper_p.h" +#include +#include + +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace QV4; + +DEFINE_MANAGED_VTABLE(QmlTypeWrapper); + +QmlTypeWrapper::QmlTypeWrapper(QV8Engine *engine) + : Object(QV8Engine::getV4(engine)), + v8(engine), mode(IncludeEnums), type(0), typeNamespace(0), importNamespace(0) +{ + Managed::type = Type_QmlTypeWrapper; + vtbl = &static_vtbl; +} + +QmlTypeWrapper::~QmlTypeWrapper() +{ + if (typeNamespace) + typeNamespace->release(); +} + +QVariant QmlTypeWrapper::toVariant() const +{ + if (type && type->isSingleton()) { + QQmlEngine *e = v8->engine(); + QQmlType::SingletonInstanceInfo *siinfo = type->singletonInstanceInfo(); + siinfo->init(e); // note: this will also create QJSValue singleton which isn't strictly required. + QObject *qobjectSingleton = siinfo->qobjectApi(e); + if (qobjectSingleton) { + return QVariant::fromValue(qobjectSingleton); + } + } + + // only QObject Singleton Type can be converted to a variant. + return QVariant(); +} + + +// Returns a type wrapper for type t on o. This allows access of enums, and attached properties. +Value QmlTypeWrapper::create(QV8Engine *v8, QObject *o, QQmlType *t, TypeNameMode mode) +{ + Q_ASSERT(t); + ExecutionEngine *v4 = QV8Engine::getV4(v8); + + QmlTypeWrapper *w = new (v4->memoryManager) QmlTypeWrapper(v8); + w->prototype = v4->objectPrototype; + w->mode = mode; w->object = o; w->type = t; + return Value::fromObject(w); +} + +// Returns a type wrapper for importNamespace (of t) on o. This allows nested resolution of a type in a +// namespace. +Value QmlTypeWrapper::create(QV8Engine *v8, QObject *o, QQmlTypeNameCache *t, const void *importNamespace, TypeNameMode mode) +{ + Q_ASSERT(t); + Q_ASSERT(importNamespace); + ExecutionEngine *v4 = QV8Engine::getV4(v8); + + QmlTypeWrapper *w = new (v4->memoryManager) QmlTypeWrapper(v8); + w->prototype = v4->objectPrototype; + w->mode = mode; w->object = o; w->typeNamespace = t; w->importNamespace = importNamespace; + t->addref(); + return Value::fromObject(w); +} + + +Value QmlTypeWrapper::get(Managed *m, ExecutionContext *ctx, String *name, bool *hasProperty) +{ + QmlTypeWrapper *w = m->asQmlTypeWrapper(); + if (!m) + ctx->throwTypeError(); + + if (hasProperty) + *hasProperty = true; + + QV8Engine *v8engine = w->v8; + QQmlContextData *context = v8engine->callingContext(); + + QObject *object = w->object; + + QHashedV4String propertystring(Value::fromString(name)); + + if (w->type) { + QQmlType *type = w->type; + + // singleton types are handled differently to other types. + if (type->isSingleton()) { + QQmlEngine *e = v8engine->engine(); + QQmlType::SingletonInstanceInfo *siinfo = type->singletonInstanceInfo(); + siinfo->init(e); + + QObject *qobjectSingleton = siinfo->qobjectApi(e); + if (qobjectSingleton) { + // check for enum value + if (name->startsWithUpper()) { + if (w->mode == IncludeEnums) { + // ### Optimize + QByteArray enumName = name->toQString().toUtf8(); + const QMetaObject *metaObject = qobjectSingleton->metaObject(); + for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) { + QMetaEnum e = metaObject->enumerator(ii); + bool ok; + int value = e.keyToValue(enumName.constData(), &ok); + if (ok) + return QV4::Value::fromInt32(value); + } + } + } + + // check for property. + return v8engine->qobjectWrapper()->getProperty(qobjectSingleton, propertystring, context, QV8QObjectWrapper::IgnoreRevision)->v4Value(); + } else if (!siinfo->scriptApi(e).isUndefined()) { + QV4::ExecutionEngine *engine = QV8Engine::getV4(v8engine); + // NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable. + QV4::Object *o = QJSValuePrivate::get(siinfo->scriptApi(e))->getValue(engine).asObject(); + if (o) + return o->get(engine->current, name); + } + + // Fall through to base implementation + + } else { + + if (name->startsWithUpper()) { + bool ok = false; + int value = type->enumValue(propertystring, &ok); + if (ok) + return QV4::Value::fromInt32(value); + + // Fall through to base implementation + + } else if (w->object) { + QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object); + if (ao) + return v8engine->qobjectWrapper()->getProperty(ao, propertystring, context, + QV8QObjectWrapper::IgnoreRevision)->v4Value(); + + // Fall through to base implementation + } + + // Fall through to base implementation + } + + // Fall through to base implementation + + } else if (w->typeNamespace) { + Q_ASSERT(w->importNamespace); + QQmlTypeNameCache::Result r = w->typeNamespace->query(propertystring, + w->importNamespace); + + if (r.isValid()) { + QQmlContextData *context = v8engine->callingContext(); + if (r.type) { + return create(w->v8, object, r.type, w->mode); + } else if (r.scriptIndex != -1) { + int index = r.scriptIndex; + if (index < context->importedScripts.count()) + return context->importedScripts.at(index).value(); + } else if (r.importNamespace) { + return create(w->v8, object, context->imports, r.importNamespace); + } + + return QV4::Value::undefinedValue(); + + } + + // Fall through to base implementation + + } else { + Q_ASSERT(!"Unreachable"); + } + + if (hasProperty) + *hasProperty = false; + return Object::get(m, ctx, name, hasProperty); +} + + +void QmlTypeWrapper::put(Managed *m, ExecutionContext *ctx, String *name, const Value &value) +{ + QmlTypeWrapper *w = m->asQmlTypeWrapper(); + + if (!w) + ctx->throwTypeError(); + + QV8Engine *v8engine = w->v8; + QQmlContextData *context = v8engine->callingContext(); + + QHashedV4String propertystring(Value::fromString(name)); + + QQmlType *type = w->type; + if (type && !type->isSingleton() && w->object) { + QObject *object = w->object; + QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object); + if (ao) + v8engine->qobjectWrapper()->setProperty(ao, propertystring, context, value, + QV8QObjectWrapper::IgnoreRevision); + } else if (type && type->isSingleton()) { + QQmlEngine *e = v8engine->engine(); + QQmlType::SingletonInstanceInfo *siinfo = type->singletonInstanceInfo(); + siinfo->init(e); + + QObject *qobjectSingleton = siinfo->qobjectApi(e); + if (qobjectSingleton) { + v8engine->qobjectWrapper()->setProperty(qobjectSingleton, propertystring, context, value, + QV8QObjectWrapper::IgnoreRevision); + } else if (!siinfo->scriptApi(e).isUndefined()) { + QV4::Object *apiprivate = QJSValuePrivate::get(siinfo->scriptApi(e))->value.asObject(); + if (!apiprivate) { + QString error = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"'); + ctx->throwError(error); + } else { + QV4::ExecutionEngine *engine = QV8Engine::getV4(v8engine); + apiprivate->put(engine->current, name, value); + } + } + } +} + +void QmlTypeWrapper::destroy(Managed *that) +{ + static_cast(that)->~QmlTypeWrapper(); +} + +QT_END_NAMESPACE -- cgit v1.2.3