KDEUI
kviewstatesaver.cpp
Go to the documentation of this file.
00001 /* 00002 Copyright (C) 2010 Klarälvdalens Datakonsult AB, 00003 a KDAB Group company, info@kdab.net, 00004 author Stephen Kelly <stephen@kdab.com> 00005 00006 This library is free software; you can redistribute it and/or modify it 00007 under the terms of the GNU Library General Public License as published by 00008 the Free Software Foundation; either version 2 of the License, or (at your 00009 option) any later version. 00010 00011 This library is distributed in the hope that it will be useful, but WITHOUT 00012 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00013 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00014 License for more details. 00015 00016 You should have received a copy of the GNU Library General Public License 00017 along with this library; see the file COPYING.LIB. If not, write to the 00018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 00019 02110-1301, USA. 00020 */ 00021 00022 #include "kviewstatesaver.h" 00023 00024 #include <QtGui/QAbstractScrollArea> 00025 #include <QScrollBar> 00026 #include <QTimer> 00027 #include <QTreeView> 00028 00029 #include "kdebug.h" 00030 00031 #include "kconfiggroup.h" 00032 00033 static const char * selectionKey = "Selection"; 00034 static const char * expansionKey = "Expansion"; 00035 static const char * currentKey = "Current"; 00036 static const char * scrollStateHorizontalKey = "HorizontalScroll"; 00037 static const char * scrollStateVerticalKey = "VerticalScroll"; 00038 00039 class KViewStateSaverPrivate 00040 { 00041 public: 00042 KViewStateSaverPrivate(KViewStateSaver *qq) 00043 : q_ptr(qq), 00044 m_treeView(0), 00045 m_view(0), 00046 m_selectionModel(0), 00047 m_scrollArea(0), 00048 m_horizontalScrollBarValue(-1), 00049 m_verticalScrollBarValue(-1) 00050 { 00051 00052 } 00053 00054 Q_DECLARE_PUBLIC(KViewStateSaver) 00055 KViewStateSaver * const q_ptr; 00056 00057 QStringList getExpandedItems(const QModelIndex &index) const; 00058 00059 void listenToPendingChanges(); 00060 void processPendingChanges(); 00061 00062 inline void restoreScrollBarState() 00063 { 00064 if ( m_horizontalScrollBarValue >= 0 && m_horizontalScrollBarValue <= m_scrollArea->horizontalScrollBar()->maximum() ) { 00065 m_scrollArea->horizontalScrollBar()->setValue( m_horizontalScrollBarValue ); 00066 m_horizontalScrollBarValue = -1; 00067 } 00068 if ( m_verticalScrollBarValue >= 0 && m_verticalScrollBarValue <= m_scrollArea->verticalScrollBar()->maximum() ) { 00069 m_scrollArea->verticalScrollBar()->setValue( m_verticalScrollBarValue ); 00070 m_verticalScrollBarValue = -1; 00071 } 00072 } 00073 00074 void restoreSelection(); 00075 void restoreCurrentItem(); 00076 void restoreExpanded(); 00077 00078 inline bool hasPendingChanges() const 00079 { 00080 return !m_pendingCurrent.isEmpty() || !m_pendingExpansions.isEmpty() || !m_pendingSelections.isEmpty(); 00081 } 00082 00083 const QAbstractItemModel* getModel() 00084 { 00085 if ( m_selectionModel && m_selectionModel->model() ) 00086 return m_selectionModel->model(); 00087 else if ( m_view && m_view->model() ) 00088 return m_view->model(); 00089 return 0; 00090 } 00091 00092 void rowsInserted( const QModelIndex &index, int start, int end ) 00093 { 00094 Q_Q(KViewStateSaver); 00095 processPendingChanges(); 00096 00097 if ( !hasPendingChanges() ) 00098 { 00099 q->disconnect( getModel(), SIGNAL( rowsInserted( const QModelIndex&, int, int ) ), 00100 q, SLOT( rowsInserted( const QModelIndex&, int, int ) ) ); 00101 q->deleteLater(); 00102 } 00103 } 00104 00105 QTreeView *m_treeView; 00106 QAbstractItemView *m_view; 00107 QItemSelectionModel *m_selectionModel; 00108 QAbstractScrollArea *m_scrollArea; 00109 00110 int m_horizontalScrollBarValue; 00111 int m_verticalScrollBarValue; 00112 QSet<QString> m_pendingSelections; 00113 QSet<QString> m_pendingExpansions; 00114 QString m_pendingCurrent; 00115 }; 00116 00117 KViewStateSaver::KViewStateSaver(QObject* parent) 00118 : QObject(0), d_ptr( new KViewStateSaverPrivate(this) ) 00119 { 00120 Q_UNUSED(parent); 00121 qRegisterMetaType<QModelIndex>( "QModelIndex" ); 00122 } 00123 00124 KViewStateSaver::~KViewStateSaver() 00125 { 00126 delete d_ptr; 00127 } 00128 00129 void KViewStateSaver::setView(QAbstractItemView* view) 00130 { 00131 Q_D(KViewStateSaver); 00132 d->m_scrollArea = view; 00133 if (view) { 00134 d->m_selectionModel = view->selectionModel(); 00135 d->m_treeView = qobject_cast<QTreeView*>(view); 00136 } else { 00137 d->m_selectionModel = 0; 00138 d->m_treeView = 0; 00139 } 00140 d->m_view = view; 00141 } 00142 00143 QAbstractItemView* KViewStateSaver::view() const 00144 { 00145 Q_D(const KViewStateSaver); 00146 return d->m_view; 00147 } 00148 00149 QItemSelectionModel* KViewStateSaver::selectionModel() const 00150 { 00151 Q_D(const KViewStateSaver); 00152 return d->m_selectionModel; 00153 } 00154 00155 void KViewStateSaver::setSelectionModel(QItemSelectionModel* selectionModel) 00156 { 00157 Q_D(KViewStateSaver); 00158 d->m_selectionModel = selectionModel; 00159 } 00160 00161 void KViewStateSaverPrivate::listenToPendingChanges() 00162 { 00163 Q_Q(KViewStateSaver); 00164 // watch the model for stuff coming in delayed 00165 if ( hasPendingChanges() ) 00166 { 00167 const QAbstractItemModel *model = getModel(); 00168 if ( model ) 00169 { 00170 q->disconnect( model, SIGNAL( rowsInserted( const QModelIndex&, int, int ) ), 00171 q, SLOT( rowsInserted( const QModelIndex&, int, int ) ) ); 00172 q->connect( model, SIGNAL( rowsInserted( const QModelIndex&, int, int ) ), 00173 SLOT( rowsInserted( const QModelIndex&, int, int ) ) ); 00174 return; 00175 } else { 00176 q->deleteLater(); 00177 } 00178 } else { 00179 q->deleteLater(); 00180 } 00181 } 00182 00183 void KViewStateSaverPrivate::processPendingChanges() 00184 { 00185 Q_Q(KViewStateSaver); 00186 00187 q->restoreCurrentItem(m_pendingCurrent); 00188 q->restoreSelection(m_pendingSelections.toList()); 00189 q->restoreExpanded(m_pendingExpansions.toList()); 00190 q->restoreScrollState(m_verticalScrollBarValue, m_horizontalScrollBarValue); 00191 } 00192 00193 void KViewStateSaver::restoreState(const KConfigGroup& configGroup) 00194 { 00195 Q_D(KViewStateSaver); 00196 00197 // Delete myself if not finished after ten seconds. 00198 QTimer::singleShot(10000, this, SLOT(deleteLater())); 00199 00200 00201 d->m_pendingCurrent = configGroup.readEntry( currentKey, QString() ); 00202 d->m_pendingSelections = configGroup.readEntry( selectionKey, QStringList() ).toSet(); 00203 d->m_pendingExpansions = configGroup.readEntry( expansionKey, QStringList() ).toSet(); 00204 d->m_horizontalScrollBarValue = configGroup.readEntry( scrollStateHorizontalKey, -1 ); 00205 d->m_verticalScrollBarValue = configGroup.readEntry( scrollStateVerticalKey, -1 ); 00206 00207 d->processPendingChanges(); 00208 if (d->hasPendingChanges()) 00209 d->listenToPendingChanges(); 00210 } 00211 00212 QStringList KViewStateSaverPrivate::getExpandedItems(const QModelIndex &index) const 00213 { 00214 Q_Q(const KViewStateSaver); 00215 00216 QStringList expansion; 00217 for ( int i = 0; i < m_treeView->model()->rowCount( index ); ++i ) { 00218 const QModelIndex child = m_treeView->model()->index( i, 0, index ); 00219 if ( m_treeView->isExpanded( child ) ) 00220 expansion << q->indexToConfigString( child ); 00221 if ( m_treeView->model()->hasChildren( child ) ) 00222 expansion << getExpandedItems( child ); 00223 } 00224 return expansion; 00225 } 00226 00227 void KViewStateSaver::saveState(KConfigGroup& configGroup) 00228 { 00229 Q_D(KViewStateSaver); 00230 00231 if ( d->m_selectionModel ) 00232 { 00233 configGroup.writeEntry( selectionKey, selectionKeys() ); 00234 configGroup.writeEntry( currentKey, currentIndexKey() ); 00235 } 00236 00237 if ( d->m_treeView ) 00238 { 00239 QStringList expansion = expansionKeys(); 00240 00241 configGroup.writeEntry( expansionKey, expansion ); 00242 } 00243 00244 if ( d->m_scrollArea ) 00245 { 00246 QPair<int, int> _scrollState = scrollState(); 00247 configGroup.writeEntry( scrollStateVerticalKey, _scrollState.first ); 00248 configGroup.writeEntry( scrollStateHorizontalKey, _scrollState.second ); 00249 } 00250 } 00251 00252 void KViewStateSaverPrivate::restoreCurrentItem() 00253 { 00254 Q_Q(KViewStateSaver); 00255 00256 QModelIndex currentIndex = q->indexFromConfigString(m_selectionModel->model(), m_pendingCurrent); 00257 if ( currentIndex.isValid() ) 00258 { 00259 if (m_treeView) 00260 m_treeView->setCurrentIndex(currentIndex); 00261 else 00262 m_selectionModel->setCurrentIndex(currentIndex, QItemSelectionModel::NoUpdate); 00263 m_pendingCurrent.clear(); 00264 } 00265 } 00266 00267 void KViewStateSaver::restoreCurrentItem(const QString& indexString) 00268 { 00269 Q_D(KViewStateSaver); 00270 if (!d->m_selectionModel || !d->m_selectionModel->model()) 00271 return; 00272 00273 if (indexString.isEmpty()) 00274 { 00275 return; 00276 } 00277 d->m_pendingCurrent = indexString; 00278 d->restoreCurrentItem(); 00279 00280 if (d->hasPendingChanges()) 00281 d->listenToPendingChanges(); 00282 } 00283 00284 void KViewStateSaverPrivate::restoreExpanded() 00285 { 00286 Q_Q(KViewStateSaver); 00287 00288 QSet<QString>::iterator it = m_pendingExpansions.begin(); 00289 for ( ; it != m_pendingExpansions.end(); ) 00290 { 00291 QModelIndex idx = q->indexFromConfigString( m_treeView->model(), *it); 00292 if ( idx.isValid() ) 00293 { 00294 m_treeView->expand( idx ); 00295 it = m_pendingExpansions.erase( it ); 00296 } else { 00297 ++it; 00298 } 00299 } 00300 } 00301 00302 void KViewStateSaver::restoreExpanded(const QStringList& indexStrings) 00303 { 00304 Q_D(KViewStateSaver); 00305 if (!d->m_treeView || !d->m_treeView->model()) 00306 return; 00307 00308 if (indexStrings.isEmpty()) 00309 return; 00310 00311 d->m_pendingExpansions.unite(indexStrings.toSet()); 00312 d->restoreExpanded(); 00313 if (d->hasPendingChanges()) 00314 d->listenToPendingChanges(); 00315 } 00316 00317 void KViewStateSaver::restoreScrollState(int verticalScoll, int horizontalScroll) 00318 { 00319 Q_D(KViewStateSaver); 00320 00321 if ( !d->m_scrollArea ) 00322 return; 00323 00324 d->m_verticalScrollBarValue = verticalScoll; 00325 d->m_horizontalScrollBarValue = horizontalScroll; 00326 00327 QTimer::singleShot( 0, this, SLOT( restoreScrollBarState() ) ); 00328 } 00329 00330 void KViewStateSaverPrivate::restoreSelection() 00331 { 00332 Q_Q(KViewStateSaver); 00333 00334 QSet<QString>::iterator it = m_pendingSelections.begin(); 00335 for ( ; it != m_pendingSelections.end(); ) 00336 { 00337 QModelIndex idx = q->indexFromConfigString( m_selectionModel->model(), *it); 00338 if ( idx.isValid() ) 00339 { 00340 m_selectionModel->select( idx, QItemSelectionModel::Select ); 00341 it = m_pendingSelections.erase( it ); 00342 } else { 00343 ++it; 00344 } 00345 } 00346 } 00347 00348 void KViewStateSaver::restoreSelection(const QStringList& indexStrings) 00349 { 00350 Q_D(KViewStateSaver); 00351 00352 if (!d->m_selectionModel || !d->m_selectionModel->model()) 00353 return; 00354 00355 if (indexStrings.isEmpty()) 00356 return; 00357 00358 d->m_pendingSelections.unite(indexStrings.toSet()); 00359 d->restoreSelection(); 00360 if (d->hasPendingChanges()) 00361 d->listenToPendingChanges(); 00362 } 00363 00364 QString KViewStateSaver::currentIndexKey() const 00365 { 00366 Q_D(const KViewStateSaver); 00367 if (!d->m_selectionModel) 00368 return QString(); 00369 return indexToConfigString(d->m_selectionModel->currentIndex()); 00370 } 00371 00372 QStringList KViewStateSaver::expansionKeys() const 00373 { 00374 Q_D(const KViewStateSaver); 00375 if (!d->m_treeView || !d->m_treeView->model()) 00376 return QStringList(); 00377 00378 return d->getExpandedItems(QModelIndex()); 00379 } 00380 00381 QStringList KViewStateSaver::selectionKeys() const 00382 { 00383 Q_D(const KViewStateSaver); 00384 if (!d->m_selectionModel) 00385 return QStringList(); 00386 00387 QModelIndexList selectedIndexes = d->m_selectionModel->selectedRows(); 00388 QStringList selection; 00389 foreach ( const QModelIndex &index, selectedIndexes ) 00390 selection << indexToConfigString( index ); 00391 00392 return selection; 00393 } 00394 00395 QPair<int, int> KViewStateSaver::scrollState() const 00396 { 00397 Q_D(const KViewStateSaver); 00398 return qMakePair(d->m_scrollArea->verticalScrollBar()->value(), d->m_scrollArea->horizontalScrollBar()->value()); 00399 } 00400 00401 #include "kviewstatesaver.moc" 00402
KDE 4.6 API Reference