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