• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

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 

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal