Ensure that copy sequences can be passed as arguments
authorChris Adams <christopher.adams@nokia.com>
Wed, 8 Aug 2012 04:53:45 +0000 (14:53 +1000)
committerQt by Nokia <qt-info@nokia.com>
Thu, 9 Aug 2012 03:57:33 +0000 (05:57 +0200)
Previously, automatic conversion from JS array to sequence copy
resource was not performed in the case where the array was passed as
a parameter to a QObject function invocation.  This commit adds code
to check if the parameter type is a sequence type - and if so, and if
the value is a variantlist, we convert it to a sequence of the
appropriate type.

Change-Id: I3cc3e2f95604bc71d1d8d237e1acffa1e03b78ba
Reviewed-by: Glenn Watson <glenn.watson@nokia.com>
src/qml/qml/v8/qv8qobjectwrapper.cpp
src/qml/qml/v8/qv8sequencewrapper.cpp
src/qml/qml/v8/qv8sequencewrapper_p.h
tests/auto/qml/qqmlecmascript/data/sequenceConversion.copy.qml
tests/auto/qml/qqmlecmascript/testtypes.cpp
tests/auto/qml/qqmlecmascript/testtypes.h
tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp

index 5fce03a..01ab252 100644 (file)
@@ -2160,13 +2160,17 @@ void CallArgument::fromValue(int callType, QV8Engine *engine, v8::Handle<v8::Val
         type = -1;
 
         QQmlEnginePrivate *ep = engine->engine() ? QQmlEnginePrivate::get(engine->engine()) : 0;
-        QVariant v = engine->toVariant(value, -1);
+        QVariant v = engine->toVariant(value, -1); // why -1 instead of callType?
 
         if (v.userType() == callType) {
             *qvariantPtr = v;
         } else if (v.canConvert(callType)) {
             *qvariantPtr = v;
             qvariantPtr->convert(callType);
+        } else if (engine->sequenceWrapper()->isSequenceType(callType) && v.userType() == qMetaTypeId<QVariantList>()) {
+            // convert the JS array to a sequence of the correct type.
+            QVariant seqV = engine->toVariant(value, callType);
+            *qvariantPtr = seqV;
         } else {
             QQmlMetaObject mo = ep ? ep->rawMetaObjectForType(callType) : QQmlMetaObject();
             if (!mo.isNull()) {
index c4b4e66..03aeb85 100644 (file)
@@ -110,6 +110,17 @@ void QV8SequenceWrapper::destroy()
     qPersistentDispose(m_constructor);
 }
 
+#define IS_SEQUENCE(unused1, unused2, SequenceType, unused3) \
+    if (sequenceTypeId == qMetaTypeId<SequenceType>()) { \
+        return true; \
+    } else
+
+bool QV8SequenceWrapper::isSequenceType(int sequenceTypeId) const
+{
+    FOREACH_QML_SEQUENCE_TYPE(IS_SEQUENCE) { /* else */ return false; }
+}
+#undef IS_SEQUENCE
+
 bool QV8SequenceWrapper::isEqual(QV8ObjectResource *lhs, QV8ObjectResource *rhs)
 {
     Q_ASSERT(lhs && rhs && lhs->resourceType() == QV8ObjectResource::SequenceType && rhs->resourceType() == QV8ObjectResource::SequenceType);
index 141d6f4..111cea9 100644 (file)
@@ -71,6 +71,8 @@ public:
     void init(QV8Engine *);
     void destroy();
 
+    bool isSequenceType(int sequenceTypeId) const;
+
     bool isEqual(QV8ObjectResource *lhs, const QVariant &rhs);
     bool isEqual(QV8ObjectResource *lhs, QV8ObjectResource *rhs);
     quint32 sequenceLength(QV8ObjectResource *);
index f6614da..088e240 100644 (file)
@@ -157,4 +157,27 @@ Item {
         if (jsIntList == jsIntList2) success = false;
         if (jsIntList != jsIntList) success = false;
     }
+
+    // this test ensures that copy resource sequences can be passed as parameters
+    function testCopyParameters() {
+        success = false;
+
+        var jsIntList = msco.generateIntSequence();
+        success = msco.parameterEqualsGeneratedIntSequence(jsIntList);
+        if (success == false) return;
+
+        // here we construct something which should be converted to a copy sequence automatically.
+        success = msco.parameterEqualsGeneratedIntSequence([1,2,3]);
+    }
+
+    // this test ensures that reference resource sequences are converted
+    // to copy resource sequences when passed as parameters.
+    function testReferenceParameters() {
+        success = false;
+
+        msco.intListProperty = msco.generateIntSequence();
+        var jsIntList = msco.intListProperty
+        success = msco.parameterEqualsGeneratedIntSequence(jsIntList);
+        if (success == false) return;
+    }
 }
index 9669e37..a0bdbb6 100644 (file)
@@ -225,35 +225,17 @@ public:
     {
         return stringList;
     }
-    Q_INVOKABLE QList<int> integers(QVariant v) const
+    Q_INVOKABLE QList<int> integers(QList<int> v) const
     {
-        QList<int> intList;
-        QList<QVariant> vList = v.toList();
-        for (int i=0 ; i < vList.size() ; ++i) {
-            int iv = vList[i].toInt();
-            intList.append(iv);
-        }
-        return intList;
+        return v;
     }
-    Q_INVOKABLE QList<qreal> reals(QVariant v) const
+    Q_INVOKABLE QList<qreal> reals(QList<qreal> v) const
     {
-        QList<qreal> realList;
-        QList<QVariant> vList = v.toList();
-        for (int i=0 ; i < vList.size() ; ++i) {
-            qreal fv = vList[i].toReal();
-            realList.append(fv);
-        }
-        return realList;
+        return v;
     }
-    Q_INVOKABLE QList<bool> bools(QVariant v) const
+    Q_INVOKABLE QList<bool> bools(QList<bool> v) const
     {
-        QList<bool> boolList;
-        QList<QVariant> vList = v.toList();
-        for (int i=0 ; i < vList.size() ; ++i) {
-            bool bv = vList[i].toBool();
-            boolList.append(bv);
-        }
-        return boolList;
+        return v;
     }
 };
 
index c05405a..da6baa4 100644 (file)
@@ -1393,6 +1393,7 @@ public:
     Q_INVOKABLE QList<QString> generateStringSequence() const { QList<QString> retn; retn << "one" << "two" << "three"; return retn; }
     Q_INVOKABLE QList<QUrl> generateUrlSequence() const { QList<QUrl> retn; retn << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com"); return retn; }
     Q_INVOKABLE QStringList generateQStringSequence() const { QStringList retn; retn << "one" << "two" << "three"; return retn; }
+    Q_INVOKABLE bool parameterEqualsGeneratedIntSequence(const QList<int>& param) const { return (param == generateIntSequence()); }
 
     // "reference resource" underlying qobject deletion test:
     Q_INVOKABLE MySequenceConversionObject *generateTestObject() const { return new MySequenceConversionObject; }
index 6fa6c3b..55b76f1 100644 (file)
@@ -5569,6 +5569,10 @@ void tst_qqmlecmascript::sequenceConversionCopy()
     QCOMPARE(object->property("success").toBool(), true);
     QMetaObject::invokeMethod(object, "testEqualitySemantics");
     QCOMPARE(object->property("success").toBool(), true);
+    QMetaObject::invokeMethod(object, "testCopyParameters");
+    QCOMPARE(object->property("success").toBool(), true);
+    QMetaObject::invokeMethod(object, "testReferenceParameters");
+    QCOMPARE(object->property("success").toBool(), true);
     delete object;
 }