00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "entityorderproxymodel.h"
00024
00025 #include <QMimeData>
00026
00027 #include <KDE/KConfigGroup>
00028
00029 #include "collection.h"
00030 #include "item.h"
00031 #include "entitytreemodel.h"
00032
00033 namespace Akonadi
00034 {
00035
00036 class EntityOrderProxyModelPrivate
00037 {
00038 public:
00039 EntityOrderProxyModelPrivate( EntityOrderProxyModel *qq )
00040 : q_ptr( qq )
00041 {
00042
00043 }
00044
00045 void saveOrder( const QModelIndex &index );
00046
00047 KConfigGroup m_orderConfig;
00048
00049 Q_DECLARE_PUBLIC(EntityOrderProxyModel)
00050 EntityOrderProxyModel * const q_ptr;
00051
00052 };
00053
00054 }
00055
00056 using namespace Akonadi;
00057
00058 EntityOrderProxyModel::EntityOrderProxyModel( QObject* parent )
00059 : QSortFilterProxyModel(parent), d_ptr( new EntityOrderProxyModelPrivate( this ) )
00060 {
00061 setDynamicSortFilter(true);
00062 }
00063
00064 EntityOrderProxyModel::~EntityOrderProxyModel()
00065 {
00066 delete d_ptr;
00067 }
00068
00069 void EntityOrderProxyModel::setOrderConfig( KConfigGroup& configGroup )
00070 {
00071 Q_D( EntityOrderProxyModel );
00072 layoutAboutToBeChanged();
00073 d->m_orderConfig = configGroup;
00074 layoutChanged();
00075 }
00076
00077 bool EntityOrderProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const
00078 {
00079 Q_D( const EntityOrderProxyModel );
00080
00081 if ( !d->m_orderConfig.isValid() )
00082 return QSortFilterProxyModel::lessThan( left, right );
00083
00084 Collection col = left.data( EntityTreeModel::ParentCollectionRole ).value<Collection>();
00085
00086 if ( !d->m_orderConfig.hasKey( QString::number( col.id() ) ) )
00087 return QSortFilterProxyModel::lessThan( left, right );
00088
00089 QStringList list = d->m_orderConfig.readEntry( QString::number( col.id() ), QStringList() );
00090
00091 if ( list.isEmpty() )
00092 return QSortFilterProxyModel::lessThan( left, right );
00093
00094 QString leftValue = configString( left );
00095 QString rightValue = configString( right );
00096
00097 int leftPosition = list.indexOf( leftValue );
00098 int rightPosition = list.indexOf( rightValue );
00099
00100 if ( leftPosition < 0 || rightPosition < 0 )
00101 return QSortFilterProxyModel::lessThan( left, right );
00102
00103 return leftPosition < rightPosition;
00104 }
00105
00106 bool EntityOrderProxyModel::dropMimeData( const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent )
00107 {
00108 Q_D( EntityOrderProxyModel );
00109
00110 if ( !d->m_orderConfig.isValid() )
00111 return QSortFilterProxyModel::dropMimeData( data, action, row, column, parent );
00112
00113 if ( !data->hasFormat( QLatin1String( "text/uri-list" ) ) )
00114 return QSortFilterProxyModel::dropMimeData( data, action, row, column, parent );
00115
00116 if ( row == -1 )
00117 return QSortFilterProxyModel::dropMimeData( data, action, row, column, parent );
00118
00119 bool containsMove = false;
00120
00121 const KUrl::List urls = KUrl::List::fromMimeData( data );
00122
00123 Collection parentCol;
00124
00125 if (parent.isValid())
00126 parentCol = parent.data( EntityTreeModel::CollectionRole ).value<Collection>();
00127 else
00128 {
00129 if (!hasChildren(parent))
00130 return QSortFilterProxyModel::dropMimeData( data, action, row, column, parent );
00131
00132 const QModelIndex targetIndex = index( 0, column, parent );
00133
00134 parentCol = targetIndex.data( EntityTreeModel::ParentCollectionRole ).value<Collection>();
00135 }
00136
00137 QStringList droppedList;
00138 foreach ( const KUrl &url, urls ) {
00139 Collection col = Collection::fromUrl( url );
00140
00141 if ( !col.isValid() )
00142 {
00143 Item item = Item::fromUrl( url );
00144 if ( !item.isValid() )
00145 continue;
00146
00147 const QModelIndexList list = EntityTreeModel::modelIndexesForItem( this, item );
00148 if ( list.isEmpty() )
00149 continue;
00150
00151 if ( !containsMove && list.first().data( EntityTreeModel::ParentCollectionRole ).value<Collection>().id() != parentCol.id() )
00152 containsMove = true;
00153
00154 droppedList << configString( list.first() );
00155 } else {
00156 const QModelIndex idx = EntityTreeModel::modelIndexForCollection( this, col );
00157 if ( !idx.isValid() )
00158 continue;
00159
00160 if ( !containsMove && idx.data( EntityTreeModel::ParentCollectionRole ).value<Collection>().id() != parentCol.id() )
00161 containsMove = true;
00162
00163 droppedList << configString( idx );
00164 }
00165 }
00166
00167 QStringList existingList;
00168 if ( d->m_orderConfig.hasKey( QString::number( parentCol.id() ) ) ) {
00169 existingList = d->m_orderConfig.readEntry( QString::number( parentCol.id() ), QStringList() );
00170 } else {
00171 const QModelIndex sourceIndex = mapToSource( parent );
00172 const int rowCount = sourceModel()->rowCount( sourceIndex );
00173 for (int row = 0; row < rowCount; ++row) {
00174 static const int column = 0;
00175 const QModelIndex idx = sourceModel()->index( row, column, sourceIndex );
00176 existingList.append( configString( idx ) );
00177 }
00178 }
00179
00180 for ( int i = 0; i < droppedList.size(); ++i )
00181 {
00182 const QString droppedItem = droppedList.at( i );
00183 const int existingIndex = existingList.indexOf( droppedItem );
00184 existingList.removeAt( existingIndex );
00185 existingList.insert( row + i - (existingIndex > row ? 0 : 1), droppedList.at( i ) );
00186 }
00187
00188 d->m_orderConfig.writeEntry( QString::number( parentCol.id() ), existingList );
00189
00190 if ( containsMove )
00191 {
00192 bool result = QSortFilterProxyModel::dropMimeData( data, action, row, column, parent );
00193 invalidate();
00194 return result;
00195 }
00196 invalidate();
00197 return true;
00198 }
00199
00200 QModelIndexList EntityOrderProxyModel::match( const QModelIndex& start, int role, const QVariant& value, int hits, Qt::MatchFlags flags ) const
00201 {
00202 if ( role < Qt::UserRole )
00203 return QSortFilterProxyModel::match( start, role, value, hits, flags );
00204
00205 QModelIndexList list;
00206 QModelIndex proxyIndex;
00207 foreach ( const QModelIndex &idx, sourceModel()->match( mapToSource( start ), role, value, hits, flags ) ) {
00208 proxyIndex = mapFromSource( idx );
00209 if ( proxyIndex.isValid() )
00210 list << proxyIndex;
00211 }
00212
00213 return list;
00214 }
00215
00216 void EntityOrderProxyModelPrivate::saveOrder( const QModelIndex &parent )
00217 {
00218 Q_Q( const EntityOrderProxyModel );
00219 int rowCount = q->rowCount( parent );
00220
00221 if ( rowCount == 0 )
00222 return;
00223
00224 static const int column = 0;
00225 QModelIndex childIndex = q->index( 0, column, parent );
00226
00227 QString parentKey = q->parentConfigString( childIndex );
00228
00229 if ( parentKey.isEmpty() )
00230 return;
00231
00232 QStringList list;
00233
00234 list << q->configString( childIndex );
00235 saveOrder( childIndex );
00236
00237 for ( int row = 1; row < rowCount; ++row )
00238 {
00239 childIndex = q->index( row, column, parent );
00240 list << q->configString( childIndex );
00241 saveOrder( childIndex );
00242 }
00243
00244 m_orderConfig.writeEntry( parentKey, list );
00245 }
00246
00247 QString EntityOrderProxyModel::parentConfigString( const QModelIndex& index ) const
00248 {
00249 const Collection col = index.data( EntityTreeModel::ParentCollectionRole ).value<Collection>();
00250
00251 Q_ASSERT( col.isValid() );
00252 if ( !col.isValid() )
00253 return QString();
00254
00255 return QString::number( col.id() );
00256 }
00257
00258 QString EntityOrderProxyModel::configString( const QModelIndex& index ) const
00259 {
00260 Entity::Id eId = index.data( EntityTreeModel::ItemIdRole ).toLongLong();
00261 if ( eId != -1 )
00262 {
00263 return QString::fromLatin1( "i" ) + QString::number( eId );
00264 }
00265 eId = index.data( EntityTreeModel::CollectionIdRole ).toLongLong();
00266 if ( eId != -1 )
00267 {
00268 return QString::fromLatin1( "c" ) + QString::number( eId );
00269 }
00270 Q_ASSERT( !"Invalid entity" );
00271 return QString();
00272 }
00273
00274 void EntityOrderProxyModel::saveOrder()
00275 {
00276 Q_D( EntityOrderProxyModel );
00277 d->saveOrder( QModelIndex() );
00278 d->m_orderConfig.sync();
00279 }
00280
00281 void EntityOrderProxyModel::clearOrder( const QModelIndex& parent )
00282 {
00283 Q_D( EntityOrderProxyModel );
00284
00285 QString parentKey = parentConfigString( index( 0, 0, parent ) );
00286
00287 if ( parentKey.isEmpty() )
00288 return;
00289
00290 d->m_orderConfig.deleteEntry( parentKey );
00291 invalidate();
00292 }
00293
00294 void EntityOrderProxyModel::clearTreeOrder()
00295 {
00296 Q_D( EntityOrderProxyModel );
00297 d->m_orderConfig.deleteGroup();
00298 invalidate();
00299 }