File indexing completed on 2024-05-12 15:43:01
0001 /* 0002 SPDX-FileCopyrightText: 2009 Stephen Kelly <steveire@gmail.com> 0003 SPDX-FileCopyrightText: 2016 Ableton AG <info@ableton.com> 0004 SPDX-FileContributor: Stephen Kelly <stephen.kelly@ableton.com> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include "kselectionproxymodel.h" 0010 0011 #include <QItemSelectionRange> 0012 #include <QPointer> 0013 #include <QStringList> 0014 0015 #include "kbihash_p.h" 0016 #include "kmodelindexproxymapper.h" 0017 #include "kvoidpointerfactory_p.h" 0018 0019 typedef KBiHash<QPersistentModelIndex, QModelIndex> SourceProxyIndexMapping; 0020 typedef KBiHash<void *, QModelIndex> ParentMapping; 0021 typedef KHash2Map<QPersistentModelIndex, int> SourceIndexProxyRowMapping; 0022 0023 /** 0024 Return true if @p idx is a descendant of one of the indexes in @p list. 0025 Note that this returns false if @p list contains @p idx. 0026 */ 0027 template<typename ModelIndex> 0028 bool isDescendantOf(const QList<ModelIndex> &list, const QModelIndex &idx) 0029 { 0030 if (!idx.isValid()) { 0031 return false; 0032 } 0033 0034 if (list.contains(idx)) { 0035 return false; 0036 } 0037 0038 QModelIndex parent = idx.parent(); 0039 while (parent.isValid()) { 0040 if (list.contains(parent)) { 0041 return true; 0042 } 0043 parent = parent.parent(); 0044 } 0045 return false; 0046 } 0047 0048 static bool isDescendantOf(const QItemSelection &selection, const QModelIndex &descendant) 0049 { 0050 if (!descendant.isValid()) { 0051 return false; 0052 } 0053 0054 if (selection.contains(descendant)) { 0055 return false; 0056 } 0057 0058 QModelIndex parent = descendant.parent(); 0059 while (parent.isValid()) { 0060 if (selection.contains(parent)) { 0061 return true; 0062 } 0063 0064 parent = parent.parent(); 0065 } 0066 return false; 0067 } 0068 0069 static bool isDescendantOf(const QItemSelectionRange &range, const QModelIndex &descendant) 0070 { 0071 if (!descendant.isValid()) { 0072 return false; 0073 } 0074 0075 if (range.contains(descendant)) { 0076 return false; 0077 } 0078 0079 QModelIndex parent = descendant.parent(); 0080 while (parent.isValid()) { 0081 if (range.contains(parent)) { 0082 return true; 0083 } 0084 0085 parent = parent.parent(); 0086 } 0087 return false; 0088 } 0089 0090 static int _getRootListRow(const QList<QModelIndexList> &rootAncestors, const QModelIndex &index) 0091 { 0092 QModelIndex commonParent = index; 0093 QModelIndex youngestAncestor; 0094 0095 int firstCommonParent = -1; 0096 int bestParentRow = -1; 0097 while (commonParent.isValid()) { 0098 youngestAncestor = commonParent; 0099 commonParent = commonParent.parent(); 0100 0101 for (int i = 0; i < rootAncestors.size(); ++i) { 0102 const QModelIndexList ancestorList = rootAncestors.at(i); 0103 0104 const int parentRow = ancestorList.indexOf(commonParent); 0105 0106 if (parentRow < 0) { 0107 continue; 0108 } 0109 0110 if (parentRow > bestParentRow) { 0111 firstCommonParent = i; 0112 bestParentRow = parentRow; 0113 } 0114 } 0115 0116 if (firstCommonParent >= 0) { 0117 break; 0118 } 0119 } 0120 0121 // If @p list is non-empty, the invalid QModelIndex() will at least be found in ancestorList. 0122 Q_ASSERT(firstCommonParent >= 0); 0123 0124 const QModelIndexList firstAnsList = rootAncestors.at(firstCommonParent); 0125 0126 const QModelIndex eldestSibling = firstAnsList.value(bestParentRow + 1); 0127 0128 if (eldestSibling.isValid()) { 0129 // firstCommonParent is a sibling of one of the ancestors of @p index. 0130 // It is the first index to share a common parent with one of the ancestors of @p index. 0131 if (eldestSibling.row() >= youngestAncestor.row()) { 0132 return firstCommonParent; 0133 } 0134 } 0135 0136 int siblingOffset = 1; 0137 0138 // The same commonParent might be common to several root indexes. 0139 // If this is the last in the list, it's the only match. We instruct the model 0140 // to insert the new index after it ( + siblingOffset). 0141 if (rootAncestors.size() <= firstCommonParent + siblingOffset) { 0142 return firstCommonParent + siblingOffset; 0143 } 0144 0145 // A 0146 // - B 0147 // - C 0148 // - D 0149 // - E 0150 // F 0151 // 0152 // F is selected, then C then D. When inserting D into the model, the commonParent is B (the parent of C). 0153 // The next existing sibling of B is F (in the proxy model). bestParentRow will then refer to an index on 0154 // the level of a child of F (which doesn't exist - Boom!). If it doesn't exist, then we've already found 0155 // the place to insert D 0156 QModelIndexList ansList = rootAncestors.at(firstCommonParent + siblingOffset); 0157 if (ansList.size() <= bestParentRow) { 0158 return firstCommonParent + siblingOffset; 0159 } 0160 0161 QModelIndex nextParent = ansList.at(bestParentRow); 0162 while (nextParent == commonParent) { 0163 if (ansList.size() < bestParentRow + 1) 0164 // If the list is longer, it means that at the end of it is a descendant of the new index. 0165 // We insert the ancestors items first in that case. 0166 { 0167 break; 0168 } 0169 0170 const QModelIndex nextSibling = ansList.value(bestParentRow + 1); 0171 0172 if (!nextSibling.isValid()) { 0173 continue; 0174 } 0175 0176 if (youngestAncestor.row() <= nextSibling.row()) { 0177 break; 0178 } 0179 0180 siblingOffset++; 0181 0182 if (rootAncestors.size() <= firstCommonParent + siblingOffset) { 0183 break; 0184 } 0185 0186 ansList = rootAncestors.at(firstCommonParent + siblingOffset); 0187 0188 // In the scenario above, E is selected after D, causing this loop to be entered, 0189 // and requiring a similar result if the next sibling in the proxy model does not have children. 0190 if (ansList.size() <= bestParentRow) { 0191 break; 0192 } 0193 0194 nextParent = ansList.at(bestParentRow); 0195 } 0196 0197 return firstCommonParent + siblingOffset; 0198 } 0199 0200 /** 0201 Determines the correct location to insert @p index into @p list. 0202 */ 0203 template<typename ModelIndex> 0204 static int getRootListRow(const QList<ModelIndex> &list, const QModelIndex &index) 0205 { 0206 if (!index.isValid()) { 0207 return -1; 0208 } 0209 0210 if (list.isEmpty()) { 0211 return 0; 0212 } 0213 0214 // What's going on? 0215 // Consider a tree like 0216 // 0217 // A 0218 // - B 0219 // - - C 0220 // - - - D 0221 // - E 0222 // - F 0223 // - - G 0224 // - - - H 0225 // - I 0226 // - - J 0227 // - K 0228 // 0229 // 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. 0230 // To figure that out, we create a list for each already selected index of its ancestors. Then, 0231 // we climb the ancestors of H until we reach an index with siblings which have a descendant 0232 // selected (F above has siblings B, E and I which have descendants which are already selected). 0233 // Those child indexes are traversed to find the right sibling to put F beside. 0234 // 0235 // i.e., new items are inserted in the expected location. 0236 0237 QList<QModelIndexList> rootAncestors; 0238 for (const QModelIndex &root : list) { 0239 QModelIndexList ancestors; 0240 ancestors << root; 0241 QModelIndex parent = root.parent(); 0242 while (parent.isValid()) { 0243 ancestors.prepend(parent); 0244 parent = parent.parent(); 0245 } 0246 ancestors.prepend(QModelIndex()); 0247 rootAncestors << ancestors; 0248 } 0249 return _getRootListRow(rootAncestors, index); 0250 } 0251 0252 /** 0253 Returns a selection in which no descendants of selected indexes are also themselves selected. 0254 For example, 0255 @code 0256 A 0257 - B 0258 C 0259 D 0260 @endcode 0261 If A, B and D are selected in @p selection, the returned selection contains only A and D. 0262 */ 0263 static QItemSelection getRootRanges(const QItemSelection &_selection) 0264 { 0265 QItemSelection rootSelection; 0266 QItemSelection selection = _selection; 0267 QList<QItemSelectionRange>::iterator it = selection.begin(); 0268 while (it != selection.end()) { 0269 if (!it->topLeft().parent().isValid()) { 0270 rootSelection.append(*it); 0271 it = selection.erase(it); 0272 } else { 0273 ++it; 0274 } 0275 } 0276 0277 it = selection.begin(); 0278 while (it != selection.end()) { 0279 const QItemSelectionRange range = *it; 0280 it = selection.erase(it); 0281 0282 if (isDescendantOf(rootSelection, range.topLeft()) || isDescendantOf(selection, range.topLeft())) { 0283 continue; 0284 } 0285 0286 rootSelection << range; 0287 } 0288 return rootSelection; 0289 } 0290 0291 /** 0292 */ 0293 struct RangeLessThan { 0294 bool operator()(const QItemSelectionRange &left, const QItemSelectionRange &right) const 0295 { 0296 if (right.model() == left.model()) { 0297 // parent has to be calculated, so we only do so once. 0298 const QModelIndex topLeftParent = left.parent(); 0299 const QModelIndex otherTopLeftParent = right.parent(); 0300 if (topLeftParent == otherTopLeftParent) { 0301 if (right.top() == left.top()) { 0302 if (right.left() == left.left()) { 0303 if (right.bottom() == left.bottom()) { 0304 return left.right() < right.right(); 0305 } 0306 return left.bottom() < right.bottom(); 0307 } 0308 return left.left() < right.left(); 0309 } 0310 return left.top() < right.top(); 0311 } 0312 return topLeftParent < otherTopLeftParent; 0313 } 0314 return left.model() < right.model(); 0315 } 0316 }; 0317 0318 static QItemSelection stableNormalizeSelection(const QItemSelection &selection) 0319 { 0320 if (selection.size() <= 1) { 0321 return selection; 0322 } 0323 0324 QItemSelection::const_iterator it = selection.begin(); 0325 const QItemSelection::const_iterator end = selection.end(); 0326 0327 Q_ASSERT(it != end); 0328 QItemSelection::const_iterator scout = it + 1; 0329 0330 QItemSelection result; 0331 while (scout != end) { 0332 Q_ASSERT(it != end); 0333 int bottom = it->bottom(); 0334 while (scout != end && it->parent() == scout->parent() && bottom + 1 == scout->top()) { 0335 bottom = scout->bottom(); 0336 ++scout; 0337 } 0338 if (bottom != it->bottom()) { 0339 const QModelIndex topLeft = it->topLeft(); 0340 result << QItemSelectionRange(topLeft, topLeft.sibling(bottom, it->right())); 0341 } 0342 Q_ASSERT(it != scout); 0343 if (scout == end) { 0344 break; 0345 } 0346 if (it + 1 == scout) { 0347 result << *it; 0348 } 0349 it = scout; 0350 ++scout; 0351 if (scout == end) { 0352 result << *it; 0353 } 0354 } 0355 return result; 0356 } 0357 0358 static QItemSelection kNormalizeSelection(QItemSelection selection) 0359 { 0360 if (selection.size() <= 1) { 0361 return selection; 0362 } 0363 0364 // KSelectionProxyModel has a strong assumption that 0365 // the views always select rows, so usually the 0366 // @p selection here contains ranges that span all 0367 // columns. However, if a QSortFilterProxyModel 0368 // is used too, it splits up the complete ranges into 0369 // one index per range. That confuses the data structures 0370 // held by this proxy (which keeps track of indexes in the 0371 // first column). As this proxy already assumes that if the 0372 // zeroth column is selected, then its entire row is selected, 0373 // we can safely remove the ranges which do not include 0374 // column 0 without a loss of functionality. 0375 QItemSelection::iterator i = selection.begin(); 0376 while (i != selection.end()) { 0377 if (i->left() > 0) { 0378 i = selection.erase(i); 0379 } else { 0380 ++i; 0381 } 0382 } 0383 0384 RangeLessThan lt; 0385 std::sort(selection.begin(), selection.end(), lt); 0386 return stableNormalizeSelection(selection); 0387 } 0388 0389 class KSelectionProxyModelPrivate 0390 { 0391 public: 0392 KSelectionProxyModelPrivate(KSelectionProxyModel *model) 0393 : q_ptr(model) 0394 , m_indexMapper(nullptr) 0395 , m_startWithChildTrees(false) 0396 , m_omitChildren(false) 0397 , m_omitDescendants(false) 0398 , m_includeAllSelected(false) 0399 , m_rowsInserted(false) 0400 , m_rowsRemoved(false) 0401 , m_recreateFirstChildMappingOnRemoval(false) 0402 , m_rowsMoved(false) 0403 , m_resetting(false) 0404 , m_sourceModelResetting(false) 0405 , m_doubleResetting(false) 0406 , m_layoutChanging(false) 0407 , m_ignoreNextLayoutAboutToBeChanged(false) 0408 , m_ignoreNextLayoutChanged(false) 0409 , m_selectionModel(nullptr) 0410 , m_filterBehavior(KSelectionProxyModel::InvalidBehavior) 0411 { 0412 } 0413 0414 Q_DECLARE_PUBLIC(KSelectionProxyModel) 0415 KSelectionProxyModel *const q_ptr; 0416 0417 // A unique id is generated for each parent. It is used for the internalPointer of its children in the proxy 0418 // This is used to store a unique id for QModelIndexes in the proxy which have children. 0419 // If an index newly gets children it is added to this hash. If its last child is removed it is removed from this map. 0420 // If this map contains an index, that index hasChildren(). This hash is populated when new rows are inserted in the 0421 // source model, or a new selection is made. 0422 mutable ParentMapping m_parentIds; 0423 // This mapping maps indexes with children in the source to indexes with children in the proxy. 0424 // The order of indexes in this list is not relevant. 0425 mutable SourceProxyIndexMapping m_mappedParents; 0426 0427 KVoidPointerFactory<> m_voidPointerFactory; 0428 0429 /** 0430 Keeping Persistent indexes from this model in this model breaks in certain situations 0431 such as after source insert, but before calling endInsertRows in this model. In such a state, 0432 the persistent indexes are not updated, but the methods assume they are already up-to-date. 0433 0434 Instead of using persistentindexes for proxy indexes in m_mappedParents, we maintain them ourselves with this method. 0435 0436 m_mappedParents and m_parentIds are affected. 0437 0438 @p parent and @p start refer to the proxy model. Any rows >= @p start will be updated. 0439 @p offset is the amount that affected indexes will be changed. 0440 */ 0441 void updateInternalIndexes(const QModelIndex &parent, int start, int offset); 0442 0443 /** 0444 * Updates stored indexes in the proxy. Any proxy row >= @p start is changed by @p offset. 0445 * 0446 * This is only called to update indexes in the top level of the proxy. Most commonly that is 0447 * 0448 * m_mappedParents, m_parentIds and m_mappedFirstChildren are affected. 0449 */ 0450 void updateInternalTopIndexes(int start, int offset); 0451 0452 void updateFirstChildMapping(const QModelIndex &parent, int offset); 0453 0454 bool isFlat() const 0455 { 0456 return m_omitChildren || (m_omitDescendants && m_startWithChildTrees); 0457 } 0458 0459 /** 0460 * Tries to ensure that @p parent is a mapped parent in the proxy. 0461 * Returns true if parent is mappable in the model, and false otherwise. 0462 */ 0463 bool ensureMappable(const QModelIndex &parent) const; 0464 bool parentIsMappable(const QModelIndex &parent) const 0465 { 0466 return parentAlreadyMapped(parent) || m_rootIndexList.contains(parent); 0467 } 0468 0469 /** 0470 * Maps @p parent to source if it is already mapped, and otherwise returns an invalid QModelIndex. 0471 */ 0472 QModelIndex mapFromSource(const QModelIndex &parent) const; 0473 0474 /** 0475 Creates mappings in m_parentIds and m_mappedParents between the source and the proxy. 0476 0477 This is not recursive 0478 */ 0479 void createParentMappings(const QModelIndex &parent, int start, int end) const; 0480 void createFirstChildMapping(const QModelIndex &parent, int proxyRow) const; 0481 bool firstChildAlreadyMapped(const QModelIndex &firstChild) const; 0482 bool parentAlreadyMapped(const QModelIndex &parent) const; 0483 void removeFirstChildMappings(int start, int end); 0484 void removeParentMappings(const QModelIndex &parent, int start, int end); 0485 0486 /** 0487 Given a QModelIndex in the proxy, return the corresponding QModelIndex in the source. 0488 0489 This method works only if the index has children in the proxy model which already has a mapping from the source. 0490 0491 This means that if the proxy is a flat list, this method will always return QModelIndex(). Additionally, it means that m_mappedParents is not populated 0492 automatically and must be populated manually. 0493 0494 No new mapping is created by this method. 0495 */ 0496 QModelIndex mapParentToSource(const QModelIndex &proxyParent) const; 0497 0498 /** 0499 Given a QModelIndex in the source model, return the corresponding QModelIndex in the proxy. 0500 0501 This method works only if the index has children in the proxy model which already has a mapping from the source. 0502 0503 No new mapping is created by this method. 0504 */ 0505 QModelIndex mapParentFromSource(const QModelIndex &sourceParent) const; 0506 0507 QModelIndex mapTopLevelToSource(int row, int column) const; 0508 QModelIndex mapTopLevelFromSource(const QModelIndex &sourceIndex) const; 0509 QModelIndex createTopLevelIndex(int row, int column) const; 0510 int topLevelRowCount() const; 0511 0512 void *parentId(const QModelIndex &proxyParent) const 0513 { 0514 return m_parentIds.rightToLeft(proxyParent); 0515 } 0516 QModelIndex parentForId(void *id) const 0517 { 0518 return m_parentIds.leftToRight(id); 0519 } 0520 0521 // Only populated if m_startWithChildTrees. 0522 0523 mutable SourceIndexProxyRowMapping m_mappedFirstChildren; 0524 0525 // Source list is the selection in the source model. 0526 QList<QPersistentModelIndex> m_rootIndexList; 0527 0528 KModelIndexProxyMapper *m_indexMapper; 0529 0530 QPair<int, int> beginRemoveRows(const QModelIndex &parent, int start, int end) const; 0531 QPair<int, int> beginInsertRows(const QModelIndex &parent, int start, int end) const; 0532 void endRemoveRows(const QModelIndex &sourceParent, int proxyStart, int proxyEnd); 0533 void endInsertRows(const QModelIndex &parent, int start, int end); 0534 0535 void sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end); 0536 void sourceRowsInserted(const QModelIndex &parent, int start, int end); 0537 void sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end); 0538 void sourceRowsRemoved(const QModelIndex &parent, int start, int end); 0539 void sourceRowsAboutToBeMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destParent, int destRow); 0540 void sourceRowsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destParent, int destRow); 0541 void sourceModelAboutToBeReset(); 0542 void sourceModelReset(); 0543 void sourceLayoutAboutToBeChanged(); 0544 void sourceLayoutChanged(); 0545 void emitContinuousRanges(const QModelIndex &sourceFirst, const QModelIndex &sourceLast, const QModelIndex &proxyFirst, const QModelIndex &proxyLast); 0546 void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); 0547 0548 void removeSelectionFromProxy(const QItemSelection &selection); 0549 0550 void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); 0551 void sourceModelDestroyed(); 0552 0553 void resetInternalData(); 0554 0555 bool rootWillBeRemoved(const QItemSelection &selection, const QModelIndex &root); 0556 0557 /** 0558 When items are inserted or removed in the m_startWithChildTrees configuration, 0559 this method helps find the startRow for use emitting the signals from the proxy. 0560 */ 0561 int getProxyInitialRow(const QModelIndex &parent) const; 0562 0563 /** 0564 If m_startWithChildTrees is true, this method returns the row in the proxy model to insert newIndex 0565 items. 0566 0567 This is a special case because the items above rootListRow in the list are not in the model, but 0568 their children are. Those children must be counted. 0569 0570 If m_startWithChildTrees is false, this method returns @p rootListRow. 0571 */ 0572 int getTargetRow(int rootListRow); 0573 0574 /** 0575 Inserts the indexes in @p list into the proxy model. 0576 */ 0577 void insertSelectionIntoProxy(const QItemSelection &selection); 0578 0579 bool m_startWithChildTrees; 0580 bool m_omitChildren; 0581 bool m_omitDescendants; 0582 bool m_includeAllSelected; 0583 bool m_rowsInserted; 0584 bool m_rowsRemoved; 0585 bool m_recreateFirstChildMappingOnRemoval; 0586 QPair<int, int> m_proxyRemoveRows; 0587 bool m_rowsMoved; 0588 bool m_resetting; 0589 bool m_sourceModelResetting; 0590 bool m_doubleResetting; 0591 bool m_layoutChanging; 0592 bool m_ignoreNextLayoutAboutToBeChanged; 0593 bool m_ignoreNextLayoutChanged; 0594 QPointer<QItemSelectionModel> m_selectionModel; 0595 0596 KSelectionProxyModel::FilterBehavior m_filterBehavior; 0597 0598 QList<QPersistentModelIndex> m_layoutChangePersistentIndexes; 0599 QModelIndexList m_proxyIndexes; 0600 0601 struct PendingSelectionChange { 0602 PendingSelectionChange() 0603 { 0604 } 0605 PendingSelectionChange(const QItemSelection &selected_, const QItemSelection &deselected_) 0606 : selected(selected_) 0607 , deselected(deselected_) 0608 { 0609 } 0610 QItemSelection selected; 0611 QItemSelection deselected; 0612 }; 0613 QVector<PendingSelectionChange> m_pendingSelectionChanges; 0614 QMetaObject::Connection selectionModelModelAboutToBeResetConnection; 0615 QMetaObject::Connection selectionModelModelResetConnection; 0616 }; 0617 0618 void KSelectionProxyModelPrivate::emitContinuousRanges(const QModelIndex &sourceFirst, 0619 const QModelIndex &sourceLast, 0620 const QModelIndex &proxyFirst, 0621 const QModelIndex &proxyLast) 0622 { 0623 Q_Q(KSelectionProxyModel); 0624 0625 Q_ASSERT(sourceFirst.model() == q->sourceModel()); 0626 Q_ASSERT(sourceLast.model() == q->sourceModel()); 0627 Q_ASSERT(proxyFirst.model() == q); 0628 Q_ASSERT(proxyLast.model() == q); 0629 0630 const int proxyRangeSize = proxyLast.row() - proxyFirst.row(); 0631 const int sourceRangeSize = sourceLast.row() - sourceFirst.row(); 0632 0633 if (proxyRangeSize == sourceRangeSize) { 0634 Q_EMIT q->dataChanged(proxyFirst, proxyLast); 0635 return; 0636 } 0637 0638 // TODO: Loop to skip descendant ranges. 0639 // int lastRow; 0640 // 0641 // const QModelIndex sourceHalfWay = sourceFirst.sibling(sourceFirst.row() + (sourceRangeSize / 2)); 0642 // const QModelIndex proxyHalfWay = proxyFirst.sibling(proxyFirst.row() + (proxyRangeSize / 2)); 0643 // const QModelIndex mappedSourceHalfway = q->mapToSource(proxyHalfWay); 0644 // 0645 // const int halfProxyRange = mappedSourceHalfway.row() - proxyFirst.row(); 0646 // const int halfSourceRange = sourceHalfWay.row() - sourceFirst.row(); 0647 // 0648 // if (proxyRangeSize == sourceRangeSize) 0649 // { 0650 // Q_EMIT q->dataChanged(proxyFirst, proxyLast.sibling(proxyFirst.row() + proxyRangeSize, proxyLast.column())); 0651 // return; 0652 // } 0653 0654 Q_EMIT q->dataChanged(proxyFirst, proxyLast); 0655 } 0656 0657 void KSelectionProxyModelPrivate::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) 0658 { 0659 Q_Q(KSelectionProxyModel); 0660 0661 Q_ASSERT(topLeft.model() == q->sourceModel()); 0662 Q_ASSERT(bottomRight.model() == q->sourceModel()); 0663 0664 const QModelIndex sourceRangeParent = topLeft.parent(); 0665 if (!sourceRangeParent.isValid() && m_startWithChildTrees && !m_rootIndexList.contains(sourceRangeParent)) { 0666 return; 0667 } 0668 0669 const QModelIndex proxyTopLeft = q->mapFromSource(topLeft); 0670 const QModelIndex proxyBottomRight = q->mapFromSource(bottomRight); 0671 0672 const QModelIndex proxyRangeParent = proxyTopLeft.parent(); 0673 0674 if (!m_omitChildren && m_omitDescendants && m_startWithChildTrees && m_includeAllSelected) { 0675 // ChildrenOfExactSelection 0676 if (proxyTopLeft.isValid()) { 0677 emitContinuousRanges(topLeft, bottomRight, proxyTopLeft, proxyBottomRight); 0678 } 0679 return; 0680 } 0681 0682 if ((m_omitChildren && !m_startWithChildTrees && m_includeAllSelected) || (!proxyRangeParent.isValid() && !m_startWithChildTrees)) { 0683 // Exact selection and SubTreeRoots and SubTrees in top level 0684 // Emit continuous ranges. 0685 QList<int> changedRows; 0686 for (int row = topLeft.row(); row <= bottomRight.row(); ++row) { 0687 const QModelIndex index = q->sourceModel()->index(row, topLeft.column(), topLeft.parent()); 0688 const int idx = m_rootIndexList.indexOf(index); 0689 if (idx != -1) { 0690 changedRows.append(idx); 0691 } 0692 } 0693 if (changedRows.isEmpty()) { 0694 return; 0695 } 0696 int first = changedRows.first(); 0697 int previous = first; 0698 QList<int>::const_iterator it = changedRows.constBegin(); 0699 const QList<int>::const_iterator end = changedRows.constEnd(); 0700 for (; it != end; ++it) { 0701 if (*it == previous + 1) { 0702 ++previous; 0703 } else { 0704 const QModelIndex _top = q->index(first, topLeft.column()); 0705 const QModelIndex _bottom = q->index(previous, bottomRight.column()); 0706 Q_EMIT q->dataChanged(_top, _bottom); 0707 previous = first = *it; 0708 } 0709 } 0710 if (first != previous) { 0711 const QModelIndex _top = q->index(first, topLeft.column()); 0712 const QModelIndex _bottom = q->index(previous, bottomRight.column()); 0713 Q_EMIT q->dataChanged(_top, _bottom); 0714 } 0715 return; 0716 } 0717 if (proxyRangeParent.isValid()) { 0718 if (m_omitChildren && !m_startWithChildTrees && !m_includeAllSelected) 0719 // SubTreeRoots 0720 { 0721 return; 0722 } 0723 if (!proxyTopLeft.isValid()) { 0724 return; 0725 } 0726 // SubTrees and SubTreesWithoutRoots 0727 Q_EMIT q->dataChanged(proxyTopLeft, proxyBottomRight); 0728 return; 0729 } 0730 0731 if (m_startWithChildTrees && !m_omitChildren && !m_includeAllSelected && !m_omitDescendants) { 0732 // SubTreesWithoutRoots 0733 if (proxyTopLeft.isValid()) { 0734 Q_EMIT q->dataChanged(proxyTopLeft, proxyBottomRight); 0735 } 0736 return; 0737 } 0738 } 0739 0740 void KSelectionProxyModelPrivate::sourceLayoutAboutToBeChanged() 0741 { 0742 Q_Q(KSelectionProxyModel); 0743 0744 if (m_ignoreNextLayoutAboutToBeChanged) { 0745 m_ignoreNextLayoutAboutToBeChanged = false; 0746 return; 0747 } 0748 0749 if (m_rootIndexList.isEmpty()) { 0750 return; 0751 } 0752 0753 Q_EMIT q->layoutAboutToBeChanged(); 0754 0755 QItemSelection selection; 0756 for (const QModelIndex &rootIndex : std::as_const(m_rootIndexList)) { 0757 // This will be optimized later. 0758 Q_EMIT q->rootIndexAboutToBeRemoved(rootIndex, KSelectionProxyModel::QPrivateSignal()); 0759 selection.append(QItemSelectionRange(rootIndex, rootIndex)); 0760 } 0761 0762 selection = kNormalizeSelection(selection); 0763 Q_EMIT q->rootSelectionAboutToBeRemoved(selection, KSelectionProxyModel::QPrivateSignal()); 0764 0765 QPersistentModelIndex srcPersistentIndex; 0766 const auto lst = q->persistentIndexList(); 0767 for (const QModelIndex &proxyPersistentIndex : lst) { 0768 m_proxyIndexes << proxyPersistentIndex; 0769 Q_ASSERT(proxyPersistentIndex.isValid()); 0770 srcPersistentIndex = q->mapToSource(proxyPersistentIndex); 0771 Q_ASSERT(srcPersistentIndex.isValid()); 0772 m_layoutChangePersistentIndexes << srcPersistentIndex; 0773 } 0774 0775 m_rootIndexList.clear(); 0776 } 0777 0778 void KSelectionProxyModelPrivate::sourceLayoutChanged() 0779 { 0780 Q_Q(KSelectionProxyModel); 0781 0782 if (m_ignoreNextLayoutChanged) { 0783 m_ignoreNextLayoutChanged = false; 0784 return; 0785 } 0786 0787 if (!m_selectionModel || !m_selectionModel->hasSelection()) { 0788 return; 0789 } 0790 0791 // Handling this signal is slow. 0792 // The problem is that anything can happen between emissions of layoutAboutToBeChanged and layoutChanged. 0793 // We can't assume anything is the same about the structure anymore. items have been sorted, items which 0794 // were parents before are now not, items which were not parents before now are, items which used to be the 0795 // first child are now the Nth child and items which used to be the Nth child are now the first child. 0796 // We effectively can't update our mapping because we don't have enough information to update everything. 0797 // The only way we would have is if we take a persistent index of the entire source model 0798 // on sourceLayoutAboutToBeChanged and then examine it here. That would be far too expensive. 0799 // Instead we just have to clear the entire mapping and recreate it. 0800 0801 m_rootIndexList.clear(); 0802 m_mappedFirstChildren.clear(); 0803 m_mappedParents.clear(); 0804 m_parentIds.clear(); 0805 0806 m_resetting = true; 0807 m_layoutChanging = true; 0808 selectionChanged(m_selectionModel->selection(), QItemSelection()); 0809 m_resetting = false; 0810 m_layoutChanging = false; 0811 0812 for (int i = 0; i < m_proxyIndexes.size(); ++i) { 0813 q->changePersistentIndex(m_proxyIndexes.at(i), q->mapFromSource(m_layoutChangePersistentIndexes.at(i))); 0814 } 0815 0816 m_layoutChangePersistentIndexes.clear(); 0817 m_proxyIndexes.clear(); 0818 0819 Q_EMIT q->layoutChanged(); 0820 } 0821 0822 void KSelectionProxyModelPrivate::resetInternalData() 0823 { 0824 m_rootIndexList.clear(); 0825 m_layoutChangePersistentIndexes.clear(); 0826 m_proxyIndexes.clear(); 0827 m_mappedParents.clear(); 0828 m_parentIds.clear(); 0829 m_mappedFirstChildren.clear(); 0830 m_voidPointerFactory.clear(); 0831 } 0832 0833 void KSelectionProxyModelPrivate::sourceModelDestroyed() 0834 { 0835 // There is very little we can do here. 0836 resetInternalData(); 0837 m_resetting = false; 0838 m_sourceModelResetting = false; 0839 } 0840 0841 void KSelectionProxyModelPrivate::sourceModelAboutToBeReset() 0842 { 0843 Q_Q(KSelectionProxyModel); 0844 0845 // We might be resetting as a result of the selection source model resetting. 0846 // If so we don't want to emit 0847 // sourceModelAboutToBeReset 0848 // sourceModelAboutToBeReset 0849 // sourceModelReset 0850 // sourceModelReset 0851 // So we ensure that we just emit one. 0852 if (m_resetting) { 0853 // If both the source model and the selection source model are reset, 0854 // We want to begin our reset before the first one is reset and end 0855 // it after the second one is reset. 0856 m_doubleResetting = true; 0857 return; 0858 } 0859 0860 q->beginResetModel(); 0861 m_resetting = true; 0862 m_sourceModelResetting = true; 0863 } 0864 0865 void KSelectionProxyModelPrivate::sourceModelReset() 0866 { 0867 Q_Q(KSelectionProxyModel); 0868 0869 if (m_doubleResetting) { 0870 m_doubleResetting = false; 0871 return; 0872 } 0873 0874 resetInternalData(); 0875 m_sourceModelResetting = false; 0876 m_resetting = false; 0877 selectionChanged(m_selectionModel->selection(), QItemSelection()); 0878 q->endResetModel(); 0879 } 0880 0881 int KSelectionProxyModelPrivate::getProxyInitialRow(const QModelIndex &parent) const 0882 { 0883 Q_ASSERT(m_rootIndexList.contains(parent)); 0884 0885 // The difficulty here is that parent and parent.parent() might both be in the m_rootIndexList. 0886 0887 // - A 0888 // - B 0889 // - - C 0890 // - - D 0891 // - - - E 0892 0893 // Consider that B and D are selected. The proxy model is: 0894 0895 // - C 0896 // - D 0897 // - E 0898 0899 // Then D gets a new child at 0. In that case we require adding F between D and E. 0900 0901 // Consider instead that D gets removed. Then @p parent will be B. 0902 0903 Q_Q(const KSelectionProxyModel); 0904 0905 Q_ASSERT(parent.model() == q->sourceModel()); 0906 0907 int parentPosition = m_rootIndexList.indexOf(parent); 0908 0909 QModelIndex parentAbove; 0910 0911 // If parentPosition == 0, then parent.parent() is not also in the model. (ordering is preserved) 0912 while (parentPosition > 0) { 0913 parentPosition--; 0914 0915 parentAbove = m_rootIndexList.at(parentPosition); 0916 Q_ASSERT(parentAbove.isValid()); 0917 0918 int rows = q->sourceModel()->rowCount(parentAbove); 0919 if (rows > 0) { 0920 QModelIndex sourceIndexAbove = q->sourceModel()->index(rows - 1, 0, parentAbove); 0921 Q_ASSERT(sourceIndexAbove.isValid()); 0922 QModelIndex proxyChildAbove = mapFromSource(sourceIndexAbove); 0923 Q_ASSERT(proxyChildAbove.isValid()); 0924 return proxyChildAbove.row() + 1; 0925 } 0926 } 0927 return 0; 0928 } 0929 0930 void KSelectionProxyModelPrivate::updateFirstChildMapping(const QModelIndex &parent, int offset) 0931 { 0932 Q_Q(KSelectionProxyModel); 0933 0934 Q_ASSERT(parent.isValid() ? parent.model() == q->sourceModel() : true); 0935 0936 static const int column = 0; 0937 static const int row = 0; 0938 0939 const QPersistentModelIndex srcIndex = q->sourceModel()->index(row, column, parent); 0940 0941 const QPersistentModelIndex previousFirstChild = q->sourceModel()->index(offset, column, parent); 0942 0943 SourceIndexProxyRowMapping::left_iterator it = m_mappedFirstChildren.findLeft(previousFirstChild); 0944 if (it == m_mappedFirstChildren.leftEnd()) { 0945 return; 0946 } 0947 0948 Q_ASSERT(srcIndex.isValid()); 0949 const int proxyRow = it.value(); 0950 Q_ASSERT(proxyRow >= 0); 0951 0952 m_mappedFirstChildren.eraseLeft(it); 0953 0954 // The proxy row in the mapping has already been updated by the offset in updateInternalTopIndexes 0955 // so we restore it by applying the reverse. 0956 m_mappedFirstChildren.insert(srcIndex, proxyRow - offset); 0957 } 0958 0959 QPair<int, int> KSelectionProxyModelPrivate::beginInsertRows(const QModelIndex &parent, int start, int end) const 0960 { 0961 const QModelIndex proxyParent = mapFromSource(parent); 0962 0963 if (!proxyParent.isValid()) { 0964 if (!m_startWithChildTrees) { 0965 return qMakePair(-1, -1); 0966 } 0967 0968 if (!m_rootIndexList.contains(parent)) { 0969 return qMakePair(-1, -1); 0970 } 0971 } 0972 0973 if (!m_startWithChildTrees) { 0974 // SubTrees 0975 if (proxyParent.isValid()) { 0976 return qMakePair(start, end); 0977 } 0978 return qMakePair(-1, -1); 0979 } 0980 0981 if (!m_includeAllSelected && proxyParent.isValid()) { 0982 // SubTreesWithoutRoots deeper than topLevel 0983 return qMakePair(start, end); 0984 } 0985 0986 if (!m_rootIndexList.contains(parent)) { 0987 return qMakePair(-1, -1); 0988 } 0989 0990 const int proxyStartRow = getProxyInitialRow(parent) + start; 0991 return qMakePair(proxyStartRow, proxyStartRow + (end - start)); 0992 } 0993 0994 void KSelectionProxyModelPrivate::sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end) 0995 { 0996 Q_Q(KSelectionProxyModel); 0997 0998 Q_ASSERT(parent.isValid() ? parent.model() == q->sourceModel() : true); 0999 1000 if (!m_selectionModel || !m_selectionModel->hasSelection()) { 1001 return; 1002 } 1003 1004 if (m_omitChildren) 1005 // ExactSelection and SubTreeRoots 1006 { 1007 return; 1008 } 1009 1010 // topLevel insertions can be ignored because topLevel items would need to be selected to affect the proxy. 1011 if (!parent.isValid()) { 1012 return; 1013 } 1014 1015 QPair<int, int> pair = beginInsertRows(parent, start, end); 1016 if (pair.first == -1) { 1017 return; 1018 } 1019 1020 const QModelIndex proxyParent = m_startWithChildTrees ? QModelIndex() : mapFromSource(parent); 1021 1022 m_rowsInserted = true; 1023 q->beginInsertRows(proxyParent, pair.first, pair.second); 1024 } 1025 1026 void KSelectionProxyModelPrivate::endInsertRows(const QModelIndex &parent, int start, int end) 1027 { 1028 Q_Q(const KSelectionProxyModel); 1029 const QModelIndex proxyParent = mapFromSource(parent); 1030 const int offset = end - start + 1; 1031 1032 const bool isNewParent = (q->sourceModel()->rowCount(parent) == offset); 1033 1034 if (m_startWithChildTrees && m_rootIndexList.contains(parent)) { 1035 const int proxyInitialRow = getProxyInitialRow(parent); 1036 Q_ASSERT(proxyInitialRow >= 0); 1037 const int proxyStartRow = proxyInitialRow + start; 1038 1039 updateInternalTopIndexes(proxyStartRow, offset); 1040 if (isNewParent) { 1041 createFirstChildMapping(parent, proxyStartRow); 1042 } else if (start == 0) 1043 // We already have a first child mapping, but what we have mapped is not the first child anymore 1044 // so we need to update it. 1045 { 1046 updateFirstChildMapping(parent, end + 1); 1047 } 1048 } else { 1049 Q_ASSERT(proxyParent.isValid()); 1050 if (!isNewParent) { 1051 updateInternalIndexes(proxyParent, start, offset); 1052 } else { 1053 createParentMappings(parent.parent(), parent.row(), parent.row()); 1054 } 1055 } 1056 createParentMappings(parent, start, end); 1057 } 1058 1059 void KSelectionProxyModelPrivate::sourceRowsInserted(const QModelIndex &parent, int start, int end) 1060 { 1061 Q_Q(KSelectionProxyModel); 1062 1063 Q_ASSERT(parent.isValid() ? parent.model() == q->sourceModel() : true); 1064 1065 if (!m_rowsInserted) { 1066 return; 1067 } 1068 m_rowsInserted = false; 1069 endInsertRows(parent, start, end); 1070 q->endInsertRows(); 1071 for (const PendingSelectionChange &pendingChange : std::as_const(m_pendingSelectionChanges)) { 1072 selectionChanged(pendingChange.selected, pendingChange.deselected); 1073 } 1074 m_pendingSelectionChanges.clear(); 1075 } 1076 1077 static bool rootWillBeRemovedFrom(const QModelIndex &ancestor, int start, int end, const QModelIndex &root) 1078 { 1079 Q_ASSERT(root.isValid()); 1080 1081 auto parent = root; 1082 while (parent.isValid()) { 1083 auto prev = parent; 1084 parent = parent.parent(); 1085 if (parent == ancestor) { 1086 return (prev.row() <= end && prev.row() >= start); 1087 } 1088 } 1089 return false; 1090 } 1091 1092 bool KSelectionProxyModelPrivate::rootWillBeRemoved(const QItemSelection &selection, const QModelIndex &root) 1093 { 1094 Q_ASSERT(root.isValid()); 1095 1096 for (auto &r : selection) { 1097 if (m_includeAllSelected) { 1098 if (r.parent() == root.parent() && root.row() <= r.bottom() && root.row() >= r.top()) { 1099 return true; 1100 } 1101 } else { 1102 if (rootWillBeRemovedFrom(r.parent(), r.top(), r.bottom(), root)) { 1103 return true; 1104 } 1105 } 1106 } 1107 return false; 1108 } 1109 1110 QPair<int, int> KSelectionProxyModelPrivate::beginRemoveRows(const QModelIndex &parent, int start, int end) const 1111 { 1112 Q_Q(const KSelectionProxyModel); 1113 1114 if (!m_includeAllSelected && !m_omitChildren) { 1115 // SubTrees and SubTreesWithoutRoots 1116 const QModelIndex proxyParent = mapParentFromSource(parent); 1117 if (proxyParent.isValid()) { 1118 return qMakePair(start, end); 1119 } 1120 } 1121 1122 if (m_startWithChildTrees && m_rootIndexList.contains(parent)) { 1123 const int proxyStartRow = getProxyInitialRow(parent) + start; 1124 const int proxyEndRow = proxyStartRow + (end - start); 1125 return qMakePair(proxyStartRow, proxyEndRow); 1126 } 1127 1128 QList<QPersistentModelIndex>::const_iterator rootIt = m_rootIndexList.constBegin(); 1129 const QList<QPersistentModelIndex>::const_iterator rootEnd = m_rootIndexList.constEnd(); 1130 int proxyStartRemove = 0; 1131 1132 for (; rootIt != rootEnd; ++rootIt) { 1133 if (rootWillBeRemovedFrom(parent, start, end, *rootIt)) { 1134 break; 1135 } else { 1136 if (m_startWithChildTrees) { 1137 proxyStartRemove += q->sourceModel()->rowCount(*rootIt); 1138 } else { 1139 ++proxyStartRemove; 1140 } 1141 } 1142 } 1143 1144 if (rootIt == rootEnd) { 1145 return qMakePair(-1, -1); 1146 } 1147 1148 int proxyEndRemove = proxyStartRemove; 1149 1150 for (; rootIt != rootEnd; ++rootIt) { 1151 if (!rootWillBeRemovedFrom(parent, start, end, *rootIt)) { 1152 break; 1153 } 1154 if (m_startWithChildTrees) { 1155 proxyEndRemove += q->sourceModel()->rowCount(*rootIt); 1156 } else { 1157 ++proxyEndRemove; 1158 } 1159 } 1160 1161 --proxyEndRemove; 1162 if (proxyEndRemove >= proxyStartRemove) { 1163 return qMakePair(proxyStartRemove, proxyEndRemove); 1164 } 1165 return qMakePair(-1, -1); 1166 } 1167 1168 void KSelectionProxyModelPrivate::sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) 1169 { 1170 Q_Q(KSelectionProxyModel); 1171 1172 Q_ASSERT(parent.isValid() ? parent.model() == q->sourceModel() : true); 1173 1174 if (!m_selectionModel || !m_selectionModel->hasSelection()) { 1175 return; 1176 } 1177 1178 QPair<int, int> pair = beginRemoveRows(parent, start, end); 1179 if (pair.first == -1) { 1180 return; 1181 } 1182 1183 const QModelIndex proxyParent = mapParentFromSource(parent); 1184 1185 m_rowsRemoved = true; 1186 m_proxyRemoveRows = pair; 1187 m_recreateFirstChildMappingOnRemoval = m_mappedFirstChildren.leftContains(q->sourceModel()->index(start, 0, parent)); 1188 q->beginRemoveRows(proxyParent, pair.first, pair.second); 1189 } 1190 1191 void KSelectionProxyModelPrivate::endRemoveRows(const QModelIndex &sourceParent, int proxyStart, int proxyEnd) 1192 { 1193 const QModelIndex proxyParent = mapParentFromSource(sourceParent); 1194 1195 // We need to make sure to remove entries from the mappings before updating internal indexes. 1196 1197 // - A 1198 // - - B 1199 // - C 1200 // - - D 1201 1202 // If A and C are selected, B and D are in the proxy. B maps to row 0 and D maps to row 1. 1203 // If B is then deleted leaving only D in the proxy, D needs to be updated to be a mapping 1204 // to row 0 instead of row 1. If that is done before removing the mapping for B, then the mapping 1205 // for D would overwrite the mapping for B and then the code for removing mappings would incorrectly 1206 // remove D. 1207 // So we first remove B and then update D. 1208 1209 { 1210 SourceProxyIndexMapping::right_iterator it = m_mappedParents.rightBegin(); 1211 1212 while (it != m_mappedParents.rightEnd()) { 1213 if (!it.value().isValid()) { 1214 m_parentIds.removeRight(it.key()); 1215 it = m_mappedParents.eraseRight(it); 1216 } else { 1217 ++it; 1218 } 1219 } 1220 } 1221 1222 { 1223 // Depending on what is selected at the time, a single removal in the source could invalidate 1224 // many mapped first child items at once. 1225 1226 // - A 1227 // - B 1228 // - - C 1229 // - - D 1230 // - - - E 1231 // - - - F 1232 // - - - - G 1233 // - - - - H 1234 1235 // If D and F are selected, the proxy contains E, F, G, H. If B is then deleted E to H will 1236 // be removed, including both first child mappings at E and G. 1237 1238 if (!proxyParent.isValid()) { 1239 removeFirstChildMappings(proxyStart, proxyEnd); 1240 } 1241 } 1242 1243 if (proxyParent.isValid()) { 1244 updateInternalIndexes(proxyParent, proxyEnd + 1, -1 * (proxyEnd - proxyStart + 1)); 1245 } else { 1246 updateInternalTopIndexes(proxyEnd + 1, -1 * (proxyEnd - proxyStart + 1)); 1247 } 1248 1249 QList<QPersistentModelIndex>::iterator rootIt = m_rootIndexList.begin(); 1250 while (rootIt != m_rootIndexList.end()) { 1251 if (!rootIt->isValid()) { 1252 rootIt = m_rootIndexList.erase(rootIt); 1253 } else { 1254 ++rootIt; 1255 } 1256 } 1257 } 1258 1259 void KSelectionProxyModelPrivate::sourceRowsRemoved(const QModelIndex &parent, int start, int end) 1260 { 1261 Q_Q(KSelectionProxyModel); 1262 Q_UNUSED(end) 1263 Q_UNUSED(start) 1264 1265 Q_ASSERT(parent.isValid() ? parent.model() == q->sourceModel() : true); 1266 1267 if (!m_selectionModel) { 1268 return; 1269 } 1270 1271 if (!m_rowsRemoved) { 1272 return; 1273 } 1274 m_rowsRemoved = false; 1275 1276 Q_ASSERT(m_proxyRemoveRows.first >= 0); 1277 Q_ASSERT(m_proxyRemoveRows.second >= 0); 1278 endRemoveRows(parent, m_proxyRemoveRows.first, m_proxyRemoveRows.second); 1279 if (m_recreateFirstChildMappingOnRemoval && q->sourceModel()->hasChildren(parent)) 1280 // The private endRemoveRows call might remove the first child mapping for parent, so 1281 // we create it again in that case. 1282 { 1283 createFirstChildMapping(parent, m_proxyRemoveRows.first); 1284 } 1285 m_recreateFirstChildMappingOnRemoval = false; 1286 1287 m_proxyRemoveRows = qMakePair(-1, -1); 1288 q->endRemoveRows(); 1289 } 1290 1291 void KSelectionProxyModelPrivate::sourceRowsAboutToBeMoved(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destRow) 1292 { 1293 Q_UNUSED(srcParent) 1294 Q_UNUSED(srcStart) 1295 Q_UNUSED(srcEnd) 1296 Q_UNUSED(destParent) 1297 Q_UNUSED(destRow) 1298 // we cheat and just act like the layout changed; this might benefit from some 1299 // optimization 1300 sourceLayoutAboutToBeChanged(); 1301 } 1302 1303 void KSelectionProxyModelPrivate::sourceRowsMoved(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destRow) 1304 { 1305 Q_UNUSED(srcParent) 1306 Q_UNUSED(srcStart) 1307 Q_UNUSED(srcEnd) 1308 Q_UNUSED(destParent) 1309 Q_UNUSED(destRow) 1310 // we cheat and just act like the layout changed; this might benefit from some 1311 // optimization 1312 sourceLayoutChanged(); 1313 } 1314 1315 QModelIndex KSelectionProxyModelPrivate::mapParentToSource(const QModelIndex &proxyParent) const 1316 { 1317 return m_mappedParents.rightToLeft(proxyParent); 1318 } 1319 1320 QModelIndex KSelectionProxyModelPrivate::mapParentFromSource(const QModelIndex &sourceParent) const 1321 { 1322 return m_mappedParents.leftToRight(sourceParent); 1323 } 1324 1325 static bool 1326 indexIsValid(bool startWithChildTrees, int row, const QList<QPersistentModelIndex> &rootIndexList, const SourceIndexProxyRowMapping &mappedFirstChildren) 1327 { 1328 if (!startWithChildTrees) { 1329 Q_ASSERT(rootIndexList.size() > row); 1330 } else { 1331 Q_ASSERT(!mappedFirstChildren.isEmpty()); 1332 1333 SourceIndexProxyRowMapping::right_const_iterator result = mappedFirstChildren.rightUpperBound(row) - 1; 1334 1335 Q_ASSERT(result != mappedFirstChildren.rightEnd()); 1336 const int proxyFirstRow = result.key(); 1337 const QModelIndex sourceFirstChild = result.value(); 1338 Q_ASSERT(proxyFirstRow >= 0); 1339 Q_ASSERT(sourceFirstChild.isValid()); 1340 Q_ASSERT(sourceFirstChild.parent().isValid()); 1341 Q_ASSERT(row <= proxyFirstRow + sourceFirstChild.model()->rowCount(sourceFirstChild.parent())); 1342 } 1343 return true; 1344 } 1345 1346 QModelIndex KSelectionProxyModelPrivate::createTopLevelIndex(int row, int column) const 1347 { 1348 Q_Q(const KSelectionProxyModel); 1349 1350 Q_ASSERT(indexIsValid(m_startWithChildTrees, row, m_rootIndexList, m_mappedFirstChildren)); 1351 return q->createIndex(row, column); 1352 } 1353 1354 QModelIndex KSelectionProxyModelPrivate::mapTopLevelFromSource(const QModelIndex &sourceIndex) const 1355 { 1356 Q_Q(const KSelectionProxyModel); 1357 1358 const QModelIndex sourceParent = sourceIndex.parent(); 1359 const int row = m_rootIndexList.indexOf(sourceIndex); 1360 if (row == -1) { 1361 return QModelIndex(); 1362 } 1363 1364 if (!m_startWithChildTrees) { 1365 Q_ASSERT(m_rootIndexList.size() > row); 1366 return q->createIndex(row, sourceIndex.column()); 1367 } 1368 if (!m_rootIndexList.contains(sourceParent)) { 1369 return QModelIndex(); 1370 } 1371 1372 const QModelIndex firstChild = q->sourceModel()->index(0, 0, sourceParent); 1373 const int firstProxyRow = m_mappedFirstChildren.leftToRight(firstChild); 1374 1375 return q->createIndex(firstProxyRow + sourceIndex.row(), sourceIndex.column()); 1376 } 1377 1378 QModelIndex KSelectionProxyModelPrivate::mapFromSource(const QModelIndex &sourceIndex) const 1379 { 1380 Q_Q(const KSelectionProxyModel); 1381 1382 const QModelIndex maybeMapped = mapParentFromSource(sourceIndex); 1383 if (maybeMapped.isValid()) { 1384 // Q_ASSERT((!d->m_startWithChildTrees && d->m_rootIndexList.contains(maybeMapped)) ? maybeMapped.row() < 0 : true ); 1385 return maybeMapped; 1386 } 1387 const QModelIndex sourceParent = sourceIndex.parent(); 1388 1389 const QModelIndex proxyParent = mapParentFromSource(sourceParent); 1390 if (proxyParent.isValid()) { 1391 void *const parentId = m_parentIds.rightToLeft(proxyParent); 1392 static const int column = 0; 1393 return q->createIndex(sourceIndex.row(), column, parentId); 1394 } 1395 1396 const QModelIndex firstChild = q->sourceModel()->index(0, 0, sourceParent); 1397 1398 if (m_mappedFirstChildren.leftContains(firstChild)) { 1399 const int firstProxyRow = m_mappedFirstChildren.leftToRight(firstChild); 1400 return q->createIndex(firstProxyRow + sourceIndex.row(), sourceIndex.column()); 1401 } 1402 return mapTopLevelFromSource(sourceIndex); 1403 } 1404 1405 int KSelectionProxyModelPrivate::topLevelRowCount() const 1406 { 1407 Q_Q(const KSelectionProxyModel); 1408 1409 if (!m_startWithChildTrees) { 1410 return m_rootIndexList.size(); 1411 } 1412 1413 if (m_mappedFirstChildren.isEmpty()) { 1414 return 0; 1415 } 1416 1417 const SourceIndexProxyRowMapping::right_const_iterator result = m_mappedFirstChildren.rightConstEnd() - 1; 1418 1419 const int proxyFirstRow = result.key(); 1420 const QModelIndex sourceFirstChild = result.value(); 1421 Q_ASSERT(sourceFirstChild.isValid()); 1422 const QModelIndex sourceParent = sourceFirstChild.parent(); 1423 Q_ASSERT(sourceParent.isValid()); 1424 return q->sourceModel()->rowCount(sourceParent) + proxyFirstRow; 1425 } 1426 1427 bool KSelectionProxyModelPrivate::ensureMappable(const QModelIndex &parent) const 1428 { 1429 Q_Q(const KSelectionProxyModel); 1430 1431 if (isFlat()) { 1432 return true; 1433 } 1434 1435 if (parentIsMappable(parent)) { 1436 return true; 1437 } 1438 1439 QModelIndex ancestor = parent.parent(); 1440 QModelIndexList ancestorList; 1441 while (ancestor.isValid()) { 1442 if (parentIsMappable(ancestor)) { 1443 break; 1444 } else { 1445 ancestorList.prepend(ancestor); 1446 } 1447 1448 ancestor = ancestor.parent(); 1449 } 1450 1451 if (!ancestor.isValid()) 1452 // @p parent is not a descendant of m_rootIndexList. 1453 { 1454 return false; 1455 } 1456 1457 // sourceIndex can be mapped to the proxy. We just need to create mappings for its ancestors first. 1458 for (int i = 0; i < ancestorList.size(); ++i) { 1459 const QModelIndex existingAncestor = mapParentFromSource(ancestor); 1460 Q_ASSERT(existingAncestor.isValid()); 1461 1462 void *const ansId = m_parentIds.rightToLeft(existingAncestor); 1463 const QModelIndex newSourceParent = ancestorList.at(i); 1464 const QModelIndex newProxyParent = q->createIndex(newSourceParent.row(), newSourceParent.column(), ansId); 1465 1466 void *const newId = m_voidPointerFactory.createPointer(); 1467 m_parentIds.insert(newId, newProxyParent); 1468 m_mappedParents.insert(QPersistentModelIndex(newSourceParent), newProxyParent); 1469 ancestor = newSourceParent; 1470 } 1471 return true; 1472 } 1473 1474 void KSelectionProxyModelPrivate::updateInternalTopIndexes(int start, int offset) 1475 { 1476 updateInternalIndexes(QModelIndex(), start, offset); 1477 1478 QHash<QPersistentModelIndex, int> updates; 1479 { 1480 SourceIndexProxyRowMapping::right_iterator it = m_mappedFirstChildren.rightLowerBound(start); 1481 const SourceIndexProxyRowMapping::right_iterator end = m_mappedFirstChildren.rightEnd(); 1482 1483 for (; it != end; ++it) { 1484 updates.insert(*it, it.key() + offset); 1485 } 1486 } 1487 { 1488 QHash<QPersistentModelIndex, int>::const_iterator it = updates.constBegin(); 1489 const QHash<QPersistentModelIndex, int>::const_iterator end = updates.constEnd(); 1490 1491 for (; it != end; ++it) { 1492 m_mappedFirstChildren.insert(it.key(), it.value()); 1493 } 1494 } 1495 } 1496 1497 void KSelectionProxyModelPrivate::updateInternalIndexes(const QModelIndex &parent, int start, int offset) 1498 { 1499 Q_Q(KSelectionProxyModel); 1500 1501 Q_ASSERT(start + offset >= 0); 1502 Q_ASSERT(parent.isValid() ? parent.model() == q : true); 1503 1504 if (isFlat()) { 1505 return; 1506 } 1507 1508 SourceProxyIndexMapping::left_iterator mappedParentIt = m_mappedParents.leftBegin(); 1509 1510 QHash<void *, QModelIndex> updatedParentIds; 1511 QHash<QPersistentModelIndex, QModelIndex> updatedParents; 1512 1513 for (; mappedParentIt != m_mappedParents.leftEnd(); ++mappedParentIt) { 1514 const QModelIndex proxyIndex = mappedParentIt.value(); 1515 Q_ASSERT(proxyIndex.isValid()); 1516 1517 if (proxyIndex.row() < start) { 1518 continue; 1519 } 1520 1521 const QModelIndex proxyParent = proxyIndex.parent(); 1522 1523 if (parent.isValid()) { 1524 if (proxyParent != parent) { 1525 continue; 1526 } 1527 } else { 1528 if (proxyParent.isValid()) { 1529 continue; 1530 } 1531 } 1532 Q_ASSERT(m_parentIds.rightContains(proxyIndex)); 1533 void *const key = m_parentIds.rightToLeft(proxyIndex); 1534 1535 const QModelIndex newIndex = q->createIndex(proxyIndex.row() + offset, proxyIndex.column(), proxyIndex.internalPointer()); 1536 1537 Q_ASSERT(newIndex.isValid()); 1538 1539 updatedParentIds.insert(key, newIndex); 1540 updatedParents.insert(mappedParentIt.key(), newIndex); 1541 } 1542 1543 { 1544 QHash<QPersistentModelIndex, QModelIndex>::const_iterator it = updatedParents.constBegin(); 1545 const QHash<QPersistentModelIndex, QModelIndex>::const_iterator end = updatedParents.constEnd(); 1546 for (; it != end; ++it) { 1547 m_mappedParents.insert(it.key(), it.value()); 1548 } 1549 } 1550 1551 { 1552 QHash<void *, QModelIndex>::const_iterator it = updatedParentIds.constBegin(); 1553 const QHash<void *, QModelIndex>::const_iterator end = updatedParentIds.constEnd(); 1554 for (; it != end; ++it) { 1555 m_parentIds.insert(it.key(), it.value()); 1556 } 1557 } 1558 } 1559 1560 bool KSelectionProxyModelPrivate::parentAlreadyMapped(const QModelIndex &parent) const 1561 { 1562 Q_Q(const KSelectionProxyModel); 1563 Q_UNUSED(q) // except in Q_ASSERT 1564 Q_ASSERT(parent.model() == q->sourceModel()); 1565 return m_mappedParents.leftContains(parent); 1566 } 1567 1568 bool KSelectionProxyModelPrivate::firstChildAlreadyMapped(const QModelIndex &firstChild) const 1569 { 1570 Q_Q(const KSelectionProxyModel); 1571 Q_UNUSED(q) // except in Q_ASSERT 1572 Q_ASSERT(firstChild.model() == q->sourceModel()); 1573 return m_mappedFirstChildren.leftContains(firstChild); 1574 } 1575 1576 void KSelectionProxyModelPrivate::createFirstChildMapping(const QModelIndex &parent, int proxyRow) const 1577 { 1578 Q_Q(const KSelectionProxyModel); 1579 1580 Q_ASSERT(parent.isValid() ? parent.model() == q->sourceModel() : true); 1581 1582 static const int column = 0; 1583 static const int row = 0; 1584 1585 const QPersistentModelIndex srcIndex = q->sourceModel()->index(row, column, parent); 1586 1587 if (firstChildAlreadyMapped(srcIndex)) { 1588 return; 1589 } 1590 1591 Q_ASSERT(srcIndex.isValid()); 1592 m_mappedFirstChildren.insert(srcIndex, proxyRow); 1593 } 1594 1595 void KSelectionProxyModelPrivate::createParentMappings(const QModelIndex &parent, int start, int end) const 1596 { 1597 if (isFlat()) { 1598 return; 1599 } 1600 1601 Q_Q(const KSelectionProxyModel); 1602 1603 Q_ASSERT(parent.isValid() ? parent.model() == q->sourceModel() : true); 1604 1605 static const int column = 0; 1606 1607 for (int row = start; row <= end; ++row) { 1608 const QModelIndex srcIndex = q->sourceModel()->index(row, column, parent); 1609 Q_ASSERT(srcIndex.isValid()); 1610 if (!q->sourceModel()->hasChildren(srcIndex) || parentAlreadyMapped(srcIndex)) { 1611 continue; 1612 } 1613 1614 const QModelIndex proxyIndex = mapFromSource(srcIndex); 1615 if (!proxyIndex.isValid()) { 1616 return; // If one of them is not mapped, its siblings won't be either 1617 } 1618 1619 void *const newId = m_voidPointerFactory.createPointer(); 1620 m_parentIds.insert(newId, proxyIndex); 1621 Q_ASSERT(srcIndex.isValid()); 1622 m_mappedParents.insert(QPersistentModelIndex(srcIndex), proxyIndex); 1623 } 1624 } 1625 1626 void KSelectionProxyModelPrivate::removeFirstChildMappings(int start, int end) 1627 { 1628 SourceIndexProxyRowMapping::right_iterator it = m_mappedFirstChildren.rightLowerBound(start); 1629 const SourceIndexProxyRowMapping::right_iterator endIt = m_mappedFirstChildren.rightUpperBound(end); 1630 while (it != endIt) { 1631 it = m_mappedFirstChildren.eraseRight(it); 1632 } 1633 } 1634 1635 void KSelectionProxyModelPrivate::removeParentMappings(const QModelIndex &parent, int start, int end) 1636 { 1637 Q_Q(KSelectionProxyModel); 1638 1639 Q_ASSERT(parent.isValid() ? parent.model() == q : true); 1640 1641 // collect all removals first, as executing them recursively will invalidate our iterators 1642 struct RemovalInfo { 1643 QPersistentModelIndex idx; 1644 QModelIndex sourceIdx; 1645 }; 1646 std::vector<RemovalInfo> removals; 1647 removals.reserve(end - start + 1); 1648 for (auto it = m_mappedParents.rightBegin(); it != m_mappedParents.rightEnd(); ++it) { 1649 if (it.key().row() >= start && it.key().row() <= end) { 1650 const QModelIndex sourceParent = it.value(); 1651 const QModelIndex proxyGrandParent = mapParentFromSource(sourceParent.parent()); 1652 if (proxyGrandParent == parent) { 1653 removals.push_back({it.key(), it.value()}); 1654 } 1655 } 1656 } 1657 1658 // execute the removals 1659 const bool flatList = isFlat(); 1660 for (const auto &r : removals) { 1661 if (!flatList) { 1662 removeParentMappings(r.idx, 0, q->sourceModel()->rowCount(r.sourceIdx) - 1); 1663 } 1664 m_parentIds.removeRight(r.idx); 1665 m_mappedParents.removeRight(r.idx); 1666 } 1667 } 1668 1669 QModelIndex KSelectionProxyModelPrivate::mapTopLevelToSource(int row, int column) const 1670 { 1671 if (!m_startWithChildTrees) { 1672 const QModelIndex idx = m_rootIndexList.at(row); 1673 return idx.sibling(idx.row(), column); 1674 } 1675 1676 if (m_mappedFirstChildren.isEmpty()) { 1677 return QModelIndex(); 1678 } 1679 1680 SourceIndexProxyRowMapping::right_iterator result = m_mappedFirstChildren.rightUpperBound(row) - 1; 1681 1682 Q_ASSERT(result != m_mappedFirstChildren.rightEnd()); 1683 1684 const int proxyFirstRow = result.key(); 1685 const QModelIndex sourceFirstChild = result.value(); 1686 Q_ASSERT(sourceFirstChild.isValid()); 1687 return sourceFirstChild.sibling(row - proxyFirstRow, column); 1688 } 1689 1690 void KSelectionProxyModelPrivate::removeSelectionFromProxy(const QItemSelection &selection) 1691 { 1692 Q_Q(KSelectionProxyModel); 1693 if (selection.isEmpty()) { 1694 return; 1695 } 1696 1697 QList<QPersistentModelIndex>::iterator rootIt = m_rootIndexList.begin(); 1698 const QList<QPersistentModelIndex>::iterator rootEnd = m_rootIndexList.end(); 1699 int proxyStartRemove = 0; 1700 1701 for (; rootIt != rootEnd; ++rootIt) { 1702 if (rootWillBeRemoved(selection, *rootIt)) { 1703 break; 1704 } else { 1705 if (m_startWithChildTrees) { 1706 auto rc = q->sourceModel()->rowCount(*rootIt); 1707 proxyStartRemove += rc; 1708 } else { 1709 ++proxyStartRemove; 1710 } 1711 } 1712 } 1713 1714 if (rootIt == rootEnd) { 1715 return; 1716 } 1717 1718 int proxyEndRemove = proxyStartRemove; 1719 1720 QList<QPersistentModelIndex>::iterator rootRemoveStart = rootIt; 1721 1722 for (; rootIt != rootEnd; ++rootIt) { 1723 if (!rootWillBeRemoved(selection, *rootIt)) { 1724 break; 1725 } 1726 q->rootIndexAboutToBeRemoved(*rootIt, KSelectionProxyModel::QPrivateSignal()); 1727 if (m_startWithChildTrees) { 1728 auto rc = q->sourceModel()->rowCount(*rootIt); 1729 proxyEndRemove += rc; 1730 } else { 1731 ++proxyEndRemove; 1732 } 1733 } 1734 1735 --proxyEndRemove; 1736 if (proxyEndRemove >= proxyStartRemove) { 1737 q->beginRemoveRows(QModelIndex(), proxyStartRemove, proxyEndRemove); 1738 1739 rootIt = m_rootIndexList.erase(rootRemoveStart, rootIt); 1740 1741 removeParentMappings(QModelIndex(), proxyStartRemove, proxyEndRemove); 1742 if (m_startWithChildTrees) { 1743 removeFirstChildMappings(proxyStartRemove, proxyEndRemove); 1744 } 1745 updateInternalTopIndexes(proxyEndRemove + 1, -1 * (proxyEndRemove - proxyStartRemove + 1)); 1746 1747 q->endRemoveRows(); 1748 } else { 1749 rootIt = m_rootIndexList.erase(rootRemoveStart, rootIt); 1750 } 1751 if (rootIt != rootEnd) { 1752 removeSelectionFromProxy(selection); 1753 } 1754 } 1755 1756 void KSelectionProxyModelPrivate::selectionChanged(const QItemSelection &_selected, const QItemSelection &_deselected) 1757 { 1758 Q_Q(KSelectionProxyModel); 1759 1760 if (!q->sourceModel() || (_selected.isEmpty() && _deselected.isEmpty())) { 1761 return; 1762 } 1763 1764 if (m_sourceModelResetting) { 1765 return; 1766 } 1767 1768 if (m_rowsInserted || m_rowsRemoved) { 1769 m_pendingSelectionChanges.append(PendingSelectionChange(_selected, _deselected)); 1770 return; 1771 } 1772 1773 // Any deselected indexes in the m_rootIndexList are removed. Then, any 1774 // indexes in the selected range which are not a descendant of one of the already selected indexes 1775 // are inserted into the model. 1776 // 1777 // All ranges from the selection model need to be split into individual rows. Ranges which are contiguous in 1778 // the selection model may not be contiguous in the source model if there's a sort filter proxy model in the chain. 1779 // 1780 // Some descendants of deselected indexes may still be selected. The ranges in m_selectionModel->selection() 1781 // are examined. If any of the ranges are descendants of one of the 1782 // indexes in deselected, they are added to the ranges to be inserted into the model. 1783 // 1784 // The new indexes are inserted in sorted order. 1785 1786 const QItemSelection selected = kNormalizeSelection(m_indexMapper->mapSelectionRightToLeft(_selected)); 1787 const QItemSelection deselected = kNormalizeSelection(m_indexMapper->mapSelectionRightToLeft(_deselected)); 1788 1789 #if QT_VERSION < 0x040800 1790 // The QItemSelectionModel sometimes doesn't remove deselected items from its selection 1791 // Fixed in Qt 4.8 : http://qt.gitorious.org/qt/qt/merge_requests/2403 1792 QItemSelection reportedSelection = m_selectionModel->selection(); 1793 reportedSelection.merge(deselected, QItemSelectionModel::Deselect); 1794 QItemSelection fullSelection = m_indexMapper->mapSelectionRightToLeft(reportedSelection); 1795 #else 1796 QItemSelection fullSelection = m_indexMapper->mapSelectionRightToLeft(m_selectionModel->selection()); 1797 #endif 1798 1799 fullSelection = kNormalizeSelection(fullSelection); 1800 1801 QItemSelection newRootRanges; 1802 QItemSelection removedRootRanges; 1803 if (!m_includeAllSelected) { 1804 newRootRanges = getRootRanges(selected); 1805 1806 QItemSelection existingSelection = fullSelection; 1807 // What was selected before the selection was made. 1808 existingSelection.merge(selected, QItemSelectionModel::Deselect); 1809 1810 // This is similar to m_rootRanges, but that m_rootRanges at this point still contains the roots 1811 // of deselected and existingRootRanges does not. 1812 1813 const QItemSelection existingRootRanges = getRootRanges(existingSelection); 1814 { 1815 QMutableListIterator<QItemSelectionRange> i(newRootRanges); 1816 while (i.hasNext()) { 1817 const QItemSelectionRange range = i.next(); 1818 const QModelIndex topLeft = range.topLeft(); 1819 if (isDescendantOf(existingRootRanges, topLeft)) { 1820 i.remove(); 1821 } 1822 } 1823 } 1824 1825 QItemSelection exposedSelection; 1826 { 1827 QItemSelection deselectedRootRanges = getRootRanges(deselected); 1828 QListIterator<QItemSelectionRange> i(deselectedRootRanges); 1829 while (i.hasNext()) { 1830 const QItemSelectionRange range = i.next(); 1831 const QModelIndex topLeft = range.topLeft(); 1832 // Consider this: 1833 // 1834 // - A 1835 // - - B 1836 // - - - C 1837 // - - - - D 1838 // 1839 // B and D were selected, then B was deselected and C was selected in one go. 1840 if (!isDescendantOf(existingRootRanges, topLeft)) { 1841 // B is topLeft and fullSelection contains D. 1842 // B is not a descendant of D. 1843 1844 // range is not a descendant of the selection, but maybe the selection is a descendant of range. 1845 // no need to check selected here. That's already in newRootRanges. 1846 // existingRootRanges and newRootRanges do not overlap. 1847 for (const QItemSelectionRange &selectedRange : existingRootRanges) { 1848 const QModelIndex selectedRangeTopLeft = selectedRange.topLeft(); 1849 // existingSelection (and selectedRangeTopLeft) is D. 1850 // D is a descendant of B, so when B was removed, D might have been exposed as a root. 1851 if (isDescendantOf(range, selectedRangeTopLeft) 1852 // But D is also a descendant of part of the new selection C, which is already set to be a new root 1853 // so D would not be added to exposedSelection because C is in newRootRanges. 1854 && !isDescendantOf(newRootRanges, selectedRangeTopLeft)) { 1855 exposedSelection.append(selectedRange); 1856 } 1857 } 1858 removedRootRanges << range; 1859 } 1860 } 1861 } 1862 1863 QItemSelection obscuredRanges; 1864 { 1865 QListIterator<QItemSelectionRange> i(existingRootRanges); 1866 while (i.hasNext()) { 1867 const QItemSelectionRange range = i.next(); 1868 if (isDescendantOf(newRootRanges, range.topLeft())) { 1869 obscuredRanges << range; 1870 } 1871 } 1872 } 1873 removedRootRanges << getRootRanges(obscuredRanges); 1874 newRootRanges << getRootRanges(exposedSelection); 1875 1876 removedRootRanges = kNormalizeSelection(removedRootRanges); 1877 newRootRanges = kNormalizeSelection(newRootRanges); 1878 } else { 1879 removedRootRanges = deselected; 1880 newRootRanges = selected; 1881 } 1882 1883 removeSelectionFromProxy(removedRootRanges); 1884 1885 if (!m_selectionModel->hasSelection()) { 1886 Q_ASSERT(m_rootIndexList.isEmpty()); 1887 Q_ASSERT(m_mappedFirstChildren.isEmpty()); 1888 Q_ASSERT(m_mappedParents.isEmpty()); 1889 Q_ASSERT(m_parentIds.isEmpty()); 1890 } 1891 1892 insertSelectionIntoProxy(newRootRanges); 1893 } 1894 1895 int KSelectionProxyModelPrivate::getTargetRow(int rootListRow) 1896 { 1897 Q_Q(KSelectionProxyModel); 1898 if (!m_startWithChildTrees) { 1899 return rootListRow; 1900 } 1901 1902 --rootListRow; 1903 while (rootListRow >= 0) { 1904 const QModelIndex idx = m_rootIndexList.at(rootListRow); 1905 Q_ASSERT(idx.isValid()); 1906 const int rowCount = q->sourceModel()->rowCount(idx); 1907 if (rowCount > 0) { 1908 static const int column = 0; 1909 const QModelIndex srcIdx = q->sourceModel()->index(rowCount - 1, column, idx); 1910 const QModelIndex proxyLastChild = mapFromSource(srcIdx); 1911 return proxyLastChild.row() + 1; 1912 } 1913 --rootListRow; 1914 } 1915 return 0; 1916 } 1917 1918 void KSelectionProxyModelPrivate::insertSelectionIntoProxy(const QItemSelection &selection) 1919 { 1920 Q_Q(KSelectionProxyModel); 1921 1922 if (selection.isEmpty()) { 1923 return; 1924 } 1925 1926 const auto lst = selection.indexes(); 1927 for (const QModelIndex &newIndex : lst) { 1928 Q_ASSERT(newIndex.model() == q->sourceModel()); 1929 if (newIndex.column() > 0) { 1930 continue; 1931 } 1932 if (m_startWithChildTrees) { 1933 const int rootListRow = getRootListRow(m_rootIndexList, newIndex); 1934 Q_ASSERT(q->sourceModel() == newIndex.model()); 1935 const int rowCount = q->sourceModel()->rowCount(newIndex); 1936 const int startRow = getTargetRow(rootListRow); 1937 1938 if (rowCount == 0) { 1939 // Even if the newindex doesn't have any children to put into the model yet, 1940 // We still need to make sure its future children are inserted into the model. 1941 m_rootIndexList.insert(rootListRow, newIndex); 1942 if (!m_resetting || m_layoutChanging) { 1943 Q_EMIT q->rootIndexAdded(newIndex, KSelectionProxyModel::QPrivateSignal()); 1944 } 1945 continue; 1946 } 1947 if (!m_resetting) { 1948 q->beginInsertRows(QModelIndex(), startRow, startRow + rowCount - 1); 1949 } 1950 Q_ASSERT(newIndex.isValid()); 1951 m_rootIndexList.insert(rootListRow, newIndex); 1952 if (!m_resetting || m_layoutChanging) { 1953 Q_EMIT q->rootIndexAdded(newIndex, KSelectionProxyModel::QPrivateSignal()); 1954 } 1955 1956 int _start = 0; 1957 for (int i = 0; i < rootListRow; ++i) { 1958 _start += q->sourceModel()->rowCount(m_rootIndexList.at(i)); 1959 } 1960 1961 updateInternalTopIndexes(_start, rowCount); 1962 createFirstChildMapping(newIndex, _start); 1963 createParentMappings(newIndex, 0, rowCount - 1); 1964 1965 if (!m_resetting) { 1966 q->endInsertRows(); 1967 } 1968 1969 } else { 1970 const int row = getRootListRow(m_rootIndexList, newIndex); 1971 if (!m_resetting) { 1972 q->beginInsertRows(QModelIndex(), row, row); 1973 } 1974 1975 Q_ASSERT(newIndex.isValid()); 1976 m_rootIndexList.insert(row, newIndex); 1977 1978 if (!m_resetting || m_layoutChanging) { 1979 Q_EMIT q->rootIndexAdded(newIndex, KSelectionProxyModel::QPrivateSignal()); 1980 } 1981 Q_ASSERT(m_rootIndexList.size() > row); 1982 updateInternalIndexes(QModelIndex(), row, 1); 1983 createParentMappings(newIndex.parent(), newIndex.row(), newIndex.row()); 1984 1985 if (!m_resetting) { 1986 q->endInsertRows(); 1987 } 1988 } 1989 } 1990 Q_EMIT q->rootSelectionAdded(selection, KSelectionProxyModel::QPrivateSignal()); 1991 } 1992 1993 KSelectionProxyModel::KSelectionProxyModel(QItemSelectionModel *selectionModel, QObject *parent) 1994 : QAbstractProxyModel(parent) 1995 , d_ptr(new KSelectionProxyModelPrivate(this)) 1996 { 1997 setSelectionModel(selectionModel); 1998 } 1999 2000 KSelectionProxyModel::KSelectionProxyModel() 2001 : QAbstractProxyModel(nullptr) 2002 , d_ptr(new KSelectionProxyModelPrivate(this)) 2003 { 2004 } 2005 2006 KSelectionProxyModel::~KSelectionProxyModel() = default; 2007 2008 void KSelectionProxyModel::setFilterBehavior(FilterBehavior behavior) 2009 { 2010 Q_D(KSelectionProxyModel); 2011 2012 Q_ASSERT(behavior != InvalidBehavior); 2013 if (behavior == InvalidBehavior) { 2014 return; 2015 } 2016 if (d->m_filterBehavior != behavior) { 2017 beginResetModel(); 2018 2019 d->m_filterBehavior = behavior; 2020 2021 switch (behavior) { 2022 case InvalidBehavior: { 2023 Q_ASSERT(!"InvalidBehavior can't be used here"); 2024 return; 2025 } 2026 case SubTrees: { 2027 d->m_omitChildren = false; 2028 d->m_omitDescendants = false; 2029 d->m_startWithChildTrees = false; 2030 d->m_includeAllSelected = false; 2031 break; 2032 } 2033 case SubTreeRoots: { 2034 d->m_omitChildren = true; 2035 d->m_startWithChildTrees = false; 2036 d->m_includeAllSelected = false; 2037 break; 2038 } 2039 case SubTreesWithoutRoots: { 2040 d->m_omitChildren = false; 2041 d->m_omitDescendants = false; 2042 d->m_startWithChildTrees = true; 2043 d->m_includeAllSelected = false; 2044 break; 2045 } 2046 case ExactSelection: { 2047 d->m_omitChildren = true; 2048 d->m_startWithChildTrees = false; 2049 d->m_includeAllSelected = true; 2050 break; 2051 } 2052 case ChildrenOfExactSelection: { 2053 d->m_omitChildren = false; 2054 d->m_omitDescendants = true; 2055 d->m_startWithChildTrees = true; 2056 d->m_includeAllSelected = true; 2057 break; 2058 } 2059 } 2060 Q_EMIT filterBehaviorChanged(QPrivateSignal()); 2061 d->resetInternalData(); 2062 if (d->m_selectionModel) { 2063 d->selectionChanged(d->m_selectionModel->selection(), QItemSelection()); 2064 } 2065 2066 endResetModel(); 2067 } 2068 } 2069 2070 KSelectionProxyModel::FilterBehavior KSelectionProxyModel::filterBehavior() const 2071 { 2072 Q_D(const KSelectionProxyModel); 2073 return d->m_filterBehavior; 2074 } 2075 2076 void KSelectionProxyModel::setSourceModel(QAbstractItemModel *_sourceModel) 2077 { 2078 Q_D(KSelectionProxyModel); 2079 2080 Q_ASSERT(_sourceModel != this); 2081 2082 if (_sourceModel == sourceModel()) { 2083 return; 2084 } 2085 2086 beginResetModel(); 2087 d->m_resetting = true; 2088 2089 if (auto *oldSourceModel = sourceModel()) { 2090 disconnect(oldSourceModel, nullptr, this, nullptr); 2091 } 2092 2093 // Must be called before QAbstractProxyModel::setSourceModel because it emit some signals. 2094 d->resetInternalData(); 2095 QAbstractProxyModel::setSourceModel(_sourceModel); 2096 if (_sourceModel) { 2097 if (d->m_selectionModel) { 2098 delete d->m_indexMapper; 2099 d->m_indexMapper = new KModelIndexProxyMapper(_sourceModel, d->m_selectionModel->model(), this); 2100 if (d->m_selectionModel->hasSelection()) { 2101 d->selectionChanged(d->m_selectionModel->selection(), QItemSelection()); 2102 } 2103 } 2104 2105 connect(_sourceModel, &QAbstractItemModel::rowsAboutToBeInserted, this, [d](const QModelIndex &parent, int start, int end) { 2106 d->sourceRowsAboutToBeInserted(parent, start, end); 2107 }); 2108 2109 connect(_sourceModel, &QAbstractItemModel::rowsInserted, this, [d](const QModelIndex &parent, int start, int end) { 2110 d->sourceRowsInserted(parent, start, end); 2111 }); 2112 2113 connect(_sourceModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, [d](const QModelIndex &parent, int start, int end) { 2114 d->sourceRowsAboutToBeRemoved(parent, start, end); 2115 }); 2116 2117 connect(_sourceModel, &QAbstractItemModel::rowsRemoved, this, [d](const QModelIndex &parent, int start, int end) { 2118 d->sourceRowsRemoved(parent, start, end); 2119 }); 2120 2121 connect(_sourceModel, 2122 &QAbstractItemModel::rowsAboutToBeMoved, 2123 this, 2124 [d](const QModelIndex &parent, int start, int end, const QModelIndex &destParent, int destRow) { 2125 d->sourceRowsAboutToBeMoved(parent, start, end, destParent, destRow); 2126 }); 2127 2128 connect(_sourceModel, 2129 &QAbstractItemModel::rowsMoved, 2130 this, 2131 [d](const QModelIndex &parent, int start, int end, const QModelIndex &destParent, int destRow) { 2132 d->sourceRowsMoved(parent, start, end, destParent, destRow); 2133 }); 2134 2135 connect(_sourceModel, &QAbstractItemModel::modelAboutToBeReset, this, [d]() { 2136 d->sourceModelAboutToBeReset(); 2137 }); 2138 2139 connect(_sourceModel, &QAbstractItemModel::modelReset, this, [d]() { 2140 d->sourceModelReset(); 2141 }); 2142 2143 connect(_sourceModel, &QAbstractItemModel::dataChanged, this, [d](const QModelIndex &topLeft, const QModelIndex &bottomRight) { 2144 d->sourceDataChanged(topLeft, bottomRight); 2145 }); 2146 2147 connect(_sourceModel, &QAbstractItemModel::layoutAboutToBeChanged, this, [d]() { 2148 d->sourceLayoutAboutToBeChanged(); 2149 }); 2150 2151 connect(_sourceModel, &QAbstractItemModel::layoutChanged, this, [d]() { 2152 d->sourceLayoutChanged(); 2153 }); 2154 2155 connect(_sourceModel, &QObject::destroyed, this, [d]() { 2156 d->sourceModelDestroyed(); 2157 }); 2158 } 2159 2160 d->m_resetting = false; 2161 endResetModel(); 2162 } 2163 2164 QModelIndex KSelectionProxyModel::mapToSource(const QModelIndex &proxyIndex) const 2165 { 2166 Q_D(const KSelectionProxyModel); 2167 2168 if (!proxyIndex.isValid() || !sourceModel() || d->m_rootIndexList.isEmpty()) { 2169 return QModelIndex(); 2170 } 2171 2172 Q_ASSERT(proxyIndex.model() == this); 2173 2174 if (proxyIndex.internalPointer() == nullptr) { 2175 return d->mapTopLevelToSource(proxyIndex.row(), proxyIndex.column()); 2176 } 2177 2178 const QModelIndex proxyParent = d->parentForId(proxyIndex.internalPointer()); 2179 Q_ASSERT(proxyParent.isValid()); 2180 const QModelIndex sourceParent = d->mapParentToSource(proxyParent); 2181 Q_ASSERT(sourceParent.isValid()); 2182 return sourceModel()->index(proxyIndex.row(), proxyIndex.column(), sourceParent); 2183 } 2184 2185 QModelIndex KSelectionProxyModel::mapFromSource(const QModelIndex &sourceIndex) const 2186 { 2187 Q_D(const KSelectionProxyModel); 2188 2189 if (!sourceModel() || !sourceIndex.isValid() || d->m_rootIndexList.isEmpty()) { 2190 return QModelIndex(); 2191 } 2192 2193 Q_ASSERT(sourceIndex.model() == sourceModel()); 2194 2195 if (!sourceIndex.isValid()) { 2196 return QModelIndex(); 2197 } 2198 2199 if (!d->ensureMappable(sourceIndex)) { 2200 return QModelIndex(); 2201 } 2202 2203 return d->mapFromSource(sourceIndex); 2204 } 2205 2206 int KSelectionProxyModel::rowCount(const QModelIndex &index) const 2207 { 2208 Q_D(const KSelectionProxyModel); 2209 2210 if (!sourceModel() || index.column() > 0 || d->m_rootIndexList.isEmpty()) { 2211 return 0; 2212 } 2213 2214 Q_ASSERT(index.isValid() ? index.model() == this : true); 2215 if (!index.isValid()) { 2216 return d->topLevelRowCount(); 2217 } 2218 2219 // index is valid 2220 if (d->isFlat()) { 2221 return 0; 2222 } 2223 2224 QModelIndex sourceParent = d->mapParentToSource(index); 2225 2226 if (!sourceParent.isValid() && sourceModel()->hasChildren(sourceParent)) { 2227 sourceParent = mapToSource(index.parent()); 2228 d->createParentMappings(sourceParent, 0, sourceModel()->rowCount(sourceParent) - 1); 2229 sourceParent = d->mapParentToSource(index); 2230 } 2231 2232 if (!sourceParent.isValid()) { 2233 return 0; 2234 } 2235 2236 return sourceModel()->rowCount(sourceParent); 2237 } 2238 2239 QModelIndex KSelectionProxyModel::index(int row, int column, const QModelIndex &parent) const 2240 { 2241 Q_D(const KSelectionProxyModel); 2242 2243 if (!sourceModel() || d->m_rootIndexList.isEmpty() || !hasIndex(row, column, parent)) { 2244 return QModelIndex(); 2245 } 2246 2247 Q_ASSERT(parent.isValid() ? parent.model() == this : true); 2248 2249 if (!parent.isValid()) { 2250 return d->createTopLevelIndex(row, column); 2251 } 2252 2253 void *const parentId = d->parentId(parent); 2254 Q_ASSERT(parentId); 2255 return createIndex(row, column, parentId); 2256 } 2257 2258 QModelIndex KSelectionProxyModel::parent(const QModelIndex &index) const 2259 { 2260 Q_D(const KSelectionProxyModel); 2261 2262 if (!sourceModel() || !index.isValid() || d->m_rootIndexList.isEmpty()) { 2263 return QModelIndex(); 2264 } 2265 2266 Q_ASSERT(index.model() == this); 2267 2268 return d->parentForId(index.internalPointer()); 2269 } 2270 2271 Qt::ItemFlags KSelectionProxyModel::flags(const QModelIndex &index) const 2272 { 2273 if (!index.isValid() || !sourceModel()) { 2274 return QAbstractProxyModel::flags(index); 2275 } 2276 2277 Q_ASSERT(index.model() == this); 2278 2279 const QModelIndex srcIndex = mapToSource(index); 2280 Q_ASSERT(srcIndex.isValid()); 2281 return sourceModel()->flags(srcIndex); 2282 } 2283 2284 QVariant KSelectionProxyModel::data(const QModelIndex &index, int role) const 2285 { 2286 if (!sourceModel()) { 2287 return QVariant(); 2288 } 2289 2290 if (index.isValid()) { 2291 Q_ASSERT(index.model() == this); 2292 const QModelIndex idx = mapToSource(index); 2293 return idx.data(role); 2294 } 2295 return sourceModel()->data(index, role); 2296 } 2297 2298 QVariant KSelectionProxyModel::headerData(int section, Qt::Orientation orientation, int role) const 2299 { 2300 if (!sourceModel()) { 2301 return QVariant(); 2302 } 2303 return sourceModel()->headerData(section, orientation, role); 2304 } 2305 2306 QMimeData *KSelectionProxyModel::mimeData(const QModelIndexList &indexes) const 2307 { 2308 if (!sourceModel()) { 2309 return QAbstractProxyModel::mimeData(indexes); 2310 } 2311 QModelIndexList sourceIndexes; 2312 for (const QModelIndex &index : indexes) { 2313 sourceIndexes << mapToSource(index); 2314 } 2315 return sourceModel()->mimeData(sourceIndexes); 2316 } 2317 2318 QStringList KSelectionProxyModel::mimeTypes() const 2319 { 2320 if (!sourceModel()) { 2321 return QAbstractProxyModel::mimeTypes(); 2322 } 2323 return sourceModel()->mimeTypes(); 2324 } 2325 2326 Qt::DropActions KSelectionProxyModel::supportedDropActions() const 2327 { 2328 if (!sourceModel()) { 2329 return QAbstractProxyModel::supportedDropActions(); 2330 } 2331 return sourceModel()->supportedDropActions(); 2332 } 2333 2334 bool KSelectionProxyModel::hasChildren(const QModelIndex &parent) const 2335 { 2336 Q_D(const KSelectionProxyModel); 2337 2338 if (d->m_rootIndexList.isEmpty() || !sourceModel()) { 2339 return false; 2340 } 2341 2342 if (parent.isValid()) { 2343 Q_ASSERT(parent.model() == this); 2344 if (d->isFlat()) { 2345 return false; 2346 } 2347 return sourceModel()->hasChildren(mapToSource(parent)); 2348 } 2349 2350 if (!d->m_startWithChildTrees) { 2351 return true; 2352 } 2353 2354 return !d->m_mappedFirstChildren.isEmpty(); 2355 } 2356 2357 int KSelectionProxyModel::columnCount(const QModelIndex &index) const 2358 { 2359 if (!sourceModel() || index.column() > 0) { 2360 return 0; 2361 } 2362 2363 return sourceModel()->columnCount(mapToSource(index)); 2364 } 2365 2366 QItemSelectionModel *KSelectionProxyModel::selectionModel() const 2367 { 2368 Q_D(const KSelectionProxyModel); 2369 return d->m_selectionModel; 2370 } 2371 2372 void KSelectionProxyModel::setSelectionModel(QItemSelectionModel *itemSelectionModel) 2373 { 2374 Q_D(KSelectionProxyModel); 2375 if (d->m_selectionModel != itemSelectionModel) { 2376 if (d->m_selectionModel) { 2377 disconnect(d->m_selectionModel, 2378 SIGNAL(selectionChanged(QItemSelection, QItemSelection)), 2379 this, 2380 SLOT(selectionChanged(QItemSelection, QItemSelection))); 2381 } 2382 2383 d->m_selectionModel = itemSelectionModel; 2384 Q_EMIT selectionModelChanged(QPrivateSignal()); 2385 2386 if (d->m_selectionModel) { 2387 connect(d->m_selectionModel, SIGNAL(selectionChanged(QItemSelection, QItemSelection)), SLOT(selectionChanged(QItemSelection, QItemSelection))); 2388 2389 auto handleSelectionModelModel = [&, d] { 2390 beginResetModel(); 2391 if (d->selectionModelModelAboutToBeResetConnection) { 2392 disconnect(d->selectionModelModelAboutToBeResetConnection); 2393 } 2394 if (d->selectionModelModelResetConnection) { 2395 disconnect(d->selectionModelModelResetConnection); 2396 } 2397 if (d->m_selectionModel->model()) { 2398 d->selectionModelModelAboutToBeResetConnection = 2399 connect(d->m_selectionModel->model(), SIGNAL(modelAboutToBeReset()), this, SLOT(sourceModelAboutToBeReset())); 2400 d->selectionModelModelResetConnection = connect(d->m_selectionModel->model(), SIGNAL(modelReset()), this, SLOT(sourceModelReset())); 2401 d->m_rootIndexList.clear(); 2402 delete d->m_indexMapper; 2403 d->m_indexMapper = new KModelIndexProxyMapper(sourceModel(), d->m_selectionModel->model(), this); 2404 } 2405 endResetModel(); 2406 }; 2407 connect(d->m_selectionModel.data(), &QItemSelectionModel::modelChanged, this, handleSelectionModelModel); 2408 handleSelectionModelModel(); 2409 } 2410 2411 if (sourceModel()) { 2412 delete d->m_indexMapper; 2413 d->m_indexMapper = new KModelIndexProxyMapper(sourceModel(), d->m_selectionModel->model(), this); 2414 if (d->m_selectionModel->hasSelection()) { 2415 d->selectionChanged(d->m_selectionModel->selection(), QItemSelection()); 2416 } 2417 } 2418 } 2419 } 2420 2421 bool KSelectionProxyModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) 2422 { 2423 Q_D(const KSelectionProxyModel); 2424 if (!sourceModel() || d->m_rootIndexList.isEmpty()) { 2425 return false; 2426 } 2427 2428 if ((row == -1) && (column == -1)) { 2429 return sourceModel()->dropMimeData(data, action, -1, -1, mapToSource(parent)); 2430 } 2431 2432 int source_destination_row = -1; 2433 int source_destination_column = -1; 2434 QModelIndex source_parent; 2435 2436 if (row == rowCount(parent)) { 2437 source_parent = mapToSource(parent); 2438 source_destination_row = sourceModel()->rowCount(source_parent); 2439 } else { 2440 const QModelIndex proxy_index = index(row, column, parent); 2441 const QModelIndex source_index = mapToSource(proxy_index); 2442 source_destination_row = source_index.row(); 2443 source_destination_column = source_index.column(); 2444 source_parent = source_index.parent(); 2445 } 2446 return sourceModel()->dropMimeData(data, action, source_destination_row, source_destination_column, source_parent); 2447 } 2448 2449 QList<QPersistentModelIndex> KSelectionProxyModel::sourceRootIndexes() const 2450 { 2451 Q_D(const KSelectionProxyModel); 2452 return d->m_rootIndexList; 2453 } 2454 2455 QModelIndexList KSelectionProxyModel::match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const 2456 { 2457 if (role < Qt::UserRole) { 2458 return QAbstractProxyModel::match(start, role, value, hits, flags); 2459 } 2460 2461 QModelIndexList list; 2462 QModelIndex proxyIndex; 2463 const auto lst = sourceModel()->match(mapToSource(start), role, value, hits, flags); 2464 for (const QModelIndex &idx : lst) { 2465 proxyIndex = mapFromSource(idx); 2466 if (proxyIndex.isValid()) { 2467 list << proxyIndex; 2468 } 2469 } 2470 return list; 2471 } 2472 2473 QItemSelection KSelectionProxyModel::mapSelectionFromSource(const QItemSelection &selection) const 2474 { 2475 Q_D(const KSelectionProxyModel); 2476 if (!d->m_startWithChildTrees && d->m_includeAllSelected) { 2477 // QAbstractProxyModel::mapSelectionFromSource puts invalid ranges in the result 2478 // without checking. We can't have that. 2479 QItemSelection proxySelection; 2480 for (const QItemSelectionRange &range : selection) { 2481 QModelIndex proxyTopLeft = mapFromSource(range.topLeft()); 2482 if (!proxyTopLeft.isValid()) { 2483 continue; 2484 } 2485 QModelIndex proxyBottomRight = mapFromSource(range.bottomRight()); 2486 Q_ASSERT(proxyBottomRight.isValid()); 2487 proxySelection.append(QItemSelectionRange(proxyTopLeft, proxyBottomRight)); 2488 } 2489 return proxySelection; 2490 } 2491 2492 QItemSelection proxySelection; 2493 QItemSelection::const_iterator it = selection.constBegin(); 2494 const QItemSelection::const_iterator end = selection.constEnd(); 2495 for (; it != end; ++it) { 2496 const QModelIndex proxyTopLeft = mapFromSource(it->topLeft()); 2497 if (!proxyTopLeft.isValid()) { 2498 continue; 2499 } 2500 2501 if (it->height() == 1 && it->width() == 1) { 2502 proxySelection.append(QItemSelectionRange(proxyTopLeft, proxyTopLeft)); 2503 } else { 2504 proxySelection.append(QItemSelectionRange(proxyTopLeft, d->mapFromSource(it->bottomRight()))); 2505 } 2506 } 2507 return proxySelection; 2508 } 2509 2510 QItemSelection KSelectionProxyModel::mapSelectionToSource(const QItemSelection &selection) const 2511 { 2512 Q_D(const KSelectionProxyModel); 2513 2514 if (selection.isEmpty()) { 2515 return selection; 2516 } 2517 2518 if (!d->m_startWithChildTrees && d->m_includeAllSelected) { 2519 // QAbstractProxyModel::mapSelectionFromSource puts invalid ranges in the result 2520 // without checking. We can't have that. 2521 QItemSelection sourceSelection; 2522 for (const QItemSelectionRange &range : selection) { 2523 QModelIndex sourceTopLeft = mapToSource(range.topLeft()); 2524 Q_ASSERT(sourceTopLeft.isValid()); 2525 2526 QModelIndex sourceBottomRight = mapToSource(range.bottomRight()); 2527 Q_ASSERT(sourceBottomRight.isValid()); 2528 sourceSelection.append(QItemSelectionRange(sourceTopLeft, sourceBottomRight)); 2529 } 2530 return sourceSelection; 2531 } 2532 2533 QItemSelection sourceSelection; 2534 QItemSelection extraSelection; 2535 QItemSelection::const_iterator it = selection.constBegin(); 2536 const QItemSelection::const_iterator end = selection.constEnd(); 2537 for (; it != end; ++it) { 2538 const QModelIndex sourceTopLeft = mapToSource(it->topLeft()); 2539 if (it->height() == 1 && it->width() == 1) { 2540 sourceSelection.append(QItemSelectionRange(sourceTopLeft, sourceTopLeft)); 2541 } else if (it->parent().isValid()) { 2542 sourceSelection.append(QItemSelectionRange(sourceTopLeft, mapToSource(it->bottomRight()))); 2543 } else { 2544 // A contiguous selection in the proxy might not be contiguous in the source if it 2545 // is at the top level of the proxy. 2546 if (d->m_startWithChildTrees) { 2547 const QModelIndex sourceParent = mapFromSource(sourceTopLeft); 2548 Q_ASSERT(sourceParent.isValid()); 2549 const int rowCount = sourceModel()->rowCount(sourceParent); 2550 if (rowCount < it->bottom()) { 2551 Q_ASSERT(sourceTopLeft.isValid()); 2552 Q_ASSERT(it->bottomRight().isValid()); 2553 const QModelIndex sourceBottomRight = mapToSource(it->bottomRight()); 2554 Q_ASSERT(sourceBottomRight.isValid()); 2555 sourceSelection.append(QItemSelectionRange(sourceTopLeft, sourceBottomRight)); 2556 continue; 2557 } 2558 // Store the contiguous part... 2559 const QModelIndex sourceBottomRight = sourceModel()->index(rowCount - 1, it->right(), sourceParent); 2560 Q_ASSERT(sourceTopLeft.isValid()); 2561 Q_ASSERT(sourceBottomRight.isValid()); 2562 sourceSelection.append(QItemSelectionRange(sourceTopLeft, sourceBottomRight)); 2563 // ... and the rest will be processed later. 2564 extraSelection.append(QItemSelectionRange(createIndex(it->top() - rowCount, it->right()), it->bottomRight())); 2565 } else { 2566 QItemSelection topSelection; 2567 const QModelIndex idx = createIndex(it->top(), it->right()); 2568 const QModelIndex sourceIdx = mapToSource(idx); 2569 Q_ASSERT(sourceIdx.isValid()); 2570 topSelection.append(QItemSelectionRange(sourceTopLeft, sourceIdx)); 2571 for (int i = it->top() + 1; i <= it->bottom(); ++i) { 2572 const QModelIndex left = mapToSource(createIndex(i, 0)); 2573 const QModelIndex right = mapToSource(createIndex(i, it->right())); 2574 Q_ASSERT(left.isValid()); 2575 Q_ASSERT(right.isValid()); 2576 topSelection.append(QItemSelectionRange(left, right)); 2577 } 2578 sourceSelection += kNormalizeSelection(topSelection); 2579 } 2580 } 2581 } 2582 sourceSelection << mapSelectionToSource(extraSelection); 2583 return sourceSelection; 2584 } 2585 2586 #include "moc_kselectionproxymodel.cpp"