Page MenuHome GnuPG

No OneTemporary

diff --git a/src/ui/treeview.cpp b/src/ui/treeview.cpp
index a12e2133..59f07879 100644
--- a/src/ui/treeview.cpp
+++ b/src/ui/treeview.cpp
@@ -1,110 +1,198 @@
/*
ui/treeview.cpp
This file is part of libkleopatra
SPDX-FileCopyrightText: 2022 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <config-libkleo.h>
#include "treeview.h"
+#include <KConfigGroup>
#include <KLocalizedString>
+#include <KSharedConfig>
#include <QContextMenuEvent>
#include <QHeaderView>
#include <QMenu>
using namespace Kleo;
class TreeView::Private
{
+ TreeView *q;
+
public:
- Private()
- {
- }
QMenu *mHeaderPopup = nullptr;
QList<QAction *> mColumnActions;
+ QString mStateGroupName;
+
+ Private(TreeView *qq)
+ : q(qq)
+ {
+ }
+
+ ~Private()
+ {
+ saveColumnLayout();
+ }
+ void saveColumnLayout();
};
TreeView::TreeView(QWidget *parent)
: QTreeView::QTreeView(parent)
- , d{new Private}
+ , d{new Private(this)}
{
header()->installEventFilter(this);
}
TreeView::~TreeView() = default;
bool TreeView::eventFilter(QObject *watched, QEvent *event)
{
Q_UNUSED(watched)
if (event->type() == QEvent::ContextMenu) {
auto e = static_cast<QContextMenuEvent *>(event);
if (!d->mHeaderPopup) {
d->mHeaderPopup = new QMenu(this);
d->mHeaderPopup->setTitle(i18nc("@title:menu", "View Columns"));
for (int i = 0; i < model()->columnCount(); ++i) {
QAction *tmp = d->mHeaderPopup->addAction(model()->headerData(i, Qt::Horizontal).toString());
tmp->setData(QVariant(i));
tmp->setCheckable(true);
d->mColumnActions << tmp;
}
connect(d->mHeaderPopup, &QMenu::triggered, this, [this](QAction *action) {
const int col = action->data().toInt();
if (action->isChecked()) {
showColumn(col);
} else {
hideColumn(col);
}
if (action->isChecked()) {
Q_EMIT columnEnabled(col);
} else {
Q_EMIT columnDisabled(col);
}
});
}
for (QAction *action : std::as_const(d->mColumnActions)) {
const int column = action->data().toInt();
action->setChecked(!isColumnHidden(column));
}
d->mHeaderPopup->popup(mapToGlobal(e->pos()));
return true;
}
return false;
}
+void TreeView::Private::saveColumnLayout()
+{
+ if (mStateGroupName.isEmpty()) {
+ return;
+ }
+ auto config = KConfigGroup(KSharedConfig::openStateConfig(), mStateGroupName);
+ auto header = q->header();
+
+ QVariantList columnVisibility;
+ QVariantList columnOrder;
+ QVariantList columnWidths;
+ const int headerCount = header->count();
+ columnVisibility.reserve(headerCount);
+ columnWidths.reserve(headerCount);
+ columnOrder.reserve(headerCount);
+ for (int i = 0; i < headerCount; ++i) {
+ columnVisibility << QVariant(!q->isColumnHidden(i));
+ columnWidths << QVariant(header->sectionSize(i));
+ columnOrder << QVariant(header->visualIndex(i));
+ }
+
+ config.writeEntry("ColumnVisibility", columnVisibility);
+ config.writeEntry("ColumnOrder", columnOrder);
+ config.writeEntry("ColumnWidths", columnWidths);
+
+ config.writeEntry("SortAscending", (int)header->sortIndicatorOrder());
+ if (header->isSortIndicatorShown()) {
+ config.writeEntry("SortColumn", header->sortIndicatorSection());
+ } else {
+ config.writeEntry("SortColumn", -1);
+ }
+}
+
+bool TreeView::restoreColumnLayout(const QString &stateGroupName)
+{
+ if (stateGroupName.isEmpty()) {
+ return false;
+ }
+ d->mStateGroupName = stateGroupName;
+ auto config = KConfigGroup(KSharedConfig::openStateConfig(), d->mStateGroupName);
+ auto header = this->header();
+
+ QVariantList columnVisibility = config.readEntry("ColumnVisibility", QVariantList());
+ QVariantList columnOrder = config.readEntry("ColumnOrder", QVariantList());
+ QVariantList columnWidths = config.readEntry("ColumnWidths", QVariantList());
+
+ if (!columnVisibility.isEmpty() && !columnOrder.isEmpty() && !columnWidths.isEmpty()) {
+ for (int i = 0; i < header->count(); ++i) {
+ if (i >= columnOrder.size() || i >= columnWidths.size() || i >= columnVisibility.size()) {
+ // An additional column that was not around last time we saved.
+ // We default to hidden.
+ hideColumn(i);
+ continue;
+ }
+ bool visible = columnVisibility[i].toBool();
+ int width = columnWidths[i].toInt();
+ int order = columnOrder[i].toInt();
+
+ header->resizeSection(i, width ? width : 100);
+ header->moveSection(header->visualIndex(i), order);
+
+ if (!visible) {
+ hideColumn(i);
+ }
+ }
+ }
+
+ int sortOrder = config.readEntry("SortAscending", (int)Qt::AscendingOrder);
+ int sortColumn = config.readEntry("SortColumn", 0);
+ if (sortColumn >= 0) {
+ sortByColumn(sortColumn, (Qt::SortOrder)sortOrder);
+ }
+ return !columnVisibility.isEmpty() && !columnOrder.isEmpty() && !columnWidths.isEmpty();
+}
+
QModelIndex TreeView::moveCursor(QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
{
// make column by column keyboard navigation with Left/Right possible by switching
// the selection behavior to SelectItems before calling the parent class's moveCursor,
// because it ignores MoveLeft/MoveRight if the selection behavior is SelectRows;
// moreover, temporarily disable exanding of items to prevent expanding/collapsing
// on MoveLeft/MoveRight
if ((cursorAction != MoveLeft) && (cursorAction != MoveRight)) {
return QTreeView::moveCursor(cursorAction, modifiers);
}
const auto savedSelectionBehavior = selectionBehavior();
setSelectionBehavior(SelectItems);
const auto savedItemsExpandable = itemsExpandable();
setItemsExpandable(false);
const auto result = QTreeView::moveCursor(cursorAction, modifiers);
setItemsExpandable(savedItemsExpandable);
setSelectionBehavior(savedSelectionBehavior);
return result;
}
#include "moc_treeview.cpp"
diff --git a/src/ui/treeview.h b/src/ui/treeview.h
index 0fd42db7..4df1594d 100644
--- a/src/ui/treeview.h
+++ b/src/ui/treeview.h
@@ -1,59 +1,67 @@
/*
ui/treeview.h
This file is part of libkleopatra
SPDX-FileCopyrightText: 2022 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include "kleo_export.h"
#include <QTreeView>
namespace Kleo
{
/**
* A tree view that allows accessible column by column keyboard navigation
* and that has customizable columns through a context menu in the header.
*
* Column by column navigation is required to make a tree view accessible.
*
* The TreeView allows column by column keyboard navigation even if
* the selection behavior is set to SelectRows and users can expand/collapse
* list items. To achieve this it deactivates the standard behavior of QTreeView
* to expand/collapse items if the left/right arrow keys are used.
*
* Additionally, you may want to disable parent-child navigation in tree views
* with left/right arrow keys because this also interferes with column by column
* navigation. You can do this by setting
* "QTreeView { arrow-keys-navigate-into-children: 0; }"
* as application style sheet.
*
* \sa TreeWidget
*/
class KLEO_EXPORT TreeView : public QTreeView
{
Q_OBJECT
public:
TreeView(QWidget *parent = nullptr);
~TreeView() override;
+ /**
+ * Restores the layout state under key @p stateGroupName and enables state
+ * saving when the object is destroyed. Make sure that @p stateGroupName is
+ * unique for each place the widget occurs. Returns true if some state was
+ * restored. If false is returned, no state was restored and the caller should
+ * apply the default configuration.
+ */
+ bool restoreColumnLayout(const QString &stateGroupName);
Q_SIGNALS:
void columnEnabled(int column);
void columnDisabled(int column);
protected:
bool eventFilter(QObject *watched, QEvent *event) override;
QModelIndex moveCursor(QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers) override;
private:
class Private;
const std::unique_ptr<Private> d;
};
}
diff --git a/src/ui/treewidget.cpp b/src/ui/treewidget.cpp
index 7056fa18..1fb33a12 100644
--- a/src/ui/treewidget.cpp
+++ b/src/ui/treewidget.cpp
@@ -1,193 +1,198 @@
/*
ui/treewidget.cpp
This file is part of libkleopatra
SPDX-FileCopyrightText: 2022 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <config-libkleo.h>
#include "treewidget.h"
#include <KConfigGroup>
#include <KLocalizedString>
#include <KSharedConfig>
#include <QContextMenuEvent>
#include <QHeaderView>
#include <QMenu>
using namespace Kleo;
class TreeWidget::Private
{
+ TreeWidget *q;
+
public:
QMenu *mHeaderPopup = nullptr;
QList<QAction *> mColumnActions;
QString mStateGroupName;
- TreeWidget *q;
+ Private(TreeWidget *qq)
+ : q(qq)
+ {
+ }
~Private()
{
- q->saveColumnLayout();
+ saveColumnLayout();
}
+ void saveColumnLayout();
};
TreeWidget::TreeWidget(QWidget *parent)
: QTreeWidget::QTreeWidget(parent)
- , d{new Private}
+ , d{new Private(this)}
{
- d->q = this;
header()->installEventFilter(this);
}
TreeWidget::~TreeWidget() = default;
-void TreeWidget::saveColumnLayout()
+void TreeWidget::Private::saveColumnLayout()
{
- if (d->mStateGroupName.isEmpty()) {
+ if (mStateGroupName.isEmpty()) {
return;
}
- auto config = KConfigGroup(KSharedConfig::openStateConfig(), d->mStateGroupName);
- auto header = this->header();
+ auto config = KConfigGroup(KSharedConfig::openStateConfig(), mStateGroupName);
+ auto header = q->header();
QVariantList columnVisibility;
QVariantList columnOrder;
QVariantList columnWidths;
const int headerCount = header->count();
columnVisibility.reserve(headerCount);
columnWidths.reserve(headerCount);
columnOrder.reserve(headerCount);
for (int i = 0; i < headerCount; ++i) {
- columnVisibility << QVariant(!isColumnHidden(i));
+ columnVisibility << QVariant(!q->isColumnHidden(i));
columnWidths << QVariant(header->sectionSize(i));
columnOrder << QVariant(header->visualIndex(i));
}
config.writeEntry("ColumnVisibility", columnVisibility);
config.writeEntry("ColumnOrder", columnOrder);
config.writeEntry("ColumnWidths", columnWidths);
config.writeEntry("SortAscending", (int)header->sortIndicatorOrder());
if (header->isSortIndicatorShown()) {
config.writeEntry("SortColumn", header->sortIndicatorSection());
} else {
config.writeEntry("SortColumn", -1);
}
}
bool TreeWidget::restoreColumnLayout(const QString &stateGroupName)
{
if (stateGroupName.isEmpty()) {
return false;
}
d->mStateGroupName = stateGroupName;
auto config = KConfigGroup(KSharedConfig::openStateConfig(), d->mStateGroupName);
auto header = this->header();
QVariantList columnVisibility = config.readEntry("ColumnVisibility", QVariantList());
QVariantList columnOrder = config.readEntry("ColumnOrder", QVariantList());
QVariantList columnWidths = config.readEntry("ColumnWidths", QVariantList());
- if (!columnVisibility.isEmpty()) {
+ if (!columnVisibility.isEmpty() && !columnOrder.isEmpty() && !columnWidths.isEmpty()) {
for (int i = 0; i < header->count(); ++i) {
if (i >= columnOrder.size() || i >= columnWidths.size() || i >= columnVisibility.size()) {
// An additional column that was not around last time we saved.
// We default to hidden.
hideColumn(i);
continue;
}
bool visible = columnVisibility[i].toBool();
int width = columnWidths[i].toInt();
int order = columnOrder[i].toInt();
header->resizeSection(i, width ? width : 100);
header->moveSection(header->visualIndex(i), order);
if (!visible) {
hideColumn(i);
}
}
}
int sortOrder = config.readEntry("SortAscending", (int)Qt::AscendingOrder);
int sortColumn = config.readEntry("SortColumn", 0);
if (sortColumn >= 0) {
sortByColumn(sortColumn, (Qt::SortOrder)sortOrder);
}
- return !columnVisibility.isEmpty();
+ return !columnVisibility.isEmpty() && !columnOrder.isEmpty() && !columnWidths.isEmpty();
}
bool TreeWidget::eventFilter(QObject *watched, QEvent *event)
{
Q_UNUSED(watched)
if (event->type() == QEvent::ContextMenu) {
auto e = static_cast<QContextMenuEvent *>(event);
if (!d->mHeaderPopup) {
d->mHeaderPopup = new QMenu(this);
d->mHeaderPopup->setTitle(i18nc("@title:menu", "View Columns"));
for (int i = 0; i < model()->columnCount(); ++i) {
QAction *tmp = d->mHeaderPopup->addAction(model()->headerData(i, Qt::Horizontal).toString());
tmp->setData(QVariant(i));
tmp->setCheckable(true);
d->mColumnActions << tmp;
}
connect(d->mHeaderPopup, &QMenu::triggered, this, [this](QAction *action) {
const int col = action->data().toInt();
if (action->isChecked()) {
showColumn(col);
} else {
hideColumn(col);
}
if (action->isChecked()) {
Q_EMIT columnEnabled(col);
} else {
Q_EMIT columnDisabled(col);
}
});
}
for (QAction *action : std::as_const(d->mColumnActions)) {
const int column = action->data().toInt();
action->setChecked(!isColumnHidden(column));
}
d->mHeaderPopup->popup(mapToGlobal(e->pos()));
return true;
}
return false;
}
QModelIndex TreeWidget::moveCursor(QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
{
// make column by column keyboard navigation with Left/Right possible by switching
// the selection behavior to SelectItems before calling the parent class's moveCursor,
// because it ignores MoveLeft/MoveRight if the selection behavior is SelectRows;
// moreover, temporarily disable exanding of items to prevent expanding/collapsing
// on MoveLeft/MoveRight
if ((cursorAction != MoveLeft) && (cursorAction != MoveRight)) {
return QTreeWidget::moveCursor(cursorAction, modifiers);
}
const auto savedSelectionBehavior = selectionBehavior();
setSelectionBehavior(SelectItems);
const auto savedItemsExpandable = itemsExpandable();
setItemsExpandable(false);
const auto result = QTreeWidget::moveCursor(cursorAction, modifiers);
setItemsExpandable(savedItemsExpandable);
setSelectionBehavior(savedSelectionBehavior);
return result;
}
#include "moc_treewidget.cpp"
diff --git a/src/ui/treewidget.h b/src/ui/treewidget.h
index 51a62df1..3039214f 100644
--- a/src/ui/treewidget.h
+++ b/src/ui/treewidget.h
@@ -1,58 +1,57 @@
/*
ui/treewidget.h
This file is part of libkleopatra
SPDX-FileCopyrightText: 2022 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include "kleo_export.h"
#include <QTreeWidget>
namespace Kleo
{
/**
* A tree widget that allows accessible column by column keyboard navigation
* and that has customizable columns through a context menu in the header.
*
* This is the QTreeWidget-derived variant of TreeView.
*
* \sa TreeView
*/
class KLEO_EXPORT TreeWidget : public QTreeWidget
{
Q_OBJECT
public:
TreeWidget(QWidget *parent = nullptr);
~TreeWidget() override;
/**
- * Restores the layout state under key 'stateGroupName' and enables state
- * saving when the object is destroyed. Make sure that 'stateGroupName' is
+ * Restores the layout state under key @p stateGroupName and enables state
+ * saving when the object is destroyed. Make sure that @p stateGroupName is
* unique for each place the widget occurs. Returns true if some state was
* restored. If false is returned, no state was restored and the caller should
* apply the default configuration.
*/
bool restoreColumnLayout(const QString &stateGroupName);
Q_SIGNALS:
void columnEnabled(int column);
void columnDisabled(int column);
protected:
bool eventFilter(QObject *watched, QEvent *event) override;
QModelIndex moveCursor(QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers) override;
private:
class Private;
const std::unique_ptr<Private> d;
- void saveColumnLayout();
};
}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Dec 23, 3:16 PM (19 h, 14 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
dd/a6/b86729164bff70d9f0767d388dd6

Event Timeline