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

source code of qtbase/src/widgets/itemviews/qdatawidgetmapper.cpp