diff -r b72c6db6890b -r 5dc02b23752f src/declarative/qml/qdeclarativevmemetaobject.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/declarative/qml/qdeclarativevmemetaobject.cpp Tue Jul 06 15:10:48 2010 +0300 @@ -0,0 +1,783 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "private/qdeclarativevmemetaobject_p.h" + +#include "qdeclarative.h" +#include "private/qdeclarativerefcount_p.h" +#include "qdeclarativeexpression.h" +#include "private/qdeclarativeexpression_p.h" +#include "private/qdeclarativecontext_p.h" + +Q_DECLARE_METATYPE(QScriptValue); + +QT_BEGIN_NAMESPACE + +class QDeclarativeVMEVariant +{ +public: + inline QDeclarativeVMEVariant(); + inline ~QDeclarativeVMEVariant(); + + inline const void *dataPtr() const; + inline void *dataPtr(); + inline int dataType() const; + + inline QObject *asQObject(); + inline const QVariant &asQVariant(); + inline int asInt(); + inline bool asBool(); + inline double asDouble(); + inline const QString &asQString(); + inline const QUrl &asQUrl(); + inline const QColor &asQColor(); + inline const QTime &asQTime(); + inline const QDate &asQDate(); + inline const QDateTime &asQDateTime(); + inline const QScriptValue &asQScriptValue(); + + inline void setValue(QObject *); + inline void setValue(const QVariant &); + inline void setValue(int); + inline void setValue(bool); + inline void setValue(double); + inline void setValue(const QString &); + inline void setValue(const QUrl &); + inline void setValue(const QColor &); + inline void setValue(const QTime &); + inline void setValue(const QDate &); + inline void setValue(const QDateTime &); + inline void setValue(const QScriptValue &); +private: + int type; + void *data[4]; // Large enough to hold all types + + inline void cleanup(); +}; + +QDeclarativeVMEVariant::QDeclarativeVMEVariant() +: type(QVariant::Invalid) +{ +} + +QDeclarativeVMEVariant::~QDeclarativeVMEVariant() +{ + cleanup(); +} + +void QDeclarativeVMEVariant::cleanup() +{ + if (type == QVariant::Invalid) { + } else if (type == QMetaType::Int || + type == QMetaType::Bool || + type == QMetaType::Double) { + type = QVariant::Invalid; + } else if (type == QMetaType::QObjectStar) { + ((QDeclarativeGuard*)dataPtr())->~QDeclarativeGuard(); + type = QVariant::Invalid; + } else if (type == QMetaType::QString) { + ((QString *)dataPtr())->~QString(); + type = QVariant::Invalid; + } else if (type == QMetaType::QUrl) { + ((QUrl *)dataPtr())->~QUrl(); + type = QVariant::Invalid; + } else if (type == QMetaType::QColor) { + ((QColor *)dataPtr())->~QColor(); + type = QVariant::Invalid; + } else if (type == QMetaType::QTime) { + ((QTime *)dataPtr())->~QTime(); + type = QVariant::Invalid; + } else if (type == QMetaType::QDate) { + ((QDate *)dataPtr())->~QDate(); + type = QVariant::Invalid; + } else if (type == QMetaType::QDateTime) { + ((QDateTime *)dataPtr())->~QDateTime(); + type = QVariant::Invalid; + } else if (type == qMetaTypeId()) { + ((QVariant *)dataPtr())->~QVariant(); + type = QVariant::Invalid; + } else if (type == qMetaTypeId()) { + ((QScriptValue *)dataPtr())->~QScriptValue(); + type = QVariant::Invalid; + } + +} + +int QDeclarativeVMEVariant::dataType() const +{ + return type; +} + +const void *QDeclarativeVMEVariant::dataPtr() const +{ + return &data; +} + +void *QDeclarativeVMEVariant::dataPtr() +{ + return &data; +} + +QObject *QDeclarativeVMEVariant::asQObject() +{ + if (type != QMetaType::QObjectStar) + setValue((QObject *)0); + + return *(QDeclarativeGuard *)(dataPtr()); +} + +const QVariant &QDeclarativeVMEVariant::asQVariant() +{ + if (type != QMetaType::QVariant) + setValue(QVariant()); + + return *(QVariant *)(dataPtr()); +} + +int QDeclarativeVMEVariant::asInt() +{ + if (type != QMetaType::Int) + setValue(int(0)); + + return *(int *)(dataPtr()); +} + +bool QDeclarativeVMEVariant::asBool() +{ + if (type != QMetaType::Bool) + setValue(bool(false)); + + return *(bool *)(dataPtr()); +} + +double QDeclarativeVMEVariant::asDouble() +{ + if (type != QMetaType::Double) + setValue(double(0)); + + return *(double *)(dataPtr()); +} + +const QString &QDeclarativeVMEVariant::asQString() +{ + if (type != QMetaType::QString) + setValue(QString()); + + return *(QString *)(dataPtr()); +} + +const QUrl &QDeclarativeVMEVariant::asQUrl() +{ + if (type != QMetaType::QUrl) + setValue(QUrl()); + + return *(QUrl *)(dataPtr()); +} + +const QColor &QDeclarativeVMEVariant::asQColor() +{ + if (type != QMetaType::QColor) + setValue(QColor()); + + return *(QColor *)(dataPtr()); +} + +const QTime &QDeclarativeVMEVariant::asQTime() +{ + if (type != QMetaType::QTime) + setValue(QTime()); + + return *(QTime *)(dataPtr()); +} + +const QDate &QDeclarativeVMEVariant::asQDate() +{ + if (type != QMetaType::QDate) + setValue(QDate()); + + return *(QDate *)(dataPtr()); +} + +const QDateTime &QDeclarativeVMEVariant::asQDateTime() +{ + if (type != QMetaType::QDateTime) + setValue(QDateTime()); + + return *(QDateTime *)(dataPtr()); +} + +const QScriptValue &QDeclarativeVMEVariant::asQScriptValue() +{ + if (type != qMetaTypeId()) + setValue(QScriptValue()); + + return *(QScriptValue *)(dataPtr()); +} + +void QDeclarativeVMEVariant::setValue(QObject *v) +{ + if (type != QMetaType::QObjectStar) { + cleanup(); + type = QMetaType::QObjectStar; + new (dataPtr()) QDeclarativeGuard(); + } + *(QDeclarativeGuard*)(dataPtr()) = v; +} + +void QDeclarativeVMEVariant::setValue(const QVariant &v) +{ + if (type != qMetaTypeId()) { + cleanup(); + type = qMetaTypeId(); + new (dataPtr()) QVariant(v); + } else { + *(QVariant *)(dataPtr()) = v; + } +} + +void QDeclarativeVMEVariant::setValue(int v) +{ + if (type != QMetaType::Int) { + cleanup(); + type = QMetaType::Int; + } + *(int *)(dataPtr()) = v; +} + +void QDeclarativeVMEVariant::setValue(bool v) +{ + if (type != QMetaType::Bool) { + cleanup(); + type = QMetaType::Bool; + } + *(bool *)(dataPtr()) = v; +} + +void QDeclarativeVMEVariant::setValue(double v) +{ + if (type != QMetaType::Double) { + cleanup(); + type = QMetaType::Double; + } + *(double *)(dataPtr()) = v; +} + +void QDeclarativeVMEVariant::setValue(const QString &v) +{ + if (type != QMetaType::QString) { + cleanup(); + type = QMetaType::QString; + new (dataPtr()) QString(v); + } else { + *(QString *)(dataPtr()) = v; + } +} + +void QDeclarativeVMEVariant::setValue(const QUrl &v) +{ + if (type != QMetaType::QUrl) { + cleanup(); + type = QMetaType::QUrl; + new (dataPtr()) QUrl(v); + } else { + *(QUrl *)(dataPtr()) = v; + } +} + +void QDeclarativeVMEVariant::setValue(const QColor &v) +{ + if (type != QMetaType::QColor) { + cleanup(); + type = QMetaType::QColor; + new (dataPtr()) QColor(v); + } else { + *(QColor *)(dataPtr()) = v; + } +} + +void QDeclarativeVMEVariant::setValue(const QTime &v) +{ + if (type != QMetaType::QTime) { + cleanup(); + type = QMetaType::QTime; + new (dataPtr()) QTime(v); + } else { + *(QTime *)(dataPtr()) = v; + } +} + +void QDeclarativeVMEVariant::setValue(const QDate &v) +{ + if (type != QMetaType::QDate) { + cleanup(); + type = QMetaType::QDate; + new (dataPtr()) QDate(v); + } else { + *(QDate *)(dataPtr()) = v; + } +} + +void QDeclarativeVMEVariant::setValue(const QDateTime &v) +{ + if (type != QMetaType::QDateTime) { + cleanup(); + type = QMetaType::QDateTime; + new (dataPtr()) QDateTime(v); + } else { + *(QDateTime *)(dataPtr()) = v; + } +} + +void QDeclarativeVMEVariant::setValue(const QScriptValue &v) +{ + if (type != qMetaTypeId()) { + cleanup(); + type = qMetaTypeId(); + new (dataPtr()) QScriptValue(v); + } else { + *(QScriptValue *)(dataPtr()) = v; + } +} + +QDeclarativeVMEMetaObject::QDeclarativeVMEMetaObject(QObject *obj, + const QMetaObject *other, + const QDeclarativeVMEMetaData *meta, + QDeclarativeCompiledData *cdata) +: object(obj), compiledData(cdata), ctxt(QDeclarativeData::get(obj, true)->outerContext), + metaData(meta), data(0), methods(0), parent(0) +{ + compiledData->addref(); + + *static_cast(this) = *other; + this->d.superdata = obj->metaObject(); + + QObjectPrivate *op = QObjectPrivate::get(obj); + if (op->metaObject) + parent = static_cast(op->metaObject); + op->metaObject = this; + + propOffset = QAbstractDynamicMetaObject::propertyOffset(); + methodOffset = QAbstractDynamicMetaObject::methodOffset(); + + data = new QDeclarativeVMEVariant[metaData->propertyCount]; + + aConnected.resize(metaData->aliasCount); + int list_type = qMetaTypeId >(); + + // ### Optimize + for (int ii = 0; ii < metaData->propertyCount; ++ii) { + int t = (metaData->propertyData() + ii)->propertyType; + if (t == list_type) { + listProperties.append(List(methodOffset + ii)); + data[ii].setValue(listProperties.count() - 1); + } + } +} + +QDeclarativeVMEMetaObject::~QDeclarativeVMEMetaObject() +{ + compiledData->release(); + delete parent; + delete [] data; + delete [] methods; +} + +int QDeclarativeVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) +{ + int id = _id; + if(c == QMetaObject::WriteProperty) { + int flags = *reinterpret_cast(a[3]); + if (!(flags & QDeclarativePropertyPrivate::BypassInterceptor) + && !aInterceptors.isEmpty() + && aInterceptors.testBit(id)) { + QPair pair = interceptors.value(id); + int valueIndex = pair.first; + QDeclarativePropertyValueInterceptor *vi = pair.second; + int type = property(id).userType(); + + if (type != QVariant::Invalid) { + if (valueIndex != -1) { + QDeclarativeEnginePrivate *ep = ctxt?QDeclarativeEnginePrivate::get(ctxt->engine):0; + QDeclarativeValueType *valueType = 0; + if (ep) valueType = ep->valueTypes[type]; + else valueType = QDeclarativeValueTypeFactory::valueType(type); + Q_ASSERT(valueType); + + valueType->setValue(QVariant(type, a[0])); + QMetaProperty valueProp = valueType->metaObject()->property(valueIndex); + vi->write(valueProp.read(valueType)); + + if (!ep) delete valueType; + return -1; + } else { + vi->write(QVariant(type, a[0])); + return -1; + } + } + } + } + if(c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty) { + if (id >= propOffset) { + id -= propOffset; + + if (id < metaData->propertyCount) { + int t = (metaData->propertyData() + id)->propertyType; + bool needActivate = false; + + if (t == -1) { + + if (c == QMetaObject::ReadProperty) { + *reinterpret_cast(a[0]) = readVarPropertyAsVariant(id); + } else if (c == QMetaObject::WriteProperty) { + writeVarProperty(id, *reinterpret_cast(a[0])); + } + + } else { + + if (c == QMetaObject::ReadProperty) { + switch(t) { + case QVariant::Int: + *reinterpret_cast(a[0]) = data[id].asInt(); + break; + case QVariant::Bool: + *reinterpret_cast(a[0]) = data[id].asBool(); + break; + case QVariant::Double: + *reinterpret_cast(a[0]) = data[id].asDouble(); + break; + case QVariant::String: + *reinterpret_cast(a[0]) = data[id].asQString(); + break; + case QVariant::Url: + *reinterpret_cast(a[0]) = data[id].asQUrl(); + break; + case QVariant::Color: + *reinterpret_cast(a[0]) = data[id].asQColor(); + break; + case QVariant::Date: + *reinterpret_cast(a[0]) = data[id].asQDate(); + break; + case QVariant::DateTime: + *reinterpret_cast(a[0]) = data[id].asQDateTime(); + break; + case QMetaType::QObjectStar: + *reinterpret_cast(a[0]) = data[id].asQObject(); + break; + default: + break; + } + if (t == qMetaTypeId >()) { + int listIndex = data[id].asInt(); + const List *list = &listProperties.at(listIndex); + *reinterpret_cast *>(a[0]) = + QDeclarativeListProperty(object, (void *)list, + list_append, list_count, list_at, + list_clear); + } + + } else if (c == QMetaObject::WriteProperty) { + + switch(t) { + case QVariant::Int: + needActivate = *reinterpret_cast(a[0]) != data[id].asInt(); + data[id].setValue(*reinterpret_cast(a[0])); + break; + case QVariant::Bool: + needActivate = *reinterpret_cast(a[0]) != data[id].asBool(); + data[id].setValue(*reinterpret_cast(a[0])); + break; + case QVariant::Double: + needActivate = *reinterpret_cast(a[0]) != data[id].asDouble(); + data[id].setValue(*reinterpret_cast(a[0])); + break; + case QVariant::String: + needActivate = *reinterpret_cast(a[0]) != data[id].asQString(); + data[id].setValue(*reinterpret_cast(a[0])); + break; + case QVariant::Url: + needActivate = *reinterpret_cast(a[0]) != data[id].asQUrl(); + data[id].setValue(*reinterpret_cast(a[0])); + break; + case QVariant::Color: + needActivate = *reinterpret_cast(a[0]) != data[id].asQColor(); + data[id].setValue(*reinterpret_cast(a[0])); + break; + case QVariant::Date: + needActivate = *reinterpret_cast(a[0]) != data[id].asQDate(); + data[id].setValue(*reinterpret_cast(a[0])); + break; + case QVariant::DateTime: + needActivate = *reinterpret_cast(a[0]) != data[id].asQDateTime(); + data[id].setValue(*reinterpret_cast(a[0])); + break; + case QMetaType::QObjectStar: + needActivate = *reinterpret_cast(a[0]) != data[id].asQObject(); + data[id].setValue(*reinterpret_cast(a[0])); + break; + default: + break; + } + } + + } + + if (c == QMetaObject::WriteProperty && needActivate) { + activate(object, methodOffset + id, 0); + } + + return -1; + } + + id -= metaData->propertyCount; + + if (id < metaData->aliasCount) { + + QDeclarativeVMEMetaData::AliasData *d = metaData->aliasData() + id; + + if (d->flags & QML_ALIAS_FLAG_PTR && c == QMetaObject::ReadProperty) + *reinterpret_cast(a[0]) = 0; + + if (!ctxt) return -1; + + QDeclarativeContext *context = ctxt->asQDeclarativeContext(); + QDeclarativeContextPrivate *ctxtPriv = QDeclarativeContextPrivate::get(context); + + QObject *target = ctxtPriv->data->idValues[d->contextIdx].data(); + if (!target) + return -1; + + if (c == QMetaObject::ReadProperty && !aConnected.testBit(id)) { + int sigIdx = methodOffset + id + metaData->propertyCount; + QMetaObject::connect(context, d->contextIdx + ctxtPriv->notifyIndex, object, sigIdx); + + if (d->propertyIdx != -1) { + QMetaProperty prop = + target->metaObject()->property(d->propertyIdx); + if (prop.hasNotifySignal()) + QMetaObject::connect(target, prop.notifySignalIndex(), + object, sigIdx); + } + aConnected.setBit(id); + } + + if (d->propertyIdx == -1) { + *reinterpret_cast(a[0]) = target; + return -1; + } else { + return QMetaObject::metacall(target, c, d->propertyIdx, a); + } + + } + return -1; + + } + + } else if(c == QMetaObject::InvokeMetaMethod) { + + if (id >= methodOffset) { + + id -= methodOffset; + int plainSignals = metaData->signalCount + metaData->propertyCount + + metaData->aliasCount; + if (id < plainSignals) { + QMetaObject::activate(object, _id, a); + return -1; + } + + id -= plainSignals; + + if (id < metaData->methodCount) { + if (!ctxt->engine) + return -1; // We can't run the method + + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(ctxt->engine); + + QScriptValue function = method(id); + + QScriptValueList args; + QDeclarativeVMEMetaData::MethodData *data = metaData->methodData() + id; + if (data->parameterCount) { + for (int ii = 0; ii < data->parameterCount; ++ii) { + args << ep->scriptValueFromVariant(*(QVariant *)a[ii + 1]); + } + } + QScriptValue rv = function.call(ep->objectClass->newQObject(object), args); + + if (a[0]) *reinterpret_cast(a[0]) = ep->scriptValueToVariant(rv); + + return -1; + } + return -1; + } + } + + if (parent) + return parent->metaCall(c, _id, a); + else + return object->qt_metacall(c, _id, a); +} + +QScriptValue QDeclarativeVMEMetaObject::method(int index) +{ + if (!methods) + methods = new QScriptValue[metaData->methodCount]; + + if (!methods[index].isValid()) { + QDeclarativeVMEMetaData::MethodData *data = metaData->methodData() + index; + + const QChar *body = + (const QChar *)(((const char*)metaData) + data->bodyOffset); + + QString code = QString::fromRawData(body, data->bodyLength); + + // XXX Use QScriptProgram + // XXX We should evaluate all methods in a single big script block to + // improve the call time between dynamic methods defined on the same + // object + methods[index] = QDeclarativeExpressionPrivate::evalInObjectScope(ctxt, object, code, ctxt->url.toString(), + data->lineNumber, 0); + } + + return methods[index]; +} + +QScriptValue QDeclarativeVMEMetaObject::readVarProperty(int id) +{ + if (data[id].dataType() == qMetaTypeId()) + return data[id].asQScriptValue(); + else if (data[id].dataType() == QMetaType::QObjectStar) + return QDeclarativeEnginePrivate::get(ctxt->engine)->objectClass->newQObject(data[id].asQObject()); + else + return QDeclarativeEnginePrivate::get(ctxt->engine)->scriptValueFromVariant(data[id].asQVariant()); +} + +QVariant QDeclarativeVMEMetaObject::readVarPropertyAsVariant(int id) +{ + if (data[id].dataType() == qMetaTypeId()) + return QDeclarativeEnginePrivate::get(ctxt->engine)->scriptValueToVariant(data[id].asQScriptValue()); + else if (data[id].dataType() == QMetaType::QObjectStar) + return QVariant::fromValue(data[id].asQObject()); + else + return data[id].asQVariant(); +} + +void QDeclarativeVMEMetaObject::writeVarProperty(int id, const QScriptValue &value) +{ + data[id].setValue(value); + activate(object, methodOffset + id, 0); +} + +void QDeclarativeVMEMetaObject::writeVarProperty(int id, const QVariant &value) +{ + if (value.userType() == QMetaType::QObjectStar) + data[id].setValue(qvariant_cast(value)); + else + data[id].setValue(value); + activate(object, methodOffset + id, 0); +} + +void QDeclarativeVMEMetaObject::listChanged(int id) +{ + activate(object, methodOffset + id, 0); +} + +void QDeclarativeVMEMetaObject::list_append(QDeclarativeListProperty *prop, QObject *o) +{ + List *list = static_cast(prop->data); + list->append(o); + QMetaObject::activate(prop->object, list->notifyIndex, 0); +} + +int QDeclarativeVMEMetaObject::list_count(QDeclarativeListProperty *prop) +{ + return static_cast(prop->data)->count(); +} + +QObject *QDeclarativeVMEMetaObject::list_at(QDeclarativeListProperty *prop, int index) +{ + return static_cast(prop->data)->at(index); +} + +void QDeclarativeVMEMetaObject::list_clear(QDeclarativeListProperty *prop) +{ + List *list = static_cast(prop->data); + list->clear(); + QMetaObject::activate(prop->object, list->notifyIndex, 0); +} + +void QDeclarativeVMEMetaObject::registerInterceptor(int index, int valueIndex, QDeclarativePropertyValueInterceptor *interceptor) +{ + if (aInterceptors.isEmpty()) + aInterceptors.resize(propertyCount() + metaData->propertyCount); + aInterceptors.setBit(index); + interceptors.insert(index, qMakePair(valueIndex, interceptor)); +} + +QScriptValue QDeclarativeVMEMetaObject::vmeMethod(int index) +{ + if (index < methodOffset) { + Q_ASSERT(parent); + return static_cast(parent)->vmeMethod(index); + } + int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount; + Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount)); + return method(index - methodOffset - plainSignals); +} + +QScriptValue QDeclarativeVMEMetaObject::vmeProperty(int index) +{ + if (index < propOffset) { + Q_ASSERT(parent); + return static_cast(parent)->vmeProperty(index); + } + return readVarProperty(index - propOffset); +} + +void QDeclarativeVMEMetaObject::setVMEProperty(int index, const QScriptValue &v) +{ + if (index < propOffset) { + Q_ASSERT(parent); + static_cast(parent)->setVMEProperty(index, v); + } + return writeVarProperty(index - propOffset, v); +} + +QT_END_NAMESPACE