From: Jędrzej Nowacki Date: Fri, 16 Sep 2011 12:06:02 +0000 (+0200) Subject: Unwrap QJSValue from QVariant in QV8Engine::fromVariant X-Git-Tag: qt-v5.0.0-alpha1~1622 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8de9a07c654492a60726e84332bba43cc7b81dbd;p=profile%2Fivi%2Fqtdeclarative.git Unwrap QJSValue from QVariant in QV8Engine::fromVariant When QML tries to unwrap real value from a QVariant and the value is a QJSValue instance, then no conversion is needed, QJSValue already contains a v8 handle. This patch, for example, solves a problem of emitting QJSValue instance in a signal that has QVariant as an argument. The QJSValue can be unwrapped and used as a normal JS value in a connected slot. This feature may be used also in a plugin model that stores QJSValues internally. Then the model in data() function can return a QJSValue which would be understood by QML. Change-Id: I1d5ede40ce2637123b09839fd848b27ad3af3dda Reviewed-on: http://codereview.qt-project.org/4451 Reviewed-by: Kent Hansen Reviewed-by: Qt Sanity Bot --- diff --git a/src/declarative/qml/v8/qv8engine.cpp b/src/declarative/qml/v8/qv8engine.cpp index c10f048..7be74f8 100644 --- a/src/declarative/qml/v8/qv8engine.cpp +++ b/src/declarative/qml/v8/qv8engine.cpp @@ -341,6 +341,11 @@ v8::Handle QV8Engine::fromVariant(const QVariant &variant) } else { return v8::Null(); } + } else if (type == qMetaTypeId()) { + const QJSValue *value = reinterpret_cast(ptr); + QJSValuePrivate *valuep = QJSValuePrivate::get(*value); + if (valuep->assignEngine(this)) + return v8::Local::New(*valuep); } else if (type == qMetaTypeId >()) { // XXX Can this be made more by using Array as a prototype and implementing // directly against QList? @@ -358,7 +363,6 @@ v8::Handle QV8Engine::fromVariant(const QVariant &variant) } // XXX TODO: To be compatible, we still need to handle: - // + QJSValue // + QObjectList // + QList diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/signalWithJSValueInVariant.qml b/tests/auto/declarative/qdeclarativeecmascript/data/signalWithJSValueInVariant.qml new file mode 100644 index 0000000..a6f1aa3 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/signalWithJSValueInVariant.qml @@ -0,0 +1,12 @@ +import Qt.test 1.0 + +MyQmlObject { + property string expression + property string compare + property bool pass: false + onSignalWithVariant: + { + var expected = eval(expression); + pass = eval(compare)(arg, expected); + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/testtypes.h b/tests/auto/declarative/qdeclarativeecmascript/testtypes.h index 52b74af..ebe8cc5 100644 --- a/tests/auto/declarative/qdeclarativeecmascript/testtypes.h +++ b/tests/auto/declarative/qdeclarativeecmascript/testtypes.h @@ -170,6 +170,7 @@ signals: void anotherBasicSignal(); void thirdBasicSignal(); void signalWithUnknownType(const MyQmlObject::MyType &arg); + void signalWithVariant(const QVariant &arg); public slots: void deleteMe() { delete this; } diff --git a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp index 36941af..941765d 100644 --- a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp +++ b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp @@ -146,6 +146,10 @@ private slots: void numberAssignment(); void propertySplicing(); void signalWithUnknownTypes(); + void signalWithJSValueInVariant_data(); + void signalWithJSValueInVariant(); + void signalWithJSValueInVariant_twoEngines_data(); + void signalWithJSValueInVariant_twoEngines(); void moduleApi_data(); void moduleApi(); void importScripts(); @@ -2758,6 +2762,77 @@ void tst_qdeclarativeecmascript::signalWithUnknownTypes() delete object; } +void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data() +{ + QTest::addColumn("expression"); + QTest::addColumn("compare"); + + QString compareStrict("(function(a, b) { return a === b; })"); + QTest::newRow("true") << "true" << compareStrict; + QTest::newRow("undefined") << "undefined" << compareStrict; + QTest::newRow("null") << "null" << compareStrict; + QTest::newRow("123") << "123" << compareStrict; + QTest::newRow("'ciao'") << "'ciao'" << compareStrict; + + QString comparePropertiesStrict( + "(function(a, b) {" + " if (typeof b != 'object')" + " return a === b;" + " var props = Object.getOwnPropertyNames(b);" + " for (var i = 0; i < props.length; ++i) {" + " var p = props[i];" + " return arguments.callee(a[p], b[p]);" + " }" + "})"); + QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict; + QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict; +} + +void tst_qdeclarativeecmascript::signalWithJSValueInVariant() +{ + QFETCH(QString, expression); + QFETCH(QString, compare); + + QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml")); + QScopedPointer object(qobject_cast(component.create())); + QVERIFY(object != 0); + + QJSValue value = engine.evaluate(expression); + QVERIFY(!engine.hasUncaughtException()); + object->setProperty("expression", expression); + object->setProperty("compare", compare); + object->setProperty("pass", false); + + emit object->signalWithVariant(QVariant::fromValue(value)); + QVERIFY(object->property("pass").toBool()); +} + +void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data() +{ + signalWithJSValueInVariant_data(); +} + +void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines() +{ + QFETCH(QString, expression); + QFETCH(QString, compare); + + QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml")); + QScopedPointer object(qobject_cast(component.create())); + QVERIFY(object != 0); + + QJSEngine engine2; + QJSValue value = engine2.evaluate(expression); + QVERIFY(!engine2.hasUncaughtException()); + object->setProperty("expression", expression); + object->setProperty("compare", compare); + object->setProperty("pass", false); + + QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine."); + emit object->signalWithVariant(QVariant::fromValue(value)); + QVERIFY(!object->property("pass").toBool()); +} + void tst_qdeclarativeecmascript::moduleApi_data() { QTest::addColumn("testfile");