Remove "All rights reserved" line from license headers.
[profile/ivi/qtdeclarative.git] / src / qtquick1 / graphicsitems / qdeclarativerepeater.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "QtQuick1/private/qdeclarativerepeater_p.h"
43 #include "QtQuick1/private/qdeclarativerepeater_p_p.h"
44
45 #include "QtQuick1/private/qdeclarativevisualitemmodel_p.h"
46 #include <QtDeclarative/private/qdeclarativeglobal_p.h>
47 #include <QtQuick1/private/qdeclarativelistaccessor_p.h>
48
49 QT_BEGIN_NAMESPACE
50
51
52 QDeclarative1RepeaterPrivate::QDeclarative1RepeaterPrivate()
53 : model(0), ownModel(false)
54 {
55 }
56
57 QDeclarative1RepeaterPrivate::~QDeclarative1RepeaterPrivate()
58 {
59     if (ownModel)
60         delete model;
61 }
62
63 /*!
64     \qmlclass Repeater QDeclarative1Repeater
65     \inqmlmodule QtQuick 1
66     \ingroup qml-utility-elements
67     \since QtQuick 1.0
68     \inherits Item
69
70     \brief The Repeater element allows you to repeat an Item-based component using a model.
71
72     The Repeater element is used to create a large number of
73     similar items. Like other view elements, a Repeater has a \l model and a \l delegate:
74     for each entry in the model, the delegate is instantiated
75     in a context seeded with data from the model. A Repeater item is usually
76     enclosed in a positioner element such as \l Row or \l Column to visually
77     position the multiple delegate items created by the Repeater.
78
79     The following Repeater creates three instances of a \l Rectangle item within
80     a \l Row:
81
82     \snippet doc/src/snippets/qtquick1/repeaters/repeater.qml import
83     \codeline
84     \snippet doc/src/snippets/qtquick1/repeaters/repeater.qml simple
85
86     \image repeater-simple.png
87
88     A Repeater's \l model can be any of the supported \l {qmlmodels}{data models}.
89     Additionally, like delegates for other views, a Repeater delegate can access
90     its index within the repeater, as well as the model data relevant to the
91     delegate. See the \l delegate property documentation for details.
92
93     Items instantiated by the Repeater are inserted, in order, as
94     children of the Repeater's parent.  The insertion starts immediately after
95     the repeater's position in its parent stacking list.  This allows
96     a Repeater to be used inside a layout. For example, the following Repeater's
97     items are stacked between a red rectangle and a blue rectangle:
98
99     \snippet doc/src/snippets/qtquick1/repeaters/repeater.qml layout
100
101     \image repeater.png
102
103
104     \note A Repeater item owns all items it instantiates. Removing or dynamically destroying
105     an item created by a Repeater results in unpredictable behavior.
106
107
108     \section2 Considerations when using Repeater
109
110     The Repeater element creates all of its delegate items when the repeater is first
111     created. This can be inefficient if there are a large number of delegate items and
112     not all of the items are required to be visible at the same time. If this is the case,
113     consider using other view elements like ListView (which only creates delegate items 
114     when they are scrolled into view) or use the \l {Dynamic Object Creation} methods to 
115     create items as they are required.
116
117     Also, note that Repeater is \l {Item}-based, and can only repeat \l {Item}-derived objects. 
118     For example, it cannot be used to repeat QtObjects:
119     \badcode
120     Item {
121         //XXX does not work! Can't repeat QtObject as it doesn't derive from Item.
122         Repeater {
123             model: 10
124             QtObject {}
125         }
126     }
127     \endcode
128  */
129
130 /*!
131     \qmlsignal QtQuick1::Repeater::onItemAdded(int index, Item item)
132     \since Quick 1.1
133
134     This handler is called when an item is added to the repeater. The \a index
135     parameter holds the index at which the item has been inserted within the
136     repeater, and the \a item parameter holds the \l Item that has been added.
137 */
138
139 /*!
140     \qmlsignal QtQuick1::Repeater::onItemRemoved(int index, Item item)
141     \since Quick 1.1
142
143     This handler is called when an item is removed from the repeater. The \a index
144     parameter holds the index at which the item was removed from the repeater,
145     and the \a item parameter holds the \l Item that was removed.
146
147     Do not keep a reference to \a item if it was created by this repeater, as
148     in these cases it will be deleted shortly after the handler is called.
149 */
150
151 QDeclarative1Repeater::QDeclarative1Repeater(QDeclarativeItem *parent)
152   : QDeclarativeItem(*(new QDeclarative1RepeaterPrivate), parent)
153 {
154 }
155
156 QDeclarative1Repeater::~QDeclarative1Repeater()
157 {
158 }
159
160 /*!
161     \qmlproperty any QtQuick1::Repeater::model
162
163     The model providing data for the repeater.
164
165     This property can be set to any of the supported \l {qmlmodels}{data models}:
166
167     \list
168     \o A number that indicates the number of delegates to be created by the repeater
169     \o A model (e.g. a ListModel item, or a QAbstractItemModel subclass)
170     \o A string list
171     \o An object list
172     \endlist
173
174     The type of model affects the properties that are exposed to the \l delegate.
175
176     \sa {qmlmodels}{Data Models}
177 */
178 QVariant QDeclarative1Repeater::model() const
179 {
180     Q_D(const QDeclarative1Repeater);
181     return d->dataSource;
182 }
183
184 void QDeclarative1Repeater::setModel(const QVariant &model)
185 {
186     Q_D(QDeclarative1Repeater);
187     if (d->dataSource == model)
188         return;
189
190     clear();
191     if (d->model) {
192         disconnect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
193         disconnect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
194         disconnect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
195         disconnect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
196         /*
197         disconnect(d->model, SIGNAL(createdItem(int,QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*)));
198         disconnect(d->model, SIGNAL(destroyingItem(QDeclarativeItem*)), this, SLOT(destroyingItem(QDeclarativeItem*)));
199     */
200     }
201     d->dataSource = model;
202     QObject *object = qvariant_cast<QObject*>(model);
203     QDeclarative1VisualModel *vim = 0;
204     if (object && (vim = qobject_cast<QDeclarative1VisualModel *>(object))) {
205         if (d->ownModel) {
206             delete d->model;
207             d->ownModel = false;
208         }
209         d->model = vim;
210     } else {
211         if (!d->ownModel) {
212             d->model = new QDeclarative1VisualDataModel(qmlContext(this), this);
213             d->ownModel = true;
214         }
215         if (QDeclarative1VisualDataModel *dataModel = qobject_cast<QDeclarative1VisualDataModel*>(d->model))
216             dataModel->setModel(model);
217     }
218     if (d->model) {
219         connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
220         connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
221         connect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
222         connect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
223         /*
224         connect(d->model, SIGNAL(createdItem(int,QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*)));
225         connect(d->model, SIGNAL(destroyingItem(QDeclarativeItem*)), this, SLOT(destroyingItem(QDeclarativeItem*)));
226         */
227         regenerate();
228     }
229     emit modelChanged();
230     emit countChanged();
231 }
232
233 /*!
234     \qmlproperty Component QtQuick1::Repeater::delegate
235     \default
236
237     The delegate provides a template defining each item instantiated by the repeater.
238
239     Delegates are exposed to a read-only \c index property that indicates the index
240     of the delegate within the repeater. For example, the following \l Text delegate
241     displays the index of each repeated item:
242
243     \table
244     \row
245     \o \snippet doc/src/snippets/qtquick1/repeaters/repeater.qml index
246     \o \image repeater-index.png
247     \endtable
248
249     If the \l model is a \l{QStringList-based model}{string list} or
250     \l{QObjectList-based model}{object list}, the delegate is also exposed to
251     a read-only \c modelData property that holds the string or object data. For
252     example:
253
254     \table
255     \row
256     \o \snippet doc/src/snippets/qtquick1/repeaters/repeater.qml modeldata
257     \o \image repeater-modeldata.png
258     \endtable
259
260     If the \l model is a model object (such as a \l ListModel) the delegate
261     can access all model roles as named properties, in the same way that delegates
262     do for view classes like ListView.
263
264     \sa {QML Data Models}
265  */
266 QDeclarativeComponent *QDeclarative1Repeater::delegate() const
267 {
268     Q_D(const QDeclarative1Repeater);
269     if (d->model) {
270         if (QDeclarative1VisualDataModel *dataModel = qobject_cast<QDeclarative1VisualDataModel*>(d->model))
271             return dataModel->delegate();
272     }
273
274     return 0;
275 }
276
277 void QDeclarative1Repeater::setDelegate(QDeclarativeComponent *delegate)
278 {
279     Q_D(QDeclarative1Repeater);
280     if (QDeclarative1VisualDataModel *dataModel = qobject_cast<QDeclarative1VisualDataModel*>(d->model))
281        if (delegate == dataModel->delegate())
282            return;
283
284     if (!d->ownModel) {
285         d->model = new QDeclarative1VisualDataModel(qmlContext(this));
286         d->ownModel = true;
287     }
288     if (QDeclarative1VisualDataModel *dataModel = qobject_cast<QDeclarative1VisualDataModel*>(d->model)) {
289         dataModel->setDelegate(delegate);
290         regenerate();
291         emit delegateChanged();
292     }
293 }
294
295 /*!
296     \qmlproperty int QtQuick1::Repeater::count
297
298     This property holds the number of items in the repeater.
299 */
300 int QDeclarative1Repeater::count() const
301 {
302     Q_D(const QDeclarative1Repeater);
303     if (d->model)
304         return d->model->count();
305     return 0;
306 }
307
308 /*!
309     \qmlmethod Item QtQuick1::Repeater::itemAt(index)
310     \since Quick 1.1
311
312     Returns the \l Item that has been created at the given \a index, or \c null
313     if no item exists at \a index.
314 */
315 QDeclarativeItem *QDeclarative1Repeater::itemAt(int index) const
316 {
317     Q_D(const QDeclarative1Repeater);
318     if (index >= 0 && index < d->deletables.count())
319         return d->deletables[index];
320     return 0;
321
322 }
323
324 void QDeclarative1Repeater::componentComplete()
325 {
326     QDeclarativeItem::componentComplete();
327     regenerate();
328 }
329
330 QVariant QDeclarative1Repeater::itemChange(GraphicsItemChange change,
331                                        const QVariant &value)
332 {
333     QVariant rv = QDeclarativeItem::itemChange(change, value);
334     if (change == ItemParentHasChanged) {
335         regenerate();
336     }
337
338     return rv;
339 }
340
341 void QDeclarative1Repeater::clear()
342 {
343     Q_D(QDeclarative1Repeater);
344     bool complete = isComponentComplete();
345
346     if (d->model) {
347         while (d->deletables.count() > 0) {
348             QDeclarativeItem *item = d->deletables.takeLast();
349             if (complete)
350                 emit itemRemoved(d->deletables.count()-1, item);
351             d->model->release(item);
352         }
353     }
354     d->deletables.clear();
355 }
356
357 void QDeclarative1Repeater::regenerate()
358 {
359     Q_D(QDeclarative1Repeater);
360     if (!isComponentComplete())
361         return;
362
363     clear();
364
365     if (!d->model || !d->model->count() || !d->model->isValid() || !parentItem() || !isComponentComplete())
366         return;
367
368     for (int ii = 0; ii < count(); ++ii) {
369         QDeclarativeItem *item = d->model->item(ii);
370         if (item) {
371             QDeclarative_setParent_noEvent(item, parentItem());
372             item->setParentItem(parentItem());
373             item->stackBefore(this);
374             d->deletables << item;
375             emit itemAdded(ii, item);
376         }
377     }
378 }
379
380 void QDeclarative1Repeater::itemsInserted(int index, int count)
381 {
382     Q_D(QDeclarative1Repeater);
383     if (!isComponentComplete())
384         return;
385     for (int i = 0; i < count; ++i) {
386         int modelIndex = index + i;
387         QDeclarativeItem *item = d->model->item(modelIndex);
388         if (item) {
389             QDeclarative_setParent_noEvent(item, parentItem());
390             item->setParentItem(parentItem());
391             if (modelIndex < d->deletables.count())
392                 item->stackBefore(d->deletables.at(modelIndex));
393             else
394                 item->stackBefore(this);
395             d->deletables.insert(modelIndex, item);
396             emit itemAdded(modelIndex, item);
397         }
398     }
399     emit countChanged();
400 }
401
402 void QDeclarative1Repeater::itemsRemoved(int index, int count)
403 {
404     Q_D(QDeclarative1Repeater);
405     if (!isComponentComplete() || count <= 0)
406         return;
407     while (count--) {
408         QDeclarativeItem *item = d->deletables.takeAt(index);
409         emit itemRemoved(index, item);
410         if (item)
411             d->model->release(item);
412         else
413             break;
414     }
415     emit countChanged();
416 }
417
418 void QDeclarative1Repeater::itemsMoved(int from, int to, int count)
419 {
420     Q_D(QDeclarative1Repeater);
421     if (!isComponentComplete() || count <= 0)
422         return;
423     if (from + count > d->deletables.count()) {
424         regenerate();
425         return;
426     }
427     QList<QDeclarativeItem*> removed;
428     int removedCount = count;
429     while (removedCount--)
430         removed << d->deletables.takeAt(from);
431     for (int i = 0; i < count; ++i)
432         d->deletables.insert(to + i, removed.at(i));
433     d->deletables.last()->stackBefore(this);
434     for (int i = d->model->count()-1; i > 0; --i) {
435         QDeclarativeItem *item = d->deletables.at(i-1);
436         item->stackBefore(d->deletables.at(i));
437     }
438 }
439
440 void QDeclarative1Repeater::modelReset()
441 {
442     if (!isComponentComplete())
443         return;
444     regenerate();
445     emit countChanged();
446 }
447
448
449
450 QT_END_NAMESPACE