diff options
-rw-r--r-- | examples/declarative/listview/dynamic.qml | 60 | ||||
-rw-r--r-- | src/declarative/util/qmllistmodel.cpp | 126 | ||||
-rw-r--r-- | src/declarative/util/qmllistmodel.h | 8 |
3 files changed, 136 insertions, 58 deletions
diff --git a/examples/declarative/listview/dynamic.qml b/examples/declarative/listview/dynamic.qml index 58ce4b4..f615c24 100644 --- a/examples/declarative/listview/dynamic.qml +++ b/examples/declarative/listview/dynamic.qml @@ -1,43 +1,75 @@ import Qt 4.6 Item { - width: 300 - height: 300 + width: 320 + height: 500 ListModel { id: FruitModel ListElement { name: "Apple" cost: 2.45 + attributes: [ + ListElement { description: "Core" }, + ListElement { description: "Deciduous" } + ] } ListElement { name: "Banana" cost: 1.95 + attributes: [ + ListElement { description: "Tropical" }, + ListElement { description: "Seedless" } + ] } ListElement { name: "Cumquat" cost: 3.25 + types: [ "Small", "Smaller" ] + attributes: [ + ListElement { description: "Citrus" } + ] } ListElement { name: "Durian" cost: 9.95 + attributes: [ + ListElement { description: "Tropical" }, + ListElement { description: "Smelly" } + ] } ListElement { name: "Elderberry" cost: 0.05 + attributes: [ + ListElement { description: "Berry" } + ] } ListElement { name: "Fig" cost: 0.25 + attributes: [ + ListElement { description: "Flower" } + ] } } Component { id: FruitDelegate Item { - width: parent.width; height: 35 - Text { font.pixelSize: 24; text: name } + width: parent.width; height: 55 + Text { id: Label; font.pixelSize: 24; text: name } Text { font.pixelSize: 24; text: '$'+Number(cost).toFixed(2); anchors.right: ItemButtons.left } + Row { + anchors.top: Label.bottom + spacing: 5 + Repeater { + model: attributes + Component { + Text { text: description } + } + } + } Row { id: ItemButtons anchors.right: parent.right @@ -79,10 +111,26 @@ Item { anchors.bottom: parent.bottom id: Buttons Image { source: "content/pics/add.png" - MouseRegion { anchors.fill: parent; onClicked: FruitModel.append({"name":"Pizza", "cost":5.95}) } + MouseRegion { anchors.fill: parent; + onClicked: { + FruitModel.append({ + "name":"Pizza Margarita", + "cost":5.95, + "attributes":[{"description": "Cheese"},{"description": "Tomato"}] + }) + } + } } Image { source: "content/pics/add.png" - MouseRegion { anchors.fill: parent; onClicked: FruitModel.insert(0,{"name":"Pizza", "cost":5.95}) } + MouseRegion { anchors.fill: parent; + onClicked: { + FruitModel.insert(0,{ + "name":"Pizza Supreme", + "cost":9.95, + "attributes":[{"description": "Cheese"},{"description": "Tomato"},{"description": "The Works"}] + }) + } + } } Image { source: "content/pics/trash.png" MouseRegion { anchors.fill: parent; onClicked: FruitModel.clear() } diff --git a/src/declarative/util/qmllistmodel.cpp b/src/declarative/util/qmllistmodel.cpp index 5b7d2bb..f988d81 100644 --- a/src/declarative/util/qmllistmodel.cpp +++ b/src/declarative/util/qmllistmodel.cpp @@ -47,6 +47,7 @@ #include "qmlopenmetaobject.h" #include <qmlcontext.h> #include "qmllistmodel.h" +#include <QtScript/qscriptvalueiterator.h> Q_DECLARE_METATYPE(QListModelInterface *) @@ -68,6 +69,8 @@ struct ListModelData ListInstruction *instructions() const { return (ListInstruction *)((char *)this + sizeof(ListModelData)); } }; +static void dump(ModelNode *node, int ind); + /*! \qmlclass ListModel \brief The ListModel element defines a free-form list data source. @@ -140,7 +143,7 @@ struct ListModelData name: "Banana" cost: 1.95 attributes: [ - ListElement { description: "Tropical" } + ListElement { description: "Tropical" }, ListElement { description: "Seedless" } ] } @@ -197,7 +200,7 @@ class ModelObject : public QObject { Q_OBJECT public: - ModelObject(ModelNode *); + ModelObject(); void setValue(const QByteArray &name, const QVariant &val) { @@ -205,8 +208,6 @@ public: } private: - ModelNode *_node; - bool _haveProperties; QmlOpenMetaObject *_mo; }; @@ -228,7 +229,7 @@ struct ModelNode ModelObject *object() { if (!objectCache) { - objectCache = new ModelObject(this); + objectCache = new ModelObject(); QHash<QString, ModelNode *>::iterator it; for (it = properties.begin(); it != properties.end(); ++it) { if (!(*it)->values.isEmpty()) @@ -238,6 +239,42 @@ struct ModelNode return objectCache; } + void setListValue(const QScriptValue& valuelist) { + QScriptValueIterator it(valuelist); + values.clear(); + while (it.hasNext()) { + it.next(); + ModelNode *value = new ModelNode; + QScriptValue v = it.value(); + if (v.isArray()) { + value->setListValue(v); + } else if (v.isObject()) { + value->setObjectValue(v); + } else { + value->values << v.toVariant(); + } + values.append(qVariantFromValue(value)); + + } + } + + void setObjectValue(const QScriptValue& valuemap) { + QScriptValueIterator it(valuemap); + while (it.hasNext()) { + it.next(); + ModelNode *value = new ModelNode; + QScriptValue v = it.value(); + if (v.isArray()) { + value->setListValue(v); + } else if (v.isObject()) { + value->setObjectValue(v); + } else { + value->values << v.toVariant(); + } + properties.insert(it.name(),value); + } + } + void setProperty(const QString& prop, const QVariant& val) { QHash<QString, ModelNode *>::const_iterator it = properties.find(prop); if (it != properties.end()) { @@ -255,8 +292,8 @@ struct ModelNode ModelObject *objectCache; }; -ModelObject::ModelObject(ModelNode *node) -: _node(node), _haveProperties(false), _mo(new QmlOpenMetaObject(this)) +ModelObject::ModelObject() +: _mo(new QmlOpenMetaObject(this)) { } @@ -424,26 +461,22 @@ void QmlListModel::remove(int index) FruitModel.insert(2, {"cost": 5.95, "name":"Pizza"}) \endcode - If \a index is not in the list, sufficient empty items are - added to the list. + The \a index must be to an existing item in the list, or one past + the end of the list (equivalent to append). \sa set() append() */ -void QmlListModel::insert(int index, const QVariantMap& valuemap) +void QmlListModel::insert(int index, const QScriptValue& valuemap) { if (!_root) _root = new ModelNode; if (index >= _root->values.count()) { - set(index,valuemap); + if (index == _root->values.count()) + append(valuemap); return; } ModelNode *mn = new ModelNode; - for (QVariantMap::const_iterator it=valuemap.begin(); it!=valuemap.end(); ++it) { - addRole(it.key()); - ModelNode *value = new ModelNode; - value->values << it.value(); - mn->properties.insert(it.key(),value); - } + mn->setObjectValue(valuemap); _root->values.insert(index,qVariantFromValue(mn)); emit itemsInserted(index,1); } @@ -506,17 +539,16 @@ void QmlListModel::move(int from, int to, int n) \sa set() remove() */ -void QmlListModel::append(const QVariantMap& valuemap) +void QmlListModel::append(const QScriptValue& valuemap) { + if (!valuemap.isObject()) { + qWarning("ListModel::append: value is not an object"); + return; + } if (!_root) _root = new ModelNode; ModelNode *mn = new ModelNode; - for (QVariantMap::const_iterator it=valuemap.begin(); it!=valuemap.end(); ++it) { - addRole(it.key()); - ModelNode *value = new ModelNode; - value->values << it.value(); - mn->properties.insert(it.key(),value); - } + mn->setObjectValue(valuemap); _root->values << qVariantFromValue(mn); emit itemsInserted(count()-1,1); } @@ -531,37 +563,35 @@ void QmlListModel::append(const QVariantMap& valuemap) FruitModel.set(3, {"cost": 5.95, "name":"Pizza"}) \endcode - If \a index is not in the list, sufficient empty items are - added to the list. + The \a index must be an element in the list. \sa append() */ -void QmlListModel::set(int index, const QVariantMap& valuemap) +void QmlListModel::set(int index, const QScriptValue& valuemap) { if (!_root) _root = new ModelNode; - int initialcount = _root->values.count(); - while (index > _root->values.count()) - _root->values.append(qVariantFromValue(new ModelNode)); + if ( index >= _root->values.count()) { + qWarning() << "ListModel::set index out of range:" << index; + return; + } if (index == _root->values.count()) append(valuemap); else { ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index)); QList<int> roles; - for (QVariantMap::const_iterator it=valuemap.begin(); it!=valuemap.end(); ++it) { - node->setProperty(it.key(),it.value()); - int r = roleStrings.indexOf(it.key()); + node->setObjectValue(valuemap); + QScriptValueIterator it(valuemap); + while (it.hasNext()) { + it.next(); + int r = roleStrings.indexOf(it.name()); if (r<0) { r = roleStrings.count(); - roleStrings << it.key(); + roleStrings << it.name(); } roles.append(r); } - if (initialcount < index) { - emit itemsInserted(initialcount,index-initialcount+1); - } else { - emit itemsChanged(index,1,roles); - } + emit itemsChanged(index,1,roles); } } @@ -574,8 +604,7 @@ void QmlListModel::set(int index, const QVariantMap& valuemap) FruitModel.set(3, "cost", 5.95) \endcode - If \a index is not in the list, sufficient empty items are - added to the list. + The \a index must be an element in the list. \sa append() */ @@ -583,9 +612,10 @@ void QmlListModel::set(int index, const QString& property, const QVariant& value { if (!_root) _root = new ModelNode; - int initialcount = _root->values.count(); - while (index >= _root->values.count()) - _root->values.append(qVariantFromValue(new ModelNode)); + if ( index >= _root->values.count()) { + qWarning() << "ListModel::set index out of range:" << index; + return; + } ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index)); int r = roleStrings.indexOf(property); if (r<0) { @@ -597,10 +627,7 @@ void QmlListModel::set(int index, const QString& property, const QVariant& value if (node) node->setProperty(property,value); - if (initialcount < index) - emit itemsInserted(initialcount,index-initialcount+1); - else - emit itemsChanged(index,1,roles); + emit itemsChanged(index,1,roles); } @@ -806,7 +833,8 @@ ModelNode::~ModelNode() ModelNode *node = qvariant_cast<ModelNode *>(values.at(ii)); if (node) { delete node; node = 0; } } - if (modelCache) { delete modelCache; modelCache = 0; } + if (modelCache) { modelCache->_root = 0/* ==this */; delete modelCache; modelCache = 0; } + if (objectCache) { delete objectCache; } } QT_END_NAMESPACE diff --git a/src/declarative/util/qmllistmodel.h b/src/declarative/util/qmllistmodel.h index 8bef347..7bb94cf 100644 --- a/src/declarative/util/qmllistmodel.h +++ b/src/declarative/util/qmllistmodel.h @@ -50,6 +50,8 @@ #include <QtDeclarative/qfxglobal.h> #include <QtDeclarative/qml.h> #include <QtDeclarative/qlistmodelinterface.h> +#include <QtScript/qscriptvalue.h> + QT_BEGIN_HEADER @@ -74,9 +76,9 @@ public: Q_INVOKABLE void clear(); Q_INVOKABLE void remove(int index); - Q_INVOKABLE void append(const QVariantMap& valuemap); - Q_INVOKABLE void insert(int index, const QVariantMap& valuemap); - Q_INVOKABLE void set(int index, const QVariantMap& valuemap); + Q_INVOKABLE void append(const QScriptValue&); + Q_INVOKABLE void insert(int index, const QScriptValue&); + Q_INVOKABLE void set(int index, const QScriptValue&); Q_INVOKABLE void set(int index, const QString& property, const QVariant& value); Q_INVOKABLE void move(int from, int to, int count); |