diff options
Diffstat (limited to 'src/script/qscriptextqobject.cpp')
-rw-r--r-- | src/script/qscriptextqobject.cpp | 2244 |
1 files changed, 0 insertions, 2244 deletions
diff --git a/src/script/qscriptextqobject.cpp b/src/script/qscriptextqobject.cpp deleted file mode 100644 index 8746cc1ab2..0000000000 --- a/src/script/qscriptextqobject.cpp +++ /dev/null @@ -1,2244 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtScript 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 either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** 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.0, 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. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://qt.nokia.com/contact. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QtCore/qglobal.h> - -#ifndef QT_NO_SCRIPT - -#include "qscriptengine_p.h" -#include "qscriptvalueimpl_p.h" -#include "qscriptcontext_p.h" -#include "qscriptmember_p.h" -#include "qscriptobject_p.h" -#include "qscriptable.h" -#include "qscriptable_p.h" -#include "qscriptextqobject_p.h" - -#include <QtCore/QtDebug> -#include <QtCore/QMetaMethod> -#include <QtCore/QRegExp> -#include <QtCore/QVarLengthArray> -#include <QtCore/QPointer> - -QT_BEGIN_NAMESPACE - -// we use bits 15..12 of property flags -enum { - PROPERTY_ID = 0 << 12, - DYNAPROPERTY_ID = 1 << 12, - METHOD_ID = 2 << 12, - CHILD_ID = 3 << 12, - ID_MASK = 7 << 12, - MAYBE_OVERLOADED = 8 << 12 -}; - -static const bool GeneratePropertyFunctions = true; - -int QScriptMetaType::typeId() const -{ - if (isVariant()) - return QMetaType::type("QVariant"); - return isMetaEnum() ? 2/*int*/ : m_typeId; -} - -QByteArray QScriptMetaType::name() const -{ - if (!m_name.isEmpty()) - return m_name; - else if (m_kind == Variant) - return "QVariant"; - return QMetaType::typeName(typeId()); -} - -namespace QScript { - -class QObjectNotifyCaller : public QObject -{ -public: - void callConnectNotify(const char *signal) - { connectNotify(signal); } - void callDisconnectNotify(const char *signal) - { disconnectNotify(signal); } -}; - -class QtPropertyFunction: public QScriptFunction -{ -public: - QtPropertyFunction(const QMetaObject *meta, int index) - : m_meta(meta), m_index(index) - { } - - ~QtPropertyFunction() { } - - virtual void execute(QScriptContextPrivate *context); - - virtual Type type() const { return QScriptFunction::QtProperty; } - - virtual QString functionName() const; - -private: - const QMetaObject *m_meta; - int m_index; -}; - -class QObjectPrototype : public QObject -{ - Q_OBJECT -public: - QObjectPrototype(QObject *parent = 0) - : QObject(parent) { } - ~QObjectPrototype() { } -}; - -static inline QByteArray methodName(const QMetaMethod &method) -{ - QByteArray signature = method.signature(); - return signature.left(signature.indexOf('(')); -} - -static inline QVariant variantFromValue(QScriptEnginePrivate *eng, - int targetType, const QScriptValueImpl &value) -{ - QVariant v(targetType, (void *)0); - Q_ASSERT(eng); - if (QScriptEnginePrivate::convert(value, targetType, v.data(), eng)) - return v; - if (uint(targetType) == QVariant::LastType) - return value.toVariant(); - if (value.isVariant()) { - v = value.toVariant(); - if (v.canConvert(QVariant::Type(targetType))) { - v.convert(QVariant::Type(targetType)); - return v; - } - QByteArray typeName = v.typeName(); - if (typeName.endsWith('*') - && (QMetaType::type(typeName.left(typeName.size()-1)) == targetType)) { - return QVariant(targetType, *reinterpret_cast<void* *>(v.data())); - } - } - - return QVariant(); -} - -void ExtQObject::Instance::finalize(QScriptEnginePrivate *eng) -{ - switch (ownership) { - case QScriptEngine::QtOwnership: - break; - case QScriptEngine::ScriptOwnership: - if (value) - eng->disposeQObject(value); - break; - case QScriptEngine::AutoOwnership: - if (value && !value->parent()) - eng->disposeQObject(value); - break; - } -} - -ExtQObject::Instance *ExtQObject::Instance::get(const QScriptValueImpl &object, QScriptClassInfo *klass) -{ - if (! klass || klass == object.classInfo()) - return static_cast<Instance*> (object.objectData()); - - return 0; -} - - -static inline QScriptable *scriptableFromQObject(QObject *qobj) -{ - void *ptr = qobj->qt_metacast("QScriptable"); - return reinterpret_cast<QScriptable*>(ptr); -} - -static bool isObjectProperty(const QScriptValueImpl &object, const char *name) -{ - QScriptEnginePrivate *eng = object.engine(); - QScriptNameIdImpl *nameId = eng->nameId(QLatin1String(name)); - QScript::Member member; - QScriptValueImpl base; - return object.resolve(nameId, &member, &base, QScriptValue::ResolveLocal, QScript::Read) - && member.testFlags(QScript::Member::ObjectProperty); -} - -static bool hasMethodAccess(const QMetaMethod &method, int index, const QScriptEngine::QObjectWrapOptions &opt) -{ - return (method.access() != QMetaMethod::Private) - && ((index != 2) || !(opt & QScriptEngine::ExcludeDeleteLater)); -} - -static bool isEnumerableMetaProperty(const QMetaProperty &prop, - const QMetaObject *mo, int index) -{ - return prop.isScriptable() && prop.isValid() - // the following lookup is to ensure that we have the - // "most derived" occurrence of the property with this name - && (mo->indexOfProperty(prop.name()) == index); -} - -static uint flagsForMetaProperty(const QMetaProperty &prop) -{ - return (QScriptValue::Undeletable - | (!prop.isWritable() - ? QScriptValue::ReadOnly - : QScriptValue::PropertyFlag(0)) - | (GeneratePropertyFunctions - ? (QScriptValue::PropertyGetter - | QScriptValue::PropertySetter) - : QScriptValue::PropertyFlag(0)) - | QScriptValue::QObjectMember - | PROPERTY_ID); -} - - -static int indexOfMetaEnum(const QMetaObject *meta, const QByteArray &str) -{ - 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 i; - } - return -1; -} - -static QMetaMethod metaMethod(const QMetaObject *meta, - QMetaMethod::MethodType type, - int index) -{ - if (type != QMetaMethod::Constructor) - return meta->method(index); - else - return meta->constructor(index); -} - -static void callQtMethod(QScriptContextPrivate *context, QMetaMethod::MethodType callType, - QObject *thisQObject, const QMetaObject *meta, int initialIndex, - bool maybeOverloaded) -{ - QScriptValueImpl result; - QScriptEnginePrivate *engine = context->engine(); - - int limit; -#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE - int lastFoundIndex = initialIndex; - QScriptMetaObject *metaCache = engine->cachedMetaObject(meta); - if (callType != QMetaMethod::Constructor) - limit = metaCache->methodLowerBound(initialIndex); - else - limit = 0; -#else - limit = 0; -#endif - - QByteArray funName; - QScriptMetaMethod chosenMethod; - int chosenIndex = -1; - QVarLengthArray<QVariant, 9> args; - QVector<QScriptMetaArguments> candidates; - QVector<QScriptMetaArguments> unresolved; - QVector<int> tooFewArgs; - QVector<int> conversionFailed; - int index; - for (index = initialIndex; index >= limit; --index) { - QScriptMetaMethod mtd; -#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE - if (callType != QMetaMethod::Constructor) - mtd = metaCache->findMethod(index); - if (!mtd.isValid()) -#endif - { - QMetaMethod method = metaMethod(meta, callType, index); - - QVector<QScriptMetaType> types; - // resolve return type - QByteArray returnTypeName = method.typeName(); - int rtype = QMetaType::type(returnTypeName); - if ((rtype == 0) && !returnTypeName.isEmpty()) { - if (returnTypeName == "QVariant") { - types.append(QScriptMetaType::variant()); - } else { - int enumIndex = indexOfMetaEnum(meta, returnTypeName); - if (enumIndex != -1) - types.append(QScriptMetaType::metaEnum(enumIndex, returnTypeName)); - else - types.append(QScriptMetaType::unresolved(returnTypeName)); - } - } else { - if (callType == QMetaMethod::Constructor) - types.append(QScriptMetaType::metaType(QMetaType::QObjectStar, "QObject*")); - else if (returnTypeName == "QVariant") - types.append(QScriptMetaType::variant()); - else - types.append(QScriptMetaType::metaType(rtype, returnTypeName)); - } - // resolve argument types - QList<QByteArray> parameterTypeNames = method.parameterTypes(); - for (int i = 0; i < parameterTypeNames.count(); ++i) { - QByteArray argTypeName = parameterTypeNames.at(i); - int atype = QMetaType::type(argTypeName); - if (atype == 0) { - if (argTypeName == "QVariant") { - types.append(QScriptMetaType::variant()); - } else { - int enumIndex = indexOfMetaEnum(meta, argTypeName); - if (enumIndex != -1) - types.append(QScriptMetaType::metaEnum(enumIndex, argTypeName)); - else - types.append(QScriptMetaType::unresolved(argTypeName)); - } - } else { - if (argTypeName == "QVariant") - types.append(QScriptMetaType::variant()); - else - types.append(QScriptMetaType::metaType(atype, argTypeName)); - } - } - - mtd = QScriptMetaMethod(methodName(method), types); - -#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE - if (mtd.fullyResolved() && (callType != QMetaMethod::Constructor)) - metaCache->registerMethod(index, mtd); -#endif - } - - if (index == initialIndex) - funName = mtd.name(); - else { - if (mtd.name() != funName) - continue; -#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE - lastFoundIndex = index; -#endif - } - - if (context->argumentCount() < mtd.argumentCount()) { - tooFewArgs.append(index); - continue; - } - - if (!mtd.fullyResolved()) { - // remember it so we can give an error message later, if necessary - unresolved.append(QScriptMetaArguments(/*matchDistance=*/INT_MAX, index, - mtd, QVarLengthArray<QVariant, 9>())); - if (mtd.hasUnresolvedReturnType()) - continue; - } - - if (args.count() != mtd.count()) - args.resize(mtd.count()); - - QScriptMetaType retType = mtd.returnType(); - args[0] = QVariant(retType.typeId(), (void *)0); // the result - - // try to convert arguments - bool converted = true; - int matchDistance = 0; - for (int i = 0; converted && i < mtd.argumentCount(); ++i) { - QScriptValueImpl actual = context->argument(i); - QScriptMetaType argType = mtd.argumentType(i); - int tid = -1; - QVariant v; - if (argType.isUnresolved()) { - v = QVariant(QMetaType::QObjectStar, (void *)0); - converted = engine->convertToNativeQObject( - actual, argType.name(), reinterpret_cast<void* *>(v.data())); - } else if (argType.isVariant()) { - if (actual.isVariant()) { - v = actual.variantValue(); - } else { - v = actual.toVariant(); - converted = v.isValid() || actual.isUndefined() || actual.isNull(); - } - } else { - tid = argType.typeId(); - v = QVariant(tid, (void *)0); - converted = QScriptEnginePrivate::convert(actual, tid, v.data(), engine); - if (engine->hasUncaughtException()) - return; - } - - if (!converted) { - if (actual.isVariant()) { - if (tid == -1) - tid = argType.typeId(); - QVariant &vv = actual.variantValue(); - if (vv.canConvert(QVariant::Type(tid))) { - v = vv; - converted = v.convert(QVariant::Type(tid)); - if (converted && (vv.userType() != tid)) - matchDistance += 10; - } else { - QByteArray vvTypeName = vv.typeName(); - if (vvTypeName.endsWith('*') - && (vvTypeName.left(vvTypeName.size()-1) == argType.name())) { - v = QVariant(tid, *reinterpret_cast<void* *>(vv.data())); - converted = true; - matchDistance += 10; - } - } - } else if (actual.isNumber() || actual.isString()) { - // see if it's an enum value - QMetaEnum m; - if (argType.isMetaEnum()) { - m = meta->enumerator(argType.enumeratorIndex()); - } else { - int mi = indexOfMetaEnum(meta, argType.name()); - if (mi != -1) - m = meta->enumerator(mi); - } - if (m.isValid()) { - if (actual.isNumber()) { - int ival = actual.toInt32(); - if (m.valueToKey(ival) != 0) { - qVariantSetValue(v, ival); - converted = true; - matchDistance += 10; - } - } else { - QString sval = actual.toString(); - int ival = m.keyToValue(sval.toLatin1()); - if (ival != -1) { - qVariantSetValue(v, ival); - converted = true; - matchDistance += 10; - } - } - } - } - } else { - // determine how well the conversion matched - if (actual.isNumber()) { - switch (tid) { - case QMetaType::Double: - // perfect - break; - case QMetaType::Float: - matchDistance += 1; - break; - case QMetaType::LongLong: - case QMetaType::ULongLong: - matchDistance += 2; - break; - case QMetaType::Long: - case QMetaType::ULong: - matchDistance += 3; - break; - case QMetaType::Int: - case QMetaType::UInt: - matchDistance += 4; - break; - case QMetaType::Short: - case QMetaType::UShort: - matchDistance += 5; - break; - case QMetaType::Char: - case QMetaType::UChar: - matchDistance += 6; - break; - default: - matchDistance += 10; - break; - } - } else if (actual.isString()) { - switch (tid) { - case QMetaType::QString: - // perfect - break; - default: - matchDistance += 10; - break; - } - } else if (actual.isBoolean()) { - switch (tid) { - case QMetaType::Bool: - // perfect - break; - default: - matchDistance += 10; - break; - } - } else if (actual.isDate()) { - switch (tid) { - case QMetaType::QDateTime: - // perfect - break; - case QMetaType::QDate: - matchDistance += 1; - break; - case QMetaType::QTime: - matchDistance += 2; - break; - default: - matchDistance += 10; - break; - } - } else if (actual.isRegExp()) { - switch (tid) { - case QMetaType::QRegExp: - // perfect - break; - default: - matchDistance += 10; - break; - } - } else if (actual.isVariant()) { - if (argType.isVariant() - || (actual.variantValue().userType() == tid)) { - // perfect - } else { - matchDistance += 10; - } - } else if (actual.isArray()) { - switch (tid) { - case QMetaType::QStringList: - case QMetaType::QVariantList: - matchDistance += 5; - break; - default: - matchDistance += 10; - break; - } - } else if (actual.isQObject()) { - switch (tid) { - case QMetaType::QObjectStar: - case QMetaType::QWidgetStar: - // perfect - break; - default: - matchDistance += 10; - break; - } - } else if (actual.isNull()) { - switch (tid) { - case QMetaType::VoidStar: - case QMetaType::QObjectStar: - case QMetaType::QWidgetStar: - // perfect - break; - default: - if (!argType.name().endsWith('*')) - matchDistance += 10; - break; - } - } else { - matchDistance += 10; - } - } - - if (converted) - args[i+1] = v; - } - - if (converted) { - if ((context->argumentCount() == mtd.argumentCount()) - && (matchDistance == 0)) { - // perfect match, use this one - chosenMethod = mtd; - chosenIndex = index; - break; - } else { - bool redundant = false; - if ((callType != QMetaMethod::Constructor) - && (index < meta->methodOffset())) { - // it is possible that a virtual method is redeclared in a subclass, - // in which case we want to ignore the superclass declaration - for (int i = 0; i < candidates.size(); ++i) { - const QScriptMetaArguments &other = candidates.at(i); - if (mtd.types() == other.method.types()) { - redundant = true; - break; - } - } - } - if (!redundant) { - QScriptMetaArguments metaArgs(matchDistance, index, mtd, args); - if (candidates.isEmpty()) { - candidates.append(metaArgs); - } else { - const QScriptMetaArguments &otherArgs = candidates.at(0); - if ((args.count() > otherArgs.args.count()) - || ((args.count() == otherArgs.args.count()) - && (matchDistance <= otherArgs.matchDistance))) { - candidates.prepend(metaArgs); - } else { - candidates.append(metaArgs); - } - } - } - } - } else if (mtd.fullyResolved()) { - conversionFailed.append(index); - } - - if (!maybeOverloaded) - break; - } - -#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE - if ((index == -1) && (lastFoundIndex != limit) && maybeOverloaded - && (callType != QMetaMethod::Constructor)) { - metaCache->setMethodLowerBound(initialIndex, lastFoundIndex); - } -#endif - - if ((chosenIndex == -1) && candidates.isEmpty()) { - context->calleeMetaIndex = initialIndex; -#ifndef Q_SCRIPT_NO_EVENT_NOTIFY - engine->notifyFunctionEntry(context); -#endif - if (!conversionFailed.isEmpty()) { - QString message = QString::fromLatin1("incompatible type of argument(s) in call to %0(); candidates were\n") - .arg(QLatin1String(funName)); - for (int i = 0; i < conversionFailed.size(); ++i) { - if (i > 0) - message += QLatin1String("\n"); - QMetaMethod mtd = metaMethod(meta, callType, conversionFailed.at(i)); - message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature())); - } - result = context->throwError(QScriptContext::TypeError, message); - } else if (!unresolved.isEmpty()) { - QScriptMetaArguments argsInstance = unresolved.first(); - int unresolvedIndex = argsInstance.method.firstUnresolvedIndex(); - Q_ASSERT(unresolvedIndex != -1); - QScriptMetaType unresolvedType = argsInstance.method.type(unresolvedIndex); - QString unresolvedTypeName = QString::fromLatin1(unresolvedType.name()); - QString message = QString::fromLatin1("cannot call %0(): ") - .arg(QString::fromLatin1(funName)); - if (unresolvedIndex > 0) { - message.append(QString::fromLatin1("argument %0 has unknown type `%1'"). - arg(unresolvedIndex).arg(unresolvedTypeName)); - } else { - message.append(QString::fromLatin1("unknown return type `%0'") - .arg(unresolvedTypeName)); - } - message.append(QString::fromLatin1(" (register the type with qScriptRegisterMetaType())")); - result = context->throwError(QScriptContext::TypeError, message); - } else { - QString message = QString::fromLatin1("too few arguments in call to %0(); candidates are\n") - .arg(QLatin1String(funName)); - for (int i = 0; i < tooFewArgs.size(); ++i) { - if (i > 0) - message += QLatin1String("\n"); - QMetaMethod mtd = metaMethod(meta, callType, tooFewArgs.at(i)); - message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature())); - } - result = context->throwError(QScriptContext::SyntaxError, message); - } - } else { - if (chosenIndex == -1) { - QScriptMetaArguments metaArgs = candidates.at(0); - if ((candidates.size() > 1) - && (metaArgs.args.count() == candidates.at(1).args.count()) - && (metaArgs.matchDistance == candidates.at(1).matchDistance)) { - // ambiguous call - QString message = QString::fromLatin1("ambiguous call of overloaded function %0(); candidates were\n") - .arg(QLatin1String(funName)); - for (int i = 0; i < candidates.size(); ++i) { - if (i > 0) - message += QLatin1String("\n"); - QMetaMethod mtd = metaMethod(meta, callType, candidates.at(i).index); - message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature())); - } - result = context->throwError(QScriptContext::TypeError, message); - } else { - chosenMethod = metaArgs.method; - chosenIndex = metaArgs.index; - args = metaArgs.args; - } - } - - if (chosenIndex != -1) { - // call it - context->calleeMetaIndex = chosenIndex; - - QVarLengthArray<void*, 9> array(args.count()); - void **params = array.data(); - for (int i = 0; i < args.count(); ++i) { - const QVariant &v = args[i]; - switch (chosenMethod.type(i).kind()) { - case QScriptMetaType::Variant: - params[i] = const_cast<QVariant*>(&v); - break; - case QScriptMetaType::MetaType: - case QScriptMetaType::MetaEnum: - case QScriptMetaType::Unresolved: - params[i] = const_cast<void*>(v.constData()); - break; - default: - Q_ASSERT(0); - } - } - - QScriptable *scriptable = 0; - if (thisQObject) - scriptable = scriptableFromQObject(thisQObject); - QScriptEngine *oldEngine = 0; - if (scriptable) { - oldEngine = QScriptablePrivate::get(scriptable)->engine; - QScriptablePrivate::get(scriptable)->engine = QScriptEnginePrivate::get(engine); - } - -#ifndef Q_SCRIPT_NO_EVENT_NOTIFY - engine->notifyFunctionEntry(context); -#endif - - if (callType == QMetaMethod::Constructor) { - Q_ASSERT(meta != 0); - meta->static_metacall(QMetaObject::CreateInstance, chosenIndex, params); - } else { - Q_ASSERT(thisQObject != 0); - QMetaObject::metacall(thisQObject, QMetaObject::InvokeMetaMethod, chosenIndex, params); - } - - if (scriptable) - QScriptablePrivate::get(scriptable)->engine = oldEngine; - - if (context->state() == QScriptContext::ExceptionState) { - result = context->returnValue(); // propagate - } else { - QScriptMetaType retType = chosenMethod.returnType(); - if (retType.isVariant()) { - result = engine->valueFromVariant(*(QVariant *)params[0]); - } else if (retType.typeId() != 0) { - result = engine->create(retType.typeId(), params[0]); - if (!result.isValid()) - engine->newVariant(&result, QVariant(retType.typeId(), params[0])); - } else { - result = engine->undefinedValue(); - } - } - } - } - - context->m_result = result; -#ifndef Q_SCRIPT_NO_EVENT_NOTIFY - engine->notifyFunctionExit(context); -#endif -} - - -class ExtQObjectDataIterator: public QScriptClassDataIterator -{ -public: - ExtQObjectDataIterator(const QScriptValueImpl &object); - virtual ~ExtQObjectDataIterator(); - - virtual bool hasNext() const; - virtual void next(QScript::Member *member); - - virtual bool hasPrevious() const; - virtual void previous(QScript::Member *member); - - virtual void toFront(); - virtual void toBack(); - -private: - enum State { - MetaProperties, - DynamicProperties, - MetaMethods - }; - - QScriptValueImpl m_object; - int m_index; - State m_state; -}; - -ExtQObjectDataIterator::ExtQObjectDataIterator(const QScriptValueImpl &object) -{ - m_object = object; - toFront(); -} - -ExtQObjectDataIterator::~ExtQObjectDataIterator() -{ -} - -bool ExtQObjectDataIterator::hasNext() const -{ - ExtQObject::Instance *inst = ExtQObject::Instance::get(m_object); - if (!inst->value) - return false; - const QMetaObject *meta = inst->value->metaObject(); - int i = m_index; - - switch (m_state) { - case MetaProperties: { - for ( ; i < meta->propertyCount(); ++i) { - QMetaProperty prop = meta->property(i); - if (isEnumerableMetaProperty(prop, meta, i) - && !isObjectProperty(m_object, prop.name())) { - return true; - } - } - i = 0; - // fall-through - } - - case DynamicProperties: { - QList<QByteArray> dpNames = inst->value->dynamicPropertyNames(); - for ( ; i < dpNames.count(); ++i) { - if (!isObjectProperty(m_object, dpNames.at(i))) { - return true; - } - } - if (inst->options & QScriptEngine::SkipMethodsInEnumeration) - return false; - i = (inst->options & QScriptEngine::ExcludeSuperClassMethods) - ? meta->methodOffset() : 0; - // fall-through - } - - case MetaMethods: { - for ( ; i < meta->methodCount(); ++i) { - QMetaMethod method = meta->method(i); - if (hasMethodAccess(method, i, inst->options) - && !isObjectProperty(m_object, method.signature())) { - return true; - } - } - } - - } // switch - - return false; -} - -void ExtQObjectDataIterator::next(QScript::Member *member) -{ - QScriptEnginePrivate *eng = m_object.engine(); - ExtQObject::Instance *inst = ExtQObject::Instance::get(m_object); - if (!inst->value) - return; - const QMetaObject *meta = inst->value->metaObject(); - int i = m_index; - - switch (m_state) { - case MetaProperties: { - for ( ; i < meta->propertyCount(); ++i) { - QMetaProperty prop = meta->property(i); - if (isEnumerableMetaProperty(prop, meta, i) - && !isObjectProperty(m_object, prop.name())) { - QScriptNameIdImpl *nameId = eng->nameId(QLatin1String(prop.name())); - member->native(nameId, i, flagsForMetaProperty(prop)); - m_index = i + 1; - return; - } - } - m_state = DynamicProperties; - m_index = 0; - i = m_index; - // fall-through - } - - case DynamicProperties: { - QList<QByteArray> dpNames = inst->value->dynamicPropertyNames(); - for ( ; i < dpNames.count(); ++i) { - if (!isObjectProperty(m_object, dpNames.at(i))) { - QByteArray name = dpNames.at(i); - QScriptNameIdImpl *nameId = eng->nameId(QLatin1String(name)); - member->native(nameId, i, - QScriptValue::QObjectMember - | DYNAPROPERTY_ID); - m_index = i + 1; - return; - } - } - m_state = MetaMethods; - m_index = (inst->options & QScriptEngine::ExcludeSuperClassMethods) - ? meta->methodOffset() : 0; - i = m_index; - // fall-through - } - - case MetaMethods: { - for ( ; i < meta->methodCount(); ++i) { - QMetaMethod method = meta->method(i); - if (hasMethodAccess(method, i, inst->options) - && !isObjectProperty(m_object, method.signature())) { - QMetaMethod method = meta->method(i); - QScriptNameIdImpl *nameId = eng->nameId(QLatin1String(method.signature())); - member->native(nameId, i, - QScriptValue::QObjectMember - | METHOD_ID); - m_index = i + 1; - return; - } - } - } - - } // switch - - member->invalidate(); -} - -bool ExtQObjectDataIterator::hasPrevious() const -{ - ExtQObject::Instance *inst = ExtQObject::Instance::get(m_object); - if (!inst->value) - return false; - const QMetaObject *meta = inst->value->metaObject(); - int i = m_index - 1; - - switch (m_state) { - case MetaMethods: { - int limit = (inst->options & QScriptEngine::ExcludeSuperClassMethods) - ? meta->methodOffset() : 0; - for ( ; i >= limit; --i) { - QMetaMethod method = meta->method(i); - if (hasMethodAccess(method, i, inst->options) - && !isObjectProperty(m_object, method.signature())) { - return true; - } - } - i = inst->value->dynamicPropertyNames().count() - 1; - // fall-through - } - - case DynamicProperties: { - QList<QByteArray> dpNames = inst->value->dynamicPropertyNames(); - for ( ; i >= 0; --i) { - if (!isObjectProperty(m_object, dpNames.at(i))) { - return true; - } - } - i = meta->propertyCount() - 1; - // fall-through - } - - case MetaProperties: { - int limit = (inst->options & QScriptEngine::ExcludeSuperClassProperties) - ? meta->propertyOffset() : 0; - for ( ; i >= limit; --i) { - QMetaProperty prop = meta->property(i); - if (isEnumerableMetaProperty(prop, meta, i) - && !isObjectProperty(m_object, prop.name())) { - return true; - } - } - } - - } // switch - - return false; -} - -void ExtQObjectDataIterator::previous(QScript::Member *member) -{ - QScriptEnginePrivate *eng = m_object.engine(); - ExtQObject::Instance *inst = ExtQObject::Instance::get(m_object); - if (!inst->value) - return; - const QMetaObject *meta = inst->value->metaObject(); - int i = m_index - 1; - - switch (m_state) { - case MetaMethods: { - int limit = (inst->options & QScriptEngine::ExcludeSuperClassMethods) - ? meta->methodOffset() : 0; - for ( ; i >= limit; --i) { - QMetaMethod method = meta->method(i); - if (hasMethodAccess(method, i, inst->options) - && !isObjectProperty(m_object, method.signature())) { - QMetaMethod method = meta->method(i); - QScriptNameIdImpl *nameId = eng->nameId(QLatin1String(method.signature())); - member->native(nameId, i, - QScriptValue::QObjectMember - | METHOD_ID); - m_index = i; - return; - } - } - m_state = DynamicProperties; - m_index = inst->value->dynamicPropertyNames().count() - 1; - i = m_index; - // fall-through - } - - case DynamicProperties: { - QList<QByteArray> dpNames = inst->value->dynamicPropertyNames(); - for ( ; i >= 0; --i) { - if (!isObjectProperty(m_object, dpNames.at(i))) { - QByteArray name = dpNames.at(i); - QScriptNameIdImpl *nameId = eng->nameId(QLatin1String(name)); - member->native(nameId, i, - QScriptValue::QObjectMember - | DYNAPROPERTY_ID); - m_index = i; - return; - } - } - m_state = MetaProperties; - m_index = meta->propertyCount() - 1; - i = m_index; - // fall-through - } - - case MetaProperties: { - int limit = (inst->options & QScriptEngine::ExcludeSuperClassProperties) - ? meta->propertyOffset() : 0; - for ( ; i >= limit; --i) { - QMetaProperty prop = meta->property(i); - if (isEnumerableMetaProperty(prop, meta, i) - && !isObjectProperty(m_object, prop.name())) { - QScriptNameIdImpl *nameId = eng->nameId(QLatin1String(prop.name())); - member->native(nameId, i, flagsForMetaProperty(prop)); - m_index = i; - return; - } - } - } - - } // switch - - member->invalidate(); -} - -void ExtQObjectDataIterator::toFront() -{ - ExtQObject::Instance *inst = ExtQObject::Instance::get(m_object); - if (!inst->value) - return; - m_state = MetaProperties; - const QMetaObject *meta = inst->value->metaObject(); - m_index = (inst->options & QScriptEngine::ExcludeSuperClassProperties) - ? meta->propertyOffset() : 0; -} - -void ExtQObjectDataIterator::toBack() -{ - ExtQObject::Instance *inst = ExtQObject::Instance::get(m_object); - if (!inst->value) - return; - if (inst->options & QScriptEngine::SkipMethodsInEnumeration) { - m_state = DynamicProperties; - m_index = inst->value->dynamicPropertyNames().count(); - } else { - m_state = MetaMethods; - const QMetaObject *meta = inst->value->metaObject(); - m_index = meta->methodCount(); - } -} - -class ExtQObjectData: public QScriptClassData -{ -public: - ExtQObjectData(QScriptClassInfo *classInfo) - : m_classInfo(classInfo) - { - } - - virtual bool resolve(const QScriptValueImpl &object, QScriptNameIdImpl *nameId, - QScript::Member *member, QScriptValueImpl *, - QScript::AccessMode access) - { - ExtQObject::Instance *inst = ExtQObject::Instance::get(object, m_classInfo); - QObject *qobject = inst->value; - if (! qobject) { - // the object was deleted. We return true so we can - // throw an error in get()/put() - member->native(nameId, /*id=*/-1, /*flags=*/0); - return true; - } - - const QScriptEngine::QObjectWrapOptions &opt = inst->options; - const QMetaObject *meta = qobject->metaObject(); - - QScriptEnginePrivate *eng = object.engine(); - -#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE - QScriptMetaObject *metaCache = eng->cachedMetaObject(meta); - if (metaCache->findMember(nameId, member)) { - bool ignore = false; - switch (member->flags() & ID_MASK) { - case PROPERTY_ID: - ignore = (opt & QScriptEngine::ExcludeSuperClassProperties) - && (member->id() < meta->propertyOffset()); - break; - case METHOD_ID: - ignore = ((opt & QScriptEngine::ExcludeSuperClassMethods) - && (member->id() < meta->methodOffset())) - || ((opt & QScriptEngine::ExcludeDeleteLater) - && (member->id() == 2)); - break; - // we don't cache dynamic properties nor children, - // so no need to handle DYNAPROPERTY_ID and CHILD_ID - default: - break; - } - if (!ignore) - return true; - } -#endif - - QString memberName = eng->toString(nameId); - QByteArray name = memberName.toLatin1(); - - int index = -1; - - if (name.contains('(')) { - QByteArray normalized = QMetaObject::normalizedSignature(name); - if (-1 != (index = meta->indexOfMethod(normalized))) { - QMetaMethod method = meta->method(index); - if (hasMethodAccess(method, index, opt)) { - member->native(nameId, index, - QScriptValue::QObjectMember - | METHOD_ID); -#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE - metaCache->registerMember(nameId, *member); -#endif - if (!(opt & QScriptEngine::ExcludeSuperClassMethods) - || (index >= meta->methodOffset())) { - return true; - } - } - } - } - - index = meta->indexOfProperty(name); - if (index != -1) { - QMetaProperty prop = meta->property(index); - if (prop.isScriptable()) { - member->native(nameId, index, flagsForMetaProperty(prop)); -#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE - metaCache->registerMember(nameId, *member); -#endif - if (!(opt & QScriptEngine::ExcludeSuperClassProperties) - || (index >= meta->propertyOffset())) { - return true; - } - } - } - - index = qobject->dynamicPropertyNames().indexOf(name); - if (index != -1) { - member->native(nameId, index, - QScriptValue::QObjectMember - | DYNAPROPERTY_ID); - // not cached because it can be removed - return true; - } - - const int offset = (opt & QScriptEngine::ExcludeSuperClassMethods) - ? meta->methodOffset() : 0; - for (index = meta->methodCount() - 1; index >= offset; --index) { - QMetaMethod method = meta->method(index); - if (hasMethodAccess(method, index, opt) - && (methodName(method) == name)) { - member->native(nameId, index, - QScriptValue::QObjectMember - | METHOD_ID - | MAYBE_OVERLOADED); -#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE - metaCache->registerMember(nameId, *member); -#endif - return true; - } - } - - if (!(opt & QScriptEngine::ExcludeChildObjects)) { - QList<QObject*> children = qobject->children(); - for (index = 0; index < children.count(); ++index) { - QObject *child = children.at(index); - if (child->objectName() == memberName) { - member->native(nameId, index, - QScriptValue::ReadOnly - | QScriptValue::Undeletable - | QScriptValue::SkipInEnumeration - | CHILD_ID); - // not cached because it can be removed or change name - return true; - } - } - } - - if ((access & QScript::Write) && (opt & QScriptEngine::AutoCreateDynamicProperties)) { - member->native(nameId, -1, DYNAPROPERTY_ID); - return true; - } - - return false; - } - - virtual bool get(const QScriptValueImpl &obj, const QScript::Member &member, QScriptValueImpl *result) - { - if (! member.isNativeProperty()) - return false; - - QScriptEnginePrivate *eng = obj.engine(); - - ExtQObject::Instance *inst = ExtQObject::Instance::get(obj, m_classInfo); - QObject *qobject = inst->value; - if (!qobject) { - QScriptContextPrivate *ctx = eng->currentContext(); - *result = ctx->throwError( - QString::fromLatin1("cannot access member `%0' of deleted QObject") - .arg(member.nameId()->s)); - return true; - } - - switch (member.flags() & ID_MASK) { - case PROPERTY_ID: { - const QMetaObject *meta = qobject->metaObject(); - const int propertyIndex = member.id(); - QMetaProperty prop = meta->property(propertyIndex); - Q_ASSERT(prop.isScriptable()); - if (GeneratePropertyFunctions) { - QScriptValueImpl accessor; -#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE - QScriptMetaObject *metaCache = eng->cachedMetaObject(meta); - accessor = metaCache->findPropertyAccessor(propertyIndex); - if (!accessor.isValid()) { -#endif - accessor = eng->createFunction(new QtPropertyFunction(meta, propertyIndex)); -#ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE - metaCache->registerPropertyAccessor(propertyIndex, accessor); - } -#endif - *result = accessor; - } else { - QVariant v = prop.read(qobject); - *result = eng->valueFromVariant(v); - } - } break; - - case DYNAPROPERTY_ID: { - if (member.id() != -1) { - QVariant v = qobject->property(member.nameId()->s.toLatin1()); - *result = eng->valueFromVariant(v); - } else { - *result = eng->undefinedValue(); - } - } break; - - case METHOD_ID: { - QScript::Member m; - bool maybeOverloaded = (member.flags() & MAYBE_OVERLOADED) != 0; - *result = eng->createFunction(new QtFunction(obj, member.id(), - maybeOverloaded)); - // make it persist (otherwise Function.prototype.disconnect() would fail) - uint flags = QScriptValue::QObjectMember; - if (inst->options & QScriptEngine::SkipMethodsInEnumeration) - flags |= QScriptValue::SkipInEnumeration; - QScriptObject *instance = obj.objectValue(); - if (!instance->findMember(member.nameId(), &m)) - instance->createMember(member.nameId(), &m, flags); - instance->put(m, *result); - } break; - - case CHILD_ID: { - QObject *child = qobject->children().at(member.id()); - result->invalidate(); - QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject; - eng->newQObject(result, child, QScriptEngine::QtOwnership, opt); - } break; - - } // switch - - return true; - } - - virtual bool put(QScriptValueImpl *object, const QScript::Member &member, const QScriptValueImpl &value) - { - if (! member.isNativeProperty() || ! member.isWritable()) - return false; - - ExtQObject::Instance *inst = ExtQObject::Instance::get(*object, m_classInfo); - QObject *qobject = inst->value; - if (!qobject) { - QScriptEnginePrivate *eng = object->engine(); - QScriptContextPrivate *ctx = eng->currentContext(); - ctx->throwError(QString::fromLatin1("cannot access member `%0' of deleted QObject") - .arg(member.nameId()->s)); - return true; - } - - switch (member.flags() & ID_MASK) { - case CHILD_ID: - return false; - - case METHOD_ID: { - QScript::Member m; - QScriptObject *instance = object->objectValue(); - if (!instance->findMember(member.nameId(), &m)) { - instance->createMember(member.nameId(), &m, - /*flags=*/0); - } - instance->put(m, value); - return true; - } - - case PROPERTY_ID: - if (GeneratePropertyFunctions) { - // we shouldn't get here, QScriptValueImpl::setProperty() messed up - Q_ASSERT_X(0, "put", "Q_PROPERTY access cannot be overridden"); - return false; - } else { - const QMetaObject *meta = qobject->metaObject(); - QMetaProperty prop = meta->property(member.id()); - Q_ASSERT(prop.isScriptable()); - QVariant v = variantFromValue(object->engine(), prop.userType(), value); - bool ok = prop.write(qobject, v); - return ok; - } - - case DYNAPROPERTY_ID: { - QVariant v = value.toVariant(); - return ! qobject->setProperty(member.nameId()->s.toLatin1(), v); - } - - } // switch - return false; - } - - virtual bool removeMember(const QScriptValueImpl &object, - const QScript::Member &member) - { - QObject *qobject = object.toQObject(); - if (!qobject || !member.isNativeProperty() || !member.isDeletable()) - return false; - - if ((member.flags() & ID_MASK) == DYNAPROPERTY_ID) { - qobject->setProperty(member.nameId()->s.toLatin1(), QVariant()); - return true; - } - - return false; - } - - virtual void mark(const QScriptValueImpl &, int) - { - } - - virtual QScriptClassDataIterator *newIterator(const QScriptValueImpl &object) - { - return new ExtQObjectDataIterator(object); - } - -private: - QScriptClassInfo *m_classInfo; -}; - -struct QObjectConnection -{ - int slotIndex; - QScriptValueImpl receiver; - QScriptValueImpl slot; - QScriptValueImpl senderWrapper; - - QObjectConnection(int i, const QScriptValueImpl &r, const QScriptValueImpl &s, - const QScriptValueImpl &sw) - : slotIndex(i), receiver(r), slot(s), senderWrapper(sw) {} - QObjectConnection() : slotIndex(-1) {} - - bool hasTarget(const QScriptValueImpl &r, const QScriptValueImpl &s) const - { - if (r.isObject() != receiver.isObject()) - return false; - if ((r.isObject() && receiver.isObject()) - && (r.objectValue() != receiver.objectValue())) { - return false; - } - return (s.objectValue() == slot.objectValue()); - } - - void mark(int generation) - { - if (senderWrapper.isValid() && !senderWrapper.isMarked(generation)) { - // see if the sender should be marked or not - ExtQObject::Instance *inst = ExtQObject::Instance::get(senderWrapper); - if ((inst->ownership == QScriptEngine::ScriptOwnership) - || ((inst->ownership == QScriptEngine::AutoOwnership) - && inst->value && !inst->value->parent())) { - senderWrapper.invalidate(); - } else { - senderWrapper.mark(generation); - } - } - if (receiver.isValid()) - receiver.mark(generation); - if (slot.isValid()) - slot.mark(generation); - } -}; - -class QObjectConnectionManager: public QObject -{ -public: - QObjectConnectionManager(); - ~QObjectConnectionManager(); - - bool addSignalHandler(QObject *sender, int signalIndex, - const QScriptValueImpl &receiver, - const QScriptValueImpl &slot, - const QScriptValueImpl &senderWrapper, - Qt::ConnectionType type); - bool removeSignalHandler( - QObject *sender, int signalIndex, - const QScriptValueImpl &receiver, - const QScriptValueImpl &slot); - - static const QMetaObject staticMetaObject; - virtual const QMetaObject *metaObject() const; - virtual void *qt_metacast(const char *); - virtual int qt_metacall(QMetaObject::Call, int, void **argv); - - void execute(int slotIndex, void **argv); - - void mark(int generation); - -private: - int m_slotCounter; - QVector<QVector<QObjectConnection> > connections; -}; - -} // ::QScript - - - -QScript::ExtQObject::ExtQObject(QScriptEnginePrivate *eng): - Ecma::Core(eng, QLatin1String("QObject"), QScriptClassInfo::QObjectType) -{ - newQObject(&publicPrototype, new QScript::QObjectPrototype(), - QScriptEngine::AutoOwnership, - QScriptEngine::ExcludeSuperClassMethods - | QScriptEngine::ExcludeSuperClassProperties - | QScriptEngine::ExcludeChildObjects); - - eng->newConstructor(&ctor, this, publicPrototype); - addPrototypeFunction(QLatin1String("toString"), method_toString, 0); - addPrototypeFunction(QLatin1String("findChild"), method_findChild, 1); - addPrototypeFunction(QLatin1String("findChildren"), method_findChildren, 1); - - classInfo()->setData(new QScript::ExtQObjectData(classInfo())); -} - -QScript::ExtQObject::~ExtQObject() -{ -} - -void QScript::ExtQObject::execute(QScriptContextPrivate *context) -{ - QScriptValueImpl tmp; - newQObject(&tmp, 0); - context->setReturnValue(tmp); -} - -void QScript::ExtQObject::newQObject(QScriptValueImpl *result, QObject *value, - QScriptEngine::ValueOwnership ownership, - const QScriptEngine::QObjectWrapOptions &options) -{ - Instance *instance; - if (!result->isValid()) { - engine()->newObject(result, publicPrototype, classInfo()); - instance = new Instance(); - result->setObjectData(instance); - } else { - Q_ASSERT(result->isObject()); - if (result->classInfo() != classInfo()) { - result->destroyObjectData(); - result->setClassInfo(classInfo()); - instance = new Instance(); - result->setObjectData(instance); - } else { - instance = Instance::get(*result); - } - } - instance->value = value; - instance->ownership = ownership; - instance->options = options; -} - -QScriptValueImpl QScript::ExtQObject::method_findChild(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) -{ - if (Instance *instance = Instance::get(context->thisObject(), classInfo)) { - QObject *obj = instance->value; - QString name = context->argument(0).toString(); - QObject *child = qFindChild<QObject*>(obj, name); - QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject; - QScriptValueImpl result; - eng->newQObject(&result, child, QScriptEngine::QtOwnership, opt); - return result; - } - return eng->undefinedValue(); -} - -QScriptValueImpl QScript::ExtQObject::method_findChildren(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) -{ - if (Instance *instance = Instance::get(context->thisObject(), classInfo)) { - QObject *obj = instance->value; - QList<QObject*> found; - QScriptValueImpl arg = context->argument(0); -#ifndef QT_NO_REGEXP - if (arg.isRegExp()) { - QRegExp re = arg.toRegExp(); - found = qFindChildren<QObject*>(obj, re); - } else -#endif - { - QString name = arg.isUndefined() ? QString() : arg.toString(); - found = qFindChildren<QObject*>(obj, name); - } - QScriptValueImpl result = eng->newArray(found.size()); - QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject; - for (int i = 0; i < found.size(); ++i) { - QScriptValueImpl value; - eng->newQObject(&value, found.at(i), QScriptEngine::QtOwnership, opt); - result.setProperty(i, value); - } - return result; - } - return eng->undefinedValue(); -} - -QScriptValueImpl QScript::ExtQObject::method_toString(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) -{ - if (Instance *instance = Instance::get(context->thisObject(), classInfo)) { - QObject *obj = instance->value; - const QMetaObject *meta = obj ? obj->metaObject() : &QObject::staticMetaObject; - QString name = obj ? obj->objectName() : QString::fromUtf8("unnamed"); - - QString str = QString::fromUtf8("%0(name = \"%1\")") - .arg(QLatin1String(meta->className())).arg(name); - return QScriptValueImpl(eng, str); - } - return eng->undefinedValue(); -} - - - -static const uint qt_meta_data_QObjectConnectionManager[] = { - - // content: - 1, // revision - 0, // classname - 0, 0, // classinfo - 1, 10, // methods - 0, 0, // properties - 0, 0, // enums/sets - - // slots: signature, parameters, type, tag, flags - 35, 34, 34, 34, 0x0a, - - 0 // eod -}; - -static const char qt_meta_stringdata_QObjectConnectionManager[] = { - "QScript::QObjectConnectionManager\0\0execute()\0" -}; - -const QMetaObject QScript::QObjectConnectionManager::staticMetaObject = { - { &QObject::staticMetaObject, qt_meta_stringdata_QObjectConnectionManager, - qt_meta_data_QObjectConnectionManager, 0 } -}; - -const QMetaObject *QScript::QObjectConnectionManager::metaObject() const -{ - return &staticMetaObject; -} - -void *QScript::QObjectConnectionManager::qt_metacast(const char *_clname) -{ - if (!_clname) return 0; - if (!strcmp(_clname, qt_meta_stringdata_QObjectConnectionManager)) - return static_cast<void*>(const_cast<QObjectConnectionManager*>(this)); - return QObject::qt_metacast(_clname); -} - -int QScript::QObjectConnectionManager::qt_metacall(QMetaObject::Call _c, int _id, void **_a) -{ - _id = QObject::qt_metacall(_c, _id, _a); - if (_id < 0) - return _id; - if (_c == QMetaObject::InvokeMetaMethod) { - execute(_id, _a); - _id -= m_slotCounter; - } - return _id; -} - -void QScript::QObjectConnectionManager::execute(int slotIndex, void **argv) -{ - QScriptValueImpl receiver; - QScriptValueImpl slot; - QScriptValueImpl senderWrapper; - int signalIndex = -1; - for (int i = 0; i < connections.size(); ++i) { - const QVector<QObjectConnection> &cs = connections.at(i); - for (int j = 0; j < cs.size(); ++j) { - const QObjectConnection &c = cs.at(j); - if (c.slotIndex == slotIndex) { - receiver = c.receiver; - slot = c.slot; - senderWrapper = c.senderWrapper; - signalIndex = i; - break; - } - } - } - Q_ASSERT(slot.isValid()); - - QScriptEnginePrivate *eng = slot.engine(); - - if (eng->isCollecting()) { - // we can't do a script function call during GC, - // so we're forced to ignore this signal - return; - } - - QScriptFunction *fun = eng->convertToNativeFunction(slot); - if (fun == 0) { - // the signal handler has been GC'ed. This can only happen when - // a QObject is owned by the engine, the engine is destroyed, and - // there is a script function connected to the destroyed() signal - Q_ASSERT(signalIndex <= 1); // destroyed(QObject*) - return; - } - - const QMetaObject *meta = sender()->metaObject(); - const QMetaMethod method = meta->method(signalIndex); - - QList<QByteArray> parameterTypes = method.parameterTypes(); - int argc = parameterTypes.count(); - - QScriptValueImpl activation; - eng->newActivation(&activation); - QScriptObject *activation_data = activation.objectValue(); - activation_data->m_scope = slot.scope(); - - int formalCount = fun->formals.count(); - int mx = qMax(formalCount, argc); - activation_data->m_members.resize(mx + 1); - activation_data->m_values.resize(mx + 1); - for (int i = 0; i < mx; ++i) { - QScriptNameIdImpl *nameId; - if (i < formalCount) - nameId = fun->formals.at(i); - else - nameId = 0; - activation_data->m_members[i].object(nameId, i, - QScriptValue::Undeletable - | QScriptValue::SkipInEnumeration); - QScriptValueImpl actual; - if (i < argc) { - void *arg = argv[i + 1]; - QByteArray typeName = parameterTypes.at(i); - int argType = QMetaType::type(typeName); - if (!argType) { - if (typeName == "QVariant") { - actual = eng->valueFromVariant(*reinterpret_cast<QVariant*>(arg)); - } else { - qWarning("QScriptEngine: Unable to handle unregistered datatype '%s' " - "when invoking handler of signal %s::%s", - typeName.constData(), meta->className(), method.signature()); - actual = eng->undefinedValue(); - } - } else { - actual = eng->create(argType, arg); - } - } else { - actual = eng->undefinedValue(); - } - activation_data->m_values[i] = actual; - } - - QScriptValueImpl senderObject; - if (senderWrapper.isQObject()) { - senderObject = senderWrapper; - } else { - QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject; - eng->newQObject(&senderObject, sender(), QScriptEngine::QtOwnership, opt); - } - activation_data->m_members[mx].object(eng->idTable()->id___qt_sender__, mx, - QScriptValue::SkipInEnumeration); - activation_data->m_values[mx] = senderObject; - - QScriptValueImpl thisObject; - if (receiver.isObject()) - thisObject = receiver; - else - thisObject = eng->globalObject(); - - QScriptContextPrivate *context_data = eng->pushContext(); - context_data->m_activation = activation; - context_data->m_callee = slot; - context_data->m_thisObject = thisObject; - context_data->argc = argc; - context_data->args = const_cast<QScriptValueImpl*> (activation_data->m_values.constData()); - - fun->execute(context_data); - - eng->popContext(); - if (eng->hasUncaughtException()) - eng->emitSignalHandlerException(); -} - -QScript::QObjectConnectionManager::QObjectConnectionManager() - : m_slotCounter(0) -{ -} - -QScript::QObjectConnectionManager::~QObjectConnectionManager() -{ -} - -void QScript::QObjectConnectionManager::mark(int generation) -{ - for (int i = 0; i < connections.size(); ++i) { - QVector<QObjectConnection> &cs = connections[i]; - for (int j = 0; j < cs.size(); ++j) - cs[j].mark(generation); - } -} - -bool QScript::QObjectConnectionManager::addSignalHandler( - QObject *sender, int signalIndex, const QScriptValueImpl &receiver, - const QScriptValueImpl &function, const QScriptValueImpl &senderWrapper, - Qt::ConnectionType type) -{ - if (connections.size() <= signalIndex) - connections.resize(signalIndex+1); - QVector<QObjectConnection> &cs = connections[signalIndex]; - int absSlotIndex = m_slotCounter + metaObject()->methodOffset(); - bool ok = QMetaObject::connect(sender, signalIndex, this, absSlotIndex, type); - if (ok) { - cs.append(QScript::QObjectConnection(m_slotCounter++, receiver, function, senderWrapper)); - QMetaMethod signal = sender->metaObject()->method(signalIndex); - QByteArray signalString; - signalString.append('2'); // signal code - signalString.append(signal.signature()); - static_cast<QScript::QObjectNotifyCaller*>(sender)->callConnectNotify(signalString); - } - return ok; -} - -bool QScript::QObjectConnectionManager::removeSignalHandler( - QObject *sender, int signalIndex, - const QScriptValueImpl &receiver, - const QScriptValueImpl &slot) -{ - if (connections.size() <= signalIndex) - return false; - QVector<QObjectConnection> &cs = connections[signalIndex]; - for (int i = 0; i < cs.size(); ++i) { - const QObjectConnection &c = cs.at(i); - if (c.hasTarget(receiver, slot)) { - int absSlotIndex = c.slotIndex + metaObject()->methodOffset(); - bool ok = QMetaObject::disconnect(sender, signalIndex, this, absSlotIndex); - if (ok) { - cs.remove(i); - QMetaMethod signal = sender->metaObject()->method(signalIndex); - QByteArray signalString; - signalString.append('2'); // signal code - signalString.append(signal.signature()); - static_cast<QScript::QObjectNotifyCaller*>(sender)->callDisconnectNotify(signalString); - } - return ok; - } - } - return false; -} - - - -QString QScript::QtPropertyFunction::functionName() const -{ - QMetaProperty prop = m_meta->property(m_index); - return QLatin1String(prop.name()); -} - -void QScript::QtPropertyFunction::execute(QScriptContextPrivate *context) -{ - context->calleeMetaIndex = m_index; - - QScriptEnginePrivate *eng_p = context->engine(); -#ifndef Q_SCRIPT_NO_EVENT_NOTIFY - eng_p->notifyFunctionEntry(context); -#endif - QScriptValueImpl result = eng_p->undefinedValue(); - - QScriptValueImpl object = context->thisObject(); - QObject *qobject = object.toQObject(); - while ((!qobject || (qobject->metaObject() != m_meta)) - && object.prototype().isObject()) { - object = object.prototype(); - qobject = object.toQObject(); - } - Q_ASSERT(qobject); - - QMetaProperty prop = m_meta->property(m_index); - Q_ASSERT(prop.isScriptable()); - if (context->argumentCount() == 0) { - // get - if (prop.isValid()) { - QScriptable *scriptable = scriptableFromQObject(qobject); - QScriptEngine *oldEngine = 0; - if (scriptable) { - oldEngine = QScriptablePrivate::get(scriptable)->engine; - QScriptablePrivate::get(scriptable)->engine = QScriptEnginePrivate::get(eng_p); - } - - QVariant v = prop.read(qobject); - - if (scriptable) - QScriptablePrivate::get(scriptable)->engine = oldEngine; - - result = eng_p->valueFromVariant(v); - } - } else { - // set - QScriptValueImpl arg = context->argument(0); - QVariant v; - if (prop.isEnumType() && arg.isString() - && !eng_p->demarshalFunction(prop.userType())) { - // give QMetaProperty::write() a chance to convert from - // string to enum value - v = arg.toString(); - } else { - v = variantFromValue(eng_p, prop.userType(), arg); - } - - QScriptable *scriptable = scriptableFromQObject(qobject); - QScriptEngine *oldEngine = 0; - if (scriptable) { - oldEngine = QScriptablePrivate::get(scriptable)->engine; - QScriptablePrivate::get(scriptable)->engine = QScriptEnginePrivate::get(eng_p); - } - - prop.write(qobject, v); - - if (scriptable) - QScriptablePrivate::get(scriptable)->engine = oldEngine; - - result = context->argument(0); - } - if (!eng_p->hasUncaughtException()) - context->m_result = result; -#ifndef Q_SCRIPT_NO_EVENT_NOTIFY - eng_p->notifyFunctionExit(context); -#endif -} - -QString QScript::QtFunction::functionName() const -{ - const QMetaObject *meta = metaObject(); - if (!meta) - return QString(); - QMetaMethod method = meta->method(m_initialIndex); - return QLatin1String(methodName(method)); -} - -void QScript::QtFunction::mark(QScriptEnginePrivate *engine, int generation) -{ - if (m_object.isValid()) - engine->markObject(m_object, generation); - QScriptFunction::mark(engine, generation); -} - -void QScript::QtFunction::execute(QScriptContextPrivate *context) -{ - QScriptEnginePrivate *eng_p = context->engine(); - QObject *qobj = qobject(); - if (!qobj) { - context->calleeMetaIndex = m_initialIndex; -#ifndef Q_SCRIPT_NO_EVENT_NOTIFY - eng_p->notifyFunctionEntry(context); -#endif - context->throwError(QLatin1String("cannot call function of deleted QObject")); -#ifndef Q_SCRIPT_NO_EVENT_NOTIFY - eng_p->notifyFunctionExit(context); -#endif - return; - } - - const QMetaObject *meta = qobj->metaObject(); - - QObject *thisQObject = context->thisObject().toQObject(); - if (!thisQObject) // ### TypeError - thisQObject = qobj; - - if (!meta->cast(thisQObject)) { -#if 0 - // ### find common superclass, see if initialIndex is - // in that class (or a superclass of that class), - // then it's still safe to execute it - funName = methodName(meta->method(m_initialIndex)); - context->throwError( - QString::fromUtf8("cannot execute %0: %1 does not inherit %2") - .arg(QLatin1String(funName)) - .arg(QLatin1String(thisQObject->metaObject()->className())) - .arg(QLatin1String(meta->className()))); - return; -#endif - // invoking a function in the prototype - thisQObject = qobj; - } - - callQtMethod(context, QMetaMethod::Method, thisQObject, - meta, m_initialIndex, m_maybeOverloaded); -} - -int QScript::QtFunction::mostGeneralMethod(QMetaMethod *out) const -{ - const QMetaObject *meta = metaObject(); - if (!meta) - return -1; - int index = m_initialIndex; - QMetaMethod method = meta->method(index); - if (maybeOverloaded() && (method.attributes() & QMetaMethod::Cloned)) { - // find the most general method - do { - method = meta->method(--index); - } while (method.attributes() & QMetaMethod::Cloned); - } - if (out) - *out = method; - return index; -} - -QList<int> QScript::QtFunction::overloadedIndexes() const -{ - if (!maybeOverloaded()) - return QList<int>(); - QList<int> result; - QString name = functionName(); - const QMetaObject *meta = metaObject(); - for (int index = mostGeneralMethod() - 1; index >= 0; --index) { - QString otherName = QString::fromLatin1(methodName(meta->method(index))); - if (otherName == name) - result.append(index); - } - return result; -} - -///////////////////////////////////////////////////////// - -namespace QScript -{ - -ExtQMetaObject::Instance *ExtQMetaObject::Instance::get(const QScriptValueImpl &object, - QScriptClassInfo *klass) -{ - if (! klass || klass == object.classInfo()) - return static_cast<Instance*> (object.objectData()); - - return 0; -} - -void ExtQMetaObject::Instance::execute(QScriptContextPrivate *context) -{ - if (ctor.isFunction()) { - QScriptValueImplList args; - for (int i = 0; i < context->argumentCount(); ++i) - args << context->argument(i); - QScriptEnginePrivate *eng = context->engine(); - context->m_result = eng->call(ctor, context->thisObject(), args, - context->isCalledAsConstructor()); - } else { - if (value->constructorCount() > 0) { - callQtMethod(context, QMetaMethod::Constructor, /*thisQObject=*/0, - value, value->constructorCount()-1, /*maybeOverloaded=*/true); - if (context->state() == QScriptContext::NormalState) { - ExtQObject::Instance *inst = ExtQObject::Instance::get(context->m_result); - Q_ASSERT(inst != 0); - inst->ownership = QScriptEngine::AutoOwnership; - context->m_result.setPrototype(prototype); - } - } else { - context->m_result = context->throwError( - QScriptContext::TypeError, - QString::fromUtf8("no constructor for %0") - .arg(QLatin1String(value->className()))); - } - } -} - -struct StaticQtMetaObject : public QObject -{ - static const QMetaObject *get() - { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; } -}; - -class ExtQMetaObjectData: public QScriptClassData -{ -public: - ExtQMetaObjectData(QScriptEnginePrivate *, QScriptClassInfo *classInfo); - - virtual bool resolve(const QScriptValueImpl &object, QScriptNameIdImpl *nameId, - QScript::Member *member, QScriptValueImpl *base, - QScript::AccessMode access); - virtual bool get(const QScriptValueImpl &object, const QScript::Member &member, - QScriptValueImpl *result); - virtual bool put(QScriptValueImpl *object, const QScript::Member &member, - const QScriptValueImpl &value); - virtual void mark(const QScriptValueImpl &object, int generation); - -private: - QScriptClassInfo *m_classInfo; -}; - -ExtQMetaObjectData::ExtQMetaObjectData(QScriptEnginePrivate *, - QScriptClassInfo *classInfo) - : m_classInfo(classInfo) -{ -} - -bool ExtQMetaObjectData::resolve(const QScriptValueImpl &object, - QScriptNameIdImpl *nameId, - QScript::Member *member, - QScriptValueImpl *base, - QScript::AccessMode /*access*/) -{ - const QMetaObject *meta = object.toQMetaObject(); - if (!meta) - return false; - - QScriptEnginePrivate *eng_p = object.engine(); - if (eng_p->idTable()->id_prototype == nameId) { - // prototype property is a proxy to constructor's prototype property - member->native(nameId, /*id=*/0, QScriptValue::Undeletable); - return true; - } - - QByteArray name = eng_p->toString(nameId).toLatin1(); - - for (int i = 0; i < meta->enumeratorCount(); ++i) { - QMetaEnum e = meta->enumerator(i); - for (int j = 0; j < e.keyCount(); ++j) { - const char *key = e.key(j); - if (! qstrcmp (key, name.constData())) { - member->native(nameId, e.value(j), - QScriptValue::ReadOnly - | QScriptValue::Undeletable); - *base = object; - return true; - } - } - } - - return false; -} - -bool ExtQMetaObjectData::get(const QScriptValueImpl &object, - const QScript::Member &member, - QScriptValueImpl *result) -{ - if (! member.isNativeProperty()) - return false; - - QScriptEnginePrivate *eng_p = object.engine(); - if (eng_p->idTable()->id_prototype == member.nameId()) { - ExtQMetaObject::Instance *inst = ExtQMetaObject::Instance::get(object, m_classInfo); - if (inst->ctor.isFunction()) - *result = inst->ctor.property(eng_p->idTable()->id_prototype); - else - *result = inst->prototype; - } else { - *result = QScriptValueImpl(member.id()); - } - return true; -} - -bool ExtQMetaObjectData::put(QScriptValueImpl *object, const Member &member, - const QScriptValueImpl &value) -{ - if (! member.isNativeProperty()) - return false; - - QScriptEnginePrivate *eng_p = object->engine(); - if (eng_p->idTable()->id_prototype == member.nameId()) { - ExtQMetaObject::Instance *inst = ExtQMetaObject::Instance::get(*object, m_classInfo); - if (inst->ctor.isFunction()) - inst->ctor.setProperty(eng_p->idTable()->id_prototype, value); - else - inst->prototype = value; - } - - return true; -} - -void ExtQMetaObjectData::mark(const QScriptValueImpl &object, int generation) -{ - ExtQMetaObject::Instance *inst = ExtQMetaObject::Instance::get(object, m_classInfo); - if (inst->ctor.isObject() || inst->ctor.isString()) - inst->ctor.mark(generation); -} - -} // namespace QScript - -QScript::ExtQMetaObject::ExtQMetaObject(QScriptEnginePrivate *eng) - : Ecma::Core(eng, QLatin1String("QMetaObject"), QScriptClassInfo::QMetaObjectType) -{ - newQMetaObject(&publicPrototype, QScript::StaticQtMetaObject::get()); - - eng->newConstructor(&ctor, this, publicPrototype); - addPrototypeFunction(QLatin1String("className"), method_className, 0); - - classInfo()->setData(new QScript::ExtQMetaObjectData(eng, classInfo())); -} - -QScript::ExtQMetaObject::~ExtQMetaObject() -{ -} - -void QScript::ExtQMetaObject::execute(QScriptContextPrivate *context) -{ - QScriptValueImpl tmp; - newQMetaObject(&tmp, 0); - context->setReturnValue(tmp); -} - -void QScript::ExtQMetaObject::newQMetaObject(QScriptValueImpl *result, const QMetaObject *value, - const QScriptValueImpl &ctor) -{ - Instance *instance = new Instance(); - instance->value = value; - if (ctor.isFunction()) { - instance->ctor = ctor; - } else { - instance->prototype = engine()->newObject(); - instance->prototype.setPrototype(engine()->qobjectConstructor->publicPrototype); - } - - engine()->newObject(result, publicPrototype, classInfo()); - result->setObjectData(instance); -} - -QScriptValueImpl QScript::ExtQMetaObject::method_className(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo) -{ - if (Instance *instance = Instance::get(context->thisObject(), classInfo)) { - return QScriptValueImpl(eng, QString::fromLatin1(instance->value->className())); - } - return eng->undefinedValue(); -} - -QScriptQObjectData::QScriptQObjectData() - : m_connectionManager(0) -{ -} - -QScriptQObjectData::~QScriptQObjectData() -{ - if (m_connectionManager) { - delete m_connectionManager; - m_connectionManager = 0; - } -} - -bool QScriptQObjectData::addSignalHandler(QObject *sender, - int signalIndex, - const QScriptValueImpl &receiver, - const QScriptValueImpl &slot, - const QScriptValueImpl &senderWrapper, - Qt::ConnectionType type) -{ - if (!m_connectionManager) - m_connectionManager = new QScript::QObjectConnectionManager(); - return m_connectionManager->addSignalHandler( - sender, signalIndex, receiver, slot, senderWrapper, type); -} - -bool QScriptQObjectData::removeSignalHandler(QObject *sender, - int signalIndex, - const QScriptValueImpl &receiver, - const QScriptValueImpl &slot) -{ - if (!m_connectionManager) - return false; - return m_connectionManager->removeSignalHandler( - sender, signalIndex, receiver, slot); -} - -bool QScriptQObjectData::findWrapper(QScriptEngine::ValueOwnership ownership, - const QScriptEngine::QObjectWrapOptions &options, - QScriptValueImpl *out) -{ - for (int i = 0; i < wrappers.size(); ++i) { - const QScriptQObjectWrapperInfo &info = wrappers.at(i); - if ((info.ownership == ownership) && (info.options == options)) { - *out = info.object; - return true; - } - } - return false; -} - -void QScriptQObjectData::registerWrapper(const QScriptValueImpl &wrapper, - QScriptEngine::ValueOwnership ownership, - const QScriptEngine::QObjectWrapOptions &options) -{ - wrappers.append(QScriptQObjectWrapperInfo(wrapper, ownership, options)); -} - -void QScriptQObjectData::mark(int generation) -{ - if (m_connectionManager) - m_connectionManager->mark(generation); - - { - QList<QScriptQObjectWrapperInfo>::iterator it; - for (it = wrappers.begin(); it != wrappers.end(); ) { - const QScriptQObjectWrapperInfo &info = *it; - if (info.object.isMarked(generation)) { - ++it; - } else { - it = wrappers.erase(it); - } - } - } -} - -QT_END_NAMESPACE - -#include "qscriptextqobject.moc" - -#endif // QT_NO_SCRIPT |