1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "QtQuick1/private/qdeclarativerepeater_p.h"
43 #include "QtQuick1/private/qdeclarativerepeater_p_p.h"
45 #include "QtQuick1/private/qdeclarativevisualitemmodel_p.h"
46 #include <QtDeclarative/private/qdeclarativeglobal_p.h>
47 #include <QtQuick1/private/qdeclarativelistaccessor_p.h>
52 QDeclarative1RepeaterPrivate::QDeclarative1RepeaterPrivate()
53 : model(0), ownModel(false)
57 QDeclarative1RepeaterPrivate::~QDeclarative1RepeaterPrivate()
64 \qmlclass Repeater QDeclarative1Repeater
65 \inqmlmodule QtQuick 1
66 \ingroup qml-utility-elements
70 \brief The Repeater element allows you to repeat an Item-based component using a model.
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.
79 The following Repeater creates three instances of a \l Rectangle item within
82 \snippet doc/src/snippets/qtquick1/repeaters/repeater.qml import
84 \snippet doc/src/snippets/qtquick1/repeaters/repeater.qml simple
86 \image repeater-simple.png
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.
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:
99 \snippet doc/src/snippets/qtquick1/repeaters/repeater.qml layout
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.
108 \section2 Considerations when using Repeater
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.
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:
121 //XXX does not work! Can't repeat QtObject as it doesn't derive from Item.
131 \qmlsignal QtQuick1::Repeater::onItemAdded(int index, Item item)
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.
140 \qmlsignal QtQuick1::Repeater::onItemRemoved(int index, Item item)
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.
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.
151 QDeclarative1Repeater::QDeclarative1Repeater(QDeclarativeItem *parent)
152 : QDeclarativeItem(*(new QDeclarative1RepeaterPrivate), parent)
156 QDeclarative1Repeater::~QDeclarative1Repeater()
161 \qmlproperty any QtQuick1::Repeater::model
163 The model providing data for the repeater.
165 This property can be set to any of the supported \l {qmlmodels}{data models}:
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)
174 The type of model affects the properties that are exposed to the \l delegate.
176 \sa {qmlmodels}{Data Models}
178 QVariant QDeclarative1Repeater::model() const
180 Q_D(const QDeclarative1Repeater);
181 return d->dataSource;
184 void QDeclarative1Repeater::setModel(const QVariant &model)
186 Q_D(QDeclarative1Repeater);
187 if (d->dataSource == 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()));
197 disconnect(d->model, SIGNAL(createdItem(int,QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*)));
198 disconnect(d->model, SIGNAL(destroyingItem(QDeclarativeItem*)), this, SLOT(destroyingItem(QDeclarativeItem*)));
201 d->dataSource = model;
202 QObject *object = qvariant_cast<QObject*>(model);
203 QDeclarative1VisualModel *vim = 0;
204 if (object && (vim = qobject_cast<QDeclarative1VisualModel *>(object))) {
212 d->model = new QDeclarative1VisualDataModel(qmlContext(this), this);
215 if (QDeclarative1VisualDataModel *dataModel = qobject_cast<QDeclarative1VisualDataModel*>(d->model))
216 dataModel->setModel(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()));
224 connect(d->model, SIGNAL(createdItem(int,QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*)));
225 connect(d->model, SIGNAL(destroyingItem(QDeclarativeItem*)), this, SLOT(destroyingItem(QDeclarativeItem*)));
234 \qmlproperty Component QtQuick1::Repeater::delegate
237 The delegate provides a template defining each item instantiated by the repeater.
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:
245 \o \snippet doc/src/snippets/qtquick1/repeaters/repeater.qml index
246 \o \image repeater-index.png
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
256 \o \snippet doc/src/snippets/qtquick1/repeaters/repeater.qml modeldata
257 \o \image repeater-modeldata.png
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.
264 \sa {QML Data Models}
266 QDeclarativeComponent *QDeclarative1Repeater::delegate() const
268 Q_D(const QDeclarative1Repeater);
270 if (QDeclarative1VisualDataModel *dataModel = qobject_cast<QDeclarative1VisualDataModel*>(d->model))
271 return dataModel->delegate();
277 void QDeclarative1Repeater::setDelegate(QDeclarativeComponent *delegate)
279 Q_D(QDeclarative1Repeater);
280 if (QDeclarative1VisualDataModel *dataModel = qobject_cast<QDeclarative1VisualDataModel*>(d->model))
281 if (delegate == dataModel->delegate())
285 d->model = new QDeclarative1VisualDataModel(qmlContext(this));
288 if (QDeclarative1VisualDataModel *dataModel = qobject_cast<QDeclarative1VisualDataModel*>(d->model)) {
289 dataModel->setDelegate(delegate);
291 emit delegateChanged();
296 \qmlproperty int QtQuick1::Repeater::count
298 This property holds the number of items in the repeater.
300 int QDeclarative1Repeater::count() const
302 Q_D(const QDeclarative1Repeater);
304 return d->model->count();
309 \qmlmethod Item QtQuick1::Repeater::itemAt(index)
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.
315 QDeclarativeItem *QDeclarative1Repeater::itemAt(int index) const
317 Q_D(const QDeclarative1Repeater);
318 if (index >= 0 && index < d->deletables.count())
319 return d->deletables[index];
324 void QDeclarative1Repeater::componentComplete()
326 QDeclarativeItem::componentComplete();
330 QVariant QDeclarative1Repeater::itemChange(GraphicsItemChange change,
331 const QVariant &value)
333 QVariant rv = QDeclarativeItem::itemChange(change, value);
334 if (change == ItemParentHasChanged) {
341 void QDeclarative1Repeater::clear()
343 Q_D(QDeclarative1Repeater);
344 bool complete = isComponentComplete();
347 while (d->deletables.count() > 0) {
348 QDeclarativeItem *item = d->deletables.takeLast();
350 emit itemRemoved(d->deletables.count()-1, item);
351 d->model->release(item);
354 d->deletables.clear();
357 void QDeclarative1Repeater::regenerate()
359 Q_D(QDeclarative1Repeater);
360 if (!isComponentComplete())
365 if (!d->model || !d->model->count() || !d->model->isValid() || !parentItem() || !isComponentComplete())
368 for (int ii = 0; ii < count(); ++ii) {
369 QDeclarativeItem *item = d->model->item(ii);
371 QDeclarative_setParent_noEvent(item, parentItem());
372 item->setParentItem(parentItem());
373 item->stackBefore(this);
374 d->deletables << item;
375 emit itemAdded(ii, item);
380 void QDeclarative1Repeater::itemsInserted(int index, int count)
382 Q_D(QDeclarative1Repeater);
383 if (!isComponentComplete())
385 for (int i = 0; i < count; ++i) {
386 int modelIndex = index + i;
387 QDeclarativeItem *item = d->model->item(modelIndex);
389 QDeclarative_setParent_noEvent(item, parentItem());
390 item->setParentItem(parentItem());
391 if (modelIndex < d->deletables.count())
392 item->stackBefore(d->deletables.at(modelIndex));
394 item->stackBefore(this);
395 d->deletables.insert(modelIndex, item);
396 emit itemAdded(modelIndex, item);
402 void QDeclarative1Repeater::itemsRemoved(int index, int count)
404 Q_D(QDeclarative1Repeater);
405 if (!isComponentComplete() || count <= 0)
408 QDeclarativeItem *item = d->deletables.takeAt(index);
409 emit itemRemoved(index, item);
411 d->model->release(item);
418 void QDeclarative1Repeater::itemsMoved(int from, int to, int count)
420 Q_D(QDeclarative1Repeater);
421 if (!isComponentComplete() || count <= 0)
423 if (from + count > d->deletables.count()) {
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));
440 void QDeclarative1Repeater::modelReset()
442 if (!isComponentComplete())