File indexing completed on 2023-09-24 04:09:50
0001 /* 0002 SPDX-FileCopyrightText: 2009 Stephen Kelly <steveire@gmail.com> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "kreparentingproxymodel.h" 0008 #include <QDebug> 0009 #include <QVector> 0010 0011 #include <algorithm> 0012 #include <functional> 0013 0014 class KReparentingProxyModelPrivate 0015 { 0016 KReparentingProxyModelPrivate(KReparentingProxyModel *proxyModel) 0017 : m_nextId(0) 0018 , q_ptr(proxyModel) 0019 { 0020 } 0021 0022 qint64 newId() const 0023 { 0024 return m_nextId++; 0025 } 0026 0027 enum MapStrategy { 0028 MapDescendants, 0029 MapChildrenOnly, 0030 }; 0031 0032 /** 0033 Creates mappings of indexes in the source model between @p start 0034 and @p end which should be represented in the proxy model as descendants 0035 of @p parent. 0036 */ 0037 QHash<QModelIndex, QModelIndexList> recreateMappings(const QModelIndex &parent, int start, int end = -1, int strategy = MapChildrenOnly) const; 0038 0039 /** 0040 Merges all indexes from @p mappings which are descendants of @p parent into the model. 0041 Returns the remaining mappings. 0042 0043 Note that this changes the internal model structure and must only be called between begin/end insert/remove/move/reset calls. 0044 */ 0045 QHash<QModelIndex, QModelIndexList> mergeDescendants(QHash<QModelIndex, QModelIndexList> mappings, const QModelIndex &parent, int start); 0046 0047 /** 0048 Verifies that the indexes below @p parent between @p start and rowCount(parent) 0049 are in the correct positions in the proxy model. Repositions them if not. 0050 */ 0051 void verifyStructure(const QModelIndex &parent, int start); 0052 0053 /** 0054 Returns the index vertically below index in the model @p model. 0055 If @p model is 0, the sourceModel is used 0056 Returns an invalid index if there is no index below @p index. 0057 */ 0058 QModelIndex getIndexBelow(const QModelIndex &index, QAbstractItemModel *model = nullptr) const; 0059 0060 /** 0061 Returns the last descendant of @p index or itself if it has no children 0062 */ 0063 QModelIndex getLastDescendant(const QModelIndex &index) const; 0064 0065 bool isDescendantInModel(const QModelIndex &ancestor, const QModelIndex &descendant) const; 0066 0067 /** 0068 Returns the ancestors of @p descendant that are already in the proxy model. 0069 0070 Note that @p descendant does not have to be in the proxy yet, and it is not part of the 0071 result list. 0072 */ 0073 QVector<QModelIndex> getExistingAncestors(const QModelIndex &descendant) const; 0074 0075 void sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end); 0076 void sourceRowsInserted(const QModelIndex &parent, int start, int end); 0077 void sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end); 0078 void sourceRowsRemoved(const QModelIndex &parent, int start, int end); 0079 void sourceRowsAboutToBeMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destParent, int destRow); 0080 void sourceRowsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destParent, int destRow); 0081 void sourceModelAboutToBeReset(); 0082 void endResetProxy(); 0083 void sourceModelReset(); 0084 void sourceLayoutAboutToBeChanged(); 0085 void sourceLayoutChanged(); 0086 void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); 0087 0088 mutable QHash<qint64, QPersistentModelIndex> m_parents; 0089 mutable QHash<QPersistentModelIndex, QList<QPersistentModelIndex>> m_childIndexes; 0090 0091 struct PendingInsertion { 0092 PendingInsertion() 0093 : parentId(-1) 0094 , start(-1) 0095 , end(-1) 0096 { 0097 } 0098 0099 PendingInsertion(const QModelIndex &_index, int _start, int _end) 0100 : index(_index) 0101 , start(_start) 0102 , end(_end) 0103 { 0104 } 0105 0106 QPersistentModelIndex index; 0107 QModelIndex sourceIndex; 0108 qint64 parentId; 0109 int start; 0110 int end; 0111 }; 0112 0113 struct PendingRemoval : PendingInsertion { 0114 int numTrailing; 0115 }; 0116 // Needed between the beginRemoveRows and endRemoveRows signals. 0117 mutable QHash<qint64, QPersistentModelIndex> m_pendingRemovalParents; 0118 mutable QHash<QPersistentModelIndex, QList<QPersistentModelIndex>> m_pendingRemovalChildIndexes; 0119 0120 QHash<QModelIndex, QModelIndexList> insertTree(QHash<QModelIndex, QModelIndexList> mappings, const QModelIndex &parent); 0121 0122 void handleInsertion(const PendingInsertion &pendingInsertion); 0123 0124 void handleRemoval(const PendingRemoval &pendingRemoval); 0125 0126 mutable QHash<QModelIndex, PendingInsertion> m_pendingInsertions; 0127 mutable QVector<PendingRemoval> m_pendingRemovals; 0128 0129 mutable qint64 m_nextId; 0130 0131 Q_DECLARE_PUBLIC(KReparentingProxyModel) 0132 KReparentingProxyModel *q_ptr; 0133 0134 QList<QPersistentModelIndex> m_layoutChangePersistentIndexes; 0135 QModelIndexList m_proxyIndexes; 0136 0137 void emitDataChangedSignals(const QModelIndex &parent, int maxChanged); 0138 0139 /** 0140 Given @p parent in the proxy model, return the last index lying between @p start and @p end 0141 which is also a descendant of @p parent. 0142 */ 0143 QModelIndex findLastInParent(QModelIndex parent, int start, int end); 0144 0145 /** 0146 Removes @P idx (which is a source model index) and its children from the model data structures. 0147 */ 0148 void removeTree(const QPersistentModelIndex &idx, int start = 0, int end = -1); 0149 0150 int pendingRemovalRowCount(const QModelIndex &sourceIndex) const; 0151 }; 0152 0153 class LessThan 0154 { 0155 const KReparentingProxyModel *m_model; 0156 0157 public: 0158 LessThan(const KReparentingProxyModel *model) 0159 : m_model(model) 0160 { 0161 } 0162 bool operator()(const QModelIndex &ancestor, const QModelIndex &descendant) 0163 { 0164 return m_model->isDescendantOf(ancestor, descendant); 0165 } 0166 }; 0167 0168 QModelIndex KReparentingProxyModelPrivate::getIndexBelow(const QModelIndex &index, QAbstractItemModel *model) const 0169 { 0170 Q_Q(const KReparentingProxyModel); 0171 0172 // qDebug() << index.data() << index; 0173 0174 if (!model) { 0175 model = q->sourceModel(); 0176 } 0177 0178 if (model->hasChildren(index)) { 0179 return model->index(0, 0, index); 0180 } 0181 0182 QModelIndex sibling = index.sibling(index.row() + 1, index.column()); 0183 if (sibling.isValid()) { 0184 return sibling; 0185 } 0186 0187 QModelIndex parent = index.parent(); 0188 0189 if (!parent.isValid()) { 0190 return QModelIndex(); 0191 } 0192 0193 int affectedRow = index.row(); 0194 const int column = 0; 0195 0196 while (parent.isValid()) { 0197 // qDebug() << "parent" << parent.data() << model->rowCount(parent) << affectedRow; 0198 if (affectedRow < model->rowCount(parent) - 1) { 0199 return model->index(affectedRow + 1, column, parent); 0200 } 0201 0202 affectedRow = parent.row(); 0203 parent = parent.parent(); 0204 } 0205 0206 if (model->rowCount(parent) >= affectedRow) { 0207 return model->index(affectedRow + 1, column, parent); 0208 } 0209 0210 return QModelIndex(); 0211 } 0212 0213 QModelIndex KReparentingProxyModelPrivate::getLastDescendant(const QModelIndex &index) const 0214 { 0215 Q_Q(const KReparentingProxyModel); 0216 0217 QModelIndex proxyIndex = q->mapFromSource(index); 0218 0219 while (q->hasChildren(proxyIndex)) { 0220 proxyIndex = q->index(q->rowCount(proxyIndex), proxyIndex.column(), proxyIndex); 0221 if (!proxyIndex.isValid()) { 0222 break; 0223 } 0224 } 0225 return q->mapToSource(proxyIndex); 0226 } 0227 0228 QVector<QModelIndex> KReparentingProxyModelPrivate::getExistingAncestors(const QModelIndex &descendant) const 0229 { 0230 Q_Q(const KReparentingProxyModel); 0231 0232 QVector<QModelIndex> vector; 0233 if (!descendant.isValid()) { 0234 return vector; 0235 } 0236 0237 QModelIndex parent = q->mapFromSource(descendant).parent(); 0238 QModelIndex sourceParent = q->mapToSource(parent); 0239 if (!sourceParent.isValid()) { 0240 return vector; 0241 } 0242 0243 vector.append(sourceParent); 0244 while (parent.isValid()) { 0245 parent = parent.parent(); 0246 sourceParent = q->mapToSource(parent); 0247 if (!sourceParent.isValid()) { 0248 return vector; 0249 } 0250 vector.prepend(sourceParent); 0251 } 0252 return vector; 0253 } 0254 0255 QHash<QModelIndex, QModelIndexList> KReparentingProxyModelPrivate::recreateMappings(const QModelIndex &ancestor, int start, int end, int strategy) const 0256 { 0257 Q_Q(const KReparentingProxyModel); 0258 const int column = 0; 0259 0260 QHash<QModelIndex, QModelIndexList> mappings; 0261 // Handle listing the root QModelIndex(). 0262 if (!ancestor.isValid() && !q->sourceModel()->hasChildren()) 0263 // Empty model. Nothing to do. 0264 { 0265 return mappings; 0266 } 0267 0268 // A 0269 // - B 0270 // - - C 0271 // - D 0272 // If start refers to D, existing ancestors will contain only A. 0273 // We need to go 'up' to C and get its ancestors in case D is to be made a child of B or C (for example if B and C have just been inserted) 0274 QModelIndex indexAbove; 0275 if (start > 0) { 0276 indexAbove = getLastDescendant(q->sourceModel()->index(start - 1, column, ancestor)); 0277 } else { 0278 indexAbove = ancestor; 0279 } 0280 0281 QVector<QModelIndex> ancestors = getExistingAncestors(indexAbove); 0282 0283 // ancestors.append(indexAbove); 0284 // qDebug() << ancestors; 0285 QModelIndex nextIndex = ancestor; 0286 0287 for (int row = start; (row <= end || end == -1);) { 0288 // A 0289 // - B 0290 // - - C 0291 // - D 0292 // The nextIndex of the invalid QModelIndex is A, 0293 // The nextIndex of A is B, 0294 // The nextIndex of B is C, 0295 // The nextIndex of C is D, 0296 // The nextIndex of D is invalid, 0297 // When the nextIndex is invalid we're finished creating mappings. 0298 if (MapDescendants == strategy) { 0299 nextIndex = getIndexBelow(nextIndex); 0300 } else { 0301 nextIndex = q->sourceModel()->index(row, column, ancestor); 0302 } 0303 0304 if (!nextIndex.isValid()) { 0305 break; 0306 } 0307 0308 const QVector<QModelIndex>::iterator ancestorIt = std::lower_bound(ancestors.begin(), ancestors.end(), nextIndex, LessThan(q)); 0309 0310 ancestors.erase(ancestorIt, ancestors.end()); 0311 0312 QModelIndex parent; 0313 if (ancestorIt != ancestors.begin()) { 0314 parent = *(ancestorIt - 1); 0315 } 0316 0317 ancestors.append(nextIndex); 0318 0319 mappings[parent].append(nextIndex); 0320 } 0321 0322 return mappings; 0323 } 0324 0325 void KReparentingProxyModelPrivate::verifyStructure(const QModelIndex &sourceParent, int sourceStart) 0326 { 0327 Q_Q(KReparentingProxyModel); 0328 0329 // If the start structure is: 0330 0331 // C 0332 // D 0333 // E 0334 0335 // and then A and B are inserted, we may need to move C D and E. Not all of the siblings will 0336 // necessarily be moved to the same destination parent. 0337 // Some example finished scenarios depending on the outcome of isDescendantOf: 0338 0339 // A 0340 // B 0341 // C 0342 // D 0343 // E 0344 0345 // A 0346 // B 0347 // - C 0348 // - D 0349 // - E 0350 0351 // A 0352 // - B 0353 // - C 0354 // - D 0355 // - E 0356 0357 // A 0358 // - B 0359 // - - C 0360 // - D 0361 // E 0362 0363 // Local variable mappings now contains all the information about finished state 0364 // When we locate the first child to be moved, we process it and its siblings 0365 0366 QHash<QModelIndex, QModelIndexList> mappings = recreateMappings(sourceParent, sourceStart, -1); 0367 0368 if (mappings.isEmpty()) { 0369 return; 0370 } 0371 0372 QModelIndex sourceFirstIndex = q->sourceModel()->index(sourceStart, 0, sourceParent); 0373 0374 QModelIndex destinationParent; 0375 QModelIndexList movedIndexes; 0376 0377 QHashIterator<QModelIndex, QModelIndexList> it(mappings); 0378 while (it.hasNext()) { 0379 it.next(); 0380 // qDebug() << it.key() << it.key().data() << it.value(); 0381 if (it.value().at(0) == sourceFirstIndex) { 0382 destinationParent = it.key(); 0383 movedIndexes = it.value(); 0384 break; 0385 } 0386 } 0387 0388 Q_FOREVER { 0389 if (destinationParent == sourceParent) 0390 // No indexes moved 0391 { 0392 return; 0393 } 0394 0395 Q_ASSERT(destinationParent.isValid()); 0396 Q_ASSERT(!movedIndexes.isEmpty()); 0397 0398 // It's only possible for things to move right, and even that's only an option 0399 // for children of parent, but not their descendants. ie, children of C D and E will not need to be reparented. 0400 // They are already in the correct positions. 0401 0402 QList<QPersistentModelIndex> &existingSourceIndexes = m_childIndexes[sourceParent]; 0403 QList<QPersistentModelIndex> existingDestinationIndexes = m_childIndexes[destinationParent]; 0404 0405 QModelIndex proxySourceParent = q->mapFromSource(sourceParent); 0406 QModelIndex proxyDestinationParent = q->mapFromSource(destinationParent); 0407 0408 // That is, start position of indexes to be moved from the source parent. 0409 int proxySourceStart = m_childIndexes.value(sourceParent).indexOf(movedIndexes.at(0)); 0410 int proxySourceEnd = proxySourceStart + movedIndexes.size() - 1; 0411 0412 // The moved indexes are appended to the destinationParent. Nothing else is possible. 0413 // If they were to be inserted in the middle somewhere, they would already be there. 0414 0415 int destinationRow = existingDestinationIndexes.size(); 0416 0417 bool allowMove = q->beginMoveRows(proxySourceParent, proxySourceStart, proxySourceEnd, proxyDestinationParent, destinationRow); 0418 Q_ASSERT(allowMove); 0419 0420 for (int row = proxySourceEnd; row >= proxySourceStart; --row) { 0421 existingSourceIndexes.removeAt(row); 0422 } 0423 0424 QHash<QModelIndex, QModelIndexList> mapping; 0425 mapping.insert(destinationParent, movedIndexes); 0426 mergeDescendants(mapping, destinationParent, existingDestinationIndexes.size()); 0427 0428 q->endMoveRows(); 0429 0430 if (!mappings.contains(q->mapToSource(proxyDestinationParent.parent()))) { 0431 break; 0432 } 0433 0434 destinationParent = q->mapToSource(proxyDestinationParent.parent()); 0435 movedIndexes = mappings.value(destinationParent); 0436 } 0437 } 0438 0439 KReparentingProxyModel::KReparentingProxyModel(QObject *parent) 0440 : QAbstractProxyModel(parent) 0441 , d_ptr(new KReparentingProxyModelPrivate(this)) 0442 { 0443 } 0444 0445 KReparentingProxyModel::~KReparentingProxyModel() 0446 { 0447 delete d_ptr; 0448 } 0449 0450 bool KReparentingProxyModelPrivate::isDescendantInModel(const QModelIndex &ancestor, const QModelIndex &descendant) const 0451 { 0452 // qDebug() << ancestor.data() << descendant.data(); 0453 0454 // if (!ancestor.isValid()) 0455 // return true; 0456 0457 QModelIndex _ancestor = descendant.parent(); 0458 while (_ancestor.isValid()) { 0459 if (_ancestor == ancestor) { 0460 return true; 0461 } 0462 _ancestor = _ancestor.parent(); 0463 } 0464 return (!ancestor.isValid() && descendant.isValid()); 0465 } 0466 0467 bool KReparentingProxyModel::isDescendantOf(const QModelIndex &ancestor, const QModelIndex &descendant) const 0468 { 0469 Q_D(const KReparentingProxyModel); 0470 return d->isDescendantInModel(ancestor, descendant); 0471 // return (!ancestor.isValid() && descendant.isValid()); 0472 } 0473 0474 QModelIndex KReparentingProxyModel::mapFromSource(const QModelIndex &sourceIndex) const 0475 { 0476 Q_D(const KReparentingProxyModel); 0477 if (!sourceIndex.isValid()) { 0478 return QModelIndex(); 0479 } 0480 0481 QModelIndex sourceIndexFirstColumn = sourceIndex.sibling(sourceIndex.row(), 0); 0482 0483 QHash<QPersistentModelIndex, QList<QPersistentModelIndex>>::const_iterator it; 0484 const QHash<QPersistentModelIndex, QList<QPersistentModelIndex>>::const_iterator begin = d->m_childIndexes.constBegin(); 0485 const QHash<QPersistentModelIndex, QList<QPersistentModelIndex>>::const_iterator end = d->m_childIndexes.constEnd(); 0486 0487 for (it = begin; it != end; ++it) { 0488 QList<QPersistentModelIndex> list = it.value(); 0489 if (list.contains(sourceIndexFirstColumn)) { 0490 QModelIndex sourceParent = it.key(); 0491 int row = list.indexOf(sourceIndexFirstColumn); 0492 0493 // There must have been a mapping made for it. 0494 Q_ASSERT(d->m_parents.values().contains(sourceParent)); 0495 0496 qint64 id = d->m_parents.key(sourceParent); 0497 0498 // id refers to the parent. 0499 return createIndex(row, sourceIndex.column(), reinterpret_cast<void *>(id)); 0500 } 0501 } 0502 return QModelIndex(); 0503 } 0504 0505 QModelIndex KReparentingProxyModel::mapToSource(const QModelIndex &proxyIndex) const 0506 { 0507 Q_D(const KReparentingProxyModel); 0508 0509 // qDebug() << "MMMMMM" << proxyIndex; 0510 0511 if (!proxyIndex.isValid()) { 0512 return QModelIndex(); 0513 } 0514 0515 qint64 id = reinterpret_cast<qint64>(proxyIndex.internalPointer()); 0516 0517 // if (!d->m_parents.contains(id)) 0518 // qDebug() << d->m_parents << id; 0519 0520 QModelIndex sourceParent; 0521 if (d->m_pendingRemovalParents.contains(id)) { 0522 // qDebug() << "pending"; 0523 sourceParent = d->m_pendingRemovalParents.value(id); 0524 } else { 0525 Q_ASSERT(d->m_parents.contains(id)); 0526 sourceParent = d->m_parents.value(id); 0527 } 0528 0529 // qDebug() << sourceParent << sourceParent.data(); 0530 0531 QModelIndex sourceIndexFirstColumn; 0532 if (d->m_pendingRemovalChildIndexes.contains(sourceParent)) { 0533 // qDebug() << "#############"; 0534 0535 for (const KReparentingProxyModelPrivate::PendingRemoval &pendingRemoval : std::as_const(d->m_pendingRemovals)) { 0536 // qDebug() << "In" << pendingRemoval.index << pendingRemoval.sourceIndex << sourceParent; 0537 if (pendingRemoval.sourceIndex == sourceParent) { 0538 // qDebug() << "Out" << pendingRemoval.sourceIndex << sourceParent; 0539 int proxyRow = proxyIndex.row(); 0540 int row = proxyRow - pendingRemoval.start; 0541 0542 // qDebug() << d->m_pendingRemovalChildIndexes.value(sourceParent) << proxyRow << row << pendingRemoval.end; 0543 0544 if (proxyRow > pendingRemoval.end) { 0545 Q_ASSERT(d->m_childIndexes.contains(sourceParent)); 0546 row = proxyRow - (pendingRemoval.end - pendingRemoval.start + 1); 0547 // qDebug() << "new row" << row; 0548 sourceIndexFirstColumn = d->m_childIndexes.value(sourceParent).at(row); 0549 } else { 0550 sourceIndexFirstColumn = d->m_pendingRemovalChildIndexes.value(sourceParent).at(row); 0551 } 0552 break; 0553 } 0554 } 0555 } else { 0556 Q_ASSERT(d->m_childIndexes.contains(sourceParent)); 0557 sourceIndexFirstColumn = d->m_childIndexes.value(sourceParent).at(proxyIndex.row()); 0558 } 0559 0560 Q_ASSERT(sourceIndexFirstColumn.isValid()); 0561 0562 return sourceIndexFirstColumn.sibling(sourceIndexFirstColumn.row(), proxyIndex.column()); 0563 } 0564 0565 int KReparentingProxyModel::columnCount(const QModelIndex &parent) const 0566 { 0567 Q_D(const KReparentingProxyModel); 0568 0569 if (!sourceModel()) { 0570 return 0; 0571 } 0572 0573 if (!parent.isValid()) { 0574 return sourceModel()->columnCount(); 0575 } 0576 0577 if (parent.column() > 0) { 0578 return 0; 0579 } 0580 QModelIndex sourceIndex = mapToSource(parent); 0581 0582 return (d->m_childIndexes.value(sourceIndex).size() > 0) ? sourceModel()->columnCount() : 0; 0583 } 0584 0585 QVariant KReparentingProxyModel::data(const QModelIndex &proxyIndex, int role) const 0586 { 0587 return QAbstractProxyModel::data(proxyIndex, role); 0588 } 0589 0590 QModelIndex KReparentingProxyModel::index(int row, int column, const QModelIndex &parent) const 0591 { 0592 Q_D(const KReparentingProxyModel); 0593 0594 if (!hasIndex(row, column, parent)) { 0595 return QModelIndex(); 0596 } 0597 0598 QModelIndex sourceParent = mapToSource(parent); 0599 0600 // if (!d->m_pendingRemovals.isEmpty()) 0601 // qDebug() << sourceParent << sourceParent.data(); 0602 0603 // ### This is where we need to have the children of removed indexes stored. 0604 0605 // if (!d->m_parents.values().contains(sourceParent)) 0606 // { 0607 // qDebug() << d->m_pendingRemovalParents.values() << sourceParent << d->m_pendingRemovalParents.values().contains(sourceParent); 0608 // } 0609 0610 qint64 id; 0611 if (d->m_pendingRemovalParents.values().contains(sourceParent)) { 0612 id = d->m_pendingRemovalParents.key(sourceParent); 0613 } else { 0614 // There must have been a mapping made for it. 0615 Q_ASSERT(d->m_parents.values().contains(sourceParent)); 0616 id = d->m_parents.key(sourceParent); 0617 } 0618 return createIndex(row, column, reinterpret_cast<void *>(id)); 0619 } 0620 0621 QModelIndex KReparentingProxyModel::parent(const QModelIndex &child) const 0622 { 0623 Q_D(const KReparentingProxyModel); 0624 0625 if (!child.isValid()) { 0626 return QModelIndex(); 0627 } 0628 0629 QModelIndex sourceIndex = mapToSource(child); 0630 0631 QModelIndex firstColumnChild = sourceIndex; 0632 if (sourceIndex.column() > 0) { 0633 firstColumnChild = sourceIndex.sibling(sourceIndex.row(), 0); 0634 } 0635 0636 QHashIterator<QPersistentModelIndex, QList<QPersistentModelIndex>> itPending(d->m_pendingRemovalChildIndexes); 0637 0638 while (itPending.hasNext()) { 0639 itPending.next(); 0640 0641 if (itPending.value().contains(firstColumnChild)) { 0642 return mapFromSource(itPending.key()); 0643 } 0644 } 0645 0646 QHashIterator<QPersistentModelIndex, QList<QPersistentModelIndex>> it(d->m_childIndexes); 0647 0648 while (it.hasNext()) { 0649 it.next(); 0650 0651 if (it.value().contains(firstColumnChild)) { 0652 return mapFromSource(it.key()); 0653 } 0654 } 0655 return QModelIndex(); 0656 } 0657 0658 int KReparentingProxyModelPrivate::pendingRemovalRowCount(const QModelIndex &sourceIndex) const 0659 { 0660 for (const PendingRemoval &pendingRemoval : std::as_const(m_pendingRemovals)) { 0661 // qDebug() << pendingRemoval.sourceIndex; 0662 if (pendingRemoval.sourceIndex == sourceIndex) { 0663 return pendingRemoval.end - pendingRemoval.start + 1; 0664 } 0665 } 0666 return 0; 0667 } 0668 0669 int KReparentingProxyModel::rowCount(const QModelIndex &parent) const 0670 { 0671 Q_D(const KReparentingProxyModel); 0672 0673 if (parent.column() > 0) { 0674 return 0; 0675 } 0676 0677 QModelIndex sourceIndex = mapToSource(parent); 0678 0679 int size = d->m_childIndexes.value(sourceIndex).size() + d->m_pendingRemovalChildIndexes.value(sourceIndex).size(); 0680 0681 // qDebug() << d->m_pendingRemovalChildIndexes.value(sourceIndex).size(); 0682 0683 // if (!d->m_pendingRemovals.isEmpty()) 0684 // { 0685 // qDebug() << "SIZE" << sourceIndex << sourceIndex.data() << size << d->m_pendingRemovals.size() << d->pendingRemovalRowCount(sourceIndex); 0686 // } 0687 0688 return size; 0689 } 0690 0691 bool KReparentingProxyModel::hasChildren(const QModelIndex &parent) const 0692 { 0693 return rowCount(parent) > 0; 0694 } 0695 0696 void KReparentingProxyModel::setSourceModel(QAbstractItemModel *sourceModel) 0697 { 0698 Q_D(KReparentingProxyModel); 0699 0700 beginResetModel(); 0701 0702 disconnect(sourceModel, SIGNAL(rowsAboutToBeInserted(QModelIndex, int, int)), this, SLOT(sourceRowsAboutToBeInserted(QModelIndex, int, int))); 0703 disconnect(sourceModel, SIGNAL(rowsInserted(QModelIndex, int, int)), this, SLOT(sourceRowsInserted(QModelIndex, int, int))); 0704 disconnect(sourceModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex, int, int)), this, SLOT(sourceRowsAboutToBeRemoved(QModelIndex, int, int))); 0705 disconnect(sourceModel, SIGNAL(rowsRemoved(QModelIndex, int, int)), this, SLOT(sourceRowsRemoved(QModelIndex, int, int))); 0706 disconnect(sourceModel, 0707 SIGNAL(rowsAboutToBeMoved(QModelIndex, int, int, QModelIndex, int)), 0708 this, 0709 SLOT(sourceRowsAboutToBeMoved(QModelIndex, int, int, QModelIndex, int))); 0710 disconnect(sourceModel, SIGNAL(rowsMoved(QModelIndex, int, int, QModelIndex, int)), this, SLOT(sourceRowsMoved(QModelIndex, int, int, QModelIndex, int))); 0711 disconnect(sourceModel, SIGNAL(modelAboutToBeReset()), this, SLOT(sourceModelAboutToBeReset())); 0712 disconnect(sourceModel, SIGNAL(modelReset()), this, SLOT(sourceModelReset())); 0713 disconnect(sourceModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(sourceDataChanged(QModelIndex, QModelIndex))); 0714 disconnect(sourceModel, SIGNAL(layoutAboutToBeChanged()), this, SLOT(sourceLayoutAboutToBeChanged())); 0715 disconnect(sourceModel, SIGNAL(layoutChanged()), this, SLOT(sourceLayoutChanged())); 0716 0717 QAbstractProxyModel::setSourceModel(sourceModel); 0718 0719 // qDebug() << "set"; 0720 QHash<QModelIndex, QModelIndexList> mappings = 0721 d->recreateMappings(QModelIndex(), 0, sourceModel->rowCount() - 1, KReparentingProxyModelPrivate::MapDescendants); 0722 // qDebug() << "begin"; 0723 d->mergeDescendants(mappings, QModelIndex(), 0); 0724 0725 connect(sourceModel, SIGNAL(rowsAboutToBeInserted(QModelIndex, int, int)), SLOT(sourceRowsAboutToBeInserted(QModelIndex, int, int))); 0726 connect(sourceModel, SIGNAL(rowsInserted(QModelIndex, int, int)), SLOT(sourceRowsInserted(QModelIndex, int, int))); 0727 connect(sourceModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex, int, int)), SLOT(sourceRowsAboutToBeRemoved(QModelIndex, int, int))); 0728 connect(sourceModel, SIGNAL(rowsRemoved(QModelIndex, int, int)), SLOT(sourceRowsRemoved(QModelIndex, int, int))); 0729 connect(sourceModel, 0730 SIGNAL(rowsAboutToBeMoved(QModelIndex, int, int, QModelIndex, int)), 0731 SLOT(sourceRowsAboutToBeMoved(QModelIndex, int, int, QModelIndex, int))); 0732 connect(sourceModel, SIGNAL(rowsMoved(QModelIndex, int, int, QModelIndex, int)), SLOT(sourceRowsMoved(QModelIndex, int, int, QModelIndex, int))); 0733 connect(sourceModel, SIGNAL(modelAboutToBeReset()), SLOT(sourceModelAboutToBeReset())); 0734 connect(sourceModel, SIGNAL(modelReset()), SLOT(sourceModelReset())); 0735 connect(sourceModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), SLOT(sourceDataChanged(QModelIndex, QModelIndex))); 0736 connect(sourceModel, SIGNAL(layoutAboutToBeChanged()), SLOT(sourceLayoutAboutToBeChanged())); 0737 connect(sourceModel, SIGNAL(layoutChanged()), SLOT(sourceLayoutChanged())); 0738 0739 endResetModel(); 0740 } 0741 0742 void KReparentingProxyModelPrivate::sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end) 0743 { 0744 Q_UNUSED(parent); 0745 Q_UNUSED(start); 0746 Q_UNUSED(end); 0747 0748 Q_Q(KReparentingProxyModel); 0749 return q->beginResetModel(); 0750 #if 0 0751 // We can't figure out the structure until the indexes are in the model. 0752 // Store the signal until the new rows are actually there in sourceRowsInserted. 0753 PendingInsertion pendingInsertion(parent, start, end); 0754 m_pendingInsertions.insert(parent, pendingInsertion); 0755 #endif 0756 } 0757 0758 QHash<QModelIndex, QModelIndexList> 0759 KReparentingProxyModelPrivate::mergeDescendants(QHash<QModelIndex, QModelIndexList> mappings, const QModelIndex &parent, int start) 0760 { 0761 const QModelIndexList childIndexes = mappings.take(parent); 0762 // qDebug() << childIndexes; 0763 if (!childIndexes.isEmpty()) { 0764 if (!m_parents.values().contains(parent)) { 0765 m_parents.insert(newId(), QPersistentModelIndex(parent)); 0766 } 0767 } 0768 int row = start; 0769 for (const QModelIndex &idx : childIndexes) { 0770 m_childIndexes[parent].insert(row++, QPersistentModelIndex(idx)); 0771 mappings = mergeDescendants(mappings, idx, 0); 0772 } 0773 return mappings; 0774 } 0775 0776 QHash<QModelIndex, QModelIndexList> KReparentingProxyModelPrivate::insertTree(QHash<QModelIndex, QModelIndexList>, const QModelIndex &) 0777 { 0778 return QHash<QModelIndex, QModelIndexList>(); 0779 } 0780 0781 void KReparentingProxyModelPrivate::handleInsertion(const PendingInsertion &pendingInsertion) 0782 { 0783 Q_Q(KReparentingProxyModel); 0784 QModelIndex parent = pendingInsertion.index; 0785 int start = pendingInsertion.start; 0786 int end = pendingInsertion.end; 0787 0788 // qDebug() << parent << parent.data() << start << end; 0789 0790 // for (int i = start; i < end; ++i) 0791 // { 0792 // QModelIndex idx = q->sourceModel()->index(i, 0, parent); 0793 // qDebug() << idx << idx.data(); 0794 // } 0795 0796 QHash<QModelIndex, QModelIndexList> newItemMappings = recreateMappings(parent, start, end, KReparentingProxyModelPrivate::MapDescendants); 0797 0798 // iterate over keys. if key in keys iterate up. This gives list of top level parents. 0799 // Pick the one whose parent is @p parent. Insert it. Look up until find the parent of another one and insert that. 0800 // If one of the parents is invalid it is necessarily the last one to be processed (if there are more to process, they'll be children of it) 0801 // That case should work too. 0802 0803 // qDebug() << "new item mappings" << newItemMappings; 0804 0805 const int column = 0; 0806 0807 // qDebug() << m_childIndexes.contains(parent); 0808 0809 if (newItemMappings.contains(parent)) { 0810 QModelIndexList newItemList = newItemMappings.value(parent); 0811 // qDebug() << "newItemList" << newItemList; 0812 int proxyStart = 0; 0813 0814 // A single insertion in the source model might be multiple insertions in the proxy model. 0815 Q_FOREVER { 0816 if (newItemList.isEmpty()) { 0817 if (!newItemMappings.contains(parent.parent())) { 0818 break; 0819 } 0820 0821 newItemList = newItemMappings.value(parent.parent()); 0822 continue; 0823 } 0824 0825 proxyStart = 0; 0826 0827 QModelIndex proxyParent = q->mapFromSource(parent); 0828 if (start > 0) { 0829 QModelIndex lastDesc = q->mapFromSource(getLastDescendant(q->sourceModel()->index(start - 1, column, parent))); 0830 0831 while (lastDesc.parent() != proxyParent) { 0832 lastDesc = lastDesc.parent(); 0833 } 0834 proxyStart = lastDesc.row() + 1; 0835 } 0836 0837 q->beginInsertRows(proxyParent, proxyStart, proxyStart + newItemList.size() - 1); 0838 0839 newItemMappings = mergeDescendants(newItemMappings, parent, proxyStart); 0840 0841 q->endInsertRows(); 0842 0843 if (!newItemMappings.contains(parent.parent())) { 0844 break; 0845 } 0846 0847 newItemList = newItemMappings.value(parent.parent()); 0848 } 0849 } 0850 0851 // // The rest are not descendants of pendingInsertion.index in the proxy model, but are elsewhere. 0852 // Q_FOREACH(const QModelIndex &parent, newItemMappings.keys()) 0853 // { 0854 // 0855 // } 0856 0857 return; 0858 } 0859 0860 void KReparentingProxyModelPrivate::sourceRowsInserted(const QModelIndex &parent, int, int end) 0861 { 0862 Q_UNUSED(parent); 0863 Q_UNUSED(end); 0864 0865 return endResetProxy(); 0866 0867 #if 0 0868 Q_Q(KReparentingProxyModel); 0869 if (m_pendingInsertions.contains(parent)) { 0870 PendingInsertion pendingInsertion = m_pendingInsertions.value(parent); 0871 handleInsertion(pendingInsertion); 0872 0873 if (q->sourceModel()->rowCount(parent) <= (end + 1)) { 0874 return; 0875 } 0876 0877 // The presence of new rows might affect the structure of indexes below. 0878 verifyStructure(parent, end + 1); 0879 } 0880 #endif 0881 } 0882 0883 void KReparentingProxyModelPrivate::removeTree(const QPersistentModelIndex &idxToRemove, int start, int end) 0884 { 0885 if (!m_childIndexes.contains(idxToRemove)) { 0886 return; 0887 } 0888 0889 // qDebug() << "idxToRemove" << idxToRemove << start << end; 0890 0891 QList<QPersistentModelIndex> &toRemove = m_childIndexes[idxToRemove]; 0892 // qDebug() << toRemove << toRemove.size(); 0893 0894 // QList<int> intList; 0895 // intList << 1 << 2 << 3 << 4 << 5; 0896 // 0897 // QList<int>::iterator intit = intList.begin(); 0898 // QList<int>::iterator intendIt = intList.end(); 0899 // 0900 // if (end == 0) 0901 // intendIt = intit + 1; 0902 // 0903 // if (end > 0) 0904 // { 0905 // intendIt = intit + (end - start + 1) + 1; 0906 // qDebug() << "intend" << *intendIt; 0907 // } 0908 // intit += start; 0909 // 0910 // while (intit != intendIt) 0911 // { 0912 // int i = *intit; 0913 // qDebug() << i; 0914 // intit = intList.erase(intit); 0915 // } 0916 0917 QList<QPersistentModelIndex>::iterator it = toRemove.begin(); 0918 QList<QPersistentModelIndex>::iterator endIt = toRemove.end(); 0919 0920 if (end == 0) { 0921 endIt = it + 1; 0922 } 0923 0924 if (end > 0) { 0925 endIt = it + (end - start + 1) + 1; 0926 } 0927 it += start; 0928 0929 int i = start; 0930 while (it != endIt) { 0931 QPersistentModelIndex idx = *it; 0932 // qDebug() << "removing" << idx << idx.data(); 0933 0934 if (m_parents.values().contains(idx)) { 0935 qint64 key = m_parents.key(idx); 0936 QPersistentModelIndex value = m_parents.take(key); 0937 m_pendingRemovalParents.insert(key, value); 0938 // qDebug() << "take from parent" << value; 0939 } 0940 removeTree(idx); 0941 0942 ++i; 0943 0944 m_pendingRemovalChildIndexes[idxToRemove].append(idx); 0945 // qDebug() << idxToRemove << idxToRemove.data() << idx << idx.data(); 0946 0947 it = toRemove.erase(it); 0948 // qDebug() << (it == endIt); 0949 // if (i > end) 0950 // break; 0951 0952 // if (it == toRemove.end()) 0953 // break; 0954 } 0955 0956 // qDebug() << "toRemove" << toRemove; 0957 0958 // for(int i = start; (i <= end || (end == -1 && toRemove.size() > i)); ) 0959 // { 0960 // qDebug() << i; 0961 // QPersistentModelIndex idx = toRemove.takeAt(i); 0962 // --end; 0963 // 0964 // qDebug() << "removing" << idx.data(); 0965 // 0966 // if (m_parents.values().contains(idx)) 0967 // { 0968 // QPersistentModelIndex bah = m_parents.take(m_parents.key(idx)); 0969 // // qDebug() << "take from parent" << bah; 0970 // } 0971 // removeTree(idx); 0972 // } 0973 } 0974 0975 void KReparentingProxyModelPrivate::sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) 0976 { 0977 Q_UNUSED(parent); 0978 Q_UNUSED(start); 0979 Q_UNUSED(end); 0980 0981 Q_Q(KReparentingProxyModel); 0982 q->beginResetModel(); 0983 0984 return; 0985 #if 0 0986 // qDebug() << parent << start << end; 0987 0988 // This is really tricky. 0989 // 0990 // We could have something like: 0991 // 0992 // A A 0993 // B - B 0994 // C -> - - C 0995 // D D 0996 // E - E 0997 // 0998 // And have to remove something like B to D. That would mean a remove signal for B, move E to its grandparent, remove D. 0999 1000 // QHashIterator<QPersistentModelIndex, QList< QPersistentModelIndex> > it(m_childIndexes); 1001 // while (it.hasNext()) 1002 // { 1003 // it.next(); 1004 // qDebug() << it.key() << it.key().data(); 1005 // qDebug() << it.value(); 1006 // } 1007 1008 const int column = 0; 1009 1010 QModelIndex firstAffectedIndex = q->mapFromSource(q->sourceModel()->index(start, column, parent)); 1011 QModelIndex lastAffectedIndex = q->mapFromSource(q->sourceModel()->index(end, column, parent)); 1012 1013 // qDebug() << "firstAffectedIndex" << firstAffectedIndex.data(); 1014 // qDebug() << "lastAffectedIndex" << lastAffectedIndex.data(); 1015 1016 QModelIndex proxyParent = firstAffectedIndex.parent(); 1017 1018 Q_ASSERT(firstAffectedIndex.isValid() && lastAffectedIndex.isValid()); 1019 1020 Q_FOREVER { 1021 if (isDescendantInModel(proxyParent, lastAffectedIndex)) 1022 { 1023 // They share a common ancestor. 1024 1025 QModelIndex _parent = lastAffectedIndex.parent(); 1026 QModelIndex lastAffectedAncestor = lastAffectedIndex; 1027 // qDebug() << "last affected ancestor" << lastAffectedAncestor.data(); 1028 while (_parent != proxyParent) { 1029 lastAffectedAncestor = _parent; 1030 _parent = _parent.parent(); 1031 } 1032 1033 if (q->hasChildren(lastAffectedAncestor)) { 1034 QModelIndex next = q->index(0, 0, lastAffectedAncestor); 1035 1036 QModelIndex proxySourceParent = lastAffectedAncestor; 1037 int startRow = next.row(); 1038 int lastRow = q->rowCount(lastAffectedAncestor) - 1; 1039 1040 QList<QPersistentModelIndex> &existingSourceIndexes = m_childIndexes[q->mapToSource(proxySourceParent)]; 1041 QList<QPersistentModelIndex> &existingDestinationIndexes = m_childIndexes[q->mapToSource(proxyParent)]; 1042 1043 int destRow = lastAffectedAncestor.row() + 1; 1044 1045 // qDebug() << "Move from" << lastAffectedAncestor.data() << startRow << lastRow << " To " << proxyParent.data() << destRow; 1046 bool allowMove = q->beginMoveRows(lastAffectedAncestor, startRow, lastRow, proxyParent, destRow); 1047 Q_ASSERT(allowMove); 1048 1049 for (int i = startRow; i <= lastRow; ++i) { 1050 QPersistentModelIndex movingIdx = existingSourceIndexes.takeAt(startRow); 1051 existingDestinationIndexes.insert(destRow + (i - startRow), movingIdx); 1052 } 1053 1054 // TODO: If source was a parent before, it might not be now. 1055 // dest was already a parent. 1056 1057 q->endMoveRows(); 1058 } 1059 PendingRemoval removal; 1060 removal.index = proxyParent; 1061 removal.start = firstAffectedIndex.row(); 1062 removal.end = lastAffectedAncestor.row(); 1063 removal.parentId = proxyParent.internalId(); 1064 removal.sourceIndex = q->mapToSource(proxyParent); 1065 m_pendingRemovals.append(removal); 1066 1067 removeTree(q->mapToSource(proxyParent), removal.start, removal.end); 1068 1069 // qDebug() << "beg rem 1"; 1070 q->beginRemoveRows(proxyParent, removal.start, removal.end); 1071 1072 return; 1073 1074 } else { 1075 QModelIndex next = getIndexBelow(firstAffectedIndex); 1076 1077 proxyParent = next.parent(); 1078 1079 while (isDescendantInModel(proxyParent, next)) 1080 { 1081 next = getIndexBelow(next); 1082 } 1083 QModelIndex _parent = next.parent(); 1084 QModelIndex lastAffectedAncestor = next; 1085 1086 while (_parent != proxyParent) 1087 { 1088 lastAffectedAncestor = _parent; 1089 _parent = _parent.parent(); 1090 } 1091 1092 PendingRemoval removal; 1093 removal.index = proxyParent; 1094 removal.start = firstAffectedIndex.row(); 1095 removal.end = lastAffectedAncestor.row(); 1096 removal.parentId = proxyParent.internalId(); 1097 removal.sourceIndex = q->mapToSource(proxyParent); 1098 m_pendingRemovals.append(removal); 1099 1100 removeTree(q->mapToSource(proxyParent), removal.start, removal.end); 1101 1102 // qDebug() << "beg rem 1"; 1103 q->beginRemoveRows(proxyParent, removal.start, removal.end); 1104 1105 proxyParent = next.parent(); 1106 } 1107 } 1108 1109 // // qDebug() << proxyParent.data() << lastAffectedIndex.parent().data() << proxyParent << lastAffectedIndex.parent(); 1110 // if (proxyParent == lastAffectedIndex.parent()) 1111 // { 1112 // PendingRemoval removal; 1113 // removal.index = proxyParent; 1114 // removal.start = firstAffectedIndex.row(); 1115 // removal.end = lastAffectedIndex.row(); 1116 // removal.parentId = proxyParent.internalId(); 1117 // removal.sourceIndex = q->mapToSource(proxyParent); 1118 // m_pendingRemovals.append(removal); 1119 // 1120 // // Also need to store a removal object for each of the descendants. 1121 // 1122 // removeTree(q->mapToSource(proxyParent), removal.start, removal.end); 1123 // 1124 // // qDebug() << "beg rem 1"; 1125 // q->beginRemoveRows(proxyParent, removal.start, removal.end); 1126 // return; 1127 // } 1128 // 1129 // QModelIndex lastParent = lastAffectedIndex.parent(); 1130 // while (lastParent.parent().isValid()) 1131 // { 1132 // if (lastParent.parent() == proxyParent) 1133 // { 1134 // PendingRemoval removal; 1135 // removal.index = proxyParent; 1136 // removal.start = firstAffectedIndex.row(); 1137 // removal.end = lastParent.row(); 1138 // removal.parentId = proxyParent.internalId(); 1139 // removal.sourceIndex = q->mapToSource(proxyParent); 1140 // m_pendingRemovals.append(removal); 1141 // 1142 // // qDebug() << "beg rem 2"; 1143 // q->beginRemoveRows(proxyParent, removal.start, removal.end); 1144 // return; 1145 // } 1146 // lastParent = lastParent.parent(); 1147 // } 1148 // 1149 // // Several blocks need to be removed from the proxy model. 1150 // // Divide and conquer to find them. 1151 // 1152 // int proxyStart = firstAffectedIndex.row(); 1153 // int proxyEnd = proxyStart + (end - start); 1154 // int processedUntil = start; 1155 // 1156 // while (processedUntil <= end) 1157 // { 1158 // QModelIndex lastInParent = findLastInParent(proxyParent, proxyStart, proxyEnd); 1159 // qDebug() << "lastInParent" << lastInParent; 1160 // 1161 // QModelIndex sourceLast = q->mapToSource(lastInParent); 1162 // processedUntil = sourceLast.row(); 1163 // 1164 // PendingRemoval removal; 1165 // removal.index = proxyParent; 1166 // removal.start = proxyStart; 1167 // removal.end = lastInParent.row(); 1168 // removal.parentId = proxyParent.internalId(); 1169 // removal.sourceIndex = q->mapToSource(proxyParent); 1170 // m_pendingRemovals.append(removal); 1171 // 1172 // qDebug() << "beg rem 3"; 1173 // q->beginRemoveRows(proxyParent, removal.start, removal.end); 1174 // 1175 // QModelIndex proxyIndexBelow = getIndexBelow(lastInParent, q); 1176 // 1177 // if (!proxyIndexBelow.isValid()) 1178 // return; 1179 // 1180 // proxyParent = proxyIndexBelow.parent(); 1181 // proxyStart = proxyIndexBelow.row(); 1182 // } 1183 #endif 1184 } 1185 1186 QModelIndex KReparentingProxyModelPrivate::findLastInParent(QModelIndex parent, int start, int end) 1187 { 1188 Q_Q(KReparentingProxyModel); 1189 1190 const int column = 0; 1191 1192 if (start == end) { 1193 return q->index(start, column, parent); 1194 } 1195 1196 int middle = start + (end - start / 2); 1197 1198 QModelIndex sourceParent = q->mapToSource(parent); 1199 QModelIndex middleIndex = q->mapFromSource(q->sourceModel()->index(middle, column, sourceParent)); 1200 1201 if (middleIndex.parent() == parent) { 1202 return findLastInParent(parent, middle, end); 1203 } else { 1204 return findLastInParent(parent, start + ((middle - start) / 2), middle); 1205 } 1206 } 1207 1208 // qDebug() << affectedIndex << affectedIndex.data() << proxyParent; 1209 // 1210 // QHash<QModelIndex, PendingRemoval> pendingRemovals; 1211 // 1212 // int i = start; 1213 // while (i <= end) 1214 // { 1215 // affectedIndex = affectedIndex.sibling(i, column); 1216 // 1217 // // affectedIndex = getIndexBelow(affectedIndex, q); 1218 // if (!affectedIndex.isValid()) 1219 // break; 1220 // // Q_ASSERT(affectedIndex.isValid()); 1221 // 1222 // if (affectedIndex.parent() != proxyParent) 1223 // { 1224 // // affectedIndex.parent() must be left of proxyParent 1225 // 1226 // PendingRemoval removal; 1227 // removal.index = proxyParent; 1228 // removal.start = start; 1229 // removal.end = i; 1230 // pendingRemovals.insert(proxyParent, removal); 1231 // 1232 // Q_EMIT q->rowsAboutToBeRemoved(proxyParent, start, i); 1233 // proxyParent = affectedIndex.parent(); 1234 // 1235 // end -= (i - start + 1); 1236 // start = affectedIndex.row(); 1237 // i = start; 1238 // } 1239 // 1240 // ++i; 1241 // } 1242 1243 // Move younger siblings out of the way so that the rows can be removed easily 1244 // No. It's easier to use verifyStructure afterward. 1245 1246 // // Removing rows in the source model could require sending the children to their grandparents. 1247 // 1248 // QHash<QModelIndex, QModelIndexList> mappings; 1249 // recreateMappings(parent, start, end); 1250 // 1251 // QHashIterator<QModelIndex, QModelIndexList> it(mappings); 1252 // while (it.hasNext()) 1253 // { 1254 // it.next(); 1255 // QModelIndexList removedList = it.value(); 1256 // PendingRemoval pendingRemoval; 1257 // pendingRemoval.index = it.key(); 1258 // pendingRemoval.start = q->mapFromSource(removedList.at(0)).row(); 1259 // pendingRemoval.end = pendingRemoval.start + removedList.size() - 1; 1260 // m_pendingRemovals.insert(parent, pendingRemoval); 1261 // } 1262 // } 1263 1264 void KReparentingProxyModelPrivate::handleRemoval(const PendingRemoval &pendingRemoval) 1265 { 1266 Q_UNUSED(pendingRemoval) 1267 // Q_Q(KReparentingProxyModel); 1268 // q->beginRemoveRows(pendingRemoval.index, pendingRemoval.start, pendingRemoval.end); 1269 // m_childIndexes.remove(pendingRemoval.index); 1270 // // Remove stuff from m_parents. 1271 // q->endRemoveRows(); 1272 } 1273 1274 void KReparentingProxyModelPrivate::sourceRowsRemoved(const QModelIndex &parent, int, int) 1275 { 1276 return endResetProxy(); 1277 1278 Q_Q(KReparentingProxyModel); 1279 1280 // loop over pending removals and process each one. Then look after the last one 1281 // to move displaced rows to where they should be. 1282 1283 int lastAffectedRow = m_pendingRemovals.last().end; 1284 QModelIndex lastAffectedIndex = m_pendingRemovals.last().index; 1285 1286 QMutableVectorIterator<PendingRemoval> it(m_pendingRemovals); 1287 1288 while (it.hasNext()) { 1289 PendingRemoval removal = it.next(); 1290 m_pendingRemovalChildIndexes.remove(removal.sourceIndex); 1291 m_pendingRemovalParents.remove(parent.internalId()); 1292 it.remove(); 1293 1294 Q_EMIT q->endRemoveRows(); 1295 } 1296 // qDebug() << "Remove done ##########"; 1297 1298 // qDebug() << lastAffectedIndex << lastAffectedIndex.data() << lastAffectedRow; 1299 1300 verifyStructure(lastAffectedIndex, lastAffectedRow - 1); 1301 } 1302 1303 void KReparentingProxyModelPrivate::sourceRowsAboutToBeMoved(const QModelIndex &parent, int start, int end, const QModelIndex &, int) 1304 { 1305 // This could be several individual moves in the proxy model, or it could be no moves at all. 1306 // We can get the top indexes of the moved list and move those. 1307 // because their children won't be moved anywhere different. 1308 1309 // I could look at the indexes between start and end (proxied could be several blocks), and move them to dest. 1310 // Then verify structure. 1311 // This could lead to an illegal move. 1312 // If we have 1313 // 1314 // Source: Proxy: 1315 // A A 1316 // B B 1317 // C - C 1318 // D - D 1319 // E E 1320 // 1321 // then source can legally move B to between C and D, however, implemented naively the proxymodel would attempt an illegal move. 1322 // We must first reparent everything below destRow in the proxy to the parent of parent in this case, then perform the move, then 1323 // verifyStructure. 1324 // 1325 // Moving B C and D to below E would be a legal move in the proxy model. 1326 // 1327 // Children of moved indexes which are not themselves moved must be first sent to their grandparents. 1328 // So if B and C were moved in the source model above to below E, D would first be moved to its grandparent, then B would be moved below E, 1329 // then the structure would need to be verified. 1330 // 1331 // Proxy start state: Intermediate state: Intermediate or final state: Possible alternative final state: 1332 // A A A A 1333 // B B E E 1334 // - C - C D - D 1335 // - D D B B 1336 // E E - C - C 1337 1338 // So, I could iterate from start to end in proxySourceParent and if the depth goes less than parent, emit a block move, then start again. 1339 1340 QHash<QModelIndex, QModelIndexList> newMappings = recreateMappings(parent, start, end); 1341 } 1342 1343 void KReparentingProxyModelPrivate::sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int) 1344 { 1345 } 1346 1347 void KReparentingProxyModelPrivate::sourceLayoutAboutToBeChanged() 1348 { 1349 Q_Q(KReparentingProxyModel); 1350 1351 q->beginResetModel(); 1352 return; 1353 #if 0 1354 1355 Q_EMIT q->layoutAboutToBeChanged(); 1356 1357 Q_FOREACH (QPersistentModelIndex proxyPersistentIndex, q->persistentIndexList()) { 1358 m_proxyIndexes << proxyPersistentIndex; 1359 m_layoutChangePersistentIndexes << QPersistentModelIndex(q->mapToSource(proxyPersistentIndex)); 1360 } 1361 #endif 1362 } 1363 1364 void KReparentingProxyModelPrivate::sourceLayoutChanged() 1365 { 1366 endResetProxy(); 1367 return; 1368 #if 0 1369 Q_Q(KReparentingProxyModel); 1370 1371 for (int i = 0; i < m_proxyIndexes.size(); ++i) { 1372 q->changePersistentIndex(m_proxyIndexes.at(i), q->mapFromSource(m_layoutChangePersistentIndexes.at(i))); 1373 } 1374 1375 m_layoutChangePersistentIndexes.clear(); 1376 m_proxyIndexes.clear(); 1377 1378 Q_EMIT q->layoutChanged(); 1379 #endif 1380 } 1381 1382 void KReparentingProxyModelPrivate::sourceModelAboutToBeReset() 1383 { 1384 Q_Q(KReparentingProxyModel); 1385 q->beginResetModel(); 1386 } 1387 1388 void KReparentingProxyModelPrivate::endResetProxy() 1389 { 1390 Q_Q(KReparentingProxyModel); 1391 1392 m_parents.clear(); 1393 m_childIndexes.clear(); 1394 m_nextId = 0; 1395 m_pendingInsertions.clear(); 1396 m_pendingRemovals.clear(); 1397 m_pendingRemovalChildIndexes.clear(); 1398 m_pendingRemovalParents.clear(); 1399 // qDebug() << q->sourceModel()->rowCount(); 1400 QHash<QModelIndex, QModelIndexList> mappings = 1401 recreateMappings(QModelIndex(), 0, q->sourceModel()->rowCount() - 1, KReparentingProxyModelPrivate::MapDescendants); 1402 qDebug() << mappings; 1403 1404 mergeDescendants(mappings, QModelIndex(), 0); 1405 q->endResetModel(); 1406 } 1407 1408 void KReparentingProxyModelPrivate::sourceModelReset() 1409 { 1410 endResetProxy(); 1411 } 1412 1413 void KReparentingProxyModelPrivate::emitDataChangedSignals(const QModelIndex &startIndex, int maxChanged) 1414 { 1415 Q_Q(KReparentingProxyModel); 1416 1417 QModelIndex proxyParent = startIndex.parent(); 1418 1419 int numChanged = 1; 1420 1421 QModelIndex lastAffectedSibling = startIndex; 1422 QModelIndex proxySibling = getIndexBelow(startIndex, q); 1423 1424 Q_FOREVER { 1425 if (proxySibling.parent() != proxyParent || numChanged >= maxChanged) { 1426 break; 1427 } 1428 1429 numChanged++; 1430 lastAffectedSibling = proxySibling; 1431 1432 proxySibling = getIndexBelow(proxySibling); 1433 } 1434 1435 Q_EMIT q->dataChanged(startIndex, lastAffectedSibling); 1436 if (numChanged < maxChanged) { 1437 emitDataChangedSignals(proxySibling, maxChanged - numChanged); 1438 } 1439 } 1440 1441 void KReparentingProxyModelPrivate::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) 1442 { 1443 Q_UNUSED(topLeft); 1444 Q_UNUSED(bottomRight); 1445 1446 Q_Q(KReparentingProxyModel); 1447 1448 q->beginResetModel(); 1449 endResetProxy(); 1450 return; 1451 #if 0 1452 QModelIndex parent = topLeft.parent(); 1453 const int start = topLeft.row(); 1454 const int end = bottomRight.row(); 1455 const int column = 0; 1456 const int maxChanged = end - start + 1; 1457 1458 // Create mappings to the end because changing data can affect structure of siblings. 1459 verifyStructure(parent, start); 1460 1461 // mapFromSource and emit signals. 1462 1463 QModelIndex proxyStartIndex = q->mapFromSource(q->sourceModel()->index(start, column, parent)); 1464 1465 emitDataChangedSignals(proxyStartIndex, maxChanged); 1466 #endif 1467 } 1468 1469 Qt::DropActions KReparentingProxyModel::supportedDropActions() const 1470 { 1471 Q_ASSERT(sourceModel()); 1472 return sourceModel()->supportedDropActions(); 1473 } 1474 1475 void KReparentingProxyModel::beginChangeRule() 1476 { 1477 Q_D(KReparentingProxyModel); 1478 d->sourceModelAboutToBeReset(); 1479 // beginResetModel(); 1480 // d->m_childIndexes.clear(); 1481 // d->m_layoutChangePersistentIndexes.clear(); 1482 // d->m_nextId = 1; 1483 // d->m_parents.clear(); 1484 // d->m_pendingInsertions.clear(); 1485 // d->m_pendingRemovalChildIndexes.clear(); 1486 // d->m_pendingRemovalParents.clear(); 1487 // d->m_pendingRemovals.clear(); 1488 // d->m_proxyIndexes.clear(); 1489 } 1490 1491 void KReparentingProxyModel::endChangeRule() 1492 { 1493 Q_D(KReparentingProxyModel); 1494 d->endResetProxy(); 1495 return; 1496 } 1497 1498 #include "moc_kreparentingproxymodel.cpp"