src/declarative/graphicsitems/qdeclarativerepeater.cpp
changeset 30 5dc02b23752f
child 33 3e2da88830cd
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 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 "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 
       
    51 QT_BEGIN_NAMESPACE
       
    52 QDeclarativeRepeaterPrivate::QDeclarativeRepeaterPrivate()
       
    53 : model(0), ownModel(false)
       
    54 {
       
    55 }
       
    56 
       
    57 QDeclarativeRepeaterPrivate::~QDeclarativeRepeaterPrivate()
       
    58 {
       
    59     if (ownModel)
       
    60         delete model;
       
    61 }
       
    62 
       
    63 /*!
       
    64     \qmlclass Repeater QDeclarativeRepeater
       
    65     \since 4.7
       
    66     \inherits Item
       
    67 
       
    68     \brief The Repeater item allows you to repeat an Item-based component using a model.
       
    69 
       
    70     The Repeater item is used to create a large number of
       
    71     similar items.  For each entry in the model, an item is instantiated
       
    72     in a context seeded with data from the model.  If the repeater will
       
    73     be instantiating a large number of instances, it may be more efficient to
       
    74     use one of Qt Declarative's \l {xmlViews}{view items}.
       
    75 
       
    76     The model may be either an object list, a string list, a number or a Qt model.
       
    77     In each case, the data element and the index is exposed to each instantiated
       
    78     component.  
       
    79     
       
    80     The index is always exposed as an accessible \c index property.
       
    81     In the case of an object or string list, the data element (of type string
       
    82     or object) is available as the \c modelData property.  In the case of a Qt model,
       
    83     all roles are available as named properties just like in the view classes. The
       
    84     following example shows how to use the index property inside the instantiated
       
    85     items.
       
    86 
       
    87     \snippet doc/src/snippets/declarative/repeater-index.qml 0
       
    88 
       
    89     \image repeater-index.png
       
    90 
       
    91     Items instantiated by the Repeater are inserted, in order, as
       
    92     children of the Repeater's parent.  The insertion starts immediately after
       
    93     the repeater's position in its parent stacking list.  This is to allow
       
    94     you to use a Repeater inside a layout.  The following QML example shows how
       
    95     the instantiated items would visually appear stacked between the red and
       
    96     blue rectangles.
       
    97 
       
    98     \snippet doc/src/snippets/declarative/repeater.qml 0
       
    99 
       
   100     \image repeater.png
       
   101 
       
   102     The repeater instance continues to own all items it instantiates, even
       
   103     if they are otherwise manipulated.  It is illegal to manually remove an item
       
   104     created by the Repeater.
       
   105 
       
   106     \note Repeater is Item-based, and cannot be used to repeat non-Item-derived objects.
       
   107     For example, it cannot be used to repeat QtObjects.
       
   108     \badcode
       
   109     Item {
       
   110         //XXX illegal. Can't repeat QtObject as it doesn't derive from Item.
       
   111         Repeater {
       
   112             model: 10
       
   113             QtObject {}
       
   114         }
       
   115     }
       
   116     \endcode
       
   117  */
       
   118 
       
   119 /*!
       
   120     \internal
       
   121     \class QDeclarativeRepeater
       
   122     \qmlclass Repeater
       
   123  */
       
   124 
       
   125 /*!
       
   126     Create a new QDeclarativeRepeater instance.
       
   127  */
       
   128 QDeclarativeRepeater::QDeclarativeRepeater(QDeclarativeItem *parent)
       
   129   : QDeclarativeItem(*(new QDeclarativeRepeaterPrivate), parent)
       
   130 {
       
   131 }
       
   132 
       
   133 /*!
       
   134     Destroy the repeater instance.  All items it instantiated are also
       
   135     destroyed.
       
   136  */
       
   137 QDeclarativeRepeater::~QDeclarativeRepeater()
       
   138 {
       
   139 }
       
   140 
       
   141 /*!
       
   142     \qmlproperty any Repeater::model
       
   143 
       
   144     The model providing data for the repeater.
       
   145 
       
   146     The model may be either an object list, a string list, a number or a Qt model.
       
   147     In each case, the data element and the index is exposed to each instantiated
       
   148     component.  The index is always exposed as an accessible \c index property.
       
   149     In the case of an object or string list, the data element (of type string
       
   150     or object) is available as the \c modelData property.  In the case of a Qt model,
       
   151     all roles are available as named properties just like in the view classes.
       
   152 
       
   153     As a special case the model can also be merely a number. In this case it will
       
   154     create that many instances of the component. They will also be assigned an index
       
   155     based on the order they are created.
       
   156 
       
   157     Models can also be created directly in QML, using a \l{ListModel} or \l{XmlListModel}.
       
   158 
       
   159     \sa {qmlmodels}{Data Models}
       
   160 */
       
   161 QVariant QDeclarativeRepeater::model() const
       
   162 {
       
   163     Q_D(const QDeclarativeRepeater);
       
   164     return d->dataSource;
       
   165 }
       
   166 
       
   167 void QDeclarativeRepeater::setModel(const QVariant &model)
       
   168 {
       
   169     Q_D(QDeclarativeRepeater);
       
   170     if (d->dataSource == model)
       
   171         return;
       
   172 
       
   173     clear();
       
   174     if (d->model) {
       
   175         disconnect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
       
   176         disconnect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
       
   177         disconnect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
       
   178         disconnect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
       
   179         /*
       
   180         disconnect(d->model, SIGNAL(createdItem(int, QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*)));
       
   181         disconnect(d->model, SIGNAL(destroyingItem(QDeclarativeItem*)), this, SLOT(destroyingItem(QDeclarativeItem*)));
       
   182     */
       
   183     }
       
   184     d->dataSource = model;
       
   185     emit modelChanged();
       
   186     QObject *object = qvariant_cast<QObject*>(model);
       
   187     QDeclarativeVisualModel *vim = 0;
       
   188     if (object && (vim = qobject_cast<QDeclarativeVisualModel *>(object))) {
       
   189         if (d->ownModel) {
       
   190             delete d->model;
       
   191             d->ownModel = false;
       
   192         }
       
   193         d->model = vim;
       
   194     } else {
       
   195         if (!d->ownModel) {
       
   196             d->model = new QDeclarativeVisualDataModel(qmlContext(this), this);
       
   197             d->ownModel = true;
       
   198         }
       
   199         if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model))
       
   200             dataModel->setModel(model);
       
   201     }
       
   202     if (d->model) {
       
   203         connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
       
   204         connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
       
   205         connect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
       
   206         connect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
       
   207         /*
       
   208         connect(d->model, SIGNAL(createdItem(int, QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*)));
       
   209         connect(d->model, SIGNAL(destroyingItem(QDeclarativeItem*)), this, SLOT(destroyingItem(QDeclarativeItem*)));
       
   210         */
       
   211         regenerate();
       
   212         emit countChanged();
       
   213     }
       
   214 }
       
   215 
       
   216 /*!
       
   217     \qmlproperty Component Repeater::delegate
       
   218     \default
       
   219 
       
   220     The delegate provides a template defining each item instantiated by the repeater.
       
   221     The index is exposed as an accessible \c index property.  Properties of the
       
   222     model are also available depending upon the type of \l {qmlmodels}{Data Model}.
       
   223  */
       
   224 QDeclarativeComponent *QDeclarativeRepeater::delegate() const
       
   225 {
       
   226     Q_D(const QDeclarativeRepeater);
       
   227     if (d->model) {
       
   228         if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model))
       
   229             return dataModel->delegate();
       
   230     }
       
   231 
       
   232     return 0;
       
   233 }
       
   234 
       
   235 void QDeclarativeRepeater::setDelegate(QDeclarativeComponent *delegate)
       
   236 {
       
   237     Q_D(QDeclarativeRepeater);
       
   238     if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model))
       
   239        if (delegate == dataModel->delegate())
       
   240            return;
       
   241 
       
   242     if (!d->ownModel) {
       
   243         d->model = new QDeclarativeVisualDataModel(qmlContext(this));
       
   244         d->ownModel = true;
       
   245     }
       
   246     if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model)) {
       
   247         dataModel->setDelegate(delegate);
       
   248         regenerate();
       
   249         emit delegateChanged();
       
   250     }
       
   251 }
       
   252 
       
   253 /*!
       
   254     \qmlproperty int Repeater::count
       
   255 
       
   256     This property holds the number of items in the repeater.
       
   257 */
       
   258 int QDeclarativeRepeater::count() const
       
   259 {
       
   260     Q_D(const QDeclarativeRepeater);
       
   261     if (d->model)
       
   262         return d->model->count();
       
   263     return 0;
       
   264 }
       
   265 
       
   266 
       
   267 /*!
       
   268     \internal
       
   269  */
       
   270 void QDeclarativeRepeater::componentComplete()
       
   271 {
       
   272     QDeclarativeItem::componentComplete();
       
   273     regenerate();
       
   274 }
       
   275 
       
   276 /*!
       
   277     \internal
       
   278  */
       
   279 QVariant QDeclarativeRepeater::itemChange(GraphicsItemChange change,
       
   280                                        const QVariant &value)
       
   281 {
       
   282     QVariant rv = QDeclarativeItem::itemChange(change, value);
       
   283     if (change == ItemParentHasChanged) {
       
   284         regenerate();
       
   285     }
       
   286 
       
   287     return rv;
       
   288 }
       
   289 
       
   290 void QDeclarativeRepeater::clear()
       
   291 {
       
   292     Q_D(QDeclarativeRepeater);
       
   293     if (d->model) {
       
   294         foreach (QDeclarativeItem *item, d->deletables) {
       
   295             d->model->release(item);
       
   296         }
       
   297     }
       
   298     d->deletables.clear();
       
   299 }
       
   300 
       
   301 /*!
       
   302     \internal
       
   303  */
       
   304 void QDeclarativeRepeater::regenerate()
       
   305 {
       
   306     Q_D(QDeclarativeRepeater);
       
   307     if (!isComponentComplete())
       
   308         return;
       
   309 
       
   310     clear();
       
   311 
       
   312     if (!d->model || !d->model->count() || !d->model->isValid() || !parentItem() || !isComponentComplete())
       
   313         return;
       
   314 
       
   315     for (int ii = 0; ii < count(); ++ii) {
       
   316         QDeclarativeItem *item = d->model->item(ii);
       
   317         if (item) {
       
   318             QDeclarative_setParent_noEvent(item, parentItem());
       
   319             item->setParentItem(parentItem());
       
   320             item->stackBefore(this);
       
   321             d->deletables << item;
       
   322         }
       
   323     }
       
   324 }
       
   325 
       
   326 void QDeclarativeRepeater::itemsInserted(int index, int count)
       
   327 {
       
   328     Q_D(QDeclarativeRepeater);
       
   329     if (!isComponentComplete())
       
   330         return;
       
   331     for (int i = 0; i < count; ++i) {
       
   332         int modelIndex = index + i;
       
   333         QDeclarativeItem *item = d->model->item(modelIndex);
       
   334         if (item) {
       
   335             QDeclarative_setParent_noEvent(item, parentItem());
       
   336             item->setParentItem(parentItem());
       
   337             if (modelIndex < d->deletables.count())
       
   338                 item->stackBefore(d->deletables.at(modelIndex));
       
   339             else
       
   340                 item->stackBefore(this);
       
   341             d->deletables.insert(modelIndex, item);
       
   342         }
       
   343     }
       
   344 }
       
   345 
       
   346 void QDeclarativeRepeater::itemsRemoved(int index, int count)
       
   347 {
       
   348     Q_D(QDeclarativeRepeater);
       
   349     if (!isComponentComplete() || count <= 0)
       
   350         return;
       
   351     while (count--) {
       
   352         QDeclarativeItem *item = d->deletables.takeAt(index);
       
   353         if (item)
       
   354             d->model->release(item);
       
   355         else
       
   356             break;
       
   357     }
       
   358 }
       
   359 
       
   360 void QDeclarativeRepeater::itemsMoved(int from, int to, int count)
       
   361 {
       
   362     Q_D(QDeclarativeRepeater);
       
   363     if (!isComponentComplete() || count <= 0)
       
   364         return;
       
   365     if (from + count > d->deletables.count()) {
       
   366         regenerate();
       
   367         return;
       
   368     }
       
   369     QList<QDeclarativeItem*> removed;
       
   370     int removedCount = count;
       
   371     while (removedCount--)
       
   372         removed << d->deletables.takeAt(from);
       
   373     for (int i = 0; i < count; ++i)
       
   374         d->deletables.insert(to + i, removed.at(i));
       
   375     d->deletables.last()->stackBefore(this);
       
   376     for (int i = d->model->count()-1; i > 0; --i) {
       
   377         QDeclarativeItem *item = d->deletables.at(i-1);
       
   378         item->stackBefore(d->deletables.at(i));
       
   379     }
       
   380 }
       
   381 
       
   382 void QDeclarativeRepeater::modelReset()
       
   383 {
       
   384     if (!isComponentComplete())
       
   385         return;
       
   386     regenerate();
       
   387 }
       
   388 
       
   389 QT_END_NAMESPACE