diff options
Diffstat (limited to 'src/ui')
24 files changed, 686 insertions, 82 deletions
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); |