summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWarwick Allison <warwick.allison@nokia.com>2010-02-19 07:18:42 (GMT)
committerWarwick Allison <warwick.allison@nokia.com>2010-02-19 07:18:42 (GMT)
commitb988ef5a3d9ac96cfa7b9fd4b87522bbab84ffce (patch)
treedb065658178c6a2387f8e289ff303b2bf87aa421
parentb442982fed0f1c40eb936babbba197ce09e28c37 (diff)
downloadQt-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.qml1
-rw-r--r--examples/declarative/listview/dynamic.qml5
-rw-r--r--src/declarative/QmlChanges.txt8
-rw-r--r--src/declarative/util/qmllistmodel.cpp42
-rw-r--r--tests/auto/declarative/qmllistmodel/tst_qmllistmodel.cpp57
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 } ] } }"