diff -r 000000000000 -r 1918ee327afb src/gui/itemviews/qdatawidgetmapper.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gui/itemviews/qdatawidgetmapper.cpp Mon Jan 11 14:00:40 2010 +0000 @@ -0,0 +1,849 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdatawidgetmapper.h" + +#ifndef QT_NO_DATAWIDGETMAPPER + +#include "qabstractitemmodel.h" +#include "qitemdelegate.h" +#include "qmetaobject.h" +#include "qwidget.h" +#include "private/qobject_p.h" +#include "private/qabstractitemmodel_p.h" + +QT_BEGIN_NAMESPACE + +class QDataWidgetMapperPrivate: public QObjectPrivate +{ +public: + Q_DECLARE_PUBLIC(QDataWidgetMapper) + + QDataWidgetMapperPrivate() + : model(QAbstractItemModelPrivate::staticEmptyModel()), delegate(0), + orientation(Qt::Horizontal), submitPolicy(QDataWidgetMapper::AutoSubmit) + { + } + + QAbstractItemModel *model; + QAbstractItemDelegate *delegate; + Qt::Orientation orientation; + QDataWidgetMapper::SubmitPolicy submitPolicy; + QPersistentModelIndex rootIndex; + QPersistentModelIndex currentTopLeft; + + inline int itemCount() + { + return orientation == Qt::Horizontal + ? model->rowCount(rootIndex) + : model->columnCount(rootIndex); + } + + inline int currentIdx() const + { + return orientation == Qt::Horizontal ? currentTopLeft.row() : currentTopLeft.column(); + } + + inline QModelIndex indexAt(int itemPos) + { + return orientation == Qt::Horizontal + ? model->index(currentIdx(), itemPos, rootIndex) + : model->index(itemPos, currentIdx(), rootIndex); + } + + inline void flipEventFilters(QAbstractItemDelegate *oldDelegate, + QAbstractItemDelegate *newDelegate) + { + for (int i = 0; i < widgetMap.count(); ++i) { + QWidget *w = widgetMap.at(i).widget; + if (!w) + continue; + w->removeEventFilter(oldDelegate); + w->installEventFilter(newDelegate); + } + } + + void populate(); + + // private slots + void _q_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); + void _q_commitData(QWidget *); + void _q_closeEditor(QWidget *, QAbstractItemDelegate::EndEditHint); + void _q_modelDestroyed(); + + struct WidgetMapper + { + inline WidgetMapper(QWidget *w = 0, int c = 0, const QModelIndex &i = QModelIndex()) + : widget(w), section(c), currentIndex(i) {} + inline WidgetMapper(QWidget *w, int c, const QModelIndex &i, const QByteArray &p) + : widget(w), section(c), currentIndex(i), property(p) {} + + QPointer widget; + int section; + QPersistentModelIndex currentIndex; + QByteArray property; + }; + + void populate(WidgetMapper &m); + int findWidget(QWidget *w) const; + + bool commit(const WidgetMapper &m); + + QList widgetMap; +}; + +int QDataWidgetMapperPrivate::findWidget(QWidget *w) const +{ + for (int i = 0; i < widgetMap.count(); ++i) { + if (widgetMap.at(i).widget == w) + return i; + } + return -1; +} + +bool QDataWidgetMapperPrivate::commit(const WidgetMapper &m) +{ + if (m.widget.isNull()) + return true; // just ignore + + if (!m.currentIndex.isValid()) + return false; + + // Create copy to avoid passing the widget mappers data + QModelIndex idx = m.currentIndex; + if (m.property.isEmpty()) + delegate->setModelData(m.widget, model, idx); + else + model->setData(idx, m.widget->property(m.property), Qt::EditRole); + + return true; +} + +void QDataWidgetMapperPrivate::populate(WidgetMapper &m) +{ + if (m.widget.isNull()) + return; + + m.currentIndex = indexAt(m.section); + if (m.property.isEmpty()) + delegate->setEditorData(m.widget, m.currentIndex); + else + m.widget->setProperty(m.property, m.currentIndex.data(Qt::EditRole)); +} + +void QDataWidgetMapperPrivate::populate() +{ + for (int i = 0; i < widgetMap.count(); ++i) + populate(widgetMap[i]); +} + +static bool qContainsIndex(const QModelIndex &idx, const QModelIndex &topLeft, + const QModelIndex &bottomRight) +{ + return idx.row() >= topLeft.row() && idx.row() <= bottomRight.row() + && idx.column() >= topLeft.column() && idx.column() <= bottomRight.column(); +} + +void QDataWidgetMapperPrivate::_q_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) +{ + if (topLeft.parent() != rootIndex) + return; // not in our hierarchy + + for (int i = 0; i < widgetMap.count(); ++i) { + WidgetMapper &m = widgetMap[i]; + if (qContainsIndex(m.currentIndex, topLeft, bottomRight)) + populate(m); + } +} + +void QDataWidgetMapperPrivate::_q_commitData(QWidget *w) +{ + if (submitPolicy == QDataWidgetMapper::ManualSubmit) + return; + + int idx = findWidget(w); + if (idx == -1) + return; // not our widget + + commit(widgetMap.at(idx)); +} + +class QFocusHelper: public QWidget +{ +public: + bool focusNextPrevChild(bool next) + { + return QWidget::focusNextPrevChild(next); + } + + static inline void focusNextPrevChild(QWidget *w, bool next) + { + static_cast(w)->focusNextPrevChild(next); + } +}; + +void QDataWidgetMapperPrivate::_q_closeEditor(QWidget *w, QAbstractItemDelegate::EndEditHint hint) +{ + int idx = findWidget(w); + if (idx == -1) + return; // not our widget + + switch (hint) { + case QAbstractItemDelegate::RevertModelCache: { + populate(widgetMap[idx]); + break; } + case QAbstractItemDelegate::EditNextItem: + QFocusHelper::focusNextPrevChild(w, true); + break; + case QAbstractItemDelegate::EditPreviousItem: + QFocusHelper::focusNextPrevChild(w, false); + break; + case QAbstractItemDelegate::SubmitModelCache: + case QAbstractItemDelegate::NoHint: + // nothing + break; + } +} + +void QDataWidgetMapperPrivate::_q_modelDestroyed() +{ + Q_Q(QDataWidgetMapper); + + model = 0; + q->setModel(QAbstractItemModelPrivate::staticEmptyModel()); +} + +/*! + \class QDataWidgetMapper + \brief The QDataWidgetMapper class provides mapping between a section + of a data model to widgets. + \since 4.2 + \ingroup model-view + \ingroup advanced + + QDataWidgetMapper can be used to create data-aware widgets by mapping + them to sections of an item model. A section is a column of a model + if the orientation is horizontal (the default), otherwise a row. + + Every time the current index changes, each widget is updated with data + from the model via the property specified when its mapping was made. + If the user edits the contents of a widget, the changes are read using + the same property and written back to the model. + By default, each widget's \l{Q_PROPERTY()}{user property} is used to + transfer data between the model and the widget. Since Qt 4.3, an + additional addMapping() function enables a named property to be used + instead of the default user property. + + It is possible to set an item delegate to support custom widgets. By default, + a QItemDelegate is used to synchronize the model with the widgets. + + Let us assume that we have an item model named \c{model} with the following contents: + + \table + \row \o 1 \o Qt Norway \o Oslo + \row \o 2 \o Qt Australia \o Brisbane + \row \o 3 \o Qt USA \o Palo Alto + \row \o 4 \o Qt China \o Beijing + \row \o 5 \o Qt Germany \o Berlin + \endtable + + The following code will map the columns of the model to widgets called \c mySpinBox, + \c myLineEdit and \c{myCountryChooser}: + + \snippet doc/src/snippets/code/src_gui_itemviews_qdatawidgetmapper.cpp 0 + + After the call to toFirst(), \c mySpinBox displays the value \c{1}, \c myLineEdit + displays \c {Nokia Corporation and/or its subsidiary(-ies)} and \c myCountryChooser displays \c{Oslo}. The + navigational functions toFirst(), toNext(), toPrevious(), toLast() and setCurrentIndex() + can be used to navigate in the model and update the widgets with contents from + the model. + + The setRootIndex() function enables a particular item in a model to be + specified as the root index - children of this item will be mapped to + the relevant widgets in the user interface. + + QDataWidgetMapper supports two submit policies, \c AutoSubmit and \c{ManualSubmit}. + \c AutoSubmit will update the model as soon as the current widget loses focus, + \c ManualSubmit will not update the model unless submit() is called. \c ManualSubmit + is useful when displaying a dialog that lets the user cancel all modifications. + Also, other views that display the model won't update until the user finishes + all their modifications and submits. + + Note that QDataWidgetMapper keeps track of external modifications. If the contents + of the model are updated in another module of the application, the widgets are + updated as well. + + \sa QAbstractItemModel, QAbstractItemDelegate + */ + +/*! \enum QDataWidgetMapper::SubmitPolicy + + This enum describes the possible submit policies a QDataWidgetMapper + supports. + + \value AutoSubmit Whenever a widget loses focus, the widget's current + value is set to the item model. + \value ManualSubmit The model is not updated until submit() is called. + */ + +/*! + \fn void QDataWidgetMapper::currentIndexChanged(int index) + + This signal is emitted after the current index has changed and + all widgets were populated with new data. \a index is the new + current index. + + \sa currentIndex(), setCurrentIndex() + */ + +/*! + Constructs a new QDataWidgetMapper with parent object \a parent. + By default, the orientation is horizontal and the submit policy + is \c{AutoSubmit}. + + \sa setOrientation(), setSubmitPolicy() + */ +QDataWidgetMapper::QDataWidgetMapper(QObject *parent) + : QObject(*new QDataWidgetMapperPrivate, parent) +{ + setItemDelegate(new QItemDelegate(this)); +} + +/*! + Destroys the object. + */ +QDataWidgetMapper::~QDataWidgetMapper() +{ +} + +/*! + Sets the current model to \a model. If another model was set, + all mappings to that old model are cleared. + + \sa model() + */ +void QDataWidgetMapper::setModel(QAbstractItemModel *model) +{ + Q_D(QDataWidgetMapper); + + if (d->model == model) + return; + + if (d->model) { + disconnect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, + SLOT(_q_dataChanged(QModelIndex,QModelIndex))); + disconnect(d->model, SIGNAL(destroyed()), this, + SLOT(_q_modelDestroyed())); + } + clearMapping(); + d->rootIndex = QModelIndex(); + d->currentTopLeft = QModelIndex(); + + d->model = model; + + connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), + SLOT(_q_dataChanged(QModelIndex,QModelIndex))); + connect(model, SIGNAL(destroyed()), SLOT(_q_modelDestroyed())); +} + +/*! + Returns the current model. + + \sa setModel() + */ +QAbstractItemModel *QDataWidgetMapper::model() const +{ + Q_D(const QDataWidgetMapper); + return d->model == QAbstractItemModelPrivate::staticEmptyModel() + ? static_cast(0) + : d->model; +} + +/*! + Sets the item delegate to \a delegate. The delegate will be used to write + data from the model into the widget and from the widget to the model, + using QAbstractItemDelegate::setEditorData() and QAbstractItemDelegate::setModelData(). + + The delegate also decides when to apply data and when to change the editor, + using QAbstractItemDelegate::commitData() and QAbstractItemDelegate::closeEditor(). + + \warning You should not share the same instance of a delegate between widget mappers + or views. Doing so can cause incorrect or unintuitive editing behavior since each + view connected to a given delegate may receive the \l{QAbstractItemDelegate::}{closeEditor()} + signal, and attempt to access, modify or close an editor that has already been closed. + */ +void QDataWidgetMapper::setItemDelegate(QAbstractItemDelegate *delegate) +{ + Q_D(QDataWidgetMapper); + QAbstractItemDelegate *oldDelegate = d->delegate; + if (oldDelegate) { + disconnect(oldDelegate, SIGNAL(commitData(QWidget*)), this, SLOT(_q_commitData(QWidget*))); + disconnect(oldDelegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)), + this, SLOT(_q_closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint))); + } + + d->delegate = delegate; + + if (delegate) { + connect(delegate, SIGNAL(commitData(QWidget*)), SLOT(_q_commitData(QWidget*))); + connect(delegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)), + SLOT(_q_closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint))); + } + + d->flipEventFilters(oldDelegate, delegate); +} + +/*! + Returns the current item delegate. + */ +QAbstractItemDelegate *QDataWidgetMapper::itemDelegate() const +{ + Q_D(const QDataWidgetMapper); + return d->delegate; +} + +/*! + Sets the root item to \a index. This can be used to display + a branch of a tree. Pass an invalid model index to display + the top-most branch. + + \sa rootIndex() + */ +void QDataWidgetMapper::setRootIndex(const QModelIndex &index) +{ + Q_D(QDataWidgetMapper); + d->rootIndex = index; +} + +/*! + Returns the current root index. + + \sa setRootIndex() +*/ +QModelIndex QDataWidgetMapper::rootIndex() const +{ + Q_D(const QDataWidgetMapper); + return QModelIndex(d->rootIndex); +} + +/*! + Adds a mapping between a \a widget and a \a section from the model. + The \a section is a column in the model if the orientation is + horizontal (the default), otherwise a row. + + For the following example, we assume a model \c myModel that + has two columns: the first one contains the names of people in a + group, and the second column contains their ages. The first column + is mapped to the QLineEdit \c nameLineEdit, and the second is + mapped to the QSpinBox \c{ageSpinBox}: + + \snippet doc/src/snippets/code/src_gui_itemviews_qdatawidgetmapper.cpp 1 + + \bold{Notes:} + \list + \o If the \a widget is already mapped to a section, the + old mapping will be replaced by the new one. + \o Only one-to-one mappings between sections and widgets are allowed. + It is not possible to map a single section to multiple widgets, or to + map a single widget to multiple sections. + \endlist + + \sa removeMapping(), mappedSection(), clearMapping() + */ +void QDataWidgetMapper::addMapping(QWidget *widget, int section) +{ + Q_D(QDataWidgetMapper); + + removeMapping(widget); + d->widgetMap.append(QDataWidgetMapperPrivate::WidgetMapper(widget, section, d->indexAt(section))); + widget->installEventFilter(d->delegate); +} + +/*! + \since 4.3 + + Essentially the same as addMapping(), but adds the possibility to specify + the property to use specifying \a propertyName. + + \sa addMapping() +*/ + +void QDataWidgetMapper::addMapping(QWidget *widget, int section, const QByteArray &propertyName) +{ + Q_D(QDataWidgetMapper); + + removeMapping(widget); + d->widgetMap.append(QDataWidgetMapperPrivate::WidgetMapper(widget, section, d->indexAt(section), propertyName)); + widget->installEventFilter(d->delegate); +} + +/*! + Removes the mapping for the given \a widget. + + \sa addMapping(), clearMapping() + */ +void QDataWidgetMapper::removeMapping(QWidget *widget) +{ + Q_D(QDataWidgetMapper); + + int idx = d->findWidget(widget); + if (idx == -1) + return; + + d->widgetMap.removeAt(idx); + widget->removeEventFilter(d->delegate); +} + +/*! + Returns the section the \a widget is mapped to or -1 + if the widget is not mapped. + + \sa addMapping(), removeMapping() + */ +int QDataWidgetMapper::mappedSection(QWidget *widget) const +{ + Q_D(const QDataWidgetMapper); + + int idx = d->findWidget(widget); + if (idx == -1) + return -1; + + return d->widgetMap.at(idx).section; +} + +/*! + \since 4.3 + Returns the name of the property that is used when mapping + data to the given \a widget. + + \sa mappedSection(), addMapping(), removeMapping() +*/ + +QByteArray QDataWidgetMapper::mappedPropertyName(QWidget *widget) const +{ + Q_D(const QDataWidgetMapper); + + int idx = d->findWidget(widget); + if (idx == -1) + return QByteArray(); + const QDataWidgetMapperPrivate::WidgetMapper &m = d->widgetMap.at(idx); + if (m.property.isEmpty()) + return m.widget->metaObject()->userProperty().name(); + else + return m.property; +} + +/*! + Returns the widget that is mapped at \a section, or + 0 if no widget is mapped at that section. + + \sa addMapping(), removeMapping() + */ +QWidget *QDataWidgetMapper::mappedWidgetAt(int section) const +{ + Q_D(const QDataWidgetMapper); + + for (int i = 0; i < d->widgetMap.count(); ++i) { + if (d->widgetMap.at(i).section == section) + return d->widgetMap.at(i).widget; + } + + return 0; +} + +/*! + Repopulates all widgets with the current data of the model. + All unsubmitted changes will be lost. + + \sa submit(), setSubmitPolicy() + */ +void QDataWidgetMapper::revert() +{ + Q_D(QDataWidgetMapper); + + d->populate(); +} + +/*! + Submits all changes from the mapped widgets to the model. + + For every mapped section, the item delegate reads the current + value from the widget and sets it in the model. Finally, the + model's \l {QAbstractItemModel::}{submit()} method is invoked. + + Returns true if all the values were submitted, otherwise false. + + Note: For database models, QSqlQueryModel::lastError() can be + used to retrieve the last error. + + \sa revert(), setSubmitPolicy() + */ +bool QDataWidgetMapper::submit() +{ + Q_D(QDataWidgetMapper); + + for (int i = 0; i < d->widgetMap.count(); ++i) { + const QDataWidgetMapperPrivate::WidgetMapper &m = d->widgetMap.at(i); + if (!d->commit(m)) + return false; + } + + return d->model->submit(); +} + +/*! + Populates the widgets with data from the first row of the model + if the orientation is horizontal (the default), otherwise + with data from the first column. + + This is equivalent to calling \c setCurrentIndex(0). + + \sa toLast(), setCurrentIndex() + */ +void QDataWidgetMapper::toFirst() +{ + setCurrentIndex(0); +} + +/*! + Populates the widgets with data from the last row of the model + if the orientation is horizontal (the default), otherwise + with data from the last column. + + Calls setCurrentIndex() internally. + + \sa toFirst(), setCurrentIndex() + */ +void QDataWidgetMapper::toLast() +{ + Q_D(QDataWidgetMapper); + setCurrentIndex(d->itemCount() - 1); +} + + +/*! + Populates the widgets with data from the next row of the model + if the orientation is horizontal (the default), otherwise + with data from the next column. + + Calls setCurrentIndex() internally. Does nothing if there is + no next row in the model. + + \sa toPrevious(), setCurrentIndex() + */ +void QDataWidgetMapper::toNext() +{ + Q_D(QDataWidgetMapper); + setCurrentIndex(d->currentIdx() + 1); +} + +/*! + Populates the widgets with data from the previous row of the model + if the orientation is horizontal (the default), otherwise + with data from the previous column. + + Calls setCurrentIndex() internally. Does nothing if there is + no previous row in the model. + + \sa toNext(), setCurrentIndex() + */ +void QDataWidgetMapper::toPrevious() +{ + Q_D(QDataWidgetMapper); + setCurrentIndex(d->currentIdx() - 1); +} + +/*! + \property QDataWidgetMapper::currentIndex + \brief the current row or column + + The widgets are populated with with data from the row at \a index + if the orientation is horizontal (the default), otherwise with + data from the column at \a index. + + \sa setCurrentModelIndex(), toFirst(), toNext(), toPrevious(), toLast() +*/ +void QDataWidgetMapper::setCurrentIndex(int index) +{ + Q_D(QDataWidgetMapper); + + if (index < 0 || index >= d->itemCount()) + return; + d->currentTopLeft = d->orientation == Qt::Horizontal + ? d->model->index(index, 0, d->rootIndex) + : d->model->index(0, index, d->rootIndex); + d->populate(); + + emit currentIndexChanged(index); +} + +int QDataWidgetMapper::currentIndex() const +{ + Q_D(const QDataWidgetMapper); + return d->currentIdx(); +} + +/*! + Sets the current index to the row of the \a index if the + orientation is horizontal (the default), otherwise to the + column of the \a index. + + Calls setCurrentIndex() internally. This convenience slot can be + connected to the signal \l + {QItemSelectionModel::}{currentRowChanged()} or \l + {QItemSelectionModel::}{currentColumnChanged()} of another view's + \l {QItemSelectionModel}{selection model}. + + The following example illustrates how to update all widgets + with new data whenever the selection of a QTableView named + \c myTableView changes: + + \snippet doc/src/snippets/code/src_gui_itemviews_qdatawidgetmapper.cpp 2 + + \sa currentIndex() +*/ +void QDataWidgetMapper::setCurrentModelIndex(const QModelIndex &index) +{ + Q_D(QDataWidgetMapper); + + if (!index.isValid() + || index.model() != d->model + || index.parent() != d->rootIndex) + return; + + setCurrentIndex(d->orientation == Qt::Horizontal ? index.row() : index.column()); +} + +/*! + Clears all mappings. + + \sa addMapping(), removeMapping() + */ +void QDataWidgetMapper::clearMapping() +{ + Q_D(QDataWidgetMapper); + + while (!d->widgetMap.isEmpty()) { + QWidget *w = d->widgetMap.takeLast().widget; + if (w) + w->removeEventFilter(d->delegate); + } +} + +/*! + \property QDataWidgetMapper::orientation + \brief the orientation of the model + + If the orientation is Qt::Horizontal (the default), a widget is + mapped to a column of a data model. The widget will be populated + with the model's data from its mapped column and the row that + currentIndex() points at. + + Use Qt::Horizontal for tabular data that looks like this: + + \table + \row \o 1 \o Qt Norway \o Oslo + \row \o 2 \o Qt Australia \o Brisbane + \row \o 3 \o Qt USA \o Silicon Valley + \row \o 4 \o Qt China \o Beijing + \row \o 5 \o Qt Germany \o Berlin + \endtable + + If the orientation is set to Qt::Vertical, a widget is mapped to + a row. Calling setCurrentIndex() will change the current column. + The widget will be populates with the model's data from its + mapped row and the column that currentIndex() points at. + + Use Qt::Vertical for tabular data that looks like this: + + \table + \row \o 1 \o 2 \o 3 \o 4 \o 5 + \row \o Qt Norway \o Qt Australia \o Qt USA \o Qt China \o Qt Germany + \row \o Oslo \o Brisbane \o Silicon Valley \o Beijing \i Berlin + \endtable + + Changing the orientation clears all existing mappings. +*/ +void QDataWidgetMapper::setOrientation(Qt::Orientation orientation) +{ + Q_D(QDataWidgetMapper); + + if (d->orientation == orientation) + return; + + clearMapping(); + d->orientation = orientation; +} + +Qt::Orientation QDataWidgetMapper::orientation() const +{ + Q_D(const QDataWidgetMapper); + return d->orientation; +} + +/*! + \property QDataWidgetMapper::submitPolicy + \brief the current submit policy + + Changing the current submit policy will revert all widgets + to the current data from the model. +*/ +void QDataWidgetMapper::setSubmitPolicy(SubmitPolicy policy) +{ + Q_D(QDataWidgetMapper); + if (policy == d->submitPolicy) + return; + + revert(); + d->submitPolicy = policy; +} + +QDataWidgetMapper::SubmitPolicy QDataWidgetMapper::submitPolicy() const +{ + Q_D(const QDataWidgetMapper); + return d->submitPolicy; +} + +QT_END_NAMESPACE + +#include "moc_qdatawidgetmapper.cpp" + +#endif // QT_NO_DATAWIDGETMAPPER