1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
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 
QDataWidgetMapperPrivate()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 
itemCount()73     inline int itemCount()
74     {
75         return orientation == Qt::Horizontal
76             ? model->rowCount(rootIndex)
77             : model->columnCount(rootIndex);
78     }
79 
currentIdx() const80     inline int currentIdx() const
81     {
82         return orientation == Qt::Horizontal ? currentTopLeft.row() : currentTopLeft.column();
83     }
84 
indexAt(int itemPos)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 
flipEventFilters(QAbstractItemDelegate * oldDelegate,QAbstractItemDelegate * newDelegate)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     {
WidgetMapperQDataWidgetMapperPrivate::WidgetMapper114         inline WidgetMapper(QWidget *w = 0, int c = 0, const QModelIndex &i = QModelIndex())
115             : widget(w), section(c), currentIndex(i) {}
WidgetMapperQDataWidgetMapperPrivate::WidgetMapper116         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 
findWidget(QWidget * w) const133 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 
commit(const WidgetMapper & m)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 
populate(WidgetMapper & m)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 
populate()172 void QDataWidgetMapperPrivate::populate()
173 {
174     for (int i = 0; i < widgetMap.count(); ++i)
175         populate(widgetMap[i]);
176 }
177 
qContainsIndex(const QModelIndex & idx,const QModelIndex & topLeft,const QModelIndex & bottomRight)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 
_q_dataChanged(const QModelIndex & topLeft,const QModelIndex & bottomRight)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 
_q_commitData(QWidget * w)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:
focusNextPrevChild(bool next)212     bool focusNextPrevChild(bool next)
213     {
214         return QWidget::focusNextPrevChild(next);
215     }
216 
focusNextPrevChild(QWidget * w,bool next)217     static inline void focusNextPrevChild(QWidget *w, bool next)
218     {
219         static_cast<QFocusHelper *>(w)->focusNextPrevChild(next);
220     }
221 };
222 
_q_closeEditor(QWidget * w,QAbstractItemDelegate::EndEditHint hint)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 
_q_modelDestroyed()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{Qt Norway} 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  */
QDataWidgetMapper(QObject * parent)344 QDataWidgetMapper::QDataWidgetMapper(QObject *parent)
345     : QObject(*new QDataWidgetMapperPrivate, parent)
346 {
347     setItemDelegate(new QItemDelegate(this));
348 }
349 
350 /*!
351     Destroys the object.
352  */
~QDataWidgetMapper()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  */
setModel(QAbstractItemModel * model)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  */
model() const392 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  */
setItemDelegate(QAbstractItemDelegate * delegate)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  */
itemDelegate() const437 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  */
setRootIndex(const QModelIndex & index)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 */
rootIndex() const461 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  */
addMapping(QWidget * widget,int section)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 
addMapping(QWidget * widget,int section,const QByteArray & propertyName)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  */
removeMapping(QWidget * widget)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  */
mappedSection(QWidget * widget) const541 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 
mappedPropertyName(QWidget * widget) const560 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  */
mappedWidgetAt(int section) const580 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  */
revert()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  */
submit()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  */
toFirst()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  */
toLast()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  */
toNext()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  */
toPrevious()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 */
setCurrentIndex(int index)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 
currentIndex() const718 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 */
setCurrentModelIndex(const QModelIndex & index)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  */
clearMapping()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 */
setOrientation(Qt::Orientation orientation)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 
orientation() const816 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 */
setSubmitPolicy(SubmitPolicy policy)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 
submitPolicy() const839 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
850