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( const QModelIndex&, int, int ) ),
00130 q, SLOT( rowsInserted( const QModelIndex&, int, int ) ) );
00131 return;
00132 }
00133
00134 for ( int i = start; i <= end && hasChanges(); ++i ) {
00135 const QModelIndex child = view->model()->index( i, 0, index);;
00136 restoreState( child );
00137 }
00138 }
00139
00140 EntityTreeViewStateSaver *q;
00141 QTreeView *view;
00142 QHash<Entity::Id, State> pendingCollectionChanges, pendingItemChanges;
00143 int horizontalScrollBarValue, verticalScrollBarValue;
00144 };
00145
00146 EntityTreeViewStateSaver::EntityTreeViewStateSaver( QTreeView * view ) :
00147 QObject( view ),
00148 d( new EntityTreeViewStateSaverPrivate( this ) )
00149 {
00150 d->view = view;
00151 }
00152
00153 EntityTreeViewStateSaver::~EntityTreeViewStateSaver()
00154 {
00155 delete d;
00156 }
00157
00158 void EntityTreeViewStateSaver::saveState( KConfigGroup &configGroup ) const
00159 {
00160 if ( !d->view->model() )
00161 return;
00162
00163 configGroup.deleteGroup();
00164 QStringList selection, expansion;
00165 const int rowCount = d->view->model()->rowCount();
00166 for ( int i = 0; i < rowCount; ++i ) {
00167 const QModelIndex index = d->view->model()->index( i, 0 );
00168 d->saveState( index, selection, expansion );
00169 }
00170
00171 const QString currentIndex = d->key( d->view->selectionModel()->currentIndex() );
00172
00173 configGroup.writeEntry( "Selection", selection );
00174 configGroup.writeEntry( "Expansion", expansion );
00175 configGroup.writeEntry( "CurrentIndex", currentIndex );
00176 configGroup.writeEntry( "ScrollBarHorizontal", d->view->horizontalScrollBar()->value() );
00177 configGroup.writeEntry( "ScrollBarVertical", d->view->verticalScrollBar()->value() );
00178 }
00179
00180 void EntityTreeViewStateSaver::restoreState (const KConfigGroup & configGroup) const
00181 {
00182 if ( !d->view->model() )
00183 return;
00184
00185 const QStringList selection = configGroup.readEntry( "Selection", QStringList() );
00186 foreach ( const QString &key, selection ) {
00187 Entity::Id id = key.mid( 1 ).toLongLong();
00188 if ( id < 0 )
00189 continue;
00190 if ( key.startsWith( QLatin1Char( 'c' ) ) )
00191 d->pendingCollectionChanges[id].selected = true;
00192 else if ( key.startsWith( QLatin1Char( 'i' ) ) )
00193 d->pendingItemChanges[id].selected = true;
00194 }
00195
00196 const QStringList expansion = configGroup.readEntry( "Expansion", QStringList() );
00197 foreach ( const QString &key, expansion ) {
00198 Entity::Id id = key.mid( 1 ).toLongLong();
00199 if ( id < 0 )
00200 continue;
00201 if ( key.startsWith( QLatin1Char( 'c' ) ) )
00202 d->pendingCollectionChanges[id].expanded = true;
00203 else if ( key.startsWith( QLatin1Char( 'i' ) ) )
00204 d->pendingItemChanges[id].expanded = true;
00205 }
00206
00207 const QString key = configGroup.readEntry( "CurrentIndex", QString() );
00208 const Entity::Id id = key.mid( 1 ).toLongLong();
00209 if ( id >= 0 ) {
00210 if ( key.startsWith( QLatin1Char( 'c' ) ) )
00211 d->pendingCollectionChanges[id].currentIndex = true;
00212 else if ( key.startsWith( QLatin1Char( 'i' ) ) )
00213 d->pendingItemChanges[id].currentIndex = true;
00214 }
00215
00216 d->horizontalScrollBarValue = configGroup.readEntry( "ScrollBarHorizontal", -1 );
00217 d->verticalScrollBarValue = configGroup.readEntry( "ScrollBarVertical", -1 );
00218
00219
00220 for ( int i = 0; i < d->view->model()->rowCount() && d->hasChanges(); ++i ) {
00221 const QModelIndex index = d->view->model()->index( i, 0 );
00222 d->restoreState( index );
00223 }
00224 d->restoreScrollBarState();
00225
00226
00227 if ( d->hasChanges() )
00228 connect( d->view->model(), SIGNAL( rowsInserted( const QModelIndex&, int, int ) ),
00229 SLOT( rowsInserted( const QModelIndex&, int, int ) ) );
00230 }
00231
00232 }
00233
00234 #include "entitytreeviewstatesaver.moc"