akonadi
entitytreeviewstatesaver.cpp
00001 /* 00002 Copyright (c) 2009 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 "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)), 00130 q, SLOT(rowsInserted(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 // initial restore run, for everything already loaded 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 // watch the model for stuff coming in delayed 00227 if ( d->hasChanges() ) 00228 connect( d->view->model(), SIGNAL(rowsInserted(QModelIndex,int,int)), 00229 SLOT(rowsInserted(QModelIndex,int,int)) ); 00230 } 00231 00232 } // namespace Akonadi 00233 00234 #include "entitytreeviewstatesaver.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Thu Aug 2 2012 15:25:18 by doxygen 1.7.5 written by Dimitri van Heesch, © 1997-2006
Documentation copyright © 1996-2012 The KDE developers.
Generated on Thu Aug 2 2012 15:25:18 by doxygen 1.7.5 written by Dimitri van Heesch, © 1997-2006
KDE's Doxygen guidelines are available online.