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