diff options
-rw-r--r-- | src/core/GpgCoreInit.cpp | 132 | ||||
-rw-r--r-- | src/core/function/gpg/GpgContext.cpp | 34 | ||||
-rw-r--r-- | src/core/function/gpg/GpgContext.h | 1 | ||||
-rw-r--r-- | src/core/function/gpg/GpgKeyGetter.cpp | 1 | ||||
-rw-r--r-- | src/core/struct/settings_object/KeyDatabaseItemSO.h | 56 | ||||
-rw-r--r-- | src/core/struct/settings_object/KeyDatabaseListSO.h | 62 | ||||
-rw-r--r-- | src/ui/UserInterfaceUtils.cpp | 6 | ||||
-rw-r--r-- | src/ui/dialog/KeyDatabaseEditDialog.cpp | 89 | ||||
-rw-r--r-- | src/ui/dialog/KeyDatabaseEditDialog.h | 60 | ||||
-rw-r--r-- | src/ui/dialog/RevocationOptionsDialog.cpp | 1 | ||||
-rw-r--r-- | src/ui/dialog/RevocationOptionsDialog.h | 1 | ||||
-rw-r--r-- | src/ui/dialog/controller/GnuPGControllerDialog.cpp | 192 | ||||
-rw-r--r-- | src/ui/dialog/controller/GnuPGControllerDialog.h | 25 | ||||
-rw-r--r-- | src/ui/widgets/KeyList.cpp | 40 | ||||
-rw-r--r-- | src/ui/widgets/KeyList.h | 9 | ||||
-rw-r--r-- | src/ui/widgets/KeyTable.h | 6 | ||||
-rw-r--r-- | ui/GnuPGControllerDialog.ui | 329 | ||||
-rw-r--r-- | ui/KeyDatabaseEditDialog.ui | 115 | ||||
-rw-r--r-- | ui/KeyList.ui | 17 |
19 files changed, 854 insertions, 322 deletions
diff --git a/src/core/GpgCoreInit.cpp b/src/core/GpgCoreInit.cpp index 68acc4cc..d89398e3 100644 --- a/src/core/GpgCoreInit.cpp +++ b/src/core/GpgCoreInit.cpp @@ -36,7 +36,9 @@ #include "core/function/gpg/GpgAdvancedOperator.h" #include "core/function/gpg/GpgContext.h" #include "core/function/gpg/GpgKeyGetter.h" +#include "core/model/SettingsObject.h" #include "core/module/ModuleManager.h" +#include "core/struct/settings_object/KeyDatabaseListSO.h" #include "core/thread/Task.h" #include "core/thread/TaskRunnerGetter.h" #include "core/utils/CommonUtils.h" @@ -130,7 +132,7 @@ auto InitGpgME(const QString& gpgconf_path, const QString& gnupg_path) -> bool { Module::UpsertRTValue("core", "gpgme.ctx.gnupg_version", QString(engine_info->version)); Module::UpsertRTValue( - "core", "gpgme.ctx.database_path", + "core", "gpgme.ctx.default_database_path", QString(engine_info->home_dir == nullptr ? "" : engine_info->home_dir)); break; @@ -298,12 +300,6 @@ void InitGpgFrontendCore(CoreInitArgs args) { auto auto_import_missing_key = settings.value("network/auto_import_missing_key", false).toBool(); - auto use_custom_key_database_path = - settings.value("gnupg/use_custom_key_database_path", false).toBool(); - - auto custom_key_database_path = - settings.value("gnupg/custom_key_database_path", QString{}).toString(); - auto use_pinentry_as_password_input_dialog = settings .value("gnupg/use_pinentry_as_password_input_dialog", @@ -314,65 +310,101 @@ void InitGpgFrontendCore(CoreInitArgs args) { auto restart_all_gnupg_components_on_start = settings.value("gnupg/restart_gpg_agent_on_start", false).toBool(); + auto key_database_list = + KeyDatabaseListSO(SettingsObject("key_database_list")); + const auto key_databases = key_database_list.key_databases; + auto* task = new Thread::Task( [=](const DataObjectPtr&) -> int { // key database path - QString key_database_fs_path; + QList<KeyDatabaseItemSO> buffered_key_dbs; // try to use user defined key database - if (use_custom_key_database_path && - !custom_key_database_path.isEmpty()) { - if (VerifyKeyDatabasePath(QFileInfo(custom_key_database_path))) { - key_database_fs_path = - QFileInfo(custom_key_database_path).absoluteFilePath(); - LOG_D() << "use custom gpg key database: " << key_database_fs_path - << "raw:" << custom_key_database_path; - - } else { - LOG_W() << "custom gpg key database path is not suitable: " - << key_database_fs_path - << "raw:" << custom_key_database_path; + if (!key_databases.empty()) { + for (const auto& key_database : key_databases) { + if (VerifyKeyDatabasePath(QFileInfo(key_database.path))) { + auto key_database_fs_path = + QFileInfo(key_database.path).absoluteFilePath(); + LOG_D() << "load gpg key database: " << key_database.path; + buffered_key_dbs.append(key_database); + } else { + LOG_W() << "gpg key database path is not suitable: " + << key_database.path; + } } } else { + QString key_database_fs_path; #if defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) // use user's home path by default key_database_fs_path = SearchKeyDatabasePath({QDir::home().path() + "/.gnupg"}); #endif + if (key_database_fs_path.isEmpty()) { + key_database_fs_path = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.default_database_path", QString{}); + } + + // add the default key database path + if (!key_database_fs_path.isEmpty()) { + auto so = SettingsObject("key_database_list"); + auto key_database_list = KeyDatabaseListSO(so); + + auto key_database = KeyDatabaseItemSO(); + key_database.name = "Default"; + key_database.path = key_database_fs_path; + key_database_list.key_databases.append(key_database); + so.Store(key_database_list.ToJson()); + buffered_key_dbs.append(key_database); + } } if (args.load_default_gpg_context) { - // init ctx, also checking the basic env - auto& ctx = GpgFrontend::GpgContext::CreateInstance( - kGpgFrontendDefaultChannel, [=]() -> ChannelObjectPtr { - GpgFrontend::GpgContextInitArgs args; - - // set key database path - if (!key_database_fs_path.isEmpty()) { - args.db_path = key_database_fs_path; - } - - // set custom gnupg path - if (!gnupg_install_fs_path.isEmpty()) { - args.gpgconf_path = gnupg_install_fs_path; - } - - args.offline_mode = forbid_all_gnupg_connection; - args.auto_import_missing_key = auto_import_missing_key; - args.use_pinentry = use_pinentry_as_password_input_dialog; - - return ConvertToChannelObjectPtr<>( - SecureCreateUniqueObject<GpgContext>( - args, kGpgFrontendDefaultChannel)); - }); - - // exit if failed - if (!ctx.Good()) { - FLOG_W("default gnupg context init error, abort"); - CoreSignalStation::GetInstance()->SignalBadGnupgEnv( - QCoreApplication::tr("GpgME Context initiation failed")); - return -1; + int channel_index = kGpgFrontendDefaultChannel; + for (const auto& key_db : buffered_key_dbs) { + // init ctx, also checking the basic env + auto& ctx = GpgFrontend::GpgContext::CreateInstance( + channel_index, [=]() -> ChannelObjectPtr { + GpgFrontend::GpgContextInitArgs args; + + // set key database path + if (!key_db.path.isEmpty()) { + args.db_name = key_db.name; + args.db_path = key_db.path; + } + + // set custom gnupg path + if (!gnupg_install_fs_path.isEmpty()) { + args.gpgconf_path = gnupg_install_fs_path; + } + + args.offline_mode = forbid_all_gnupg_connection; + args.auto_import_missing_key = auto_import_missing_key; + args.use_pinentry = use_pinentry_as_password_input_dialog; + + LOG_D() << "new gpgme context, channel" << channel_index + << ", key db name" << args.db_name << "key db path" + << args.db_path << ""; + + return ConvertToChannelObjectPtr<>( + SecureCreateUniqueObject<GpgContext>(args, + channel_index)); + }); + + // exit if failed + if (channel_index == kGpgFrontendDefaultChannel && !ctx.Good()) { + FLOG_W() << "gnupg default context init error, key database: " + << key_db.name << "key database path: " << key_db.path; + CoreSignalStation::GetInstance()->SignalBadGnupgEnv( + QCoreApplication::tr("GpgME Context initiation failed")); + return -1; + } + + FLOG_D() << "gnupg context init success, index" << channel_index + << " key database: " << key_db.name + << "key database path: " << key_db.path; + + channel_index++; } Module::UpsertRTValue("core", "env.state.ctx", 1); } diff --git a/src/core/function/gpg/GpgContext.cpp b/src/core/function/gpg/GpgContext.cpp index a661f183..5c5dd813 100644 --- a/src/core/function/gpg/GpgContext.cpp +++ b/src/core/function/gpg/GpgContext.cpp @@ -209,13 +209,19 @@ class GpgContext::Impl { GPGME_KEYLIST_MODE_WITH_TOFU)) == GPG_ERR_NO_ERROR; } - static auto set_ctx_openpgp_engine_info(gpgme_ctx_t ctx) -> bool { + auto set_ctx_openpgp_engine_info(gpgme_ctx_t ctx) -> bool { const auto app_path = Module::RetrieveRTValueTypedOrDefault<>( - "core", "gpgme.ctx.app_path", QString{}); - const auto database_path = Module::RetrieveRTValueTypedOrDefault<>( - "core", "gpgme.ctx.database_path", QString{}); + "core", QString("gpgme.ctx.app_path").arg(parent_->GetChannel()), + QString{}); - LOG_D() << "ctx set engine info, db path: " << database_path + QString database_path; + // set custom gpg key db path + if (!args_.db_path.isEmpty()) { + database_path = args_.db_path; + } + + LOG_D() << "ctx set engine info, channel: " << parent_->GetChannel() + << ", db name: " << args_.db_name << ", db path: " << args_.db_path << ", app path: " << app_path; auto app_path_buffer = app_path.toUtf8(); @@ -281,17 +287,23 @@ class GpgContext::Impl { } } - // set custom gpg key db path - if (!args_.db_path.isEmpty()) { - LOG_D() << "set context database path to" << args_.db_path; - Module::UpsertRTValue("core", "gpgme.ctx.database_path", args_.db_path); - } - if (!set_ctx_openpgp_engine_info(ctx)) { FLOG_W("set gpgme context openpgp engine info failed"); return false; } + Module::UpsertRTValue( + "core", QString("gpgme.ctx.list.%1.channel").arg(parent_->GetChannel()), + parent_->GetChannel()); + Module::UpsertRTValue( + "core", + QString("gpgme.ctx.list.%1.database_name").arg(parent_->GetChannel()), + args_.db_name); + Module::UpsertRTValue( + "core", + QString("gpgme.ctx.list.%1.database_path").arg(parent_->GetChannel()), + args_.db_path); + return true; } diff --git a/src/core/function/gpg/GpgContext.h b/src/core/function/gpg/GpgContext.h index 1ff22b8a..f98adde8 100644 --- a/src/core/function/gpg/GpgContext.h +++ b/src/core/function/gpg/GpgContext.h @@ -40,6 +40,7 @@ namespace GpgFrontend { * */ struct GpgContextInitArgs { + QString db_name; ///< QString db_path; ///< bool test_mode = false; ///< diff --git a/src/core/function/gpg/GpgKeyGetter.cpp b/src/core/function/gpg/GpgKeyGetter.cpp index af77b067..5d002b0d 100644 --- a/src/core/function/gpg/GpgKeyGetter.cpp +++ b/src/core/function/gpg/GpgKeyGetter.cpp @@ -31,7 +31,6 @@ #include <gpg-error.h> #include <mutex> -#include <shared_mutex> #include "core/GpgModel.h" #include "core/function/gpg/GpgContext.h" diff --git a/src/core/struct/settings_object/KeyDatabaseItemSO.h b/src/core/struct/settings_object/KeyDatabaseItemSO.h new file mode 100644 index 00000000..e15165ad --- /dev/null +++ b/src/core/struct/settings_object/KeyDatabaseItemSO.h @@ -0,0 +1,56 @@ +/** + * Copyright (C) 2021-2024 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +namespace GpgFrontend { + +struct KeyDatabaseItemSO { + QString name; + QString path; + + KeyDatabaseItemSO() = default; + + explicit KeyDatabaseItemSO(const QJsonObject& j) { + if (const auto v = j["name"]; v.isString()) { + name = v.toString(); + } + if (const auto v = j["path"]; v.isString()) { + path = v.toString(); + } + } + + [[nodiscard]] auto ToJson() const -> QJsonObject { + QJsonObject j; + j["name"] = name; + j["path"] = path; + return j; + } +}; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/struct/settings_object/KeyDatabaseListSO.h b/src/core/struct/settings_object/KeyDatabaseListSO.h new file mode 100644 index 00000000..3e5e1320 --- /dev/null +++ b/src/core/struct/settings_object/KeyDatabaseListSO.h @@ -0,0 +1,62 @@ +/** + * Copyright (C) 2021-2024 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "core/struct/settings_object/KeyDatabaseItemSO.h" + +namespace GpgFrontend { + +struct KeyDatabaseListSO { + QList<KeyDatabaseItemSO> key_databases; + + KeyDatabaseListSO() = default; + + explicit KeyDatabaseListSO(const QJsonObject& j) { + if (const auto v = j["key_databases"]; v.isArray()) { + const QJsonArray j_array = v.toArray(); + for (const auto& key_database : j_array) { + if (key_database.isObject()) { + key_databases.append(KeyDatabaseItemSO(key_database.toObject())); + } + } + } + } + + auto ToJson() -> QJsonObject { + QJsonObject j; + auto j_array = QJsonArray(); + for (const auto& s : key_databases) { + j_array.push_back(s.ToJson()); + } + j["key_databases"] = j_array; + return j; + } +}; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/ui/UserInterfaceUtils.cpp b/src/ui/UserInterfaceUtils.cpp index 0f462cf7..0dfe9867 100644 --- a/src/ui/UserInterfaceUtils.cpp +++ b/src/ui/UserInterfaceUtils.cpp @@ -472,6 +472,7 @@ void CommonUtils::slot_update_key_status() { [](DataObjectPtr) -> int { // flush key cache for all GpgKeyGetter Intances. for (const auto &channel_id : GpgKeyGetter::GetAllChannelId()) { + LOG_D() << "refreshing key database at channel: " << channel_id; GpgKeyGetter::GetInstance(channel_id).FlushKeyCache(); } return 0; @@ -481,8 +482,9 @@ void CommonUtils::slot_update_key_status() { &CommonUtils::SignalKeyDatabaseRefreshDone); // post the task to the default task runner - Thread::TaskRunnerGetter::GetInstance().GetTaskRunner()->PostTask( - refresh_task); + Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_GPG) + ->PostTask(refresh_task); } void CommonUtils::slot_update_key_from_server_finished( diff --git a/src/ui/dialog/KeyDatabaseEditDialog.cpp b/src/ui/dialog/KeyDatabaseEditDialog.cpp new file mode 100644 index 00000000..15604f39 --- /dev/null +++ b/src/ui/dialog/KeyDatabaseEditDialog.cpp @@ -0,0 +1,89 @@ +/** + * Copyright (C) 2021-2024 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "KeyDatabaseEditDialog.h" + +#include "core/utils/MemoryUtils.h" +#include "ui_KeyDatabaseEditDialog.h" + +namespace GpgFrontend::UI { +KeyDatabaseEditDialog::KeyDatabaseEditDialog(QWidget* parent) + : GeneralDialog("KeyDatabaseEditDialog", parent), + ui_(GpgFrontend::SecureCreateSharedObject<Ui_KeyDatabaseEditDialog>()) { + ui_->setupUi(this); + + ui_->keyDBNameLabel->setText(tr("Key Database Name")); + ui_->keyDBPathLabel->setText(tr("Key Database Path")); + ui_->selectKeyDBButton->setText(tr("Select A Key Database Path")); + + this->setWindowTitle(tr("Key Database Info")); + + connect(ui_->selectKeyDBButton, &QPushButton::clicked, this, [this](bool) { + auto path = QFileDialog::getExistingDirectory( + this, tr("Open Directory"), {}, + QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + if (!check_custom_gnupg_key_database_path(path)) { + QMessageBox::critical(this, tr("Illegal GnuPG Key Database Path"), + tr("Target GnuPG Key Database Path is not an " + "exists readable directory.")); + } + + path_ = QFileInfo(path).absoluteFilePath(); + ui_->keyDBPathShowLabel->setText(path_); + }); + + connect(ui_->buttonBox, &QDialogButtonBox::accepted, this, + &KeyDatabaseEditDialog::slot_button_box_accepted); + connect(ui_->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(ui_->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + setAttribute(Qt::WA_DeleteOnClose); + setModal(true); +} + +void KeyDatabaseEditDialog::slot_button_box_accepted() { + name_ = ui_->keyDBNameLineEdit->text(); + emit SignalKeyDatabaseInfoAccepted(name_, path_); +} + +auto KeyDatabaseEditDialog::check_custom_gnupg_key_database_path( + const QString& path) -> bool { + if (path.isEmpty()) return false; + + QFileInfo const dir_info(path); + return dir_info.exists() && dir_info.isReadable() && dir_info.isDir(); +} + +void KeyDatabaseEditDialog::SetDefaultName(QString name) { + name_ = std::move(name); +} + +void KeyDatabaseEditDialog::SetDefaultPath(QString path) { + path_ = QFileInfo(path).absoluteFilePath(); + ui_->keyDBPathShowLabel->setText(path_); +} +}; // namespace GpgFrontend::UI
\ No newline at end of file diff --git a/src/ui/dialog/KeyDatabaseEditDialog.h b/src/ui/dialog/KeyDatabaseEditDialog.h new file mode 100644 index 00000000..287a97df --- /dev/null +++ b/src/ui/dialog/KeyDatabaseEditDialog.h @@ -0,0 +1,60 @@ +/** + * Copyright (C) 2021-2024 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include <utility> + +#include "ui/dialog/GeneralDialog.h" + +class Ui_KeyDatabaseEditDialog; + +namespace GpgFrontend::UI { +class KeyDatabaseEditDialog : public GeneralDialog { + Q_OBJECT + public: + explicit KeyDatabaseEditDialog(QWidget* parent); + + void SetDefaultName(QString name); + + void SetDefaultPath(QString path); + + signals: + void SignalKeyDatabaseInfoAccepted(QString name, QString path); + + private: + std::shared_ptr<Ui_KeyDatabaseEditDialog> ui_; ///< + QString name_; + QString path_; + + void slot_button_box_accepted(); + + auto check_custom_gnupg_key_database_path(const QString& path) -> bool; +}; + +} // namespace GpgFrontend::UI
\ No newline at end of file diff --git a/src/ui/dialog/RevocationOptionsDialog.cpp b/src/ui/dialog/RevocationOptionsDialog.cpp index e2bbba00..ea11d747 100644 --- a/src/ui/dialog/RevocationOptionsDialog.cpp +++ b/src/ui/dialog/RevocationOptionsDialog.cpp @@ -53,6 +53,7 @@ GpgFrontend::UI::RevocationOptionsDialog::RevocationOptionsDialog( connect(ui_->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(ui_->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); setAttribute(Qt::WA_DeleteOnClose); + setModal(true); } auto GpgFrontend::UI::RevocationOptionsDialog::Code() const -> int { diff --git a/src/ui/dialog/RevocationOptionsDialog.h b/src/ui/dialog/RevocationOptionsDialog.h index 0f404ca2..17356a4d 100644 --- a/src/ui/dialog/RevocationOptionsDialog.h +++ b/src/ui/dialog/RevocationOptionsDialog.h @@ -1,4 +1,3 @@ - /** * Copyright (C) 2021-2024 Saturneric <[email protected]> * diff --git a/src/ui/dialog/controller/GnuPGControllerDialog.cpp b/src/ui/dialog/controller/GnuPGControllerDialog.cpp index 859c26aa..1ae1278b 100644 --- a/src/ui/dialog/controller/GnuPGControllerDialog.cpp +++ b/src/ui/dialog/controller/GnuPGControllerDialog.cpp @@ -30,9 +30,14 @@ #include "core/GpgModel.h" #include "core/function/GlobalSettingStation.h" +#include "core/model/SettingsObject.h" #include "core/module/ModuleManager.h" +#include "core/struct/settings_object/KeyDatabaseListSO.h" #include "ui/UISignalStation.h" #include "ui/dialog/GeneralDialog.h" +#include "ui/dialog/KeyDatabaseEditDialog.h" + +// #include "ui_GnuPGControllerDialog.h" namespace GpgFrontend::UI { @@ -42,9 +47,9 @@ GnuPGControllerDialog::GnuPGControllerDialog(QWidget* parent) ui_(GpgFrontend::SecureCreateSharedObject<Ui_GnuPGControllerDialog>()) { ui_->setupUi(this); - ui_->generalBox->setTitle(tr("General")); - ui_->keyDatabaseGroupBox->setTitle(tr("Key Database")); - ui_->advanceGroupBox->setTitle(tr("Advanced")); + ui_->tab->setWindowTitle(tr("General")); + ui_->tab_2->setWindowTitle(tr("Key Database")); + ui_->tab_3->setWindowTitle(tr("Advanced")); ui_->asciiModeCheckBox->setText(tr("Use Binary Mode for File Operations")); ui_->usePinentryAsPasswordInputDialogCheckBox->setText( @@ -52,10 +57,6 @@ GnuPGControllerDialog::GnuPGControllerDialog(QWidget* parent) ui_->gpgmeDebugLogCheckBox->setText(tr("Enable GpgME Debug Log")); ui_->useCustomGnuPGInstallPathCheckBox->setText(tr("Use Custom GnuPG")); ui_->useCustomGnuPGInstallPathButton->setText(tr("Select GnuPG Path")); - ui_->keyDatabaseUseCustomCheckBox->setText( - tr("Use Custom GnuPG Key Database Path")); - ui_->customKeyDatabasePathSelectButton->setText( - tr("Select Key Database Path")); ui_->restartGpgAgentOnStartCheckBox->setText( tr("Restart Gpg Agent on start")); ui_->killAllGnuPGDaemonCheckBox->setText( @@ -68,49 +69,25 @@ GnuPGControllerDialog::GnuPGControllerDialog(QWidget* parent) tr("Tips: notice that modify any of these settings will cause an " "Application restart.")); + popup_menu_ = new QMenu(this); + popup_menu_->addAction(ui_->actionRemove_Selected_Key_Database); + // announce main window connect(this, &GnuPGControllerDialog::SignalRestartNeeded, UISignalStation::GetInstance(), &UISignalStation::SignalRestartApplication); - connect(ui_->keyDatabaseUseCustomCheckBox, &QCheckBox::stateChanged, this, - [=](int state) { - ui_->customKeyDatabasePathSelectButton->setDisabled( - state != Qt::CheckState::Checked); - }); - connect(ui_->useCustomGnuPGInstallPathCheckBox, &QCheckBox::stateChanged, this, [=](int state) { ui_->useCustomGnuPGInstallPathButton->setDisabled( state != Qt::CheckState::Checked); }); - connect(ui_->keyDatabaseUseCustomCheckBox, &QCheckBox::stateChanged, this, - &GnuPGControllerDialog::slot_update_custom_key_database_path_label); - connect(ui_->useCustomGnuPGInstallPathCheckBox, &QCheckBox::stateChanged, this, &GnuPGControllerDialog::slot_update_custom_gnupg_install_path_label); connect( - ui_->customKeyDatabasePathSelectButton, &QPushButton::clicked, this, - [=]() { - QString selected_custom_key_database_path = - QFileDialog::getExistingDirectory( - this, tr("Open Directory"), {}, - QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); - - custom_key_database_path_ = selected_custom_key_database_path; - - // announce the restart - this->slot_set_restart_needed(kDeepRestartCode); - - // update ui - this->slot_update_custom_key_database_path_label( - this->ui_->keyDatabaseUseCustomCheckBox->checkState()); - }); - - connect( ui_->useCustomGnuPGInstallPathButton, &QPushButton::clicked, this, [=]() { QString selected_custom_gnupg_install_path = QFileDialog::getExistingDirectory( @@ -149,18 +126,18 @@ GnuPGControllerDialog::GnuPGControllerDialog(QWidget* parent) this->slot_set_restart_needed(kDeepRestartCode); }); - connect(ui_->keyDatabaseUseCustomCheckBox, &QCheckBox::stateChanged, this, - [=](int) { - // announce the restart - this->slot_set_restart_needed(kDeepRestartCode); - }); - connect(ui_->useCustomGnuPGInstallPathCheckBox, &QCheckBox::stateChanged, this, [=](int) { // announce the restart this->slot_set_restart_needed(kDeepRestartCode); }); + connect(ui_->addNewKeyDatabaseButton, &QPushButton::clicked, this, + &GnuPGControllerDialog::slot_add_new_key_database); + + connect(ui_->actionRemove_Selected_Key_Database, &QAction::triggered, this, + &GnuPGControllerDialog::slot_remove_existing_key_database); + #if defined(__APPLE__) && defined(__MACH__) // macOS style settings ui_->buttonBox->setDisabled(true); @@ -188,40 +165,6 @@ void GnuPGControllerDialog::SlotAccept() { close(); } -void GnuPGControllerDialog::slot_update_custom_key_database_path_label( - int state) { - // hide label (not necessary to show the default path) - this->ui_->currentKeyDatabasePathLabel->setHidden(state != - Qt::CheckState::Checked); - if (state == Qt::CheckState::Checked) { - if (custom_key_database_path_.isEmpty()) { - // read from settings file - QString custom_key_database_path = - GlobalSettingStation::GetInstance() - .GetSettings() - .value("gnupg/custom_key_database_path") - .toString(); - custom_key_database_path_ = custom_key_database_path; - } - - // notify the user - if (!check_custom_gnupg_key_database_path(custom_key_database_path_)) { - return; - }; - - // set label value - if (!custom_key_database_path_.isEmpty()) { - ui_->currentKeyDatabasePathLabel->setText(custom_key_database_path_); - } - } - - if (ui_->currentKeyDatabasePathLabel->text().isEmpty()) { - const auto database_path = Module::RetrieveRTValueTypedOrDefault<>( - "core", "gpgme.ctx.database_path", QString{}); - ui_->currentKeyDatabasePathLabel->setText(database_path); - } -} - void GnuPGControllerDialog::slot_update_custom_gnupg_install_path_label( int state) { // hide label (not necessary to show the default path) @@ -268,12 +211,6 @@ void GnuPGControllerDialog::set_settings() { ui_->asciiModeCheckBox->setCheckState(Qt::Checked); } - auto use_custom_key_database_path = - settings.value("gnupg/use_custom_key_database_path", false).toBool(); - if (use_custom_key_database_path) { - ui_->keyDatabaseUseCustomCheckBox->setCheckState(Qt::Checked); - } - auto enable_gpgme_debug_log = settings.value("gnupg/enable_gpgme_debug_log", false).toBool(); if (enable_gpgme_debug_log) { @@ -286,9 +223,6 @@ void GnuPGControllerDialog::set_settings() { ui_->killAllGnuPGDaemonCheckBox->setCheckState(Qt::Checked); } - this->slot_update_custom_key_database_path_label( - ui_->keyDatabaseUseCustomCheckBox->checkState()); - auto use_custom_gnupg_install_path = settings.value("gnupg/use_custom_gnupg_install_path", false).toBool(); if (use_custom_gnupg_install_path) { @@ -310,13 +244,16 @@ void GnuPGControllerDialog::set_settings() { ui_->restartGpgAgentOnStartCheckBox->setCheckState(Qt::Checked); } - this->slot_update_custom_key_database_path_label( - use_custom_key_database_path ? Qt::Checked : Qt::Unchecked); - this->slot_update_custom_gnupg_install_path_label( use_custom_gnupg_install_path ? Qt::Checked : Qt::Unchecked); this->slot_set_restart_needed(kNonRestartCode); + + auto key_database_list = + KeyDatabaseListSO(SettingsObject("key_database_list")); + buffered_key_db_so_ = key_database_list.key_databases; + + this->slot_refresh_key_database_table(); } void GnuPGControllerDialog::apply_settings() { @@ -325,22 +262,23 @@ void GnuPGControllerDialog::apply_settings() { settings.setValue("gnupg/non_ascii_at_file_operation", ui_->asciiModeCheckBox->isChecked()); - settings.setValue("gnupg/use_custom_key_database_path", - ui_->keyDatabaseUseCustomCheckBox->isChecked()); settings.setValue("gnupg/use_custom_gnupg_install_path", ui_->useCustomGnuPGInstallPathCheckBox->isChecked()); settings.setValue("gnupg/use_pinentry_as_password_input_dialog", ui_->usePinentryAsPasswordInputDialogCheckBox->isChecked()); settings.setValue("gnupg/enable_gpgme_debug_log", ui_->gpgmeDebugLogCheckBox->isChecked()); - settings.setValue("gnupg/custom_key_database_path", - ui_->currentKeyDatabasePathLabel->text()); settings.setValue("gnupg/custom_gnupg_install_path", ui_->currentCustomGnuPGInstallPathLabel->text()); settings.setValue("gnupg/restart_gpg_agent_on_start", ui_->restartGpgAgentOnStartCheckBox->isChecked()); settings.setValue("gnupg/kill_all_gnupg_daemon_at_close", ui_->killAllGnuPGDaemonCheckBox->isChecked()); + + auto so = SettingsObject("key_database_list"); + auto key_database_list = KeyDatabaseListSO(so); + key_database_list.key_databases = buffered_key_db_so_; + so.Store(key_database_list.ToJson()); } auto GnuPGControllerDialog::get_restart_needed() const -> int { @@ -384,19 +322,73 @@ auto GnuPGControllerDialog::check_custom_gnupg_path(QString path) -> bool { return true; } -auto GnuPGControllerDialog::check_custom_gnupg_key_database_path(QString path) - -> bool { - if (path.isEmpty()) return false; +void GnuPGControllerDialog::slot_add_new_key_database() { + auto* dialog = new KeyDatabaseEditDialog(this); + connect(dialog, &KeyDatabaseEditDialog::SignalKeyDatabaseInfoAccepted, this, + [this](const QString& name, const QString& path) { + auto& key_databases = buffered_key_db_so_; + for (const auto& key_database : key_databases) { + if (QFileInfo(key_database.path) == QFileInfo(path)) { + QMessageBox::warning( + this, tr("Duplicate Key Database Paths"), + tr("The newly added key database path duplicates a " + "previously existing one.")); + return; + } + } + + LOG_D() << "new key database path, name: " << name + << "path: " << path; + + KeyDatabaseItemSO key_database; + key_database.name = name; + key_database.path = path; + key_databases.append(key_database); + + slot_refresh_key_database_table(); + }); + dialog->show(); +} - QFileInfo const dir_info(path); - if (!dir_info.exists() || !dir_info.isReadable() || !dir_info.isDir()) { - QMessageBox::critical(this, tr("Illegal GnuPG Key Database Path"), - tr("Target GnuPG Key Database Path is not an " - "exists readable directory.")); - return false; +void GnuPGControllerDialog::slot_refresh_key_database_table() { + auto key_databases = buffered_key_db_so_; + ui_->keyDatabaseTable->setRowCount(static_cast<int>(key_databases.size())); + + int index = 0; + for (const auto& key_database : key_databases) { + LOG_D() << "key database table item index: " << index + << "name: " << key_database.name << "path: " << key_database.path; + + auto* i_name = new QTableWidgetItem(key_database.name); + i_name->setTextAlignment(Qt::AlignCenter); + ui_->keyDatabaseTable->setItem(index, 0, i_name); + + ui_->keyDatabaseTable->setItem(index, 1, + new QTableWidgetItem(key_database.path)); + + index++; } + ui_->keyDatabaseTable->resizeColumnsToContents(); +} - return true; +void GnuPGControllerDialog::contextMenuEvent(QContextMenuEvent* event) { + QDialog::contextMenuEvent(event); + if (ui_->keyDatabaseTable->selectedItems().length() > 0) { + popup_menu_->exec(event->globalPos()); + } } +void GnuPGControllerDialog::slot_remove_existing_key_database() { + const auto row_size = ui_->keyDatabaseTable->rowCount(); + + auto& key_databases = buffered_key_db_so_; + for (int i = 0; i < row_size; i++) { + auto* const item = ui_->keyDatabaseTable->item(i, 1); + if (!item->isSelected()) continue; + key_databases.remove(i); + break; + } + + this->slot_refresh_key_database_table(); +} } // namespace GpgFrontend::UI diff --git a/src/ui/dialog/controller/GnuPGControllerDialog.h b/src/ui/dialog/controller/GnuPGControllerDialog.h index ab2f305c..37ec2f62 100644 --- a/src/ui/dialog/controller/GnuPGControllerDialog.h +++ b/src/ui/dialog/controller/GnuPGControllerDialog.h @@ -28,6 +28,7 @@ #pragma once +#include "core/struct/settings_object/KeyDatabaseItemSO.h" #include "ui/dialog/GeneralDialog.h" class Ui_GnuPGControllerDialog; @@ -73,19 +74,33 @@ class GnuPGControllerDialog : public GeneralDialog { * @brief * */ - void slot_update_custom_key_database_path_label(int state); + void slot_update_custom_gnupg_install_path_label(int state); /** * @brief * */ - void slot_update_custom_gnupg_install_path_label(int state); + void slot_add_new_key_database(); + + /** + * @brief + * + */ + void slot_remove_existing_key_database(); + + /** + * @brief + * + */ + void slot_refresh_key_database_table(); private: std::shared_ptr<Ui_GnuPGControllerDialog> ui_; ///< int restart_mode_{0}; ///< QString custom_key_database_path_; QString custom_gnupg_path_; + QMenu* popup_menu_{}; + QList<KeyDatabaseItemSO> buffered_key_db_so_; /** * @brief Get the Restart Needed object @@ -115,12 +130,12 @@ class GnuPGControllerDialog : public GeneralDialog { */ auto check_custom_gnupg_path(QString) -> bool; + protected: /** * @brief * - * @return true - * @return false + * @param event */ - auto check_custom_gnupg_key_database_path(QString) -> bool; + void contextMenuEvent(QContextMenuEvent* event) override; }; } // namespace GpgFrontend::UI diff --git a/src/ui/widgets/KeyList.cpp b/src/ui/widgets/KeyList.cpp index a9363e19..ff6f4e22 100644 --- a/src/ui/widgets/KeyList.cpp +++ b/src/ui/widgets/KeyList.cpp @@ -33,6 +33,7 @@ #include "core/function/GlobalSettingStation.h" #include "core/function/gpg/GpgKeyGetter.h" +#include "core/module/ModuleManager.h" #include "ui/UISignalStation.h" #include "ui/UserInterfaceUtils.h" #include "ui/dialog/import_export/KeyImportDetailDialog.h" @@ -69,6 +70,37 @@ void KeyList::init() { KeyMenuAbility::kCOLUMN_FILTER); ui_->searchBarEdit->setHidden(~menu_ability_ & KeyMenuAbility::kSEARCH_BAR); + auto* gpg_context_menu = new QMenu(this); + auto* gpg_context_groups = new QActionGroup(this); + gpg_context_groups->setExclusive(true); + auto context_index_list = Module::ListRTChildKeys("core", "gpgme.ctx.list"); + for (auto& context_index : context_index_list) { + LOG_D() << "context grt key: " << context_index; + + const auto grt_key_prefix = QString("gpgme.ctx.list.%1").arg(context_index); + auto channel = Module::RetrieveRTValueTypedOrDefault( + "core", grt_key_prefix + ".channel", -1); + auto database_name = Module::RetrieveRTValueTypedOrDefault( + "core", grt_key_prefix + ".database_name", QString{}); + + LOG_D() << "context grt channel: " << channel + << "GRT key prefix: " << grt_key_prefix + << "database name: " << database_name; + + auto* switch_context_action = + new QAction(QString("%1: %2").arg(channel).arg(database_name), this); + switch_context_action->setCheckable(true); + switch_context_action->setChecked(channel == current_gpg_context_channel_); + connect(switch_context_action, &QAction::toggled, this, + [this, channel](bool checked) { + current_gpg_context_channel_ = channel; + emit SignalRefreshDatabase(); + }); + gpg_context_groups->addAction(switch_context_action); + gpg_context_menu->addAction(switch_context_action); + } + ui_->switchContextButton->setMenu(gpg_context_menu); + auto* column_type_menu = new QMenu(this); key_id_column_action_ = new QAction(tr("Key ID"), this); @@ -253,7 +285,8 @@ void KeyList::SlotRefresh() { ui_->refreshKeyListButton->setDisabled(true); ui_->syncButton->setDisabled(true); - model_ = GpgKeyGetter::GetInstance().GetGpgKeyTableModel(); + model_ = GpgKeyGetter::GetInstance(current_gpg_context_channel_) + .GetGpgKeyTableModel(); for (int i = 0; i < ui_->keyGroupTab->count(); i++) { auto* key_table = qobject_cast<KeyTable*>(ui_->keyGroupTab->widget(i)); @@ -261,8 +294,6 @@ void KeyList::SlotRefresh() { } emit SignalRefreshStatusBar(tr("Refreshing Key List..."), 3000); - this->model_ = GpgKeyGetter::GetInstance().GetGpgKeyTableModel(); - this->SlotRefreshUI(); } @@ -600,4 +631,7 @@ void KeyList::UpdateKeyTableColumnType(GpgKeyTableColumn column_type) { emit SignalColumnTypeChange(fixed_columns_filter_ & global_column_filter_); } +auto KeyList::GetCurrentGpgContextChannel() const -> int { + return current_gpg_context_channel_; +} } // namespace GpgFrontend::UI diff --git a/src/ui/widgets/KeyList.h b/src/ui/widgets/KeyList.h index 8563df8f..47c4d2a1 100644 --- a/src/ui/widgets/KeyList.h +++ b/src/ui/widgets/KeyList.h @@ -209,6 +209,13 @@ class KeyList : public QWidget { */ void UpdateKeyTableColumnType(GpgKeyTableColumn); + /** + * @brief + * + * @return int + */ + [[nodiscard]] auto GetCurrentGpgContextChannel() const -> int; + signals: /** * @brief @@ -293,6 +300,8 @@ class KeyList : public QWidget { QAction* subkeys_number_column_action_; QAction* comment_column_action_; + int current_gpg_context_channel_ = kGpgFrontendDefaultChannel; + private slots: /** diff --git a/src/ui/widgets/KeyTable.h b/src/ui/widgets/KeyTable.h index 11aca803..a03a1c83 100644 --- a/src/ui/widgets/KeyTable.h +++ b/src/ui/widgets/KeyTable.h @@ -166,6 +166,12 @@ struct KeyTable : public QTableView { */ void SignalColumnTypeChange(GpgKeyTableColumn); + /** + * @brief + * + */ + void SignalGpgContextChannelChange(int); + private: QSharedPointer<GpgKeyTableModel> model_; GpgKeyTableProxyModel proxy_model_; diff --git a/ui/GnuPGControllerDialog.ui b/ui/GnuPGControllerDialog.ui index 4f0bdfc6..2876e2e4 100644 --- a/ui/GnuPGControllerDialog.ui +++ b/ui/GnuPGControllerDialog.ui @@ -6,155 +6,191 @@ <rect> <x>0</x> <y>0</y> - <width>607</width> - <height>581</height> + <width>535</width> + <height>498</height> </rect> </property> <property name="windowTitle"> <string>GnuPG Controller</string> </property> <layout class="QGridLayout" name="gridLayout"> - <item row="0" column="0"> + <item row="1" column="0"> <layout class="QVBoxLayout" name="verticalLayout"> <item> - <widget class="QGroupBox" name="generalBox"> - <property name="title"> - <string>General</string> + <widget class="QTabWidget" name="tabWidget"> + <property name="currentIndex"> + <number>1</number> </property> - <layout class="QGridLayout" name="gridLayout_7"> - <item row="0" column="0"> - <layout class="QVBoxLayout" name="verticalLayout_7"> - <item> - <widget class="QCheckBox" name="asciiModeCheckBox"> + <widget class="QWidget" name="tab"> + <attribute name="title"> + <string>General</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <layout class="QVBoxLayout" name="verticalLayout_7"> + <item> + <widget class="QCheckBox" name="asciiModeCheckBox"> + <property name="text"> + <string>Use Binary Mode for File Operations</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="usePinentryAsPasswordInputDialogCheckBox"> + <property name="text"> + <string>Use Pinentry as Password Input Dialog</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="gpgmeDebugLogCheckBox"> + <property name="text"> + <string>Enable GpgME Debug Log</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="restartGpgAgentOnStartCheckBox"> + <property name="text"> + <string>Restart Gpg Agent on start</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="killAllGnuPGDaemonCheckBox"> + <property name="text"> + <string>Kill all gnupg daemon at close</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab_2"> + <attribute name="title"> + <string>Key Database</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <item> + <widget class="QTableWidget" name="keyDatabaseTable"> + <property name="editTriggers"> + <set>QAbstractItemView::NoEditTriggers</set> + </property> + <property name="dragEnabled"> + <bool>false</bool> + </property> + <property name="dragDropOverwriteMode"> + <bool>false</bool> + </property> + <property name="dragDropMode"> + <enum>QAbstractItemView::NoDragDrop</enum> + </property> + <property name="defaultDropAction"> + <enum>Qt::IgnoreAction</enum> + </property> + <property name="selectionMode"> + <enum>QAbstractItemView::SingleSelection</enum> + </property> + <property name="selectionBehavior"> + <enum>QAbstractItemView::SelectRows</enum> + </property> + <property name="columnCount"> + <number>2</number> + </property> + <column> <property name="text"> - <string>Use Binary Mode for File Operations</string> + <string>Name</string> </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="usePinentryAsPasswordInputDialogCheckBox"> + </column> + <column> <property name="text"> - <string>Use Pinentry as Password Input Dialog</string> + <string>Path</string> </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="gpgmeDebugLogCheckBox"> - <property name="text"> - <string>Enable GpgME Debug Log</string> - </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="restartGpgAgentOnStartCheckBox"> - <property name="text"> - <string>Restart Gpg Agent on start</string> - </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="killAllGnuPGDaemonCheckBox"> - <property name="text"> - <string>Kill all gnupg daemon at close</string> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="keyDatabaseGroupBox"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="title"> - <string>Key Database</string> - </property> - <property name="flat"> - <bool>false</bool> - </property> - <property name="checkable"> - <bool>false</bool> - </property> - <layout class="QGridLayout" name="gridLayout_2"> - <item row="0" column="0"> - <layout class="QVBoxLayout" name="verticalLayout_6"> - <item> - <widget class="QCheckBox" name="keyDatabaseUseCustomCheckBox"> - <property name="text"> - <string>Use Custom GnuPG Key Database Path</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="currentKeyDatabasePathLabel"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="customKeyDatabasePathSelectButton"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="text"> - <string>Select Key Database Path</string> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="advanceGroupBox"> - <property name="title"> - <string>Advance</string> - </property> - <layout class="QGridLayout" name="gridLayout_3"> - <item row="0" column="0"> - <layout class="QVBoxLayout" name="verticalLayout_9"> - <item> - <widget class="QCheckBox" name="useCustomGnuPGInstallPathCheckBox"> - <property name="text"> - <string>Use Custom GnuPG</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="currentCustomGnuPGInstallPathLabel"> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="useCustomGnuPGInstallPathButton"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="text"> - <string>Select GnuPG Path</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="customGnuPGPathTipsLabel"> - <property name="text"> - <string>Tips: please select a directroy where "gpgconf" is located in.</string> - </property> - </widget> - </item> - </layout> - </item> - </layout> + </column> + </widget> + </item> + <item> + <widget class="QPushButton" name="addNewKeyDatabaseButton"> + <property name="text"> + <string>Add New Key Database</string> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab_3"> + <attribute name="title"> + <string>Advanced</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_5"> + <item> + <layout class="QVBoxLayout" name="verticalLayout_9"> + <item> + <widget class="QCheckBox" name="useCustomGnuPGInstallPathCheckBox"> + <property name="text"> + <string>Use Custom GnuPG</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="currentCustomGnuPGInstallPathLabel"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="useCustomGnuPGInstallPathButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Select GnuPG Path</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="customGnuPGPathTipsLabel"> + <property name="text"> + <string>Tips: please select a directroy where "gpgconf" is located in.</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> </widget> </item> <item> @@ -165,19 +201,6 @@ </widget> </item> <item> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - <item> <widget class="QDialogButtonBox" name="buttonBox"> <property name="orientation"> <enum>Qt::Horizontal</enum> @@ -190,6 +213,14 @@ </layout> </item> </layout> + <action name="actionRemove_Selected_Key_Database"> + <property name="text"> + <string>Remove</string> + </property> + <property name="menuRole"> + <enum>QAction::NoRole</enum> + </property> + </action> </widget> <resources/> <connections> diff --git a/ui/KeyDatabaseEditDialog.ui b/ui/KeyDatabaseEditDialog.ui new file mode 100644 index 00000000..794e753c --- /dev/null +++ b/ui/KeyDatabaseEditDialog.ui @@ -0,0 +1,115 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>KeyDatabaseEditDialog</class> + <widget class="QDialog" name="KeyDatabaseEditDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>472</width> + <height>330</height> + </rect> + </property> + <property name="windowTitle"> + <string>Key Database Info</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QLabel" name="keyDBNameLabel"> + <property name="text"> + <string>Key Database Name</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="keyDBNameLineEdit"/> + </item> + <item> + <widget class="QLabel" name="keyDBPathLabel"> + <property name="text"> + <string>Key Database Path</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="keyDBPathShowLabel"> + <property name="text"> + <string/> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="selectKeyDBButton"> + <property name="text"> + <string>Select A Key Database Path</string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>KeyDatabaseEditDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>KeyDatabaseEditDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/ui/KeyList.ui b/ui/KeyList.ui index 618b44fd..af95698c 100644 --- a/ui/KeyList.ui +++ b/ui/KeyList.ui @@ -93,6 +93,23 @@ </widget> </item> <item> + <widget class="QToolButton" name="switchContextButton"> + <property name="toolTip"> + <string>Uncheck ALL</string> + </property> + <property name="text"> + <string>Switch Context</string> + </property> + <property name="icon"> + <iconset resource="../gpgfrontend.qrc"> + <normaloff>:/icons/none.png</normaloff>:/icons/none.png</iconset> + </property> + <property name="popupMode"> + <enum>QToolButton::InstantPopup</enum> + </property> + </widget> + </item> + <item> <widget class="QToolButton" name="columnTypeButton"> <property name="acceptDrops"> <bool>false</bool> |