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

akonadi

  • sources
  • kde-4.14
  • kdepimlibs
  • akonadi
entitytreeviewstatesaver.cpp
1 /*
2  Copyright (c) 2009 Volker Krause <vkrause@kde.org>
3 
4  This library is free software; you can redistribute it and/or modify it
5  under the terms of the GNU Library General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or (at your
7  option) any later version.
8 
9  This library is distributed in the hope that it will be useful, but WITHOUT
10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12  License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to the
16  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  02110-1301, USA.
18 */
19 
20 #include "entitytreeviewstatesaver.h"
21 
22 #include <akonadi/collection.h>
23 #include <akonadi/entitytreemodel.h>
24 #include <akonadi/item.h>
25 
26 #include <KConfigGroup>
27 #include <KDebug>
28 
29 #include <QScrollBar>
30 #include <QTimer>
31 #include <QTreeView>
32 
33 namespace Akonadi {
34 
35 struct State
36 {
37  State()
38  : selected(false)
39  , expanded(false)
40  , currentIndex(false)
41  {
42  }
43  bool selected;
44  bool expanded;
45  bool currentIndex;
46 };
47 
48 class EntityTreeViewStateSaverPrivate
49 {
50 public:
51  explicit EntityTreeViewStateSaverPrivate(EntityTreeViewStateSaver *parent)
52  : q(parent)
53  , view(0)
54  , horizontalScrollBarValue(-1)
55  , verticalScrollBarValue(-1)
56  {
57  }
58 
59  inline bool hasChanges() const
60  {
61  return !pendingCollectionChanges.isEmpty() || !pendingItemChanges.isEmpty();
62  }
63 
64  static inline QString key(const QModelIndex &index)
65  {
66  if (!index.isValid()) {
67  return QLatin1String("x-1");
68  }
69  const Collection c = index.data(EntityTreeModel::CollectionRole).value<Collection>();
70  if (c.isValid()) {
71  return QString::fromLatin1("c%1").arg(c.id());
72  }
73  return QString::fromLatin1("i%1").arg(index.data(EntityTreeModel::ItemIdRole).value<Entity::Id>());
74  }
75 
76  void saveState(const QModelIndex &index, QStringList &selection, QStringList &expansion)
77  {
78  const QString cfgKey = key(index);
79  if (view->selectionModel()->isSelected(index)) {
80  selection.append(cfgKey);
81  }
82  if (view->isExpanded(index)) {
83  expansion.append(cfgKey);
84  }
85  for (int i = 0; i < view->model()->rowCount(index); ++i) {
86  const QModelIndex child = view->model()->index(i, 0, index);
87  saveState(child, selection, expansion);
88  }
89  }
90 
91  inline void restoreState(const QModelIndex &index, const State &state)
92  {
93  if (state.selected) {
94  view->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Rows);
95  }
96  if (state.expanded) {
97  view->setExpanded(index, true);
98  }
99  if (state.currentIndex) {
100  view->setCurrentIndex(index);
101  }
102  QTimer::singleShot(0, q, SLOT(restoreScrollBarState()));
103  }
104 
105  void restoreState(const QModelIndex &index)
106  {
107  const Collection c = index.data(EntityTreeModel::CollectionRole).value<Collection>();
108  if (c.isValid()) {
109  if (pendingCollectionChanges.contains(c.id())) {
110  restoreState(index, pendingCollectionChanges.value(c.id()));
111  pendingCollectionChanges.remove(c.id());
112  }
113  } else {
114  Entity::Id itemId = index.data(EntityTreeModel::ItemIdRole).value<Entity::Id>();
115  if (pendingItemChanges.contains(itemId)) {
116  restoreState(index, pendingItemChanges.value(itemId));
117  pendingItemChanges.remove(itemId);
118  }
119  }
120  for (int i = 0; i < view->model()->rowCount(index) && hasChanges(); ++i) {
121  const QModelIndex child = view->model()->index(i, 0, index);
122  restoreState(child);
123  }
124  }
125 
126  inline void restoreScrollBarState()
127  {
128  if (horizontalScrollBarValue >= 0 && horizontalScrollBarValue <= view->horizontalScrollBar()->maximum()) {
129  view->horizontalScrollBar()->setValue(horizontalScrollBarValue);
130  horizontalScrollBarValue = -1;
131  }
132  if (verticalScrollBarValue >= 0 && verticalScrollBarValue <= view->verticalScrollBar()->maximum()) {
133  view->verticalScrollBar()->setValue(verticalScrollBarValue);
134  verticalScrollBarValue = -1;
135  }
136  }
137 
138  void rowsInserted(const QModelIndex &index, int start, int end)
139  {
140  if (!hasChanges()) {
141  QObject::disconnect(view->model(), SIGNAL(rowsInserted(QModelIndex,int,int)),
142  q, SLOT(rowsInserted(QModelIndex,int,int)));
143  return;
144  }
145 
146  for (int i = start; i <= end && hasChanges(); ++i) {
147  const QModelIndex child = view->model()->index(i, 0, index);;
148  restoreState(child);
149  }
150  }
151 
152  EntityTreeViewStateSaver *q;
153  QTreeView *view;
154  QHash<Entity::Id, State> pendingCollectionChanges, pendingItemChanges;
155  int horizontalScrollBarValue, verticalScrollBarValue;
156 };
157 
158 EntityTreeViewStateSaver::EntityTreeViewStateSaver(QTreeView *view)
159  : QObject(view)
160  , d(new EntityTreeViewStateSaverPrivate(this))
161 {
162  d->view = view;
163 }
164 
165 EntityTreeViewStateSaver::~EntityTreeViewStateSaver()
166 {
167  delete d;
168 }
169 
170 void EntityTreeViewStateSaver::saveState(KConfigGroup &configGroup) const
171 {
172  if (!d->view->model()) {
173  return;
174  }
175 
176  configGroup.deleteGroup();
177  QStringList selection, expansion;
178  const int rowCount = d->view->model()->rowCount();
179  for (int i = 0; i < rowCount; ++i) {
180  const QModelIndex index = d->view->model()->index(i, 0);
181  d->saveState(index, selection, expansion);
182  }
183 
184  const QString currentIndex = d->key(d->view->selectionModel()->currentIndex());
185 
186  configGroup.writeEntry("Selection", selection);
187  configGroup.writeEntry("Expansion", expansion);
188  configGroup.writeEntry("CurrentIndex", currentIndex);
189  configGroup.writeEntry("ScrollBarHorizontal", d->view->horizontalScrollBar()->value());
190  configGroup.writeEntry("ScrollBarVertical", d->view->verticalScrollBar()->value());
191 }
192 
193 void EntityTreeViewStateSaver::restoreState(const KConfigGroup &configGroup) const
194 {
195  if (!d->view->model()) {
196  return;
197  }
198 
199  const QStringList selection = configGroup.readEntry("Selection", QStringList());
200  foreach (const QString &key, selection) {
201  Entity::Id id = key.mid(1).toLongLong();
202  if (id < 0) {
203  continue;
204  }
205  if (key.startsWith(QLatin1Char('c'))) {
206  d->pendingCollectionChanges[id].selected = true;
207  } else if (key.startsWith(QLatin1Char('i'))) {
208  d->pendingItemChanges[id].selected = true;
209  }
210  }
211 
212  const QStringList expansion = configGroup.readEntry("Expansion", QStringList());
213  foreach (const QString &key, expansion) {
214  Entity::Id id = key.mid(1).toLongLong();
215  if (id < 0) {
216  continue;
217  }
218  if (key.startsWith(QLatin1Char('c'))) {
219  d->pendingCollectionChanges[id].expanded = true;
220  } else if (key.startsWith(QLatin1Char('i'))) {
221  d->pendingItemChanges[id].expanded = true;
222  }
223  }
224 
225  const QString key = configGroup.readEntry("CurrentIndex", QString());
226  const Entity::Id id = key.mid(1).toLongLong();
227  if (id >= 0) {
228  if (key.startsWith(QLatin1Char('c'))) {
229  d->pendingCollectionChanges[id].currentIndex = true;
230  } else if (key.startsWith(QLatin1Char('i'))) {
231  d->pendingItemChanges[id].currentIndex = true;
232  }
233  }
234 
235  d->horizontalScrollBarValue = configGroup.readEntry("ScrollBarHorizontal", -1);
236  d->verticalScrollBarValue = configGroup.readEntry("ScrollBarVertical", -1);
237 
238  // initial restore run, for everything already loaded
239  for (int i = 0; i < d->view->model()->rowCount() && d->hasChanges(); ++i) {
240  const QModelIndex index = d->view->model()->index(i, 0);
241  d->restoreState(index);
242  }
243  d->restoreScrollBarState();
244 
245  // watch the model for stuff coming in delayed
246  if (d->hasChanges()) {
247  connect(d->view->model(), SIGNAL(rowsInserted(QModelIndex,int,int)),
248  SLOT(rowsInserted(QModelIndex,int,int)));
249  }
250 }
251 
252 } // namespace Akonadi
253 
254 #include "moc_entitytreeviewstatesaver.cpp"
QModelIndex
QAbstractItemModel::index
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const =0
Akonadi::EntityTreeViewStateSaver::~EntityTreeViewStateSaver
~EntityTreeViewStateSaver()
Destroys this state saver.
Definition: entitytreeviewstatesaver.cpp:165
Akonadi::Entity::Id
qint64 Id
Describes the unique id type.
Definition: entity.h:65
QVariant::value
T value() const
QObject::disconnect
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
QModelIndex::isValid
bool isValid() const
QList::append
void append(const T &value)
QHash
QObject
Akonadi::EntityTreeViewStateSaver::EntityTreeViewStateSaver
EntityTreeViewStateSaver(QTreeView *view)
Creates a new state saver, for saving or restoring.
Definition: entitytreeviewstatesaver.cpp:158
QString::startsWith
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
Akonadi::EntityTreeModel::CollectionRole
The collection.
Definition: entitytreemodel.h:336
QString
Akonadi::EntityTreeViewStateSaver::restoreState
void restoreState(const KConfigGroup &configGroup) const
Restore the state stored in configGroup as soon as the corresponding entities become available in the...
Definition: entitytreeviewstatesaver.cpp:193
QStringList
QLatin1Char
QModelIndex::model
const QAbstractItemModel * model() const
QString::mid
QString mid(int position, int n) const
QModelIndex::data
QVariant data(int role) const
QLatin1String
QTreeView
QString::fromLatin1
QString fromLatin1(const char *str, int size)
Akonadi::EntityTreeViewStateSaver::saveState
void saveState(KConfigGroup &configGroup) const
Stores the current state in the given config group.
Definition: entitytreeviewstatesaver.cpp:170
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QString::arg
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QString::toLongLong
qlonglong toLongLong(bool *ok, int base) const
QTimer::singleShot
singleShot
Akonadi::EntityTreeModel::ItemIdRole
The item id.
Definition: entitytreemodel.h:331
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:38:03 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akonadi

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

kdepimlibs API Reference

Skip menu "kdepimlibs API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal