diff options
author | Warwick Allison <warwick.allison@nokia.com> | 2010-02-19 07:18:42 (GMT) |
---|---|---|
committer | Warwick Allison <warwick.allison@nokia.com> | 2010-02-19 07:18:42 (GMT) |
commit | b988ef5a3d9ac96cfa7b9fd4b87522bbab84ffce (patch) | |
tree | db065658178c6a2387f8e289ff303b2bf87aa421 | |
parent | b442982fed0f1c40eb936babbba197ce09e28c37 (diff) | |
download | Qt-b988ef5a3d9ac96cfa7b9fd4b87522bbab84ffce.zip Qt-b988ef5a3d9ac96cfa7b9fd4b87522bbab84ffce.tar.gz Qt-b988ef5a3d9ac96cfa7b9fd4b87522bbab84ffce.tar.bz2 |
More strict type checking of ListElement properties.
Task-number: QTBUG-6203
-rw-r--r-- | examples/declarative/listview/content/ClickAutoRepeating.qml | 1 | ||||
-rw-r--r-- | examples/declarative/listview/dynamic.qml | 5 | ||||
-rw-r--r-- | src/declarative/QmlChanges.txt | 8 | ||||
-rw-r--r-- | src/declarative/util/qmllistmodel.cpp | 42 | ||||
-rw-r--r-- | tests/auto/declarative/qmllistmodel/tst_qmllistmodel.cpp | 57 |
5 files changed, 99 insertions, 14 deletions
diff --git a/examples/declarative/listview/content/ClickAutoRepeating.qml b/examples/declarative/listview/content/ClickAutoRepeating.qml index 796f9e3..be37b50 100644 --- a/examples/declarative/listview/content/ClickAutoRepeating.qml +++ b/examples/declarative/listview/content/ClickAutoRepeating.qml @@ -11,6 +11,7 @@ Item { signal clicked isPressed: SequentialAnimation { + running: false id: autoRepeat PropertyAction { target: page; property: "isPressed"; value: true } ScriptAction { script: page.pressed() } diff --git a/examples/declarative/listview/dynamic.qml b/examples/declarative/listview/dynamic.qml index 2607527..dd898f9 100644 --- a/examples/declarative/listview/dynamic.qml +++ b/examples/declarative/listview/dynamic.qml @@ -24,7 +24,6 @@ Rectangle { } ListElement { name: "Cumquat"; cost: 3.25 - types: [ "Small", "Smaller" ] attributes: [ ListElement { description: "Citrus" } ] @@ -82,12 +81,12 @@ Rectangle { anchors.right: removeButton.left; anchors.rightMargin: 35; spacing: 10 width: childrenRect.width; anchors.verticalCenter: parent.verticalCenter Image { source: "content/pics/list-add.png" - ClickAutoRepeating { id: clickUp; anchors.fill: parent; onClicked: fruitModel.set(index,"cost",Number(cost)+0.25) } + ClickAutoRepeating { id: clickUp; anchors.fill: parent; onClicked: fruitModel.setProperty(index,"cost",cost+0.25) } scale: clickUp.isPressed ? 0.9 : 1; transformOrigin: Item.Center } Text { id: costText; text: '$'+Number(cost).toFixed(2); font.pixelSize: 15; color: "White"; font.bold: true; } Image { source: "content/pics/list-remove.png" - ClickAutoRepeating { id: clickDown; anchors.fill: parent; onClicked: fruitModel.set(index,"cost",Math.max(0,Number(cost)-0.25)) } + ClickAutoRepeating { id: clickDown; anchors.fill: parent; onClicked: fruitModel.setProperty(index,"cost",Math.max(0,cost-0.25)) } scale: clickDown.isPressed ? 0.9 : 1; transformOrigin: Item.Center } } diff --git a/src/declarative/QmlChanges.txt b/src/declarative/QmlChanges.txt index 3a709e8..e3aab65 100644 --- a/src/declarative/QmlChanges.txt +++ b/src/declarative/QmlChanges.txt @@ -18,6 +18,14 @@ reinforced. sectionExpression has been replaced by section.property, section.criteria +ListModel +--------- +- types are strictly checked (previously, everything was a string) + - foo: "bar" continues to work as before + - foo: bar is now invalid, use foo: "bar" + - foo: true is now a bool (not string "true") + - foo: false is now a bool (not string "false" == true!) + ============================================================================= The changes below are pre-4.6.0 release. diff --git a/src/declarative/util/qmllistmodel.cpp b/src/declarative/util/qmllistmodel.cpp index ee35d2e..af41dfd 100644 --- a/src/declarative/util/qmllistmodel.cpp +++ b/src/declarative/util/qmllistmodel.cpp @@ -806,7 +806,23 @@ bool QmlListModelParser::compileProperty(const QmlCustomParserProperty &prop, QL qvariant_cast<QmlParser::Variant>(value); int ref = data.count(); - QByteArray d = variant.asScript().toUtf8(); + + QByteArray d; + d += char(variant.type()); // type tag + if (variant.isString()) { + d += variant.asString().toUtf8(); + } else if (variant.isNumber()) { + d += QByteArray::number(variant.asNumber(),'g',20); + } else if (variant.isBoolean()) { + d += char(variant.asBoolean()); + } else if (variant.isScript()) { + if (definesEmptyList(variant.asScript())) { + d[0] = 0; // QmlParser::Variant::Invalid - marks empty list + } else { + error(prop, QmlListModel::tr("ListElement: cannot use script for property value")); + return false; + } + } d.append('\0'); data.append(d); @@ -814,7 +830,6 @@ bool QmlListModelParser::compileProperty(const QmlCustomParserProperty &prop, QL li.type = ListInstruction::Value; li.dataIdx = ref; instr << li; - } } @@ -892,15 +907,22 @@ void QmlListModelParser::setCustomData(QObject *obj, const QByteArray &d) case ListInstruction::Value: { ModelNode *n = nodes.top(); - QString s = QString::fromUtf8(QByteArray(data + instr.dataIdx)); - - bool isEmptyList = false; - if (!n->isArray) - isEmptyList = definesEmptyList(s); - if (isEmptyList) + switch (QmlParser::Variant::Type(data[instr.dataIdx])) { + case QmlParser::Variant::Invalid: n->isArray = true; - else - n->values.append(s); + break; + case QmlParser::Variant::Boolean: + n->values.append(bool(data[1 + instr.dataIdx])); + break; + case QmlParser::Variant::Number: + n->values.append(QByteArray(data + 1 + instr.dataIdx).toDouble()); + break; + case QmlParser::Variant::String: + n->values.append(QString::fromUtf8(data + 1 + instr.dataIdx)); + break; + default: + Q_ASSERT("Format error in ListInstruction"); + } processingSet = false; } diff --git a/tests/auto/declarative/qmllistmodel/tst_qmllistmodel.cpp b/tests/auto/declarative/qmllistmodel/tst_qmllistmodel.cpp index fa45a01..e70c7f1 100644 --- a/tests/auto/declarative/qmllistmodel/tst_qmllistmodel.cpp +++ b/tests/auto/declarative/qmllistmodel/tst_qmllistmodel.cpp @@ -51,6 +51,8 @@ public: tst_QmlListModel() {} private slots: + void static_types(); + void static_types_data(); void static_i18n(); void static_nestedElements(); void static_nestedElements_data(); @@ -223,6 +225,59 @@ void tst_QmlListModel::dynamic() QCOMPARE(actual,result); } +void tst_QmlListModel::static_types_data() +{ + QTest::addColumn<QString>("qml"); + QTest::addColumn<QVariant>("value"); + + QTest::newRow("string") + << "ListElement { foo: \"bar\" }" + << QVariant(QString("bar")); + + QTest::newRow("real") + << "ListElement { foo: 10.5 }" + << QVariant(10.5); + + QTest::newRow("real0") + << "ListElement { foo: 0 }" + << QVariant(double(0)); + + QTest::newRow("bool") + << "ListElement { foo: false }" + << QVariant(false); + + QTest::newRow("bool") + << "ListElement { foo: true }" + << QVariant(true); +} + +void tst_QmlListModel::static_types() +{ + QFETCH(QString, qml); + QFETCH(QVariant, value); + + qml = "import Qt 4.6\nListModel { " + qml + " }"; + + QmlEngine engine; + QmlComponent component(&engine); + component.setData(qml.toUtf8(), + QUrl::fromLocalFile(QString("dummy.qml"))); + QVERIFY(!component.isError()); + + QmlListModel *obj = qobject_cast<QmlListModel*>(component.create()); + QVERIFY(obj != 0); + + QScriptValue actual = obj->get(0).property(QLatin1String("foo")); + + QCOMPARE(actual.isString(), value.type() == QVariant::String); + QCOMPARE(actual.isBoolean(), value.type() == QVariant::Bool); + QCOMPARE(actual.isNumber(), value.type() == QVariant::Double); + + QCOMPARE(actual.toString(), value.toString()); + + delete obj; +} + void tst_QmlListModel::error_data() { QTest::addColumn<QString>("qml"); @@ -246,7 +301,7 @@ void tst_QmlListModel::error_data() QTest::newRow("bindings not allowed in ListElement") << "import Qt 4.6\nRectangle { id: rect; ListModel { ListElement { foo: rect.color } } }" - << "QTBUG-6203 ListElement should not allow binding its data to something"; + << "ListElement: cannot use script for property value"; QTest::newRow("random object list properties allowed in ListElement") << "import Qt 4.6\nListModel { ListElement { foo: [ ListElement { bar: 123 } ] } }" |