/**************************************************************************** ** ** 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 "qdeclarativevmemetaobject_p.h" #include "qdeclarative.h" #include "qdeclarativerefcount_p.h" #include "qdeclarativeexpression.h" #include "qdeclarativeexpression_p.h" #include "qdeclarativecontext_p.h" #include #include #include #include QT_BEGIN_NAMESPACE QDeclarativeVMEMetaObject::QDeclarativeVMEMetaObject(QObject *obj, const QMetaObject *other, const QDeclarativeVMEMetaData *meta, QDeclarativeCompiledData *cdata) : object(obj), compiledData(cdata), ctxt(qmlContext(obj)), metaData(meta), 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 QVariant[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(new List(methodOffset + ii)); data[ii] = QVariant::fromValue(QDeclarativeListProperty(obj, listProperties.last(), list_append, list_count, list_at, list_clear)); } else if (t != -1) { data[ii] = QVariant((QVariant::Type)t); } } } QDeclarativeVMEMetaObject::~QDeclarativeVMEMetaObject() { compiledData->release(); delete parent; qDeleteAll(listProperties); 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 & QDeclarativeMetaProperty::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]) = data[id]; } else if (c == QMetaObject::WriteProperty) { needActivate = (data[id] != *reinterpret_cast(a[0])); data[id] = *reinterpret_cast(a[0]); } } else { if (c == QMetaObject::ReadProperty) { switch(t) { case QVariant::Int: *reinterpret_cast(a[0]) = data[id].toInt(); break; case QVariant::Bool: *reinterpret_cast(a[0]) = data[id].toBool(); break; case QVariant::Double: *reinterpret_cast(a[0]) = data[id].toDouble(); break; case QVariant::String: *reinterpret_cast(a[0]) = data[id].toString(); break; case QVariant::Url: *reinterpret_cast(a[0]) = data[id].toUrl(); break; case QVariant::Color: *reinterpret_cast(a[0]) = data[id].value(); break; case QVariant::Date: *reinterpret_cast(a[0]) = data[id].toDate(); break; case QMetaType::QObjectStar: *reinterpret_cast(a[0]) = data[id].value(); break; default: break; } if (t == qMetaTypeId >()) { *reinterpret_cast *>(a[0]) = data[id].value >(); } } else if (c == QMetaObject::WriteProperty) { QVariant value = QVariant((QVariant::Type)data[id].type(), a[0]); needActivate = (data[id] != value); data[id] = value; } } 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; QDeclarativeContextPrivate *ctxtPriv = (QDeclarativeContextPrivate *)QObjectPrivate::get(ctxt); QObject *target = ctxtPriv->idValues[d->contextIdx].data(); if (!target) return -1; if (c == QMetaObject::ReadProperty && !aConnected.testBit(id)) { int sigIdx = methodOffset + id + metaData->propertyCount; QMetaObject::connect(ctxt, 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); } return methods[index]; } 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); } QT_END_NAMESPACE