From: Chris Adams Date: Wed, 2 Nov 2011 00:21:37 +0000 (+1000) Subject: Add support for assigning literal value to sequence property X-Git-Url: http://git.silmor.de/gitweb/?a=commitdiff_plain;h=fdbdbbdd4ff05d1ceb7667227db5b14687a77c96;p=konrad%2Fqtdeclarative.git Add support for assigning literal value to sequence property It is a language semantic that we allow clients to assign a single value to a sequence/list property (assuming that the types match). Now that we support sequence types, this commit adds support for this semantic by determining whether the built-in type of the literal corresponds to the associated sequence (eg, int for QList, qreal for QList, bool for QList, QString for QStringList etc). Similarly, some value types can be constructed from literal string values (via string converters) and these need to be handled also. Task-number: QTBUG-18062 Task-number: QTBUG-21770 Change-Id: Iacd91b2af122cd8f20b7df2fa6056a7d7c52bf53 Reviewed-by: Aaron Kennedy --- diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp index 9b80c2c..3b47e20 100644 --- a/src/declarative/qml/qdeclarativecompiler.cpp +++ b/src/declarative/qml/qdeclarativecompiler.cpp @@ -72,6 +72,12 @@ #include #include +Q_DECLARE_METATYPE(QList) +Q_DECLARE_METATYPE(QList) +Q_DECLARE_METATYPE(QList) +Q_DECLARE_METATYPE(QList) +Q_DECLARE_METATYPE(QList) + QT_BEGIN_NAMESPACE DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP); @@ -235,6 +241,9 @@ bool QDeclarativeCompiler::testLiteralAssignment(QDeclarativeScript::Property *p case QVariant::String: if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected")); break; + case QVariant::StringList: // we expect a string literal. A string list is not a literal assignment. + if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or string list expected")); + break; case QVariant::ByteArray: if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: byte array expected")); break; @@ -344,6 +353,41 @@ bool QDeclarativeCompiler::testLiteralAssignment(QDeclarativeScript::Property *p break; default: { + // check if assigning a literal value to a list property. + // in each case, check the singular, since an Array of the specified type + // will not go via this literal assignment codepath. + if (type == qMetaTypeId >()) { + if (!v->value.isNumber()) { + COMPILE_EXCEPTION(v, tr("Invalid property assignment: real or array of reals expected")); + } + break; + } else if (type == qMetaTypeId >()) { + bool ok = v->value.isNumber(); + if (ok) { + double n = v->value.asNumber(); + if (double(int(n)) != n) + ok = false; + } + if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int or array of ints expected")); + break; + } else if (type == qMetaTypeId >()) { + if (!v->value.isBoolean()) { + COMPILE_EXCEPTION(v, tr("Invalid property assignment: bool or array of bools expected")); + } + break; + } else if (type == qMetaTypeId >()) { // we expect a string literal. A string list is not a literal assignment. + if (!v->value.isString()) { + COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or array of strings expected")); + } + break; + } else if (type == qMetaTypeId >()) { + if (!v->value.isString()) { + COMPILE_EXCEPTION(v, tr("Invalid property assignment: url or array of urls expected")); + } + break; + } + + // otherwise, check for existence of string converter to custom type QDeclarativeMetaType::StringConverter converter = QDeclarativeMetaType::customStringConverter(type); if (!converter) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName((QVariant::Type)type)))); @@ -440,6 +484,14 @@ void QDeclarativeCompiler::genLiteralAssignment(QDeclarativeScript::Property *pr output->addInstruction(instr); } break; + case QVariant::StringList: + { + Instruction::StoreStringList instr; + instr.propertyIndex = prop->index; + instr.value = output->indexForString(v->value.asString()); + output->addInstruction(instr); + } + break; case QVariant::ByteArray: { Instruction::StoreByteArray instr; @@ -638,6 +690,43 @@ void QDeclarativeCompiler::genLiteralAssignment(QDeclarativeScript::Property *pr break; default: { + // generate single literal value assignment to a list property if required + if (type == qMetaTypeId >()) { + Instruction::StoreDoubleQList instr; + instr.propertyIndex = prop->index; + instr.value = v->value.asNumber(); + output->addInstruction(instr); + break; + } else if (type == qMetaTypeId >()) { + Instruction::StoreIntegerQList instr; + instr.propertyIndex = prop->index; + instr.value = int(v->value.asNumber()); + output->addInstruction(instr); + break; + } else if (type == qMetaTypeId >()) { + Instruction::StoreBoolQList instr; + bool b = v->value.asBoolean(); + instr.propertyIndex = prop->index; + instr.value = b; + output->addInstruction(instr); + break; + } else if (type == qMetaTypeId >()) { + Instruction::StoreUrlQList instr; + QString string = v->value.asString(); + QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string)); + instr.propertyIndex = prop->index; + instr.value = output->indexForUrl(u); + output->addInstruction(instr); + break; + } else if (type == qMetaTypeId >()) { + Instruction::StoreStringQList instr; + instr.propertyIndex = prop->index; + instr.value = output->indexForString(v->value.asString()); + output->addInstruction(instr); + break; + } + + // otherwise, generate custom type literal assignment Instruction::AssignCustomType instr; instr.propertyIndex = prop->index; instr.primitive = output->indexForString(v->value.asString()); diff --git a/src/declarative/qml/qdeclarativeinstruction.cpp b/src/declarative/qml/qdeclarativeinstruction.cpp index 5f8b253..da5c290 100644 --- a/src/declarative/qml/qdeclarativeinstruction.cpp +++ b/src/declarative/qml/qdeclarativeinstruction.cpp @@ -93,21 +93,39 @@ void QDeclarativeCompiledData::dump(QDeclarativeInstruction *instr, int idx) case QDeclarativeInstruction::StoreDouble: qWarning().nospace() << idx << "\t\t" << "STORE_DOUBLE\t\t" << instr->storeDouble.propertyIndex << "\t" << instr->storeDouble.value; break; + case QDeclarativeInstruction::StoreDoubleQList: + qWarning().nospace() << idx << "\t\t" << "STORE_DOUBLE_QLIST\t\t" << instr->storeDouble.propertyIndex << "\t" << instr->storeDouble.value; + break; case QDeclarativeInstruction::StoreInteger: qWarning().nospace() << idx << "\t\t" << "STORE_INTEGER\t\t" << instr->storeInteger.propertyIndex << "\t" << instr->storeInteger.value; break; + case QDeclarativeInstruction::StoreIntegerQList: + qWarning().nospace() << idx << "\t\t" << "STORE_INTEGER_QLIST\t\t" << instr->storeInteger.propertyIndex << "\t" << instr->storeInteger.value; + break; case QDeclarativeInstruction::StoreBool: qWarning().nospace() << idx << "\t\t" << "STORE_BOOL\t\t" << instr->storeBool.propertyIndex << "\t" << instr->storeBool.value; break; + case QDeclarativeInstruction::StoreBoolQList: + qWarning().nospace() << idx << "\t\t" << "STORE_BOOL_QLIST\t\t" << instr->storeBool.propertyIndex << "\t" << instr->storeBool.value; + break; case QDeclarativeInstruction::StoreString: qWarning().nospace() << idx << "\t\t" << "STORE_STRING\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value); break; + case QDeclarativeInstruction::StoreStringList: + qWarning().nospace() << idx << "\t\t" << "STORE_STRINGLIST\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value); + break; + case QDeclarativeInstruction::StoreStringQList: + qWarning().nospace() << idx << "\t\t" << "STORE_STRING_QLIST\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value); + break; case QDeclarativeInstruction::StoreByteArray: qWarning().nospace() << idx << "\t\t" << "STORE_BYTEARRAY" << instr->storeByteArray.propertyIndex << "\t" << instr->storeByteArray.value << "\t\t" << datas.at(instr->storeByteArray.value); break; case QDeclarativeInstruction::StoreUrl: qWarning().nospace() << idx << "\t\t" << "STORE_URL\t\t" << instr->storeUrl.propertyIndex << "\t" << instr->storeUrl.value << "\t\t" << urls.at(instr->storeUrl.value); break; + case QDeclarativeInstruction::StoreUrlQList: + qWarning().nospace() << idx << "\t\t" << "STORE_URL_QLIST\t\t" << instr->storeUrl.propertyIndex << "\t" << instr->storeUrl.value << "\t\t" << urls.at(instr->storeUrl.value); + break; case QDeclarativeInstruction::StoreColor: qWarning().nospace() << idx << "\t\t" << "STORE_COLOR\t\t" << instr->storeColor.propertyIndex << "\t\t\t" << QString::number(instr->storeColor.value, 16); break; diff --git a/src/declarative/qml/qdeclarativeinstruction_p.h b/src/declarative/qml/qdeclarativeinstruction_p.h index d73ce46..b36a664 100644 --- a/src/declarative/qml/qdeclarativeinstruction_p.h +++ b/src/declarative/qml/qdeclarativeinstruction_p.h @@ -79,12 +79,18 @@ QT_BEGIN_NAMESPACE F(StoreVarDouble, storeDouble) \ F(StoreVarBool, storeBool) \ F(StoreString, storeString) \ + F(StoreStringList, storeString) \ + F(StoreStringQList, storeString) \ F(StoreByteArray, storeByteArray) \ F(StoreUrl, storeUrl) \ + F(StoreUrlQList, storeUrl) \ F(StoreFloat, storeFloat) \ F(StoreDouble, storeDouble) \ + F(StoreDoubleQList, storeDouble) \ F(StoreBool, storeBool) \ + F(StoreBoolQList, storeBool) \ F(StoreInteger, storeInteger) \ + F(StoreIntegerQList, storeInteger) \ F(StoreColor, storeColor) \ F(StoreDate, storeDate) \ F(StoreTime, storeTime) \ diff --git a/src/declarative/qml/qdeclarativeproperty.cpp b/src/declarative/qml/qdeclarativeproperty.cpp index d6a2776..795283c 100644 --- a/src/declarative/qml/qdeclarativeproperty.cpp +++ b/src/declarative/qml/qdeclarativeproperty.cpp @@ -61,6 +61,12 @@ #include +Q_DECLARE_METATYPE(QList) +Q_DECLARE_METATYPE(QList) +Q_DECLARE_METATYPE(QList) +Q_DECLARE_METATYPE(QList) +Q_DECLARE_METATYPE(QList) + QT_BEGIN_NAMESPACE /*! @@ -1285,6 +1291,59 @@ bool QDeclarativePropertyPrivate::write(QObject *object, } } } + if (!ok) { + // the only other option is that they are assigning a single value + // to a sequence type property (eg, an int to a QList property). + if (variantType == QVariant::Int && propertyType == qMetaTypeId >()) { + QList list; + list << value.toInt(); + v = QVariant::fromValue >(list); + ok = true; + } else if (variantType == QVariant::Double && propertyType == qMetaTypeId >()) { + QList list; + list << value.toReal(); + v = QVariant::fromValue >(list); + ok = true; + } else if (variantType == QVariant::Bool && propertyType == qMetaTypeId >()) { + QList list; + list << value.toBool(); + v = QVariant::fromValue >(list); + ok = true; + } else if ((variantType == QVariant::Url || variantType == QVariant::String || variantType == QVariant::ByteArray) + && propertyType == qMetaTypeId >()) { + QUrl u; + bool found = false; + if (variantType == QVariant::Url) { + u = value.toUrl(); + found = true; + } else if (variantType == QVariant::ByteArray) { + u = QUrl(QString::fromUtf8(value.toByteArray())); + found = true; + } else if (variantType == QVariant::String) { + u = QUrl(value.toString()); + found = true; + } + if (!found) + return false; + if (context && u.isRelative() && !u.isEmpty()) + u = context->resolvedUrl(u); + QList list; + list << u; + v = QVariant::fromValue >(list); + ok = true; + } else if (variantType == QVariant::String && propertyType == qMetaTypeId >()) { + QList list; + list << value.toString(); + v = QVariant::fromValue >(list); + ok = true; + } else if (variantType == QVariant::String && propertyType == qMetaTypeId()) { + QStringList list; + list << value.toString(); + v = QVariant::fromValue(list); + ok = true; + } + } + if (ok) { void *a[] = { (void *)v.constData(), 0, &status, &flags}; QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a); @@ -1358,6 +1417,10 @@ bool QDeclarativePropertyPrivate::writeBinding(QObject *object, value = v8engine->toVariant(result, qMetaTypeId >()); } else if (result->IsNull() && core.isQObject()) { value = QVariant::fromValue((QObject *)0); + } else if (core.propType == qMetaTypeId >()) { + value = v8engine->toVariant(result, qMetaTypeId >()); + if (value.userType() == qMetaTypeId()) + value = QVariant(QUrl(value.toString())); } else if (!isVmeProperty) { value = v8engine->toVariant(result, type); } diff --git a/src/declarative/qml/qdeclarativevme.cpp b/src/declarative/qml/qdeclarativevme.cpp index 313d7f1..a6fc8ba 100644 --- a/src/declarative/qml/qdeclarativevme.cpp +++ b/src/declarative/qml/qdeclarativevme.cpp @@ -624,6 +624,27 @@ QObject *QDeclarativeVME::run(QList *errors, instr.propertyIndex, a); QML_END_INSTR(StoreString) + QML_BEGIN_INSTR(StoreStringList) + QObject *target = objects.top(); + CLEAN_PROPERTY(target, instr.propertyIndex); + + QStringList stringlist(PRIMITIVES.at(instr.value)); + void *a[] = { (void *)&stringlist, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.propertyIndex, a); + QML_END_INSTR(StoreStringList) + + QML_BEGIN_INSTR(StoreStringQList) + QObject *target = objects.top(); + CLEAN_PROPERTY(target, instr.propertyIndex); + + QList stringqlist; + stringqlist.append(PRIMITIVES.at(instr.value)); + void *a[] = { (void *)&stringqlist, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.propertyIndex, a); + QML_END_INSTR(StoreStringQList) + QML_BEGIN_INSTR(StoreByteArray) QObject *target = objects.top(); void *a[] = { (void *)&DATAS.at(instr.value), 0, &status, &flags }; @@ -640,6 +661,17 @@ QObject *QDeclarativeVME::run(QList *errors, instr.propertyIndex, a); QML_END_INSTR(StoreUrl) + QML_BEGIN_INSTR(StoreUrlQList) + QObject *target = objects.top(); + CLEAN_PROPERTY(target, instr.propertyIndex); + + QList urlqlist; + urlqlist.append(URLS.at(instr.value)); + void *a[] = { (void *)&urlqlist, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.propertyIndex, a); + QML_END_INSTR(StoreUrlQList) + QML_BEGIN_INSTR(StoreFloat) QObject *target = objects.top(); CLEAN_PROPERTY(target, instr.propertyIndex); @@ -660,6 +692,17 @@ QObject *QDeclarativeVME::run(QList *errors, instr.propertyIndex, a); QML_END_INSTR(StoreDouble) + QML_BEGIN_INSTR(StoreDoubleQList) + QObject *target = objects.top(); + CLEAN_PROPERTY(target, instr.propertyIndex); + + QList doubleqlist; + doubleqlist.append(instr.value); + void *a[] = { (void *)&doubleqlist, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.propertyIndex, a); + QML_END_INSTR(StoreDoubleQList) + QML_BEGIN_INSTR(StoreBool) QObject *target = objects.top(); CLEAN_PROPERTY(target, instr.propertyIndex); @@ -669,6 +712,17 @@ QObject *QDeclarativeVME::run(QList *errors, instr.propertyIndex, a); QML_END_INSTR(StoreBool) + QML_BEGIN_INSTR(StoreBoolQList) + QObject *target = objects.top(); + CLEAN_PROPERTY(target, instr.propertyIndex); + + QList boolqlist; + boolqlist.append(instr.value); + void *a[] = { (void *)&boolqlist, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.propertyIndex, a); + QML_END_INSTR(StoreBoolQList) + QML_BEGIN_INSTR(StoreInteger) QObject *target = objects.top(); CLEAN_PROPERTY(target, instr.propertyIndex); @@ -678,6 +732,17 @@ QObject *QDeclarativeVME::run(QList *errors, instr.propertyIndex, a); QML_END_INSTR(StoreInteger) + QML_BEGIN_INSTR(StoreIntegerQList) + QObject *target = objects.top(); + CLEAN_PROPERTY(target, instr.propertyIndex); + + QList intqlist; + intqlist.append(instr.value); + void *a[] = { (void *)&intqlist, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.propertyIndex, a); + QML_END_INSTR(StoreIntegerQList) + QML_BEGIN_INSTR(StoreColor) QObject *target = objects.top(); CLEAN_PROPERTY(target, instr.propertyIndex); diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.1.qml b/tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.1.qml new file mode 100644 index 0000000..be283fd --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.1.qml @@ -0,0 +1,11 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +MySequenceConversionObject { + intListProperty: [1, 2] + qrealListProperty: [1.1, 2.2] + boolListProperty: [false, true] + urlListProperty: [ "http://www.example1.com", "http://www.example2.com" ] + stringListProperty: [ "one", "two" ] + qstringListProperty: [ "one", "two" ] +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.2.qml b/tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.2.qml new file mode 100644 index 0000000..c8fb28b --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.2.qml @@ -0,0 +1,11 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +MySequenceConversionObject { + intListProperty: 1 + qrealListProperty: 1.1 + boolListProperty: false + urlListProperty: "http://www.example1.com" + stringListProperty: "one" + qstringListProperty: "two" +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.3.qml b/tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.3.qml new file mode 100644 index 0000000..ad8a92e --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.3.qml @@ -0,0 +1,9 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +MySequenceConversionObject { + intListProperty: 1 + qrealListProperty: 1.1 + boolListProperty: false + urlListProperty: Qt.resolvedUrl("example.html") +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.4.qml b/tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.4.qml new file mode 100644 index 0000000..a9f2e64 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.4.qml @@ -0,0 +1,13 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +MySequenceConversionObject { + Component.onCompleted: { + intListProperty = [1, 2] + qrealListProperty = [1.1, 2.2] + boolListProperty = [false, true] + urlListProperty = [ "http://www.example1.com", "http://www.example2.com" ] + stringListProperty = [ "one", "two" ] + qstringListProperty = [ "one", "two" ] + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.5.qml b/tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.5.qml new file mode 100644 index 0000000..b8697e4 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.5.qml @@ -0,0 +1,13 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +MySequenceConversionObject { + Component.onCompleted: { + intListProperty = 1; + qrealListProperty = 1.1; + boolListProperty = false; + urlListProperty = "http://www.example1.com"; + stringListProperty = "one"; + qstringListProperty = "two"; + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.6.qml b/tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.6.qml new file mode 100644 index 0000000..7a794eb --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/assignSequenceTypes.6.qml @@ -0,0 +1,11 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +MySequenceConversionObject { + Component.onCompleted: { + intListProperty = 1; + qrealListProperty = 1.1; + boolListProperty = false; + urlListProperty = Qt.resolvedUrl("example.html"); + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp index 3fdf1e9..52e7661 100644 --- a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp +++ b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp @@ -177,8 +177,10 @@ private slots: void sequenceConversionThreads(); void sequenceConversionBindings(); void sequenceConversionCopy(); + void assignSequenceTypes(); void qtbug_22464(); void qtbug_21580(); + void bug1(); void bug2(); void dynamicCreationCrash(); @@ -4320,6 +4322,89 @@ void tst_qdeclarativeecmascript::sequenceConversionCopy() delete object; } +void tst_qdeclarativeecmascript::assignSequenceTypes() +{ + // test binding array to sequence type property + { + QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.1.qml")); + MySequenceConversionObject *object = qobject_cast(component.create()); + QVERIFY(object != 0); + QCOMPARE(object->intListProperty(), (QList() << 1 << 2)); + QCOMPARE(object->qrealListProperty(), (QList() << 1.1 << 2.2)); + QCOMPARE(object->boolListProperty(), (QList() << false << true)); + QCOMPARE(object->urlListProperty(), (QList() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com"))); + QCOMPARE(object->stringListProperty(), (QList() << QLatin1String("one") << QLatin1String("two"))); + QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two"))); + delete object; + } + + // test binding literal to sequence type property + { + QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.2.qml")); + MySequenceConversionObject *object = qobject_cast(component.create()); + QVERIFY(object != 0); + QCOMPARE(object->intListProperty(), (QList() << 1)); + QCOMPARE(object->qrealListProperty(), (QList() << 1.1)); + QCOMPARE(object->boolListProperty(), (QList() << false)); + QCOMPARE(object->urlListProperty(), (QList() << QUrl("http://www.example1.com"))); + QCOMPARE(object->stringListProperty(), (QList() << QLatin1String("one"))); + QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two"))); + delete object; + } + + // test binding single value to sequence type property + { + QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.3.qml")); + MySequenceConversionObject *object = qobject_cast(component.create()); + QVERIFY(object != 0); + QCOMPARE(object->intListProperty(), (QList() << 1)); + QCOMPARE(object->qrealListProperty(), (QList() << 1.1)); + QCOMPARE(object->boolListProperty(), (QList() << false)); + QCOMPARE(object->urlListProperty(), (QList() << QUrl(TEST_FILE("example.html")))); + delete object; + } + + // test assigning array to sequence type property in js function + { + QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.4.qml")); + MySequenceConversionObject *object = qobject_cast(component.create()); + QVERIFY(object != 0); + QCOMPARE(object->intListProperty(), (QList() << 1 << 2)); + QCOMPARE(object->qrealListProperty(), (QList() << 1.1 << 2.2)); + QCOMPARE(object->boolListProperty(), (QList() << false << true)); + QCOMPARE(object->urlListProperty(), (QList() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com"))); + QCOMPARE(object->stringListProperty(), (QList() << QLatin1String("one") << QLatin1String("two"))); + QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two"))); + delete object; + } + + // test assigning literal to sequence type property in js function + { + QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.5.qml")); + MySequenceConversionObject *object = qobject_cast(component.create()); + QVERIFY(object != 0); + QCOMPARE(object->intListProperty(), (QList() << 1)); + QCOMPARE(object->qrealListProperty(), (QList() << 1.1)); + QCOMPARE(object->boolListProperty(), (QList() << false)); + QCOMPARE(object->urlListProperty(), (QList() << QUrl("http://www.example1.com"))); + QCOMPARE(object->stringListProperty(), (QList() << QLatin1String("one"))); + QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two"))); + delete object; + } + + // test assigning single value to sequence type property in js function + { + QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.6.qml")); + MySequenceConversionObject *object = qobject_cast(component.create()); + QVERIFY(object != 0); + QCOMPARE(object->intListProperty(), (QList() << 1)); + QCOMPARE(object->qrealListProperty(), (QList() << 1.1)); + QCOMPARE(object->boolListProperty(), (QList() << false)); + QCOMPARE(object->urlListProperty(), (QList() << QUrl(TEST_FILE("example.html")))); + delete object; + } +} + // Test that assigning a null object works // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4 void tst_qdeclarativeecmascript::nullObjectBinding()