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