diff options
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); } |