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