• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

KDEUI

kdescendantsproxymodel.cpp

Go to the documentation of this file.
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.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( QLatin1String( " / " ) )
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 invokation.
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 static QModelIndex getFirstDeepest(QAbstractItemModel *model, const QModelIndex &parent, int *count) {
00714   static const int column = 0;
00715   Q_ASSERT(model->hasChildren(parent));
00716   Q_ASSERT(model->rowCount(parent) > 0);
00717   for (int row = 0; row < model->rowCount(parent); ++row) {
00718     (*count)++;
00719     const QModelIndex child = model->index(row, column, parent);
00720     Q_ASSERT(child.isValid());
00721     if (model->hasChildren(child))
00722       return getFirstDeepest(model, child, count);
00723   }
00724   return model->index(model->rowCount(parent) - 1, column, parent);
00725 }
00726 
00727 void KDescendantsProxyModelPrivate::sourceRowsRemoved(const QModelIndex &parent, int start, int end)
00728 {
00729   Q_Q(KDescendantsProxyModel);
00730   Q_UNUSED(end)
00731 
00732   const int rowCount = q->sourceModel()->rowCount(parent);
00733 
00734 
00735   const int proxyStart = m_removePair.first;
00736   const int proxyEnd = m_removePair.second;
00737 
00738   const int difference = proxyEnd - proxyStart + 1;
00739   {
00740     Mapping::right_iterator it = m_mapping.rightLowerBound(proxyStart);
00741     const Mapping::right_iterator endIt = m_mapping.rightUpperBound(proxyEnd);
00742 
00743     if (endIt != m_mapping.rightEnd())
00744       while (it != endIt)
00745         it = m_mapping.eraseRight(it);
00746     else
00747       while (it != m_mapping.rightUpperBound(proxyEnd))
00748         it = m_mapping.eraseRight(it);
00749   }
00750 
00751   m_removePair = qMakePair(-1, -1);
00752   m_rowCount -= difference;
00753   Q_ASSERT(m_rowCount >= 0);
00754 
00755   updateInternalIndexes(proxyStart, -1 * difference);
00756 
00757   if (rowCount != start || rowCount == 0) {
00758     q->endRemoveRows();
00759     return;
00760   }
00761 
00762   static const int column = 0;
00763   const QModelIndex newEnd = q->sourceModel()->index(rowCount - 1, column, parent);
00764   Q_ASSERT(newEnd.isValid());
00765 
00766   if (m_mapping.isEmpty()) {
00767     m_mapping.insert(newEnd, newEnd.row());
00768     q->endRemoveRows();
00769     return;
00770   }
00771   if (q->sourceModel()->hasChildren(newEnd)) {
00772     int count = 0;
00773     const QModelIndex firstDeepest = getFirstDeepest(q->sourceModel(), newEnd, &count);
00774     Q_ASSERT(firstDeepest.isValid());
00775     const int firstDeepestProxy = m_mapping.leftToRight(firstDeepest);
00776 
00777     m_mapping.insert(newEnd, firstDeepestProxy - count);
00778     q->endRemoveRows();
00779     return;
00780   }
00781   Mapping::right_iterator lowerBound = m_mapping.rightLowerBound(proxyStart);
00782   if (lowerBound == m_mapping.rightEnd()) {
00783     int proxyRow = (lowerBound - 1).key();
00784 
00785     for (int row = newEnd.row(); row >= 0; --row ) {
00786       const QModelIndex newEndSibling = q->sourceModel()->index(row, column, parent);
00787       if (!q->sourceModel()->hasChildren(newEndSibling)) {
00788         ++proxyRow;
00789       } else {
00790         break;
00791       }
00792     }
00793     m_mapping.insert(newEnd, proxyRow);
00794     q->endRemoveRows();
00795     return;
00796   } else if (lowerBound == m_mapping.rightBegin()) {
00797     int proxyRow = rowCount - 1;
00798     QModelIndex trackedParent = parent;
00799     while (trackedParent.isValid()) {
00800       proxyRow += (trackedParent.row() + 1);
00801       trackedParent = trackedParent.parent();
00802     }
00803     m_mapping.insert(newEnd, proxyRow);
00804     q->endRemoveRows();
00805     return;
00806   }
00807   const Mapping::right_iterator boundAbove = lowerBound - 1;
00808 
00809   QVector<QModelIndex> targetParents;
00810   targetParents.push_back(parent);
00811   {
00812     QModelIndex target = parent;
00813     int count = 0;
00814     while (target.isValid()) {
00815       if (target == boundAbove.value()) {
00816         m_mapping.insert(newEnd, count + boundAbove.key() + newEnd.row() + 1);
00817         q->endRemoveRows();
00818         return;
00819       }
00820       count += (target.row() + 1);
00821       target = target.parent();
00822       if (target.isValid())
00823         targetParents.push_back(target);
00824     }
00825   }
00826 
00827   QModelIndex boundParent = boundAbove.value().parent();
00828   QModelIndex prevParent = boundParent;
00829   Q_ASSERT(boundParent.isValid());
00830   while (boundParent.isValid()) {
00831     prevParent = boundParent;
00832     boundParent = boundParent.parent();
00833 
00834     if (targetParents.contains(prevParent))
00835       break;
00836 
00837     if (!m_mapping.leftContains(prevParent))
00838       break;
00839 
00840     if (m_mapping.leftToRight(prevParent) > boundAbove.key())
00841       break;
00842   }
00843 
00844   QModelIndex trackedParent = parent;
00845 
00846   int proxyRow = boundAbove.key();
00847 
00848   Q_ASSERT(prevParent.isValid());
00849   proxyRow -= prevParent.row();
00850   while (trackedParent != boundParent) {
00851     proxyRow += (trackedParent.row() + 1);
00852     trackedParent = trackedParent.parent();
00853   }
00854   m_mapping.insert(newEnd, proxyRow + newEnd.row());
00855   q->endRemoveRows();
00856 }
00857 
00858 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeMoved(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destStart)
00859 {
00860   Q_UNUSED(srcParent)
00861   Q_UNUSED(srcStart)
00862   Q_UNUSED(srcEnd)
00863   Q_UNUSED(destParent)
00864   Q_UNUSED(destStart)
00865   Q_Q(KDescendantsProxyModel);
00866   q->beginResetModel();
00867 }
00868 
00869 void KDescendantsProxyModelPrivate::sourceRowsMoved(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destStart)
00870 {
00871   Q_UNUSED(srcParent)
00872   Q_UNUSED(srcStart)
00873   Q_UNUSED(srcEnd)
00874   Q_UNUSED(destParent)
00875   Q_UNUSED(destStart)
00876   Q_Q(KDescendantsProxyModel);
00877   resetInternalData();
00878   q->endResetModel();
00879 }
00880 
00881 void KDescendantsProxyModelPrivate::sourceModelAboutToBeReset()
00882 {
00883   Q_Q(KDescendantsProxyModel);
00884   q->beginResetModel();
00885 }
00886 
00887 void KDescendantsProxyModelPrivate::sourceModelReset()
00888 {
00889   Q_Q(KDescendantsProxyModel);
00890   resetInternalData();
00891   if (q->sourceModel()->hasChildren())
00892   {
00893     Q_ASSERT(q->sourceModel()->rowCount() > 0);
00894     m_pendingParents.append(QModelIndex());
00895     scheduleProcessPendingParents();
00896   }
00897   q->endResetModel();
00898 }
00899 
00900 void KDescendantsProxyModelPrivate::sourceLayoutAboutToBeChanged()
00901 {
00902   Q_Q(KDescendantsProxyModel);
00903 
00904   if (m_ignoreNextLayoutChanged) {
00905       m_ignoreNextLayoutChanged = false;
00906       return;
00907   }
00908 
00909   if (m_mapping.isEmpty())
00910     return;
00911 
00912   QPersistentModelIndex srcPersistentIndex;
00913   foreach(const QPersistentModelIndex &proxyPersistentIndex, q->persistentIndexList()) {
00914       m_proxyIndexes << proxyPersistentIndex;
00915       Q_ASSERT(proxyPersistentIndex.isValid());
00916       srcPersistentIndex = q->mapToSource(proxyPersistentIndex);
00917       Q_ASSERT(srcPersistentIndex.isValid());
00918       m_layoutChangePersistentIndexes << srcPersistentIndex;
00919   }
00920 
00921   q->layoutAboutToBeChanged();
00922 }
00923 
00924 void KDescendantsProxyModelPrivate::sourceLayoutChanged()
00925 {
00926   Q_Q(KDescendantsProxyModel);
00927 
00928   if (m_ignoreNextLayoutAboutToBeChanged) {
00929       m_ignoreNextLayoutAboutToBeChanged = false;
00930       return;
00931   }
00932 
00933   if (m_mapping.isEmpty())
00934     return;
00935 
00936   m_rowCount = 0;
00937 
00938   synchronousMappingRefresh();
00939 
00940   for (int i = 0; i < m_proxyIndexes.size(); ++i) {
00941       q->changePersistentIndex(m_proxyIndexes.at(i), q->mapFromSource(m_layoutChangePersistentIndexes.at(i)));
00942   }
00943 
00944   m_layoutChangePersistentIndexes.clear();
00945   m_proxyIndexes.clear();
00946 
00947   q->layoutChanged();
00948 }
00949 
00950 void KDescendantsProxyModelPrivate::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
00951 {
00952   Q_Q(KDescendantsProxyModel);
00953   Q_ASSERT(topLeft.model() == q->sourceModel());
00954   Q_ASSERT(bottomRight.model() == q->sourceModel());
00955 
00956   const int topRow = topLeft.row();
00957   const int bottomRow = bottomRight.row();
00958 
00959   for(int i = topRow; i <= bottomRow; ++i)
00960   {
00961     const QModelIndex sourceTopLeft = q->sourceModel()->index(i, topLeft.column(), topLeft.parent());
00962     Q_ASSERT(sourceTopLeft.isValid());
00963     const QModelIndex proxyTopLeft = q->mapFromSource(sourceTopLeft);
00964     // TODO. If an index does not have any descendants, then we can emit in blocks of rows.
00965     // As it is we emit once for each row.
00966     const QModelIndex sourceBottomRight = q->sourceModel()->index(i, bottomRight.column(), bottomRight.parent());
00967     const QModelIndex proxyBottomRight = q->mapFromSource(sourceBottomRight);
00968     Q_ASSERT(proxyTopLeft.isValid());
00969     Q_ASSERT(proxyBottomRight.isValid());
00970     emit q->dataChanged(proxyTopLeft, proxyBottomRight);
00971   }
00972 }
00973 
00974 void KDescendantsProxyModelPrivate::sourceModelDestroyed()
00975 {
00976   Q_Q(KDescendantsProxyModel);
00977   resetInternalData();
00978 //   q->endResetModel();
00979 }
00980 
00981 QMimeData* KDescendantsProxyModel::mimeData( const QModelIndexList & indexes ) const
00982 {
00983   if (!sourceModel())
00984     return QAbstractProxyModel::mimeData(indexes);
00985   Q_ASSERT(sourceModel());
00986   QModelIndexList sourceIndexes;
00987   foreach(const QModelIndex& index, indexes)
00988     sourceIndexes << mapToSource(index);
00989   return sourceModel()->mimeData(sourceIndexes);
00990 }
00991 
00992 QStringList KDescendantsProxyModel::mimeTypes() const
00993 {
00994   if (!sourceModel())
00995     return QAbstractProxyModel::mimeTypes();
00996   Q_ASSERT(sourceModel());
00997   return sourceModel()->mimeTypes();
00998 }
00999 
01000 Qt::DropActions KDescendantsProxyModel::supportedDropActions() const
01001 {
01002   if (!sourceModel())
01003     return QAbstractProxyModel::supportedDropActions();
01004   return sourceModel()->supportedDropActions();
01005 }
01006 
01007 #include "moc_kdescendantsproxymodel.cpp"

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal