KDEUI
kselectionproxymodel.cpp
Go to the documentation of this file.
00001 /* 00002 Copyright (c) 2009 Stephen Kelly <steveire@gmail.com> 00003 00004 This library is free software; you can redistribute it and/or modify it 00005 under the terms of the GNU Library General Public License as published by 00006 the Free Software Foundation; either version 2 of the License, or (at your 00007 option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, but WITHOUT 00010 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00011 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00012 License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to the 00016 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 00017 02110-1301, USA. 00018 */ 00019 00020 #include "kselectionproxymodel.h" 00021 00022 #include <QtCore/QStack> 00023 #include <QtCore/QStringList> 00024 #include <QtCore/QWeakPointer> 00025 #include <QtGui/QItemSelectionRange> 00026 00027 #include "kmodelindexproxymapper.h" 00028 #include "kbihash_p.h" 00029 #include "kvoidpointerfactory_p.h" 00030 00031 #include "kdebug.h" 00032 00033 typedef KBiHash<QPersistentModelIndex, QModelIndex> SourceProxyIndexMapping; 00034 typedef KBiHash<void*, QModelIndex> ParentMapping; 00035 typedef KHash2Map<QPersistentModelIndex, int> SourceIndexProxyRowMapping; 00036 00037 #define KDO(object) kDebug() << #object << object 00038 #define SON(object) object->setObjectName(#object) 00039 00044 template<typename ModelIndex> 00045 bool isDescendantOf(const QList<ModelIndex> &list, const QModelIndex &idx) 00046 { 00047 if (!idx.isValid()) 00048 return false; 00049 00050 if (list.contains(idx)) 00051 return false; 00052 00053 QModelIndex parent = idx.parent(); 00054 while (parent.isValid()) { 00055 if (list.contains(parent)) 00056 return true; 00057 parent = parent.parent(); 00058 } 00059 return false; 00060 } 00061 00062 static bool isDescendantOf(const QModelIndex &ancestor, const QModelIndex &descendant) 00063 { 00064 if (!descendant.isValid()) 00065 return false; 00066 00067 if (ancestor == descendant) 00068 return false; 00069 00070 QModelIndex parent = descendant.parent(); 00071 while (parent.isValid()) { 00072 if (parent == ancestor) 00073 return true; 00074 00075 parent = parent.parent(); 00076 } 00077 return false; 00078 } 00079 00080 static bool isDescendantOf(const QItemSelection &selection, const QModelIndex &descendant) 00081 { 00082 if (!descendant.isValid()) 00083 return false; 00084 00085 if (selection.contains(descendant)) 00086 return false; 00087 00088 QModelIndex parent = descendant.parent(); 00089 while (parent.isValid()) { 00090 if (selection.contains(parent)) 00091 return true; 00092 00093 parent = parent.parent(); 00094 } 00095 return false; 00096 } 00097 00098 static bool isDescendantOf(const QItemSelectionRange &range, const QModelIndex &descendant) 00099 { 00100 if (!descendant.isValid()) 00101 return false; 00102 00103 if (range.contains(descendant)) 00104 return false; 00105 00106 QModelIndex parent = descendant.parent(); 00107 while (parent.isValid()) { 00108 if (range.contains(parent)) 00109 return true; 00110 00111 parent = parent.parent(); 00112 } 00113 return false; 00114 } 00115 00116 static int _getRootListRow(const QList<QModelIndexList> &rootAncestors, const QModelIndex &index) 00117 { 00118 QModelIndex commonParent = index; 00119 QModelIndex youngestAncestor; 00120 00121 int firstCommonParent = -1; 00122 int bestParentRow = -1; 00123 while (commonParent.isValid()) { 00124 youngestAncestor = commonParent; 00125 commonParent = commonParent.parent(); 00126 00127 for (int i = 0; i < rootAncestors.size(); ++i) { 00128 const QModelIndexList ancestorList = rootAncestors.at(i); 00129 00130 const int parentRow = ancestorList.indexOf(commonParent); 00131 00132 if (parentRow < 0) 00133 continue; 00134 00135 if (parentRow > bestParentRow) { 00136 firstCommonParent = i; 00137 bestParentRow = parentRow; 00138 } 00139 } 00140 00141 if (firstCommonParent >= 0) 00142 break; 00143 } 00144 00145 // If @p list is non-empty, the invalid QModelIndex() will at least be found in ancestorList. 00146 Q_ASSERT(firstCommonParent >= 0); 00147 00148 const QModelIndexList firstAnsList = rootAncestors.at(firstCommonParent); 00149 00150 const QModelIndex eldestSibling = firstAnsList.value(bestParentRow + 1); 00151 00152 if (eldestSibling.isValid()) { 00153 // firstCommonParent is a sibling of one of the ancestors of @p index. 00154 // It is the first index to share a common parent with one of the ancestors of @p index. 00155 if (eldestSibling.row() >= youngestAncestor.row()) 00156 return firstCommonParent; 00157 } 00158 00159 int siblingOffset = 1; 00160 00161 // The same commonParent might be common to several root indexes. 00162 // If this is the last in the list, it's the only match. We instruct the model 00163 // to insert the new index after it ( + siblingOffset). 00164 if (rootAncestors.size() <= firstCommonParent + siblingOffset) { 00165 return firstCommonParent + siblingOffset; 00166 } 00167 00168 // A 00169 // - B 00170 // - C 00171 // - D 00172 // - E 00173 // F 00174 // 00175 // F is selected, then C then D. When inserting D into the model, the commonParent is B (the parent of C). 00176 // The next existing sibling of B is F (in the proxy model). bestParentRow will then refer to an index on 00177 // the level of a child of F (which doesn't exist - Boom!). If it doesn't exist, then we've already found 00178 // the place to insert D 00179 QModelIndexList ansList = rootAncestors.at(firstCommonParent + siblingOffset); 00180 if (ansList.size() <= bestParentRow) { 00181 return firstCommonParent + siblingOffset; 00182 } 00183 00184 QModelIndex nextParent = ansList.at(bestParentRow); 00185 while (nextParent == commonParent) { 00186 if (ansList.size() < bestParentRow + 1) 00187 // If the list is longer, it means that at the end of it is a descendant of the new index. 00188 // We insert the ancestors items first in that case. 00189 break; 00190 00191 const QModelIndex nextSibling = ansList.value(bestParentRow + 1); 00192 00193 if (!nextSibling.isValid()) { 00194 continue; 00195 } 00196 00197 if (youngestAncestor.row() <= nextSibling.row()) { 00198 break; 00199 } 00200 00201 siblingOffset++; 00202 00203 if (rootAncestors.size() <= firstCommonParent + siblingOffset) 00204 break; 00205 00206 ansList = rootAncestors.at(firstCommonParent + siblingOffset); 00207 00208 // In the scenario above, E is selected after D, causing this loop to be entered, 00209 // and requiring a similar result if the next sibling in the proxy model does not have children. 00210 if (ansList.size() <= bestParentRow) { 00211 break; 00212 } 00213 00214 nextParent = ansList.at(bestParentRow); 00215 } 00216 00217 return firstCommonParent + siblingOffset; 00218 } 00219 00223 template<typename ModelIndex> 00224 static int getRootListRow(const QList<ModelIndex> &list, const QModelIndex &index) 00225 { 00226 if (!index.isValid()) 00227 return -1; 00228 00229 if (list.isEmpty()) 00230 return 0; 00231 00232 // What's going on? 00233 // Consider a tree like 00234 // 00235 // A 00236 // - B 00237 // - - C 00238 // - - - D 00239 // - E 00240 // - F 00241 // - - G 00242 // - - - H 00243 // - I 00244 // - - J 00245 // - K 00246 // 00247 // 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. 00248 // To figure that out, we create a list for each already selected index of its ancestors. Then, 00249 // we climb the ancestors of H until we reach an index with siblings which have a descendant 00250 // selected (F above has siblings B, E and I which have descendants which are already selected). 00251 // Those child indexes are traversed to find the right sibling to put F beside. 00252 // 00253 // i.e., new items are inserted in the expected location. 00254 00255 QList<QModelIndexList> rootAncestors; 00256 foreach(const QModelIndex &root, list) { 00257 QModelIndexList ancestors; 00258 ancestors << root; 00259 QModelIndex parent = root.parent(); 00260 while (parent.isValid()) { 00261 ancestors.prepend(parent); 00262 parent = parent.parent(); 00263 } 00264 ancestors.prepend(QModelIndex()); 00265 rootAncestors << ancestors; 00266 } 00267 return _getRootListRow(rootAncestors, index); 00268 } 00269 00281 static QItemSelection getRootRanges(const QItemSelection &_selection) 00282 { 00283 QItemSelection rootSelection; 00284 QItemSelection selection = _selection; 00285 QList<QItemSelectionRange>::iterator it = selection.begin(); 00286 while (it != selection.end()) { 00287 if (!it->topLeft().parent().isValid()) 00288 { 00289 rootSelection.append(*it); 00290 it = selection.erase(it); 00291 } else 00292 ++it; 00293 } 00294 00295 it = selection.begin(); 00296 const QList<QItemSelectionRange>::iterator end = selection.end(); 00297 while ( it != end ) { 00298 const QItemSelectionRange range = *it; 00299 it = selection.erase(it); 00300 00301 if (isDescendantOf(rootSelection, range.topLeft()) || isDescendantOf(selection, range.topLeft())) 00302 continue; 00303 00304 rootSelection << range; 00305 } 00306 return rootSelection; 00307 } 00308 00311 struct RangeLessThan 00312 { 00313 bool operator()(const QItemSelectionRange &left, const QItemSelectionRange &right) const 00314 { 00315 if (right.model() == left.model()) { 00316 // parent has to be calculated, so we only do so once. 00317 const QModelIndex topLeftParent = left.parent(); 00318 const QModelIndex otherTopLeftParent = right.parent(); 00319 if (topLeftParent == otherTopLeftParent) { 00320 if (right.top() == left.top()) { 00321 if (right.left() == left.left()) { 00322 if (right.bottom() == left.bottom()) { 00323 return left.right() < right.right(); 00324 } 00325 return left.bottom() < right.bottom(); 00326 } 00327 return left.left() < right.left(); 00328 } 00329 return left.top() < right.top(); 00330 } 00331 return topLeftParent < otherTopLeftParent; 00332 } 00333 return left.model() < right.model(); 00334 } 00335 }; 00336 00337 static QItemSelection stableNormalizeSelection(QItemSelection selection) 00338 { 00339 if (selection.size() <= 1) 00340 return selection; 00341 00342 QList<QItemSelectionRange>::iterator it = selection.begin(); 00343 00344 Q_ASSERT(it != selection.end()); 00345 QList<QItemSelectionRange>::iterator scout = it + 1; 00346 while (scout != selection.end()) { 00347 Q_ASSERT(it != selection.end()); 00348 int bottom = it->bottom(); 00349 while (scout != selection.end() && it->parent() == scout->parent() && bottom + 1 == scout->top()) { 00350 bottom = scout->bottom(); 00351 scout = selection.erase(scout); 00352 } 00353 if (bottom != it->bottom()) { 00354 const QModelIndex topLeft = it->topLeft(); 00355 *it = QItemSelectionRange(topLeft, topLeft.sibling(bottom, it->right())); 00356 } 00357 Q_ASSERT(it != scout); 00358 if (scout == selection.end()) 00359 break; 00360 it = scout; 00361 ++scout; 00362 } 00363 return selection; 00364 } 00365 00366 QItemSelection kNormalizeSelection(QItemSelection selection) 00367 { 00368 if (selection.size() <= 1) 00369 return selection; 00370 00371 RangeLessThan lt; 00372 qSort(selection.begin(), selection.end(), lt); 00373 return stableNormalizeSelection(selection); 00374 } 00375 00376 00377 class KSelectionProxyModelPrivate 00378 { 00379 public: 00380 KSelectionProxyModelPrivate(KSelectionProxyModel *model, QItemSelectionModel *selectionModel) 00381 : q_ptr(model), 00382 m_startWithChildTrees(false), 00383 m_omitChildren(false), 00384 m_omitDescendants(false), 00385 m_includeAllSelected(false), 00386 m_rowsInserted(false), 00387 m_rowsRemoved(false), 00388 m_rowsMoved(false), 00389 m_resetting(false), 00390 m_doubleResetting(false), 00391 m_layoutChanging(false), 00392 m_ignoreNextLayoutAboutToBeChanged(false), 00393 m_ignoreNextLayoutChanged(false), 00394 m_selectionModel(selectionModel) 00395 { 00396 } 00397 00398 Q_DECLARE_PUBLIC(KSelectionProxyModel) 00399 KSelectionProxyModel * const q_ptr; 00400 00401 // A unique id is generated for each parent. It is used for the internalPointer of its children in the proxy 00402 // This is used to store a unique id for QModelIndexes in the proxy which have children. 00403 // If an index newly gets children it is added to this hash. If its last child is removed it is removed from this map. 00404 // If this map contains an index, that index hasChildren(). This hash is populated when new rows are inserted in the 00405 // source model, or a new selection is made. 00406 mutable ParentMapping m_parentIds; 00407 // This mapping maps indexes with children in the source to indexes with children in the proxy. 00408 // The order of indexes in this list is not relevant. 00409 mutable SourceProxyIndexMapping m_mappedParents; 00410 00411 KVoidPointerFactory<> m_voidPointerFactory; 00412 00425 void updateInternalIndexes(const QModelIndex &parent, int start, int offset); 00426 00434 void updateInternalTopIndexes(int start, int offset); 00435 00436 void updateFirstChildMapping(const QModelIndex& parent, int offset); 00437 00438 bool isFlat() const { return m_omitChildren || (m_omitDescendants && m_startWithChildTrees); } 00439 00444 bool ensureMappable(const QModelIndex &parent) const; 00445 bool parentIsMappable(const QModelIndex &parent) const { return parentAlreadyMapped(parent) || m_rootIndexList.contains(parent); } 00446 00450 QModelIndex mapFromSource(const QModelIndex &parent) const; 00451 00457 void createParentMappings(const QModelIndex &parent, int start, int end) const; 00458 void createFirstChildMapping(const QModelIndex &parent, int proxyRow) const; 00459 bool firstChildAlreadyMapped(const QModelIndex &firstChild) const; 00460 bool parentAlreadyMapped(const QModelIndex &parent) const; 00461 void removeFirstChildMappings(int start, int end); 00462 void removeParentMappings(const QModelIndex &parent, int start, int end); 00463 00473 QModelIndex mapParentToSource(const QModelIndex &proxyParent) const; 00474 00482 QModelIndex mapParentFromSource(const QModelIndex &sourceParent) const; 00483 00484 QModelIndex mapTopLevelToSource(int row, int column) const; 00485 QModelIndex mapTopLevelFromSource(const QModelIndex &sourceIndex) const; 00486 QModelIndex createTopLevelIndex(int row, int column) const; 00487 int topLevelRowCount() const; 00488 00489 void* parentId(const QModelIndex &proxyParent) const { return m_parentIds.rightToLeft(proxyParent); } 00490 QModelIndex parentForId(void *id) const { return m_parentIds.leftToRight(id); } 00491 00492 // Only populated if m_startWithChildTrees. 00493 00494 mutable SourceIndexProxyRowMapping m_mappedFirstChildren; 00495 00496 // Source list is the selection in the source model. 00497 QList<QPersistentModelIndex> m_rootIndexList; 00498 00499 KModelIndexProxyMapper *m_indexMapper; 00500 00501 QPair<int, int> beginRemoveRows(const QModelIndex &parent, int start, int end) const; 00502 QPair<int, int> beginInsertRows(const QModelIndex &parent, int start, int end) const; 00503 void endRemoveRows(const QModelIndex &sourceParent, int proxyStart, int proxyEnd); 00504 void endInsertRows(const QModelIndex &parent, int start, int end); 00505 00506 void sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end); 00507 void sourceRowsInserted(const QModelIndex &parent, int start, int end); 00508 void sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end); 00509 void sourceRowsRemoved(const QModelIndex &parent, int start, int end); 00510 void sourceRowsAboutToBeMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destParent, int destRow); 00511 void sourceRowsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destParent, int destRow); 00512 void sourceModelAboutToBeReset(); 00513 void sourceModelReset(); 00514 void sourceLayoutAboutToBeChanged(); 00515 void sourceLayoutChanged(); 00516 void emitContinuousRanges(const QModelIndex &sourceFirst, const QModelIndex &sourceLast, 00517 const QModelIndex &proxyFirst, const QModelIndex &proxyLast); 00518 void sourceDataChanged(const QModelIndex &topLeft , const QModelIndex &bottomRight); 00519 00520 void removeSelectionFromProxy(const QItemSelection &selection); 00521 void removeRangeFromProxy(const QItemSelectionRange &range); 00522 00523 void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); 00524 void sourceModelDestroyed(); 00525 00526 void resetInternalData(); 00527 00532 int getProxyInitialRow(const QModelIndex &parent) const; 00533 00543 int getTargetRow(int rootListRow); 00544 00548 void insertSelectionIntoProxy(const QItemSelection& selection); 00549 00550 bool m_startWithChildTrees; 00551 bool m_omitChildren; 00552 bool m_omitDescendants; 00553 bool m_includeAllSelected; 00554 bool m_rowsInserted; 00555 bool m_rowsRemoved; 00556 QPair<int, int> m_proxyRemoveRows; 00557 bool m_rowsMoved; 00558 bool m_resetting; 00559 bool m_doubleResetting; 00560 bool m_layoutChanging; 00561 bool m_ignoreNextLayoutAboutToBeChanged; 00562 bool m_ignoreNextLayoutChanged; 00563 const QWeakPointer<QItemSelectionModel> m_selectionModel; 00564 00565 KSelectionProxyModel::FilterBehavior m_filterBehavior; 00566 00567 QList<QPersistentModelIndex> m_layoutChangePersistentIndexes; 00568 QModelIndexList m_proxyIndexes; 00569 }; 00570 00571 void KSelectionProxyModelPrivate::emitContinuousRanges(const QModelIndex &sourceFirst, const QModelIndex &sourceLast, 00572 const QModelIndex &proxyFirst, const QModelIndex &proxyLast) 00573 { 00574 Q_Q(KSelectionProxyModel); 00575 00576 Q_ASSERT(sourceFirst.model() == q->sourceModel()); 00577 Q_ASSERT(sourceLast.model() == q->sourceModel()); 00578 Q_ASSERT(proxyFirst.model() == q); 00579 Q_ASSERT(proxyLast.model() == q); 00580 00581 const int proxyRangeSize = proxyLast.row() - proxyFirst.row(); 00582 const int sourceRangeSize = sourceLast.row() - sourceFirst.row(); 00583 00584 if (proxyRangeSize == sourceRangeSize) { 00585 emit q->dataChanged(proxyFirst, proxyLast); 00586 return; 00587 } 00588 00589 00590 // TODO: Loop to skip descendant ranges. 00591 // int lastRow; 00592 // 00593 // const QModelIndex sourceHalfWay = sourceFirst.sibling(sourceFirst.row() + (sourceRangeSize / 2)); 00594 // const QModelIndex proxyHalfWay = proxyFirst.sibling(proxyFirst.row() + (proxyRangeSize / 2)); 00595 // const QModelIndex mappedSourceHalfway = q->mapToSource(proxyHalfWay); 00596 // 00597 // const int halfProxyRange = mappedSourceHalfway.row() - proxyFirst.row(); 00598 // const int halfSourceRange = sourceHalfWay.row() - sourceFirst.row(); 00599 // 00600 // if (proxyRangeSize == sourceRangeSize) 00601 // { 00602 // emit q->dataChanged(proxyFirst, proxyLast.sibling(proxyFirst.row() + proxyRangeSize, proxyLast.column())); 00603 // return; 00604 // } 00605 00606 emit q->dataChanged(proxyFirst, proxyLast); 00607 } 00608 00609 void KSelectionProxyModelPrivate::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) 00610 { 00611 Q_Q(KSelectionProxyModel); 00612 00613 Q_ASSERT(topLeft.model() == q->sourceModel()); 00614 Q_ASSERT(bottomRight.model() == q->sourceModel()); 00615 00616 const QModelIndex sourceRangeParent = topLeft.parent(); 00617 if (!sourceRangeParent.isValid() && m_startWithChildTrees && !m_rootIndexList.contains(sourceRangeParent)) 00618 return; 00619 00620 const QModelIndex proxyTopLeft = q->mapFromSource(topLeft); 00621 const QModelIndex proxyBottomRight = q->mapFromSource(bottomRight); 00622 00623 const QModelIndex proxyRangeParent = proxyTopLeft.parent(); 00624 00625 if (!m_omitChildren && m_omitDescendants && m_startWithChildTrees && m_includeAllSelected) { 00626 // ChildrenOfExactSelection 00627 if (proxyTopLeft.isValid()) 00628 emitContinuousRanges(topLeft, bottomRight, proxyTopLeft, proxyBottomRight); 00629 return; 00630 } 00631 00632 if ((m_omitChildren && !m_startWithChildTrees && m_includeAllSelected) 00633 || (!proxyRangeParent.isValid() && !m_startWithChildTrees)) { 00634 // Exact selection and SubTreeRoots and SubTrees in top level 00635 // Emit continuous ranges. 00636 QList<int> changedRows; 00637 for (int row = topLeft.row(); row <= bottomRight.row(); ++row) { 00638 const QModelIndex index = q->sourceModel()->index(row, topLeft.column(), topLeft.parent()); 00639 const int idx = m_rootIndexList.indexOf(index); 00640 if (idx != -1) { 00641 changedRows.append(idx); 00642 } 00643 } 00644 if (changedRows.isEmpty()) 00645 return; 00646 int first = changedRows.first(); 00647 int previous = first; 00648 QList<int>::const_iterator it = changedRows.constBegin(); 00649 const QList<int>::const_iterator end = changedRows.constEnd(); 00650 for ( ; it != end; ++it) { 00651 if (*it == previous + 1) { 00652 ++previous; 00653 } else { 00654 const QModelIndex _top = q->index(first, topLeft.column()); 00655 const QModelIndex _bottom = q->index(previous, bottomRight.column()); 00656 emit q->dataChanged(_top, _bottom); 00657 previous = first = *it; 00658 } 00659 } 00660 if (first != previous) { 00661 const QModelIndex _top = q->index(first, topLeft.column()); 00662 const QModelIndex _bottom = q->index(previous, bottomRight.column()); 00663 emit q->dataChanged(_top, _bottom); 00664 } 00665 return; 00666 } 00667 if (proxyRangeParent.isValid()) { 00668 if (m_omitChildren && !m_startWithChildTrees && !m_includeAllSelected) 00669 // SubTreeRoots 00670 return; 00671 if (!proxyTopLeft.isValid()) 00672 return; 00673 // SubTrees and SubTreesWithoutRoots 00674 emit q->dataChanged(proxyTopLeft, proxyBottomRight); 00675 return; 00676 } 00677 00678 if (m_startWithChildTrees && !m_omitChildren && !m_includeAllSelected && !m_omitDescendants) { 00679 // SubTreesWithoutRoots 00680 if (proxyTopLeft.isValid()) 00681 emit q->dataChanged(proxyTopLeft, proxyBottomRight); 00682 return; 00683 } 00684 } 00685 00686 void KSelectionProxyModelPrivate::sourceLayoutAboutToBeChanged() 00687 { 00688 Q_Q(KSelectionProxyModel); 00689 00690 if (m_ignoreNextLayoutAboutToBeChanged) { 00691 m_ignoreNextLayoutAboutToBeChanged = false; 00692 return; 00693 } 00694 00695 if (m_rootIndexList.isEmpty()) 00696 return; 00697 00698 emit q->layoutAboutToBeChanged(); 00699 00700 QPersistentModelIndex srcPersistentIndex; 00701 foreach(const QPersistentModelIndex &proxyPersistentIndex, q->persistentIndexList()) { 00702 m_proxyIndexes << proxyPersistentIndex; 00703 Q_ASSERT(proxyPersistentIndex.isValid()); 00704 srcPersistentIndex = q->mapToSource(proxyPersistentIndex); 00705 Q_ASSERT(srcPersistentIndex.isValid()); 00706 m_layoutChangePersistentIndexes << srcPersistentIndex; 00707 } 00708 00709 QItemSelection selection; 00710 foreach (const QModelIndex &rootIndex, m_rootIndexList) 00711 { 00712 // This will be optimized later. 00713 emit q->rootIndexAboutToBeRemoved(rootIndex); 00714 selection.append(QItemSelectionRange(rootIndex, rootIndex)); 00715 } 00716 00717 selection = kNormalizeSelection(selection); 00718 emit q->rootSelectionAboutToBeRemoved(selection); 00719 00720 m_rootIndexList.clear(); 00721 } 00722 00723 void KSelectionProxyModelPrivate::sourceLayoutChanged() 00724 { 00725 Q_Q(KSelectionProxyModel); 00726 00727 if (m_ignoreNextLayoutChanged) { 00728 m_ignoreNextLayoutChanged = false; 00729 return; 00730 } 00731 00732 if (m_selectionModel.data()->selection().isEmpty()) { 00733 return; 00734 } 00735 00736 // Handling this signal is slow. 00737 // The problem is that anything can happen between emissions of layoutAboutToBeChanged and layoutChanged. 00738 // We can't assume anything is the same about the structure anymore. items have been sorted, items which 00739 // were parents before are now not, items which were not parents before now are, items which used to be the 00740 // first child are now the Nth child and items which used to be the Nth child are now the first child. 00741 // We effectively can't update our mapping because we don't have enough information to update everything. 00742 // The only way we would have is if we take a persistent index of the entire source model 00743 // on sourceLayoutAboutToBeChanged and then examine it here. That would be far too expensive. 00744 // Instead we just have to clear the entire mapping and recreate it. 00745 00746 m_rootIndexList.clear(); 00747 m_mappedFirstChildren.clear(); 00748 m_mappedParents.clear(); 00749 m_parentIds.clear(); 00750 00751 m_resetting = true; 00752 m_layoutChanging = true; 00753 selectionChanged(m_selectionModel.data()->selection(), QItemSelection()); 00754 m_resetting = false; 00755 m_layoutChanging = false; 00756 00757 for (int i = 0; i < m_proxyIndexes.size(); ++i) { 00758 q->changePersistentIndex(m_proxyIndexes.at(i), q->mapFromSource(m_layoutChangePersistentIndexes.at(i))); 00759 } 00760 00761 m_layoutChangePersistentIndexes.clear(); 00762 m_proxyIndexes.clear(); 00763 00764 emit q->layoutChanged(); 00765 } 00766 00767 void KSelectionProxyModelPrivate::resetInternalData() 00768 { 00769 m_rootIndexList.clear(); 00770 m_layoutChangePersistentIndexes.clear(); 00771 m_proxyIndexes.clear(); 00772 m_mappedParents.clear(); 00773 m_parentIds.clear(); 00774 m_mappedFirstChildren.clear(); 00775 m_voidPointerFactory.clear(); 00776 } 00777 00778 void KSelectionProxyModelPrivate::sourceModelDestroyed() 00779 { 00780 Q_Q(KSelectionProxyModel); 00781 // There is very little we can do here. 00782 resetInternalData(); 00783 m_resetting = false; 00784 // q->endResetModel(); 00785 } 00786 00787 void KSelectionProxyModelPrivate::sourceModelAboutToBeReset() 00788 { 00789 Q_Q(KSelectionProxyModel); 00790 00791 // We might be resetting as a result of the selection source model resetting. 00792 // If so we don't want to emit 00793 // sourceModelAboutToBeReset 00794 // sourceModelAboutToBeReset 00795 // sourceModelReset 00796 // sourceModelReset 00797 // So we ensure that we just emit one. 00798 if (m_resetting) { 00799 00800 // If both the source model and the selection source model are reset, 00801 // We want to begin our reset before the first one is reset and end 00802 // it after the second one is reset. 00803 m_doubleResetting = true; 00804 return; 00805 } 00806 00807 q->beginResetModel(); 00808 m_resetting = true; 00809 } 00810 00811 void KSelectionProxyModelPrivate::sourceModelReset() 00812 { 00813 Q_Q(KSelectionProxyModel); 00814 00815 if (m_doubleResetting) { 00816 m_doubleResetting = false; 00817 return; 00818 } 00819 00820 resetInternalData(); 00821 // No need to try to refill this. When the model is reset it doesn't have a meaningful selection anymore, 00822 // but when it gets one we'll be notified anyway. 00823 if (!m_selectionModel.isNull()) 00824 m_selectionModel.data()->reset(); 00825 m_resetting = false; 00826 q->endResetModel(); 00827 } 00828 00829 int KSelectionProxyModelPrivate::getProxyInitialRow(const QModelIndex &parent) const 00830 { 00831 Q_ASSERT(m_rootIndexList.contains(parent)); 00832 00833 // The difficulty here is that parent and parent.parent() might both be in the m_rootIndexList. 00834 00835 // - A 00836 // - B 00837 // - - C 00838 // - - D 00839 // - - - E 00840 00841 // Consider that B and D are selected. The proxy model is: 00842 00843 // - C 00844 // - D 00845 // - E 00846 00847 // Then D gets a new child at 0. In that case we require adding F between D and E. 00848 00849 // Consider instead that D gets removed. Then @p parent will be B. 00850 00851 00852 Q_Q(const KSelectionProxyModel); 00853 00854 Q_ASSERT(parent.model() == q->sourceModel()); 00855 00856 int parentPosition = m_rootIndexList.indexOf(parent); 00857 00858 QModelIndex parentAbove; 00859 00860 // If parentPosition == 0, then parent.parent() is not also in the model. (ordering is preserved) 00861 while (parentPosition > 0) { 00862 parentPosition--; 00863 00864 parentAbove = m_rootIndexList.at(parentPosition); 00865 Q_ASSERT(parentAbove.isValid()); 00866 00867 int rows = q->sourceModel()->rowCount(parentAbove); 00868 if (rows > 0) { 00869 QModelIndex sourceIndexAbove = q->sourceModel()->index(rows - 1, 0, parentAbove); 00870 Q_ASSERT(sourceIndexAbove.isValid()); 00871 QModelIndex proxyChildAbove = mapFromSource(sourceIndexAbove); 00872 Q_ASSERT(proxyChildAbove.isValid()); 00873 return proxyChildAbove.row() + 1; 00874 } 00875 } 00876 return 0; 00877 } 00878 00879 void KSelectionProxyModelPrivate::updateFirstChildMapping(const QModelIndex& parent, int offset) 00880 { 00881 Q_Q(KSelectionProxyModel); 00882 00883 Q_ASSERT(parent.isValid() ? parent.model() == q->sourceModel() : true); 00884 00885 static const int column = 0; 00886 static const int row = 0; 00887 00888 const QPersistentModelIndex srcIndex = q->sourceModel()->index(row, column, parent); 00889 00890 const QPersistentModelIndex previousFirstChild = q->sourceModel()->index(offset, column, parent); 00891 00892 SourceIndexProxyRowMapping::left_iterator it = m_mappedFirstChildren.findLeft(previousFirstChild); 00893 if (it == m_mappedFirstChildren.leftEnd()) 00894 return; 00895 00896 Q_ASSERT(srcIndex.isValid()); 00897 const int proxyRow = it.value(); 00898 Q_ASSERT(proxyRow >= 0); 00899 00900 m_mappedFirstChildren.eraseLeft(it); 00901 00902 // The proxy row in the mapping has already been updated by the offset in updateInternalTopIndexes 00903 // so we restore it by applying the reverse. 00904 m_mappedFirstChildren.insert(srcIndex, proxyRow - offset); 00905 } 00906 00907 QPair< int, int > KSelectionProxyModelPrivate::beginInsertRows(const QModelIndex& parent, int start, int end) const 00908 { 00909 const QModelIndex proxyParent = mapFromSource(parent); 00910 00911 if (!proxyParent.isValid()) 00912 { 00913 if (!m_startWithChildTrees) 00914 return qMakePair(-1, -1); 00915 00916 if (!m_rootIndexList.contains(parent)) 00917 return qMakePair(-1, -1); 00918 } 00919 00920 if (!m_startWithChildTrees) { 00921 // SubTrees 00922 if (proxyParent.isValid()) 00923 return qMakePair(start, end); 00924 return qMakePair(-1, -1); 00925 } 00926 00927 if (!m_includeAllSelected && proxyParent.isValid()) { 00928 // SubTreesWithoutRoots deeper than topLevel 00929 return qMakePair(start, end); 00930 } 00931 00932 if (!m_rootIndexList.contains(parent)) 00933 return qMakePair(-1, -1); 00934 00935 const int proxyStartRow = getProxyInitialRow(parent) + start; 00936 return qMakePair(proxyStartRow, proxyStartRow + (end - start)); 00937 } 00938 00939 void KSelectionProxyModelPrivate::sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end) 00940 { 00941 Q_Q(KSelectionProxyModel); 00942 00943 Q_ASSERT(parent.isValid() ? parent.model() == q->sourceModel() : true); 00944 00945 if (!m_selectionModel.data()->hasSelection()) 00946 return; 00947 00948 if (m_omitChildren) 00949 // ExactSelection and SubTreeRoots 00950 return; 00951 00952 // topLevel insertions can be ignored because topLevel items would need to be selected to affect the proxy. 00953 if (!parent.isValid()) 00954 return; 00955 00956 QPair<int, int> pair = beginInsertRows(parent, start, end); 00957 if (pair.first == -1) 00958 return; 00959 00960 const QModelIndex proxyParent = m_startWithChildTrees ? QModelIndex() : mapFromSource(parent); 00961 00962 m_rowsInserted = true; 00963 q->beginInsertRows(proxyParent, pair.first, pair.second); 00964 } 00965 00966 void KSelectionProxyModelPrivate::endInsertRows(const QModelIndex& parent, int start, int end) 00967 { 00968 Q_Q(const KSelectionProxyModel); 00969 const QModelIndex proxyParent = mapFromSource(parent); 00970 const int offset = end - start + 1; 00971 00972 const bool isNewParent = (q->sourceModel()->rowCount(parent) == offset); 00973 00974 if (m_startWithChildTrees && m_rootIndexList.contains(parent)) { 00975 const int proxyInitialRow = getProxyInitialRow(parent); 00976 Q_ASSERT(proxyInitialRow >= 0); 00977 const int proxyStartRow = proxyInitialRow + start; 00978 00979 updateInternalTopIndexes(proxyStartRow, offset); 00980 if (isNewParent) 00981 createFirstChildMapping(parent, proxyStartRow); 00982 else if (start == 0) 00983 // We already have a first child mapping, but what we have mapped is not the first child anymore 00984 // so we need to update it. 00985 updateFirstChildMapping(parent, end + 1); 00986 } else { 00987 Q_ASSERT(proxyParent.isValid()); 00988 if (!isNewParent) 00989 updateInternalIndexes(proxyParent, start, offset); 00990 else 00991 createParentMappings(parent.parent(), parent.row(), parent.row()); 00992 } 00993 createParentMappings(parent, start, end); 00994 } 00995 00996 void KSelectionProxyModelPrivate::sourceRowsInserted(const QModelIndex &parent, int start, int end) 00997 { 00998 Q_Q(KSelectionProxyModel); 00999 01000 Q_ASSERT(parent.isValid() ? parent.model() == q->sourceModel() : true); 01001 01002 if (!m_rowsInserted) 01003 return; 01004 m_rowsInserted = false; 01005 endInsertRows(parent, start, end); 01006 q->endInsertRows(); 01007 } 01008 01009 QPair<int, int> KSelectionProxyModelPrivate::beginRemoveRows(const QModelIndex& parent, int start, int end) const 01010 { 01011 Q_Q(const KSelectionProxyModel); 01012 01013 QPair<int, int> pair = qMakePair(start, end); 01014 01015 if (m_omitChildren && !m_startWithChildTrees && !m_includeAllSelected) { 01016 // SubTreeRoots 01017 if (m_rootIndexList.contains(parent) || isDescendantOf(m_rootIndexList, parent)) { 01018 return qMakePair(-1, -1); 01019 } 01020 } 01021 01022 const QModelIndex proxyParent = mapParentFromSource(parent); 01023 01024 if (!m_includeAllSelected && !m_omitChildren) { 01025 // SubTrees and SubTreesWithoutRoots 01026 if (proxyParent.isValid()) { 01027 return pair; 01028 } 01029 if (m_startWithChildTrees && m_rootIndexList.contains(parent)) { 01030 // SubTreesWithoutRoots topLevel 01031 const int proxyStartRow = getProxyInitialRow(parent) + start; 01032 return qMakePair(proxyStartRow, proxyStartRow + (end - start)); 01033 } 01034 } 01035 01036 if (m_includeAllSelected && m_startWithChildTrees) { 01037 // ChildrenOfExactSelection 01038 int position = m_rootIndexList.indexOf(parent); 01039 if (position != -1) { 01040 const int proxyStartRow = getProxyInitialRow(parent) + start; 01041 int proxyEndRow = proxyStartRow + (end - start); 01042 ++position; 01043 while (m_rootIndexList.size() < position) { 01044 const QModelIndex idx = m_rootIndexList.at(position); 01045 if (isDescendantOf(parent, idx)) 01046 proxyEndRow += q->sourceModel()->rowCount(idx); 01047 else 01048 break; 01049 } 01050 return qMakePair(proxyStartRow, proxyEndRow); 01051 } 01052 } 01053 01054 QList<QPersistentModelIndex>::const_iterator rootIt = m_rootIndexList.constBegin(); 01055 const QList<QPersistentModelIndex>::const_iterator rootEnd = m_rootIndexList.constEnd(); 01056 int rootPosition = 0; 01057 int rootStartRemove = -1; 01058 int rootEndRemove = -1; 01059 int siblingCount = 0; 01060 01061 for ( ; rootIt != rootEnd; ++rootIt, ++rootPosition) { 01062 if (m_omitChildren && m_includeAllSelected) { 01063 // ExactSelection 01064 if (parent == rootIt->parent() && rootIt->row() <= end && rootIt->row() >= start) { 01065 if (rootStartRemove == -1) 01066 rootStartRemove = rootPosition; 01067 ++rootEndRemove; 01068 } else { 01069 if (rootStartRemove != -1) 01070 break; 01071 } 01072 } else { 01073 if (isDescendantOf(parent, *rootIt)) { 01074 if (rootStartRemove == -1) 01075 rootStartRemove = rootPosition; 01076 ++rootEndRemove; 01077 if (m_startWithChildTrees) 01078 siblingCount += q->sourceModel()->rowCount(*rootIt); 01079 } else { 01080 if (rootStartRemove != -1) 01081 break; 01082 } 01083 } 01084 } 01085 if (rootStartRemove != -1) { 01086 return qMakePair(siblingCount + rootStartRemove, siblingCount + rootEndRemove); 01087 } 01088 01089 return qMakePair(-1, -1); 01090 } 01091 01092 void KSelectionProxyModelPrivate::sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) 01093 { 01094 Q_Q(KSelectionProxyModel); 01095 01096 Q_ASSERT(parent.isValid() ? parent.model() == q->sourceModel() : true); 01097 01098 if (!m_selectionModel.data()->hasSelection()) 01099 return; 01100 01101 QPair<int, int> pair = beginRemoveRows(parent, start, end); 01102 if (pair.first == -1) 01103 return; 01104 01105 const QModelIndex proxyParent = mapParentFromSource(parent); 01106 01107 m_rowsRemoved = true; 01108 m_proxyRemoveRows = pair; 01109 q->beginRemoveRows(proxyParent, pair.first, pair.second); 01110 } 01111 01112 void KSelectionProxyModelPrivate::endRemoveRows(const QModelIndex &sourceParent, int proxyStart, int proxyEnd) 01113 { 01114 const QModelIndex proxyParent = mapParentFromSource(sourceParent); 01115 01116 // We need to make sure to remove entries from the mappings before updating internal indexes. 01117 01118 // - A 01119 // - - B 01120 // - C 01121 // - - D 01122 01123 // If A and C are selected, B and D are in the proxy. B maps to row 0 and D maps to row 1. 01124 // If B is then deleted leaving only D in the proxy, D needs to be updated to be a mapping 01125 // to row 0 instead of row 1. If that is done before removing the mapping for B, then the mapping 01126 // for D would overwrite the mapping for B and then the code for removing mappings would incorrectly 01127 // remove D. 01128 // So we first remove B and then update D. 01129 01130 { 01131 SourceProxyIndexMapping::right_iterator it = m_mappedParents.rightBegin(); 01132 01133 while (it != m_mappedParents.rightEnd()) { 01134 if (!it.value().isValid()) { 01135 m_parentIds.removeRight(it.key()); 01136 it = m_mappedParents.eraseRight(it); 01137 } else 01138 ++it; 01139 } 01140 } 01141 01142 { 01143 // Depending on what is selected at the time, a single removal in the source could invalidate 01144 // many mapped first child items at once. 01145 01146 // - A 01147 // - B 01148 // - - C 01149 // - - D 01150 // - - - E 01151 // - - - F 01152 // - - - - G 01153 // - - - - H 01154 01155 // If D and F are selected, the proxy contains E, F, G, H. If B is then deleted E to H will 01156 // be removed, including both first child mappings at E and G. 01157 01158 removeFirstChildMappings(proxyStart, proxyEnd); 01159 } 01160 01161 if (proxyParent.isValid()) 01162 updateInternalIndexes(proxyParent, proxyEnd + 1, -1*(proxyEnd - proxyStart + 1)); 01163 else 01164 updateInternalTopIndexes(proxyEnd + 1, -1*(proxyEnd - proxyStart + 1)); 01165 01166 QList<QPersistentModelIndex>::iterator rootIt = m_rootIndexList.begin(); 01167 while (rootIt != m_rootIndexList.end()) { 01168 if (!rootIt->isValid()) 01169 rootIt = m_rootIndexList.erase(rootIt); 01170 else 01171 ++rootIt; 01172 } 01173 } 01174 01175 void KSelectionProxyModelPrivate::sourceRowsRemoved(const QModelIndex &parent, int start, int end) 01176 { 01177 Q_Q(KSelectionProxyModel); 01178 Q_UNUSED(end) 01179 01180 Q_ASSERT(parent.isValid() ? parent.model() == q->sourceModel() : true); 01181 01182 if (!m_selectionModel.data()->hasSelection()) 01183 return; 01184 01185 if (!m_rowsRemoved) 01186 return; 01187 m_rowsRemoved = false; 01188 01189 Q_ASSERT(m_proxyRemoveRows.first >= 0); 01190 Q_ASSERT(m_proxyRemoveRows.second >= 0); 01191 endRemoveRows(parent, m_proxyRemoveRows.first, m_proxyRemoveRows.second); 01192 if (m_startWithChildTrees && start == 0 && q->sourceModel()->hasChildren(parent)) 01193 // The private endRemoveRows call might remove the first child mapping for parent, so 01194 // we create it again in that case. 01195 createFirstChildMapping(parent, m_proxyRemoveRows.first); 01196 01197 m_proxyRemoveRows = qMakePair(-1, -1); 01198 q->endRemoveRows(); 01199 } 01200 01201 void KSelectionProxyModelPrivate::sourceRowsAboutToBeMoved(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destRow) 01202 { 01203 Q_UNUSED(srcParent) 01204 Q_UNUSED(srcStart) 01205 Q_UNUSED(srcEnd) 01206 Q_UNUSED(destParent) 01207 Q_UNUSED(destRow) 01208 } 01209 01210 void KSelectionProxyModelPrivate::sourceRowsMoved(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destRow) 01211 { 01212 Q_UNUSED(srcParent) 01213 Q_UNUSED(srcStart) 01214 Q_UNUSED(srcEnd) 01215 Q_UNUSED(destParent) 01216 Q_UNUSED(destRow) 01217 } 01218 01219 QModelIndex KSelectionProxyModelPrivate::mapParentToSource(const QModelIndex &proxyParent) const 01220 { 01221 return m_mappedParents.rightToLeft(proxyParent); 01222 } 01223 01224 QModelIndex KSelectionProxyModelPrivate::mapParentFromSource(const QModelIndex &sourceParent) const 01225 { 01226 return m_mappedParents.leftToRight(sourceParent); 01227 } 01228 01229 static bool indexIsValid(bool startWithChildTrees, int row, const QList<QPersistentModelIndex> &rootIndexList, const SourceIndexProxyRowMapping &mappedFirstChildren) 01230 { 01231 if (!startWithChildTrees) { 01232 Q_ASSERT(rootIndexList.size() > row); 01233 } else { 01234 01235 Q_ASSERT(!mappedFirstChildren.isEmpty()); 01236 01237 SourceIndexProxyRowMapping::right_const_iterator result = mappedFirstChildren.rightUpperBound(row) - 1; 01238 01239 Q_ASSERT(result != mappedFirstChildren.rightEnd()); 01240 const int proxyFirstRow = result.key(); 01241 const QModelIndex sourceFirstChild = result.value(); 01242 Q_ASSERT(proxyFirstRow >= 0); 01243 Q_ASSERT(sourceFirstChild.isValid()); 01244 Q_ASSERT(sourceFirstChild.parent().isValid()); 01245 Q_ASSERT(row <= proxyFirstRow + sourceFirstChild.model()->rowCount(sourceFirstChild.parent())); 01246 } 01247 return true; 01248 } 01249 01250 QModelIndex KSelectionProxyModelPrivate::createTopLevelIndex(int row, int column) const 01251 { 01252 Q_Q(const KSelectionProxyModel); 01253 01254 Q_ASSERT(indexIsValid(m_startWithChildTrees, row, m_rootIndexList, m_mappedFirstChildren)); 01255 return q->createIndex(row, column); 01256 } 01257 01258 01259 QModelIndex KSelectionProxyModelPrivate::mapTopLevelFromSource(const QModelIndex &sourceIndex) const 01260 { 01261 Q_Q(const KSelectionProxyModel); 01262 01263 const QModelIndex sourceParent = sourceIndex.parent(); 01264 const int row = m_rootIndexList.indexOf(sourceIndex); 01265 if (row == -1) 01266 return QModelIndex(); 01267 01268 if (!m_startWithChildTrees) { 01269 Q_ASSERT(m_rootIndexList.size() > row); 01270 return q->createIndex(row, sourceIndex.column()); 01271 } 01272 if (!m_rootIndexList.contains(sourceParent)) 01273 return QModelIndex(); 01274 01275 const QModelIndex firstChild = q->sourceModel()->index(0, 0, sourceParent); 01276 const int firstProxyRow = m_mappedFirstChildren.leftToRight(firstChild); 01277 01278 return q->createIndex(firstProxyRow + sourceIndex.row(), sourceIndex.column()); 01279 } 01280 01281 QModelIndex KSelectionProxyModelPrivate::mapFromSource(const QModelIndex &sourceIndex) const 01282 { 01283 Q_Q(const KSelectionProxyModel); 01284 01285 const QModelIndex maybeMapped = mapParentFromSource(sourceIndex); 01286 if (maybeMapped.isValid()) { 01287 // Q_ASSERT((!d->m_startWithChildTrees && d->m_rootIndexList.contains(maybeMapped)) ? maybeMapped.row() < 0 : true ); 01288 return maybeMapped; 01289 } 01290 const QModelIndex sourceParent = sourceIndex.parent(); 01291 01292 const QModelIndex proxyParent = mapParentFromSource(sourceParent); 01293 if (proxyParent.isValid()) { 01294 void * const parentId = m_parentIds.rightToLeft(proxyParent); 01295 static const int column = 0; 01296 return q->createIndex(sourceIndex.row(), column, parentId); 01297 } 01298 01299 const QModelIndex firstChild = q->sourceModel()->index(0, 0, sourceParent); 01300 01301 if (m_mappedFirstChildren.leftContains(firstChild)) 01302 { 01303 const int firstProxyRow = m_mappedFirstChildren.leftToRight(firstChild); 01304 return q->createIndex(firstProxyRow + sourceIndex.row(), sourceIndex.column()); 01305 } 01306 return mapTopLevelFromSource(sourceIndex); 01307 } 01308 01309 int KSelectionProxyModelPrivate::topLevelRowCount() const 01310 { 01311 Q_Q(const KSelectionProxyModel); 01312 01313 if (!m_startWithChildTrees) 01314 return m_rootIndexList.size(); 01315 01316 if (m_mappedFirstChildren.isEmpty()) 01317 return 0; 01318 01319 const SourceIndexProxyRowMapping::right_const_iterator result = m_mappedFirstChildren.rightConstEnd() - 1; 01320 01321 const int proxyFirstRow = result.key(); 01322 const QModelIndex sourceFirstChild = result.value(); 01323 Q_ASSERT(sourceFirstChild.isValid()); 01324 const QModelIndex sourceParent = sourceFirstChild.parent(); 01325 Q_ASSERT(sourceParent.isValid()); 01326 return q->sourceModel()->rowCount(sourceParent) + proxyFirstRow; 01327 } 01328 01329 bool KSelectionProxyModelPrivate::ensureMappable(const QModelIndex &parent) const 01330 { 01331 Q_Q(const KSelectionProxyModel); 01332 01333 if (isFlat()) 01334 return true; 01335 01336 if (parentIsMappable(parent)) 01337 return true; 01338 01339 QModelIndex ancestor = parent.parent(); 01340 QModelIndexList ancestorList; 01341 while (ancestor.isValid()) 01342 { 01343 if (parentIsMappable(ancestor)) 01344 break; 01345 else 01346 ancestorList.prepend(ancestor); 01347 01348 ancestor = ancestor.parent(); 01349 } 01350 01351 if (!ancestor.isValid()) 01352 // @p parent is not a descendant of m_rootIndexList. 01353 return false; 01354 01355 // sourceIndex can be mapped to the proxy. We just need to create mappings for its ancestors first. 01356 for(int i = 0; i < ancestorList.size(); ++i) 01357 { 01358 const QModelIndex existingAncestor = mapParentFromSource(ancestor); 01359 Q_ASSERT(existingAncestor.isValid()); 01360 01361 void * const ansId = m_parentIds.rightToLeft(existingAncestor); 01362 const QModelIndex newSourceParent = ancestorList.at(i); 01363 const QModelIndex newProxyParent = q->createIndex(newSourceParent.row(), newSourceParent.column(), ansId); 01364 01365 void * const newId = m_voidPointerFactory.createPointer(); 01366 m_parentIds.insert(newId, newProxyParent); 01367 m_mappedParents.insert(QPersistentModelIndex(newSourceParent), newProxyParent); 01368 ancestor = newSourceParent; 01369 } 01370 return true; 01371 } 01372 01373 void KSelectionProxyModelPrivate::updateInternalTopIndexes(int start, int offset) 01374 { 01375 updateInternalIndexes(QModelIndex(), start, offset); 01376 01377 QHash<QPersistentModelIndex, int> updates; 01378 { 01379 SourceIndexProxyRowMapping::right_iterator it = m_mappedFirstChildren.rightLowerBound(start); 01380 const SourceIndexProxyRowMapping::right_iterator end = m_mappedFirstChildren.rightEnd(); 01381 01382 for ( ; it != end; ++it) 01383 { 01384 updates.insert(*it, it.key() + offset); 01385 } 01386 } 01387 { 01388 QHash<QPersistentModelIndex, int>::const_iterator it = updates.constBegin(); 01389 const QHash<QPersistentModelIndex, int>::const_iterator end = updates.constEnd(); 01390 01391 for ( ; it != end; ++it) 01392 { 01393 m_mappedFirstChildren.insert(it.key(), it.value()); 01394 } 01395 } 01396 } 01397 01398 void KSelectionProxyModelPrivate::updateInternalIndexes(const QModelIndex &parent, int start, int offset) 01399 { 01400 Q_Q(KSelectionProxyModel); 01401 01402 Q_ASSERT(start + offset >= 0); 01403 Q_ASSERT(parent.isValid() ? parent.model() == q : true); 01404 01405 if (isFlat()) 01406 return; 01407 01408 SourceProxyIndexMapping::left_iterator mappedParentIt = m_mappedParents.leftBegin(); 01409 01410 QHash<void*, QModelIndex> updatedParentIds; 01411 QHash<QPersistentModelIndex, QModelIndex> updatedParents; 01412 01413 for ( ; mappedParentIt != m_mappedParents.leftEnd(); ++mappedParentIt) { 01414 const QModelIndex proxyIndex = mappedParentIt.value(); 01415 Q_ASSERT(proxyIndex.isValid()); 01416 01417 if (proxyIndex.row() < start) 01418 continue; 01419 01420 const QModelIndex proxyParent = proxyIndex.parent(); 01421 01422 if (parent.isValid()) { 01423 if (proxyParent != parent) 01424 continue; 01425 } else { 01426 if (proxyParent.isValid()) 01427 continue; 01428 } 01429 Q_ASSERT(m_parentIds.rightContains(proxyIndex)); 01430 void * const key = m_parentIds.rightToLeft(proxyIndex); 01431 01432 const QModelIndex newIndex = q->createIndex(proxyIndex.row() + offset, proxyIndex.column(), proxyIndex.internalPointer()); 01433 01434 Q_ASSERT(newIndex.isValid()); 01435 01436 updatedParentIds.insert(key, newIndex); 01437 updatedParents.insert(mappedParentIt.key(), newIndex); 01438 } 01439 01440 { 01441 QHash<QPersistentModelIndex, QModelIndex>::const_iterator it = updatedParents.constBegin(); 01442 const QHash<QPersistentModelIndex, QModelIndex>::const_iterator end = updatedParents.constEnd(); 01443 for ( ; it != end; ++it) 01444 m_mappedParents.insert(it.key(), it.value()); 01445 } 01446 01447 { 01448 QHash<void*, QModelIndex>::const_iterator it = updatedParentIds.constBegin(); 01449 const QHash<void*, QModelIndex>::const_iterator end = updatedParentIds.constEnd(); 01450 for ( ; it != end; ++it) 01451 m_parentIds.insert(it.key(), it.value()); 01452 } 01453 } 01454 01455 bool KSelectionProxyModelPrivate::parentAlreadyMapped(const QModelIndex &parent) const 01456 { 01457 Q_Q(const KSelectionProxyModel); 01458 Q_ASSERT(parent.model() == q->sourceModel()); 01459 return m_mappedParents.leftContains(parent); 01460 } 01461 01462 bool KSelectionProxyModelPrivate::firstChildAlreadyMapped(const QModelIndex &firstChild) const 01463 { 01464 Q_Q(const KSelectionProxyModel); 01465 Q_ASSERT(firstChild.model() == q->sourceModel()); 01466 return m_mappedFirstChildren.leftContains(firstChild); 01467 } 01468 01469 void KSelectionProxyModelPrivate::createFirstChildMapping(const QModelIndex& parent, int proxyRow) const 01470 { 01471 Q_Q(const KSelectionProxyModel); 01472 01473 Q_ASSERT(parent.isValid() ? parent.model() == q->sourceModel() : true); 01474 01475 static const int column = 0; 01476 static const int row = 0; 01477 01478 const QPersistentModelIndex srcIndex = q->sourceModel()->index(row, column, parent); 01479 01480 if (firstChildAlreadyMapped(srcIndex)) 01481 return; 01482 01483 Q_ASSERT(srcIndex.isValid()); 01484 m_mappedFirstChildren.insert(srcIndex, proxyRow); 01485 } 01486 01487 void KSelectionProxyModelPrivate::createParentMappings(const QModelIndex &parent, int start, int end) const 01488 { 01489 if (isFlat()) 01490 return; 01491 01492 Q_Q(const KSelectionProxyModel); 01493 01494 Q_ASSERT(parent.isValid() ? parent.model() == q->sourceModel() : true); 01495 01496 static const int column = 0; 01497 01498 for (int row = start; row <= end; ++row) { 01499 const QModelIndex srcIndex = q->sourceModel()->index(row, column, parent); 01500 Q_ASSERT(srcIndex.isValid()); 01501 if (!q->sourceModel()->hasChildren(srcIndex) || parentAlreadyMapped(srcIndex)) 01502 continue; 01503 01504 const QModelIndex proxyIndex = mapFromSource(srcIndex); 01505 if (!proxyIndex.isValid()) 01506 return; // If one of them is not mapped, its siblings won't be either 01507 01508 void * const newId = m_voidPointerFactory.createPointer(); 01509 m_parentIds.insert(newId, proxyIndex); 01510 Q_ASSERT(srcIndex.isValid()); 01511 m_mappedParents.insert(QPersistentModelIndex(srcIndex), proxyIndex); 01512 } 01513 } 01514 01515 void KSelectionProxyModelPrivate::removeFirstChildMappings(int start, int end) 01516 { 01517 SourceIndexProxyRowMapping::right_iterator it = m_mappedFirstChildren.rightLowerBound(start); 01518 const SourceIndexProxyRowMapping::right_iterator endIt = m_mappedFirstChildren.rightUpperBound(end); 01519 while (it != endIt) 01520 it = m_mappedFirstChildren.eraseRight(it); 01521 } 01522 01523 void KSelectionProxyModelPrivate::removeParentMappings(const QModelIndex &parent, int start, int end) 01524 { 01525 Q_Q(KSelectionProxyModel); 01526 01527 Q_ASSERT(parent.isValid() ? parent.model() == q : true); 01528 01529 SourceProxyIndexMapping::right_iterator it = m_mappedParents.rightBegin(); 01530 SourceProxyIndexMapping::right_iterator endIt = m_mappedParents.rightEnd(); 01531 01532 typedef QPair<QModelIndex, QPersistentModelIndex> Pair; 01533 01534 QList<Pair> pairs; 01535 01536 QModelIndexList list; 01537 01538 const bool flatList = isFlat(); 01539 01540 while (it != endIt) { 01541 if (it.key().row() >= start && it.key().row() <= end) 01542 { 01543 const QModelIndex sourceParent = it.value(); 01544 const QModelIndex proxyGrandParent = mapParentFromSource(sourceParent.parent()); 01545 if (proxyGrandParent == parent) 01546 { 01547 if (!flatList) 01548 // Due to recursive calls, we could have several iterators on the container 01549 // when erase is called. That's safe accoring to the QHash::iterator docs though. 01550 removeParentMappings(it.key(), 0, q->sourceModel()->rowCount(it.value()) - 1); 01551 01552 m_parentIds.removeRight(it.key()); 01553 it = m_mappedParents.eraseRight(it); 01554 } else 01555 ++it; 01556 } else 01557 ++it; 01558 } 01559 } 01560 01561 QModelIndex KSelectionProxyModelPrivate::mapTopLevelToSource(int row, int column) const 01562 { 01563 if (!m_startWithChildTrees) 01564 { 01565 const QModelIndex idx = m_rootIndexList.at(row); 01566 return idx.sibling(idx.row(), column); 01567 } 01568 01569 if (m_mappedFirstChildren.isEmpty()) 01570 return QModelIndex(); 01571 01572 SourceIndexProxyRowMapping::right_iterator result = m_mappedFirstChildren.rightUpperBound(row) - 1; 01573 01574 Q_ASSERT(result != m_mappedFirstChildren.rightEnd()); 01575 01576 const int proxyFirstRow = result.key(); 01577 const QModelIndex sourceFirstChild = result.value(); 01578 Q_ASSERT(sourceFirstChild.isValid()); 01579 return sourceFirstChild.sibling(row - proxyFirstRow, column); 01580 } 01581 01582 void KSelectionProxyModelPrivate::removeSelectionFromProxy(const QItemSelection &selection) 01583 { 01584 Q_Q(KSelectionProxyModel); 01585 if (selection.isEmpty()) 01586 return; 01587 01588 q->rootSelectionAboutToBeRemoved(selection); 01589 01590 foreach(const QItemSelectionRange range, selection) 01591 removeRangeFromProxy(range); 01592 } 01593 01594 void KSelectionProxyModelPrivate::removeRangeFromProxy(const QItemSelectionRange &range) 01595 { 01596 Q_Q(KSelectionProxyModel); 01597 01598 Q_ASSERT(range.model() == q->sourceModel()); 01599 01600 const QModelIndex sourceTopLeft = range.topLeft(); 01601 const QModelIndex proxyTopLeft = mapFromSource(sourceTopLeft); 01602 const QModelIndex sourceBottomLeft = range.bottomRight().sibling(range.bottom(), 0); 01603 const QModelIndex proxyBottomLeft = mapFromSource(sourceBottomLeft); 01604 const QModelIndex proxyParent = proxyTopLeft.parent(); 01605 const QModelIndex sourceParent = sourceTopLeft.parent(); 01606 01607 if (m_startWithChildTrees) { 01608 Q_ASSERT(sourceTopLeft.isValid()); 01609 Q_ASSERT(sourceBottomLeft.isValid()); 01610 const int startRootIdx = m_rootIndexList.indexOf(sourceTopLeft); 01611 int endRootIdx = m_rootIndexList.indexOf(sourceBottomLeft); 01612 QItemSelection extraRanges; 01613 if (m_includeAllSelected) { 01614 // It can happen that indexes of descendants get in between indexes which make up a range. 01615 // We handle only the first contiguous block here and handle the rest later. 01616 int idx = startRootIdx; 01617 const int bottomIdx = endRootIdx; 01618 const int rootListSize = m_rootIndexList.size(); 01619 int next = idx + 1; 01620 while (next <= bottomIdx) 01621 { 01622 if (next < rootListSize && m_rootIndexList.at(next).parent() == sourceParent) { 01623 idx = next; 01624 ++next; 01625 } else 01626 break; 01627 } 01628 endRootIdx = idx; 01629 ++idx; 01630 while (idx <= bottomIdx) 01631 { 01632 const QModelIndex index= m_rootIndexList.at(idx); 01633 if (m_rootIndexList.at(idx).parent() == sourceParent) 01634 extraRanges << QItemSelectionRange(index, index); 01635 ++idx; 01636 } 01637 } 01638 Q_ASSERT(endRootIdx != -1); 01639 int childrenCount = q->sourceModel()->rowCount(sourceTopLeft); 01640 for (int rootIdx = startRootIdx + 1; rootIdx <= endRootIdx; ++rootIdx) 01641 { 01642 childrenCount += q->sourceModel()->rowCount(m_rootIndexList.at(rootIdx)); 01643 } 01644 if (childrenCount == 0) 01645 { 01646 for (int rootIdx = startRootIdx; rootIdx <= endRootIdx; --endRootIdx) 01647 { 01648 const QModelIndex idx = m_rootIndexList.at(rootIdx); 01649 q->rootIndexAboutToBeRemoved(idx); 01650 m_rootIndexList.removeOne(idx); 01651 } 01652 return; 01653 } 01654 if (!m_includeAllSelected) 01655 { 01656 ++endRootIdx; 01657 for ( ; endRootIdx < m_rootIndexList.size(); ++endRootIdx) { 01658 const QModelIndex idx = m_rootIndexList.at(endRootIdx); 01659 if (isDescendantOf(sourceBottomLeft, idx)) 01660 childrenCount += q->sourceModel()->rowCount(idx); 01661 else 01662 break; 01663 } 01664 --endRootIdx; 01665 } 01666 const int proxyStart = getTargetRow(startRootIdx); 01667 int proxyEnd = proxyStart + childrenCount - 1; 01668 q->beginRemoveRows(QModelIndex(), proxyStart, proxyEnd); 01669 01670 for (int rootIdx = startRootIdx; rootIdx <= endRootIdx; ++rootIdx) 01671 { 01672 q->rootIndexAboutToBeRemoved(m_rootIndexList.at(rootIdx)); 01673 } 01674 01675 removeParentMappings(QModelIndex(), proxyStart, proxyEnd); 01676 removeFirstChildMappings(proxyStart, proxyEnd); 01677 int numRemovedChildren = 0; 01678 for (int rootIdx = startRootIdx; rootIdx <= endRootIdx; --endRootIdx) 01679 { 01680 const QModelIndex idx = m_rootIndexList.at(rootIdx); 01681 const int childCount = q->sourceModel()->rowCount(idx); 01682 m_rootIndexList.removeAt(rootIdx); 01683 numRemovedChildren += childCount; 01684 } 01685 updateInternalTopIndexes(proxyEnd + 1, -1 * numRemovedChildren); 01686 q->endRemoveRows(); 01687 if (m_includeAllSelected) { 01688 removeSelectionFromProxy(kNormalizeSelection(extraRanges)); 01689 } 01690 } else { 01691 if (!proxyTopLeft.isValid()) 01692 return; 01693 const int height = range.height(); 01694 q->beginRemoveRows(proxyParent, proxyTopLeft.row(), proxyTopLeft.row() + height - 1); 01695 01696 // TODO: Do this conditionally if the signal is connected to anything. 01697 for (int i = 0; i < height; ++i) 01698 { 01699 const QModelIndex idx = sourceTopLeft.sibling(range.top() + i, sourceTopLeft.column()); 01700 q->rootIndexAboutToBeRemoved(idx); 01701 } 01702 01703 removeParentMappings(proxyParent, proxyTopLeft.row(), proxyTopLeft.row() + height - 1); 01704 updateInternalIndexes(proxyParent, proxyTopLeft.row() + height, -1 * height); 01705 01706 for (int i = 0; i < height; ++i) 01707 { 01708 const QModelIndex idx = sourceTopLeft.sibling(range.top() + i, sourceTopLeft.column()); 01709 Q_ASSERT(idx.isValid()); 01710 const bool b = m_rootIndexList.removeOne(idx); 01711 Q_UNUSED(b) 01712 if (!b) 01713 kDebug() << idx; 01714 Q_ASSERT(b); 01715 } 01716 01717 q->endRemoveRows(); 01718 } 01719 } 01720 01721 void KSelectionProxyModelPrivate::selectionChanged(const QItemSelection &_selected, const QItemSelection &_deselected) 01722 { 01723 Q_Q(KSelectionProxyModel); 01724 01725 if (!q->sourceModel() || (_selected.isEmpty() && _deselected.isEmpty())) 01726 return; 01727 01728 // Any deselected indexes in the m_rootIndexList are removed. Then, any 01729 // indexes in the selected range which are not a descendant of one of the already selected indexes 01730 // are inserted into the model. 01731 // 01732 // All ranges from the selection model need to be split into individual rows. Ranges which are contiguous in 01733 // the selection model may not be contiguous in the source model if there's a sort filter proxy model in the chain. 01734 // 01735 // Some descendants of deselected indexes may still be selected. The ranges in m_selectionModel.data()->selection() 01736 // are examined. If any of the ranges are descendants of one of the 01737 // indexes in deselected, they are added to the ranges to be inserted into the model. 01738 // 01739 // The new indexes are inserted in sorted order. 01740 01741 const QItemSelection selected = kNormalizeSelection(m_indexMapper->mapSelectionRightToLeft(_selected)); 01742 const QItemSelection deselected = kNormalizeSelection(m_indexMapper->mapSelectionRightToLeft(_deselected)); 01743 01744 #if QT_VERSION < 0x040800 01745 // The QItemSelectionModel sometimes doesn't remove deselected items from its selection 01746 // Fixed in Qt 4.8 : http://qt.gitorious.org/qt/qt/merge_requests/2403 01747 QItemSelection reportedSelection = m_selectionModel.data()->selection(); 01748 reportedSelection.merge(deselected, QItemSelectionModel::Deselect); 01749 QItemSelection fullSelection = m_indexMapper->mapSelectionRightToLeft(reportedSelection); 01750 #else 01751 QItemSelection fullSelection = m_indexMapper->mapSelectionRightToLeft(m_selectionModel.data()->selection()); 01752 #endif 01753 01754 fullSelection = kNormalizeSelection(fullSelection); 01755 01756 QItemSelection newRootRanges; 01757 QItemSelection removedRootRanges; 01758 if (!m_includeAllSelected) { 01759 newRootRanges = getRootRanges(selected); 01760 01761 QItemSelection existingSelection = fullSelection; 01762 // What was selected before the selection was made. 01763 existingSelection.merge(selected, QItemSelectionModel::Deselect); 01764 01765 // This is similar to m_rootRanges, but that m_rootRanges at this point still contains the roots 01766 // of deselected and existingRootRanges does not. 01767 01768 const QItemSelection existingRootRanges = getRootRanges(existingSelection); 01769 { 01770 QMutableListIterator<QItemSelectionRange> i(newRootRanges); 01771 while (i.hasNext()) { 01772 const QItemSelectionRange range = i.next(); 01773 const QModelIndex topLeft = range.topLeft(); 01774 if (isDescendantOf(existingRootRanges, topLeft)) { 01775 i.remove(); 01776 } 01777 } 01778 } 01779 01780 QItemSelection exposedSelection; 01781 { 01782 QItemSelection deselectedRootRanges = getRootRanges(deselected); 01783 QListIterator<QItemSelectionRange> i(deselectedRootRanges); 01784 while (i.hasNext()) { 01785 const QItemSelectionRange range = i.next(); 01786 const QModelIndex topLeft = range.topLeft(); 01787 // Consider this: 01788 // 01789 // - A 01790 // - - B 01791 // - - - C 01792 // - - - - D 01793 // 01794 // B and D were selected, then B was deselected and C was selected in one go. 01795 if (!isDescendantOf(existingRootRanges, topLeft)) { 01796 // B is topLeft and fullSelection contains D. 01797 // B is not a descendant of D. 01798 01799 // range is not a descendant of the selection, but maybe the selection is a descendant of range. 01800 // no need to check selected here. That's already in newRootRanges. 01801 // existingRootRanges and newRootRanges do not overlap. 01802 foreach (const QItemSelectionRange &selectedRange, existingRootRanges) { 01803 const QModelIndex selectedRangeTopLeft = selectedRange.topLeft(); 01804 // existingSelection (and selectedRangeTopLeft) is D. 01805 // D is a descendant of B, so when B was removed, D might have been exposed as a root. 01806 if (isDescendantOf(range, selectedRangeTopLeft) 01807 // But D is also a descendant of part of the new selection C, which is already set to be a new root 01808 // so D would not be added to exposedSelection because C is in newRootRanges. 01809 && !isDescendantOf(newRootRanges, selectedRangeTopLeft)) 01810 exposedSelection.append(selectedRange); 01811 } 01812 removedRootRanges << range; 01813 } 01814 } 01815 } 01816 01817 QItemSelection obscuredRanges; 01818 { 01819 QListIterator<QItemSelectionRange> i(existingRootRanges); 01820 while (i.hasNext()) { 01821 const QItemSelectionRange range = i.next(); 01822 if (isDescendantOf(newRootRanges, range.topLeft())) 01823 obscuredRanges << range; 01824 } 01825 } 01826 removedRootRanges << getRootRanges(obscuredRanges); 01827 newRootRanges << getRootRanges(exposedSelection); 01828 01829 removedRootRanges = kNormalizeSelection(removedRootRanges); 01830 newRootRanges = kNormalizeSelection(newRootRanges); 01831 } else { 01832 removedRootRanges = deselected; 01833 newRootRanges = selected; 01834 } 01835 01836 removeSelectionFromProxy(removedRootRanges); 01837 01838 if (!m_selectionModel.data()->hasSelection()) 01839 { 01840 Q_ASSERT(m_rootIndexList.isEmpty()); 01841 Q_ASSERT(m_mappedFirstChildren.isEmpty()); 01842 Q_ASSERT(m_mappedParents.isEmpty()); 01843 Q_ASSERT(m_parentIds.isEmpty()); 01844 } 01845 01846 insertSelectionIntoProxy(newRootRanges); 01847 } 01848 01849 int KSelectionProxyModelPrivate::getTargetRow(int rootListRow) 01850 { 01851 Q_Q(KSelectionProxyModel); 01852 if (!m_startWithChildTrees) 01853 return rootListRow; 01854 01855 --rootListRow; 01856 while (rootListRow >= 0) { 01857 const QModelIndex idx = m_rootIndexList.at(rootListRow); 01858 Q_ASSERT(idx.isValid()); 01859 const int rowCount = q->sourceModel()->rowCount(idx); 01860 if (rowCount > 0) { 01861 static const int column = 0; 01862 const QModelIndex srcIdx = q->sourceModel()->index(rowCount - 1, column, idx); 01863 const QModelIndex proxyLastChild = mapFromSource(srcIdx); 01864 return proxyLastChild.row() + 1; 01865 } 01866 --rootListRow; 01867 } 01868 return 0; 01869 } 01870 01871 void KSelectionProxyModelPrivate::insertSelectionIntoProxy(const QItemSelection &selection) 01872 { 01873 Q_Q(KSelectionProxyModel); 01874 01875 if (selection.isEmpty()) 01876 return; 01877 01878 foreach(const QModelIndex &newIndex, selection.indexes()) { 01879 Q_ASSERT(newIndex.model() == q->sourceModel()); 01880 if (newIndex.column() > 0) 01881 continue; 01882 if (m_startWithChildTrees) { 01883 const int rootListRow = getRootListRow(m_rootIndexList, newIndex); 01884 Q_ASSERT(q->sourceModel() == newIndex.model()); 01885 const int rowCount = q->sourceModel()->rowCount(newIndex); 01886 const int startRow = getTargetRow(rootListRow); 01887 01888 if (rowCount == 0) { 01889 // Even if the newindex doesn't have any children to put into the model yet, 01890 // We still need to make sure it's future children are inserted into the model. 01891 m_rootIndexList.insert(rootListRow, newIndex); 01892 if (!m_resetting || m_layoutChanging) 01893 emit q->rootIndexAdded(newIndex); 01894 continue; 01895 } 01896 if (!m_resetting) 01897 q->beginInsertRows(QModelIndex(), startRow, startRow + rowCount - 1); 01898 Q_ASSERT(newIndex.isValid()); 01899 m_rootIndexList.insert(rootListRow, newIndex); 01900 if (!m_resetting || m_layoutChanging) 01901 emit q->rootIndexAdded(newIndex); 01902 01903 int _start = 0; 01904 for (int i = 0; i < rootListRow; ++i) 01905 _start += q->sourceModel()->rowCount(m_rootIndexList.at(i)); 01906 01907 updateInternalTopIndexes(_start, rowCount); 01908 createFirstChildMapping(newIndex, _start); 01909 createParentMappings(newIndex, 0, rowCount - 1); 01910 01911 if (!m_resetting) { 01912 q->endInsertRows(); 01913 } 01914 01915 } else { 01916 const int row = getRootListRow(m_rootIndexList, newIndex); 01917 if (!m_resetting) 01918 q->beginInsertRows(QModelIndex(), row, row); 01919 01920 Q_ASSERT(newIndex.isValid()); 01921 m_rootIndexList.insert(row, newIndex); 01922 01923 if (!m_resetting || m_layoutChanging) 01924 emit q->rootIndexAdded(newIndex); 01925 Q_ASSERT(m_rootIndexList.size() > row); 01926 updateInternalIndexes(QModelIndex(), row, 1); 01927 createParentMappings(newIndex.parent(), newIndex.row(), newIndex.row()); 01928 01929 if (!m_resetting) { 01930 q->endInsertRows(); 01931 } 01932 } 01933 } 01934 q->rootSelectionAdded(selection); 01935 } 01936 01937 KSelectionProxyModel::KSelectionProxyModel(QItemSelectionModel *selectionModel, QObject *parent) 01938 : QAbstractProxyModel(parent), d_ptr(new KSelectionProxyModelPrivate(this, selectionModel)) 01939 { 01940 } 01941 01942 KSelectionProxyModel::~KSelectionProxyModel() 01943 { 01944 delete d_ptr; 01945 } 01946 01947 void KSelectionProxyModel::setFilterBehavior(FilterBehavior behavior) 01948 { 01949 Q_D(KSelectionProxyModel); 01950 01951 beginResetModel(); 01952 01953 d->m_filterBehavior = behavior; 01954 01955 switch (behavior) { 01956 case SubTrees: { 01957 d->m_omitChildren = false; 01958 d->m_omitDescendants = false; 01959 d->m_startWithChildTrees = false; 01960 d->m_includeAllSelected = false; 01961 break; 01962 } 01963 case SubTreeRoots: { 01964 d->m_omitChildren = true; 01965 d->m_startWithChildTrees = false; 01966 d->m_includeAllSelected = false; 01967 break; 01968 } 01969 case SubTreesWithoutRoots: { 01970 d->m_omitChildren = false; 01971 d->m_omitDescendants = false; 01972 d->m_startWithChildTrees = true; 01973 d->m_includeAllSelected = false; 01974 break; 01975 } 01976 case ExactSelection: { 01977 d->m_omitChildren = true; 01978 d->m_startWithChildTrees = false; 01979 d->m_includeAllSelected = true; 01980 break; 01981 } 01982 case ChildrenOfExactSelection: { 01983 d->m_omitChildren = false; 01984 d->m_omitDescendants = true; 01985 d->m_startWithChildTrees = true; 01986 d->m_includeAllSelected = true; 01987 break; 01988 } 01989 } 01990 d->resetInternalData(); 01991 d->selectionChanged(d->m_selectionModel.data()->selection(), QItemSelection()); 01992 01993 endResetModel(); 01994 } 01995 01996 KSelectionProxyModel::FilterBehavior KSelectionProxyModel::filterBehavior() const 01997 { 01998 Q_D(const KSelectionProxyModel); 01999 return d->m_filterBehavior; 02000 } 02001 02002 void KSelectionProxyModel::setSourceModel(QAbstractItemModel *_sourceModel) 02003 { 02004 Q_D(KSelectionProxyModel); 02005 02006 Q_ASSERT(_sourceModel != this); 02007 02008 if (_sourceModel == sourceModel()) 02009 return; 02010 02011 disconnect(d->m_selectionModel.data()->model(), SIGNAL(modelAboutToBeReset()), this, SLOT(sourceModelAboutToBeReset())); 02012 connect(d->m_selectionModel.data()->model(), SIGNAL(modelAboutToBeReset()), this, SLOT(sourceModelAboutToBeReset())); 02013 disconnect(d->m_selectionModel.data()->model(), SIGNAL(modelReset()), this, SLOT(sourceModelReset())); 02014 connect(d->m_selectionModel.data()->model(), SIGNAL(modelReset()), this, SLOT(sourceModelReset())); 02015 02016 disconnect(d->m_selectionModel.data(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), 02017 this, SLOT(selectionChanged(const QItemSelection &, const QItemSelection &))); 02018 connect(d->m_selectionModel.data(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), 02019 SLOT(selectionChanged(const QItemSelection &, const QItemSelection &))); 02020 02021 beginResetModel(); 02022 d->m_resetting = true; 02023 02024 if (_sourceModel) { 02025 disconnect(_sourceModel, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)), 02026 this, SLOT(sourceRowsAboutToBeInserted(const QModelIndex &, int, int))); 02027 disconnect(_sourceModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)), 02028 this, SLOT(sourceRowsInserted(const QModelIndex &, int, int))); 02029 disconnect(_sourceModel, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)), 02030 this, SLOT(sourceRowsAboutToBeRemoved(const QModelIndex &, int, int))); 02031 disconnect(_sourceModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), 02032 this, SLOT(sourceRowsRemoved(const QModelIndex &, int, int))); 02033 // disconnect(_sourceModel, SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)), 02034 // this, SLOT(sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int))); 02035 // disconnect(_sourceModel, SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), 02036 // this, SLOT(sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int))); 02037 disconnect(_sourceModel, SIGNAL(modelAboutToBeReset()), 02038 this, SLOT(sourceModelAboutToBeReset())); 02039 disconnect(_sourceModel, SIGNAL(modelReset()), 02040 this, SLOT(sourceModelReset())); 02041 disconnect(_sourceModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), 02042 this, SLOT(sourceDataChanged(const QModelIndex &, const QModelIndex &))); 02043 disconnect(_sourceModel, SIGNAL(layoutAboutToBeChanged()), 02044 this, SLOT(sourceLayoutAboutToBeChanged())); 02045 disconnect(_sourceModel, SIGNAL(layoutChanged()), 02046 this, SLOT(sourceLayoutChanged())); 02047 disconnect(_sourceModel, SIGNAL(destroyed()), 02048 this, SLOT(sourceModelDestroyed())); 02049 } 02050 02051 // Must be called before QAbstractProxyModel::setSourceModel because it emits some signals. 02052 d->resetInternalData(); 02053 QAbstractProxyModel::setSourceModel(_sourceModel); 02054 if (_sourceModel) { 02055 d->m_indexMapper = new KModelIndexProxyMapper(_sourceModel, d->m_selectionModel.data()->model(), this); 02056 if (d->m_selectionModel.data()->hasSelection()) 02057 d->selectionChanged(d->m_selectionModel.data()->selection(), QItemSelection()); 02058 02059 connect(_sourceModel, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)), 02060 SLOT(sourceRowsAboutToBeInserted(const QModelIndex &, int, int))); 02061 connect(_sourceModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)), 02062 SLOT(sourceRowsInserted(const QModelIndex &, int, int))); 02063 connect(_sourceModel, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)), 02064 SLOT(sourceRowsAboutToBeRemoved(const QModelIndex &, int, int))); 02065 connect(_sourceModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), 02066 SLOT(sourceRowsRemoved(const QModelIndex &, int, int))); 02067 // connect(_sourceModel, SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)), 02068 // SLOT(sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int))); 02069 // connect(_sourceModel, SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), 02070 // SLOT(sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int))); 02071 connect(_sourceModel, SIGNAL(modelAboutToBeReset()), 02072 SLOT(sourceModelAboutToBeReset())); 02073 connect(_sourceModel, SIGNAL(modelReset()), 02074 SLOT(sourceModelReset())); 02075 connect(_sourceModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), 02076 SLOT(sourceDataChanged(const QModelIndex &, const QModelIndex &))); 02077 connect(_sourceModel, SIGNAL(layoutAboutToBeChanged()), 02078 SLOT(sourceLayoutAboutToBeChanged())); 02079 connect(_sourceModel, SIGNAL(layoutChanged()), 02080 SLOT(sourceLayoutChanged())); 02081 connect(_sourceModel, SIGNAL(destroyed()), 02082 SLOT(sourceModelDestroyed())); 02083 } 02084 02085 d->m_resetting = false; 02086 endResetModel(); 02087 } 02088 02089 QModelIndex KSelectionProxyModel::mapToSource(const QModelIndex &proxyIndex) const 02090 { 02091 Q_D(const KSelectionProxyModel); 02092 02093 if (!proxyIndex.isValid() || !sourceModel() || d->m_rootIndexList.isEmpty()) 02094 return QModelIndex(); 02095 02096 Q_ASSERT(proxyIndex.internalPointer() >= 0); 02097 Q_ASSERT(proxyIndex.model() == this); 02098 02099 if (proxyIndex.internalPointer() == 0) 02100 return d->mapTopLevelToSource(proxyIndex.row(), proxyIndex.column()); 02101 02102 const QModelIndex proxyParent = d->parentForId(proxyIndex.internalPointer()); 02103 Q_ASSERT(proxyParent.isValid()); 02104 const QModelIndex sourceParent = d->mapParentToSource(proxyParent); 02105 Q_ASSERT(sourceParent.isValid()); 02106 return sourceModel()->index(proxyIndex.row(), proxyIndex.column(), sourceParent); 02107 } 02108 02109 QModelIndex KSelectionProxyModel::mapFromSource(const QModelIndex &sourceIndex) const 02110 { 02111 Q_D(const KSelectionProxyModel); 02112 02113 if (!sourceModel() || !sourceIndex.isValid() || d->m_rootIndexList.isEmpty()) 02114 return QModelIndex(); 02115 02116 Q_ASSERT(sourceIndex.model() == sourceModel()); 02117 02118 if (!sourceIndex.isValid()) 02119 return QModelIndex(); 02120 02121 if (!d->ensureMappable(sourceIndex)) 02122 return QModelIndex(); 02123 02124 return d->mapFromSource(sourceIndex); 02125 } 02126 02127 int KSelectionProxyModel::rowCount(const QModelIndex &index) const 02128 { 02129 Q_D(const KSelectionProxyModel); 02130 02131 if (!sourceModel() || index.column() > 0 || d->m_rootIndexList.isEmpty()) 02132 return 0; 02133 02134 Q_ASSERT(index.isValid() ? index.model() == this : true); 02135 if (!index.isValid()) 02136 return d->topLevelRowCount(); 02137 02138 // index is valid 02139 if (d->isFlat()) 02140 return 0; 02141 02142 QModelIndex sourceParent = d->mapParentToSource(index); 02143 02144 if (!sourceParent.isValid() && sourceModel()->hasChildren(sourceParent)) { 02145 sourceParent = mapToSource(index.parent()); 02146 d->createParentMappings(sourceParent, 0, sourceModel()->rowCount(sourceParent) - 1); 02147 sourceParent = d->mapParentToSource(index); 02148 } 02149 02150 if (!sourceParent.isValid()) 02151 return 0; 02152 02153 return sourceModel()->rowCount(sourceParent); 02154 } 02155 02156 QModelIndex KSelectionProxyModel::index(int row, int column, const QModelIndex &parent) const 02157 { 02158 Q_D(const KSelectionProxyModel); 02159 02160 if (!sourceModel() || d->m_rootIndexList.isEmpty() || !hasIndex(row, column, parent)) 02161 return QModelIndex(); 02162 02163 Q_ASSERT(parent.isValid() ? parent.model() == this : true); 02164 02165 if (!parent.isValid()) 02166 return d->createTopLevelIndex(row, column); 02167 02168 void * const parentId = d->parentId(parent); 02169 Q_ASSERT(parentId); 02170 return createIndex(row, column, parentId); 02171 } 02172 02173 QModelIndex KSelectionProxyModel::parent(const QModelIndex &index) const 02174 { 02175 Q_D(const KSelectionProxyModel); 02176 02177 if (!sourceModel() || !index.isValid() || d->m_rootIndexList.isEmpty()) 02178 return QModelIndex(); 02179 02180 Q_ASSERT(index.model() == this); 02181 02182 return d->parentForId(index.internalPointer()); 02183 } 02184 02185 Qt::ItemFlags KSelectionProxyModel::flags(const QModelIndex &index) const 02186 { 02187 if (!index.isValid() || !sourceModel()) 02188 return QAbstractProxyModel::flags(index); 02189 02190 Q_ASSERT(index.model() == this); 02191 02192 const QModelIndex srcIndex = mapToSource(index); 02193 Q_ASSERT(srcIndex.isValid()); 02194 return sourceModel()->flags(srcIndex); 02195 } 02196 02197 QVariant KSelectionProxyModel::data(const QModelIndex & index, int role) const 02198 { 02199 if (!sourceModel()) 02200 return QVariant(); 02201 02202 if (index.isValid()) { 02203 Q_ASSERT(index.model() == this); 02204 const QModelIndex idx = mapToSource(index); 02205 return idx.data(role); 02206 } 02207 return sourceModel()->data(index, role); 02208 } 02209 02210 QVariant KSelectionProxyModel::headerData(int section, Qt::Orientation orientation, int role) const 02211 { 02212 if (!sourceModel()) 02213 return QVariant(); 02214 return sourceModel()->headerData(section, orientation, role); 02215 } 02216 02217 QMimeData* KSelectionProxyModel::mimeData(const QModelIndexList & indexes) const 02218 { 02219 if (!sourceModel()) 02220 return QAbstractProxyModel::mimeData(indexes); 02221 QModelIndexList sourceIndexes; 02222 foreach(const QModelIndex& index, indexes) 02223 sourceIndexes << mapToSource(index); 02224 return sourceModel()->mimeData(sourceIndexes); 02225 } 02226 02227 QStringList KSelectionProxyModel::mimeTypes() const 02228 { 02229 if (!sourceModel()) 02230 return QAbstractProxyModel::mimeTypes(); 02231 return sourceModel()->mimeTypes(); 02232 } 02233 02234 Qt::DropActions KSelectionProxyModel::supportedDropActions() const 02235 { 02236 if (!sourceModel()) 02237 return QAbstractProxyModel::supportedDropActions(); 02238 return sourceModel()->supportedDropActions(); 02239 } 02240 02241 bool KSelectionProxyModel::hasChildren(const QModelIndex & parent) const 02242 { 02243 Q_D(const KSelectionProxyModel); 02244 02245 if (d->m_rootIndexList.isEmpty() || !sourceModel()) 02246 return false; 02247 02248 if (parent.isValid()) { 02249 Q_ASSERT(parent.model() == this); 02250 if (d->isFlat()) 02251 return false; 02252 return sourceModel()->hasChildren(mapToSource(parent)); 02253 } 02254 02255 if (!d->m_startWithChildTrees) 02256 return true; 02257 02258 return !d->m_mappedFirstChildren.isEmpty(); 02259 } 02260 02261 int KSelectionProxyModel::columnCount(const QModelIndex &index) const 02262 { 02263 Q_D(const KSelectionProxyModel); 02264 02265 if (!sourceModel() || index.column() > 0 02266 // Qt 4.6 doesn't notice changes in columnCount, so we can't return 0 when 02267 // it's actually 0 ,but must return what the source model says, even if we 02268 // have no rows or columns. 02269 #if QT_VERSION >= 0x040700 02270 || d->m_rootIndexList.isEmpty() 02271 #endif 02272 ) 02273 return 0; 02274 02275 return sourceModel()->columnCount(mapToSource(index)); 02276 } 02277 02278 QItemSelectionModel* KSelectionProxyModel::selectionModel() const 02279 { 02280 Q_D(const KSelectionProxyModel); 02281 return d->m_selectionModel.data(); 02282 } 02283 02284 bool KSelectionProxyModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) 02285 { 02286 Q_D(const KSelectionProxyModel); 02287 if (!sourceModel() || d->m_rootIndexList.isEmpty()) 02288 return false; 02289 02290 if ((row == -1) && (column == -1)) 02291 return sourceModel()->dropMimeData(data, action, -1, -1, mapToSource(parent)); 02292 02293 int source_destination_row = -1; 02294 int source_destination_column = -1; 02295 QModelIndex source_parent; 02296 02297 if (row == rowCount(parent)) { 02298 source_parent = mapToSource(parent); 02299 source_destination_row = sourceModel()->rowCount(source_parent); 02300 } else { 02301 const QModelIndex proxy_index = index(row, column, parent); 02302 const QModelIndex source_index = mapToSource(proxy_index); 02303 source_destination_row = source_index.row(); 02304 source_destination_column = source_index.column(); 02305 source_parent = source_index.parent(); 02306 } 02307 return sourceModel()->dropMimeData(data, action, source_destination_row, 02308 source_destination_column, source_parent); 02309 } 02310 02311 QList<QPersistentModelIndex> KSelectionProxyModel::sourceRootIndexes() const 02312 { 02313 Q_D(const KSelectionProxyModel); 02314 return d->m_rootIndexList; 02315 } 02316 02317 QModelIndexList KSelectionProxyModel::match(const QModelIndex& start, int role, const QVariant& value, int hits, Qt::MatchFlags flags) const 02318 { 02319 if (role < Qt::UserRole) 02320 return QAbstractProxyModel::match(start, role, value, hits, flags); 02321 02322 QModelIndexList list; 02323 QModelIndex proxyIndex; 02324 foreach(const QModelIndex &idx, sourceModel()->match(mapToSource(start), role, value, hits, flags)) { 02325 proxyIndex = mapFromSource(idx); 02326 if (proxyIndex.isValid()) 02327 list << proxyIndex; 02328 } 02329 return list; 02330 } 02331 02332 QItemSelection KSelectionProxyModel::mapSelectionFromSource(const QItemSelection& selection) const 02333 { 02334 Q_D(const KSelectionProxyModel); 02335 if (!d->m_startWithChildTrees && d->m_includeAllSelected) { 02336 // QAbstractProxyModel::mapSelectionFromSource puts invalid ranges in the result 02337 // without checking. We can't have that. 02338 QItemSelection proxySelection; 02339 foreach(const QItemSelectionRange &range, selection) 02340 { 02341 QModelIndex proxyTopLeft = mapFromSource(range.topLeft()); 02342 if (!proxyTopLeft.isValid()) 02343 continue; 02344 QModelIndex proxyBottomRight = mapFromSource(range.bottomRight()); 02345 Q_ASSERT(proxyBottomRight.isValid()); 02346 proxySelection.append(QItemSelectionRange(proxyTopLeft, proxyBottomRight)); 02347 } 02348 return proxySelection; 02349 } 02350 02351 QItemSelection proxySelection; 02352 QItemSelection::const_iterator it = selection.constBegin(); 02353 const QItemSelection::const_iterator end = selection.constEnd(); 02354 for ( ; it != end; ++it) { 02355 const QModelIndex proxyTopLeft = mapFromSource(it->topLeft()); 02356 if (!proxyTopLeft.isValid()) 02357 continue; 02358 02359 if (it->height() == 1 && it->width() == 1) 02360 proxySelection.append(QItemSelectionRange(proxyTopLeft, proxyTopLeft)); 02361 else 02362 proxySelection.append(QItemSelectionRange(proxyTopLeft, d->mapFromSource(it->bottomRight()))); 02363 } 02364 return proxySelection; 02365 } 02366 02367 QItemSelection KSelectionProxyModel::mapSelectionToSource(const QItemSelection& selection) const 02368 { 02369 Q_D(const KSelectionProxyModel); 02370 02371 if (selection.isEmpty()) 02372 return selection; 02373 02374 if (!d->m_startWithChildTrees && d->m_includeAllSelected) { 02375 // QAbstractProxyModel::mapSelectionFromSource puts invalid ranges in the result 02376 // without checking. We can't have that. 02377 QItemSelection sourceSelection; 02378 foreach(const QItemSelectionRange &range, selection) 02379 { 02380 QModelIndex sourceTopLeft = mapToSource(range.topLeft()); 02381 Q_ASSERT(sourceTopLeft.isValid()); 02382 02383 QModelIndex sourceBottomRight = mapToSource(range.bottomRight()); 02384 Q_ASSERT(sourceBottomRight.isValid()); 02385 sourceSelection.append(QItemSelectionRange(sourceTopLeft, sourceBottomRight)); 02386 } 02387 return sourceSelection; 02388 } 02389 02390 02391 QItemSelection sourceSelection; 02392 QItemSelection extraSelection; 02393 QItemSelection::const_iterator it = selection.constBegin(); 02394 const QItemSelection::const_iterator end = selection.constEnd(); 02395 for ( ; it != end; ++it) { 02396 const QModelIndex sourceTopLeft = mapToSource(it->topLeft()); 02397 if (it->height() == 1 && it->width() == 1) { 02398 sourceSelection.append(QItemSelectionRange(sourceTopLeft, sourceTopLeft)); 02399 } else if (it->parent().isValid()) { 02400 sourceSelection.append(QItemSelectionRange(sourceTopLeft, mapToSource(it->bottomRight()))); 02401 } else { 02402 // A contiguous selection in the proxy might not be contiguous in the source if it 02403 // is at the top level of the proxy. 02404 if (d->m_startWithChildTrees) { 02405 const QModelIndex sourceParent = mapFromSource(sourceTopLeft); 02406 Q_ASSERT(sourceParent.isValid()); 02407 const int rowCount = sourceModel()->rowCount(sourceParent); 02408 if (rowCount < it->bottom()) { 02409 Q_ASSERT(sourceTopLeft.isValid()); 02410 Q_ASSERT(it->bottomRight().isValid()); 02411 const QModelIndex sourceBottomRight = mapToSource(it->bottomRight()); 02412 Q_ASSERT(sourceBottomRight.isValid()); 02413 sourceSelection.append(QItemSelectionRange(sourceTopLeft, sourceBottomRight)); 02414 continue; 02415 } 02416 // Store the contiguous part... 02417 const QModelIndex sourceBottomRight = sourceModel()->index(rowCount - 1, it->right(), sourceParent); 02418 Q_ASSERT(sourceTopLeft.isValid()); 02419 Q_ASSERT(sourceBottomRight.isValid()); 02420 sourceSelection.append(QItemSelectionRange(sourceTopLeft, sourceBottomRight)); 02421 // ... and the rest will be processed later. 02422 extraSelection.append(QItemSelectionRange(createIndex(it->top() - rowCount, it->right()), it->bottomRight())); 02423 } else { 02424 QItemSelection topSelection; 02425 const QModelIndex idx = createIndex(it->top(), it->right()); 02426 const QModelIndex sourceIdx = mapToSource(idx); 02427 Q_ASSERT(sourceIdx.isValid()); 02428 topSelection.append(QItemSelectionRange(sourceTopLeft, sourceIdx)); 02429 for (int i = it->top() + 1; i < it->bottom(); ++it) { 02430 const QModelIndex left = mapToSource(createIndex(i, 0)); 02431 const QModelIndex right = mapToSource(createIndex(i, it->right())); 02432 Q_ASSERT(left.isValid()); 02433 Q_ASSERT(right.isValid()); 02434 topSelection.append(QItemSelectionRange(left, right)); 02435 } 02436 sourceSelection += kNormalizeSelection(topSelection); 02437 } 02438 } 02439 } 02440 sourceSelection << mapSelectionToSource(extraSelection); 02441 return sourceSelection; 02442 } 02443 02444 #include "moc_kselectionproxymodel.cpp"
KDE 4.6 API Reference