Page MenuHome GnuPG

No OneTemporary

diff --git a/src/ui/treeview.cpp b/src/ui/treeview.cpp
index f2399870..46a067a9 100644
--- a/src/ui/treeview.cpp
+++ b/src/ui/treeview.cpp
@@ -1,224 +1,227 @@
/*
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:
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(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);
+ if (columnWidth(col) == 0) {
+ resizeColumnToContents(col);
+ }
} else {
hideColumn(col);
}
if (action->isChecked()) {
Q_EMIT columnEnabled(col);
} else {
Q_EMIT columnDisabled(col);
}
d->saveColumnLayout();
});
}
for (QAction *action : std::as_const(d->mColumnActions)) {
const int column = action->data().toInt();
action->setChecked(!isColumnHidden(column));
}
auto numVisibleColumns = std::count_if(d->mColumnActions.cbegin(), d->mColumnActions.cend(), [](const auto &action) {
return action->isChecked();
});
for (auto action : std::as_const(d->mColumnActions)) {
action->setEnabled(numVisibleColumns != 1 || !action->isChecked());
}
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);
}
config.sync();
}
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);
}
connect(header, &QHeaderView::sectionResized, this, [this]() {
d->saveColumnLayout();
});
connect(header, &QHeaderView::sectionMoved, this, [this]() {
d->saveColumnLayout();
});
connect(header, &QHeaderView::sortIndicatorChanged, this, [this]() {
d->saveColumnLayout();
});
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;
}
void TreeView::saveColumnLayout(const QString &stateGroupName)
{
d->mStateGroupName = stateGroupName;
d->saveColumnLayout();
}
#include "moc_treeview.cpp"
diff --git a/src/ui/treewidget.cpp b/src/ui/treewidget.cpp
index 69f2ca1a..650133f0 100644
--- a/src/ui/treewidget.cpp
+++ b/src/ui/treewidget.cpp
@@ -1,255 +1,258 @@
/*
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;
std::vector<bool> mColumnForcedHidden;
Private(TreeWidget *qq)
: q(qq)
{
}
~Private()
{
saveColumnLayout();
}
void saveColumnLayout();
};
TreeWidget::TreeWidget(QWidget *parent)
: QTreeWidget::QTreeWidget(parent)
, d{new Private(this)}
{
header()->installEventFilter(this);
}
TreeWidget::~TreeWidget() = default;
void TreeWidget::forceColumnHidden(int column)
{
if (column > columnCount()) {
return;
}
// ensure that the mColumnForcedHidden vector is initialized
d->mColumnForcedHidden.resize(columnCount(), false);
d->mColumnForcedHidden[column] = true;
}
void TreeWidget::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);
}
config.sync();
}
bool TreeWidget::restoreColumnLayout(const QString &stateGroupName)
{
if (stateGroupName.isEmpty()) {
return false;
}
// ensure that the mColumnForcedHidden vector is initialized
d->mColumnForcedHidden.resize(columnCount(), 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 (d->mColumnForcedHidden[i] || i >= columnOrder.size() || i >= columnWidths.size() || i >= columnVisibility.size()) {
// Hide columns that are forced hidden and new columns that were not around the last time we saved
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);
}
}
} else {
for (int i = 0; i < header->count(); ++i) {
if (d->mColumnForcedHidden[i]) {
hideColumn(i);
}
}
}
int sortOrder = config.readEntry("SortAscending", (int)Qt::AscendingOrder);
int sortColumn = config.readEntry("SortColumn", 0);
if (sortColumn >= 0) {
sortByColumn(sortColumn, (Qt::SortOrder)sortOrder);
}
connect(header, &QHeaderView::sectionResized, this, [this]() {
d->saveColumnLayout();
});
connect(header, &QHeaderView::sectionMoved, this, [this]() {
d->saveColumnLayout();
});
connect(header, &QHeaderView::sortIndicatorChanged, this, [this]() {
d->saveColumnLayout();
});
return !columnVisibility.isEmpty() && !columnOrder.isEmpty() && !columnWidths.isEmpty();
}
bool TreeWidget::eventFilter(QObject *watched, QEvent *event)
{
if ((watched == header()) && (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);
+ if (columnWidth(col) == 0) {
+ resizeColumnToContents(col);
+ }
} else {
hideColumn(col);
}
if (action->isChecked()) {
Q_EMIT columnEnabled(col);
} else {
Q_EMIT columnDisabled(col);
}
d->saveColumnLayout();
});
}
for (QAction *action : std::as_const(d->mColumnActions)) {
const int column = action->data().toInt();
action->setChecked(!isColumnHidden(column));
}
auto numVisibleColumns = std::count_if(d->mColumnActions.cbegin(), d->mColumnActions.cend(), [](const auto &action) {
return action->isChecked();
});
for (auto action : std::as_const(d->mColumnActions)) {
action->setEnabled(numVisibleColumns != 1 || !action->isChecked());
}
d->mHeaderPopup->popup(mapToGlobal(e->pos()));
return true;
}
return QTreeWidget::eventFilter(watched, event);
}
void TreeWidget::focusInEvent(QFocusEvent *event)
{
QTreeWidget::focusInEvent(event);
// workaround for wrong order of accessible focus events emitted by Qt for QTreeWidget;
// on first focusing of QTreeWidget, Qt sends focus event for current item before focus event for tree
// so that orca doesn't announce the current item;
// on re-focusing of QTreeWidget, Qt only sends focus event for tree
auto forceAccessibleFocusEventForCurrentItem = [this]() {
// force Qt to send a focus event for the current item to accessibility
// tools; otherwise, the user has no idea which item is selected when the
// list gets keyboard input focus
const QModelIndex index = currentIndex();
if (index.isValid()) {
currentChanged(index, QModelIndex{});
}
};
// queue the invocation, so that it happens after the widget itself got focus
QMetaObject::invokeMethod(this, forceAccessibleFocusEventForCurrentItem, Qt::QueuedConnection);
}
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"

File Metadata

Mime Type
text/x-diff
Expires
Mon, Dec 23, 3:20 PM (18 m, 53 s)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
94/e6/27330fd21378e7e2c0928deba428

Event Timeline