src/gui/itemviews/qdatawidgetmapper.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 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 QtGui 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 "qdatawidgetmapper.h"
       
    43 
       
    44 #ifndef QT_NO_DATAWIDGETMAPPER
       
    45 
       
    46 #include "qabstractitemmodel.h"
       
    47 #include "qitemdelegate.h"
       
    48 #include "qmetaobject.h"
       
    49 #include "qwidget.h"
       
    50 #include "private/qobject_p.h"
       
    51 #include "private/qabstractitemmodel_p.h"
       
    52 
       
    53 QT_BEGIN_NAMESPACE
       
    54 
       
    55 class QDataWidgetMapperPrivate: public QObjectPrivate
       
    56 {
       
    57 public:
       
    58     Q_DECLARE_PUBLIC(QDataWidgetMapper)
       
    59 
       
    60     QDataWidgetMapperPrivate()
       
    61         : model(QAbstractItemModelPrivate::staticEmptyModel()), delegate(0),
       
    62           orientation(Qt::Horizontal), submitPolicy(QDataWidgetMapper::AutoSubmit)
       
    63     {
       
    64     }
       
    65 
       
    66     QAbstractItemModel *model;
       
    67     QAbstractItemDelegate *delegate;
       
    68     Qt::Orientation orientation;
       
    69     QDataWidgetMapper::SubmitPolicy submitPolicy;
       
    70     QPersistentModelIndex rootIndex;
       
    71     QPersistentModelIndex currentTopLeft;
       
    72 
       
    73     inline int itemCount()
       
    74     {
       
    75         return orientation == Qt::Horizontal
       
    76             ? model->rowCount(rootIndex)
       
    77             : model->columnCount(rootIndex);
       
    78     }
       
    79 
       
    80     inline int currentIdx() const
       
    81     {
       
    82         return orientation == Qt::Horizontal ? currentTopLeft.row() : currentTopLeft.column();
       
    83     }
       
    84 
       
    85     inline QModelIndex indexAt(int itemPos)
       
    86     {
       
    87         return orientation == Qt::Horizontal
       
    88             ? model->index(currentIdx(), itemPos, rootIndex)
       
    89             : model->index(itemPos, currentIdx(), rootIndex);
       
    90     }
       
    91 
       
    92     inline void flipEventFilters(QAbstractItemDelegate *oldDelegate,
       
    93                                  QAbstractItemDelegate *newDelegate)
       
    94     {
       
    95         for (int i = 0; i < widgetMap.count(); ++i) {
       
    96             QWidget *w = widgetMap.at(i).widget;
       
    97             if (!w)
       
    98                 continue;
       
    99             w->removeEventFilter(oldDelegate);
       
   100             w->installEventFilter(newDelegate);
       
   101         }
       
   102     }
       
   103 
       
   104     void populate();
       
   105 
       
   106     // private slots
       
   107     void _q_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
       
   108     void _q_commitData(QWidget *);
       
   109     void _q_closeEditor(QWidget *, QAbstractItemDelegate::EndEditHint);
       
   110     void _q_modelDestroyed();
       
   111 
       
   112     struct WidgetMapper
       
   113     {
       
   114         inline WidgetMapper(QWidget *w = 0, int c = 0, const QModelIndex &i = QModelIndex())
       
   115             : widget(w), section(c), currentIndex(i) {}
       
   116         inline WidgetMapper(QWidget *w, int c, const QModelIndex &i, const QByteArray &p)
       
   117             : widget(w), section(c), currentIndex(i), property(p) {}
       
   118 
       
   119         QPointer<QWidget> widget;
       
   120         int section;
       
   121         QPersistentModelIndex currentIndex;
       
   122         QByteArray property;
       
   123     };
       
   124 
       
   125     void populate(WidgetMapper &m);
       
   126     int findWidget(QWidget *w) const;
       
   127 
       
   128     bool commit(const WidgetMapper &m);
       
   129 
       
   130     QList<WidgetMapper> widgetMap;
       
   131 };
       
   132 
       
   133 int QDataWidgetMapperPrivate::findWidget(QWidget *w) const
       
   134 {
       
   135     for (int i = 0; i < widgetMap.count(); ++i) {
       
   136         if (widgetMap.at(i).widget == w)
       
   137             return i;
       
   138     }
       
   139     return -1;
       
   140 }
       
   141 
       
   142 bool QDataWidgetMapperPrivate::commit(const WidgetMapper &m)
       
   143 {
       
   144     if (m.widget.isNull())
       
   145         return true; // just ignore
       
   146 
       
   147     if (!m.currentIndex.isValid())
       
   148         return false;
       
   149 
       
   150     // Create copy to avoid passing the widget mappers data
       
   151     QModelIndex idx = m.currentIndex;
       
   152     if (m.property.isEmpty())
       
   153         delegate->setModelData(m.widget, model, idx);
       
   154     else
       
   155         model->setData(idx, m.widget->property(m.property), Qt::EditRole);
       
   156 
       
   157     return true;
       
   158 }
       
   159 
       
   160 void QDataWidgetMapperPrivate::populate(WidgetMapper &m)
       
   161 {
       
   162     if (m.widget.isNull())
       
   163         return;
       
   164 
       
   165     m.currentIndex = indexAt(m.section);
       
   166     if (m.property.isEmpty())
       
   167         delegate->setEditorData(m.widget, m.currentIndex);
       
   168     else
       
   169         m.widget->setProperty(m.property, m.currentIndex.data(Qt::EditRole));
       
   170 }
       
   171 
       
   172 void QDataWidgetMapperPrivate::populate()
       
   173 {
       
   174     for (int i = 0; i < widgetMap.count(); ++i)
       
   175         populate(widgetMap[i]);
       
   176 }
       
   177 
       
   178 static bool qContainsIndex(const QModelIndex &idx, const QModelIndex &topLeft,
       
   179                            const QModelIndex &bottomRight)
       
   180 {
       
   181     return idx.row() >= topLeft.row() && idx.row() <= bottomRight.row()
       
   182            && idx.column() >= topLeft.column() && idx.column() <= bottomRight.column();
       
   183 }
       
   184 
       
   185 void QDataWidgetMapperPrivate::_q_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
       
   186 {
       
   187     if (topLeft.parent() != rootIndex)
       
   188         return; // not in our hierarchy
       
   189 
       
   190     for (int i = 0; i < widgetMap.count(); ++i) {
       
   191         WidgetMapper &m = widgetMap[i];
       
   192         if (qContainsIndex(m.currentIndex, topLeft, bottomRight))
       
   193             populate(m);
       
   194     }
       
   195 }
       
   196 
       
   197 void QDataWidgetMapperPrivate::_q_commitData(QWidget *w)
       
   198 {
       
   199     if (submitPolicy == QDataWidgetMapper::ManualSubmit)
       
   200         return;
       
   201 
       
   202     int idx = findWidget(w);
       
   203     if (idx == -1)
       
   204         return; // not our widget
       
   205 
       
   206     commit(widgetMap.at(idx));
       
   207 }
       
   208 
       
   209 class QFocusHelper: public QWidget
       
   210 {
       
   211 public:
       
   212     bool focusNextPrevChild(bool next)
       
   213     {
       
   214         return QWidget::focusNextPrevChild(next);
       
   215     }
       
   216 
       
   217     static inline void focusNextPrevChild(QWidget *w, bool next)
       
   218     {
       
   219         static_cast<QFocusHelper *>(w)->focusNextPrevChild(next);
       
   220     }
       
   221 };
       
   222 
       
   223 void QDataWidgetMapperPrivate::_q_closeEditor(QWidget *w, QAbstractItemDelegate::EndEditHint hint)
       
   224 {
       
   225     int idx = findWidget(w);
       
   226     if (idx == -1)
       
   227         return; // not our widget
       
   228 
       
   229     switch (hint) {
       
   230     case QAbstractItemDelegate::RevertModelCache: {
       
   231         populate(widgetMap[idx]);
       
   232         break; }
       
   233     case QAbstractItemDelegate::EditNextItem:
       
   234         QFocusHelper::focusNextPrevChild(w, true);
       
   235         break;
       
   236     case QAbstractItemDelegate::EditPreviousItem:
       
   237         QFocusHelper::focusNextPrevChild(w, false);
       
   238         break;
       
   239     case QAbstractItemDelegate::SubmitModelCache:
       
   240     case QAbstractItemDelegate::NoHint:
       
   241         // nothing
       
   242         break;
       
   243     }
       
   244 }
       
   245 
       
   246 void QDataWidgetMapperPrivate::_q_modelDestroyed()
       
   247 {
       
   248     Q_Q(QDataWidgetMapper);
       
   249 
       
   250     model = 0;
       
   251     q->setModel(QAbstractItemModelPrivate::staticEmptyModel());
       
   252 }
       
   253 
       
   254 /*!
       
   255     \class QDataWidgetMapper
       
   256     \brief The QDataWidgetMapper class provides mapping between a section
       
   257     of a data model to widgets.
       
   258     \since 4.2
       
   259     \ingroup model-view
       
   260     \ingroup advanced
       
   261 
       
   262     QDataWidgetMapper can be used to create data-aware widgets by mapping
       
   263     them to sections of an item model. A section is a column of a model
       
   264     if the orientation is horizontal (the default), otherwise a row.
       
   265 
       
   266     Every time the current index changes, each widget is updated with data
       
   267     from the model via the property specified when its mapping was made.
       
   268     If the user edits the contents of a widget, the changes are read using
       
   269     the same property and written back to the model.
       
   270     By default, each widget's \l{Q_PROPERTY()}{user property} is used to
       
   271     transfer data between the model and the widget. Since Qt 4.3, an
       
   272     additional addMapping() function enables a named property to be used
       
   273     instead of the default user property.
       
   274 
       
   275     It is possible to set an item delegate to support custom widgets. By default,
       
   276     a QItemDelegate is used to synchronize the model with the widgets.
       
   277 
       
   278     Let us assume that we have an item model named \c{model} with the following contents:
       
   279 
       
   280     \table
       
   281     \row \o 1 \o Qt Norway       \o Oslo
       
   282     \row \o 2 \o Qt Australia    \o Brisbane
       
   283     \row \o 3 \o Qt USA          \o Palo Alto
       
   284     \row \o 4 \o Qt China        \o Beijing
       
   285     \row \o 5 \o Qt Germany      \o Berlin
       
   286     \endtable
       
   287 
       
   288     The following code will map the columns of the model to widgets called \c mySpinBox,
       
   289     \c myLineEdit and \c{myCountryChooser}:
       
   290 
       
   291     \snippet doc/src/snippets/code/src_gui_itemviews_qdatawidgetmapper.cpp 0
       
   292 
       
   293     After the call to toFirst(), \c mySpinBox displays the value \c{1}, \c myLineEdit
       
   294     displays \c {Nokia Corporation and/or its subsidiary(-ies)} and \c myCountryChooser displays \c{Oslo}. The
       
   295     navigational functions toFirst(), toNext(), toPrevious(), toLast() and setCurrentIndex()
       
   296     can be used to navigate in the model and update the widgets with contents from
       
   297     the model.
       
   298 
       
   299     The setRootIndex() function enables a particular item in a model to be
       
   300     specified as the root index - children of this item will be mapped to
       
   301     the relevant widgets in the user interface.
       
   302 
       
   303     QDataWidgetMapper supports two submit policies, \c AutoSubmit and \c{ManualSubmit}.
       
   304     \c AutoSubmit will update the model as soon as the current widget loses focus,
       
   305     \c ManualSubmit will not update the model unless submit() is called. \c ManualSubmit
       
   306     is useful when displaying a dialog that lets the user cancel all modifications.
       
   307     Also, other views that display the model won't update until the user finishes
       
   308     all their modifications and submits.
       
   309 
       
   310     Note that QDataWidgetMapper keeps track of external modifications. If the contents
       
   311     of the model are updated in another module of the application, the widgets are
       
   312     updated as well.
       
   313 
       
   314     \sa QAbstractItemModel, QAbstractItemDelegate
       
   315  */
       
   316 
       
   317 /*! \enum QDataWidgetMapper::SubmitPolicy
       
   318 
       
   319     This enum describes the possible submit policies a QDataWidgetMapper
       
   320     supports.
       
   321 
       
   322     \value AutoSubmit    Whenever a widget loses focus, the widget's current
       
   323                          value is set to the item model.
       
   324     \value ManualSubmit  The model is not updated until submit() is called.
       
   325  */
       
   326 
       
   327 /*!
       
   328     \fn void QDataWidgetMapper::currentIndexChanged(int index)
       
   329 
       
   330     This signal is emitted after the current index has changed and
       
   331     all widgets were populated with new data. \a index is the new
       
   332     current index.
       
   333 
       
   334     \sa currentIndex(), setCurrentIndex()
       
   335  */
       
   336 
       
   337 /*!
       
   338     Constructs a new QDataWidgetMapper with parent object \a parent.
       
   339     By default, the orientation is horizontal and the submit policy
       
   340     is \c{AutoSubmit}.
       
   341 
       
   342     \sa setOrientation(), setSubmitPolicy()
       
   343  */
       
   344 QDataWidgetMapper::QDataWidgetMapper(QObject *parent)
       
   345     : QObject(*new QDataWidgetMapperPrivate, parent)
       
   346 {
       
   347     setItemDelegate(new QItemDelegate(this));
       
   348 }
       
   349 
       
   350 /*!
       
   351     Destroys the object.
       
   352  */
       
   353 QDataWidgetMapper::~QDataWidgetMapper()
       
   354 {
       
   355 }
       
   356 
       
   357 /*!
       
   358      Sets the current model to \a model. If another model was set,
       
   359      all mappings to that old model are cleared.
       
   360 
       
   361      \sa model()
       
   362  */
       
   363 void QDataWidgetMapper::setModel(QAbstractItemModel *model)
       
   364 {
       
   365     Q_D(QDataWidgetMapper);
       
   366 
       
   367     if (d->model == model)
       
   368         return;
       
   369 
       
   370     if (d->model) {
       
   371         disconnect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this,
       
   372                    SLOT(_q_dataChanged(QModelIndex,QModelIndex)));
       
   373         disconnect(d->model, SIGNAL(destroyed()), this,
       
   374                    SLOT(_q_modelDestroyed()));
       
   375     }
       
   376     clearMapping();
       
   377     d->rootIndex = QModelIndex();
       
   378     d->currentTopLeft = QModelIndex();
       
   379 
       
   380     d->model = model;
       
   381 
       
   382     connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
       
   383             SLOT(_q_dataChanged(QModelIndex,QModelIndex)));
       
   384     connect(model, SIGNAL(destroyed()), SLOT(_q_modelDestroyed()));
       
   385 }
       
   386 
       
   387 /*!
       
   388     Returns the current model.
       
   389 
       
   390     \sa setModel()
       
   391  */
       
   392 QAbstractItemModel *QDataWidgetMapper::model() const
       
   393 {
       
   394     Q_D(const QDataWidgetMapper);
       
   395     return d->model == QAbstractItemModelPrivate::staticEmptyModel()
       
   396             ? static_cast<QAbstractItemModel *>(0)
       
   397             : d->model;
       
   398 }
       
   399 
       
   400 /*!
       
   401     Sets the item delegate to \a delegate. The delegate will be used to write
       
   402     data from the model into the widget and from the widget to the model,
       
   403     using QAbstractItemDelegate::setEditorData() and QAbstractItemDelegate::setModelData().
       
   404 
       
   405     The delegate also decides when to apply data and when to change the editor,
       
   406     using QAbstractItemDelegate::commitData() and QAbstractItemDelegate::closeEditor().
       
   407 
       
   408     \warning You should not share the same instance of a delegate between widget mappers
       
   409     or views. Doing so can cause incorrect or unintuitive editing behavior since each
       
   410     view connected to a given delegate may receive the \l{QAbstractItemDelegate::}{closeEditor()}
       
   411     signal, and attempt to access, modify or close an editor that has already been closed.
       
   412  */
       
   413 void QDataWidgetMapper::setItemDelegate(QAbstractItemDelegate *delegate)
       
   414 {
       
   415     Q_D(QDataWidgetMapper);
       
   416     QAbstractItemDelegate *oldDelegate = d->delegate;
       
   417     if (oldDelegate) {
       
   418         disconnect(oldDelegate, SIGNAL(commitData(QWidget*)), this, SLOT(_q_commitData(QWidget*)));
       
   419         disconnect(oldDelegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)),
       
   420                    this, SLOT(_q_closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)));
       
   421     }
       
   422 
       
   423     d->delegate = delegate;
       
   424 
       
   425     if (delegate) {
       
   426         connect(delegate, SIGNAL(commitData(QWidget*)), SLOT(_q_commitData(QWidget*)));
       
   427         connect(delegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)),
       
   428                 SLOT(_q_closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)));
       
   429     }
       
   430 
       
   431     d->flipEventFilters(oldDelegate, delegate);
       
   432 }
       
   433 
       
   434 /*!
       
   435     Returns the current item delegate.
       
   436  */
       
   437 QAbstractItemDelegate *QDataWidgetMapper::itemDelegate() const
       
   438 {
       
   439     Q_D(const QDataWidgetMapper);
       
   440     return d->delegate;
       
   441 }
       
   442 
       
   443 /*!
       
   444     Sets the root item to \a index. This can be used to display
       
   445     a branch of a tree. Pass an invalid model index to display
       
   446     the top-most branch.
       
   447 
       
   448     \sa rootIndex()
       
   449  */
       
   450 void QDataWidgetMapper::setRootIndex(const QModelIndex &index)
       
   451 {
       
   452     Q_D(QDataWidgetMapper);
       
   453     d->rootIndex = index;
       
   454 }
       
   455 
       
   456 /*!
       
   457     Returns the current root index.
       
   458 
       
   459     \sa setRootIndex()
       
   460 */
       
   461 QModelIndex QDataWidgetMapper::rootIndex() const
       
   462 {
       
   463     Q_D(const QDataWidgetMapper);
       
   464     return QModelIndex(d->rootIndex);
       
   465 }
       
   466 
       
   467 /*!
       
   468     Adds a mapping between a \a widget and a \a section from the model.
       
   469     The \a section is a column in the model if the orientation is
       
   470     horizontal (the default), otherwise a row.
       
   471 
       
   472     For the following example, we assume a model \c myModel that
       
   473     has two columns: the first one contains the names of people in a
       
   474     group, and the second column contains their ages. The first column
       
   475     is mapped to the QLineEdit \c nameLineEdit, and the second is
       
   476     mapped to the QSpinBox \c{ageSpinBox}:
       
   477 
       
   478     \snippet doc/src/snippets/code/src_gui_itemviews_qdatawidgetmapper.cpp 1
       
   479 
       
   480     \bold{Notes:}
       
   481     \list
       
   482     \o If the \a widget is already mapped to a section, the
       
   483     old mapping will be replaced by the new one.
       
   484     \o Only one-to-one mappings between sections and widgets are allowed.
       
   485     It is not possible to map a single section to multiple widgets, or to
       
   486     map a single widget to multiple sections.
       
   487     \endlist
       
   488 
       
   489     \sa removeMapping(), mappedSection(), clearMapping()
       
   490  */
       
   491 void QDataWidgetMapper::addMapping(QWidget *widget, int section)
       
   492 {
       
   493     Q_D(QDataWidgetMapper);
       
   494 
       
   495     removeMapping(widget);
       
   496     d->widgetMap.append(QDataWidgetMapperPrivate::WidgetMapper(widget, section, d->indexAt(section)));
       
   497     widget->installEventFilter(d->delegate);
       
   498 }
       
   499 
       
   500 /*!
       
   501   \since 4.3
       
   502 
       
   503   Essentially the same as addMapping(), but adds the possibility to specify
       
   504   the property to use specifying \a propertyName.
       
   505 
       
   506   \sa addMapping()
       
   507 */
       
   508 
       
   509 void QDataWidgetMapper::addMapping(QWidget *widget, int section, const QByteArray &propertyName)
       
   510 {
       
   511     Q_D(QDataWidgetMapper);
       
   512 
       
   513     removeMapping(widget);
       
   514     d->widgetMap.append(QDataWidgetMapperPrivate::WidgetMapper(widget, section, d->indexAt(section), propertyName));
       
   515     widget->installEventFilter(d->delegate);
       
   516 }
       
   517 
       
   518 /*!
       
   519     Removes the mapping for the given \a widget.
       
   520 
       
   521     \sa addMapping(), clearMapping()
       
   522  */
       
   523 void QDataWidgetMapper::removeMapping(QWidget *widget)
       
   524 {
       
   525     Q_D(QDataWidgetMapper);
       
   526 
       
   527     int idx = d->findWidget(widget);
       
   528     if (idx == -1)
       
   529         return;
       
   530 
       
   531     d->widgetMap.removeAt(idx);
       
   532     widget->removeEventFilter(d->delegate);
       
   533 }
       
   534 
       
   535 /*!
       
   536     Returns the section the \a widget is mapped to or -1
       
   537     if the widget is not mapped.
       
   538 
       
   539     \sa addMapping(), removeMapping()
       
   540  */
       
   541 int QDataWidgetMapper::mappedSection(QWidget *widget) const
       
   542 {
       
   543     Q_D(const QDataWidgetMapper);
       
   544 
       
   545     int idx = d->findWidget(widget);
       
   546     if (idx == -1)
       
   547         return -1;
       
   548 
       
   549     return d->widgetMap.at(idx).section;
       
   550 }
       
   551 
       
   552 /*!
       
   553   \since 4.3
       
   554   Returns the name of the property that is used when mapping
       
   555   data to the given \a widget.
       
   556 
       
   557   \sa mappedSection(), addMapping(), removeMapping()
       
   558 */
       
   559 
       
   560 QByteArray QDataWidgetMapper::mappedPropertyName(QWidget *widget) const
       
   561 {
       
   562     Q_D(const QDataWidgetMapper);
       
   563 
       
   564     int idx = d->findWidget(widget);
       
   565     if (idx == -1)
       
   566         return QByteArray();
       
   567     const QDataWidgetMapperPrivate::WidgetMapper &m = d->widgetMap.at(idx);
       
   568     if (m.property.isEmpty())
       
   569         return m.widget->metaObject()->userProperty().name();
       
   570     else
       
   571         return m.property;
       
   572 }
       
   573 
       
   574 /*!
       
   575     Returns the widget that is mapped at \a section, or
       
   576     0 if no widget is mapped at that section.
       
   577 
       
   578     \sa addMapping(), removeMapping()
       
   579  */
       
   580 QWidget *QDataWidgetMapper::mappedWidgetAt(int section) const
       
   581 {
       
   582     Q_D(const QDataWidgetMapper);
       
   583 
       
   584     for (int i = 0; i < d->widgetMap.count(); ++i) {
       
   585         if (d->widgetMap.at(i).section == section)
       
   586             return d->widgetMap.at(i).widget;
       
   587     }
       
   588 
       
   589     return 0;
       
   590 }
       
   591 
       
   592 /*!
       
   593     Repopulates all widgets with the current data of the model.
       
   594     All unsubmitted changes will be lost.
       
   595 
       
   596     \sa submit(), setSubmitPolicy()
       
   597  */
       
   598 void QDataWidgetMapper::revert()
       
   599 {
       
   600     Q_D(QDataWidgetMapper);
       
   601 
       
   602     d->populate();
       
   603 }
       
   604 
       
   605 /*!
       
   606     Submits all changes from the mapped widgets to the model.
       
   607 
       
   608     For every mapped section, the item delegate reads the current
       
   609     value from the widget and sets it in the model. Finally, the
       
   610     model's \l {QAbstractItemModel::}{submit()} method is invoked.
       
   611 
       
   612     Returns true if all the values were submitted, otherwise false.
       
   613 
       
   614     Note: For database models, QSqlQueryModel::lastError() can be
       
   615     used to retrieve the last error.
       
   616 
       
   617     \sa revert(), setSubmitPolicy()
       
   618  */
       
   619 bool QDataWidgetMapper::submit()
       
   620 {
       
   621     Q_D(QDataWidgetMapper);
       
   622 
       
   623     for (int i = 0; i < d->widgetMap.count(); ++i) {
       
   624         const QDataWidgetMapperPrivate::WidgetMapper &m = d->widgetMap.at(i);
       
   625         if (!d->commit(m))
       
   626             return false;
       
   627     }
       
   628 
       
   629     return d->model->submit();
       
   630 }
       
   631 
       
   632 /*!
       
   633     Populates the widgets with data from the first row of the model
       
   634     if the orientation is horizontal (the default), otherwise
       
   635     with data from the first column.
       
   636 
       
   637     This is equivalent to calling \c setCurrentIndex(0).
       
   638 
       
   639     \sa toLast(), setCurrentIndex()
       
   640  */
       
   641 void QDataWidgetMapper::toFirst()
       
   642 {
       
   643     setCurrentIndex(0);
       
   644 }
       
   645 
       
   646 /*!
       
   647     Populates the widgets with data from the last row of the model
       
   648     if the orientation is horizontal (the default), otherwise
       
   649     with data from the last column.
       
   650 
       
   651     Calls setCurrentIndex() internally.
       
   652 
       
   653     \sa toFirst(), setCurrentIndex()
       
   654  */
       
   655 void QDataWidgetMapper::toLast()
       
   656 {
       
   657     Q_D(QDataWidgetMapper);
       
   658     setCurrentIndex(d->itemCount() - 1);
       
   659 }
       
   660 
       
   661 
       
   662 /*!
       
   663     Populates the widgets with data from the next row of the model
       
   664     if the orientation is horizontal (the default), otherwise
       
   665     with data from the next column.
       
   666 
       
   667     Calls setCurrentIndex() internally. Does nothing if there is
       
   668     no next row in the model.
       
   669 
       
   670     \sa toPrevious(), setCurrentIndex()
       
   671  */
       
   672 void QDataWidgetMapper::toNext()
       
   673 {
       
   674     Q_D(QDataWidgetMapper);
       
   675     setCurrentIndex(d->currentIdx() + 1);
       
   676 }
       
   677 
       
   678 /*!
       
   679     Populates the widgets with data from the previous row of the model
       
   680     if the orientation is horizontal (the default), otherwise
       
   681     with data from the previous column.
       
   682 
       
   683     Calls setCurrentIndex() internally. Does nothing if there is
       
   684     no previous row in the model.
       
   685 
       
   686     \sa toNext(), setCurrentIndex()
       
   687  */
       
   688 void QDataWidgetMapper::toPrevious()
       
   689 {
       
   690     Q_D(QDataWidgetMapper);
       
   691     setCurrentIndex(d->currentIdx() - 1);
       
   692 }
       
   693 
       
   694 /*!
       
   695     \property QDataWidgetMapper::currentIndex
       
   696     \brief the current row or column
       
   697 
       
   698     The widgets are populated with with data from the row at \a index
       
   699     if the orientation is horizontal (the default), otherwise with
       
   700     data from the column at \a index.
       
   701 
       
   702     \sa setCurrentModelIndex(), toFirst(), toNext(), toPrevious(), toLast()
       
   703 */
       
   704 void QDataWidgetMapper::setCurrentIndex(int index)
       
   705 {
       
   706     Q_D(QDataWidgetMapper);
       
   707 
       
   708     if (index < 0 || index >= d->itemCount())
       
   709         return;
       
   710     d->currentTopLeft = d->orientation == Qt::Horizontal
       
   711                             ? d->model->index(index, 0, d->rootIndex)
       
   712                             : d->model->index(0, index, d->rootIndex);
       
   713     d->populate();
       
   714 
       
   715     emit currentIndexChanged(index);
       
   716 }
       
   717 
       
   718 int QDataWidgetMapper::currentIndex() const
       
   719 {
       
   720     Q_D(const QDataWidgetMapper);
       
   721     return d->currentIdx();
       
   722 }
       
   723 
       
   724 /*!
       
   725     Sets the current index to the row of the \a index if the
       
   726     orientation is horizontal (the default), otherwise to the
       
   727     column of the \a index.
       
   728 
       
   729     Calls setCurrentIndex() internally. This convenience slot can be
       
   730     connected to the signal \l
       
   731     {QItemSelectionModel::}{currentRowChanged()} or \l
       
   732     {QItemSelectionModel::}{currentColumnChanged()} of another view's
       
   733     \l {QItemSelectionModel}{selection model}.
       
   734 
       
   735     The following example illustrates how to update all widgets
       
   736     with new data whenever the selection of a QTableView named
       
   737     \c myTableView changes:
       
   738 
       
   739     \snippet doc/src/snippets/code/src_gui_itemviews_qdatawidgetmapper.cpp 2
       
   740 
       
   741     \sa currentIndex()
       
   742 */
       
   743 void QDataWidgetMapper::setCurrentModelIndex(const QModelIndex &index)
       
   744 {
       
   745     Q_D(QDataWidgetMapper);
       
   746 
       
   747     if (!index.isValid()
       
   748         || index.model() != d->model
       
   749         || index.parent() != d->rootIndex)
       
   750         return;
       
   751 
       
   752     setCurrentIndex(d->orientation == Qt::Horizontal ? index.row() : index.column());
       
   753 }
       
   754 
       
   755 /*!
       
   756     Clears all mappings.
       
   757 
       
   758     \sa addMapping(), removeMapping()
       
   759  */
       
   760 void QDataWidgetMapper::clearMapping()
       
   761 {
       
   762     Q_D(QDataWidgetMapper);
       
   763 
       
   764     while (!d->widgetMap.isEmpty()) {
       
   765         QWidget *w = d->widgetMap.takeLast().widget;
       
   766         if (w)
       
   767             w->removeEventFilter(d->delegate);
       
   768     }
       
   769 }
       
   770 
       
   771 /*!
       
   772     \property QDataWidgetMapper::orientation
       
   773     \brief the orientation of the model
       
   774 
       
   775     If the orientation is Qt::Horizontal (the default), a widget is
       
   776     mapped to a column of a data model. The widget will be populated
       
   777     with the model's data from its mapped column and the row that
       
   778     currentIndex() points at.
       
   779 
       
   780     Use Qt::Horizontal for tabular data that looks like this:
       
   781 
       
   782     \table
       
   783     \row \o 1 \o Qt Norway       \o Oslo
       
   784     \row \o 2 \o Qt Australia    \o Brisbane
       
   785     \row \o 3 \o Qt USA          \o Silicon Valley
       
   786     \row \o 4 \o Qt China        \o Beijing
       
   787     \row \o 5 \o Qt Germany      \o Berlin
       
   788     \endtable
       
   789 
       
   790     If the orientation is set to Qt::Vertical, a widget is mapped to
       
   791     a row. Calling setCurrentIndex() will change the current column.
       
   792     The widget will be populates with the model's data from its
       
   793     mapped row and the column that currentIndex() points at.
       
   794 
       
   795     Use Qt::Vertical for tabular data that looks like this:
       
   796 
       
   797     \table
       
   798     \row \o 1 \o 2 \o 3 \o 4 \o 5
       
   799     \row \o Qt Norway \o Qt Australia \o Qt USA \o Qt China \o Qt Germany
       
   800     \row \o Oslo \o Brisbane \o Silicon Valley \o Beijing \i Berlin
       
   801     \endtable
       
   802 
       
   803     Changing the orientation clears all existing mappings.
       
   804 */
       
   805 void QDataWidgetMapper::setOrientation(Qt::Orientation orientation)
       
   806 {
       
   807     Q_D(QDataWidgetMapper);
       
   808 
       
   809     if (d->orientation == orientation)
       
   810         return;
       
   811 
       
   812     clearMapping();
       
   813     d->orientation = orientation;
       
   814 }
       
   815 
       
   816 Qt::Orientation QDataWidgetMapper::orientation() const
       
   817 {
       
   818     Q_D(const QDataWidgetMapper);
       
   819     return d->orientation;
       
   820 }
       
   821 
       
   822 /*!
       
   823     \property QDataWidgetMapper::submitPolicy
       
   824     \brief the current submit policy
       
   825 
       
   826     Changing the current submit policy will revert all widgets
       
   827     to the current data from the model.
       
   828 */
       
   829 void QDataWidgetMapper::setSubmitPolicy(SubmitPolicy policy)
       
   830 {
       
   831     Q_D(QDataWidgetMapper);
       
   832     if (policy == d->submitPolicy)
       
   833         return;
       
   834 
       
   835     revert();
       
   836     d->submitPolicy = policy;
       
   837 }
       
   838 
       
   839 QDataWidgetMapper::SubmitPolicy QDataWidgetMapper::submitPolicy() const
       
   840 {
       
   841     Q_D(const QDataWidgetMapper);
       
   842     return d->submitPolicy;
       
   843 }
       
   844 
       
   845 QT_END_NAMESPACE
       
   846 
       
   847 #include "moc_qdatawidgetmapper.cpp"
       
   848 
       
   849 #endif // QT_NO_DATAWIDGETMAPPER