• Skip to content
  • Skip to link menu
KDE 4.5 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • Sitemap
  • 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( 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         newPendingParents.append(child);
00175     }
00176   }
00177   m_pendingParents += newPendingParents;
00178   if (!m_pendingParents.isEmpty())
00179       processPendingParents();
00180 //   scheduleProcessPendingParents();
00181 }
00182 
00183 void KDescendantsProxyModelPrivate::updateInternalIndexes(int start, int offset)
00184 {
00185   // TODO: Make KHash2Map support key updates and do this backwards.
00186   QHash<int, QPersistentModelIndex> updates;
00187   {
00188     Mapping::right_const_iterator it = const_cast<const Mapping&>(m_mapping).rightLowerBound(start);
00189     const Mapping::right_const_iterator end = m_mapping.rightConstEnd();
00190 
00191     while (it != end)
00192     {
00193       updates.insert(it.key() + offset, *it);
00194       ++it;
00195     }
00196   }
00197 
00198   {
00199     QHash<int, QPersistentModelIndex>::const_iterator it = updates.constBegin();
00200     const QHash<int, QPersistentModelIndex>::const_iterator end = updates.constEnd();
00201 
00202     for ( ; it != end; ++it)
00203     {
00204       m_mapping.insert(it.value(), it.key());
00205     }
00206   }
00207 
00208 }
00209 
00210 KDescendantsProxyModel::KDescendantsProxyModel(QObject *parent)
00211   : QAbstractProxyModel(parent), d_ptr(new KDescendantsProxyModelPrivate(this))
00212 {
00213 }
00214 
00215 KDescendantsProxyModel::~KDescendantsProxyModel()
00216 {
00217   delete d_ptr;
00218 }
00219 
00220 void KDescendantsProxyModel::setRootIndex(const QModelIndex &index)
00221 {
00222   Q_UNUSED(index)
00223 }
00224 
00225 QModelIndexList KDescendantsProxyModel::match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const
00226 {
00227   return QAbstractProxyModel::match(start, role, value, hits, flags);
00228 }
00229 
00230 void KDescendantsProxyModel::setDisplayAncestorData( bool display )
00231 {
00232   Q_D(KDescendantsProxyModel);
00233   d->m_displayAncestorData = display;
00234 }
00235 
00236 bool KDescendantsProxyModel::displayAncestorData() const
00237 {
00238   Q_D(const KDescendantsProxyModel );
00239   return d->m_displayAncestorData;
00240 }
00241 
00242 void KDescendantsProxyModel::setAncestorSeparator( const QString &separator )
00243 {
00244   Q_D(KDescendantsProxyModel);
00245   d->m_ancestorSeparator = separator;
00246 }
00247 
00248 QString KDescendantsProxyModel::ancestorSeparator() const
00249 {
00250   Q_D(const KDescendantsProxyModel );
00251   return d->m_ancestorSeparator;
00252 }
00253 
00254 
00255 void KDescendantsProxyModel::setSourceModel(QAbstractItemModel *_sourceModel)
00256 {
00257   beginResetModel();
00258 
00259   if (_sourceModel) {
00260     disconnect(_sourceModel, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)),
00261                this, SLOT(sourceRowsAboutToBeInserted(const QModelIndex &, int, int)));
00262     disconnect(_sourceModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)),
00263                this, SLOT(sourceRowsInserted(const QModelIndex &, int, int)));
00264     disconnect(_sourceModel, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)),
00265                this, SLOT(sourceRowsAboutToBeRemoved(const QModelIndex &, int, int)));
00266     disconnect(_sourceModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
00267                this, SLOT(sourceRowsRemoved(const QModelIndex &, int, int)));
00268 //     disconnect(_sourceModel, SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)),
00269 //             this, SLOT(sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
00270 //     disconnect(_sourceModel, SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)),
00271 //             this, SLOT(sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
00272     disconnect(_sourceModel, SIGNAL(modelAboutToBeReset()),
00273                this, SLOT(sourceModelAboutToBeReset()));
00274     disconnect(_sourceModel, SIGNAL(modelReset()),
00275                this, SLOT(sourceModelReset()));
00276     disconnect(_sourceModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
00277                this, SLOT(sourceDataChanged(const QModelIndex &, const QModelIndex &)));
00278     disconnect(_sourceModel, SIGNAL(layoutAboutToBeChanged()),
00279                this, SLOT(sourceLayoutAboutToBeChanged()));
00280     disconnect(_sourceModel, SIGNAL(layoutChanged()),
00281                this, SLOT(sourceLayoutChanged()));
00282     disconnect(_sourceModel, SIGNAL(destroyed()),
00283                this, SLOT(sourceModelDestroyed()));
00284   }
00285 
00286   QAbstractProxyModel::setSourceModel(_sourceModel);
00287 
00288   if (_sourceModel) {
00289     connect(_sourceModel, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)),
00290             SLOT(sourceRowsAboutToBeInserted(const QModelIndex &, int, int)));
00291     connect(_sourceModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)),
00292             SLOT(sourceRowsInserted(const QModelIndex &, int, int)));
00293     connect(_sourceModel, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)),
00294             SLOT(sourceRowsAboutToBeRemoved(const QModelIndex &, int, int)));
00295     connect(_sourceModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
00296             SLOT(sourceRowsRemoved(const QModelIndex &, int, int)));
00297 //     connect(_sourceModel, SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)),
00298 //             SLOT(sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
00299 //     connect(_sourceModel, SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)),
00300 //             SLOT(sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
00301     connect(_sourceModel, SIGNAL(modelAboutToBeReset()),
00302             SLOT(sourceModelAboutToBeReset()));
00303     connect(_sourceModel, SIGNAL(modelReset()),
00304             SLOT(sourceModelReset()));
00305     connect(_sourceModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
00306             SLOT(sourceDataChanged(const QModelIndex &, const QModelIndex &)));
00307     connect(_sourceModel, SIGNAL(layoutAboutToBeChanged()),
00308             SLOT(sourceLayoutAboutToBeChanged()));
00309     connect(_sourceModel, SIGNAL(layoutChanged()),
00310             SLOT(sourceLayoutChanged()));
00311     connect(_sourceModel, SIGNAL(destroyed()),
00312             SLOT(sourceModelDestroyed()));
00313   }
00314 
00315   endResetModel();
00316 }
00317 
00318 QModelIndex KDescendantsProxyModel::parent(const QModelIndex &index) const
00319 {
00320   Q_UNUSED(index)
00321   return QModelIndex();
00322 }
00323 
00324 bool KDescendantsProxyModel::hasChildren(const QModelIndex &parent) const
00325 {
00326   Q_D(const KDescendantsProxyModel);
00327   return !(d->m_mapping.isEmpty() || parent.isValid());
00328 }
00329 
00330 int KDescendantsProxyModel::rowCount(const QModelIndex &parent) const
00331 {
00332   Q_D(const KDescendantsProxyModel);
00333   if (d->m_pendingParents.contains(parent) || parent.isValid() || !sourceModel())
00334     return 0;
00335 
00336   if (d->m_mapping.isEmpty() && sourceModel()->hasChildren())
00337   {
00338     const_cast<KDescendantsProxyModelPrivate*>(d)->synchronousMappingRefresh();
00339   }
00340   return d->m_rowCount;
00341 }
00342 
00343 QModelIndex KDescendantsProxyModel::index(int row, int column, const QModelIndex &parent) const
00344 {
00345   if (parent.isValid())
00346     return QModelIndex();
00347 
00348   if (!hasIndex(row, column, parent))
00349     return QModelIndex();
00350 
00351   return createIndex(row, column);
00352 }
00353 
00354 QModelIndex KDescendantsProxyModel::mapToSource(const QModelIndex &proxyIndex) const
00355 {
00356   Q_D(const KDescendantsProxyModel);
00357   if (d->m_mapping.isEmpty() || !proxyIndex.isValid() || !sourceModel())
00358     return QModelIndex();
00359 
00360   const Mapping::right_const_iterator result = d->m_mapping.rightLowerBound(proxyIndex.row());
00361   Q_ASSERT(result != d->m_mapping.rightEnd());
00362 
00363   const int proxyLastRow = result.key();
00364   const QModelIndex sourceLastChild = result.value();
00365   Q_ASSERT(sourceLastChild.isValid());
00366 
00367   // proxyLastRow is greater than proxyIndex.row().
00368   // sourceLastChild is vertically below the result we're looking for
00369   // and not necessarily in the correct parent.
00370   // We travel up through its parent hierarchy until we are in the
00371   // right parent, then return the correct sibling.
00372 
00373   // Source:           Proxy:    Row
00374   // - A               - A       - 0
00375   // - B               - B       - 1
00376   // - C               - C       - 2
00377   // - D               - D       - 3
00378   // - - E             - E       - 4
00379   // - - F             - F       - 5
00380   // - - G             - G       - 6
00381   // - - H             - H       - 7
00382   // - - I             - I       - 8
00383   // - - - J           - J       - 9
00384   // - - - K           - K       - 10
00385   // - - - L           - L       - 11
00386   // - - M             - M       - 12
00387   // - - N             - N       - 13
00388   // - O               - O       - 14
00389 
00390   // Note that L, N and O are lastChildIndexes, and therefore have a mapping. If we
00391   // are trying to map G from the proxy to the source, We at this point have an iterator
00392   // pointing to (L -> 11). The proxy row of G is 6. (proxyIndex.row() == 6). We seek the
00393   // sourceIndex which is vertically above L by the distance proxyLastRow - proxyIndex.row().
00394   // In this case the verticalDistance is 5.
00395 
00396   int verticalDistance = proxyLastRow - proxyIndex.row();
00397 
00398   // We traverse the ancestors of L, until we can index the desired row in the source.
00399 
00400   QModelIndex ancestor = sourceLastChild;
00401   while (ancestor.isValid())
00402   {
00403     const int ancestorRow = ancestor.row();
00404     if (verticalDistance <= ancestorRow)
00405     {
00406       return ancestor.sibling(ancestorRow - verticalDistance, proxyIndex.column());
00407     }
00408     verticalDistance -= (ancestorRow + 1);
00409     ancestor = ancestor.parent();
00410   }
00411   Q_ASSERT(!"Didn't find target row.");
00412   return QModelIndex();
00413 }
00414 
00415 QModelIndex KDescendantsProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
00416 {
00417   Q_D(const KDescendantsProxyModel);
00418 
00419   if (!sourceModel())
00420     return QModelIndex();
00421 
00422   if (d->m_mapping.isEmpty())
00423     return QModelIndex();
00424 
00425 
00426   {
00427     // TODO: Consider a parent Mapping to speed this up.
00428 
00429     Mapping::right_const_iterator it = d->m_mapping.rightConstBegin();
00430     const Mapping::right_const_iterator end = d->m_mapping.rightConstEnd();
00431     const QModelIndex sourceParent = sourceIndex.parent();
00432     Mapping::right_const_iterator result = end;
00433 
00434     for ( ; it != end; ++it )
00435     {
00436       QModelIndex index = it.value();
00437       bool found_block = false;
00438       while (index.isValid())
00439       {
00440         const QModelIndex ancestor = index.parent();
00441         if (ancestor == sourceParent && index.row() >= sourceIndex.row())
00442         {
00443           found_block = true;
00444           if (result == end || it.key() < result.key())
00445           {
00446             result = it;
00447             break; // Leave the while loop. index is still valid.
00448           }
00449         }
00450         index = ancestor;
00451       }
00452       if (found_block && !index.isValid())
00453         // Looked through the ascendants of it.key() without finding sourceParent.
00454         // That means we've already got the result we need.
00455         break;
00456     }
00457     Q_ASSERT(result != end);
00458     const QModelIndex sourceLastChild = result.value();
00459     int proxyRow = result.key();
00460     QModelIndex index = sourceLastChild;
00461     while (index.isValid())
00462     {
00463       const QModelIndex ancestor = index.parent();
00464       if (ancestor == sourceParent)
00465       {
00466         return createIndex(proxyRow - (index.row() - sourceIndex.row()), sourceIndex.column());
00467       }
00468       proxyRow -= (index.row() + 1);
00469       index = ancestor;
00470     }
00471     Q_ASSERT(!"Didn't find valid proxy mapping.");
00472     return QModelIndex();
00473   }
00474 
00475 }
00476 
00477 int KDescendantsProxyModel::columnCount(const QModelIndex &parent) const
00478 {
00479   if (parent.isValid() /* || rowCount(parent) == 0 */ || !sourceModel())
00480     return 0;
00481 
00482   return sourceModel()->columnCount();
00483 }
00484 
00485 QVariant KDescendantsProxyModel::data(const QModelIndex &index, int role) const
00486 {
00487   Q_D(const KDescendantsProxyModel );
00488 
00489   if (!sourceModel())
00490     return QVariant();
00491 
00492   if (!index.isValid())
00493     return sourceModel()->data(index, role);
00494 
00495   QModelIndex sourceIndex = mapToSource( index );
00496 
00497   if ((d->m_displayAncestorData) && ( role == Qt::DisplayRole ) )
00498   {
00499     if (!sourceIndex.isValid())
00500     {
00501       return QVariant();
00502     }
00503     QString displayData = sourceIndex.data().toString();
00504     sourceIndex = sourceIndex.parent();
00505     while (sourceIndex.isValid())
00506     {
00507       displayData.prepend(d->m_ancestorSeparator);
00508       displayData.prepend(sourceIndex.data().toString());
00509       sourceIndex = sourceIndex.parent();
00510     }
00511     return displayData;
00512   } else {
00513     return sourceIndex.data(role);
00514   }
00515 }
00516 
00517 QVariant KDescendantsProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
00518 {
00519   if (!sourceModel() || columnCount() <= section)
00520     return QVariant();
00521 
00522   return QAbstractProxyModel::headerData(section, orientation, role);
00523 }
00524 
00525 Qt::ItemFlags KDescendantsProxyModel::flags(const QModelIndex &index) const
00526 {
00527   if (!index.isValid() || !sourceModel())
00528     return QAbstractProxyModel::flags(index);
00529 
00530   const QModelIndex srcIndex = mapToSource(index);
00531   Q_ASSERT(srcIndex.isValid());
00532   return sourceModel()->flags(srcIndex);
00533 }
00534 
00535 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
00536 {
00537   Q_Q(KDescendantsProxyModel);
00538 
00539   if (!q->sourceModel()->hasChildren(parent))
00540   {
00541     // parent was not a parent before.
00542     return;
00543   }
00544 
00545   int proxyStart = -1;
00546 
00547   const int rowCount = q->sourceModel()->rowCount(parent);
00548 
00549   if (rowCount > start)
00550   {
00551     const QModelIndex belowStart = q->sourceModel()->index(start, 0, parent);
00552     proxyStart = q->mapFromSource(belowStart).row();
00553   } else if (rowCount == 0)
00554   {
00555     proxyStart = q->mapFromSource(parent).row() + 1;
00556   } else {
00557     Q_ASSERT(rowCount == start);
00558     static const int column = 0;
00559     QModelIndex idx = q->sourceModel()->index(rowCount - 1, column, parent);
00560     while (q->sourceModel()->hasChildren(idx))
00561     {
00562       idx = q->sourceModel()->index(q->sourceModel()->rowCount(idx) - 1, column, idx);
00563     }
00564     // The last item in the list is getting a sibling below it.
00565     proxyStart = q->mapFromSource(idx).row() + 1;
00566   }
00567   const int proxyEnd = proxyStart + (end - start);
00568 
00569   m_insertPair = qMakePair(proxyStart, proxyEnd);
00570   q->beginInsertRows(QModelIndex(), proxyStart, proxyEnd);
00571 }
00572 
00573 void KDescendantsProxyModelPrivate::sourceRowsInserted(const QModelIndex &parent, int start, int end)
00574 {
00575   Q_Q(KDescendantsProxyModel);
00576 
00577   const QModelIndex sourceStart = q->sourceModel()->index(start, 0, parent);
00578   Q_ASSERT(sourceStart.isValid());
00579 
00580   const int rowCount = q->sourceModel()->rowCount(parent);
00581   Q_ASSERT(rowCount > 0);
00582 
00583   const int difference = end - start + 1;
00584 
00585   if (rowCount == difference)
00586   {
00587     // @p parent was not a parent before.
00588     m_pendingParents.append(parent);
00589     scheduleProcessPendingParents();
00590     return;
00591   }
00592 
00593   const int proxyStart = m_insertPair.first;
00594 
00595   Q_ASSERT(proxyStart >= 0);
00596 
00597   updateInternalIndexes(proxyStart, difference);
00598 
00599   if (rowCount - 1 == end)
00600   {
00601     // The previously last row (the mapped one) is no longer the last.
00602     // For example,
00603 
00604     // - A            - A           0
00605     // - - B          - B           1
00606     // - - C          - C           2
00607     // - - - D        - D           3
00608     // - - - E   ->   - E           4
00609     // - - F          - F           5
00610     // - - G     ->   - G           6
00611     // - H            - H           7
00612     // - I       ->   - I           8
00613 
00614     // As last children, E, F and G have mappings.
00615     // Consider that 'J' is appended to the children of 'C', below 'E'.
00616 
00617     // - A            - A           0
00618     // - - B          - B           1
00619     // - - C          - C           2
00620     // - - - D        - D           3
00621     // - - - E   ->   - E           4
00622     // - - - J        - ???         5
00623     // - - F          - F           6
00624     // - - G     ->   - G           7
00625     // - H            - H           8
00626     // - I       ->   - I           9
00627 
00628     // The updateInternalIndexes call above will have updated the F and G mappings correctly because proxyStart is 5.
00629     // That means that E -> 4 was not affected by the updateInternalIndexes call.
00630     // Now the mapping for E -> 4 needs to be updated so that it's a mapping for J -> 5.
00631 
00632     Q_ASSERT(!m_mapping.isEmpty());
00633     static const int column = 0;
00634     const QModelIndex oldIndex = q->sourceModel()->index(rowCount - 1 - difference, column, parent);
00635     Q_ASSERT(m_mapping.leftContains(oldIndex));
00636 
00637     // oldIndex is E in the source. proxyRow is 4.
00638     const int proxyRow = m_mapping.takeLeft(oldIndex);
00639     const QModelIndex newIndex = q->sourceModel()->index(rowCount - 1, column, parent);
00640 
00641     // newIndex is J. (proxyRow + difference) is 5.
00642     m_mapping.insert(newIndex, proxyRow + difference);
00643   }
00644 
00645   for (int row = start; row <= end; ++row)
00646   {
00647     static const int column = 0;
00648     const QModelIndex idx = q->sourceModel()->index(row, column, parent);
00649     Q_ASSERT(idx.isValid());
00650     if (q->sourceModel()->hasChildren(idx))
00651       m_pendingParents.append(idx);
00652   }
00653 
00654   m_rowCount += difference;
00655 
00656   scheduleProcessPendingParents();
00657   q->endInsertRows();
00658 }
00659 
00660 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
00661 {
00662   Q_Q(KDescendantsProxyModel);
00663 
00664   const int proxyStart = q->mapFromSource(q->sourceModel()->index(start, 0, parent)).row();
00665 
00666   static const int column = 0;
00667   QModelIndex idx = q->sourceModel()->index(end, column, parent);
00668   while (q->sourceModel()->hasChildren(idx))
00669   {
00670     idx = q->sourceModel()->index(q->sourceModel()->rowCount(idx) - 1, column, idx);
00671   }
00672   const int proxyEnd = q->mapFromSource(idx).row();
00673 
00674   m_removePair = qMakePair(proxyStart, proxyEnd);
00675 
00676   q->beginRemoveRows(QModelIndex(), proxyStart, proxyEnd);
00677 }
00678 
00679 void KDescendantsProxyModelPrivate::sourceRowsRemoved(const QModelIndex &parent, int start, int end)
00680 {
00681   Q_Q(KDescendantsProxyModel);
00682   Q_UNUSED(end)
00683 
00684   const int rowCount = q->sourceModel()->rowCount(parent);
00685 
00686 
00687   const int proxyStart = m_removePair.first;
00688   const int proxyEnd = m_removePair.second;
00689 
00690   const int difference = proxyEnd - proxyStart + 1;
00691   {
00692     Mapping::right_iterator it = m_mapping.rightLowerBound(proxyStart);
00693     const Mapping::right_iterator endIt = m_mapping.rightUpperBound(proxyEnd);
00694 
00695     if (endIt != m_mapping.rightEnd())
00696       while (it != endIt)
00697         it = m_mapping.eraseRight(it);
00698     else
00699       while (it != m_mapping.rightUpperBound(proxyEnd))
00700         it = m_mapping.eraseRight(it);
00701   }
00702 
00703   m_removePair = qMakePair(-1, -1);
00704   m_rowCount -= difference;
00705   Q_ASSERT(m_rowCount >= 0);
00706 
00707   updateInternalIndexes(proxyStart, -1 * difference);
00708 
00709   if (rowCount == start && rowCount != 0)
00710   {
00711     static const int column = 0;
00712     const QModelIndex newIndex = q->sourceModel()->index(rowCount - 1, column, parent);
00713     m_mapping.insert(newIndex, proxyStart - 1);
00714   }
00715 
00716   q->endRemoveRows();
00717 }
00718 
00719 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeMoved(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destStart)
00720 {
00721   Q_UNUSED(srcParent)
00722   Q_UNUSED(srcStart)
00723   Q_UNUSED(srcEnd)
00724   Q_UNUSED(destParent)
00725   Q_UNUSED(destStart)
00726   Q_Q(KDescendantsProxyModel);
00727   q->beginResetModel();
00728 }
00729 
00730 void KDescendantsProxyModelPrivate::sourceRowsMoved(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destStart)
00731 {
00732   Q_UNUSED(srcParent)
00733   Q_UNUSED(srcStart)
00734   Q_UNUSED(srcEnd)
00735   Q_UNUSED(destParent)
00736   Q_UNUSED(destStart)
00737   Q_Q(KDescendantsProxyModel);
00738   resetInternalData();
00739   q->endResetModel();
00740 }
00741 
00742 void KDescendantsProxyModelPrivate::sourceModelAboutToBeReset()
00743 {
00744   Q_Q(KDescendantsProxyModel);
00745   q->beginResetModel();
00746 }
00747 
00748 void KDescendantsProxyModelPrivate::sourceModelReset()
00749 {
00750   Q_Q(KDescendantsProxyModel);
00751   resetInternalData();
00752   if (q->sourceModel()->hasChildren())
00753   {
00754     m_pendingParents.append(QModelIndex());
00755     scheduleProcessPendingParents();
00756   }
00757   q->endResetModel();
00758 }
00759 
00760 void KDescendantsProxyModelPrivate::sourceLayoutAboutToBeChanged()
00761 {
00762   Q_Q(KDescendantsProxyModel);
00763 
00764   if (m_ignoreNextLayoutChanged) {
00765       m_ignoreNextLayoutChanged = false;
00766       return;
00767   }
00768 
00769   if (m_mapping.isEmpty())
00770     return;
00771 
00772   QPersistentModelIndex srcPersistentIndex;
00773   foreach(const QPersistentModelIndex &proxyPersistentIndex, q->persistentIndexList()) {
00774       m_proxyIndexes << proxyPersistentIndex;
00775       Q_ASSERT(proxyPersistentIndex.isValid());
00776       srcPersistentIndex = q->mapToSource(proxyPersistentIndex);
00777       Q_ASSERT(srcPersistentIndex.isValid());
00778       m_layoutChangePersistentIndexes << srcPersistentIndex;
00779   }
00780 
00781   q->layoutAboutToBeChanged();
00782 }
00783 
00784 void KDescendantsProxyModelPrivate::sourceLayoutChanged()
00785 {
00786   Q_Q(KDescendantsProxyModel);
00787 
00788   if (m_ignoreNextLayoutAboutToBeChanged) {
00789       m_ignoreNextLayoutAboutToBeChanged = false;
00790       return;
00791   }
00792 
00793   if (m_mapping.isEmpty())
00794     return;
00795 
00796   m_rowCount = 0;
00797 
00798   synchronousMappingRefresh();
00799 
00800   for (int i = 0; i < m_proxyIndexes.size(); ++i) {
00801       q->changePersistentIndex(m_proxyIndexes.at(i), q->mapFromSource(m_layoutChangePersistentIndexes.at(i)));
00802   }
00803 
00804   m_layoutChangePersistentIndexes.clear();
00805   m_proxyIndexes.clear();
00806 
00807   q->layoutChanged();
00808 }
00809 
00810 void KDescendantsProxyModelPrivate::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
00811 {
00812   Q_Q(KDescendantsProxyModel);
00813 
00814   const int topRow = topLeft.row();
00815   const int bottomRow = bottomRight.row();
00816 
00817   for(int i = topRow; i <= bottomRow; ++i)
00818   {
00819     const QModelIndex sourceTopLeft = q->sourceModel()->index(i, topLeft.column(), topLeft.parent());
00820     const QModelIndex proxyTopLeft = q->mapFromSource(sourceTopLeft);
00821     // TODO. If an index does not have any descendants, then we can emit in blocks of rows.
00822     // As it is we emit once for each row.
00823     const QModelIndex sourceBottomRight = q->sourceModel()->index(i, bottomRight.column(), bottomRight.parent());
00824     const QModelIndex proxyBottomRight = q->mapFromSource(sourceBottomRight);
00825     emit q->dataChanged(proxyTopLeft, proxyBottomRight);
00826   }
00827 }
00828 
00829 void KDescendantsProxyModelPrivate::sourceModelDestroyed()
00830 {
00831   Q_Q(KDescendantsProxyModel);
00832   resetInternalData();
00833   q->endResetModel();
00834 }
00835 
00836 QMimeData* KDescendantsProxyModel::mimeData( const QModelIndexList & indexes ) const
00837 {
00838   if (!sourceModel())
00839     return QAbstractProxyModel::mimeData(indexes);
00840   Q_ASSERT(sourceModel());
00841   QModelIndexList sourceIndexes;
00842   foreach(const QModelIndex& index, indexes)
00843     sourceIndexes << mapToSource(index);
00844   return sourceModel()->mimeData(sourceIndexes);
00845 }
00846 
00847 QStringList KDescendantsProxyModel::mimeTypes() const
00848 {
00849   if (!sourceModel())
00850     return QAbstractProxyModel::mimeTypes();
00851   Q_ASSERT(sourceModel());
00852   return sourceModel()->mimeTypes();
00853 }
00854 
00855 Qt::DropActions KDescendantsProxyModel::supportedDropActions() const
00856 {
00857   if (!sourceModel())
00858     return QAbstractProxyModel::supportedDropActions();
00859   return sourceModel()->supportedDropActions();
00860 }
00861 
00862 #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
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • 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.1
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