• Skip to content
  • Skip to link menu
KDE 4.4 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 
00004     This library is free software; you can redistribute it and/or modify it
00005     under the terms of the GNU Library General Public License as published by
00006     the Free Software Foundation; either version 2 of the License, or (at your
00007     option) any later version.
00008 
00009     This library is distributed in the hope that it will be useful, but WITHOUT
00010     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00011     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00012     License for more details.
00013 
00014     You should have received a copy of the GNU Library General Public License
00015     along with this library; see the file COPYING.LIB.  If not, write to the
00016     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017     02110-1301, USA.
00018 */
00019 
00020 
00021 #include "kdescendantsproxymodel_p.h"
00022 
00023 #include "kdebug.h"
00024 
00025 #include <QtCore/QStringList>
00026 
00032 class KDescendantsProxyModelPrivate
00033 {
00034   public:
00035 
00036   KDescendantsProxyModelPrivate(KDescendantsProxyModel *model)
00037     : q_ptr(model),
00038       m_displayAncestorData( false ),
00039       m_ancestorSeparator( QLatin1String( " / " ) )
00040     {
00041     }
00042 
00043   Q_DECLARE_PUBLIC( KDescendantsProxyModel )
00044   KDescendantsProxyModel *q_ptr;
00065   QModelIndex findSourceIndexForRow( int row, QModelIndex sourceParent) const;
00066 
00075   bool isDescended(const QModelIndex &sourceIndex) const;
00076 
00099   int descendantCount(const QModelIndex &sourceIndex, int ignoreTerminals=ObserveTerminals) const;
00100 
00101   enum TerminalIgnorance
00102   {
00103     ObserveTerminals,
00104     IgnoreTerminals
00105   };
00106 
00131   int descendedRow(const QModelIndex &sourceIndex) const;
00132 
00133   QModelIndexList matchDescendants(const QModelIndex& start, int role, const QVariant& value, int hits, Qt::MatchFlags flags, int until, const bool matchAll) const;
00134 
00135   enum Operation
00136   {
00137     InsertOperation,
00138     RemoveOperation
00139   };
00140 
00141   void insertOrRemoveRows(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, int type);
00142 
00143   void sourceRowsAboutToBeInserted(const QModelIndex &, int start, int end);
00144   void sourceRowsInserted(const QModelIndex &, int start, int end);
00145   void sourceRowsAboutToBeRemoved(const QModelIndex &, int start, int end);
00146   void sourceRowsRemoved(const QModelIndex &, int start, int end);
00147   void sourceRowsAboutToBeMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destParent, int destRow);
00148   void sourceRowsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destParent, int destRow);
00149   void sourceModelAboutToBeReset();
00150   void sourceModelReset();
00151   void sourceLayoutAboutToBeChanged();
00152   void sourceLayoutChanged();
00153   void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
00154 
00155   QPersistentModelIndex m_rootDescendIndex;
00156   // Hmm, if I make this QHash<QPersistentModelIndex, int> instead then moves are
00157   // automatically handled. Nope, they're not. deeper levels than base would
00158   // still need to be updated or calculated.
00159 
00160   mutable QHash<qint64, int> m_descendantsCount;
00161 
00162   bool m_displayAncestorData;
00163   QString m_ancestorSeparator;
00164 
00165   QList<QPersistentModelIndex> m_terminalIndexes;
00166   void descendNewIndexes();
00167 
00168   QList<QPersistentModelIndex> m_layoutChangePersistentIndexes;
00169   QModelIndexList m_proxyIndexes;
00170 
00171 };
00172 
00173 KDescendantsProxyModel::KDescendantsProxyModel( QObject *parent )
00174       : QAbstractProxyModel( parent ),
00175         d_ptr( new KDescendantsProxyModelPrivate(this) )
00176 {
00177   Q_D(KDescendantsProxyModel);
00178 
00179   d->m_rootDescendIndex = QModelIndex();
00180 }
00181 
00182 void KDescendantsProxyModel::setRootIndex(const QModelIndex &index)
00183 {
00184   Q_D(KDescendantsProxyModel);
00185 
00186   if (index.isValid())
00187     Q_ASSERT(index.model() == sourceModel());
00188 
00189   d->m_rootDescendIndex = index;
00190   d->m_descendantsCount.clear();
00191   reset();
00192 }
00193 
00194 KDescendantsProxyModel::~KDescendantsProxyModel()
00195 {
00196   Q_D(KDescendantsProxyModel);
00197   d->m_descendantsCount.clear();
00198   delete d_ptr;
00199 }
00200 
00201 QModelIndex KDescendantsProxyModelPrivate::findSourceIndexForRow( int row, QModelIndex idx ) const
00202 {
00203     Q_Q( const KDescendantsProxyModel );
00204     int childCount = q->sourceModel()->rowCount(idx);
00205     for (int childRow = 0; childRow < childCount; childRow++)
00206     {
00207       QModelIndex childIndex = q->sourceModel()->index(childRow, 0, idx);
00208       if (row == 0)
00209       {
00210         return childIndex;
00211       }
00212       row--;
00213       if (q->sourceModel()->hasChildren(childIndex))
00214       {
00215         int childDesc = descendantCount(childIndex);
00216         if (childDesc > row)
00217         {
00218           return findSourceIndexForRow(row, childIndex);
00219         }
00220         row -= childDesc;
00221       }
00222     }
00223 
00224     // This should probably never happen if you use descendantCount before calling this method.
00225     return QModelIndex();
00226 }
00227 
00228 void KDescendantsProxyModel::setSourceModel(QAbstractItemModel * sourceModel)
00229 {
00230   Q_D(KDescendantsProxyModel);
00231 
00232   disconnect( sourceModel, SIGNAL(modelReset()), this, SLOT( sourceModelReset() ) );
00233   disconnect( sourceModel, SIGNAL(modelAboutToBeReset()), this, SLOT(sourceModelAboutToBeReset() ) );
00234   disconnect( sourceModel, SIGNAL(layoutChanged()), this, SLOT(sourceLayoutChanged()) );
00235   disconnect( sourceModel, SIGNAL(layoutAboutToBeChanged()), this, SLOT(sourceLayoutAboutToBeChanged()) );
00236   disconnect( sourceModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
00237           this, SLOT(sourceDataChanged(const QModelIndex &, const QModelIndex & ) ) );
00238   disconnect( sourceModel, SIGNAL(rowsInserted(const QModelIndex, int, int)),
00239           this, SLOT(sourceRowsInserted(const QModelIndex, int, int)) );
00240   disconnect( sourceModel, SIGNAL(rowsAboutToBeInserted(const QModelIndex, int, int)),
00241           this, SLOT(sourceRowsAboutToBeInserted(const QModelIndex, int, int)) );
00242   disconnect( sourceModel, SIGNAL(rowsRemoved(const QModelIndex, int, int)),
00243           this, SLOT(sourceRowsRemoved(const QModelIndex, int, int)) );
00244   disconnect( sourceModel, SIGNAL(rowsAboutToBeRemoved(const QModelIndex, int, int)),
00245           this, SLOT(sourceRowsAboutToBeRemoved(const QModelIndex, int, int)) );
00246   disconnect( sourceModel, SIGNAL(rowsMoved(const QModelIndex, int, int, const QModelIndex, int)),
00247           this, SLOT(sourceRowsMoved(const QModelIndex, int, int, const QModelIndex, int)) );
00248   disconnect( sourceModel, SIGNAL(rowsAboutToBeMoved(const QModelIndex, int, int, const QModelIndex, int)),
00249           this, SLOT(sourceRowsAboutToBeMoved(const QModelIndex, int, int, const QModelIndex, int) ) );
00250 
00251   QAbstractProxyModel::setSourceModel( sourceModel );
00252   connect( sourceModel, SIGNAL(modelReset()), SLOT( sourceModelReset() ) );
00253   connect( sourceModel, SIGNAL(modelAboutToBeReset()), SLOT(sourceModelAboutToBeReset() ) );
00254   connect( sourceModel, SIGNAL(layoutChanged()), SLOT(sourceLayoutChanged()) );
00255   connect( sourceModel, SIGNAL(layoutAboutToBeChanged()), SLOT(sourceLayoutAboutToBeChanged()) );
00256   connect( sourceModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
00257           SLOT(sourceDataChanged(const QModelIndex &, const QModelIndex & ) ) );
00258   connect( sourceModel, SIGNAL(rowsInserted(const QModelIndex, int, int)),
00259           SLOT(sourceRowsInserted(const QModelIndex, int, int)) );
00260   connect( sourceModel, SIGNAL(rowsAboutToBeInserted(const QModelIndex, int, int)),
00261           SLOT(sourceRowsAboutToBeInserted(const QModelIndex, int, int)) );
00262   connect( sourceModel, SIGNAL(rowsRemoved(const QModelIndex, int, int)),
00263           SLOT(sourceRowsRemoved(const QModelIndex, int, int)) );
00264   connect( sourceModel, SIGNAL(rowsAboutToBeRemoved(const QModelIndex, int, int)),
00265           SLOT(sourceRowsAboutToBeRemoved(const QModelIndex, int, int)) );
00266   connect( sourceModel, SIGNAL(rowsMoved(const QModelIndex, int, int, const QModelIndex, int)),
00267           SLOT(sourceRowsMoved(const QModelIndex, int, int, const QModelIndex, int)) );
00268   connect( sourceModel, SIGNAL(rowsAboutToBeMoved(const QModelIndex, int, int, const QModelIndex, int)),
00269           SLOT(sourceRowsAboutToBeMoved(const QModelIndex, int, int, const QModelIndex, int) ) );
00270 
00271   d->m_descendantsCount.clear();
00272   reset();
00273 }
00274 
00275 bool KDescendantsProxyModelPrivate::isDescended(const QModelIndex &sourceIndex) const
00276 {
00277   Q_Q(const KDescendantsProxyModel);
00278 
00279   if (sourceIndex == m_rootDescendIndex)
00280   {
00281     return false;
00282   }
00283 
00284   QModelIndex parentIndex = q->sourceModel()->parent(sourceIndex);
00285 
00286   if (parentIndex == m_rootDescendIndex)
00287   {
00288     return true;
00289   }
00290   bool found = false;
00291 
00292   forever
00293   {
00294     parentIndex = parentIndex.parent();
00295     if (parentIndex == m_rootDescendIndex)
00296     {
00297       found = true;
00298       break;
00299     }
00300     if (!parentIndex.isValid())
00301       break;
00302   }
00303   return found;
00304 }
00305 
00306 int KDescendantsProxyModelPrivate::descendedRow(const QModelIndex &sourceIndex) const
00307 {
00308   Q_Q(const KDescendantsProxyModel);
00309   QModelIndex parentIndex = sourceIndex.parent();
00310   int row = sourceIndex.row();
00311 
00312   for (int childRow = 0; childRow < sourceIndex.row(); childRow++ )
00313   {
00314     QModelIndex childIndex = q->sourceModel()->index( childRow, sourceIndex.column(), parentIndex );
00315     if (q->sourceModel()->hasChildren(childIndex))
00316       row += descendantCount(childIndex);
00317   }
00318 
00319   if (parentIndex == m_rootDescendIndex)
00320   {
00321     // Return 0 instead of -1 for an invalid index.
00322     if (row < 0)
00323     {
00324       return 0;
00325     }
00326     return row;
00327   }
00328   else if(!parentIndex.isValid())
00329   {
00330     // Should never happen.
00331     // Someone must have called this with sourceIndex outside of m_rootDescendIndex
00332     return 0;
00333   }
00334   else {
00335   int dr = descendedRow(parentIndex);
00336     return row + dr + 1;
00337   }
00338 }
00339 
00340 QModelIndex KDescendantsProxyModel::mapFromSource(const QModelIndex & sourceIndex) const
00341 {
00342   Q_D(const KDescendantsProxyModel);
00343 
00344   if (sourceIndex == d->m_rootDescendIndex)
00345   {
00346     return QModelIndex();
00347   }
00348 
00349   if ( d->isDescended( sourceIndex ) )
00350   {
00351     int row = d->descendedRow( sourceIndex );
00352     if (row < 0)
00353       return QModelIndex();
00354     return createIndex( row, sourceIndex.column() );
00355   } else {
00356     return QModelIndex();
00357   }
00358 }
00359 
00360 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeInserted(const QModelIndex &sourceParentIndex, int start, int end)
00361 {
00362   insertOrRemoveRows(sourceParentIndex, start, end, InsertOperation);
00363 }
00364 
00365 void KDescendantsProxyModelPrivate::insertOrRemoveRows(const QModelIndex &sourceParentIndex, int start, int end, int operationType)
00366 {
00367 
00368   Q_Q(KDescendantsProxyModel);
00369 
00370   int c = descendedRow(sourceParentIndex);
00371 
00372 // Can't simply get the descendantCount of sourceModel()->index(start, 0, sourceParent),
00373 // because start might not exist as a child of sourceParent yet.
00374 // Maybe I should special case (!sourceParent.hasChildren) instead.
00375 
00376   // Only the first column can have child items. It is only those we need to count.
00377   const int column = 0;
00378   for (int childRow = 0; childRow < start; childRow++)
00379   {
00380     QModelIndex childIndex = q->sourceModel()->index( childRow, column, sourceParentIndex );
00381 //     kDebug() << childIndex << descendantCount(childIndex);
00382     if (q->sourceModel()->hasChildren(childIndex))
00383       c += descendantCount(childIndex);
00384   }
00385 
00386 //   @code
00387 //   -> Item 0-0 (this is row-depth)
00388 //   -> -> Item 0-1
00389 //   -> -> Item 1-1
00390 //   -> -> -> Item 0-2
00391 //   -> -> -> Item 1-2
00392 //   -> Item 1-0
00393 //   @endcode
00394 //
00395 // If the sourceModel reports that a row is inserted between Item 0-2 Item 1-2,
00396 // this methods receives a sourceParent of Item 1-1, and a start of 1.
00397 // It has a descendedRow of 2. The proxied start is the number of rows above parent,
00398 // and the start below parent. The parent itself must also be accounted for if it
00399 // is part of the model.
00400 
00401 // Check if it's descended instead?
00402 
00403   int proxy_start = c + start;
00404   int proxy_end = c + end;
00405 
00406   if (isDescended(sourceParentIndex))
00407   {
00408     proxy_start++;
00409     proxy_end++;
00410   }
00411 
00412   if (operationType == InsertOperation)
00413     q->beginInsertRows(m_rootDescendIndex, proxy_start, proxy_end);
00414   else if (operationType == RemoveOperation)
00415   {
00416     // need to notify that we're also removing the descendants.
00417     for (int childRow = start; childRow <= end; childRow++)
00418     {
00419       QModelIndex childIndex = q->sourceModel()->index(childRow, column, sourceParentIndex);
00420       if (q->sourceModel()->hasChildren(childIndex))
00421         proxy_end += descendantCount(childIndex);
00422     }
00423     Q_ASSERT( proxy_end <= q->rowCount() );
00424     q->beginRemoveRows(m_rootDescendIndex, proxy_start, proxy_end);
00425   }
00426 }
00427 
00428 void KDescendantsProxyModelPrivate::sourceRowsInserted(const QModelIndex &sourceParentIndex, int start, int end)
00429 {
00430   Q_Q(KDescendantsProxyModel);
00431 
00432   m_descendantsCount.clear();
00433 
00434   // Don't count the descendants of newly inserted indexes until after endInsertRows.
00435   // The reason for this is that at the time we emitted beginInsertRows, we couldn't count the descendants
00436   // of new items (they weren't known to the sourceModel), and now we can.
00437   const int column = 0;
00438   for (int childRow = start; childRow <= end; childRow++)
00439   {
00440     QModelIndex childIndex = q->sourceModel()->index( childRow, column, sourceParentIndex );
00441     m_terminalIndexes << QPersistentModelIndex(childIndex);
00442   }
00443 
00444   q->endInsertRows();
00445   descendNewIndexes();
00446 }
00447 
00448 void KDescendantsProxyModelPrivate::descendNewIndexes()
00449 {
00450   Q_Q(KDescendantsProxyModel);
00451 
00452   QMutableListIterator<QPersistentModelIndex> i(m_terminalIndexes);
00453   while (i.hasNext())
00454   {
00455     QModelIndex idx = i.next();
00456 
00457     int descCount = descendantCount(idx, IgnoreTerminals);
00458 
00459     if (descCount <= 0)
00460     {
00461       i.remove();
00462       continue;
00463     }
00464 
00465     // if descCount > 0, this is a new index which has new child indexes.
00466 
00467     int proxyStart = descendedRow(idx);
00468     // Need to ignore terminals so we know how many rows will be inserted by removing them.
00469     int proxyEnd = proxyStart + descendantCount(idx, IgnoreTerminals);
00470 
00471     if (isDescended(idx))
00472     {
00473       proxyStart++;
00474       proxyEnd++;
00475     }
00476     q->beginInsertRows(QModelIndex(), proxyStart, proxyEnd - 1 );
00477     i.remove();
00478     m_descendantsCount.clear();
00479     q->endInsertRows();
00480   }
00481 }
00482 
00483 
00484 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destParent, int destRow)
00485 {
00486   Q_Q(KDescendantsProxyModel);
00487   int c = descendedRow(parent);
00488   int d = descendedRow(destParent);
00489 
00490   bool allowMove = q->beginMoveRows(QModelIndex(), c+1+start, c+1+end, QModelIndex(), d+1+destRow);
00491   Q_ASSERT(allowMove);
00492 }
00493 
00494 void KDescendantsProxyModelPrivate::sourceRowsMoved(const QModelIndex &sourceParentIndex, int start, int end, const QModelIndex &destParentIndex, int destRow)
00495 {
00496   Q_Q(KDescendantsProxyModel);
00497   Q_UNUSED(sourceParentIndex);
00498   Q_UNUSED(start);
00499   Q_UNUSED(end);
00500   Q_UNUSED(destParentIndex);
00501   Q_UNUSED(destRow);
00502 
00503   m_descendantsCount.clear();
00504 
00505   q->endMoveRows();
00506 }
00507 
00508 
00509 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
00510 {
00511   insertOrRemoveRows(parent, start, end, RemoveOperation);
00512 }
00513 
00514 void KDescendantsProxyModelPrivate::sourceRowsRemoved(const QModelIndex &sourceParentIndex, int start, int end)
00515 {
00516   Q_Q(KDescendantsProxyModel);
00517   Q_UNUSED(sourceParentIndex);
00518   Q_UNUSED(start);
00519   Q_UNUSED(end);
00520 
00521   m_descendantsCount.clear();
00522   q->endRemoveRows();
00523 }
00524 
00525 void KDescendantsProxyModelPrivate::sourceModelAboutToBeReset()
00526 {
00527   Q_Q(KDescendantsProxyModel);
00528   q->beginResetModel();
00529 }
00530 
00531 void KDescendantsProxyModelPrivate::sourceModelReset()
00532 {
00533   Q_Q(KDescendantsProxyModel);
00534 
00535   m_descendantsCount.clear();
00536   q->endResetModel();
00537 }
00538 
00539 void KDescendantsProxyModelPrivate::sourceLayoutAboutToBeChanged()
00540 {
00541   Q_Q(KDescendantsProxyModel);
00542 
00543   emit q->layoutAboutToBeChanged();
00544 
00545   foreach(const QPersistentModelIndex &proxyPersistentIndex, q->persistentIndexList())
00546   {
00547     m_proxyIndexes << proxyPersistentIndex;
00548     m_layoutChangePersistentIndexes << QPersistentModelIndex(q->mapToSource(proxyPersistentIndex));
00549   }
00550 }
00551 
00552 void KDescendantsProxyModelPrivate::sourceLayoutChanged()
00553 {
00554   Q_Q(KDescendantsProxyModel);
00555 
00556   for(int i = 0; i < m_proxyIndexes.size(); ++i)
00557   {
00558     q->changePersistentIndex(m_proxyIndexes.at(i), q->mapFromSource(m_layoutChangePersistentIndexes.at(i)));
00559   }
00560 
00561   m_layoutChangePersistentIndexes.clear();
00562   m_proxyIndexes.clear();
00563 
00564   m_descendantsCount.clear();
00565 
00566   emit q->layoutChanged();
00567 }
00568 
00569 QModelIndex KDescendantsProxyModel::mapToSource(const QModelIndex &proxyIndex) const
00570 {
00571   Q_D(const KDescendantsProxyModel);
00572 
00573   if (!proxyIndex.isValid())
00574     return d->m_rootDescendIndex;
00575 
00576   if (proxyIndex.column() >= sourceModel()->columnCount())
00577     return QModelIndex();
00578 
00579   QModelIndex idx = d->findSourceIndexForRow( proxyIndex.row(), d->m_rootDescendIndex );
00580 
00581   if (proxyIndex.column() > 0)
00582   {
00583     return sourceModel()->index(idx.row(), proxyIndex.column(), idx.parent());
00584   }
00585   return idx;
00586 }
00587 
00588 QVariant KDescendantsProxyModel::data(const QModelIndex & index, int role) const
00589 {
00590   Q_D(const KDescendantsProxyModel );
00591 
00592   if (!sourceModel())
00593     return QVariant();
00594 
00595   if (!index.isValid())
00596     return sourceModel()->data(index, role);
00597 
00598   QModelIndex sourceIndex = mapToSource( index );
00599 
00600   if ((d->m_displayAncestorData) && ( role == Qt::DisplayRole ) )
00601   {
00602     if (!sourceIndex.isValid())
00603     {
00604       return QVariant();
00605     }
00606     QString displayData = sourceIndex.data().toString();
00607     sourceIndex = sourceIndex.parent();
00608     while (sourceIndex.isValid())
00609     {
00610       displayData.prepend(d->m_ancestorSeparator);
00611       displayData.prepend(sourceIndex.data().toString());
00612       sourceIndex = sourceIndex.parent();
00613     }
00614     return displayData;
00615   } else {
00616     return sourceIndex.data(role);
00617   }
00618 
00619 }
00620 
00621 QMimeData* KDescendantsProxyModel::mimeData( const QModelIndexList & indexes ) const
00622 {
00623   Q_ASSERT(sourceModel());
00624   QModelIndexList sourceIndexes;
00625   foreach(const QModelIndex& index, indexes)
00626     sourceIndexes << mapToSource(index);
00627   return sourceModel()->mimeData(sourceIndexes);
00628 }
00629 
00630 QStringList KDescendantsProxyModel::mimeTypes() const
00631 {
00632   Q_ASSERT(sourceModel());
00633   return sourceModel()->mimeTypes();
00634 }
00635 
00636 bool KDescendantsProxyModel::hasChildren ( const QModelIndex & parent ) const
00637 {
00638   return rowCount(parent) > 0;
00639 }
00640 
00641 int KDescendantsProxyModel::rowCount(const QModelIndex & proxyIndex) const
00642 {
00643   Q_D(const KDescendantsProxyModel );
00644 
00645   if (!sourceModel() || proxyIndex.column() > 0)
00646     return 0;
00647 
00648   QModelIndex sourceIndex = mapToSource(proxyIndex);
00649 
00650   if (sourceIndex == d->m_rootDescendIndex)
00651   {
00652     int c = d->descendantCount(sourceIndex);
00653     return c;
00654   }
00655   return 0;
00656 }
00657 
00658 void KDescendantsProxyModelPrivate::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
00659 {
00660   Q_Q( KDescendantsProxyModel );
00661   int topRow = topLeft.row();
00662   int bottomRow = bottomRight.row();
00663 
00664   for(int i = topRow; i <= bottomRow; ++i)
00665   {
00666     QModelIndex sourceTopLeft = q->sourceModel()->index(i, topLeft.column(), topLeft.parent());
00667     QModelIndex proxyTopLeft = q->mapFromSource(sourceTopLeft);
00668     // TODO. If an index does not have any descendants, then we can emit in blocks of rows.
00669     // As it is we emit once for each row.
00670     QModelIndex sourceBottomRight = q->sourceModel()->index(i, bottomRight.column(), bottomRight.parent());
00671     QModelIndex proxyBottomRight = q->mapFromSource(sourceBottomRight);
00672     emit q->dataChanged(proxyTopLeft, proxyBottomRight);
00673   }
00674 }
00675 
00676 int KDescendantsProxyModelPrivate::descendantCount(const QModelIndex &sourceIndex, int ignoreTerminals) const
00677 {
00678   if (sourceIndex.column() > 0)
00679     return 0;
00680 
00681   if (ObserveTerminals == ignoreTerminals)
00682   {
00683     if (m_terminalIndexes.contains(sourceIndex))
00684     {
00685       return 0;
00686     }
00687   }
00688 
00689   Q_Q( const KDescendantsProxyModel );
00690   if (m_descendantsCount.contains(sourceIndex.internalId()))
00691   {
00692     return m_descendantsCount.value(sourceIndex.internalId());
00693   }
00694 
00695   int sourceIndexRowCount = q->sourceModel()->rowCount(sourceIndex);
00696   if (sourceIndexRowCount == 0)
00697     return 0;
00698   int c = 0;
00699   c += sourceIndexRowCount;
00700 
00701   int childRow = 0;
00702   QModelIndex childIndex = q->sourceModel()->index(childRow, 0, sourceIndex);
00703   while (childIndex.isValid())
00704   {
00705     c += descendantCount(childIndex);
00706     childRow++;
00707     childIndex = q->sourceModel()->index(childRow, 0, sourceIndex);
00708   }
00709 
00710   m_descendantsCount.insert( sourceIndex.internalId(), c );
00711 
00712   return c;
00713 }
00714 
00715 QModelIndex KDescendantsProxyModel::index(int r, int c, const QModelIndex& parent) const
00716 {
00717   Q_D(const KDescendantsProxyModel );
00718 
00719   if (!sourceModel())
00720     return QModelIndex();
00721 
00722 
00723   if ( (r < 0) || (c < 0) || (c >= sourceModel()->columnCount() ) )
00724     return QModelIndex();
00725 
00726   if ( r >= d->descendantCount(parent) )
00727     return QModelIndex();
00728 
00729   // TODO: Use is decended instead?
00730   if (parent.isValid())
00731     return QModelIndex();
00732 
00733   return createIndex(r, c);
00734 }
00735 
00736 QModelIndex KDescendantsProxyModel::parent(const QModelIndex& proxyIndex) const
00737 {
00738   Q_UNUSED(proxyIndex);
00739 
00740   return QModelIndex();
00741 }
00742 
00743 int KDescendantsProxyModel::columnCount(const QModelIndex &index) const
00744 {
00745   if (!sourceModel())
00746     return 0;
00747 
00748   return sourceModel()->columnCount();
00749 }
00750 
00751 void KDescendantsProxyModel::setDisplayAncestorData( bool display )
00752 {
00753   Q_D(KDescendantsProxyModel);
00754   d->m_displayAncestorData = display;
00755 }
00756 
00757 bool KDescendantsProxyModel::displayAncestorData() const
00758 {
00759   Q_D(const KDescendantsProxyModel );
00760   return d->m_displayAncestorData;
00761 }
00762 
00763 void KDescendantsProxyModel::setAncestorSeparator( const QString &separator )
00764 {
00765   Q_D(KDescendantsProxyModel);
00766   d->m_ancestorSeparator = separator;
00767 }
00768 
00769 QString KDescendantsProxyModel::ancestorSeparator() const
00770 {
00771   Q_D(const KDescendantsProxyModel );
00772   return d->m_ancestorSeparator;
00773 }
00774 
00775 Qt::ItemFlags KDescendantsProxyModel::flags( const QModelIndex &index ) const
00776 {
00777   // if index is invalid, it might be mapped to a valid source index with more flags.
00778   // Can't allow that...
00779   if (!index.isValid())
00780     return 0;
00781   return QAbstractProxyModel::flags(index);
00782 }
00783 
00784 QModelIndexList KDescendantsProxyModelPrivate::matchDescendants(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags, int until, const bool matchAll) const
00785 {
00786   Q_Q(const KDescendantsProxyModel);
00787   QModelIndexList matches;
00788 
00789   if (!start.isValid())
00790     return matches;
00791 
00792   const int column = start.column();
00793   const int firstRow = 0;
00794   QModelIndex idx = start;
00795 
00796   while (idx.row() <= until)
00797   {
00798     Q_ASSERT(idx.isValid());
00799 
00800     if (q->sourceModel()->hasChildren(idx))
00801     {
00802       QModelIndex firstChild = idx.child(firstRow, column);
00803       matches << q->match(q->mapFromSource(firstChild), role, value, hits, flags);
00804       if (!matchAll && (matches.size() >= hits))
00805       {
00806         return matches.mid(0, hits);
00807       }
00808     }
00809     int row = idx.row();
00810     if (row == until)
00811     {
00812       break;
00813     }
00814     idx = idx.sibling(row + 1, column);
00815   }
00816 
00817   return matches;
00818 }
00819 
00820 QModelIndexList KDescendantsProxyModel::match(const QModelIndex& start, int role, const QVariant& value, int hits, Qt::MatchFlags flags) const
00821 {
00822   Q_D(const KDescendantsProxyModel );
00823 
00824   // We only really need to do all this for the AmazingCompletionRole, but there's no clean way to
00825   // determine what that is.
00826 
00827   QModelIndexList sourceList;
00828   QModelIndexList proxyList;
00829 
00830   QModelIndex beginIndex = start;
00831   QModelIndex sourceStart = mapToSource(start);
00832   QModelIndex parent = sourceModel()->parent(sourceStart);
00833 
00834   int parentRowCount = sourceModel()->rowCount(sourceModel()->parent(sourceStart));
00835 
00836   const bool matchAll = (hits == -1);
00837   const int firstHit = 1;
00838   const int column = start.column();
00839   const int proxyRowCount = rowCount();
00840 
00841   Q_ASSERT(sourceStart.column() == start.column());
00842   sourceList = sourceModel()->match(sourceStart, role, value, firstHit, flags);
00843 
00844   int lastRow;
00845   if (sourceList.isEmpty())
00846   {
00847     lastRow = parentRowCount - 1;
00848     proxyList = d->matchDescendants(mapToSource(start), role, value, hits, flags, lastRow, matchAll);
00849 
00850     if (matchAll)
00851       return proxyList;
00852 
00853     return proxyList.mid(0, hits);
00854 
00855   } else {
00856     forever
00857     {
00858       QModelIndex firstIndexHit;
00859       if (sourceList.isEmpty())
00860       {
00861         lastRow = parentRowCount - 1;
00862       } else {
00863         firstIndexHit = sourceList.first();
00864 
00865         Q_ASSERT(firstIndexHit.column() == start.column());
00866 
00867         lastRow = firstIndexHit.row() - 1;
00868       }
00869 
00870       proxyList << d->matchDescendants(sourceStart, role, value, hits, flags, lastRow, matchAll);
00871 
00872       if (sourceList.isEmpty())
00873         break;
00874 
00875       QModelIndex proxyFirst = mapFromSource(firstIndexHit);
00876       proxyList << proxyFirst;
00877 
00878       if (!matchAll && ( proxyList.size() >= hits))
00879       {
00880         return proxyList.mid(0, hits);
00881       }
00882 
00883       if (proxyFirst.row() == proxyRowCount - 1)
00884         break;
00885 
00886       sourceStart = mapToSource(index(proxyFirst.row() + 1, proxyFirst.column()));
00887       Q_ASSERT(sourceStart.isValid());
00888 
00889       sourceList = sourceModel()->match(sourceStart, role, value, firstHit, flags);
00890     }
00891   }
00892 
00893   QModelIndex nextStart = start.sibling(start.row() + parentRowCount + 1, column);
00894   if (nextStart.isValid())
00895     proxyList << match(nextStart, role, value, hits, flags);
00896 
00897   if (matchAll)
00898     return proxyList;
00899 
00900   return proxyList.mid(0, hits);
00901 }
00902 
00903 Qt::DropActions KDescendantsProxyModel::supportedDropActions() const
00904 {
00905   Q_ASSERT(sourceModel());
00906   return sourceModel()->supportedDropActions();
00907 }
00908 
00909 #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.6.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