From 1208d2800d4810a472262d8e04f0cf3a59a3efdb Mon Sep 17 00:00:00 2001
From: Michael Brasser <michael.brasser@nokia.com>
Date: Wed, 21 Oct 2009 14:57:07 +1000
Subject: Give QmlPropertyMap a more complete API.

---
 src/declarative/util/qmlopenmetaobject.cpp         |   8 ++
 src/declarative/util/qmlopenmetaobject.h           |   1 +
 src/declarative/util/qmlpropertymap.cpp            | 105 ++++++++++++++++++---
 src/declarative/util/qmlpropertymap.h              |  14 ++-
 .../qmlpropertymap/tst_qmlpropertymap.cpp          |  51 ++++++++--
 5 files changed, 152 insertions(+), 27 deletions(-)

diff --git a/src/declarative/util/qmlopenmetaobject.cpp b/src/declarative/util/qmlopenmetaobject.cpp
index 7305362..11648f6 100644
--- a/src/declarative/util/qmlopenmetaobject.cpp
+++ b/src/declarative/util/qmlopenmetaobject.cpp
@@ -136,6 +136,14 @@ QVariant QmlOpenMetaObject::value(const QByteArray &name) const
     return d->data.at(*iter);
 }
 
+QVariant &QmlOpenMetaObject::operator[](const QByteArray &name)
+{
+    QHash<QByteArray, int>::ConstIterator iter = d->names.find(name);
+    Q_ASSERT(iter != d->names.end());
+
+    return d->data[*iter];
+}
+
 void QmlOpenMetaObject::setValue(const QByteArray &name, const QVariant &val)
 {
     QHash<QByteArray, int>::ConstIterator iter = d->names.find(name);
diff --git a/src/declarative/util/qmlopenmetaobject.h b/src/declarative/util/qmlopenmetaobject.h
index f65660d..be0490d 100644
--- a/src/declarative/util/qmlopenmetaobject.h
+++ b/src/declarative/util/qmlopenmetaobject.h
@@ -64,6 +64,7 @@ public:
     void setValue(const QByteArray &, const QVariant &);
     QVariant value(int) const;
     void setValue(int, const QVariant &);
+    QVariant &operator[](const QByteArray &);
 
     int count() const;
     QByteArray name(int) const;
diff --git a/src/declarative/util/qmlpropertymap.cpp b/src/declarative/util/qmlpropertymap.cpp
index 0a92a8b..a587af3 100644
--- a/src/declarative/util/qmlpropertymap.cpp
+++ b/src/declarative/util/qmlpropertymap.cpp
@@ -72,7 +72,7 @@ public:
 void QmlPropertyMapPrivate::emitChanged(const QString &key)
 {
     Q_Q(QmlPropertyMap);
-    emit q->changed(key);
+    emit q->valueChanged(key);
 }
 
 QmlPropertyMapMetaObject::QmlPropertyMapMetaObject(QmlPropertyMap *obj, QmlPropertyMapPrivate *objPriv) : QmlOpenMetaObject(obj)
@@ -98,8 +98,8 @@ void QmlPropertyMapMetaObject::propertyWrite(int index)
     \code
     //create our data
     QmlPropertyMap ownerData;
-    ownerData.setValue("name", QVariant(QString("John Smith")));
-    ownerData.setValue("phone", QVariant(QString("555-5555")));
+    ownerData.insert("name", QVariant(QString("John Smith")));
+    ownerData.insert("phone", QVariant(QString("555-5555")));
 
     //expose it to the UI layer
     QmlContext *ctxt = view->bindContext();
@@ -115,16 +115,13 @@ void QmlPropertyMapMetaObject::propertyWrite(int index)
     The binding is dynamic - whenever a key's value is updated, anything bound to that
     key will be updated as well.
 
-    To detect value changes made in the UI layer you can connect to the changed() signal.
-    However, note that changed() is \b NOT emitted when changes are made by calling setValue()
-    or clearValue() - it is only emitted when a value is updated from QML.
-*/
+    To detect value changes made in the UI layer you can connect to the valueChanged() signal.
+    However, note that valueChanged() is \b NOT emitted when changes are made by calling insert()
+    or clear() - it is only emitted when a value is updated from QML.
 
-// is there a more efficient way to store/return keys?
-//        (or should we just provide an iterator or something else instead?)
-// can we provide a way to clear keys?
-// do we want to make any claims regarding key ordering?
-// should we have signals for insertion and and deletion -- becoming more model like
+    \note It is not possible to remove keys from the map; once a key has been added, you can only
+    modify or clear its associated value.
+*/
 
 /*!
     Constructs a bindable map with parent object \a parent.
@@ -146,7 +143,7 @@ QmlPropertyMap::~QmlPropertyMap()
 /*!
     Clears the value (if any) associated with \a key.
 */
-void QmlPropertyMap::clearValue(const QString &key)
+void QmlPropertyMap::clear(const QString &key)
 {
     Q_D(QmlPropertyMap);
     d->mo->setValue(key.toUtf8(), QVariant());
@@ -169,7 +166,7 @@ QVariant QmlPropertyMap::value(const QString &key) const
 
     If the key doesn't exist, it is automatically created.
 */
-void QmlPropertyMap::setValue(const QString &key, const QVariant &value)
+void QmlPropertyMap::insert(const QString &key, const QVariant &value)
 {
     Q_D(QmlPropertyMap);
     if (!d->keys.contains(key))
@@ -190,7 +187,85 @@ QStringList QmlPropertyMap::keys() const
 }
 
 /*!
-    \fn void QmlPropertyMap::changed(const QString &key)
+    \overload
+
+    Same as size().
+*/
+int QmlPropertyMap::count() const
+{
+    Q_D(const QmlPropertyMap);
+    return d->keys.count();
+}
+
+/*!
+    Returns the number of keys in the map.
+
+    \sa isEmpty(), count()
+*/
+int QmlPropertyMap::size() const
+{
+    Q_D(const QmlPropertyMap);
+    return d->keys.size();
+}
+
+/*!
+    Returns true if the map contains no keys; otherwise returns
+    false.
+
+    \sa size()
+*/
+bool QmlPropertyMap::isEmpty() const
+{
+    Q_D(const QmlPropertyMap);
+    return d->keys.isEmpty();
+}
+
+/*!
+    Returns true if the map contains \a key.
+
+    \sa size()
+*/
+bool QmlPropertyMap::contains(const QString &key) const
+{
+    Q_D(const QmlPropertyMap);
+    return d->keys.contains(key);
+}
+
+/*!
+    Returns the value associated with the key \a key as a modifiable
+    reference.
+
+    If the map contains no item with key \a key, the function inserts
+    an invalid QVariant into the map with key \a key, and
+    returns a reference to it.
+
+    \sa insert(), value()
+*/
+QVariant &QmlPropertyMap::operator[](const QString &key)
+{
+    //### optimize
+    Q_D(QmlPropertyMap);
+    QByteArray utf8key = key.toUtf8();
+    if (!d->keys.contains(key)) {
+        d->keys.append(key);
+        d->mo->setValue(utf8key, QVariant());   //force creation -- needed below
+    }
+
+    return (*(d->mo))[utf8key];
+}
+
+/*!
+    \overload
+
+    Same as value().
+*/
+const QVariant QmlPropertyMap::operator[](const QString &key) const
+{
+    return value(key);
+}
+
+/*!
+    \fn void QmlPropertyMap::valueChanged(const QString &key)
     This signal is emitted whenever one of the values in the map is changed. \a key
     is the key corresponding to the value that was changed.
 */
diff --git a/src/declarative/util/qmlpropertymap.h b/src/declarative/util/qmlpropertymap.h
index 295f4b7..24b4395 100644
--- a/src/declarative/util/qmlpropertymap.h
+++ b/src/declarative/util/qmlpropertymap.h
@@ -63,13 +63,21 @@ public:
     virtual ~QmlPropertyMap();
 
     QVariant value(const QString &key) const;
-    void setValue(const QString &key, const QVariant &value);
-    void clearValue(const QString &key);
+    void insert(const QString &key, const QVariant &value);
+    void clear(const QString &key);
 
     Q_INVOKABLE QStringList keys() const;
 
+    int count() const;
+    int size() const;
+    bool isEmpty() const;
+    bool contains(const QString &key) const;
+
+    QVariant &operator[](const QString &key);
+    const QVariant operator[](const QString &key) const;
+
 Q_SIGNALS:
-    void changed(const QString &key);
+    void valueChanged(const QString &key);
 
 private:
     Q_DECLARE_PRIVATE(QmlPropertyMap)
diff --git a/tests/auto/declarative/qmlpropertymap/tst_qmlpropertymap.cpp b/tests/auto/declarative/qmlpropertymap/tst_qmlpropertymap.cpp
index a923234..7d3cc43 100644
--- a/tests/auto/declarative/qmlpropertymap/tst_qmlpropertymap.cpp
+++ b/tests/auto/declarative/qmlpropertymap/tst_qmlpropertymap.cpp
@@ -14,33 +14,49 @@ public:
 
 private slots:
     void insert();
+    void operatorInsert();
     void clear();
     void changed();
+    void count();
 };
 
 void tst_QmlPropertyMap::insert()
 {
     QmlPropertyMap map;
-    map.setValue(QLatin1String("key1"),100);
-    map.setValue(QLatin1String("key2"),200);
+    map.insert(QLatin1String("key1"),100);
+    map.insert(QLatin1String("key2"),200);
     QVERIFY(map.keys().count() == 2);
 
     QCOMPARE(map.value(QLatin1String("key1")), QVariant(100));
     QCOMPARE(map.value(QLatin1String("key2")), QVariant(200));
 
-    map.setValue(QLatin1String("key1"),"Hello World");
+    map.insert(QLatin1String("key1"),"Hello World");
+    QCOMPARE(map.value(QLatin1String("key1")), QVariant("Hello World"));
+}
+
+void tst_QmlPropertyMap::operatorInsert()
+{
+    QmlPropertyMap map;
+    map[QLatin1String("key1")] = 100;
+    map[QLatin1String("key2")] = 200;
+    QVERIFY(map.keys().count() == 2);
+
+    QCOMPARE(map.value(QLatin1String("key1")), QVariant(100));
+    QCOMPARE(map.value(QLatin1String("key2")), QVariant(200));
+
+    map[QLatin1String("key1")] = "Hello World";
     QCOMPARE(map.value(QLatin1String("key1")), QVariant("Hello World"));
 }
 
 void tst_QmlPropertyMap::clear()
 {
     QmlPropertyMap map;
-    map.setValue(QLatin1String("key1"),100);
+    map.insert(QLatin1String("key1"),100);
     QVERIFY(map.keys().count() == 1);
 
     QCOMPARE(map.value(QLatin1String("key1")), QVariant(100));
 
-    map.clearValue(QLatin1String("key1"));
+    map.clear(QLatin1String("key1"));
     QVERIFY(map.keys().count() == 1);
     QCOMPARE(map.value(QLatin1String("key1")), QVariant());
 }
@@ -48,12 +64,12 @@ void tst_QmlPropertyMap::clear()
 void tst_QmlPropertyMap::changed()
 {
     QmlPropertyMap map;
-    QSignalSpy spy(&map, SIGNAL(changed(const QString&)));
-    map.setValue(QLatin1String("key1"),100);
-    map.setValue(QLatin1String("key2"),200);
+    QSignalSpy spy(&map, SIGNAL(valueChanged(const QString&)));
+    map.insert(QLatin1String("key1"),100);
+    map.insert(QLatin1String("key2"),200);
     QCOMPARE(spy.count(), 0);
 
-    map.clearValue(QLatin1String("key1"));
+    map.clear(QLatin1String("key1"));
     QCOMPARE(spy.count(), 0);
 
     //make changes in QML
@@ -72,6 +88,23 @@ void tst_QmlPropertyMap::changed()
     QCOMPARE(map.value(QLatin1String("key1")), QVariant("Hello World"));
 }
 
+void tst_QmlPropertyMap::count()
+{
+    QmlPropertyMap map;
+    QCOMPARE(map.isEmpty(), true);
+    map.insert(QLatin1String("key1"),100);
+    map.insert(QLatin1String("key2"),200);
+    QCOMPARE(map.count(), 2);
+    QCOMPARE(map.isEmpty(), false);
+
+    map.insert(QLatin1String("key3"),"Hello World");
+    QCOMPARE(map.count(), 3);
+
+    //clearing doesn't remove the key
+    map.clear(QLatin1String("key3"));
+    QCOMPARE(map.count(), 3);
+}
+
 QTEST_MAIN(tst_QmlPropertyMap)
 
 #include "tst_qmlpropertymap.moc"
-- 
cgit v0.12