Page MenuHome GnuPG

No OneTemporary

diff --git a/src/dialogs/certificateselectiondialog.cpp b/src/dialogs/certificateselectiondialog.cpp
index 84b528266..f85f9a8e3 100644
--- a/src/dialogs/certificateselectiondialog.cpp
+++ b/src/dialogs/certificateselectiondialog.cpp
@@ -1,523 +1,521 @@
/* -*- mode: c++; c-basic-offset:4 -*-
dialogs/certificateselectiondialog.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <config-kleopatra.h>
#include "certificateselectiondialog.h"
#include <kleopatraapplication.h>
#include <settings.h>
#include <view/keytreeview.h>
#include <view/searchbar.h>
#include <view/tabwidget.h>
#include "utils/tags.h"
#include <Libkleo/Algorithm>
#include <Libkleo/Compat>
#include <Libkleo/KeyCache>
#include <Libkleo/KeyGroup>
#include <Libkleo/KeyListModel>
#include <Libkleo/UserIDProxyModel>
#include <commands/importcertificatefromfilecommand.h>
#include <commands/lookupcertificatescommand.h>
#include <commands/newopenpgpcertificatecommand.h>
#include <commands/reloadkeyscommand.h>
#include <gpgme++/key.h>
#include <KConfigDialog>
#include <KConfigGroup>
#include <KLocalizedString>
#include <KSharedConfig>
#include <QAbstractItemView>
#include <QDialogButtonBox>
#include <QItemSelectionModel>
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>
#include <algorithm>
using namespace Kleo;
using namespace Kleo::Dialogs;
using namespace Kleo::Commands;
using namespace GpgME;
CertificateSelectionDialog::Option CertificateSelectionDialog::optionsFromProtocol(Protocol proto)
{
switch (proto) {
case OpenPGP:
return CertificateSelectionDialog::OpenPGPFormat;
case CMS:
return CertificateSelectionDialog::CMSFormat;
default:
return CertificateSelectionDialog::AnyFormat;
}
}
namespace
{
auto protocolFromOptions(CertificateSelectionDialog::Options options)
{
switch (options & CertificateSelectionDialog::AnyFormat) {
case CertificateSelectionDialog::OpenPGPFormat:
return GpgME::OpenPGP;
case CertificateSelectionDialog::CMSFormat:
return GpgME::CMS;
default:
return GpgME::UnknownProtocol;
}
}
}
class CertificateSelectionDialog::Private
{
friend class ::Kleo::Dialogs::CertificateSelectionDialog;
CertificateSelectionDialog *const q;
public:
explicit Private(CertificateSelectionDialog *qq);
private:
void reload()
{
Command *const cmd = new ReloadKeysCommand(nullptr);
cmd->setParentWidget(q);
cmd->start();
}
void create()
{
auto cmd = new NewOpenPGPCertificateCommand;
cmd->setParentWidget(q);
cmd->start();
}
void lookup()
{
const auto cmd = new LookupCertificatesCommand(nullptr);
cmd->setParentWidget(q);
cmd->setProtocol(protocolFromOptions(options));
cmd->start();
}
void manageGroups()
{
// ensure that the dialog is shown on top of the modal CertificateSelectionDialog
KleopatraApplication::instance()->openOrRaiseGroupsConfigDialog(q);
}
void slotKeysMayHaveChanged();
void slotCurrentViewChanged(QAbstractItemView *newView);
void slotSelectionChanged();
void slotDoubleClicked(const QModelIndex &idx);
private:
bool acceptable(const std::vector<Key> &keys, const std::vector<KeyGroup> &groups)
{
return !keys.empty() || !groups.empty();
}
void updateLabelText()
{
ui.label.setText(!customLabelText.isEmpty() ? customLabelText
: (options & MultiSelection) ? i18n("Please select one or more of the following certificates:")
: i18n("Please select one of the following certificates:"));
}
private:
std::vector<QAbstractItemView *> connectedViews;
QString customLabelText;
Options options = AnyCertificate | AnyFormat;
struct UI {
QLabel label;
SearchBar searchBar;
TabWidget tabWidget;
QDialogButtonBox buttonBox;
QPushButton *createButton = nullptr;
} ui;
void setUpUI(CertificateSelectionDialog *q)
{
KDAB_SET_OBJECT_NAME(ui.label);
KDAB_SET_OBJECT_NAME(ui.searchBar);
KDAB_SET_OBJECT_NAME(ui.tabWidget);
KDAB_SET_OBJECT_NAME(ui.buttonBox);
auto vlay = new QVBoxLayout(q);
vlay->addWidget(&ui.label);
vlay->addWidget(&ui.searchBar);
vlay->addWidget(&ui.tabWidget, 1);
vlay->addWidget(&ui.buttonBox);
QPushButton *const okButton = ui.buttonBox.addButton(QDialogButtonBox::Ok);
okButton->setEnabled(false);
ui.buttonBox.addButton(QDialogButtonBox::Close);
QPushButton *const reloadButton = ui.buttonBox.addButton(i18n("Reload"), QDialogButtonBox::ActionRole);
reloadButton->setToolTip(i18nc("@info:tooltip", "Refresh certificate list"));
QPushButton *const importButton = ui.buttonBox.addButton(i18n("Import..."), QDialogButtonBox::ActionRole);
importButton->setToolTip(i18nc("@info:tooltip", "Import certificate from file"));
importButton->setAccessibleName(i18n("Import certificate"));
QPushButton *const lookupButton = ui.buttonBox.addButton(i18n("Lookup..."), QDialogButtonBox::ActionRole);
lookupButton->setToolTip(i18nc("@info:tooltip", "Look up certificate on server"));
lookupButton->setAccessibleName(i18n("Look up certificate"));
ui.createButton = ui.buttonBox.addButton(i18n("New..."), QDialogButtonBox::ActionRole);
ui.createButton->setToolTip(i18nc("@info:tooltip", "Create a new OpenPGP certificate"));
ui.createButton->setAccessibleName(i18n("Create certificate"));
QPushButton *const groupsButton = ui.buttonBox.addButton(i18n("Groups..."), QDialogButtonBox::ActionRole);
groupsButton->setToolTip(i18nc("@info:tooltip", "Manage certificate groups"));
groupsButton->setAccessibleName(i18n("Manage groups"));
groupsButton->setVisible(Settings().groupsEnabled());
connect(&ui.buttonBox, &QDialogButtonBox::accepted, q, &CertificateSelectionDialog::accept);
connect(&ui.buttonBox, &QDialogButtonBox::rejected, q, &CertificateSelectionDialog::reject);
connect(reloadButton, &QPushButton::clicked, q, [this]() {
reload();
});
connect(lookupButton, &QPushButton::clicked, q, [this]() {
lookup();
});
connect(ui.createButton, &QPushButton::clicked, q, [this]() {
create();
});
connect(groupsButton, &QPushButton::clicked, q, [this]() {
manageGroups();
});
connect(KeyCache::instance().get(), &KeyCache::keysMayHaveChanged, q, [this]() {
slotKeysMayHaveChanged();
});
connect(importButton, &QPushButton::clicked, q, [importButton, q]() {
importButton->setEnabled(false);
auto cmd = new Kleo::ImportCertificateFromFileCommand();
connect(cmd, &Kleo::ImportCertificateFromFileCommand::finished, q, [importButton]() {
importButton->setEnabled(true);
});
cmd->setParentWidget(q);
cmd->start();
});
}
};
CertificateSelectionDialog::Private::Private(CertificateSelectionDialog *qq)
: q(qq)
{
setUpUI(q);
ui.tabWidget.setFlatModel(AbstractKeyListModel::createFlatKeyListModel(q));
ui.tabWidget.setHierarchicalModel(AbstractKeyListModel::createHierarchicalKeyListModel(q));
const auto tagKeys = Tags::tagKeys();
ui.tabWidget.flatModel()->setRemarkKeys(tagKeys);
ui.tabWidget.hierarchicalModel()->setRemarkKeys(tagKeys);
ui.tabWidget.connectSearchBar(&ui.searchBar);
connect(&ui.tabWidget, &TabWidget::currentViewChanged, q, [this](QAbstractItemView *view) {
slotCurrentViewChanged(view);
});
updateLabelText();
q->setWindowTitle(i18nc("@title:window", "Certificate Selection"));
}
CertificateSelectionDialog::CertificateSelectionDialog(QWidget *parent)
: QDialog(parent)
, d(new Private(this))
{
- const KSharedConfig::Ptr config = KSharedConfig::openStateConfig(QStringLiteral("kleopatracertificateselectiondialogrc"));
d->ui.tabWidget.loadViews(KSharedConfig::openStateConfig(), QStringLiteral("CertificateSelectionDialog"), TabWidget::ShowUserIDs);
- const KConfigGroup geometry(config, QStringLiteral("Geometry"));
+ const auto geometry = KSharedConfig::openStateConfig()->group(QStringLiteral("CertificateSelectionDialog")).group(QStringLiteral("Geometry"));
resize(geometry.readEntry("size", size()));
d->slotKeysMayHaveChanged();
}
CertificateSelectionDialog::~CertificateSelectionDialog()
{
}
void CertificateSelectionDialog::setCustomLabelText(const QString &txt)
{
if (txt == d->customLabelText) {
return;
}
d->customLabelText = txt;
d->updateLabelText();
}
QString CertificateSelectionDialog::customLabelText() const
{
return d->customLabelText;
}
void CertificateSelectionDialog::setOptions(Options options)
{
Q_ASSERT((options & CertificateSelectionDialog::AnyCertificate) != 0);
Q_ASSERT((options & CertificateSelectionDialog::AnyFormat) != 0);
if (d->options == options) {
return;
}
d->options = options;
d->ui.tabWidget.setMultiSelection(options & MultiSelection);
d->slotKeysMayHaveChanged();
d->updateLabelText();
d->ui.createButton->setVisible(options & OpenPGPFormat);
}
CertificateSelectionDialog::Options CertificateSelectionDialog::options() const
{
return d->options;
}
void CertificateSelectionDialog::setStringFilter(const QString &filter)
{
d->ui.tabWidget.setStringFilter(filter);
}
void CertificateSelectionDialog::setKeyFilter(const std::shared_ptr<KeyFilter> &filter)
{
d->ui.tabWidget.setKeyFilter(filter);
}
namespace
{
void selectRows(const QAbstractItemView *view, const QModelIndexList &indexes)
{
if (!view) {
return;
}
QItemSelectionModel *const sm = view->selectionModel();
Q_ASSERT(sm);
for (const QModelIndex &idx : std::as_const(indexes)) {
if (idx.isValid()) {
sm->select(idx, QItemSelectionModel::Select | QItemSelectionModel::Rows);
}
}
}
QModelIndexList getGroupIndexes(const KeyListModelInterface *model, const std::vector<KeyGroup> &groups)
{
QModelIndexList indexes;
indexes.reserve(groups.size());
std::transform(groups.begin(), groups.end(), std::back_inserter(indexes), [model](const KeyGroup &group) {
return model->index(group);
});
indexes.erase(std::remove_if(indexes.begin(),
indexes.end(),
[](const QModelIndex &index) {
return !index.isValid();
}),
indexes.end());
return indexes;
}
}
void CertificateSelectionDialog::selectCertificates(const std::vector<Key> &keys)
{
const auto *const model = d->ui.tabWidget.currentModel();
Q_ASSERT(model);
selectRows(d->ui.tabWidget.currentView(), model->indexes(keys));
}
void CertificateSelectionDialog::selectCertificate(const Key &key)
{
selectCertificates(std::vector<Key>(1, key));
}
void CertificateSelectionDialog::selectGroups(const std::vector<KeyGroup> &groups)
{
const auto *const model = d->ui.tabWidget.currentModel();
Q_ASSERT(model);
selectRows(d->ui.tabWidget.currentView(), getGroupIndexes(model, groups));
}
namespace
{
QModelIndexList getSelectedRows(const QAbstractItemView *view)
{
if (!view) {
return {};
}
const QItemSelectionModel *const sm = view->selectionModel();
Q_ASSERT(sm);
return sm->selectedRows();
}
std::vector<KeyGroup> getGroups(const KeyListModelInterface *model, const QModelIndexList &indexes)
{
std::vector<KeyGroup> groups;
groups.reserve(indexes.size());
std::transform(indexes.begin(), indexes.end(), std::back_inserter(groups), [model](const QModelIndex &idx) {
return model->group(idx);
});
groups.erase(std::remove_if(groups.begin(), groups.end(), std::mem_fn(&Kleo::KeyGroup::isNull)), groups.end());
return groups;
}
}
std::vector<Key> CertificateSelectionDialog::selectedCertificates() const
{
const KeyListModelInterface *const model = d->ui.tabWidget.currentModel();
Q_ASSERT(model);
return model->keys(getSelectedRows(d->ui.tabWidget.currentView()));
}
std::vector<UserID> CertificateSelectionDialog::selectedUserIDs() const
{
const auto model = d->ui.tabWidget.currentView()->model();
Q_ASSERT(model);
std::vector<UserID> userIds;
for (const auto &index : getSelectedRows(d->ui.tabWidget.currentView())) {
const auto userID = model->data(index, KeyList::UserIDRole).value<UserID>();
if (!userID.isNull()) {
userIds.push_back(userID);
}
}
return userIds;
}
Key CertificateSelectionDialog::selectedCertificate() const
{
const std::vector<Key> keys = selectedCertificates();
return keys.empty() ? Key() : keys.front();
}
std::vector<KeyGroup> CertificateSelectionDialog::selectedGroups() const
{
const KeyListModelInterface *const model = d->ui.tabWidget.currentModel();
Q_ASSERT(model);
return getGroups(model, getSelectedRows(d->ui.tabWidget.currentView()));
}
void CertificateSelectionDialog::hideEvent(QHideEvent *e)
{
- KSharedConfig::Ptr config = KSharedConfig::openConfig(QStringLiteral("kleopatracertificateselectiondialogrc"));
d->ui.tabWidget.saveViews();
- KConfigGroup geometry(config, QStringLiteral("Geometry"));
+ auto geometry = KSharedConfig::openStateConfig()->group(QStringLiteral("CertificateSelectionDialog")).group(QStringLiteral("Geometry"));
geometry.writeEntry("size", size());
QDialog::hideEvent(e);
}
void CertificateSelectionDialog::Private::slotKeysMayHaveChanged()
{
q->setEnabled(true);
std::vector<Key> keys = (options & SecretKeys) ? KeyCache::instance()->secretKeys() : KeyCache::instance()->keys();
q->filterAllowedKeys(keys, options);
const std::vector<KeyGroup> groups = (options & IncludeGroups) ? KeyCache::instance()->groups() : std::vector<KeyGroup>();
const std::vector<Key> selectedKeys = q->selectedCertificates();
const std::vector<KeyGroup> selectedGroups = q->selectedGroups();
if (AbstractKeyListModel *const model = ui.tabWidget.flatModel()) {
model->setKeys(keys);
model->setGroups(groups);
}
if (AbstractKeyListModel *const model = ui.tabWidget.hierarchicalModel()) {
model->setKeys(keys);
model->setGroups(groups);
}
q->selectCertificates(selectedKeys);
q->selectGroups(selectedGroups);
}
void CertificateSelectionDialog::filterAllowedKeys(std::vector<Key> &keys, int options)
{
auto end = keys.end();
switch (options & AnyFormat) {
case OpenPGPFormat:
end = std::remove_if(keys.begin(), end, [](const Key &key) {
return key.protocol() != OpenPGP;
});
break;
case CMSFormat:
end = std::remove_if(keys.begin(), end, [](const Key &key) {
return key.protocol() != CMS;
});
break;
default:
case AnyFormat:;
}
switch (options & AnyCertificate) {
case SignOnly:
end = std::remove_if(keys.begin(), end, [](const Key &key) {
return !Kleo::keyHasSign(key);
});
break;
case EncryptOnly:
end = std::remove_if(keys.begin(), end, [](const Key &key) {
return !Kleo::keyHasEncrypt(key);
});
break;
default:
case AnyCertificate:;
}
if (options & SecretKeys) {
end = std::remove_if(keys.begin(), end, [](const Key &key) {
return !key.hasSecret();
});
}
keys.erase(end, keys.end());
}
void CertificateSelectionDialog::Private::slotCurrentViewChanged(QAbstractItemView *newView)
{
if (!Kleo::contains(connectedViews, newView)) {
connectedViews.push_back(newView);
connect(newView, &QAbstractItemView::doubleClicked, q, [this](const QModelIndex &index) {
slotDoubleClicked(index);
});
Q_ASSERT(newView->selectionModel());
connect(newView->selectionModel(), &QItemSelectionModel::selectionChanged, q, [this](const QItemSelection &, const QItemSelection &) {
slotSelectionChanged();
});
}
slotSelectionChanged();
}
void CertificateSelectionDialog::Private::slotSelectionChanged()
{
if (QPushButton *const pb = ui.buttonBox.button(QDialogButtonBox::Ok)) {
pb->setEnabled(acceptable(q->selectedCertificates(), q->selectedGroups()));
}
}
void CertificateSelectionDialog::Private::slotDoubleClicked(const QModelIndex &idx)
{
QAbstractItemView *const view = ui.tabWidget.currentView();
Q_ASSERT(view);
const auto *const model = ui.tabWidget.currentModel();
Q_ASSERT(model);
Q_UNUSED(model)
QItemSelectionModel *const sm = view->selectionModel();
Q_ASSERT(sm);
sm->select(idx, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
QMetaObject::invokeMethod(
q,
[this]() {
q->accept();
},
Qt::QueuedConnection);
}
void CertificateSelectionDialog::accept()
{
if (d->acceptable(selectedCertificates(), selectedGroups())) {
QDialog::accept();
}
}
#include "moc_certificateselectiondialog.cpp"
diff --git a/src/utils/migration.cpp b/src/utils/migration.cpp
index 497f953ee..a312f65b8 100644
--- a/src/utils/migration.cpp
+++ b/src/utils/migration.cpp
@@ -1,47 +1,50 @@
// SPDX-FileCopyrightText: 2024 g10 Code GmbH
// SPDX-FileContributor: Tobias Fella <tobias.fella@gnupg.com>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "utils/migration.h"
#include <KConfigGroup>
#include <KSharedConfig>
#include <QRegularExpression>
#include <QUuid>
static const QStringList groupStateIgnoredKeys = {
QStringLiteral("magic"),
};
static void migrateGroupState(const QString &configName, const QString &name)
{
const auto config = KSharedConfig::openConfig(configName);
auto groups = config->groupList().filter(QRegularExpression(QStringLiteral("^View #\\d+$")));
groups.sort();
QStringList uuids;
const auto newConfig = KSharedConfig::openStateConfig();
for (const auto &g : groups) {
auto group = KConfigGroup(config, g);
- auto newGroup = KConfigGroup(newConfig, QUuid::createUuid().toString());
+ auto newGroup = KConfigGroup(newConfig, QStringLiteral("%1:View %2").arg(name, QUuid::createUuid().toString()));
for (const auto &key : group.keyList()) {
if (key == QStringLiteral("column-sizes")) {
newGroup.writeEntry("ColumnWidths", group.readEntry(key));
} else if (!groupStateIgnoredKeys.contains(key)) {
newGroup.writeEntry(key, group.readEntry(key));
}
}
- group.deleteGroup();
- group.sync();
+ newGroup.sync();
uuids += newGroup.name();
}
if (!uuids.isEmpty()) {
- KSharedConfig::openStateConfig()->group(name).writeEntry("Tabs", uuids);
+ newConfig->group(name).writeEntry("Tabs", uuids);
}
}
void Migration::migrate()
{
- migrateGroupState({}, QStringLiteral("KeyList"));
- migrateGroupState(QStringLiteral("kleopatracertificateselectiondialogrc"), QStringLiteral("CertificateSelectionDialog"));
+ auto migrations = KSharedConfig::openStateConfig()->group(QStringLiteral("Migrations"));
+ if (!migrations.readEntry("01-key-list-layout", false)) {
+ migrateGroupState({}, QStringLiteral("KeyList"));
+ migrateGroupState(QStringLiteral("kleopatracertificateselectiondialogrc"), QStringLiteral("CertificateSelectionDialog"));
+ migrations.writeEntry("01-key-list-layout", true);
+ }
}
diff --git a/src/view/tabwidget.cpp b/src/view/tabwidget.cpp
index 594f528e8..c7d8ad198 100644
--- a/src/view/tabwidget.cpp
+++ b/src/view/tabwidget.cpp
@@ -1,1139 +1,1139 @@
/* -*- mode: c++; c-basic-offset:4 -*-
view/tabwidget.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <config-kleopatra.h>
#include "tabwidget.h"
#include "keytreeview.h"
#include "kleopatra_debug.h"
#include "searchbar.h"
#include <settings.h>
#include <utils/action_data.h>
#include <Libkleo/KeyFilter>
#include <Libkleo/KeyFilterManager>
#include <Libkleo/KeyListModel>
#include <Libkleo/KeyListSortFilterProxyModel>
#include <Libkleo/Stl_Util>
#include <Libkleo/UserIDProxyModel>
#include <gpgme++/key.h>
// needed for GPGME_VERSION_NUMBER
#include <gpgme.h>
#include <KActionCollection>
#include <KConfig>
#include <KConfigGroup>
#include <KLocalizedString>
#include <KSharedConfig>
#include <QAction>
#include <QInputDialog>
#include <QTabWidget>
#include <QAbstractProxyModel>
#include <QHeaderView>
#include <QMenu>
#include <QRegularExpression>
#include <QTimer>
#include <QToolButton>
#include <QTreeView>
#include <QVBoxLayout>
#include <map>
using namespace Kleo;
using namespace GpgME;
namespace
{
class Page : public Kleo::KeyTreeView
{
Q_OBJECT
Page(const Page &other);
public:
Page(const QString &title,
const QString &id,
const QString &text,
AbstractKeyListSortFilterProxyModel *proxy = nullptr,
const QString &toolTip = QString(),
QWidget *parent = nullptr,
const KConfigGroup &group = KConfigGroup());
Page(const KConfigGroup &group, QWidget *parent = nullptr);
~Page() override;
void setTemporary(bool temporary);
bool isTemporary() const
{
return m_isTemporary;
}
void setHierarchicalView(bool hierarchical) override;
void setStringFilter(const QString &filter) override;
void setKeyFilter(const std::shared_ptr<KeyFilter> &filter) override;
QString title() const
{
return m_title.isEmpty() && keyFilter() ? keyFilter()->name() : m_title;
}
void setTitle(const QString &title);
QString toolTip() const
{
return m_toolTip.isEmpty() ? title() : m_toolTip;
}
// not used void setToolTip(const QString &tip);
bool canBeClosed() const
{
return m_canBeClosed;
}
bool canBeRenamed() const
{
return m_canBeRenamed;
}
bool canChangeStringFilter() const
{
return m_canChangeStringFilter;
}
bool canChangeKeyFilter() const
{
return m_canChangeKeyFilter && !m_isTemporary;
}
bool canChangeHierarchical() const
{
return m_canChangeHierarchical;
}
void saveState();
Page *clone() const override
{
return new Page(*this);
}
void liftAllRestrictions()
{
m_canBeClosed = m_canBeRenamed = m_canChangeStringFilter = m_canChangeKeyFilter = m_canChangeHierarchical = true;
}
void closePage()
{
m_configGroup.deleteGroup();
m_configGroup.sync();
}
KConfigGroup configGroup() const
{
return m_configGroup;
}
Q_SIGNALS:
void titleChanged(const QString &title);
private:
void init();
private:
QString m_title;
QString m_toolTip;
bool m_isTemporary : 1;
bool m_canBeClosed : 1;
bool m_canBeRenamed : 1;
bool m_canChangeStringFilter : 1;
bool m_canChangeKeyFilter : 1;
bool m_canChangeHierarchical : 1;
KConfigGroup m_configGroup;
};
} // anon namespace
Page::Page(const Page &other)
: KeyTreeView(other)
, m_title(other.m_title)
, m_toolTip(other.m_toolTip)
, m_isTemporary(other.m_isTemporary)
, m_canBeClosed(other.m_canBeClosed)
, m_canBeRenamed(other.m_canBeRenamed)
, m_canChangeStringFilter(other.m_canChangeStringFilter)
, m_canChangeKeyFilter(other.m_canChangeKeyFilter)
, m_canChangeHierarchical(other.m_canChangeHierarchical)
, m_configGroup(other.configGroup().config()->group(QUuid::createUuid().toString()))
{
init();
}
Page::Page(const QString &title,
const QString &id,
const QString &text,
AbstractKeyListSortFilterProxyModel *proxy,
const QString &toolTip,
QWidget *parent,
const KConfigGroup &group)
: KeyTreeView(text, KeyFilterManager::instance()->keyFilterByID(id), proxy, parent, group)
, m_title(title)
, m_toolTip(toolTip)
, m_isTemporary(false)
, m_canBeClosed(true)
, m_canBeRenamed(true)
, m_canChangeStringFilter(true)
, m_canChangeKeyFilter(true)
, m_canChangeHierarchical(true)
, m_configGroup(group)
{
init();
}
static const char TITLE_ENTRY[] = "title";
static const char STRING_FILTER_ENTRY[] = "string-filter";
static const char KEY_FILTER_ENTRY[] = "key-filter";
static const char HIERARCHICAL_VIEW_ENTRY[] = "hierarchical-view";
static const char COLUMN_SIZES[] = "column-sizes";
static const char SORT_COLUMN[] = "sort-column";
static const char SORT_DESCENDING[] = "sort-descending";
Page::Page(const KConfigGroup &group, QWidget *parent)
: KeyTreeView(group.readEntry(STRING_FILTER_ENTRY), KeyFilterManager::instance()->keyFilterByID(group.readEntry(KEY_FILTER_ENTRY)), nullptr, parent, group)
, m_title(group.readEntry(TITLE_ENTRY))
, m_toolTip()
, m_isTemporary(false)
, m_canBeClosed(!group.isImmutable())
, m_canBeRenamed(!group.isEntryImmutable(TITLE_ENTRY))
, m_canChangeStringFilter(!group.isEntryImmutable(STRING_FILTER_ENTRY))
, m_canChangeKeyFilter(!group.isEntryImmutable(KEY_FILTER_ENTRY))
, m_canChangeHierarchical(!group.isEntryImmutable(HIERARCHICAL_VIEW_ENTRY))
, m_configGroup(group)
{
init();
setHierarchicalView(group.readEntry(HIERARCHICAL_VIEW_ENTRY, true));
const QList<int> settings = group.readEntry(COLUMN_SIZES, QList<int>());
std::vector<int> sizes;
sizes.reserve(settings.size());
std::copy(settings.cbegin(), settings.cend(), std::back_inserter(sizes));
setColumnSizes(sizes);
setSortColumn(group.readEntry(SORT_COLUMN, 0), group.readEntry(SORT_DESCENDING, true) ? Qt::DescendingOrder : Qt::AscendingOrder);
}
void Page::init()
{
#if GPGME_VERSION_NUMBER >= 0x011800 // 1.24.0
view()->setDragDropMode(QAbstractItemView::DragOnly);
view()->setDragEnabled(true);
#endif
}
Page::~Page()
{
}
void Page::saveState()
{
m_configGroup.writeEntry(TITLE_ENTRY, m_title);
m_configGroup.writeEntry(STRING_FILTER_ENTRY, stringFilter());
m_configGroup.writeEntry(KEY_FILTER_ENTRY, keyFilter() ? keyFilter()->id() : QString());
m_configGroup.writeEntry(HIERARCHICAL_VIEW_ENTRY, isHierarchicalView());
}
void Page::setStringFilter(const QString &filter)
{
if (!m_canChangeStringFilter) {
return;
}
KeyTreeView::setStringFilter(filter);
}
void Page::setKeyFilter(const std::shared_ptr<KeyFilter> &filter)
{
if (!canChangeKeyFilter()) {
return;
}
const QString oldTitle = title();
KeyTreeView::setKeyFilter(filter);
const QString newTitle = title();
if (oldTitle != newTitle) {
Q_EMIT titleChanged(newTitle);
}
}
void Page::setTitle(const QString &t)
{
if (t == m_title) {
return;
}
if (!m_canBeRenamed) {
return;
}
const QString oldTitle = title();
m_title = t;
const QString newTitle = title();
if (oldTitle != newTitle) {
Q_EMIT titleChanged(newTitle);
}
}
#if 0 // not used
void Page::setToolTip(const QString &tip)
{
if (tip == m_toolTip) {
return;
}
if (!m_canBeRenamed) {
return;
}
const QString oldTip = toolTip();
m_toolTip = tip;
const QString newTip = toolTip();
if (oldTip != newTip) {
Q_EMIT titleChanged(title());
}
}
#endif
void Page::setHierarchicalView(bool on)
{
if (!m_canChangeHierarchical) {
return;
}
KeyTreeView::setHierarchicalView(on);
}
void Page::setTemporary(bool on)
{
if (on == m_isTemporary) {
return;
}
m_isTemporary = on;
if (on) {
setKeyFilter(std::shared_ptr<KeyFilter>());
}
}
namespace
{
class Actions
{
public:
constexpr static const char *Rename = "window_rename_tab";
constexpr static const char *Duplicate = "window_duplicate_tab";
constexpr static const char *Close = "window_close_tab";
constexpr static const char *MoveLeft = "window_move_tab_left";
constexpr static const char *MoveRight = "window_move_tab_right";
constexpr static const char *Hierarchical = "window_view_hierarchical";
constexpr static const char *ExpandAll = "window_expand_all";
constexpr static const char *CollapseAll = "window_collapse_all";
explicit Actions()
{
}
void insert(const std::string &name, QAction *action)
{
actions.insert({name, action});
}
auto get(const std::string &name) const
{
const auto it = actions.find(name);
return (it != actions.end()) ? it->second : nullptr;
}
void setChecked(const std::string &name, bool checked) const
{
if (auto action = get(name)) {
action->setChecked(checked);
}
}
void setEnabled(const std::string &name, bool enabled) const
{
if (auto action = get(name)) {
action->setEnabled(enabled);
}
}
void setVisible(const std::string &name, bool visible) const
{
if (auto action = get(name)) {
action->setVisible(visible);
}
}
private:
std::map<std::string, QAction *> actions;
};
}
//
//
// TabWidget
//
//
class TabWidget::Private
{
friend class ::Kleo::TabWidget;
TabWidget *const q;
public:
explicit Private(TabWidget *qq);
~Private()
{
}
private:
void slotContextMenu(const QPoint &p);
void currentIndexChanged(int index);
void slotPageTitleChanged(const QString &title);
void slotPageKeyFilterChanged(const std::shared_ptr<KeyFilter> &filter);
void slotPageStringFilterChanged(const QString &filter);
void slotPageHierarchyChanged(bool on);
#ifndef QT_NO_INPUTDIALOG
void slotRenameCurrentTab()
{
renamePage(currentPage());
}
#endif // QT_NO_INPUTDIALOG
void slotNewTab();
void slotDuplicateCurrentTab()
{
duplicatePage(currentPage());
}
void slotCloseCurrentTab()
{
closePage(currentPage());
}
void slotMoveCurrentTabLeft()
{
movePageLeft(currentPage());
}
void slotMoveCurrentTabRight()
{
movePageRight(currentPage());
}
void slotToggleHierarchicalView(bool on)
{
toggleHierarchicalView(currentPage(), on);
}
void slotExpandAll()
{
expandAll(currentPage());
}
void slotCollapseAll()
{
collapseAll(currentPage());
}
#ifndef QT_NO_INPUTDIALOG
void renamePage(Page *page);
#endif
void duplicatePage(Page *page);
void closePage(Page *page);
void movePageLeft(Page *page);
void movePageRight(Page *page);
void toggleHierarchicalView(Page *page, bool on);
void expandAll(Page *page);
void collapseAll(Page *page);
void enableDisableCurrentPageActions();
void enableDisablePageActions(const Actions &actions, const Page *page);
Page *currentPage() const
{
Q_ASSERT(!tabWidget->currentWidget() || qobject_cast<Page *>(tabWidget->currentWidget()));
return static_cast<Page *>(tabWidget->currentWidget());
}
Page *page(unsigned int idx) const
{
Q_ASSERT(!tabWidget->widget(idx) || qobject_cast<Page *>(tabWidget->widget(idx)));
return static_cast<Page *>(tabWidget->widget(idx));
}
Page *senderPage() const
{
QObject *const sender = q->sender();
Q_ASSERT(!sender || qobject_cast<Page *>(sender));
return static_cast<Page *>(sender);
}
bool isSenderCurrentPage() const
{
Page *const sp = senderPage();
return sp && sp == currentPage();
}
QTreeView *addView(Page *page, Page *columnReference);
private:
AbstractKeyListModel *flatModel = nullptr;
AbstractKeyListModel *hierarchicalModel = nullptr;
QToolButton *newTabButton = nullptr;
QToolButton *closeTabButton = nullptr;
QTabWidget *tabWidget = nullptr;
QAction *newAction = nullptr;
Actions currentPageActions;
Actions otherPageActions;
bool actionsCreated = false;
KSharedConfig::Ptr config;
QString configKey;
};
TabWidget::Private::Private(TabWidget *qq)
: q{qq}
{
auto layout = new QVBoxLayout{q};
layout->setContentsMargins(0, 0, 0, 0);
// create "New Tab" button before tab widget to ensure correct tab order
newTabButton = new QToolButton{q};
tabWidget = new QTabWidget{q};
KDAB_SET_OBJECT_NAME(tabWidget);
layout->addWidget(tabWidget);
tabWidget->setMovable(true);
tabWidget->tabBar()->setContextMenuPolicy(Qt::CustomContextMenu);
// create "Close Tab" button after tab widget to ensure correct tab order
closeTabButton = new QToolButton{q};
connect(tabWidget, &QTabWidget::currentChanged, q, [this](int index) {
currentIndexChanged(index);
});
connect(tabWidget->tabBar(), &QWidget::customContextMenuRequested, q, [this](const QPoint &p) {
slotContextMenu(p);
});
}
void TabWidget::Private::slotContextMenu(const QPoint &p)
{
const int tabUnderPos = tabWidget->tabBar()->tabAt(p);
Page *const contextMenuPage = static_cast<Page *>(tabWidget->widget(tabUnderPos));
const Page *const current = currentPage();
const auto actions = contextMenuPage == current ? currentPageActions : otherPageActions;
enableDisablePageActions(actions, contextMenuPage);
QMenu menu;
if (auto action = actions.get(Actions::Rename)) {
menu.addAction(action);
}
menu.addSeparator();
menu.addAction(newAction);
if (auto action = actions.get(Actions::Duplicate)) {
menu.addAction(action);
}
menu.addSeparator();
if (auto action = actions.get(Actions::MoveLeft)) {
menu.addAction(action);
}
if (auto action = actions.get(Actions::MoveRight)) {
menu.addAction(action);
}
menu.addSeparator();
if (auto action = actions.get(Actions::Close)) {
menu.addAction(action);
}
const QAction *const action = menu.exec(tabWidget->tabBar()->mapToGlobal(p));
if (!action) {
return;
}
if (contextMenuPage == current || action == newAction) {
return; // performed through signal/slot connections...
}
#ifndef QT_NO_INPUTDIALOG
if (action == otherPageActions.get(Actions::Rename)) {
renamePage(contextMenuPage);
}
#endif // QT_NO_INPUTDIALOG
else if (action == otherPageActions.get(Actions::Duplicate)) {
duplicatePage(contextMenuPage);
} else if (action == otherPageActions.get(Actions::Close)) {
closePage(contextMenuPage);
} else if (action == otherPageActions.get(Actions::MoveLeft)) {
movePageLeft(contextMenuPage);
} else if (action == otherPageActions.get(Actions::MoveRight)) {
movePageRight(contextMenuPage);
}
}
void TabWidget::Private::currentIndexChanged(int index)
{
const Page *const page = this->page(index);
Q_EMIT q->currentViewChanged(page ? page->view() : nullptr);
Q_EMIT q->keyFilterChanged(page ? page->keyFilter() : std::shared_ptr<KeyFilter>());
Q_EMIT q->stringFilterChanged(page ? page->stringFilter() : QString());
enableDisableCurrentPageActions();
}
void TabWidget::Private::enableDisableCurrentPageActions()
{
const Page *const page = currentPage();
Q_EMIT q->enableChangeStringFilter(page && page->canChangeStringFilter());
Q_EMIT q->enableChangeKeyFilter(page && page->canChangeKeyFilter());
enableDisablePageActions(currentPageActions, page);
}
void TabWidget::Private::enableDisablePageActions(const Actions &actions, const Page *p)
{
actions.setEnabled(Actions::Rename, p && p->canBeRenamed());
actions.setEnabled(Actions::Duplicate, p);
actions.setEnabled(Actions::Close, p && p->canBeClosed() && tabWidget->count() > 1);
actions.setEnabled(Actions::MoveLeft, p && tabWidget->indexOf(const_cast<Page *>(p)) != 0);
actions.setEnabled(Actions::MoveRight, p && tabWidget->indexOf(const_cast<Page *>(p)) != tabWidget->count() - 1);
actions.setEnabled(Actions::Hierarchical, p && p->canChangeHierarchical());
actions.setChecked(Actions::Hierarchical, p && p->isHierarchicalView());
actions.setVisible(Actions::Hierarchical, Kleo::Settings{}.cmsEnabled());
actions.setEnabled(Actions::ExpandAll, p && p->isHierarchicalView());
actions.setEnabled(Actions::CollapseAll, p && p->isHierarchicalView());
}
void TabWidget::Private::slotPageTitleChanged(const QString &)
{
if (Page *const page = senderPage()) {
const int idx = tabWidget->indexOf(page);
tabWidget->setTabText(idx, page->title());
tabWidget->setTabToolTip(idx, page->toolTip());
}
}
void TabWidget::Private::slotPageKeyFilterChanged(const std::shared_ptr<KeyFilter> &kf)
{
if (isSenderCurrentPage()) {
Q_EMIT q->keyFilterChanged(kf);
}
}
void TabWidget::Private::slotPageStringFilterChanged(const QString &filter)
{
if (isSenderCurrentPage()) {
Q_EMIT q->stringFilterChanged(filter);
}
}
void TabWidget::Private::slotPageHierarchyChanged(bool)
{
enableDisableCurrentPageActions();
}
void TabWidget::Private::slotNewTab()
{
- const auto group = KSharedConfig::openStateConfig()->group(QStringLiteral("View %1").arg(QUuid::createUuid().toString()));
+ const auto group = KSharedConfig::openStateConfig()->group(QStringLiteral("%1:View %2").arg(configKey, QUuid::createUuid().toString()));
Page *page = new Page(QString(), QStringLiteral("all-certificates"), QString(), nullptr, QString(), nullptr, group);
addView(page, currentPage());
tabWidget->setCurrentIndex(tabWidget->count() - 1);
}
void TabWidget::Private::renamePage(Page *page)
{
if (!page) {
return;
}
bool ok;
const QString text = QInputDialog::getText(q, i18n("Rename Tab"), i18n("New tab title:"), QLineEdit::Normal, page->title(), &ok);
if (!ok) {
return;
}
page->setTitle(text);
}
void TabWidget::Private::duplicatePage(Page *page)
{
if (!page) {
return;
}
Page *const clone = page->clone();
Q_ASSERT(clone);
clone->liftAllRestrictions();
addView(clone, page);
}
void TabWidget::Private::closePage(Page *page)
{
if (!page || !page->canBeClosed() || tabWidget->count() <= 1) {
return;
}
Q_EMIT q->viewAboutToBeRemoved(page->view());
page->closePage();
tabWidget->removeTab(tabWidget->indexOf(page));
enableDisableCurrentPageActions();
}
void TabWidget::Private::movePageLeft(Page *page)
{
if (!page) {
return;
}
const int idx = tabWidget->indexOf(page);
if (idx <= 0) {
return;
}
tabWidget->tabBar()->moveTab(idx, idx - 1);
enableDisableCurrentPageActions();
}
void TabWidget::Private::movePageRight(Page *page)
{
if (!page) {
return;
}
const int idx = tabWidget->indexOf(page);
if (idx < 0 || idx >= tabWidget->count() - 1) {
return;
}
tabWidget->tabBar()->moveTab(idx, idx + 1);
enableDisableCurrentPageActions();
}
void TabWidget::Private::toggleHierarchicalView(Page *page, bool on)
{
if (!page) {
return;
}
page->setHierarchicalView(on);
}
void TabWidget::Private::expandAll(Page *page)
{
if (!page || !page->view()) {
return;
}
page->view()->expandAll();
}
void TabWidget::Private::collapseAll(Page *page)
{
if (!page || !page->view()) {
return;
}
page->view()->collapseAll();
}
TabWidget::TabWidget(QWidget *p, Qt::WindowFlags f)
: QWidget(p, f)
, d(new Private(this))
{
}
TabWidget::~TabWidget()
{
saveViews();
}
void TabWidget::setFlatModel(AbstractKeyListModel *model)
{
if (model == d->flatModel) {
return;
}
d->flatModel = model;
for (unsigned int i = 0, end = count(); i != end; ++i)
if (Page *const page = d->page(i)) {
page->setFlatModel(model);
}
}
AbstractKeyListModel *TabWidget::flatModel() const
{
return d->flatModel;
}
void TabWidget::setHierarchicalModel(AbstractKeyListModel *model)
{
if (model == d->hierarchicalModel) {
return;
}
d->hierarchicalModel = model;
for (unsigned int i = 0, end = count(); i != end; ++i)
if (Page *const page = d->page(i)) {
page->setHierarchicalModel(model);
}
}
AbstractKeyListModel *TabWidget::hierarchicalModel() const
{
return d->hierarchicalModel;
}
QString TabWidget::stringFilter() const
{
return d->currentPage() ? d->currentPage()->stringFilter() : QString{};
}
void TabWidget::setStringFilter(const QString &filter)
{
if (Page *const page = d->currentPage()) {
page->setStringFilter(filter);
}
}
void TabWidget::setKeyFilter(const std::shared_ptr<KeyFilter> &filter)
{
if (!filter) {
qCDebug(KLEOPATRA_LOG) << "TabWidget::setKeyFilter() trial to set filter=NULL";
return;
}
if (Page *const page = d->currentPage()) {
page->setKeyFilter(filter);
}
}
std::vector<QAbstractItemView *> TabWidget::views() const
{
std::vector<QAbstractItemView *> result;
const unsigned int N = count();
result.reserve(N);
for (unsigned int i = 0; i != N; ++i)
if (const Page *const p = d->page(i)) {
result.push_back(p->view());
}
return result;
}
QAbstractItemView *TabWidget::currentView() const
{
if (Page *const page = d->currentPage()) {
return page->view();
} else {
return nullptr;
}
}
KeyListModelInterface *TabWidget::currentModel() const
{
const QAbstractItemView *const view = currentView();
if (!view) {
return nullptr;
}
auto const proxy = qobject_cast<QAbstractProxyModel *>(view->model());
if (!proxy) {
return nullptr;
}
return dynamic_cast<KeyListModelInterface *>(proxy);
}
unsigned int TabWidget::count() const
{
return d->tabWidget->count();
}
void TabWidget::setMultiSelection(bool on)
{
for (unsigned int i = 0, end = count(); i != end; ++i)
if (const Page *const p = d->page(i))
if (QTreeView *const view = p->view()) {
view->setSelectionMode(on ? QAbstractItemView::ExtendedSelection : QAbstractItemView::SingleSelection);
}
}
void TabWidget::createActions(KActionCollection *coll)
{
if (!coll) {
return;
}
const action_data actionDataNew = {
"window_new_tab",
i18n("New Tab"),
i18n("Open a new tab"),
"tab-new-background",
this,
[this](bool) {
d->slotNewTab();
},
QStringLiteral("CTRL+SHIFT+N"),
};
d->newAction = make_action_from_data(actionDataNew, coll);
const std::vector<action_data> actionData = {
{
Actions::Rename,
i18n("Rename Tab..."),
i18n("Rename this tab"),
"edit-rename",
this,
[this](bool) {
d->slotRenameCurrentTab();
},
QStringLiteral("CTRL+SHIFT+R"),
RegularQAction,
Disabled,
},
{
Actions::Duplicate,
i18n("Duplicate Tab"),
i18n("Duplicate this tab"),
"tab-duplicate",
this,
[this](bool) {
d->slotDuplicateCurrentTab();
},
QStringLiteral("CTRL+SHIFT+D"),
},
{
Actions::Close,
i18n("Close Tab"),
i18n("Close this tab"),
"tab-close",
this,
[this](bool) {
d->slotCloseCurrentTab();
},
QStringLiteral("CTRL+SHIFT+W"),
RegularQAction,
Disabled,
}, // ### CTRL-W when available
{
Actions::MoveLeft,
i18n("Move Tab Left"),
i18n("Move this tab left"),
nullptr,
this,
[this](bool) {
d->slotMoveCurrentTabLeft();
},
QStringLiteral("CTRL+SHIFT+LEFT"),
RegularQAction,
Disabled,
},
{
Actions::MoveRight,
i18n("Move Tab Right"),
i18n("Move this tab right"),
nullptr,
this,
[this](bool) {
d->slotMoveCurrentTabRight();
},
QStringLiteral("CTRL+SHIFT+RIGHT"),
RegularQAction,
Disabled,
},
{
Actions::Hierarchical,
i18n("Hierarchical Certificate List"),
QString(),
nullptr,
this,
[this](bool on) {
d->slotToggleHierarchicalView(on);
},
QString(),
KFToggleAction,
Disabled,
},
{
Actions::ExpandAll,
i18n("Expand All"),
QString(),
nullptr,
this,
[this](bool) {
d->slotExpandAll();
},
QStringLiteral("CTRL+."),
RegularQAction,
Disabled,
},
{
Actions::CollapseAll,
i18n("Collapse All"),
QString(),
nullptr,
this,
[this](bool) {
d->slotCollapseAll();
},
QStringLiteral("CTRL+,"),
RegularQAction,
Disabled,
},
};
for (const auto &ad : actionData) {
d->currentPageActions.insert(ad.name, make_action_from_data(ad, coll));
}
for (const auto &ad : actionData) {
// create actions for the context menu of the currently not active tabs,
// but do not add those actions to the action collection
auto action = new QAction(ad.text, coll);
if (ad.icon) {
action->setIcon(QIcon::fromTheme(QLatin1StringView(ad.icon)));
}
action->setEnabled(ad.actionState == Enabled);
d->otherPageActions.insert(ad.name, action);
}
d->newTabButton->setDefaultAction(d->newAction);
d->tabWidget->setCornerWidget(d->newTabButton, Qt::TopLeftCorner);
if (auto action = d->currentPageActions.get(Actions::Close)) {
d->closeTabButton->setDefaultAction(action);
d->tabWidget->setCornerWidget(d->closeTabButton, Qt::TopRightCorner);
} else {
d->closeTabButton->setVisible(false);
}
d->actionsCreated = true;
}
QAbstractItemView *TabWidget::addView(const QString &title, const QString &id, const QString &text)
{
- const KConfigGroup group = KSharedConfig::openStateConfig()->group(QStringLiteral("View %1").arg(QUuid::createUuid().toString()));
+ const KConfigGroup group = KSharedConfig::openStateConfig()->group(QStringLiteral("%1:View %2").arg(d->configKey, QUuid::createUuid().toString()));
Page *page = new Page(title, id, text, nullptr, QString(), nullptr, group);
return d->addView(page, d->currentPage());
}
QAbstractItemView *TabWidget::addView(const KConfigGroup &group, Options options)
{
if (options & ShowUserIDs) {
return d->addView(new Page(group.readEntry(TITLE_ENTRY),
group.readEntry(KEY_FILTER_ENTRY),
group.readEntry(STRING_FILTER_ENTRY),
new UserIDProxyModel(this),
{},
nullptr,
group),
nullptr);
} else {
return d->addView(new Page(group), nullptr);
}
}
QAbstractItemView *TabWidget::addTemporaryView(const QString &title, AbstractKeyListSortFilterProxyModel *proxy, const QString &tabToolTip)
{
const KConfigGroup group = KSharedConfig::openConfig()->group(QStringLiteral("KeyTreeView_default"));
Page *const page = new Page(title, QString(), QString(), proxy, tabToolTip, nullptr, group);
page->setTemporary(true);
QAbstractItemView *v = d->addView(page, d->currentPage());
d->tabWidget->setCurrentIndex(d->tabWidget->count() - 1);
return v;
}
QTreeView *TabWidget::Private::addView(Page *page, Page *columnReference)
{
if (!page) {
return nullptr;
}
if (!actionsCreated) {
auto coll = new KActionCollection(q);
q->createActions(coll);
}
page->setFlatModel(flatModel);
page->setHierarchicalModel(hierarchicalModel);
connect(page, &Page::titleChanged, q, [this](const QString &text) {
slotPageTitleChanged(text);
});
connect(page, &Page::keyFilterChanged, q, [this](const std::shared_ptr<Kleo::KeyFilter> &filter) {
slotPageKeyFilterChanged(filter);
});
connect(page, &Page::stringFilterChanged, q, [this](const QString &text) {
slotPageStringFilterChanged(text);
});
connect(page, &Page::hierarchicalChanged, q, [this](bool on) {
slotPageHierarchyChanged(on);
});
if (columnReference) {
QMetaObject::invokeMethod(
q,
[=]() {
page->setColumnSizes(columnReference->columnSizes());
page->setSortColumn(columnReference->sortColumn(), columnReference->sortOrder());
},
Qt::QueuedConnection);
for (auto i = 0; i < columnReference->view()->model()->columnCount(); i++) {
page->view()->setColumnHidden(i, columnReference->view()->isColumnHidden(i));
page->view()->header()->moveSection(page->view()->header()->visualIndex(i), columnReference->view()->header()->visualIndex(i));
}
for (auto row = 0; row < page->view()->model()->rowCount(); row++) {
page->view()->setExpanded(page->view()->model()->index(row, 0),
columnReference->view()->isExpanded(columnReference->view()->model()->index(row, 0)));
}
}
QAbstractItemView *const previous = q->currentView();
const int tabIndex = tabWidget->addTab(page, page->title());
setTabOrder(closeTabButton, page->view());
tabWidget->setTabToolTip(tabIndex, page->toolTip());
// work around a bug in QTabWidget (tested with 4.3.2) not emitting currentChanged() when the first widget is inserted
QAbstractItemView *const current = q->currentView();
if (previous != current) {
currentIndexChanged(tabWidget->currentIndex());
}
enableDisableCurrentPageActions();
QTreeView *view = page->view();
Q_EMIT q->viewAdded(view);
return view;
}
static QStringList extractViewGroups(const KConfigGroup &config)
{
return config.readEntry("Tabs", QStringList());
}
-void TabWidget::loadViews(const KSharedConfig::Ptr &config, const QString &key, Options options)
+void TabWidget::loadViews(const KSharedConfig::Ptr &config, const QString &configKey, Options options)
{
d->config = config;
- d->configKey = key;
- QStringList groupList = extractViewGroups(config->group(key));
+ d->configKey = configKey;
+ QStringList groupList = extractViewGroups(config->group(configKey));
for (const QString &view : std::as_const(groupList)) {
addView(KConfigGroup(config, view), options);
}
if (!count()) {
// add default view:
addView({}, QStringLiteral("all-certificates"));
}
}
void TabWidget::saveViews()
{
if (!d->config) {
return;
}
QStringList tabs;
for (unsigned int i = 0, end = count(); i != end; ++i) {
if (Page *const p = d->page(i)) {
if (p->isTemporary()) {
continue;
}
tabs += p->configGroup().name();
p->saveState();
}
}
d->config->group(d->configKey).writeEntry("Tabs", tabs);
}
void TabWidget::connectSearchBar(SearchBar *sb)
{
connect(sb, &SearchBar::stringFilterChanged, this, &TabWidget::setStringFilter);
connect(this, &TabWidget::stringFilterChanged, sb, &SearchBar::setStringFilter);
connect(sb, &SearchBar::keyFilterChanged, this, &TabWidget::setKeyFilter);
connect(this, &TabWidget::keyFilterChanged, sb, &SearchBar::setKeyFilter);
connect(this, &TabWidget::enableChangeStringFilter, sb, &SearchBar::setChangeStringFilterEnabled);
connect(this, &TabWidget::enableChangeKeyFilter, sb, &SearchBar::setChangeKeyFilterEnabled);
}
#include "moc_tabwidget.cpp"
#include "tabwidget.moc"
diff --git a/src/view/tabwidget.h b/src/view/tabwidget.h
index e7f4291d3..58334dcd3 100644
--- a/src/view/tabwidget.h
+++ b/src/view/tabwidget.h
@@ -1,94 +1,94 @@
/* -*- mode: c++; c-basic-offset:4 -*-
view/tabwidget.h
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <KSharedConfig>
#include <QWidget>
#include <memory>
#include <vector>
#include <utils/pimpl_ptr.h>
class QAbstractItemView;
class KConfigGroup;
class KActionCollection;
namespace Kleo
{
class AbstractKeyListModel;
class AbstractKeyListSortFilterProxyModel;
class KeyFilter;
class KeyListModelInterface;
class SearchBar;
class TabWidget : public QWidget
{
Q_OBJECT
public:
enum Option {
ShowKeys = 0x00,
ShowUserIDs = 0x01,
};
Q_DECLARE_FLAGS(Options, Option)
explicit TabWidget(QWidget *parent = nullptr, Qt::WindowFlags f = {});
~TabWidget() override;
void setFlatModel(AbstractKeyListModel *model);
AbstractKeyListModel *flatModel() const;
void setHierarchicalModel(AbstractKeyListModel *model);
AbstractKeyListModel *hierarchicalModel() const;
QAbstractItemView *addView(const QString &title = QString(), const QString &keyFilterID = QString(), const QString &searchString = QString());
QAbstractItemView *addView(const KConfigGroup &group, Options options);
QAbstractItemView *
addTemporaryView(const QString &title = QString(), AbstractKeyListSortFilterProxyModel *proxy = nullptr, const QString &tabToolTip = QString());
- void loadViews(const KSharedConfig::Ptr &config, const QString &keys, Options options = ShowKeys);
+ void loadViews(const KSharedConfig::Ptr &config, const QString &configKeys, Options options = ShowKeys);
void saveViews();
std::vector<QAbstractItemView *> views() const;
QAbstractItemView *currentView() const;
KeyListModelInterface *currentModel() const;
unsigned int count() const;
void createActions(KActionCollection *collection);
void connectSearchBar(SearchBar *sb);
void setMultiSelection(bool on);
QString stringFilter() const;
public Q_SLOTS:
void setKeyFilter(const std::shared_ptr<Kleo::KeyFilter> &filter);
void setStringFilter(const QString &filter);
Q_SIGNALS:
void viewAdded(QAbstractItemView *view);
void viewAboutToBeRemoved(QAbstractItemView *view);
void currentViewChanged(QAbstractItemView *view);
void stringFilterChanged(const QString &filter);
void keyFilterChanged(const std::shared_ptr<Kleo::KeyFilter> &filter);
void enableChangeStringFilter(bool enable);
void enableChangeKeyFilter(bool enable);
private:
class Private;
kdtools::pimpl_ptr<Private> d;
};
}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Dec 23, 3:13 PM (11 h, 28 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
16/bc/329d4f9f1de8323562a640b4c0b5

Event Timeline