clazy: fix QString(QLatin1String(...))
[trojita.git] / src / Imap / Model / kdeui-itemviews / kdescendantsproxymodel.cpp
blob447505ce236d49b6fbbd65ba027116b31aadc8d5
1 /*
2 Copyright (c) 2009 Stephen Kelly <steveire@gmail.com>
3 Copyright (C) 2010 Klarälvdalens Datakonsult AB,
4 a KDAB Group company, info@kdab.net,
5 author Stephen Kelly <stephen@kdab.com>
7 This library is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Library General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or (at your
10 option) any later version.
12 This library is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
15 License for more details.
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301, USA.
23 #include "kdescendantsproxymodel.h"
25 #include <QtCore/QStringList>
26 #include <QtCore/QTimer>
28 #include "kbihash_p.h"
30 typedef KHash2Map<QPersistentModelIndex, int> Mapping;
32 class KDescendantsProxyModelPrivate
34 KDescendantsProxyModelPrivate(KDescendantsProxyModel * qq)
35 : q_ptr(qq),
36 m_rowCount(0),
37 m_ignoreNextLayoutAboutToBeChanged(false),
38 m_ignoreNextLayoutChanged(false),
39 m_relayouting(false),
40 m_displayAncestorData( false ),
41 m_ancestorSeparator( QStringLiteral( " / " ) )
45 Q_DECLARE_PUBLIC(KDescendantsProxyModel)
46 KDescendantsProxyModel * const q_ptr;
48 mutable QVector<QPersistentModelIndex> m_pendingParents;
50 void scheduleProcessPendingParents() const;
51 void processPendingParents();
53 void synchronousMappingRefresh();
55 void updateInternalIndexes(int start, int offset);
57 void resetInternalData();
59 void sourceRowsAboutToBeInserted(const QModelIndex &, int, int);
60 void sourceRowsInserted(const QModelIndex &, int, int);
61 void sourceRowsAboutToBeRemoved(const QModelIndex &, int, int);
62 void sourceRowsRemoved(const QModelIndex &, int, int);
63 void sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int);
64 void sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int);
65 void sourceModelAboutToBeReset();
66 void sourceModelReset();
67 void sourceLayoutAboutToBeChanged();
68 void sourceLayoutChanged();
69 void sourceDataChanged(const QModelIndex &, const QModelIndex &);
70 void sourceModelDestroyed();
72 Mapping m_mapping;
73 int m_rowCount;
74 QPair<int, int> m_removePair;
75 QPair<int, int> m_insertPair;
77 bool m_ignoreNextLayoutAboutToBeChanged;
78 bool m_ignoreNextLayoutChanged;
79 bool m_relayouting;
81 bool m_displayAncestorData;
82 QString m_ancestorSeparator;
84 QList<QPersistentModelIndex> m_layoutChangePersistentIndexes;
85 QModelIndexList m_proxyIndexes;
86 QHash<int,QByteArray> m_roleNames;
89 void KDescendantsProxyModelPrivate::resetInternalData()
91 m_rowCount = 0;
92 m_mapping.clear();
93 m_layoutChangePersistentIndexes.clear();
94 m_proxyIndexes.clear();
97 void KDescendantsProxyModelPrivate::synchronousMappingRefresh()
99 m_rowCount = 0;
100 m_mapping.clear();
101 m_pendingParents.clear();
103 m_pendingParents.append(QModelIndex());
105 m_relayouting = true;
106 while (!m_pendingParents.isEmpty())
108 processPendingParents();
110 m_relayouting = false;
113 void KDescendantsProxyModelPrivate::scheduleProcessPendingParents() const
115 const_cast<KDescendantsProxyModelPrivate*>(this)->processPendingParents();
118 void KDescendantsProxyModelPrivate::processPendingParents()
120 Q_Q(KDescendantsProxyModel);
121 const QVector<QPersistentModelIndex>::iterator begin = m_pendingParents.begin();
122 QVector<QPersistentModelIndex>::iterator it = begin;
124 const QVector<QPersistentModelIndex>::iterator end = m_pendingParents.end();
126 QVector<QPersistentModelIndex> newPendingParents;
128 while (it != end && it != m_pendingParents.end()) {
129 const QModelIndex sourceParent = *it;
130 if (!sourceParent.isValid() && m_rowCount > 0)
132 // It was removed from the source model before it was inserted.
133 it = m_pendingParents.erase(it);
134 continue;
136 const int rowCount = q->sourceModel()->rowCount(sourceParent);
138 Q_ASSERT(rowCount > 0);
139 const QPersistentModelIndex sourceIndex = q->sourceModel()->index(rowCount - 1, 0, sourceParent);
141 Q_ASSERT(sourceIndex.isValid());
143 const QModelIndex proxyParent = q->mapFromSource(sourceParent);
145 Q_ASSERT(sourceParent.isValid() == proxyParent.isValid());
146 const int proxyEndRow = proxyParent.row() + rowCount;
147 const int proxyStartRow = proxyEndRow - rowCount + 1;
149 if (!m_relayouting)
150 q->beginInsertRows(QModelIndex(), proxyStartRow, proxyEndRow);
152 updateInternalIndexes(proxyStartRow, rowCount);
153 m_mapping.insert(sourceIndex, proxyEndRow);
154 it = m_pendingParents.erase(it);
155 m_rowCount += rowCount;
157 if (!m_relayouting)
158 q->endInsertRows();
160 for (int sourceRow = 0; sourceRow < rowCount; ++sourceRow ) {
161 static const int column = 0;
162 const QModelIndex child = q->sourceModel()->index(sourceRow, column, sourceParent);
163 Q_ASSERT(child.isValid());
165 if (q->sourceModel()->hasChildren(child))
167 Q_ASSERT(q->sourceModel()->rowCount(child) > 0);
168 newPendingParents.append(child);
172 m_pendingParents += newPendingParents;
173 if (!m_pendingParents.isEmpty())
174 processPendingParents();
175 // scheduleProcessPendingParents();
178 void KDescendantsProxyModelPrivate::updateInternalIndexes(int start, int offset)
180 // TODO: Make KHash2Map support key updates and do this backwards.
181 QHash<int, QPersistentModelIndex> updates;
183 Mapping::right_iterator it = m_mapping.rightLowerBound(start);
184 const Mapping::right_iterator end = m_mapping.rightEnd();
186 while (it != end)
188 updates.insert(it.key() + offset, *it);
189 ++it;
194 QHash<int, QPersistentModelIndex>::const_iterator it = updates.constBegin();
195 const QHash<int, QPersistentModelIndex>::const_iterator end = updates.constEnd();
197 for ( ; it != end; ++it)
199 m_mapping.insert(it.value(), it.key());
205 KDescendantsProxyModel::KDescendantsProxyModel(QObject *parent)
206 : QAbstractProxyModel(parent), d_ptr(new KDescendantsProxyModelPrivate(this))
210 KDescendantsProxyModel::~KDescendantsProxyModel()
212 delete d_ptr;
215 void KDescendantsProxyModel::setRootIndex(const QModelIndex &index)
217 Q_UNUSED(index)
220 QModelIndexList KDescendantsProxyModel::match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const
222 return QAbstractProxyModel::match(start, role, value, hits, flags);
225 void KDescendantsProxyModel::setDisplayAncestorData( bool display )
227 Q_D(KDescendantsProxyModel);
228 d->m_displayAncestorData = display;
231 bool KDescendantsProxyModel::displayAncestorData() const
233 Q_D(const KDescendantsProxyModel );
234 return d->m_displayAncestorData;
237 void KDescendantsProxyModel::setAncestorSeparator( const QString &separator )
239 Q_D(KDescendantsProxyModel);
240 d->m_ancestorSeparator = separator;
243 QString KDescendantsProxyModel::ancestorSeparator() const
245 Q_D(const KDescendantsProxyModel );
246 return d->m_ancestorSeparator;
250 void KDescendantsProxyModel::setSourceModel(QAbstractItemModel *_sourceModel)
252 beginResetModel();
254 if (_sourceModel) {
255 disconnect(_sourceModel, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)),
256 this, SLOT(sourceRowsAboutToBeInserted(const QModelIndex &, int, int)));
257 disconnect(_sourceModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)),
258 this, SLOT(sourceRowsInserted(const QModelIndex &, int, int)));
259 disconnect(_sourceModel, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)),
260 this, SLOT(sourceRowsAboutToBeRemoved(const QModelIndex &, int, int)));
261 disconnect(_sourceModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
262 this, SLOT(sourceRowsRemoved(const QModelIndex &, int, int)));
263 // disconnect(_sourceModel, SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)),
264 // this, SLOT(sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
265 // disconnect(_sourceModel, SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)),
266 // this, SLOT(sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
267 disconnect(_sourceModel, SIGNAL(modelAboutToBeReset()),
268 this, SLOT(sourceModelAboutToBeReset()));
269 disconnect(_sourceModel, SIGNAL(modelReset()),
270 this, SLOT(sourceModelReset()));
271 disconnect(_sourceModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
272 this, SLOT(sourceDataChanged(const QModelIndex &, const QModelIndex &)));
273 disconnect(_sourceModel, SIGNAL(layoutAboutToBeChanged()),
274 this, SLOT(sourceLayoutAboutToBeChanged()));
275 disconnect(_sourceModel, SIGNAL(layoutChanged()),
276 this, SLOT(sourceLayoutChanged()));
277 disconnect(_sourceModel, SIGNAL(destroyed()),
278 this, SLOT(sourceModelDestroyed()));
281 QAbstractProxyModel::setSourceModel(_sourceModel);
283 if (_sourceModel) {
284 connect(_sourceModel, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)),
285 SLOT(sourceRowsAboutToBeInserted(const QModelIndex &, int, int)));
286 connect(_sourceModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)),
287 SLOT(sourceRowsInserted(const QModelIndex &, int, int)));
288 connect(_sourceModel, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)),
289 SLOT(sourceRowsAboutToBeRemoved(const QModelIndex &, int, int)));
290 connect(_sourceModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
291 SLOT(sourceRowsRemoved(const QModelIndex &, int, int)));
292 // connect(_sourceModel, SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)),
293 // SLOT(sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
294 // connect(_sourceModel, SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)),
295 // SLOT(sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
296 connect(_sourceModel, SIGNAL(modelAboutToBeReset()),
297 SLOT(sourceModelAboutToBeReset()));
298 connect(_sourceModel, SIGNAL(modelReset()),
299 SLOT(sourceModelReset()));
300 connect(_sourceModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
301 SLOT(sourceDataChanged(const QModelIndex &, const QModelIndex &)));
302 connect(_sourceModel, SIGNAL(layoutAboutToBeChanged()),
303 SLOT(sourceLayoutAboutToBeChanged()));
304 connect(_sourceModel, SIGNAL(layoutChanged()),
305 SLOT(sourceLayoutChanged()));
306 connect(_sourceModel, SIGNAL(destroyed()),
307 SLOT(sourceModelDestroyed()));
310 endResetModel();
313 QModelIndex KDescendantsProxyModel::parent(const QModelIndex &index) const
315 Q_UNUSED(index)
316 return QModelIndex();
319 bool KDescendantsProxyModel::hasChildren(const QModelIndex &parent) const
321 Q_D(const KDescendantsProxyModel);
322 return !(d->m_mapping.isEmpty() || parent.isValid());
325 int KDescendantsProxyModel::rowCount(const QModelIndex &parent) const
327 Q_D(const KDescendantsProxyModel);
328 if (d->m_pendingParents.contains(parent) || parent.isValid() || !sourceModel())
329 return 0;
331 if (d->m_mapping.isEmpty() && sourceModel()->hasChildren())
333 Q_ASSERT(sourceModel()->rowCount() > 0);
334 const_cast<KDescendantsProxyModelPrivate*>(d)->synchronousMappingRefresh();
336 return d->m_rowCount;
339 QModelIndex KDescendantsProxyModel::index(int row, int column, const QModelIndex &parent) const
341 if (parent.isValid())
342 return QModelIndex();
344 if (!hasIndex(row, column, parent))
345 return QModelIndex();
347 return createIndex(row, column);
350 QModelIndex KDescendantsProxyModel::mapToSource(const QModelIndex &proxyIndex) const
352 Q_D(const KDescendantsProxyModel);
353 if (d->m_mapping.isEmpty() || !proxyIndex.isValid() || !sourceModel())
354 return QModelIndex();
356 const Mapping::right_const_iterator result = d->m_mapping.rightLowerBound(proxyIndex.row());
357 Q_ASSERT(result != d->m_mapping.rightEnd());
359 const int proxyLastRow = result.key();
360 const QModelIndex sourceLastChild = result.value();
361 Q_ASSERT(sourceLastChild.isValid());
363 // proxyLastRow is greater than proxyIndex.row().
364 // sourceLastChild is vertically below the result we're looking for
365 // and not necessarily in the correct parent.
366 // We travel up through its parent hierarchy until we are in the
367 // right parent, then return the correct sibling.
369 // Source: Proxy: Row
370 // - A - A - 0
371 // - B - B - 1
372 // - C - C - 2
373 // - D - D - 3
374 // - - E - E - 4
375 // - - F - F - 5
376 // - - G - G - 6
377 // - - H - H - 7
378 // - - I - I - 8
379 // - - - J - J - 9
380 // - - - K - K - 10
381 // - - - L - L - 11
382 // - - M - M - 12
383 // - - N - N - 13
384 // - O - O - 14
386 // Note that L, N and O are lastChildIndexes, and therefore have a mapping. If we
387 // are trying to map G from the proxy to the source, We at this point have an iterator
388 // pointing to (L -> 11). The proxy row of G is 6. (proxyIndex.row() == 6). We seek the
389 // sourceIndex which is vertically above L by the distance proxyLastRow - proxyIndex.row().
390 // In this case the verticalDistance is 5.
392 int verticalDistance = proxyLastRow - proxyIndex.row();
394 // We traverse the ancestors of L, until we can index the desired row in the source.
396 QModelIndex ancestor = sourceLastChild;
397 while (ancestor.isValid())
399 const int ancestorRow = ancestor.row();
400 if (verticalDistance <= ancestorRow)
402 return ancestor.sibling(ancestorRow - verticalDistance, proxyIndex.column());
404 verticalDistance -= (ancestorRow + 1);
405 ancestor = ancestor.parent();
407 Q_ASSERT(!"Didn't find target row.");
408 return QModelIndex();
411 QModelIndex KDescendantsProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
413 Q_D(const KDescendantsProxyModel);
415 if (!sourceModel())
416 return QModelIndex();
418 if (d->m_mapping.isEmpty())
419 return QModelIndex();
423 // TODO: Consider a parent Mapping to speed this up.
425 Mapping::right_const_iterator it = d->m_mapping.rightConstBegin();
426 const Mapping::right_const_iterator end = d->m_mapping.rightConstEnd();
427 const QModelIndex sourceParent = sourceIndex.parent();
428 Mapping::right_const_iterator result = end;
430 for ( ; it != end; ++it )
432 QModelIndex index = it.value();
433 bool found_block = false;
434 while (index.isValid())
436 const QModelIndex ancestor = index.parent();
437 if (ancestor == sourceParent && index.row() >= sourceIndex.row())
439 found_block = true;
440 if (result == end || it.key() < result.key())
442 result = it;
443 break; // Leave the while loop. index is still valid.
446 index = ancestor;
448 if (found_block && !index.isValid())
449 // Looked through the ascendants of it.key() without finding sourceParent.
450 // That means we've already got the result we need.
451 break;
453 Q_ASSERT(result != end);
454 const QModelIndex sourceLastChild = result.value();
455 int proxyRow = result.key();
456 QModelIndex index = sourceLastChild;
457 while (index.isValid())
459 const QModelIndex ancestor = index.parent();
460 if (ancestor == sourceParent)
462 return createIndex(proxyRow - (index.row() - sourceIndex.row()), sourceIndex.column());
464 proxyRow -= (index.row() + 1);
465 index = ancestor;
467 Q_ASSERT(!"Didn't find valid proxy mapping.");
468 return QModelIndex();
473 int KDescendantsProxyModel::columnCount(const QModelIndex &parent) const
475 if (parent.isValid() /* || rowCount(parent) == 0 */ || !sourceModel())
476 return 0;
478 return sourceModel()->columnCount();
481 QVariant KDescendantsProxyModel::data(const QModelIndex &index, int role) const
483 Q_D(const KDescendantsProxyModel );
485 if (!sourceModel())
486 return QVariant();
488 if (!index.isValid())
489 return sourceModel()->data(index, role);
491 QModelIndex sourceIndex = mapToSource( index );
493 if ((d->m_displayAncestorData) && ( role == Qt::DisplayRole ) )
495 if (!sourceIndex.isValid())
497 return QVariant();
499 QString displayData = sourceIndex.data().toString();
500 sourceIndex = sourceIndex.parent();
501 while (sourceIndex.isValid())
503 displayData.prepend(d->m_ancestorSeparator);
504 displayData.prepend(sourceIndex.data().toString());
505 sourceIndex = sourceIndex.parent();
507 return displayData;
508 } else {
509 return sourceIndex.data(role);
513 QVariant KDescendantsProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
515 if (!sourceModel() || columnCount() <= section)
516 return QVariant();
518 return QAbstractProxyModel::headerData(section, orientation, role);
521 Qt::ItemFlags KDescendantsProxyModel::flags(const QModelIndex &index) const
523 if (!index.isValid() || !sourceModel())
524 return QAbstractProxyModel::flags(index);
526 const QModelIndex srcIndex = mapToSource(index);
527 Q_ASSERT(srcIndex.isValid());
528 return sourceModel()->flags(srcIndex);
531 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
533 Q_Q(KDescendantsProxyModel);
535 if (!q->sourceModel()->hasChildren(parent))
537 Q_ASSERT(q->sourceModel()->rowCount(parent) == 0);
538 // parent was not a parent before.
539 return;
542 int proxyStart = -1;
544 const int rowCount = q->sourceModel()->rowCount(parent);
546 if (rowCount > start)
548 const QModelIndex belowStart = q->sourceModel()->index(start, 0, parent);
549 proxyStart = q->mapFromSource(belowStart).row();
550 } else if (rowCount == 0)
552 proxyStart = q->mapFromSource(parent).row() + 1;
553 } else {
554 Q_ASSERT(rowCount == start);
555 static const int column = 0;
556 QModelIndex idx = q->sourceModel()->index(rowCount - 1, column, parent);
557 while (q->sourceModel()->hasChildren(idx))
559 Q_ASSERT(q->sourceModel()->rowCount(idx) > 0);
560 idx = q->sourceModel()->index(q->sourceModel()->rowCount(idx) - 1, column, idx);
562 // The last item in the list is getting a sibling below it.
563 proxyStart = q->mapFromSource(idx).row() + 1;
565 const int proxyEnd = proxyStart + (end - start);
567 m_insertPair = qMakePair(proxyStart, proxyEnd);
568 q->beginInsertRows(QModelIndex(), proxyStart, proxyEnd);
571 void KDescendantsProxyModelPrivate::sourceRowsInserted(const QModelIndex &parent, int start, int end)
573 Q_Q(KDescendantsProxyModel);
575 Q_ASSERT(q->sourceModel()->index(start, 0, parent).isValid());
577 const int rowCount = q->sourceModel()->rowCount(parent);
578 Q_ASSERT(rowCount > 0);
580 const int difference = end - start + 1;
582 if (rowCount == difference)
584 // @p parent was not a parent before.
585 m_pendingParents.append(parent);
586 scheduleProcessPendingParents();
587 return;
590 const int proxyStart = m_insertPair.first;
592 Q_ASSERT(proxyStart >= 0);
594 updateInternalIndexes(proxyStart, difference);
596 if (rowCount - 1 == end)
598 // The previously last row (the mapped one) is no longer the last.
599 // For example,
601 // - A - A 0
602 // - - B - B 1
603 // - - C - C 2
604 // - - - D - D 3
605 // - - - E -> - E 4
606 // - - F - F 5
607 // - - G -> - G 6
608 // - H - H 7
609 // - I -> - I 8
611 // As last children, E, F and G have mappings.
612 // Consider that 'J' is appended to the children of 'C', below 'E'.
614 // - A - A 0
615 // - - B - B 1
616 // - - C - C 2
617 // - - - D - D 3
618 // - - - E -> - E 4
619 // - - - J - ??? 5
620 // - - F - F 6
621 // - - G -> - G 7
622 // - H - H 8
623 // - I -> - I 9
625 // The updateInternalIndexes call above will have updated the F and G mappings correctly because proxyStart is 5.
626 // That means that E -> 4 was not affected by the updateInternalIndexes call.
627 // Now the mapping for E -> 4 needs to be updated so that it's a mapping for J -> 5.
629 Q_ASSERT(!m_mapping.isEmpty());
630 static const int column = 0;
631 const QModelIndex oldIndex = q->sourceModel()->index(rowCount - 1 - difference, column, parent);
632 Q_ASSERT(m_mapping.leftContains(oldIndex));
634 const QModelIndex newIndex = q->sourceModel()->index(rowCount - 1, column, parent);
636 QModelIndex indexAbove = oldIndex;
638 if (start > 0) {
639 // If we have something like this:
641 // - A
642 // - - B
643 // - - C
645 // and we then insert D as a sibling of A below it, we need to remove the mapping for A,
646 // and the row number used for D must take into account the descendants of A.
648 while (q->sourceModel()->hasChildren(indexAbove)) {
649 Q_ASSERT(q->sourceModel()->rowCount(indexAbove) > 0);
650 indexAbove = q->sourceModel()->index(q->sourceModel()->rowCount(indexAbove) - 1, column, indexAbove);
652 Q_ASSERT(q->sourceModel()->rowCount(indexAbove) == 0);
655 Q_ASSERT(m_mapping.leftContains(indexAbove));
657 const int newProxyRow = m_mapping.leftToRight(indexAbove) + difference;
659 // oldIndex is E in the source. proxyRow is 4.
660 m_mapping.removeLeft(oldIndex);
662 // newIndex is J. (proxyRow + difference) is 5.
663 m_mapping.insert(newIndex, newProxyRow);
666 for (int row = start; row <= end; ++row)
668 static const int column = 0;
669 const QModelIndex idx = q->sourceModel()->index(row, column, parent);
670 Q_ASSERT(idx.isValid());
671 if (q->sourceModel()->hasChildren(idx))
673 Q_ASSERT(q->sourceModel()->rowCount(idx) > 0);
674 m_pendingParents.append(idx);
678 m_rowCount += difference;
680 q->endInsertRows();
681 scheduleProcessPendingParents();
684 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
686 Q_Q(KDescendantsProxyModel);
688 const int proxyStart = q->mapFromSource(q->sourceModel()->index(start, 0, parent)).row();
690 static const int column = 0;
691 QModelIndex idx = q->sourceModel()->index(end, column, parent);
692 while (q->sourceModel()->hasChildren(idx))
694 Q_ASSERT(q->sourceModel()->rowCount(idx) > 0);
695 idx = q->sourceModel()->index(q->sourceModel()->rowCount(idx) - 1, column, idx);
697 const int proxyEnd = q->mapFromSource(idx).row();
699 m_removePair = qMakePair(proxyStart, proxyEnd);
701 q->beginRemoveRows(QModelIndex(), proxyStart, proxyEnd);
704 static QModelIndex getFirstDeepest(QAbstractItemModel *model, const QModelIndex &parent, int *count) {
705 static const int column = 0;
706 Q_ASSERT(model->hasChildren(parent));
707 Q_ASSERT(model->rowCount(parent) > 0);
708 for (int row = 0; row < model->rowCount(parent); ++row) {
709 (*count)++;
710 const QModelIndex child = model->index(row, column, parent);
711 Q_ASSERT(child.isValid());
712 if (model->hasChildren(child))
713 return getFirstDeepest(model, child, count);
715 return model->index(model->rowCount(parent) - 1, column, parent);
718 void KDescendantsProxyModelPrivate::sourceRowsRemoved(const QModelIndex &parent, int start, int end)
720 Q_Q(KDescendantsProxyModel);
721 Q_UNUSED(end)
723 const int rowCount = q->sourceModel()->rowCount(parent);
726 const int proxyStart = m_removePair.first;
727 const int proxyEnd = m_removePair.second;
729 const int difference = proxyEnd - proxyStart + 1;
731 Mapping::right_iterator it = m_mapping.rightLowerBound(proxyStart);
732 const Mapping::right_iterator endIt = m_mapping.rightUpperBound(proxyEnd);
734 if (endIt != m_mapping.rightEnd())
735 while (it != endIt)
736 it = m_mapping.eraseRight(it);
737 else
738 while (it != m_mapping.rightUpperBound(proxyEnd))
739 it = m_mapping.eraseRight(it);
742 m_removePair = qMakePair(-1, -1);
743 m_rowCount -= difference;
744 Q_ASSERT(m_rowCount >= 0);
746 updateInternalIndexes(proxyStart, -1 * difference);
748 if (rowCount != start || rowCount == 0) {
749 q->endRemoveRows();
750 return;
753 static const int column = 0;
754 const QModelIndex newEnd = q->sourceModel()->index(rowCount - 1, column, parent);
755 Q_ASSERT(newEnd.isValid());
757 if (m_mapping.isEmpty()) {
758 m_mapping.insert(newEnd, newEnd.row());
759 q->endRemoveRows();
760 return;
762 if (q->sourceModel()->hasChildren(newEnd)) {
763 int count = 0;
764 const QModelIndex firstDeepest = getFirstDeepest(q->sourceModel(), newEnd, &count);
765 Q_ASSERT(firstDeepest.isValid());
766 const int firstDeepestProxy = m_mapping.leftToRight(firstDeepest);
768 m_mapping.insert(newEnd, firstDeepestProxy - count);
769 q->endRemoveRows();
770 return;
772 Mapping::right_iterator lowerBound = m_mapping.rightLowerBound(proxyStart);
773 if (lowerBound == m_mapping.rightEnd()) {
774 int proxyRow = (lowerBound - 1).key();
776 for (int row = newEnd.row(); row >= 0; --row ) {
777 const QModelIndex newEndSibling = q->sourceModel()->index(row, column, parent);
778 if (!q->sourceModel()->hasChildren(newEndSibling)) {
779 ++proxyRow;
780 } else {
781 break;
784 m_mapping.insert(newEnd, proxyRow);
785 q->endRemoveRows();
786 return;
787 } else if (lowerBound == m_mapping.rightBegin()) {
788 int proxyRow = rowCount - 1;
789 QModelIndex trackedParent = parent;
790 while (trackedParent.isValid()) {
791 proxyRow += (trackedParent.row() + 1);
792 trackedParent = trackedParent.parent();
794 m_mapping.insert(newEnd, proxyRow);
795 q->endRemoveRows();
796 return;
798 const Mapping::right_iterator boundAbove = lowerBound - 1;
800 QVector<QModelIndex> targetParents;
801 targetParents.push_back(parent);
803 QModelIndex target = parent;
804 int count = 0;
805 while (target.isValid()) {
806 if (target == boundAbove.value()) {
807 m_mapping.insert(newEnd, count + boundAbove.key() + newEnd.row() + 1);
808 q->endRemoveRows();
809 return;
811 count += (target.row() + 1);
812 target = target.parent();
813 if (target.isValid())
814 targetParents.push_back(target);
818 QModelIndex boundParent = boundAbove.value().parent();
819 QModelIndex prevParent = boundParent;
820 Q_ASSERT(boundParent.isValid());
821 while (boundParent.isValid()) {
822 prevParent = boundParent;
823 boundParent = boundParent.parent();
825 if (targetParents.contains(prevParent))
826 break;
828 if (!m_mapping.leftContains(prevParent))
829 break;
831 if (m_mapping.leftToRight(prevParent) > boundAbove.key())
832 break;
835 QModelIndex trackedParent = parent;
837 int proxyRow = boundAbove.key();
839 Q_ASSERT(prevParent.isValid());
840 proxyRow -= prevParent.row();
841 while (trackedParent != boundParent) {
842 proxyRow += (trackedParent.row() + 1);
843 trackedParent = trackedParent.parent();
845 m_mapping.insert(newEnd, proxyRow + newEnd.row());
846 q->endRemoveRows();
849 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeMoved(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destStart)
851 Q_UNUSED(srcParent)
852 Q_UNUSED(srcStart)
853 Q_UNUSED(srcEnd)
854 Q_UNUSED(destParent)
855 Q_UNUSED(destStart)
856 Q_Q(KDescendantsProxyModel);
857 q->beginResetModel();
860 void KDescendantsProxyModelPrivate::sourceRowsMoved(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destStart)
862 Q_UNUSED(srcParent)
863 Q_UNUSED(srcStart)
864 Q_UNUSED(srcEnd)
865 Q_UNUSED(destParent)
866 Q_UNUSED(destStart)
867 Q_Q(KDescendantsProxyModel);
868 resetInternalData();
869 q->endResetModel();
872 void KDescendantsProxyModelPrivate::sourceModelAboutToBeReset()
874 Q_Q(KDescendantsProxyModel);
875 q->beginResetModel();
878 void KDescendantsProxyModelPrivate::sourceModelReset()
880 Q_Q(KDescendantsProxyModel);
881 resetInternalData();
882 if (q->sourceModel()->hasChildren())
884 Q_ASSERT(q->sourceModel()->rowCount() > 0);
885 m_pendingParents.append(QModelIndex());
886 scheduleProcessPendingParents();
888 q->endResetModel();
891 void KDescendantsProxyModelPrivate::sourceLayoutAboutToBeChanged()
893 Q_Q(KDescendantsProxyModel);
895 if (m_ignoreNextLayoutChanged) {
896 m_ignoreNextLayoutChanged = false;
897 return;
900 if (m_mapping.isEmpty())
901 return;
903 QPersistentModelIndex srcPersistentIndex;
904 foreach(const QPersistentModelIndex &proxyPersistentIndex, q->persistentIndexList()) {
905 m_proxyIndexes << proxyPersistentIndex;
906 Q_ASSERT(proxyPersistentIndex.isValid());
907 srcPersistentIndex = q->mapToSource(proxyPersistentIndex);
908 Q_ASSERT(srcPersistentIndex.isValid());
909 m_layoutChangePersistentIndexes << srcPersistentIndex;
912 q->layoutAboutToBeChanged();
915 void KDescendantsProxyModelPrivate::sourceLayoutChanged()
917 Q_Q(KDescendantsProxyModel);
919 if (m_ignoreNextLayoutAboutToBeChanged) {
920 m_ignoreNextLayoutAboutToBeChanged = false;
921 return;
924 if (m_mapping.isEmpty())
925 return;
927 m_rowCount = 0;
929 synchronousMappingRefresh();
931 for (int i = 0; i < m_proxyIndexes.size(); ++i) {
932 q->changePersistentIndex(m_proxyIndexes.at(i), q->mapFromSource(m_layoutChangePersistentIndexes.at(i)));
935 m_layoutChangePersistentIndexes.clear();
936 m_proxyIndexes.clear();
938 q->layoutChanged();
941 void KDescendantsProxyModelPrivate::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
943 Q_Q(KDescendantsProxyModel);
944 Q_ASSERT(topLeft.model() == q->sourceModel());
945 Q_ASSERT(bottomRight.model() == q->sourceModel());
947 const int topRow = topLeft.row();
948 const int bottomRow = bottomRight.row();
950 for(int i = topRow; i <= bottomRow; ++i)
952 const QModelIndex sourceTopLeft = q->sourceModel()->index(i, topLeft.column(), topLeft.parent());
953 Q_ASSERT(sourceTopLeft.isValid());
954 const QModelIndex proxyTopLeft = q->mapFromSource(sourceTopLeft);
955 // TODO. If an index does not have any descendants, then we can emit in blocks of rows.
956 // As it is we emit once for each row.
957 const QModelIndex sourceBottomRight = q->sourceModel()->index(i, bottomRight.column(), bottomRight.parent());
958 Q_ASSERT(sourceBottomRight.isValid());
959 const QModelIndex proxyBottomRight = q->mapFromSource(sourceBottomRight);
960 Q_ASSERT(proxyTopLeft.isValid());
961 Q_ASSERT(proxyBottomRight.isValid());
962 emit q->dataChanged(proxyTopLeft, proxyBottomRight);
966 void KDescendantsProxyModelPrivate::sourceModelDestroyed()
968 resetInternalData();
971 QMimeData* KDescendantsProxyModel::mimeData( const QModelIndexList & indexes ) const
973 if (!sourceModel())
974 return QAbstractProxyModel::mimeData(indexes);
975 Q_ASSERT(sourceModel());
976 QModelIndexList sourceIndexes;
977 foreach(const QModelIndex& index, indexes)
978 sourceIndexes << mapToSource(index);
979 return sourceModel()->mimeData(sourceIndexes);
982 QStringList KDescendantsProxyModel::mimeTypes() const
984 if (!sourceModel())
985 return QAbstractProxyModel::mimeTypes();
986 Q_ASSERT(sourceModel());
987 return sourceModel()->mimeTypes();
990 Qt::DropActions KDescendantsProxyModel::supportedDropActions() const
992 if (!sourceModel())
993 return QAbstractProxyModel::supportedDropActions();
994 return sourceModel()->supportedDropActions();
997 void KDescendantsProxyModel::proxySetRoleNames(const QHash<int, QByteArray> &roleNames)
999 Q_D(KDescendantsProxyModel);
1000 d->m_roleNames = roleNames;
1003 QHash<int,QByteArray> KDescendantsProxyModel::roleNames() const
1005 Q_D(const KDescendantsProxyModel);
1006 return d->m_roleNames;
1009 #include "moc_kdescendantsproxymodel.cpp"