Warning, file /frameworks/kitemmodels/src/core/kdescendantsproxymodel.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-FileCopyrightText: 2009 Stephen Kelly <steveire@gmail.com> 0003 SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net> 0004 SPDX-FileContributor: Stephen Kelly <stephen@kdab.com> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include "kdescendantsproxymodel.h" 0010 0011 #include <QStringList> 0012 0013 #include "kbihash_p.h" 0014 0015 typedef KHash2Map<QPersistentModelIndex, int> Mapping; 0016 0017 class KDescendantsProxyModelPrivate 0018 { 0019 KDescendantsProxyModelPrivate(KDescendantsProxyModel *qq) 0020 : q_ptr(qq) 0021 , m_rowCount(0) 0022 , m_ignoreNextLayoutAboutToBeChanged(false) 0023 , m_ignoreNextLayoutChanged(false) 0024 , m_relayouting(false) 0025 , m_displayAncestorData(false) 0026 , m_ancestorSeparator(QStringLiteral(" / ")) 0027 { 0028 } 0029 0030 Q_DECLARE_PUBLIC(KDescendantsProxyModel) 0031 KDescendantsProxyModel *const q_ptr; 0032 0033 mutable QVector<QPersistentModelIndex> m_pendingParents; 0034 0035 void scheduleProcessPendingParents() const; 0036 void processPendingParents(); 0037 0038 void synchronousMappingRefresh(); 0039 0040 void updateInternalIndexes(int start, int offset); 0041 0042 void resetInternalData(); 0043 0044 void notifyhasSiblings(const QModelIndex &parent); 0045 void sourceRowsAboutToBeInserted(const QModelIndex &, int, int); 0046 void sourceRowsInserted(const QModelIndex &, int, int); 0047 void sourceRowsAboutToBeRemoved(const QModelIndex &, int, int); 0048 void sourceRowsRemoved(const QModelIndex &, int, int); 0049 void sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int); 0050 void sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int); 0051 void sourceModelAboutToBeReset(); 0052 void sourceModelReset(); 0053 void sourceLayoutAboutToBeChanged(); 0054 void sourceLayoutChanged(); 0055 void sourceDataChanged(const QModelIndex &, const QModelIndex &); 0056 void sourceModelDestroyed(); 0057 0058 Mapping m_mapping; 0059 int m_rowCount; 0060 QPair<int, int> m_removePair; 0061 QPair<int, int> m_insertPair; 0062 0063 bool m_expandsByDefault = true; 0064 bool m_ignoreNextLayoutAboutToBeChanged; 0065 bool m_ignoreNextLayoutChanged; 0066 bool m_relayouting; 0067 0068 bool m_displayAncestorData; 0069 QString m_ancestorSeparator; 0070 0071 QSet<QPersistentModelIndex> m_expandedSourceIndexes; 0072 QSet<QPersistentModelIndex> m_collapsedSourceIndexes; 0073 0074 QList<QPersistentModelIndex> m_layoutChangePersistentIndexes; 0075 QModelIndexList m_proxyIndexes; 0076 }; 0077 0078 void KDescendantsProxyModelPrivate::resetInternalData() 0079 { 0080 m_rowCount = 0; 0081 m_mapping.clear(); 0082 m_layoutChangePersistentIndexes.clear(); 0083 m_proxyIndexes.clear(); 0084 } 0085 0086 void KDescendantsProxyModelPrivate::synchronousMappingRefresh() 0087 { 0088 m_rowCount = 0; 0089 m_mapping.clear(); 0090 m_pendingParents.clear(); 0091 0092 m_pendingParents.append(QModelIndex()); 0093 0094 m_relayouting = true; 0095 while (!m_pendingParents.isEmpty()) { 0096 processPendingParents(); 0097 } 0098 m_relayouting = false; 0099 } 0100 0101 void KDescendantsProxyModelPrivate::scheduleProcessPendingParents() const 0102 { 0103 const_cast<KDescendantsProxyModelPrivate *>(this)->processPendingParents(); 0104 } 0105 0106 void KDescendantsProxyModelPrivate::processPendingParents() 0107 { 0108 Q_Q(KDescendantsProxyModel); 0109 const QVector<QPersistentModelIndex>::iterator begin = m_pendingParents.begin(); 0110 QVector<QPersistentModelIndex>::iterator it = begin; 0111 0112 const QVector<QPersistentModelIndex>::iterator end = m_pendingParents.end(); 0113 0114 QVector<QPersistentModelIndex> newPendingParents; 0115 0116 while (it != end && it != m_pendingParents.end()) { 0117 const QModelIndex sourceParent = *it; 0118 if (!sourceParent.isValid() && m_rowCount > 0) { 0119 // It was removed from the source model before it was inserted. 0120 it = m_pendingParents.erase(it); 0121 continue; 0122 } 0123 if (!q->isSourceIndexVisible(sourceParent)) { 0124 // It's a collapsed node, or its parents are collapsed, ignore. 0125 it = m_pendingParents.erase(it); 0126 continue; 0127 } 0128 0129 const int rowCount = q->sourceModel()->rowCount(sourceParent); 0130 0131 // A node can be marked as collapsed or expanded even if it doesn't have children 0132 if (rowCount == 0) { 0133 it = m_pendingParents.erase(it); 0134 continue; 0135 } 0136 const QPersistentModelIndex sourceIndex = q->sourceModel()->index(rowCount - 1, 0, sourceParent); 0137 0138 Q_ASSERT(sourceIndex.isValid()); 0139 0140 const QModelIndex proxyParent = q->mapFromSource(sourceParent); 0141 0142 Q_ASSERT(sourceParent.isValid() == proxyParent.isValid()); 0143 const int proxyEndRow = proxyParent.row() + rowCount; 0144 const int proxyStartRow = proxyEndRow - rowCount + 1; 0145 0146 if (!m_relayouting) { 0147 q->beginInsertRows(QModelIndex(), proxyStartRow, proxyEndRow); 0148 } 0149 0150 updateInternalIndexes(proxyStartRow, rowCount); 0151 m_mapping.insert(sourceIndex, proxyEndRow); 0152 it = m_pendingParents.erase(it); 0153 m_rowCount += rowCount; 0154 0155 if (!m_relayouting) { 0156 q->endInsertRows(); 0157 } 0158 0159 for (int sourceRow = 0; sourceRow < rowCount; ++sourceRow) { 0160 static const int column = 0; 0161 const QModelIndex child = q->sourceModel()->index(sourceRow, column, sourceParent); 0162 Q_ASSERT(child.isValid()); 0163 0164 if (q->sourceModel()->hasChildren(child) && q->isSourceIndexExpanded(child) && q->sourceModel()->rowCount(child) > 0) { 0165 newPendingParents.append(child); 0166 } 0167 } 0168 } 0169 m_pendingParents += newPendingParents; 0170 if (!m_pendingParents.isEmpty()) { 0171 processPendingParents(); 0172 } 0173 // scheduleProcessPendingParents(); 0174 } 0175 0176 void KDescendantsProxyModelPrivate::updateInternalIndexes(int start, int offset) 0177 { 0178 // TODO: Make KHash2Map support key updates and do this backwards. 0179 QHash<int, QPersistentModelIndex> updates; 0180 { 0181 Mapping::right_iterator it = m_mapping.rightLowerBound(start); 0182 const Mapping::right_iterator end = m_mapping.rightEnd(); 0183 0184 while (it != end) { 0185 updates.insert(it.key() + offset, *it); 0186 ++it; 0187 } 0188 } 0189 0190 { 0191 QHash<int, QPersistentModelIndex>::const_iterator it = updates.constBegin(); 0192 const QHash<int, QPersistentModelIndex>::const_iterator end = updates.constEnd(); 0193 0194 for (; it != end; ++it) { 0195 m_mapping.insert(it.value(), it.key()); 0196 } 0197 } 0198 } 0199 0200 KDescendantsProxyModel::KDescendantsProxyModel(QObject *parent) 0201 : QAbstractProxyModel(parent) 0202 , d_ptr(new KDescendantsProxyModelPrivate(this)) 0203 { 0204 } 0205 0206 KDescendantsProxyModel::~KDescendantsProxyModel() = default; 0207 0208 QHash<int, QByteArray> KDescendantsProxyModel::roleNames() const 0209 { 0210 QHash<int, QByteArray> roleNames = QAbstractProxyModel::roleNames(); 0211 0212 roleNames[LevelRole] = "kDescendantLevel"; 0213 roleNames[ExpandableRole] = "kDescendantExpandable"; 0214 roleNames[ExpandedRole] = "kDescendantExpanded"; 0215 roleNames[HasSiblingsRole] = "kDescendantHasSiblings"; 0216 return roleNames; 0217 } 0218 0219 void KDescendantsProxyModel::setExpandsByDefault(bool expand) 0220 { 0221 if (d_ptr->m_expandsByDefault == expand) { 0222 return; 0223 } 0224 0225 beginResetModel(); 0226 d_ptr->m_expandsByDefault = expand; 0227 d_ptr->m_expandedSourceIndexes.clear(); 0228 d_ptr->m_collapsedSourceIndexes.clear(); 0229 endResetModel(); 0230 } 0231 0232 bool KDescendantsProxyModel::expandsByDefault() const 0233 { 0234 return d_ptr->m_expandsByDefault; 0235 } 0236 0237 bool KDescendantsProxyModel::isSourceIndexExpanded(const QModelIndex &sourceIndex) const 0238 { 0239 // Root is always expanded 0240 if (!sourceIndex.isValid()) { 0241 return true; 0242 } else if (d_ptr->m_expandsByDefault) { 0243 return !d_ptr->m_collapsedSourceIndexes.contains(QPersistentModelIndex(sourceIndex)); 0244 } else { 0245 return d_ptr->m_expandedSourceIndexes.contains(QPersistentModelIndex(sourceIndex)); 0246 } 0247 } 0248 0249 bool KDescendantsProxyModel::isSourceIndexVisible(const QModelIndex &sourceIndex) const 0250 { 0251 // Root is always visible 0252 if (!sourceIndex.isValid()) { 0253 return true; 0254 } 0255 0256 QModelIndex index(sourceIndex); 0257 do { 0258 index = index.parent(); 0259 if (!index.isValid()) { 0260 return true; 0261 } 0262 } while (isSourceIndexExpanded(index)); 0263 0264 return false; 0265 } 0266 0267 void KDescendantsProxyModel::expandSourceIndex(const QModelIndex &sourceIndex) 0268 { 0269 if (!sourceIndex.isValid() || isSourceIndexExpanded(sourceIndex)) { 0270 return; 0271 } 0272 0273 if (d_ptr->m_expandsByDefault) { 0274 d_ptr->m_collapsedSourceIndexes.remove(QPersistentModelIndex(sourceIndex)); 0275 } else { 0276 d_ptr->m_expandedSourceIndexes << QPersistentModelIndex(sourceIndex); 0277 } 0278 0279 d_ptr->m_pendingParents << sourceIndex; 0280 d_ptr->scheduleProcessPendingParents(); 0281 Q_EMIT sourceIndexExpanded(sourceIndex); 0282 0283 const QModelIndex index = mapFromSource(sourceIndex); 0284 Q_EMIT dataChanged(index, index, {ExpandedRole}); 0285 } 0286 0287 void KDescendantsProxyModel::collapseSourceIndex(const QModelIndex &sourceIndex) 0288 { 0289 if (!sourceIndex.isValid() || !isSourceIndexExpanded(sourceIndex)) { 0290 return; 0291 } 0292 0293 const int row = mapFromSource(sourceIndex).row(); 0294 const int rowStart = row + 1; 0295 int rowEnd = row; 0296 0297 QList<QModelIndex> toVisit = {sourceIndex}; 0298 QSet<QModelIndex> visited; 0299 while (!toVisit.isEmpty()) { 0300 QModelIndex index = toVisit.takeLast(); 0301 if (!visited.contains(index)) { 0302 visited << index; 0303 const int nRows = sourceModel()->rowCount(index); 0304 rowEnd += nRows; 0305 for (int i = 0; i < nRows; ++i) { 0306 QModelIndex child = sourceModel()->index(i, 0, index); 0307 if (isSourceIndexExpanded(child)) { 0308 toVisit << child; 0309 } 0310 } 0311 } 0312 } 0313 0314 beginRemoveRows(QModelIndex(), rowStart, rowEnd); 0315 0316 if (d_ptr->m_expandsByDefault) { 0317 d_ptr->m_collapsedSourceIndexes << QPersistentModelIndex(sourceIndex); 0318 } else { 0319 d_ptr->m_expandedSourceIndexes.remove(QPersistentModelIndex(sourceIndex)); 0320 } 0321 0322 { 0323 Mapping::right_iterator it = d_ptr->m_mapping.rightLowerBound(rowStart); 0324 const Mapping::right_iterator endIt = d_ptr->m_mapping.rightUpperBound(rowEnd); 0325 0326 if (endIt != d_ptr->m_mapping.rightEnd()) { 0327 while (it != endIt) { 0328 it = d_ptr->m_mapping.eraseRight(it); 0329 } 0330 } else { 0331 while (it != d_ptr->m_mapping.rightUpperBound(rowEnd)) { 0332 it = d_ptr->m_mapping.eraseRight(it); 0333 } 0334 } 0335 } 0336 0337 d_ptr->m_removePair = qMakePair(rowStart, rowEnd); 0338 0339 d_ptr->synchronousMappingRefresh(); 0340 endRemoveRows(); 0341 Q_EMIT sourceIndexCollapsed(sourceIndex); 0342 0343 const QModelIndex ownIndex = mapFromSource(sourceIndex); 0344 Q_EMIT dataChanged(ownIndex, ownIndex, {ExpandedRole}); 0345 } 0346 0347 #if KITEMMODELS_BUILD_DEPRECATED_SINCE(4, 8) 0348 void KDescendantsProxyModel::setRootIndex(const QModelIndex &index) 0349 { 0350 Q_UNUSED(index) 0351 } 0352 #endif 0353 0354 QModelIndexList KDescendantsProxyModel::match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const 0355 { 0356 return QAbstractProxyModel::match(start, role, value, hits, flags); 0357 } 0358 0359 namespace 0360 { 0361 // we only work on DisplayRole for now 0362 static const QVector<int> changedRoles = {Qt::DisplayRole}; 0363 } 0364 0365 void KDescendantsProxyModel::setDisplayAncestorData(bool display) 0366 { 0367 Q_D(KDescendantsProxyModel); 0368 bool displayChanged = (display != d->m_displayAncestorData); 0369 d->m_displayAncestorData = display; 0370 if (displayChanged) { 0371 Q_EMIT displayAncestorDataChanged(); 0372 // send out big hammer. Everything needs to be updated. 0373 Q_EMIT dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1), changedRoles); 0374 } 0375 } 0376 0377 bool KDescendantsProxyModel::displayAncestorData() const 0378 { 0379 Q_D(const KDescendantsProxyModel); 0380 return d->m_displayAncestorData; 0381 } 0382 0383 void KDescendantsProxyModel::setAncestorSeparator(const QString &separator) 0384 { 0385 Q_D(KDescendantsProxyModel); 0386 bool separatorChanged = (separator != d->m_ancestorSeparator); 0387 d->m_ancestorSeparator = separator; 0388 if (separatorChanged) { 0389 Q_EMIT ancestorSeparatorChanged(); 0390 if (d->m_displayAncestorData) { 0391 // send out big hammer. Everything needs to be updated. 0392 Q_EMIT dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1), changedRoles); 0393 } 0394 } 0395 } 0396 0397 QString KDescendantsProxyModel::ancestorSeparator() const 0398 { 0399 Q_D(const KDescendantsProxyModel); 0400 return d->m_ancestorSeparator; 0401 } 0402 0403 void KDescendantsProxyModel::setSourceModel(QAbstractItemModel *_sourceModel) 0404 { 0405 Q_D(KDescendantsProxyModel); 0406 0407 beginResetModel(); 0408 0409 if (sourceModel()) { 0410 disconnect(sourceModel(), nullptr, this, nullptr); 0411 } 0412 0413 QAbstractProxyModel::setSourceModel(_sourceModel); 0414 d_ptr->m_expandedSourceIndexes.clear(); 0415 0416 if (_sourceModel) { 0417 connect(_sourceModel, &QAbstractItemModel::rowsAboutToBeInserted, this, [d](const QModelIndex &parent, int start, int end) { 0418 d->sourceRowsAboutToBeInserted(parent, start, end); 0419 }); 0420 0421 connect(_sourceModel, &QAbstractItemModel::rowsInserted, this, [d](const QModelIndex &parent, int start, int end) { 0422 d->sourceRowsInserted(parent, start, end); 0423 }); 0424 0425 connect(_sourceModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, [d](const QModelIndex &parent, int start, int end) { 0426 d->sourceRowsAboutToBeRemoved(parent, start, end); 0427 }); 0428 0429 connect(_sourceModel, &QAbstractItemModel::rowsRemoved, this, [d](const QModelIndex &parent, int start, int end) { 0430 d->sourceRowsRemoved(parent, start, end); 0431 }); 0432 0433 connect(_sourceModel, 0434 &QAbstractItemModel::rowsAboutToBeMoved, 0435 this, 0436 [d](const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destStart) { 0437 d->sourceRowsAboutToBeMoved(srcParent, srcStart, srcEnd, destParent, destStart); 0438 }); 0439 0440 connect(_sourceModel, 0441 &QAbstractItemModel::rowsMoved, 0442 this, 0443 [d](const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destStart) { 0444 d->sourceRowsMoved(srcParent, srcStart, srcEnd, destParent, destStart); 0445 }); 0446 0447 connect(_sourceModel, &QAbstractItemModel::modelAboutToBeReset, this, [d]() { 0448 d->sourceModelAboutToBeReset(); 0449 }); 0450 0451 connect(_sourceModel, &QAbstractItemModel::modelReset, this, [d]() { 0452 d->sourceModelReset(); 0453 }); 0454 0455 connect(_sourceModel, &QAbstractItemModel::dataChanged, this, [d](const QModelIndex &topLeft, const QModelIndex &bottomRight) { 0456 d->sourceDataChanged(topLeft, bottomRight); 0457 }); 0458 0459 connect(_sourceModel, &QAbstractItemModel::layoutAboutToBeChanged, this, [d]() { 0460 d->sourceLayoutAboutToBeChanged(); 0461 }); 0462 0463 connect(_sourceModel, &QAbstractItemModel::layoutChanged, this, [d]() { 0464 d->sourceLayoutChanged(); 0465 }); 0466 0467 connect(_sourceModel, &QObject::destroyed, this, [d]() { 0468 d->sourceModelDestroyed(); 0469 }); 0470 } 0471 0472 resetInternalData(); 0473 if (_sourceModel && _sourceModel->hasChildren()) { 0474 d->synchronousMappingRefresh(); 0475 } 0476 0477 endResetModel(); 0478 Q_EMIT sourceModelChanged(); 0479 } 0480 0481 QModelIndex KDescendantsProxyModel::parent(const QModelIndex &index) const 0482 { 0483 Q_UNUSED(index) 0484 return QModelIndex(); 0485 } 0486 0487 bool KDescendantsProxyModel::hasChildren(const QModelIndex &parent) const 0488 { 0489 Q_D(const KDescendantsProxyModel); 0490 return !(d->m_mapping.isEmpty() || parent.isValid()); 0491 } 0492 0493 int KDescendantsProxyModel::rowCount(const QModelIndex &parent) const 0494 { 0495 Q_D(const KDescendantsProxyModel); 0496 if (d->m_pendingParents.contains(parent) || parent.isValid() || !sourceModel()) { 0497 return 0; 0498 } 0499 0500 if (d->m_mapping.isEmpty() && sourceModel()->hasChildren()) { 0501 const_cast<KDescendantsProxyModelPrivate *>(d)->synchronousMappingRefresh(); 0502 } 0503 return d->m_rowCount; 0504 } 0505 0506 QModelIndex KDescendantsProxyModel::index(int row, int column, const QModelIndex &parent) const 0507 { 0508 if (parent.isValid()) { 0509 return QModelIndex(); 0510 } 0511 0512 if (!hasIndex(row, column, parent)) { 0513 return QModelIndex(); 0514 } 0515 0516 return createIndex(row, column); 0517 } 0518 0519 QModelIndex KDescendantsProxyModel::mapToSource(const QModelIndex &proxyIndex) const 0520 { 0521 Q_D(const KDescendantsProxyModel); 0522 if (d->m_mapping.isEmpty() || !proxyIndex.isValid() || !sourceModel()) { 0523 return QModelIndex(); 0524 } 0525 0526 const Mapping::right_const_iterator result = d->m_mapping.rightLowerBound(proxyIndex.row()); 0527 Q_ASSERT(result != d->m_mapping.rightEnd()); 0528 0529 const int proxyLastRow = result.key(); 0530 const QModelIndex sourceLastChild = result.value(); 0531 Q_ASSERT(sourceLastChild.isValid()); 0532 0533 // proxyLastRow is greater than proxyIndex.row(). 0534 // sourceLastChild is vertically below the result we're looking for 0535 // and not necessarily in the correct parent. 0536 // We travel up through its parent hierarchy until we are in the 0537 // right parent, then return the correct sibling. 0538 0539 // Source: Proxy: Row 0540 // - A - A - 0 0541 // - B - B - 1 0542 // - C - C - 2 0543 // - D - D - 3 0544 // - - E - E - 4 0545 // - - F - F - 5 0546 // - - G - G - 6 0547 // - - H - H - 7 0548 // - - I - I - 8 0549 // - - - J - J - 9 0550 // - - - K - K - 10 0551 // - - - L - L - 11 0552 // - - M - M - 12 0553 // - - N - N - 13 0554 // - O - O - 14 0555 0556 // Note that L, N and O are lastChildIndexes, and therefore have a mapping. If we 0557 // are trying to map G from the proxy to the source, We at this point have an iterator 0558 // pointing to (L -> 11). The proxy row of G is 6. (proxyIndex.row() == 6). We seek the 0559 // sourceIndex which is vertically above L by the distance proxyLastRow - proxyIndex.row(). 0560 // In this case the verticalDistance is 5. 0561 0562 int verticalDistance = proxyLastRow - proxyIndex.row(); 0563 0564 // We traverse the ancestors of L, until we can index the desired row in the source. 0565 0566 QModelIndex ancestor = sourceLastChild; 0567 while (ancestor.isValid()) { 0568 const int ancestorRow = ancestor.row(); 0569 if (verticalDistance <= ancestorRow) { 0570 return ancestor.sibling(ancestorRow - verticalDistance, proxyIndex.column()); 0571 } 0572 verticalDistance -= (ancestorRow + 1); 0573 ancestor = ancestor.parent(); 0574 } 0575 Q_ASSERT(!"Didn't find target row."); 0576 return QModelIndex(); 0577 } 0578 0579 QModelIndex KDescendantsProxyModel::mapFromSource(const QModelIndex &sourceIndex) const 0580 { 0581 Q_D(const KDescendantsProxyModel); 0582 0583 if (!sourceModel()) { 0584 return QModelIndex(); 0585 } 0586 0587 if (d->m_mapping.isEmpty()) { 0588 return QModelIndex(); 0589 } 0590 0591 { 0592 // TODO: Consider a parent Mapping to speed this up. 0593 0594 Mapping::right_const_iterator it = d->m_mapping.rightConstBegin(); 0595 const Mapping::right_const_iterator end = d->m_mapping.rightConstEnd(); 0596 const QModelIndex sourceParent = sourceIndex.parent(); 0597 Mapping::right_const_iterator result = end; 0598 0599 if (!isSourceIndexVisible(sourceIndex)) { 0600 return QModelIndex(); 0601 } 0602 0603 for (; it != end; ++it) { 0604 QModelIndex index = it.value(); 0605 bool found_block = false; 0606 while (index.isValid()) { 0607 const QModelIndex ancestor = index.parent(); 0608 if (ancestor == sourceParent && index.row() >= sourceIndex.row()) { 0609 found_block = true; 0610 if (result == end || it.key() < result.key()) { 0611 result = it; 0612 break; // Leave the while loop. index is still valid. 0613 } 0614 } 0615 index = ancestor; 0616 } 0617 if (found_block && !index.isValid()) 0618 // Looked through the ascendants of it.key() without finding sourceParent. 0619 // That means we've already got the result we need. 0620 { 0621 break; 0622 } 0623 } 0624 Q_ASSERT(result != end); 0625 const QModelIndex sourceLastChild = result.value(); 0626 int proxyRow = result.key(); 0627 QModelIndex index = sourceLastChild; 0628 while (index.isValid()) { 0629 const QModelIndex ancestor = index.parent(); 0630 if (ancestor == sourceParent) { 0631 return createIndex(proxyRow - (index.row() - sourceIndex.row()), sourceIndex.column()); 0632 } 0633 proxyRow -= (index.row() + 1); 0634 index = ancestor; 0635 } 0636 Q_ASSERT(!"Didn't find valid proxy mapping."); 0637 return QModelIndex(); 0638 } 0639 } 0640 0641 int KDescendantsProxyModel::columnCount(const QModelIndex &parent) const 0642 { 0643 if (parent.isValid() /* || rowCount(parent) == 0 */ || !sourceModel()) { 0644 return 0; 0645 } 0646 0647 return sourceModel()->columnCount(); 0648 } 0649 0650 QVariant KDescendantsProxyModel::data(const QModelIndex &index, int role) const 0651 { 0652 Q_D(const KDescendantsProxyModel); 0653 0654 if (!sourceModel()) { 0655 return QVariant(); 0656 } 0657 0658 if (!index.isValid()) { 0659 return sourceModel()->data(index, role); 0660 } 0661 0662 QModelIndex sourceIndex = mapToSource(index); 0663 0664 if ((d->m_displayAncestorData) && (role == Qt::DisplayRole)) { 0665 if (!sourceIndex.isValid()) { 0666 return QVariant(); 0667 } 0668 QString displayData = sourceIndex.data().toString(); 0669 sourceIndex = sourceIndex.parent(); 0670 while (sourceIndex.isValid()) { 0671 displayData.prepend(d->m_ancestorSeparator); 0672 displayData.prepend(sourceIndex.data().toString()); 0673 sourceIndex = sourceIndex.parent(); 0674 } 0675 return displayData; 0676 } else if (role == LevelRole) { 0677 QModelIndex sourceIndex = mapToSource(index); 0678 int level = 0; 0679 while (sourceIndex.isValid()) { 0680 sourceIndex = sourceIndex.parent(); 0681 ++level; 0682 } 0683 return level; 0684 } else if (role == ExpandableRole) { 0685 QModelIndex sourceIndex = mapToSource(index); 0686 return sourceModel()->hasChildren(sourceIndex); 0687 } else if (role == ExpandedRole) { 0688 return isSourceIndexExpanded(mapToSource(index)); 0689 } else if (role == HasSiblingsRole) { 0690 QModelIndex sourceIndex = mapToSource(index); 0691 QList<bool> hasSibling; 0692 while (sourceIndex.isValid()) { 0693 hasSibling.prepend(sourceModel()->rowCount(sourceIndex.parent()) > sourceIndex.row() + 1); 0694 sourceIndex = sourceIndex.parent(); 0695 } 0696 return QVariant::fromValue(hasSibling); 0697 } else { 0698 return sourceIndex.data(role); 0699 } 0700 } 0701 0702 QVariant KDescendantsProxyModel::headerData(int section, Qt::Orientation orientation, int role) const 0703 { 0704 if (!sourceModel() || columnCount() <= section) { 0705 return QVariant(); 0706 } 0707 0708 // Here is safe to do sourceModel()->headerData, as in this proxy we neither filter out nor reorder columns 0709 return sourceModel()->headerData(section, orientation, role); 0710 } 0711 0712 Qt::ItemFlags KDescendantsProxyModel::flags(const QModelIndex &index) const 0713 { 0714 if (!index.isValid() || !sourceModel()) { 0715 return QAbstractProxyModel::flags(index); 0716 } 0717 0718 const QModelIndex srcIndex = mapToSource(index); 0719 Q_ASSERT(srcIndex.isValid()); 0720 return sourceModel()->flags(srcIndex); 0721 } 0722 0723 void KDescendantsProxyModelPrivate::notifyhasSiblings(const QModelIndex &parent) 0724 { 0725 Q_Q(KDescendantsProxyModel); 0726 0727 if (!parent.isValid()) { 0728 return; 0729 } 0730 0731 QModelIndex localParent = q->mapFromSource(parent); 0732 Q_EMIT q->dataChanged(localParent, localParent, {KDescendantsProxyModel::HasSiblingsRole}); 0733 for (int i = 0; i < q->sourceModel()->rowCount(parent); ++i) { 0734 notifyhasSiblings(q->sourceModel()->index(i, 0, parent)); 0735 } 0736 } 0737 0738 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end) 0739 { 0740 Q_Q(KDescendantsProxyModel); 0741 0742 if (parent.isValid() && (!q->isSourceIndexExpanded(parent) || !q->isSourceIndexVisible(parent))) { 0743 return; 0744 } 0745 0746 if (!q->sourceModel()->hasChildren(parent)) { 0747 Q_ASSERT(q->sourceModel()->rowCount(parent) == 0); 0748 // parent was not a parent before. 0749 return; 0750 } 0751 0752 int proxyStart = -1; 0753 0754 const int rowCount = q->sourceModel()->rowCount(parent); 0755 0756 if (rowCount > start) { 0757 const QModelIndex belowStart = q->sourceModel()->index(start, 0, parent); 0758 proxyStart = q->mapFromSource(belowStart).row(); 0759 } else if (rowCount == 0) { 0760 proxyStart = q->mapFromSource(parent).row() + 1; 0761 } else { 0762 Q_ASSERT(rowCount == start); 0763 static const int column = 0; 0764 QModelIndex idx = q->sourceModel()->index(rowCount - 1, column, parent); 0765 while (q->isSourceIndexExpanded(idx) && q->sourceModel()->hasChildren(idx) && q->sourceModel()->rowCount(idx) > 0) { 0766 idx = q->sourceModel()->index(q->sourceModel()->rowCount(idx) - 1, column, idx); 0767 } 0768 // The last item in the list is getting a sibling below it. 0769 proxyStart = q->mapFromSource(idx).row() + 1; 0770 } 0771 const int proxyEnd = proxyStart + (end - start); 0772 0773 m_insertPair = qMakePair(proxyStart, proxyEnd); 0774 q->beginInsertRows(QModelIndex(), proxyStart, proxyEnd); 0775 } 0776 0777 void KDescendantsProxyModelPrivate::sourceRowsInserted(const QModelIndex &parent, int start, int end) 0778 { 0779 Q_Q(KDescendantsProxyModel); 0780 if (parent.isValid() && (!q->isSourceIndexExpanded(parent) || !q->isSourceIndexVisible(parent))) { 0781 const QModelIndex index = q->mapFromSource(parent); 0782 Q_EMIT q->dataChanged(index, 0783 index, 0784 {KDescendantsProxyModel::ExpandableRole, KDescendantsProxyModel::ExpandedRole, KDescendantsProxyModel::HasSiblingsRole}); 0785 if (start > 0) { 0786 notifyhasSiblings(q->sourceModel()->index(start - 1, 0, parent)); 0787 } 0788 return; 0789 } 0790 Q_ASSERT(q->sourceModel()->index(start, 0, parent).isValid()); 0791 0792 const int rowCount = q->sourceModel()->rowCount(parent); 0793 Q_ASSERT(rowCount > 0); 0794 0795 const int difference = end - start + 1; 0796 0797 if (rowCount == difference) { 0798 const QModelIndex index = q->mapFromSource(parent); 0799 if (parent.isValid()) { 0800 Q_EMIT q->dataChanged(index, 0801 index, 0802 {KDescendantsProxyModel::ExpandableRole, KDescendantsProxyModel::ExpandedRole, KDescendantsProxyModel::HasSiblingsRole}); 0803 } 0804 // @p parent was not a parent before. 0805 m_pendingParents.append(parent); 0806 scheduleProcessPendingParents(); 0807 if (start > 0) { 0808 notifyhasSiblings(q->sourceModel()->index(start - 1, 0, parent)); 0809 } 0810 return; 0811 } 0812 0813 const int proxyStart = m_insertPair.first; 0814 0815 Q_ASSERT(proxyStart >= 0); 0816 0817 updateInternalIndexes(proxyStart, difference); 0818 0819 if (rowCount - 1 == end) { 0820 // The previously last row (the mapped one) is no longer the last. 0821 // For example, 0822 0823 // - A - A 0 0824 // - - B - B 1 0825 // - - C - C 2 0826 // - - - D - D 3 0827 // - - - E -> - E 4 0828 // - - F - F 5 0829 // - - G -> - G 6 0830 // - H - H 7 0831 // - I -> - I 8 0832 0833 // As last children, E, F and G have mappings. 0834 // Consider that 'J' is appended to the children of 'C', below 'E'. 0835 0836 // - A - A 0 0837 // - - B - B 1 0838 // - - C - C 2 0839 // - - - D - D 3 0840 // - - - E -> - E 4 0841 // - - - J - ??? 5 0842 // - - F - F 6 0843 // - - G -> - G 7 0844 // - H - H 8 0845 // - I -> - I 9 0846 0847 // The updateInternalIndexes call above will have updated the F and G mappings correctly because proxyStart is 5. 0848 // That means that E -> 4 was not affected by the updateInternalIndexes call. 0849 // Now the mapping for E -> 4 needs to be updated so that it's a mapping for J -> 5. 0850 0851 Q_ASSERT(!m_mapping.isEmpty()); 0852 static const int column = 0; 0853 const QModelIndex oldIndex = q->sourceModel()->index(rowCount - 1 - difference, column, parent); 0854 Q_ASSERT(m_mapping.leftContains(oldIndex)); 0855 0856 const QModelIndex newIndex = q->sourceModel()->index(rowCount - 1, column, parent); 0857 0858 QModelIndex indexAbove = oldIndex; 0859 0860 if (start > 0) { 0861 // If we have something like this: 0862 // 0863 // - A 0864 // - - B 0865 // - - C 0866 // 0867 // and we then insert D as a sibling of A below it, we need to remove the mapping for A, 0868 // and the row number used for D must take into account the descendants of A. 0869 0870 while (q->isSourceIndexExpanded(indexAbove) && q->sourceModel()->hasChildren(indexAbove)) { 0871 Q_ASSERT(q->sourceModel()->rowCount(indexAbove) > 0); 0872 indexAbove = q->sourceModel()->index(q->sourceModel()->rowCount(indexAbove) - 1, column, indexAbove); 0873 } 0874 Q_ASSERT(!q->isSourceIndexExpanded(indexAbove) || q->sourceModel()->rowCount(indexAbove) == 0); 0875 } 0876 0877 Q_ASSERT(m_mapping.leftContains(indexAbove)); 0878 0879 const int newProxyRow = m_mapping.leftToRight(indexAbove) + difference; 0880 0881 // oldIndex is E in the source. proxyRow is 4. 0882 m_mapping.removeLeft(oldIndex); 0883 0884 // newIndex is J. (proxyRow + difference) is 5. 0885 m_mapping.insert(newIndex, newProxyRow); 0886 } 0887 0888 for (int row = start; row <= end; ++row) { 0889 static const int column = 0; 0890 const QModelIndex idx = q->sourceModel()->index(row, column, parent); 0891 Q_ASSERT(idx.isValid()); 0892 0893 if (q->isSourceIndexExpanded(idx) && q->sourceModel()->hasChildren(idx) && q->sourceModel()->rowCount(idx) > 0) { 0894 m_pendingParents.append(idx); 0895 } 0896 } 0897 0898 m_rowCount += difference; 0899 0900 q->endInsertRows(); 0901 scheduleProcessPendingParents(); 0902 if (parent.isValid()) { 0903 const QModelIndex index = q->mapFromSource(parent); 0904 Q_EMIT q->dataChanged(index, 0905 index, 0906 {KDescendantsProxyModel::ExpandableRole, KDescendantsProxyModel::ExpandedRole, KDescendantsProxyModel::HasSiblingsRole}); 0907 } 0908 0909 if (start > 0) { 0910 notifyhasSiblings(q->sourceModel()->index(start - 1, 0, parent)); 0911 } 0912 } 0913 0914 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) 0915 { 0916 Q_Q(KDescendantsProxyModel); 0917 0918 if (!q->isSourceIndexExpanded(parent) || !q->isSourceIndexVisible(parent)) { 0919 return; 0920 } 0921 0922 const int proxyStart = q->mapFromSource(q->sourceModel()->index(start, 0, parent)).row(); 0923 0924 static const int column = 0; 0925 QModelIndex idx = q->sourceModel()->index(end, column, parent); 0926 while (q->sourceModel()->hasChildren(idx) && q->sourceModel()->rowCount(idx) > 0) { 0927 idx = q->sourceModel()->index(q->sourceModel()->rowCount(idx) - 1, column, idx); 0928 } 0929 const int proxyEnd = q->mapFromSource(idx).row(); 0930 0931 for (int i = start; i <= end; ++i) { 0932 QModelIndex idx = q->sourceModel()->index(i, column, parent); 0933 m_expandedSourceIndexes.remove(QPersistentModelIndex(idx)); 0934 } 0935 0936 m_removePair = qMakePair(proxyStart, proxyEnd); 0937 0938 q->beginRemoveRows(QModelIndex(), proxyStart, proxyEnd); 0939 } 0940 0941 static QModelIndex getFirstDeepest(QAbstractItemModel *model, const QModelIndex &parent, int *count) 0942 { 0943 static const int column = 0; 0944 Q_ASSERT(model->hasChildren(parent)); 0945 Q_ASSERT(model->rowCount(parent) > 0); 0946 for (int row = 0; row < model->rowCount(parent); ++row) { 0947 (*count)++; 0948 const QModelIndex child = model->index(row, column, parent); 0949 Q_ASSERT(child.isValid()); 0950 if (model->hasChildren(child)) { 0951 return getFirstDeepest(model, child, count); 0952 } 0953 } 0954 return model->index(model->rowCount(parent) - 1, column, parent); 0955 } 0956 0957 void KDescendantsProxyModelPrivate::sourceRowsRemoved(const QModelIndex &parent, int start, int end) 0958 { 0959 Q_Q(KDescendantsProxyModel); 0960 Q_UNUSED(end) 0961 0962 if (!q->isSourceIndexExpanded(parent) || !q->isSourceIndexVisible(parent)) { 0963 if (parent.isValid()) { 0964 const QModelIndex index = q->mapFromSource(parent); 0965 Q_EMIT q->dataChanged(index, index, {KDescendantsProxyModel::ExpandableRole, KDescendantsProxyModel::ExpandedRole}); 0966 } 0967 return; 0968 } 0969 0970 const int rowCount = q->sourceModel()->rowCount(parent); 0971 0972 const int proxyStart = m_removePair.first; 0973 const int proxyEnd = m_removePair.second; 0974 0975 const int difference = proxyEnd - proxyStart + 1; 0976 { 0977 Mapping::right_iterator it = m_mapping.rightLowerBound(proxyStart); 0978 const Mapping::right_iterator endIt = m_mapping.rightUpperBound(proxyEnd); 0979 0980 if (endIt != m_mapping.rightEnd()) { 0981 while (it != endIt) { 0982 it = m_mapping.eraseRight(it); 0983 } 0984 } else { 0985 while (it != m_mapping.rightUpperBound(proxyEnd)) { 0986 it = m_mapping.eraseRight(it); 0987 } 0988 } 0989 } 0990 0991 m_removePair = qMakePair(-1, -1); 0992 m_rowCount -= difference; 0993 Q_ASSERT(m_rowCount >= 0); 0994 0995 updateInternalIndexes(proxyStart, -1 * difference); 0996 0997 if (rowCount != start || rowCount == 0) { 0998 q->endRemoveRows(); 0999 if (parent.isValid()) { 1000 const QModelIndex index = q->mapFromSource(parent); 1001 Q_EMIT q->dataChanged(index, index, {KDescendantsProxyModel::ExpandableRole, KDescendantsProxyModel::ExpandedRole}); 1002 } 1003 if (start > 0) { 1004 notifyhasSiblings(q->sourceModel()->index(start - 1, 0, parent)); 1005 } 1006 return; 1007 } 1008 1009 static const int column = 0; 1010 const QModelIndex newEnd = q->sourceModel()->index(rowCount - 1, column, parent); 1011 Q_ASSERT(newEnd.isValid()); 1012 1013 if (m_mapping.isEmpty()) { 1014 m_mapping.insert(newEnd, newEnd.row()); 1015 q->endRemoveRows(); 1016 if (start > 0) { 1017 notifyhasSiblings(q->sourceModel()->index(start - 1, 0, parent)); 1018 } 1019 return; 1020 } 1021 if (q->sourceModel()->hasChildren(newEnd)) { 1022 int count = 0; 1023 const QModelIndex firstDeepest = getFirstDeepest(q->sourceModel(), newEnd, &count); 1024 Q_ASSERT(firstDeepest.isValid()); 1025 const int firstDeepestProxy = m_mapping.leftToRight(firstDeepest); 1026 1027 m_mapping.insert(newEnd, firstDeepestProxy - count); 1028 q->endRemoveRows(); 1029 if (start > 0) { 1030 notifyhasSiblings(q->sourceModel()->index(start - 1, 0, parent)); 1031 } 1032 return; 1033 } 1034 Mapping::right_iterator lowerBound = m_mapping.rightLowerBound(proxyStart); 1035 if (lowerBound == m_mapping.rightEnd()) { 1036 int proxyRow = (lowerBound - 1).key(); 1037 1038 for (int row = newEnd.row(); row >= 0; --row) { 1039 const QModelIndex newEndSibling = q->sourceModel()->index(row, column, parent); 1040 if (!q->sourceModel()->hasChildren(newEndSibling)) { 1041 ++proxyRow; 1042 } else { 1043 break; 1044 } 1045 } 1046 m_mapping.insert(newEnd, proxyRow); 1047 q->endRemoveRows(); 1048 if (start > 0) { 1049 notifyhasSiblings(q->sourceModel()->index(start - 1, 0, parent)); 1050 } 1051 return; 1052 } else if (lowerBound == m_mapping.rightBegin()) { 1053 int proxyRow = rowCount - 1; 1054 QModelIndex trackedParent = parent; 1055 while (trackedParent.isValid()) { 1056 proxyRow += (trackedParent.row() + 1); 1057 trackedParent = trackedParent.parent(); 1058 } 1059 m_mapping.insert(newEnd, proxyRow); 1060 q->endRemoveRows(); 1061 if (start > 0) { 1062 notifyhasSiblings(q->sourceModel()->index(start - 1, 0, parent)); 1063 } 1064 return; 1065 } 1066 const Mapping::right_iterator boundAbove = lowerBound - 1; 1067 1068 QVector<QModelIndex> targetParents; 1069 targetParents.push_back(parent); 1070 { 1071 QModelIndex target = parent; 1072 int count = 0; 1073 while (target.isValid()) { 1074 if (target == boundAbove.value()) { 1075 m_mapping.insert(newEnd, count + boundAbove.key() + newEnd.row() + 1); 1076 q->endRemoveRows(); 1077 if (start > 0) { 1078 notifyhasSiblings(q->sourceModel()->index(start - 1, 0, parent)); 1079 } 1080 return; 1081 } 1082 count += (target.row() + 1); 1083 target = target.parent(); 1084 if (target.isValid()) { 1085 targetParents.push_back(target); 1086 } 1087 } 1088 } 1089 1090 QModelIndex boundParent = boundAbove.value().parent(); 1091 QModelIndex prevParent = boundParent; 1092 Q_ASSERT(boundParent.isValid()); 1093 while (boundParent.isValid()) { 1094 prevParent = boundParent; 1095 boundParent = boundParent.parent(); 1096 1097 if (targetParents.contains(prevParent)) { 1098 break; 1099 } 1100 1101 if (!m_mapping.leftContains(prevParent)) { 1102 break; 1103 } 1104 1105 if (m_mapping.leftToRight(prevParent) > boundAbove.key()) { 1106 break; 1107 } 1108 } 1109 1110 QModelIndex trackedParent = parent; 1111 1112 int proxyRow = boundAbove.key(); 1113 1114 Q_ASSERT(prevParent.isValid()); 1115 proxyRow -= prevParent.row(); 1116 while (trackedParent != boundParent) { 1117 proxyRow += (trackedParent.row() + 1); 1118 trackedParent = trackedParent.parent(); 1119 } 1120 m_mapping.insert(newEnd, proxyRow + newEnd.row()); 1121 q->endRemoveRows(); 1122 1123 if (parent.isValid()) { 1124 const QModelIndex oindex = q->mapFromSource(parent); 1125 QVector<int> rolesChanged({KDescendantsProxyModel::ExpandableRole}); 1126 1127 if (!q->sourceModel()->hasChildren(parent)) { 1128 rolesChanged << KDescendantsProxyModel::ExpandedRole; 1129 } else if (q->sourceModel()->rowCount(parent) <= start) { 1130 const QModelIndex index = q->mapFromSource(q->sourceModel()->index(q->sourceModel()->rowCount(parent) - 1, 0, parent)); 1131 Q_EMIT q->dataChanged(index, index, {KDescendantsProxyModel::ExpandedRole}); 1132 } 1133 1134 Q_EMIT q->dataChanged(oindex, oindex, rolesChanged); 1135 } 1136 1137 if (start > 0) { 1138 notifyhasSiblings(q->sourceModel()->index(start - 1, 0, parent)); 1139 } 1140 } 1141 1142 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeMoved(const QModelIndex &srcParent, 1143 int srcStart, 1144 int srcEnd, 1145 const QModelIndex &destParent, 1146 int destStart) 1147 { 1148 Q_Q(KDescendantsProxyModel); 1149 1150 Q_UNUSED(destStart) 1151 1152 if (q->isSourceIndexExpanded(srcParent) && q->isSourceIndexVisible(srcParent) 1153 && (!q->isSourceIndexExpanded(destParent) || !q->isSourceIndexVisible(destParent))) { 1154 const QModelIndex proxySrcParent = q->mapFromSource(srcParent); 1155 const int proxyParentRow = proxySrcParent.isValid() ? proxySrcParent.row() : 0; 1156 q->beginRemoveRows(QModelIndex(), proxyParentRow + srcStart, proxyParentRow + srcEnd); 1157 1158 } else if ((!q->isSourceIndexExpanded(srcParent) || !q->isSourceIndexVisible(srcParent)) && q->isSourceIndexExpanded(destParent) 1159 && q->isSourceIndexVisible(destParent)) { 1160 const QModelIndex proxyDestParent = q->mapFromSource(srcParent); 1161 const int proxyParentRow = proxyDestParent.isValid() ? proxyDestParent.row() : 0; 1162 1163 q->beginInsertRows(QModelIndex(), proxyParentRow + destStart, proxyParentRow + destStart + (srcEnd - srcStart)); 1164 } 1165 1166 sourceLayoutAboutToBeChanged(); 1167 } 1168 1169 void KDescendantsProxyModelPrivate::sourceRowsMoved(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destStart) 1170 { 1171 Q_Q(KDescendantsProxyModel); 1172 1173 Q_UNUSED(srcParent) 1174 Q_UNUSED(srcStart) 1175 Q_UNUSED(srcEnd) 1176 Q_UNUSED(destParent) 1177 Q_UNUSED(destStart) 1178 1179 if (q->isSourceIndexExpanded(srcParent) && q->isSourceIndexVisible(srcParent) 1180 && (!q->isSourceIndexExpanded(destParent) || !q->isSourceIndexVisible(destParent))) { 1181 q->endRemoveRows(); 1182 } else if (!q->isSourceIndexExpanded(srcParent) && q->isSourceIndexExpanded(destParent)) { 1183 q->endInsertRows(); 1184 } 1185 1186 sourceLayoutChanged(); 1187 1188 const QModelIndex index1 = q->mapFromSource(srcParent); 1189 const QModelIndex index2 = q->mapFromSource(destParent); 1190 Q_EMIT q->dataChanged(index1, index1, {KDescendantsProxyModel::ExpandableRole}); 1191 if (index1 != index2) { 1192 Q_EMIT q->dataChanged(index2, index2, {KDescendantsProxyModel::ExpandableRole}); 1193 if (!q->sourceModel()->hasChildren(destParent)) { 1194 Q_EMIT q->dataChanged(index2, index2, {KDescendantsProxyModel::ExpandableRole}); 1195 } 1196 } 1197 const QModelIndex lastIndex = q->mapFromSource(q->sourceModel()->index(q->sourceModel()->rowCount(srcParent) - 1, 0, srcParent)); 1198 Q_EMIT q->dataChanged(lastIndex, lastIndex, {KDescendantsProxyModel::ExpandableRole}); 1199 1200 if (srcStart > 0) { 1201 notifyhasSiblings(q->sourceModel()->index(srcStart - 1, 0, srcParent)); 1202 } 1203 if (destStart > 0) { 1204 notifyhasSiblings(q->sourceModel()->index(destStart - 1, 0, destParent)); 1205 } 1206 } 1207 1208 void KDescendantsProxyModelPrivate::sourceModelAboutToBeReset() 1209 { 1210 Q_Q(KDescendantsProxyModel); 1211 q->beginResetModel(); 1212 } 1213 1214 void KDescendantsProxyModelPrivate::sourceModelReset() 1215 { 1216 Q_Q(KDescendantsProxyModel); 1217 resetInternalData(); 1218 if (q->sourceModel()->hasChildren() && q->sourceModel()->rowCount() > 0) { 1219 m_pendingParents.append(QModelIndex()); 1220 scheduleProcessPendingParents(); 1221 } 1222 q->endResetModel(); 1223 } 1224 1225 void KDescendantsProxyModelPrivate::sourceLayoutAboutToBeChanged() 1226 { 1227 Q_Q(KDescendantsProxyModel); 1228 1229 if (m_ignoreNextLayoutChanged) { 1230 m_ignoreNextLayoutChanged = false; 1231 return; 1232 } 1233 1234 if (m_mapping.isEmpty()) { 1235 return; 1236 } 1237 1238 Q_EMIT q->layoutAboutToBeChanged(); 1239 1240 QPersistentModelIndex srcPersistentIndex; 1241 const auto lst = q->persistentIndexList(); 1242 for (const QModelIndex &proxyPersistentIndex : lst) { 1243 m_proxyIndexes << proxyPersistentIndex; 1244 Q_ASSERT(proxyPersistentIndex.isValid()); 1245 srcPersistentIndex = q->mapToSource(proxyPersistentIndex); 1246 Q_ASSERT(srcPersistentIndex.isValid()); 1247 m_layoutChangePersistentIndexes << srcPersistentIndex; 1248 } 1249 } 1250 1251 void KDescendantsProxyModelPrivate::sourceLayoutChanged() 1252 { 1253 Q_Q(KDescendantsProxyModel); 1254 1255 if (m_ignoreNextLayoutAboutToBeChanged) { 1256 m_ignoreNextLayoutAboutToBeChanged = false; 1257 return; 1258 } 1259 1260 if (m_mapping.isEmpty()) { 1261 return; 1262 } 1263 1264 m_rowCount = 0; 1265 1266 synchronousMappingRefresh(); 1267 1268 for (int i = 0; i < m_proxyIndexes.size(); ++i) { 1269 q->changePersistentIndex(m_proxyIndexes.at(i), q->mapFromSource(m_layoutChangePersistentIndexes.at(i))); 1270 } 1271 1272 m_layoutChangePersistentIndexes.clear(); 1273 m_proxyIndexes.clear(); 1274 1275 Q_EMIT q->layoutChanged(); 1276 } 1277 1278 void KDescendantsProxyModelPrivate::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) 1279 { 1280 Q_Q(KDescendantsProxyModel); 1281 // It is actually possible in a real world scenario that the source model emits dataChanged 1282 // with invalid indexes when the source model is a QSortFilterProxyModel 1283 // because QSortFilterProxyModel doesn't check for mapped index validity when its 1284 // source model emitted dataChanged on a column QSortFilterProxyModel doesn't accept. 1285 // See https://bugreports.qt.io/browse/QTBUG-86850 1286 if (!topLeft.isValid() || !bottomRight.isValid()) { 1287 return; 1288 } 1289 Q_ASSERT(topLeft.model() == q->sourceModel()); 1290 Q_ASSERT(bottomRight.model() == q->sourceModel()); 1291 1292 if (!q->isSourceIndexExpanded(topLeft.parent()) || !q->isSourceIndexVisible(topLeft.parent())) { 1293 return; 1294 } 1295 1296 const int topRow = topLeft.row(); 1297 const int bottomRow = bottomRight.row(); 1298 1299 for (int i = topRow; i <= bottomRow; ++i) { 1300 const QModelIndex sourceTopLeft = q->sourceModel()->index(i, topLeft.column(), topLeft.parent()); 1301 1302 Q_ASSERT(sourceTopLeft.isValid()); 1303 const QModelIndex proxyTopLeft = q->mapFromSource(sourceTopLeft); 1304 // TODO. If an index does not have any descendants, then we can emit in blocks of rows. 1305 // As it is we emit once for each row. 1306 const QModelIndex sourceBottomRight = q->sourceModel()->index(i, bottomRight.column(), bottomRight.parent()); 1307 const QModelIndex proxyBottomRight = q->mapFromSource(sourceBottomRight); 1308 Q_ASSERT(proxyTopLeft.isValid()); 1309 Q_ASSERT(proxyBottomRight.isValid()); 1310 Q_EMIT q->dataChanged(proxyTopLeft, proxyBottomRight); 1311 } 1312 } 1313 1314 void KDescendantsProxyModelPrivate::sourceModelDestroyed() 1315 { 1316 resetInternalData(); 1317 } 1318 1319 QMimeData *KDescendantsProxyModel::mimeData(const QModelIndexList &indexes) const 1320 { 1321 if (!sourceModel()) { 1322 return QAbstractProxyModel::mimeData(indexes); 1323 } 1324 Q_ASSERT(sourceModel()); 1325 QModelIndexList sourceIndexes; 1326 for (const QModelIndex &index : indexes) { 1327 sourceIndexes << mapToSource(index); 1328 } 1329 return sourceModel()->mimeData(sourceIndexes); 1330 } 1331 1332 QStringList KDescendantsProxyModel::mimeTypes() const 1333 { 1334 if (!sourceModel()) { 1335 return QAbstractProxyModel::mimeTypes(); 1336 } 1337 Q_ASSERT(sourceModel()); 1338 return sourceModel()->mimeTypes(); 1339 } 1340 1341 Qt::DropActions KDescendantsProxyModel::supportedDropActions() const 1342 { 1343 if (!sourceModel()) { 1344 return QAbstractProxyModel::supportedDropActions(); 1345 } 1346 return sourceModel()->supportedDropActions(); 1347 } 1348 1349 #include "moc_kdescendantsproxymodel.cpp"