Don't call virtual methods after the source model is destroyed.
[qt:qt.git] / src / gui / itemviews / qabstractproxymodel.cpp
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 "qabstractproxymodel.h"
43
44 #ifndef QT_NO_PROXYMODEL
45
46 #include "qitemselectionmodel.h"
47 #include <private/qabstractproxymodel_p.h>
48 #include <QtCore/QSize>
49 #include <QtCore/QStringList>
50
51
52 QT_BEGIN_NAMESPACE
53
54 /*!
55     \since 4.1
56     \class QAbstractProxyModel
57     \brief The QAbstractProxyModel class provides a base class for proxy item
58     models that can do sorting, filtering or other data processing tasks.
59     \ingroup model-view
60
61     This class defines the standard interface that proxy models must use to be
62     able to interoperate correctly with other model/view components. It is not
63     supposed to be instantiated directly.
64
65     All standard proxy models are derived from the QAbstractProxyModel class.
66     If you need to create a new proxy model class, it is usually better to
67     subclass an existing class that provides the closest behavior to the one
68     you want to provide.
69
70     Proxy models that filter or sort items of data from a source model should
71     be created by using or subclassing QSortFilterProxyModel.
72
73     To subclass QAbstractProxyModel, you need to implement mapFromSource() and
74     mapToSource(). The mapSelectionFromSource() and mapSelectionToSource()
75     functions only need to be reimplemented if you need a behavior different
76     from the default behavior.
77
78     \note If the source model is deleted or no source model is specified, the
79     proxy model operates on a empty placeholder model.
80
81     \sa QSortFilterProxyModel, QAbstractItemModel, {Model/View Programming}
82 */
83
84 //detects the deletion of the source model
85 void QAbstractProxyModelPrivate::_q_sourceModelDestroyed()
86 {
87     invalidatePersistentIndexes();
88     model = QAbstractItemModelPrivate::staticEmptyModel();
89 }
90
91 /*!
92     Constructs a proxy model with the given \a parent.
93 */
94
95 QAbstractProxyModel::QAbstractProxyModel(QObject *parent)
96     :QAbstractItemModel(*new QAbstractProxyModelPrivate, parent)
97 {
98     setSourceModel(QAbstractItemModelPrivate::staticEmptyModel());
99 }
100
101 /*!
102     \internal
103 */
104
105 QAbstractProxyModel::QAbstractProxyModel(QAbstractProxyModelPrivate &dd, QObject *parent)
106     : QAbstractItemModel(dd, parent)
107 {
108     setSourceModel(QAbstractItemModelPrivate::staticEmptyModel());
109 }
110
111 /*!
112     Destroys the proxy model.
113 */
114 QAbstractProxyModel::~QAbstractProxyModel()
115 {
116
117 }
118
119 /*!
120     Sets the given \a sourceModel to be processed by the proxy model.
121 */
122 void QAbstractProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
123 {
124     Q_D(QAbstractProxyModel);
125     if (d->model)
126         disconnect(d->model, SIGNAL(destroyed()), this, SLOT(_q_sourceModelDestroyed()));
127
128     if (sourceModel) {
129         d->model = sourceModel;
130         connect(d->model, SIGNAL(destroyed()), this, SLOT(_q_sourceModelDestroyed()));
131     } else {
132         d->model = QAbstractItemModelPrivate::staticEmptyModel();
133     }
134     d->roleNames = d->model->roleNames();
135 }
136
137 /*!
138     Returns the model that contains the data that is available through the proxy model.
139 */
140 QAbstractItemModel *QAbstractProxyModel::sourceModel() const
141 {
142     Q_D(const QAbstractProxyModel);
143     if (d->model == QAbstractItemModelPrivate::staticEmptyModel())
144         return 0;
145     return d->model;
146 }
147
148 /*!
149     \reimp
150  */
151 bool QAbstractProxyModel::submit()
152 {
153     Q_D(QAbstractProxyModel);
154     return d->model->submit();
155 }
156
157 /*!
158     \reimp
159  */
160 void QAbstractProxyModel::revert()
161 {
162     Q_D(QAbstractProxyModel);
163     d->model->revert();
164 }
165
166
167 /*!
168   \fn QModelIndex QAbstractProxyModel::mapToSource(const QModelIndex &proxyIndex) const
169
170   Reimplement this function to return the model index in the source model that
171   corresponds to the \a proxyIndex in the proxy model.
172
173   \sa mapFromSource()
174 */
175
176 /*!
177   \fn QModelIndex QAbstractProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
178
179   Reimplement this function to return the model index in the proxy model that
180   corresponds to the \a sourceIndex from the source model.
181
182   \sa mapToSource()
183 */
184
185 /*!
186   Returns a source selection mapped from the specified \a proxySelection.
187
188   Reimplement this method to map proxy selections to source selections.
189  */
190 QItemSelection QAbstractProxyModel::mapSelectionToSource(const QItemSelection &proxySelection) const
191 {
192     QModelIndexList proxyIndexes = proxySelection.indexes();
193     QItemSelection sourceSelection;
194     for (int i = 0; i < proxyIndexes.size(); ++i) {
195         const QModelIndex proxyIdx = mapToSource(proxyIndexes.at(i));
196         if (!proxyIdx.isValid())
197             continue;
198         sourceSelection << QItemSelectionRange(proxyIdx);
199     }
200     return sourceSelection;
201 }
202
203 /*!
204   Returns a proxy selection mapped from the specified \a sourceSelection.
205
206   Reimplement this method to map source selections to proxy selections.
207 */
208 QItemSelection QAbstractProxyModel::mapSelectionFromSource(const QItemSelection &sourceSelection) const
209 {
210     QModelIndexList sourceIndexes = sourceSelection.indexes();
211     QItemSelection proxySelection;
212     for (int i = 0; i < sourceIndexes.size(); ++i) {
213         const QModelIndex srcIdx = mapFromSource(sourceIndexes.at(i));
214         if (!srcIdx.isValid())
215             continue;
216         proxySelection << QItemSelectionRange(srcIdx);
217     }
218     return proxySelection;
219 }
220
221 /*!
222     \reimp
223  */
224 QVariant QAbstractProxyModel::data(const QModelIndex &proxyIndex, int role) const
225 {
226     Q_D(const QAbstractProxyModel);
227     return d->model->data(mapToSource(proxyIndex), role);
228 }
229
230 /*!
231     \reimp
232  */
233 QVariant QAbstractProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
234 {
235     Q_D(const QAbstractProxyModel);
236     int sourceSection;
237     if (orientation == Qt::Horizontal) {
238         const QModelIndex proxyIndex = index(0, section);
239         sourceSection = mapToSource(proxyIndex).column();
240     } else {
241         const QModelIndex proxyIndex = index(section, 0);
242         sourceSection = mapToSource(proxyIndex).row();
243     }
244     return d->model->headerData(sourceSection, orientation, role);
245 }
246
247 /*!
248     \reimp
249  */
250 QMap<int, QVariant> QAbstractProxyModel::itemData(const QModelIndex &proxyIndex) const
251 {
252     return QAbstractItemModel::itemData(proxyIndex);
253 }
254
255 /*!
256     \reimp
257  */
258 Qt::ItemFlags QAbstractProxyModel::flags(const QModelIndex &index) const
259 {
260     Q_D(const QAbstractProxyModel);
261     return d->model->flags(mapToSource(index));
262 }
263
264 /*!
265     \reimp
266  */
267 bool QAbstractProxyModel::setData(const QModelIndex &index, const QVariant &value, int role)
268 {
269     Q_D(QAbstractProxyModel);
270     return d->model->setData(mapToSource(index), value, role);
271 }
272
273 /*!
274     \reimp
275  */
276 bool QAbstractProxyModel::setItemData(const QModelIndex &index, const QMap< int, QVariant >& roles)
277 {
278     return QAbstractItemModel::setItemData(index, roles);
279 }
280
281 /*!
282     \reimp
283  */
284 bool QAbstractProxyModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role)
285 {
286     Q_D(QAbstractProxyModel);
287     int sourceSection;
288     if (orientation == Qt::Horizontal) {
289         const QModelIndex proxyIndex = index(0, section);
290         sourceSection = mapToSource(proxyIndex).column();
291     } else {
292         const QModelIndex proxyIndex = index(section, 0);
293         sourceSection = mapToSource(proxyIndex).row();
294     }
295     return d->model->setHeaderData(sourceSection, orientation, value, role);
296 }
297
298 /*!
299     \reimp
300     \since 4.8
301  */
302 QModelIndex QAbstractProxyModel::buddy(const QModelIndex &index) const
303 {
304     Q_D(const QAbstractProxyModel);
305     return mapFromSource(d->model->buddy(mapToSource(index)));
306 }
307
308 /*!
309     \reimp
310     \since 4.8
311  */
312 bool QAbstractProxyModel::canFetchMore(const QModelIndex &parent) const
313 {
314     Q_D(const QAbstractProxyModel);
315     return d->model->canFetchMore(mapToSource(parent));
316 }
317
318 /*!
319     \reimp
320     \since 4.8
321  */
322 void QAbstractProxyModel::fetchMore(const QModelIndex &parent)
323 {
324     Q_D(QAbstractProxyModel);
325     d->model->fetchMore(mapToSource(parent));
326 }
327
328 /*!
329     \reimp
330     \since 4.8
331  */
332 void QAbstractProxyModel::sort(int column, Qt::SortOrder order)
333 {
334     Q_D(QAbstractProxyModel);
335     d->model->sort(column, order);
336 }
337
338 /*!
339     \reimp
340     \since 4.8
341  */
342 QSize QAbstractProxyModel::span(const QModelIndex &index) const
343 {
344     Q_D(const QAbstractProxyModel);
345     return d->model->span(mapToSource(index));
346 }
347
348 /*!
349     \reimp
350     \since 4.8
351  */
352 bool QAbstractProxyModel::hasChildren(const QModelIndex &parent) const
353 {
354     Q_D(const QAbstractProxyModel);
355     return d->model->hasChildren(mapToSource(parent));
356 }
357
358 /*!
359     \reimp
360     \since 4.8
361  */
362 QMimeData* QAbstractProxyModel::mimeData(const QModelIndexList &indexes) const
363 {
364     Q_D(const QAbstractProxyModel);
365     QModelIndexList list;
366     foreach(const QModelIndex &index, indexes)
367         list << mapToSource(index);
368     return d->model->mimeData(list);
369 }
370
371 /*!
372     \reimp
373     \since 4.8
374  */
375 QStringList QAbstractProxyModel::mimeTypes() const
376 {
377     Q_D(const QAbstractProxyModel);
378     return d->model->mimeTypes();
379 }
380
381 /*!
382     \reimp
383     \since 4.8
384  */
385 Qt::DropActions QAbstractProxyModel::supportedDropActions() const
386 {
387     Q_D(const QAbstractProxyModel);
388     return d->model->supportedDropActions();
389 }
390
391 QT_END_NAMESPACE
392
393 #include "moc_qabstractproxymodel.cpp"
394
395 #endif // QT_NO_PROXYMODEL