diff options
author | Saturneric <[email protected]> | 2021-12-05 18:51:59 +0000 |
---|---|---|
committer | Saturneric <[email protected]> | 2021-12-05 19:00:26 +0000 |
commit | 590f222de4abdf2aae4d2d8de6f9af25996a713e (patch) | |
tree | 4108a6205fb517a694d65b3044f7369f32b43862 | |
parent | Add Submodules & Update & Fixed (diff) | |
download | GpgFrontend-590f222de4abdf2aae4d2d8de6f9af25996a713e.tar.gz GpgFrontend-590f222de4abdf2aae4d2d8de6f9af25996a713e.zip |
Improve UI
1. Support Key List Tab
2. File Hash Calculate
3. File Rename
4. Fix known bugs
5. Fix known ci issues.
26 files changed, 959 insertions, 780 deletions
diff --git a/.github/workflows/debug.yml b/.github/workflows/debug.yml index 5c541fbd..b6dcc211 100644 --- a/.github/workflows/debug.yml +++ b/.github/workflows/debug.yml @@ -30,6 +30,8 @@ jobs: steps: - uses: actions/checkout@v2 + with: + submodules: 'recursive' - name: Install Dependence (Linux) run: | @@ -41,7 +43,6 @@ jobs: - name: Git Sumbodule Update run: | - git pull --recurse-submodules git submodule update --init --recursive - name: Codesign Configuration (macOS) diff --git a/gpgfrontend.qrc b/gpgfrontend.qrc index 71513dbd..b067b7ca 100644 --- a/gpgfrontend.qrc +++ b/gpgfrontend.qrc @@ -25,7 +25,9 @@ <file alias="decrypted_verified.png">resource/icons/decrypted_verified.png</file> <file alias="exit.png">resource/icons/exit.png</file> <file alias="export_key_to_file.png">resource/icons/export_key_to_file.png</file> + <file alias="file.png">resource/icons/file.png</file> <file alias="fileencryption.png">resource/icons/fileencrytion.png</file> + <file alias="file-browser.png">resource/icons/file-browser.png</file> <file alias="fileopen.png">resource/icons/fileopen.png</file> <file alias="fileprint.png">resource/icons/fileprint.png</file> <file alias="filesave.png">resource/icons/filesave.png</file> diff --git a/resource/icons/file-browser.png b/resource/icons/file-browser.png Binary files differnew file mode 100644 index 00000000..29dba7e1 --- /dev/null +++ b/resource/icons/file-browser.png diff --git a/resource/icons/file.png b/resource/icons/file.png Binary files differnew file mode 100644 index 00000000..d8562029 --- /dev/null +++ b/resource/icons/file.png diff --git a/resource/icons/verify.png b/resource/icons/verify.png Binary files differindex bfaa5536..e359b69f 100644 --- a/resource/icons/verify.png +++ b/resource/icons/verify.png diff --git a/src/gpg/result_analyse/VerifyResultAnalyse.cpp b/src/gpg/result_analyse/VerifyResultAnalyse.cpp index 55e50f38..74d2d204 100644 --- a/src/gpg/result_analyse/VerifyResultAnalyse.cpp +++ b/src/gpg/result_analyse/VerifyResultAnalyse.cpp @@ -24,6 +24,8 @@ #include "gpg/result_analyse/VerifyResultAnalyse.h" +#include <boost/format.hpp> + #include "GpgFrontend.h" #include "gpg/GpgConstants.h" #include "gpg/function/GpgKeyGetter.h" @@ -59,14 +61,18 @@ void GpgFrontend::VerifyResultAnalyse::do_analyse() { boost::posix_time::from_time_t(sign->timestamp)) << std::endl; - stream << std::endl << "[>] " << _("Signatures") << ":" << std::endl; + stream << std::endl << "[>] " << _("Signatures List") << ":" << std::endl; bool canContinue = true; + int count = 1; while (sign && canContinue) { + stream << boost::format(_("Signature [%1%]:")) % count++ << std::endl; switch (gpg_err_code(sign->status)) { case GPG_ERR_BAD_SIGNATURE: - stream << _("One or More Bad Signatures.") << std::endl; + stream << _("A Bad Signature.") << std::endl; + print_signer(stream, sign); + stream << _("This Signature is invalid.") << std::endl; canContinue = false; setStatus(-1); break; @@ -173,14 +179,17 @@ bool GpgFrontend::VerifyResultAnalyse::print_signer(std::stringstream &stream, stream << " " << _("Signed By") << ": " << key.uids()->front().uid() << std::endl; } - stream << " " << _("Public Key Algo") << ": " - << gpgme_pubkey_algo_name(sign->pubkey_algo) << std::endl; - stream << " " << _("Hash Algo") << ": " - << gpgme_hash_algo_name(sign->hash_algo) << std::endl; - stream << " " << _("Date & Time") << ": " - << boost::posix_time::to_iso_string( - boost::posix_time::from_time_t(sign->timestamp)) - << std::endl; + if (sign->pubkey_algo) + stream << " " << _("Public Key Algo") << ": " + << gpgme_pubkey_algo_name(sign->pubkey_algo) << std::endl; + if (sign->hash_algo) + stream << " " << _("Hash Algo") << ": " + << gpgme_hash_algo_name(sign->hash_algo) << std::endl; + if (sign->timestamp) + stream << " " << _("Date & Time") << ": " + << boost::posix_time::to_iso_string( + boost::posix_time::from_time_t(sign->timestamp)) + << std::endl; stream << std::endl; return keyFound; } diff --git a/src/ui/FileEncryptionDialog.cpp b/src/ui/FileEncryptionDialog.cpp index 3e1e9b9a..137d8555 100755 --- a/src/ui/FileEncryptionDialog.cpp +++ b/src/ui/FileEncryptionDialog.cpp @@ -86,32 +86,43 @@ FileEncryptionDialog::FileEncryptionDialog(KeyIdArgsListPtr keyList, groupBox1->setLayout(gLayout); /*Setup KeyList*/ - mKeyList = new KeyList( - KeyListRow::ONLY_SECRET_KEY, - KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage); - if (mAction == Verify) - mKeyList->setFilter([](const GpgKey& key) -> bool { - if (key.disabled() || key.expired() || key.revoked()) - return false; - else - return true; - }); - - if (mAction == Encrypt) - mKeyList->setFilter([](const GpgKey& key) -> bool { - if (!key.CanEncrActual()) - return false; - else - return true; - }); - - if (mAction == Sign) - mKeyList->setFilter([](const GpgKey& key) -> bool { - if (!key.CanSignActual()) - return false; - else - return true; - }); + + if (mAction == Verify) { + mKeyList = + new KeyList(KeyListRow::ONLY_SECRET_KEY, + KeyListColumn::NAME | KeyListColumn::EmailAddress | + KeyListColumn::Usage, + [](const GpgKey& key) -> bool { + if (key.disabled() || key.expired() || key.revoked()) + return false; + else + return true; + }); + } + + if (mAction == Encrypt) { + mKeyList = new KeyList(KeyListRow::ONLY_SECRET_KEY, + KeyListColumn::NAME | KeyListColumn::EmailAddress | + KeyListColumn::Usage, + [](const GpgKey& key) -> bool { + if (!key.CanEncrActual()) + return false; + else + return true; + }); + } + + if (mAction == Encrypt) { + mKeyList = new KeyList(KeyListRow::ONLY_SECRET_KEY, + KeyListColumn::NAME | KeyListColumn::EmailAddress | + KeyListColumn::Usage, + [](const GpgKey& key) -> bool { + if (!key.CanSignActual()) + return false; + else + return true; + }); + } if (mAction == Decrypt) mKeyList->setDisabled(true); diff --git a/src/ui/KeyMgmt.cpp b/src/ui/KeyMgmt.cpp index 7459906d..aa6df120 100755 --- a/src/ui/KeyMgmt.cpp +++ b/src/ui/KeyMgmt.cpp @@ -36,9 +36,49 @@ namespace GpgFrontend::UI { KeyMgmt::KeyMgmt(QWidget* parent) : QMainWindow(parent) { /* the list of Keys available*/ - mKeyList = new KeyList(); - mKeyList->setColumnWidth(2, 250); - mKeyList->setColumnWidth(3, 250); + mKeyList = new KeyList(this); + + mKeyList->addListGroupTab(_("All"), KeyListRow::SECRET_OR_PUBLIC_KEY); + + mKeyList->addListGroupTab( + _("Only Public Key"), KeyListRow::SECRET_OR_PUBLIC_KEY, + KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress | + KeyListColumn::Usage | KeyListColumn::Validity, + [](const GpgKey& key) -> bool { + return !key.is_private_key() && + !(key.revoked() || key.disabled() || key.expired()); + }); + + mKeyList->addListGroupTab( + _("Has Private Key"), KeyListRow::SECRET_OR_PUBLIC_KEY, + KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress | + KeyListColumn::Usage | KeyListColumn::Validity, + [](const GpgKey& key) -> bool { + return key.is_private_key() && + !(key.revoked() || key.disabled() || key.expired()); + }); + + mKeyList->addListGroupTab( + _("No Master Key"), KeyListRow::SECRET_OR_PUBLIC_KEY, + KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress | + KeyListColumn::Usage | KeyListColumn::Validity, + [](const GpgKey& key) -> bool { + return !key.has_master_key() && + !(key.revoked() || key.disabled() || key.expired()); + }); + + mKeyList->addListGroupTab( + _("Revoked"), KeyListRow::SECRET_OR_PUBLIC_KEY, + KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress | + KeyListColumn::Usage | KeyListColumn::Validity, + [](const GpgKey& key) -> bool { return key.revoked(); }); + + mKeyList->addListGroupTab( + _("Expired"), KeyListRow::SECRET_OR_PUBLIC_KEY, + KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress | + KeyListColumn::Usage | KeyListColumn::Validity, + [](const GpgKey& key) -> bool { return key.expired(); }); + setCentralWidget(mKeyList); mKeyList->setDoubleClickedAction([this](const GpgKey& key, QWidget* parent) { new KeyDetailsDialog(key, parent); diff --git a/src/ui/MainWindow.cpp b/src/ui/MainWindow.cpp index e29278e9..d13a0bd5 100644 --- a/src/ui/MainWindow.cpp +++ b/src/ui/MainWindow.cpp @@ -59,14 +59,7 @@ void MainWindow::init() noexcept { setCentralWidget(edit); /* the list of Keys available*/ - mKeyList = new KeyList(KeyListRow::SECRET_OR_PUBLIC_KEY, - KeyListColumn::TYPE | KeyListColumn::NAME | - KeyListColumn::EmailAddress | - KeyListColumn::Usage | KeyListColumn::Validity, - this); - mKeyList->setFilter([](const GpgKey& key) -> bool { - return !(key.revoked() || key.disabled() || key.expired()); - }); + mKeyList = new KeyList(this); mKeyList->slotRefresh(); @@ -144,7 +137,6 @@ void MainWindow::init() noexcept { &MainWindow::slotVersionUpgrade); version_thread->start(); - #endif } catch (...) { @@ -244,7 +236,6 @@ void MainWindow::restoreSettings() { // icons ize this->setIconSize(QSize(width, height)); importButton->setIconSize(QSize(width, height)); - fileEncButton->setIconSize(QSize(width, height)); if (!settings.exists("keyserver") || settings.lookup("keyserver").getType() != libconfig::Setting::TypeGroup) @@ -279,7 +270,6 @@ void MainWindow::restoreSettings() { auto icon_style = static_cast<Qt::ToolButtonStyle>(s_icon_style); this->setToolButtonStyle(icon_style); importButton->setToolButtonStyle(icon_style); - fileEncButton->setToolButtonStyle(icon_style); if (!settings.exists("general") || settings.lookup("general").getType() != libconfig::Setting::TypeGroup) @@ -300,12 +290,12 @@ void MainWindow::restoreSettings() { general.add("save_key_checked_key_ids", libconfig::Setting::TypeList); } auto key_ids_ptr = std::make_unique<KeyIdArgsList>(); - ; auto& save_key_checked_key_ids = general["save_key_checked_key_ids"]; const auto key_ids_size = general.lookup("save_key_checked_key_ids").getLength(); for (auto i = 0; i < key_ids_size; i++) { std::string key_id = save_key_checked_key_ids[i]; + LOG(INFO) << "get checked key id" << key_id; key_ids_ptr->push_back(key_id); } mKeyList->setChecked(key_ids_ptr); diff --git a/src/ui/SignalStation.cpp b/src/ui/SignalStation.cpp index fff2971a..0c550f88 100644 --- a/src/ui/SignalStation.cpp +++ b/src/ui/SignalStation.cpp @@ -24,6 +24,8 @@ #include "SignalStation.h" +namespace GpgFrontend::UI { + std::unique_ptr<SignalStation> SignalStation::_instance = nullptr; SignalStation* SignalStation::GetInstance() { @@ -32,3 +34,5 @@ SignalStation* SignalStation::GetInstance() { } return _instance.get(); } + +} // namespace GpgFrontend::UI diff --git a/src/ui/SignalStation.h b/src/ui/SignalStation.h index 38e55d9f..bfd5e197 100644 --- a/src/ui/SignalStation.h +++ b/src/ui/SignalStation.h @@ -26,6 +26,9 @@ #define GPGFRONTEND_SIGNALSTATION_H #include "ui/GpgFrontendUI.h" +#include "ui/widgets/InfoBoardWidget.h" + +namespace GpgFrontend::UI { class SignalStation : public QObject { Q_OBJECT @@ -36,6 +39,11 @@ class SignalStation : public QObject { signals: void KeyDatabaseRefresh(); + + void signalRefreshInfoBoard(const QString& text, + InfoBoardStatus verify_label_status); }; +} // namespace GpgFrontend::UI + #endif // GPGFRONTEND_SIGNALSTATION_H diff --git a/src/ui/UserInterfaceUtils.cpp b/src/ui/UserInterfaceUtils.cpp index e8f27d2c..52fc8457 100644 --- a/src/ui/UserInterfaceUtils.cpp +++ b/src/ui/UserInterfaceUtils.cpp @@ -50,7 +50,6 @@ void refresh_info_board(InfoBoardWidget* info_board, int status, void process_result_analyse(TextEdit* edit, InfoBoardWidget* info_board, const ResultAnalyse& result_analyse) { info_board->associateTabWidget(edit->tabWidget); - info_board->associateFileTreeView(edit->curFilePage()); refresh_info_board(info_board, result_analyse.getStatus(), result_analyse.getResultReport()); } @@ -61,8 +60,7 @@ void process_result_analyse(TextEdit* edit, InfoBoardWidget* info_board, LOG(INFO) << "process_result_analyse Started"; info_board->associateTabWidget(edit->tabWidget); - info_board->associateFileTreeView(edit->curFilePage()); - + refresh_info_board( info_board, std::min(result_analyse_a.getStatus(), result_analyse_b.getStatus()), diff --git a/src/ui/Wizard.cpp b/src/ui/Wizard.cpp index de0107c4..3df00683 100644 --- a/src/ui/Wizard.cpp +++ b/src/ui/Wizard.cpp @@ -104,73 +104,17 @@ IntroPage::IntroPage(QWidget* parent) : QWizardPage(parent) { "system, GpgFrontend will automatically set it.")); langLabel->setWordWrap(true); - languages = SettingsDialog::listLanguages(); - auto* langSelectBox = new QComboBox(); - - for (const auto& l : languages) { - langSelectBox->addItem(l); - } - // selected entry from config - - // auto lang = ""; - // auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); - // try { - // lang = settings.lookup("general.lang"); - // } catch (...) { - // LOG(INFO) << "Read for general.lang failed"; - // } - // - // QString langKey = lang; - // QString langValue = languages.value(langKey); - // LOG(INFO) << "lang key" << langKey.toStdString() << "lang value" - // << langValue.toStdString(); - // langSelectBox->setCurrentIndex(langSelectBox->findText(langValue)); - - // connect(langSelectBox, SIGNAL(currentIndexChanged(QString)), this, - // SLOT(slotLangChange(QString))); - // set layout and add widgets auto* layout = new QVBoxLayout; layout->addWidget(topLabel); layout->addStretch(); +#ifdef MULTI_LANG_SUPPORT layout->addWidget(langLabel); - // layout->addWidget(langSelectBox); +#endif setLayout(layout); } -// void IntroPage::slotLangChange(const QString& lang) { -// auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); -// -// if (!settings.exists("general") || -// settings.lookup("general").getType() != libconfig::Setting::TypeGroup) -// settings.add("general", libconfig::Setting::TypeGroup); -// -// auto& general = settings["general"]; -// if (!general.exists("lang")) -// general.add("lang", libconfig::Setting::TypeString) = -// languages.key(lang).toStdString(); -// else { -// general["lang"] = languages.key(lang).toStdString(); -// } -// -// if (!settings.exists("wizard") || -// settings.lookup("wizard").getType() != libconfig::Setting::TypeGroup) -// settings.add("wizard", libconfig::Setting::TypeGroup); -// -// auto& wizard = settings["wizard"]; -// if (!wizard.exists("next_page")) -// wizard.add("next_page", libconfig::Setting::TypeInt) = -// this->wizard()->currentId(); -// else { -// wizard["next_page"] = this->wizard()->currentId(); -// } -// -// GlobalSettingStation::GetInstance().Sync(); -// -// qApp->exit(RESTART_CODE); -// } - int IntroPage::nextId() const { return Wizard::Page_Choose; } ChoosePage::ChoosePage(QWidget* parent) : QWizardPage(parent) { diff --git a/src/ui/Wizard.h b/src/ui/Wizard.h index 8d7395db..7145d310 100644 --- a/src/ui/Wizard.h +++ b/src/ui/Wizard.h @@ -40,14 +40,12 @@ class Wizard : public QWizard { public: enum WizardPages { Page_Intro, Page_Choose, Page_GenKey, Page_Conclusion }; - Wizard(QWidget* parent = nullptr); + explicit Wizard(QWidget* parent = nullptr); private slots: - void slotWizardAccepted(); signals: - void signalOpenHelp(QString page); }; @@ -57,14 +55,7 @@ class IntroPage : public QWizardPage { public: explicit IntroPage(QWidget* parent = nullptr); - QHash<QString, QString> languages; - [[nodiscard]] int nextId() const override; - - private: - private slots: - - // void slotLangChange(const QString& lang); }; class ChoosePage : public QWizardPage { diff --git a/src/ui/keypair_details/KeyUIDSignDialog.cpp b/src/ui/keypair_details/KeyUIDSignDialog.cpp index 6cce116b..78e4900c 100644 --- a/src/ui/keypair_details/KeyUIDSignDialog.cpp +++ b/src/ui/keypair_details/KeyUIDSignDialog.cpp @@ -33,18 +33,18 @@ namespace GpgFrontend::UI { KeyUIDSignDialog::KeyUIDSignDialog(const GpgKey& key, UIDArgsListPtr uid, QWidget* parent) : QDialog(parent), mUids(std::move(uid)), mKey(key) { - mKeyList = - new KeyList(KeyListRow::ONLY_SECRET_KEY, - KeyListColumn::NAME | KeyListColumn::EmailAddress, this); - - mKeyList->setFilter([](const GpgKey& key) -> bool { - if (key.disabled() || !key.can_certify() || !key.has_master_key() || - key.expired() || key.revoked()) - return false; - else - return true; - }); - mKeyList->setExcludeKeys({key.id()}); + const auto key_id = mKey.id(); + mKeyList = new KeyList( + KeyListRow::ONLY_SECRET_KEY, + KeyListColumn::NAME | KeyListColumn::EmailAddress, + [key_id](const GpgKey& key) -> bool { + if (key.disabled() || !key.can_certify() || !key.has_master_key() || + key.expired() || key.revoked() || key_id == key.id()) + return false; + else + return true; + }, + this); mKeyList->slotRefresh(); signKeyButton = new QPushButton("Sign"); diff --git a/src/ui/main_window/MainWindowFileSlotFunction.cpp b/src/ui/main_window/MainWindowFileSlotFunction.cpp index 25445dcc..c258e8b0 100644 --- a/src/ui/main_window/MainWindowFileSlotFunction.cpp +++ b/src/ui/main_window/MainWindowFileSlotFunction.cpp @@ -164,15 +164,6 @@ void MainWindow::slotFileSign() { if (!file_pre_check(this, path)) return; - if (QFile::exists(path + ".sig")) { - auto ret = QMessageBox::warning( - this, _("Warning"), - _("The target file already exists, do you need to overwrite it?"), - QMessageBox::Ok | QMessageBox::Cancel); - - if (ret == QMessageBox::Cancel) return; - } - auto key_ids = mKeyList->getChecked(); auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); @@ -193,6 +184,18 @@ void MainWindow::slotFileSign() { } } + auto sig_file_path = boost::filesystem::path(path.toStdString() + ".sig"); + if (QFile::exists(sig_file_path.string().c_str())) { + auto ret = QMessageBox::warning( + this, _("Warning"), + QString(_("The signature file \"%1\" exists, " + "do you need to overwrite it?")) + .arg(sig_file_path.filename().string().c_str()), + QMessageBox::Ok | QMessageBox::Cancel); + + if (ret == QMessageBox::Cancel) return; + } + GpgSignResult result = nullptr; gpgme_error_t error; bool if_error = false; @@ -242,12 +245,22 @@ void MainWindow::slotFileVerify() { signFilePath = path + ".sig"; } + bool ok; + QString text = + QInputDialog::getText(this, _("Origin file to verify"), _("Filepath"), + QLineEdit::Normal, dataFilePath, &ok); + if (ok && !text.isEmpty()) { + dataFilePath = text; + } else { + return; + } + QFileInfo dataFileInfo(dataFilePath), signFileInfo(signFilePath); if (!dataFileInfo.isFile() || !signFileInfo.isFile()) { QMessageBox::critical( this, _("Error"), - _("Please select the appropriate target file or signature file. " + _("Please select the appropriate origin file or signature file. " "Ensure that both are in this directory.")); return; } @@ -433,8 +446,6 @@ void MainWindow::slotFileDecryptVerify() { }); if (!if_error) { - infoBoard->associateFileTreeView(edit->curFilePage()); - auto decrypt_res = DecryptResultAnalyse(error, std::move(d_result)); auto verify_res = VerifyResultAnalyse(error, std::move(v_result)); decrypt_res.analyse(); diff --git a/src/ui/main_window/MainWindowSlotFunction.cpp b/src/ui/main_window/MainWindowSlotFunction.cpp index f1432196..e05c6e13 100644 --- a/src/ui/main_window/MainWindowSlotFunction.cpp +++ b/src/ui/main_window/MainWindowSlotFunction.cpp @@ -46,181 +46,166 @@ namespace GpgFrontend::UI { * Encrypt Entry(Text & File) */ void MainWindow::slotEncrypt() { - if (edit->tabCount() == 0) return; + if (edit->tabCount() == 0 || edit->slotCurPageTextEdit() == nullptr) return; - if (edit->slotCurPageTextEdit() != nullptr) { - auto key_ids = mKeyList->getChecked(); + auto key_ids = mKeyList->getChecked(); - if (key_ids->empty()) { - QMessageBox::critical(nullptr, _("No Key Selected"), - _("No Key Selected")); - return; - } + if (key_ids->empty()) { + QMessageBox::critical(nullptr, _("No Key Selected"), _("No Key Selected")); + return; + } - auto key_getter = GpgFrontend::GpgKeyGetter::GetInstance(); - auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); - for (const auto& key : *keys) { - if (!key.CanEncrActual()) { - QMessageBox::information( - nullptr, _("Invalid Operation"), - QString(_( - "The selected key contains a key that does not actually have a " + auto key_getter = GpgFrontend::GpgKeyGetter::GetInstance(); + auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); + for (const auto& key : *keys) { + if (!key.CanEncrActual()) { + QMessageBox::information( + nullptr, _("Invalid Operation"), + QString( + _("The selected key contains a key that does not actually have a " "encrypt usage.")) + - "<br/><br/>" + _("For example the Following Key:") + " <br/>" + - QString::fromStdString(key.uids()->front().uid())); - return; - } + "<br/><br/>" + _("For example the Following Key:") + " <br/>" + + QString::fromStdString(key.uids()->front().uid())); + return; } + } - auto tmp = std::make_unique<ByteArray>(); - - GpgEncrResult result = nullptr; - GpgError error; - bool if_error = false; - process_operation(this, _("Encrypting"), [&]() { - try { - auto buffer = edit->curTextPage()->toPlainText().toUtf8().toStdString(); - error = GpgFrontend::BasicOperator::GetInstance().Encrypt( - std::move(keys), buffer, tmp, result); - } catch (const std::runtime_error& e) { - if_error = true; - } - }); + auto tmp = std::make_unique<ByteArray>(); + + GpgEncrResult result = nullptr; + GpgError error; + bool if_error = false; + process_operation(this, _("Encrypting"), [&]() { + try { + auto buffer = edit->curTextPage()->toPlainText().toUtf8().toStdString(); + error = GpgFrontend::BasicOperator::GetInstance().Encrypt( + std::move(keys), buffer, tmp, result); + } catch (const std::runtime_error& e) { + if_error = true; + } + }); - if (!if_error) { - auto resultAnalyse = EncryptResultAnalyse(error, std::move(result)); - resultAnalyse.analyse(); - process_result_analyse(edit, infoBoard, resultAnalyse); + if (!if_error) { + auto resultAnalyse = EncryptResultAnalyse(error, std::move(result)); + resultAnalyse.analyse(); + process_result_analyse(edit, infoBoard, resultAnalyse); - if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR) - edit->slotFillTextEditWithText(QString::fromStdString(*tmp)); + if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR) + edit->slotFillTextEditWithText(QString::fromStdString(*tmp)); #ifdef SMTP_SUPPORT - // set optional actions - if (resultAnalyse.getStatus() >= 0) { - infoBoard->resetOptionActionsMenu(); - infoBoard->addOptionalAction("Send Mail", [this]() { - if (settings.value("sendMail/enable", false).toBool()) - new SendMailDialog(edit->curTextPage()->toPlainText(), this); - else { - QMessageBox::warning(nullptr, _("Function Disabled"), - _("Please go to the settings interface to " - "enable and configure this function.")); - } - }); - } -#endif - - } else { - QMessageBox::critical(this, _("Error"), - _("An error occurred during operation.")); - return; + // set optional actions + if (resultAnalyse.getStatus() >= 0) { + infoBoard->resetOptionActionsMenu(); + infoBoard->addOptionalAction("Send Mail", [this]() { + if (settings.value("sendMail/enable", false).toBool()) + new SendMailDialog(edit->curTextPage()->toPlainText(), this); + else { + QMessageBox::warning(nullptr, _("Function Disabled"), + _("Please go to the settings interface to " + "enable and configure this function.")); + } + }); } +#endif - } else if (edit->slotCurPageFileTreeView() != nullptr) { - this->slotFileEncrypt(); + } else { + QMessageBox::critical(this, _("Error"), + _("An error occurred during operation.")); + return; } } void MainWindow::slotSign() { - if (edit->tabCount() == 0) return; + if (edit->tabCount() == 0 || edit->slotCurPageTextEdit() == nullptr) return; - if (edit->slotCurPageTextEdit() != nullptr) { - auto key_ids = mKeyList->getPrivateChecked(); + auto key_ids = mKeyList->getPrivateChecked(); - if (key_ids->empty()) { - QMessageBox::critical(this, _("No Key Selected"), _("No Key Selected")); - return; - } + if (key_ids->empty()) { + QMessageBox::critical(this, _("No Key Selected"), _("No Key Selected")); + return; + } - auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); - for (const auto& key : *keys) { - if (!key.CanSignActual()) { - QMessageBox::information( - this, _("Invalid Operation"), - QString(_( - "The selected key contains a key that does not actually have a " + auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); + for (const auto& key : *keys) { + if (!key.CanSignActual()) { + QMessageBox::information( + this, _("Invalid Operation"), + QString( + _("The selected key contains a key that does not actually have a " "signature usage.")) + - "<br/><br/>" + _("For example the Following Key:") + "<br/>" + - key.uids()->front().uid().c_str()); - return; - } + "<br/><br/>" + _("For example the Following Key:") + "<br/>" + + key.uids()->front().uid().c_str()); + return; } + } - auto tmp = std::make_unique<ByteArray>(); + auto tmp = std::make_unique<ByteArray>(); - GpgSignResult result = nullptr; - gpgme_error_t error; - bool if_error = false; + GpgSignResult result = nullptr; + gpgme_error_t error; + bool if_error = false; - process_operation(this, _("Signing"), [&]() { - try { - auto buffer = edit->curTextPage()->toPlainText().toUtf8().toStdString(); - error = GpgFrontend::BasicOperator::GetInstance().Sign( - std::move(keys), buffer, tmp, GPGME_SIG_MODE_CLEAR, result); - } catch (const std::runtime_error& e) { - if_error = true; - } - }); + process_operation(this, _("Signing"), [&]() { + try { + auto buffer = edit->curTextPage()->toPlainText().toUtf8().toStdString(); + error = GpgFrontend::BasicOperator::GetInstance().Sign( + std::move(keys), buffer, tmp, GPGME_SIG_MODE_CLEAR, result); + } catch (const std::runtime_error& e) { + if_error = true; + } + }); - if (!if_error) { - auto resultAnalyse = SignResultAnalyse(error, std::move(result)); - resultAnalyse.analyse(); - process_result_analyse(edit, infoBoard, resultAnalyse); + if (!if_error) { + auto resultAnalyse = SignResultAnalyse(error, std::move(result)); + resultAnalyse.analyse(); + process_result_analyse(edit, infoBoard, resultAnalyse); - if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR) - edit->slotFillTextEditWithText(QString::fromStdString(*tmp)); - } else { - QMessageBox::critical(this, _("Error"), - _("An error occurred during operation.")); - return; - } - } else if (edit->slotCurPageFileTreeView() != nullptr) { - this->slotFileSign(); + if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR) + edit->slotFillTextEditWithText(QString::fromStdString(*tmp)); + } else { + QMessageBox::critical(this, _("Error"), + _("An error occurred during operation.")); + return; } } void MainWindow::slotDecrypt() { - if (edit->tabCount() == 0) return; + if (edit->tabCount() == 0 || edit->slotCurPageTextEdit() == nullptr) return; - if (edit->slotCurPageTextEdit() != nullptr) { - auto decrypted = std::make_unique<ByteArray>(); - QByteArray text = edit->curTextPage()->toPlainText().toUtf8(); + auto decrypted = std::make_unique<ByteArray>(); + QByteArray text = edit->curTextPage()->toPlainText().toUtf8(); - if (text.trimmed().startsWith( - GpgConstants::GPG_FRONTEND_SHORT_CRYPTO_HEAD)) { - QMessageBox::critical( - this, _("Notice"), - _("Short Crypto Text only supports Decrypt & Verify.")); - return; - } + if (text.trimmed().startsWith(GpgConstants::GPG_FRONTEND_SHORT_CRYPTO_HEAD)) { + QMessageBox::critical( + this, _("Notice"), + _("Short Crypto Text only supports Decrypt & Verify.")); + return; + } - GpgDecrResult result = nullptr; - gpgme_error_t error; - bool if_error = false; - process_operation(this, _("Decrypting"), [&]() { - try { - auto buffer = text.toStdString(); - error = GpgFrontend::BasicOperator::GetInstance().Decrypt( - buffer, decrypted, result); - } catch (const std::runtime_error& e) { - if_error = true; - } - }); + GpgDecrResult result = nullptr; + gpgme_error_t error; + bool if_error = false; + process_operation(this, _("Decrypting"), [&]() { + try { + auto buffer = text.toStdString(); + error = GpgFrontend::BasicOperator::GetInstance().Decrypt( + buffer, decrypted, result); + } catch (const std::runtime_error& e) { + if_error = true; + } + }); - if (!if_error) { - auto resultAnalyse = DecryptResultAnalyse(error, std::move(result)); - resultAnalyse.analyse(); - process_result_analyse(edit, infoBoard, resultAnalyse); + if (!if_error) { + auto resultAnalyse = DecryptResultAnalyse(error, std::move(result)); + resultAnalyse.analyse(); + process_result_analyse(edit, infoBoard, resultAnalyse); - if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR) - edit->slotFillTextEditWithText(QString::fromStdString(*decrypted)); - } else { - QMessageBox::critical(this, _("Error"), - _("An error occurred during operation.")); - return; - } - } else if (edit->slotCurPageFileTreeView() != nullptr) { - this->slotFileDecrypt(); + if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR) + edit->slotFillTextEditWithText(QString::fromStdString(*decrypted)); + } else { + QMessageBox::critical(this, _("Error"), + _("An error occurred during operation.")); + return; } } @@ -237,244 +222,222 @@ void MainWindow::slotFind() { } void MainWindow::slotVerify() { - if (edit->tabCount() == 0) return; - - if (edit->slotCurPageTextEdit() != nullptr) { - auto text = edit->curTextPage()->toPlainText().toUtf8(); - // TODO(Saturneric) PreventNoDataErr - - auto sig_buffer = std::make_unique<ByteArray>(); - sig_buffer.reset(); - - GpgVerifyResult result = nullptr; - GpgError error; - bool if_error = false; - process_operation(this, _("Verifying"), [&]() { - try { - auto buffer = text.toStdString(); - error = GpgFrontend::BasicOperator::GetInstance().Verify( - buffer, sig_buffer, result); - } catch (const std::runtime_error& e) { - if_error = true; - } - }); - - if (!if_error) { - auto resultAnalyse = VerifyResultAnalyse(error, std::move(result)); - resultAnalyse.analyse(); - process_result_analyse(edit, infoBoard, resultAnalyse); - - // if (resultAnalyse->getStatus() >= 0) { - // infoBoard->resetOptionActionsMenu(); - // infoBoard->addOptionalAction( - // "Show Verify Details", [this, error, result]() { - // VerifyDetailsDialog(this, mCtx, mKeyList, error, result); - // }); - // } - - } else { - QMessageBox::critical(this, _("Error"), - _("An error occurred during operation.")); - return; + if (edit->tabCount() == 0 || edit->slotCurPageTextEdit() == nullptr) return; + + auto text = edit->curTextPage()->toPlainText().toUtf8(); + // TODO(Saturneric) PreventNoDataErr + + auto sig_buffer = std::make_unique<ByteArray>(); + sig_buffer.reset(); + + GpgVerifyResult result = nullptr; + GpgError error; + bool if_error = false; + process_operation(this, _("Verifying"), [&]() { + try { + auto buffer = text.toStdString(); + error = GpgFrontend::BasicOperator::GetInstance().Verify( + buffer, sig_buffer, result); + } catch (const std::runtime_error& e) { + if_error = true; } - } else if (edit->slotCurPageFileTreeView() != nullptr) { - this->slotFileVerify(); + }); + + if (!if_error) { + auto resultAnalyse = VerifyResultAnalyse(error, std::move(result)); + resultAnalyse.analyse(); + process_result_analyse(edit, infoBoard, resultAnalyse); + + // if (resultAnalyse->getStatus() >= 0) { + // infoBoard->resetOptionActionsMenu(); + // infoBoard->addOptionalAction( + // "Show Verify Details", [this, error, result]() { + // VerifyDetailsDialog(this, mCtx, mKeyList, error, result); + // }); + // } } } void MainWindow::slotEncryptSign() { - if (edit->tabCount() == 0) return; + if (edit->tabCount() == 0 || edit->slotCurPageTextEdit() == nullptr) return; - if (edit->slotCurPageTextEdit() != nullptr) { - auto key_ids = mKeyList->getChecked(); + auto key_ids = mKeyList->getChecked(); - if (key_ids->empty()) { - QMessageBox::critical(nullptr, _("No Key Selected"), - _("No Key Selected")); - return; - } + if (key_ids->empty()) { + QMessageBox::critical(nullptr, _("No Key Selected"), _("No Key Selected")); + return; + } - auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); + auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); - for (const auto& key : *keys) { - bool key_can_encrypt = key.CanEncrActual(); + for (const auto& key : *keys) { + bool key_can_encrypt = key.CanEncrActual(); - if (!key_can_encrypt) { - QMessageBox::critical( - nullptr, _("Invalid KeyPair"), - QString(_("The selected keypair cannot be used for encryption.")) + - "<br/><br/>" + _("For example the Following Key:") + " <br/>" + - QString::fromStdString(key.uids()->front().uid())); - return; - } + if (!key_can_encrypt) { + QMessageBox::critical( + nullptr, _("Invalid KeyPair"), + QString(_("The selected keypair cannot be used for encryption.")) + + "<br/><br/>" + _("For example the Following Key:") + " <br/>" + + QString::fromStdString(key.uids()->front().uid())); + return; } + } - auto signersPicker = new SignersPicker(this); - QEventLoop loop; - connect(signersPicker, SIGNAL(finished(int)), &loop, SLOT(quit())); - loop.exec(); + auto signersPicker = new SignersPicker(this); + QEventLoop loop; + connect(signersPicker, SIGNAL(finished(int)), &loop, SLOT(quit())); + loop.exec(); - auto signer_key_ids = signersPicker->getCheckedSigners(); - auto signer_keys = GpgKeyGetter::GetInstance().GetKeys(signer_key_ids); + auto signer_key_ids = signersPicker->getCheckedSigners(); + auto signer_keys = GpgKeyGetter::GetInstance().GetKeys(signer_key_ids); - for (const auto& key : *keys) { - LOG(INFO) << "Keys " << key.email(); - } + for (const auto& key : *keys) { + LOG(INFO) << "Keys " << key.email(); + } - for (const auto& signer : *signer_keys) { - LOG(INFO) << "Signers " << signer.email(); - } + for (const auto& signer : *signer_keys) { + LOG(INFO) << "Signers " << signer.email(); + } - GpgEncrResult encr_result = nullptr; - GpgSignResult sign_result = nullptr; - GpgError error; - bool if_error = false; - - auto tmp = std::make_unique<ByteArray>(); - process_operation(this, _("Encrypting and Signing"), [&]() { - try { - auto buffer = edit->curTextPage()->toPlainText().toUtf8().toStdString(); - error = GpgFrontend::BasicOperator::GetInstance().EncryptSign( - std::move(keys), std::move(signer_keys), buffer, tmp, encr_result, - sign_result); - } catch (const std::runtime_error& e) { - if_error = true; - } - }); + GpgEncrResult encr_result = nullptr; + GpgSignResult sign_result = nullptr; + GpgError error; + bool if_error = false; + + auto tmp = std::make_unique<ByteArray>(); + process_operation(this, _("Encrypting and Signing"), [&]() { + try { + auto buffer = edit->curTextPage()->toPlainText().toUtf8().toStdString(); + error = GpgFrontend::BasicOperator::GetInstance().EncryptSign( + std::move(keys), std::move(signer_keys), buffer, tmp, encr_result, + sign_result); + } catch (const std::runtime_error& e) { + if_error = true; + } + }); - if (!if_error) { + if (!if_error) { #ifdef ADVANCE_SUPPORT - if (settings.value("advanced/autoPubkeyExchange").toBool()) { - PubkeyUploader pubkeyUploader(mCtx, signerKeys); - pubkeyUploader.start(); - if (!pubkeyUploader.result()) { - QMessageBox::warning( - nullptr, _("Automatic Key Exchange Warning"), - _("Part of the automatic key exchange failed, " - "which may be related to your key.") + - _("If possible, try to use the RSA algorithm " - "compatible with the server for signing.")); - } + if (settings.value("advanced/autoPubkeyExchange").toBool()) { + PubkeyUploader pubkeyUploader(mCtx, signerKeys); + pubkeyUploader.start(); + if (!pubkeyUploader.result()) { + QMessageBox::warning(nullptr, _("Automatic Key Exchange Warning"), + _("Part of the automatic key exchange failed, " + "which may be related to your key.") + + _("If possible, try to use the RSA algorithm " + "compatible with the server for signing.")); } + } #endif - LOG(INFO) << "ResultAnalyse Started"; - auto encrypt_res = EncryptResultAnalyse(error, std::move(encr_result)); - auto sign_res = SignResultAnalyse(error, std::move(sign_result)); - encrypt_res.analyse(); - sign_res.analyse(); - process_result_analyse(edit, infoBoard, encrypt_res, sign_res); - if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR) - edit->slotFillTextEditWithText(QString::fromStdString(*tmp)); + LOG(INFO) << "ResultAnalyse Started"; + auto encrypt_res = EncryptResultAnalyse(error, std::move(encr_result)); + auto sign_res = SignResultAnalyse(error, std::move(sign_result)); + encrypt_res.analyse(); + sign_res.analyse(); + process_result_analyse(edit, infoBoard, encrypt_res, sign_res); + if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR) + edit->slotFillTextEditWithText(QString::fromStdString(*tmp)); #ifdef SMTP_SUPPORT - infoBoard->resetOptionActionsMenu(); - infoBoard->addOptionalAction("Send Mail", [this]() { - if (settings.value("sendMail/enable", false).toBool()) - new SendMailDialog(edit->curTextPage()->toPlainText(), this); - else { - QMessageBox::warning(nullptr, _("Function Disabled"), - _("Please go to the settings interface to " - "enable and configure this function.")); - } - }); + infoBoard->resetOptionActionsMenu(); + infoBoard->addOptionalAction("Send Mail", [this]() { + if (settings.value("sendMail/enable", false).toBool()) + new SendMailDialog(edit->curTextPage()->toPlainText(), this); + else { + QMessageBox::warning(nullptr, _("Function Disabled"), + _("Please go to the settings interface to " + "enable and configure this function.")); + } + }); #endif #ifdef ADVANCE_SUPPORT - infoBoard->addOptionalAction("Shorten Ciphertext", [this]() { - if (settings.value("general/serviceToken").toString().isEmpty()) - QMessageBox::warning(nullptr, _("Service Token Empty"), - _("Please go to the settings interface to set " - "Own Key and get Service Token.")); - else { - shortenCryptText(); - } - }); + infoBoard->addOptionalAction("Shorten Ciphertext", [this]() { + if (settings.value("general/serviceToken").toString().isEmpty()) + QMessageBox::warning(nullptr, _("Service Token Empty"), + _("Please go to the settings interface to set " + "Own Key and get Service Token.")); + else { + shortenCryptText(); + } + }); #endif - } else { - QMessageBox::critical(this, _("Error"), - _("An error occurred during operation.")); - return; - } - } else if (edit->slotCurPageFileTreeView() != nullptr) { - this->slotFileEncryptSign(); + } else { + QMessageBox::critical(this, _("Error"), + _("An error occurred during operation.")); + return; } } void MainWindow::slotDecryptVerify() { - if (edit->tabCount() == 0) return; + if (edit->tabCount() == 0 || edit->slotCurPageTextEdit() == nullptr) return; - if (edit->slotCurPageTextEdit() != nullptr) { - QString plainText = edit->curTextPage()->toPlainText(); + QString plainText = edit->curTextPage()->toPlainText(); #ifdef ADVANCE_SUPPORT - if (plainText.trimmed().startsWith( - GpgConstants::GPG_FRONTEND_SHORT_CRYPTO_HEAD)) { - auto cryptoText = getCryptText(plainText); - if (!cryptoText.isEmpty()) { - plainText = cryptoText; - } + if (plainText.trimmed().startsWith( + GpgConstants::GPG_FRONTEND_SHORT_CRYPTO_HEAD)) { + auto cryptoText = getCryptText(plainText); + if (!cryptoText.isEmpty()) { + plainText = cryptoText; } + } #endif - QByteArray text = plainText.toUtf8(); + QByteArray text = plainText.toUtf8(); - GpgDecrResult d_result = nullptr; - GpgVerifyResult v_result = nullptr; - gpgme_error_t error; - bool if_error = false; + GpgDecrResult d_result = nullptr; + GpgVerifyResult v_result = nullptr; + gpgme_error_t error; + bool if_error = false; #ifdef ADVANCE_SUPPORT - // Automatically import public keys that are not stored locally - if (settings.value("advanced/autoPubkeyExchange").toBool()) { - gpgme_verify_result_t tmp_v_result = nullptr; - auto thread = QThread::create( - [&]() { mCtx->verify(&text, nullptr, &tmp_v_result); }); - thread->start(); - while (thread->isRunning()) QApplication::processEvents(); - auto* checker = new UnknownSignersChecker(mCtx, tmp_v_result); - checker->start(); - checker->deleteLater(); - } + // Automatically import public keys that are not stored locally + if (settings.value("advanced/autoPubkeyExchange").toBool()) { + gpgme_verify_result_t tmp_v_result = nullptr; + auto thread = + QThread::create([&]() { mCtx->verify(&text, nullptr, &tmp_v_result); }); + thread->start(); + while (thread->isRunning()) QApplication::processEvents(); + auto* checker = new UnknownSignersChecker(mCtx, tmp_v_result); + checker->start(); + checker->deleteLater(); + } #endif - auto decrypted = std::make_unique<ByteArray>(); - process_operation(this, _("Decrypting and Verifying"), [&]() { - try { - auto buffer = text.toStdString(); - error = BasicOperator::GetInstance().DecryptVerify(buffer, decrypted, - d_result, v_result); - } catch (const std::runtime_error& e) { - if_error = true; - } - }); - - if (!if_error) { - infoBoard->associateFileTreeView(edit->curFilePage()); - - auto decrypt_res = DecryptResultAnalyse(error, std::move(d_result)); - auto verify_res = VerifyResultAnalyse(error, std::move(v_result)); - decrypt_res.analyse(); - verify_res.analyse(); - process_result_analyse(edit, infoBoard, decrypt_res, verify_res); - - edit->slotFillTextEditWithText(QString::fromStdString(*decrypted)); - - // if (verify_res.getStatus() >= 0) { - // infoBoard->resetOptionActionsMenu(); - // infoBoard->addOptionalAction( - // "Show Verify Details", [this, error, v_result]() { - // VerifyDetailsDialog(this, mCtx, mKeyList, error, - // v_result); - // }); - // } - } else { - QMessageBox::critical(this, _("Error"), - _("An error occurred during operation.")); - return; + auto decrypted = std::make_unique<ByteArray>(); + process_operation(this, _("Decrypting and Verifying"), [&]() { + try { + auto buffer = text.toStdString(); + error = BasicOperator::GetInstance().DecryptVerify(buffer, decrypted, + d_result, v_result); + } catch (const std::runtime_error& e) { + if_error = true; } - - } else if (edit->slotCurPageFileTreeView() != nullptr) { - this->slotFileDecryptVerify(); + }); + + if (!if_error) { + auto decrypt_res = DecryptResultAnalyse(error, std::move(d_result)); + auto verify_res = VerifyResultAnalyse(error, std::move(v_result)); + decrypt_res.analyse(); + verify_res.analyse(); + process_result_analyse(edit, infoBoard, decrypt_res, verify_res); + + edit->slotFillTextEditWithText(QString::fromStdString(*decrypted)); + + // if (verify_res.getStatus() >= 0) { + // infoBoard->resetOptionActionsMenu(); + // infoBoard->addOptionalAction( + // "Show Verify Details", [this, error, v_result]() { + // VerifyDetailsDialog(this, mCtx, mKeyList, error, + // v_result); + // }); + // } + } else { + QMessageBox::critical(this, _("Error"), + _("An error occurred during operation.")); + return; } } diff --git a/src/ui/main_window/MainWindowUI.cpp b/src/ui/main_window/MainWindowUI.cpp index ee7a1bc0..b56472e4 100644 --- a/src/ui/main_window/MainWindowUI.cpp +++ b/src/ui/main_window/MainWindowUI.cpp @@ -45,7 +45,8 @@ void MainWindow::createActions() { openAct->setToolTip(_("Open an existing file")); connect(openAct, SIGNAL(triggered()), edit, SLOT(slotOpen())); - browserAct = new QAction(_("Browser"), this); + browserAct = new QAction(_("File Browser"), this); + browserAct->setIcon(QIcon(":file-browser.png")); browserAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_B)); browserAct->setToolTip(_("Open a file browser")); connect(browserAct, SIGNAL(triggered()), this, SLOT(slotOpenFileTab())); @@ -406,7 +407,7 @@ void MainWindow::createToolBars() { fileToolBar->addAction(newTabAct); fileToolBar->addAction(openAct); fileToolBar->addAction(saveAct); - fileToolBar->hide(); + fileToolBar->addAction(browserAct); viewMenu->addAction(fileToolBar->toggleViewAction()); cryptToolBar = addToolBar(_("Crypt")); @@ -429,6 +430,7 @@ void MainWindow::createToolBars() { editToolBar->addAction(copyAct); editToolBar->addAction(pasteAct); editToolBar->addAction(selectAllAct); + editToolBar->hide(); viewMenu->addAction(editToolBar->toggleViewAction()); specialEditToolBar = addToolBar(_("Special Edit")); @@ -446,15 +448,6 @@ void MainWindow::createToolBars() { importButton->setToolTip(_("Import key from...")); importButton->setText(_("Import key")); keyToolBar->addWidget(importButton); - - // Add dropdown menu for file encryption/decryption to crypttoolbar - fileEncButton = new QToolButton(); - connect(fileEncButton, SIGNAL(clicked(bool)), this, SLOT(slotOpenFileTab())); - fileEncButton->setPopupMode(QToolButton::InstantPopup); - fileEncButton->setIcon(QIcon(":fileencryption.png")); - fileEncButton->setToolTip(_("Browser to view and operate file")); - fileEncButton->setText(_("Browser")); - fileToolBar->addWidget(fileEncButton); } void MainWindow::createStatusBar() { @@ -469,7 +462,6 @@ void MainWindow::createStatusBar() { statusBarIcon->setPixmap(*pixmap); statusBar()->insertPermanentWidget(0, statusBarIcon, 0); - statusBarIcon->hide(); statusBar()->showMessage(_("Ready"), 2000); statusBarBox->setLayout(statusBarBoxLayout); } @@ -483,6 +475,33 @@ void MainWindow::createDockWindows() { Qt::RightDockWidgetArea); keyListDock->setMinimumWidth(460); addDockWidget(Qt::RightDockWidgetArea, keyListDock); + + mKeyList->addListGroupTab( + _("Default"), KeyListRow::SECRET_OR_PUBLIC_KEY, + KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress | + KeyListColumn::Usage | KeyListColumn::Validity, + [](const GpgKey& key) -> bool { + return !(key.revoked() || key.disabled() || key.expired()); + }); + + mKeyList->addListGroupTab( + _("Only Public Key"), KeyListRow::SECRET_OR_PUBLIC_KEY, + KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress | + KeyListColumn::Usage | KeyListColumn::Validity, + [](const GpgKey& key) -> bool { + return !key.is_private_key() && + !(key.revoked() || key.disabled() || key.expired()); + }); + + mKeyList->addListGroupTab( + _("Has Private Key"), KeyListRow::SECRET_OR_PUBLIC_KEY, + KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress | + KeyListColumn::Usage | KeyListColumn::Validity, + [](const GpgKey& key) -> bool { + return key.is_private_key() && + !(key.revoked() || key.disabled() || key.expired()); + }); + keyListDock->setWidget(mKeyList); viewMenu->addAction(keyListDock->toggleViewAction()); diff --git a/src/ui/widgets/FilePage.cpp b/src/ui/widgets/FilePage.cpp index 2c8df5e4..073ccf6b 100644 --- a/src/ui/widgets/FilePage.cpp +++ b/src/ui/widgets/FilePage.cpp @@ -26,13 +26,13 @@ #include <boost/filesystem.hpp> -#include "MainWindow.h" +#include "ui/MainWindow.h" +#include "ui/SignalStation.h" namespace GpgFrontend::UI { FilePage::FilePage(QWidget* parent) : QWidget(parent) { firstParent = parent; - LOG(INFO) << "New File Page"; dirModel = new QFileSystemModel(); dirModel->setRootPath(QDir::currentPath()); @@ -86,8 +86,6 @@ FilePage::FilePage(QWidget* parent) : QWidget(parent) { menuLayout->setStretchFactor(pathEdit, 10); menuLayout->addWidget(goPathButton); menuLayout->setStretchFactor(goPathButton, 1); - // menuLayout->addWidget(refreshButton); - // menuLayout->setStretchFactor(refreshButton, 1); auto* layout = new QVBoxLayout(); layout->setContentsMargins(0, 0, 0, 0); @@ -99,20 +97,21 @@ FilePage::FilePage(QWidget* parent) : QWidget(parent) { this->setLayout(layout); - connect(dirTreeView, SIGNAL(clicked(const QModelIndex&)), this, - SLOT(fileTreeViewItemClicked(const QModelIndex&))); - connect(dirTreeView, SIGNAL(doubleClicked(const QModelIndex&)), this, - SLOT(fileTreeViewItemDoubleClicked(const QModelIndex&))); - connect(dirTreeView, SIGNAL(customContextMenuRequested(const QPoint&)), this, - SLOT(onCustomContextMenu(const QPoint&))); + connect(dirTreeView, &QTreeView::clicked, this, + &FilePage::fileTreeViewItemClicked); + connect(dirTreeView, &QTreeView::doubleClicked, this, + &FilePage::fileTreeViewItemDoubleClicked); + connect(dirTreeView, &QTreeView::customContextMenuRequested, this, + &FilePage::onCustomContextMenu); - // refresh - slotGoPath(); + connect(this, &FilePage::signalRefreshInfoBoard, SignalStation::GetInstance(), + &SignalStation::signalRefreshInfoBoard); } void FilePage::fileTreeViewItemClicked(const QModelIndex& index) { selectedPath = boost::filesystem::path( dirModel->fileInfo(index).absoluteFilePath().toStdString()); + mPath = selectedPath; LOG(INFO) << "selected path" << selectedPath; } @@ -121,51 +120,42 @@ void FilePage::slotUpLevel() { mPath = boost::filesystem::path( dirModel->fileInfo(currentRoot).absoluteFilePath().toStdString()); - + LOG(INFO) << "get path" << mPath; if (mPath.has_parent_path()) { mPath = mPath.parent_path(); - auto fileInfo = QFileInfo(QString::fromStdString(mPath.string())); - if (fileInfo.isDir() && fileInfo.isReadable() && fileInfo.isExecutable()) { - pathEdit->setText(QString::fromStdString(mPath.string())); - slotGoPath(); - } - LOG(INFO) << "Current Root mPath" << mPath; - emit pathChanged(QString::fromStdString(mPath.string())); + LOG(INFO) << "parent path" << mPath; + pathEdit->setText(mPath.string().c_str()); + slotGoPath(); } } void FilePage::fileTreeViewItemDoubleClicked(const QModelIndex& index) { - mPath = boost::filesystem::path( - dirModel->fileInfo(index).absoluteFilePath().toStdString()); - auto fileInfo = QFileInfo(QString::fromStdString(mPath.string())); - auto targetModelIndex = - dirTreeView->model()->index(index.row(), 0, index.parent()); - if (fileInfo.isDir() && fileInfo.isReadable() && fileInfo.isExecutable()) { - dirTreeView->setRootIndex(targetModelIndex); - pathEdit->setText(QString::fromStdString(mPath.string())); - } - for (int i = 1; i < dirModel->columnCount(); ++i) - dirTreeView->resizeColumnToContents(i); - LOG(INFO) << "Index mPath" << mPath; - emit pathChanged(QString::fromStdString(mPath.string())); + pathEdit->setText(dirModel->fileInfo(index).absoluteFilePath()); + slotGoPath(); } -QString FilePage::getSelected() const { return QString::fromStdString(selectedPath.string()); } +QString FilePage::getSelected() const { + return QString::fromStdString(selectedPath.string()); +} void FilePage::slotGoPath() { - qDebug() << "getSelected" << pathEdit->text(); - auto fileInfo = QFileInfo(pathEdit->text()); + const auto path_edit = pathEdit->text().toStdString(); + LOG(INFO) << "get path edit" << path_edit; + if (mPath.string() != path_edit) mPath = path_edit; + auto fileInfo = QFileInfo(mPath.string().c_str()); if (fileInfo.isDir() && fileInfo.isReadable() && fileInfo.isExecutable()) { mPath = boost::filesystem::path(fileInfo.filePath().toStdString()); - LOG(INFO) << "Set Path" << mPath; + LOG(INFO) << "set path" << mPath; dirTreeView->setRootIndex(dirModel->index(fileInfo.filePath())); - for (int i = 1; i < dirModel->columnCount(); ++i) + for (int i = 1; i < dirModel->columnCount(); ++i) { dirTreeView->resizeColumnToContents(i); + } + pathEdit->setText(mPath.generic_path().string().c_str()); } else { - QMessageBox::critical(this, "Error", - "The path is unprivileged or unreachable."); + QMessageBox::critical(this, _("Error"), + _("The path is unprivileged or unreachable.")); } - emit pathChanged(QString::fromStdString(mPath.string())); + emit pathChanged(mPath.string().c_str()); } void FilePage::createPopupMenu() { @@ -173,35 +163,47 @@ void FilePage::createPopupMenu() { auto openItemAct = new QAction(_("Open"), this); connect(openItemAct, SIGNAL(triggered()), this, SLOT(slotOpenItem())); + auto renameItemAct = new QAction(_("Rename"), this); + connect(renameItemAct, SIGNAL(triggered()), this, SLOT(slotRenameItem())); auto deleteItemAct = new QAction(_("Delete"), this); connect(deleteItemAct, SIGNAL(triggered()), this, SLOT(slotDeleteItem())); - encryptItemAct = new QAction(_("Encrypt and Sign"), this); + encryptItemAct = new QAction(_("Encrypt Sign"), this); connect(encryptItemAct, SIGNAL(triggered()), this, SLOT(slotEncryptItem())); - decryptItemAct = new QAction(_("Decrypt and Verify"), this); + decryptItemAct = + new QAction(QString(_("Decrypt Verify")) + " " + _("(.gpg .asc)"), this); connect(decryptItemAct, SIGNAL(triggered()), this, SLOT(slotDecryptItem())); - signItemAct = new QAction(_("Only Sign"), this); + signItemAct = new QAction(_("Sign"), this); connect(signItemAct, SIGNAL(triggered()), this, SLOT(slotSignItem())); - verifyItemAct = new QAction(_("Only Verify"), this); + verifyItemAct = + new QAction(QString(_("Verify")) + " " + _("(.sig .gpg .asc)"), this); connect(verifyItemAct, SIGNAL(triggered()), this, SLOT(slotVerifyItem())); + auto hashItemAct = new QAction(_("Calculate Hash"), this); + connect(hashItemAct, SIGNAL(triggered()), this, SLOT(slotCalculateHash())); + popUpMenu->addAction(openItemAct); + popUpMenu->addAction(renameItemAct); popUpMenu->addAction(deleteItemAct); popUpMenu->addSeparator(); popUpMenu->addAction(encryptItemAct); popUpMenu->addAction(decryptItemAct); popUpMenu->addAction(signItemAct); popUpMenu->addAction(verifyItemAct); + popUpMenu->addSeparator(); + popUpMenu->addAction(hashItemAct); } void FilePage::onCustomContextMenu(const QPoint& point) { QModelIndex index = dirTreeView->indexAt(point); selectedPath = boost::filesystem::path( dirModel->fileInfo(index).absoluteFilePath().toStdString()); - LOG(INFO) << "FilePage::onCustomContextMenu Right Click" << selectedPath; + LOG(INFO) << "right click" << selectedPath; if (index.isValid()) { QFileInfo info(QString::fromStdString(selectedPath.string())); encryptItemAct->setEnabled( info.isFile() && (info.suffix() != "gpg" && info.suffix() != "sig")); + encryptItemAct->setEnabled( + info.isFile() && (info.suffix() != "gpg" && info.suffix() != "sig")); decryptItemAct->setEnabled(info.isFile() && info.suffix() == "gpg"); signItemAct->setEnabled(info.isFile() && (info.suffix() != "gpg" && info.suffix() != "sig")); @@ -215,21 +217,49 @@ void FilePage::onCustomContextMenu(const QPoint& point) { void FilePage::slotOpenItem() { QFileInfo info(QString::fromStdString(selectedPath.string())); if (info.isDir()) { - LOG(INFO) << "FilePage::slotOpenItem getSelected" - << pathEdit->text().toStdString(); if (info.isReadable() && info.isExecutable()) { - LOG(INFO) << "FilePage::slotOpenItem Set Path" - << info.filePath().toStdString(); - dirTreeView->setRootIndex(dirModel->index(info.filePath())); + const auto file_path = info.filePath().toStdString(); + LOG(INFO) << "set path" << file_path; + pathEdit->setText(info.filePath()); + slotGoPath(); } else { - QMessageBox::critical(this, "Error", - "The path is unprivileged or unreachable."); + QMessageBox::critical(this, _("Error"), + _("The directory is unprivileged or unreachable.")); } } else { - auto mainWindow = qobject_cast<MainWindow*>(firstParent); - LOG(INFO) << "FilePage::slotOpenItem Open Item" << selectedPath; - auto qt_path = QString::fromStdString(selectedPath.string()); - if (mainWindow != nullptr) mainWindow->slotOpenFile(qt_path); + if (info.isReadable()) { + auto mainWindow = qobject_cast<MainWindow*>(firstParent); + LOG(INFO) << "open item" << selectedPath; + auto qt_path = QString::fromStdString(selectedPath.string()); + if (mainWindow != nullptr) mainWindow->slotOpenFile(qt_path); + } else { + QMessageBox::critical(this, _("Error"), + _("The file is unprivileged or unreachable.")); + } + } +} + +void FilePage::slotRenameItem() { + auto new_name_path = selectedPath, old_name_path = selectedPath; + auto old_name = old_name_path.filename(); + new_name_path = new_name_path.remove_filename(); + + bool ok; + auto text = + QInputDialog::getText(this, _("Rename"), _("New Filename"), + QLineEdit::Normal, old_name.string().c_str(), &ok); + if (ok && !text.isEmpty()) { + try { + new_name_path /= text.toStdString(); + LOG(INFO) << "new name path" << new_name_path; + boost::filesystem::rename(old_name_path, new_name_path); + // refresh + this->slotGoPath(); + } catch (...) { + LOG(ERROR) << "rename error" << new_name_path; + QMessageBox::critical(this, _("Error"), + _("Unable to rename the file or folder.")); + } } } @@ -271,6 +301,52 @@ void FilePage::slotVerifyItem() { if (mainWindow != nullptr) mainWindow->slotFileVerify(); } +void FilePage::slotCalculateHash() { + // Returns empty QByteArray() on failure. + QFileInfo info(QString::fromStdString(selectedPath.string())); + + if (info.isFile() && info.isReadable()) { + std::stringstream ss; + + ss << "[#] " << _("File Hash") << std::endl; + ss << " " << _("filename") << _(": ") + << selectedPath.filename().string().c_str() << std::endl; + + QFile f(info.filePath()); + f.open(QFile::ReadOnly); + auto buffer = f.readAll(); + LOG(INFO) << "buffer size" << buffer.size(); + f.close(); + if (f.open(QFile::ReadOnly)) { + auto hash_md5 = QCryptographicHash(QCryptographicHash::Md5); + // md5 + hash_md5.addData(buffer); + auto md5 = hash_md5.result().toHex().toStdString(); + LOG(INFO) << "md5" << md5; + ss << " " << _("md5") << _(": ") << md5 << std::endl; + + auto hash_sha1 = QCryptographicHash(QCryptographicHash::Sha1); + // sha1 + hash_sha1.addData(buffer); + auto sha1 = hash_sha1.result().toHex().toStdString(); + LOG(INFO) << "sha1" << sha1; + ss << " " << _("sha1") << _(": ") << sha1 << std::endl; + + auto hash_sha256 = QCryptographicHash(QCryptographicHash::Sha256); + // sha1 + hash_sha256.addData(buffer); + auto sha256 = hash_sha256.result().toHex().toStdString(); + LOG(INFO) << "sha256" << sha256; + ss << " " << _("sha256") << _(": ") << sha256 << std::endl; + + ss << std::endl; + + emit signalRefreshInfoBoard(ss.str().c_str(), + InfoBoardStatus::INFO_ERROR_OK); + } + } +} + void FilePage::keyPressEvent(QKeyEvent* event) { qDebug() << "Key Press" << event->key(); if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) { diff --git a/src/ui/widgets/FilePage.h b/src/ui/widgets/FilePage.h index 31be81f3..8533aaac 100644 --- a/src/ui/widgets/FilePage.h +++ b/src/ui/widgets/FilePage.h @@ -28,6 +28,7 @@ #include <boost/filesystem.hpp> #include "ui/GpgFrontendUI.h" +#include "ui/widgets/InfoBoardWidget.h" namespace GpgFrontend::UI { @@ -38,25 +39,30 @@ class FilePage : public QWidget { [[nodiscard]] QString getSelected() const; - void createPopupMenu(); + public slots: + void slotGoPath(); signals: void pathChanged(const QString& path); + void signalRefreshInfoBoard(const QString& text, + InfoBoardStatus verify_label_status); + private slots: void fileTreeViewItemClicked(const QModelIndex& index); void fileTreeViewItemDoubleClicked(const QModelIndex& index); void slotUpLevel(); - void slotGoPath(); - + void slotOpenItem(); + void slotRenameItem(); void slotDeleteItem(); void slotEncryptItem(); void slotDecryptItem(); void slotSignItem(); void slotVerifyItem(); + void slotCalculateHash(); void onCustomContextMenu(const QPoint& point); @@ -64,6 +70,8 @@ class FilePage : public QWidget { void keyPressEvent(QKeyEvent* event) override; private: + void createPopupMenu(); + QFileSystemModel* dirModel; QTreeView* dirTreeView; QLineEdit* pathEdit; diff --git a/src/ui/widgets/InfoBoardWidget.cpp b/src/ui/widgets/InfoBoardWidget.cpp index cd469422..0f3a1f74 100644 --- a/src/ui/widgets/InfoBoardWidget.cpp +++ b/src/ui/widgets/InfoBoardWidget.cpp @@ -24,6 +24,7 @@ #include "ui/widgets/InfoBoardWidget.h" +#include "ui/SignalStation.h" #include "ui/settings/GlobalSettingStation.h" namespace GpgFrontend::UI { @@ -81,6 +82,9 @@ InfoBoardWidget::InfoBoardWidget(QWidget* parent, KeyList* keyList) notificationWidgetLayout->addStretch(0); this->setLayout(notificationWidgetLayout); + connect(SignalStation::GetInstance(), &SignalStation::signalRefreshInfoBoard, + this, &InfoBoardWidget::slotRefresh); + // set default size infoBoard->resize(480, 120); resize(480, 120); @@ -145,15 +149,6 @@ void InfoBoardWidget::associateTextEdit(QTextEdit* edit) { connect(edit, SIGNAL(textChanged()), this, SLOT(slotReset())); } -void InfoBoardWidget::associateFileTreeView(FilePage* treeView) { - // if (mFileTreeView != nullptr) - // disconnect(mFileTreeView, &FilePage::pathChanged, this, - // &InfoBoardWidget::slotReset); - // this->mFileTreeView = treeView; - // connect(treeView, &FilePage::pathChanged, this, - // &InfoBoardWidget::slotReset); -} - void InfoBoardWidget::associateTabWidget(QTabWidget* tab) { if (mTextPage != nullptr) disconnect(mTextPage, SIGNAL(textChanged()), this, SLOT(slotReset())); @@ -167,7 +162,6 @@ void InfoBoardWidget::associateTabWidget(QTabWidget* tab) { } mTextPage = nullptr; - mFileTreeView = nullptr; mTabWidget = tab; connect(tab, SIGNAL(tabBarClicked(int)), this, SLOT(slotReset())); connect(tab, SIGNAL(tabCloseRequested(int)), this, SLOT(slotReset())); diff --git a/src/ui/widgets/InfoBoardWidget.h b/src/ui/widgets/InfoBoardWidget.h index 1a13e1a2..3c43f733 100644 --- a/src/ui/widgets/InfoBoardWidget.h +++ b/src/ui/widgets/InfoBoardWidget.h @@ -26,11 +26,11 @@ #define __VERIFYNOTIFICATION_H__ #include "EditorPage.h" -#include "FilePage.h" #include "gpg/result_analyse/VerifyResultAnalyse.h" #include "ui/VerifyDetailsDialog.h" namespace GpgFrontend::UI { + /** * @details Enumeration for the status of Verifylabel */ @@ -57,8 +57,6 @@ class InfoBoardWidget : public QWidget { void associateTextEdit(QTextEdit* edit); - void associateFileTreeView(FilePage* treeView); - void associateTabWidget(QTabWidget* tab); void addOptionalAction(const QString& name, @@ -100,8 +98,6 @@ class InfoBoardWidget : public QWidget { KeyList* mKeyList; /** Table holding the keys */ QTextEdit* mTextPage{nullptr}; /** TextEdit associated to the notification */ - FilePage* mFileTreeView{ - nullptr}; /** TreeView associated to the notification */ QTabWidget* mTabWidget{ nullptr}; /** TreeView associated to the notification */ diff --git a/src/ui/widgets/KeyList.cpp b/src/ui/widgets/KeyList.cpp index f9f33d78..83ffcbb5 100644 --- a/src/ui/widgets/KeyList.cpp +++ b/src/ui/widgets/KeyList.cpp @@ -31,61 +31,24 @@ namespace GpgFrontend::UI { -KeyList::KeyList(KeyListRow::KeyType selectType, - KeyListColumn::InfoType infoType, QWidget* parent) - : QWidget(parent), - appPath(qApp->applicationDirPath()), - settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", - QSettings::IniFormat), - mSelectType(selectType), - mInfoType(infoType) { - mKeyList = new QTableWidget(this); - mKeyList->setColumnCount(7); - mKeyList->horizontalHeader()->setSectionResizeMode( - QHeaderView::ResizeToContents); - mKeyList->verticalHeader()->hide(); - mKeyList->setShowGrid(false); - mKeyList->sortByColumn(2, Qt::AscendingOrder); - mKeyList->setSelectionBehavior(QAbstractItemView::SelectRows); - mKeyList->setSelectionMode(QAbstractItemView::SingleSelection); - - // table items not editable - mKeyList->setEditTriggers(QAbstractItemView::NoEditTriggers); - // no focus (rectangle around table items) - // maybe it should focus on whole row - mKeyList->setFocusPolicy(Qt::NoFocus); - - mKeyList->setAlternatingRowColors(true); - - // Hidden Column For Purpose - if (!(mInfoType & KeyListColumn::TYPE)) { - mKeyList->setColumnHidden(1, true); - } - if (!(mInfoType & KeyListColumn::NAME)) { - mKeyList->setColumnHidden(2, true); - } - if (!(mInfoType & KeyListColumn::EmailAddress)) { - mKeyList->setColumnHidden(3, true); - } - if (!(mInfoType & KeyListColumn::Usage)) { - mKeyList->setColumnHidden(4, true); - } - if (!(mInfoType & KeyListColumn::Validity)) { - mKeyList->setColumnHidden(5, true); - } - if (!(mInfoType & KeyListColumn::FingerPrint)) { - mKeyList->setColumnHidden(6, true); - } +KeyList::KeyList(QWidget* parent) : QWidget(parent) { init(); } - QStringList labels; - labels << _("Select") << _("Type") << _("Name") << _("Email Address") - << _("Usage") << _("Validity") << _("Finger Print"); +KeyList::KeyList(KeyListRow::KeyType selectType, + KeyListColumn::InfoType infoType, + const std::function<bool(const GpgKey&)>& filter, + QWidget* parent) + : QWidget(parent) { + init(); + addListGroupTab("Default", selectType, infoType, filter); +} - mKeyList->setHorizontalHeaderLabels(labels); - mKeyList->horizontalHeader()->setStretchLastSection(false); +void KeyList::init() { + mGroupTab = new QTabWidget(); + mGroupTab->setMovable(true); + mGroupTab->setTabsClosable(false); auto* layout = new QVBoxLayout; - layout->addWidget(mKeyList); + layout->addWidget(mGroupTab); layout->setContentsMargins(0, 0, 0, 0); layout->setSpacing(3); setLayout(layout); @@ -95,136 +58,97 @@ KeyList::KeyList(KeyListRow::KeyType selectType, // register key database refresh signal connect(SignalStation::GetInstance(), SIGNAL(KeyDatabaseRefresh()), this, SLOT(slotRefresh())); - connect(mKeyList, SIGNAL(doubleClicked(const QModelIndex&)), this, - SLOT(slotDoubleClicked(const QModelIndex&))); setAcceptDrops(true); - slotRefresh(); } -void KeyList::slotRefresh() { - LOG(INFO) << "KeyList::slotRefresh Called"; - - auto keyList = getChecked(); - // while filling the table, sort enabled causes errors - mKeyList->setSortingEnabled(false); - mKeyList->clearContents(); - - auto keys = GpgKeyGetter::GetInstance().FetchKey(); - - auto it = keys->begin(); - - int row_count = 0; - - while (it != keys->end()) { - if (mFilter != nullptr) { - if (!mFilter(*it)) { - it = keys->erase(it); - continue; - } - } - if (!excluded_key_ids.empty()) { - auto iterator = - std::find_if(excluded_key_ids.begin(), excluded_key_ids.end(), - [it](const auto& key_id) -> bool { - if (it->id() == key_id) - return true; - else - return false; - }); - - if (iterator != excluded_key_ids.end()) { - it = keys->erase(it); - continue; - } - } - if (mSelectType == KeyListRow::ONLY_SECRET_KEY && !it->is_private_key()) { - it = keys->erase(it); - continue; - } - row_count++; - it++; +void KeyList::addListGroupTab( + const QString& name, KeyListRow::KeyType selectType, + KeyListColumn::InfoType infoType, + const std::function<bool(const GpgKey&)>& filter) { + auto key_list = new QTableWidget(this); + if (mKeyList == nullptr) { + mKeyList = key_list; } + mGroupTab->addTab(key_list, name); + mKeyTables.emplace_back(key_list, selectType, infoType, filter); - mKeyList->setRowCount(row_count); - - int row_index = 0; - it = keys->begin(); - buffered_keys.clear(); + key_list->setColumnCount(7); + key_list->horizontalHeader()->setSectionResizeMode( + QHeaderView::ResizeToContents); + key_list->verticalHeader()->hide(); + key_list->setShowGrid(false); + key_list->sortByColumn(2, Qt::AscendingOrder); + key_list->setSelectionBehavior(QAbstractItemView::SelectRows); + key_list->setSelectionMode(QAbstractItemView::SingleSelection); - while (it != keys->end()) { - buffered_keys.push_back(GpgKeyGetter::GetInstance().GetKey(it->id())); + // table items not editable + key_list->setEditTriggers(QAbstractItemView::NoEditTriggers); + // no focus (rectangle around table items) + // maybe it should focus on whole row + key_list->setFocusPolicy(Qt::NoFocus); - auto* tmp0 = new QTableWidgetItem(QString::number(row_index)); - tmp0->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | - Qt::ItemIsSelectable); - tmp0->setTextAlignment(Qt::AlignCenter); - tmp0->setCheckState(Qt::Unchecked); - mKeyList->setItem(row_index, 0, tmp0); + key_list->setAlternatingRowColors(true); - QString type_str; - QTextStream type_steam(&type_str); - if (it->is_private_key()) { - type_steam << "pub/sec"; - } else { - type_steam << "pub"; - } - - if (it->is_private_key() && !it->has_master_key()) { - type_steam << "#"; - } - auto* tmp1 = new QTableWidgetItem(type_str); - mKeyList->setItem(row_index, 1, tmp1); + // Hidden Column For Purpose + if (!(infoType & KeyListColumn::TYPE)) { + key_list->setColumnHidden(1, true); + } + if (!(infoType & KeyListColumn::NAME)) { + key_list->setColumnHidden(2, true); + } + if (!(infoType & KeyListColumn::EmailAddress)) { + key_list->setColumnHidden(3, true); + } + if (!(infoType & KeyListColumn::Usage)) { + key_list->setColumnHidden(4, true); + } + if (!(infoType & KeyListColumn::Validity)) { + key_list->setColumnHidden(5, true); + } + if (!(infoType & KeyListColumn::FingerPrint)) { + key_list->setColumnHidden(6, true); + } - auto* tmp2 = new QTableWidgetItem(QString::fromStdString(it->name())); - mKeyList->setItem(row_index, 2, tmp2); - auto* tmp3 = new QTableWidgetItem(QString::fromStdString(it->email())); - mKeyList->setItem(row_index, 3, tmp3); + QStringList labels; + labels << _("Select") << _("Type") << _("Name") << _("Email Address") + << _("Usage") << _("Validity") << _("Finger Print"); - QString usage; - QTextStream usage_steam(&usage); + key_list->setHorizontalHeaderLabels(labels); + key_list->horizontalHeader()->setStretchLastSection(false); - if (it->CanCertActual()) usage_steam << "C"; - if (it->CanEncrActual()) usage_steam << "E"; - if (it->CanSignActual()) usage_steam << "S"; - if (it->CanAuthActual()) usage_steam << "A"; + connect(key_list, &QTableWidget::doubleClicked, this, + &KeyList::slotDoubleClicked); - auto* temp_usage = new QTableWidgetItem(usage); - temp_usage->setTextAlignment(Qt::AlignCenter); - mKeyList->setItem(row_index, 4, temp_usage); + // refresh + mKeyTables.back().Refresh(); +} - auto* temp_validity = - new QTableWidgetItem(QString::fromStdString(it->owner_trust())); - temp_validity->setTextAlignment(Qt::AlignCenter); - mKeyList->setItem(row_index, 5, temp_validity); +void KeyList::slotRefresh() { + LOG(INFO) << _("called"); - auto* temp_fpr = new QTableWidgetItem(QString::fromStdString(it->fpr())); - temp_fpr->setTextAlignment(Qt::AlignCenter); - mKeyList->setItem(row_index, 6, temp_fpr); + for (auto& key_table : mKeyTables) { + key_table.Refresh(); + } +} - // strike out expired keys - if (it->expired() || it->revoked()) { - QFont strike = tmp2->font(); - strike.setStrikeOut(true); - tmp0->setFont(strike); - temp_usage->setFont(strike); - temp_fpr->setFont(strike); - temp_validity->setFont(strike); - tmp1->setFont(strike); - tmp2->setFont(strike); - tmp3->setFont(strike); +KeyIdArgsListPtr KeyList::getChecked(const KeyTable& key_table) { + auto ret = std::make_unique<KeyIdArgsList>(); + for (int i = 0; i < key_table.key_list->rowCount(); i++) { + if (key_table.key_list->item(i, 0)->checkState() == Qt::Checked) { + ret->push_back(key_table.buffered_keys[i].id()); } - it++; - ++row_index; } - - setChecked(keyList); + return ret; } KeyIdArgsListPtr KeyList::getChecked() { + auto key_list = qobject_cast<QTableWidget*>(mGroupTab->currentWidget()); + const auto& buffered_keys = + mKeyTables[mGroupTab->currentIndex()].buffered_keys; auto ret = std::make_unique<KeyIdArgsList>(); - for (int i = 0; i < mKeyList->rowCount(); i++) { - if (mKeyList->item(i, 0)->checkState() == Qt::Checked) { + for (int i = 0; i < key_list->rowCount(); i++) { + if (key_list->item(i, 0)->checkState() == Qt::Checked) { ret->push_back(buffered_keys[i].id()); } } @@ -232,9 +156,12 @@ KeyIdArgsListPtr KeyList::getChecked() { } KeyIdArgsListPtr KeyList::getAllPrivateKeys() { + auto key_list = qobject_cast<QTableWidget*>(mGroupTab->currentWidget()); + const auto& buffered_keys = + mKeyTables[mGroupTab->currentIndex()].buffered_keys; auto ret = std::make_unique<KeyIdArgsList>(); - for (int i = 0; i < mKeyList->rowCount(); i++) { - if (mKeyList->item(i, 1) && buffered_keys[i].is_private_key()) { + for (int i = 0; i < key_list->rowCount(); i++) { + if (key_list->item(i, 1) && buffered_keys[i].is_private_key()) { ret->push_back(buffered_keys[i].id()); } } @@ -243,21 +170,44 @@ KeyIdArgsListPtr KeyList::getAllPrivateKeys() { KeyIdArgsListPtr KeyList::getPrivateChecked() { auto ret = std::make_unique<KeyIdArgsList>(); - for (int i = 0; i < mKeyList->rowCount(); i++) { - if ((mKeyList->item(i, 0)->checkState() == Qt::Checked) && - (mKeyList->item(i, 1))) { + if (mGroupTab->size().isEmpty()) return ret; + + auto key_list = qobject_cast<QTableWidget*>(mGroupTab->currentWidget()); + const auto& buffered_keys = + mKeyTables[mGroupTab->currentIndex()].buffered_keys; + + for (int i = 0; i < key_list->rowCount(); i++) { + if ((key_list->item(i, 0)->checkState() == Qt::Checked) && + (key_list->item(i, 1))) { ret->push_back(buffered_keys[i].id()); } } return ret; } +void KeyList::setChecked(const KeyIdArgsListPtr& keyIds, + const KeyTable& key_table) { + if (!keyIds->empty()) { + for (int i = 0; i < key_table.key_list->rowCount(); i++) { + if (std::find(keyIds->begin(), keyIds->end(), + key_table.buffered_keys[i].id()) != keyIds->end()) { + key_table.key_list->item(i, 0)->setCheckState(Qt::Checked); + } + } + } +} + void KeyList::setChecked(const KeyIdArgsListPtr& keyIds) { + if (mGroupTab->size().isEmpty()) return; + auto key_list = qobject_cast<QTableWidget*>(mGroupTab->currentWidget()); + const auto& buffered_keys = + mKeyTables[mGroupTab->currentIndex()].buffered_keys; + if (!keyIds->empty()) { - for (int i = 0; i < mKeyList->rowCount(); i++) { + for (int i = 0; i < key_list->rowCount(); i++) { if (std::find(keyIds->begin(), keyIds->end(), buffered_keys[i].id()) != keyIds->end()) { - mKeyList->item(i, 0)->setCheckState(Qt::Checked); + key_list->item(i, 0)->setCheckState(Qt::Checked); } } } @@ -265,9 +215,14 @@ void KeyList::setChecked(const KeyIdArgsListPtr& keyIds) { KeyIdArgsListPtr KeyList::getSelected() { auto ret = std::make_unique<KeyIdArgsList>(); + if (mGroupTab->size().isEmpty()) return ret; - for (int i = 0; i < mKeyList->rowCount(); i++) { - if (mKeyList->item(i, 0)->isSelected() == 1) { + auto key_list = qobject_cast<QTableWidget*>(mGroupTab->currentWidget()); + const auto& buffered_keys = + mKeyTables[mGroupTab->currentIndex()].buffered_keys; + + for (int i = 0; i < key_list->rowCount(); i++) { + if (key_list->item(i, 0)->isSelected() == 1) { ret->push_back(buffered_keys[i].id()); } } @@ -275,6 +230,9 @@ KeyIdArgsListPtr KeyList::getSelected() { } [[maybe_unused]] bool KeyList::containsPrivateKeys() { + if (mGroupTab->size().isEmpty()) return false; + mKeyList = qobject_cast<QTableWidget*>(mGroupTab->currentWidget()); + for (int i = 0; i < mKeyList->rowCount(); i++) { if (mKeyList->item(i, 1)) { return true; @@ -284,10 +242,16 @@ KeyIdArgsListPtr KeyList::getSelected() { } void KeyList::setColumnWidth(int row, int size) { + if (mGroupTab->size().isEmpty()) return; + mKeyList = qobject_cast<QTableWidget*>(mGroupTab->currentWidget()); + mKeyList->setColumnWidth(row, size); } void KeyList::contextMenuEvent(QContextMenuEvent* event) { + if (mGroupTab->size().isEmpty()) return; + mKeyList = qobject_cast<QTableWidget*>(mGroupTab->currentWidget()); + if (mKeyList->selectedItems().length() > 0) { popupMenu->exec(event->globalPos()); } @@ -374,18 +338,10 @@ void KeyList::importKeys(const QByteArray& inBuffer) { new KeyImportDetailDialog(result, false, this); } -void KeyList::setExcludeKeys(std::initializer_list<std::string> key_ids) { - excluded_key_ids.clear(); - for (auto& key_id : key_ids) { - excluded_key_ids.push_back(key_id); - } -} - -void KeyList::setFilter(std::function<bool(const GpgKey&)> filter) { - this->mFilter = std::move(filter); -} - void KeyList::slotDoubleClicked(const QModelIndex& index) { + if (mGroupTab->size().isEmpty()) return; + const auto& buffered_keys = + mKeyTables[mGroupTab->currentIndex()].buffered_keys; if (mAction != nullptr) { const auto key = GpgKeyGetter::GetInstance().GetKey(buffered_keys[index.row()].id()); @@ -399,6 +355,10 @@ void KeyList::setDoubleClickedAction( } std::string KeyList::getSelectedKey() { + if (mGroupTab->size().isEmpty()) return {}; + const auto& buffered_keys = + mKeyTables[mGroupTab->currentIndex()].buffered_keys; + for (int i = 0; i < mKeyList->rowCount(); i++) { if (mKeyList->item(i, 0)->isSelected() == 1) { return buffered_keys[i].id(); @@ -407,4 +367,128 @@ std::string KeyList::getSelectedKey() { return {}; } +KeyIdArgsListPtr KeyTable::GetChecked() { + auto ret = std::make_unique<KeyIdArgsList>(); + for (int i = 0; i < key_list->rowCount(); i++) { + if (key_list->item(i, 0)->checkState() == Qt::Checked) { + ret->push_back(buffered_keys[i].id()); + } + } + return ret; +} + +void KeyTable::SetChecked(const KeyIdArgsListPtr& key_ids) { + if (!key_ids->empty()) { + for (int i = 0; i < key_list->rowCount(); i++) { + if (std::find(key_ids->begin(), key_ids->end(), buffered_keys[i].id()) != + key_ids->end()) { + key_list->item(i, 0)->setCheckState(Qt::Checked); + } + } + } +} + +void KeyTable::Refresh() { + auto checked_key_list = GetChecked(); + // while filling the table, sort enabled causes errors + + key_list->setSortingEnabled(false); + key_list->clearContents(); + + auto keys = GpgKeyGetter::GetInstance().FetchKey(); + auto it = keys->begin(); + int row_count = 0; + + while (it != keys->end()) { + if (filter != nullptr) { + if (!filter(*it)) { + it = keys->erase(it); + continue; + } + } + if (select_type == KeyListRow::ONLY_SECRET_KEY && !it->is_private_key()) { + it = keys->erase(it); + continue; + } + row_count++; + it++; + } + + key_list->setRowCount(row_count); + + int row_index = 0; + it = keys->begin(); + + auto& table_buffered_keys = buffered_keys; + + table_buffered_keys.clear(); + + while (it != keys->end()) { + table_buffered_keys.push_back(GpgKeyGetter::GetInstance().GetKey(it->id())); + + auto* tmp0 = new QTableWidgetItem(QString::number(row_index)); + tmp0->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | + Qt::ItemIsSelectable); + tmp0->setTextAlignment(Qt::AlignCenter); + tmp0->setCheckState(Qt::Unchecked); + key_list->setItem(row_index, 0, tmp0); + + QString type_str; + QTextStream type_steam(&type_str); + if (it->is_private_key()) { + type_steam << "pub/sec"; + } else { + type_steam << "pub"; + } + + if (it->is_private_key() && !it->has_master_key()) { + type_steam << "#"; + } + auto* tmp1 = new QTableWidgetItem(type_str); + key_list->setItem(row_index, 1, tmp1); + + auto* tmp2 = new QTableWidgetItem(QString::fromStdString(it->name())); + key_list->setItem(row_index, 2, tmp2); + auto* tmp3 = new QTableWidgetItem(QString::fromStdString(it->email())); + key_list->setItem(row_index, 3, tmp3); + + QString usage; + QTextStream usage_steam(&usage); + + if (it->CanCertActual()) usage_steam << "C"; + if (it->CanEncrActual()) usage_steam << "E"; + if (it->CanSignActual()) usage_steam << "S"; + if (it->CanAuthActual()) usage_steam << "A"; + + auto* temp_usage = new QTableWidgetItem(usage); + temp_usage->setTextAlignment(Qt::AlignCenter); + key_list->setItem(row_index, 4, temp_usage); + + auto* temp_validity = + new QTableWidgetItem(QString::fromStdString(it->owner_trust())); + temp_validity->setTextAlignment(Qt::AlignCenter); + key_list->setItem(row_index, 5, temp_validity); + + auto* temp_fpr = new QTableWidgetItem(QString::fromStdString(it->fpr())); + temp_fpr->setTextAlignment(Qt::AlignCenter); + key_list->setItem(row_index, 6, temp_fpr); + + // strike out expired keys + if (it->expired() || it->revoked()) { + QFont strike = tmp2->font(); + strike.setStrikeOut(true); + tmp0->setFont(strike); + temp_usage->setFont(strike); + temp_fpr->setFont(strike); + temp_validity->setFont(strike); + tmp1->setFont(strike); + tmp2->setFont(strike); + tmp3->setFont(strike); + } + it++; + ++row_index; + } + + SetChecked(checked_key_list); +} } // namespace GpgFrontend::UI diff --git a/src/ui/widgets/KeyList.h b/src/ui/widgets/KeyList.h index 524b2bd0..f09ae2ac 100644 --- a/src/ui/widgets/KeyList.h +++ b/src/ui/widgets/KeyList.h @@ -25,6 +25,8 @@ #ifndef __KEYLIST_H__ #define __KEYLIST_H__ +#include <utility> + #include "gpg/GpgContext.h" #include "ui/KeyImportDetailDialog.h" namespace GpgFrontend::UI { @@ -48,6 +50,31 @@ struct KeyListColumn { static constexpr InfoType FingerPrint = 1 << 5; }; +struct KeyTable { + QTableWidget* key_list; + KeyListRow::KeyType select_type; + KeyListColumn::InfoType info_type; + std::vector<GpgKey> buffered_keys; + std::function<bool(const GpgKey&)> filter; + + KeyTable( + QTableWidget* _key_list, KeyListRow::KeyType _select_type, + KeyListColumn::InfoType _info_type, + std::function<bool(const GpgKey&)> _filter = [](const GpgKey&) -> bool { + return true; + }) + : key_list(_key_list), + select_type(_select_type), + info_type(_info_type), + filter(std::move(_filter)) {} + + void Refresh(); + + KeyIdArgsListPtr GetChecked(); + + void SetChecked(const KeyIdArgsListPtr& key_ids); +}; + class KeyList : public QWidget { Q_OBJECT @@ -55,31 +82,34 @@ class KeyList : public QWidget { explicit KeyList( 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; }, QWidget* parent = nullptr); - void setExcludeKeys(std::initializer_list<std::string> key_ids); + explicit KeyList(QWidget* parent); - void setFilter(std::function<bool(const GpgKey&)> filter); + void addListGroupTab( + const QString& name, + 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; }); void setDoubleClickedAction( std::function<void(const GpgKey&, QWidget*)> action); void setColumnWidth(int row, int size); - void addMenuAction(QAction* act); - void addSeparator(); KeyIdArgsListPtr getChecked(); - + static KeyIdArgsListPtr getChecked(const KeyTable& key_table); KeyIdArgsListPtr getPrivateChecked(); - KeyIdArgsListPtr getAllPrivateKeys(); - void setChecked(const KeyIdArgsListPtr& keyIds); - + static void setChecked(const KeyIdArgsListPtr& keyIds, + const KeyTable& key_table); KeyIdArgsListPtr getSelected(); - std::string getSelectedKey(); [[maybe_unused]] static void markKeys(QStringList* keyIds); @@ -91,20 +121,19 @@ class KeyList : public QWidget { void slotRefresh(); private: + void init(); void importKeys(const QByteArray& inBuffer); QString appPath; QSettings settings; - QTableWidget* mKeyList; - QMenu* popupMenu; - QNetworkAccessManager* qnam{}; - std::vector<GpgKey> buffered_keys; - KeyListRow::KeyType mSelectType; - KeyListColumn::InfoType mInfoType; - std::vector<std::string> excluded_key_ids; + QTabWidget* mGroupTab{}; + QTableWidget* mKeyList{}; + + std::vector<KeyTable> mKeyTables; + + QMenu* popupMenu{}; - std::function<bool(const GpgKey&)> mFilter = nullptr; std::function<void(const GpgKey&, QWidget*)> mAction = nullptr; private slots: diff --git a/src/ui/widgets/SignersPicker.cpp b/src/ui/widgets/SignersPicker.cpp index 3e4b3bb5..997ee27a 100644 --- a/src/ui/widgets/SignersPicker.cpp +++ b/src/ui/widgets/SignersPicker.cpp @@ -33,14 +33,13 @@ SignersPicker::SignersPicker(QWidget* parent) : QDialog(parent) { /*Setup KeyList*/ mKeyList = new KeyList( KeyListRow::ONLY_SECRET_KEY, - KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage); - - mKeyList->setFilter([](const GpgKey& key) -> bool { - if (!key.CanSignActual()) - return false; - else - return true; - }); + KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage, + [](const GpgKey& key) -> bool { + if (!key.CanSignActual()) + return false; + else + return true; + }); mKeyList->slotRefresh(); diff --git a/src/ui/widgets/TextEdit.cpp b/src/ui/widgets/TextEdit.cpp index 8d4ea4a0..ec6c6c7a 100644 --- a/src/ui/widgets/TextEdit.cpp +++ b/src/ui/widgets/TextEdit.cpp @@ -51,7 +51,8 @@ void TextEdit::slotNewTab() { QString header = _("untitled") + QString::number(++countPage) + ".txt"; auto* page = new EditorPage(); - tabWidget->addTab(page, header); + auto index = tabWidget->addTab(page, header); + tabWidget->setTabIcon(index, QIcon(":file.png")); tabWidget->setCurrentIndex(tabWidget->count() - 1); page->getTextPage()->setFocus(); connect(page->getTextPage()->document(), SIGNAL(modificationChanged(bool)), @@ -66,10 +67,12 @@ void TextEdit::slotNewHelpTab(const QString& title, const QString& path) const { void TextEdit::slotNewFileTab() const { auto* page = new FilePage(qobject_cast<QWidget*>(parent())); - tabWidget->addTab(page, "[Browser]"); + auto index = tabWidget->addTab(page, QString()); + tabWidget->setTabIcon(index, QIcon(":file-browser.png")); tabWidget->setCurrentIndex(tabWidget->count() - 1); - connect(page, SIGNAL(pathChanged(const QString&)), this, - SLOT(slotFilePagePathChanged(const QString&))); + connect(page, &FilePage::pathChanged, this, + &TextEdit::slotFilePagePathChanged); + page->slotGoPath(); } void TextEdit::slotOpenFile(QString& path) { @@ -580,7 +583,6 @@ void TextEdit::slotFilePagePathChanged(const QString& path) const { } else { mPath = tPath; } - mPath.prepend("[Browser] "); tabWidget->setTabText(index, mPath); } |