Qt 4.8
qdatawidgetmapper.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui 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 Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qdatawidgetmapper.h"
43 
44 #ifndef QT_NO_DATAWIDGETMAPPER
45 
46 #include "qabstractitemmodel.h"
47 #include "qitemdelegate.h"
48 #include "qmetaobject.h"
49 #include "qwidget.h"
50 #include "private/qobject_p.h"
51 #include "private/qabstractitemmodel_p.h"
52 
54 
56 {
57 public:
59 
61  : model(QAbstractItemModelPrivate::staticEmptyModel()), delegate(0),
63  {
64  }
65 
72 
73  inline int itemCount()
74  {
75  return orientation == Qt::Horizontal
76  ? model->rowCount(rootIndex)
77  : model->columnCount(rootIndex);
78  }
79 
80  inline int currentIdx() const
81  {
82  return orientation == Qt::Horizontal ? currentTopLeft.row() : currentTopLeft.column();
83  }
84 
85  inline QModelIndex indexAt(int itemPos)
86  {
87  return orientation == Qt::Horizontal
88  ? model->index(currentIdx(), itemPos, rootIndex)
89  : model->index(itemPos, currentIdx(), rootIndex);
90  }
91 
92  inline void flipEventFilters(QAbstractItemDelegate *oldDelegate,
93  QAbstractItemDelegate *newDelegate)
94  {
95  for (int i = 0; i < widgetMap.count(); ++i) {
96  QWidget *w = widgetMap.at(i).widget;
97  if (!w)
98  continue;
99  w->removeEventFilter(oldDelegate);
100  w->installEventFilter(newDelegate);
101  }
102  }
103 
104  void populate();
105 
106  // private slots
107  void _q_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
108  void _q_commitData(QWidget *);
110  void _q_modelDestroyed();
111 
113  {
114  inline WidgetMapper(QWidget *w = 0, int c = 0, const QModelIndex &i = QModelIndex())
115  : widget(w), section(c), currentIndex(i) {}
116  inline WidgetMapper(QWidget *w, int c, const QModelIndex &i, const QByteArray &p)
117  : widget(w), section(c), currentIndex(i), property(p) {}
118 
120  int section;
123  };
124 
125  void populate(WidgetMapper &m);
126  int findWidget(QWidget *w) const;
127 
128  bool commit(const WidgetMapper &m);
129 
131 };
132 
134 {
135  for (int i = 0; i < widgetMap.count(); ++i) {
136  if (widgetMap.at(i).widget == w)
137  return i;
138  }
139  return -1;
140 }
141 
143 {
144  if (m.widget.isNull())
145  return true; // just ignore
146 
147  if (!m.currentIndex.isValid())
148  return false;
149 
150  // Create copy to avoid passing the widget mappers data
151  QModelIndex idx = m.currentIndex;
152  if (m.property.isEmpty())
153  delegate->setModelData(m.widget, model, idx);
154  else
155  model->setData(idx, m.widget->property(m.property), Qt::EditRole);
156 
157  return true;
158 }
159 
161 {
162  if (m.widget.isNull())
163  return;
164 
166  if (m.property.isEmpty())
167  delegate->setEditorData(m.widget, m.currentIndex);
168  else
170 }
171 
173 {
174  for (int i = 0; i < widgetMap.count(); ++i)
175  populate(widgetMap[i]);
176 }
177 
178 static bool qContainsIndex(const QModelIndex &idx, const QModelIndex &topLeft,
179  const QModelIndex &bottomRight)
180 {
181  return idx.row() >= topLeft.row() && idx.row() <= bottomRight.row()
182  && idx.column() >= topLeft.column() && idx.column() <= bottomRight.column();
183 }
184 
185 void QDataWidgetMapperPrivate::_q_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
186 {
187  if (topLeft.parent() != rootIndex)
188  return; // not in our hierarchy
189 
190  for (int i = 0; i < widgetMap.count(); ++i) {
191  WidgetMapper &m = widgetMap[i];
192  if (qContainsIndex(m.currentIndex, topLeft, bottomRight))
193  populate(m);
194  }
195 }
196 
198 {
200  return;
201 
202  int idx = findWidget(w);
203  if (idx == -1)
204  return; // not our widget
205 
206  commit(widgetMap.at(idx));
207 }
208 
209 class QFocusHelper: public QWidget
210 {
211 public:
212  bool focusNextPrevChild(bool next)
213  {
214  return QWidget::focusNextPrevChild(next);
215  }
216 
217  static inline void focusNextPrevChild(QWidget *w, bool next)
218  {
219  static_cast<QFocusHelper *>(w)->focusNextPrevChild(next);
220  }
221 };
222 
224 {
225  int idx = findWidget(w);
226  if (idx == -1)
227  return; // not our widget
228 
229  switch (hint) {
231  populate(widgetMap[idx]);
232  break; }
235  break;
238  break;
241  // nothing
242  break;
243  }
244 }
245 
247 {
249 
250  model = 0;
252 }
253 
352  : QObject(*new QDataWidgetMapperPrivate, parent)
353 {
354  setItemDelegate(new QItemDelegate(this));
355 }
356 
361 {
362 }
363 
371 {
373 
374  if (d->model == model)
375  return;
376 
377  if (d->model) {
378  disconnect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this,
379  SLOT(_q_dataChanged(QModelIndex,QModelIndex)));
380  disconnect(d->model, SIGNAL(destroyed()), this,
381  SLOT(_q_modelDestroyed()));
382  }
383  clearMapping();
384  d->rootIndex = QModelIndex();
385  d->currentTopLeft = QModelIndex();
386 
387  d->model = model;
388 
389  connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
390  SLOT(_q_dataChanged(QModelIndex,QModelIndex)));
391  connect(model, SIGNAL(destroyed()), SLOT(_q_modelDestroyed()));
392 }
393 
400 {
401  Q_D(const QDataWidgetMapper);
403  ? static_cast<QAbstractItemModel *>(0)
404  : d->model;
405 }
406 
421 {
423  QAbstractItemDelegate *oldDelegate = d->delegate;
424  if (oldDelegate) {
425  disconnect(oldDelegate, SIGNAL(commitData(QWidget*)), this, SLOT(_q_commitData(QWidget*)));
426  disconnect(oldDelegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)),
427  this, SLOT(_q_closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)));
428  }
429 
430  d->delegate = delegate;
431 
432  if (delegate) {
433  connect(delegate, SIGNAL(commitData(QWidget*)), SLOT(_q_commitData(QWidget*)));
434  connect(delegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)),
436  }
437 
438  d->flipEventFilters(oldDelegate, delegate);
439 }
440 
445 {
446  Q_D(const QDataWidgetMapper);
447  return d->delegate;
448 }
449 
458 {
460  d->rootIndex = index;
461 }
462 
469 {
470  Q_D(const QDataWidgetMapper);
471  return QModelIndex(d->rootIndex);
472 }
473 
499 {
501 
502  removeMapping(widget);
503  d->widgetMap.append(QDataWidgetMapperPrivate::WidgetMapper(widget, section, d->indexAt(section)));
504  widget->installEventFilter(d->delegate);
505 }
506 
519 void QDataWidgetMapper::addMapping(QWidget *widget, int section, const QByteArray &propertyName)
520 {
522 
523  removeMapping(widget);
524  d->widgetMap.append(QDataWidgetMapperPrivate::WidgetMapper(widget, section, d->indexAt(section), propertyName));
525  widget->installEventFilter(d->delegate);
526 }
527 
534 {
536 
537  int idx = d->findWidget(widget);
538  if (idx == -1)
539  return;
540 
541  d->widgetMap.removeAt(idx);
542  widget->removeEventFilter(d->delegate);
543 }
544 
552 {
553  Q_D(const QDataWidgetMapper);
554 
555  int idx = d->findWidget(widget);
556  if (idx == -1)
557  return -1;
558 
559  return d->widgetMap.at(idx).section;
560 }
561 
574 {
575  Q_D(const QDataWidgetMapper);
576 
577  int idx = d->findWidget(widget);
578  if (idx == -1)
579  return QByteArray();
580  const QDataWidgetMapperPrivate::WidgetMapper &m = d->widgetMap.at(idx);
581  if (m.property.isEmpty())
582  return m.widget->metaObject()->userProperty().name();
583  else
584  return m.property;
585 }
586 
594 {
595  Q_D(const QDataWidgetMapper);
596 
597  for (int i = 0; i < d->widgetMap.count(); ++i) {
598  if (d->widgetMap.at(i).section == section)
599  return d->widgetMap.at(i).widget;
600  }
601 
602  return 0;
603 }
604 
612 {
614 
615  d->populate();
616 }
617 
633 {
635 
636  for (int i = 0; i < d->widgetMap.count(); ++i) {
637  const QDataWidgetMapperPrivate::WidgetMapper &m = d->widgetMap.at(i);
638  if (!d->commit(m))
639  return false;
640  }
641 
642  return d->model->submit();
643 }
644 
655 {
656  setCurrentIndex(0);
657 }
658 
669 {
671  setCurrentIndex(d->itemCount() - 1);
672 }
673 
674 
686 {
688  setCurrentIndex(d->currentIdx() + 1);
689 }
690 
702 {
704  setCurrentIndex(d->currentIdx() - 1);
705 }
706 
721 {
723 
724  if (index < 0 || index >= d->itemCount())
725  return;
726  d->currentTopLeft = d->orientation == Qt::Horizontal
727  ? d->model->index(index, 0, d->rootIndex)
728  : d->model->index(0, index, d->rootIndex);
729  d->populate();
730 
731  emit currentIndexChanged(index);
732 }
733 
735 {
736  Q_D(const QDataWidgetMapper);
737  return d->currentIdx();
738 }
739 
758 {
760 
761  if (!index.isValid()
762  || index.model() != d->model
763  || index.parent() != d->rootIndex)
764  return;
765 
766  setCurrentIndex(d->orientation == Qt::Horizontal ? index.row() : index.column());
767 }
768 
775 {
777 
778  while (!d->widgetMap.isEmpty()) {
779  QWidget *w = d->widgetMap.takeLast().widget;
780  if (w)
781  w->removeEventFilter(d->delegate);
782  }
783 }
784 
823 {
825 
826  if (d->orientation == orientation)
827  return;
828 
829  clearMapping();
830  d->orientation = orientation;
831 }
832 
834 {
835  Q_D(const QDataWidgetMapper);
836  return d->orientation;
837 }
838 
850 {
852  if (policy == d->submitPolicy)
853  return;
854 
855  revert();
856  d->submitPolicy = policy;
857 }
858 
860 {
861  Q_D(const QDataWidgetMapper);
862  return d->submitPolicy;
863 }
864 
866 
867 #include "moc_qdatawidgetmapper.cpp"
868 
869 #endif // QT_NO_DATAWIDGETMAPPER
int findWidget(QWidget *w) const
double d
Definition: qnumeric_p.h:62
virtual int columnCount(const QModelIndex &parent=QModelIndex()) const =0
Returns the number of columns for the children of the given parent.
void addMapping(QWidget *widget, int section)
Adds a mapping between a widget and a section from the model.
void toNext()
Populates the widgets with data from the next row of the model if the orientation is horizontal (the ...
The QAbstractItemDelegate class is used to display and edit data items from a model.
int row() const
Returns the row this persistent model index refers to.
void setItemDelegate(QAbstractItemDelegate *delegate)
Sets the item delegate to delegate.
static QAbstractItemModel * staticEmptyModel()
QList< WidgetMapper > widgetMap
unsigned char c[8]
Definition: qnumeric_p.h:62
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
void setOrientation(Qt::Orientation aOrientation)
QPointer< QWidget > widget
QAbstractItemDelegate * delegate
void setRootIndex(const QModelIndex &index)
Sets the root item to index.
bool isNull() const
Returns true if the referenced object has been destroyed or if there is no referenced object; otherwi...
Definition: qpointer.h:70
bool commit(const WidgetMapper &m)
int column() const
Returns the column this persistent model index refers to.
static bool qContainsIndex(const QModelIndex &idx, const QModelIndex &topLeft, const QModelIndex &bottomRight)
virtual int rowCount(const QModelIndex &parent=QModelIndex()) const =0
Returns the number of rows under the given parent.
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
#define SLOT(a)
Definition: qobjectdefs.h:226
void removeEventFilter(QObject *)
Removes an event filter object obj from this object.
Definition: qobject.cpp:2099
The QWidget class is the base class of all user interface objects.
Definition: qwidget.h:150
bool setProperty(const char *name, const QVariant &value)
Sets the value of the object&#39;s name property to value.
Definition: qobject.cpp:3755
SubmitPolicy submitPolicy() const
virtual bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole)
Sets the role data for the item at index to value.
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
#define Q_D(Class)
Definition: qglobal.h:2482
virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
Sets the data for the item at the given index in the model to the contents of the given editor...
bool submit()
Submits all changes from the mapped widgets to the model.
QAbstractItemModel * model
static void focusNextPrevChild(QWidget *w, bool next)
void revert()
Repopulates all widgets with the current data of the model.
QModelIndex parent() const
Returns the parent of the model index, or QModelIndex() if it has no parent.
QDataWidgetMapper::SubmitPolicy submitPolicy
void setSubmitPolicy(SubmitPolicy policy)
QVariant data(int role=Qt::DisplayRole) const
Returns the data for the given role for the item referred to by the index.
#define Q_Q(Class)
Definition: qglobal.h:2483
QAbstractItemModel * model() const
Returns the current model.
QModelIndex indexAt(int itemPos)
virtual QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const =0
Returns the index of the item in the model specified by the given row, column and parent index...
#define SIGNAL(a)
Definition: qobjectdefs.h:227
virtual void setCurrentIndex(int index)
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
void destroyed(QObject *=0)
This signal is emitted immediately before the object obj is destroyed, and can not be blocked...
static bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
Creates a connection of the given type from the signal in the sender object to the method in the rece...
Definition: qobject.cpp:2580
QByteArray mappedPropertyName(QWidget *widget) const
Returns the name of the property that is used when mapping data to the given widget.
int row() const
Returns the row this model index refers to.
void setModel(QAbstractItemModel *model)
Sets the current model to model.
void setCurrentModelIndex(const QModelIndex &index)
Sets the current index to the row of the index if the orientation is horizontal (the default)...
#define emit
Definition: qobjectdefs.h:76
const QAbstractItemModel * model() const
Returns a pointer to the model containing the item that this index refers to.
bool focusNextPrevChild(bool next)
Finds a new widget to give the keyboard focus to, as appropriate for Tab and Shift+Tab, and returns true if it can find a new widget, or false if it can&#39;t.
void _q_closeEditor(QWidget *, QAbstractItemDelegate::EndEditHint)
QModelIndex rootIndex() const
Returns the current root index.
SubmitPolicy
This enum describes the possible submit policies a QDataWidgetMapper supports.
void toFirst()
Populates the widgets with data from the first row of the model if the orientation is horizontal (the...
void toPrevious()
Populates the widgets with data from the previous row of the model if the orientation is horizontal (...
bool isValid() const
Returns true if this model index is valid; otherwise returns false.
The QAbstractItemModel class provides the abstract interface for item model classes.
void toLast()
Populates the widgets with data from the last row of the model if the orientation is horizontal (the ...
int currentIndex() const
QWidget * mappedWidgetAt(int section) const
Returns the widget that is mapped at section, or 0 if no widget is mapped at that section...
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
Disconnects signal in object sender from method in object receiver.
Definition: qobject.cpp:2895
void removeMapping(QWidget *widget)
Removes the mapping for the given widget.
Qt::Orientation orientation() const
void clearMapping()
Clears all mappings.
#define Q_DECLARE_PUBLIC(Class)
Definition: qglobal.h:2477
const char * name() const
Returns this property&#39;s name.
QPersistentModelIndex currentTopLeft
The QPersistentModelIndex class is used to locate data in a data model.
QAbstractItemDelegate * itemDelegate() const
Returns the current item delegate.
The QItemDelegate class provides display and editing facilities for data items from a model...
Definition: qitemdelegate.h:61
void installEventFilter(QObject *)
Installs an event filter filterObj on this object.
Definition: qobject.cpp:2070
virtual bool focusNextPrevChild(bool next)
Finds a new widget to give the keyboard focus to, as appropriate for Tab and Shift+Tab, and returns true if it can find a new widget, or false if it can&#39;t.
Definition: qwidget.cpp:6836
The QModelIndex class is used to locate data in a data model.
Definition: qnamespace.h:54
quint16 index
EndEditHint
This enum describes the different hints that the delegate can give to the model and view components t...
QVariant property(const char *name) const
Returns the value of the object&#39;s name property.
Definition: qobject.cpp:3807
QObject * parent
Definition: qobject.h:92
WidgetMapper(QWidget *w=0, int c=0, const QModelIndex &i=QModelIndex())
QMetaProperty userProperty() const
Returns the property that has the USER flag set to true.
QPersistentModelIndex rootIndex
The QDataWidgetMapper class provides mapping between a section of a data model to widgets...
WidgetMapper(QWidget *w, int c, const QModelIndex &i, const QByteArray &p)
bool isEmpty() const
Returns true if the byte array has size 0; otherwise returns false.
Definition: qbytearray.h:421
void flipEventFilters(QAbstractItemDelegate *oldDelegate, QAbstractItemDelegate *newDelegate)
void currentIndexChanged(int index)
This signal is emitted after the current index has changed and all widgets were populated with new da...
virtual void setEditorData(QWidget *editor, const QModelIndex &index) const
Sets the contents of the given editor to the data for the item at the given index.
~QDataWidgetMapper()
Destroys the object.
Orientation
Definition: qnamespace.h:174
QDataWidgetMapper(QObject *parent=0)
Constructs a new QDataWidgetMapper with parent object parent.
virtual const QMetaObject * metaObject() const
Returns a pointer to the meta-object of this object.
int column() const
Returns the column this model index refers to.
int mappedSection(QWidget *widget) const
Returns the section the widget is mapped to or -1 if the widget is not mapped.
The QList class is a template class that provides lists.
Definition: qdatastream.h:62
bool isValid() const
Returns true if this persistent model index is valid; otherwise returns false.
void _q_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)