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

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