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 00220 // http://bugreports.qt.nokia.com/browse/QTBUG-18039 00221 if ( m_treeView->model()->hasChildren( child ) ) { 00222 if ( m_treeView->isExpanded( child ) ) 00223 expansion << q->indexToConfigString( child ); 00224 expansion << getExpandedItems( child ); 00225 } 00226 } 00227 return expansion; 00228 } 00229 00230 void KViewStateSaver::saveState(KConfigGroup& configGroup) 00231 { 00232 Q_D(KViewStateSaver); 00233 00234 if ( d->m_selectionModel ) 00235 { 00236 configGroup.writeEntry( selectionKey, selectionKeys() ); 00237 configGroup.writeEntry( currentKey, currentIndexKey() ); 00238 } 00239 00240 if ( d->m_treeView ) 00241 { 00242 QStringList expansion = expansionKeys(); 00243 00244 configGroup.writeEntry( expansionKey, expansion ); 00245 } 00246 00247 if ( d->m_scrollArea ) 00248 { 00249 QPair<int, int> _scrollState = scrollState(); 00250 configGroup.writeEntry( scrollStateVerticalKey, _scrollState.first ); 00251 configGroup.writeEntry( scrollStateHorizontalKey, _scrollState.second ); 00252 } 00253 } 00254 00255 void KViewStateSaverPrivate::restoreCurrentItem() 00256 { 00257 Q_Q(KViewStateSaver); 00258 00259 QModelIndex currentIndex = q->indexFromConfigString(m_selectionModel->model(), m_pendingCurrent); 00260 if ( currentIndex.isValid() ) 00261 { 00262 if (m_treeView) 00263 m_treeView->setCurrentIndex(currentIndex); 00264 else 00265 m_selectionModel->setCurrentIndex(currentIndex, QItemSelectionModel::NoUpdate); 00266 m_pendingCurrent.clear(); 00267 } 00268 } 00269 00270 void KViewStateSaver::restoreCurrentItem(const QString& indexString) 00271 { 00272 Q_D(KViewStateSaver); 00273 if (!d->m_selectionModel || !d->m_selectionModel->model()) 00274 return; 00275 00276 if (indexString.isEmpty()) 00277 { 00278 return; 00279 } 00280 d->m_pendingCurrent = indexString; 00281 d->restoreCurrentItem(); 00282 00283 if (d->hasPendingChanges()) 00284 d->listenToPendingChanges(); 00285 } 00286 00287 void KViewStateSaverPrivate::restoreExpanded() 00288 { 00289 Q_Q(KViewStateSaver); 00290 00291 QSet<QString>::iterator it = m_pendingExpansions.begin(); 00292 for ( ; it != m_pendingExpansions.end(); ) 00293 { 00294 QModelIndex idx = q->indexFromConfigString( m_treeView->model(), *it); 00295 if ( idx.isValid() ) 00296 { 00297 m_treeView->expand( idx ); 00298 it = m_pendingExpansions.erase( it ); 00299 } else { 00300 ++it; 00301 } 00302 } 00303 } 00304 00305 void KViewStateSaver::restoreExpanded(const QStringList& indexStrings) 00306 { 00307 Q_D(KViewStateSaver); 00308 if (!d->m_treeView || !d->m_treeView->model()) 00309 return; 00310 00311 if (indexStrings.isEmpty()) 00312 return; 00313 00314 d->m_pendingExpansions.unite(indexStrings.toSet()); 00315 d->restoreExpanded(); 00316 if (d->hasPendingChanges()) 00317 d->listenToPendingChanges(); 00318 } 00319 00320 void KViewStateSaver::restoreScrollState(int verticalScoll, int horizontalScroll) 00321 { 00322 Q_D(KViewStateSaver); 00323 00324 if ( !d->m_scrollArea ) 00325 return; 00326 00327 d->m_verticalScrollBarValue = verticalScoll; 00328 d->m_horizontalScrollBarValue = horizontalScroll; 00329 00330 QTimer::singleShot( 0, this, SLOT( restoreScrollBarState() ) ); 00331 } 00332 00333 void KViewStateSaverPrivate::restoreSelection() 00334 { 00335 Q_Q(KViewStateSaver); 00336 00337 QSet<QString>::iterator it = m_pendingSelections.begin(); 00338 for ( ; it != m_pendingSelections.end(); ) 00339 { 00340 QModelIndex idx = q->indexFromConfigString( m_selectionModel->model(), *it); 00341 if ( idx.isValid() ) 00342 { 00343 m_selectionModel->select( idx, QItemSelectionModel::Select ); 00344 it = m_pendingSelections.erase( it ); 00345 } else { 00346 ++it; 00347 } 00348 } 00349 } 00350 00351 void KViewStateSaver::restoreSelection(const QStringList& indexStrings) 00352 { 00353 Q_D(KViewStateSaver); 00354 00355 if (!d->m_selectionModel || !d->m_selectionModel->model()) 00356 return; 00357 00358 if (indexStrings.isEmpty()) 00359 return; 00360 00361 d->m_pendingSelections.unite(indexStrings.toSet()); 00362 d->restoreSelection(); 00363 if (d->hasPendingChanges()) 00364 d->listenToPendingChanges(); 00365 } 00366 00367 QString KViewStateSaver::currentIndexKey() const 00368 { 00369 Q_D(const KViewStateSaver); 00370 if (!d->m_selectionModel) 00371 return QString(); 00372 return indexToConfigString(d->m_selectionModel->currentIndex()); 00373 } 00374 00375 QStringList KViewStateSaver::expansionKeys() const 00376 { 00377 Q_D(const KViewStateSaver); 00378 if (!d->m_treeView || !d->m_treeView->model()) 00379 return QStringList(); 00380 00381 return d->getExpandedItems(QModelIndex()); 00382 } 00383 00384 QStringList KViewStateSaver::selectionKeys() const 00385 { 00386 Q_D(const KViewStateSaver); 00387 if (!d->m_selectionModel) 00388 return QStringList(); 00389 00390 QModelIndexList selectedIndexes = d->m_selectionModel->selectedRows(); 00391 QStringList selection; 00392 foreach ( const QModelIndex &index, selectedIndexes ) 00393 selection << indexToConfigString( index ); 00394 00395 return selection; 00396 } 00397 00398 QPair<int, int> KViewStateSaver::scrollState() const 00399 { 00400 Q_D(const KViewStateSaver); 00401 return qMakePair(d->m_scrollArea->verticalScrollBar()->value(), d->m_scrollArea->horizontalScrollBar()->value()); 00402 } 00403 00404 #include "kviewstatesaver.moc" 00405
KDE 4.6 API Reference