diff options
author | Kent Hansen <khansen@trolltech.com> | 2009-07-02 13:00:17 (GMT) |
---|---|---|
committer | Kent Hansen <khansen@trolltech.com> | 2009-07-02 13:00:17 (GMT) |
commit | 5d3ae53770a0b6ba0ad8c3271f6fcda72179c68e (patch) | |
tree | 241cfb0df7a4c1dc5eaf14f66ae3b691306017d2 /src/script | |
parent | c1ac464798858d9a5a3b98bc20f7ef2e98f2d1a1 (diff) | |
download | Qt-5d3ae53770a0b6ba0ad8c3271f6fcda72179c68e.zip Qt-5d3ae53770a0b6ba0ad8c3271f6fcda72179c68e.tar.gz Qt-5d3ae53770a0b6ba0ad8c3271f6fcda72179c68e.tar.bz2 |
first stab at implementing Qt property getter/setters
Not fully working yet, so disabled for now
Diffstat (limited to 'src/script')
-rw-r--r-- | src/script/api/qscriptengine.cpp | 6 | ||||
-rw-r--r-- | src/script/api/qscriptengine_p.h | 1 | ||||
-rw-r--r-- | src/script/bridge/qscriptqobject.cpp | 205 | ||||
-rw-r--r-- | src/script/bridge/qscriptqobject_p.h | 42 |
4 files changed, 230 insertions, 24 deletions
diff --git a/src/script/api/qscriptengine.cpp b/src/script/api/qscriptengine.cpp index 9849710..e8a2436 100644 --- a/src/script/api/qscriptengine.cpp +++ b/src/script/api/qscriptengine.cpp @@ -2241,6 +2241,12 @@ bool QScriptEnginePrivate::convert(const QScriptValue &value, return false; } +bool QScriptEnginePrivate::hasDemarshalFunction(int type) const +{ + QScriptTypeInfo *info = m_typeInfos.value(type); + return info && (info->demarshal != 0); +} + /*! \internal */ diff --git a/src/script/api/qscriptengine_p.h b/src/script/api/qscriptengine_p.h index ff4b2ce..8a81fd3 100644 --- a/src/script/api/qscriptengine_p.h +++ b/src/script/api/qscriptengine_p.h @@ -78,6 +78,7 @@ public: int type, void *ptr, QScriptEnginePrivate *eng); QScriptValue create(int type, const void *ptr); + bool hasDemarshalFunction(int type) const; QScriptValue scriptValueFromJSCValue(JSC::JSValue value); JSC::JSValue scriptValueToJSCValue(const QScriptValue &value); diff --git a/src/script/bridge/qscriptqobject.cpp b/src/script/bridge/qscriptqobject.cpp index 188ded9..716a0e4 100644 --- a/src/script/bridge/qscriptqobject.cpp +++ b/src/script/bridge/qscriptqobject.cpp @@ -36,6 +36,8 @@ ASSERT_CLASS_FITS_IN_CELL(QScript::QObjectWrapperObject); ASSERT_CLASS_FITS_IN_CELL(QScript::QObjectPrototype); ASSERT_CLASS_FITS_IN_CELL(QScript::QMetaObjectWrapperObject); ASSERT_CLASS_FITS_IN_CELL(QScript::QMetaObjectPrototype); +ASSERT_CLASS_FITS_IN_CELL(QScript::QtFunction); +ASSERT_CLASS_FITS_IN_CELL(QScript::QtPropertyFunction); } namespace QScript @@ -144,10 +146,40 @@ static inline QByteArray methodName(const QMetaMethod &method) return signature.left(signature.indexOf('(')); } +static QVariant variantFromValue(QScriptEnginePrivate *eng, + int targetType, const QScriptValue &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(); +} + +static const bool GeneratePropertyFunctions = false; + static unsigned flagsForMetaProperty(const QMetaProperty &prop) { return (JSC::DontDelete | (!prop.isWritable() ? unsigned(JSC::ReadOnly) : unsigned(0)) + | (GeneratePropertyFunctions + ? unsigned(JSC::Getter | JSC::Setter) + : unsigned(0)) | QObjectMemberAttribute); } @@ -179,9 +211,6 @@ static inline QScriptable *scriptableFromQObject(QObject *qobj) JSC::UString qtStringToJSCUString(const QString &str); QString qtStringFromJSCUString(const JSC::UString &str); -static JSC::JSValue JSC_HOST_CALL QtFunction_call(JSC::ExecState *exec, JSC::JSObject*, - JSC::JSValue thisValue, const JSC::ArgList &args); - QtFunction::QtFunction(JSC::JSValue object, int initialIndex, bool maybeOverloaded, JSC::JSGlobalData *data, WTF::PassRefPtr<JSC::Structure> sid, const JSC::Identifier &ident) @@ -197,7 +226,7 @@ QtFunction::~QtFunction() JSC::CallType QtFunction::getCallData(JSC::CallData &callData) { - callData.native.function = QtFunction_call; + callData.native.function = call; return JSC::CallTypeHost; } @@ -430,8 +459,8 @@ struct QScriptMetaArguments { return (index != -1); } }; -JSC::JSValue QtFunction::call(JSC::ExecState *exec, JSC::JSValue thisValue, - const JSC::ArgList &scriptArgs) +JSC::JSValue QtFunction::execute(JSC::ExecState *exec, JSC::JSValue thisValue, + const JSC::ArgList &scriptArgs) { Q_ASSERT(data->object.isObject(&QObjectWrapperObject::info)); QObjectWrapperObject *wrapper = static_cast<QObjectWrapperObject*>(JSC::asObject(data->object)); @@ -919,11 +948,11 @@ JSC::JSValue QtFunction::call(JSC::ExecState *exec, JSC::JSValue thisValue, const JSC::ClassInfo QtFunction::info = { "QtFunction", 0, 0, 0 }; -JSC::JSValue QtFunction_call(JSC::ExecState *exec, JSC::JSObject *callee, - JSC::JSValue thisValue, const JSC::ArgList &args) +JSC::JSValue JSC_HOST_CALL QtFunction::call(JSC::ExecState *exec, JSC::JSObject *callee, + JSC::JSValue thisValue, const JSC::ArgList &args) { if (!callee->isObject(&QtFunction::info)) - return throwError(exec, JSC::TypeError); + return throwError(exec, JSC::TypeError, "callee is not a QtFunction object"); QtFunction *qfun = static_cast<QtFunction*>(callee); QScriptEnginePrivate *eng_p = static_cast<QScript::GlobalObject*>(exec->dynamicGlobalObject())->engine; QScriptContext *previousContext = eng_p->currentContext; @@ -932,12 +961,123 @@ JSC::JSValue QtFunction_call(JSC::ExecState *exec, JSC::JSObject *callee, previousContext, eng_p); QScriptContext *ctx = QScriptContextPrivate::create(ctx_p); eng_p->currentContext = ctx; - JSC::JSValue result = qfun->call(exec, thisValue, args); + JSC::JSValue result = qfun->execute(exec, thisValue, args); eng_p->currentContext = previousContext; delete ctx; return result; } +const JSC::ClassInfo QtPropertyFunction::info = { "QtPropertyFunction", 0, 0, 0 }; + +QtPropertyFunction::QtPropertyFunction(const QMetaObject *meta, int index, + JSC::JSGlobalData *data, + WTF::PassRefPtr<JSC::Structure> sid, + const JSC::Identifier &ident) + : JSC::InternalFunction(data, sid, ident), + data(new Data(meta, index)) +{ +} + +QtPropertyFunction::~QtPropertyFunction() +{ + delete data; +} + +JSC::CallType QtPropertyFunction::getCallData(JSC::CallData &callData) +{ + callData.native.function = call; + return JSC::CallTypeHost; +} + +JSC::JSValue JSC_HOST_CALL QtPropertyFunction::call( + JSC::ExecState *exec, JSC::JSObject *callee, + JSC::JSValue thisValue, const JSC::ArgList &args) +{ + if (!callee->isObject(&QtPropertyFunction::info)) + return throwError(exec, JSC::TypeError, "callee is not a QtPropertyFunction object"); + QtPropertyFunction *qfun = static_cast<QtPropertyFunction*>(callee); + QScriptEnginePrivate *eng_p = static_cast<QScript::GlobalObject*>(exec->dynamicGlobalObject())->engine; + QScriptContext *previousContext = eng_p->currentContext; + QScriptContextPrivate ctx_p(callee, thisValue, args, + /*calledAsConstructor=*/false, + previousContext, eng_p); + QScriptContext *ctx = QScriptContextPrivate::create(ctx_p); + eng_p->currentContext = ctx; + JSC::JSValue result = qfun->execute(exec, thisValue, args); + eng_p->currentContext = previousContext; + delete ctx; + return result; +} + +JSC::JSValue QtPropertyFunction::execute(JSC::ExecState *exec, + JSC::JSValue thisValue, + const JSC::ArgList &args) +{ + JSC::JSValue result = JSC::jsUndefined(); + + // ### don't go via QScriptValue + QScriptEnginePrivate *engine = static_cast<QScript::GlobalObject*>(exec->dynamicGlobalObject())->engine; + QScriptValue object = engine->scriptValueFromJSCValue(thisValue); + QObject *qobject = object.toQObject(); + while ((!qobject || (qobject->metaObject() != data->meta)) + && object.prototype().isObject()) { + object = object.prototype(); + qobject = object.toQObject(); + } + Q_ASSERT(qobject); + + QMetaProperty prop = data->meta->property(data->index); + Q_ASSERT(prop.isScriptable()); + if (args.size() == 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(engine); + } + + QVariant v = prop.read(qobject); + + if (scriptable) + QScriptablePrivate::get(scriptable)->engine = oldEngine; + + result = engine->jscValueFromVariant(v); + } + } else { + // set + Q_ASSERT_X(false, Q_FUNC_INFO, "check me"); + JSC::JSValue arg = args.at(0); + QVariant v; + if (prop.isEnumType() && arg.isString() + && !engine->hasDemarshalFunction(prop.userType())) { + // give QMetaProperty::write() a chance to convert from + // string to enum value + v = qtStringFromJSCUString(arg.toString(exec)); + } else { + // ### don't go via QScriptValue + QScriptValue tmp = engine->scriptValueFromJSCValue(arg); + v = variantFromValue(engine, prop.userType(), tmp); + } + + QScriptable *scriptable = scriptableFromQObject(qobject); + QScriptEngine *oldEngine = 0; + if (scriptable) { + oldEngine = QScriptablePrivate::get(scriptable)->engine; + QScriptablePrivate::get(scriptable)->engine = QScriptEnginePrivate::get(engine); + } + + prop.write(qobject, v); + + if (scriptable) + QScriptablePrivate::get(scriptable)->engine = oldEngine; + + result = arg; + } + return result; +} + const JSC::ClassInfo QObjectWrapperObject::info = { "QObject", 0, 0, 0 }; QObjectWrapperObject::QObjectWrapperObject( @@ -1017,13 +1157,21 @@ bool QObjectWrapperObject::getOwnPropertySlot(JSC::ExecState *exec, if (prop.isScriptable()) { if (!(opt & QScriptEngine::ExcludeSuperClassProperties) || (index >= meta->propertyOffset())) { - // ### use property getter function - JSC::JSValue val; - if (!prop.isValid()) - val = JSC::jsUndefined(); - else - val = eng->jscValueFromVariant(prop.read(qobject)); - slot.setValue(val); + if (GeneratePropertyFunctions) { + QtPropertyFunction *fun = new (exec)QtPropertyFunction( + meta, index, &exec->globalData(), + exec->dynamicGlobalObject()->functionStructure(), + propertyName); + data->cachedMembers.insert(name, fun); + slot.setGetterSlot(fun); + } else { + JSC::JSValue val; + if (!prop.isValid()) + val = JSC::jsUndefined(); + else + val = eng->jscValueFromVariant(prop.read(qobject)); + slot.setValue(val); + } return true; } } @@ -1100,6 +1248,8 @@ void QObjectWrapperObject::put(JSC::ExecState* exec, const JSC::Identifier& prop index = meta->indexOfProperty(name); if (index != -1) { + if (GeneratePropertyFunctions) + qWarning("Booo, the property setter should be called..."); QMetaProperty prop = meta->property(index); if (prop.isScriptable()) { if (!(opt & QScriptEngine::ExcludeSuperClassProperties) @@ -1173,7 +1323,6 @@ bool QObjectWrapperObject::getPropertyAttributes(JSC::ExecState *exec, const QScriptEngine::QObjectWrapOptions &opt = data->options; const QMetaObject *meta = qobject->metaObject(); - QScriptEnginePrivate *eng = static_cast<QScript::GlobalObject*>(exec->dynamicGlobalObject())->engine; int index = -1; if (name.contains('(')) { QByteArray normalized = QMetaObject::normalizedSignature(name); @@ -1236,6 +1385,18 @@ bool QObjectWrapperObject::getPropertyAttributes(JSC::ExecState *exec, return JSC::JSObject::getPropertyAttributes(exec, propertyName, attributes); } +JSC::JSValue QObjectWrapperObject::lookupGetter(JSC::ExecState* exec, const JSC::Identifier& propertyName) +{ + Q_ASSERT_X(false, Q_FUNC_INFO, "implement me"); + return JSC::JSObject::lookupGetter(exec, propertyName); +} + +JSC::JSValue QObjectWrapperObject::lookupSetter(JSC::ExecState* exec, const JSC::Identifier& propertyName) +{ + Q_ASSERT_X(false, Q_FUNC_INFO, "implement me"); + return JSC::JSObject::lookupSetter(exec, propertyName); +} + void QObjectWrapperObject::getPropertyNames(JSC::ExecState *exec, JSC::PropertyNameArray &propertyNames) { QObject *qobject = data->value; @@ -1298,7 +1459,7 @@ static JSC::JSValue JSC_HOST_CALL qobjectProtoFuncFindChild(JSC::ExecState *exec JSC::JSValue thisValue, const JSC::ArgList &args) { if (!thisValue.isObject(&QObjectWrapperObject::info)) - return throwError(exec, JSC::TypeError); + return throwError(exec, JSC::TypeError, "this object is not a QObject"); QObject *obj = static_cast<QObjectWrapperObject*>(JSC::asObject(thisValue))->value(); QString name; if (args.size() != 0) @@ -1313,7 +1474,7 @@ static JSC::JSValue JSC_HOST_CALL qobjectProtoFuncFindChildren(JSC::ExecState *e JSC::JSValue thisValue, const JSC::ArgList &args) { if (!thisValue.isObject(&QObjectWrapperObject::info)) - return throwError(exec, JSC::TypeError); + return throwError(exec, JSC::TypeError, "this object is not a QObject"); return throwError(exec, JSC::GeneralError, "QObject.prototype.findChildren not implemented"); } @@ -1321,7 +1482,7 @@ static JSC::JSValue JSC_HOST_CALL qobjectProtoFuncToString(JSC::ExecState *exec, JSC::JSValue thisValue, const JSC::ArgList&) { if (!thisValue.isObject(&QObjectWrapperObject::info)) - return throwError(exec, JSC::TypeError); + return throwError(exec, JSC::TypeError, "this object is not a QObject"); QObject *obj = static_cast<QObjectWrapperObject*>(JSC::asObject(thisValue))->value(); const QMetaObject *meta = obj ? obj->metaObject() : &QObject::staticMetaObject; QString name = obj ? obj->objectName() : QString::fromUtf8("unnamed"); @@ -1457,7 +1618,7 @@ static JSC::JSValue JSC_HOST_CALL qmetaobjectProtoFuncClassName( JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue thisValue, const JSC::ArgList&) { if (!thisValue.isObject(&QMetaObjectWrapperObject::info)) - return throwError(exec, JSC::TypeError); + return throwError(exec, JSC::TypeError, "this object is not a QMetaObject"); const QMetaObject *meta = static_cast<QMetaObjectWrapperObject*>(JSC::asObject(thisValue))->value(); return JSC::jsString(exec, meta->className()); } diff --git a/src/script/bridge/qscriptqobject_p.h b/src/script/bridge/qscriptqobject_p.h index b35b6ba..31f6446 100644 --- a/src/script/bridge/qscriptqobject_p.h +++ b/src/script/bridge/qscriptqobject_p.h @@ -76,6 +76,8 @@ public: virtual bool getPropertyAttributes(JSC::ExecState*, const JSC::Identifier&, unsigned&) const; virtual void getPropertyNames(JSC::ExecState*, JSC::PropertyNameArray&); + virtual JSC::JSValue lookupGetter(JSC::ExecState*, const JSC::Identifier& propertyName); + virtual JSC::JSValue lookupSetter(JSC::ExecState*, const JSC::Identifier& propertyName); virtual void mark(); virtual const JSC::ClassInfo* classInfo() const { return &info; } @@ -160,8 +162,11 @@ public: virtual const JSC::ClassInfo* classInfo() const { return &info; } static const JSC::ClassInfo info; - JSC::JSValue call(JSC::ExecState *exec, JSC::JSValue thisValue, - const JSC::ArgList &args); + static JSC::JSValue JSC_HOST_CALL call(JSC::ExecState*, JSC::JSObject*, + JSC::JSValue, const JSC::ArgList&); + + JSC::JSValue execute(JSC::ExecState *exec, JSC::JSValue thisValue, + const JSC::ArgList &args); QObjectWrapperObject *wrapperObject() const; QObject *qobject() const; @@ -176,6 +181,39 @@ private: Data *data; }; +class QtPropertyFunction: public JSC::InternalFunction +{ +public: + // work around CELL_SIZE limitation + struct Data + { + const QMetaObject *meta; + int index; + + Data(const QMetaObject *m, int i) + : meta(m), index(i) {} + }; + + QtPropertyFunction(const QMetaObject *meta, int index, + JSC::JSGlobalData*, WTF::PassRefPtr<JSC::Structure>, + const JSC::Identifier&); + virtual ~QtPropertyFunction(); + + virtual JSC::CallType getCallData(JSC::CallData&); + + virtual const JSC::ClassInfo* classInfo() const { return &info; } + static const JSC::ClassInfo info; + + static JSC::JSValue JSC_HOST_CALL call(JSC::ExecState*, JSC::JSObject*, + JSC::JSValue, const JSC::ArgList&); + + JSC::JSValue execute(JSC::ExecState *exec, JSC::JSValue thisValue, + const JSC::ArgList &args); + +private: + Data *data; +}; + class QMetaObjectWrapperObject : public JSC::JSObject { public: |