akonadi
flatcollectionproxymodel.cpp
00001 /* 00002 Copyright (c) 2008 Volker Krause <vkrause@kde.org> 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 #include "flatcollectionproxymodel_p.h" 00021 00022 #include <kdebug.h> 00023 00024 using namespace Akonadi; 00025 00029 class FlatCollectionProxyModel::Private 00030 { 00031 public: 00032 Private( FlatCollectionProxyModel* parent ) : q( parent ) {} 00033 00034 // ### SLOW! 00035 static int totalCount( QAbstractItemModel *model, const QModelIndex &index ) 00036 { 00037 Q_ASSERT( model ); 00038 const int rows = model->rowCount( index ); 00039 int count = rows; 00040 for ( int i = 0; i < rows; ++i ) { 00041 QModelIndex current = model->index( i, 0, index ); 00042 if ( current.isValid() ) 00043 count += totalCount( model, current ); 00044 } 00045 return count; 00046 } 00047 00048 // ### EVEN SLOWER, and even called multiple times in a row! 00049 static QModelIndex findSourceIndex( QAbstractItemModel *model, int _row, int col, const QModelIndex &parent = QModelIndex() ) 00050 { 00051 int row = _row; 00052 Q_ASSERT( model ); 00053 for ( int i = 0; i <= row; ++i ) { 00054 QModelIndex current = model->index( i, col, parent ); 00055 if ( i == row ) 00056 return current; 00057 const int childCount = totalCount( model, current ); 00058 if ( childCount >= ( row - i ) ) 00059 return findSourceIndex( model, row - i - 1, col, current ); 00060 else 00061 row -= childCount; 00062 } 00063 Q_ASSERT( false ); 00064 return QModelIndex(); 00065 } 00066 00067 void sourceDataChanged( const QModelIndex &sourceTopLeft, const QModelIndex &sourceBottomRight ) 00068 { 00069 if ( sourceTopLeft != sourceBottomRight ) { 00070 emit q->dataChanged( q->mapFromSource( sourceTopLeft ), q->mapFromSource( sourceBottomRight ) ); 00071 } else { 00072 const QModelIndex proxyIndex = q->mapFromSource( sourceTopLeft ); 00073 emit q->dataChanged( proxyIndex, proxyIndex ); 00074 } 00075 } 00076 00077 FlatCollectionProxyModel *q; 00078 }; 00079 00080 FlatCollectionProxyModel::FlatCollectionProxyModel(QObject * parent) : 00081 QAbstractProxyModel( parent ), 00082 d( new Private( this ) ) 00083 { 00084 } 00085 00086 FlatCollectionProxyModel::~FlatCollectionProxyModel() 00087 { 00088 delete d; 00089 } 00090 00091 void FlatCollectionProxyModel::setSourceModel(QAbstractItemModel * sourceModel) 00092 { 00093 QAbstractProxyModel::setSourceModel( sourceModel ); 00094 connect( sourceModel, SIGNAL( modelReset() ), SIGNAL( modelReset() ) ); 00095 connect( sourceModel, SIGNAL( layoutChanged() ), SIGNAL( layoutChanged() ) ); 00096 connect( sourceModel, SIGNAL( dataChanged( const QModelIndex&, const QModelIndex& ) ), 00097 SLOT( sourceDataChanged( const QModelIndex&, const QModelIndex& ) ) ); 00098 } 00099 00100 int FlatCollectionProxyModel::rowCount(const QModelIndex & parent) const 00101 { 00102 if ( parent.isValid() ) 00103 return 0; 00104 return d->totalCount( sourceModel(), mapToSource( parent ) ); 00105 } 00106 00107 int FlatCollectionProxyModel::columnCount(const QModelIndex & parent) const 00108 { 00109 return sourceModel()->columnCount( mapToSource( parent ) ); 00110 } 00111 00112 QModelIndex FlatCollectionProxyModel::index(int row, int column, const QModelIndex & parent) const 00113 { 00114 Q_UNUSED( parent ); 00115 return createIndex( row, column ); 00116 } 00117 00118 QModelIndex FlatCollectionProxyModel::parent(const QModelIndex & index) const 00119 { 00120 Q_UNUSED( index ); 00121 return QModelIndex(); 00122 } 00123 00124 QModelIndex FlatCollectionProxyModel::mapToSource(const QModelIndex & proxyIndex) const 00125 { 00126 if ( !proxyIndex.isValid() ) 00127 return QModelIndex(); 00128 return d->findSourceIndex( sourceModel(), proxyIndex.row(), proxyIndex.column() ); 00129 } 00130 00131 QModelIndex FlatCollectionProxyModel::mapFromSource(const QModelIndex & sourceIndex) const 00132 { 00133 if ( !sourceIndex.isValid() ) 00134 return QModelIndex(); 00135 int row = 0; 00136 QModelIndex current = sourceIndex; 00137 while ( current.parent() != QModelIndex() ) { 00138 row += current.row() + 1; 00139 for ( int i = current.row() - 1; i >= 0; --i ) 00140 row += d->totalCount( sourceModel(), sourceModel()->index( i, 0, current.parent() ) ); 00141 current = current.parent(); 00142 } 00143 row += current.row(); 00144 for ( int i = current.row() - 1; i >= 0; --i ) 00145 row += d->totalCount( sourceModel(), sourceModel()->index( i, 0 ) ); 00146 return createIndex( row, sourceIndex.column() ); 00147 } 00148 00149 QVariant FlatCollectionProxyModel::data(const QModelIndex & index, int role) const 00150 { 00151 if ( role == Qt::DisplayRole ) { 00152 QModelIndex sourceIndex = mapToSource( index ); 00153 QString name = sourceIndex.data( role ).toString(); 00154 sourceIndex = sourceIndex.parent(); 00155 while ( sourceIndex.isValid() ) { 00156 name.prepend( sourceIndex.data( role ).toString() + QLatin1String( "/" ) ); 00157 sourceIndex = sourceIndex.parent(); 00158 } 00159 return name; 00160 } 00161 return QAbstractProxyModel::data( index, role ); 00162 } 00163 00164 #include "flatcollectionproxymodel_p.moc"