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#include "kptflatproxymodel.h"
21
22#include "kptglobal.h"
23
24#include <klocale.h>
25
26#include <QModelIndex>
27#include <QPersistentModelIndex>
28#include <QItemSelection>
29
30#include "kptdebug.h"
31
32namespace KPlato
33{
34
35
36FlatProxyModel::FlatProxyModel(QObject *parent)
37 : QAbstractProxyModel( parent )
38{
39}
40
41void FlatProxyModel::sourceModelDestroyed()
42{
43 m_sourceIndexList.clear();
44}
45
46void FlatProxyModel::sourceDataChanged(const QModelIndex &source_top_left, const QModelIndex &source_bottom_right)
47{
48 emit dataChanged( mapFromSource( source_top_left ), mapFromSource( source_bottom_right ) );
49}
50
51void FlatProxyModel::sourceHeaderDataChanged(Qt::Orientation orientation, int start, int end)
52{
53 emit headerDataChanged(orientation, start, end);
54}
55
56void FlatProxyModel::sourceReset()
57{
58 beginResetModel();
59 initiateMaps();
60 endResetModel();
61}
62
63void FlatProxyModel::sourceLayoutAboutToBeChanged()
64{
65 emit layoutAboutToBeChanged();
66}
67
68void FlatProxyModel::sourceLayoutChanged()
69{
70 initiateMaps();
71 emit layoutChanged();
72}
73
74void FlatProxyModel::sourceRowsAboutToBeInserted(const QModelIndex &source_parent, int start, int end)
75{
76 int rc = sourceModel()->rowCount( source_parent );
77 if ( rc == 0 ) {
78 Q_ASSERT( start == 0 );
79 QModelIndex idx = mapFromSource( source_parent );
80 //kDebug(planDbg())<<"start<rc"<<source_parent<<start<<end<<":"<<idx;
81 if ( idx.isValid() ) {
82 beginInsertRows( QModelIndex(), idx.row() + start, idx.row() + end );
83 } else {
84 beginInsertRows( QModelIndex(), start, end );
85 }
86 } else if ( start < rc ) {
87 QModelIndex source_idx = sourceModel()->index( start, 0, source_parent );
88 QModelIndex idx = mapFromSource( source_idx );
89 //kDebug(planDbg())<<"start<rc"<<source_parent<<start<<end<<":"<<idx;
90 beginInsertRows( QModelIndex(), idx.row(), idx.row() + end - start );
91 } else if ( start == rc ) {
92 QModelIndex source_idx = sourceModel()->index( start - 1, 0, source_parent );
93 QModelIndex idx = mapFromSource( source_idx );
94 //kDebug(planDbg())<<"start==rc"<<source_parent<<start<<end<<":"<<idx;
95 beginInsertRows( QModelIndex(), idx.row() + 1, idx.row() + 1 + end - start );
96 } else {
97 kFatal()<<"Strange data from source model"<<source_parent<<start<<end;
98 }
99}
100
101void FlatProxyModel::sourceRowsInserted(const QModelIndex &source_parent, int start, int end)
102{
103 Q_UNUSED(source_parent);
104 Q_UNUSED(start);
105 Q_UNUSED(end);
106 initiateMaps();
107 endInsertRows();
108}
109
110void FlatProxyModel::sourceRowsAboutToBeRemoved( const QModelIndex &source_parent, int start, int end )
111{
112 Q_UNUSED(source_parent);
113 Q_UNUSED(start);
114 Q_UNUSED(end);
115 beginResetModel();
116}
117
118void FlatProxyModel::sourceRowsRemoved( const QModelIndex &source_parent, int start, int end )
119{
120 Q_UNUSED(source_parent);
121 Q_UNUSED(start);
122 Q_UNUSED(end);
123
124 initiateMaps();
125 endResetModel();
126}
127
128void FlatProxyModel::sourceRowsAboutToBeMoved(const QModelIndex &source_parent, int start, int end, const QModelIndex &destParent, int destStart)
129{
130 beginMoveRows(source_parent, start, end, destParent, destStart );
131}
132
133void FlatProxyModel::sourceRowsMoved(const QModelIndex &source_parent, int start, int end, const QModelIndex &destParent, int destStart)
134{
135 Q_UNUSED(source_parent);
136 Q_UNUSED(start);
137 Q_UNUSED(end);
138 Q_UNUSED(destParent);
139 Q_UNUSED(destStart);
140 kDebug(planDbg());
141 initiateMaps();
142 endMoveRows();
143}
144
145void FlatProxyModel::setSourceModel(QAbstractItemModel *model)
146{
147 if ( sourceModel() ) {
148 disconnect(sourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex)),
149 this, SLOT(sourceDataChanged(QModelIndex,QModelIndex)));
150
151 disconnect(sourceModel(), SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
152 this, SLOT(sourceHeaderDataChanged(Qt::Orientation,int,int)));
153
154 disconnect(sourceModel(), SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
155 this, SLOT(sourceRowsAboutToBeInserted(QModelIndex,int,int)));
156
157 disconnect(sourceModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
158 this, SLOT(sourceRowsInserted(QModelIndex,int,int)));
159
160 disconnect(sourceModel(), SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
161 this, SLOT(sourceRowsAboutToBeRemoved(QModelIndex,int,int)));
162
163 disconnect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
164 this, SLOT(sourceRowsRemoved(QModelIndex,int,int)));
165
166 disconnect(sourceModel(), SIGNAL(layoutAboutToBeChanged()),
167 this, SLOT(sourceLayoutAboutToBeChanged()));
168
169 disconnect(sourceModel(), SIGNAL(layoutChanged()),
170 this, SLOT(sourceLayoutChanged()));
171
172 disconnect(sourceModel(), SIGNAL(modelReset()), this, SLOT(sourceReset()));
173
174 connect(sourceModel(), SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
175 this, SLOT(sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
176 connect(sourceModel(), SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
177 this, SLOT(sourceRowsMoved(QModelIndex,int,int,QModelIndex,int)));
178 }
179 QAbstractProxyModel::setSourceModel(model);
180 connect(sourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex)),
181 this, SLOT(sourceDataChanged(QModelIndex,QModelIndex)));
182
183 connect(sourceModel(), SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
184 this, SLOT(sourceHeaderDataChanged(Qt::Orientation,int,int)));
185
186 connect(sourceModel(), SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
187 this, SLOT(sourceRowsAboutToBeInserted(QModelIndex,int,int)));
188
189 connect(sourceModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
190 this, SLOT(sourceRowsInserted(QModelIndex,int,int)));
191
192 connect(sourceModel(), SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
193 this, SLOT(sourceRowsAboutToBeRemoved(QModelIndex,int,int)));
194
195 connect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
196 this, SLOT(sourceRowsRemoved(QModelIndex,int,int)));
197
198 connect(sourceModel(), SIGNAL(layoutAboutToBeChanged()),
199 this, SLOT(sourceLayoutAboutToBeChanged()));
200
201 connect(sourceModel(), SIGNAL(layoutChanged()),
202 this, SLOT(sourceLayoutChanged()));
203
204 connect(sourceModel(), SIGNAL(modelReset()), this, SLOT(sourceReset()));
205
206 connect(sourceModel(), SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
207 this, SLOT(sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
208 connect(sourceModel(), SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
209 this, SLOT(sourceRowsMoved(QModelIndex,int,int,QModelIndex,int)));
210
211 beginResetModel();
212 initiateMaps();
213 endResetModel();
214}
215
216QModelIndex FlatProxyModel::index(int row, int column, const QModelIndex &parent) const
217{
218 if ( parent.isValid() ) {
219 return QModelIndex();
220 }
221 return createIndex( row, column );
222}
223
224QModelIndex FlatProxyModel::parent(const QModelIndex &child) const
225{
226 Q_UNUSED(child);
227 return QModelIndex();
228}
229
230int FlatProxyModel::rowCount(const QModelIndex &parent) const
231{
232 return parent.isValid() ? 0 : m_sourceIndexList.count();
233}
234
235int FlatProxyModel::columnCount(const QModelIndex &parent) const
236{
237 Q_UNUSED(parent);
238 if ( sourceModel() == 0 ) {
239 return 0;
240 }
241 return sourceModel()->columnCount() + 1;
242}
243
244bool FlatProxyModel::hasChildren(const QModelIndex &parent) const
245{
246 return rowCount( parent ) > 0;
247}
248
249QVariant FlatProxyModel::data(const QModelIndex &index, int role) const
250{
251 if ( sourceModel() == 0 || !index.isValid()) {
252 kDebug(planDbg())<<"No source model || invalid index";
253 return QVariant();
254 }
255 QModelIndex source_index;
256 int col = index.column() - sourceModel()->columnCount();
257 if ( col < 0 ) {
258 source_index = mapToSource(index);
259 //kDebug(planDbg())<<"source column"<<col<<sourceModel()->columnCount();
260 } else {
261 source_index = mapToSource( this->index( index.row(), 0 ) );
262 //kDebug(planDbg())<<"proxy column"<<col<<sourceModel()->columnCount();
263 }
264 if ( !source_index.isValid() ) {
265 kDebug(planDbg())<<"index valid but source index not valid:"<<index;
266 return QVariant();
267 }
268 QVariant r;
269 if ( col < 0 ) {
270 r = sourceModel()->data(source_index, role);
271 } else if ( col == 0 ) {
272 if ( role == Role::ColumnTag ) {
273 r = headerData( col, Qt::Horizontal, role );
274 } else {
275 source_index = source_index.parent();
276 if ( source_index.isValid() ) {
277 r = sourceModel()->data(source_index, role);
278 }
279 }
280 }
281 //kDebug(planDbg())<<index<<r;
282 return r;
283}
284
285bool FlatProxyModel::setData(const QModelIndex &index, const QVariant &value, int role)
286{
287 if ( sourceModel() == 0 ) {
288 return false;
289 }
290 QModelIndex source_index = mapToSource(index);
291 if (index.isValid() && !source_index.isValid()) {
292 return false;
293 }
294 return sourceModel()->setData(source_index, value, role);
295}
296
297QVariant FlatProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
298{
299 if ( sourceModel() == 0 ) {
300 return QVariant();
301 }
302 int sec = section - sourceModel()->columnCount();
303 if ( sec < 0 ) {
304 return sourceModel()->headerData(section, orientation, role);
305 }
306 if ( sec == 0 ) {
307 return role == Role::ColumnTag ? "Parent" : i18n( "Parent" );
308 }
309 return QVariant();
310}
311
312bool FlatProxyModel::setHeaderData(int section, Qt::Orientation orientation,
313 const QVariant &value, int role)
314{
315 if ( sourceModel() == 0 ) {
316 return false;
317 }
318 //TODO
319 return sourceModel()->setHeaderData(section, orientation, value, role);
320}
321
322QMimeData *FlatProxyModel::mimeData(const QModelIndexList &indexes) const
323{
324 if ( sourceModel() == 0 ) {
325 return 0;
326 }
327 QModelIndexList source_indexes;
328 for (int i = 0; i < indexes.count(); ++i) {
329 source_indexes << mapToSource(indexes.at(i));
330 }
331 return sourceModel()->mimeData(source_indexes);
332}
333
334QStringList FlatProxyModel::mimeTypes() const
335{
336 if ( sourceModel() == 0 ) {
337 return QStringList();
338 }
339 return sourceModel()->mimeTypes();
340}
341
342Qt::DropActions FlatProxyModel::supportedDropActions() const
343{
344 if ( sourceModel() == 0 ) {
345 return 0;
346 }
347 return sourceModel()->supportedDropActions();
348}
349
350bool FlatProxyModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
351 int row, int column, const QModelIndex &parent)
352{
353 if ( sourceModel() == 0 ) {
354 return false;
355 }
356 if ((row == -1) && (column == -1))
357 return sourceModel()->dropMimeData(data, action, -1, -1, mapToSource(parent));
358 int source_destination_row = -1;
359 int source_destination_column = -1;
360 QModelIndex source_parent;
361 if (row == rowCount(parent)) {
362 source_parent = mapToSource(parent);
363 source_destination_row = sourceModel()->rowCount(source_parent);
364 } else {
365 QModelIndex proxy_index = index(row, column, parent);
366 QModelIndex source_index = mapToSource(proxy_index);
367 source_destination_row = source_index.row();
368 source_destination_column = source_index.column();
369 source_parent = source_index.parent();
370 }
371 return sourceModel()->dropMimeData(data, action, source_destination_row,
372 source_destination_column, source_parent);
373}
374
375bool FlatProxyModel::insertRows(int row, int count, const QModelIndex &parent)
376{
377 Q_UNUSED(row);
378 Q_UNUSED(count);
379 Q_UNUSED(parent);
380 return false;
381}
382
383bool FlatProxyModel::removeRows(int row, int count, const QModelIndex &parent)
384{
385 Q_UNUSED(row);
386 Q_UNUSED(count);
387 Q_UNUSED(parent);
388 //TODO
389 return false;
390}
391
392
393/*!
394 Returns the source model index corresponding to the given \a
395 proxyIndex from the sorting filter model.
396
397 \sa mapFromSource()
398*/
399QModelIndex FlatProxyModel::mapToSource(const QModelIndex &proxyIndex) const
400{
401 if ( ! proxyIndex.isValid() ) {
402 return QModelIndex();
403 }
404 QModelIndex source_index = m_sourceIndexList.value( proxyIndex.row() );
405 if ( proxyIndex.column() != 0 ) {
406 source_index = sourceModel()->index( source_index.row(), proxyIndex.column(), source_index.parent() );
407 }
408 //kDebug(planDbg())<<proxyIndex<<"->"<<source_index;
409 return source_index;
410}
411
412/*!
413 Returns the model index in the FlatProxyModel given the \a
414 sourceIndex from the source model.
415
416 \sa mapToSource()
417*/
418QModelIndex FlatProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
419{
420 if ( ! sourceIndex.isValid() ) {
421 return QModelIndex();
422 }
423 QPersistentModelIndex idx = sourceIndex;
424 if ( idx.column() != 0 ) {
425 // we only map indices with column 0
426 idx = sourceModel()->index( idx.row(), 0, idx.parent() );
427 }
428 QModelIndex proxy_index = index( m_sourceIndexList.indexOf( idx ), sourceIndex.column() );
429 //kDebug(planDbg())<<sourceIndex<<"->"<<proxy_index;
430 return proxy_index;
431}
432
433QItemSelection FlatProxyModel::mapSelectionToSource(const QItemSelection &proxySelection) const
434{
435 return QAbstractProxyModel::mapSelectionToSource(proxySelection);
436}
437
438QItemSelection FlatProxyModel::mapSelectionFromSource(const QItemSelection &sourceSelection) const
439{
440 return QAbstractProxyModel::mapSelectionFromSource(sourceSelection);
441}
442
443void FlatProxyModel::initiateMaps( const QModelIndex &sourceParent )
444{
445 if ( ! sourceParent.isValid() ) {
446 m_sourceIndexList.clear();
447 m_sourceIndexMap.clear();
448 }
449 QAbstractItemModel *m = sourceModel();
450 if ( m == 0 ) {
451 kDebug(planDbg())<<"No source model";
452 return;
453 }
454 int count = m->rowCount( sourceParent );
455 for ( int row = 0; row < count; ++row ) {
456 QPersistentModelIndex idx = m->index( row, 0, sourceParent );
457 //kDebug(planDbg())<<"map:"<<sourceParent<<row<<idx;
458 if ( idx.isValid() ) { // fail safe
459 m_sourceIndexList.append( idx );
460 m_sourceIndexMap.insert( idx.parent(), idx );
461
462 initiateMaps( idx );
463 }
464 }
465 //kDebug(planDbg())<<"source index list="<<m_sourceIndexList;
466}
467
468
469} // namespace KPlato
470
471#include "kptflatproxymodel.moc"
472