File indexing completed on 2025-01-05 04:55:50
0001 /* 0002 ui/treeview.cpp 0003 0004 This file is part of libkleopatra 0005 SPDX-FileCopyrightText: 2022 g10 Code GmbH 0006 SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 #include <config-libkleo.h> 0012 0013 #include "treeview.h" 0014 0015 #include <KConfigGroup> 0016 #include <KLocalizedString> 0017 #include <KSharedConfig> 0018 0019 #include <QContextMenuEvent> 0020 #include <QHeaderView> 0021 #include <QMenu> 0022 0023 using namespace Kleo; 0024 0025 class TreeView::Private 0026 { 0027 TreeView *q; 0028 0029 public: 0030 QMenu *mHeaderPopup = nullptr; 0031 QList<QAction *> mColumnActions; 0032 QString mStateGroupName; 0033 0034 Private(TreeView *qq) 0035 : q(qq) 0036 { 0037 } 0038 0039 ~Private() 0040 { 0041 saveColumnLayout(); 0042 } 0043 void saveColumnLayout(); 0044 }; 0045 0046 TreeView::TreeView(QWidget *parent) 0047 : QTreeView::QTreeView(parent) 0048 , d{new Private(this)} 0049 { 0050 header()->installEventFilter(this); 0051 } 0052 0053 TreeView::~TreeView() = default; 0054 0055 bool TreeView::eventFilter(QObject *watched, QEvent *event) 0056 { 0057 Q_UNUSED(watched) 0058 if (event->type() == QEvent::ContextMenu) { 0059 auto e = static_cast<QContextMenuEvent *>(event); 0060 0061 if (!d->mHeaderPopup) { 0062 d->mHeaderPopup = new QMenu(this); 0063 d->mHeaderPopup->setTitle(i18nc("@title:menu", "View Columns")); 0064 for (int i = 0; i < model()->columnCount(); ++i) { 0065 QAction *tmp = d->mHeaderPopup->addAction(model()->headerData(i, Qt::Horizontal).toString()); 0066 tmp->setData(QVariant(i)); 0067 tmp->setCheckable(true); 0068 d->mColumnActions << tmp; 0069 } 0070 0071 connect(d->mHeaderPopup, &QMenu::triggered, this, [this](QAction *action) { 0072 const int col = action->data().toInt(); 0073 if (action->isChecked()) { 0074 showColumn(col); 0075 } else { 0076 hideColumn(col); 0077 } 0078 0079 if (action->isChecked()) { 0080 Q_EMIT columnEnabled(col); 0081 } else { 0082 Q_EMIT columnDisabled(col); 0083 } 0084 }); 0085 } 0086 0087 for (QAction *action : std::as_const(d->mColumnActions)) { 0088 const int column = action->data().toInt(); 0089 action->setChecked(!isColumnHidden(column)); 0090 } 0091 0092 d->mHeaderPopup->popup(mapToGlobal(e->pos())); 0093 return true; 0094 } 0095 0096 return false; 0097 } 0098 0099 void TreeView::Private::saveColumnLayout() 0100 { 0101 if (mStateGroupName.isEmpty()) { 0102 return; 0103 } 0104 auto config = KConfigGroup(KSharedConfig::openStateConfig(), mStateGroupName); 0105 auto header = q->header(); 0106 0107 QVariantList columnVisibility; 0108 QVariantList columnOrder; 0109 QVariantList columnWidths; 0110 const int headerCount = header->count(); 0111 columnVisibility.reserve(headerCount); 0112 columnWidths.reserve(headerCount); 0113 columnOrder.reserve(headerCount); 0114 for (int i = 0; i < headerCount; ++i) { 0115 columnVisibility << QVariant(!q->isColumnHidden(i)); 0116 columnWidths << QVariant(header->sectionSize(i)); 0117 columnOrder << QVariant(header->visualIndex(i)); 0118 } 0119 0120 config.writeEntry("ColumnVisibility", columnVisibility); 0121 config.writeEntry("ColumnOrder", columnOrder); 0122 config.writeEntry("ColumnWidths", columnWidths); 0123 0124 config.writeEntry("SortAscending", (int)header->sortIndicatorOrder()); 0125 if (header->isSortIndicatorShown()) { 0126 config.writeEntry("SortColumn", header->sortIndicatorSection()); 0127 } else { 0128 config.writeEntry("SortColumn", -1); 0129 } 0130 } 0131 0132 bool TreeView::restoreColumnLayout(const QString &stateGroupName) 0133 { 0134 if (stateGroupName.isEmpty()) { 0135 return false; 0136 } 0137 d->mStateGroupName = stateGroupName; 0138 auto config = KConfigGroup(KSharedConfig::openStateConfig(), d->mStateGroupName); 0139 auto header = this->header(); 0140 0141 QVariantList columnVisibility = config.readEntry("ColumnVisibility", QVariantList()); 0142 QVariantList columnOrder = config.readEntry("ColumnOrder", QVariantList()); 0143 QVariantList columnWidths = config.readEntry("ColumnWidths", QVariantList()); 0144 0145 if (!columnVisibility.isEmpty() && !columnOrder.isEmpty() && !columnWidths.isEmpty()) { 0146 for (int i = 0; i < header->count(); ++i) { 0147 if (i >= columnOrder.size() || i >= columnWidths.size() || i >= columnVisibility.size()) { 0148 // An additional column that was not around last time we saved. 0149 // We default to hidden. 0150 hideColumn(i); 0151 continue; 0152 } 0153 bool visible = columnVisibility[i].toBool(); 0154 int width = columnWidths[i].toInt(); 0155 int order = columnOrder[i].toInt(); 0156 0157 header->resizeSection(i, width ? width : 100); 0158 header->moveSection(header->visualIndex(i), order); 0159 0160 if (!visible) { 0161 hideColumn(i); 0162 } 0163 } 0164 } 0165 0166 int sortOrder = config.readEntry("SortAscending", (int)Qt::AscendingOrder); 0167 int sortColumn = config.readEntry("SortColumn", 0); 0168 if (sortColumn >= 0) { 0169 sortByColumn(sortColumn, (Qt::SortOrder)sortOrder); 0170 } 0171 return !columnVisibility.isEmpty() && !columnOrder.isEmpty() && !columnWidths.isEmpty(); 0172 } 0173 0174 QModelIndex TreeView::moveCursor(QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers) 0175 { 0176 // make column by column keyboard navigation with Left/Right possible by switching 0177 // the selection behavior to SelectItems before calling the parent class's moveCursor, 0178 // because it ignores MoveLeft/MoveRight if the selection behavior is SelectRows; 0179 // moreover, temporarily disable exanding of items to prevent expanding/collapsing 0180 // on MoveLeft/MoveRight 0181 if ((cursorAction != MoveLeft) && (cursorAction != MoveRight)) { 0182 return QTreeView::moveCursor(cursorAction, modifiers); 0183 } 0184 0185 const auto savedSelectionBehavior = selectionBehavior(); 0186 setSelectionBehavior(SelectItems); 0187 const auto savedItemsExpandable = itemsExpandable(); 0188 setItemsExpandable(false); 0189 0190 const auto result = QTreeView::moveCursor(cursorAction, modifiers); 0191 0192 setItemsExpandable(savedItemsExpandable); 0193 setSelectionBehavior(savedSelectionBehavior); 0194 0195 return result; 0196 } 0197 0198 #include "moc_treeview.cpp"