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