mirror of
https://bitbucket.org/smil3y/kde-playground.git
synced 2025-02-23 10:22:50 +00:00
254 lines
8.3 KiB
C++
254 lines
8.3 KiB
C++
/*
|
|
Copyright (c) 2009 Volker Krause <vkrause@kde.org>
|
|
|
|
This library is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU Library General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or (at your
|
|
option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
|
|
License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; see the file COPYING.LIB. If not, write to the
|
|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
02110-1301, USA.
|
|
*/
|
|
|
|
#include "entitytreeviewstatesaver.h"
|
|
|
|
#include <akonadi/collection.h>
|
|
#include <akonadi/entitytreemodel.h>
|
|
#include <akonadi/item.h>
|
|
|
|
#include <KConfigGroup>
|
|
#include <KDebug>
|
|
|
|
#include <QScrollBar>
|
|
#include <QTimer>
|
|
#include <QTreeView>
|
|
|
|
namespace Akonadi {
|
|
|
|
struct State
|
|
{
|
|
State()
|
|
: selected(false)
|
|
, expanded(false)
|
|
, currentIndex(false)
|
|
{
|
|
}
|
|
bool selected;
|
|
bool expanded;
|
|
bool currentIndex;
|
|
};
|
|
|
|
class EntityTreeViewStateSaverPrivate
|
|
{
|
|
public:
|
|
explicit EntityTreeViewStateSaverPrivate(EntityTreeViewStateSaver *parent)
|
|
: q(parent)
|
|
, view(0)
|
|
, horizontalScrollBarValue(-1)
|
|
, verticalScrollBarValue(-1)
|
|
{
|
|
}
|
|
|
|
inline bool hasChanges() const
|
|
{
|
|
return !pendingCollectionChanges.isEmpty() || !pendingItemChanges.isEmpty();
|
|
}
|
|
|
|
static inline QString key(const QModelIndex &index)
|
|
{
|
|
if (!index.isValid()) {
|
|
return QLatin1String("x-1");
|
|
}
|
|
const Collection c = index.data(EntityTreeModel::CollectionRole).value<Collection>();
|
|
if (c.isValid()) {
|
|
return QString::fromLatin1("c%1").arg(c.id());
|
|
}
|
|
return QString::fromLatin1("i%1").arg(index.data(EntityTreeModel::ItemIdRole).value<Entity::Id>());
|
|
}
|
|
|
|
void saveState(const QModelIndex &index, QStringList &selection, QStringList &expansion)
|
|
{
|
|
const QString cfgKey = key(index);
|
|
if (view->selectionModel()->isSelected(index)) {
|
|
selection.append(cfgKey);
|
|
}
|
|
if (view->isExpanded(index)) {
|
|
expansion.append(cfgKey);
|
|
}
|
|
for (int i = 0; i < view->model()->rowCount(index); ++i) {
|
|
const QModelIndex child = view->model()->index(i, 0, index);
|
|
saveState(child, selection, expansion);
|
|
}
|
|
}
|
|
|
|
inline void restoreState(const QModelIndex &index, const State &state)
|
|
{
|
|
if (state.selected) {
|
|
view->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Rows);
|
|
}
|
|
if (state.expanded) {
|
|
view->setExpanded(index, true);
|
|
}
|
|
if (state.currentIndex) {
|
|
view->setCurrentIndex(index);
|
|
}
|
|
QTimer::singleShot(0, q, SLOT(restoreScrollBarState()));
|
|
}
|
|
|
|
void restoreState(const QModelIndex &index)
|
|
{
|
|
const Collection c = index.data(EntityTreeModel::CollectionRole).value<Collection>();
|
|
if (c.isValid()) {
|
|
if (pendingCollectionChanges.contains(c.id())) {
|
|
restoreState(index, pendingCollectionChanges.value(c.id()));
|
|
pendingCollectionChanges.remove(c.id());
|
|
}
|
|
} else {
|
|
Entity::Id itemId = index.data(EntityTreeModel::ItemIdRole).value<Entity::Id>();
|
|
if (pendingItemChanges.contains(itemId)) {
|
|
restoreState(index, pendingItemChanges.value(itemId));
|
|
pendingItemChanges.remove(itemId);
|
|
}
|
|
}
|
|
for (int i = 0; i < view->model()->rowCount(index) && hasChanges(); ++i) {
|
|
const QModelIndex child = view->model()->index(i, 0, index);
|
|
restoreState(child);
|
|
}
|
|
}
|
|
|
|
inline void restoreScrollBarState()
|
|
{
|
|
if (horizontalScrollBarValue >= 0 && horizontalScrollBarValue <= view->horizontalScrollBar()->maximum()) {
|
|
view->horizontalScrollBar()->setValue(horizontalScrollBarValue);
|
|
horizontalScrollBarValue = -1;
|
|
}
|
|
if (verticalScrollBarValue >= 0 && verticalScrollBarValue <= view->verticalScrollBar()->maximum()) {
|
|
view->verticalScrollBar()->setValue(verticalScrollBarValue);
|
|
verticalScrollBarValue = -1;
|
|
}
|
|
}
|
|
|
|
void rowsInserted(const QModelIndex &index, int start, int end)
|
|
{
|
|
if (!hasChanges()) {
|
|
QObject::disconnect(view->model(), SIGNAL(rowsInserted(QModelIndex,int,int)),
|
|
q, SLOT(rowsInserted(QModelIndex,int,int)));
|
|
return;
|
|
}
|
|
|
|
for (int i = start; i <= end && hasChanges(); ++i) {
|
|
const QModelIndex child = view->model()->index(i, 0, index);;
|
|
restoreState(child);
|
|
}
|
|
}
|
|
|
|
EntityTreeViewStateSaver *q;
|
|
QTreeView *view;
|
|
QHash<Entity::Id, State> pendingCollectionChanges, pendingItemChanges;
|
|
int horizontalScrollBarValue, verticalScrollBarValue;
|
|
};
|
|
|
|
EntityTreeViewStateSaver::EntityTreeViewStateSaver(QTreeView *view)
|
|
: QObject(view)
|
|
, d(new EntityTreeViewStateSaverPrivate(this))
|
|
{
|
|
d->view = view;
|
|
}
|
|
|
|
EntityTreeViewStateSaver::~EntityTreeViewStateSaver()
|
|
{
|
|
delete d;
|
|
}
|
|
|
|
void EntityTreeViewStateSaver::saveState(KConfigGroup &configGroup) const
|
|
{
|
|
if (!d->view->model()) {
|
|
return;
|
|
}
|
|
|
|
configGroup.deleteGroup();
|
|
QStringList selection, expansion;
|
|
const int rowCount = d->view->model()->rowCount();
|
|
for (int i = 0; i < rowCount; ++i) {
|
|
const QModelIndex index = d->view->model()->index(i, 0);
|
|
d->saveState(index, selection, expansion);
|
|
}
|
|
|
|
const QString currentIndex = d->key(d->view->selectionModel()->currentIndex());
|
|
|
|
configGroup.writeEntry("Selection", selection);
|
|
configGroup.writeEntry("Expansion", expansion);
|
|
configGroup.writeEntry("CurrentIndex", currentIndex);
|
|
configGroup.writeEntry("ScrollBarHorizontal", d->view->horizontalScrollBar()->value());
|
|
configGroup.writeEntry("ScrollBarVertical", d->view->verticalScrollBar()->value());
|
|
}
|
|
|
|
void EntityTreeViewStateSaver::restoreState(const KConfigGroup &configGroup) const
|
|
{
|
|
if (!d->view->model()) {
|
|
return;
|
|
}
|
|
|
|
const QStringList selection = configGroup.readEntry("Selection", QStringList());
|
|
foreach (const QString &key, selection) {
|
|
Entity::Id id = key.mid(1).toLongLong();
|
|
if (id < 0) {
|
|
continue;
|
|
}
|
|
if (key.startsWith(QLatin1Char('c'))) {
|
|
d->pendingCollectionChanges[id].selected = true;
|
|
} else if (key.startsWith(QLatin1Char('i'))) {
|
|
d->pendingItemChanges[id].selected = true;
|
|
}
|
|
}
|
|
|
|
const QStringList expansion = configGroup.readEntry("Expansion", QStringList());
|
|
foreach (const QString &key, expansion) {
|
|
Entity::Id id = key.mid(1).toLongLong();
|
|
if (id < 0) {
|
|
continue;
|
|
}
|
|
if (key.startsWith(QLatin1Char('c'))) {
|
|
d->pendingCollectionChanges[id].expanded = true;
|
|
} else if (key.startsWith(QLatin1Char('i'))) {
|
|
d->pendingItemChanges[id].expanded = true;
|
|
}
|
|
}
|
|
|
|
const QString key = configGroup.readEntry("CurrentIndex", QString());
|
|
const Entity::Id id = key.mid(1).toLongLong();
|
|
if (id >= 0) {
|
|
if (key.startsWith(QLatin1Char('c'))) {
|
|
d->pendingCollectionChanges[id].currentIndex = true;
|
|
} else if (key.startsWith(QLatin1Char('i'))) {
|
|
d->pendingItemChanges[id].currentIndex = true;
|
|
}
|
|
}
|
|
|
|
d->horizontalScrollBarValue = configGroup.readEntry("ScrollBarHorizontal", -1);
|
|
d->verticalScrollBarValue = configGroup.readEntry("ScrollBarVertical", -1);
|
|
|
|
// initial restore run, for everything already loaded
|
|
for (int i = 0; i < d->view->model()->rowCount() && d->hasChanges(); ++i) {
|
|
const QModelIndex index = d->view->model()->index(i, 0);
|
|
d->restoreState(index);
|
|
}
|
|
d->restoreScrollBarState();
|
|
|
|
// watch the model for stuff coming in delayed
|
|
if (d->hasChanges()) {
|
|
connect(d->view->model(), SIGNAL(rowsInserted(QModelIndex,int,int)),
|
|
SLOT(rowsInserted(QModelIndex,int,int)));
|
|
}
|
|
}
|
|
|
|
} // namespace Akonadi
|
|
|
|
#include "moc_entitytreeviewstatesaver.cpp"
|