Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F34602014
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
19 KB
Subscribers
None
View Options
diff --git a/src/conf/CMakeLists.txt b/src/conf/CMakeLists.txt
index 618d09fc6..fdde1771a 100644
--- a/src/conf/CMakeLists.txt
+++ b/src/conf/CMakeLists.txt
@@ -1,88 +1,91 @@
include_directories(${kleopatra_SOURCE_DIR}/src)
if(BUILD_libkleopatraclient)
set(_kcm_kleopatra_libkleopatraclient_extra_SRCS
smimevalidationconfigurationwidget.cpp
smimevalidationconfigurationpage.cpp
cryptooperationsconfigwidget.cpp
cryptooperationsconfigpage.cpp
)
ki18n_wrap_ui(_kcm_kleopatra_libkleopatraclient_extra_SRCS
smimevalidationconfigurationwidget.ui
)
kconfig_add_kcfg_files(_kcm_kleopatra_libkleopatraclient_extra_SRCS
${kleopatra_SOURCE_DIR}/src/kcfg/smimevalidationpreferences.kcfgc
)
set(_kcm_kleopatra_libkleopatraclient_extra_LIBS kleopatraclientgui)
set(_kcm_kleopatra_libkleopatraclient_extra_install_FILES
kleopatra_config_smimevalidation.desktop
kleopatra_config_cryptooperations.desktop
)
else()
set(_kcm_kleopatra_libkleopatraclient_extra_SRCS)
set(_kcm_kleopatra_libkleopatraclient_extra_LIBS)
set(_kcm_kleopatra_libkleopatraclient_extra_install_FILES)
endif()
set(kcm_kleopatra_PART_SRCS
dirservconfigpage.cpp
appearanceconfigpage.cpp
appearanceconfigwidget.cpp
gnupgsystemconfigurationpage.cpp
+ groupsconfigpage.cpp
+ groupsconfigwidget.cpp
+ ${kleopatra_SOURCE_DIR}/src/dialogs/editgroupdialog.cpp
${kleopatra_BINARY_DIR}/src/kleopatra_debug.cpp
${_kcm_kleopatra_libkleopatraclient_extra_SRCS}
)
ki18n_wrap_ui(kcm_kleopatra_PART_SRCS
appearanceconfigwidget.ui
smimevalidationconfigurationwidget.ui
)
kconfig_add_kcfg_files(kcm_kleopatra_PART_SRCS
${kleopatra_SOURCE_DIR}/src/kcfg/tooltippreferences.kcfgc
${kleopatra_SOURCE_DIR}/src/kcfg/emailoperationspreferences.kcfgc
${kleopatra_SOURCE_DIR}/src/kcfg/fileoperationspreferences.kcfgc
${kleopatra_SOURCE_DIR}/src/kcfg/tagspreferences.kcfgc
${kleopatra_SOURCE_DIR}/src/kcfg/settings.kcfgc
)
add_library(kcm_kleopatra MODULE ${kcm_kleopatra_PART_SRCS})
if(HAVE_KCMUTILS)
set (_kcm_kleopatra_extra_libs KF5::KCMUtils)
endif()
target_link_libraries(kcm_kleopatra
KF5::Libkleo
KF5::IconThemes
KF5::I18n
KF5::WidgetsAddons
KF5::ConfigWidgets
${_kcm_kleopatra_extra_libs}
${_kleopatra_dbusaddons_libs}
${_kcm_kleopatra_libkleopatraclient_extra_LIBS}
)
if (COMPILE_WITH_UNITY_CMAKE_SUPPORT)
set_target_properties(kcm_kleopatra PROPERTIES UNITY_BUILD ON)
endif()
install(TARGETS kcm_kleopatra DESTINATION ${KDE_INSTALL_PLUGINDIR})
########### install files ###############
install(FILES
kleopatra_config_dirserv.desktop
kleopatra_config_appear.desktop
kleopatra_config_gnupgsystem.desktop
+ kleopatra_config_groups.desktop
${_kcm_kleopatra_libkleopatraclient_extra_install_FILES}
DESTINATION ${KDE_INSTALL_KSERVICES5DIR}
)
-
diff --git a/src/conf/configuredialog.cpp b/src/conf/configuredialog.cpp
index 63b5bd7aa..086d0643f 100644
--- a/src/conf/configuredialog.cpp
+++ b/src/conf/configuredialog.cpp
@@ -1,70 +1,71 @@
/*
configuredialog.cpp
This file is part of kleopatra
SPDX-FileCopyrightText: 2000 Espen Sand <espen@kde.org>
SPDX-FileCopyrightText: 2001-2002 Marc Mutz <mutz@kde.org>
SPDX-FileCopyrightText: 2004, 2008 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2016 Bundesamt für Sicherheit in der Informationstechnik
SPDX-FileContributor: Intevation GmbH
SPDX-License-Identifier: GPL-2.0-only
*/
#include "configuredialog.h"
#include <KConfig>
#include <KLocalizedString>
#include <KConfigGroup>
#include <KSharedConfig>
#if HAVE_KCMUTILS
# include <KCMultiDialog>
#else
# include "kleopageconfigdialog.h"
#endif
ConfigureDialog::ConfigureDialog(QWidget *parent)
#if HAVE_KCMUTILS
: KCMultiDialog(parent)
#else
: KleoPageConfigDialog(parent)
#endif
{
setFaceType(KPageDialog::List);
setWindowTitle(i18nc("@title:window", "Configure"));
+ addModule(QStringLiteral("kleopatra_config_groups"));
addModule(QStringLiteral("kleopatra_config_dirserv"));
addModule(QStringLiteral("kleopatra_config_appear"));
addModule(QStringLiteral("kleopatra_config_cryptooperations"));
addModule(QStringLiteral("kleopatra_config_smimevalidation"));
addModule(QStringLiteral("kleopatra_config_gnupgsystem"));
// We store the minimum size of the dialog on hide, because otherwise
// the KCMultiDialog starts with the size of the first kcm, not
// the largest one. This way at least after the first showing of
// the largest kcm the size is kept.
const KConfigGroup geometry(KSharedConfig::openConfig(), "Geometry");
const int width = geometry.readEntry("ConfigureDialogWidth", 0);
const int height = geometry.readEntry("ConfigureDialogHeight", 0);
if (width != 0 && height != 0) {
setMinimumSize(width, height);
}
}
void ConfigureDialog::hideEvent(QHideEvent *e)
{
const QSize minSize = minimumSizeHint();
KConfigGroup geometry(KSharedConfig::openConfig(), "Geometry");
geometry.writeEntry("ConfigureDialogWidth", minSize.width());
geometry.writeEntry("ConfigureDialogHeight", minSize.height());
#if HAVE_KCMUTILS
KCMultiDialog::hideEvent(e);
#else
KleoPageConfigDialog::hideEvent(e);
#endif
}
ConfigureDialog::~ConfigureDialog()
{
}
diff --git a/src/conf/groupsconfigpage.cpp b/src/conf/groupsconfigpage.cpp
new file mode 100644
index 000000000..e89179855
--- /dev/null
+++ b/src/conf/groupsconfigpage.cpp
@@ -0,0 +1,89 @@
+/*
+ conf/groupsconfigpage.cpp
+
+ This file is part of Kleopatra, the KDE keymanager
+ SPDX-FileCopyrightText: 2021 g10 Code GmbH
+ SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
+
+ SPDX-License-Identifier: GPL-2.0-or-later
+*/
+
+#include <config-kleopatra.h>
+
+#include "groupsconfigpage.h"
+
+#include "groupsconfigwidget.h"
+
+#include <Libkleo/Debug>
+#include <Libkleo/KeyCache>
+#include <Libkleo/KeyGroup>
+
+#include <QVBoxLayout>
+
+#include "kleopatra_debug.h"
+
+using namespace Kleo;
+
+class GroupsConfigPage::Private
+{
+ friend class ::GroupsConfigPage;
+ GroupsConfigPage *const q;
+
+ Private(GroupsConfigPage *qq);
+public:
+ ~Private() = default;
+
+private:
+ GroupsConfigWidget *widget = nullptr;
+};
+
+GroupsConfigPage::Private::Private(GroupsConfigPage *qq)
+ : q(qq)
+{
+}
+
+GroupsConfigPage::GroupsConfigPage(QWidget *parent, const QVariantList &args)
+ : KCModule(parent, args)
+ , d(new Private(this))
+{
+ // do not show the Defaults button; it has no effect
+ setButtons(buttons() & ~KCModule::Default);
+
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ layout->setContentsMargins(0, 0, 0, 0);
+
+ d->widget = new Kleo::GroupsConfigWidget(this);
+ if (QLayout *l = d->widget->layout()) {
+ l->setContentsMargins(0, 0, 0, 0);
+ }
+
+ layout->addWidget(d->widget);
+
+ connect(d->widget, &GroupsConfigWidget::changed, this, &GroupsConfigPage::markAsChanged);
+}
+
+GroupsConfigPage::~GroupsConfigPage() = default;
+
+void GroupsConfigPage::load()
+{
+ qCDebug(KLEOPATRA_LOG) << "GroupsConfigPage::load()";
+ d->widget->setGroups(KeyCache::instance()->configurableGroups());
+}
+
+void GroupsConfigPage::save()
+{
+ KeyCache::mutableInstance()->saveConfigurableGroups(d->widget->groups());
+
+ // reload after saving to ensure that the groups reflect the saved groups (e.g. in case of immutable entries)
+ load();
+}
+
+extern "C"
+{
+ Q_DECL_EXPORT KCModule *create_kleopatra_config_groups(QWidget *parent = nullptr, const QVariantList &args = QVariantList())
+ {
+ GroupsConfigPage *page = new GroupsConfigPage(parent, args);
+ page->setObjectName(QStringLiteral("kleopatra_config_groups"));
+ return page;
+ }
+}
diff --git a/src/conf/groupsconfigpage.h b/src/conf/groupsconfigpage.h
new file mode 100644
index 000000000..b4b3432a4
--- /dev/null
+++ b/src/conf/groupsconfigpage.h
@@ -0,0 +1,31 @@
+/*
+ conf/groupsconfigpage.h
+
+ This file is part of Kleopatra, the KDE keymanager
+ SPDX-FileCopyrightText: 2021 g10 Code GmbH
+ SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
+
+ SPDX-License-Identifier: GPL-2.0-or-later
+*/
+
+#ifndef __KLEOPATRA_CONF_GROUPSCONFIGPAGE_H__
+#define __KLEOPATRA_CONF_GROUPSCONFIGPAGE_H__
+
+#include <KCModule>
+
+class GroupsConfigPage : public KCModule
+{
+ Q_OBJECT
+public:
+ explicit GroupsConfigPage(QWidget *parent = nullptr, const QVariantList &args = QVariantList());
+ ~GroupsConfigPage() override;
+
+ void load() override;
+ void save() override;
+
+private:
+ class Private;
+ const std::unique_ptr<Private> d;
+};
+
+#endif // __KLEOPATRA_CONF_GROUPSCONFIGPAGE_H__
diff --git a/src/conf/groupsconfigwidget.cpp b/src/conf/groupsconfigwidget.cpp
new file mode 100644
index 000000000..eaf98df3b
--- /dev/null
+++ b/src/conf/groupsconfigwidget.cpp
@@ -0,0 +1,278 @@
+/*
+ conf/groupsconfigwidget.cpp
+
+ This file is part of Kleopatra, the KDE keymanager
+ SPDX-FileCopyrightText: 2021 g10 Code GmbH
+ SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
+
+ SPDX-License-Identifier: GPL-2.0-or-later
+*/
+
+#include "groupsconfigwidget.h"
+
+#include "dialogs/editgroupdialog.h"
+
+#include <Libkleo/KeyCache>
+#include <Libkleo/KeyGroup>
+#include <Libkleo/KeyListModel>
+#include <Libkleo/KeyListSortFilterProxyModel>
+
+#include <KLocalizedString>
+#include <KRandom>
+
+#include <QLabel>
+#include <QLineEdit>
+#include <QListView>
+#include <QPointer>
+#include <QPushButton>
+#include <QVBoxLayout>
+
+#include "kleopatra_debug.h"
+
+using namespace Kleo;
+using namespace Kleo::Dialogs;
+
+Q_DECLARE_METATYPE(KeyGroup)
+
+namespace
+{
+
+class ProxyModel : public AbstractKeyListSortFilterProxyModel
+{
+ Q_OBJECT
+public:
+ ProxyModel(QObject *parent = nullptr)
+ : AbstractKeyListSortFilterProxyModel(parent)
+ {
+ }
+
+ ~ProxyModel() override = default;
+
+ ProxyModel *clone() const override
+ {
+ // compiler-generated copy ctor is fine!
+ return new ProxyModel(*this);
+ }
+};
+
+}
+
+class GroupsConfigWidget::Private
+{
+ friend class ::Kleo::GroupsConfigWidget;
+ GroupsConfigWidget *const q;
+
+ struct {
+ QLineEdit *groupsFilter = nullptr;
+ QListView *groupsList = nullptr;
+ QPushButton *newButton = nullptr;
+ QPushButton *editButton = nullptr;
+ QPushButton *deleteButton = nullptr;
+ } ui;
+ AbstractKeyListModel *groupsModel = nullptr;
+ ProxyModel *groupsFilterModel = nullptr;
+
+public:
+ Private(GroupsConfigWidget *qq)
+ : q(qq)
+ {
+ auto mainLayout = new QVBoxLayout(q);
+
+ auto groupsLayout = new QGridLayout();
+ groupsLayout->setColumnStretch(0, 1);
+ groupsLayout->setRowStretch(1, 1);
+
+ ui.groupsFilter = new QLineEdit();
+ ui.groupsFilter->setClearButtonEnabled(true);
+ ui.groupsFilter->setPlaceholderText(i18nc("Placeholder text", "Search..."));
+ groupsLayout->addWidget(ui.groupsFilter, 0, 0);
+
+ groupsModel = AbstractKeyListModel::createFlatKeyListModel(q);
+ groupsFilterModel = new ProxyModel(q);
+ groupsFilterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
+ groupsFilterModel->setFilterKeyColumn(KeyList::Summary);
+ groupsFilterModel->setSortCaseSensitivity(Qt::CaseInsensitive);
+ groupsFilterModel->setSourceModel(groupsModel);
+ groupsFilterModel->sort(KeyList::Summary, Qt::AscendingOrder);
+ ui.groupsList = new QListView();
+ ui.groupsList->setModel(groupsFilterModel);
+ ui.groupsList->setModelColumn(KeyList::Summary);
+ ui.groupsList->setSelectionBehavior(QAbstractItemView::SelectRows);
+ ui.groupsList->setSelectionMode(QAbstractItemView::SingleSelection);
+
+ groupsLayout->addWidget(ui.groupsList, 1, 0);
+
+ auto groupsButtonLayout = new QVBoxLayout();
+
+ ui.newButton = new QPushButton(i18n("New"));
+ groupsButtonLayout->addWidget(ui.newButton);
+
+ ui.editButton = new QPushButton(i18n("Edit"));
+ ui.editButton->setEnabled(false);
+ groupsButtonLayout->addWidget(ui.editButton);
+
+ ui.deleteButton = new QPushButton(i18n("Delete"));
+ ui.deleteButton->setEnabled(false);
+ groupsButtonLayout->addWidget(ui.deleteButton);
+
+ groupsButtonLayout->addStretch(1);
+
+ groupsLayout->addLayout(groupsButtonLayout, 1, 1);
+
+ mainLayout->addLayout(groupsLayout, /*stretch=*/ 1);
+
+ connect(ui.groupsFilter, &QLineEdit::textChanged, groupsFilterModel, &QSortFilterProxyModel::setFilterFixedString);
+ connect(ui.groupsList->selectionModel(), &QItemSelectionModel::selectionChanged,
+ q, [this] () { selectionChanged(); });
+ connect(ui.groupsList, &QListView::doubleClicked,
+ q, [this] (const QModelIndex &index) { editGroup(index); });
+ connect(ui.newButton, &QPushButton::clicked, q, [this] () { addGroup(); });
+ connect(ui.editButton, &QPushButton::clicked, q, [this] () { editGroup(); });
+ connect(ui.deleteButton, &QPushButton::clicked, q, [this] () { deleteGroup(); });
+ }
+
+ ~Private()
+ {
+ }
+
+private:
+ QModelIndex selectedIndex()
+ {
+ const QModelIndexList selected = ui.groupsList->selectionModel()->selectedRows();
+ return selected.empty() ? QModelIndex() : selected[0];
+ }
+
+ KeyGroup getGroup(const QModelIndex &index)
+ {
+ return index.isValid() ? ui.groupsList->model()->data(index, KeyList::GroupRole).value<KeyGroup>() : KeyGroup();
+ }
+
+ void selectionChanged()
+ {
+ const KeyGroup selectedGroup = getGroup(selectedIndex());
+ const bool selectedGroupIsEditable = !selectedGroup.isNull() && !selectedGroup.isImmutable();
+ ui.editButton->setEnabled(selectedGroupIsEditable);
+ ui.deleteButton->setEnabled(selectedGroupIsEditable);
+ }
+
+ KeyGroup showEditGroupDialog(KeyGroup group, const QString &windowTitle, EditGroupDialog::FocusWidget focusWidget)
+ {
+ auto dialog = std::make_unique<EditGroupDialog>(q);
+ dialog->setWindowTitle(windowTitle);
+ dialog->setGroupName(group.name());
+ const KeyGroup::Keys &keys = group.keys();
+ dialog->setGroupKeys(std::vector<GpgME::Key>(keys.cbegin(), keys.cend()));
+ dialog->setInitialFocus(focusWidget);
+
+ const int result = dialog->exec();
+ if (result == QDialog::Rejected) {
+ return KeyGroup();
+ }
+
+ group.setName(dialog->groupName());
+ group.setKeys(dialog->groupKeys());
+
+ return group;
+ }
+
+ void addGroup()
+ {
+ const KeyGroup::Id newId = KRandom::randomString(8);
+ KeyGroup group = KeyGroup(newId, i18nc("default name for new group of keys", "New Group"), {}, KeyGroup::ApplicationConfig);
+ group.setIsImmutable(false);
+
+ const KeyGroup newGroup = showEditGroupDialog(
+ group, i18nc("@title:window a group of keys", "New Group"), EditGroupDialog::GroupName);
+ if (newGroup.isNull()) {
+ return;
+ }
+
+ const QModelIndex newIndex = groupsModel->addGroup(newGroup);
+ if (!newIndex.isValid()) {
+ qCDebug(KLEOPATRA_LOG) << "Adding group to model failed";
+ return;
+ }
+
+ Q_EMIT q->changed();
+ }
+
+ void editGroup(const QModelIndex &index = QModelIndex())
+ {
+ const QModelIndex groupIndex = index.isValid() ? index : selectedIndex();
+ if (!groupIndex.isValid()) {
+ qCDebug(KLEOPATRA_LOG) << "selection is empty";
+ return;
+ }
+ const KeyGroup group = getGroup(groupIndex);
+ if (group.isNull()) {
+ qCDebug(KLEOPATRA_LOG) << "selected group is null";
+ return;
+ }
+ if (group.isImmutable()) {
+ qCDebug(KLEOPATRA_LOG) << "selected group is immutable";
+ return;
+ }
+
+ const KeyGroup updatedGroup = showEditGroupDialog(
+ group, i18nc("@title:window a group of keys", "Edit Group"), EditGroupDialog::KeysFilter);
+ if (updatedGroup.isNull()) {
+ return;
+ }
+
+ const bool success = ui.groupsList->model()->setData(groupIndex, QVariant::fromValue(updatedGroup));
+ if (!success) {
+ qCDebug(KLEOPATRA_LOG) << "Updating group in model failed";
+ return;
+ }
+
+ Q_EMIT q->changed();
+ }
+
+ void deleteGroup()
+ {
+ const QModelIndex groupIndex = selectedIndex();
+ if (!groupIndex.isValid()) {
+ qCDebug(KLEOPATRA_LOG) << "selection is empty";
+ return;
+ }
+ const KeyGroup group = getGroup(groupIndex);
+ if (group.isNull()) {
+ qCDebug(KLEOPATRA_LOG) << "selected group is null";
+ return;
+ }
+
+ const bool success = groupsModel->removeGroup(group);
+ if (!success) {
+ qCDebug(KLEOPATRA_LOG) << "Removing group from model failed";
+ return;
+ }
+
+ Q_EMIT q->changed();
+ }
+};
+
+GroupsConfigWidget::GroupsConfigWidget(QWidget *parent)
+ : QWidget(parent)
+ , d(new Private(this))
+{
+}
+
+GroupsConfigWidget::~GroupsConfigWidget() = default;
+
+void GroupsConfigWidget::setGroups(const std::vector<KeyGroup> &groups)
+{
+ d->groupsModel->setGroups(groups);
+}
+
+std::vector<KeyGroup> GroupsConfigWidget::groups() const
+{
+ std::vector<KeyGroup> result;
+ result.reserve(d->groupsModel->rowCount());
+ for (int row = 0; row < d->groupsModel->rowCount(); ++row) {
+ const QModelIndex index = d->groupsModel->index(row, 0);
+ result.push_back(d->groupsModel->group(index));
+ }
+ return result;
+}
+
+#include "groupsconfigwidget.moc"
diff --git a/src/conf/groupsconfigwidget.h b/src/conf/groupsconfigwidget.h
new file mode 100644
index 000000000..ceb66a050
--- /dev/null
+++ b/src/conf/groupsconfigwidget.h
@@ -0,0 +1,42 @@
+/*
+ conf/groupsconfigwidget.h
+
+ This file is part of Kleopatra, the KDE keymanager
+ SPDX-FileCopyrightText: 2021 g10 Code GmbH
+ SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
+
+ SPDX-License-Identifier: GPL-2.0-or-later
+*/
+
+#ifndef __KLEOPATRA_CONF_GROUPSCONFIGWIDGET_H__
+#define __KLEOPATRA_CONF_GROUPSCONFIGWIDGET_H__
+
+#include <QWidget>
+
+#include <vector>
+
+namespace Kleo
+{
+class KeyGroup;
+
+class GroupsConfigWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit GroupsConfigWidget(QWidget *parent = nullptr);
+ ~GroupsConfigWidget() override;
+
+ void setGroups(const std::vector<KeyGroup> &groups);
+ std::vector<KeyGroup> groups() const;
+
+Q_SIGNALS:
+ void changed();
+
+private:
+ class Private;
+ const std::unique_ptr<Private> d;
+};
+
+}
+
+#endif // __KLEOPATRA_CONF_GROUPSCONFIGWIDGET_H__
diff --git a/src/conf/kleopatra_config_groups.desktop b/src/conf/kleopatra_config_groups.desktop
new file mode 100644
index 000000000..44bf87dc2
--- /dev/null
+++ b/src/conf/kleopatra_config_groups.desktop
@@ -0,0 +1,17 @@
+[Desktop Entry]
+Icon=group
+Type=Service
+X-KDE-ServiceTypes=KCModule
+X-DocPath=kleopatra/configuration.html
+
+X-KDE-ModuleType=Library
+X-KDE-Library=kcm_kleopatra
+X-KDE-FactoryName=kleopatra_config_groups
+X-KDE-HasReadOnlyMode=false
+X-KDE-ParentApp=kleopatra
+X-KDE-ParentComponents=kleopatra
+X-KDE-CfgDlgHierarchy=Kleopatra
+
+Name=Groups
+Comment=Configuration of groups of keys
+X-KDE-Keywords=groups,keys,certificates,configuration
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Jan 18, 4:30 PM (13 h, 36 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
7a/fe/8e05c32c60d60ba377219a8c5936
Attached To
rKLEOPATRA Kleopatra
Event Timeline
Log In to Comment