diff options
Diffstat (limited to 'src/declarative/qml/qdeclarativeobjectscriptclass.cpp')
-rw-r--r-- | src/declarative/qml/qdeclarativeobjectscriptclass.cpp | 1226 |
1 files changed, 0 insertions, 1226 deletions
diff --git a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp deleted file mode 100644 index edc1755a72..0000000000 --- a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp +++ /dev/null @@ -1,1226 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 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/qdeclarativeobjectscriptclass_p.h" - -#include "private/qdeclarativeengine_p.h" -#include "private/qdeclarativecontext_p.h" -#include "private/qdeclarativedata_p.h" -#include "private/qdeclarativetypenamescriptclass_p.h" -#include "private/qdeclarativelistscriptclass_p.h" -#include "private/qdeclarativebinding_p.h" -#include "private/qdeclarativeguard_p.h" -#include "private/qdeclarativevmemetaobject_p.h" - -#include <QtCore/qtimer.h> -#include <QtCore/qvarlengtharray.h> -#include <QtScript/qscriptcontextinfo.h> - -Q_DECLARE_METATYPE(QScriptValue) - -#if defined(__GNUC__) -# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 405 -// The code in this file does not violate strict aliasing, but GCC thinks it does -// so turn off the warnings for us to have a clean build -# pragma GCC diagnostic ignored "-Wstrict-aliasing" -# endif -#endif - -QT_BEGIN_NAMESPACE - -struct ObjectData : public QScriptDeclarativeClass::Object { - ObjectData(QObject *o, int t) : object(o), type(t) { - if (o) { - QDeclarativeData *ddata = QDeclarativeData::get(object, true); - if (ddata) ddata->objectDataRefCount++; - } - } - - virtual ~ObjectData() { - if (object && !object->parent()) { - QDeclarativeData *ddata = QDeclarativeData::get(object, false); - if (ddata && !ddata->indestructible && 0 == --ddata->objectDataRefCount) - object->deleteLater(); - } - } - - QDeclarativeGuard<QObject> object; - int type; -}; - -/* - The QDeclarativeObjectScriptClass handles property access for QObjects - via QtScript. It is also used to provide a more useful API in - QtScript for QML. - */ -QDeclarativeObjectScriptClass::QDeclarativeObjectScriptClass(QDeclarativeEngine *bindEngine) -: QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)), - methods(bindEngine), lastData(0), engine(bindEngine) -{ - QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); - - m_destroy = scriptEngine->newFunction(destroy); - m_destroyId = createPersistentIdentifier(QLatin1String("destroy")); - m_toString = scriptEngine->newFunction(tostring); - m_toStringId = createPersistentIdentifier(QLatin1String("toString")); -} - -QDeclarativeObjectScriptClass::~QDeclarativeObjectScriptClass() -{ -} - -QScriptValue QDeclarativeObjectScriptClass::newQObject(QObject *object, int type) -{ - QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); - - if (!object) - return scriptEngine->nullValue(); -// return newObject(scriptEngine, this, new ObjectData(object, type)); - - if (QObjectPrivate::get(object)->wasDeleted) - return scriptEngine->undefinedValue(); - - QDeclarativeData *ddata = QDeclarativeData::get(object, true); - - if (!ddata) { - return scriptEngine->undefinedValue(); - } else if (!ddata->indestructible && !object->parent()) { - return newObject(scriptEngine, this, new ObjectData(object, type)); - } else if (!ddata->scriptValue) { - ddata->scriptValue = new QScriptValue(newObject(scriptEngine, this, new ObjectData(object, type))); - return *ddata->scriptValue; - } else if (ddata->scriptValue->engine() == QDeclarativeEnginePrivate::getScriptEngine(engine)) { - return *ddata->scriptValue; - } else { - return newObject(scriptEngine, this, new ObjectData(object, type)); - } -} - -QObject *QDeclarativeObjectScriptClass::toQObject(const QScriptValue &value) const -{ - return value.toQObject(); -} - -int QDeclarativeObjectScriptClass::objectType(const QScriptValue &value) const -{ - if (scriptClass(value) != this) - return QVariant::Invalid; - - Object *o = object(value); - return ((ObjectData*)(o))->type; -} - -QScriptClass::QueryFlags -QDeclarativeObjectScriptClass::queryProperty(Object *object, const Identifier &name, - QScriptClass::QueryFlags flags) -{ - return queryProperty(toQObject(object), name, flags, 0); -} - -QScriptClass::QueryFlags -QDeclarativeObjectScriptClass::queryProperty(QObject *obj, const Identifier &name, - QScriptClass::QueryFlags flags, QDeclarativeContextData *evalContext, - QueryHints hints) -{ - Q_UNUSED(flags); - lastData = 0; - lastTNData = 0; - - if (name == m_destroyId.identifier || - name == m_toStringId.identifier) - return QScriptClass::HandlesReadAccess; - - if (!obj) - return 0; - - QDeclarativeEnginePrivate *enginePrivate = QDeclarativeEnginePrivate::get(engine); - lastData = QDeclarativePropertyCache::property(engine, obj, name, local); - if ((hints & ImplicitObject) && lastData && lastData->revision != 0) { - - QDeclarativeData *ddata = QDeclarativeData::get(obj); - if (ddata && ddata->propertyCache && !ddata->propertyCache->isAllowedInRevision(lastData)) - return 0; - } - - if (lastData) - return QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess; - - if (!(hints & SkipAttachedProperties)) { - if (!evalContext && context()) { - // Global object, QScriptContext activation object, QDeclarativeContext object - QScriptValue scopeNode = scopeChainValue(context(), -3); - if (scopeNode.isValid()) { - Q_ASSERT(scriptClass(scopeNode) == enginePrivate->contextClass); - - evalContext = enginePrivate->contextClass->contextFromValue(scopeNode); - } - } - - if (evalContext && evalContext->imports) { - QDeclarativeTypeNameCache::Data *data = evalContext->imports->data(name); - if (data) { - lastTNData = data; - return QScriptClass::HandlesReadAccess; - } - } - } - - if (!(hints & ImplicitObject)) { - local.coreIndex = -1; - lastData = &local; - return QScriptClass::HandlesWriteAccess; - } - - return 0; -} - -QDeclarativeObjectScriptClass::Value -QDeclarativeObjectScriptClass::property(Object *object, const Identifier &name) -{ - return property(toQObject(object), name); -} - -QDeclarativeObjectScriptClass::Value -QDeclarativeObjectScriptClass::property(QObject *obj, const Identifier &name) -{ - QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); - - if (name == m_destroyId.identifier) - return Value(scriptEngine, m_destroy); - else if (name == m_toStringId.identifier) - return Value(scriptEngine, m_toString); - - if (lastData && !lastData->isValid()) - return Value(); - - Q_ASSERT(obj); - - QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine); - - if (lastTNData) { - - if (lastTNData->type) - return Value(scriptEngine, enginePriv->typeNameClass->newObject(obj, lastTNData->type)); - else - return Value(scriptEngine, enginePriv->typeNameClass->newObject(obj, lastTNData->typeNamespace)); - - } else if (lastData->flags & QDeclarativePropertyCache::Data::IsFunction) { - if (lastData->flags & QDeclarativePropertyCache::Data::IsVMEFunction) { - return Value(scriptEngine, ((QDeclarativeVMEMetaObject *)(obj->metaObject()))->vmeMethod(lastData->coreIndex)); - } else { - // Uncomment to use QtScript method call logic - // QScriptValue sobj = scriptEngine->newQObject(obj); - // return Value(scriptEngine, sobj.property(toString(name))); - return Value(scriptEngine, methods.newMethod(obj, lastData)); - } - } else { - if (enginePriv->captureProperties && !(lastData->flags & QDeclarativePropertyCache::Data::IsConstant)) { - if (lastData->coreIndex == 0) { - enginePriv->capturedProperties << - QDeclarativeEnginePrivate::CapturedProperty(QDeclarativeData::get(obj, true)->objectNameNotifier()); - } else { - enginePriv->capturedProperties << - QDeclarativeEnginePrivate::CapturedProperty(obj, lastData->coreIndex, lastData->notifyIndex); - } - } - - if (QDeclarativeValueTypeFactory::isValueType((uint)lastData->propType)) { - QDeclarativeValueType *valueType = enginePriv->valueTypes[lastData->propType]; - if (valueType) - return Value(scriptEngine, enginePriv->valueTypeClass->newObject(obj, lastData->coreIndex, valueType)); - } - - if (lastData->flags & QDeclarativePropertyCache::Data::IsQList) { - return Value(scriptEngine, enginePriv->listClass->newList(obj, lastData->coreIndex, lastData->propType)); - } else if (lastData->flags & QDeclarativePropertyCache::Data::IsQObjectDerived) { - QObject *rv = 0; - void *args[] = { &rv, 0 }; - QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); - return Value(scriptEngine, newQObject(rv, lastData->propType)); - } else if (lastData->flags & QDeclarativePropertyCache::Data::IsQScriptValue) { - QScriptValue rv = scriptEngine->nullValue(); - void *args[] = { &rv, 0 }; - QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); - return Value(scriptEngine, rv); - } else if (lastData->propType == QMetaType::QReal) { - qreal rv = 0; - void *args[] = { &rv, 0 }; - QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); - return Value(scriptEngine, rv); - } else if (lastData->propType == QMetaType::Int || lastData->flags & QDeclarativePropertyCache::Data::IsEnumType) { - int rv = 0; - void *args[] = { &rv, 0 }; - QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); - return Value(scriptEngine, rv); - } else if (lastData->propType == QMetaType::Bool) { - bool rv = false; - void *args[] = { &rv, 0 }; - QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); - return Value(scriptEngine, rv); - } else if (lastData->propType == QMetaType::QString) { - QString rv; - void *args[] = { &rv, 0 }; - QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); - return Value(scriptEngine, rv); - } else if (lastData->propType == QMetaType::UInt) { - uint rv = 0; - void *args[] = { &rv, 0 }; - QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); - return Value(scriptEngine, rv); - } else if (lastData->propType == QMetaType::Float) { - float rv = 0; - void *args[] = { &rv, 0 }; - QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); - return Value(scriptEngine, rv); - } else if (lastData->propType == QMetaType::Double) { - double rv = 0; - void *args[] = { &rv, 0 }; - QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); - return Value(scriptEngine, rv); - } else { - QVariant var = obj->metaObject()->property(lastData->coreIndex).read(obj); - return Value(scriptEngine, enginePriv->scriptValueFromVariant(var)); - } - } -} - -void QDeclarativeObjectScriptClass::setProperty(Object *object, - const Identifier &name, - const QScriptValue &value) -{ - return setProperty(toQObject(object), name, value, context()); -} - -void QDeclarativeObjectScriptClass::setProperty(QObject *obj, - const Identifier &name, - const QScriptValue &value, - QScriptContext *context, - QDeclarativeContextData *evalContext) -{ - Q_UNUSED(name); - - Q_ASSERT(obj); - Q_ASSERT(lastData); - Q_ASSERT(context); - - if (!lastData->isValid()) { - QString error = QLatin1String("Cannot assign to non-existent property \"") + - toString(name) + QLatin1Char('\"'); - context->throwError(error); - return; - } - - if (!(lastData->flags & QDeclarativePropertyCache::Data::IsWritable) && - !(lastData->flags & QDeclarativePropertyCache::Data::IsQList)) { - QString error = QLatin1String("Cannot assign to read-only property \"") + - toString(name) + QLatin1Char('\"'); - context->throwError(error); - return; - } - - QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine); - - if (!evalContext) { - // Global object, QScriptContext activation object, QDeclarativeContext object - QScriptValue scopeNode = scopeChainValue(context, -3); - if (scopeNode.isValid()) { - Q_ASSERT(scriptClass(scopeNode) == enginePriv->contextClass); - - evalContext = enginePriv->contextClass->contextFromValue(scopeNode); - } - } - - QDeclarativeBinding *newBinding = 0; - if (value.isFunction() && !value.isRegExp()) { - QScriptContextInfo ctxtInfo(context); - QDeclarativePropertyCache::ValueTypeData valueTypeData; - - newBinding = new QDeclarativeBinding(value, obj, evalContext); - newBinding->setSourceLocation(ctxtInfo.fileName(), ctxtInfo.functionStartLineNumber()); - newBinding->setTarget(QDeclarativePropertyPrivate::restore(*lastData, valueTypeData, obj, evalContext)); - if (newBinding->expression().contains(QLatin1String("this"))) - newBinding->setEvaluateFlags(newBinding->evaluateFlags() | QDeclarativeBinding::RequiresThisObject); - } - - QDeclarativeAbstractBinding *delBinding = - QDeclarativePropertyPrivate::setBinding(obj, lastData->coreIndex, -1, newBinding); - if (delBinding) - delBinding->destroy(); - - if (value.isNull() && lastData->flags & QDeclarativePropertyCache::Data::IsQObjectDerived) { - QObject *o = 0; - int status = -1; - int flags = 0; - void *argv[] = { &o, 0, &status, &flags }; - QMetaObject::metacall(obj, QMetaObject::WriteProperty, lastData->coreIndex, argv); - } else if (value.isUndefined() && lastData->flags & QDeclarativePropertyCache::Data::IsResettable) { - void *a[] = { 0 }; - QMetaObject::metacall(obj, QMetaObject::ResetProperty, lastData->coreIndex, a); - } else if (value.isUndefined() && lastData->propType == qMetaTypeId<QVariant>()) { - QDeclarativePropertyPrivate::write(obj, *lastData, QVariant(), evalContext); - } else if (value.isUndefined()) { - QString error = QLatin1String("Cannot assign [undefined] to ") + - QLatin1String(QMetaType::typeName(lastData->propType)); - context->throwError(error); - } else if (value.isFunction() && !value.isRegExp()) { - // this is handled by the binding creation above - } else { - //### expand optimization for other known types - if (lastData->propType == QMetaType::Int && value.isNumber()) { - int rawValue = qRound(value.toNumber()); - int status = -1; - int flags = 0; - void *a[] = { (void *)&rawValue, 0, &status, &flags }; - QMetaObject::metacall(obj, QMetaObject::WriteProperty, - lastData->coreIndex, a); - return; - } else if (lastData->propType == QMetaType::QReal && value.isNumber()) { - qreal rawValue = qreal(value.toNumber()); - int status = -1; - int flags = 0; - void *a[] = { (void *)&rawValue, 0, &status, &flags }; - QMetaObject::metacall(obj, QMetaObject::WriteProperty, - lastData->coreIndex, a); - return; - } else if (lastData->propType == QMetaType::QString && value.isString()) { - const QString &rawValue = value.toString(); - int status = -1; - int flags = 0; - void *a[] = { (void *)&rawValue, 0, &status, &flags }; - QMetaObject::metacall(obj, QMetaObject::WriteProperty, - lastData->coreIndex, a); - return; - } - - QVariant v; - if (lastData->flags & QDeclarativePropertyCache::Data::IsQList) - v = enginePriv->scriptValueToVariant(value, qMetaTypeId<QList<QObject *> >()); - else - v = enginePriv->scriptValueToVariant(value, lastData->propType); - - if (!QDeclarativePropertyPrivate::write(obj, *lastData, v, evalContext)) { - const char *valueType = 0; - if (v.userType() == QVariant::Invalid) valueType = "null"; - else valueType = QMetaType::typeName(v.userType()); - - QString error = QLatin1String("Cannot assign ") + - QLatin1String(valueType) + - QLatin1String(" to ") + - QLatin1String(QMetaType::typeName(lastData->propType)); - context->throwError(error); - } - } -} - -bool QDeclarativeObjectScriptClass::isQObject() const -{ - return true; -} - -QObject *QDeclarativeObjectScriptClass::toQObject(Object *object, bool *ok) -{ - if (ok) *ok = true; - - ObjectData *data = (ObjectData*)object; - return data->object.data(); -} - -QScriptValue QDeclarativeObjectScriptClass::tostring(QScriptContext *context, QScriptEngine *) -{ - QObject* obj = context->thisObject().toQObject(); - - QString ret; - if(obj){ - QString objectName = obj->objectName(); - - ret += QString::fromUtf8(obj->metaObject()->className()); - ret += QLatin1String("(0x"); - ret += QString::number((quintptr)obj,16); - - if (!objectName.isEmpty()) { - ret += QLatin1String(", \""); - ret += objectName; - ret += QLatin1Char('\"'); - } - - ret += QLatin1Char(')'); - }else{ - ret += QLatin1String("null"); - } - return QScriptValue(ret); -} - -QScriptValue QDeclarativeObjectScriptClass::destroy(QScriptContext *context, QScriptEngine *engine) -{ - QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine); - QScriptValue that = context->thisObject(); - - if (scriptClass(that) != p->objectClass) - return engine->undefinedValue(); - - ObjectData *data = (ObjectData *)p->objectClass->object(that); - if (!data->object) - return engine->undefinedValue(); - - QDeclarativeData *ddata = QDeclarativeData::get(data->object, false); - if (!ddata || ddata->indestructible) - return engine->currentContext()->throwError(QLatin1String("Invalid attempt to destroy() an indestructible object")); - - QObject *obj = data->object; - int delay = 0; - if (context->argumentCount() > 0) - delay = context->argument(0).toInt32(); - if (delay > 0) - QTimer::singleShot(delay, obj, SLOT(deleteLater())); - else - obj->deleteLater(); - - return engine->undefinedValue(); -} - -QStringList QDeclarativeObjectScriptClass::propertyNames(Object *object) -{ - QObject *obj = toQObject(object); - if (!obj) - return QStringList(); - - QDeclarativeEnginePrivate *enginePrivate = QDeclarativeEnginePrivate::get(engine); - - QDeclarativePropertyCache *cache = 0; - QDeclarativeData *ddata = QDeclarativeData::get(obj); - if (ddata) - cache = ddata->propertyCache; - if (!cache) { - cache = enginePrivate->cache(obj); - if (cache) { - if (ddata) { cache->addref(); ddata->propertyCache = cache; } - } else { - // Not cachable - fall back to QMetaObject (eg. dynamic meta object) - // XXX QDeclarativeOpenMetaObject has a cache, so this is suboptimal. - // XXX This is a workaround for QTBUG-9420. - const QMetaObject *mo = obj->metaObject(); - QStringList r; - int pc = mo->propertyCount(); - int po = mo->propertyOffset(); - for (int i=po; i<pc; ++i) - r += QString::fromUtf8(mo->property(i).name()); - return r; - } - } - return cache->propertyNames(); -} - -bool QDeclarativeObjectScriptClass::compare(Object *o1, Object *o2) -{ - ObjectData *d1 = (ObjectData *)o1; - ObjectData *d2 = (ObjectData *)o2; - - return d1 == d2 || d1->object == d2->object; -} - -struct MethodData : public QScriptDeclarativeClass::Object { - MethodData(QObject *o, const QDeclarativePropertyCache::Data &d) : object(o), data(d) {} - - QDeclarativeGuard<QObject> object; - QDeclarativePropertyCache::Data data; -}; - -QDeclarativeObjectMethodScriptClass::QDeclarativeObjectMethodScriptClass(QDeclarativeEngine *bindEngine) -: QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)), - engine(bindEngine) -{ - qRegisterMetaType<QList<QObject *> >("QList<QObject *>"); - - setSupportsCall(true); - - QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); - - m_connect = scriptEngine->newFunction(connect); - m_connectId = createPersistentIdentifier(QLatin1String("connect")); - m_disconnect = scriptEngine->newFunction(disconnect); - m_disconnectId = createPersistentIdentifier(QLatin1String("disconnect")); -} - -QDeclarativeObjectMethodScriptClass::~QDeclarativeObjectMethodScriptClass() -{ -} - -QScriptValue QDeclarativeObjectMethodScriptClass::newMethod(QObject *object, const QDeclarativePropertyCache::Data *method) -{ - QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); - - return newObject(scriptEngine, this, new MethodData(object, *method)); -} - -QScriptValue QDeclarativeObjectMethodScriptClass::connect(QScriptContext *context, QScriptEngine *engine) -{ - QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine); - - QScriptValue that = context->thisObject(); - if (&p->objectClass->methods != scriptClass(that)) - return engine->undefinedValue(); - - MethodData *data = (MethodData *)object(that); - - if (!data->object || context->argumentCount() == 0) - return engine->undefinedValue(); - - QByteArray signal("2"); - signal.append(data->object->metaObject()->method(data->data.coreIndex).signature()); - - if (context->argumentCount() == 1) { - qScriptConnect(data->object, signal.constData(), QScriptValue(), context->argument(0)); - } else { - qScriptConnect(data->object, signal.constData(), context->argument(0), context->argument(1)); - } - - return engine->undefinedValue(); -} - -QScriptValue QDeclarativeObjectMethodScriptClass::disconnect(QScriptContext *context, QScriptEngine *engine) -{ - QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine); - - QScriptValue that = context->thisObject(); - if (&p->objectClass->methods != scriptClass(that)) - return engine->undefinedValue(); - - MethodData *data = (MethodData *)object(that); - - if (!data->object || context->argumentCount() == 0) - return engine->undefinedValue(); - - QByteArray signal("2"); - signal.append(data->object->metaObject()->method(data->data.coreIndex).signature()); - - if (context->argumentCount() == 1) { - qScriptDisconnect(data->object, signal.constData(), QScriptValue(), context->argument(0)); - } else { - qScriptDisconnect(data->object, signal.constData(), context->argument(0), context->argument(1)); - } - - return engine->undefinedValue(); -} - -QScriptClass::QueryFlags -QDeclarativeObjectMethodScriptClass::queryProperty(Object *, const Identifier &name, - QScriptClass::QueryFlags flags) -{ - Q_UNUSED(flags); - if (name == m_connectId.identifier || name == m_disconnectId.identifier) - return QScriptClass::HandlesReadAccess; - else - return 0; - -} - -QDeclarativeObjectMethodScriptClass::Value -QDeclarativeObjectMethodScriptClass::property(Object *, const Identifier &name) -{ - QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); - - if (name == m_connectId.identifier) - return Value(scriptEngine, m_connect); - else if (name == m_disconnectId.identifier) - return Value(scriptEngine, m_disconnect); - else - return Value(); -} - -namespace { -struct MetaCallArgument { - inline MetaCallArgument(); - inline ~MetaCallArgument(); - inline void *dataPtr(); - - inline void initAsType(int type, QDeclarativeEngine *); - void fromScriptValue(int type, QDeclarativeEngine *, const QScriptValue &); - inline QScriptDeclarativeClass::Value toValue(QDeclarativeEngine *); - -private: - MetaCallArgument(const MetaCallArgument &); - - inline void cleanup(); - - char data[4 * sizeof(void *)]; - int type; - bool isObjectType; -}; -} - -MetaCallArgument::MetaCallArgument() -: type(QVariant::Invalid), isObjectType(false) -{ -} - -MetaCallArgument::~MetaCallArgument() -{ - cleanup(); -} - -void MetaCallArgument::cleanup() -{ - if (type == QMetaType::QString) { - ((QString *)&data)->~QString(); - } else if (type == -1 || type == qMetaTypeId<QVariant>()) { - ((QVariant *)&data)->~QVariant(); - } else if (type == qMetaTypeId<QScriptValue>()) { - ((QScriptValue *)&data)->~QScriptValue(); - } else if (type == qMetaTypeId<QList<QObject *> >()) { - ((QList<QObject *> *)&data)->~QList<QObject *>(); - } -} - -void *MetaCallArgument::dataPtr() -{ - if (type == -1) - return ((QVariant *)data)->data(); - else - return (void *)&data; -} - -void MetaCallArgument::initAsType(int callType, QDeclarativeEngine *e) -{ - if (type != 0) { cleanup(); type = 0; } - if (callType == 0) return; - - QScriptEngine *engine = QDeclarativeEnginePrivate::getScriptEngine(e); - - if (callType == qMetaTypeId<QScriptValue>()) { - new (&data) QScriptValue(engine->undefinedValue()); - type = callType; - } else if (callType == QMetaType::Int || - callType == QMetaType::UInt || - callType == QMetaType::Bool || - callType == QMetaType::Double || - callType == QMetaType::Float) { - type = callType; - } else if (callType == QMetaType::QObjectStar) { - *((QObject **)&data) = 0; - type = callType; - } else if (callType == QMetaType::QString) { - new (&data) QString(); - type = callType; - } else if (callType == qMetaTypeId<QVariant>()) { - type = callType; - new (&data) QVariant(); - } else if (callType == qMetaTypeId<QList<QObject *> >()) { - type = callType; - new (&data) QList<QObject *>(); - } else { - type = -1; - new (&data) QVariant(callType, (void *)0); - } -} - -void MetaCallArgument::fromScriptValue(int callType, QDeclarativeEngine *engine, const QScriptValue &value) -{ - if (type != 0) { cleanup(); type = 0; } - - if (callType == qMetaTypeId<QScriptValue>()) { - new (&data) QScriptValue(value); - type = qMetaTypeId<QScriptValue>(); - } else if (callType == QMetaType::Int) { - *((int *)&data) = int(value.toInt32()); - type = callType; - } else if (callType == QMetaType::UInt) { - *((uint *)&data) = uint(value.toUInt32()); - type = callType; - } else if (callType == QMetaType::Bool) { - *((bool *)&data) = value.toBool(); - type = callType; - } else if (callType == QMetaType::Double) { - *((double *)&data) = double(value.toNumber()); - type = callType; - } else if (callType == QMetaType::Float) { - *((float *)&data) = float(value.toNumber()); - type = callType; - } else if (callType == QMetaType::QString) { - if (value.isNull() || value.isUndefined()) - new (&data) QString(); - else - new (&data) QString(value.toString()); - type = callType; - } else if (callType == QMetaType::QObjectStar) { - *((QObject **)&data) = value.toQObject(); - type = callType; - } else if (callType == qMetaTypeId<QVariant>()) { - new (&data) QVariant(QDeclarativeEnginePrivate::get(engine)->scriptValueToVariant(value)); - type = callType; - } else if (callType == qMetaTypeId<QList<QObject*> >()) { - QList<QObject *> *list = new (&data) QList<QObject *>(); - if (value.isArray()) { - int length = value.property(QLatin1String("length")).toInt32(); - for (int ii = 0; ii < length; ++ii) { - QScriptValue arrayItem = value.property(ii); - QObject *d = arrayItem.toQObject(); - list->append(d); - } - } else if (QObject *d = value.toQObject()) { - list->append(d); - } - type = callType; - } else { - new (&data) QVariant(); - type = -1; - - QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(engine); - QVariant v = priv->scriptValueToVariant(value); - if (v.userType() == callType) { - *((QVariant *)&data) = v; - } else if (v.canConvert((QVariant::Type)callType)) { - *((QVariant *)&data) = v; - ((QVariant *)&data)->convert((QVariant::Type)callType); - } else if (const QMetaObject *mo = priv->rawMetaObjectForType(callType)) { - QObject *obj = priv->toQObject(v); - - if (obj) { - const QMetaObject *objMo = obj->metaObject(); - while (objMo && objMo != mo) objMo = objMo->superClass(); - if (!objMo) obj = 0; - } - - *((QVariant *)&data) = QVariant(callType, &obj); - } else { - *((QVariant *)&data) = QVariant(callType, (void *)0); - } - } -} - -QScriptDeclarativeClass::Value MetaCallArgument::toValue(QDeclarativeEngine *e) -{ - QScriptEngine *engine = QDeclarativeEnginePrivate::getScriptEngine(e); - - if (type == qMetaTypeId<QScriptValue>()) { - return QScriptDeclarativeClass::Value(engine, *((QScriptValue *)&data)); - } else if (type == QMetaType::Int) { - return QScriptDeclarativeClass::Value(engine, *((int *)&data)); - } else if (type == QMetaType::UInt) { - return QScriptDeclarativeClass::Value(engine, *((uint *)&data)); - } else if (type == QMetaType::Bool) { - return QScriptDeclarativeClass::Value(engine, *((bool *)&data)); - } else if (type == QMetaType::Double) { - return QScriptDeclarativeClass::Value(engine, *((double *)&data)); - } else if (type == QMetaType::Float) { - return QScriptDeclarativeClass::Value(engine, *((float *)&data)); - } else if (type == QMetaType::QString) { - return QScriptDeclarativeClass::Value(engine, *((QString *)&data)); - } else if (type == QMetaType::QObjectStar) { - QObject *object = *((QObject **)&data); - if (object) - QDeclarativeData::get(object, true)->setImplicitDestructible(); - QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(e); - return QScriptDeclarativeClass::Value(engine, priv->objectClass->newQObject(object)); - } else if (type == qMetaTypeId<QList<QObject *> >()) { - QList<QObject *> &list = *(QList<QObject *>*)&data; - QScriptValue rv = engine->newArray(list.count()); - QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(e); - for (int ii = 0; ii < list.count(); ++ii) { - QObject *object = list.at(ii); - QDeclarativeData::get(object, true)->setImplicitDestructible(); - rv.setProperty(ii, priv->objectClass->newQObject(object)); - } - return QScriptDeclarativeClass::Value(engine, rv); - } else if (type == -1 || type == qMetaTypeId<QVariant>()) { - QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(e); - QScriptValue rv = ep->scriptValueFromVariant(*((QVariant *)&data)); - if (rv.isQObject()) { - QObject *object = rv.toQObject(); - if (object) - QDeclarativeData::get(object, true)->setImplicitDestructible(); - } - return QScriptDeclarativeClass::Value(engine, rv); - } else { - return QScriptDeclarativeClass::Value(); - } -} - -int QDeclarativeObjectMethodScriptClass::enumType(const QMetaObject *meta, const QString &strname) -{ - QByteArray str = strname.toUtf8(); - QByteArray scope; - QByteArray name; - int scopeIdx = str.lastIndexOf("::"); - if (scopeIdx != -1) { - scope = str.left(scopeIdx); - name = str.mid(scopeIdx + 2); - } else { - name = str; - } - for (int i = meta->enumeratorCount() - 1; i >= 0; --i) { - QMetaEnum m = meta->enumerator(i); - if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope))) - return QVariant::Int; - } - return QVariant::Invalid; -} - -QDeclarativeObjectMethodScriptClass::Value QDeclarativeObjectMethodScriptClass::call(Object *o, QScriptContext *ctxt) -{ - MethodData *method = static_cast<MethodData *>(o); - - if (method->data.relatedIndex == -1) - return callPrecise(method->object, method->data, ctxt); - else - return callOverloaded(method, ctxt); -} - -QDeclarativeObjectMethodScriptClass::Value -QDeclarativeObjectMethodScriptClass::callPrecise(QObject *object, const QDeclarativePropertyCache::Data &data, - QScriptContext *ctxt) -{ - if (data.flags & QDeclarativePropertyCache::Data::HasArguments) { - - QMetaMethod m = object->metaObject()->method(data.coreIndex); - QList<QByteArray> argTypeNames = m.parameterTypes(); - QVarLengthArray<int, 9> argTypes(argTypeNames.count()); - - // ### Cache - for (int ii = 0; ii < argTypeNames.count(); ++ii) { - argTypes[ii] = QMetaType::type(argTypeNames.at(ii)); - if (argTypes[ii] == QVariant::Invalid) - argTypes[ii] = enumType(object->metaObject(), QString::fromLatin1(argTypeNames.at(ii))); - if (argTypes[ii] == QVariant::Invalid) - return Value(ctxt, ctxt->throwError(QString::fromLatin1("Unknown method parameter type: %1").arg(QLatin1String(argTypeNames.at(ii))))); - } - - if (argTypes.count() > ctxt->argumentCount()) - return Value(ctxt, ctxt->throwError(QLatin1String("Insufficient arguments"))); - - return callMethod(object, data.coreIndex, data.propType, argTypes.count(), argTypes.data(), ctxt); - - } else { - - return callMethod(object, data.coreIndex, data.propType, 0, 0, ctxt); - - } -} - -QDeclarativeObjectMethodScriptClass::Value -QDeclarativeObjectMethodScriptClass::callMethod(QObject *object, int index, - int returnType, int argCount, int *argTypes, - QScriptContext *ctxt) -{ - if (argCount > 0) { - - QVarLengthArray<MetaCallArgument, 9> args(argCount + 1); - args[0].initAsType(returnType, engine); - - for (int ii = 0; ii < argCount; ++ii) - args[ii + 1].fromScriptValue(argTypes[ii], engine, ctxt->argument(ii)); - - QVarLengthArray<void *, 9> argData(args.count()); - for (int ii = 0; ii < args.count(); ++ii) - argData[ii] = args[ii].dataPtr(); - - QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, argData.data()); - - return args[0].toValue(engine); - - } else if (returnType != 0) { - - MetaCallArgument arg; - arg.initAsType(returnType, engine); - - void *args[] = { arg.dataPtr() }; - - QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, args); - - return arg.toValue(engine); - - } else { - - void *args[] = { 0 }; - QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, args); - return Value(); - - } -} - -/*! -Resolve the overloaded method to call. The algorithm works conceptually like this: - 1. Resolve the set of overloads it is *possible* to call. - Impossible overloads include those that have too many parameters or have parameters - of unknown type. - 2. Filter the set of overloads to only contain those with the closest number of - parameters. - For example, if we are called with 3 parameters and there are 2 overloads that - take 2 parameters and one that takes 3, eliminate the 2 parameter overloads. - 3. Find the best remaining overload based on its match score. - If two or more overloads have the same match score, call the last one. The match - score is constructed by adding the matchScore() result for each of the parameters. -*/ -QDeclarativeObjectMethodScriptClass::Value -QDeclarativeObjectMethodScriptClass::callOverloaded(MethodData *method, QScriptContext *ctxt) -{ - int argumentCount = ctxt->argumentCount(); - - QDeclarativePropertyCache::Data *best = 0; - int bestParameterScore = INT_MAX; - int bestMatchScore = INT_MAX; - - QDeclarativePropertyCache::Data dummy; - QDeclarativePropertyCache::Data *attempt = &method->data; - - do { - QList<QByteArray> methodArgTypeNames; - - if (attempt->flags & QDeclarativePropertyCache::Data::HasArguments) - methodArgTypeNames = method->object->metaObject()->method(attempt->coreIndex).parameterTypes(); - - int methodArgumentCount = methodArgTypeNames.count(); - - if (methodArgumentCount > argumentCount) - continue; // We don't have sufficient arguments to call this method - - int methodParameterScore = argumentCount - methodArgumentCount; - if (methodParameterScore > bestParameterScore) - continue; // We already have a better option - - int methodMatchScore = 0; - QVarLengthArray<int, 9> methodArgTypes(methodArgumentCount); - - bool unknownArgument = false; - for (int ii = 0; ii < methodArgumentCount; ++ii) { - methodArgTypes[ii] = QMetaType::type(methodArgTypeNames.at(ii)); - if (methodArgTypes[ii] == QVariant::Invalid) - methodArgTypes[ii] = enumType(method->object->metaObject(), - QString::fromLatin1(methodArgTypeNames.at(ii))); - if (methodArgTypes[ii] == QVariant::Invalid) { - unknownArgument = true; - break; - } - methodMatchScore += matchScore(ctxt->argument(ii), methodArgTypes[ii], methodArgTypeNames.at(ii)); - } - if (unknownArgument) - continue; // We don't understand all the parameters - - if (bestParameterScore > methodParameterScore || bestMatchScore > methodMatchScore) { - best = attempt; - bestParameterScore = methodParameterScore; - bestMatchScore = methodMatchScore; - } - - if (bestParameterScore == 0 && bestMatchScore == 0) - break; // We can't get better than that - - } while((attempt = relatedMethod(method->object, attempt, dummy)) != 0); - - if (best) { - return callPrecise(method->object, *best, ctxt); - } else { - QString error = QLatin1String("Unable to determine callable overload. Candidates are:"); - QDeclarativePropertyCache::Data *candidate = &method->data; - while (candidate) { - error += QLatin1String("\n ") + QString::fromUtf8(method->object->metaObject()->method(candidate->coreIndex).signature()); - candidate = relatedMethod(method->object, candidate, dummy); - } - return Value(ctxt, ctxt->throwError(error)); - } -} - -/*! - Returns the match score for converting \a actual to be of type \a conversionType. A - zero score means "perfect match" whereas a higher score is worse. - - The conversion table is copied out of the QtScript callQtMethod() function. -*/ -int QDeclarativeObjectMethodScriptClass::matchScore(const QScriptValue &actual, int conversionType, - const QByteArray &conversionTypeName) -{ - if (actual.isNumber()) { - switch (conversionType) { - case QMetaType::Double: - return 0; - case QMetaType::Float: - return 1; - case QMetaType::LongLong: - case QMetaType::ULongLong: - return 2; - case QMetaType::Long: - case QMetaType::ULong: - return 3; - case QMetaType::Int: - case QMetaType::UInt: - return 4; - case QMetaType::Short: - case QMetaType::UShort: - return 5; - break; - case QMetaType::Char: - case QMetaType::UChar: - return 6; - default: - return 10; - } - } else if (actual.isString()) { - switch (conversionType) { - case QMetaType::QString: - return 0; - default: - return 10; - } - } else if (actual.isBoolean()) { - switch (conversionType) { - case QMetaType::Bool: - return 0; - default: - return 10; - } - } else if (actual.isDate()) { - switch (conversionType) { - case QMetaType::QDateTime: - return 0; - case QMetaType::QDate: - return 1; - case QMetaType::QTime: - return 2; - default: - return 10; - } - } else if (actual.isRegExp()) { - switch (conversionType) { - case QMetaType::QRegExp: - return 0; - default: - return 10; - } - } else if (actual.isVariant()) { - if (conversionType == qMetaTypeId<QVariant>()) - return 0; - else if (actual.toVariant().userType() == conversionType) - return 0; - else - return 10; - } else if (actual.isArray()) { - switch (conversionType) { - case QMetaType::QStringList: - case QMetaType::QVariantList: - return 5; - default: - return 10; - } - } else if (actual.isQObject()) { - switch (conversionType) { - case QMetaType::QObjectStar: - return 0; - default: - return 10; - } - } else if (actual.isNull()) { - switch (conversionType) { - case QMetaType::VoidStar: - case QMetaType::QObjectStar: - return 0; - default: - if (!conversionTypeName.endsWith('*')) - return 10; - else - return 0; - } - } else { - return 10; - } -} - -static inline int QMetaObject_methods(const QMetaObject *metaObject) -{ - struct Private - { - int revision; - int className; - int classInfoCount, classInfoData; - int methodCount, methodData; - }; - - return reinterpret_cast<const Private *>(metaObject->d.data)->methodCount; -} - -static QByteArray QMetaMethod_name(const QMetaMethod &m) -{ - QByteArray sig = m.signature(); - int paren = sig.indexOf('('); - if (paren == -1) - return sig; - else - return sig.left(paren); -} - -/*! -Returns the next related method, if one, or 0. -*/ -QDeclarativePropertyCache::Data * -QDeclarativeObjectMethodScriptClass::relatedMethod(QObject *object, QDeclarativePropertyCache::Data *current, - QDeclarativePropertyCache::Data &dummy) -{ - QDeclarativePropertyCache *cache = QDeclarativeData::get(object)->propertyCache; - if (current->relatedIndex == -1) - return 0; - - if (cache) { - return cache->method(current->relatedIndex); - } else { - const QMetaObject *mo = object->metaObject(); - int methodOffset = mo->methodCount() - QMetaObject_methods(mo); - - while (methodOffset > current->relatedIndex) { - mo = mo->superClass(); - methodOffset -= QMetaObject_methods(mo); - } - - QMetaMethod method = mo->method(current->relatedIndex); - dummy.load(method); - - // Look for overloaded methods - QByteArray methodName = QMetaMethod_name(method); - for (int ii = current->relatedIndex - 1; ii >= methodOffset; --ii) { - if (methodName == QMetaMethod_name(mo->method(ii))) { - dummy.relatedIndex = ii; - return &dummy; - } - } - - return &dummy; - } -} - -QT_END_NAMESPACE - |