• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • KDE Home
  • Contact Us
 

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"

akonadi

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

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries 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