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

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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