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 struct PendingSelectionChange 00571 { 00572 PendingSelectionChange() {} 00573 PendingSelectionChange(const QItemSelection &selected_, const QItemSelection &deselected_) 00574 : selected(selected_), deselected(deselected_) 00575 { 00576 00577 } 00578 QItemSelection selected; 00579 QItemSelection deselected; 00580 }; 00581 QVector<PendingSelectionChange> m_pendingSelectionChanges; 00582 }; 00583 00584 void KSelectionProxyModelPrivate::emitContinuousRanges(const QModelIndex &sourceFirst, const QModelIndex &sourceLast, 00585 const QModelIndex &proxyFirst, const QModelIndex &proxyLast) 00586 { 00587 Q_Q(KSelectionProxyModel); 00588 00589 Q_ASSERT(sourceFirst.model() == q->sourceModel()); 00590 Q_ASSERT(sourceLast.model() == q->sourceModel()); 00591 Q_ASSERT(proxyFirst.model() == q); 00592 Q_ASSERT(proxyLast.model() == q); 00593 00594 const int proxyRangeSize = proxyLast.row() - proxyFirst.row(); 00595 const int sourceRangeSize = sourceLast.row() - sourceFirst.row(); 00596 00597 if (proxyRangeSize == sourceRangeSize) { 00598 emit q->dataChanged(proxyFirst, proxyLast); 00599 return; 00600 } 00601 00602 00603 // TODO: Loop to skip descendant ranges. 00604 // int lastRow; 00605 // 00606 // const QModelIndex sourceHalfWay = sourceFirst.sibling(sourceFirst.row() + (sourceRangeSize / 2)); 00607 // const QModelIndex proxyHalfWay = proxyFirst.sibling(proxyFirst.row() + (proxyRangeSize / 2)); 00608 // const QModelIndex mappedSourceHalfway = q->mapToSource(proxyHalfWay); 00609 // 00610 // const int halfProxyRange = mappedSourceHalfway.row() - proxyFirst.row(); 00611 // const int halfSourceRange = sourceHalfWay.row() - sourceFirst.row(); 00612 // 00613 // if (proxyRangeSize == sourceRangeSize) 00614 // { 00615 // emit q->dataChanged(proxyFirst, proxyLast.sibling(proxyFirst.row() + proxyRangeSize, proxyLast.column())); 00616 // return; 00617 // } 00618 00619 emit q->dataChanged(proxyFirst, proxyLast); 00620 } 00621 00622 void KSelectionProxyModelPrivate::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) 00623 { 00624 Q_Q(KSelectionProxyModel); 00625 00626 Q_ASSERT(topLeft.model() == q->sourceModel()); 00627 Q_ASSERT(bottomRight.model() == q->sourceModel()); 00628 00629 const QModelIndex sourceRangeParent = topLeft.parent(); 00630 if (!sourceRangeParent.isValid() && m_startWithChildTrees && !m_rootIndexList.contains(sourceRangeParent)) 00631 return; 00632 00633 const QModelIndex proxyTopLeft = q->mapFromSource(topLeft); 00634 const QModelIndex proxyBottomRight = q->mapFromSource(bottomRight); 00635 00636 const QModelIndex proxyRangeParent = proxyTopLeft.parent(); 00637 00638 if (!m_omitChildren && m_omitDescendants && m_startWithChildTrees && m_includeAllSelected) { 00639 // ChildrenOfExactSelection 00640 if (proxyTopLeft.isValid()) 00641 emitContinuousRanges(topLeft, bottomRight, proxyTopLeft, proxyBottomRight); 00642 return; 00643 } 00644 00645 if ((m_omitChildren && !m_startWithChildTrees && m_includeAllSelected) 00646 || (!proxyRangeParent.isValid() && !m_startWithChildTrees)) { 00647 // Exact selection and SubTreeRoots and SubTrees in top level 00648 // Emit continuous ranges. 00649 QList<int> changedRows; 00650 for (int row = topLeft.row(); row <= bottomRight.row(); ++row) { 00651 const QModelIndex index = q->sourceModel()->index(row, topLeft.column(), topLeft.parent()); 00652 const int idx = m_rootIndexList.indexOf(index); 00653 if (idx != -1) { 00654 changedRows.append(idx); 00655 } 00656 } 00657 if (changedRows.isEmpty()) 00658 return; 00659 int first = changedRows.first(); 00660 int previous = first; 00661 QList<int>::const_iterator it = changedRows.constBegin(); 00662 const QList<int>::const_iterator end = changedRows.constEnd(); 00663 for ( ; it != end; ++it) { 00664 if (*it == previous + 1) { 00665 ++previous; 00666 } else { 00667 const QModelIndex _top = q->index(first, topLeft.column()); 00668 const QModelIndex _bottom = q->index(previous, bottomRight.column()); 00669 emit q->dataChanged(_top, _bottom); 00670 previous = first = *it; 00671 } 00672 } 00673 if (first != previous) { 00674 const QModelIndex _top = q->index(first, topLeft.column()); 00675 const QModelIndex _bottom = q->index(previous, bottomRight.column()); 00676 emit q->dataChanged(_top, _bottom); 00677 } 00678 return; 00679 } 00680 if (proxyRangeParent.isValid()) { 00681 if (m_omitChildren && !m_startWithChildTrees && !m_includeAllSelected) 00682 // SubTreeRoots 00683 return; 00684 if (!proxyTopLeft.isValid()) 00685 return; 00686 // SubTrees and SubTreesWithoutRoots 00687 emit q->dataChanged(proxyTopLeft, proxyBottomRight); 00688 return; 00689 } 00690 00691 if (m_startWithChildTrees && !m_omitChildren && !m_includeAllSelected && !m_omitDescendants) { 00692 // SubTreesWithoutRoots 00693 if (proxyTopLeft.isValid()) 00694 emit q->dataChanged(proxyTopLeft, proxyBottomRight); 00695 return; 00696 } 00697 } 00698 00699 void KSelectionProxyModelPrivate::sourceLayoutAboutToBeChanged() 00700 { 00701 Q_Q(KSelectionProxyModel); 00702 00703 if (m_ignoreNextLayoutAboutToBeChanged) { 00704 m_ignoreNextLayoutAboutToBeChanged = false; 00705 return; 00706 } 00707 00708 if (m_rootIndexList.isEmpty()) 00709 return; 00710 00711 emit q->layoutAboutToBeChanged(); 00712 00713 QPersistentModelIndex srcPersistentIndex; 00714 foreach(const QPersistentModelIndex &proxyPersistentIndex, q->persistentIndexList()) { 00715 m_proxyIndexes << proxyPersistentIndex; 00716 Q_ASSERT(proxyPersistentIndex.isValid()); 00717 srcPersistentIndex = q->mapToSource(proxyPersistentIndex); 00718 Q_ASSERT(srcPersistentIndex.isValid()); 00719 m_layoutChangePersistentIndexes << srcPersistentIndex; 00720 } 00721 00722 QItemSelection selection; 00723 foreach (const QModelIndex &rootIndex, m_rootIndexList) 00724 { 00725 // This will be optimized later. 00726 emit q->rootIndexAboutToBeRemoved(rootIndex); 00727 selection.append(QItemSelectionRange(rootIndex, rootIndex)); 00728 } 00729 00730 selection = kNormalizeSelection(selection); 00731 emit q->rootSelectionAboutToBeRemoved(selection); 00732 00733 m_rootIndexList.clear(); 00734 } 00735 00736 void KSelectionProxyModelPrivate::sourceLayoutChanged() 00737 { 00738 Q_Q(KSelectionProxyModel); 00739 00740 if (m_ignoreNextLayoutChanged) { 00741 m_ignoreNextLayoutChanged = false; 00742 return; 00743 } 00744 00745 if (m_selectionModel.data()->selection().isEmpty()) { 00746 return; 00747 } 00748 00749 // Handling this signal is slow. 00750 // The problem is that anything can happen between emissions of layoutAboutToBeChanged and layoutChanged. 00751 // We can't assume anything is the same about the structure anymore. items have been sorted, items which 00752 // were parents before are now not, items which were not parents before now are, items which used to be the 00753 // first child are now the Nth child and items which used to be the Nth child are now the first child. 00754 // We effectively can't update our mapping because we don't have enough information to update everything. 00755 // The only way we would have is if we take a persistent index of the entire source model 00756 // on sourceLayoutAboutToBeChanged and then examine it here. That would be far too expensive. 00757 // Instead we just have to clear the entire mapping and recreate it. 00758 00759 m_rootIndexList.clear(); 00760 m_mappedFirstChildren.clear(); 00761 m_mappedParents.clear(); 00762 m_parentIds.clear(); 00763 00764 m_resetting = true; 00765 m_layoutChanging = true; 00766 selectionChanged(m_selectionModel.data()->selection(), QItemSelection()); 00767 m_resetting = false; 00768 m_layoutChanging = false; 00769 00770 for (int i = 0; i < m_proxyIndexes.size(); ++i) { 00771 q->changePersistentIndex(m_proxyIndexes.at(i), q->mapFromSource(m_layoutChangePersistentIndexes.at(i))); 00772 } 00773 00774 m_layoutChangePersistentIndexes.clear(); 00775 m_proxyIndexes.clear(); 00776 00777 emit q->layoutChanged(); 00778 } 00779 00780 void KSelectionProxyModelPrivate::resetInternalData() 00781 { 00782 m_rootIndexList.clear(); 00783 m_layoutChangePersistentIndexes.clear(); 00784 m_proxyIndexes.clear(); 00785 m_mappedParents.clear(); 00786 m_parentIds.clear(); 00787 m_mappedFirstChildren.clear(); 00788 m_voidPointerFactory.clear(); 00789 } 00790 00791 void KSelectionProxyModelPrivate::sourceModelDestroyed() 00792 { 00793 Q_Q(KSelectionProxyModel); 00794 // There is very little we can do here. 00795 resetInternalData(); 00796 m_resetting = false; 00797 // q->endResetModel(); 00798 } 00799 00800 void KSelectionProxyModelPrivate::sourceModelAboutToBeReset() 00801 { 00802 Q_Q(KSelectionProxyModel); 00803 00804 // We might be resetting as a result of the selection source model resetting. 00805 // If so we don't want to emit 00806 // sourceModelAboutToBeReset 00807 // sourceModelAboutToBeReset 00808 // sourceModelReset 00809 // sourceModelReset 00810 // So we ensure that we just emit one. 00811 if (m_resetting) { 00812 00813 // If both the source model and the selection source model are reset, 00814 // We want to begin our reset before the first one is reset and end 00815 // it after the second one is reset. 00816 m_doubleResetting = true; 00817 return; 00818 } 00819 00820 q->beginResetModel(); 00821 m_resetting = true; 00822 } 00823 00824 void KSelectionProxyModelPrivate::sourceModelReset() 00825 { 00826 Q_Q(KSelectionProxyModel); 00827 00828 if (m_doubleResetting) { 00829 m_doubleResetting = false; 00830 return; 00831 } 00832 00833 resetInternalData(); 00834 // No need to try to refill this. When the model is reset it doesn't have a meaningful selection anymore, 00835 // but when it gets one we'll be notified anyway. 00836 if (!m_selectionModel.isNull()) 00837 m_selectionModel.data()->reset(); 00838 m_resetting = false; 00839 q->endResetModel(); 00840 } 00841 00842 int KSelectionProxyModelPrivate::getProxyInitialRow(const QModelIndex &parent) const 00843 { 00844 Q_ASSERT(m_rootIndexList.contains(parent)); 00845 00846 // The difficulty here is that parent and parent.parent() might both be in the m_rootIndexList. 00847 00848 // - A 00849 // - B 00850 // - - C 00851 // - - D 00852 // - - - E 00853 00854 // Consider that B and D are selected. The proxy model is: 00855 00856 // - C 00857 // - D 00858 // - E 00859 00860 // Then D gets a new child at 0. In that case we require adding F between D and E. 00861 00862 // Consider instead that D gets removed. Then @p parent will be B. 00863 00864 00865 Q_Q(const KSelectionProxyModel); 00866 00867 Q_ASSERT(parent.model() == q->sourceModel()); 00868 00869 int parentPosition = m_rootIndexList.indexOf(parent); 00870 00871 QModelIndex parentAbove; 00872 00873 // If parentPosition == 0, then parent.parent() is not also in the model. (ordering is preserved) 00874 while (parentPosition > 0) { 00875 parentPosition--; 00876 00877 parentAbove = m_rootIndexList.at(parentPosition); 00878 Q_ASSERT(parentAbove.isValid()); 00879 00880 int rows = q->sourceModel()->rowCount(parentAbove); 00881 if (rows > 0) { 00882 QModelIndex sourceIndexAbove = q->sourceModel()->index(rows - 1, 0, parentAbove); 00883 Q_ASSERT(sourceIndexAbove.isValid()); 00884 QModelIndex proxyChildAbove = mapFromSource(sourceIndexAbove); 00885 Q_ASSERT(proxyChildAbove.isValid()); 00886 return proxyChildAbove.row() + 1; 00887 } 00888 } 00889 return 0; 00890 } 00891 00892 void KSelectionProxyModelPrivate::updateFirstChildMapping(const QModelIndex& parent, int offset) 00893 { 00894 Q_Q(KSelectionProxyModel); 00895 00896 Q_ASSERT(parent.isValid() ? parent.model() == q->sourceModel() : true); 00897 00898 static const int column = 0; 00899 static const int row = 0; 00900 00901 const QPersistentModelIndex srcIndex = q->sourceModel()->index(row, column, parent); 00902 00903 const QPersistentModelIndex previousFirstChild = q->sourceModel()->index(offset, column, parent); 00904 00905 SourceIndexProxyRowMapping::left_iterator it = m_mappedFirstChildren.findLeft(previousFirstChild); 00906 if (it == m_mappedFirstChildren.leftEnd()) 00907 return; 00908 00909 Q_ASSERT(srcIndex.isValid()); 00910 const int proxyRow = it.value(); 00911 Q_ASSERT(proxyRow >= 0); 00912 00913 m_mappedFirstChildren.eraseLeft(it); 00914 00915 // The proxy row in the mapping has already been updated by the offset in updateInternalTopIndexes 00916 // so we restore it by applying the reverse. 00917 m_mappedFirstChildren.insert(srcIndex, proxyRow - offset); 00918 } 00919 00920 QPair< int, int > KSelectionProxyModelPrivate::beginInsertRows(const QModelIndex& parent, int start, int end) const 00921 { 00922 const QModelIndex proxyParent = mapFromSource(parent); 00923 00924 if (!proxyParent.isValid()) 00925 { 00926 if (!m_startWithChildTrees) 00927 return qMakePair(-1, -1); 00928 00929 if (!m_rootIndexList.contains(parent)) 00930 return qMakePair(-1, -1); 00931 } 00932 00933 if (!m_startWithChildTrees) { 00934 // SubTrees 00935 if (proxyParent.isValid()) 00936 return qMakePair(start, end); 00937 return qMakePair(-1, -1); 00938 } 00939 00940 if (!m_includeAllSelected && proxyParent.isValid()) { 00941 // SubTreesWithoutRoots deeper than topLevel 00942 return qMakePair(start, end); 00943 } 00944 00945 if (!m_rootIndexList.contains(parent)) 00946 return qMakePair(-1, -1); 00947 00948 const int proxyStartRow = getProxyInitialRow(parent) + start; 00949 return qMakePair(proxyStartRow, proxyStartRow + (end - start)); 00950 } 00951 00952 void KSelectionProxyModelPrivate::sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end) 00953 { 00954 Q_Q(KSelectionProxyModel); 00955 00956 Q_ASSERT(parent.isValid() ? parent.model() == q->sourceModel() : true); 00957 00958 if (!m_selectionModel.data()->hasSelection()) 00959 return; 00960 00961 if (m_omitChildren) 00962 // ExactSelection and SubTreeRoots 00963 return; 00964 00965 // topLevel insertions can be ignored because topLevel items would need to be selected to affect the proxy. 00966 if (!parent.isValid()) 00967 return; 00968 00969 QPair<int, int> pair = beginInsertRows(parent, start, end); 00970 if (pair.first == -1) 00971 return; 00972 00973 const QModelIndex proxyParent = m_startWithChildTrees ? QModelIndex() : mapFromSource(parent); 00974 00975 m_rowsInserted = true; 00976 q->beginInsertRows(proxyParent, pair.first, pair.second); 00977 } 00978 00979 void KSelectionProxyModelPrivate::endInsertRows(const QModelIndex& parent, int start, int end) 00980 { 00981 Q_Q(const KSelectionProxyModel); 00982 const QModelIndex proxyParent = mapFromSource(parent); 00983 const int offset = end - start + 1; 00984 00985 const bool isNewParent = (q->sourceModel()->rowCount(parent) == offset); 00986 00987 if (m_startWithChildTrees && m_rootIndexList.contains(parent)) { 00988 const int proxyInitialRow = getProxyInitialRow(parent); 00989 Q_ASSERT(proxyInitialRow >= 0); 00990 const int proxyStartRow = proxyInitialRow + start; 00991 00992 updateInternalTopIndexes(proxyStartRow, offset); 00993 if (isNewParent) 00994 createFirstChildMapping(parent, proxyStartRow); 00995 else if (start == 0) 00996 // We already have a first child mapping, but what we have mapped is not the first child anymore 00997 // so we need to update it. 00998 updateFirstChildMapping(parent, end + 1); 00999 } else { 01000 Q_ASSERT(proxyParent.isValid()); 01001 if (!isNewParent) 01002 updateInternalIndexes(proxyParent, start, offset); 01003 else 01004 createParentMappings(parent.parent(), parent.row(), parent.row()); 01005 } 01006 createParentMappings(parent, start, end); 01007 } 01008 01009 void KSelectionProxyModelPrivate::sourceRowsInserted(const QModelIndex &parent, int start, int end) 01010 { 01011 Q_Q(KSelectionProxyModel); 01012 01013 Q_ASSERT(parent.isValid() ? parent.model() == q->sourceModel() : true); 01014 01015 if (!m_rowsInserted) 01016 return; 01017 m_rowsInserted = false; 01018 endInsertRows(parent, start, end); 01019 q->endInsertRows(); 01020 foreach(const PendingSelectionChange &pendingChange, m_pendingSelectionChanges) 01021 { 01022 selectionChanged(pendingChange.selected, pendingChange.deselected); 01023 } 01024 m_pendingSelectionChanges.clear(); 01025 } 01026 01027 QPair<int, int> KSelectionProxyModelPrivate::beginRemoveRows(const QModelIndex& parent, int start, int end) const 01028 { 01029 Q_Q(const KSelectionProxyModel); 01030 01031 QPair<int, int> pair = qMakePair(start, end); 01032 01033 if (m_omitChildren && !m_startWithChildTrees && !m_includeAllSelected) { 01034 // SubTreeRoots 01035 if (m_rootIndexList.contains(parent) || isDescendantOf(m_rootIndexList, parent)) { 01036 return qMakePair(-1, -1); 01037 } 01038 } 01039 01040 const QModelIndex proxyParent = mapParentFromSource(parent); 01041 01042 if (!m_includeAllSelected && !m_omitChildren) { 01043 // SubTrees and SubTreesWithoutRoots 01044 if (proxyParent.isValid()) { 01045 return pair; 01046 } 01047 if (m_startWithChildTrees && m_rootIndexList.contains(parent)) { 01048 // SubTreesWithoutRoots topLevel 01049 const int proxyStartRow = getProxyInitialRow(parent) + start; 01050 return qMakePair(proxyStartRow, proxyStartRow + (end - start)); 01051 } 01052 } 01053 01054 if (m_includeAllSelected && m_startWithChildTrees) { 01055 // ChildrenOfExactSelection 01056 int position = m_rootIndexList.indexOf(parent); 01057 if (position != -1) { 01058 const int proxyStartRow = getProxyInitialRow(parent) + start; 01059 int proxyEndRow = proxyStartRow + (end - start); 01060 ++position; 01061 while (m_rootIndexList.size() < position) { 01062 const QModelIndex idx = m_rootIndexList.at(position); 01063 if (isDescendantOf(parent, idx)) 01064 proxyEndRow += q->sourceModel()->rowCount(idx); 01065 else 01066 break; 01067 } 01068 return qMakePair(proxyStartRow, proxyEndRow); 01069 } 01070 } 01071 01072 QList<QPersistentModelIndex>::const_iterator rootIt = m_rootIndexList.constBegin(); 01073 const QList<QPersistentModelIndex>::const_iterator rootEnd = m_rootIndexList.constEnd(); 01074 int rootPosition = 0; 01075 int rootStartRemove = -1; 01076 int rootEndRemove = -1; 01077 int siblingCount = 0; 01078 01079 for ( ; rootIt != rootEnd; ++rootIt, ++rootPosition) { 01080 if (m_omitChildren && m_includeAllSelected) { 01081 // ExactSelection 01082 if (parent == rootIt->parent() && rootIt->row() <= end && rootIt->row() >= start) { 01083 if (rootStartRemove == -1) 01084 rootStartRemove = rootPosition; 01085 ++rootEndRemove; 01086 } else { 01087 if (rootStartRemove != -1) 01088 break; 01089 } 01090 } else { 01091 if (isDescendantOf(parent, *rootIt)) { 01092 if (rootStartRemove == -1) 01093 rootStartRemove = rootPosition; 01094 ++rootEndRemove; 01095 if (m_startWithChildTrees) 01096 siblingCount += q->sourceModel()->rowCount(*rootIt); 01097 } else { 01098 if (rootStartRemove != -1) 01099 break; 01100 } 01101 } 01102 } 01103 if (rootStartRemove != -1) { 01104 return qMakePair(siblingCount + rootStartRemove, siblingCount + rootEndRemove); 01105 } 01106 01107 return qMakePair(-1, -1); 01108 } 01109 01110 void KSelectionProxyModelPrivate::sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) 01111 { 01112 Q_Q(KSelectionProxyModel); 01113 01114 Q_ASSERT(parent.isValid() ? parent.model() == q->sourceModel() : true); 01115 01116 if (!m_selectionModel.data()->hasSelection()) 01117 return; 01118 01119 QPair<int, int> pair = beginRemoveRows(parent, start, end); 01120 if (pair.first == -1) 01121 return; 01122 01123 const QModelIndex proxyParent = mapParentFromSource(parent); 01124 01125 m_rowsRemoved = true; 01126 m_proxyRemoveRows = pair; 01127 q->beginRemoveRows(proxyParent, pair.first, pair.second); 01128 } 01129 01130 void KSelectionProxyModelPrivate::endRemoveRows(const QModelIndex &sourceParent, int proxyStart, int proxyEnd) 01131 { 01132 const QModelIndex proxyParent = mapParentFromSource(sourceParent); 01133 01134 // We need to make sure to remove entries from the mappings before updating internal indexes. 01135 01136 // - A 01137 // - - B 01138 // - C 01139 // - - D 01140 01141 // If A and C are selected, B and D are in the proxy. B maps to row 0 and D maps to row 1. 01142 // If B is then deleted leaving only D in the proxy, D needs to be updated to be a mapping 01143 // to row 0 instead of row 1. If that is done before removing the mapping for B, then the mapping 01144 // for D would overwrite the mapping for B and then the code for removing mappings would incorrectly 01145 // remove D. 01146 // So we first remove B and then update D. 01147 01148 { 01149 SourceProxyIndexMapping::right_iterator it = m_mappedParents.rightBegin(); 01150 01151 while (it != m_mappedParents.rightEnd()) { 01152 if (!it.value().isValid()) { 01153 m_parentIds.removeRight(it.key()); 01154 it = m_mappedParents.eraseRight(it); 01155 } else 01156 ++it; 01157 } 01158 } 01159 01160 { 01161 // Depending on what is selected at the time, a single removal in the source could invalidate 01162 // many mapped first child items at once. 01163 01164 // - A 01165 // - B 01166 // - - C 01167 // - - D 01168 // - - - E 01169 // - - - F 01170 // - - - - G 01171 // - - - - H 01172 01173 // If D and F are selected, the proxy contains E, F, G, H. If B is then deleted E to H will 01174 // be removed, including both first child mappings at E and G. 01175 01176 removeFirstChildMappings(proxyStart, proxyEnd); 01177 } 01178 01179 if (proxyParent.isValid()) 01180 updateInternalIndexes(proxyParent, proxyEnd + 1, -1*(proxyEnd - proxyStart + 1)); 01181 else 01182 updateInternalTopIndexes(proxyEnd + 1, -1*(proxyEnd - proxyStart + 1)); 01183 01184 QList<QPersistentModelIndex>::iterator rootIt = m_rootIndexList.begin(); 01185 while (rootIt != m_rootIndexList.end()) { 01186 if (!rootIt->isValid()) 01187 rootIt = m_rootIndexList.erase(rootIt); 01188 else 01189 ++rootIt; 01190 } 01191 } 01192 01193 void KSelectionProxyModelPrivate::sourceRowsRemoved(const QModelIndex &parent, int start, int end) 01194 { 01195 Q_Q(KSelectionProxyModel); 01196 Q_UNUSED(end) 01197 01198 Q_ASSERT(parent.isValid() ? parent.model() == q->sourceModel() : true); 01199 01200 if (!m_selectionModel.data()->hasSelection()) 01201 return; 01202 01203 if (!m_rowsRemoved) 01204 return; 01205 m_rowsRemoved = false; 01206 01207 Q_ASSERT(m_proxyRemoveRows.first >= 0); 01208 Q_ASSERT(m_proxyRemoveRows.second >= 0); 01209 endRemoveRows(parent, m_proxyRemoveRows.first, m_proxyRemoveRows.second); 01210 if (m_startWithChildTrees && start == 0 && q->sourceModel()->hasChildren(parent)) 01211 // The private endRemoveRows call might remove the first child mapping for parent, so 01212 // we create it again in that case. 01213 createFirstChildMapping(parent, m_proxyRemoveRows.first); 01214 01215 m_proxyRemoveRows = qMakePair(-1, -1); 01216 q->endRemoveRows(); 01217 } 01218 01219 void KSelectionProxyModelPrivate::sourceRowsAboutToBeMoved(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destRow) 01220 { 01221 Q_UNUSED(srcParent) 01222 Q_UNUSED(srcStart) 01223 Q_UNUSED(srcEnd) 01224 Q_UNUSED(destParent) 01225 Q_UNUSED(destRow) 01226 } 01227 01228 void KSelectionProxyModelPrivate::sourceRowsMoved(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destRow) 01229 { 01230 Q_UNUSED(srcParent) 01231 Q_UNUSED(srcStart) 01232 Q_UNUSED(srcEnd) 01233 Q_UNUSED(destParent) 01234 Q_UNUSED(destRow) 01235 } 01236 01237 QModelIndex KSelectionProxyModelPrivate::mapParentToSource(const QModelIndex &proxyParent) const 01238 { 01239 return m_mappedParents.rightToLeft(proxyParent); 01240 } 01241 01242 QModelIndex KSelectionProxyModelPrivate::mapParentFromSource(const QModelIndex &sourceParent) const 01243 { 01244 return m_mappedParents.leftToRight(sourceParent); 01245 } 01246 01247 static bool indexIsValid(bool startWithChildTrees, int row, const QList<QPersistentModelIndex> &rootIndexList, const SourceIndexProxyRowMapping &mappedFirstChildren) 01248 { 01249 if (!startWithChildTrees) { 01250 Q_ASSERT(rootIndexList.size() > row); 01251 Q_UNUSED(rootIndexList); 01252 } else { 01253 01254 Q_ASSERT(!mappedFirstChildren.isEmpty()); 01255 01256 SourceIndexProxyRowMapping::right_const_iterator result = mappedFirstChildren.rightUpperBound(row) - 1; 01257 01258 Q_ASSERT(result != mappedFirstChildren.rightEnd()); 01259 const int proxyFirstRow = result.key(); 01260 const QModelIndex sourceFirstChild = result.value(); 01261 Q_ASSERT(proxyFirstRow >= 0); 01262 Q_ASSERT(sourceFirstChild.isValid()); 01263 Q_ASSERT(sourceFirstChild.parent().isValid()); 01264 Q_ASSERT(row <= proxyFirstRow + sourceFirstChild.model()->rowCount(sourceFirstChild.parent())); 01265 } 01266 return true; 01267 } 01268 01269 QModelIndex KSelectionProxyModelPrivate::createTopLevelIndex(int row, int column) const 01270 { 01271 Q_Q(const KSelectionProxyModel); 01272 01273 Q_ASSERT(indexIsValid(m_startWithChildTrees, row, m_rootIndexList, m_mappedFirstChildren)); 01274 return q->createIndex(row, column); 01275 } 01276 01277 01278 QModelIndex KSelectionProxyModelPrivate::mapTopLevelFromSource(const QModelIndex &sourceIndex) const 01279 { 01280 Q_Q(const KSelectionProxyModel); 01281 01282 const QModelIndex sourceParent = sourceIndex.parent(); 01283 const int row = m_rootIndexList.indexOf(sourceIndex); 01284 if (row == -1) 01285 return QModelIndex(); 01286 01287 if (!m_startWithChildTrees) { 01288 Q_ASSERT(m_rootIndexList.size() > row); 01289 return q->createIndex(row, sourceIndex.column()); 01290 } 01291 if (!m_rootIndexList.contains(sourceParent)) 01292 return QModelIndex(); 01293 01294 const QModelIndex firstChild = q->sourceModel()->index(0, 0, sourceParent); 01295 const int firstProxyRow = m_mappedFirstChildren.leftToRight(firstChild); 01296 01297 return q->createIndex(firstProxyRow + sourceIndex.row(), sourceIndex.column()); 01298 } 01299 01300 QModelIndex KSelectionProxyModelPrivate::mapFromSource(const QModelIndex &sourceIndex) const 01301 { 01302 Q_Q(const KSelectionProxyModel); 01303 01304 const QModelIndex maybeMapped = mapParentFromSource(sourceIndex); 01305 if (maybeMapped.isValid()) { 01306 // Q_ASSERT((!d->m_startWithChildTrees && d->m_rootIndexList.contains(maybeMapped)) ? maybeMapped.row() < 0 : true ); 01307 return maybeMapped; 01308 } 01309 const QModelIndex sourceParent = sourceIndex.parent(); 01310 01311 const QModelIndex proxyParent = mapParentFromSource(sourceParent); 01312 if (proxyParent.isValid()) { 01313 void * const parentId = m_parentIds.rightToLeft(proxyParent); 01314 static const int column = 0; 01315 return q->createIndex(sourceIndex.row(), column, parentId); 01316 } 01317 01318 const QModelIndex firstChild = q->sourceModel()->index(0, 0, sourceParent); 01319 01320 if (m_mappedFirstChildren.leftContains(firstChild)) 01321 { 01322 const int firstProxyRow = m_mappedFirstChildren.leftToRight(firstChild); 01323 return q->createIndex(firstProxyRow + sourceIndex.row(), sourceIndex.column()); 01324 } 01325 return mapTopLevelFromSource(sourceIndex); 01326 } 01327 01328 int KSelectionProxyModelPrivate::topLevelRowCount() const 01329 { 01330 Q_Q(const KSelectionProxyModel); 01331 01332 if (!m_startWithChildTrees) 01333 return m_rootIndexList.size(); 01334 01335 if (m_mappedFirstChildren.isEmpty()) 01336 return 0; 01337 01338 const SourceIndexProxyRowMapping::right_const_iterator result = m_mappedFirstChildren.rightConstEnd() - 1; 01339 01340 const int proxyFirstRow = result.key(); 01341 const QModelIndex sourceFirstChild = result.value(); 01342 Q_ASSERT(sourceFirstChild.isValid()); 01343 const QModelIndex sourceParent = sourceFirstChild.parent(); 01344 Q_ASSERT(sourceParent.isValid()); 01345 return q->sourceModel()->rowCount(sourceParent) + proxyFirstRow; 01346 } 01347 01348 bool KSelectionProxyModelPrivate::ensureMappable(const QModelIndex &parent) const 01349 { 01350 Q_Q(const KSelectionProxyModel); 01351 01352 if (isFlat()) 01353 return true; 01354 01355 if (parentIsMappable(parent)) 01356 return true; 01357 01358 QModelIndex ancestor = parent.parent(); 01359 QModelIndexList ancestorList; 01360 while (ancestor.isValid()) 01361 { 01362 if (parentIsMappable(ancestor)) 01363 break; 01364 else 01365 ancestorList.prepend(ancestor); 01366 01367 ancestor = ancestor.parent(); 01368 } 01369 01370 if (!ancestor.isValid()) 01371 // @p parent is not a descendant of m_rootIndexList. 01372 return false; 01373 01374 // sourceIndex can be mapped to the proxy. We just need to create mappings for its ancestors first. 01375 for(int i = 0; i < ancestorList.size(); ++i) 01376 { 01377 const QModelIndex existingAncestor = mapParentFromSource(ancestor); 01378 Q_ASSERT(existingAncestor.isValid()); 01379 01380 void * const ansId = m_parentIds.rightToLeft(existingAncestor); 01381 const QModelIndex newSourceParent = ancestorList.at(i); 01382 const QModelIndex newProxyParent = q->createIndex(newSourceParent.row(), newSourceParent.column(), ansId); 01383 01384 void * const newId = m_voidPointerFactory.createPointer(); 01385 m_parentIds.insert(newId, newProxyParent); 01386 m_mappedParents.insert(QPersistentModelIndex(newSourceParent), newProxyParent); 01387 ancestor = newSourceParent; 01388 } 01389 return true; 01390 } 01391 01392 void KSelectionProxyModelPrivate::updateInternalTopIndexes(int start, int offset) 01393 { 01394 updateInternalIndexes(QModelIndex(), start, offset); 01395 01396 QHash<QPersistentModelIndex, int> updates; 01397 { 01398 SourceIndexProxyRowMapping::right_iterator it = m_mappedFirstChildren.rightLowerBound(start); 01399 const SourceIndexProxyRowMapping::right_iterator end = m_mappedFirstChildren.rightEnd(); 01400 01401 for ( ; it != end; ++it) 01402 { 01403 updates.insert(*it, it.key() + offset); 01404 } 01405 } 01406 { 01407 QHash<QPersistentModelIndex, int>::const_iterator it = updates.constBegin(); 01408 const QHash<QPersistentModelIndex, int>::const_iterator end = updates.constEnd(); 01409 01410 for ( ; it != end; ++it) 01411 { 01412 m_mappedFirstChildren.insert(it.key(), it.value()); 01413 } 01414 } 01415 } 01416 01417 void KSelectionProxyModelPrivate::updateInternalIndexes(const QModelIndex &parent, int start, int offset) 01418 { 01419 Q_Q(KSelectionProxyModel); 01420 01421 Q_ASSERT(start + offset >= 0); 01422 Q_ASSERT(parent.isValid() ? parent.model() == q : true); 01423 01424 if (isFlat()) 01425 return; 01426 01427 SourceProxyIndexMapping::left_iterator mappedParentIt = m_mappedParents.leftBegin(); 01428 01429 QHash<void*, QModelIndex> updatedParentIds; 01430 QHash<QPersistentModelIndex, QModelIndex> updatedParents; 01431 01432 for ( ; mappedParentIt != m_mappedParents.leftEnd(); ++mappedParentIt) { 01433 const QModelIndex proxyIndex = mappedParentIt.value(); 01434 Q_ASSERT(proxyIndex.isValid()); 01435 01436 if (proxyIndex.row() < start) 01437 continue; 01438 01439 const QModelIndex proxyParent = proxyIndex.parent(); 01440 01441 if (parent.isValid()) { 01442 if (proxyParent != parent) 01443 continue; 01444 } else { 01445 if (proxyParent.isValid()) 01446 continue; 01447 } 01448 Q_ASSERT(m_parentIds.rightContains(proxyIndex)); 01449 void * const key = m_parentIds.rightToLeft(proxyIndex); 01450 01451 const QModelIndex newIndex = q->createIndex(proxyIndex.row() + offset, proxyIndex.column(), proxyIndex.internalPointer()); 01452 01453 Q_ASSERT(newIndex.isValid()); 01454 01455 updatedParentIds.insert(key, newIndex); 01456 updatedParents.insert(mappedParentIt.key(), newIndex); 01457 } 01458 01459 { 01460 QHash<QPersistentModelIndex, QModelIndex>::const_iterator it = updatedParents.constBegin(); 01461 const QHash<QPersistentModelIndex, QModelIndex>::const_iterator end = updatedParents.constEnd(); 01462 for ( ; it != end; ++it) 01463 m_mappedParents.insert(it.key(), it.value()); 01464 } 01465 01466 { 01467 QHash<void*, QModelIndex>::const_iterator it = updatedParentIds.constBegin(); 01468 const QHash<void*, QModelIndex>::const_iterator end = updatedParentIds.constEnd(); 01469 for ( ; it != end; ++it) 01470 m_parentIds.insert(it.key(), it.value()); 01471 } 01472 } 01473 01474 bool KSelectionProxyModelPrivate::parentAlreadyMapped(const QModelIndex &parent) const 01475 { 01476 Q_Q(const KSelectionProxyModel); 01477 Q_ASSERT(parent.model() == q->sourceModel()); 01478 return m_mappedParents.leftContains(parent); 01479 } 01480 01481 bool KSelectionProxyModelPrivate::firstChildAlreadyMapped(const QModelIndex &firstChild) const 01482 { 01483 Q_Q(const KSelectionProxyModel); 01484 Q_ASSERT(firstChild.model() == q->sourceModel()); 01485 return m_mappedFirstChildren.leftContains(firstChild); 01486 } 01487 01488 void KSelectionProxyModelPrivate::createFirstChildMapping(const QModelIndex& parent, int proxyRow) const 01489 { 01490 Q_Q(const KSelectionProxyModel); 01491 01492 Q_ASSERT(parent.isValid() ? parent.model() == q->sourceModel() : true); 01493 01494 static const int column = 0; 01495 static const int row = 0; 01496 01497 const QPersistentModelIndex srcIndex = q->sourceModel()->index(row, column, parent); 01498 01499 if (firstChildAlreadyMapped(srcIndex)) 01500 return; 01501 01502 Q_ASSERT(srcIndex.isValid()); 01503 m_mappedFirstChildren.insert(srcIndex, proxyRow); 01504 } 01505 01506 void KSelectionProxyModelPrivate::createParentMappings(const QModelIndex &parent, int start, int end) const 01507 { 01508 if (isFlat()) 01509 return; 01510 01511 Q_Q(const KSelectionProxyModel); 01512 01513 Q_ASSERT(parent.isValid() ? parent.model() == q->sourceModel() : true); 01514 01515 static const int column = 0; 01516 01517 for (int row = start; row <= end; ++row) { 01518 const QModelIndex srcIndex = q->sourceModel()->index(row, column, parent); 01519 Q_ASSERT(srcIndex.isValid()); 01520 if (!q->sourceModel()->hasChildren(srcIndex) || parentAlreadyMapped(srcIndex)) 01521 continue; 01522 01523 const QModelIndex proxyIndex = mapFromSource(srcIndex); 01524 if (!proxyIndex.isValid()) 01525 return; // If one of them is not mapped, its siblings won't be either 01526 01527 void * const newId = m_voidPointerFactory.createPointer(); 01528 m_parentIds.insert(newId, proxyIndex); 01529 Q_ASSERT(srcIndex.isValid()); 01530 m_mappedParents.insert(QPersistentModelIndex(srcIndex), proxyIndex); 01531 } 01532 } 01533 01534 void KSelectionProxyModelPrivate::removeFirstChildMappings(int start, int end) 01535 { 01536 SourceIndexProxyRowMapping::right_iterator it = m_mappedFirstChildren.rightLowerBound(start); 01537 const SourceIndexProxyRowMapping::right_iterator endIt = m_mappedFirstChildren.rightUpperBound(end); 01538 while (it != endIt) 01539 it = m_mappedFirstChildren.eraseRight(it); 01540 } 01541 01542 void KSelectionProxyModelPrivate::removeParentMappings(const QModelIndex &parent, int start, int end) 01543 { 01544 Q_Q(KSelectionProxyModel); 01545 01546 Q_ASSERT(parent.isValid() ? parent.model() == q : true); 01547 01548 SourceProxyIndexMapping::right_iterator it = m_mappedParents.rightBegin(); 01549 SourceProxyIndexMapping::right_iterator endIt = m_mappedParents.rightEnd(); 01550 01551 typedef QPair<QModelIndex, QPersistentModelIndex> Pair; 01552 01553 QList<Pair> pairs; 01554 01555 QModelIndexList list; 01556 01557 const bool flatList = isFlat(); 01558 01559 while (it != endIt) { 01560 if (it.key().row() >= start && it.key().row() <= end) 01561 { 01562 const QModelIndex sourceParent = it.value(); 01563 const QModelIndex proxyGrandParent = mapParentFromSource(sourceParent.parent()); 01564 if (proxyGrandParent == parent) 01565 { 01566 if (!flatList) 01567 // Due to recursive calls, we could have several iterators on the container 01568 // when erase is called. That's safe accoring to the QHash::iterator docs though. 01569 removeParentMappings(it.key(), 0, q->sourceModel()->rowCount(it.value()) - 1); 01570 01571 m_parentIds.removeRight(it.key()); 01572 it = m_mappedParents.eraseRight(it); 01573 } else 01574 ++it; 01575 } else 01576 ++it; 01577 } 01578 } 01579 01580 QModelIndex KSelectionProxyModelPrivate::mapTopLevelToSource(int row, int column) const 01581 { 01582 if (!m_startWithChildTrees) 01583 { 01584 const QModelIndex idx = m_rootIndexList.at(row); 01585 return idx.sibling(idx.row(), column); 01586 } 01587 01588 if (m_mappedFirstChildren.isEmpty()) 01589 return QModelIndex(); 01590 01591 SourceIndexProxyRowMapping::right_iterator result = m_mappedFirstChildren.rightUpperBound(row) - 1; 01592 01593 Q_ASSERT(result != m_mappedFirstChildren.rightEnd()); 01594 01595 const int proxyFirstRow = result.key(); 01596 const QModelIndex sourceFirstChild = result.value(); 01597 Q_ASSERT(sourceFirstChild.isValid()); 01598 return sourceFirstChild.sibling(row - proxyFirstRow, column); 01599 } 01600 01601 void KSelectionProxyModelPrivate::removeSelectionFromProxy(const QItemSelection &selection) 01602 { 01603 Q_Q(KSelectionProxyModel); 01604 if (selection.isEmpty()) 01605 return; 01606 01607 q->rootSelectionAboutToBeRemoved(selection); 01608 01609 foreach(const QItemSelectionRange range, selection) 01610 removeRangeFromProxy(range); 01611 } 01612 01613 void KSelectionProxyModelPrivate::removeRangeFromProxy(const QItemSelectionRange &range) 01614 { 01615 Q_Q(KSelectionProxyModel); 01616 01617 Q_ASSERT(range.model() == q->sourceModel()); 01618 01619 const QModelIndex sourceTopLeft = range.topLeft(); 01620 const QModelIndex proxyTopLeft = mapFromSource(sourceTopLeft); 01621 const QModelIndex sourceBottomLeft = range.bottomRight().sibling(range.bottom(), 0); 01622 const QModelIndex proxyBottomLeft = mapFromSource(sourceBottomLeft); 01623 const QModelIndex proxyParent = proxyTopLeft.parent(); 01624 const QModelIndex sourceParent = sourceTopLeft.parent(); 01625 01626 if (m_startWithChildTrees) { 01627 Q_ASSERT(sourceTopLeft.isValid()); 01628 Q_ASSERT(sourceBottomLeft.isValid()); 01629 const int startRootIdx = m_rootIndexList.indexOf(sourceTopLeft); 01630 int endRootIdx = m_rootIndexList.indexOf(sourceBottomLeft); 01631 QItemSelection extraRanges; 01632 if (m_includeAllSelected) { 01633 // It can happen that indexes of descendants get in between indexes which make up a range. 01634 // We handle only the first contiguous block here and handle the rest later. 01635 int idx = startRootIdx; 01636 const int bottomIdx = endRootIdx; 01637 const int rootListSize = m_rootIndexList.size(); 01638 int next = idx + 1; 01639 while (next <= bottomIdx) 01640 { 01641 if (next < rootListSize && m_rootIndexList.at(next).parent() == sourceParent) { 01642 idx = next; 01643 ++next; 01644 } else 01645 break; 01646 } 01647 endRootIdx = idx; 01648 ++idx; 01649 while (idx <= bottomIdx) 01650 { 01651 const QModelIndex index= m_rootIndexList.at(idx); 01652 if (m_rootIndexList.at(idx).parent() == sourceParent) 01653 extraRanges << QItemSelectionRange(index, index); 01654 ++idx; 01655 } 01656 } 01657 Q_ASSERT(endRootIdx != -1); 01658 int childrenCount = q->sourceModel()->rowCount(sourceTopLeft); 01659 for (int rootIdx = startRootIdx + 1; rootIdx <= endRootIdx; ++rootIdx) 01660 { 01661 childrenCount += q->sourceModel()->rowCount(m_rootIndexList.at(rootIdx)); 01662 } 01663 if (childrenCount == 0) 01664 { 01665 for (int rootIdx = startRootIdx; rootIdx <= endRootIdx; --endRootIdx) 01666 { 01667 const QModelIndex idx = m_rootIndexList.at(rootIdx); 01668 q->rootIndexAboutToBeRemoved(idx); 01669 m_rootIndexList.removeOne(idx); 01670 } 01671 return; 01672 } 01673 if (!m_includeAllSelected) 01674 { 01675 ++endRootIdx; 01676 for ( ; endRootIdx < m_rootIndexList.size(); ++endRootIdx) { 01677 const QModelIndex idx = m_rootIndexList.at(endRootIdx); 01678 if (isDescendantOf(sourceBottomLeft, idx)) 01679 childrenCount += q->sourceModel()->rowCount(idx); 01680 else 01681 break; 01682 } 01683 --endRootIdx; 01684 } 01685 const int proxyStart = getTargetRow(startRootIdx); 01686 int proxyEnd = proxyStart + childrenCount - 1; 01687 q->beginRemoveRows(QModelIndex(), proxyStart, proxyEnd); 01688 01689 for (int rootIdx = startRootIdx; rootIdx <= endRootIdx; ++rootIdx) 01690 { 01691 q->rootIndexAboutToBeRemoved(m_rootIndexList.at(rootIdx)); 01692 } 01693 01694 removeParentMappings(QModelIndex(), proxyStart, proxyEnd); 01695 removeFirstChildMappings(proxyStart, proxyEnd); 01696 int numRemovedChildren = 0; 01697 for (int rootIdx = startRootIdx; rootIdx <= endRootIdx; --endRootIdx) 01698 { 01699 const QModelIndex idx = m_rootIndexList.at(rootIdx); 01700 const int childCount = q->sourceModel()->rowCount(idx); 01701 m_rootIndexList.removeAt(rootIdx); 01702 numRemovedChildren += childCount; 01703 } 01704 updateInternalTopIndexes(proxyEnd + 1, -1 * numRemovedChildren); 01705 q->endRemoveRows(); 01706 if (m_includeAllSelected) { 01707 removeSelectionFromProxy(kNormalizeSelection(extraRanges)); 01708 } 01709 } else { 01710 if (!proxyTopLeft.isValid()) 01711 return; 01712 const int height = range.height(); 01713 q->beginRemoveRows(proxyParent, proxyTopLeft.row(), proxyTopLeft.row() + height - 1); 01714 01715 // TODO: Do this conditionally if the signal is connected to anything. 01716 for (int i = 0; i < height; ++i) 01717 { 01718 const QModelIndex idx = sourceTopLeft.sibling(range.top() + i, sourceTopLeft.column()); 01719 q->rootIndexAboutToBeRemoved(idx); 01720 } 01721 01722 removeParentMappings(proxyParent, proxyTopLeft.row(), proxyTopLeft.row() + height - 1); 01723 updateInternalIndexes(proxyParent, proxyTopLeft.row() + height, -1 * height); 01724 01725 for (int i = 0; i < height; ++i) 01726 { 01727 const QModelIndex idx = sourceTopLeft.sibling(range.top() + i, sourceTopLeft.column()); 01728 Q_ASSERT(idx.isValid()); 01729 const bool b = m_rootIndexList.removeOne(idx); 01730 Q_UNUSED(b) 01731 if (!b) 01732 kDebug() << idx; 01733 Q_ASSERT(b); 01734 } 01735 01736 q->endRemoveRows(); 01737 } 01738 } 01739 01740 void KSelectionProxyModelPrivate::selectionChanged(const QItemSelection &_selected, const QItemSelection &_deselected) 01741 { 01742 Q_Q(KSelectionProxyModel); 01743 01744 if (!q->sourceModel() || (_selected.isEmpty() && _deselected.isEmpty())) 01745 return; 01746 01747 if (m_rowsInserted || m_rowsRemoved) { 01748 m_pendingSelectionChanges.append(PendingSelectionChange(_selected, _deselected)); 01749 return; 01750 } 01751 01752 // Any deselected indexes in the m_rootIndexList are removed. Then, any 01753 // indexes in the selected range which are not a descendant of one of the already selected indexes 01754 // are inserted into the model. 01755 // 01756 // All ranges from the selection model need to be split into individual rows. Ranges which are contiguous in 01757 // the selection model may not be contiguous in the source model if there's a sort filter proxy model in the chain. 01758 // 01759 // Some descendants of deselected indexes may still be selected. The ranges in m_selectionModel.data()->selection() 01760 // are examined. If any of the ranges are descendants of one of the 01761 // indexes in deselected, they are added to the ranges to be inserted into the model. 01762 // 01763 // The new indexes are inserted in sorted order. 01764 01765 const QItemSelection selected = kNormalizeSelection(m_indexMapper->mapSelectionRightToLeft(_selected)); 01766 const QItemSelection deselected = kNormalizeSelection(m_indexMapper->mapSelectionRightToLeft(_deselected)); 01767 01768 #if QT_VERSION < 0x040800 01769 // The QItemSelectionModel sometimes doesn't remove deselected items from its selection 01770 // Fixed in Qt 4.8 : http://qt.gitorious.org/qt/qt/merge_requests/2403 01771 QItemSelection reportedSelection = m_selectionModel.data()->selection(); 01772 reportedSelection.merge(deselected, QItemSelectionModel::Deselect); 01773 QItemSelection fullSelection = m_indexMapper->mapSelectionRightToLeft(reportedSelection); 01774 #else 01775 QItemSelection fullSelection = m_indexMapper->mapSelectionRightToLeft(m_selectionModel.data()->selection()); 01776 #endif 01777 01778 fullSelection = kNormalizeSelection(fullSelection); 01779 01780 QItemSelection newRootRanges; 01781 QItemSelection removedRootRanges; 01782 if (!m_includeAllSelected) { 01783 newRootRanges = getRootRanges(selected); 01784 01785 QItemSelection existingSelection = fullSelection; 01786 // What was selected before the selection was made. 01787 existingSelection.merge(selected, QItemSelectionModel::Deselect); 01788 01789 // This is similar to m_rootRanges, but that m_rootRanges at this point still contains the roots 01790 // of deselected and existingRootRanges does not. 01791 01792 const QItemSelection existingRootRanges = getRootRanges(existingSelection); 01793 { 01794 QMutableListIterator<QItemSelectionRange> i(newRootRanges); 01795 while (i.hasNext()) { 01796 const QItemSelectionRange range = i.next(); 01797 const QModelIndex topLeft = range.topLeft(); 01798 if (isDescendantOf(existingRootRanges, topLeft)) { 01799 i.remove(); 01800 } 01801 } 01802 } 01803 01804 QItemSelection exposedSelection; 01805 { 01806 QItemSelection deselectedRootRanges = getRootRanges(deselected); 01807 QListIterator<QItemSelectionRange> i(deselectedRootRanges); 01808 while (i.hasNext()) { 01809 const QItemSelectionRange range = i.next(); 01810 const QModelIndex topLeft = range.topLeft(); 01811 // Consider this: 01812 // 01813 // - A 01814 // - - B 01815 // - - - C 01816 // - - - - D 01817 // 01818 // B and D were selected, then B was deselected and C was selected in one go. 01819 if (!isDescendantOf(existingRootRanges, topLeft)) { 01820 // B is topLeft and fullSelection contains D. 01821 // B is not a descendant of D. 01822 01823 // range is not a descendant of the selection, but maybe the selection is a descendant of range. 01824 // no need to check selected here. That's already in newRootRanges. 01825 // existingRootRanges and newRootRanges do not overlap. 01826 foreach (const QItemSelectionRange &selectedRange, existingRootRanges) { 01827 const QModelIndex selectedRangeTopLeft = selectedRange.topLeft(); 01828 // existingSelection (and selectedRangeTopLeft) is D. 01829 // D is a descendant of B, so when B was removed, D might have been exposed as a root. 01830 if (isDescendantOf(range, selectedRangeTopLeft) 01831 // But D is also a descendant of part of the new selection C, which is already set to be a new root 01832 // so D would not be added to exposedSelection because C is in newRootRanges. 01833 && !isDescendantOf(newRootRanges, selectedRangeTopLeft)) 01834 exposedSelection.append(selectedRange); 01835 } 01836 removedRootRanges << range; 01837 } 01838 } 01839 } 01840 01841 QItemSelection obscuredRanges; 01842 { 01843 QListIterator<QItemSelectionRange> i(existingRootRanges); 01844 while (i.hasNext()) { 01845 const QItemSelectionRange range = i.next(); 01846 if (isDescendantOf(newRootRanges, range.topLeft())) 01847 obscuredRanges << range; 01848 } 01849 } 01850 removedRootRanges << getRootRanges(obscuredRanges); 01851 newRootRanges << getRootRanges(exposedSelection); 01852 01853 removedRootRanges = kNormalizeSelection(removedRootRanges); 01854 newRootRanges = kNormalizeSelection(newRootRanges); 01855 } else { 01856 removedRootRanges = deselected; 01857 newRootRanges = selected; 01858 } 01859 01860 removeSelectionFromProxy(removedRootRanges); 01861 01862 if (!m_selectionModel.data()->hasSelection()) 01863 { 01864 Q_ASSERT(m_rootIndexList.isEmpty()); 01865 Q_ASSERT(m_mappedFirstChildren.isEmpty()); 01866 Q_ASSERT(m_mappedParents.isEmpty()); 01867 Q_ASSERT(m_parentIds.isEmpty()); 01868 } 01869 01870 insertSelectionIntoProxy(newRootRanges); 01871 } 01872 01873 int KSelectionProxyModelPrivate::getTargetRow(int rootListRow) 01874 { 01875 Q_Q(KSelectionProxyModel); 01876 if (!m_startWithChildTrees) 01877 return rootListRow; 01878 01879 --rootListRow; 01880 while (rootListRow >= 0) { 01881 const QModelIndex idx = m_rootIndexList.at(rootListRow); 01882 Q_ASSERT(idx.isValid()); 01883 const int rowCount = q->sourceModel()->rowCount(idx); 01884 if (rowCount > 0) { 01885 static const int column = 0; 01886 const QModelIndex srcIdx = q->sourceModel()->index(rowCount - 1, column, idx); 01887 const QModelIndex proxyLastChild = mapFromSource(srcIdx); 01888 return proxyLastChild.row() + 1; 01889 } 01890 --rootListRow; 01891 } 01892 return 0; 01893 } 01894 01895 void KSelectionProxyModelPrivate::insertSelectionIntoProxy(const QItemSelection &selection) 01896 { 01897 Q_Q(KSelectionProxyModel); 01898 01899 if (selection.isEmpty()) 01900 return; 01901 01902 foreach(const QModelIndex &newIndex, selection.indexes()) { 01903 Q_ASSERT(newIndex.model() == q->sourceModel()); 01904 if (newIndex.column() > 0) 01905 continue; 01906 if (m_startWithChildTrees) { 01907 const int rootListRow = getRootListRow(m_rootIndexList, newIndex); 01908 Q_ASSERT(q->sourceModel() == newIndex.model()); 01909 const int rowCount = q->sourceModel()->rowCount(newIndex); 01910 const int startRow = getTargetRow(rootListRow); 01911 01912 if (rowCount == 0) { 01913 // Even if the newindex doesn't have any children to put into the model yet, 01914 // We still need to make sure it's future children are inserted into the model. 01915 m_rootIndexList.insert(rootListRow, newIndex); 01916 if (!m_resetting || m_layoutChanging) 01917 emit q->rootIndexAdded(newIndex); 01918 continue; 01919 } 01920 if (!m_resetting) 01921 q->beginInsertRows(QModelIndex(), startRow, startRow + rowCount - 1); 01922 Q_ASSERT(newIndex.isValid()); 01923 m_rootIndexList.insert(rootListRow, newIndex); 01924 if (!m_resetting || m_layoutChanging) 01925 emit q->rootIndexAdded(newIndex); 01926 01927 int _start = 0; 01928 for (int i = 0; i < rootListRow; ++i) 01929 _start += q->sourceModel()->rowCount(m_rootIndexList.at(i)); 01930 01931 updateInternalTopIndexes(_start, rowCount); 01932 createFirstChildMapping(newIndex, _start); 01933 createParentMappings(newIndex, 0, rowCount - 1); 01934 01935 if (!m_resetting) { 01936 q->endInsertRows(); 01937 } 01938 01939 } else { 01940 const int row = getRootListRow(m_rootIndexList, newIndex); 01941 if (!m_resetting) 01942 q->beginInsertRows(QModelIndex(), row, row); 01943 01944 Q_ASSERT(newIndex.isValid()); 01945 m_rootIndexList.insert(row, newIndex); 01946 01947 if (!m_resetting || m_layoutChanging) 01948 emit q->rootIndexAdded(newIndex); 01949 Q_ASSERT(m_rootIndexList.size() > row); 01950 updateInternalIndexes(QModelIndex(), row, 1); 01951 createParentMappings(newIndex.parent(), newIndex.row(), newIndex.row()); 01952 01953 if (!m_resetting) { 01954 q->endInsertRows(); 01955 } 01956 } 01957 } 01958 q->rootSelectionAdded(selection); 01959 } 01960 01961 KSelectionProxyModel::KSelectionProxyModel(QItemSelectionModel *selectionModel, QObject *parent) 01962 : QAbstractProxyModel(parent), d_ptr(new KSelectionProxyModelPrivate(this, selectionModel)) 01963 { 01964 } 01965 01966 KSelectionProxyModel::~KSelectionProxyModel() 01967 { 01968 delete d_ptr; 01969 } 01970 01971 void KSelectionProxyModel::setFilterBehavior(FilterBehavior behavior) 01972 { 01973 Q_D(KSelectionProxyModel); 01974 01975 beginResetModel(); 01976 01977 d->m_filterBehavior = behavior; 01978 01979 switch (behavior) { 01980 case SubTrees: { 01981 d->m_omitChildren = false; 01982 d->m_omitDescendants = false; 01983 d->m_startWithChildTrees = false; 01984 d->m_includeAllSelected = false; 01985 break; 01986 } 01987 case SubTreeRoots: { 01988 d->m_omitChildren = true; 01989 d->m_startWithChildTrees = false; 01990 d->m_includeAllSelected = false; 01991 break; 01992 } 01993 case SubTreesWithoutRoots: { 01994 d->m_omitChildren = false; 01995 d->m_omitDescendants = false; 01996 d->m_startWithChildTrees = true; 01997 d->m_includeAllSelected = false; 01998 break; 01999 } 02000 case ExactSelection: { 02001 d->m_omitChildren = true; 02002 d->m_startWithChildTrees = false; 02003 d->m_includeAllSelected = true; 02004 break; 02005 } 02006 case ChildrenOfExactSelection: { 02007 d->m_omitChildren = false; 02008 d->m_omitDescendants = true; 02009 d->m_startWithChildTrees = true; 02010 d->m_includeAllSelected = true; 02011 break; 02012 } 02013 } 02014 d->resetInternalData(); 02015 d->selectionChanged(d->m_selectionModel.data()->selection(), QItemSelection()); 02016 02017 endResetModel(); 02018 } 02019 02020 KSelectionProxyModel::FilterBehavior KSelectionProxyModel::filterBehavior() const 02021 { 02022 Q_D(const KSelectionProxyModel); 02023 return d->m_filterBehavior; 02024 } 02025 02026 void KSelectionProxyModel::setSourceModel(QAbstractItemModel *_sourceModel) 02027 { 02028 Q_D(KSelectionProxyModel); 02029 02030 Q_ASSERT(_sourceModel != this); 02031 02032 if (_sourceModel == sourceModel()) 02033 return; 02034 02035 disconnect(d->m_selectionModel.data()->model(), SIGNAL(modelAboutToBeReset()), this, SLOT(sourceModelAboutToBeReset())); 02036 connect(d->m_selectionModel.data()->model(), SIGNAL(modelAboutToBeReset()), this, SLOT(sourceModelAboutToBeReset())); 02037 disconnect(d->m_selectionModel.data()->model(), SIGNAL(modelReset()), this, SLOT(sourceModelReset())); 02038 connect(d->m_selectionModel.data()->model(), SIGNAL(modelReset()), this, SLOT(sourceModelReset())); 02039 02040 disconnect(d->m_selectionModel.data(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), 02041 this, SLOT(selectionChanged(const QItemSelection &, const QItemSelection &))); 02042 connect(d->m_selectionModel.data(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), 02043 SLOT(selectionChanged(const QItemSelection &, const QItemSelection &))); 02044 02045 beginResetModel(); 02046 d->m_resetting = true; 02047 02048 if (_sourceModel) { 02049 disconnect(_sourceModel, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)), 02050 this, SLOT(sourceRowsAboutToBeInserted(const QModelIndex &, int, int))); 02051 disconnect(_sourceModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)), 02052 this, SLOT(sourceRowsInserted(const QModelIndex &, int, int))); 02053 disconnect(_sourceModel, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)), 02054 this, SLOT(sourceRowsAboutToBeRemoved(const QModelIndex &, int, int))); 02055 disconnect(_sourceModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), 02056 this, SLOT(sourceRowsRemoved(const QModelIndex &, int, int))); 02057 // disconnect(_sourceModel, SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)), 02058 // this, SLOT(sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int))); 02059 // disconnect(_sourceModel, SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), 02060 // this, SLOT(sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int))); 02061 disconnect(_sourceModel, SIGNAL(modelAboutToBeReset()), 02062 this, SLOT(sourceModelAboutToBeReset())); 02063 disconnect(_sourceModel, SIGNAL(modelReset()), 02064 this, SLOT(sourceModelReset())); 02065 disconnect(_sourceModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), 02066 this, SLOT(sourceDataChanged(const QModelIndex &, const QModelIndex &))); 02067 disconnect(_sourceModel, SIGNAL(layoutAboutToBeChanged()), 02068 this, SLOT(sourceLayoutAboutToBeChanged())); 02069 disconnect(_sourceModel, SIGNAL(layoutChanged()), 02070 this, SLOT(sourceLayoutChanged())); 02071 disconnect(_sourceModel, SIGNAL(destroyed()), 02072 this, SLOT(sourceModelDestroyed())); 02073 } 02074 02075 // Must be called before QAbstractProxyModel::setSourceModel because it emits some signals. 02076 d->resetInternalData(); 02077 QAbstractProxyModel::setSourceModel(_sourceModel); 02078 if (_sourceModel) { 02079 d->m_indexMapper = new KModelIndexProxyMapper(_sourceModel, d->m_selectionModel.data()->model(), this); 02080 if (d->m_selectionModel.data()->hasSelection()) 02081 d->selectionChanged(d->m_selectionModel.data()->selection(), QItemSelection()); 02082 02083 connect(_sourceModel, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)), 02084 SLOT(sourceRowsAboutToBeInserted(const QModelIndex &, int, int))); 02085 connect(_sourceModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)), 02086 SLOT(sourceRowsInserted(const QModelIndex &, int, int))); 02087 connect(_sourceModel, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)), 02088 SLOT(sourceRowsAboutToBeRemoved(const QModelIndex &, int, int))); 02089 connect(_sourceModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), 02090 SLOT(sourceRowsRemoved(const QModelIndex &, int, int))); 02091 // connect(_sourceModel, SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)), 02092 // SLOT(sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int))); 02093 // connect(_sourceModel, SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), 02094 // SLOT(sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int))); 02095 connect(_sourceModel, SIGNAL(modelAboutToBeReset()), 02096 SLOT(sourceModelAboutToBeReset())); 02097 connect(_sourceModel, SIGNAL(modelReset()), 02098 SLOT(sourceModelReset())); 02099 connect(_sourceModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), 02100 SLOT(sourceDataChanged(const QModelIndex &, const QModelIndex &))); 02101 connect(_sourceModel, SIGNAL(layoutAboutToBeChanged()), 02102 SLOT(sourceLayoutAboutToBeChanged())); 02103 connect(_sourceModel, SIGNAL(layoutChanged()), 02104 SLOT(sourceLayoutChanged())); 02105 connect(_sourceModel, SIGNAL(destroyed()), 02106 SLOT(sourceModelDestroyed())); 02107 } 02108 02109 d->m_resetting = false; 02110 endResetModel(); 02111 } 02112 02113 QModelIndex KSelectionProxyModel::mapToSource(const QModelIndex &proxyIndex) const 02114 { 02115 Q_D(const KSelectionProxyModel); 02116 02117 if (!proxyIndex.isValid() || !sourceModel() || d->m_rootIndexList.isEmpty()) 02118 return QModelIndex(); 02119 02120 Q_ASSERT(proxyIndex.internalPointer() >= 0); 02121 Q_ASSERT(proxyIndex.model() == this); 02122 02123 if (proxyIndex.internalPointer() == 0) 02124 return d->mapTopLevelToSource(proxyIndex.row(), proxyIndex.column()); 02125 02126 const QModelIndex proxyParent = d->parentForId(proxyIndex.internalPointer()); 02127 Q_ASSERT(proxyParent.isValid()); 02128 const QModelIndex sourceParent = d->mapParentToSource(proxyParent); 02129 Q_ASSERT(sourceParent.isValid()); 02130 return sourceModel()->index(proxyIndex.row(), proxyIndex.column(), sourceParent); 02131 } 02132 02133 QModelIndex KSelectionProxyModel::mapFromSource(const QModelIndex &sourceIndex) const 02134 { 02135 Q_D(const KSelectionProxyModel); 02136 02137 if (!sourceModel() || !sourceIndex.isValid() || d->m_rootIndexList.isEmpty()) 02138 return QModelIndex(); 02139 02140 Q_ASSERT(sourceIndex.model() == sourceModel()); 02141 02142 if (!sourceIndex.isValid()) 02143 return QModelIndex(); 02144 02145 if (!d->ensureMappable(sourceIndex)) 02146 return QModelIndex(); 02147 02148 return d->mapFromSource(sourceIndex); 02149 } 02150 02151 int KSelectionProxyModel::rowCount(const QModelIndex &index) const 02152 { 02153 Q_D(const KSelectionProxyModel); 02154 02155 if (!sourceModel() || index.column() > 0 || d->m_rootIndexList.isEmpty()) 02156 return 0; 02157 02158 Q_ASSERT(index.isValid() ? index.model() == this : true); 02159 if (!index.isValid()) 02160 return d->topLevelRowCount(); 02161 02162 // index is valid 02163 if (d->isFlat()) 02164 return 0; 02165 02166 QModelIndex sourceParent = d->mapParentToSource(index); 02167 02168 if (!sourceParent.isValid() && sourceModel()->hasChildren(sourceParent)) { 02169 sourceParent = mapToSource(index.parent()); 02170 d->createParentMappings(sourceParent, 0, sourceModel()->rowCount(sourceParent) - 1); 02171 sourceParent = d->mapParentToSource(index); 02172 } 02173 02174 if (!sourceParent.isValid()) 02175 return 0; 02176 02177 return sourceModel()->rowCount(sourceParent); 02178 } 02179 02180 QModelIndex KSelectionProxyModel::index(int row, int column, const QModelIndex &parent) const 02181 { 02182 Q_D(const KSelectionProxyModel); 02183 02184 if (!sourceModel() || d->m_rootIndexList.isEmpty() || !hasIndex(row, column, parent)) 02185 return QModelIndex(); 02186 02187 Q_ASSERT(parent.isValid() ? parent.model() == this : true); 02188 02189 if (!parent.isValid()) 02190 return d->createTopLevelIndex(row, column); 02191 02192 void * const parentId = d->parentId(parent); 02193 Q_ASSERT(parentId); 02194 return createIndex(row, column, parentId); 02195 } 02196 02197 QModelIndex KSelectionProxyModel::parent(const QModelIndex &index) const 02198 { 02199 Q_D(const KSelectionProxyModel); 02200 02201 if (!sourceModel() || !index.isValid() || d->m_rootIndexList.isEmpty()) 02202 return QModelIndex(); 02203 02204 Q_ASSERT(index.model() == this); 02205 02206 return d->parentForId(index.internalPointer()); 02207 } 02208 02209 Qt::ItemFlags KSelectionProxyModel::flags(const QModelIndex &index) const 02210 { 02211 if (!index.isValid() || !sourceModel()) 02212 return QAbstractProxyModel::flags(index); 02213 02214 Q_ASSERT(index.model() == this); 02215 02216 const QModelIndex srcIndex = mapToSource(index); 02217 Q_ASSERT(srcIndex.isValid()); 02218 return sourceModel()->flags(srcIndex); 02219 } 02220 02221 QVariant KSelectionProxyModel::data(const QModelIndex & index, int role) const 02222 { 02223 if (!sourceModel()) 02224 return QVariant(); 02225 02226 if (index.isValid()) { 02227 Q_ASSERT(index.model() == this); 02228 const QModelIndex idx = mapToSource(index); 02229 return idx.data(role); 02230 } 02231 return sourceModel()->data(index, role); 02232 } 02233 02234 QVariant KSelectionProxyModel::headerData(int section, Qt::Orientation orientation, int role) const 02235 { 02236 if (!sourceModel()) 02237 return QVariant(); 02238 return sourceModel()->headerData(section, orientation, role); 02239 } 02240 02241 QMimeData* KSelectionProxyModel::mimeData(const QModelIndexList & indexes) const 02242 { 02243 if (!sourceModel()) 02244 return QAbstractProxyModel::mimeData(indexes); 02245 QModelIndexList sourceIndexes; 02246 foreach(const QModelIndex& index, indexes) 02247 sourceIndexes << mapToSource(index); 02248 return sourceModel()->mimeData(sourceIndexes); 02249 } 02250 02251 QStringList KSelectionProxyModel::mimeTypes() const 02252 { 02253 if (!sourceModel()) 02254 return QAbstractProxyModel::mimeTypes(); 02255 return sourceModel()->mimeTypes(); 02256 } 02257 02258 Qt::DropActions KSelectionProxyModel::supportedDropActions() const 02259 { 02260 if (!sourceModel()) 02261 return QAbstractProxyModel::supportedDropActions(); 02262 return sourceModel()->supportedDropActions(); 02263 } 02264 02265 bool KSelectionProxyModel::hasChildren(const QModelIndex & parent) const 02266 { 02267 Q_D(const KSelectionProxyModel); 02268 02269 if (d->m_rootIndexList.isEmpty() || !sourceModel()) 02270 return false; 02271 02272 if (parent.isValid()) { 02273 Q_ASSERT(parent.model() == this); 02274 if (d->isFlat()) 02275 return false; 02276 return sourceModel()->hasChildren(mapToSource(parent)); 02277 } 02278 02279 if (!d->m_startWithChildTrees) 02280 return true; 02281 02282 return !d->m_mappedFirstChildren.isEmpty(); 02283 } 02284 02285 int KSelectionProxyModel::columnCount(const QModelIndex &index) const 02286 { 02287 Q_D(const KSelectionProxyModel); 02288 02289 if (!sourceModel() || index.column() > 0 02290 // Qt 4.6 doesn't notice changes in columnCount, so we can't return 0 when 02291 // it's actually 0 ,but must return what the source model says, even if we 02292 // have no rows or columns. 02293 #if QT_VERSION >= 0x040700 02294 || d->m_rootIndexList.isEmpty() 02295 #endif 02296 ) 02297 return 0; 02298 02299 return sourceModel()->columnCount(mapToSource(index)); 02300 } 02301 02302 QItemSelectionModel* KSelectionProxyModel::selectionModel() const 02303 { 02304 Q_D(const KSelectionProxyModel); 02305 return d->m_selectionModel.data(); 02306 } 02307 02308 bool KSelectionProxyModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) 02309 { 02310 Q_D(const KSelectionProxyModel); 02311 if (!sourceModel() || d->m_rootIndexList.isEmpty()) 02312 return false; 02313 02314 if ((row == -1) && (column == -1)) 02315 return sourceModel()->dropMimeData(data, action, -1, -1, mapToSource(parent)); 02316 02317 int source_destination_row = -1; 02318 int source_destination_column = -1; 02319 QModelIndex source_parent; 02320 02321 if (row == rowCount(parent)) { 02322 source_parent = mapToSource(parent); 02323 source_destination_row = sourceModel()->rowCount(source_parent); 02324 } else { 02325 const QModelIndex proxy_index = index(row, column, parent); 02326 const QModelIndex source_index = mapToSource(proxy_index); 02327 source_destination_row = source_index.row(); 02328 source_destination_column = source_index.column(); 02329 source_parent = source_index.parent(); 02330 } 02331 return sourceModel()->dropMimeData(data, action, source_destination_row, 02332 source_destination_column, source_parent); 02333 } 02334 02335 QList<QPersistentModelIndex> KSelectionProxyModel::sourceRootIndexes() const 02336 { 02337 Q_D(const KSelectionProxyModel); 02338 return d->m_rootIndexList; 02339 } 02340 02341 QModelIndexList KSelectionProxyModel::match(const QModelIndex& start, int role, const QVariant& value, int hits, Qt::MatchFlags flags) const 02342 { 02343 if (role < Qt::UserRole) 02344 return QAbstractProxyModel::match(start, role, value, hits, flags); 02345 02346 QModelIndexList list; 02347 QModelIndex proxyIndex; 02348 foreach(const QModelIndex &idx, sourceModel()->match(mapToSource(start), role, value, hits, flags)) { 02349 proxyIndex = mapFromSource(idx); 02350 if (proxyIndex.isValid()) 02351 list << proxyIndex; 02352 } 02353 return list; 02354 } 02355 02356 QItemSelection KSelectionProxyModel::mapSelectionFromSource(const QItemSelection& selection) const 02357 { 02358 Q_D(const KSelectionProxyModel); 02359 if (!d->m_startWithChildTrees && d->m_includeAllSelected) { 02360 // QAbstractProxyModel::mapSelectionFromSource puts invalid ranges in the result 02361 // without checking. We can't have that. 02362 QItemSelection proxySelection; 02363 foreach(const QItemSelectionRange &range, selection) 02364 { 02365 QModelIndex proxyTopLeft = mapFromSource(range.topLeft()); 02366 if (!proxyTopLeft.isValid()) 02367 continue; 02368 QModelIndex proxyBottomRight = mapFromSource(range.bottomRight()); 02369 Q_ASSERT(proxyBottomRight.isValid()); 02370 proxySelection.append(QItemSelectionRange(proxyTopLeft, proxyBottomRight)); 02371 } 02372 return proxySelection; 02373 } 02374 02375 QItemSelection proxySelection; 02376 QItemSelection::const_iterator it = selection.constBegin(); 02377 const QItemSelection::const_iterator end = selection.constEnd(); 02378 for ( ; it != end; ++it) { 02379 const QModelIndex proxyTopLeft = mapFromSource(it->topLeft()); 02380 if (!proxyTopLeft.isValid()) 02381 continue; 02382 02383 if (it->height() == 1 && it->width() == 1) 02384 proxySelection.append(QItemSelectionRange(proxyTopLeft, proxyTopLeft)); 02385 else 02386 proxySelection.append(QItemSelectionRange(proxyTopLeft, d->mapFromSource(it->bottomRight()))); 02387 } 02388 return proxySelection; 02389 } 02390 02391 QItemSelection KSelectionProxyModel::mapSelectionToSource(const QItemSelection& selection) const 02392 { 02393 Q_D(const KSelectionProxyModel); 02394 02395 if (selection.isEmpty()) 02396 return selection; 02397 02398 if (!d->m_startWithChildTrees && d->m_includeAllSelected) { 02399 // QAbstractProxyModel::mapSelectionFromSource puts invalid ranges in the result 02400 // without checking. We can't have that. 02401 QItemSelection sourceSelection; 02402 foreach(const QItemSelectionRange &range, selection) 02403 { 02404 QModelIndex sourceTopLeft = mapToSource(range.topLeft()); 02405 Q_ASSERT(sourceTopLeft.isValid()); 02406 02407 QModelIndex sourceBottomRight = mapToSource(range.bottomRight()); 02408 Q_ASSERT(sourceBottomRight.isValid()); 02409 sourceSelection.append(QItemSelectionRange(sourceTopLeft, sourceBottomRight)); 02410 } 02411 return sourceSelection; 02412 } 02413 02414 02415 QItemSelection sourceSelection; 02416 QItemSelection extraSelection; 02417 QItemSelection::const_iterator it = selection.constBegin(); 02418 const QItemSelection::const_iterator end = selection.constEnd(); 02419 for ( ; it != end; ++it) { 02420 const QModelIndex sourceTopLeft = mapToSource(it->topLeft()); 02421 if (it->height() == 1 && it->width() == 1) { 02422 sourceSelection.append(QItemSelectionRange(sourceTopLeft, sourceTopLeft)); 02423 } else if (it->parent().isValid()) { 02424 sourceSelection.append(QItemSelectionRange(sourceTopLeft, mapToSource(it->bottomRight()))); 02425 } else { 02426 // A contiguous selection in the proxy might not be contiguous in the source if it 02427 // is at the top level of the proxy. 02428 if (d->m_startWithChildTrees) { 02429 const QModelIndex sourceParent = mapFromSource(sourceTopLeft); 02430 Q_ASSERT(sourceParent.isValid()); 02431 const int rowCount = sourceModel()->rowCount(sourceParent); 02432 if (rowCount < it->bottom()) { 02433 Q_ASSERT(sourceTopLeft.isValid()); 02434 Q_ASSERT(it->bottomRight().isValid()); 02435 const QModelIndex sourceBottomRight = mapToSource(it->bottomRight()); 02436 Q_ASSERT(sourceBottomRight.isValid()); 02437 sourceSelection.append(QItemSelectionRange(sourceTopLeft, sourceBottomRight)); 02438 continue; 02439 } 02440 // Store the contiguous part... 02441 const QModelIndex sourceBottomRight = sourceModel()->index(rowCount - 1, it->right(), sourceParent); 02442 Q_ASSERT(sourceTopLeft.isValid()); 02443 Q_ASSERT(sourceBottomRight.isValid()); 02444 sourceSelection.append(QItemSelectionRange(sourceTopLeft, sourceBottomRight)); 02445 // ... and the rest will be processed later. 02446 extraSelection.append(QItemSelectionRange(createIndex(it->top() - rowCount, it->right()), it->bottomRight())); 02447 } else { 02448 QItemSelection topSelection; 02449 const QModelIndex idx = createIndex(it->top(), it->right()); 02450 const QModelIndex sourceIdx = mapToSource(idx); 02451 Q_ASSERT(sourceIdx.isValid()); 02452 topSelection.append(QItemSelectionRange(sourceTopLeft, sourceIdx)); 02453 for (int i = it->top() + 1; i < it->bottom(); ++it) { 02454 const QModelIndex left = mapToSource(createIndex(i, 0)); 02455 const QModelIndex right = mapToSource(createIndex(i, it->right())); 02456 Q_ASSERT(left.isValid()); 02457 Q_ASSERT(right.isValid()); 02458 topSelection.append(QItemSelectionRange(left, right)); 02459 } 02460 sourceSelection += kNormalizeSelection(topSelection); 02461 } 02462 } 02463 } 02464 sourceSelection << mapSelectionToSource(extraSelection); 02465 return sourceSelection; 02466 } 02467 02468 #include "moc_kselectionproxymodel.cpp"
KDE 4.7 API Reference