00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "entitytreeviewstatesaver.h"
00021
00022 #include <akonadi/collection.h>
00023 #include <akonadi/entitytreemodel.h>
00024 #include <akonadi/item.h>
00025
00026 #include <KConfigGroup>
00027 #include <KDebug>
00028
00029 #include <QScrollBar>
00030 #include <QTimer>
00031 #include <QTreeView>
00032
00033 namespace Akonadi {
00034
00035 struct State
00036 {
00037 State() : selected( false ), expanded( false ), currentIndex( false ) {}
00038 bool selected;
00039 bool expanded;
00040 bool currentIndex;
00041 };
00042
00043 class EntityTreeViewStateSaverPrivate
00044 {
00045 public:
00046 explicit EntityTreeViewStateSaverPrivate( EntityTreeViewStateSaver *parent ) :
00047 q( parent ),
00048 view( 0 ),
00049 horizontalScrollBarValue( -1 ),
00050 verticalScrollBarValue( -1 )
00051 {
00052 }
00053
00054 inline bool hasChanges() const
00055 {
00056 return !pendingCollectionChanges.isEmpty() || !pendingItemChanges.isEmpty();
00057 }
00058
00059 static inline QString key( const QModelIndex &index )
00060 {
00061 if ( !index.isValid() )
00062 return QLatin1String( "x-1" );
00063 const Collection c = index.data( EntityTreeModel::CollectionRole ).value<Collection>();
00064 if ( c.isValid() )
00065 return QString::fromLatin1( "c%1" ).arg( c.id() );
00066 return QString::fromLatin1( "i%1" ).arg( index.data( EntityTreeModel::ItemIdRole ).value<Entity::Id>() );
00067 }
00068
00069 void saveState( const QModelIndex &index, QStringList &selection, QStringList &expansion )
00070 {
00071 const QString cfgKey = key( index );
00072 if ( view->selectionModel()->isSelected( index ) )
00073 selection.append( cfgKey );
00074 if ( view->isExpanded( index ) )
00075 expansion.append( cfgKey );
00076 for ( int i = 0; i < view->model()->rowCount( index ); ++i ) {
00077 const QModelIndex child = view->model()->index( i, 0, index );
00078 saveState( child, selection, expansion );
00079 }
00080 }
00081
00082 inline void restoreState( const QModelIndex &index, const State &state )
00083 {
00084 if ( state.selected )
00085 view->selectionModel()->select( index, QItemSelectionModel::Select | QItemSelectionModel::Rows );
00086 if ( state.expanded )
00087 view->setExpanded( index, true );
00088 if ( state.currentIndex )
00089 view->setCurrentIndex( index );
00090 QTimer::singleShot( 0, q, SLOT(restoreScrollBarState()) );
00091 }
00092
00093 void restoreState( const QModelIndex &index )
00094 {
00095 const Collection c = index.data( EntityTreeModel::CollectionRole ).value<Collection>();
00096 if ( c.isValid() ) {
00097 if ( pendingCollectionChanges.contains( c.id() ) ) {
00098 restoreState( index, pendingCollectionChanges.value( c.id() ) );
00099 pendingCollectionChanges.remove( c.id() );
00100 }
00101 } else {
00102 Entity::Id itemId = index.data( EntityTreeModel::ItemIdRole ).value<Entity::Id>();
00103 if ( pendingItemChanges.contains( itemId ) ) {
00104 restoreState( index, pendingItemChanges.value( itemId ) );
00105 pendingItemChanges.remove( itemId );
00106 }
00107 }
00108 for ( int i = 0; i < view->model()->rowCount( index ) && hasChanges(); ++i ) {
00109 const QModelIndex child = view->model()->index( i, 0, index );
00110 restoreState( child );
00111 }
00112 }
00113
00114 inline void restoreScrollBarState()
00115 {
00116 if ( horizontalScrollBarValue >= 0 && horizontalScrollBarValue <= view->horizontalScrollBar()->maximum() ) {
00117 view->horizontalScrollBar()->setValue( horizontalScrollBarValue );
00118 horizontalScrollBarValue = -1;
00119 }
00120 if ( verticalScrollBarValue >= 0 && verticalScrollBarValue <= view->verticalScrollBar()->maximum() ) {
00121 view->verticalScrollBar()->setValue( verticalScrollBarValue );
00122 verticalScrollBarValue = -1;
00123 }
00124 }
00125
00126 void rowsInserted( const QModelIndex &index, int start, int end )
00127 {
00128 if ( !hasChanges() ) {
00129 QObject::disconnect( view->model(), SIGNAL(rowsInserted(QModelIndex,int,int)), q, SLOT(rowsInserted(QModelIndex,int,int)) );
00130 return;
00131 }
00132
00133 for ( int i = start; i <= end && hasChanges(); ++i ) {
00134 const QModelIndex child = view->model()->index( i, 0, index);;
00135 restoreState( child );
00136 }
00137 }
00138
00139 EntityTreeViewStateSaver *q;
00140 QTreeView *view;
00141 QHash<Entity::Id, State> pendingCollectionChanges, pendingItemChanges;
00142 int horizontalScrollBarValue, verticalScrollBarValue;
00143 };
00144
00145 EntityTreeViewStateSaver::EntityTreeViewStateSaver( QTreeView * view ) :
00146 QObject( view ),
00147 d( new EntityTreeViewStateSaverPrivate( this ) )
00148 {
00149 d->view = view;
00150 }
00151
00152 EntityTreeViewStateSaver::~EntityTreeViewStateSaver()
00153 {
00154 delete d;
00155 }
00156
00157 void EntityTreeViewStateSaver::saveState( KConfigGroup &configGroup ) const
00158 {
00159 if ( !d->view->model() )
00160 return;
00161
00162 configGroup.deleteGroup();
00163 QStringList selection, expansion;
00164 for ( int i = 0; i < d->view->model()->rowCount(); ++i ) {
00165 const QModelIndex index = d->view->model()->index( i, 0 );
00166 d->saveState( index, selection, expansion );
00167 }
00168
00169 const QString currentIndex = d->key( d->view->selectionModel()->currentIndex() );
00170
00171 configGroup.writeEntry( "Selection", selection );
00172 configGroup.writeEntry( "Expansion", expansion );
00173 configGroup.writeEntry( "CurrentIndex", currentIndex );
00174 configGroup.writeEntry( "ScrollBarHorizontal", d->view->horizontalScrollBar()->value() );
00175 configGroup.writeEntry( "ScrollBarVertical", d->view->verticalScrollBar()->value() );
00176 }
00177
00178 void EntityTreeViewStateSaver::restoreState (const KConfigGroup & configGroup) const
00179 {
00180 if ( !d->view->model() )
00181 return;
00182
00183 const QStringList selection = configGroup.readEntry( "Selection", QStringList() );
00184 foreach( const QString &key, selection ) {
00185 Entity::Id id = key.mid( 1 ).toLongLong();
00186 if ( id < 0 )
00187 continue;
00188 if ( key.startsWith( QLatin1Char( 'c' ) ) )
00189 d->pendingCollectionChanges[id].selected = true;
00190 else if ( key.startsWith( QLatin1Char( 'i' ) ) )
00191 d->pendingItemChanges[id].selected = true;
00192 }
00193
00194 const QStringList expansion = configGroup.readEntry( "Expansion", QStringList() );
00195 foreach( const QString &key, expansion ) {
00196 Entity::Id id = key.mid( 1 ).toLongLong();
00197 if ( id < 0 )
00198 continue;
00199 if ( key.startsWith( QLatin1Char( 'c' ) ) )
00200 d->pendingCollectionChanges[id].expanded = true;
00201 else if ( key.startsWith( QLatin1Char( 'i' ) ) )
00202 d->pendingItemChanges[id].expanded = true;
00203 }
00204
00205 const QString key = configGroup.readEntry( "CurrentIndex", QString() );
00206 const Entity::Id id = key.mid( 1 ).toLongLong();
00207 if ( id >= 0 ) {
00208 if ( key.startsWith( QLatin1Char( 'c' ) ) )
00209 d->pendingCollectionChanges[id].currentIndex = true;
00210 else if ( key.startsWith( QLatin1Char( 'i' ) ) )
00211 d->pendingItemChanges[id].currentIndex = true;
00212 }
00213
00214 d->horizontalScrollBarValue = configGroup.readEntry( "ScrollBarHorizontal", -1 );
00215 d->verticalScrollBarValue = configGroup.readEntry( "ScrollBarVertical", -1 );
00216
00217
00218 for ( int i = 0; i < d->view->model()->rowCount() && d->hasChanges(); ++i ) {
00219 const QModelIndex index = d->view->model()->index( i, 0 );
00220 d->restoreState( index );
00221 }
00222 d->restoreScrollBarState();
00223
00224
00225 if ( d->hasChanges() )
00226 connect( d->view->model(), SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(rowsInserted(QModelIndex,int,int)), Qt::QueuedConnection );
00227 }
00228
00229 }
00230
00231 #include "entitytreeviewstatesaver.moc"