1 | /* |
2 | Copyright (C) 2010 Klarälvdalens Datakonsult AB, |
3 | a KDAB Group company, info@kdab.net, |
4 | author Stephen Kelly <stephen@kdab.com> |
5 | |
6 | This library is free software; you can redistribute it and/or modify it |
7 | under the terms of the GNU Library General Public License as published by |
8 | the Free Software Foundation; either version 2 of the License, or (at your |
9 | option) any later version. |
10 | |
11 | This library is distributed in the hope that it will be useful, but WITHOUT |
12 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public |
14 | License for more details. |
15 | |
16 | You should have received a copy of the GNU Library General Public License |
17 | along with this library; see the file COPYING.LIB. If not, write to the |
18 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
19 | 02110-1301, USA. |
20 | */ |
21 | |
22 | #ifndef KVIEWSTATESAVER_H |
23 | #define KVIEWSTATESAVER_H |
24 | |
25 | #include <QtCore/QObject> |
26 | #include <QtCore/QPair> |
27 | |
28 | #include "kdeui_export.h" |
29 | |
30 | class QAbstractItemView; |
31 | class QItemSelectionModel; |
32 | class QAbstractItemModel; |
33 | class QAbstractScrollArea; |
34 | class QModelIndex; |
35 | class QStringList; |
36 | |
37 | class KConfigGroup; |
38 | |
39 | class KViewStateSaverPrivate; |
40 | |
41 | /** |
42 | @brief Object for saving and restoring state in QTreeViews and QItemSelectionModels |
43 | |
44 | Implement the indexFromConfigString and indexToConfigString methods to |
45 | handle the model in the view whose state is being saved. These implementations can be quite trivial: |
46 | |
47 | @code |
48 | QModelIndex DynamicTreeStateSaver::indexFromConfigString(const QAbstractItemModel* model, const QString& key) const |
49 | { |
50 | QModelIndexList list = model->match(model->index(0, 0), DynamicTreeModel::DynamicTreeModelId, key.toInt(), 1, Qt::MatchRecursive); |
51 | if (list.isEmpty()) |
52 | return QModelIndex(); |
53 | return list.first(); |
54 | } |
55 | |
56 | QString DynamicTreeStateSaver::indexToConfigString(const QModelIndex& index) const |
57 | { |
58 | return index.data(DynamicTreeModel::DynamicTreeModelId).toString(); |
59 | } |
60 | @endcode |
61 | |
62 | It is possible to restore the state of a QTreeView (that is, the expanded state and selected state of all indexes |
63 | as well as the horizontal and vertical scroll state) by using setTreeView. |
64 | |
65 | If there is no tree view state to restore (for example if using QML), the selection state of a QItemSelectionModel |
66 | can be saved or restored instead. |
67 | |
68 | The state of any QAbstractScrollArea can also be saved and restored. |
69 | |
70 | A KViewStateSaver should be created on the stack when saving and on the heap when restoring. The model may be populated dynamically between several |
71 | event loops, so it may not be immediate for the indexes that should be selected to be in the model. The saver should *not* be persisted as a |
72 | member. The saver will destroy itself when it has completed the restoration specified in the config group, or a small amount of time has elapsed. |
73 | |
74 | @code |
75 | MyWidget::MyWidget(Qobject *parent) |
76 | : QWidget(parent) |
77 | { |
78 | ... |
79 | |
80 | m_view = new QTreeView(splitter); |
81 | m_view->setModel(model); |
82 | |
83 | connect( model, SIGNAL(modelAboutToBeReset()), SLOT(saveState()) ); |
84 | connect( model, SIGNAL(modelReset()), SLOT(restoreState()) ); |
85 | connect( qApp, SIGNAL(aboutToQuit()), SLOT(saveState()) ); |
86 | |
87 | restoreState(); |
88 | } |
89 | |
90 | void StateSaverWidget::saveState() |
91 | { |
92 | ConcreteStateSaver saver; |
93 | saver.setTreeView(m_view); |
94 | |
95 | KConfigGroup cfg( KGlobal::config(), "ExampleViewState" ); |
96 | saver.saveState( cfg ); |
97 | cfg.sync(); |
98 | } |
99 | |
100 | void StateSaverWidget::restoreState() |
101 | { |
102 | // Will delete itself. |
103 | ConcreteTreeStateSaver *saver = new ConcreteStateSaver(); |
104 | saver->setTreeView(m_view); |
105 | KConfigGroup cfg( KGlobal::config(), "ExampleViewState" ); |
106 | saver->restoreState( cfg ); |
107 | } |
108 | @endcode |
109 | |
110 | After creating a saver, the state can be saved using a KConfigGroup. |
111 | |
112 | It is also possible to save and restore state directly by using the restoreSelection, |
113 | restoreExpanded etc methods. Note that the implementation of these methods should return |
114 | strings that the indexFromConfigString implementation can handle. |
115 | |
116 | @code |
117 | class DynamicTreeStateSaver : public KViewStateSaver |
118 | { |
119 | Q_OBJECT |
120 | public: |
121 | // ... |
122 | |
123 | void selectItems(const QList<qint64> &items) |
124 | { |
125 | QStringList itemStrings; |
126 | foreach(qint64 item, items) |
127 | itemStrings << QString::number(item); |
128 | restoreSelection(itemStrings); |
129 | } |
130 | |
131 | void expandItems(const QList<qint64> &items) |
132 | { |
133 | QStringList itemStrings; |
134 | foreach(qint64 item, items) |
135 | itemStrings << QString::number(item); |
136 | restoreSelection(itemStrings); |
137 | } |
138 | |
139 | }; |
140 | @endcode |
141 | |
142 | |
143 | Note that a single instance of this class should be used with only one widget. That is don't do this: |
144 | |
145 | @code |
146 | saver->setTreeView(treeView1); |
147 | saver->setSelectionModel(treeView2->selectionModel()); |
148 | saver->setScrollArea(treeView3); |
149 | @endcode |
150 | |
151 | To save the state of 3 different widgets, use three savers, even if they operate on the same root model. |
152 | |
153 | @code |
154 | saver1->setTreeView(treeView1); |
155 | saver2->setSelectionModel(treeView2->selectionModel()); |
156 | saver3->setScrollArea(treeView3); |
157 | @endcode |
158 | |
159 | @note The KViewStateSaver does not take ownership of any widgets set on it. |
160 | |
161 | It is recommended to restore the state on application startup and after the model has been reset, and to |
162 | save the state on application close and before the model has been reset. |
163 | |
164 | @see QAbstractItemModel::modelAboutToBeReset QAbstractItemModel::modelReset |
165 | |
166 | @author Stephen Kelly <stephen@kdab.com> |
167 | @since 4.5 |
168 | */ |
169 | class KDEUI_EXPORT KViewStateSaver : public QObject |
170 | { |
171 | Q_OBJECT |
172 | public: |
173 | /** |
174 | Constructor |
175 | @param parent standard parent object, but ignored since this object will delete itself |
176 | */ |
177 | explicit KViewStateSaver(QObject *parent = 0); |
178 | |
179 | /** |
180 | Destructor |
181 | */ |
182 | ~KViewStateSaver(); |
183 | |
184 | /** |
185 | * The view whose state is persisted. |
186 | */ |
187 | QAbstractItemView* view() const; |
188 | |
189 | /** |
190 | * Sets the view whose state is persisted. |
191 | */ |
192 | void setView(QAbstractItemView *view); |
193 | |
194 | /** |
195 | The QItemSelectionModel whose state is persisted. |
196 | */ |
197 | QItemSelectionModel* selectionModel() const; |
198 | |
199 | /** |
200 | Sets the QItemSelectionModel whose state is persisted. |
201 | */ |
202 | void setSelectionModel( QItemSelectionModel *selectionModel ); |
203 | |
204 | /** |
205 | Saves the state to the @p configGroup |
206 | */ |
207 | void saveState(KConfigGroup &configGroup); |
208 | |
209 | /** |
210 | Restores the state from the @p configGroup |
211 | */ |
212 | void restoreState(const KConfigGroup &configGroup); |
213 | |
214 | /** |
215 | * Returns a QStringList describing the selection in the selectionModel. |
216 | */ |
217 | QStringList selectionKeys() const; |
218 | |
219 | /** |
220 | * Returns a QStringList representing the expanded indexes in the QTreeView. |
221 | */ |
222 | QStringList expansionKeys() const; |
223 | |
224 | /** |
225 | * Returns a QString describing the current index in the selection model. |
226 | */ |
227 | QString currentIndexKey() const; |
228 | |
229 | /** |
230 | * Returns the vertical and horizontal scroll of the QAbstractScrollArea. |
231 | */ |
232 | QPair<int, int> scrollState() const; |
233 | |
234 | /** |
235 | * Select the indexes described by @p indexStrings |
236 | */ |
237 | void restoreSelection( const QStringList &indexStrings ); |
238 | |
239 | /** |
240 | * Make the index described by @p indexString the currentIndex in the selectionModel. |
241 | */ |
242 | void restoreCurrentItem( const QString &indexString ); |
243 | |
244 | /** |
245 | * Expand the indexes described by @p indexStrings in the QTreeView. |
246 | */ |
247 | void restoreExpanded( const QStringList &indexStrings ); |
248 | |
249 | /** |
250 | * Restores the scroll state of the QAbstractScrollArea to the @p verticalScoll |
251 | * and @p horizontalScroll |
252 | */ |
253 | void restoreScrollState( int verticalScoll, int horizontalScroll ); |
254 | |
255 | protected: |
256 | /** |
257 | Reimplement to return an index in the @p model described by the unique key @p key |
258 | */ |
259 | virtual QModelIndex indexFromConfigString(const QAbstractItemModel *model, const QString &key) const = 0; |
260 | |
261 | /** |
262 | Reimplement to return a unique string for the @p index. |
263 | */ |
264 | virtual QString indexToConfigString(const QModelIndex &index) const = 0; |
265 | |
266 | private: |
267 | //@cond PRIVATE |
268 | Q_DECLARE_PRIVATE(KViewStateSaver) |
269 | KViewStateSaverPrivate * const d_ptr; |
270 | Q_PRIVATE_SLOT( d_func(), void rowsInserted( const QModelIndex&, int, int ) ) |
271 | Q_PRIVATE_SLOT( d_func(), void restoreScrollBarState() ) |
272 | //@endcond |
273 | }; |
274 | |
275 | #endif |
276 | |