/**************************************************************************** ** ** 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 "qmlvmemetaobject_p.h" #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE QmlVMEMetaObject::QmlVMEMetaObject(QObject *obj, const QMetaObject *other, const QmlVMEMetaData *meta, QmlRefCount *rc) : object(obj), ref(rc), ctxt(qmlContext(obj)), metaData(meta), parent(0) { if (ref) ref->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(this, ii)); data[ii] = QVariant::fromValue((QmlList*)listProperties.last()); } else if (t != -1) { data[ii] = QVariant((QVariant::Type)t); } } } QmlVMEMetaObject::~QmlVMEMetaObject() { if (ref) ref->release(); if (parent) delete parent; qDeleteAll(listProperties); delete [] data; } int QmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) { int id = _id; if(c == QMetaObject::WriteProperty) { int flags = *reinterpret_cast(a[3]); if (!(flags & QmlMetaProperty::BypassInterceptor) && !aInterceptors.isEmpty() && aInterceptors.testBit(id)) { QPair pair = interceptors.value(id); int valueIndex = pair.first; QmlPropertyValueInterceptor *vi = pair.second; QVariant::Type type = property(id).type(); if (type != QVariant::Invalid) { if (valueIndex != -1) { QmlEnginePrivate *ep = ctxt?QmlEnginePrivate::get(ctxt->engine()):0; QmlValueType *valueType = 0; if (ep) valueType = ep->valueTypes[type]; else valueType = QmlValueTypeFactory::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) { QmlVMEMetaData::AliasData *d = metaData->aliasData() + id; if (d->flags & QML_ALIAS_FLAG_PTR && c == QMetaObject::ReadProperty) *reinterpret_cast(a[0]) = 0; if (!ctxt) return -1; QmlContextPrivate *ctxtPriv = (QmlContextPrivate *)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) { QmlVMEMetaData::MethodData *data = metaData->methodData() + id; const QChar *body = (const QChar *)(((const char*)metaData) + data->bodyOffset); QString code = QString::fromRawData(body, data->bodyLength); QVariant rv; if (0 == (metaData->methodData() + id)->parameterCount) { QmlExpression expr(ctxt, code, object); expr.setTrackChange(false); rv = expr.value(); } else { QmlContext newCtxt(ctxt); QMetaMethod m = method(_id); QList names = m.parameterNames(); for (int ii = 0; ii < names.count(); ++ii) newCtxt.setContextProperty(QString::fromLatin1(names.at(ii)), *(QVariant *)a[ii + 1]); QmlExpression expr(&newCtxt, code, object); expr.setTrackChange(false); rv = expr.value(); } if (a[0]) *reinterpret_cast(a[0]) = rv; } return -1; } } if (parent) return parent->metaCall(c, _id, a); else return object->qt_metacall(c, _id, a); } void QmlVMEMetaObject::listChanged(int id) { activate(object, methodOffset + id, 0); } void QmlVMEMetaObject::registerInterceptor(int index, int valueIndex, QmlPropertyValueInterceptor *interceptor) { if (aInterceptors.isEmpty()) aInterceptors.resize(propertyCount() + metaData->propertyCount); aInterceptors.setBit(index); interceptors.insert(index, qMakePair(valueIndex, interceptor)); } QT_END_NAMESPACE