akonadi
kdescendantsproxymodel.cpp
00001 /* 00002 Copyright (c) 2009 Stephen Kelly <steveire@gmail.com> 00003 Copyright (C) 2010 Klarälvdalens Datakonsult AB, 00004 a KDAB Group company, info@kdab.net, 00005 author Stephen Kelly <stephen@kdab.com> 00006 00007 This library is free software; you can redistribute it and/or modify it 00008 under the terms of the GNU Library General Public License as published by 00009 the Free Software Foundation; either version 2 of the License, or (at your 00010 option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, but WITHOUT 00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00014 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00015 License for more details. 00016 00017 You should have received a copy of the GNU Library General Public License 00018 along with this library; see the file COPYING.LIB. If not, write to the 00019 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 00020 02110-1301, USA. 00021 */ 00022 00023 #include "kdescendantsproxymodel_p.h" 00024 00025 #include <QtCore/QStringList> 00026 #include <QtCore/QTimer> 00027 00028 #include "kdebug.h" 00029 00030 #define KDO(object) kDebug() << #object << object 00031 00032 #include "kbihash_p.h" 00033 00034 typedef KHash2Map<QPersistentModelIndex, int> Mapping; 00035 00036 class KDescendantsProxyModelPrivate 00037 { 00038 KDescendantsProxyModelPrivate(KDescendantsProxyModel * qq) 00039 : q_ptr(qq), 00040 m_rowCount(0), 00041 m_ignoreNextLayoutAboutToBeChanged(false), 00042 m_ignoreNextLayoutChanged(false), 00043 m_relayouting(false), 00044 m_displayAncestorData( false ), 00045 m_ancestorSeparator( QLatin1Char( '/' ) ) 00046 { 00047 } 00048 00049 Q_DECLARE_PUBLIC(KDescendantsProxyModel) 00050 KDescendantsProxyModel * const q_ptr; 00051 00052 mutable QVector<QPersistentModelIndex> m_pendingParents; 00053 00054 void scheduleProcessPendingParents() const; 00055 void processPendingParents(); 00056 00057 void synchronousMappingRefresh(); 00058 00059 void updateInternalIndexes(int start, int offset); 00060 00061 void resetInternalData(); 00062 00063 void sourceRowsAboutToBeInserted(const QModelIndex &, int, int); 00064 void sourceRowsInserted(const QModelIndex &, int, int); 00065 void sourceRowsAboutToBeRemoved(const QModelIndex &, int, int); 00066 void sourceRowsRemoved(const QModelIndex &, int, int); 00067 void sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int); 00068 void sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int); 00069 void sourceModelAboutToBeReset(); 00070 void sourceModelReset(); 00071 void sourceLayoutAboutToBeChanged(); 00072 void sourceLayoutChanged(); 00073 void sourceDataChanged(const QModelIndex &, const QModelIndex &); 00074 void sourceModelDestroyed(); 00075 00076 Mapping m_mapping; 00077 int m_rowCount; 00078 QPair<int, int> m_removePair; 00079 QPair<int, int> m_insertPair; 00080 00081 bool m_ignoreNextLayoutAboutToBeChanged; 00082 bool m_ignoreNextLayoutChanged; 00083 bool m_relayouting; 00084 00085 bool m_displayAncestorData; 00086 QString m_ancestorSeparator; 00087 00088 QList<QPersistentModelIndex> m_layoutChangePersistentIndexes; 00089 QModelIndexList m_proxyIndexes; 00090 }; 00091 00092 void KDescendantsProxyModelPrivate::resetInternalData() 00093 { 00094 m_rowCount = 0; 00095 m_mapping.clear(); 00096 m_layoutChangePersistentIndexes.clear(); 00097 m_proxyIndexes.clear(); 00098 } 00099 00100 void KDescendantsProxyModelPrivate::synchronousMappingRefresh() 00101 { 00102 m_rowCount = 0; 00103 m_mapping.clear(); 00104 m_pendingParents.clear(); 00105 00106 m_pendingParents.append(QModelIndex()); 00107 00108 m_relayouting = true; 00109 while (!m_pendingParents.isEmpty()) 00110 { 00111 processPendingParents(); 00112 } 00113 m_relayouting = false; 00114 } 00115 00116 void KDescendantsProxyModelPrivate::scheduleProcessPendingParents() const 00117 { 00118 Q_Q(const KDescendantsProxyModel); 00119 const_cast<KDescendantsProxyModelPrivate*>(this)->processPendingParents(); 00120 } 00121 00122 void KDescendantsProxyModelPrivate::processPendingParents() 00123 { 00124 Q_Q(KDescendantsProxyModel); 00125 const QVector<QPersistentModelIndex>::iterator begin = m_pendingParents.begin(); 00126 QVector<QPersistentModelIndex>::iterator it = begin; 00127 00128 // Process chunkSize elements per invocation. 00129 static const int chunkSize = 30; 00130 00131 const QVector<QPersistentModelIndex>::iterator end = 00132 /* (m_pendingParents.size() > chunkSize) ? begin + chunkSize : */ m_pendingParents.end(); 00133 00134 QVector<QPersistentModelIndex> newPendingParents; 00135 00136 while (it != end && it != m_pendingParents.end()) { 00137 const QModelIndex sourceParent = *it; 00138 if (!sourceParent.isValid() && m_rowCount > 0) 00139 { 00140 // It was removed from the source model before it was inserted. 00141 it = m_pendingParents.erase(it); 00142 continue; 00143 } 00144 const int rowCount = q->sourceModel()->rowCount(sourceParent); 00145 00146 Q_ASSERT(rowCount > 0); 00147 const QPersistentModelIndex sourceIndex = q->sourceModel()->index(rowCount - 1, 0, sourceParent); 00148 00149 Q_ASSERT(sourceIndex.isValid()); 00150 00151 const QModelIndex proxyParent = q->mapFromSource(sourceParent); 00152 00153 Q_ASSERT(sourceParent.isValid() == proxyParent.isValid()); 00154 const int proxyEndRow = proxyParent.row() + rowCount; 00155 const int proxyStartRow = proxyEndRow - rowCount + 1; 00156 00157 if (!m_relayouting) 00158 q->beginInsertRows(QModelIndex(), proxyStartRow, proxyEndRow); 00159 00160 updateInternalIndexes(proxyStartRow, rowCount); 00161 m_mapping.insert(sourceIndex, proxyEndRow); 00162 it = m_pendingParents.erase(it); 00163 m_rowCount += rowCount; 00164 00165 if (!m_relayouting) 00166 q->endInsertRows(); 00167 00168 for (int sourceRow = 0; sourceRow < rowCount; ++sourceRow ) { 00169 static const int column = 0; 00170 const QModelIndex child = q->sourceModel()->index(sourceRow, column, sourceParent); 00171 Q_ASSERT(child.isValid()); 00172 00173 if (q->sourceModel()->hasChildren(child)) 00174 { 00175 Q_ASSERT(q->sourceModel()->rowCount(child) > 0); 00176 newPendingParents.append(child); 00177 } 00178 } 00179 } 00180 m_pendingParents += newPendingParents; 00181 if (!m_pendingParents.isEmpty()) 00182 processPendingParents(); 00183 // scheduleProcessPendingParents(); 00184 } 00185 00186 void KDescendantsProxyModelPrivate::updateInternalIndexes(int start, int offset) 00187 { 00188 // TODO: Make KHash2Map support key updates and do this backwards. 00189 QHash<int, QPersistentModelIndex> updates; 00190 { 00191 Mapping::right_iterator it = m_mapping.rightLowerBound(start); 00192 const Mapping::right_iterator end = m_mapping.rightEnd(); 00193 00194 while (it != end) 00195 { 00196 updates.insert(it.key() + offset, *it); 00197 ++it; 00198 } 00199 } 00200 00201 { 00202 QHash<int, QPersistentModelIndex>::const_iterator it = updates.constBegin(); 00203 const QHash<int, QPersistentModelIndex>::const_iterator end = updates.constEnd(); 00204 00205 for ( ; it != end; ++it) 00206 { 00207 m_mapping.insert(it.value(), it.key()); 00208 } 00209 } 00210 00211 } 00212 00213 KDescendantsProxyModel::KDescendantsProxyModel(QObject *parent) 00214 : QAbstractProxyModel(parent), d_ptr(new KDescendantsProxyModelPrivate(this)) 00215 { 00216 } 00217 00218 KDescendantsProxyModel::~KDescendantsProxyModel() 00219 { 00220 delete d_ptr; 00221 } 00222 00223 void KDescendantsProxyModel::setRootIndex(const QModelIndex &index) 00224 { 00225 Q_UNUSED(index) 00226 } 00227 00228 QModelIndexList KDescendantsProxyModel::match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const 00229 { 00230 return QAbstractProxyModel::match(start, role, value, hits, flags); 00231 } 00232 00233 void KDescendantsProxyModel::setDisplayAncestorData( bool display ) 00234 { 00235 Q_D(KDescendantsProxyModel); 00236 d->m_displayAncestorData = display; 00237 } 00238 00239 bool KDescendantsProxyModel::displayAncestorData() const 00240 { 00241 Q_D(const KDescendantsProxyModel ); 00242 return d->m_displayAncestorData; 00243 } 00244 00245 void KDescendantsProxyModel::setAncestorSeparator( const QString &separator ) 00246 { 00247 Q_D(KDescendantsProxyModel); 00248 d->m_ancestorSeparator = separator; 00249 } 00250 00251 QString KDescendantsProxyModel::ancestorSeparator() const 00252 { 00253 Q_D(const KDescendantsProxyModel ); 00254 return d->m_ancestorSeparator; 00255 } 00256 00257 00258 void KDescendantsProxyModel::setSourceModel(QAbstractItemModel *_sourceModel) 00259 { 00260 beginResetModel(); 00261 00262 if (_sourceModel) { 00263 disconnect(_sourceModel, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)), 00264 this, SLOT(sourceRowsAboutToBeInserted(const QModelIndex &, int, int))); 00265 disconnect(_sourceModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)), 00266 this, SLOT(sourceRowsInserted(const QModelIndex &, int, int))); 00267 disconnect(_sourceModel, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)), 00268 this, SLOT(sourceRowsAboutToBeRemoved(const QModelIndex &, int, int))); 00269 disconnect(_sourceModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), 00270 this, SLOT(sourceRowsRemoved(const QModelIndex &, int, int))); 00271 // disconnect(_sourceModel, SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)), 00272 // this, SLOT(sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int))); 00273 // disconnect(_sourceModel, SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), 00274 // this, SLOT(sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int))); 00275 disconnect(_sourceModel, SIGNAL(modelAboutToBeReset()), 00276 this, SLOT(sourceModelAboutToBeReset())); 00277 disconnect(_sourceModel, SIGNAL(modelReset()), 00278 this, SLOT(sourceModelReset())); 00279 disconnect(_sourceModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), 00280 this, SLOT(sourceDataChanged(const QModelIndex &, const QModelIndex &))); 00281 disconnect(_sourceModel, SIGNAL(layoutAboutToBeChanged()), 00282 this, SLOT(sourceLayoutAboutToBeChanged())); 00283 disconnect(_sourceModel, SIGNAL(layoutChanged()), 00284 this, SLOT(sourceLayoutChanged())); 00285 disconnect(_sourceModel, SIGNAL(destroyed()), 00286 this, SLOT(sourceModelDestroyed())); 00287 } 00288 00289 QAbstractProxyModel::setSourceModel(_sourceModel); 00290 00291 if (_sourceModel) { 00292 connect(_sourceModel, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)), 00293 SLOT(sourceRowsAboutToBeInserted(const QModelIndex &, int, int))); 00294 connect(_sourceModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)), 00295 SLOT(sourceRowsInserted(const QModelIndex &, int, int))); 00296 connect(_sourceModel, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)), 00297 SLOT(sourceRowsAboutToBeRemoved(const QModelIndex &, int, int))); 00298 connect(_sourceModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), 00299 SLOT(sourceRowsRemoved(const QModelIndex &, int, int))); 00300 // connect(_sourceModel, SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)), 00301 // SLOT(sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int))); 00302 // connect(_sourceModel, SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), 00303 // SLOT(sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int))); 00304 connect(_sourceModel, SIGNAL(modelAboutToBeReset()), 00305 SLOT(sourceModelAboutToBeReset())); 00306 connect(_sourceModel, SIGNAL(modelReset()), 00307 SLOT(sourceModelReset())); 00308 connect(_sourceModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), 00309 SLOT(sourceDataChanged(const QModelIndex &, const QModelIndex &))); 00310 connect(_sourceModel, SIGNAL(layoutAboutToBeChanged()), 00311 SLOT(sourceLayoutAboutToBeChanged())); 00312 connect(_sourceModel, SIGNAL(layoutChanged()), 00313 SLOT(sourceLayoutChanged())); 00314 connect(_sourceModel, SIGNAL(destroyed()), 00315 SLOT(sourceModelDestroyed())); 00316 } 00317 00318 endResetModel(); 00319 } 00320 00321 QModelIndex KDescendantsProxyModel::parent(const QModelIndex &index) const 00322 { 00323 Q_UNUSED(index) 00324 return QModelIndex(); 00325 } 00326 00327 bool KDescendantsProxyModel::hasChildren(const QModelIndex &parent) const 00328 { 00329 Q_D(const KDescendantsProxyModel); 00330 return !(d->m_mapping.isEmpty() || parent.isValid()); 00331 } 00332 00333 int KDescendantsProxyModel::rowCount(const QModelIndex &parent) const 00334 { 00335 Q_D(const KDescendantsProxyModel); 00336 if (d->m_pendingParents.contains(parent) || parent.isValid() || !sourceModel()) 00337 return 0; 00338 00339 if (d->m_mapping.isEmpty() && sourceModel()->hasChildren()) 00340 { 00341 Q_ASSERT(sourceModel()->rowCount() > 0); 00342 const_cast<KDescendantsProxyModelPrivate*>(d)->synchronousMappingRefresh(); 00343 } 00344 return d->m_rowCount; 00345 } 00346 00347 QModelIndex KDescendantsProxyModel::index(int row, int column, const QModelIndex &parent) const 00348 { 00349 if (parent.isValid()) 00350 return QModelIndex(); 00351 00352 if (!hasIndex(row, column, parent)) 00353 return QModelIndex(); 00354 00355 return createIndex(row, column); 00356 } 00357 00358 QModelIndex KDescendantsProxyModel::mapToSource(const QModelIndex &proxyIndex) const 00359 { 00360 Q_D(const KDescendantsProxyModel); 00361 if (d->m_mapping.isEmpty() || !proxyIndex.isValid() || !sourceModel()) 00362 return QModelIndex(); 00363 00364 const Mapping::right_const_iterator result = d->m_mapping.rightLowerBound(proxyIndex.row()); 00365 Q_ASSERT(result != d->m_mapping.rightEnd()); 00366 00367 const int proxyLastRow = result.key(); 00368 const QModelIndex sourceLastChild = result.value(); 00369 Q_ASSERT(sourceLastChild.isValid()); 00370 00371 // proxyLastRow is greater than proxyIndex.row(). 00372 // sourceLastChild is vertically below the result we're looking for 00373 // and not necessarily in the correct parent. 00374 // We travel up through its parent hierarchy until we are in the 00375 // right parent, then return the correct sibling. 00376 00377 // Source: Proxy: Row 00378 // - A - A - 0 00379 // - B - B - 1 00380 // - C - C - 2 00381 // - D - D - 3 00382 // - - E - E - 4 00383 // - - F - F - 5 00384 // - - G - G - 6 00385 // - - H - H - 7 00386 // - - I - I - 8 00387 // - - - J - J - 9 00388 // - - - K - K - 10 00389 // - - - L - L - 11 00390 // - - M - M - 12 00391 // - - N - N - 13 00392 // - O - O - 14 00393 00394 // Note that L, N and O are lastChildIndexes, and therefore have a mapping. If we 00395 // are trying to map G from the proxy to the source, We at this point have an iterator 00396 // pointing to (L -> 11). The proxy row of G is 6. (proxyIndex.row() == 6). We seek the 00397 // sourceIndex which is vertically above L by the distance proxyLastRow - proxyIndex.row(). 00398 // In this case the verticalDistance is 5. 00399 00400 int verticalDistance = proxyLastRow - proxyIndex.row(); 00401 00402 // We traverse the ancestors of L, until we can index the desired row in the source. 00403 00404 QModelIndex ancestor = sourceLastChild; 00405 while (ancestor.isValid()) 00406 { 00407 const int ancestorRow = ancestor.row(); 00408 if (verticalDistance <= ancestorRow) 00409 { 00410 return ancestor.sibling(ancestorRow - verticalDistance, proxyIndex.column()); 00411 } 00412 verticalDistance -= (ancestorRow + 1); 00413 ancestor = ancestor.parent(); 00414 } 00415 Q_ASSERT(!"Didn't find target row."); 00416 return QModelIndex(); 00417 } 00418 00419 QModelIndex KDescendantsProxyModel::mapFromSource(const QModelIndex &sourceIndex) const 00420 { 00421 Q_D(const KDescendantsProxyModel); 00422 00423 if (!sourceModel()) 00424 return QModelIndex(); 00425 00426 if (d->m_mapping.isEmpty()) 00427 return QModelIndex(); 00428 00429 00430 { 00431 // TODO: Consider a parent Mapping to speed this up. 00432 00433 Mapping::right_const_iterator it = d->m_mapping.rightConstBegin(); 00434 const Mapping::right_const_iterator end = d->m_mapping.rightConstEnd(); 00435 const QModelIndex sourceParent = sourceIndex.parent(); 00436 Mapping::right_const_iterator result = end; 00437 00438 for ( ; it != end; ++it ) 00439 { 00440 QModelIndex index = it.value(); 00441 bool found_block = false; 00442 while (index.isValid()) 00443 { 00444 const QModelIndex ancestor = index.parent(); 00445 if (ancestor == sourceParent && index.row() >= sourceIndex.row()) 00446 { 00447 found_block = true; 00448 if (result == end || it.key() < result.key()) 00449 { 00450 result = it; 00451 break; // Leave the while loop. index is still valid. 00452 } 00453 } 00454 index = ancestor; 00455 } 00456 if (found_block && !index.isValid()) 00457 // Looked through the ascendants of it.key() without finding sourceParent. 00458 // That means we've already got the result we need. 00459 break; 00460 } 00461 Q_ASSERT(result != end); 00462 const QModelIndex sourceLastChild = result.value(); 00463 int proxyRow = result.key(); 00464 QModelIndex index = sourceLastChild; 00465 while (index.isValid()) 00466 { 00467 const QModelIndex ancestor = index.parent(); 00468 if (ancestor == sourceParent) 00469 { 00470 return createIndex(proxyRow - (index.row() - sourceIndex.row()), sourceIndex.column()); 00471 } 00472 proxyRow -= (index.row() + 1); 00473 index = ancestor; 00474 } 00475 Q_ASSERT(!"Didn't find valid proxy mapping."); 00476 return QModelIndex(); 00477 } 00478 00479 } 00480 00481 int KDescendantsProxyModel::columnCount(const QModelIndex &parent) const 00482 { 00483 if (parent.isValid() /* || rowCount(parent) == 0 */ || !sourceModel()) 00484 return 0; 00485 00486 return sourceModel()->columnCount(); 00487 } 00488 00489 QVariant KDescendantsProxyModel::data(const QModelIndex &index, int role) const 00490 { 00491 Q_D(const KDescendantsProxyModel ); 00492 00493 if (!sourceModel()) 00494 return QVariant(); 00495 00496 if (!index.isValid()) 00497 return sourceModel()->data(index, role); 00498 00499 QModelIndex sourceIndex = mapToSource( index ); 00500 00501 if ((d->m_displayAncestorData) && ( role == Qt::DisplayRole ) ) 00502 { 00503 if (!sourceIndex.isValid()) 00504 { 00505 return QVariant(); 00506 } 00507 QString displayData = sourceIndex.data().toString(); 00508 sourceIndex = sourceIndex.parent(); 00509 while (sourceIndex.isValid()) 00510 { 00511 displayData.prepend(d->m_ancestorSeparator); 00512 displayData.prepend(sourceIndex.data().toString()); 00513 sourceIndex = sourceIndex.parent(); 00514 } 00515 return displayData; 00516 } else { 00517 return sourceIndex.data(role); 00518 } 00519 } 00520 00521 QVariant KDescendantsProxyModel::headerData(int section, Qt::Orientation orientation, int role) const 00522 { 00523 if (!sourceModel() || columnCount() <= section) 00524 return QVariant(); 00525 00526 return QAbstractProxyModel::headerData(section, orientation, role); 00527 } 00528 00529 Qt::ItemFlags KDescendantsProxyModel::flags(const QModelIndex &index) const 00530 { 00531 if (!index.isValid() || !sourceModel()) 00532 return QAbstractProxyModel::flags(index); 00533 00534 const QModelIndex srcIndex = mapToSource(index); 00535 Q_ASSERT(srcIndex.isValid()); 00536 return sourceModel()->flags(srcIndex); 00537 } 00538 00539 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end) 00540 { 00541 Q_Q(KDescendantsProxyModel); 00542 00543 if (!q->sourceModel()->hasChildren(parent)) 00544 { 00545 Q_ASSERT(q->sourceModel()->rowCount(parent) == 0); 00546 // parent was not a parent before. 00547 return; 00548 } 00549 00550 int proxyStart = -1; 00551 00552 const int rowCount = q->sourceModel()->rowCount(parent); 00553 00554 if (rowCount > start) 00555 { 00556 const QModelIndex belowStart = q->sourceModel()->index(start, 0, parent); 00557 proxyStart = q->mapFromSource(belowStart).row(); 00558 } else if (rowCount == 0) 00559 { 00560 proxyStart = q->mapFromSource(parent).row() + 1; 00561 } else { 00562 Q_ASSERT(rowCount == start); 00563 static const int column = 0; 00564 QModelIndex idx = q->sourceModel()->index(rowCount - 1, column, parent); 00565 while (q->sourceModel()->hasChildren(idx)) 00566 { 00567 Q_ASSERT(q->sourceModel()->rowCount(idx) > 0); 00568 idx = q->sourceModel()->index(q->sourceModel()->rowCount(idx) - 1, column, idx); 00569 } 00570 // The last item in the list is getting a sibling below it. 00571 proxyStart = q->mapFromSource(idx).row() + 1; 00572 } 00573 const int proxyEnd = proxyStart + (end - start); 00574 00575 m_insertPair = qMakePair(proxyStart, proxyEnd); 00576 q->beginInsertRows(QModelIndex(), proxyStart, proxyEnd); 00577 } 00578 00579 void KDescendantsProxyModelPrivate::sourceRowsInserted(const QModelIndex &parent, int start, int end) 00580 { 00581 Q_Q(KDescendantsProxyModel); 00582 00583 const QModelIndex sourceStart = q->sourceModel()->index(start, 0, parent); 00584 Q_ASSERT(sourceStart.isValid()); 00585 00586 const int rowCount = q->sourceModel()->rowCount(parent); 00587 Q_ASSERT(rowCount > 0); 00588 00589 const int difference = end - start + 1; 00590 00591 if (rowCount == difference) 00592 { 00593 // @p parent was not a parent before. 00594 m_pendingParents.append(parent); 00595 scheduleProcessPendingParents(); 00596 return; 00597 } 00598 00599 const int proxyStart = m_insertPair.first; 00600 00601 Q_ASSERT(proxyStart >= 0); 00602 00603 updateInternalIndexes(proxyStart, difference); 00604 00605 if (rowCount - 1 == end) 00606 { 00607 // The previously last row (the mapped one) is no longer the last. 00608 // For example, 00609 00610 // - A - A 0 00611 // - - B - B 1 00612 // - - C - C 2 00613 // - - - D - D 3 00614 // - - - E -> - E 4 00615 // - - F - F 5 00616 // - - G -> - G 6 00617 // - H - H 7 00618 // - I -> - I 8 00619 00620 // As last children, E, F and G have mappings. 00621 // Consider that 'J' is appended to the children of 'C', below 'E'. 00622 00623 // - A - A 0 00624 // - - B - B 1 00625 // - - C - C 2 00626 // - - - D - D 3 00627 // - - - E -> - E 4 00628 // - - - J - ??? 5 00629 // - - F - F 6 00630 // - - G -> - G 7 00631 // - H - H 8 00632 // - I -> - I 9 00633 00634 // The updateInternalIndexes call above will have updated the F and G mappings correctly because proxyStart is 5. 00635 // That means that E -> 4 was not affected by the updateInternalIndexes call. 00636 // Now the mapping for E -> 4 needs to be updated so that it's a mapping for J -> 5. 00637 00638 Q_ASSERT(!m_mapping.isEmpty()); 00639 static const int column = 0; 00640 const QModelIndex oldIndex = q->sourceModel()->index(rowCount - 1 - difference, column, parent); 00641 Q_ASSERT(m_mapping.leftContains(oldIndex)); 00642 00643 const QModelIndex newIndex = q->sourceModel()->index(rowCount - 1, column, parent); 00644 00645 QModelIndex indexAbove = oldIndex; 00646 00647 if (start > 0) { 00648 // If we have something like this: 00649 // 00650 // - A 00651 // - - B 00652 // - - C 00653 // 00654 // and we then insert D as a sibling of A below it, we need to remove the mapping for A, 00655 // and the row number used for D must take into account the descendants of A. 00656 00657 while (q->sourceModel()->hasChildren(indexAbove)) { 00658 Q_ASSERT(q->sourceModel()->rowCount(indexAbove) > 0); 00659 indexAbove = q->sourceModel()->index(q->sourceModel()->rowCount(indexAbove) - 1, column, indexAbove); 00660 } 00661 Q_ASSERT(q->sourceModel()->rowCount(indexAbove) == 0); 00662 } 00663 00664 Q_ASSERT(m_mapping.leftContains(indexAbove)); 00665 00666 const int newProxyRow = m_mapping.leftToRight(indexAbove) + difference; 00667 00668 // oldIndex is E in the source. proxyRow is 4. 00669 m_mapping.removeLeft(oldIndex); 00670 00671 // newIndex is J. (proxyRow + difference) is 5. 00672 m_mapping.insert(newIndex, newProxyRow); 00673 } 00674 00675 for (int row = start; row <= end; ++row) 00676 { 00677 static const int column = 0; 00678 const QModelIndex idx = q->sourceModel()->index(row, column, parent); 00679 Q_ASSERT(idx.isValid()); 00680 if (q->sourceModel()->hasChildren(idx)) 00681 { 00682 Q_ASSERT(q->sourceModel()->rowCount(idx) > 0); 00683 m_pendingParents.append(idx); 00684 } 00685 } 00686 00687 m_rowCount += difference; 00688 00689 q->endInsertRows(); 00690 scheduleProcessPendingParents(); 00691 } 00692 00693 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) 00694 { 00695 Q_Q(KDescendantsProxyModel); 00696 00697 const int proxyStart = q->mapFromSource(q->sourceModel()->index(start, 0, parent)).row(); 00698 00699 static const int column = 0; 00700 QModelIndex idx = q->sourceModel()->index(end, column, parent); 00701 while (q->sourceModel()->hasChildren(idx)) 00702 { 00703 Q_ASSERT(q->sourceModel()->rowCount(idx) > 0); 00704 idx = q->sourceModel()->index(q->sourceModel()->rowCount(idx) - 1, column, idx); 00705 } 00706 const int proxyEnd = q->mapFromSource(idx).row(); 00707 00708 m_removePair = qMakePair(proxyStart, proxyEnd); 00709 00710 q->beginRemoveRows(QModelIndex(), proxyStart, proxyEnd); 00711 } 00712 00713 void KDescendantsProxyModelPrivate::sourceRowsRemoved(const QModelIndex &parent, int start, int end) 00714 { 00715 Q_Q(KDescendantsProxyModel); 00716 Q_UNUSED(end) 00717 00718 const int rowCount = q->sourceModel()->rowCount(parent); 00719 00720 00721 const int proxyStart = m_removePair.first; 00722 const int proxyEnd = m_removePair.second; 00723 00724 const int difference = proxyEnd - proxyStart + 1; 00725 { 00726 Mapping::right_iterator it = m_mapping.rightLowerBound(proxyStart); 00727 const Mapping::right_iterator endIt = m_mapping.rightUpperBound(proxyEnd); 00728 00729 if (endIt != m_mapping.rightEnd()) 00730 while (it != endIt) 00731 it = m_mapping.eraseRight(it); 00732 else 00733 while (it != m_mapping.rightUpperBound(proxyEnd)) 00734 it = m_mapping.eraseRight(it); 00735 } 00736 00737 m_removePair = qMakePair(-1, -1); 00738 m_rowCount -= difference; 00739 Q_ASSERT(m_rowCount >= 0); 00740 00741 updateInternalIndexes(proxyStart, -1 * difference); 00742 00743 if (rowCount == start && rowCount != 0) 00744 { 00745 static const int column = 0; 00746 const QModelIndex newIndex = q->sourceModel()->index(rowCount - 1, column, parent); 00747 m_mapping.insert(newIndex, proxyStart - 1); 00748 } 00749 00750 q->endRemoveRows(); 00751 } 00752 00753 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeMoved(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destStart) 00754 { 00755 Q_UNUSED(srcParent) 00756 Q_UNUSED(srcStart) 00757 Q_UNUSED(srcEnd) 00758 Q_UNUSED(destParent) 00759 Q_UNUSED(destStart) 00760 Q_Q(KDescendantsProxyModel); 00761 q->beginResetModel(); 00762 } 00763 00764 void KDescendantsProxyModelPrivate::sourceRowsMoved(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destStart) 00765 { 00766 Q_UNUSED(srcParent) 00767 Q_UNUSED(srcStart) 00768 Q_UNUSED(srcEnd) 00769 Q_UNUSED(destParent) 00770 Q_UNUSED(destStart) 00771 Q_Q(KDescendantsProxyModel); 00772 resetInternalData(); 00773 q->endResetModel(); 00774 } 00775 00776 void KDescendantsProxyModelPrivate::sourceModelAboutToBeReset() 00777 { 00778 Q_Q(KDescendantsProxyModel); 00779 q->beginResetModel(); 00780 } 00781 00782 void KDescendantsProxyModelPrivate::sourceModelReset() 00783 { 00784 Q_Q(KDescendantsProxyModel); 00785 resetInternalData(); 00786 if (q->sourceModel()->hasChildren()) 00787 { 00788 Q_ASSERT(q->sourceModel()->rowCount() > 0); 00789 m_pendingParents.append(QModelIndex()); 00790 scheduleProcessPendingParents(); 00791 } 00792 q->endResetModel(); 00793 } 00794 00795 void KDescendantsProxyModelPrivate::sourceLayoutAboutToBeChanged() 00796 { 00797 Q_Q(KDescendantsProxyModel); 00798 00799 if (m_ignoreNextLayoutChanged) { 00800 m_ignoreNextLayoutChanged = false; 00801 return; 00802 } 00803 00804 if (m_mapping.isEmpty()) 00805 return; 00806 00807 QPersistentModelIndex srcPersistentIndex; 00808 foreach(const QPersistentModelIndex &proxyPersistentIndex, q->persistentIndexList()) { 00809 m_proxyIndexes << proxyPersistentIndex; 00810 Q_ASSERT(proxyPersistentIndex.isValid()); 00811 srcPersistentIndex = q->mapToSource(proxyPersistentIndex); 00812 Q_ASSERT(srcPersistentIndex.isValid()); 00813 m_layoutChangePersistentIndexes << srcPersistentIndex; 00814 } 00815 00816 q->layoutAboutToBeChanged(); 00817 } 00818 00819 void KDescendantsProxyModelPrivate::sourceLayoutChanged() 00820 { 00821 Q_Q(KDescendantsProxyModel); 00822 00823 if (m_ignoreNextLayoutAboutToBeChanged) { 00824 m_ignoreNextLayoutAboutToBeChanged = false; 00825 return; 00826 } 00827 00828 if (m_mapping.isEmpty()) 00829 return; 00830 00831 m_rowCount = 0; 00832 00833 synchronousMappingRefresh(); 00834 00835 for (int i = 0; i < m_proxyIndexes.size(); ++i) { 00836 q->changePersistentIndex(m_proxyIndexes.at(i), q->mapFromSource(m_layoutChangePersistentIndexes.at(i))); 00837 } 00838 00839 m_layoutChangePersistentIndexes.clear(); 00840 m_proxyIndexes.clear(); 00841 00842 q->layoutChanged(); 00843 } 00844 00845 void KDescendantsProxyModelPrivate::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) 00846 { 00847 Q_Q(KDescendantsProxyModel); 00848 00849 const int topRow = topLeft.row(); 00850 const int bottomRow = bottomRight.row(); 00851 00852 for(int i = topRow; i <= bottomRow; ++i) 00853 { 00854 const QModelIndex sourceTopLeft = q->sourceModel()->index(i, topLeft.column(), topLeft.parent()); 00855 const QModelIndex proxyTopLeft = q->mapFromSource(sourceTopLeft); 00856 // TODO. If an index does not have any descendants, then we can emit in blocks of rows. 00857 // As it is we emit once for each row. 00858 const QModelIndex sourceBottomRight = q->sourceModel()->index(i, bottomRight.column(), bottomRight.parent()); 00859 const QModelIndex proxyBottomRight = q->mapFromSource(sourceBottomRight); 00860 emit q->dataChanged(proxyTopLeft, proxyBottomRight); 00861 } 00862 } 00863 00864 void KDescendantsProxyModelPrivate::sourceModelDestroyed() 00865 { 00866 Q_Q(KDescendantsProxyModel); 00867 resetInternalData(); 00868 q->endResetModel(); 00869 } 00870 00871 QMimeData* KDescendantsProxyModel::mimeData( const QModelIndexList & indexes ) const 00872 { 00873 if (!sourceModel()) 00874 return QAbstractProxyModel::mimeData(indexes); 00875 Q_ASSERT(sourceModel()); 00876 QModelIndexList sourceIndexes; 00877 foreach(const QModelIndex& index, indexes) 00878 sourceIndexes << mapToSource(index); 00879 return sourceModel()->mimeData(sourceIndexes); 00880 } 00881 00882 QStringList KDescendantsProxyModel::mimeTypes() const 00883 { 00884 if (!sourceModel()) 00885 return QAbstractProxyModel::mimeTypes(); 00886 Q_ASSERT(sourceModel()); 00887 return sourceModel()->mimeTypes(); 00888 } 00889 00890 Qt::DropActions KDescendantsProxyModel::supportedDropActions() const 00891 { 00892 if (!sourceModel()) 00893 return QAbstractProxyModel::supportedDropActions(); 00894 return sourceModel()->supportedDropActions(); 00895 } 00896 00897 #include "moc_kdescendantsproxymodel_p.cpp"