aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/GpgContext.cpp33
-rw-r--r--src/core/function/CacheManager.cpp116
-rw-r--r--src/core/function/CacheManager.h76
-rw-r--r--src/core/function/DataObjectOperator.h1
-rw-r--r--src/core/function/GlobalSettingStation.cpp68
-rw-r--r--src/core/function/GlobalSettingStation.h32
-rw-r--r--src/core/function/gpg/GpgKeyManager.cpp152
-rw-r--r--src/core/function/gpg/GpgKeyManager.h60
-rw-r--r--src/core/model/GpgKey.cpp30
-rw-r--r--src/core/model/GpgKey.h7
-rw-r--r--src/ui/SignalStation.h6
-rw-r--r--src/ui/UserInterfaceUtils.cpp40
-rw-r--r--src/ui/UserInterfaceUtils.h19
-rw-r--r--src/ui/dialog/SignersPicker.cpp9
-rw-r--r--src/ui/dialog/Wizard.cpp32
-rw-r--r--src/ui/dialog/help/AboutDialog.cpp4
-rw-r--r--src/ui/dialog/keypair_details/KeyPairDetailTab.cpp23
-rw-r--r--src/ui/dialog/keypair_details/KeyPairDetailTab.h1
-rw-r--r--src/ui/dialog/keypair_details/KeyPairOperaTab.cpp60
-rw-r--r--src/ui/dialog/keypair_details/KeyPairOperaTab.h13
-rw-r--r--src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp4
-rw-r--r--src/ui/dialog/settings/SettingsGeneral.cpp55
-rw-r--r--src/ui/main_window/GeneralMainWindow.cpp4
-rw-r--r--src/ui/main_window/KeyMgmt.cpp26
-rw-r--r--src/ui/main_window/MainWindow.cpp71
-rw-r--r--src/ui/main_window/MainWindow.h34
-rw-r--r--src/ui/main_window/MainWindowSlotFunction.cpp71
-rw-r--r--src/ui/main_window/MainWindowUI.cpp41
-rw-r--r--src/ui/widgets/FilePage.cpp21
-rw-r--r--src/ui/widgets/FilePage.h6
-rw-r--r--src/ui/widgets/KeyList.cpp96
-rw-r--r--src/ui/widgets/KeyList.h50
-rw-r--r--src/ui/widgets/TextEdit.cpp76
-rw-r--r--src/ui/widgets/TextEdit.h6
34 files changed, 1217 insertions, 126 deletions
diff --git a/src/core/GpgContext.cpp b/src/core/GpgContext.cpp
index 1cb137e6..7d98004d 100644
--- a/src/core/GpgContext.cpp
+++ b/src/core/GpgContext.cpp
@@ -43,6 +43,7 @@
#include "core/function/gpg/GpgCommandExecutor.h"
#include "core/thread/Task.h"
#include "core/thread/TaskRunnerGetter.h"
+#include "function/gpg/GpgKeyGetter.h"
#ifdef _WIN32
#include <windows.h>
@@ -169,6 +170,23 @@ GpgContext::GpgContext(const GpgContextInitArgs &args) : args_(args) {
SPDLOG_ERROR("env check failed");
return;
} else {
+ // speed up loading process
+ gpgme_set_offline(*this, 1);
+
+ // set keylist mode
+ if (info_.GnupgVersion >= "2.0.0") {
+ check_gpg_error(gpgme_set_keylist_mode(
+ *this, GPGME_KEYLIST_MODE_LOCAL | GPGME_KEYLIST_MODE_WITH_SECRET |
+ GPGME_KEYLIST_MODE_SIGS |
+ GPGME_KEYLIST_MODE_SIG_NOTATIONS |
+ GPGME_KEYLIST_MODE_WITH_TOFU));
+ } else {
+ check_gpg_error(gpgme_set_keylist_mode(
+ *this, GPGME_KEYLIST_MODE_LOCAL | GPGME_KEYLIST_MODE_SIGS |
+ GPGME_KEYLIST_MODE_SIG_NOTATIONS |
+ GPGME_KEYLIST_MODE_WITH_TOFU));
+ }
+
// async, init context
Thread::TaskRunnerGetter::GetInstance()
.GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_GPG)
@@ -206,21 +224,6 @@ void GpgContext::post_init_ctx() {
gpgme_set_armor(*this, 0);
}
- // Speed up loading process
- gpgme_set_offline(*this, 1);
-
- if (info_.GnupgVersion >= "2.0.0") {
- check_gpg_error(gpgme_set_keylist_mode(
- *this, GPGME_KEYLIST_MODE_LOCAL | GPGME_KEYLIST_MODE_WITH_SECRET |
- GPGME_KEYLIST_MODE_SIGS | GPGME_KEYLIST_MODE_SIG_NOTATIONS |
- GPGME_KEYLIST_MODE_WITH_TOFU));
- } else {
- check_gpg_error(gpgme_set_keylist_mode(
- *this, GPGME_KEYLIST_MODE_LOCAL | GPGME_KEYLIST_MODE_SIGS |
- GPGME_KEYLIST_MODE_SIG_NOTATIONS |
- GPGME_KEYLIST_MODE_WITH_TOFU));
- }
-
// for unit test
if (args_.test_mode) {
if (info_.GnupgVersion >= "2.1.0") SetPassphraseCb(test_passphrase_cb);
diff --git a/src/core/function/CacheManager.cpp b/src/core/function/CacheManager.cpp
index a20b8003..b24a8050 100644
--- a/src/core/function/CacheManager.cpp
+++ b/src/core/function/CacheManager.cpp
@@ -29,38 +29,120 @@
#include "CacheManager.h"
#include <algorithm>
+#include <boost/format.hpp>
+#include <string>
#include "function/DataObjectOperator.h"
-#include "nlohmann/json_fwd.hpp"
#include "spdlog/spdlog.h"
+GpgFrontend::CacheManager::CacheManager(int channel)
+ : m_timer_(new QTimer(this)),
+ SingletonFunctionObject<CacheManager>(channel) {
+ connect(m_timer_, &QTimer::timeout, this, &CacheManager::flush_cache_storage);
+ m_timer_->start(15000);
+
+ load_all_cache_storage();
+}
+
void GpgFrontend::CacheManager::SaveCache(std::string key,
- const nlohmann::json &value) {
+ const nlohmann::json& value,
+ bool flush) {
+ auto data_object_key = get_data_object_key(key);
+ cache_storage_.insert(key, value);
+
+ if (std::find(key_storage_.begin(), key_storage_.end(), key) ==
+ key_storage_.end()) {
+ SPDLOG_DEBUG("register new key of cache", key);
+ key_storage_.push_back(key);
+ }
+
+ if (flush) {
+ flush_cache_storage();
+ }
+}
+
+nlohmann::json GpgFrontend::CacheManager::LoadCache(std::string key) {
+ auto data_object_key = get_data_object_key(key);
+
+ SPDLOG_DEBUG("load cache, data object key: {}", data_object_key);
+ if (!cache_storage_.exists(key)) {
+ cache_storage_.insert(key, load_cache_storage(key, {}));
+ }
+
+ auto cache = cache_storage_.get(key);
+ if (cache)
+ return *cache;
+ else
+ return {};
+}
+
+nlohmann::json GpgFrontend::CacheManager::LoadCache(
+ std::string key, nlohmann::json default_value) {
+ auto data_object_key = get_data_object_key(key);
+ if (!cache_storage_.exists(key)) {
+ cache_storage_.insert(key, load_cache_storage(key, default_value));
+ }
+
+ auto cache = cache_storage_.get(key);
+ if (cache)
+ return *cache;
+ else
+ return {};
+}
+
+std::string GpgFrontend::CacheManager::get_data_object_key(std::string key) {
+ return (boost::format("__cache_data_%1%") % key).str();
+}
+
+nlohmann::json GpgFrontend::CacheManager::load_cache_storage(
+ std::string key, nlohmann::json default_value) {
+ auto data_object_key = get_data_object_key(key);
auto stored_data =
GpgFrontend::DataObjectOperator::GetInstance().GetDataObject(
- "__cache_data_list");
+ data_object_key);
- // get cache data list from file system
- nlohmann::json cache_data_list;
if (stored_data.has_value()) {
- cache_data_list = std::move(stored_data.value());
+ return stored_data.value();
+ } else {
+ return default_value;
}
+}
- if (!cache_data_list.is_array()) {
- cache_data_list.clear();
+void GpgFrontend::CacheManager::flush_cache_storage() {
+ for (auto cache : cache_storage_.mirror()) {
+ auto key = get_data_object_key(cache.first);
+ SPDLOG_DEBUG("save cache into filesystem, key {}, value size: {}", key,
+ cache.second.size());
+ GpgFrontend::DataObjectOperator::GetInstance().SaveDataObj(key,
+ cache.second);
}
+ GpgFrontend::DataObjectOperator::GetInstance().SaveDataObj(drk_key_,
+ key_storage_);
+}
+
+void GpgFrontend::CacheManager::register_cache_key(std::string key) {}
- if (GpgFrontend::DataObjectOperator::GetInstance()
- .SaveDataObj(key, value)
- .empty()) {
+void GpgFrontend::CacheManager::load_all_cache_storage() {
+ SPDLOG_DEBUG("start to load all cache from file system");
+ auto stored_data =
+ GpgFrontend::DataObjectOperator::GetInstance().GetDataObject(drk_key_);
+
+ // get cache data list from file system
+ nlohmann::json registered_key_list;
+ if (stored_data.has_value()) {
+ registered_key_list = std::move(stored_data.value());
+ }
+
+ if (!registered_key_list.is_array()) {
+ GpgFrontend::DataObjectOperator::GetInstance().SaveDataObj(
+ drk_key_, nlohmann::json::array());
+ SPDLOG_ERROR("drk_key_ is not an array, abort.");
return;
}
- if (std::find(cache_data_list.begin(), cache_data_list.end(), key) ==
- cache_data_list.end()) {
- cache_data_list.push_back(key);
+ for (auto key : registered_key_list) {
+ load_cache_storage(key, {});
}
- GpgFrontend::DataObjectOperator::GetInstance().SaveDataObj(
- "__cache_data_list", cache_data_list);
-}
+ key_storage_ = registered_key_list;
+} \ No newline at end of file
diff --git a/src/core/function/CacheManager.h b/src/core/function/CacheManager.h
index e489182f..8234de2a 100644
--- a/src/core/function/CacheManager.h
+++ b/src/core/function/CacheManager.h
@@ -29,15 +29,83 @@
#ifndef GPGFRONTEND_CACHEMANAGER_H
#define GPGFRONTEND_CACHEMANAGER_H
+#include <string>
+
+#include "core/GpgFunctionObject.h"
+
namespace GpgFrontend {
-class CacheManager {
+template <typename Key, typename Value>
+class ThreadSafeMap {
public:
- static void SaveCache(std::string key, const nlohmann::json &value);
+ using MapType = std::map<Key, Value>;
+ using IteratorType = typename MapType::iterator;
+
+ void insert(const Key& key, const Value& value) {
+ std::unique_lock lock(mutex_);
+ map_[key] = value;
+ }
+
+ std::optional<Value> get(const Key& key) {
+ std::shared_lock lock(mutex_);
+ auto it = map_.find(key);
+ if (it != map_.end()) {
+ return it->second;
+ }
+ return std::nullopt;
+ }
+
+ bool exists(const Key& key) {
+ std::shared_lock lock(mutex_);
+ return map_.count(key) > 0;
+ }
+
+ IteratorType begin() { return map_mirror_.begin(); }
+
+ IteratorType end() { return map_mirror_.end(); }
+
+ ThreadSafeMap& mirror() {
+ std::shared_lock lock(mutex_);
+ map_mirror_ = map_;
+ return *this;
+ }
+
+ private:
+ MapType map_mirror_;
+ MapType map_;
+ mutable std::shared_mutex mutex_;
+};
+
+class GPGFRONTEND_CORE_EXPORT CacheManager
+ : public QObject,
+ public SingletonFunctionObject<CacheManager> {
+ Q_OBJECT
+ public:
+ CacheManager(int channel = SingletonFunctionObject::GetDefaultChannel());
+
+ void SaveCache(std::string key, const nlohmann::json& value,
+ bool flush = false);
+
+ nlohmann::json LoadCache(std::string key);
+
+ nlohmann::json LoadCache(std::string key, nlohmann::json default_value);
+
+ private:
+ std::string get_data_object_key(std::string key);
+
+ nlohmann::json load_cache_storage(std::string key,
+ nlohmann::json default_value);
+
+ void load_all_cache_storage();
+
+ void flush_cache_storage();
- static nlohmann::json LoadCache(std::string name);
+ void register_cache_key(std::string key);
- static void ClearAllCache();
+ ThreadSafeMap<std::string, nlohmann::json> cache_storage_;
+ nlohmann::json key_storage_;
+ QTimer* m_timer_;
+ const std::string drk_key_ = "__cache_manage_data_register_key_list";
};
} // namespace GpgFrontend
diff --git a/src/core/function/DataObjectOperator.h b/src/core/function/DataObjectOperator.h
index 97abc607..ae5dc62c 100644
--- a/src/core/function/DataObjectOperator.h
+++ b/src/core/function/DataObjectOperator.h
@@ -29,7 +29,6 @@
#ifndef GPGFRONTEND_DATAOBJECTOPERATOR_H
#define GPGFRONTEND_DATAOBJECTOPERATOR_H
-#include "core/GpgFrontendCore.h"
#include "core/GpgFunctionObject.h"
#include "core/function/GlobalSettingStation.h"
diff --git a/src/core/function/GlobalSettingStation.cpp b/src/core/function/GlobalSettingStation.cpp
index cc126ebd..6b743268 100644
--- a/src/core/function/GlobalSettingStation.cpp
+++ b/src/core/function/GlobalSettingStation.cpp
@@ -55,6 +55,10 @@ GpgFrontend::GlobalSettingStation::GlobalSettingStation(int channel) noexcept
SPDLOG_INFO("app locale path: {}", app_locale_path_.u8string());
SPDLOG_INFO("app conf path: {}", ui_config_path_.u8string());
+ SPDLOG_INFO("app log files total size: {}", GetLogFilesSize());
+ SPDLOG_INFO("app data objects files total size: {}",
+ GetDataObjectsFilesSize());
+
if (!is_directory(app_configure_path_)) create_directory(app_configure_path_);
if (!is_directory(app_data_path_)) create_directory(app_data_path_);
if (!is_directory(app_log_path_)) create_directory(app_log_path_);
@@ -92,4 +96,68 @@ GpgFrontend::GlobalSettingStation::GetUISettings() noexcept {
void GpgFrontend::GlobalSettingStation::init_app_secure_key() {}
+int64_t GpgFrontend::GlobalSettingStation::get_files_size_at_path(
+ std::filesystem::path path, std::string filename_pattern) const {
+ auto dir = QDir(QString::fromStdString(path.u8string()));
+ QFileInfoList fileList = dir.entryInfoList(
+ QStringList() << QString::fromStdString(filename_pattern), QDir::Files);
+ qint64 totalSize = 0;
+
+ for (const QFileInfo &fileInfo : fileList) {
+ totalSize += fileInfo.size();
+ }
+ return totalSize;
+}
+
+std::string GpgFrontend::GlobalSettingStation::get_human_readable_size(
+ int64_t size) const {
+ double num = size;
+ QStringList list;
+ list << "KB"
+ << "MB"
+ << "GB"
+ << "TB";
+
+ QStringListIterator i(list);
+ QString unit("bytes");
+
+ while (num >= 1024.0 && i.hasNext()) {
+ unit = i.next();
+ num /= 1024.0;
+ }
+ return (QString().setNum(num, 'f', 2) + " " + unit).toStdString();
+}
+
+std::string GpgFrontend::GlobalSettingStation::GetLogFilesSize() const {
+ return get_human_readable_size(
+ get_files_size_at_path(app_log_path_, "*.log"));
+}
+
+std::string GpgFrontend::GlobalSettingStation::GetDataObjectsFilesSize() const {
+ return get_human_readable_size(
+ get_files_size_at_path(app_data_objs_path_, "*"));
+}
+
+void GpgFrontend::GlobalSettingStation::ClearAllLogFiles() const {
+ delete_all_files(app_log_path_, "*.log");
+}
+
+void GpgFrontend::GlobalSettingStation::ClearAllDataObjects() const {
+ delete_all_files(app_data_objs_path_, "*");
+}
+
+void GpgFrontend::GlobalSettingStation::delete_all_files(
+ std::filesystem::path path, std::string filename_pattern) const {
+ auto dir = QDir(QString::fromStdString(path.u8string()));
+
+ // 使用name filters来只选取以.log结尾的文件
+ QStringList logFiles = dir.entryList(
+ QStringList() << QString::fromStdString(filename_pattern), QDir::Files);
+
+ // 遍历并删除所有符合条件的文件
+ for (const auto &file : logFiles) {
+ QFile::remove(dir.absoluteFilePath(file));
+ }
+}
+
GpgFrontend::GlobalSettingStation::~GlobalSettingStation() noexcept = default;
diff --git a/src/core/function/GlobalSettingStation.h b/src/core/function/GlobalSettingStation.h
index d70b3b63..80780f4b 100644
--- a/src/core/function/GlobalSettingStation.h
+++ b/src/core/function/GlobalSettingStation.h
@@ -29,6 +29,8 @@
#ifndef GPGFRONTEND_GLOBALSETTINGSTATION_H
#define GPGFRONTEND_GLOBALSETTINGSTATION_H
+#include <filesystem>
+
#include "GpgFrontendBuildInstallInfo.h"
#include "core/GpgFrontendCore.h"
#include "core/GpgFunctionObject.h"
@@ -151,6 +153,14 @@ class GPGFRONTEND_CORE_EXPORT GlobalSettingStation
return app_resource_path_ / "certs";
}
+ [[nodiscard]] std::string GetLogFilesSize() const;
+
+ [[nodiscard]] std::string GetDataObjectsFilesSize() const;
+
+ void ClearAllLogFiles() const;
+
+ void ClearAllDataObjects() const;
+
/**
* @brief sync the settings to the file
*
@@ -166,7 +176,7 @@ class GPGFRONTEND_CORE_EXPORT GlobalSettingStation
std::filesystem::path app_log_path_ =
app_data_path_ / "logs"; ///< Program Data Location
std::filesystem::path app_data_objs_path_ =
- app_data_path_ / "objs"; ///< Object storage path
+ app_data_path_ / "data_objs"; ///< Object storage path
#ifdef LINUX_INSTALL_BUILD
std::filesystem::path app_resource_path_ =
@@ -200,6 +210,26 @@ class GPGFRONTEND_CORE_EXPORT GlobalSettingStation
*
*/
void init_app_secure_key();
+
+ /**
+ * @brief
+ *
+ */
+ int64_t get_files_size_at_path(std::filesystem::path path,
+ std::string filename_pattern) const;
+
+ /**
+ * @brief
+ *
+ */
+ std::string get_human_readable_size(int64_t size) const;
+
+ /**
+ * @brief
+ *
+ */
+ void delete_all_files(std::filesystem::path path,
+ std::string filename_pattern) const;
};
} // namespace GpgFrontend
diff --git a/src/core/function/gpg/GpgKeyManager.cpp b/src/core/function/gpg/GpgKeyManager.cpp
index 050a8238..e556eec6 100644
--- a/src/core/function/gpg/GpgKeyManager.cpp
+++ b/src/core/function/gpg/GpgKeyManager.cpp
@@ -28,11 +28,14 @@
#include "GpgKeyManager.h"
+#include <boost/algorithm/string.hpp>
#include <boost/date_time/posix_time/conversion.hpp>
+#include <memory>
#include <string>
#include "GpgBasicOperator.h"
#include "GpgKeyGetter.h"
+#include "spdlog/spdlog.h"
GpgFrontend::GpgKeyManager::GpgKeyManager(int channel)
: SingletonFunctionObject<GpgKeyManager>(channel) {}
@@ -93,3 +96,152 @@ bool GpgFrontend::GpgKeyManager::SetExpire(
return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR;
}
+
+bool GpgFrontend::GpgKeyManager::SetOwnerTrustLevel(const GpgKey& key,
+ int trust_level) {
+ if (trust_level < 0 || trust_level > 5) {
+ SPDLOG_ERROR("illegal owner trust level: {}", trust_level);
+ }
+
+ AutomatonNextStateHandler next_state_handler =
+ [](AutomatonState state, std::string status, std::string args) {
+ SPDLOG_DEBUG("next_state_handler state: {}, gpg_status: {}, args: {}",
+ state, status, args);
+ std::vector<std::string> tokens;
+ boost::split(tokens, args, boost::is_any_of(" "));
+
+ switch (state) {
+ case AS_START:
+ if (status == "GET_LINE" && args == "keyedit.prompt")
+ return AS_COMMAND;
+ return AS_ERROR;
+ case AS_COMMAND:
+ if (status == "GET_LINE" && args == "edit_ownertrust.value") {
+ return AS_VALUE;
+ }
+ return AS_ERROR;
+ case AS_VALUE:
+ if (status == "GET_LINE" && args == "keyedit.prompt") {
+ return AS_QUIT;
+ } else if (status == "GET_BOOL" &&
+ args == "edit_ownertrust.set_ultimate.okay") {
+ return AS_REALLY_ULTIMATE;
+ }
+ return AS_ERROR;
+ case AS_REALLY_ULTIMATE:
+ if (status == "GET_LINE" && args == "keyedit.prompt") {
+ return AS_QUIT;
+ }
+ return AS_ERROR;
+ case AS_QUIT:
+ if (status == "GET_LINE" && args == "keyedit.save.okay") {
+ return AS_SAVE;
+ }
+ return AS_ERROR;
+ case AS_ERROR:
+ if (status == "GET_LINE" && args == "keyedit.prompt") {
+ return AS_QUIT;
+ }
+ return AS_ERROR;
+ default:
+ return AS_ERROR;
+ };
+ };
+
+ AutomatonActionHandler action_handler =
+ [trust_level](AutomatonHandelStruct& handler, AutomatonState state) {
+ SPDLOG_DEBUG("action_handler state: {}", state);
+ switch (state) {
+ case AS_COMMAND:
+ return std::string("trust");
+ case AS_VALUE:
+ handler.SetSuccess(true);
+ return std::to_string(trust_level);
+ case AS_REALLY_ULTIMATE:
+ handler.SetSuccess(true);
+ return std::string("Y");
+ case AS_QUIT:
+ return std::string("quit");
+ case AS_SAVE:
+ handler.SetSuccess(true);
+ return std::string("Y");
+ case AS_START:
+ case AS_ERROR:
+ return std::string("");
+ default:
+ return std::string("");
+ }
+ return std::string("");
+ };
+
+ auto key_fpr = key.GetFingerprint();
+ AutomatonHandelStruct handel_struct(key_fpr);
+ handel_struct.SetHandler(next_state_handler, action_handler);
+
+ GpgData data_out;
+
+ auto err = gpgme_op_interact(ctx_, gpgme_key_t(key), 0,
+ GpgKeyManager::interactor_cb_fnc,
+ (void*)&handel_struct, data_out);
+ if (err != GPG_ERR_NO_ERROR) {
+ SPDLOG_ERROR("fail to set owner trust level {} to key {}, err: {}",
+ trust_level, key.GetId(), gpgme_strerror(err));
+ }
+
+ return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR &&
+ handel_struct.Success();
+}
+
+gpgme_error_t GpgFrontend::GpgKeyManager::interactor_cb_fnc(void* handle,
+ const char* status,
+ const char* args,
+ int fd) {
+ auto handle_struct = static_cast<AutomatonHandelStruct*>(handle);
+ std::string status_s = status;
+ std::string args_s = args;
+ SPDLOG_DEBUG("cb start status: {}, args: {}, fd: {}, handle struct state: {}",
+ status_s, args_s, fd, handle_struct->CuurentStatus());
+
+ if (status_s == "KEY_CONSIDERED") {
+ std::vector<std::string> tokens;
+ boost::split(tokens, args, boost::is_any_of(" "));
+
+ if (tokens.empty() || tokens[0] != handle_struct->KeyFpr()) {
+ SPDLOG_ERROR("handle struct key fpr {} mismatch token: {}, exit...",
+ handle_struct->KeyFpr(), tokens[0]);
+ return -1;
+ }
+
+ return 0;
+ }
+
+ if (status_s == "GOT_IT" || status_s.empty()) {
+ SPDLOG_DEBUG("status GOT_IT, continue...");
+ return 0;
+ }
+
+ AutomatonState next_state = handle_struct->NextState(status_s, args_s);
+ if (next_state == AS_ERROR) {
+ SPDLOG_DEBUG("handle struct next state caught error, skipping...");
+ return GPG_ERR_FALSE;
+ }
+
+ if (next_state == AS_SAVE) {
+ handle_struct->SetSuccess(true);
+ }
+
+ // set state and preform action
+ handle_struct->SetStatus(next_state);
+ Command cmd = handle_struct->Action();
+ SPDLOG_DEBUG("handle struct action done, next state: {}, action cmd: {}",
+ next_state, cmd);
+ if (!cmd.empty()) {
+ gpgme_io_write(fd, cmd.c_str(), cmd.size());
+ gpgme_io_write(fd, "\n", 1);
+ } else if (status_s == "GET_LINE") {
+ // avoid trapping in this state
+ return GPG_ERR_FALSE;
+ }
+
+ return 0;
+} \ No newline at end of file
diff --git a/src/core/function/gpg/GpgKeyManager.h b/src/core/function/gpg/GpgKeyManager.h
index 22738594..62f7baca 100644
--- a/src/core/function/gpg/GpgKeyManager.h
+++ b/src/core/function/gpg/GpgKeyManager.h
@@ -29,6 +29,9 @@
#ifndef GPGFRONTEND_ZH_CN_TS_GPGKEYMANAGER_H
#define GPGFRONTEND_ZH_CN_TS_GPGKEYMANAGER_H
+#include <functional>
+#include <string>
+
#include "core/GpgContext.h"
#include "core/GpgFunctionObject.h"
#include "core/GpgModel.h"
@@ -83,7 +86,64 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyManager
bool SetExpire(const GpgKey& key, std::unique_ptr<GpgSubKey>& subkey,
std::unique_ptr<boost::posix_time::ptime>& expires);
+ /**
+ * @brief
+ *
+ * @return
+ */
+ bool SetOwnerTrustLevel(const GpgKey& key, int trust_level);
+
private:
+ static gpgme_error_t interactor_cb_fnc(void* handle, const char* status,
+ const char* args, int fd);
+
+ using Command = std::string;
+ using AutomatonState = enum {
+ AS_START,
+ AS_COMMAND,
+ AS_VALUE,
+ AS_REALLY_ULTIMATE,
+ AS_SAVE,
+ AS_ERROR,
+ AS_QUIT,
+ };
+
+ struct AutomatonHandelStruct;
+
+ using AutomatonActionHandler =
+ std::function<Command(AutomatonHandelStruct&, AutomatonState)>;
+ using AutomatonNextStateHandler =
+ std::function<AutomatonState(AutomatonState, std::string, std::string)>;
+
+ struct AutomatonHandelStruct {
+ void SetStatus(AutomatonState next_state) { current_state_ = next_state; }
+ AutomatonState CuurentStatus() { return current_state_; }
+ void SetHandler(AutomatonNextStateHandler next_state_handler,
+ AutomatonActionHandler action_handler) {
+ next_state_handler_ = next_state_handler;
+ action_handler_ = action_handler;
+ }
+ AutomatonState NextState(std::string gpg_status, std::string args) {
+ return next_state_handler_(current_state_, gpg_status, args);
+ }
+ Command Action() { return action_handler_(*this, current_state_); }
+
+ void SetSuccess(bool success) { success_ = success; }
+
+ bool Success() { return success_; }
+
+ std::string KeyFpr() { return key_fpr_; }
+
+ AutomatonHandelStruct(std::string key_fpr) : key_fpr_(key_fpr) {}
+
+ private:
+ AutomatonState current_state_ = AS_START;
+ AutomatonNextStateHandler next_state_handler_;
+ AutomatonActionHandler action_handler_;
+ bool success_ = false;
+ std::string key_fpr_;
+ };
+
GpgContext& ctx_ =
GpgContext::GetInstance(SingletonFunctionObject::GetChannel()); ///<
};
diff --git a/src/core/model/GpgKey.cpp b/src/core/model/GpgKey.cpp
index 4716d9cc..3a167b81 100644
--- a/src/core/model/GpgKey.cpp
+++ b/src/core/model/GpgKey.cpp
@@ -78,21 +78,39 @@ std::string GpgFrontend::GpgKey::GetProtocol() const {
std::string GpgFrontend::GpgKey::GetOwnerTrust() const {
switch (key_ref_->owner_trust) {
case GPGME_VALIDITY_UNKNOWN:
- return "Unknown";
+ return _("Unknown");
case GPGME_VALIDITY_UNDEFINED:
- return "Undefined";
+ return _("Undefined");
case GPGME_VALIDITY_NEVER:
- return "Never";
+ return _("Never");
case GPGME_VALIDITY_MARGINAL:
- return "Marginal";
+ return _("Marginal");
case GPGME_VALIDITY_FULL:
- return "FULL";
+ return _("Full");
case GPGME_VALIDITY_ULTIMATE:
- return "Ultimate";
+ return _("Ultimate");
}
return "Invalid";
}
+int GpgFrontend::GpgKey::GetOwnerTrustLevel() const {
+ switch (key_ref_->owner_trust) {
+ case GPGME_VALIDITY_UNKNOWN:
+ return 0;
+ case GPGME_VALIDITY_UNDEFINED:
+ return 1;
+ case GPGME_VALIDITY_NEVER:
+ return 2;
+ case GPGME_VALIDITY_MARGINAL:
+ return 3;
+ case GPGME_VALIDITY_FULL:
+ return 4;
+ case GPGME_VALIDITY_ULTIMATE:
+ return 5;
+ }
+ return 0;
+}
+
std::string GpgFrontend::GpgKey::GetPublicKeyAlgo() const {
return gpgme_pubkey_algo_name(key_ref_->subkeys->pubkey_algo);
}
diff --git a/src/core/model/GpgKey.h b/src/core/model/GpgKey.h
index 8c24ca5d..fb87b791 100644
--- a/src/core/model/GpgKey.h
+++ b/src/core/model/GpgKey.h
@@ -102,6 +102,13 @@ class GPGFRONTEND_CORE_EXPORT GpgKey {
/**
* @brief
*
+ * @return int
+ */
+ [[nodiscard]] int GetOwnerTrustLevel() const;
+
+ /**
+ * @brief
+ *
* @return std::string
*/
[[nodiscard]] std::string GetPublicKeyAlgo() const;
diff --git a/src/ui/SignalStation.h b/src/ui/SignalStation.h
index 5037ef4f..17e866f5 100644
--- a/src/ui/SignalStation.h
+++ b/src/ui/SignalStation.h
@@ -66,6 +66,12 @@ class SignalStation : public QObject {
/**
* @brief
*
+ */
+ void SignalUIRefresh();
+
+ /**
+ * @brief
+ *
* @param text
* @param verify_label_status
*/
diff --git a/src/ui/UserInterfaceUtils.cpp b/src/ui/UserInterfaceUtils.cpp
index 80b6f482..7e236c02 100644
--- a/src/ui/UserInterfaceUtils.cpp
+++ b/src/ui/UserInterfaceUtils.cpp
@@ -34,6 +34,7 @@
#include "core/GpgConstants.h"
#include "core/common/CoreCommonUtil.h"
+#include "core/function/CacheManager.h"
#include "core/function/CoreSignalStation.h"
#include "core/function/FileOperator.h"
#include "core/function/GlobalSettingStation.h"
@@ -189,7 +190,7 @@ CommonUtils::CommonUtils() : QWidget(nullptr) {
msgBox.setText(_("GnuPG Context Loading Failed"));
msgBox.setInformativeText(
_("Gnupg(gpg) is not installed correctly, please follow "
- "<a href='https://www.gpgfrontend.pub/#/"
+ "<a href='https://www.gpgfrontend.bktus.com/#/"
"faq?id=how-to-deal-with-39env-loading-failed39'>this notes</a>"
" in FAQ to install Gnupg and then open "
"GpgFrontend. Or, you can open GnuPG Controller to set a custom "
@@ -481,4 +482,41 @@ bool CommonUtils::isApplicationNeedRestart() {
return application_need_to_restart_at_once_;
}
+bool CommonUtils::KeyExistsinFavouriteList(const GpgKey &key) {
+ // load cache
+ auto key_array = CacheManager::GetInstance().LoadCache("favourite_key_pair");
+ if (!key_array.is_array()) {
+ CacheManager::GetInstance().SaveCache("favourite_key_pair",
+ nlohmann::json::array());
+ }
+ return std::find(key_array.begin(), key_array.end(), key.GetFingerprint()) !=
+ key_array.end();
+}
+
+void CommonUtils::AddKey2Favourtie(const GpgKey &key) {
+ auto key_array = CacheManager::GetInstance().LoadCache("favourite_key_pair");
+ if (!key_array.is_array()) {
+ CacheManager::GetInstance().SaveCache("favourite_key_pair",
+ nlohmann::json::array());
+ }
+ key_array.push_back(key.GetFingerprint());
+ CacheManager::GetInstance().SaveCache("favourite_key_pair", key_array, true);
+}
+
+void CommonUtils::RemoveKeyFromFavourite(const GpgKey &key) {
+ auto key_array = CacheManager::GetInstance().LoadCache("favourite_key_pair");
+ if (!key_array.is_array()) {
+ CacheManager::GetInstance().SaveCache("favourite_key_pair",
+ nlohmann::json::array(), true);
+ return;
+ }
+ auto it = std::find(key_array.begin(), key_array.end(), key.GetFingerprint());
+ if (it != key_array.end()) {
+ auto rm_it =
+ std::remove(key_array.begin(), key_array.end(), key.GetFingerprint());
+ key_array.erase(rm_it, key_array.end());
+ CacheManager::GetInstance().SaveCache("favourite_key_pair", key_array);
+ }
+}
+
} // namespace GpgFrontend::UI \ No newline at end of file
diff --git a/src/ui/UserInterfaceUtils.h b/src/ui/UserInterfaceUtils.h
index 7dd7bb1e..59c803b9 100644
--- a/src/ui/UserInterfaceUtils.h
+++ b/src/ui/UserInterfaceUtils.h
@@ -31,6 +31,7 @@
#include "core/GpgModel.h"
#include "core/function/result_analyse/GpgVerifyResultAnalyse.h"
+#include "core/model/GpgKey.h"
#include "ui/GpgFrontendUI.h"
namespace GpgFrontend {
@@ -150,6 +151,24 @@ class CommonUtils : public QWidget {
*/
bool isApplicationNeedRestart();
+ /**
+ * @brief
+ *
+ */
+ bool KeyExistsinFavouriteList(const GpgKey& key);
+
+ /**
+ * @brief
+ *
+ */
+ void AddKey2Favourtie(const GpgKey& key);
+
+ /**
+ * @brief
+ *
+ */
+ void RemoveKeyFromFavourite(const GpgKey& key);
+
signals:
/**
* @brief
diff --git a/src/ui/dialog/SignersPicker.cpp b/src/ui/dialog/SignersPicker.cpp
index a670e514..8969618e 100644
--- a/src/ui/dialog/SignersPicker.cpp
+++ b/src/ui/dialog/SignersPicker.cpp
@@ -36,18 +36,17 @@ SignersPicker::SignersPicker(QWidget* parent)
auto confirm_button = new QPushButton(_("Confirm"));
auto cancel_button = new QPushButton(_("Cancel"));
- connect(confirm_button, &QPushButton::clicked, [=]() {
- this->accepted_ = true;
- });
+ connect(confirm_button, &QPushButton::clicked,
+ [=]() { this->accepted_ = true; });
connect(confirm_button, &QPushButton::clicked, this, &QDialog::accept);
connect(cancel_button, &QPushButton::clicked, this, &QDialog::reject);
/*Setup KeyList*/
key_list_ = new KeyList(false, this);
key_list_->AddListGroupTab(
- _("Signers"), KeyListRow::ONLY_SECRET_KEY,
+ _("Signers"), "signers", KeyListRow::ONLY_SECRET_KEY,
KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage,
- [](const GpgKey& key) -> bool {
+ [](const GpgKey& key, const KeyTable&) -> bool {
return key.IsHasActualSigningCapability();
});
key_list_->SlotRefresh();
diff --git a/src/ui/dialog/Wizard.cpp b/src/ui/dialog/Wizard.cpp
index 5235a5dd..77f07559 100644
--- a/src/ui/dialog/Wizard.cpp
+++ b/src/ui/dialog/Wizard.cpp
@@ -83,11 +83,11 @@ IntroPage::IntroPage(QWidget* parent) : QWizardPage(parent) {
auto* topLabel = new QLabel(
QString(_("Welcome to use GpgFrontend for decrypting and signing text or "
"file!")) +
- " <br><br><a href='https://gpgfrontend.pub'>GpgFrontend</a> " +
+ " <br><br><a href='https://gpgfrontend.bktus.com'>GpgFrontend</a> " +
_("is a Powerful, Easy-to-Use, Compact, Cross-Platform, and "
"Installation-Free OpenPGP Crypto Tool.") +
_("For brief information have a look at the") +
- " <a href='https://gpgfrontend.pub/index.html#/overview'>" +
+ " <a href='https://gpgfrontend.bktus.com/index.html#/overview'>" +
_("Overview") + "</a> (" +
_("by clicking the link, the page will open in the web browser") +
"). <br>");
@@ -124,7 +124,9 @@ ChoosePage::ChoosePage(QWidget* parent) : QWizardPage(parent) {
"If you have never used GpgFrontend before and also don't own a gpg "
"key yet you "
"may possibly want to read how to")) +
- " <a href=\"https://gpgfrontend.pub/index.html#/manual/generate-key\">" +
+ " <a "
+ "href=\"https://gpgfrontend.bktus.com/index.html#/manual/"
+ "generate-key\">" +
_("Generate Key") + "</a><hr>");
keygenLabel->setTextFormat(Qt::RichText);
keygenLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
@@ -136,11 +138,12 @@ ChoosePage::ChoosePage(QWidget* parent) : QWizardPage(parent) {
"If you want to learn how to encrypt, decrypt, sign and verify text, "
"you can read ")) +
"<a "
- "href=\"https://gpgfrontend.pub/index.html#/manual/"
+ "href=\"https://gpgfrontend.bktus.com/index.html#/manual/"
"encrypt-decrypt-text\">" +
_("Encrypt & Decrypt Text") + "</a> " + _("or") +
" <a "
- "href=\"https://gpgfrontend.pub/index.html#/manual/sign-verify-text\">" +
+ "href=\"https://gpgfrontend.bktus.com/index.html#/manual/"
+ "sign-verify-text\">" +
_("Sign & Verify Text") + "</a><hr>");
encrDecyTextLabel->setTextFormat(Qt::RichText);
@@ -148,15 +151,16 @@ ChoosePage::ChoosePage(QWidget* parent) : QWizardPage(parent) {
encrDecyTextLabel->setOpenExternalLinks(true);
encrDecyTextLabel->setWordWrap(true);
- auto* signVerifyTextLabel = new QLabel(
- QString(_("If you want to operate file, you can read ")) +
- "<a "
- "href=\"https://gpgfrontend.pub/index.html#/manual/"
- "encrypt-decrypt-file\">" +
- _("Encrypt & Sign File") + "</a> " + _("or") +
- " <a "
- "href=\"https://gpgfrontend.pub/index.html#/manual/sign-verify-file\">" +
- _("Sign & Verify File") + "</a><hr>");
+ auto* signVerifyTextLabel =
+ new QLabel(QString(_("If you want to operate file, you can read ")) +
+ "<a "
+ "href=\"https://gpgfrontend.bktus.com/index.html#/manual/"
+ "encrypt-decrypt-file\">" +
+ _("Encrypt & Sign File") + "</a> " + _("or") +
+ " <a "
+ "href=\"https://gpgfrontend.bktus.com/index.html#/manual/"
+ "sign-verify-file\">" +
+ _("Sign & Verify File") + "</a><hr>");
signVerifyTextLabel->setTextFormat(Qt::RichText);
signVerifyTextLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
signVerifyTextLabel->setOpenExternalLinks(true);
diff --git a/src/ui/dialog/help/AboutDialog.cpp b/src/ui/dialog/help/AboutDialog.cpp
index faf2b316..111a77af 100644
--- a/src/ui/dialog/help/AboutDialog.cpp
+++ b/src/ui/dialog/help/AboutDialog.cpp
@@ -231,7 +231,7 @@ void UpdateTab::slot_show_version_status(const SoftwareVersion& version) {
"github.")) +
"</center><center>" + _("Please click") +
" <a "
- "href=\"https://www.gpgfrontend.pub/#/downloads\">" +
+ "href=\"https://www.gpgfrontend.bktus.com/#/downloads\">" +
_("Here") + "</a> " + _("to download the latest stable version.") +
"</center>");
upgrade_label_->show();
@@ -254,7 +254,7 @@ void UpdateTab::slot_show_version_status(const SoftwareVersion& version) {
"stability, please do not use this version.")) +
"</center><center>" + _("Please click") +
" <a "
- "href=\"https://www.gpgfrontend.pub/#/downloads\">" +
+ "href=\"https://www.gpgfrontend.bktus.com/#/downloads\">" +
_("Here") + "</a> " + _("to download the latest stable version.") +
"</center>");
upgrade_label_->show();
diff --git a/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp b/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp
index 2785603b..578e3279 100644
--- a/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp
+++ b/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp
@@ -56,6 +56,7 @@ KeyPairDetailTab::KeyPairDetailTab(const std::string& key_id, QWidget* parent)
usage_var_label_ = new QLabel();
actual_usage_var_label_ = new QLabel();
+ owner_trust_var_label_ = new QLabel();
key_size_var_label_ = new QLabel();
expire_var_label_ = new QLabel();
created_var_label_ = new QLabel();
@@ -79,13 +80,14 @@ KeyPairDetailTab::KeyPairDetailTab(const std::string& key_id, QWidget* parent)
vboxKD->addWidget(new QLabel(QString(_("Key Size")) + ": "), 2, 0);
vboxKD->addWidget(new QLabel(QString(_("Nominal Usage")) + ": "), 3, 0);
vboxKD->addWidget(new QLabel(QString(_("Actual Usage")) + ": "), 4, 0);
+ vboxKD->addWidget(new QLabel(QString(_("Owner Trust Level")) + ": "), 5, 0);
vboxKD->addWidget(new QLabel(QString(_("Create Date (Local Time)")) + ": "),
- 5, 0);
- vboxKD->addWidget(new QLabel(QString(_("Expires on (Local Time)")) + ": "), 6,
+ 6, 0);
+ vboxKD->addWidget(new QLabel(QString(_("Expires on (Local Time)")) + ": "), 7,
0);
vboxKD->addWidget(new QLabel(QString(_("Last Update (Local Time)")) + ": "),
- 7, 0);
- vboxKD->addWidget(new QLabel(QString(_("Primary Key Existence")) + ": "), 8,
+ 8, 0);
+ vboxKD->addWidget(new QLabel(QString(_("Primary Key Existence")) + ": "), 9,
0);
key_id_var_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
@@ -94,10 +96,11 @@ KeyPairDetailTab::KeyPairDetailTab(const std::string& key_id, QWidget* parent)
vboxKD->addWidget(key_size_var_label_, 2, 1, 1, 2);
vboxKD->addWidget(usage_var_label_, 3, 1, 1, 2);
vboxKD->addWidget(actual_usage_var_label_, 4, 1, 1, 2);
- vboxKD->addWidget(created_var_label_, 5, 1, 1, 2);
- vboxKD->addWidget(expire_var_label_, 6, 1, 1, 2);
- vboxKD->addWidget(last_update_var_label_, 7, 1, 1, 2);
- vboxKD->addWidget(primary_key_exist_var_label_, 8, 1, 1, 2);
+ vboxKD->addWidget(owner_trust_var_label_, 5, 1, 1, 2);
+ vboxKD->addWidget(created_var_label_, 6, 1, 1, 2);
+ vboxKD->addWidget(expire_var_label_, 7, 1, 1, 2);
+ vboxKD->addWidget(last_update_var_label_, 8, 1, 1, 2);
+ vboxKD->addWidget(primary_key_exist_var_label_, 9, 1, 1, 2);
auto* copyKeyIdButton = new QPushButton(_("Copy"));
copyKeyIdButton->setFlat(true);
@@ -222,7 +225,9 @@ void KeyPairDetailTab::slot_refresh_key_info() {
if (key_.IsHasActualAuthenticationCapability())
actual_usage_steam << _("Auth") << " ";
- actual_usage_var_label_->setText(actual_usage_steam.str().c_str());
+ actual_usage_var_label_->setText(
+ QString::fromStdString(actual_usage_steam.str()));
+ owner_trust_var_label_->setText(QString::fromStdString(key_.GetOwnerTrust()));
std::string key_size_val, key_expire_val, key_create_time_val, key_algo_val,
key_last_update_val;
diff --git a/src/ui/dialog/keypair_details/KeyPairDetailTab.h b/src/ui/dialog/keypair_details/KeyPairDetailTab.h
index 91ccdab8..efa3269c 100644
--- a/src/ui/dialog/keypair_details/KeyPairDetailTab.h
+++ b/src/ui/dialog/keypair_details/KeyPairDetailTab.h
@@ -79,6 +79,7 @@ class KeyPairDetailTab : public QWidget {
QLabel* usage_var_label_;
QLabel* actual_usage_var_label_;
QLabel* primary_key_exist_var_label_;
+ QLabel* owner_trust_var_label_;
QLabel* icon_label_; ///<
QLabel* exp_label_; ///<
diff --git a/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp b/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp
index 9be77923..13c857a0 100644
--- a/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp
+++ b/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp
@@ -29,6 +29,7 @@
#include "KeySetExpireDateDialog.h"
#include "core/function/GlobalSettingStation.h"
#include "core/function/gpg/GpgKeyImportExporter.h"
+#include "core/function/gpg/GpgKeyManager.h"
#include "core/function/gpg/GpgKeyOpera.h"
#include "ui/SignalStation.h"
#include "ui/UserInterfaceUtils.h"
@@ -105,13 +106,25 @@ KeyPairOperaTab::KeyPairOperaTab(const std::string& key_id, QWidget* parent)
connect(modify_tofu_button, &QPushButton::clicked, this,
&KeyPairOperaTab::slot_modify_tofu_policy);
+ auto* set_owner_trust_level_button =
+ new QPushButton(_("Set Owner Trust Level"));
+ connect(set_owner_trust_level_button, &QPushButton::clicked, this,
+ &KeyPairOperaTab::slot_set_owner_trust_level);
+
vbox_p_k->addLayout(advance_h_box_layout);
opera_key_box->setLayout(vbox_p_k);
m_vbox->addWidget(opera_key_box);
+ // modify owner trust of public key
+ if (!m_key_.IsPrivateKey()) vbox_p_k->addWidget(set_owner_trust_level_button);
vbox_p_k->addWidget(modify_tofu_button);
m_vbox->addStretch(0);
setLayout(m_vbox);
+
+ // set up signal
+ connect(this, &KeyPairOperaTab::SignalKeyDatabaseRefresh,
+ SignalStation::GetInstance(),
+ &SignalStation::SignalKeyDatabaseRefresh);
}
void KeyPairOperaTab::CreateOperaMenu() {
@@ -389,4 +402,51 @@ void KeyPairOperaTab::slot_modify_tofu_policy() {
}
}
+void KeyPairOperaTab::slot_set_owner_trust_level() {
+ QStringList items;
+
+ items << _("Unknown") << _("Undefined") << _("Never") << _("Marginal")
+ << _("Full") << _("Ultimate");
+ bool ok;
+ QString item = QInputDialog::getItem(this, _("Modify Owner Trust Level"),
+ _("Trust for the Key Pair:"), items,
+ m_key_.GetOwnerTrustLevel(), false, &ok);
+
+ if (ok && !item.isEmpty()) {
+ SPDLOG_DEBUG("selected policy: {}", item.toStdString());
+ int trust_level = 0; // Unknown Level
+ if (item == _("Ultimate")) {
+ trust_level = 5;
+ } else if (item == _("Full")) {
+ trust_level = 4;
+ } else if (item == _("Marginal")) {
+ trust_level = 3;
+ } else if (item == _("Never")) {
+ trust_level = 2;
+ } else if (item == _("Undefined")) {
+ trust_level = 1;
+ }
+
+ if (trust_level == 0) {
+ QMessageBox::warning(
+ this, _("Warning"),
+ QString(_("Owner Trust Level cannot set to Unknown level, automately "
+ "changing it into Undefined level.")));
+ trust_level = 1;
+ }
+
+ bool status =
+ GpgKeyManager::GetInstance().SetOwnerTrustLevel(m_key_, trust_level);
+ if (!status) {
+ QMessageBox::critical(this, _("Failed"),
+ QString(_("Modify Owner Trust Level failed.")));
+ } else {
+ QMessageBox::information(this, _("Success"),
+ QString(_("Set Owner Trust Level successful.")));
+ // update key database and refresh ui
+ emit SignalKeyDatabaseRefresh();
+ }
+ }
+}
+
} // namespace GpgFrontend::UI
diff --git a/src/ui/dialog/keypair_details/KeyPairOperaTab.h b/src/ui/dialog/keypair_details/KeyPairOperaTab.h
index af6b1eee..0c4a7916 100644
--- a/src/ui/dialog/keypair_details/KeyPairOperaTab.h
+++ b/src/ui/dialog/keypair_details/KeyPairOperaTab.h
@@ -48,6 +48,13 @@ class KeyPairOperaTab : public QWidget {
*/
void CreateOperaMenu();
+ signals:
+ /**
+ * @brief
+ *
+ */
+ void SignalKeyDatabaseRefresh();
+
private slots:
/**
@@ -103,6 +110,12 @@ class KeyPairOperaTab : public QWidget {
*/
void slot_modify_tofu_policy();
+ /**
+ * @brief
+ *
+ */
+ void slot_set_owner_trust_level();
+
private:
GpgKey m_key_; ///<
QMenu* key_server_opera_menu_{}; ///<
diff --git a/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp b/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp
index ca83dbfd..12da3284 100644
--- a/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp
+++ b/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp
@@ -40,9 +40,9 @@ KeyUIDSignDialog::KeyUIDSignDialog(const GpgKey& key, UIDArgsListPtr uid,
const auto key_id = m_key_.GetId();
m_key_list_ = new KeyList(KeyMenuAbility::NONE, this);
m_key_list_->AddListGroupTab(
- _("Signers"), KeyListRow::ONLY_SECRET_KEY,
+ _("Signers"), "signers", KeyListRow::ONLY_SECRET_KEY,
KeyListColumn::NAME | KeyListColumn::EmailAddress,
- [key_id](const GpgKey& key) -> bool {
+ [key_id](const GpgKey& key, const KeyTable&) -> bool {
if (key.IsDisabled() || !key.IsHasCertificationCapability() ||
!key.IsHasMasterKey() || key.IsExpired() || key.IsRevoked() ||
key_id == key.GetId())
diff --git a/src/ui/dialog/settings/SettingsGeneral.cpp b/src/ui/dialog/settings/SettingsGeneral.cpp
index c967b8fd..be5190dd 100644
--- a/src/ui/dialog/settings/SettingsGeneral.cpp
+++ b/src/ui/dialog/settings/SettingsGeneral.cpp
@@ -48,6 +48,9 @@ GeneralTab::GeneralTab(QWidget* parent)
_("Save checked private keys on exit and restore them on next start."));
ui_->clearGpgPasswordCacheCheckBox->setText(
_("Clear gpg password cache when closing GpgFrontend."));
+ ui_->restoreTextEditorPageCheckBox->setText(
+ _("Automatically restore unsaved Text Editor pages after an application "
+ "crash."));
ui_->importConfirmationBox->setTitle(_("Operation"));
ui_->longerKeyExpirationDateCheckBox->setText(
@@ -60,6 +63,16 @@ GeneralTab::GeneralTab(QWidget* parent)
"<b>" + QString(_("NOTE")) + _(": ") + "</b>" +
_("GpgFrontend will restart automatically if you change the language!"));
+ ui_->dataBox->setTitle(_("Data"));
+ ui_->clearAllLogFilesButton->setText(QString::fromStdString(
+ (boost::format(_("Clear All Log (Total Size: %s)")) %
+ GlobalSettingStation::GetInstance().GetLogFilesSize())
+ .str()));
+ ui_->clearAllDataObjectsButton->setText(QString::fromStdString(
+ (boost::format(_("Clear All Data Objects (Total Size: %s)")) %
+ GlobalSettingStation::GetInstance().GetDataObjectsFilesSize())
+ .str()));
+
#ifdef MULTI_LANG_SUPPORT
lang_ = SettingsDialog::ListLanguages();
for (const auto& l : lang_) {
@@ -69,6 +82,31 @@ GeneralTab::GeneralTab(QWidget* parent)
this, &GeneralTab::slot_language_changed);
#endif
+ connect(ui_->clearAllLogFilesButton, &QPushButton::clicked, this, [=]() {
+ GlobalSettingStation::GetInstance().ClearAllLogFiles();
+ ui_->clearAllLogFilesButton->setText(QString::fromStdString(
+ (boost::format(_("Clear All Log (Total Size: %s)")) %
+ GlobalSettingStation::GetInstance().GetLogFilesSize())
+ .str()));
+ });
+
+ connect(ui_->clearAllDataObjectsButton, &QPushButton::clicked, this, [=]() {
+ QMessageBox::StandardButton reply;
+ reply = QMessageBox::question(
+ this, _("Confirm"),
+ _("Are you sure you want to clear all data objects?\nThis will result "
+ "in "
+ "loss of all cached form positions, statuses, key servers, etc."),
+ QMessageBox::Yes | QMessageBox::No);
+ if (reply == QMessageBox::Yes) {
+ GlobalSettingStation::GetInstance().ClearAllDataObjects();
+ ui_->clearAllDataObjectsButton->setText(QString::fromStdString(
+ (boost::format(_("Clear All Data Objects (Total Size: %s)")) %
+ GlobalSettingStation::GetInstance().GetDataObjectsFilesSize())
+ .str()));
+ }
+ });
+
SetSettings();
}
@@ -98,6 +136,15 @@ void GeneralTab::SetSettings() {
}
try {
+ bool restore_text_editor_page =
+ settings.lookup("general.restore_text_editor_page");
+ if (restore_text_editor_page)
+ ui_->restoreTextEditorPageCheckBox->setCheckState(Qt::Checked);
+ } catch (...) {
+ SPDLOG_ERROR("setting operation error: restore_text_editor_page");
+ }
+
+ try {
bool longer_expiration_date =
settings.lookup("general.longer_expiration_date");
SPDLOG_DEBUG("longer_expiration_date: {}", longer_expiration_date);
@@ -170,6 +217,14 @@ void GeneralTab::ApplySettings() {
ui_->saveCheckedKeysCheckBox->isChecked();
}
+ if (!general.exists("restore_text_editor_page"))
+ general.add("restore_text_editor_page", libconfig::Setting::TypeBoolean) =
+ ui_->restoreTextEditorPageCheckBox->isChecked();
+ else {
+ general["restore_text_editor_page"] =
+ ui_->restoreTextEditorPageCheckBox->isChecked();
+ }
+
#ifdef MULTI_LANG_SUPPORT
if (!general.exists("lang"))
general.add("lang", libconfig::Setting::TypeBoolean) =
diff --git a/src/ui/main_window/GeneralMainWindow.cpp b/src/ui/main_window/GeneralMainWindow.cpp
index 66255a08..0acedec6 100644
--- a/src/ui/main_window/GeneralMainWindow.cpp
+++ b/src/ui/main_window/GeneralMainWindow.cpp
@@ -41,7 +41,9 @@ GpgFrontend::UI::GeneralMainWindow::GeneralMainWindow(std::string name,
GpgFrontend::UI::GeneralMainWindow::~GeneralMainWindow() = default;
void GpgFrontend::UI::GeneralMainWindow::closeEvent(QCloseEvent *event) {
+ SPDLOG_DEBUG("main window close event caught, event type: {}", event->type());
slot_save_settings();
+
QMainWindow::closeEvent(event);
}
@@ -51,6 +53,7 @@ void GpgFrontend::UI::GeneralMainWindow::slot_restore_settings() noexcept {
std::string window_state = general_windows_state.Check(
"window_state", saveState().toBase64().toStdString());
+ SPDLOG_DEBUG("restore main window state: {}", window_state);
// state sets pos & size of dock-widgets
this->restoreState(
@@ -133,6 +136,7 @@ void GpgFrontend::UI::GeneralMainWindow::slot_restore_settings() noexcept {
void GpgFrontend::UI::GeneralMainWindow::slot_save_settings() noexcept {
try {
+ SPDLOG_DEBUG("save main window state, name: {}", name_);
SettingsObject general_windows_state(name_ + "_state");
// window position and size
diff --git a/src/ui/main_window/KeyMgmt.cpp b/src/ui/main_window/KeyMgmt.cpp
index 758a7af1..47b0dcb0 100644
--- a/src/ui/main_window/KeyMgmt.cpp
+++ b/src/ui/main_window/KeyMgmt.cpp
@@ -48,46 +48,50 @@ KeyMgmt::KeyMgmt(QWidget* parent)
/* the list of Keys available*/
key_list_ = new KeyList(KeyMenuAbility::ALL, this);
- key_list_->AddListGroupTab(_("All"), KeyListRow::SECRET_OR_PUBLIC_KEY);
+ key_list_->AddListGroupTab(_("All"), "all", KeyListRow::SECRET_OR_PUBLIC_KEY);
key_list_->AddListGroupTab(
- _("Only Public Key"), KeyListRow::SECRET_OR_PUBLIC_KEY,
+ _("Only Public Key"), "only_public_key", KeyListRow::SECRET_OR_PUBLIC_KEY,
KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress |
KeyListColumn::Usage | KeyListColumn::Validity,
- [](const GpgKey& key) -> bool {
+ [](const GpgKey& key, const KeyTable&) -> bool {
return !key.IsPrivateKey() &&
!(key.IsRevoked() || key.IsDisabled() || key.IsExpired());
});
key_list_->AddListGroupTab(
- _("Has Private Key"), KeyListRow::SECRET_OR_PUBLIC_KEY,
+ _("Has Private Key"), "has_private_key", KeyListRow::SECRET_OR_PUBLIC_KEY,
KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress |
KeyListColumn::Usage | KeyListColumn::Validity,
- [](const GpgKey& key) -> bool {
+ [](const GpgKey& key, const KeyTable&) -> bool {
return key.IsPrivateKey() &&
!(key.IsRevoked() || key.IsDisabled() || key.IsExpired());
});
key_list_->AddListGroupTab(
- _("No Primary Key"), KeyListRow::SECRET_OR_PUBLIC_KEY,
+ _("No Primary Key"), "no_primary_key", KeyListRow::SECRET_OR_PUBLIC_KEY,
KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress |
KeyListColumn::Usage | KeyListColumn::Validity,
- [](const GpgKey& key) -> bool {
+ [](const GpgKey& key, const KeyTable&) -> bool {
return !key.IsHasMasterKey() &&
!(key.IsRevoked() || key.IsDisabled() || key.IsExpired());
});
key_list_->AddListGroupTab(
- _("Revoked"), KeyListRow::SECRET_OR_PUBLIC_KEY,
+ _("Revoked"), "revoked", KeyListRow::SECRET_OR_PUBLIC_KEY,
KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress |
KeyListColumn::Usage | KeyListColumn::Validity,
- [](const GpgKey& key) -> bool { return key.IsRevoked(); });
+ [](const GpgKey& key, const KeyTable&) -> bool {
+ return key.IsRevoked();
+ });
key_list_->AddListGroupTab(
- _("Expired"), KeyListRow::SECRET_OR_PUBLIC_KEY,
+ _("Expired"), "expired", KeyListRow::SECRET_OR_PUBLIC_KEY,
KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress |
KeyListColumn::Usage | KeyListColumn::Validity,
- [](const GpgKey& key) -> bool { return key.IsExpired(); });
+ [](const GpgKey& key, const KeyTable&) -> bool {
+ return key.IsExpired();
+ });
setCentralWidget(key_list_);
key_list_->SetDoubleClickedAction([this](const GpgKey& key, QWidget* parent) {
diff --git a/src/ui/main_window/MainWindow.cpp b/src/ui/main_window/MainWindow.cpp
index 9e02c095..b07ad309 100644
--- a/src/ui/main_window/MainWindow.cpp
+++ b/src/ui/main_window/MainWindow.cpp
@@ -29,12 +29,17 @@
#include "MainWindow.h"
#include "core/GpgConstants.h"
+#include "core/function/CacheManager.h"
#include "core/function/GlobalSettingStation.h"
#include "core/function/gpg/GpgAdvancedOperator.h"
+#include "main_window/GeneralMainWindow.h"
+#include "nlohmann/json_fwd.hpp"
+#include "spdlog/spdlog.h"
#include "ui/SignalStation.h"
#include "ui/UserInterfaceUtils.h"
#include "ui/struct/SettingsObject.h"
#include "ui/thread/VersionCheckTask.h"
+#include "widgets/KeyList.h"
namespace GpgFrontend::UI {
@@ -53,8 +58,10 @@ void MainWindow::Init() noexcept {
setCentralWidget(edit_);
/* the list of Keys available*/
- m_key_list_ = new KeyList(
- KeyMenuAbility::REFRESH | KeyMenuAbility::UNCHECK_ALL, this);
+ m_key_list_ =
+ new KeyList(KeyMenuAbility::REFRESH | KeyMenuAbility::UNCHECK_ALL |
+ KeyMenuAbility::SEARCH_BAR,
+ this);
info_board_ = new InfoBoardWidget(this);
@@ -80,6 +87,12 @@ void MainWindow::Init() noexcept {
SignalStation::GetInstance(),
&SignalStation::SignalRestartApplication);
+ connect(this, &MainWindow::SignalUIRefresh, SignalStation::GetInstance(),
+ &SignalStation::SignalUIRefresh);
+ connect(this, &MainWindow::SignalKeyDatabaseRefresh,
+ SignalStation::GetInstance(),
+ &SignalStation::SignalKeyDatabaseRefresh);
+
connect(edit_->tab_widget_, &QTabWidget::currentChanged, this,
&MainWindow::slot_disable_tab_actions);
connect(SignalStation::GetInstance(),
@@ -96,6 +109,10 @@ void MainWindow::Init() noexcept {
m_key_list_->AddMenuAction(copy_mail_address_to_clipboard_act_);
m_key_list_->AddMenuAction(copy_key_default_uid_to_clipboard_act_);
m_key_list_->AddMenuAction(copy_key_id_to_clipboard_act_);
+ m_key_list_->AddMenuAction(set_owner_trust_of_key_act_);
+ m_key_list_->AddMenuAction(add_key_2_favourtie_act_);
+ m_key_list_->AddMenuAction(remove_key_from_favourtie_act_);
+
m_key_list_->AddSeparator();
m_key_list_->AddMenuAction(show_key_details_act_);
@@ -155,6 +172,9 @@ void MainWindow::Init() noexcept {
}
});
+ // recover unsaved page from cache if it exists
+ recover_editor_unsaved_pages_from_cache();
+
} catch (...) {
SPDLOG_ERROR(_("Critical error occur while loading GpgFrontend."));
QMessageBox::critical(nullptr, _("Loading Failed"),
@@ -235,6 +255,40 @@ void MainWindow::restore_settings() {
SPDLOG_DEBUG("settings restored");
}
+void MainWindow::recover_editor_unsaved_pages_from_cache() {
+ auto unsaved_page_array =
+ CacheManager::GetInstance().LoadCache("editor_unsaved_pages");
+
+ if (!unsaved_page_array.is_array() || unsaved_page_array.empty()) {
+ return;
+ }
+
+ SPDLOG_DEBUG("plan ot recover unsaved page from cache, page array: {}",
+ unsaved_page_array.dump());
+
+ bool first = true;
+
+ for (auto &unsaved_page_json : unsaved_page_array) {
+ if (!unsaved_page_json.contains("title") ||
+ !unsaved_page_json.contains("content")) {
+ continue;
+ }
+ std::string title = unsaved_page_json["title"];
+ std::string content = unsaved_page_json["content"];
+
+ SPDLOG_DEBUG(
+ "recovering unsaved page from cache, page title: {}, content size",
+ title, content.size());
+
+ if (first) {
+ edit_->SlotCloseTab();
+ first = false;
+ }
+
+ edit_->SlotNewTabWithContent(title, content);
+ }
+}
+
void MainWindow::save_settings() {
bool save_key_checked = GlobalSettingStation::GetInstance().LookupSettings(
"general.save_key_checked", false);
@@ -277,8 +331,17 @@ void MainWindow::closeEvent(QCloseEvent *event) {
event->ignore();
}
- // clear password from memory
- // GpgContext::GetInstance().clearPasswordCache();
+ if (event->isAccepted()) {
+ // clear cache of unsaved page
+ CacheManager::GetInstance().SaveCache("editor_unsaved_pages",
+ nlohmann::json::array(), true);
+
+ // clear password from memory
+ // GpgContext::GetInstance().clearPasswordCache();
+
+ // call parent
+ GeneralMainWindow::closeEvent(event);
+ }
}
} // namespace GpgFrontend::UI
diff --git a/src/ui/main_window/MainWindow.h b/src/ui/main_window/MainWindow.h
index 8f0b2e4d..42f9daf3 100644
--- a/src/ui/main_window/MainWindow.h
+++ b/src/ui/main_window/MainWindow.h
@@ -97,6 +97,16 @@ class MainWindow : public GeneralMainWindow {
*/
void SignalRestartApplication(int);
+ /**
+ * @brief
+ */
+ void SignalUIRefresh();
+
+ /**
+ * @brief
+ */
+ void SignalKeyDatabaseRefresh();
+
public slots:
/**
@@ -307,6 +317,21 @@ class MainWindow : public GeneralMainWindow {
*/
void slot_version_upgrade(const SoftwareVersion& version);
+ /**
+ * @details
+ */
+ void slot_add_key_2_favourite();
+
+ /**
+ * @details
+ */
+ void slot_remove_key_from_favourite();
+
+ /**
+ * @details
+ */
+ void slot_set_owner_trust_level_of_key();
+
private:
/**
* @details Create actions for the main-menu and the context-menu of the
@@ -350,6 +375,11 @@ class MainWindow : public GeneralMainWindow {
void restore_settings();
/**
+ * @details
+ */
+ void recover_editor_unsaved_pages_from_cache();
+
+ /**
* @details Save settings to ini-file.
*/
void save_settings();
@@ -421,6 +451,10 @@ class MainWindow : public GeneralMainWindow {
QAction* copy_key_id_to_clipboard_act_{}; ///<
QAction* copy_key_default_uid_to_clipboard_act_{}; ///<
+ QAction* add_key_2_favourtie_act_{}; ///<
+ QAction* remove_key_from_favourtie_act_{}; ///<
+ QAction* set_owner_trust_of_key_act_{}; ///<
+
QAction* open_key_management_act_{}; ///< Action to open key management
QAction* copy_act_{}; ///< Action to copy text
QAction* quote_act_{}; ///< Action to quote text
diff --git a/src/ui/main_window/MainWindowSlotFunction.cpp b/src/ui/main_window/MainWindowSlotFunction.cpp
index 841c8680..1adf2d4e 100644
--- a/src/ui/main_window/MainWindowSlotFunction.cpp
+++ b/src/ui/main_window/MainWindowSlotFunction.cpp
@@ -39,6 +39,7 @@
#include "core/function/gpg/GpgBasicOperator.h"
#include "core/function/gpg/GpgKeyGetter.h"
#include "core/function/gpg/GpgKeyImportExporter.h"
+#include "core/function/gpg/GpgKeyManager.h"
#include "dialog/SignersPicker.h"
#include "spdlog/spdlog.h"
#include "ui/UserInterfaceUtils.h"
@@ -747,6 +748,26 @@ void MainWindow::slot_show_key_details() {
}
}
+void MainWindow::slot_add_key_2_favourite() {
+ auto key_ids = m_key_list_->GetSelected();
+ if (key_ids->empty()) return;
+
+ auto key = GpgKeyGetter::GetInstance().GetKey(key_ids->front());
+ CommonUtils::GetInstance()->AddKey2Favourtie(key);
+
+ emit SignalUIRefresh();
+}
+
+void MainWindow::slot_remove_key_from_favourite() {
+ auto key_ids = m_key_list_->GetSelected();
+ if (key_ids->empty()) return;
+
+ auto key = GpgKeyGetter::GetInstance().GetKey(key_ids->front());
+ CommonUtils::GetInstance()->RemoveKeyFromFavourite(key);
+
+ emit SignalUIRefresh();
+}
+
void MainWindow::refresh_keys_from_key_server() {
auto key_ids = m_key_list_->GetSelected();
if (key_ids->empty()) return;
@@ -756,6 +777,56 @@ void MainWindow::refresh_keys_from_key_server() {
dialog->SlotImport(key_ids);
}
+void MainWindow::slot_set_owner_trust_level_of_key() {
+ auto key_ids = m_key_list_->GetSelected();
+ if (key_ids->empty()) return;
+
+ auto key = GpgKeyGetter::GetInstance().GetKey(key_ids->front());
+
+ QStringList items;
+
+ items << _("Unknown") << _("Undefined") << _("Never") << _("Marginal")
+ << _("Full") << _("Ultimate");
+ bool ok;
+ QString item = QInputDialog::getItem(this, _("Modify Owner Trust Level"),
+ _("Trust for the Key Pair:"), items,
+ key.GetOwnerTrustLevel(), false, &ok);
+
+ if (ok && !item.isEmpty()) {
+ SPDLOG_DEBUG("selected policy: {}", item.toStdString());
+ int trust_level = 0; // Unknown Level
+ if (item == _("Ultimate")) {
+ trust_level = 5;
+ } else if (item == _("Full")) {
+ trust_level = 4;
+ } else if (item == _("Marginal")) {
+ trust_level = 3;
+ } else if (item == _("Never")) {
+ trust_level = 2;
+ } else if (item == _("Undefined")) {
+ trust_level = 1;
+ }
+
+ if (trust_level == 0) {
+ QMessageBox::warning(
+ this, _("Warning"),
+ QString(_("Owner Trust Level cannot set to Unknown level, automately "
+ "changing it into Undefined level.")));
+ trust_level = 1;
+ }
+
+ bool status =
+ GpgKeyManager::GetInstance().SetOwnerTrustLevel(key, trust_level);
+ if (!status) {
+ QMessageBox::critical(this, _("Failed"),
+ QString(_("Modify Owner Trust Level failed.")));
+ } else {
+ // update key database and refresh ui
+ emit SignalKeyDatabaseRefresh();
+ }
+ }
+}
+
void MainWindow::upload_key_to_server() {
auto key_ids = m_key_list_->GetSelected();
auto* dialog = new KeyUploadDialog(key_ids, this);
diff --git a/src/ui/main_window/MainWindowUI.cpp b/src/ui/main_window/MainWindowUI.cpp
index 6e664988..d1a3cb68 100644
--- a/src/ui/main_window/MainWindowUI.cpp
+++ b/src/ui/main_window/MainWindowUI.cpp
@@ -418,6 +418,27 @@ void MainWindow::create_actions() {
connect(show_key_details_act_, &QAction::triggered, this,
&MainWindow::slot_show_key_details);
+ add_key_2_favourtie_act_ = new QAction(_("Add To Favourite"), this);
+ add_key_2_favourtie_act_->setToolTip(_("Add this key to Favourite Table"));
+ add_key_2_favourtie_act_->setData(QVariant("add_key_2_favourite_action"));
+ connect(add_key_2_favourtie_act_, &QAction::triggered, this,
+ &MainWindow::slot_add_key_2_favourite);
+
+ remove_key_from_favourtie_act_ =
+ new QAction(_("Remove From Favourite"), this);
+ remove_key_from_favourtie_act_->setToolTip(
+ _("Remove this key from Favourite Table"));
+ remove_key_from_favourtie_act_->setData(
+ QVariant("remove_key_from_favourtie_action"));
+ connect(remove_key_from_favourtie_act_, &QAction::triggered, this,
+ &MainWindow::slot_remove_key_from_favourite);
+
+ set_owner_trust_of_key_act_ = new QAction(_("Set Owner Trust Level"), this);
+ set_owner_trust_of_key_act_->setToolTip(_("Set Owner Trust Level"));
+ set_owner_trust_of_key_act_->setData(QVariant("set_owner_trust_level"));
+ connect(set_owner_trust_of_key_act_, &QAction::triggered, this,
+ &MainWindow::slot_set_owner_trust_level_of_key);
+
/* Key-Shortcuts for Tab-Switchung-Action
*/
switch_tab_up_act_ = new QAction(this);
@@ -591,27 +612,35 @@ void MainWindow::create_dock_windows() {
addDockWidget(Qt::RightDockWidgetArea, key_list_dock_);
m_key_list_->AddListGroupTab(
- _("Default"), KeyListRow::SECRET_OR_PUBLIC_KEY,
+ _("Default"), "default", KeyListRow::SECRET_OR_PUBLIC_KEY,
KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress |
KeyListColumn::Usage | KeyListColumn::Validity,
- [](const GpgKey& key) -> bool {
+ [](const GpgKey& key, const KeyTable&) -> bool {
return !(key.IsRevoked() || key.IsDisabled() || key.IsExpired());
});
m_key_list_->AddListGroupTab(
- _("Only Public Key"), KeyListRow::SECRET_OR_PUBLIC_KEY,
+ _("Favourite"), "favourite", KeyListRow::SECRET_OR_PUBLIC_KEY,
+ KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress |
+ KeyListColumn::Usage | KeyListColumn::Validity,
+ [](const GpgKey& key, const KeyTable&) -> bool {
+ return CommonUtils::GetInstance()->KeyExistsinFavouriteList(key);
+ });
+
+ m_key_list_->AddListGroupTab(
+ _("Only Public Key"), "only_public_key", KeyListRow::SECRET_OR_PUBLIC_KEY,
KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress |
KeyListColumn::Usage | KeyListColumn::Validity,
- [](const GpgKey& key) -> bool {
+ [](const GpgKey& key, const KeyTable&) -> bool {
return !key.IsPrivateKey() &&
!(key.IsRevoked() || key.IsDisabled() || key.IsExpired());
});
m_key_list_->AddListGroupTab(
- _("Has Private Key"), KeyListRow::SECRET_OR_PUBLIC_KEY,
+ _("Has Private Key"), "has_private_key", KeyListRow::SECRET_OR_PUBLIC_KEY,
KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress |
KeyListColumn::Usage | KeyListColumn::Validity,
- [](const GpgKey& key) -> bool {
+ [](const GpgKey& key, const KeyTable&) -> bool {
return key.IsPrivateKey() &&
!(key.IsRevoked() || key.IsDisabled() || key.IsExpired());
});
diff --git a/src/ui/widgets/FilePage.cpp b/src/ui/widgets/FilePage.cpp
index 144de3d8..b5243da0 100644
--- a/src/ui/widgets/FilePage.cpp
+++ b/src/ui/widgets/FilePage.cpp
@@ -249,14 +249,23 @@ void FilePage::create_popup_menu() {
connect(ui_->actionCompressFiles, &QAction::triggered, this,
&FilePage::slot_compress_files);
+ ui_->actionOpenWithSystemDefaultApplication->setText(
+ _("Open with Default System Application"));
+ connect(ui_->actionOpenWithSystemDefaultApplication, &QAction::triggered,
+ this, &FilePage::slot_open_item_by_system_application);
+
auto new_item_action_menu = new QMenu(this);
new_item_action_menu->setTitle(_("New"));
new_item_action_menu->addAction(ui_->actionCreateEmptyFile);
new_item_action_menu->addAction(ui_->actionMakeDirectory);
popup_menu_->addAction(ui_->actionOpenFile);
+ popup_menu_->addAction(ui_->actionOpenWithSystemDefaultApplication);
+
+ popup_menu_->addSeparator();
popup_menu_->addMenu(new_item_action_menu);
popup_menu_->addSeparator();
+
popup_menu_->addAction(ui_->actionRenameFile);
popup_menu_->addAction(ui_->actionDeleteFile);
popup_menu_->addAction(ui_->actionCompressFiles);
@@ -349,6 +358,18 @@ void FilePage::slot_open_item() {
}
}
+void FilePage::slot_open_item_by_system_application() {
+ QFileInfo info(QString::fromStdString(selected_path_.u8string()));
+ auto q_selected_path = QString::fromStdString(selected_path_.u8string());
+ if (info.isDir()) {
+ const auto file_path = info.filePath().toUtf8().toStdString();
+ QDesktopServices::openUrl(QUrl::fromLocalFile(q_selected_path));
+
+ } else {
+ QDesktopServices::openUrl(QUrl::fromLocalFile(q_selected_path));
+ }
+}
+
void FilePage::slot_rename_item() {
auto new_name_path = selected_path_, old_name_path = selected_path_;
auto old_name = old_name_path.filename();
diff --git a/src/ui/widgets/FilePage.h b/src/ui/widgets/FilePage.h
index 8e278de7..74548b13 100644
--- a/src/ui/widgets/FilePage.h
+++ b/src/ui/widgets/FilePage.h
@@ -114,6 +114,12 @@ class FilePage : public QWidget {
* @brief
*
*/
+ void slot_open_item_by_system_application();
+
+ /**
+ * @brief
+ *
+ */
void slot_rename_item();
/**
diff --git a/src/ui/widgets/KeyList.cpp b/src/ui/widgets/KeyList.cpp
index 2d4c925a..e411e036 100644
--- a/src/ui/widgets/KeyList.cpp
+++ b/src/ui/widgets/KeyList.cpp
@@ -35,9 +35,11 @@
#include "core/GpgCoreInit.h"
#include "core/function/GlobalSettingStation.h"
#include "core/function/gpg/GpgKeyGetter.h"
+#include "spdlog/spdlog.h"
#include "ui/SignalStation.h"
#include "ui/UserInterfaceUtils.h"
#include "ui_KeyList.h"
+#include "widgets/TextEdit.h"
namespace GpgFrontend::UI {
@@ -56,6 +58,7 @@ void KeyList::init() {
KeyMenuAbility::REFRESH);
ui_->syncButton->setHidden(~menu_ability_ & KeyMenuAbility::SYNC_PUBLIC_KEY);
ui_->uncheckButton->setHidden(~menu_ability_ & KeyMenuAbility::UNCHECK_ALL);
+ ui_->searchBarEdit->setHidden(~menu_ability_ & KeyMenuAbility::SEARCH_BAR);
ui_->keyGroupTab->clear();
popup_menu_ = new QMenu(this);
@@ -73,6 +76,8 @@ void KeyList::init() {
connect(SignalStation::GetInstance(),
&SignalStation::SignalKeyDatabaseRefreshDone, this,
&KeyList::SlotRefresh);
+ connect(SignalStation::GetInstance(), &SignalStation::SignalUIRefresh, this,
+ &KeyList::SlotRefreshUI);
// register key database sync signal for refresh button
connect(ui_->refreshKeyListButton, &QPushButton::clicked, this,
@@ -84,6 +89,8 @@ void KeyList::init() {
&KeyList::check_all);
connect(ui_->syncButton, &QPushButton::clicked, this,
&KeyList::slot_sync_with_key_server);
+ connect(ui_->searchBarEdit, &QLineEdit::textChanged, this,
+ &KeyList::filter_by_keyword);
connect(this, &KeyList::SignalRefreshStatusBar, SignalStation::GetInstance(),
&SignalStation::SignalRefreshStatusBar);
@@ -101,20 +108,23 @@ void KeyList::init() {
ui_->checkALLButton->setText(_("Check ALL"));
ui_->checkALLButton->setToolTip(
_("Check all items in the current tab at once"));
+ ui_->searchBarEdit->setPlaceholderText(_("Search for keys..."));
}
-void KeyList::AddListGroupTab(
- const QString& name, KeyListRow::KeyType selectType,
- KeyListColumn::InfoType infoType,
- const std::function<bool(const GpgKey&)>& filter) {
+void KeyList::AddListGroupTab(const QString& name, const QString& id,
+ KeyListRow::KeyType selectType,
+ KeyListColumn::InfoType infoType,
+ const KeyTable::KeyTableFilter filter) {
SPDLOG_DEBUG("add tab: {}", name.toStdString());
auto key_list = new QTableWidget(this);
if (m_key_list_ == nullptr) {
m_key_list_ = key_list;
}
+ key_list->setObjectName(id);
ui_->keyGroupTab->addTab(key_list, name);
m_key_tables_.emplace_back(key_list, selectType, infoType, filter);
+ m_key_tables_.back().SetMenuAbility(menu_ability_);
key_list->setColumnCount(7);
key_list->horizontalHeader()->setSectionResizeMode(
@@ -155,7 +165,7 @@ void KeyList::AddListGroupTab(
QStringList labels;
labels << _("Select") << _("Type") << _("Name") << _("Email Address")
- << _("Usage") << _("Validity") << _("Finger Print");
+ << _("Usage") << _("Trust") << _("Finger Print");
key_list->setHorizontalHeaderLabels(labels);
key_list->horizontalHeader()->setStretchLastSection(false);
@@ -175,6 +185,11 @@ void KeyList::SlotRefresh() {
this->slot_refresh_ui();
}
+void KeyList::SlotRefreshUI() {
+ SPDLOG_DEBUG("refresh, address: {}", static_cast<void*>(this));
+ this->slot_refresh_ui();
+}
+
KeyIdArgsListPtr KeyList::GetChecked(const KeyTable& key_table) {
auto ret = std::make_unique<KeyIdArgsList>();
for (int i = 0; i < key_table.key_list_->rowCount(); i++) {
@@ -297,6 +312,30 @@ void KeyList::contextMenuEvent(QContextMenuEvent* event) {
if (ui_->keyGroupTab->size().isEmpty()) return;
m_key_list_ = qobject_cast<QTableWidget*>(ui_->keyGroupTab->currentWidget());
+ QString current_tab_widget_obj_name =
+ ui_->keyGroupTab->widget(ui_->keyGroupTab->currentIndex())->objectName();
+ SPDLOG_DEBUG("current tab widget object name: {}",
+ current_tab_widget_obj_name.toStdString());
+ if (current_tab_widget_obj_name == "favourite") {
+ QList<QAction*> actions = popup_menu_->actions();
+ for (QAction* action : actions) {
+ if (action->data().toString() == "remove_key_from_favourtie_action") {
+ action->setVisible(true);
+ } else if (action->data().toString() == "add_key_2_favourite_action") {
+ action->setVisible(false);
+ }
+ }
+ } else {
+ QList<QAction*> actions = popup_menu_->actions();
+ for (QAction* action : actions) {
+ if (action->data().toString() == "remove_key_from_favourtie_action") {
+ action->setVisible(false);
+ } else if (action->data().toString() == "add_key_2_favourite_action") {
+ action->setVisible(true);
+ }
+ }
+ }
+
if (m_key_list_->selectedItems().length() > 0) {
popup_menu_->exec(event->globalPos());
}
@@ -426,6 +465,7 @@ void KeyList::slot_refresh_ui() {
SPDLOG_DEBUG("refresh: {}", static_cast<void*>(buffered_keys_list_.get()));
if (buffered_keys_list_ != nullptr) {
std::lock_guard<std::mutex> guard(buffered_key_list_mutex_);
+
for (auto& key_table : m_key_tables_) {
key_table.Refresh(
GpgKeyGetter::GetInstance().GetKeysCopy(buffered_keys_list_));
@@ -473,6 +513,20 @@ void KeyList::slot_sync_with_key_server() {
});
}
+void KeyList::filter_by_keyword() {
+ auto keyword = ui_->searchBarEdit->text();
+ keyword = keyword.trimmed();
+
+ SPDLOG_DEBUG("get new keyword of search bar: {}", keyword.toStdString());
+ for (auto& table : m_key_tables_) {
+ // refresh arguments
+ table.SetFilterKeyword(keyword.toLower().toStdString());
+ table.SetMenuAbility(menu_ability_);
+ }
+ // refresh ui
+ SlotRefreshUI();
+}
+
void KeyList::uncheck_all() {
auto key_list =
qobject_cast<QTableWidget*>(ui_->keyGroupTab->currentWidget());
@@ -539,8 +593,30 @@ void KeyTable::Refresh(KeyLinkListPtr m_keys) {
while (it != keys->end()) {
SPDLOG_DEBUG("filtering key id: {}", it->GetId());
+ // filter by search bar's keyword
+ if (ability_ & KeyMenuAbility::SEARCH_BAR && !keyword_.empty()) {
+ auto name = it->GetName();
+ std::transform(name.begin(), name.end(), name.begin(),
+ [](unsigned char c) { return std::tolower(c); });
+
+ auto email = it->GetEmail();
+ std::transform(email.begin(), email.end(), email.begin(),
+ [](unsigned char c) { return std::tolower(c); });
+
+ auto comment = it->GetComment();
+ std::transform(comment.begin(), comment.end(), comment.begin(),
+ [](unsigned char c) { return std::tolower(c); });
+
+ if (name.find(keyword_) == std::string::npos &&
+ email.find(keyword_) == std::string::npos &&
+ comment.find(keyword_) == std::string::npos) {
+ it = keys->erase(it);
+ continue;
+ }
+ }
+
if (filter_ != nullptr) {
- if (!filter_(*it)) {
+ if (!filter_(*it, *this)) {
it = keys->erase(it);
continue;
}
@@ -659,4 +735,12 @@ void KeyTable::CheckALL() const {
key_list_->item(i, 0)->setCheckState(Qt::Checked);
}
}
+
+void KeyTable::SetMenuAbility(KeyMenuAbility::AbilityType ability) {
+ this->ability_ = ability;
+}
+
+void KeyTable::SetFilterKeyword(std::string keyword) {
+ this->keyword_ = keyword;
+}
} // namespace GpgFrontend::UI
diff --git a/src/ui/widgets/KeyList.h b/src/ui/widgets/KeyList.h
index f1c88cc6..eb346740 100644
--- a/src/ui/widgets/KeyList.h
+++ b/src/ui/widgets/KeyList.h
@@ -29,6 +29,7 @@
#ifndef __KEYLIST_H__
#define __KEYLIST_H__
+#include <string>
#include <utility>
#include "core/GpgContext.h"
@@ -78,6 +79,7 @@ struct KeyMenuAbility {
static constexpr AbilityType SYNC_PUBLIC_KEY = 1 << 1; ///<
static constexpr AbilityType UNCHECK_ALL = 1 << 3; ///<
static constexpr AbilityType CHECK_ALL = 1 << 5; ///<
+ static constexpr AbilityType SEARCH_BAR = 1 << 6; ///<
};
/**
@@ -85,12 +87,16 @@ struct KeyMenuAbility {
*
*/
struct KeyTable {
- QTableWidget* key_list_; ///<
- KeyListRow::KeyType select_type_; ///<
- KeyListColumn::InfoType info_type_; ///<
- std::vector<GpgKey> buffered_keys_; ///<
- std::function<bool(const GpgKey&)> filter_; ///<
- KeyIdArgsListPtr checked_key_ids_; ///<
+ using KeyTableFilter = std::function<bool(const GpgKey&, const KeyTable&)>;
+
+ QTableWidget* key_list_; ///<
+ KeyListRow::KeyType select_type_; ///<
+ KeyListColumn::InfoType info_type_; ///<
+ std::vector<GpgKey> buffered_keys_; ///<
+ KeyTableFilter filter_; ///<
+ KeyIdArgsListPtr checked_key_ids_; ///<
+ KeyMenuAbility::AbilityType ability_; ///<
+ std::string keyword_; ///<
/**
* @brief Construct a new Key Table object
@@ -103,7 +109,7 @@ struct KeyTable {
KeyTable(
QTableWidget* _key_list, KeyListRow::KeyType _select_type,
KeyListColumn::InfoType _info_type,
- std::function<bool(const GpgKey&)> _filter = [](const GpgKey&) -> bool {
+ KeyTableFilter _filter = [](const GpgKey&, const KeyTable&) -> bool {
return true;
})
: key_list_(_key_list),
@@ -143,6 +149,18 @@ struct KeyTable {
* @param key_ids
*/
void SetChecked(KeyIdArgsListPtr key_ids);
+
+ /**
+ * @brief
+ *
+ */
+ void SetMenuAbility(KeyMenuAbility::AbilityType ability);
+
+ /**
+ * @brief
+ *
+ */
+ void SetFilterKeyword(std::string keyword);
};
/**
@@ -171,11 +189,11 @@ class KeyList : public QWidget {
* @param filter
*/
void AddListGroupTab(
- const QString& name,
+ const QString& name, const QString& id,
KeyListRow::KeyType selectType = KeyListRow::SECRET_OR_PUBLIC_KEY,
KeyListColumn::InfoType infoType = KeyListColumn::ALL,
- const std::function<bool(const GpgKey&)>& filter =
- [](const GpgKey&) -> bool { return true; });
+ const KeyTable::KeyTableFilter filter =
+ [](const GpgKey&, const KeyTable&) -> bool { return true; });
/**
* @brief Set the Double Clicked Action object
@@ -303,6 +321,12 @@ class KeyList : public QWidget {
*/
void SlotRefresh();
+ /**
+ * @brief
+ *
+ */
+ void SlotRefreshUI();
+
private:
/**
* @brief
@@ -329,6 +353,12 @@ class KeyList : public QWidget {
*/
void check_all();
+ /**
+ * @brief
+ *
+ */
+ void filter_by_keyword();
+
std::mutex buffered_key_list_mutex_; ///<
std::shared_ptr<Ui_KeyList> ui_; ///<
diff --git a/src/ui/widgets/TextEdit.cpp b/src/ui/widgets/TextEdit.cpp
index d22c091a..7af4d5f8 100644
--- a/src/ui/widgets/TextEdit.cpp
+++ b/src/ui/widgets/TextEdit.cpp
@@ -33,6 +33,9 @@
#include <tuple>
#include <vector>
+#include "core/function/CacheManager.h"
+#include "core/function/GlobalSettingStation.h"
+#include "nlohmann/json_fwd.hpp"
#include "spdlog/spdlog.h"
namespace GpgFrontend::UI {
@@ -70,6 +73,33 @@ void TextEdit::SlotNewTab() {
this, &TextEdit::slot_save_status_to_cache_for_revovery);
}
+void TextEdit::SlotNewTabWithContent(std::string title,
+ const std::string& content) {
+ QString header = _("untitled") + QString::number(++count_page_) + ".txt";
+ if (!title.empty()) {
+ // modify title
+ if (!title.empty() && title[0] == '*') {
+ title.erase(0, 1);
+ }
+ // set title
+ header = QString::fromStdString(title);
+ }
+
+ auto* page = new PlainTextEditorPage();
+ auto index = tab_widget_->addTab(page, header);
+ tab_widget_->setTabIcon(index, QIcon(":file.png"));
+ tab_widget_->setCurrentIndex(tab_widget_->count() - 1);
+ page->GetTextPage()->setFocus();
+ connect(page->GetTextPage()->document(), &QTextDocument::modificationChanged,
+ this, &TextEdit::SlotShowModified);
+ connect(page->GetTextPage()->document(), &QTextDocument::contentsChanged,
+ this, &TextEdit::slot_save_status_to_cache_for_revovery);
+
+ // set content with modified status
+ page->GetTextPage()->document()->setPlainText(
+ QString::fromStdString(content));
+}
+
void TextEdit::slotNewHelpTab(const QString& title, const QString& path) const {
auto* page = new HelpPage(path);
tab_widget_->addTab(page, title);
@@ -599,15 +629,29 @@ void TextEdit::slot_file_page_path_changed(const QString& path) const {
}
void TextEdit::slot_save_status_to_cache_for_revovery() {
- SPDLOG_DEBUG("catch text page modified event, count: {}",
- text_page_data_modified_count_);
- if (this->text_page_data_modified_count_++ % 3 != 0) return;
+ if (this->text_page_data_modified_count_++ % 8 != 0) return;
+
+ auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
+ bool restore_text_editor_page = false;
+ try {
+ restore_text_editor_page =
+ settings.lookup("general.restore_text_editor_page");
+ } catch (...) {
+ SPDLOG_ERROR("setting operation error: restore_text_editor_page");
+ }
+
+ if (!restore_text_editor_page) {
+ SPDLOG_DEBUG("restore_text_editor_page is false, ignoring...");
+ return;
+ }
-#ifdef DEBUG
int tab_count = tab_widget_->count();
- SPDLOG_DEBUG("current tabs count {}", tab_count);
+ SPDLOG_DEBUG(
+ "restore_text_editor_page is true, pan to save pages, current tabs "
+ "count: "
+ "{}",
+ tab_count);
- std::vector<std::pair<int, std::string>> saved_pages;
std::vector<std::tuple<int, std::string, std::string>> unsaved_pages;
for (int i = 0; i < tab_count; i++) {
@@ -623,11 +667,6 @@ void TextEdit::slot_save_status_to_cache_for_revovery() {
auto tab_title = tab_widget_->tabText(i).toStdString();
if (!target_page->ReadDone() || !target_page->isEnabled() ||
!document->isModified()) {
- auto file_path = target_page->GetFilePath().toStdString();
- SPDLOG_DEBUG("saved page index: {}, tab title: {} tab file path: {}", i,
- tab_title, file_path);
-
- saved_pages.push_back({i, file_path});
continue;
}
@@ -636,7 +675,20 @@ void TextEdit::slot_save_status_to_cache_for_revovery() {
tab_title, raw_text.size());
unsaved_pages.push_back({i, tab_title, raw_text});
}
-#endif
+
+ nlohmann::json unsaved_page_array = nlohmann::json::array();
+ for (const auto& page : unsaved_pages) {
+ nlohmann::json page_json;
+ page_json["index"] = std::get<0>(page);
+ page_json["title"] = std::get<1>(page);
+ page_json["content"] = std::get<2>(page);
+
+ unsaved_page_array.push_back(page_json);
+ }
+
+ SPDLOG_DEBUG("unsaved page json array: {}", unsaved_page_array.dump());
+ CacheManager::GetInstance().SaveCache("editor_unsaved_pages",
+ unsaved_page_array);
}
} // namespace GpgFrontend::UI
diff --git a/src/ui/widgets/TextEdit.h b/src/ui/widgets/TextEdit.h
index 2e2f949d..f69bda4c 100644
--- a/src/ui/widgets/TextEdit.h
+++ b/src/ui/widgets/TextEdit.h
@@ -151,6 +151,12 @@ class TextEdit : public QWidget {
void SlotNewTab();
/**
+ * @details
+ *
+ */
+ void SlotNewTabWithContent(std::string title, const std::string& content);
+
+ /**
* @details Adds a new tab with opening file by path
*/
void SlotOpenFile(const QString& path);