• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 API Reference
  • KDE Home
  • Contact Us
 

KDEUI

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

KDE's Doxygen guidelines are available online.

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal