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

KDEUI

  • kdeui
  • itemviews
kselectionproxymodel.cpp
Go to the documentation of this file.
1/*
2 Copyright (c) 2009 Stephen Kelly <steveire@gmail.com>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18*/
19
20#include "kselectionproxymodel.h"
21
22#include <QtCore/QStack>
23#include <QtCore/QStringList>
24#include <QtCore/QWeakPointer>
25#include <QtGui/QItemSelectionRange>
26
27#include "kmodelindexproxymapper.h"
28#include "kbihash_p.h"
29#include "kvoidpointerfactory_p.h"
30
31#include "kdebug.h"
32
33typedef KBiHash<QPersistentModelIndex, QModelIndex> SourceProxyIndexMapping;
34typedef KBiHash<void*, QModelIndex> ParentMapping;
35typedef KHash2Map<QPersistentModelIndex, int> SourceIndexProxyRowMapping;
36
37#define KDO(object) kDebug() << #object << object
38#define SON(object) object->setObjectName(#object)
39
44template<typename ModelIndex>
45bool isDescendantOf(const QList<ModelIndex> &list, const QModelIndex &idx)
46{
47 if (!idx.isValid())
48 return false;
49
50 if (list.contains(idx))
51 return false;
52
53 QModelIndex parent = idx.parent();
54 while (parent.isValid()) {
55 if (list.contains(parent))
56 return true;
57 parent = parent.parent();
58 }
59 return false;
60}
61
62static bool isDescendantOf(const QModelIndex &ancestor, const QModelIndex &descendant)
63{
64 if (!descendant.isValid())
65 return false;
66
67 if (ancestor == descendant)
68 return false;
69
70 QModelIndex parent = descendant.parent();
71 while (parent.isValid()) {
72 if (parent == ancestor)
73 return true;
74
75 parent = parent.parent();
76 }
77 return false;
78}
79
80static bool isDescendantOf(const QItemSelection &selection, const QModelIndex &descendant)
81{
82 if (!descendant.isValid())
83 return false;
84
85 if (selection.contains(descendant))
86 return false;
87
88 QModelIndex parent = descendant.parent();
89 while (parent.isValid()) {
90 if (selection.contains(parent))
91 return true;
92
93 parent = parent.parent();
94 }
95 return false;
96}
97
98static bool isDescendantOf(const QItemSelectionRange &range, const QModelIndex &descendant)
99{
100 if (!descendant.isValid())
101 return false;
102
103 if (range.contains(descendant))
104 return false;
105
106 QModelIndex parent = descendant.parent();
107 while (parent.isValid()) {
108 if (range.contains(parent))
109 return true;
110
111 parent = parent.parent();
112 }
113 return false;
114}
115
116static int _getRootListRow(const QList<QModelIndexList> &rootAncestors, const QModelIndex &index)
117{
118 QModelIndex commonParent = index;
119 QModelIndex youngestAncestor;
120
121 int firstCommonParent = -1;
122 int bestParentRow = -1;
123 while (commonParent.isValid()) {
124 youngestAncestor = commonParent;
125 commonParent = commonParent.parent();
126
127 for (int i = 0; i < rootAncestors.size(); ++i) {
128 const QModelIndexList ancestorList = rootAncestors.at(i);
129
130 const int parentRow = ancestorList.indexOf(commonParent);
131
132 if (parentRow < 0)
133 continue;
134
135 if (parentRow > bestParentRow) {
136 firstCommonParent = i;
137 bestParentRow = parentRow;
138 }
139 }
140
141 if (firstCommonParent >= 0)
142 break;
143 }
144
145 // If @p list is non-empty, the invalid QModelIndex() will at least be found in ancestorList.
146 Q_ASSERT(firstCommonParent >= 0);
147
148 const QModelIndexList firstAnsList = rootAncestors.at(firstCommonParent);
149
150 const QModelIndex eldestSibling = firstAnsList.value(bestParentRow + 1);
151
152 if (eldestSibling.isValid()) {
153 // firstCommonParent is a sibling of one of the ancestors of @p index.
154 // It is the first index to share a common parent with one of the ancestors of @p index.
155 if (eldestSibling.row() >= youngestAncestor.row())
156 return firstCommonParent;
157 }
158
159 int siblingOffset = 1;
160
161 // The same commonParent might be common to several root indexes.
162 // If this is the last in the list, it's the only match. We instruct the model
163 // to insert the new index after it ( + siblingOffset).
164 if (rootAncestors.size() <= firstCommonParent + siblingOffset) {
165 return firstCommonParent + siblingOffset;
166 }
167
168 // A
169 // - B
170 // - C
171 // - D
172 // - E
173 // F
174 //
175 // F is selected, then C then D. When inserting D into the model, the commonParent is B (the parent of C).
176 // The next existing sibling of B is F (in the proxy model). bestParentRow will then refer to an index on
177 // the level of a child of F (which doesn't exist - Boom!). If it doesn't exist, then we've already found
178 // the place to insert D
179 QModelIndexList ansList = rootAncestors.at(firstCommonParent + siblingOffset);
180 if (ansList.size() <= bestParentRow) {
181 return firstCommonParent + siblingOffset;
182 }
183
184 QModelIndex nextParent = ansList.at(bestParentRow);
185 while (nextParent == commonParent) {
186 if (ansList.size() < bestParentRow + 1)
187 // If the list is longer, it means that at the end of it is a descendant of the new index.
188 // We insert the ancestors items first in that case.
189 break;
190
191 const QModelIndex nextSibling = ansList.value(bestParentRow + 1);
192
193 if (!nextSibling.isValid()) {
194 continue;
195 }
196
197 if (youngestAncestor.row() <= nextSibling.row()) {
198 break;
199 }
200
201 siblingOffset++;
202
203 if (rootAncestors.size() <= firstCommonParent + siblingOffset)
204 break;
205
206 ansList = rootAncestors.at(firstCommonParent + siblingOffset);
207
208 // In the scenario above, E is selected after D, causing this loop to be entered,
209 // and requiring a similar result if the next sibling in the proxy model does not have children.
210 if (ansList.size() <= bestParentRow) {
211 break;
212 }
213
214 nextParent = ansList.at(bestParentRow);
215 }
216
217 return firstCommonParent + siblingOffset;
218}
219
223template<typename ModelIndex>
224static int getRootListRow(const QList<ModelIndex> &list, const QModelIndex &index)
225{
226 if (!index.isValid())
227 return -1;
228
229 if (list.isEmpty())
230 return 0;
231
232 // What's going on?
233 // Consider a tree like
234 //
235 // A
236 // - B
237 // - - C
238 // - - - D
239 // - E
240 // - F
241 // - - G
242 // - - - H
243 // - I
244 // - - J
245 // - K
246 //
247 // If D, E and J are already selected, and H is newly selected, we need to put H between E and J in the proxy model.
248 // To figure that out, we create a list for each already selected index of its ancestors. Then,
249 // we climb the ancestors of H until we reach an index with siblings which have a descendant
250 // selected (F above has siblings B, E and I which have descendants which are already selected).
251 // Those child indexes are traversed to find the right sibling to put F beside.
252 //
253 // i.e., new items are inserted in the expected location.
254
255 QList<QModelIndexList> rootAncestors;
256 foreach(const QModelIndex &root, list) {
257 QModelIndexList ancestors;
258 ancestors << root;
259 QModelIndex parent = root.parent();
260 while (parent.isValid()) {
261 ancestors.prepend(parent);
262 parent = parent.parent();
263 }
264 ancestors.prepend(QModelIndex());
265 rootAncestors << ancestors;
266 }
267 return _getRootListRow(rootAncestors, index);
268}
269
281static QItemSelection getRootRanges(const QItemSelection &_selection)
282{
283 QItemSelection rootSelection;
284 QItemSelection selection = _selection;
285 QList<QItemSelectionRange>::iterator it = selection.begin();
286 while (it != selection.end()) {
287 if (!it->topLeft().parent().isValid())
288 {
289 rootSelection.append(*it);
290 it = selection.erase(it);
291 } else
292 ++it;
293 }
294
295 it = selection.begin();
296 const QList<QItemSelectionRange>::iterator end = selection.end();
297 while ( it != end ) {
298 const QItemSelectionRange range = *it;
299 it = selection.erase(it);
300
301 if (isDescendantOf(rootSelection, range.topLeft()) || isDescendantOf(selection, range.topLeft()))
302 continue;
303
304 rootSelection << range;
305 }
306 return rootSelection;
307}
308
311struct RangeLessThan
312{
313 bool operator()(const QItemSelectionRange &left, const QItemSelectionRange &right) const
314 {
315 if (right.model() == left.model()) {
316 // parent has to be calculated, so we only do so once.
317 const QModelIndex topLeftParent = left.parent();
318 const QModelIndex otherTopLeftParent = right.parent();
319 if (topLeftParent == otherTopLeftParent) {
320 if (right.top() == left.top()) {
321 if (right.left() == left.left()) {
322 if (right.bottom() == left.bottom()) {
323 return left.right() < right.right();
324 }
325 return left.bottom() < right.bottom();
326 }
327 return left.left() < right.left();
328 }
329 return left.top() < right.top();
330 }
331 return topLeftParent < otherTopLeftParent;
332 }
333 return left.model() < right.model();
334 }
335};
336
337static QItemSelection stableNormalizeSelection(const QItemSelection &selection)
338{
339 if (selection.size() <= 1)
340 return selection;
341
342 QItemSelection::const_iterator it = selection.begin();
343 const QItemSelection::const_iterator end = selection.end();
344
345 Q_ASSERT(it != end);
346 QItemSelection::const_iterator scout = it + 1;
347
348 QItemSelection result;
349 while (scout != end) {
350 Q_ASSERT(it != end);
351 int bottom = it->bottom();
352 while (scout != end && it->parent() == scout->parent() && bottom + 1 == scout->top()) {
353 bottom = scout->bottom();
354 ++scout;
355 }
356 if (bottom != it->bottom()) {
357 const QModelIndex topLeft = it->topLeft();
358 result << QItemSelectionRange(topLeft, topLeft.sibling(bottom, it->right()));
359 }
360 Q_ASSERT(it != scout);
361 if (scout == end)
362 break;
363 if (it + 1 == scout)
364 result << *it;
365 it = scout;
366 ++scout;
367 if (scout == end)
368 result << *it;
369 }
370 return result;
371}
372
373QItemSelection kNormalizeSelection(QItemSelection selection)
374{
375 if (selection.size() <= 1)
376 return selection;
377
378 // KSelectionProxyModel has a strong assumption that
379 // the views always select rows, so usually the
380 // @p selection here contains ranges that span all
381 // columns. However, if a QSortFilterProxyModel
382 // is used too, it splits up the complete ranges into
383 // one index per range. That confuses the data structures
384 // held by this proxy (which keeps track of indexes in the
385 // first column). As this proxy already assumes that if the
386 // zeroth column is selected, then its entire row is selected,
387 // we can safely remove the ranges which do not include
388 // column 0 without a loss of functionality.
389 QItemSelection::iterator i = selection.begin();
390 while (i != selection.end()) {
391 if (i->left() > 0)
392 i = selection.erase(i);
393 else
394 ++i;
395 }
396
397 RangeLessThan lt;
398 qSort(selection.begin(), selection.end(), lt);
399 return stableNormalizeSelection(selection);
400}
401
402
403class KSelectionProxyModelPrivate
404{
405public:
406 KSelectionProxyModelPrivate(KSelectionProxyModel *model, QItemSelectionModel *selectionModel)
407 : q_ptr(model),
408 m_startWithChildTrees(false),
409 m_omitChildren(false),
410 m_omitDescendants(false),
411 m_includeAllSelected(false),
412 m_rowsInserted(false),
413 m_rowsRemoved(false),
414 m_rowsMoved(false),
415 m_resetting(false),
416 m_doubleResetting(false),
417 m_layoutChanging(false),
418 m_ignoreNextLayoutAboutToBeChanged(false),
419 m_ignoreNextLayoutChanged(false),
420 m_selectionModel(selectionModel)
421 {
422 }
423
424 Q_DECLARE_PUBLIC(KSelectionProxyModel)
425 KSelectionProxyModel * const q_ptr;
426
427 // A unique id is generated for each parent. It is used for the internalPointer of its children in the proxy
428 // This is used to store a unique id for QModelIndexes in the proxy which have children.
429 // If an index newly gets children it is added to this hash. If its last child is removed it is removed from this map.
430 // If this map contains an index, that index hasChildren(). This hash is populated when new rows are inserted in the
431 // source model, or a new selection is made.
432 mutable ParentMapping m_parentIds;
433 // This mapping maps indexes with children in the source to indexes with children in the proxy.
434 // The order of indexes in this list is not relevant.
435 mutable SourceProxyIndexMapping m_mappedParents;
436
437 KVoidPointerFactory<> m_voidPointerFactory;
438
451 void updateInternalIndexes(const QModelIndex &parent, int start, int offset);
452
460 void updateInternalTopIndexes(int start, int offset);
461
462 void updateFirstChildMapping(const QModelIndex& parent, int offset);
463
464 bool isFlat() const { return m_omitChildren || (m_omitDescendants && m_startWithChildTrees); }
465
470 bool ensureMappable(const QModelIndex &parent) const;
471 bool parentIsMappable(const QModelIndex &parent) const { return parentAlreadyMapped(parent) || m_rootIndexList.contains(parent); }
472
476 QModelIndex mapFromSource(const QModelIndex &parent) const;
477
483 void createParentMappings(const QModelIndex &parent, int start, int end) const;
484 void createFirstChildMapping(const QModelIndex &parent, int proxyRow) const;
485 bool firstChildAlreadyMapped(const QModelIndex &firstChild) const;
486 bool parentAlreadyMapped(const QModelIndex &parent) const;
487 void removeFirstChildMappings(int start, int end);
488 void removeParentMappings(const QModelIndex &parent, int start, int end);
489
499 QModelIndex mapParentToSource(const QModelIndex &proxyParent) const;
500
508 QModelIndex mapParentFromSource(const QModelIndex &sourceParent) const;
509
510 QModelIndex mapTopLevelToSource(int row, int column) const;
511 QModelIndex mapTopLevelFromSource(const QModelIndex &sourceIndex) const;
512 QModelIndex createTopLevelIndex(int row, int column) const;
513 int topLevelRowCount() const;
514
515 void* parentId(const QModelIndex &proxyParent) const { return m_parentIds.rightToLeft(proxyParent); }
516 QModelIndex parentForId(void *id) const { return m_parentIds.leftToRight(id); }
517
518 // Only populated if m_startWithChildTrees.
519
520 mutable SourceIndexProxyRowMapping m_mappedFirstChildren;
521
522 // Source list is the selection in the source model.
523 QList<QPersistentModelIndex> m_rootIndexList;
524
525 KModelIndexProxyMapper *m_indexMapper;
526
527 QPair<int, int> beginRemoveRows(const QModelIndex &parent, int start, int end) const;
528 QPair<int, int> beginInsertRows(const QModelIndex &parent, int start, int end) const;
529 void endRemoveRows(const QModelIndex &sourceParent, int proxyStart, int proxyEnd);
530 void endInsertRows(const QModelIndex &parent, int start, int end);
531
532 void sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end);
533 void sourceRowsInserted(const QModelIndex &parent, int start, int end);
534 void sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
535 void sourceRowsRemoved(const QModelIndex &parent, int start, int end);
536 void sourceRowsAboutToBeMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destParent, int destRow);
537 void sourceRowsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destParent, int destRow);
538 void sourceModelAboutToBeReset();
539 void sourceModelReset();
540 void sourceLayoutAboutToBeChanged();
541 void sourceLayoutChanged();
542 void emitContinuousRanges(const QModelIndex &sourceFirst, const QModelIndex &sourceLast,
543 const QModelIndex &proxyFirst, const QModelIndex &proxyLast);
544 void sourceDataChanged(const QModelIndex &topLeft , const QModelIndex &bottomRight);
545
546 void removeSelectionFromProxy(const QItemSelection &selection);
547 void removeRangeFromProxy(const QItemSelectionRange &range);
548
549 void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
550 void sourceModelDestroyed();
551
552 void resetInternalData();
553
558 int getProxyInitialRow(const QModelIndex &parent) const;
559
569 int getTargetRow(int rootListRow);
570
574 void insertSelectionIntoProxy(const QItemSelection& selection);
575
576 bool m_startWithChildTrees;
577 bool m_omitChildren;
578 bool m_omitDescendants;
579 bool m_includeAllSelected;
580 bool m_rowsInserted;
581 bool m_rowsRemoved;
582 QPair<int, int> m_proxyRemoveRows;
583 bool m_rowsMoved;
584 bool m_resetting;
585 bool m_doubleResetting;
586 bool m_layoutChanging;
587 bool m_ignoreNextLayoutAboutToBeChanged;
588 bool m_ignoreNextLayoutChanged;
589 const QWeakPointer<QItemSelectionModel> m_selectionModel;
590
591 KSelectionProxyModel::FilterBehavior m_filterBehavior;
592
593 QList<QPersistentModelIndex> m_layoutChangePersistentIndexes;
594 QModelIndexList m_proxyIndexes;
595
596 struct PendingSelectionChange
597 {
598 PendingSelectionChange() {}
599 PendingSelectionChange(const QItemSelection &selected_, const QItemSelection &deselected_)
600 : selected(selected_), deselected(deselected_)
601 {
602
603 }
604 QItemSelection selected;
605 QItemSelection deselected;
606 };
607 QVector<PendingSelectionChange> m_pendingSelectionChanges;
608};
609
610void KSelectionProxyModelPrivate::emitContinuousRanges(const QModelIndex &sourceFirst, const QModelIndex &sourceLast,
611 const QModelIndex &proxyFirst, const QModelIndex &proxyLast)
612{
613 Q_Q(KSelectionProxyModel);
614
615 Q_ASSERT(sourceFirst.model() == q->sourceModel());
616 Q_ASSERT(sourceLast.model() == q->sourceModel());
617 Q_ASSERT(proxyFirst.model() == q);
618 Q_ASSERT(proxyLast.model() == q);
619
620 const int proxyRangeSize = proxyLast.row() - proxyFirst.row();
621 const int sourceRangeSize = sourceLast.row() - sourceFirst.row();
622
623 if (proxyRangeSize == sourceRangeSize) {
624 emit q->dataChanged(proxyFirst, proxyLast);
625 return;
626 }
627
628
629 // TODO: Loop to skip descendant ranges.
630// int lastRow;
631//
632// const QModelIndex sourceHalfWay = sourceFirst.sibling(sourceFirst.row() + (sourceRangeSize / 2));
633// const QModelIndex proxyHalfWay = proxyFirst.sibling(proxyFirst.row() + (proxyRangeSize / 2));
634// const QModelIndex mappedSourceHalfway = q->mapToSource(proxyHalfWay);
635//
636// const int halfProxyRange = mappedSourceHalfway.row() - proxyFirst.row();
637// const int halfSourceRange = sourceHalfWay.row() - sourceFirst.row();
638//
639// if (proxyRangeSize == sourceRangeSize)
640// {
641// emit q->dataChanged(proxyFirst, proxyLast.sibling(proxyFirst.row() + proxyRangeSize, proxyLast.column()));
642// return;
643// }
644
645 emit q->dataChanged(proxyFirst, proxyLast);
646}
647
648void KSelectionProxyModelPrivate::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
649{
650 Q_Q(KSelectionProxyModel);
651
652 Q_ASSERT(topLeft.model() == q->sourceModel());
653 Q_ASSERT(bottomRight.model() == q->sourceModel());
654
655 const QModelIndex sourceRangeParent = topLeft.parent();
656 if (!sourceRangeParent.isValid() && m_startWithChildTrees && !m_rootIndexList.contains(sourceRangeParent))
657 return;
658
659 const QModelIndex proxyTopLeft = q->mapFromSource(topLeft);
660 const QModelIndex proxyBottomRight = q->mapFromSource(bottomRight);
661
662 const QModelIndex proxyRangeParent = proxyTopLeft.parent();
663
664 if (!m_omitChildren && m_omitDescendants && m_startWithChildTrees && m_includeAllSelected) {
665 // ChildrenOfExactSelection
666 if (proxyTopLeft.isValid())
667 emitContinuousRanges(topLeft, bottomRight, proxyTopLeft, proxyBottomRight);
668 return;
669 }
670
671 if ((m_omitChildren && !m_startWithChildTrees && m_includeAllSelected)
672 || (!proxyRangeParent.isValid() && !m_startWithChildTrees)) {
673 // Exact selection and SubTreeRoots and SubTrees in top level
674 // Emit continuous ranges.
675 QList<int> changedRows;
676 for (int row = topLeft.row(); row <= bottomRight.row(); ++row) {
677 const QModelIndex index = q->sourceModel()->index(row, topLeft.column(), topLeft.parent());
678 const int idx = m_rootIndexList.indexOf(index);
679 if (idx != -1) {
680 changedRows.append(idx);
681 }
682 }
683 if (changedRows.isEmpty())
684 return;
685 int first = changedRows.first();
686 int previous = first;
687 QList<int>::const_iterator it = changedRows.constBegin();
688 const QList<int>::const_iterator end = changedRows.constEnd();
689 for ( ; it != end; ++it) {
690 if (*it == previous + 1) {
691 ++previous;
692 } else {
693 const QModelIndex _top = q->index(first, topLeft.column());
694 const QModelIndex _bottom = q->index(previous, bottomRight.column());
695 emit q->dataChanged(_top, _bottom);
696 previous = first = *it;
697 }
698 }
699 if (first != previous) {
700 const QModelIndex _top = q->index(first, topLeft.column());
701 const QModelIndex _bottom = q->index(previous, bottomRight.column());
702 emit q->dataChanged(_top, _bottom);
703 }
704 return;
705 }
706 if (proxyRangeParent.isValid()) {
707 if (m_omitChildren && !m_startWithChildTrees && !m_includeAllSelected)
708 // SubTreeRoots
709 return;
710 if (!proxyTopLeft.isValid())
711 return;
712 // SubTrees and SubTreesWithoutRoots
713 emit q->dataChanged(proxyTopLeft, proxyBottomRight);
714 return;
715 }
716
717 if (m_startWithChildTrees && !m_omitChildren && !m_includeAllSelected && !m_omitDescendants) {
718 // SubTreesWithoutRoots
719 if (proxyTopLeft.isValid())
720 emit q->dataChanged(proxyTopLeft, proxyBottomRight);
721 return;
722 }
723}
724
725void KSelectionProxyModelPrivate::sourceLayoutAboutToBeChanged()
726{
727 Q_Q(KSelectionProxyModel);
728
729 if (m_ignoreNextLayoutAboutToBeChanged) {
730 m_ignoreNextLayoutAboutToBeChanged = false;
731 return;
732 }
733
734 if (m_rootIndexList.isEmpty())
735 return;
736
737 emit q->layoutAboutToBeChanged();
738
739 QPersistentModelIndex srcPersistentIndex;
740 foreach(const QPersistentModelIndex &proxyPersistentIndex, q->persistentIndexList()) {
741 m_proxyIndexes << proxyPersistentIndex;
742 Q_ASSERT(proxyPersistentIndex.isValid());
743 srcPersistentIndex = q->mapToSource(proxyPersistentIndex);
744 Q_ASSERT(srcPersistentIndex.isValid());
745 m_layoutChangePersistentIndexes << srcPersistentIndex;
746 }
747
748 QItemSelection selection;
749 foreach (const QModelIndex &rootIndex, m_rootIndexList)
750 {
751 // This will be optimized later.
752 emit q->rootIndexAboutToBeRemoved(rootIndex);
753 selection.append(QItemSelectionRange(rootIndex, rootIndex));
754 }
755
756 selection = kNormalizeSelection(selection);
757 emit q->rootSelectionAboutToBeRemoved(selection);
758
759 m_rootIndexList.clear();
760}
761
762void KSelectionProxyModelPrivate::sourceLayoutChanged()
763{
764 Q_Q(KSelectionProxyModel);
765
766 if (m_ignoreNextLayoutChanged) {
767 m_ignoreNextLayoutChanged = false;
768 return;
769 }
770
771 if (m_selectionModel.data()->selection().isEmpty()) {
772 return;
773 }
774
775 // Handling this signal is slow.
776 // The problem is that anything can happen between emissions of layoutAboutToBeChanged and layoutChanged.
777 // We can't assume anything is the same about the structure anymore. items have been sorted, items which
778 // were parents before are now not, items which were not parents before now are, items which used to be the
779 // first child are now the Nth child and items which used to be the Nth child are now the first child.
780 // We effectively can't update our mapping because we don't have enough information to update everything.
781 // The only way we would have is if we take a persistent index of the entire source model
782 // on sourceLayoutAboutToBeChanged and then examine it here. That would be far too expensive.
783 // Instead we just have to clear the entire mapping and recreate it.
784
785 m_rootIndexList.clear();
786 m_mappedFirstChildren.clear();
787 m_mappedParents.clear();
788 m_parentIds.clear();
789
790 m_resetting = true;
791 m_layoutChanging = true;
792 selectionChanged(m_selectionModel.data()->selection(), QItemSelection());
793 m_resetting = false;
794 m_layoutChanging = false;
795
796 for (int i = 0; i < m_proxyIndexes.size(); ++i) {
797 q->changePersistentIndex(m_proxyIndexes.at(i), q->mapFromSource(m_layoutChangePersistentIndexes.at(i)));
798 }
799
800 m_layoutChangePersistentIndexes.clear();
801 m_proxyIndexes.clear();
802
803 emit q->layoutChanged();
804}
805
806void KSelectionProxyModelPrivate::resetInternalData()
807{
808 m_rootIndexList.clear();
809 m_layoutChangePersistentIndexes.clear();
810 m_proxyIndexes.clear();
811 m_mappedParents.clear();
812 m_parentIds.clear();
813 m_mappedFirstChildren.clear();
814 m_voidPointerFactory.clear();
815}
816
817void KSelectionProxyModelPrivate::sourceModelDestroyed()
818{
819 Q_Q(KSelectionProxyModel);
820 // There is very little we can do here.
821 resetInternalData();
822 m_resetting = false;
823 // q->endResetModel();
824}
825
826void KSelectionProxyModelPrivate::sourceModelAboutToBeReset()
827{
828 Q_Q(KSelectionProxyModel);
829
830 // We might be resetting as a result of the selection source model resetting.
831 // If so we don't want to emit
832 // sourceModelAboutToBeReset
833 // sourceModelAboutToBeReset
834 // sourceModelReset
835 // sourceModelReset
836 // So we ensure that we just emit one.
837 if (m_resetting) {
838
839 // If both the source model and the selection source model are reset,
840 // We want to begin our reset before the first one is reset and end
841 // it after the second one is reset.
842 m_doubleResetting = true;
843 return;
844 }
845
846 q->beginResetModel();
847 m_resetting = true;
848}
849
850void KSelectionProxyModelPrivate::sourceModelReset()
851{
852 Q_Q(KSelectionProxyModel);
853
854 if (m_doubleResetting) {
855 m_doubleResetting = false;
856 return;
857 }
858
859 resetInternalData();
860 // No need to try to refill this. When the model is reset it doesn't have a meaningful selection anymore,
861 // but when it gets one we'll be notified anyway.
862 if (!m_selectionModel.isNull())
863 m_selectionModel.data()->reset();
864 m_resetting = false;
865 q->endResetModel();
866}
867
868int KSelectionProxyModelPrivate::getProxyInitialRow(const QModelIndex &parent) const
869{
870 Q_ASSERT(m_rootIndexList.contains(parent));
871
872 // The difficulty here is that parent and parent.parent() might both be in the m_rootIndexList.
873
874 // - A
875 // - B
876 // - - C
877 // - - D
878 // - - - E
879
880 // Consider that B and D are selected. The proxy model is:
881
882 // - C
883 // - D
884 // - E
885
886 // Then D gets a new child at 0. In that case we require adding F between D and E.
887
888 // Consider instead that D gets removed. Then @p parent will be B.
889
890
891 Q_Q(const KSelectionProxyModel);
892
893 Q_ASSERT(parent.model() == q->sourceModel());
894
895 int parentPosition = m_rootIndexList.indexOf(parent);
896
897 QModelIndex parentAbove;
898
899 // If parentPosition == 0, then parent.parent() is not also in the model. (ordering is preserved)
900 while (parentPosition > 0) {
901 parentPosition--;
902
903 parentAbove = m_rootIndexList.at(parentPosition);
904 Q_ASSERT(parentAbove.isValid());
905
906 int rows = q->sourceModel()->rowCount(parentAbove);
907 if (rows > 0) {
908 QModelIndex sourceIndexAbove = q->sourceModel()->index(rows - 1, 0, parentAbove);
909 Q_ASSERT(sourceIndexAbove.isValid());
910 QModelIndex proxyChildAbove = mapFromSource(sourceIndexAbove);
911 Q_ASSERT(proxyChildAbove.isValid());
912 return proxyChildAbove.row() + 1;
913 }
914 }
915 return 0;
916}
917
918void KSelectionProxyModelPrivate::updateFirstChildMapping(const QModelIndex& parent, int offset)
919{
920 Q_Q(KSelectionProxyModel);
921
922 Q_ASSERT(parent.isValid() ? parent.model() == q->sourceModel() : true);
923
924 static const int column = 0;
925 static const int row = 0;
926
927 const QPersistentModelIndex srcIndex = q->sourceModel()->index(row, column, parent);
928
929 const QPersistentModelIndex previousFirstChild = q->sourceModel()->index(offset, column, parent);
930
931 SourceIndexProxyRowMapping::left_iterator it = m_mappedFirstChildren.findLeft(previousFirstChild);
932 if (it == m_mappedFirstChildren.leftEnd())
933 return;
934
935 Q_ASSERT(srcIndex.isValid());
936 const int proxyRow = it.value();
937 Q_ASSERT(proxyRow >= 0);
938
939 m_mappedFirstChildren.eraseLeft(it);
940
941 // The proxy row in the mapping has already been updated by the offset in updateInternalTopIndexes
942 // so we restore it by applying the reverse.
943 m_mappedFirstChildren.insert(srcIndex, proxyRow - offset);
944}
945
946QPair< int, int > KSelectionProxyModelPrivate::beginInsertRows(const QModelIndex& parent, int start, int end) const
947{
948 const QModelIndex proxyParent = mapFromSource(parent);
949
950 if (!proxyParent.isValid())
951 {
952 if (!m_startWithChildTrees)
953 return qMakePair(-1, -1);
954
955 if (!m_rootIndexList.contains(parent))
956 return qMakePair(-1, -1);
957 }
958
959 if (!m_startWithChildTrees) {
960 // SubTrees
961 if (proxyParent.isValid())
962 return qMakePair(start, end);
963 return qMakePair(-1, -1);
964 }
965
966 if (!m_includeAllSelected && proxyParent.isValid()) {
967 // SubTreesWithoutRoots deeper than topLevel
968 return qMakePair(start, end);
969 }
970
971 if (!m_rootIndexList.contains(parent))
972 return qMakePair(-1, -1);
973
974 const int proxyStartRow = getProxyInitialRow(parent) + start;
975 return qMakePair(proxyStartRow, proxyStartRow + (end - start));
976}
977
978void KSelectionProxyModelPrivate::sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
979{
980 Q_Q(KSelectionProxyModel);
981
982 Q_ASSERT(parent.isValid() ? parent.model() == q->sourceModel() : true);
983
984 if (!m_selectionModel.data()->hasSelection())
985 return;
986
987 if (m_omitChildren)
988 // ExactSelection and SubTreeRoots
989 return;
990
991 // topLevel insertions can be ignored because topLevel items would need to be selected to affect the proxy.
992 if (!parent.isValid())
993 return;
994
995 QPair<int, int> pair = beginInsertRows(parent, start, end);
996 if (pair.first == -1)
997 return;
998
999 const QModelIndex proxyParent = m_startWithChildTrees ? QModelIndex() : mapFromSource(parent);
1000
1001 m_rowsInserted = true;
1002 q->beginInsertRows(proxyParent, pair.first, pair.second);
1003}
1004
1005void KSelectionProxyModelPrivate::endInsertRows(const QModelIndex& parent, int start, int end)
1006{
1007 Q_Q(const KSelectionProxyModel);
1008 const QModelIndex proxyParent = mapFromSource(parent);
1009 const int offset = end - start + 1;
1010
1011 const bool isNewParent = (q->sourceModel()->rowCount(parent) == offset);
1012
1013 if (m_startWithChildTrees && m_rootIndexList.contains(parent)) {
1014 const int proxyInitialRow = getProxyInitialRow(parent);
1015 Q_ASSERT(proxyInitialRow >= 0);
1016 const int proxyStartRow = proxyInitialRow + start;
1017
1018 updateInternalTopIndexes(proxyStartRow, offset);
1019 if (isNewParent)
1020 createFirstChildMapping(parent, proxyStartRow);
1021 else if (start == 0)
1022 // We already have a first child mapping, but what we have mapped is not the first child anymore
1023 // so we need to update it.
1024 updateFirstChildMapping(parent, end + 1);
1025 } else {
1026 Q_ASSERT(proxyParent.isValid());
1027 if (!isNewParent)
1028 updateInternalIndexes(proxyParent, start, offset);
1029 else
1030 createParentMappings(parent.parent(), parent.row(), parent.row());
1031 }
1032 createParentMappings(parent, start, end);
1033}
1034
1035void KSelectionProxyModelPrivate::sourceRowsInserted(const QModelIndex &parent, int start, int end)
1036{
1037 Q_Q(KSelectionProxyModel);
1038
1039 Q_ASSERT(parent.isValid() ? parent.model() == q->sourceModel() : true);
1040
1041 if (!m_rowsInserted)
1042 return;
1043 m_rowsInserted = false;
1044 endInsertRows(parent, start, end);
1045 q->endInsertRows();
1046 foreach(const PendingSelectionChange &pendingChange, m_pendingSelectionChanges)
1047 {
1048 selectionChanged(pendingChange.selected, pendingChange.deselected);
1049 }
1050 m_pendingSelectionChanges.clear();
1051}
1052
1053QPair<int, int> KSelectionProxyModelPrivate::beginRemoveRows(const QModelIndex& parent, int start, int end) const
1054{
1055 Q_Q(const KSelectionProxyModel);
1056
1057 QPair<int, int> pair = qMakePair(start, end);
1058
1059 if (m_omitChildren && !m_startWithChildTrees && !m_includeAllSelected) {
1060 // SubTreeRoots
1061 if (m_rootIndexList.contains(parent) || isDescendantOf(m_rootIndexList, parent)) {
1062 return qMakePair(-1, -1);
1063 }
1064 }
1065
1066 const QModelIndex proxyParent = mapParentFromSource(parent);
1067
1068 if (!m_includeAllSelected && !m_omitChildren) {
1069 // SubTrees and SubTreesWithoutRoots
1070 if (proxyParent.isValid()) {
1071 return pair;
1072 }
1073 if (m_startWithChildTrees && m_rootIndexList.contains(parent)) {
1074 // SubTreesWithoutRoots topLevel
1075 const int proxyStartRow = getProxyInitialRow(parent) + start;
1076 return qMakePair(proxyStartRow, proxyStartRow + (end - start));
1077 }
1078 }
1079
1080 if (m_includeAllSelected && m_startWithChildTrees) {
1081 // ChildrenOfExactSelection
1082 int position = m_rootIndexList.indexOf(parent);
1083 if (position != -1) {
1084 const int proxyStartRow = getProxyInitialRow(parent) + start;
1085 int proxyEndRow = proxyStartRow + (end - start);
1086 ++position;
1087 while (m_rootIndexList.size() < position) {
1088 const QModelIndex idx = m_rootIndexList.at(position);
1089 if (isDescendantOf(parent, idx))
1090 proxyEndRow += q->sourceModel()->rowCount(idx);
1091 else
1092 break;
1093 }
1094 return qMakePair(proxyStartRow, proxyEndRow);
1095 }
1096 return qMakePair(-1, -1);
1097 }
1098
1099 QList<QPersistentModelIndex>::const_iterator rootIt = m_rootIndexList.constBegin();
1100 const QList<QPersistentModelIndex>::const_iterator rootEnd = m_rootIndexList.constEnd();
1101 int rootPosition = 0;
1102 int rootStartRemove = -1;
1103 int rootEndRemove = -1;
1104 int siblingCount = 0;
1105
1106 for ( ; rootIt != rootEnd; ++rootIt, ++rootPosition) {
1107 if (m_omitChildren && m_includeAllSelected) {
1108 // ExactSelection
1109 if (parent == rootIt->parent() && rootIt->row() <= end && rootIt->row() >= start) {
1110 if (rootStartRemove == -1)
1111 rootStartRemove = rootPosition;
1112 ++rootEndRemove;
1113 } else {
1114 if (rootStartRemove != -1)
1115 break;
1116 }
1117 } else {
1118 if (isDescendantOf(parent, *rootIt)) {
1119 if (rootStartRemove == -1)
1120 rootStartRemove = rootPosition;
1121 ++rootEndRemove;
1122 if (m_startWithChildTrees)
1123 siblingCount += q->sourceModel()->rowCount(*rootIt);
1124 } else {
1125 if (rootStartRemove != -1)
1126 break;
1127 }
1128 }
1129 }
1130 if (rootStartRemove != -1) {
1131 return qMakePair(siblingCount + rootStartRemove, siblingCount + rootEndRemove);
1132 }
1133
1134 return qMakePair(-1, -1);
1135}
1136
1137void KSelectionProxyModelPrivate::sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
1138{
1139 Q_Q(KSelectionProxyModel);
1140
1141 Q_ASSERT(parent.isValid() ? parent.model() == q->sourceModel() : true);
1142
1143 if (!m_selectionModel.data()->hasSelection())
1144 return;
1145
1146 QPair<int, int> pair = beginRemoveRows(parent, start, end);
1147 if (pair.first == -1)
1148 return;
1149
1150 const QModelIndex proxyParent = mapParentFromSource(parent);
1151
1152 m_rowsRemoved = true;
1153 m_proxyRemoveRows = pair;
1154 q->beginRemoveRows(proxyParent, pair.first, pair.second);
1155}
1156
1157void KSelectionProxyModelPrivate::endRemoveRows(const QModelIndex &sourceParent, int proxyStart, int proxyEnd)
1158{
1159 const QModelIndex proxyParent = mapParentFromSource(sourceParent);
1160
1161 // We need to make sure to remove entries from the mappings before updating internal indexes.
1162
1163 // - A
1164 // - - B
1165 // - C
1166 // - - D
1167
1168 // If A and C are selected, B and D are in the proxy. B maps to row 0 and D maps to row 1.
1169 // If B is then deleted leaving only D in the proxy, D needs to be updated to be a mapping
1170 // to row 0 instead of row 1. If that is done before removing the mapping for B, then the mapping
1171 // for D would overwrite the mapping for B and then the code for removing mappings would incorrectly
1172 // remove D.
1173 // So we first remove B and then update D.
1174
1175 {
1176 SourceProxyIndexMapping::right_iterator it = m_mappedParents.rightBegin();
1177
1178 while (it != m_mappedParents.rightEnd()) {
1179 if (!it.value().isValid()) {
1180 m_parentIds.removeRight(it.key());
1181 it = m_mappedParents.eraseRight(it);
1182 } else
1183 ++it;
1184 }
1185 }
1186
1187 {
1188 // Depending on what is selected at the time, a single removal in the source could invalidate
1189 // many mapped first child items at once.
1190
1191 // - A
1192 // - B
1193 // - - C
1194 // - - D
1195 // - - - E
1196 // - - - F
1197 // - - - - G
1198 // - - - - H
1199
1200 // If D and F are selected, the proxy contains E, F, G, H. If B is then deleted E to H will
1201 // be removed, including both first child mappings at E and G.
1202
1203 removeFirstChildMappings(proxyStart, proxyEnd);
1204 }
1205
1206 if (proxyParent.isValid())
1207 updateInternalIndexes(proxyParent, proxyEnd + 1, -1*(proxyEnd - proxyStart + 1));
1208 else
1209 updateInternalTopIndexes(proxyEnd + 1, -1*(proxyEnd - proxyStart + 1));
1210
1211 QList<QPersistentModelIndex>::iterator rootIt = m_rootIndexList.begin();
1212 while (rootIt != m_rootIndexList.end()) {
1213 if (!rootIt->isValid())
1214 rootIt = m_rootIndexList.erase(rootIt);
1215 else
1216 ++rootIt;
1217 }
1218}
1219
1220void KSelectionProxyModelPrivate::sourceRowsRemoved(const QModelIndex &parent, int start, int end)
1221{
1222 Q_Q(KSelectionProxyModel);
1223 Q_UNUSED(end)
1224
1225 Q_ASSERT(parent.isValid() ? parent.model() == q->sourceModel() : true);
1226
1227 if (!m_selectionModel.data()->hasSelection())
1228 return;
1229
1230 if (!m_rowsRemoved)
1231 return;
1232 m_rowsRemoved = false;
1233
1234 Q_ASSERT(m_proxyRemoveRows.first >= 0);
1235 Q_ASSERT(m_proxyRemoveRows.second >= 0);
1236 endRemoveRows(parent, m_proxyRemoveRows.first, m_proxyRemoveRows.second);
1237 if (m_startWithChildTrees && start == 0 && q->sourceModel()->hasChildren(parent))
1238 // The private endRemoveRows call might remove the first child mapping for parent, so
1239 // we create it again in that case.
1240 createFirstChildMapping(parent, m_proxyRemoveRows.first);
1241
1242 m_proxyRemoveRows = qMakePair(-1, -1);
1243 q->endRemoveRows();
1244}
1245
1246void KSelectionProxyModelPrivate::sourceRowsAboutToBeMoved(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destRow)
1247{
1248 Q_UNUSED(srcParent)
1249 Q_UNUSED(srcStart)
1250 Q_UNUSED(srcEnd)
1251 Q_UNUSED(destParent)
1252 Q_UNUSED(destRow)
1253}
1254
1255void KSelectionProxyModelPrivate::sourceRowsMoved(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destRow)
1256{
1257 Q_UNUSED(srcParent)
1258 Q_UNUSED(srcStart)
1259 Q_UNUSED(srcEnd)
1260 Q_UNUSED(destParent)
1261 Q_UNUSED(destRow)
1262}
1263
1264QModelIndex KSelectionProxyModelPrivate::mapParentToSource(const QModelIndex &proxyParent) const
1265{
1266 return m_mappedParents.rightToLeft(proxyParent);
1267}
1268
1269QModelIndex KSelectionProxyModelPrivate::mapParentFromSource(const QModelIndex &sourceParent) const
1270{
1271 return m_mappedParents.leftToRight(sourceParent);
1272}
1273
1274static bool indexIsValid(bool startWithChildTrees, int row, const QList<QPersistentModelIndex> &rootIndexList, const SourceIndexProxyRowMapping &mappedFirstChildren)
1275{
1276 if (!startWithChildTrees) {
1277 Q_ASSERT(rootIndexList.size() > row);
1278 Q_UNUSED(rootIndexList);
1279 } else {
1280
1281 Q_ASSERT(!mappedFirstChildren.isEmpty());
1282
1283 SourceIndexProxyRowMapping::right_const_iterator result = mappedFirstChildren.rightUpperBound(row) - 1;
1284
1285 Q_ASSERT(result != mappedFirstChildren.rightEnd());
1286 const int proxyFirstRow = result.key();
1287 const QModelIndex sourceFirstChild = result.value();
1288 Q_ASSERT(proxyFirstRow >= 0);
1289 Q_ASSERT(sourceFirstChild.isValid());
1290 Q_ASSERT(sourceFirstChild.parent().isValid());
1291 Q_ASSERT(row <= proxyFirstRow + sourceFirstChild.model()->rowCount(sourceFirstChild.parent()));
1292 }
1293 return true;
1294}
1295
1296QModelIndex KSelectionProxyModelPrivate::createTopLevelIndex(int row, int column) const
1297{
1298 Q_Q(const KSelectionProxyModel);
1299
1300 Q_ASSERT(indexIsValid(m_startWithChildTrees, row, m_rootIndexList, m_mappedFirstChildren));
1301 return q->createIndex(row, column);
1302}
1303
1304
1305QModelIndex KSelectionProxyModelPrivate::mapTopLevelFromSource(const QModelIndex &sourceIndex) const
1306{
1307 Q_Q(const KSelectionProxyModel);
1308
1309 const QModelIndex sourceParent = sourceIndex.parent();
1310 const int row = m_rootIndexList.indexOf(sourceIndex);
1311 if (row == -1)
1312 return QModelIndex();
1313
1314 if (!m_startWithChildTrees) {
1315 Q_ASSERT(m_rootIndexList.size() > row);
1316 return q->createIndex(row, sourceIndex.column());
1317 }
1318 if (!m_rootIndexList.contains(sourceParent))
1319 return QModelIndex();
1320
1321 const QModelIndex firstChild = q->sourceModel()->index(0, 0, sourceParent);
1322 const int firstProxyRow = m_mappedFirstChildren.leftToRight(firstChild);
1323
1324 return q->createIndex(firstProxyRow + sourceIndex.row(), sourceIndex.column());
1325}
1326
1327QModelIndex KSelectionProxyModelPrivate::mapFromSource(const QModelIndex &sourceIndex) const
1328{
1329 Q_Q(const KSelectionProxyModel);
1330
1331 const QModelIndex maybeMapped = mapParentFromSource(sourceIndex);
1332 if (maybeMapped.isValid()) {
1333// Q_ASSERT((!d->m_startWithChildTrees && d->m_rootIndexList.contains(maybeMapped)) ? maybeMapped.row() < 0 : true );
1334 return maybeMapped;
1335 }
1336 const QModelIndex sourceParent = sourceIndex.parent();
1337
1338 const QModelIndex proxyParent = mapParentFromSource(sourceParent);
1339 if (proxyParent.isValid()) {
1340 void * const parentId = m_parentIds.rightToLeft(proxyParent);
1341 static const int column = 0;
1342 return q->createIndex(sourceIndex.row(), column, parentId);
1343 }
1344
1345 const QModelIndex firstChild = q->sourceModel()->index(0, 0, sourceParent);
1346
1347 if (m_mappedFirstChildren.leftContains(firstChild))
1348 {
1349 const int firstProxyRow = m_mappedFirstChildren.leftToRight(firstChild);
1350 return q->createIndex(firstProxyRow + sourceIndex.row(), sourceIndex.column());
1351 }
1352 return mapTopLevelFromSource(sourceIndex);
1353}
1354
1355int KSelectionProxyModelPrivate::topLevelRowCount() const
1356{
1357 Q_Q(const KSelectionProxyModel);
1358
1359 if (!m_startWithChildTrees)
1360 return m_rootIndexList.size();
1361
1362 if (m_mappedFirstChildren.isEmpty())
1363 return 0;
1364
1365 const SourceIndexProxyRowMapping::right_const_iterator result = m_mappedFirstChildren.rightConstEnd() - 1;
1366
1367 const int proxyFirstRow = result.key();
1368 const QModelIndex sourceFirstChild = result.value();
1369 Q_ASSERT(sourceFirstChild.isValid());
1370 const QModelIndex sourceParent = sourceFirstChild.parent();
1371 Q_ASSERT(sourceParent.isValid());
1372 return q->sourceModel()->rowCount(sourceParent) + proxyFirstRow;
1373}
1374
1375bool KSelectionProxyModelPrivate::ensureMappable(const QModelIndex &parent) const
1376{
1377 Q_Q(const KSelectionProxyModel);
1378
1379 if (isFlat())
1380 return true;
1381
1382 if (parentIsMappable(parent))
1383 return true;
1384
1385 QModelIndex ancestor = parent.parent();
1386 QModelIndexList ancestorList;
1387 while (ancestor.isValid())
1388 {
1389 if (parentIsMappable(ancestor))
1390 break;
1391 else
1392 ancestorList.prepend(ancestor);
1393
1394 ancestor = ancestor.parent();
1395 }
1396
1397 if (!ancestor.isValid())
1398 // @p parent is not a descendant of m_rootIndexList.
1399 return false;
1400
1401 // sourceIndex can be mapped to the proxy. We just need to create mappings for its ancestors first.
1402 for(int i = 0; i < ancestorList.size(); ++i)
1403 {
1404 const QModelIndex existingAncestor = mapParentFromSource(ancestor);
1405 Q_ASSERT(existingAncestor.isValid());
1406
1407 void * const ansId = m_parentIds.rightToLeft(existingAncestor);
1408 const QModelIndex newSourceParent = ancestorList.at(i);
1409 const QModelIndex newProxyParent = q->createIndex(newSourceParent.row(), newSourceParent.column(), ansId);
1410
1411 void * const newId = m_voidPointerFactory.createPointer();
1412 m_parentIds.insert(newId, newProxyParent);
1413 m_mappedParents.insert(QPersistentModelIndex(newSourceParent), newProxyParent);
1414 ancestor = newSourceParent;
1415 }
1416 return true;
1417}
1418
1419void KSelectionProxyModelPrivate::updateInternalTopIndexes(int start, int offset)
1420{
1421 updateInternalIndexes(QModelIndex(), start, offset);
1422
1423 QHash<QPersistentModelIndex, int> updates;
1424 {
1425 SourceIndexProxyRowMapping::right_iterator it = m_mappedFirstChildren.rightLowerBound(start);
1426 const SourceIndexProxyRowMapping::right_iterator end = m_mappedFirstChildren.rightEnd();
1427
1428 for ( ; it != end; ++it)
1429 {
1430 updates.insert(*it, it.key() + offset);
1431 }
1432 }
1433 {
1434 QHash<QPersistentModelIndex, int>::const_iterator it = updates.constBegin();
1435 const QHash<QPersistentModelIndex, int>::const_iterator end = updates.constEnd();
1436
1437 for ( ; it != end; ++it)
1438 {
1439 m_mappedFirstChildren.insert(it.key(), it.value());
1440 }
1441 }
1442}
1443
1444void KSelectionProxyModelPrivate::updateInternalIndexes(const QModelIndex &parent, int start, int offset)
1445{
1446 Q_Q(KSelectionProxyModel);
1447
1448 Q_ASSERT(start + offset >= 0);
1449 Q_ASSERT(parent.isValid() ? parent.model() == q : true);
1450
1451 if (isFlat())
1452 return;
1453
1454 SourceProxyIndexMapping::left_iterator mappedParentIt = m_mappedParents.leftBegin();
1455
1456 QHash<void*, QModelIndex> updatedParentIds;
1457 QHash<QPersistentModelIndex, QModelIndex> updatedParents;
1458
1459 for ( ; mappedParentIt != m_mappedParents.leftEnd(); ++mappedParentIt) {
1460 const QModelIndex proxyIndex = mappedParentIt.value();
1461 Q_ASSERT(proxyIndex.isValid());
1462
1463 if (proxyIndex.row() < start)
1464 continue;
1465
1466 const QModelIndex proxyParent = proxyIndex.parent();
1467
1468 if (parent.isValid()) {
1469 if (proxyParent != parent)
1470 continue;
1471 } else {
1472 if (proxyParent.isValid())
1473 continue;
1474 }
1475 Q_ASSERT(m_parentIds.rightContains(proxyIndex));
1476 void * const key = m_parentIds.rightToLeft(proxyIndex);
1477
1478 const QModelIndex newIndex = q->createIndex(proxyIndex.row() + offset, proxyIndex.column(), proxyIndex.internalPointer());
1479
1480 Q_ASSERT(newIndex.isValid());
1481
1482 updatedParentIds.insert(key, newIndex);
1483 updatedParents.insert(mappedParentIt.key(), newIndex);
1484 }
1485
1486 {
1487 QHash<QPersistentModelIndex, QModelIndex>::const_iterator it = updatedParents.constBegin();
1488 const QHash<QPersistentModelIndex, QModelIndex>::const_iterator end = updatedParents.constEnd();
1489 for ( ; it != end; ++it)
1490 m_mappedParents.insert(it.key(), it.value());
1491 }
1492
1493 {
1494 QHash<void*, QModelIndex>::const_iterator it = updatedParentIds.constBegin();
1495 const QHash<void*, QModelIndex>::const_iterator end = updatedParentIds.constEnd();
1496 for ( ; it != end; ++it)
1497 m_parentIds.insert(it.key(), it.value());
1498 }
1499}
1500
1501bool KSelectionProxyModelPrivate::parentAlreadyMapped(const QModelIndex &parent) const
1502{
1503 Q_Q(const KSelectionProxyModel);
1504 Q_ASSERT(parent.model() == q->sourceModel());
1505 return m_mappedParents.leftContains(parent);
1506}
1507
1508bool KSelectionProxyModelPrivate::firstChildAlreadyMapped(const QModelIndex &firstChild) const
1509{
1510 Q_Q(const KSelectionProxyModel);
1511 Q_ASSERT(firstChild.model() == q->sourceModel());
1512 return m_mappedFirstChildren.leftContains(firstChild);
1513}
1514
1515void KSelectionProxyModelPrivate::createFirstChildMapping(const QModelIndex& parent, int proxyRow) const
1516{
1517 Q_Q(const KSelectionProxyModel);
1518
1519 Q_ASSERT(parent.isValid() ? parent.model() == q->sourceModel() : true);
1520
1521 static const int column = 0;
1522 static const int row = 0;
1523
1524 const QPersistentModelIndex srcIndex = q->sourceModel()->index(row, column, parent);
1525
1526 if (firstChildAlreadyMapped(srcIndex))
1527 return;
1528
1529 Q_ASSERT(srcIndex.isValid());
1530 m_mappedFirstChildren.insert(srcIndex, proxyRow);
1531}
1532
1533void KSelectionProxyModelPrivate::createParentMappings(const QModelIndex &parent, int start, int end) const
1534{
1535 if (isFlat())
1536 return;
1537
1538 Q_Q(const KSelectionProxyModel);
1539
1540 Q_ASSERT(parent.isValid() ? parent.model() == q->sourceModel() : true);
1541
1542 static const int column = 0;
1543
1544 for (int row = start; row <= end; ++row) {
1545 const QModelIndex srcIndex = q->sourceModel()->index(row, column, parent);
1546 Q_ASSERT(srcIndex.isValid());
1547 if (!q->sourceModel()->hasChildren(srcIndex) || parentAlreadyMapped(srcIndex))
1548 continue;
1549
1550 const QModelIndex proxyIndex = mapFromSource(srcIndex);
1551 if (!proxyIndex.isValid())
1552 return; // If one of them is not mapped, its siblings won't be either
1553
1554 void * const newId = m_voidPointerFactory.createPointer();
1555 m_parentIds.insert(newId, proxyIndex);
1556 Q_ASSERT(srcIndex.isValid());
1557 m_mappedParents.insert(QPersistentModelIndex(srcIndex), proxyIndex);
1558 }
1559}
1560
1561void KSelectionProxyModelPrivate::removeFirstChildMappings(int start, int end)
1562{
1563 SourceIndexProxyRowMapping::right_iterator it = m_mappedFirstChildren.rightLowerBound(start);
1564 const SourceIndexProxyRowMapping::right_iterator endIt = m_mappedFirstChildren.rightUpperBound(end);
1565 while (it != endIt)
1566 it = m_mappedFirstChildren.eraseRight(it);
1567}
1568
1569void KSelectionProxyModelPrivate::removeParentMappings(const QModelIndex &parent, int start, int end)
1570{
1571 Q_Q(KSelectionProxyModel);
1572
1573 Q_ASSERT(parent.isValid() ? parent.model() == q : true);
1574
1575 SourceProxyIndexMapping::right_iterator it = m_mappedParents.rightBegin();
1576 SourceProxyIndexMapping::right_iterator endIt = m_mappedParents.rightEnd();
1577
1578 typedef QPair<QModelIndex, QPersistentModelIndex> Pair;
1579
1580 QList<Pair> pairs;
1581
1582 QModelIndexList list;
1583
1584 const bool flatList = isFlat();
1585
1586 while (it != endIt) {
1587 if (it.key().row() >= start && it.key().row() <= end)
1588 {
1589 const QModelIndex sourceParent = it.value();
1590 const QModelIndex proxyGrandParent = mapParentFromSource(sourceParent.parent());
1591 if (proxyGrandParent == parent)
1592 {
1593 if (!flatList)
1594 // Due to recursive calls, we could have several iterators on the container
1595 // when erase is called. That's safe accoring to the QHash::iterator docs though.
1596 removeParentMappings(it.key(), 0, q->sourceModel()->rowCount(it.value()) - 1);
1597
1598 m_parentIds.removeRight(it.key());
1599 it = m_mappedParents.eraseRight(it);
1600 } else
1601 ++it;
1602 } else
1603 ++it;
1604 }
1605}
1606
1607QModelIndex KSelectionProxyModelPrivate::mapTopLevelToSource(int row, int column) const
1608{
1609 if (!m_startWithChildTrees)
1610 {
1611 const QModelIndex idx = m_rootIndexList.at(row);
1612 return idx.sibling(idx.row(), column);
1613 }
1614
1615 if (m_mappedFirstChildren.isEmpty())
1616 return QModelIndex();
1617
1618 SourceIndexProxyRowMapping::right_iterator result = m_mappedFirstChildren.rightUpperBound(row) - 1;
1619
1620 Q_ASSERT(result != m_mappedFirstChildren.rightEnd());
1621
1622 const int proxyFirstRow = result.key();
1623 const QModelIndex sourceFirstChild = result.value();
1624 Q_ASSERT(sourceFirstChild.isValid());
1625 return sourceFirstChild.sibling(row - proxyFirstRow, column);
1626}
1627
1628void KSelectionProxyModelPrivate::removeSelectionFromProxy(const QItemSelection &selection)
1629{
1630 Q_Q(KSelectionProxyModel);
1631 if (selection.isEmpty())
1632 return;
1633
1634 q->rootSelectionAboutToBeRemoved(selection);
1635
1636 foreach(const QItemSelectionRange range, selection)
1637 removeRangeFromProxy(range);
1638}
1639
1640void KSelectionProxyModelPrivate::removeRangeFromProxy(const QItemSelectionRange &range)
1641{
1642 Q_Q(KSelectionProxyModel);
1643
1644 Q_ASSERT(range.model() == q->sourceModel());
1645
1646 const QModelIndex sourceTopLeft = range.topLeft();
1647 const QModelIndex proxyTopLeft = mapFromSource(sourceTopLeft);
1648 const QModelIndex sourceBottomLeft = range.bottomRight().sibling(range.bottom(), 0);
1649 const QModelIndex proxyBottomLeft = mapFromSource(sourceBottomLeft);
1650 const QModelIndex proxyParent = proxyTopLeft.parent();
1651 const QModelIndex sourceParent = sourceTopLeft.parent();
1652
1653 if (m_startWithChildTrees) {
1654 Q_ASSERT(sourceTopLeft.isValid());
1655 Q_ASSERT(sourceBottomLeft.isValid());
1656 const int startRootIdx = m_rootIndexList.indexOf(sourceTopLeft);
1657 int endRootIdx = m_rootIndexList.indexOf(sourceBottomLeft);
1658 QItemSelection extraRanges;
1659 if (m_includeAllSelected) {
1660 // It can happen that indexes of descendants get in between indexes which make up a range.
1661 // We handle only the first contiguous block here and handle the rest later.
1662 int idx = startRootIdx;
1663 const int bottomIdx = endRootIdx;
1664 const int rootListSize = m_rootIndexList.size();
1665 int next = idx + 1;
1666 while (next <= bottomIdx)
1667 {
1668 if (next < rootListSize && m_rootIndexList.at(next).parent() == sourceParent) {
1669 idx = next;
1670 ++next;
1671 } else
1672 break;
1673 }
1674 endRootIdx = idx;
1675 ++idx;
1676 while (idx <= bottomIdx)
1677 {
1678 const QModelIndex index= m_rootIndexList.at(idx);
1679 if (m_rootIndexList.at(idx).parent() == sourceParent)
1680 extraRanges << QItemSelectionRange(index, index);
1681 ++idx;
1682 }
1683 }
1684 Q_ASSERT(endRootIdx != -1);
1685 int childrenCount = q->sourceModel()->rowCount(sourceTopLeft);
1686 for (int rootIdx = startRootIdx + 1; rootIdx <= endRootIdx; ++rootIdx)
1687 {
1688 childrenCount += q->sourceModel()->rowCount(m_rootIndexList.at(rootIdx));
1689 }
1690 if (childrenCount == 0)
1691 {
1692 for (int rootIdx = startRootIdx; rootIdx <= endRootIdx; --endRootIdx)
1693 {
1694 const QModelIndex idx = m_rootIndexList.at(rootIdx);
1695 q->rootIndexAboutToBeRemoved(idx);
1696 m_rootIndexList.removeOne(idx);
1697 }
1698 return;
1699 }
1700 if (!m_includeAllSelected)
1701 {
1702 ++endRootIdx;
1703 for ( ; endRootIdx < m_rootIndexList.size(); ++endRootIdx) {
1704 const QModelIndex idx = m_rootIndexList.at(endRootIdx);
1705 if (isDescendantOf(sourceBottomLeft, idx))
1706 childrenCount += q->sourceModel()->rowCount(idx);
1707 else
1708 break;
1709 }
1710 --endRootIdx;
1711 }
1712 const int proxyStart = getTargetRow(startRootIdx);
1713 int proxyEnd = proxyStart + childrenCount - 1;
1714 q->beginRemoveRows(QModelIndex(), proxyStart, proxyEnd);
1715
1716 for (int rootIdx = startRootIdx; rootIdx <= endRootIdx; ++rootIdx)
1717 {
1718 q->rootIndexAboutToBeRemoved(m_rootIndexList.at(rootIdx));
1719 }
1720
1721 removeParentMappings(QModelIndex(), proxyStart, proxyEnd);
1722 removeFirstChildMappings(proxyStart, proxyEnd);
1723 int numRemovedChildren = 0;
1724 for (int rootIdx = startRootIdx; rootIdx <= endRootIdx; --endRootIdx)
1725 {
1726 const QModelIndex idx = m_rootIndexList.at(rootIdx);
1727 const int childCount = q->sourceModel()->rowCount(idx);
1728 m_rootIndexList.removeAt(rootIdx);
1729 numRemovedChildren += childCount;
1730 }
1731 updateInternalTopIndexes(proxyEnd + 1, -1 * numRemovedChildren);
1732 q->endRemoveRows();
1733 if (m_includeAllSelected) {
1734 removeSelectionFromProxy(kNormalizeSelection(extraRanges));
1735 }
1736 } else {
1737 if (!proxyTopLeft.isValid())
1738 return;
1739 const int height = range.height();
1740 q->beginRemoveRows(proxyParent, proxyTopLeft.row(), proxyTopLeft.row() + height - 1);
1741
1742 // TODO: Do this conditionally if the signal is connected to anything.
1743 for (int i = 0; i < height; ++i)
1744 {
1745 const QModelIndex idx = sourceTopLeft.sibling(range.top() + i, sourceTopLeft.column());
1746 q->rootIndexAboutToBeRemoved(idx);
1747 }
1748
1749 removeParentMappings(proxyParent, proxyTopLeft.row(), proxyTopLeft.row() + height - 1);
1750 updateInternalIndexes(proxyParent, proxyTopLeft.row() + height, -1 * height);
1751
1752 for (int i = 0; i < height; ++i)
1753 {
1754 const QModelIndex idx = sourceTopLeft.sibling(range.top() + i, sourceTopLeft.column());
1755 Q_ASSERT(idx.isValid());
1756 const bool b = m_rootIndexList.removeOne(idx);
1757 Q_UNUSED(b)
1758 if (!b)
1759 kDebug() << idx;
1760 Q_ASSERT(b);
1761 }
1762
1763 q->endRemoveRows();
1764 }
1765}
1766
1767void KSelectionProxyModelPrivate::selectionChanged(const QItemSelection &_selected, const QItemSelection &_deselected)
1768{
1769 Q_Q(KSelectionProxyModel);
1770
1771 if (!q->sourceModel() || (_selected.isEmpty() && _deselected.isEmpty()))
1772 return;
1773
1774 if (m_rowsInserted || m_rowsRemoved) {
1775 m_pendingSelectionChanges.append(PendingSelectionChange(_selected, _deselected));
1776 return;
1777 }
1778
1779 // Any deselected indexes in the m_rootIndexList are removed. Then, any
1780 // indexes in the selected range which are not a descendant of one of the already selected indexes
1781 // are inserted into the model.
1782 //
1783 // All ranges from the selection model need to be split into individual rows. Ranges which are contiguous in
1784 // the selection model may not be contiguous in the source model if there's a sort filter proxy model in the chain.
1785 //
1786 // Some descendants of deselected indexes may still be selected. The ranges in m_selectionModel.data()->selection()
1787 // are examined. If any of the ranges are descendants of one of the
1788 // indexes in deselected, they are added to the ranges to be inserted into the model.
1789 //
1790 // The new indexes are inserted in sorted order.
1791
1792 const QItemSelection selected = kNormalizeSelection(m_indexMapper->mapSelectionRightToLeft(_selected));
1793 const QItemSelection deselected = kNormalizeSelection(m_indexMapper->mapSelectionRightToLeft(_deselected));
1794
1795#if QT_VERSION < 0x040800
1796 // The QItemSelectionModel sometimes doesn't remove deselected items from its selection
1797 // Fixed in Qt 4.8 : http://qt.gitorious.org/qt/qt/merge_requests/2403
1798 QItemSelection reportedSelection = m_selectionModel.data()->selection();
1799 reportedSelection.merge(deselected, QItemSelectionModel::Deselect);
1800 QItemSelection fullSelection = m_indexMapper->mapSelectionRightToLeft(reportedSelection);
1801#else
1802 QItemSelection fullSelection = m_indexMapper->mapSelectionRightToLeft(m_selectionModel.data()->selection());
1803#endif
1804
1805 fullSelection = kNormalizeSelection(fullSelection);
1806
1807 QItemSelection newRootRanges;
1808 QItemSelection removedRootRanges;
1809 if (!m_includeAllSelected) {
1810 newRootRanges = getRootRanges(selected);
1811
1812 QItemSelection existingSelection = fullSelection;
1813 // What was selected before the selection was made.
1814 existingSelection.merge(selected, QItemSelectionModel::Deselect);
1815
1816 // This is similar to m_rootRanges, but that m_rootRanges at this point still contains the roots
1817 // of deselected and existingRootRanges does not.
1818
1819 const QItemSelection existingRootRanges = getRootRanges(existingSelection);
1820 {
1821 QMutableListIterator<QItemSelectionRange> i(newRootRanges);
1822 while (i.hasNext()) {
1823 const QItemSelectionRange range = i.next();
1824 const QModelIndex topLeft = range.topLeft();
1825 if (isDescendantOf(existingRootRanges, topLeft)) {
1826 i.remove();
1827 }
1828 }
1829 }
1830
1831 QItemSelection exposedSelection;
1832 {
1833 QItemSelection deselectedRootRanges = getRootRanges(deselected);
1834 QListIterator<QItemSelectionRange> i(deselectedRootRanges);
1835 while (i.hasNext()) {
1836 const QItemSelectionRange range = i.next();
1837 const QModelIndex topLeft = range.topLeft();
1838 // Consider this:
1839 //
1840 // - A
1841 // - - B
1842 // - - - C
1843 // - - - - D
1844 //
1845 // B and D were selected, then B was deselected and C was selected in one go.
1846 if (!isDescendantOf(existingRootRanges, topLeft)) {
1847 // B is topLeft and fullSelection contains D.
1848 // B is not a descendant of D.
1849
1850 // range is not a descendant of the selection, but maybe the selection is a descendant of range.
1851 // no need to check selected here. That's already in newRootRanges.
1852 // existingRootRanges and newRootRanges do not overlap.
1853 foreach (const QItemSelectionRange &selectedRange, existingRootRanges) {
1854 const QModelIndex selectedRangeTopLeft = selectedRange.topLeft();
1855 // existingSelection (and selectedRangeTopLeft) is D.
1856 // D is a descendant of B, so when B was removed, D might have been exposed as a root.
1857 if (isDescendantOf(range, selectedRangeTopLeft)
1858 // But D is also a descendant of part of the new selection C, which is already set to be a new root
1859 // so D would not be added to exposedSelection because C is in newRootRanges.
1860 && !isDescendantOf(newRootRanges, selectedRangeTopLeft))
1861 exposedSelection.append(selectedRange);
1862 }
1863 removedRootRanges << range;
1864 }
1865 }
1866 }
1867
1868 QItemSelection obscuredRanges;
1869 {
1870 QListIterator<QItemSelectionRange> i(existingRootRanges);
1871 while (i.hasNext()) {
1872 const QItemSelectionRange range = i.next();
1873 if (isDescendantOf(newRootRanges, range.topLeft()))
1874 obscuredRanges << range;
1875 }
1876 }
1877 removedRootRanges << getRootRanges(obscuredRanges);
1878 newRootRanges << getRootRanges(exposedSelection);
1879
1880 removedRootRanges = kNormalizeSelection(removedRootRanges);
1881 newRootRanges = kNormalizeSelection(newRootRanges);
1882 } else {
1883 removedRootRanges = deselected;
1884 newRootRanges = selected;
1885 }
1886
1887 removeSelectionFromProxy(removedRootRanges);
1888
1889 if (!m_selectionModel.data()->hasSelection())
1890 {
1891 Q_ASSERT(m_rootIndexList.isEmpty());
1892 Q_ASSERT(m_mappedFirstChildren.isEmpty());
1893 Q_ASSERT(m_mappedParents.isEmpty());
1894 Q_ASSERT(m_parentIds.isEmpty());
1895 }
1896
1897 insertSelectionIntoProxy(newRootRanges);
1898}
1899
1900int KSelectionProxyModelPrivate::getTargetRow(int rootListRow)
1901{
1902 Q_Q(KSelectionProxyModel);
1903 if (!m_startWithChildTrees)
1904 return rootListRow;
1905
1906 --rootListRow;
1907 while (rootListRow >= 0) {
1908 const QModelIndex idx = m_rootIndexList.at(rootListRow);
1909 Q_ASSERT(idx.isValid());
1910 const int rowCount = q->sourceModel()->rowCount(idx);
1911 if (rowCount > 0) {
1912 static const int column = 0;
1913 const QModelIndex srcIdx = q->sourceModel()->index(rowCount - 1, column, idx);
1914 const QModelIndex proxyLastChild = mapFromSource(srcIdx);
1915 return proxyLastChild.row() + 1;
1916 }
1917 --rootListRow;
1918 }
1919 return 0;
1920}
1921
1922void KSelectionProxyModelPrivate::insertSelectionIntoProxy(const QItemSelection &selection)
1923{
1924 Q_Q(KSelectionProxyModel);
1925
1926 if (selection.isEmpty())
1927 return;
1928
1929 foreach(const QModelIndex &newIndex, selection.indexes()) {
1930 Q_ASSERT(newIndex.model() == q->sourceModel());
1931 if (newIndex.column() > 0)
1932 continue;
1933 if (m_startWithChildTrees) {
1934 const int rootListRow = getRootListRow(m_rootIndexList, newIndex);
1935 Q_ASSERT(q->sourceModel() == newIndex.model());
1936 const int rowCount = q->sourceModel()->rowCount(newIndex);
1937 const int startRow = getTargetRow(rootListRow);
1938
1939 if (rowCount == 0) {
1940 // Even if the newindex doesn't have any children to put into the model yet,
1941 // We still need to make sure it's future children are inserted into the model.
1942 m_rootIndexList.insert(rootListRow, newIndex);
1943 if (!m_resetting || m_layoutChanging)
1944 emit q->rootIndexAdded(newIndex);
1945 continue;
1946 }
1947 if (!m_resetting)
1948 q->beginInsertRows(QModelIndex(), startRow, startRow + rowCount - 1);
1949 Q_ASSERT(newIndex.isValid());
1950 m_rootIndexList.insert(rootListRow, newIndex);
1951 if (!m_resetting || m_layoutChanging)
1952 emit q->rootIndexAdded(newIndex);
1953
1954 int _start = 0;
1955 for (int i = 0; i < rootListRow; ++i)
1956 _start += q->sourceModel()->rowCount(m_rootIndexList.at(i));
1957
1958 updateInternalTopIndexes(_start, rowCount);
1959 createFirstChildMapping(newIndex, _start);
1960 createParentMappings(newIndex, 0, rowCount - 1);
1961
1962 if (!m_resetting) {
1963 q->endInsertRows();
1964 }
1965
1966 } else {
1967 const int row = getRootListRow(m_rootIndexList, newIndex);
1968 if (!m_resetting)
1969 q->beginInsertRows(QModelIndex(), row, row);
1970
1971 Q_ASSERT(newIndex.isValid());
1972 m_rootIndexList.insert(row, newIndex);
1973
1974 if (!m_resetting || m_layoutChanging)
1975 emit q->rootIndexAdded(newIndex);
1976 Q_ASSERT(m_rootIndexList.size() > row);
1977 updateInternalIndexes(QModelIndex(), row, 1);
1978 createParentMappings(newIndex.parent(), newIndex.row(), newIndex.row());
1979
1980 if (!m_resetting) {
1981 q->endInsertRows();
1982 }
1983 }
1984 }
1985 q->rootSelectionAdded(selection);
1986}
1987
1988KSelectionProxyModel::KSelectionProxyModel(QItemSelectionModel *selectionModel, QObject *parent)
1989 : QAbstractProxyModel(parent), d_ptr(new KSelectionProxyModelPrivate(this, selectionModel))
1990{
1991}
1992
1993KSelectionProxyModel::~KSelectionProxyModel()
1994{
1995 delete d_ptr;
1996}
1997
1998void KSelectionProxyModel::setFilterBehavior(FilterBehavior behavior)
1999{
2000 Q_D(KSelectionProxyModel);
2001
2002 beginResetModel();
2003
2004 d->m_filterBehavior = behavior;
2005
2006 switch (behavior) {
2007 case SubTrees: {
2008 d->m_omitChildren = false;
2009 d->m_omitDescendants = false;
2010 d->m_startWithChildTrees = false;
2011 d->m_includeAllSelected = false;
2012 break;
2013 }
2014 case SubTreeRoots: {
2015 d->m_omitChildren = true;
2016 d->m_startWithChildTrees = false;
2017 d->m_includeAllSelected = false;
2018 break;
2019 }
2020 case SubTreesWithoutRoots: {
2021 d->m_omitChildren = false;
2022 d->m_omitDescendants = false;
2023 d->m_startWithChildTrees = true;
2024 d->m_includeAllSelected = false;
2025 break;
2026 }
2027 case ExactSelection: {
2028 d->m_omitChildren = true;
2029 d->m_startWithChildTrees = false;
2030 d->m_includeAllSelected = true;
2031 break;
2032 }
2033 case ChildrenOfExactSelection: {
2034 d->m_omitChildren = false;
2035 d->m_omitDescendants = true;
2036 d->m_startWithChildTrees = true;
2037 d->m_includeAllSelected = true;
2038 break;
2039 }
2040 }
2041 d->resetInternalData();
2042 d->selectionChanged(d->m_selectionModel.data()->selection(), QItemSelection());
2043
2044 endResetModel();
2045}
2046
2047KSelectionProxyModel::FilterBehavior KSelectionProxyModel::filterBehavior() const
2048{
2049 Q_D(const KSelectionProxyModel);
2050 return d->m_filterBehavior;
2051}
2052
2053void KSelectionProxyModel::setSourceModel(QAbstractItemModel *_sourceModel)
2054{
2055 Q_D(KSelectionProxyModel);
2056
2057 Q_ASSERT(_sourceModel != this);
2058
2059 if (_sourceModel == sourceModel())
2060 return;
2061
2062 disconnect(d->m_selectionModel.data()->model(), SIGNAL(modelAboutToBeReset()), this, SLOT(sourceModelAboutToBeReset()));
2063 connect(d->m_selectionModel.data()->model(), SIGNAL(modelAboutToBeReset()), this, SLOT(sourceModelAboutToBeReset()));
2064 disconnect(d->m_selectionModel.data()->model(), SIGNAL(modelReset()), this, SLOT(sourceModelReset()));
2065 connect(d->m_selectionModel.data()->model(), SIGNAL(modelReset()), this, SLOT(sourceModelReset()));
2066
2067 disconnect(d->m_selectionModel.data(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
2068 this, SLOT(selectionChanged(QItemSelection,QItemSelection)));
2069 connect(d->m_selectionModel.data(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
2070 SLOT(selectionChanged(QItemSelection,QItemSelection)));
2071
2072 beginResetModel();
2073 d->m_resetting = true;
2074
2075 if (_sourceModel) {
2076 disconnect(_sourceModel, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
2077 this, SLOT(sourceRowsAboutToBeInserted(QModelIndex,int,int)));
2078 disconnect(_sourceModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
2079 this, SLOT(sourceRowsInserted(QModelIndex,int,int)));
2080 disconnect(_sourceModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
2081 this, SLOT(sourceRowsAboutToBeRemoved(QModelIndex,int,int)));
2082 disconnect(_sourceModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
2083 this, SLOT(sourceRowsRemoved(QModelIndex,int,int)));
2084// disconnect(_sourceModel, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
2085// this, SLOT(sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
2086// disconnect(_sourceModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
2087// this, SLOT(sourceRowsMoved(QModelIndex,int,int,QModelIndex,int)));
2088 disconnect(_sourceModel, SIGNAL(modelAboutToBeReset()),
2089 this, SLOT(sourceModelAboutToBeReset()));
2090 disconnect(_sourceModel, SIGNAL(modelReset()),
2091 this, SLOT(sourceModelReset()));
2092 disconnect(_sourceModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
2093 this, SLOT(sourceDataChanged(QModelIndex,QModelIndex)));
2094 disconnect(_sourceModel, SIGNAL(layoutAboutToBeChanged()),
2095 this, SLOT(sourceLayoutAboutToBeChanged()));
2096 disconnect(_sourceModel, SIGNAL(layoutChanged()),
2097 this, SLOT(sourceLayoutChanged()));
2098 disconnect(_sourceModel, SIGNAL(destroyed()),
2099 this, SLOT(sourceModelDestroyed()));
2100 }
2101
2102 // Must be called before QAbstractProxyModel::setSourceModel because it emits some signals.
2103 d->resetInternalData();
2104 QAbstractProxyModel::setSourceModel(_sourceModel);
2105 if (_sourceModel) {
2106 d->m_indexMapper = new KModelIndexProxyMapper(_sourceModel, d->m_selectionModel.data()->model(), this);
2107 if (d->m_selectionModel.data()->hasSelection())
2108 d->selectionChanged(d->m_selectionModel.data()->selection(), QItemSelection());
2109
2110 connect(_sourceModel, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
2111 SLOT(sourceRowsAboutToBeInserted(QModelIndex,int,int)));
2112 connect(_sourceModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
2113 SLOT(sourceRowsInserted(QModelIndex,int,int)));
2114 connect(_sourceModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
2115 SLOT(sourceRowsAboutToBeRemoved(QModelIndex,int,int)));
2116 connect(_sourceModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
2117 SLOT(sourceRowsRemoved(QModelIndex,int,int)));
2118// connect(_sourceModel, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
2119// SLOT(sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
2120// connect(_sourceModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
2121// SLOT(sourceRowsMoved(QModelIndex,int,int,QModelIndex,int)));
2122 connect(_sourceModel, SIGNAL(modelAboutToBeReset()),
2123 SLOT(sourceModelAboutToBeReset()));
2124 connect(_sourceModel, SIGNAL(modelReset()),
2125 SLOT(sourceModelReset()));
2126 connect(_sourceModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
2127 SLOT(sourceDataChanged(QModelIndex,QModelIndex)));
2128 connect(_sourceModel, SIGNAL(layoutAboutToBeChanged()),
2129 SLOT(sourceLayoutAboutToBeChanged()));
2130 connect(_sourceModel, SIGNAL(layoutChanged()),
2131 SLOT(sourceLayoutChanged()));
2132 connect(_sourceModel, SIGNAL(destroyed()),
2133 SLOT(sourceModelDestroyed()));
2134 }
2135
2136 d->m_resetting = false;
2137 endResetModel();
2138}
2139
2140QModelIndex KSelectionProxyModel::mapToSource(const QModelIndex &proxyIndex) const
2141{
2142 Q_D(const KSelectionProxyModel);
2143
2144 if (!proxyIndex.isValid() || !sourceModel() || d->m_rootIndexList.isEmpty())
2145 return QModelIndex();
2146
2147 Q_ASSERT(proxyIndex.internalPointer() >= 0);
2148 Q_ASSERT(proxyIndex.model() == this);
2149
2150 if (proxyIndex.internalPointer() == 0)
2151 return d->mapTopLevelToSource(proxyIndex.row(), proxyIndex.column());
2152
2153 const QModelIndex proxyParent = d->parentForId(proxyIndex.internalPointer());
2154 Q_ASSERT(proxyParent.isValid());
2155 const QModelIndex sourceParent = d->mapParentToSource(proxyParent);
2156 Q_ASSERT(sourceParent.isValid());
2157 return sourceModel()->index(proxyIndex.row(), proxyIndex.column(), sourceParent);
2158}
2159
2160QModelIndex KSelectionProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
2161{
2162 Q_D(const KSelectionProxyModel);
2163
2164 if (!sourceModel() || !sourceIndex.isValid() || d->m_rootIndexList.isEmpty())
2165 return QModelIndex();
2166
2167 Q_ASSERT(sourceIndex.model() == sourceModel());
2168
2169 if (!sourceIndex.isValid())
2170 return QModelIndex();
2171
2172 if (!d->ensureMappable(sourceIndex))
2173 return QModelIndex();
2174
2175 return d->mapFromSource(sourceIndex);
2176}
2177
2178int KSelectionProxyModel::rowCount(const QModelIndex &index) const
2179{
2180 Q_D(const KSelectionProxyModel);
2181
2182 if (!sourceModel() || index.column() > 0 || d->m_rootIndexList.isEmpty())
2183 return 0;
2184
2185 Q_ASSERT(index.isValid() ? index.model() == this : true);
2186 if (!index.isValid())
2187 return d->topLevelRowCount();
2188
2189 // index is valid
2190 if (d->isFlat())
2191 return 0;
2192
2193 QModelIndex sourceParent = d->mapParentToSource(index);
2194
2195 if (!sourceParent.isValid() && sourceModel()->hasChildren(sourceParent)) {
2196 sourceParent = mapToSource(index.parent());
2197 d->createParentMappings(sourceParent, 0, sourceModel()->rowCount(sourceParent) - 1);
2198 sourceParent = d->mapParentToSource(index);
2199 }
2200
2201 if (!sourceParent.isValid())
2202 return 0;
2203
2204 return sourceModel()->rowCount(sourceParent);
2205}
2206
2207QModelIndex KSelectionProxyModel::index(int row, int column, const QModelIndex &parent) const
2208{
2209 Q_D(const KSelectionProxyModel);
2210
2211 if (!sourceModel() || d->m_rootIndexList.isEmpty() || !hasIndex(row, column, parent))
2212 return QModelIndex();
2213
2214 Q_ASSERT(parent.isValid() ? parent.model() == this : true);
2215
2216 if (!parent.isValid())
2217 return d->createTopLevelIndex(row, column);
2218
2219 void * const parentId = d->parentId(parent);
2220 Q_ASSERT(parentId);
2221 return createIndex(row, column, parentId);
2222}
2223
2224QModelIndex KSelectionProxyModel::parent(const QModelIndex &index) const
2225{
2226 Q_D(const KSelectionProxyModel);
2227
2228 if (!sourceModel() || !index.isValid() || d->m_rootIndexList.isEmpty())
2229 return QModelIndex();
2230
2231 Q_ASSERT(index.model() == this);
2232
2233 return d->parentForId(index.internalPointer());
2234}
2235
2236Qt::ItemFlags KSelectionProxyModel::flags(const QModelIndex &index) const
2237{
2238 if (!index.isValid() || !sourceModel())
2239 return QAbstractProxyModel::flags(index);
2240
2241 Q_ASSERT(index.model() == this);
2242
2243 const QModelIndex srcIndex = mapToSource(index);
2244 Q_ASSERT(srcIndex.isValid());
2245 return sourceModel()->flags(srcIndex);
2246}
2247
2248QVariant KSelectionProxyModel::data(const QModelIndex & index, int role) const
2249{
2250 if (!sourceModel())
2251 return QVariant();
2252
2253 if (index.isValid()) {
2254 Q_ASSERT(index.model() == this);
2255 const QModelIndex idx = mapToSource(index);
2256 return idx.data(role);
2257 }
2258 return sourceModel()->data(index, role);
2259}
2260
2261QVariant KSelectionProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
2262{
2263 if (!sourceModel())
2264 return QVariant();
2265 return sourceModel()->headerData(section, orientation, role);
2266}
2267
2268QMimeData* KSelectionProxyModel::mimeData(const QModelIndexList & indexes) const
2269{
2270 if (!sourceModel())
2271 return QAbstractProxyModel::mimeData(indexes);
2272 QModelIndexList sourceIndexes;
2273 foreach(const QModelIndex& index, indexes)
2274 sourceIndexes << mapToSource(index);
2275 return sourceModel()->mimeData(sourceIndexes);
2276}
2277
2278QStringList KSelectionProxyModel::mimeTypes() const
2279{
2280 if (!sourceModel())
2281 return QAbstractProxyModel::mimeTypes();
2282 return sourceModel()->mimeTypes();
2283}
2284
2285Qt::DropActions KSelectionProxyModel::supportedDropActions() const
2286{
2287 if (!sourceModel())
2288 return QAbstractProxyModel::supportedDropActions();
2289 return sourceModel()->supportedDropActions();
2290}
2291
2292bool KSelectionProxyModel::hasChildren(const QModelIndex & parent) const
2293{
2294 Q_D(const KSelectionProxyModel);
2295
2296 if (d->m_rootIndexList.isEmpty() || !sourceModel())
2297 return false;
2298
2299 if (parent.isValid()) {
2300 Q_ASSERT(parent.model() == this);
2301 if (d->isFlat())
2302 return false;
2303 return sourceModel()->hasChildren(mapToSource(parent));
2304 }
2305
2306 if (!d->m_startWithChildTrees)
2307 return true;
2308
2309 return !d->m_mappedFirstChildren.isEmpty();
2310}
2311
2312int KSelectionProxyModel::columnCount(const QModelIndex &index) const
2313{
2314 Q_D(const KSelectionProxyModel);
2315
2316 if (!sourceModel() || index.column() > 0
2317 // Qt 4.6 doesn't notice changes in columnCount, so we can't return 0 when
2318 // it's actually 0 ,but must return what the source model says, even if we
2319 // have no rows or columns.
2320#if QT_VERSION >= 0x040700
2321 || d->m_rootIndexList.isEmpty()
2322#endif
2323 )
2324 return 0;
2325
2326 return sourceModel()->columnCount(mapToSource(index));
2327}
2328
2329QItemSelectionModel* KSelectionProxyModel::selectionModel() const
2330{
2331 Q_D(const KSelectionProxyModel);
2332 return d->m_selectionModel.data();
2333}
2334
2335bool KSelectionProxyModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent)
2336{
2337 Q_D(const KSelectionProxyModel);
2338 if (!sourceModel() || d->m_rootIndexList.isEmpty())
2339 return false;
2340
2341 if ((row == -1) && (column == -1))
2342 return sourceModel()->dropMimeData(data, action, -1, -1, mapToSource(parent));
2343
2344 int source_destination_row = -1;
2345 int source_destination_column = -1;
2346 QModelIndex source_parent;
2347
2348 if (row == rowCount(parent)) {
2349 source_parent = mapToSource(parent);
2350 source_destination_row = sourceModel()->rowCount(source_parent);
2351 } else {
2352 const QModelIndex proxy_index = index(row, column, parent);
2353 const QModelIndex source_index = mapToSource(proxy_index);
2354 source_destination_row = source_index.row();
2355 source_destination_column = source_index.column();
2356 source_parent = source_index.parent();
2357 }
2358 return sourceModel()->dropMimeData(data, action, source_destination_row,
2359 source_destination_column, source_parent);
2360}
2361
2362QList<QPersistentModelIndex> KSelectionProxyModel::sourceRootIndexes() const
2363{
2364 Q_D(const KSelectionProxyModel);
2365 return d->m_rootIndexList;
2366}
2367
2368QModelIndexList KSelectionProxyModel::match(const QModelIndex& start, int role, const QVariant& value, int hits, Qt::MatchFlags flags) const
2369{
2370 if (role < Qt::UserRole)
2371 return QAbstractProxyModel::match(start, role, value, hits, flags);
2372
2373 QModelIndexList list;
2374 QModelIndex proxyIndex;
2375 foreach(const QModelIndex &idx, sourceModel()->match(mapToSource(start), role, value, hits, flags)) {
2376 proxyIndex = mapFromSource(idx);
2377 if (proxyIndex.isValid())
2378 list << proxyIndex;
2379 }
2380 return list;
2381}
2382
2383QItemSelection KSelectionProxyModel::mapSelectionFromSource(const QItemSelection& selection) const
2384{
2385 Q_D(const KSelectionProxyModel);
2386 if (!d->m_startWithChildTrees && d->m_includeAllSelected) {
2387 // QAbstractProxyModel::mapSelectionFromSource puts invalid ranges in the result
2388 // without checking. We can't have that.
2389 QItemSelection proxySelection;
2390 foreach(const QItemSelectionRange &range, selection)
2391 {
2392 QModelIndex proxyTopLeft = mapFromSource(range.topLeft());
2393 if (!proxyTopLeft.isValid())
2394 continue;
2395 QModelIndex proxyBottomRight = mapFromSource(range.bottomRight());
2396 Q_ASSERT(proxyBottomRight.isValid());
2397 proxySelection.append(QItemSelectionRange(proxyTopLeft, proxyBottomRight));
2398 }
2399 return proxySelection;
2400 }
2401
2402 QItemSelection proxySelection;
2403 QItemSelection::const_iterator it = selection.constBegin();
2404 const QItemSelection::const_iterator end = selection.constEnd();
2405 for ( ; it != end; ++it) {
2406 const QModelIndex proxyTopLeft = mapFromSource(it->topLeft());
2407 if (!proxyTopLeft.isValid())
2408 continue;
2409
2410 if (it->height() == 1 && it->width() == 1)
2411 proxySelection.append(QItemSelectionRange(proxyTopLeft, proxyTopLeft));
2412 else
2413 proxySelection.append(QItemSelectionRange(proxyTopLeft, d->mapFromSource(it->bottomRight())));
2414 }
2415 return proxySelection;
2416}
2417
2418QItemSelection KSelectionProxyModel::mapSelectionToSource(const QItemSelection& selection) const
2419{
2420 Q_D(const KSelectionProxyModel);
2421
2422 if (selection.isEmpty())
2423 return selection;
2424
2425 if (!d->m_startWithChildTrees && d->m_includeAllSelected) {
2426 // QAbstractProxyModel::mapSelectionFromSource puts invalid ranges in the result
2427 // without checking. We can't have that.
2428 QItemSelection sourceSelection;
2429 foreach(const QItemSelectionRange &range, selection)
2430 {
2431 QModelIndex sourceTopLeft = mapToSource(range.topLeft());
2432 Q_ASSERT(sourceTopLeft.isValid());
2433
2434 QModelIndex sourceBottomRight = mapToSource(range.bottomRight());
2435 Q_ASSERT(sourceBottomRight.isValid());
2436 sourceSelection.append(QItemSelectionRange(sourceTopLeft, sourceBottomRight));
2437 }
2438 return sourceSelection;
2439 }
2440
2441
2442 QItemSelection sourceSelection;
2443 QItemSelection extraSelection;
2444 QItemSelection::const_iterator it = selection.constBegin();
2445 const QItemSelection::const_iterator end = selection.constEnd();
2446 for ( ; it != end; ++it) {
2447 const QModelIndex sourceTopLeft = mapToSource(it->topLeft());
2448 if (it->height() == 1 && it->width() == 1) {
2449 sourceSelection.append(QItemSelectionRange(sourceTopLeft, sourceTopLeft));
2450 } else if (it->parent().isValid()) {
2451 sourceSelection.append(QItemSelectionRange(sourceTopLeft, mapToSource(it->bottomRight())));
2452 } else {
2453 // A contiguous selection in the proxy might not be contiguous in the source if it
2454 // is at the top level of the proxy.
2455 if (d->m_startWithChildTrees) {
2456 const QModelIndex sourceParent = mapFromSource(sourceTopLeft);
2457 Q_ASSERT(sourceParent.isValid());
2458 const int rowCount = sourceModel()->rowCount(sourceParent);
2459 if (rowCount < it->bottom()) {
2460 Q_ASSERT(sourceTopLeft.isValid());
2461 Q_ASSERT(it->bottomRight().isValid());
2462 const QModelIndex sourceBottomRight = mapToSource(it->bottomRight());
2463 Q_ASSERT(sourceBottomRight.isValid());
2464 sourceSelection.append(QItemSelectionRange(sourceTopLeft, sourceBottomRight));
2465 continue;
2466 }
2467 // Store the contiguous part...
2468 const QModelIndex sourceBottomRight = sourceModel()->index(rowCount - 1, it->right(), sourceParent);
2469 Q_ASSERT(sourceTopLeft.isValid());
2470 Q_ASSERT(sourceBottomRight.isValid());
2471 sourceSelection.append(QItemSelectionRange(sourceTopLeft, sourceBottomRight));
2472 // ... and the rest will be processed later.
2473 extraSelection.append(QItemSelectionRange(createIndex(it->top() - rowCount, it->right()), it->bottomRight()));
2474 } else {
2475 QItemSelection topSelection;
2476 const QModelIndex idx = createIndex(it->top(), it->right());
2477 const QModelIndex sourceIdx = mapToSource(idx);
2478 Q_ASSERT(sourceIdx.isValid());
2479 topSelection.append(QItemSelectionRange(sourceTopLeft, sourceIdx));
2480 for (int i = it->top() + 1; i < it->bottom(); ++it) {
2481 const QModelIndex left = mapToSource(createIndex(i, 0));
2482 const QModelIndex right = mapToSource(createIndex(i, it->right()));
2483 Q_ASSERT(left.isValid());
2484 Q_ASSERT(right.isValid());
2485 topSelection.append(QItemSelectionRange(left, right));
2486 }
2487 sourceSelection += kNormalizeSelection(topSelection);
2488 }
2489 }
2490 }
2491 sourceSelection << mapSelectionToSource(extraSelection);
2492 return sourceSelection;
2493}
2494
2495#include "moc_kselectionproxymodel.cpp"
KModelIndexProxyMapper
This class facilitates easy mapping of indexes and selections through proxy models.
Definition: kmodelindexproxymapper.h:80
KSelectionProxyModel
A Proxy Model which presents a subset of its source model to observers.
Definition: kselectionproxymodel.h:87
KSelectionProxyModel::columnCount
virtual int columnCount(const QModelIndex &=QModelIndex()) const
Definition: kselectionproxymodel.cpp:2312
KSelectionProxyModel::mimeTypes
virtual QStringList mimeTypes() const
Definition: kselectionproxymodel.cpp:2278
KSelectionProxyModel::sourceRootIndexes
QList< QPersistentModelIndex > sourceRootIndexes() const
Definition: kselectionproxymodel.cpp:2362
KSelectionProxyModel::supportedDropActions
virtual Qt::DropActions supportedDropActions() const
Definition: kselectionproxymodel.cpp:2285
KSelectionProxyModel::setSourceModel
virtual void setSourceModel(QAbstractItemModel *sourceModel)
reimp.
Definition: kselectionproxymodel.cpp:2053
KSelectionProxyModel::data
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const
Definition: kselectionproxymodel.cpp:2248
KSelectionProxyModel::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
Definition: kselectionproxymodel.cpp:2368
KSelectionProxyModel::parent
virtual QModelIndex parent(const QModelIndex &) const
Definition: kselectionproxymodel.cpp:2224
KSelectionProxyModel::FilterBehavior
FilterBehavior
Definition: kselectionproxymodel.h:110
KSelectionProxyModel::ExactSelection
@ ExactSelection
Definition: kselectionproxymodel.h:114
KSelectionProxyModel::SubTrees
@ SubTrees
Definition: kselectionproxymodel.h:111
KSelectionProxyModel::ChildrenOfExactSelection
@ ChildrenOfExactSelection
Definition: kselectionproxymodel.h:115
KSelectionProxyModel::SubTreesWithoutRoots
@ SubTreesWithoutRoots
Definition: kselectionproxymodel.h:113
KSelectionProxyModel::SubTreeRoots
@ SubTreeRoots
Definition: kselectionproxymodel.h:112
KSelectionProxyModel::index
virtual QModelIndex index(int, int, const QModelIndex &=QModelIndex()) const
Definition: kselectionproxymodel.cpp:2207
KSelectionProxyModel::mapSelectionFromSource
QItemSelection mapSelectionFromSource(const QItemSelection &selection) const
Definition: kselectionproxymodel.cpp:2383
KSelectionProxyModel::setFilterBehavior
void setFilterBehavior(FilterBehavior behavior)
Set the filter behaviors of this model.
Definition: kselectionproxymodel.cpp:1998
KSelectionProxyModel::hasChildren
virtual bool hasChildren(const QModelIndex &parent=QModelIndex()) const
Definition: kselectionproxymodel.cpp:2292
KSelectionProxyModel::~KSelectionProxyModel
virtual ~KSelectionProxyModel()
dtor
Definition: kselectionproxymodel.cpp:1993
KSelectionProxyModel::mapToSource
QModelIndex mapToSource(const QModelIndex &proxyIndex) const
Definition: kselectionproxymodel.cpp:2140
KSelectionProxyModel::mapSelectionToSource
QItemSelection mapSelectionToSource(const QItemSelection &selection) const
Definition: kselectionproxymodel.cpp:2418
KSelectionProxyModel::headerData
virtual QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const
Definition: kselectionproxymodel.cpp:2261
KSelectionProxyModel::flags
virtual Qt::ItemFlags flags(const QModelIndex &index) const
Definition: kselectionproxymodel.cpp:2236
KSelectionProxyModel::rowCount
virtual int rowCount(const QModelIndex &parent=QModelIndex()) const
Definition: kselectionproxymodel.cpp:2178
KSelectionProxyModel::mimeData
virtual QMimeData * mimeData(const QModelIndexList &indexes) const
Definition: kselectionproxymodel.cpp:2268
KSelectionProxyModel::dropMimeData
virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
Definition: kselectionproxymodel.cpp:2335
KSelectionProxyModel::selectionModel
QItemSelectionModel * selectionModel() const
Definition: kselectionproxymodel.cpp:2329
KSelectionProxyModel::filterBehavior
FilterBehavior filterBehavior() const
Definition: kselectionproxymodel.cpp:2047
KSelectionProxyModel::mapFromSource
QModelIndex mapFromSource(const QModelIndex &sourceIndex) const
Definition: kselectionproxymodel.cpp:2160
KSelectionProxyModel::KSelectionProxyModel
KSelectionProxyModel(QItemSelectionModel *selectionModel, QObject *parent=0)
ctor.
Definition: kselectionproxymodel.cpp:1988
QAbstractItemModel
QAbstractProxyModel
QHash
QItemSelectionModel
QList
QObject
QPair
kDebug
#define kDebug
kdebug.h
kmodelindexproxymapper.h
SourceProxyIndexMapping
KBiHash< QPersistentModelIndex, QModelIndex > SourceProxyIndexMapping
Definition: kselectionproxymodel.cpp:33
SourceIndexProxyRowMapping
KHash2Map< QPersistentModelIndex, int > SourceIndexProxyRowMapping
Definition: kselectionproxymodel.cpp:35
getRootListRow
static int getRootListRow(const QList< ModelIndex > &list, const QModelIndex &index)
Determines the correct location to insert index into list.
Definition: kselectionproxymodel.cpp:224
indexIsValid
static bool indexIsValid(bool startWithChildTrees, int row, const QList< QPersistentModelIndex > &rootIndexList, const SourceIndexProxyRowMapping &mappedFirstChildren)
Definition: kselectionproxymodel.cpp:1274
isDescendantOf
bool isDescendantOf(const QList< ModelIndex > &list, const QModelIndex &idx)
Return true if idx is a descendant of one of the indexes in list.
Definition: kselectionproxymodel.cpp:45
_getRootListRow
static int _getRootListRow(const QList< QModelIndexList > &rootAncestors, const QModelIndex &index)
Definition: kselectionproxymodel.cpp:116
ParentMapping
KBiHash< void *, QModelIndex > ParentMapping
Definition: kselectionproxymodel.cpp:34
kNormalizeSelection
QItemSelection kNormalizeSelection(QItemSelection selection)
Definition: kselectionproxymodel.cpp:373
stableNormalizeSelection
static QItemSelection stableNormalizeSelection(const QItemSelection &selection)
Definition: kselectionproxymodel.cpp:337
getRootRanges
static QItemSelection getRootRanges(const QItemSelection &_selection)
Returns a selection in which no descendants of selected indexes are also themselves selected.
Definition: kselectionproxymodel.cpp:281
kselectionproxymodel.h
KStandardAction::next
KAction * next(const QObject *recvr, const char *slot, QObject *parent)
Scroll down one page.
Definition: kstandardaction.cpp:414
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