File indexing completed on 2024-05-05 03:56:41
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 QList<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 QList<QPersistentModelIndex>::iterator begin = m_pendingParents.begin(); 0110 QList<QPersistentModelIndex>::iterator it = begin; 0111 0112 const QList<QPersistentModelIndex>::iterator end = m_pendingParents.end(); 0113 0114 QList<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 QModelIndexList KDescendantsProxyModel::match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const 0348 { 0349 return QAbstractProxyModel::match(start, role, value, hits, flags); 0350 } 0351 0352 namespace 0353 { 0354 // we only work on DisplayRole for now 0355 static const QList<int> changedRoles = {Qt::DisplayRole}; 0356 } 0357 0358 void KDescendantsProxyModel::setDisplayAncestorData(bool display) 0359 { 0360 Q_D(KDescendantsProxyModel); 0361 bool displayChanged = (display != d->m_displayAncestorData); 0362 d->m_displayAncestorData = display; 0363 if (displayChanged) { 0364 Q_EMIT displayAncestorDataChanged(); 0365 // send out big hammer. Everything needs to be updated. 0366 Q_EMIT dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1), changedRoles); 0367 } 0368 } 0369 0370 bool KDescendantsProxyModel::displayAncestorData() const 0371 { 0372 Q_D(const KDescendantsProxyModel); 0373 return d->m_displayAncestorData; 0374 } 0375 0376 void KDescendantsProxyModel::setAncestorSeparator(const QString &separator) 0377 { 0378 Q_D(KDescendantsProxyModel); 0379 bool separatorChanged = (separator != d->m_ancestorSeparator); 0380 d->m_ancestorSeparator = separator; 0381 if (separatorChanged) { 0382 Q_EMIT ancestorSeparatorChanged(); 0383 if (d->m_displayAncestorData) { 0384 // send out big hammer. Everything needs to be updated. 0385 Q_EMIT dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1), changedRoles); 0386 } 0387 } 0388 } 0389 0390 QString KDescendantsProxyModel::ancestorSeparator() const 0391 { 0392 Q_D(const KDescendantsProxyModel); 0393 return d->m_ancestorSeparator; 0394 } 0395 0396 void KDescendantsProxyModel::setSourceModel(QAbstractItemModel *_sourceModel) 0397 { 0398 Q_D(KDescendantsProxyModel); 0399 0400 beginResetModel(); 0401 0402 if (sourceModel()) { 0403 disconnect(sourceModel(), nullptr, this, nullptr); 0404 } 0405 0406 QAbstractProxyModel::setSourceModel(_sourceModel); 0407 d_ptr->m_expandedSourceIndexes.clear(); 0408 0409 if (_sourceModel) { 0410 connect(_sourceModel, &QAbstractItemModel::rowsAboutToBeInserted, this, [d](const QModelIndex &parent, int start, int end) { 0411 d->sourceRowsAboutToBeInserted(parent, start, end); 0412 }); 0413 0414 connect(_sourceModel, &QAbstractItemModel::rowsInserted, this, [d](const QModelIndex &parent, int start, int end) { 0415 d->sourceRowsInserted(parent, start, end); 0416 }); 0417 0418 connect(_sourceModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, [d](const QModelIndex &parent, int start, int end) { 0419 d->sourceRowsAboutToBeRemoved(parent, start, end); 0420 }); 0421 0422 connect(_sourceModel, &QAbstractItemModel::rowsRemoved, this, [d](const QModelIndex &parent, int start, int end) { 0423 d->sourceRowsRemoved(parent, start, end); 0424 }); 0425 0426 connect(_sourceModel, 0427 &QAbstractItemModel::rowsAboutToBeMoved, 0428 this, 0429 [d](const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destStart) { 0430 d->sourceRowsAboutToBeMoved(srcParent, srcStart, srcEnd, destParent, destStart); 0431 }); 0432 0433 connect(_sourceModel, 0434 &QAbstractItemModel::rowsMoved, 0435 this, 0436 [d](const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destStart) { 0437 d->sourceRowsMoved(srcParent, srcStart, srcEnd, destParent, destStart); 0438 }); 0439 0440 connect(_sourceModel, &QAbstractItemModel::modelAboutToBeReset, this, [d]() { 0441 d->sourceModelAboutToBeReset(); 0442 }); 0443 0444 connect(_sourceModel, &QAbstractItemModel::modelReset, this, [d]() { 0445 d->sourceModelReset(); 0446 }); 0447 0448 connect(_sourceModel, &QAbstractItemModel::dataChanged, this, [d](const QModelIndex &topLeft, const QModelIndex &bottomRight) { 0449 d->sourceDataChanged(topLeft, bottomRight); 0450 }); 0451 0452 connect(_sourceModel, &QAbstractItemModel::layoutAboutToBeChanged, this, [d]() { 0453 d->sourceLayoutAboutToBeChanged(); 0454 }); 0455 0456 connect(_sourceModel, &QAbstractItemModel::layoutChanged, this, [d]() { 0457 d->sourceLayoutChanged(); 0458 }); 0459 0460 connect(_sourceModel, &QObject::destroyed, this, [d]() { 0461 d->sourceModelDestroyed(); 0462 }); 0463 } 0464 0465 resetInternalData(); 0466 if (_sourceModel && _sourceModel->hasChildren()) { 0467 d->synchronousMappingRefresh(); 0468 } 0469 0470 endResetModel(); 0471 Q_EMIT sourceModelChanged(); 0472 } 0473 0474 QModelIndex KDescendantsProxyModel::parent(const QModelIndex &index) const 0475 { 0476 Q_UNUSED(index) 0477 return QModelIndex(); 0478 } 0479 0480 bool KDescendantsProxyModel::hasChildren(const QModelIndex &parent) const 0481 { 0482 Q_D(const KDescendantsProxyModel); 0483 return !(d->m_mapping.isEmpty() || parent.isValid()); 0484 } 0485 0486 int KDescendantsProxyModel::rowCount(const QModelIndex &parent) const 0487 { 0488 Q_D(const KDescendantsProxyModel); 0489 if (d->m_pendingParents.contains(parent) || parent.isValid() || !sourceModel()) { 0490 return 0; 0491 } 0492 0493 if (d->m_mapping.isEmpty() && sourceModel()->hasChildren()) { 0494 const_cast<KDescendantsProxyModelPrivate *>(d)->synchronousMappingRefresh(); 0495 } 0496 return d->m_rowCount; 0497 } 0498 0499 QModelIndex KDescendantsProxyModel::index(int row, int column, const QModelIndex &parent) const 0500 { 0501 if (parent.isValid()) { 0502 return QModelIndex(); 0503 } 0504 0505 if (!hasIndex(row, column, parent)) { 0506 return QModelIndex(); 0507 } 0508 0509 return createIndex(row, column); 0510 } 0511 0512 QModelIndex KDescendantsProxyModel::mapToSource(const QModelIndex &proxyIndex) const 0513 { 0514 Q_D(const KDescendantsProxyModel); 0515 if (d->m_mapping.isEmpty() || !proxyIndex.isValid() || !sourceModel()) { 0516 return QModelIndex(); 0517 } 0518 0519 const Mapping::right_const_iterator result = d->m_mapping.rightLowerBound(proxyIndex.row()); 0520 Q_ASSERT(result != d->m_mapping.rightEnd()); 0521 0522 const int proxyLastRow = result.key(); 0523 const QModelIndex sourceLastChild = result.value(); 0524 Q_ASSERT(sourceLastChild.isValid()); 0525 0526 // proxyLastRow is greater than proxyIndex.row(). 0527 // sourceLastChild is vertically below the result we're looking for 0528 // and not necessarily in the correct parent. 0529 // We travel up through its parent hierarchy until we are in the 0530 // right parent, then return the correct sibling. 0531 0532 // Source: Proxy: Row 0533 // - A - A - 0 0534 // - B - B - 1 0535 // - C - C - 2 0536 // - D - D - 3 0537 // - - E - E - 4 0538 // - - F - F - 5 0539 // - - G - G - 6 0540 // - - H - H - 7 0541 // - - I - I - 8 0542 // - - - J - J - 9 0543 // - - - K - K - 10 0544 // - - - L - L - 11 0545 // - - M - M - 12 0546 // - - N - N - 13 0547 // - O - O - 14 0548 0549 // Note that L, N and O are lastChildIndexes, and therefore have a mapping. If we 0550 // are trying to map G from the proxy to the source, We at this point have an iterator 0551 // pointing to (L -> 11). The proxy row of G is 6. (proxyIndex.row() == 6). We seek the 0552 // sourceIndex which is vertically above L by the distance proxyLastRow - proxyIndex.row(). 0553 // In this case the verticalDistance is 5. 0554 0555 int verticalDistance = proxyLastRow - proxyIndex.row(); 0556 0557 // We traverse the ancestors of L, until we can index the desired row in the source. 0558 0559 QModelIndex ancestor = sourceLastChild; 0560 while (ancestor.isValid()) { 0561 const int ancestorRow = ancestor.row(); 0562 if (verticalDistance <= ancestorRow) { 0563 return ancestor.sibling(ancestorRow - verticalDistance, proxyIndex.column()); 0564 } 0565 verticalDistance -= (ancestorRow + 1); 0566 ancestor = ancestor.parent(); 0567 } 0568 Q_ASSERT(!"Didn't find target row."); 0569 return QModelIndex(); 0570 } 0571 0572 QModelIndex KDescendantsProxyModel::mapFromSource(const QModelIndex &sourceIndex) const 0573 { 0574 Q_D(const KDescendantsProxyModel); 0575 0576 if (!sourceModel()) { 0577 return QModelIndex(); 0578 } 0579 0580 if (d->m_mapping.isEmpty()) { 0581 return QModelIndex(); 0582 } 0583 0584 { 0585 // TODO: Consider a parent Mapping to speed this up. 0586 0587 Mapping::right_const_iterator it = d->m_mapping.rightConstBegin(); 0588 const Mapping::right_const_iterator end = d->m_mapping.rightConstEnd(); 0589 const QModelIndex sourceParent = sourceIndex.parent(); 0590 Mapping::right_const_iterator result = end; 0591 0592 if (!isSourceIndexVisible(sourceIndex)) { 0593 return QModelIndex(); 0594 } 0595 0596 for (; it != end; ++it) { 0597 QModelIndex index = it.value(); 0598 bool found_block = false; 0599 while (index.isValid()) { 0600 const QModelIndex ancestor = index.parent(); 0601 if (ancestor == sourceParent && index.row() >= sourceIndex.row()) { 0602 found_block = true; 0603 if (result == end || it.key() < result.key()) { 0604 result = it; 0605 break; // Leave the while loop. index is still valid. 0606 } 0607 } 0608 index = ancestor; 0609 } 0610 if (found_block && !index.isValid()) 0611 // Looked through the ascendants of it.key() without finding sourceParent. 0612 // That means we've already got the result we need. 0613 { 0614 break; 0615 } 0616 } 0617 Q_ASSERT(result != end); 0618 const QModelIndex sourceLastChild = result.value(); 0619 int proxyRow = result.key(); 0620 QModelIndex index = sourceLastChild; 0621 while (index.isValid()) { 0622 const QModelIndex ancestor = index.parent(); 0623 if (ancestor == sourceParent) { 0624 return createIndex(proxyRow - (index.row() - sourceIndex.row()), sourceIndex.column()); 0625 } 0626 proxyRow -= (index.row() + 1); 0627 index = ancestor; 0628 } 0629 Q_ASSERT(!"Didn't find valid proxy mapping."); 0630 return QModelIndex(); 0631 } 0632 } 0633 0634 int KDescendantsProxyModel::columnCount(const QModelIndex &parent) const 0635 { 0636 if (parent.isValid() /* || rowCount(parent) == 0 */ || !sourceModel()) { 0637 return 0; 0638 } 0639 0640 return sourceModel()->columnCount(); 0641 } 0642 0643 QVariant KDescendantsProxyModel::data(const QModelIndex &index, int role) const 0644 { 0645 Q_D(const KDescendantsProxyModel); 0646 0647 if (!sourceModel()) { 0648 return QVariant(); 0649 } 0650 0651 if (!index.isValid()) { 0652 return sourceModel()->data(index, role); 0653 } 0654 0655 QModelIndex sourceIndex = mapToSource(index); 0656 0657 if ((d->m_displayAncestorData) && (role == Qt::DisplayRole)) { 0658 if (!sourceIndex.isValid()) { 0659 return QVariant(); 0660 } 0661 QString displayData = sourceIndex.data().toString(); 0662 sourceIndex = sourceIndex.parent(); 0663 while (sourceIndex.isValid()) { 0664 displayData.prepend(d->m_ancestorSeparator); 0665 displayData.prepend(sourceIndex.data().toString()); 0666 sourceIndex = sourceIndex.parent(); 0667 } 0668 return displayData; 0669 } else if (role == LevelRole) { 0670 QModelIndex sourceIndex = mapToSource(index); 0671 int level = 0; 0672 while (sourceIndex.isValid()) { 0673 sourceIndex = sourceIndex.parent(); 0674 ++level; 0675 } 0676 return level; 0677 } else if (role == ExpandableRole) { 0678 QModelIndex sourceIndex = mapToSource(index); 0679 return sourceModel()->hasChildren(sourceIndex); 0680 } else if (role == ExpandedRole) { 0681 return isSourceIndexExpanded(mapToSource(index)); 0682 } else if (role == HasSiblingsRole) { 0683 QModelIndex sourceIndex = mapToSource(index); 0684 QList<bool> hasSibling; 0685 while (sourceIndex.isValid()) { 0686 hasSibling.prepend(sourceModel()->rowCount(sourceIndex.parent()) > sourceIndex.row() + 1); 0687 sourceIndex = sourceIndex.parent(); 0688 } 0689 return QVariant::fromValue(hasSibling); 0690 } else { 0691 return sourceIndex.data(role); 0692 } 0693 } 0694 0695 QVariant KDescendantsProxyModel::headerData(int section, Qt::Orientation orientation, int role) const 0696 { 0697 if (!sourceModel() || columnCount() <= section) { 0698 return QVariant(); 0699 } 0700 0701 // Here is safe to do sourceModel()->headerData, as in this proxy we neither filter out nor reorder columns 0702 return sourceModel()->headerData(section, orientation, role); 0703 } 0704 0705 Qt::ItemFlags KDescendantsProxyModel::flags(const QModelIndex &index) const 0706 { 0707 if (!index.isValid() || !sourceModel()) { 0708 return QAbstractProxyModel::flags(index); 0709 } 0710 0711 const QModelIndex srcIndex = mapToSource(index); 0712 Q_ASSERT(srcIndex.isValid()); 0713 return sourceModel()->flags(srcIndex); 0714 } 0715 0716 void KDescendantsProxyModelPrivate::notifyhasSiblings(const QModelIndex &parent) 0717 { 0718 Q_Q(KDescendantsProxyModel); 0719 0720 if (!parent.isValid()) { 0721 return; 0722 } 0723 0724 QModelIndex localParent = q->mapFromSource(parent); 0725 Q_EMIT q->dataChanged(localParent, localParent, {KDescendantsProxyModel::HasSiblingsRole}); 0726 for (int i = 0; i < q->sourceModel()->rowCount(parent); ++i) { 0727 notifyhasSiblings(q->sourceModel()->index(i, 0, parent)); 0728 } 0729 } 0730 0731 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end) 0732 { 0733 Q_Q(KDescendantsProxyModel); 0734 0735 if (parent.isValid() && (!q->isSourceIndexExpanded(parent) || !q->isSourceIndexVisible(parent))) { 0736 return; 0737 } 0738 0739 if (!q->sourceModel()->hasChildren(parent)) { 0740 Q_ASSERT(q->sourceModel()->rowCount(parent) == 0); 0741 // parent was not a parent before. 0742 return; 0743 } 0744 0745 int proxyStart = -1; 0746 0747 const int rowCount = q->sourceModel()->rowCount(parent); 0748 0749 if (rowCount > start) { 0750 const QModelIndex belowStart = q->sourceModel()->index(start, 0, parent); 0751 proxyStart = q->mapFromSource(belowStart).row(); 0752 } else if (rowCount == 0) { 0753 proxyStart = q->mapFromSource(parent).row() + 1; 0754 } else { 0755 Q_ASSERT(rowCount == start); 0756 static const int column = 0; 0757 QModelIndex idx = q->sourceModel()->index(rowCount - 1, column, parent); 0758 while (q->isSourceIndexExpanded(idx) && q->sourceModel()->hasChildren(idx) && q->sourceModel()->rowCount(idx) > 0) { 0759 idx = q->sourceModel()->index(q->sourceModel()->rowCount(idx) - 1, column, idx); 0760 } 0761 // The last item in the list is getting a sibling below it. 0762 proxyStart = q->mapFromSource(idx).row() + 1; 0763 } 0764 const int proxyEnd = proxyStart + (end - start); 0765 0766 m_insertPair = qMakePair(proxyStart, proxyEnd); 0767 q->beginInsertRows(QModelIndex(), proxyStart, proxyEnd); 0768 } 0769 0770 void KDescendantsProxyModelPrivate::sourceRowsInserted(const QModelIndex &parent, int start, int end) 0771 { 0772 Q_Q(KDescendantsProxyModel); 0773 if (parent.isValid() && (!q->isSourceIndexExpanded(parent) || !q->isSourceIndexVisible(parent))) { 0774 const QModelIndex index = q->mapFromSource(parent); 0775 Q_EMIT q->dataChanged(index, 0776 index, 0777 {KDescendantsProxyModel::ExpandableRole, KDescendantsProxyModel::ExpandedRole, KDescendantsProxyModel::HasSiblingsRole}); 0778 if (start > 0) { 0779 notifyhasSiblings(q->sourceModel()->index(start - 1, 0, parent)); 0780 } 0781 return; 0782 } 0783 Q_ASSERT(q->sourceModel()->index(start, 0, parent).isValid()); 0784 0785 const int rowCount = q->sourceModel()->rowCount(parent); 0786 Q_ASSERT(rowCount > 0); 0787 0788 const int difference = end - start + 1; 0789 0790 if (rowCount == difference) { 0791 const QModelIndex index = q->mapFromSource(parent); 0792 if (parent.isValid()) { 0793 Q_EMIT q->dataChanged(index, 0794 index, 0795 {KDescendantsProxyModel::ExpandableRole, KDescendantsProxyModel::ExpandedRole, KDescendantsProxyModel::HasSiblingsRole}); 0796 } 0797 // @p parent was not a parent before. 0798 m_pendingParents.append(parent); 0799 scheduleProcessPendingParents(); 0800 if (start > 0) { 0801 notifyhasSiblings(q->sourceModel()->index(start - 1, 0, parent)); 0802 } 0803 return; 0804 } 0805 0806 const int proxyStart = m_insertPair.first; 0807 0808 Q_ASSERT(proxyStart >= 0); 0809 0810 updateInternalIndexes(proxyStart, difference); 0811 0812 if (rowCount - 1 == end) { 0813 // The previously last row (the mapped one) is no longer the last. 0814 // For example, 0815 0816 // - A - A 0 0817 // - - B - B 1 0818 // - - C - C 2 0819 // - - - D - D 3 0820 // - - - E -> - E 4 0821 // - - F - F 5 0822 // - - G -> - G 6 0823 // - H - H 7 0824 // - I -> - I 8 0825 0826 // As last children, E, F and G have mappings. 0827 // Consider that 'J' is appended to the children of 'C', below 'E'. 0828 0829 // - A - A 0 0830 // - - B - B 1 0831 // - - C - C 2 0832 // - - - D - D 3 0833 // - - - E -> - E 4 0834 // - - - J - ??? 5 0835 // - - F - F 6 0836 // - - G -> - G 7 0837 // - H - H 8 0838 // - I -> - I 9 0839 0840 // The updateInternalIndexes call above will have updated the F and G mappings correctly because proxyStart is 5. 0841 // That means that E -> 4 was not affected by the updateInternalIndexes call. 0842 // Now the mapping for E -> 4 needs to be updated so that it's a mapping for J -> 5. 0843 0844 Q_ASSERT(!m_mapping.isEmpty()); 0845 static const int column = 0; 0846 const QModelIndex oldIndex = q->sourceModel()->index(rowCount - 1 - difference, column, parent); 0847 Q_ASSERT(m_mapping.leftContains(oldIndex)); 0848 0849 const QModelIndex newIndex = q->sourceModel()->index(rowCount - 1, column, parent); 0850 0851 QModelIndex indexAbove = oldIndex; 0852 0853 if (start > 0) { 0854 // If we have something like this: 0855 // 0856 // - A 0857 // - - B 0858 // - - C 0859 // 0860 // and we then insert D as a sibling of A below it, we need to remove the mapping for A, 0861 // and the row number used for D must take into account the descendants of A. 0862 0863 while (q->isSourceIndexExpanded(indexAbove) && q->sourceModel()->hasChildren(indexAbove)) { 0864 Q_ASSERT(q->sourceModel()->rowCount(indexAbove) > 0); 0865 indexAbove = q->sourceModel()->index(q->sourceModel()->rowCount(indexAbove) - 1, column, indexAbove); 0866 } 0867 Q_ASSERT(!q->isSourceIndexExpanded(indexAbove) || q->sourceModel()->rowCount(indexAbove) == 0); 0868 } 0869 0870 Q_ASSERT(m_mapping.leftContains(indexAbove)); 0871 0872 const int newProxyRow = m_mapping.leftToRight(indexAbove) + difference; 0873 0874 // oldIndex is E in the source. proxyRow is 4. 0875 m_mapping.removeLeft(oldIndex); 0876 0877 // newIndex is J. (proxyRow + difference) is 5. 0878 m_mapping.insert(newIndex, newProxyRow); 0879 } 0880 0881 for (int row = start; row <= end; ++row) { 0882 static const int column = 0; 0883 const QModelIndex idx = q->sourceModel()->index(row, column, parent); 0884 Q_ASSERT(idx.isValid()); 0885 0886 if (q->isSourceIndexExpanded(idx) && q->sourceModel()->hasChildren(idx) && q->sourceModel()->rowCount(idx) > 0) { 0887 m_pendingParents.append(idx); 0888 } 0889 } 0890 0891 m_rowCount += difference; 0892 0893 q->endInsertRows(); 0894 scheduleProcessPendingParents(); 0895 if (parent.isValid()) { 0896 const QModelIndex index = q->mapFromSource(parent); 0897 Q_EMIT q->dataChanged(index, 0898 index, 0899 {KDescendantsProxyModel::ExpandableRole, KDescendantsProxyModel::ExpandedRole, KDescendantsProxyModel::HasSiblingsRole}); 0900 } 0901 0902 if (start > 0) { 0903 notifyhasSiblings(q->sourceModel()->index(start - 1, 0, parent)); 0904 } 0905 } 0906 0907 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) 0908 { 0909 Q_Q(KDescendantsProxyModel); 0910 0911 if (!q->isSourceIndexExpanded(parent) || !q->isSourceIndexVisible(parent)) { 0912 return; 0913 } 0914 0915 const int proxyStart = q->mapFromSource(q->sourceModel()->index(start, 0, parent)).row(); 0916 0917 static const int column = 0; 0918 QModelIndex idx = q->sourceModel()->index(end, column, parent); 0919 while (q->sourceModel()->hasChildren(idx) && q->sourceModel()->rowCount(idx) > 0) { 0920 idx = q->sourceModel()->index(q->sourceModel()->rowCount(idx) - 1, column, idx); 0921 } 0922 const int proxyEnd = q->mapFromSource(idx).row(); 0923 0924 for (int i = start; i <= end; ++i) { 0925 QModelIndex idx = q->sourceModel()->index(i, column, parent); 0926 m_expandedSourceIndexes.remove(QPersistentModelIndex(idx)); 0927 } 0928 0929 m_removePair = qMakePair(proxyStart, proxyEnd); 0930 0931 q->beginRemoveRows(QModelIndex(), proxyStart, proxyEnd); 0932 } 0933 0934 static QModelIndex getFirstDeepest(QAbstractItemModel *model, const QModelIndex &parent, int *count) 0935 { 0936 static const int column = 0; 0937 Q_ASSERT(model->hasChildren(parent)); 0938 Q_ASSERT(model->rowCount(parent) > 0); 0939 for (int row = 0; row < model->rowCount(parent); ++row) { 0940 (*count)++; 0941 const QModelIndex child = model->index(row, column, parent); 0942 Q_ASSERT(child.isValid()); 0943 if (model->hasChildren(child)) { 0944 return getFirstDeepest(model, child, count); 0945 } 0946 } 0947 return model->index(model->rowCount(parent) - 1, column, parent); 0948 } 0949 0950 void KDescendantsProxyModelPrivate::sourceRowsRemoved(const QModelIndex &parent, int start, int end) 0951 { 0952 Q_Q(KDescendantsProxyModel); 0953 Q_UNUSED(end) 0954 0955 if (!q->isSourceIndexExpanded(parent) || !q->isSourceIndexVisible(parent)) { 0956 if (parent.isValid()) { 0957 const QModelIndex index = q->mapFromSource(parent); 0958 Q_EMIT q->dataChanged(index, index, {KDescendantsProxyModel::ExpandableRole, KDescendantsProxyModel::ExpandedRole}); 0959 } 0960 return; 0961 } 0962 0963 const int rowCount = q->sourceModel()->rowCount(parent); 0964 0965 const int proxyStart = m_removePair.first; 0966 const int proxyEnd = m_removePair.second; 0967 0968 const int difference = proxyEnd - proxyStart + 1; 0969 { 0970 Mapping::right_iterator it = m_mapping.rightLowerBound(proxyStart); 0971 const Mapping::right_iterator endIt = m_mapping.rightUpperBound(proxyEnd); 0972 0973 if (endIt != m_mapping.rightEnd()) { 0974 while (it != endIt) { 0975 it = m_mapping.eraseRight(it); 0976 } 0977 } else { 0978 while (it != m_mapping.rightUpperBound(proxyEnd)) { 0979 it = m_mapping.eraseRight(it); 0980 } 0981 } 0982 } 0983 0984 m_removePair = qMakePair(-1, -1); 0985 m_rowCount -= difference; 0986 Q_ASSERT(m_rowCount >= 0); 0987 0988 updateInternalIndexes(proxyStart, -1 * difference); 0989 0990 if (rowCount != start || rowCount == 0) { 0991 q->endRemoveRows(); 0992 if (parent.isValid()) { 0993 const QModelIndex index = q->mapFromSource(parent); 0994 Q_EMIT q->dataChanged(index, index, {KDescendantsProxyModel::ExpandableRole, KDescendantsProxyModel::ExpandedRole}); 0995 } 0996 if (start > 0) { 0997 notifyhasSiblings(q->sourceModel()->index(start - 1, 0, parent)); 0998 } 0999 return; 1000 } 1001 1002 static const int column = 0; 1003 const QModelIndex newEnd = q->sourceModel()->index(rowCount - 1, column, parent); 1004 Q_ASSERT(newEnd.isValid()); 1005 1006 if (m_mapping.isEmpty()) { 1007 m_mapping.insert(newEnd, newEnd.row()); 1008 q->endRemoveRows(); 1009 if (start > 0) { 1010 notifyhasSiblings(q->sourceModel()->index(start - 1, 0, parent)); 1011 } 1012 return; 1013 } 1014 if (q->sourceModel()->hasChildren(newEnd)) { 1015 int count = 0; 1016 const QModelIndex firstDeepest = getFirstDeepest(q->sourceModel(), newEnd, &count); 1017 Q_ASSERT(firstDeepest.isValid()); 1018 const int firstDeepestProxy = m_mapping.leftToRight(firstDeepest); 1019 1020 m_mapping.insert(newEnd, firstDeepestProxy - count); 1021 q->endRemoveRows(); 1022 if (start > 0) { 1023 notifyhasSiblings(q->sourceModel()->index(start - 1, 0, parent)); 1024 } 1025 return; 1026 } 1027 Mapping::right_iterator lowerBound = m_mapping.rightLowerBound(proxyStart); 1028 if (lowerBound == m_mapping.rightEnd()) { 1029 int proxyRow = std::prev(lowerBound).key(); 1030 1031 for (int row = newEnd.row(); row >= 0; --row) { 1032 const QModelIndex newEndSibling = q->sourceModel()->index(row, column, parent); 1033 if (!q->sourceModel()->hasChildren(newEndSibling)) { 1034 ++proxyRow; 1035 } else { 1036 break; 1037 } 1038 } 1039 m_mapping.insert(newEnd, proxyRow); 1040 q->endRemoveRows(); 1041 if (start > 0) { 1042 notifyhasSiblings(q->sourceModel()->index(start - 1, 0, parent)); 1043 } 1044 return; 1045 } else if (lowerBound == m_mapping.rightBegin()) { 1046 int proxyRow = rowCount - 1; 1047 QModelIndex trackedParent = parent; 1048 while (trackedParent.isValid()) { 1049 proxyRow += (trackedParent.row() + 1); 1050 trackedParent = trackedParent.parent(); 1051 } 1052 m_mapping.insert(newEnd, proxyRow); 1053 q->endRemoveRows(); 1054 if (start > 0) { 1055 notifyhasSiblings(q->sourceModel()->index(start - 1, 0, parent)); 1056 } 1057 return; 1058 } 1059 const Mapping::right_iterator boundAbove = std::prev(lowerBound); 1060 1061 QList<QModelIndex> targetParents; 1062 targetParents.push_back(parent); 1063 { 1064 QModelIndex target = parent; 1065 int count = 0; 1066 while (target.isValid()) { 1067 if (target == boundAbove.value()) { 1068 m_mapping.insert(newEnd, count + boundAbove.key() + newEnd.row() + 1); 1069 q->endRemoveRows(); 1070 if (start > 0) { 1071 notifyhasSiblings(q->sourceModel()->index(start - 1, 0, parent)); 1072 } 1073 return; 1074 } 1075 count += (target.row() + 1); 1076 target = target.parent(); 1077 if (target.isValid()) { 1078 targetParents.push_back(target); 1079 } 1080 } 1081 } 1082 1083 QModelIndex boundParent = boundAbove.value().parent(); 1084 QModelIndex prevParent = boundParent; 1085 Q_ASSERT(boundParent.isValid()); 1086 while (boundParent.isValid()) { 1087 prevParent = boundParent; 1088 boundParent = boundParent.parent(); 1089 1090 if (targetParents.contains(prevParent)) { 1091 break; 1092 } 1093 1094 if (!m_mapping.leftContains(prevParent)) { 1095 break; 1096 } 1097 1098 if (m_mapping.leftToRight(prevParent) > boundAbove.key()) { 1099 break; 1100 } 1101 } 1102 1103 QModelIndex trackedParent = parent; 1104 1105 int proxyRow = boundAbove.key(); 1106 1107 Q_ASSERT(prevParent.isValid()); 1108 proxyRow -= prevParent.row(); 1109 while (trackedParent != boundParent) { 1110 proxyRow += (trackedParent.row() + 1); 1111 trackedParent = trackedParent.parent(); 1112 } 1113 m_mapping.insert(newEnd, proxyRow + newEnd.row()); 1114 q->endRemoveRows(); 1115 1116 if (parent.isValid()) { 1117 const QModelIndex oindex = q->mapFromSource(parent); 1118 QList<int> rolesChanged({KDescendantsProxyModel::ExpandableRole}); 1119 1120 if (!q->sourceModel()->hasChildren(parent)) { 1121 rolesChanged << KDescendantsProxyModel::ExpandedRole; 1122 } else if (q->sourceModel()->rowCount(parent) <= start) { 1123 const QModelIndex index = q->mapFromSource(q->sourceModel()->index(q->sourceModel()->rowCount(parent) - 1, 0, parent)); 1124 Q_EMIT q->dataChanged(index, index, {KDescendantsProxyModel::ExpandedRole}); 1125 } 1126 1127 Q_EMIT q->dataChanged(oindex, oindex, rolesChanged); 1128 } 1129 1130 if (start > 0) { 1131 notifyhasSiblings(q->sourceModel()->index(start - 1, 0, parent)); 1132 } 1133 } 1134 1135 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeMoved(const QModelIndex &srcParent, 1136 int srcStart, 1137 int srcEnd, 1138 const QModelIndex &destParent, 1139 int destStart) 1140 { 1141 Q_Q(KDescendantsProxyModel); 1142 1143 Q_UNUSED(destStart) 1144 1145 if (q->isSourceIndexExpanded(srcParent) && q->isSourceIndexVisible(srcParent) 1146 && (!q->isSourceIndexExpanded(destParent) || !q->isSourceIndexVisible(destParent))) { 1147 const QModelIndex proxySrcParent = q->mapFromSource(srcParent); 1148 const int proxyParentRow = proxySrcParent.isValid() ? proxySrcParent.row() : 0; 1149 q->beginRemoveRows(QModelIndex(), proxyParentRow + srcStart, proxyParentRow + srcEnd); 1150 1151 } else if ((!q->isSourceIndexExpanded(srcParent) || !q->isSourceIndexVisible(srcParent)) && q->isSourceIndexExpanded(destParent) 1152 && q->isSourceIndexVisible(destParent)) { 1153 const QModelIndex proxyDestParent = q->mapFromSource(srcParent); 1154 const int proxyParentRow = proxyDestParent.isValid() ? proxyDestParent.row() : 0; 1155 1156 q->beginInsertRows(QModelIndex(), proxyParentRow + destStart, proxyParentRow + destStart + (srcEnd - srcStart)); 1157 } 1158 1159 sourceLayoutAboutToBeChanged(); 1160 } 1161 1162 void KDescendantsProxyModelPrivate::sourceRowsMoved(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destStart) 1163 { 1164 Q_Q(KDescendantsProxyModel); 1165 1166 Q_UNUSED(srcParent) 1167 Q_UNUSED(srcStart) 1168 Q_UNUSED(srcEnd) 1169 Q_UNUSED(destParent) 1170 Q_UNUSED(destStart) 1171 1172 if (q->isSourceIndexExpanded(srcParent) && q->isSourceIndexVisible(srcParent) 1173 && (!q->isSourceIndexExpanded(destParent) || !q->isSourceIndexVisible(destParent))) { 1174 q->endRemoveRows(); 1175 } else if (!q->isSourceIndexExpanded(srcParent) && q->isSourceIndexExpanded(destParent)) { 1176 q->endInsertRows(); 1177 } 1178 1179 sourceLayoutChanged(); 1180 1181 const QModelIndex index1 = q->mapFromSource(srcParent); 1182 const QModelIndex index2 = q->mapFromSource(destParent); 1183 Q_EMIT q->dataChanged(index1, index1, {KDescendantsProxyModel::ExpandableRole}); 1184 if (index1 != index2) { 1185 Q_EMIT q->dataChanged(index2, index2, {KDescendantsProxyModel::ExpandableRole}); 1186 if (!q->sourceModel()->hasChildren(destParent)) { 1187 Q_EMIT q->dataChanged(index2, index2, {KDescendantsProxyModel::ExpandableRole}); 1188 } 1189 } 1190 const QModelIndex lastIndex = q->mapFromSource(q->sourceModel()->index(q->sourceModel()->rowCount(srcParent) - 1, 0, srcParent)); 1191 Q_EMIT q->dataChanged(lastIndex, lastIndex, {KDescendantsProxyModel::ExpandableRole}); 1192 1193 if (srcStart > 0) { 1194 notifyhasSiblings(q->sourceModel()->index(srcStart - 1, 0, srcParent)); 1195 } 1196 if (destStart > 0) { 1197 notifyhasSiblings(q->sourceModel()->index(destStart - 1, 0, destParent)); 1198 } 1199 } 1200 1201 void KDescendantsProxyModelPrivate::sourceModelAboutToBeReset() 1202 { 1203 Q_Q(KDescendantsProxyModel); 1204 q->beginResetModel(); 1205 } 1206 1207 void KDescendantsProxyModelPrivate::sourceModelReset() 1208 { 1209 Q_Q(KDescendantsProxyModel); 1210 resetInternalData(); 1211 if (q->sourceModel()->hasChildren() && q->sourceModel()->rowCount() > 0) { 1212 m_pendingParents.append(QModelIndex()); 1213 scheduleProcessPendingParents(); 1214 } 1215 q->endResetModel(); 1216 } 1217 1218 void KDescendantsProxyModelPrivate::sourceLayoutAboutToBeChanged() 1219 { 1220 Q_Q(KDescendantsProxyModel); 1221 1222 if (m_ignoreNextLayoutChanged) { 1223 m_ignoreNextLayoutChanged = false; 1224 return; 1225 } 1226 1227 if (m_mapping.isEmpty()) { 1228 return; 1229 } 1230 1231 Q_EMIT q->layoutAboutToBeChanged(); 1232 1233 QPersistentModelIndex srcPersistentIndex; 1234 const auto lst = q->persistentIndexList(); 1235 for (const QModelIndex &proxyPersistentIndex : lst) { 1236 m_proxyIndexes << proxyPersistentIndex; 1237 Q_ASSERT(proxyPersistentIndex.isValid()); 1238 srcPersistentIndex = q->mapToSource(proxyPersistentIndex); 1239 Q_ASSERT(srcPersistentIndex.isValid()); 1240 m_layoutChangePersistentIndexes << srcPersistentIndex; 1241 } 1242 } 1243 1244 void KDescendantsProxyModelPrivate::sourceLayoutChanged() 1245 { 1246 Q_Q(KDescendantsProxyModel); 1247 1248 if (m_ignoreNextLayoutAboutToBeChanged) { 1249 m_ignoreNextLayoutAboutToBeChanged = false; 1250 return; 1251 } 1252 1253 if (m_mapping.isEmpty()) { 1254 return; 1255 } 1256 1257 m_rowCount = 0; 1258 1259 synchronousMappingRefresh(); 1260 1261 for (int i = 0; i < m_proxyIndexes.size(); ++i) { 1262 q->changePersistentIndex(m_proxyIndexes.at(i), q->mapFromSource(m_layoutChangePersistentIndexes.at(i))); 1263 } 1264 1265 m_layoutChangePersistentIndexes.clear(); 1266 m_proxyIndexes.clear(); 1267 1268 Q_EMIT q->layoutChanged(); 1269 } 1270 1271 void KDescendantsProxyModelPrivate::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) 1272 { 1273 Q_Q(KDescendantsProxyModel); 1274 // It is actually possible in a real world scenario that the source model emits dataChanged 1275 // with invalid indexes when the source model is a QSortFilterProxyModel 1276 // because QSortFilterProxyModel doesn't check for mapped index validity when its 1277 // source model emitted dataChanged on a column QSortFilterProxyModel doesn't accept. 1278 // See https://bugreports.qt.io/browse/QTBUG-86850 1279 if (!topLeft.isValid() || !bottomRight.isValid()) { 1280 return; 1281 } 1282 Q_ASSERT(topLeft.model() == q->sourceModel()); 1283 Q_ASSERT(bottomRight.model() == q->sourceModel()); 1284 1285 if (!q->isSourceIndexExpanded(topLeft.parent()) || !q->isSourceIndexVisible(topLeft.parent())) { 1286 return; 1287 } 1288 1289 const int topRow = topLeft.row(); 1290 const int bottomRow = bottomRight.row(); 1291 1292 for (int i = topRow; i <= bottomRow; ++i) { 1293 const QModelIndex sourceTopLeft = q->sourceModel()->index(i, topLeft.column(), topLeft.parent()); 1294 1295 Q_ASSERT(sourceTopLeft.isValid()); 1296 const QModelIndex proxyTopLeft = q->mapFromSource(sourceTopLeft); 1297 // TODO. If an index does not have any descendants, then we can emit in blocks of rows. 1298 // As it is we emit once for each row. 1299 const QModelIndex sourceBottomRight = q->sourceModel()->index(i, bottomRight.column(), bottomRight.parent()); 1300 const QModelIndex proxyBottomRight = q->mapFromSource(sourceBottomRight); 1301 Q_ASSERT(proxyTopLeft.isValid()); 1302 Q_ASSERT(proxyBottomRight.isValid()); 1303 Q_EMIT q->dataChanged(proxyTopLeft, proxyBottomRight); 1304 } 1305 } 1306 1307 void KDescendantsProxyModelPrivate::sourceModelDestroyed() 1308 { 1309 resetInternalData(); 1310 } 1311 1312 QMimeData *KDescendantsProxyModel::mimeData(const QModelIndexList &indexes) const 1313 { 1314 if (!sourceModel()) { 1315 return QAbstractProxyModel::mimeData(indexes); 1316 } 1317 Q_ASSERT(sourceModel()); 1318 QModelIndexList sourceIndexes; 1319 for (const QModelIndex &index : indexes) { 1320 sourceIndexes << mapToSource(index); 1321 } 1322 return sourceModel()->mimeData(sourceIndexes); 1323 } 1324 1325 QStringList KDescendantsProxyModel::mimeTypes() const 1326 { 1327 if (!sourceModel()) { 1328 return QAbstractProxyModel::mimeTypes(); 1329 } 1330 Q_ASSERT(sourceModel()); 1331 return sourceModel()->mimeTypes(); 1332 } 1333 1334 Qt::DropActions KDescendantsProxyModel::supportedDropActions() const 1335 { 1336 if (!sourceModel()) { 1337 return QAbstractProxyModel::supportedDropActions(); 1338 } 1339 return sourceModel()->supportedDropActions(); 1340 } 1341 1342 #include "moc_kdescendantsproxymodel.cpp"