Initial import from the monolithic Qt.
[profile/ivi/qtdeclarative.git] / src / declarative / util / qdeclarativepropertymap.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qdeclarativepropertymap.h"
43
44 #include <private/qmetaobjectbuilder_p.h>
45 #include "private/qdeclarativeopenmetaobject_p.h"
46
47 #include <QDebug>
48
49 QT_BEGIN_NAMESPACE
50
51 //QDeclarativePropertyMapMetaObject lets us listen for changes coming from QML
52 //so we can emit the changed signal.
53 class QDeclarativePropertyMapMetaObject : public QDeclarativeOpenMetaObject
54 {
55 public:
56     QDeclarativePropertyMapMetaObject(QDeclarativePropertyMap *obj, QDeclarativePropertyMapPrivate *objPriv);
57
58 protected:
59     virtual void propertyWritten(int index);
60     virtual void propertyCreated(int, QMetaPropertyBuilder &);
61
62 private:
63     QDeclarativePropertyMap *map;
64     QDeclarativePropertyMapPrivate *priv;
65 };
66
67 class QDeclarativePropertyMapPrivate : public QObjectPrivate
68 {
69     Q_DECLARE_PUBLIC(QDeclarativePropertyMap)
70 public:
71     QDeclarativePropertyMapMetaObject *mo;
72     QStringList keys;
73     void emitChanged(const QString &key, const QVariant &value);
74 };
75
76 void QDeclarativePropertyMapPrivate::emitChanged(const QString &key, const QVariant &value)
77 {
78     Q_Q(QDeclarativePropertyMap);
79     emit q->valueChanged(key, value);
80 }
81
82 QDeclarativePropertyMapMetaObject::QDeclarativePropertyMapMetaObject(QDeclarativePropertyMap *obj, QDeclarativePropertyMapPrivate *objPriv) : QDeclarativeOpenMetaObject(obj)
83 {
84     map = obj;
85     priv = objPriv;
86 }
87
88 void QDeclarativePropertyMapMetaObject::propertyWritten(int index)
89 {
90     priv->emitChanged(QString::fromUtf8(name(index)), operator[](index));
91 }
92
93 void QDeclarativePropertyMapMetaObject::propertyCreated(int, QMetaPropertyBuilder &b)
94 {
95     priv->keys.append(QString::fromUtf8(b.name()));
96 }
97
98 /*!
99     \class QDeclarativePropertyMap
100     \since 4.7
101     \brief The QDeclarativePropertyMap class allows you to set key-value pairs that can be used in QML bindings.
102
103     QDeclarativePropertyMap provides a convenient way to expose domain data to the UI layer.
104     The following example shows how you might declare data in C++ and then
105     access it in QML.
106
107     In the C++ file:
108     \code
109     // create our data
110     QDeclarativePropertyMap ownerData;
111     ownerData.insert("name", QVariant(QString("John Smith")));
112     ownerData.insert("phone", QVariant(QString("555-5555")));
113
114     // expose it to the UI layer
115     QDeclarativeView view;
116     QDeclarativeContext *ctxt = view.rootContext();
117     ctxt->setContextProperty("owner", &ownerData);
118
119     view.setSource(QUrl::fromLocalFile("main.qml"));
120     view.show();
121     \endcode
122
123     Then, in \c main.qml:
124     \code
125     Text { text: owner.name + " " + owner.phone }
126     \endcode
127
128     The binding is dynamic - whenever a key's value is updated, anything bound to that
129     key will be updated as well.
130
131     To detect value changes made in the UI layer you can connect to the valueChanged() signal.
132     However, note that valueChanged() is \bold NOT emitted when changes are made by calling insert()
133     or clear() - it is only emitted when a value is updated from QML.
134
135     \note It is not possible to remove keys from the map; once a key has been added, you can only
136     modify or clear its associated value.
137 */
138
139 /*!
140     Constructs a bindable map with parent object \a parent.
141 */
142 QDeclarativePropertyMap::QDeclarativePropertyMap(QObject *parent)
143 : QObject(*(new QDeclarativePropertyMapPrivate), parent)
144 {
145     Q_D(QDeclarativePropertyMap);
146     d->mo = new QDeclarativePropertyMapMetaObject(this, d);
147 }
148
149 /*!
150     Destroys the bindable map.
151 */
152 QDeclarativePropertyMap::~QDeclarativePropertyMap()
153 {
154 }
155
156 /*!
157     Clears the value (if any) associated with \a key.
158 */
159 void QDeclarativePropertyMap::clear(const QString &key)
160 {
161     Q_D(QDeclarativePropertyMap);
162     d->mo->setValue(key.toUtf8(), QVariant());
163 }
164
165 /*!
166     Returns the value associated with \a key.
167
168     If no value has been set for this key (or if the value has been cleared),
169     an invalid QVariant is returned.
170 */
171 QVariant QDeclarativePropertyMap::value(const QString &key) const
172 {
173     Q_D(const QDeclarativePropertyMap);
174     return d->mo->value(key.toUtf8());
175 }
176
177 /*!
178     Sets the value associated with \a key to \a value.
179
180     If the key doesn't exist, it is automatically created.
181 */
182 void QDeclarativePropertyMap::insert(const QString &key, const QVariant &value)
183 {
184     Q_D(QDeclarativePropertyMap);
185     //The following strings shouldn't be used as property names
186     if (key != QLatin1String("keys")
187      && key != QLatin1String("valueChanged")
188      && key != QLatin1String("QObject")
189      && key != QLatin1String("destroyed")
190      && key != QLatin1String("deleteLater")) {
191         d->mo->setValue(key.toUtf8(), value);
192     } else {
193         qWarning() << "Creating property with name"
194                    << key
195                    << "is not permitted, conflicts with internal symbols.";
196     }
197 }
198
199 /*!
200     Returns the list of keys.
201
202     Keys that have been cleared will still appear in this list, even though their
203     associated values are invalid QVariants.
204 */
205 QStringList QDeclarativePropertyMap::keys() const
206 {
207     Q_D(const QDeclarativePropertyMap);
208     return d->keys;
209 }
210
211 /*!
212     \overload
213
214     Same as size().
215 */
216 int QDeclarativePropertyMap::count() const
217 {
218     Q_D(const QDeclarativePropertyMap);
219     return d->keys.count();
220 }
221
222 /*!
223     Returns the number of keys in the map.
224
225     \sa isEmpty(), count()
226 */
227 int QDeclarativePropertyMap::size() const
228 {
229     Q_D(const QDeclarativePropertyMap);
230     return d->keys.size();
231 }
232
233 /*!
234     Returns true if the map contains no keys; otherwise returns
235     false.
236
237     \sa size()
238 */
239 bool QDeclarativePropertyMap::isEmpty() const
240 {
241     Q_D(const QDeclarativePropertyMap);
242     return d->keys.isEmpty();
243 }
244
245 /*!
246     Returns true if the map contains \a key.
247
248     \sa size()
249 */
250 bool QDeclarativePropertyMap::contains(const QString &key) const
251 {
252     Q_D(const QDeclarativePropertyMap);
253     return d->keys.contains(key);
254 }
255
256 /*!
257     Returns the value associated with the key \a key as a modifiable
258     reference.
259
260     If the map contains no item with key \a key, the function inserts
261     an invalid QVariant into the map with key \a key, and
262     returns a reference to it.
263
264     \sa insert(), value()
265 */
266 QVariant &QDeclarativePropertyMap::operator[](const QString &key)
267 {
268     //### optimize
269     Q_D(QDeclarativePropertyMap);
270     QByteArray utf8key = key.toUtf8();
271     if (!d->keys.contains(key))
272         insert(key, QVariant());//force creation -- needed below
273
274     return (*(d->mo))[utf8key];
275 }
276
277 /*!
278     \overload
279
280     Same as value().
281 */
282 QVariant QDeclarativePropertyMap::operator[](const QString &key) const
283 {
284     return value(key);
285 }
286
287 /*!
288     \fn void QDeclarativePropertyMap::valueChanged(const QString &key, const QVariant &value)
289     This signal is emitted whenever one of the values in the map is changed. \a key
290     is the key corresponding to the \a value that was changed.
291
292     \note valueChanged() is \bold NOT emitted when changes are made by calling insert()
293     or clear() - it is only emitted when a value is updated from QML.
294 */
295
296 QT_END_NAMESPACE