1 /* This file is part of the KDE project
2   Copyright (C) 2010, 2012 Dag Andersen <danders@get2net.dk>
3 
4   This library is free software; you can redistribute it and/or
5   modify it under the terms of the GNU Library General Public
6   License as published by the Free Software Foundation; either
7   version 2 of the License, or (at your option) any later version.
8 
9   This library is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   Library General Public License for more details.
13 
14   You should have received a copy of the GNU Library General Public License
15   along with this library; see the file COPYING.LIB.  If not, write to
16   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17   Boston, MA 02110-1301, USA.
18 */
19 
20 // clazy:excludeall=qstring-arg
21 #include "kptflatproxymodel.h"
22 
23 #include "kptglobal.h"
24 
25 #include <KLocalizedString>
26 
27 #include <QModelIndex>
28 #include <QPersistentModelIndex>
29 #include <QItemSelection>
30 
31 #include "kptdebug.h"
32 
33 namespace KPlato
34 {
35 
36 
FlatProxyModel(QObject * parent)37 FlatProxyModel::FlatProxyModel(QObject *parent)
38     : QAbstractProxyModel(parent)
39 {
40 }
41 
sourceModelDestroyed()42 void FlatProxyModel::sourceModelDestroyed()
43 {
44     m_sourceIndexList.clear();
45 }
46 
sourceDataChanged(const QModelIndex & source_top_left,const QModelIndex & source_bottom_right)47 void FlatProxyModel::sourceDataChanged(const QModelIndex &source_top_left, const QModelIndex &source_bottom_right)
48 {
49     emit dataChanged(mapFromSource(source_top_left), mapFromSource(source_bottom_right));
50 }
51 
sourceHeaderDataChanged(Qt::Orientation orientation,int start,int end)52 void FlatProxyModel::sourceHeaderDataChanged(Qt::Orientation orientation, int start, int end)
53 {
54     emit headerDataChanged(orientation, start, end);
55 }
56 
sourceReset()57 void FlatProxyModel::sourceReset()
58 {
59     beginResetModel();
60     initiateMaps();
61     endResetModel();
62 }
63 
sourceLayoutAboutToBeChanged()64 void FlatProxyModel::sourceLayoutAboutToBeChanged()
65 {
66     emit layoutAboutToBeChanged();
67 }
68 
sourceLayoutChanged()69 void FlatProxyModel::sourceLayoutChanged()
70 {
71     initiateMaps();
72     emit layoutChanged();
73 }
74 
sourceRowsAboutToBeInserted(const QModelIndex & source_parent,int start,int end)75 void FlatProxyModel::sourceRowsAboutToBeInserted(const QModelIndex &source_parent, int start, int end)
76 {
77     Q_UNUSED(source_parent);
78     Q_UNUSED(start);
79     Q_UNUSED(end);
80     beginResetModel();
81 }
82 
sourceRowsInserted(const QModelIndex & source_parent,int start,int end)83 void FlatProxyModel::sourceRowsInserted(const QModelIndex &source_parent, int start, int end)
84 {
85     Q_UNUSED(source_parent);
86     Q_UNUSED(start);
87     Q_UNUSED(end);
88 
89     initiateMaps();
90     endResetModel();
91 }
92 
sourceRowsAboutToBeRemoved(const QModelIndex & source_parent,int start,int end)93 void FlatProxyModel::sourceRowsAboutToBeRemoved(const QModelIndex &source_parent, int start, int end)
94 {
95     Q_UNUSED(source_parent);
96     Q_UNUSED(start);
97     Q_UNUSED(end);
98     beginResetModel();
99 }
100 
sourceRowsRemoved(const QModelIndex & source_parent,int start,int end)101 void FlatProxyModel::sourceRowsRemoved(const QModelIndex &source_parent, int start, int end)
102 {
103     Q_UNUSED(source_parent);
104     Q_UNUSED(start);
105     Q_UNUSED(end);
106 
107     initiateMaps();
108     endResetModel();
109 }
110 
sourceRowsAboutToBeMoved(const QModelIndex & source_parent,int start,int end,const QModelIndex & destParent,int destStart)111 void FlatProxyModel::sourceRowsAboutToBeMoved(const QModelIndex &source_parent, int start, int end, const QModelIndex &destParent, int destStart)
112 {
113     Q_UNUSED(source_parent);
114     Q_UNUSED(start);
115     Q_UNUSED(end);
116     Q_UNUSED(destParent);
117     Q_UNUSED(destStart);
118     beginResetModel();
119 }
120 
sourceRowsMoved(const QModelIndex & source_parent,int start,int end,const QModelIndex & destParent,int destStart)121 void FlatProxyModel::sourceRowsMoved(const QModelIndex &source_parent, int start, int end, const QModelIndex &destParent, int destStart)
122 {
123     Q_UNUSED(source_parent);
124     Q_UNUSED(start);
125     Q_UNUSED(end);
126     Q_UNUSED(destParent);
127     Q_UNUSED(destStart);
128 
129     initiateMaps();
130     endResetModel();
131 }
132 
setSourceModel(QAbstractItemModel * model)133 void FlatProxyModel::setSourceModel(QAbstractItemModel *model)
134 {
135     if (sourceModel()) {
136         disconnect(sourceModel(), &QAbstractItemModel::dataChanged,
137                 this, &FlatProxyModel::sourceDataChanged);
138 
139         disconnect(sourceModel(), &QAbstractItemModel::headerDataChanged,
140                 this, &FlatProxyModel::sourceHeaderDataChanged);
141 
142         disconnect(sourceModel(), &QAbstractItemModel::rowsAboutToBeInserted,
143                 this, &FlatProxyModel::sourceRowsAboutToBeInserted);
144 
145         disconnect(sourceModel(), &QAbstractItemModel::rowsInserted,
146                 this, &FlatProxyModel::sourceRowsInserted);
147 
148         disconnect(sourceModel(), &QAbstractItemModel::rowsAboutToBeRemoved,
149                 this, &FlatProxyModel::sourceRowsAboutToBeRemoved);
150 
151         disconnect(sourceModel(), &QAbstractItemModel::rowsRemoved,
152                 this, &FlatProxyModel::sourceRowsRemoved);
153 
154         disconnect(sourceModel(), &QAbstractItemModel::layoutAboutToBeChanged,
155                 this, &FlatProxyModel::sourceLayoutAboutToBeChanged);
156 
157         disconnect(sourceModel(), &QAbstractItemModel::layoutChanged,
158                 this, &FlatProxyModel::sourceLayoutChanged);
159 
160         disconnect(sourceModel(), &QAbstractItemModel::modelReset, this, &FlatProxyModel::sourceReset);
161 
162         connect(sourceModel(), &QAbstractItemModel::rowsAboutToBeMoved,
163                 this, &FlatProxyModel::sourceRowsAboutToBeMoved);
164         connect(sourceModel(), &QAbstractItemModel::rowsMoved,
165                 this, &FlatProxyModel::sourceRowsMoved);
166     }
167     QAbstractProxyModel::setSourceModel(model);
168     connect(sourceModel(), &QAbstractItemModel::dataChanged,
169             this, &FlatProxyModel::sourceDataChanged);
170 
171     connect(sourceModel(), &QAbstractItemModel::headerDataChanged,
172             this, &FlatProxyModel::sourceHeaderDataChanged);
173 
174     connect(sourceModel(), &QAbstractItemModel::rowsAboutToBeInserted,
175             this, &FlatProxyModel::sourceRowsAboutToBeInserted);
176 
177     connect(sourceModel(), &QAbstractItemModel::rowsInserted,
178             this, &FlatProxyModel::sourceRowsInserted);
179 
180     connect(sourceModel(), &QAbstractItemModel::rowsAboutToBeRemoved,
181             this, &FlatProxyModel::sourceRowsAboutToBeRemoved);
182 
183     connect(sourceModel(), &QAbstractItemModel::rowsRemoved,
184             this, &FlatProxyModel::sourceRowsRemoved);
185 
186     connect(sourceModel(), &QAbstractItemModel::layoutAboutToBeChanged,
187             this, &FlatProxyModel::sourceLayoutAboutToBeChanged);
188 
189     connect(sourceModel(), &QAbstractItemModel::layoutChanged,
190             this, &FlatProxyModel::sourceLayoutChanged);
191 
192     connect(sourceModel(), &QAbstractItemModel::modelReset, this, &FlatProxyModel::sourceReset);
193 
194     connect(sourceModel(), &QAbstractItemModel::rowsAboutToBeMoved,
195             this, &FlatProxyModel::sourceRowsAboutToBeMoved);
196     connect(sourceModel(), &QAbstractItemModel::rowsMoved,
197             this, &FlatProxyModel::sourceRowsMoved);
198 
199     beginResetModel();
200     initiateMaps();
201     endResetModel();
202 }
203 
index(int row,int column,const QModelIndex & parent) const204 QModelIndex FlatProxyModel::index(int row, int column, const QModelIndex &parent) const
205 {
206     if (parent.isValid()) {
207         return QModelIndex();
208     }
209     return createIndex(row, column);
210 }
211 
parent(const QModelIndex & child) const212 QModelIndex FlatProxyModel::parent(const QModelIndex &child) const
213 {
214     Q_UNUSED(child);
215     return QModelIndex();
216 }
217 
rowCount(const QModelIndex & parent) const218 int FlatProxyModel::rowCount(const QModelIndex &parent) const
219 {
220     return parent.isValid() ? 0 : m_sourceIndexList.count();
221 }
222 
columnCount(const QModelIndex & parent) const223 int FlatProxyModel::columnCount(const QModelIndex &parent) const
224 {
225     Q_UNUSED(parent);
226     if (sourceModel() == 0) {
227         return 0;
228     }
229     return sourceModel()->columnCount() + 1;
230 }
231 
hasChildren(const QModelIndex & parent) const232 bool FlatProxyModel::hasChildren(const QModelIndex &parent) const
233 {
234     return rowCount(parent) > 0;
235 }
236 
data(const QModelIndex & index,int role) const237 QVariant FlatProxyModel::data(const QModelIndex &index, int role) const
238 {
239     if (sourceModel() == 0 || !index.isValid()) {
240         debugPlan<<"No source model || invalid index";
241         return QVariant();
242     }
243     QModelIndex source_index;
244     int col = index.column() - sourceModel()->columnCount();
245     if (col < 0) {
246         source_index = mapToSource(index);
247         //debugPlan<<"source column"<<col<<sourceModel()->columnCount();
248     } else {
249         source_index = mapToSource(this->index(index.row(), 0));
250         //debugPlan<<"proxy column"<<col<<sourceModel()->columnCount();
251     }
252     if (!source_index.isValid()) {
253         debugPlan<<"index valid but source index not valid:"<<index;
254         return QVariant();
255     }
256     QVariant r;
257     if (col < 0) {
258         r = sourceModel()->data(source_index, role);
259     } else if (col == 0) {
260         if (role == Role::ColumnTag) {
261             r = headerData(col, Qt::Horizontal, role);
262         } else {
263             source_index = source_index.parent();
264             if (source_index.isValid()) {
265                 r = sourceModel()->data(source_index, role);
266             }
267         }
268     }
269     //debugPlan<<index<<r;
270     return r;
271 }
272 
setData(const QModelIndex & index,const QVariant & value,int role)273 bool FlatProxyModel::setData(const QModelIndex &index, const QVariant &value, int role)
274 {
275     if (sourceModel() == 0) {
276         return false;
277     }
278     QModelIndex source_index = mapToSource(index);
279     if (index.isValid() && !source_index.isValid()) {
280         return false;
281     }
282     return sourceModel()->setData(source_index, value, role);
283 }
284 
headerData(int section,Qt::Orientation orientation,int role) const285 QVariant FlatProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
286 {
287     if (sourceModel() == 0) {
288         return QVariant();
289     }
290     int sec = section - sourceModel()->columnCount();
291     if (sec < 0) {
292         return sourceModel()->headerData(section, orientation, role);
293     }
294     if (sec == 0) {
295         return role == Role::ColumnTag ? "Parent" : i18n("Parent");
296     }
297     return QVariant();
298 }
299 
setHeaderData(int section,Qt::Orientation orientation,const QVariant & value,int role)300 bool FlatProxyModel::setHeaderData(int section, Qt::Orientation orientation,
301                                           const QVariant &value, int role)
302 {
303     if (sourceModel() == 0) {
304         return false;
305     }
306     //TODO
307     return sourceModel()->setHeaderData(section, orientation, value, role);
308 }
309 
mimeData(const QModelIndexList & indexes) const310 QMimeData *FlatProxyModel::mimeData(const QModelIndexList &indexes) const
311 {
312     if (sourceModel() == 0) {
313         return 0;
314     }
315     QModelIndexList source_indexes;
316     for (int i = 0; i < indexes.count(); ++i) {
317         source_indexes << mapToSource(indexes.at(i));
318     }
319     return sourceModel()->mimeData(source_indexes);
320 }
321 
mimeTypes() const322 QStringList FlatProxyModel::mimeTypes() const
323 {
324     if (sourceModel() == 0) {
325         return QStringList();
326     }
327     return sourceModel()->mimeTypes();
328 }
329 
supportedDropActions() const330 Qt::DropActions FlatProxyModel::supportedDropActions() const
331 {
332     if (sourceModel() == 0) {
333         return 0;
334     }
335     return sourceModel()->supportedDropActions();
336 }
337 
dropMimeData(const QMimeData * data,Qt::DropAction action,int row,int column,const QModelIndex & parent)338 bool FlatProxyModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
339                                          int row, int column, const QModelIndex &parent)
340 {
341     if (sourceModel() == 0) {
342         return false;
343     }
344     if ((row == -1) && (column == -1))
345         return sourceModel()->dropMimeData(data, action, -1, -1, mapToSource(parent));
346     int source_destination_row = -1;
347     int source_destination_column = -1;
348     QModelIndex source_parent;
349     if (row == rowCount(parent)) {
350         source_parent = mapToSource(parent);
351         source_destination_row = sourceModel()->rowCount(source_parent);
352     } else {
353         QModelIndex proxy_index = index(row, column, parent);
354         QModelIndex source_index = mapToSource(proxy_index);
355         source_destination_row = source_index.row();
356         source_destination_column = source_index.column();
357         source_parent = source_index.parent();
358     }
359     return sourceModel()->dropMimeData(data, action, source_destination_row,
360                                   source_destination_column, source_parent);
361 }
362 
insertRows(int row,int count,const QModelIndex & parent)363 bool FlatProxyModel::insertRows(int row, int count, const QModelIndex &parent)
364 {
365     Q_UNUSED(row);
366     Q_UNUSED(count);
367     Q_UNUSED(parent);
368     return false;
369 }
370 
removeRows(int row,int count,const QModelIndex & parent)371 bool FlatProxyModel::removeRows(int row, int count, const QModelIndex &parent)
372 {
373     Q_UNUSED(row);
374     Q_UNUSED(count);
375     Q_UNUSED(parent);
376     //TODO
377     return false;
378 }
379 
380 
381 /*!
382    Returns the source model index corresponding to the given \a
383    proxyIndex from the sorting filter model.
384 
385    \sa mapFromSource()
386 */
mapToSource(const QModelIndex & proxyIndex) const387 QModelIndex FlatProxyModel::mapToSource(const QModelIndex &proxyIndex) const
388 {
389     if (! proxyIndex.isValid()) {
390         return QModelIndex();
391     }
392     QModelIndex source_index = m_sourceIndexList.value(proxyIndex.row());
393     if (proxyIndex.column() != 0) {
394         source_index = sourceModel()->index(source_index.row(), proxyIndex.column(), source_index.parent());
395     }
396     //debugPlan<<proxyIndex<<"->"<<source_index;
397     return source_index;
398 }
399 
400 /*!
401     Returns the model index in the FlatProxyModel given the \a
402     sourceIndex from the source model.
403 
404     \sa mapToSource()
405 */
mapFromSource(const QModelIndex & sourceIndex) const406 QModelIndex FlatProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
407 {
408     if (! sourceIndex.isValid()) {
409         return QModelIndex();
410     }
411     QPersistentModelIndex idx = sourceIndex;
412     if (idx.column() != 0) {
413         // we only map indices with column 0
414         idx = sourceModel()->index(idx.row(), 0, idx.parent());
415     }
416     QModelIndex proxy_index = index(m_sourceIndexList.indexOf(idx), sourceIndex.column());
417     //debugPlan<<sourceIndex<<"->"<<proxy_index;
418     Q_ASSERT(proxy_index.model() == this);
419     return proxy_index;
420 }
421 
mapSelectionToSource(const QItemSelection & proxySelection) const422 QItemSelection FlatProxyModel::mapSelectionToSource(const QItemSelection &proxySelection) const
423 {
424     return QAbstractProxyModel::mapSelectionToSource(proxySelection);
425 }
426 
mapSelectionFromSource(const QItemSelection & sourceSelection) const427 QItemSelection FlatProxyModel::mapSelectionFromSource(const QItemSelection &sourceSelection) const
428 {
429     return QAbstractProxyModel::mapSelectionFromSource(sourceSelection);
430 }
431 
initiateMaps(const QModelIndex & sourceParent)432 void FlatProxyModel::initiateMaps(const QModelIndex &sourceParent)
433 {
434     if (! sourceParent.isValid()) {
435         m_sourceIndexList.clear();
436     }
437     QAbstractItemModel *m = sourceModel();
438     if (m == 0) {
439         debugPlan<<"No source model";
440         return;
441     }
442     int count = m->rowCount(sourceParent);
443     for (int row = 0; row < count; ++row) {
444         QPersistentModelIndex idx = m->index(row, 0, sourceParent);
445         Q_ASSERT(idx.isValid());
446         //debugPlan<<"map:"<<sourceParent<<row<<idx;
447         if (idx.isValid()) { // fail safe
448             m_sourceIndexList.append(idx);
449 
450             initiateMaps(idx);
451         }
452     }
453     //debugPlan<<"source index list="<<m_sourceIndexList;
454 }
455 
456 
457 } // namespace KPlato
458