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

KDEUI

  • sources
  • kde-4.12
  • kdelibs
  • 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 
33 typedef KBiHash<QPersistentModelIndex, QModelIndex> SourceProxyIndexMapping;
34 typedef KBiHash<void*, QModelIndex> ParentMapping;
35 typedef KHash2Map<QPersistentModelIndex, int> SourceIndexProxyRowMapping;
36 
37 #define KDO(object) kDebug() << #object << object
38 #define SON(object) object->setObjectName(#object)
39 
44 template<typename ModelIndex>
45 bool 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 
62 static 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 
80 static 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 
98 static 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 
116 static 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 
223 template<typename ModelIndex>
224 static 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 
281 static 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 
311 struct 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 
337 static 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 
373 QItemSelection 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 
403 class KSelectionProxyModelPrivate
404 {
405 public:
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 
610 void 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 
648 void 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 
725 void 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 
762 void 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 
806 void 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 
817 void 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 
826 void 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 
850 void 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 
868 int 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 
918 void 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 
946 QPair< 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 
978 void 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 
1005 void 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 
1035 void 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 
1053 QPair<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 
1137 void 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 
1157 void 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 
1220 void 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 
1246 void 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 
1255 void 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 
1264 QModelIndex KSelectionProxyModelPrivate::mapParentToSource(const QModelIndex &proxyParent) const
1265 {
1266  return m_mappedParents.rightToLeft(proxyParent);
1267 }
1268 
1269 QModelIndex KSelectionProxyModelPrivate::mapParentFromSource(const QModelIndex &sourceParent) const
1270 {
1271  return m_mappedParents.leftToRight(sourceParent);
1272 }
1273 
1274 static 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 
1296 QModelIndex 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 
1305 QModelIndex 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 
1327 QModelIndex 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 
1355 int 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 
1375 bool 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 
1419 void 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 
1444 void 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 
1501 bool 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 
1508 bool 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 
1515 void 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 
1533 void 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 
1561 void 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 
1569 void 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 
1607 QModelIndex 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 
1628 void 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 
1640 void 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 
1767 void 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 
1900 int 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 
1922 void 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 
1988 KSelectionProxyModel::KSelectionProxyModel(QItemSelectionModel *selectionModel, QObject *parent)
1989  : QAbstractProxyModel(parent), d_ptr(new KSelectionProxyModelPrivate(this, selectionModel))
1990 {
1991 }
1992 
1993 KSelectionProxyModel::~KSelectionProxyModel()
1994 {
1995  delete d_ptr;
1996 }
1997 
1998 void 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 
2047 KSelectionProxyModel::FilterBehavior KSelectionProxyModel::filterBehavior() const
2048 {
2049  Q_D(const KSelectionProxyModel);
2050  return d->m_filterBehavior;
2051 }
2052 
2053 void 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 
2140 QModelIndex 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 
2160 QModelIndex 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 
2178 int 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 
2207 QModelIndex 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 
2224 QModelIndex 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 
2236 Qt::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 
2248 QVariant 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 
2261 QVariant 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 
2268 QMimeData* 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 
2278 QStringList KSelectionProxyModel::mimeTypes() const
2279 {
2280  if (!sourceModel())
2281  return QAbstractProxyModel::mimeTypes();
2282  return sourceModel()->mimeTypes();
2283 }
2284 
2285 Qt::DropActions KSelectionProxyModel::supportedDropActions() const
2286 {
2287  if (!sourceModel())
2288  return QAbstractProxyModel::supportedDropActions();
2289  return sourceModel()->supportedDropActions();
2290 }
2291 
2292 bool 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 
2312 int 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 
2329 QItemSelectionModel* KSelectionProxyModel::selectionModel() const
2330 {
2331  Q_D(const KSelectionProxyModel);
2332  return d->m_selectionModel.data();
2333 }
2334 
2335 bool 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 
2362 QList<QPersistentModelIndex> KSelectionProxyModel::sourceRootIndexes() const
2363 {
2364  Q_D(const KSelectionProxyModel);
2365  return d->m_rootIndexList;
2366 }
2367 
2368 QModelIndexList 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 
2383 QItemSelection 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 
2418 QItemSelection 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"
QVariant
KSelectionProxyModel::SubTreeRoots
Definition: kselectionproxymodel.h:112
QItemSelectionModel
KSelectionProxyModel::mimeTypes
virtual QStringList mimeTypes() const
Definition: kselectionproxymodel.cpp:2278
kdebug.h
KSelectionProxyModel::sourceRootIndexes
QList< QPersistentModelIndex > sourceRootIndexes() const
Definition: kselectionproxymodel.cpp:2362
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
indexIsValid
static bool indexIsValid(bool startWithChildTrees, int row, const QList< QPersistentModelIndex > &rootIndexList, const SourceIndexProxyRowMapping &mappedFirstChildren)
Definition: kselectionproxymodel.cpp:1274
KSelectionProxyModel::rowCount
virtual int rowCount(const QModelIndex &parent=QModelIndex()) const
Definition: kselectionproxymodel.cpp:2178
kNormalizeSelection
QItemSelection kNormalizeSelection(QItemSelection selection)
Definition: kselectionproxymodel.cpp:373
KSelectionProxyModel::supportedDropActions
virtual Qt::DropActions supportedDropActions() const
Definition: kselectionproxymodel.cpp:2285
KSelectionProxyModel::setSourceModel
virtual void setSourceModel(QAbstractItemModel *sourceModel)
reimp.
Definition: kselectionproxymodel.cpp:2053
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
KSelectionProxyModel::SubTreesWithoutRoots
Definition: kselectionproxymodel.h:113
KSelectionProxyModel::mimeData
virtual QMimeData * mimeData(const QModelIndexList &indexes) const
Definition: kselectionproxymodel.cpp:2268
KSelectionProxyModel::ExactSelection
Definition: kselectionproxymodel.h:114
KSelectionProxyModel::dropMimeData
virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
Definition: kselectionproxymodel.cpp:2335
QHash
kmodelindexproxymapper.h
QObject
kDebug
static QDebug kDebug(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
ParentMapping
KBiHash< void *, QModelIndex > ParentMapping
Definition: kselectionproxymodel.cpp:34
KStandardAction::Deselect
Definition: kstandardaction.h:133
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
QStringList
KSelectionProxyModel::hasChildren
virtual bool hasChildren(const QModelIndex &parent=QModelIndex()) const
Definition: kselectionproxymodel.cpp:2292
KSelectionProxyModel::data
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const
Definition: kselectionproxymodel.cpp:2248
getRootListRow
static int getRootListRow(const QList< ModelIndex > &list, const QModelIndex &index)
Determines the correct location to insert index into list.
Definition: kselectionproxymodel.cpp:224
KSelectionProxyModel::mapSelectionToSource
QItemSelection mapSelectionToSource(const QItemSelection &selection) const
Definition: kselectionproxymodel.cpp:2418
KStandardAction::next
KAction * next(const QObject *recvr, const char *slot, QObject *parent)
Scroll down one page.
Definition: kstandardaction.cpp:414
QAbstractItemModel
QAbstractProxyModel
KSelectionProxyModel::flags
virtual Qt::ItemFlags flags(const QModelIndex &index) const
Definition: kselectionproxymodel.cpp:2236
kselectionproxymodel.h
_getRootListRow
static int _getRootListRow(const QList< QModelIndexList > &rootAncestors, const QModelIndex &index)
Definition: kselectionproxymodel.cpp:116
KSelectionProxyModel::mapSelectionFromSource
QItemSelection mapSelectionFromSource(const QItemSelection &selection) const
Definition: kselectionproxymodel.cpp:2383
KSelectionProxyModel::index
virtual QModelIndex index(int, int, const QModelIndex &=QModelIndex()) const
Definition: kselectionproxymodel.cpp:2207
KSelectionProxyModel::mapToSource
QModelIndex mapToSource(const QModelIndex &proxyIndex) const
Definition: kselectionproxymodel.cpp:2140
KSelectionProxyModel::KSelectionProxyModel
KSelectionProxyModel(QItemSelectionModel *selectionModel, QObject *parent=0)
ctor.
Definition: kselectionproxymodel.cpp:1988
SourceProxyIndexMapping
KBiHash< QPersistentModelIndex, QModelIndex > SourceProxyIndexMapping
Definition: kselectionproxymodel.cpp:33
KSelectionProxyModel::SubTrees
Definition: kselectionproxymodel.h:111
KModelIndexProxyMapper
This class facilitates easy mapping of indexes and selections through proxy models.
Definition: kmodelindexproxymapper.h:79
KSelectionProxyModel::setFilterBehavior
void setFilterBehavior(FilterBehavior behavior)
Set the filter behaviors of this model.
Definition: kselectionproxymodel.cpp:1998
KSelectionProxyModel::headerData
virtual QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const
Definition: kselectionproxymodel.cpp:2261
KSelectionProxyModel::mapFromSource
QModelIndex mapFromSource(const QModelIndex &sourceIndex) const
Definition: kselectionproxymodel.cpp:2160
KSelectionProxyModel::columnCount
virtual int columnCount(const QModelIndex &=QModelIndex()) const
Definition: kselectionproxymodel.cpp:2312
KSelectionProxyModel::ChildrenOfExactSelection
Definition: kselectionproxymodel.h:115
KSelectionProxyModel
A Proxy Model which presents a subset of its source model to observers.
Definition: kselectionproxymodel.h:86
QPair< int, int >
KSelectionProxyModel::~KSelectionProxyModel
virtual ~KSelectionProxyModel()
dtor
Definition: kselectionproxymodel.cpp:1993
SourceIndexProxyRowMapping
KHash2Map< QPersistentModelIndex, int > SourceIndexProxyRowMapping
Definition: kselectionproxymodel.cpp:35
KSelectionProxyModel::parent
virtual QModelIndex parent(const QModelIndex &) const
Definition: kselectionproxymodel.cpp:2224
KSelectionProxyModel::FilterBehavior
FilterBehavior
Definition: kselectionproxymodel.h:110
stableNormalizeSelection
static QItemSelection stableNormalizeSelection(const QItemSelection &selection)
Definition: kselectionproxymodel.cpp:337
KStandardShortcut::end
const KShortcut & end()
Goto end of the document.
Definition: kstandardshortcut.cpp:348
KSelectionProxyModel::selectionModel
QItemSelectionModel * selectionModel() const
Definition: kselectionproxymodel.cpp:2329
QList
KSelectionProxyModel::filterBehavior
FilterBehavior filterBehavior() const
Definition: kselectionproxymodel.cpp:2047
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:49:15 by doxygen 1.8.7 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 API Reference

Skip menu "kdelibs 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
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



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