1 /*
2 SPDX-FileCopyrightText: 2009 Stephen Kelly <steveire@gmail.com>
3 SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB a KDAB Group company <info@kdab.net>
4 SPDX-FileContributor: Stephen Kelly <stephen@kdab.com>
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8
9 #include "kdescendantsproxymodel.h"
10
11 #include <QStringList>
12 #include <QTimer>
13
14 #include "kbihash_p.h"
15
16 namespace Marble
17 {
18
19 typedef KHash2Map<QPersistentModelIndex, int> Mapping;
20
21 class KDescendantsProxyModelPrivate
22 {
KDescendantsProxyModelPrivate(KDescendantsProxyModel * qq)23 KDescendantsProxyModelPrivate(KDescendantsProxyModel *qq)
24 : q_ptr(qq),
25 m_rowCount(0),
26 m_ignoreNextLayoutAboutToBeChanged(false),
27 m_ignoreNextLayoutChanged(false),
28 m_relayouting(false),
29 m_displayAncestorData(false),
30 m_ancestorSeparator(QStringLiteral(" / "))
31 {
32 }
33
34 Q_DECLARE_PUBLIC(KDescendantsProxyModel)
35 KDescendantsProxyModel *const q_ptr;
36
37 mutable QVector<QPersistentModelIndex> m_pendingParents;
38
39 void scheduleProcessPendingParents() const;
40 void processPendingParents();
41
42 void synchronousMappingRefresh();
43
44 void updateInternalIndexes(int start, int offset);
45
46 void resetInternalData();
47
48 void sourceRowsAboutToBeInserted(const QModelIndex &, int, int);
49 void sourceRowsInserted(const QModelIndex &, int, int);
50 void sourceRowsAboutToBeRemoved(const QModelIndex &, int, int);
51 void sourceRowsRemoved(const QModelIndex &, int, int);
52 void sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int);
53 void sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int);
54 void sourceModelAboutToBeReset();
55 void sourceModelReset();
56 void sourceLayoutAboutToBeChanged();
57 void sourceLayoutChanged();
58 void sourceDataChanged(const QModelIndex &, const QModelIndex &);
59 void sourceModelDestroyed();
60
61 Mapping m_mapping;
62 int m_rowCount;
63 QPair<int, int> m_removePair;
64 QPair<int, int> m_insertPair;
65
66 bool m_ignoreNextLayoutAboutToBeChanged;
67 bool m_ignoreNextLayoutChanged;
68 bool m_relayouting;
69
70 bool m_displayAncestorData;
71 QString m_ancestorSeparator;
72
73 QList<QPersistentModelIndex> m_layoutChangePersistentIndexes;
74 QModelIndexList m_proxyIndexes;
75 };
76
resetInternalData()77 void KDescendantsProxyModelPrivate::resetInternalData()
78 {
79 m_rowCount = 0;
80 m_mapping.clear();
81 m_layoutChangePersistentIndexes.clear();
82 m_proxyIndexes.clear();
83 }
84
synchronousMappingRefresh()85 void KDescendantsProxyModelPrivate::synchronousMappingRefresh()
86 {
87 m_rowCount = 0;
88 m_mapping.clear();
89 m_pendingParents.clear();
90
91 m_pendingParents.append(QModelIndex());
92
93 m_relayouting = true;
94 while (!m_pendingParents.isEmpty()) {
95 processPendingParents();
96 }
97 m_relayouting = false;
98 }
99
scheduleProcessPendingParents() const100 void KDescendantsProxyModelPrivate::scheduleProcessPendingParents() const
101 {
102 const_cast<KDescendantsProxyModelPrivate *>(this)->processPendingParents();
103 }
104
processPendingParents()105 void KDescendantsProxyModelPrivate::processPendingParents()
106 {
107 Q_Q(KDescendantsProxyModel);
108 const QVector<QPersistentModelIndex>::iterator begin = m_pendingParents.begin();
109 QVector<QPersistentModelIndex>::iterator it = begin;
110
111 const QVector<QPersistentModelIndex>::iterator end = m_pendingParents.end();
112
113 QVector<QPersistentModelIndex> newPendingParents;
114
115 while (it != end && it != m_pendingParents.end()) {
116 const QModelIndex sourceParent = *it;
117 if (!sourceParent.isValid() && m_rowCount > 0) {
118 // It was removed from the source model before it was inserted.
119 it = m_pendingParents.erase(it);
120 continue;
121 }
122 const int rowCount = q->sourceModel()->rowCount(sourceParent);
123
124 Q_ASSERT(rowCount > 0);
125 const QPersistentModelIndex sourceIndex = q->sourceModel()->index(rowCount - 1, 0, sourceParent);
126
127 Q_ASSERT(sourceIndex.isValid());
128
129 const QModelIndex proxyParent = q->mapFromSource(sourceParent);
130
131 Q_ASSERT(sourceParent.isValid() == proxyParent.isValid());
132 const int proxyEndRow = proxyParent.row() + rowCount;
133 const int proxyStartRow = proxyEndRow - rowCount + 1;
134
135 if (!m_relayouting) {
136 q->beginInsertRows(QModelIndex(), proxyStartRow, proxyEndRow);
137 }
138
139 updateInternalIndexes(proxyStartRow, rowCount);
140 m_mapping.insert(sourceIndex, proxyEndRow);
141 it = m_pendingParents.erase(it);
142 m_rowCount += rowCount;
143
144 if (!m_relayouting) {
145 q->endInsertRows();
146 }
147
148 for (int sourceRow = 0; sourceRow < rowCount; ++sourceRow) {
149 static const int column = 0;
150 const QModelIndex child = q->sourceModel()->index(sourceRow, column, sourceParent);
151 Q_ASSERT(child.isValid());
152
153 if (q->sourceModel()->hasChildren(child)) {
154 Q_ASSERT(q->sourceModel()->rowCount(child) > 0);
155 newPendingParents.append(child);
156 }
157 }
158 }
159 m_pendingParents += newPendingParents;
160 if (!m_pendingParents.isEmpty()) {
161 processPendingParents();
162 }
163 // scheduleProcessPendingParents();
164 }
165
updateInternalIndexes(int start,int offset)166 void KDescendantsProxyModelPrivate::updateInternalIndexes(int start, int offset)
167 {
168 // TODO: Make KHash2Map support key updates and do this backwards.
169 QHash<int, QPersistentModelIndex> updates;
170 {
171 Mapping::right_iterator it = m_mapping.rightLowerBound(start);
172 const Mapping::right_iterator end = m_mapping.rightEnd();
173
174 while (it != end) {
175 updates.insert(it.key() + offset, *it);
176 ++it;
177 }
178 }
179
180 {
181 QHash<int, QPersistentModelIndex>::const_iterator it = updates.constBegin();
182 const QHash<int, QPersistentModelIndex>::const_iterator end = updates.constEnd();
183
184 for (; it != end; ++it) {
185 m_mapping.insert(it.value(), it.key());
186 }
187 }
188
189 }
190
KDescendantsProxyModel(QObject * parent)191 KDescendantsProxyModel::KDescendantsProxyModel(QObject *parent)
192 : QAbstractProxyModel(parent), d_ptr(new KDescendantsProxyModelPrivate(this))
193 {
194 }
195
~KDescendantsProxyModel()196 KDescendantsProxyModel::~KDescendantsProxyModel()
197 {
198 delete d_ptr;
199 }
200
201 #if 0
202 void KDescendantsProxyModel::setRootIndex(const QModelIndex &index)
203 {
204 Q_UNUSED(index)
205 }
206 #endif
207
match(const QModelIndex & start,int role,const QVariant & value,int hits,Qt::MatchFlags flags) const208 QModelIndexList KDescendantsProxyModel::match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const
209 {
210 return QAbstractProxyModel::match(start, role, value, hits, flags);
211 }
212
setDisplayAncestorData(bool display)213 void KDescendantsProxyModel::setDisplayAncestorData(bool display)
214 {
215 Q_D(KDescendantsProxyModel);
216 d->m_displayAncestorData = display;
217 }
218
displayAncestorData() const219 bool KDescendantsProxyModel::displayAncestorData() const
220 {
221 Q_D(const KDescendantsProxyModel);
222 return d->m_displayAncestorData;
223 }
224
setAncestorSeparator(const QString & separator)225 void KDescendantsProxyModel::setAncestorSeparator(const QString &separator)
226 {
227 Q_D(KDescendantsProxyModel);
228 d->m_ancestorSeparator = separator;
229 }
230
ancestorSeparator() const231 QString KDescendantsProxyModel::ancestorSeparator() const
232 {
233 Q_D(const KDescendantsProxyModel);
234 return d->m_ancestorSeparator;
235 }
236
setSourceModel(QAbstractItemModel * _sourceModel)237 void KDescendantsProxyModel::setSourceModel(QAbstractItemModel *_sourceModel)
238 {
239 Q_D(KDescendantsProxyModel);
240
241 beginResetModel();
242
243 static const char *const modelSignals[] = {
244 SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
245 SIGNAL(rowsInserted(QModelIndex,int,int)),
246 SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
247 SIGNAL(rowsRemoved(QModelIndex,int,int)),
248 SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
249 SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
250 SIGNAL(modelAboutToBeReset()),
251 SIGNAL(modelReset()),
252 SIGNAL(dataChanged(QModelIndex,QModelIndex)),
253 SIGNAL(layoutAboutToBeChanged()),
254 SIGNAL(layoutChanged()),
255 SIGNAL(destroyed())
256 };
257 static const char *const proxySlots[] = {
258 SLOT(sourceRowsAboutToBeInserted(QModelIndex,int,int)),
259 SLOT(sourceRowsInserted(QModelIndex,int,int)),
260 SLOT(sourceRowsAboutToBeRemoved(QModelIndex,int,int)),
261 SLOT(sourceRowsRemoved(QModelIndex,int,int)),
262 SLOT(sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
263 SLOT(sourceRowsMoved(QModelIndex,int,int,QModelIndex,int)),
264 SLOT(sourceModelAboutToBeReset()),
265 SLOT(sourceModelReset()),
266 SLOT(sourceDataChanged(QModelIndex,QModelIndex)),
267 SLOT(sourceLayoutAboutToBeChanged()),
268 SLOT(sourceLayoutChanged()),
269 SLOT(sourceModelDestroyed())
270 };
271
272 if (sourceModel()) {
273 for (int i = 0; i < int(sizeof modelSignals / sizeof * modelSignals); ++i) {
274 disconnect(sourceModel(), modelSignals[i], this, proxySlots[i]);
275 }
276 }
277
278 QAbstractProxyModel::setSourceModel(_sourceModel);
279
280 if (_sourceModel) {
281 for (int i = 0; i < int(sizeof modelSignals / sizeof * modelSignals); ++i) {
282 connect(_sourceModel, modelSignals[i], this, proxySlots[i]);
283 }
284 }
285
286 resetInternalData();
287 if (_sourceModel && _sourceModel->hasChildren()) {
288 d->synchronousMappingRefresh();
289 }
290
291 endResetModel();
292 }
293
parent(const QModelIndex & index) const294 QModelIndex KDescendantsProxyModel::parent(const QModelIndex &index) const
295 {
296 Q_UNUSED(index)
297 return QModelIndex();
298 }
299
hasChildren(const QModelIndex & parent) const300 bool KDescendantsProxyModel::hasChildren(const QModelIndex &parent) const
301 {
302 Q_D(const KDescendantsProxyModel);
303 return !(d->m_mapping.isEmpty() || parent.isValid());
304 }
305
rowCount(const QModelIndex & parent) const306 int KDescendantsProxyModel::rowCount(const QModelIndex &parent) const
307 {
308 Q_D(const KDescendantsProxyModel);
309 if (d->m_pendingParents.contains(parent) || parent.isValid() || !sourceModel()) {
310 return 0;
311 }
312
313 if (d->m_mapping.isEmpty() && sourceModel()->hasChildren()) {
314 Q_ASSERT(sourceModel()->rowCount() > 0);
315 const_cast<KDescendantsProxyModelPrivate *>(d)->synchronousMappingRefresh();
316 }
317 return d->m_rowCount;
318 }
319
index(int row,int column,const QModelIndex & parent) const320 QModelIndex KDescendantsProxyModel::index(int row, int column, const QModelIndex &parent) const
321 {
322 if (parent.isValid()) {
323 return QModelIndex();
324 }
325
326 if (!hasIndex(row, column, parent)) {
327 return QModelIndex();
328 }
329
330 return createIndex(row, column);
331 }
332
mapToSource(const QModelIndex & proxyIndex) const333 QModelIndex KDescendantsProxyModel::mapToSource(const QModelIndex &proxyIndex) const
334 {
335 Q_D(const KDescendantsProxyModel);
336 if (d->m_mapping.isEmpty() || !proxyIndex.isValid() || !sourceModel()) {
337 return QModelIndex();
338 }
339
340 const Mapping::right_const_iterator result = d->m_mapping.rightLowerBound(proxyIndex.row());
341 Q_ASSERT(result != d->m_mapping.rightEnd());
342
343 const int proxyLastRow = result.key();
344 const QModelIndex sourceLastChild = result.value();
345 Q_ASSERT(sourceLastChild.isValid());
346
347 // proxyLastRow is greater than proxyIndex.row().
348 // sourceLastChild is vertically below the result we're looking for
349 // and not necessarily in the correct parent.
350 // We travel up through its parent hierarchy until we are in the
351 // right parent, then return the correct sibling.
352
353 // Source: Proxy: Row
354 // - A - A - 0
355 // - B - B - 1
356 // - C - C - 2
357 // - D - D - 3
358 // - - E - E - 4
359 // - - F - F - 5
360 // - - G - G - 6
361 // - - H - H - 7
362 // - - I - I - 8
363 // - - - J - J - 9
364 // - - - K - K - 10
365 // - - - L - L - 11
366 // - - M - M - 12
367 // - - N - N - 13
368 // - O - O - 14
369
370 // Note that L, N and O are lastChildIndexes, and therefore have a mapping. If we
371 // are trying to map G from the proxy to the source, We at this point have an iterator
372 // pointing to (L -> 11). The proxy row of G is 6. (proxyIndex.row() == 6). We seek the
373 // sourceIndex which is vertically above L by the distance proxyLastRow - proxyIndex.row().
374 // In this case the verticalDistance is 5.
375
376 int verticalDistance = proxyLastRow - proxyIndex.row();
377
378 // We traverse the ancestors of L, until we can index the desired row in the source.
379
380 QModelIndex ancestor = sourceLastChild;
381 while (ancestor.isValid()) {
382 const int ancestorRow = ancestor.row();
383 if (verticalDistance <= ancestorRow) {
384 return ancestor.sibling(ancestorRow - verticalDistance, proxyIndex.column());
385 }
386 verticalDistance -= (ancestorRow + 1);
387 ancestor = ancestor.parent();
388 }
389 Q_ASSERT(!"Didn't find target row.");
390 return QModelIndex();
391 }
392
mapFromSource(const QModelIndex & sourceIndex) const393 QModelIndex KDescendantsProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
394 {
395 Q_D(const KDescendantsProxyModel);
396
397 if (!sourceModel()) {
398 return QModelIndex();
399 }
400
401 if (d->m_mapping.isEmpty()) {
402 return QModelIndex();
403 }
404
405 {
406 // TODO: Consider a parent Mapping to speed this up.
407
408 Mapping::right_const_iterator it = d->m_mapping.rightConstBegin();
409 const Mapping::right_const_iterator end = d->m_mapping.rightConstEnd();
410 const QModelIndex sourceParent = sourceIndex.parent();
411 Mapping::right_const_iterator result = end;
412
413 for (; it != end; ++it) {
414 QModelIndex index = it.value();
415 bool found_block = false;
416 while (index.isValid()) {
417 const QModelIndex ancestor = index.parent();
418 if (ancestor == sourceParent && index.row() >= sourceIndex.row()) {
419 found_block = true;
420 if (result == end || it.key() < result.key()) {
421 result = it;
422 break; // Leave the while loop. index is still valid.
423 }
424 }
425 index = ancestor;
426 }
427 if (found_block && !index.isValid())
428 // Looked through the ascendants of it.key() without finding sourceParent.
429 // That means we've already got the result we need.
430 {
431 break;
432 }
433 }
434 Q_ASSERT(result != end);
435 const QModelIndex sourceLastChild = result.value();
436 int proxyRow = result.key();
437 QModelIndex index = sourceLastChild;
438 while (index.isValid()) {
439 const QModelIndex ancestor = index.parent();
440 if (ancestor == sourceParent) {
441 return createIndex(proxyRow - (index.row() - sourceIndex.row()), sourceIndex.column());
442 }
443 proxyRow -= (index.row() + 1);
444 index = ancestor;
445 }
446 Q_ASSERT(!"Didn't find valid proxy mapping.");
447 return QModelIndex();
448 }
449
450 }
451
columnCount(const QModelIndex & parent) const452 int KDescendantsProxyModel::columnCount(const QModelIndex &parent) const
453 {
454 if (parent.isValid() /* || rowCount(parent) == 0 */ || !sourceModel()) {
455 return 0;
456 }
457
458 return sourceModel()->columnCount();
459 }
460
data(const QModelIndex & index,int role) const461 QVariant KDescendantsProxyModel::data(const QModelIndex &index, int role) const
462 {
463 Q_D(const KDescendantsProxyModel);
464
465 if (!sourceModel()) {
466 return QVariant();
467 }
468
469 if (!index.isValid()) {
470 return sourceModel()->data(index, role);
471 }
472
473 QModelIndex sourceIndex = mapToSource(index);
474
475 if ((d->m_displayAncestorData) && (role == Qt::DisplayRole)) {
476 if (!sourceIndex.isValid()) {
477 return QVariant();
478 }
479 QString displayData = sourceIndex.data().toString();
480 sourceIndex = sourceIndex.parent();
481 while (sourceIndex.isValid()) {
482 displayData.prepend(d->m_ancestorSeparator);
483 displayData.prepend(sourceIndex.data().toString());
484 sourceIndex = sourceIndex.parent();
485 }
486 return displayData;
487 } else {
488 return sourceIndex.data(role);
489 }
490 }
491
headerData(int section,Qt::Orientation orientation,int role) const492 QVariant KDescendantsProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
493 {
494 if (!sourceModel() || columnCount() <= section) {
495 return QVariant();
496 }
497
498 return QAbstractProxyModel::headerData(section, orientation, role);
499 }
500
flags(const QModelIndex & index) const501 Qt::ItemFlags KDescendantsProxyModel::flags(const QModelIndex &index) const
502 {
503 if (!index.isValid() || !sourceModel()) {
504 return QAbstractProxyModel::flags(index);
505 }
506
507 const QModelIndex srcIndex = mapToSource(index);
508 Q_ASSERT(srcIndex.isValid());
509 return sourceModel()->flags(srcIndex);
510 }
511
sourceRowsAboutToBeInserted(const QModelIndex & parent,int start,int end)512 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
513 {
514 Q_Q(KDescendantsProxyModel);
515
516 if (!q->sourceModel()->hasChildren(parent)) {
517 Q_ASSERT(q->sourceModel()->rowCount(parent) == 0);
518 // parent was not a parent before.
519 return;
520 }
521
522 int proxyStart = -1;
523
524 const int rowCount = q->sourceModel()->rowCount(parent);
525
526 if (rowCount > start) {
527 const QModelIndex belowStart = q->sourceModel()->index(start, 0, parent);
528 proxyStart = q->mapFromSource(belowStart).row();
529 } else if (rowCount == 0) {
530 proxyStart = q->mapFromSource(parent).row() + 1;
531 } else {
532 Q_ASSERT(rowCount == start);
533 static const int column = 0;
534 QModelIndex idx = q->sourceModel()->index(rowCount - 1, column, parent);
535 while (q->sourceModel()->hasChildren(idx)) {
536 Q_ASSERT(q->sourceModel()->rowCount(idx) > 0);
537 idx = q->sourceModel()->index(q->sourceModel()->rowCount(idx) - 1, column, idx);
538 }
539 // The last item in the list is getting a sibling below it.
540 proxyStart = q->mapFromSource(idx).row() + 1;
541 }
542 const int proxyEnd = proxyStart + (end - start);
543
544 m_insertPair = qMakePair(proxyStart, proxyEnd);
545 q->beginInsertRows(QModelIndex(), proxyStart, proxyEnd);
546 }
547
sourceRowsInserted(const QModelIndex & parent,int start,int end)548 void KDescendantsProxyModelPrivate::sourceRowsInserted(const QModelIndex &parent, int start, int end)
549 {
550 Q_Q(KDescendantsProxyModel);
551
552 Q_ASSERT(q->sourceModel()->index(start, 0, parent).isValid());
553
554 const int rowCount = q->sourceModel()->rowCount(parent);
555 Q_ASSERT(rowCount > 0);
556
557 const int difference = end - start + 1;
558
559 if (rowCount == difference) {
560 // @p parent was not a parent before.
561 m_pendingParents.append(parent);
562 scheduleProcessPendingParents();
563 return;
564 }
565
566 const int proxyStart = m_insertPair.first;
567
568 Q_ASSERT(proxyStart >= 0);
569
570 updateInternalIndexes(proxyStart, difference);
571
572 if (rowCount - 1 == end) {
573 // The previously last row (the mapped one) is no longer the last.
574 // For example,
575
576 // - A - A 0
577 // - - B - B 1
578 // - - C - C 2
579 // - - - D - D 3
580 // - - - E -> - E 4
581 // - - F - F 5
582 // - - G -> - G 6
583 // - H - H 7
584 // - I -> - I 8
585
586 // As last children, E, F and G have mappings.
587 // Consider that 'J' is appended to the children of 'C', below 'E'.
588
589 // - A - A 0
590 // - - B - B 1
591 // - - C - C 2
592 // - - - D - D 3
593 // - - - E -> - E 4
594 // - - - J - ??? 5
595 // - - F - F 6
596 // - - G -> - G 7
597 // - H - H 8
598 // - I -> - I 9
599
600 // The updateInternalIndexes call above will have updated the F and G mappings correctly because proxyStart is 5.
601 // That means that E -> 4 was not affected by the updateInternalIndexes call.
602 // Now the mapping for E -> 4 needs to be updated so that it's a mapping for J -> 5.
603
604 Q_ASSERT(!m_mapping.isEmpty());
605 static const int column = 0;
606 const QModelIndex oldIndex = q->sourceModel()->index(rowCount - 1 - difference, column, parent);
607 Q_ASSERT(m_mapping.leftContains(oldIndex));
608
609 const QModelIndex newIndex = q->sourceModel()->index(rowCount - 1, column, parent);
610
611 QModelIndex indexAbove = oldIndex;
612
613 if (start > 0) {
614 // If we have something like this:
615 //
616 // - A
617 // - - B
618 // - - C
619 //
620 // and we then insert D as a sibling of A below it, we need to remove the mapping for A,
621 // and the row number used for D must take into account the descendants of A.
622
623 while (q->sourceModel()->hasChildren(indexAbove)) {
624 Q_ASSERT(q->sourceModel()->rowCount(indexAbove) > 0);
625 indexAbove = q->sourceModel()->index(q->sourceModel()->rowCount(indexAbove) - 1, column, indexAbove);
626 }
627 Q_ASSERT(q->sourceModel()->rowCount(indexAbove) == 0);
628 }
629
630 Q_ASSERT(m_mapping.leftContains(indexAbove));
631
632 const int newProxyRow = m_mapping.leftToRight(indexAbove) + difference;
633
634 // oldIndex is E in the source. proxyRow is 4.
635 m_mapping.removeLeft(oldIndex);
636
637 // newIndex is J. (proxyRow + difference) is 5.
638 m_mapping.insert(newIndex, newProxyRow);
639 }
640
641 for (int row = start; row <= end; ++row) {
642 static const int column = 0;
643 const QModelIndex idx = q->sourceModel()->index(row, column, parent);
644 Q_ASSERT(idx.isValid());
645 if (q->sourceModel()->hasChildren(idx)) {
646 Q_ASSERT(q->sourceModel()->rowCount(idx) > 0);
647 m_pendingParents.append(idx);
648 }
649 }
650
651 m_rowCount += difference;
652
653 q->endInsertRows();
654 scheduleProcessPendingParents();
655 }
656
sourceRowsAboutToBeRemoved(const QModelIndex & parent,int start,int end)657 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
658 {
659 Q_Q(KDescendantsProxyModel);
660
661 const int proxyStart = q->mapFromSource(q->sourceModel()->index(start, 0, parent)).row();
662
663 static const int column = 0;
664 QModelIndex idx = q->sourceModel()->index(end, column, parent);
665 while (q->sourceModel()->hasChildren(idx)) {
666 Q_ASSERT(q->sourceModel()->rowCount(idx) > 0);
667 idx = q->sourceModel()->index(q->sourceModel()->rowCount(idx) - 1, column, idx);
668 }
669 const int proxyEnd = q->mapFromSource(idx).row();
670
671 m_removePair = qMakePair(proxyStart, proxyEnd);
672
673 q->beginRemoveRows(QModelIndex(), proxyStart, proxyEnd);
674 }
675
getFirstDeepest(QAbstractItemModel * model,const QModelIndex & parent,int * count)676 static QModelIndex getFirstDeepest(QAbstractItemModel *model, const QModelIndex &parent, int *count)
677 {
678 static const int column = 0;
679 Q_ASSERT(model->hasChildren(parent));
680 Q_ASSERT(model->rowCount(parent) > 0);
681 for (int row = 0; row < model->rowCount(parent); ++row) {
682 (*count)++;
683 const QModelIndex child = model->index(row, column, parent);
684 Q_ASSERT(child.isValid());
685 if (model->hasChildren(child)) {
686 return getFirstDeepest(model, child, count);
687 }
688 }
689 return model->index(model->rowCount(parent) - 1, column, parent);
690 }
691
sourceRowsRemoved(const QModelIndex & parent,int start,int end)692 void KDescendantsProxyModelPrivate::sourceRowsRemoved(const QModelIndex &parent, int start, int end)
693 {
694 Q_Q(KDescendantsProxyModel);
695 Q_UNUSED(end)
696
697 const int rowCount = q->sourceModel()->rowCount(parent);
698
699 const int proxyStart = m_removePair.first;
700 const int proxyEnd = m_removePair.second;
701
702 const int difference = proxyEnd - proxyStart + 1;
703 {
704 Mapping::right_iterator it = m_mapping.rightLowerBound(proxyStart);
705 const Mapping::right_iterator endIt = m_mapping.rightUpperBound(proxyEnd);
706
707 if (endIt != m_mapping.rightEnd())
708 while (it != endIt) {
709 it = m_mapping.eraseRight(it);
710 }
711 else
712 while (it != m_mapping.rightUpperBound(proxyEnd)) {
713 it = m_mapping.eraseRight(it);
714 }
715 }
716
717 m_removePair = qMakePair(-1, -1);
718 m_rowCount -= difference;
719 Q_ASSERT(m_rowCount >= 0);
720
721 updateInternalIndexes(proxyStart, -1 * difference);
722
723 if (rowCount != start || rowCount == 0) {
724 q->endRemoveRows();
725 return;
726 }
727
728 static const int column = 0;
729 const QModelIndex newEnd = q->sourceModel()->index(rowCount - 1, column, parent);
730 Q_ASSERT(newEnd.isValid());
731
732 if (m_mapping.isEmpty()) {
733 m_mapping.insert(newEnd, newEnd.row());
734 q->endRemoveRows();
735 return;
736 }
737 if (q->sourceModel()->hasChildren(newEnd)) {
738 int count = 0;
739 const QModelIndex firstDeepest = getFirstDeepest(q->sourceModel(), newEnd, &count);
740 Q_ASSERT(firstDeepest.isValid());
741 const int firstDeepestProxy = m_mapping.leftToRight(firstDeepest);
742
743 m_mapping.insert(newEnd, firstDeepestProxy - count);
744 q->endRemoveRows();
745 return;
746 }
747 Mapping::right_iterator lowerBound = m_mapping.rightLowerBound(proxyStart);
748 if (lowerBound == m_mapping.rightEnd()) {
749 int proxyRow = (lowerBound - 1).key();
750
751 for (int row = newEnd.row(); row >= 0; --row) {
752 const QModelIndex newEndSibling = q->sourceModel()->index(row, column, parent);
753 if (!q->sourceModel()->hasChildren(newEndSibling)) {
754 ++proxyRow;
755 } else {
756 break;
757 }
758 }
759 m_mapping.insert(newEnd, proxyRow);
760 q->endRemoveRows();
761 return;
762 } else if (lowerBound == m_mapping.rightBegin()) {
763 int proxyRow = rowCount - 1;
764 QModelIndex trackedParent = parent;
765 while (trackedParent.isValid()) {
766 proxyRow += (trackedParent.row() + 1);
767 trackedParent = trackedParent.parent();
768 }
769 m_mapping.insert(newEnd, proxyRow);
770 q->endRemoveRows();
771 return;
772 }
773 const Mapping::right_iterator boundAbove = lowerBound - 1;
774
775 QVector<QModelIndex> targetParents;
776 targetParents.push_back(parent);
777 {
778 QModelIndex target = parent;
779 int count = 0;
780 while (target.isValid()) {
781 if (target == boundAbove.value()) {
782 m_mapping.insert(newEnd, count + boundAbove.key() + newEnd.row() + 1);
783 q->endRemoveRows();
784 return;
785 }
786 count += (target.row() + 1);
787 target = target.parent();
788 if (target.isValid()) {
789 targetParents.push_back(target);
790 }
791 }
792 }
793
794 QModelIndex boundParent = boundAbove.value().parent();
795 QModelIndex prevParent = boundParent;
796 Q_ASSERT(boundParent.isValid());
797 while (boundParent.isValid()) {
798 prevParent = boundParent;
799 boundParent = boundParent.parent();
800
801 if (targetParents.contains(prevParent)) {
802 break;
803 }
804
805 if (!m_mapping.leftContains(prevParent)) {
806 break;
807 }
808
809 if (m_mapping.leftToRight(prevParent) > boundAbove.key()) {
810 break;
811 }
812 }
813
814 QModelIndex trackedParent = parent;
815
816 int proxyRow = boundAbove.key();
817
818 Q_ASSERT(prevParent.isValid());
819 proxyRow -= prevParent.row();
820 while (trackedParent != boundParent) {
821 proxyRow += (trackedParent.row() + 1);
822 trackedParent = trackedParent.parent();
823 }
824 m_mapping.insert(newEnd, proxyRow + newEnd.row());
825 q->endRemoveRows();
826 }
827
sourceRowsAboutToBeMoved(const QModelIndex & srcParent,int srcStart,int srcEnd,const QModelIndex & destParent,int destStart)828 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeMoved(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destStart)
829 {
830 Q_UNUSED(srcParent)
831 Q_UNUSED(srcStart)
832 Q_UNUSED(srcEnd)
833 Q_UNUSED(destParent)
834 Q_UNUSED(destStart)
835 sourceLayoutAboutToBeChanged();
836 }
837
sourceRowsMoved(const QModelIndex & srcParent,int srcStart,int srcEnd,const QModelIndex & destParent,int destStart)838 void KDescendantsProxyModelPrivate::sourceRowsMoved(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destStart)
839 {
840 Q_UNUSED(srcParent)
841 Q_UNUSED(srcStart)
842 Q_UNUSED(srcEnd)
843 Q_UNUSED(destParent)
844 Q_UNUSED(destStart)
845 sourceLayoutChanged();
846 }
847
sourceModelAboutToBeReset()848 void KDescendantsProxyModelPrivate::sourceModelAboutToBeReset()
849 {
850 Q_Q(KDescendantsProxyModel);
851 q->beginResetModel();
852 }
853
sourceModelReset()854 void KDescendantsProxyModelPrivate::sourceModelReset()
855 {
856 Q_Q(KDescendantsProxyModel);
857 resetInternalData();
858 if (q->sourceModel()->hasChildren()) {
859 Q_ASSERT(q->sourceModel()->rowCount() > 0);
860 m_pendingParents.append(QModelIndex());
861 scheduleProcessPendingParents();
862 }
863 q->endResetModel();
864 }
865
sourceLayoutAboutToBeChanged()866 void KDescendantsProxyModelPrivate::sourceLayoutAboutToBeChanged()
867 {
868 Q_Q(KDescendantsProxyModel);
869
870 if (m_ignoreNextLayoutChanged) {
871 m_ignoreNextLayoutChanged = false;
872 return;
873 }
874
875 if (m_mapping.isEmpty()) {
876 return;
877 }
878
879 QPersistentModelIndex srcPersistentIndex;
880 for (const QPersistentModelIndex &proxyPersistentIndex: q->persistentIndexList()) {
881 m_proxyIndexes << proxyPersistentIndex;
882 Q_ASSERT(proxyPersistentIndex.isValid());
883 srcPersistentIndex = q->mapToSource(proxyPersistentIndex);
884 Q_ASSERT(srcPersistentIndex.isValid());
885 m_layoutChangePersistentIndexes << srcPersistentIndex;
886 }
887
888 q->layoutAboutToBeChanged();
889 }
890
sourceLayoutChanged()891 void KDescendantsProxyModelPrivate::sourceLayoutChanged()
892 {
893 Q_Q(KDescendantsProxyModel);
894
895 if (m_ignoreNextLayoutAboutToBeChanged) {
896 m_ignoreNextLayoutAboutToBeChanged = false;
897 return;
898 }
899
900 if (m_mapping.isEmpty()) {
901 return;
902 }
903
904 m_rowCount = 0;
905
906 synchronousMappingRefresh();
907
908 for (int i = 0; i < m_proxyIndexes.size(); ++i) {
909 q->changePersistentIndex(m_proxyIndexes.at(i), q->mapFromSource(m_layoutChangePersistentIndexes.at(i)));
910 }
911
912 m_layoutChangePersistentIndexes.clear();
913 m_proxyIndexes.clear();
914
915 q->layoutChanged();
916 }
917
sourceDataChanged(const QModelIndex & topLeft,const QModelIndex & bottomRight)918 void KDescendantsProxyModelPrivate::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
919 {
920 Q_Q(KDescendantsProxyModel);
921 Q_ASSERT(topLeft.model() == q->sourceModel());
922 Q_ASSERT(bottomRight.model() == q->sourceModel());
923
924 const int topRow = topLeft.row();
925 const int bottomRow = bottomRight.row();
926
927 for (int i = topRow; i <= bottomRow; ++i) {
928 const QModelIndex sourceTopLeft = q->sourceModel()->index(i, topLeft.column(), topLeft.parent());
929 Q_ASSERT(sourceTopLeft.isValid());
930 const QModelIndex proxyTopLeft = q->mapFromSource(sourceTopLeft);
931 // TODO. If an index does not have any descendants, then we can emit in blocks of rows.
932 // As it is we emit once for each row.
933 const QModelIndex sourceBottomRight = q->sourceModel()->index(i, bottomRight.column(), bottomRight.parent());
934 const QModelIndex proxyBottomRight = q->mapFromSource(sourceBottomRight);
935 Q_ASSERT(proxyTopLeft.isValid());
936 Q_ASSERT(proxyBottomRight.isValid());
937 emit q->dataChanged(proxyTopLeft, proxyBottomRight);
938 }
939 }
940
sourceModelDestroyed()941 void KDescendantsProxyModelPrivate::sourceModelDestroyed()
942 {
943 resetInternalData();
944 }
945
mimeData(const QModelIndexList & indexes) const946 QMimeData *KDescendantsProxyModel::mimeData(const QModelIndexList &indexes) const
947 {
948 if (!sourceModel()) {
949 return QAbstractProxyModel::mimeData(indexes);
950 }
951 Q_ASSERT(sourceModel());
952 QModelIndexList sourceIndexes;
953 for (const QModelIndex &index: indexes) {
954 sourceIndexes << mapToSource(index);
955 }
956 return sourceModel()->mimeData(sourceIndexes);
957 }
958
mimeTypes() const959 QStringList KDescendantsProxyModel::mimeTypes() const
960 {
961 if (!sourceModel()) {
962 return QAbstractProxyModel::mimeTypes();
963 }
964 Q_ASSERT(sourceModel());
965 return sourceModel()->mimeTypes();
966 }
967
supportedDropActions() const968 Qt::DropActions KDescendantsProxyModel::supportedDropActions() const
969 {
970 if (!sourceModel()) {
971 return QAbstractProxyModel::supportedDropActions();
972 }
973 return sourceModel()->supportedDropActions();
974 }
975
976 }
977
978 #include "moc_kdescendantsproxymodel.cpp"
979