source: trunk/src/declarative/graphicsitems/qdeclarativerepeater.cpp@ 918

Last change on this file since 918 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 13.5 KB
Line 
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** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "private/qdeclarativerepeater_p.h"
43#include "private/qdeclarativerepeater_p_p.h"
44
45#include "private/qdeclarativevisualitemmodel_p.h"
46#include <private/qdeclarativeglobal_p.h>
47#include <qdeclarativelistaccessor_p.h>
48
49#include <qlistmodelinterface_p.h>
50
51QT_BEGIN_NAMESPACE
52QDeclarativeRepeaterPrivate::QDeclarativeRepeaterPrivate()
53: model(0), ownModel(false)
54{
55}
56
57QDeclarativeRepeaterPrivate::~QDeclarativeRepeaterPrivate()
58{
59 if (ownModel)
60 delete model;
61}
62
63/*!
64 \qmlclass Repeater QDeclarativeRepeater
65 \ingroup qml-utility-elements
66 \since 4.7
67 \inherits Item
68
69 \brief The Repeater element allows you to repeat an Item-based component using a model.
70
71 The Repeater element is used to create a large number of
72 similar items. Like other view elements, a Repeater has a \l model and a \l delegate:
73 for each entry in the model, the delegate is instantiated
74 in a context seeded with data from the model. A Repeater item is usually
75 enclosed in a positioner element such as \l Row or \l Column to visually
76 position the multiple delegate items created by the Repeater.
77
78 The following Repeater creates three instances of a \l Rectangle item within
79 a \l Row:
80
81 \snippet doc/src/snippets/declarative/repeaters/repeater.qml import
82 \codeline
83 \snippet doc/src/snippets/declarative/repeaters/repeater.qml simple
84
85 \image repeater-simple.png
86
87 The \l model of a Repeater can be any of the supported \l {qmlmodels}{Data Models}.
88
89 Items instantiated by the Repeater are inserted, in order, as
90 children of the Repeater's parent. The insertion starts immediately after
91 the repeater's position in its parent stacking list. This allows
92 a Repeater to be used inside a layout. For example, the following Repeater's
93 items are stacked between a red rectangle and a blue rectangle:
94
95 \snippet doc/src/snippets/declarative/repeaters/repeater.qml layout
96
97 \image repeater.png
98
99
100 \section2 The \c index and \c modelData properties
101
102 The index of a delegate is exposed as an accessible \c index property in the delegate.
103 Properties of the model are also available depending upon the type of \l {qmlmodels}{Data Model}.
104
105 Here is a Repeater that uses the \c index property inside the instantiated items:
106
107 \table
108 \row
109 \o \snippet doc/src/snippets/declarative/repeaters/repeater.qml index
110 \o \image repeater-index.png
111 \endtable
112
113 Here is another Repeater that uses the \c modelData property to reference the data for a
114 particular index:
115
116 \table
117 \row
118 \o \snippet doc/src/snippets/declarative/repeaters/repeater.qml modeldata
119 \o \image repeater-modeldata.png
120 \endtable
121
122
123 A Repeater item owns all items it instantiates. Removing or dynamically destroying
124 an item created by a Repeater results in unpredictable behavior.
125
126
127 \section2 Considerations when using Repeater
128
129 The Repeater element creates all of its delegate items when the repeater is first
130 created. This can be inefficient if there are a large number of delegate items and
131 not all of the items are required to be visible at the same time. If this is the case,
132 consider using other view elements like ListView (which only creates delegate items
133 when they are scrolled into view) or use the \l {Dynamic Object Creation} methods to
134 create items as they are required.
135
136 Also, note that Repeater is \l {Item}-based, and can only repeat \l {Item}-derived objects.
137 For example, it cannot be used to repeat QtObjects:
138 \badcode
139 Item {
140 //XXX does not work! Can't repeat QtObject as it doesn't derive from Item.
141 Repeater {
142 model: 10
143 QtObject {}
144 }
145 }
146 \endcode
147 */
148
149QDeclarativeRepeater::QDeclarativeRepeater(QDeclarativeItem *parent)
150 : QDeclarativeItem(*(new QDeclarativeRepeaterPrivate), parent)
151{
152}
153
154QDeclarativeRepeater::~QDeclarativeRepeater()
155{
156}
157
158/*!
159 \qmlproperty any Repeater::model
160
161 The model providing data for the repeater.
162
163 This property can be set to any of the following:
164
165 \list
166 \o A number that indicates the number of delegates to be created
167 \o A model (e.g. a ListModel item, or a QAbstractItemModel subclass)
168 \o A string list
169 \o An object list
170 \endlist
171
172 In each case, the data element and the index is exposed to each instantiated
173 component. The index is always exposed as an accessible \c index property.
174 In the case of an object or string list, the data element (of type string
175 or object) is available as the \c modelData property. In the case of a Qt model,
176 all roles are available as named properties just like in the view classes.
177
178 As a special case the model can also be merely a number. In this case it will
179 create that many instances of the component. They will also be assigned an index
180 based on the order they are created.
181
182 Models can also be created directly in QML, using a \l{ListModel} or \l{XmlListModel}.
183
184 \sa {qmlmodels}{Data Models}
185*/
186QVariant QDeclarativeRepeater::model() const
187{
188 Q_D(const QDeclarativeRepeater);
189 return d->dataSource;
190}
191
192void QDeclarativeRepeater::setModel(const QVariant &model)
193{
194 Q_D(QDeclarativeRepeater);
195 if (d->dataSource == model)
196 return;
197
198 clear();
199 if (d->model) {
200 disconnect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
201 disconnect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
202 disconnect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
203 disconnect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
204 /*
205 disconnect(d->model, SIGNAL(createdItem(int,QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*)));
206 disconnect(d->model, SIGNAL(destroyingItem(QDeclarativeItem*)), this, SLOT(destroyingItem(QDeclarativeItem*)));
207 */
208 }
209 d->dataSource = model;
210 emit modelChanged();
211 QObject *object = qvariant_cast<QObject*>(model);
212 QDeclarativeVisualModel *vim = 0;
213 if (object && (vim = qobject_cast<QDeclarativeVisualModel *>(object))) {
214 if (d->ownModel) {
215 delete d->model;
216 d->ownModel = false;
217 }
218 d->model = vim;
219 } else {
220 if (!d->ownModel) {
221 d->model = new QDeclarativeVisualDataModel(qmlContext(this), this);
222 d->ownModel = true;
223 }
224 if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model))
225 dataModel->setModel(model);
226 }
227 if (d->model) {
228 connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
229 connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
230 connect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
231 connect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
232 /*
233 connect(d->model, SIGNAL(createdItem(int,QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*)));
234 connect(d->model, SIGNAL(destroyingItem(QDeclarativeItem*)), this, SLOT(destroyingItem(QDeclarativeItem*)));
235 */
236 regenerate();
237 }
238 emit countChanged();
239}
240
241/*!
242 \qmlproperty Component Repeater::delegate
243 \default
244
245 The delegate provides a template defining each item instantiated by the repeater.
246 The index is exposed as an accessible \c index property. Properties of the
247 model are also available depending upon the type of \l {qmlmodels}{Data Model}.
248 */
249QDeclarativeComponent *QDeclarativeRepeater::delegate() const
250{
251 Q_D(const QDeclarativeRepeater);
252 if (d->model) {
253 if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model))
254 return dataModel->delegate();
255 }
256
257 return 0;
258}
259
260void QDeclarativeRepeater::setDelegate(QDeclarativeComponent *delegate)
261{
262 Q_D(QDeclarativeRepeater);
263 if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model))
264 if (delegate == dataModel->delegate())
265 return;
266
267 if (!d->ownModel) {
268 d->model = new QDeclarativeVisualDataModel(qmlContext(this));
269 d->ownModel = true;
270 }
271 if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model)) {
272 dataModel->setDelegate(delegate);
273 regenerate();
274 emit delegateChanged();
275 }
276}
277
278/*!
279 \qmlproperty int Repeater::count
280
281 This property holds the number of items in the repeater.
282*/
283int QDeclarativeRepeater::count() const
284{
285 Q_D(const QDeclarativeRepeater);
286 if (d->model)
287 return d->model->count();
288 return 0;
289}
290
291
292void QDeclarativeRepeater::componentComplete()
293{
294 QDeclarativeItem::componentComplete();
295 regenerate();
296}
297
298QVariant QDeclarativeRepeater::itemChange(GraphicsItemChange change,
299 const QVariant &value)
300{
301 QVariant rv = QDeclarativeItem::itemChange(change, value);
302 if (change == ItemParentHasChanged) {
303 regenerate();
304 }
305
306 return rv;
307}
308
309void QDeclarativeRepeater::clear()
310{
311 Q_D(QDeclarativeRepeater);
312 if (d->model) {
313 foreach (QDeclarativeItem *item, d->deletables) {
314 d->model->release(item);
315 }
316 }
317 d->deletables.clear();
318}
319
320void QDeclarativeRepeater::regenerate()
321{
322 Q_D(QDeclarativeRepeater);
323 if (!isComponentComplete())
324 return;
325
326 clear();
327
328 if (!d->model || !d->model->count() || !d->model->isValid() || !parentItem() || !isComponentComplete())
329 return;
330
331 for (int ii = 0; ii < count(); ++ii) {
332 QDeclarativeItem *item = d->model->item(ii);
333 if (item) {
334 QDeclarative_setParent_noEvent(item, parentItem());
335 item->setParentItem(parentItem());
336 item->stackBefore(this);
337 d->deletables << item;
338 }
339 }
340}
341
342void QDeclarativeRepeater::itemsInserted(int index, int count)
343{
344 Q_D(QDeclarativeRepeater);
345 if (!isComponentComplete())
346 return;
347 for (int i = 0; i < count; ++i) {
348 int modelIndex = index + i;
349 QDeclarativeItem *item = d->model->item(modelIndex);
350 if (item) {
351 QDeclarative_setParent_noEvent(item, parentItem());
352 item->setParentItem(parentItem());
353 if (modelIndex < d->deletables.count())
354 item->stackBefore(d->deletables.at(modelIndex));
355 else
356 item->stackBefore(this);
357 d->deletables.insert(modelIndex, item);
358 }
359 }
360 emit countChanged();
361}
362
363void QDeclarativeRepeater::itemsRemoved(int index, int count)
364{
365 Q_D(QDeclarativeRepeater);
366 if (!isComponentComplete() || count <= 0)
367 return;
368 while (count--) {
369 QDeclarativeItem *item = d->deletables.takeAt(index);
370 if (item)
371 d->model->release(item);
372 else
373 break;
374 }
375 emit countChanged();
376}
377
378void QDeclarativeRepeater::itemsMoved(int from, int to, int count)
379{
380 Q_D(QDeclarativeRepeater);
381 if (!isComponentComplete() || count <= 0)
382 return;
383 if (from + count > d->deletables.count()) {
384 regenerate();
385 return;
386 }
387 QList<QDeclarativeItem*> removed;
388 int removedCount = count;
389 while (removedCount--)
390 removed << d->deletables.takeAt(from);
391 for (int i = 0; i < count; ++i)
392 d->deletables.insert(to + i, removed.at(i));
393 d->deletables.last()->stackBefore(this);
394 for (int i = d->model->count()-1; i > 0; --i) {
395 QDeclarativeItem *item = d->deletables.at(i-1);
396 item->stackBefore(d->deletables.at(i));
397 }
398}
399
400void QDeclarativeRepeater::modelReset()
401{
402 if (!isComponentComplete())
403 return;
404 regenerate();
405 emit countChanged();
406}
407
408QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.