aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--.github/workflows/debug.yml4
-rw-r--r--CMakeLists.txt4
-rw-r--r--gpgfrontend.qrc1
-rw-r--r--resource/icons/ssh-key.pngbin0 -> 6510 bytes
-rw-r--r--src/gpg/function/GpgKeyImportExportor.cpp28
-rw-r--r--src/gpg/function/GpgKeyImportExportor.h5
-rwxr-xr-xsrc/ui/KeyMgmt.cpp52
-rwxr-xr-xsrc/ui/KeyMgmt.h3
-rw-r--r--src/ui/keypair_details/KeyPairDetailTab.cpp106
-rw-r--r--src/ui/keypair_details/KeyPairDetailTab.h5
-rw-r--r--src/ui/keypair_details/KeyPairSubkeyTab.cpp27
-rw-r--r--src/ui/widgets/FilePage.cpp64
-rw-r--r--src/ui/widgets/FilePage.h7
-rw-r--r--src/ui/widgets/InfoBoardWidget.cpp67
-rw-r--r--src/ui/widgets/InfoBoardWidget.h12
-rw-r--r--ui/VerifyDetails.ui150
16 files changed, 447 insertions, 88 deletions
diff --git a/.github/workflows/debug.yml b/.github/workflows/debug.yml
index 2a0f6319..b468761c 100644
--- a/.github/workflows/debug.yml
+++ b/.github/workflows/debug.yml
@@ -2,12 +2,13 @@ name: Debug Build & Package
on:
push:
- branches: [ develop ]
+ branches: [ develop, develop_ui ]
paths-ignore:
- '**/README.md'
- '**/README_CN.md'
- 'resource/ts/**'
- 'docs/**'
+ - '**.md'
pull_request:
branches: [ develop ]
paths-ignore:
@@ -15,6 +16,7 @@ on:
- '**/README_CN.md'
- 'resource/ts/**'
- 'docs/**'
+ - '**.md'
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9d759f6a..377f627c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.16)
-project(GpgFrontend VERSION 2.0.1 LANGUAGES CXX)
+project(GpgFrontend VERSION 2.0.2 LANGUAGES CXX)
message(STATUS "GpgFrontend Build Configuration Started CMAKE Version ${CMAKE_VERSION}")
@@ -274,7 +274,7 @@ if (QT5_ENV_SUPPORT)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
-
+
set(CMAKE_AUTORCC_OPTIONS "--compress;9")
set(CMAKE_AUTOUIC_SEARCH_PATHS ${CMAKE_AUTOUIC_SEARCH_PATHS} ${CMAKE_SOURCE_DIR}/ui)
message(STATUS "CMAKE_AUTOUIC_SEARCH_PATHS ${CMAKE_AUTOUIC_SEARCH_PATHS}")
diff --git a/gpgfrontend.qrc b/gpgfrontend.qrc
index 1f8953a6..c2589b83 100644
--- a/gpgfrontend.qrc
+++ b/gpgfrontend.qrc
@@ -47,6 +47,7 @@
<file alias="misc_doc.png">resource/icons/misc_doc.png</file>
<file alias="quote.png">resource/icons/quote.png</file>
<file alias="signature.png">resource/icons/signature.png</file>
+ <file alias="ssh-key.png">resource/icons/ssh-key.png</file>
<file alias="statusbar_icon.png">resource/icons/statusbar_icon.png</file>
<file alias="txt.png">resource/icons/txt.png</file>
<file alias="undo.png">resource/icons/undo.png</file>
diff --git a/resource/icons/ssh-key.png b/resource/icons/ssh-key.png
new file mode 100644
index 00000000..c3563e43
--- /dev/null
+++ b/resource/icons/ssh-key.png
Binary files differ
diff --git a/src/gpg/function/GpgKeyImportExportor.cpp b/src/gpg/function/GpgKeyImportExportor.cpp
index d8812839..89d3b002 100644
--- a/src/gpg/function/GpgKeyImportExportor.cpp
+++ b/src/gpg/function/GpgKeyImportExportor.cpp
@@ -130,3 +130,31 @@ bool GpgFrontend::GpgKeyImportExportor::ExportKey(
std::swap(out_buffer, temp_out_buffer);
return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR;
}
+
+bool GpgFrontend::GpgKeyImportExportor::ExportKeyOpenSSH(
+ const GpgFrontend::GpgKey& key,
+ GpgFrontend::ByteArrayPtr& out_buffer) const {
+ GpgData data_out;
+ auto err =
+ gpgme_op_export(ctx, key.id().c_str(), GPGME_EXPORT_MODE_SSH, data_out);
+
+ DLOG(INFO) << "read_bytes" << gpgme_data_seek(data_out, 0, SEEK_END);
+
+ auto temp_out_buffer = data_out.Read2Buffer();
+ std::swap(out_buffer, temp_out_buffer);
+ return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR;
+}
+
+bool GpgFrontend::GpgKeyImportExportor::ExportSecretKeyShortest(
+ const GpgFrontend::GpgKey& key,
+ GpgFrontend::ByteArrayPtr& out_buffer) const {
+ GpgData data_out;
+ auto err = gpgme_op_export(ctx, key.id().c_str(), GPGME_EXPORT_MODE_MINIMAL,
+ data_out);
+
+ DLOG(INFO) << "read_bytes" << gpgme_data_seek(data_out, 0, SEEK_END);
+
+ auto temp_out_buffer = data_out.Read2Buffer();
+ std::swap(out_buffer, temp_out_buffer);
+ return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR;
+}
diff --git a/src/gpg/function/GpgKeyImportExportor.h b/src/gpg/function/GpgKeyImportExportor.h
index 35a237ba..ad43d539 100644
--- a/src/gpg/function/GpgKeyImportExportor.h
+++ b/src/gpg/function/GpgKeyImportExportor.h
@@ -90,8 +90,13 @@ class GpgKeyImportExportor
bool ExportKey(const GpgKey& key, ByteArrayPtr& out_buffer) const;
+ bool ExportKeyOpenSSH(const GpgKey& key, ByteArrayPtr& out_buffer) const;
+
bool ExportSecretKey(const GpgKey& key, ByteArrayPtr& outBuffer) const;
+ bool ExportSecretKeyShortest(const GpgKey& key,
+ ByteArrayPtr& outBuffer) const;
+
private:
GpgContext& ctx =
GpgContext::GetInstance(SingletonFunctionObject::GetDefaultChannel());
diff --git a/src/ui/KeyMgmt.cpp b/src/ui/KeyMgmt.cpp
index aa6df120..f28e6587 100755
--- a/src/ui/KeyMgmt.cpp
+++ b/src/ui/KeyMgmt.cpp
@@ -207,6 +207,13 @@ void KeyMgmt::createActions() {
connect(exportKeyToFileAct, SIGNAL(triggered()), this,
SLOT(slotExportKeyToFile()));
+ exportKeyAsOpenSSHFormat = new QAction(_("Export As OpenSSH"), this);
+ exportKeyAsOpenSSHFormat->setIcon(QIcon(":ssh-key.png"));
+ exportKeyAsOpenSSHFormat->setToolTip(
+ _("Export Selected Key(s) As OpenSSH Format to File"));
+ connect(exportKeyAsOpenSSHFormat, SIGNAL(triggered()), this,
+ SLOT(slotExportAsOpenSSHFormat()));
+
deleteSelectedKeysAct = new QAction(_("Delete Selected Key(s)"), this);
deleteSelectedKeysAct->setToolTip(_("Delete the Selected keys"));
connect(deleteSelectedKeysAct, SIGNAL(triggered()), this,
@@ -240,6 +247,7 @@ void KeyMgmt::createMenus() {
importKeyMenu->addAction(importKeyFromKeyServerAct);
keyMenu->addAction(exportKeyToFileAct);
keyMenu->addAction(exportKeyToClipboardAct);
+ keyMenu->addAction(exportKeyAsOpenSSHFormat);
keyMenu->addSeparator();
keyMenu->addAction(deleteCheckedKeysAct);
}
@@ -273,6 +281,7 @@ void KeyMgmt::createToolBars() {
keyToolBar->addSeparator();
keyToolBar->addAction(exportKeyToFileAct);
keyToolBar->addAction(exportKeyToClipboardAct);
+ keyToolBar->addAction(exportKeyAsOpenSSHFormat);
}
void KeyMgmt::slotDeleteSelectedKeys() {
@@ -446,4 +455,47 @@ void KeyMgmt::slotSaveWindowState() {
GlobalSettingStation::GetInstance().Sync();
}
+void KeyMgmt::slotExportAsOpenSSHFormat() {
+ ByteArrayPtr key_export_data = nullptr;
+ auto keys_checked = mKeyList->getChecked();
+
+ if (keys_checked->empty()) {
+ QMessageBox::critical(nullptr, _("Error"), _("No Key Checked."));
+ return;
+ }
+
+ auto key = GpgKeyGetter::GetInstance().GetKey(keys_checked->front());
+ if (!GpgKeyImportExportor::GetInstance().ExportKeyOpenSSH(key,
+ key_export_data)) {
+ QMessageBox::critical(nullptr, _("Error"),
+ _("An error occur in exporting."));
+ return;
+ }
+
+ if (key_export_data->empty()) {
+ QMessageBox::critical(
+ nullptr, _("Error"),
+ _("This key may not be able to export as OpenSSH format. Please check "
+ "the key-size of the subkey(s) used to sign."));
+ return;
+ }
+
+ key = GpgKeyGetter::GetInstance().GetKey(keys_checked->front());
+ if (!key.good()) {
+ QMessageBox::critical(nullptr, _("Error"), _("Key Not Found."));
+ return;
+ }
+ QString fileString = QString::fromStdString(key.name() + " " + key.email() +
+ "(" + key.id() + ").pub");
+
+ QString file_name = QFileDialog::getSaveFileName(
+ this, _("Export OpenSSH Key To File"), fileString,
+ QString(_("OpenSSH Public Key Files")) + " (*.pub);;All Files (*)");
+
+ if (!file_name.isEmpty()) {
+ write_buffer_to_file(file_name.toStdString(), *key_export_data);
+ emit signalStatusBarChanged(QString(_("key(s) exported")));
+ }
+}
+
} // namespace GpgFrontend::UI
diff --git a/src/ui/KeyMgmt.h b/src/ui/KeyMgmt.h
index bf1c9b5a..7edb1b5c 100755
--- a/src/ui/KeyMgmt.h
+++ b/src/ui/KeyMgmt.h
@@ -48,6 +48,8 @@ class KeyMgmt : public QMainWindow {
void slotExportKeyToClipboard();
+ void slotExportAsOpenSSHFormat();
+
void slotDeleteSelectedKeys();
void slotDeleteCheckedKeys();
@@ -80,6 +82,7 @@ class KeyMgmt : public QMainWindow {
QMenu* importKeyMenu{};
QAction* openKeyFileAct{};
QAction* exportKeyToFileAct{};
+ QAction* exportKeyAsOpenSSHFormat{};
QAction* exportKeyToClipboardAct{};
QAction* deleteCheckedKeysAct{};
QAction* deleteSelectedKeysAct{};
diff --git a/src/ui/keypair_details/KeyPairDetailTab.cpp b/src/ui/keypair_details/KeyPairDetailTab.cpp
index de16ccf7..3de83e38 100644
--- a/src/ui/keypair_details/KeyPairDetailTab.cpp
+++ b/src/ui/keypair_details/KeyPairDetailTab.cpp
@@ -81,15 +81,24 @@ KeyPairDetailTab::KeyPairDetailTab(const std::string& key_id, QWidget* parent)
vboxKD->addWidget(new QLabel(QString(_("Master Key Existence")) + ": "), 8,
0);
- vboxKD->addWidget(keyidVarLabel, 0, 1);
- vboxKD->addWidget(algorithmVarLabel, 1, 1);
- vboxKD->addWidget(keySizeVarLabel, 2, 1);
- vboxKD->addWidget(usageVarLabel, 3, 1);
- vboxKD->addWidget(actualUsageVarLabel, 4, 1);
- vboxKD->addWidget(createdVarLabel, 5, 1);
- vboxKD->addWidget(expireVarLabel, 6, 1);
- vboxKD->addWidget(lastUpdateVarLabel, 7, 1);
- vboxKD->addWidget(masterKeyExistVarLabel, 8, 1);
+ vboxKD->addWidget(keyidVarLabel, 0, 1, 1, 1);
+ vboxKD->addWidget(algorithmVarLabel, 1, 1, 1, 2);
+ vboxKD->addWidget(keySizeVarLabel, 2, 1, 1, 2);
+ vboxKD->addWidget(usageVarLabel, 3, 1, 1, 2);
+ vboxKD->addWidget(actualUsageVarLabel, 4, 1, 1, 2);
+ vboxKD->addWidget(createdVarLabel, 5, 1, 1, 2);
+ vboxKD->addWidget(expireVarLabel, 6, 1, 1, 2);
+ vboxKD->addWidget(lastUpdateVarLabel, 7, 1, 1, 2);
+ vboxKD->addWidget(masterKeyExistVarLabel, 8, 1, 1, 2);
+
+ auto* copyKeyIdButton = new QPushButton(_("Copy"));
+ copyKeyIdButton->setFlat(true);
+ vboxKD->addWidget(copyKeyIdButton, 0, 2);
+ connect(copyKeyIdButton, &QPushButton::clicked, this, [=]() {
+ QString fpr = keyidVarLabel->text().trimmed();
+ QClipboard* cb = QApplication::clipboard();
+ cb->setText(fpr);
+ });
ownerBox->setLayout(vboxOD);
mvbox->addWidget(ownerBox);
@@ -119,6 +128,9 @@ KeyPairDetailTab::KeyPairDetailTab(const std::string& key_id, QWidget* parent)
mvbox->addStretch();
mvbox->addWidget(fingerprintBox);
+ // Set Menu
+ createOperaMenu();
+
auto* opera_key_box = new QGroupBox(_("Operations"));
auto* vbox_p_k = new QVBoxLayout();
@@ -131,10 +143,9 @@ KeyPairDetailTab::KeyPairDetailTab(const std::string& key_id, QWidget* parent)
SLOT(slotExportPublicKey()));
if (mKey.is_private_key()) {
- auto* export_private_button =
- new QPushButton(_("Export Private Key (Include Subkey)"));
- connect(export_private_button, SIGNAL(clicked()), this,
- SLOT(slotExportPrivateKey()));
+ auto* export_private_button = new QPushButton(_("Export Private Key"));
+ export_private_button->setStyleSheet("text-align:center;");
+ export_private_button->setMenu(secretKeyExportOperaMenu);
export_h_box_layout->addWidget(export_private_button);
if (mKey.has_master_key()) {
@@ -157,10 +168,6 @@ KeyPairDetailTab::KeyPairDetailTab(const std::string& key_id, QWidget* parent)
auto* key_server_opera_button =
new QPushButton(_("Key Server Operation (Pubkey)"));
key_server_opera_button->setStyleSheet("text-align:center;");
- connect(key_server_opera_button, SIGNAL(clicked()), this,
- SLOT(slotModifyEditDatetime()));
- // Set Menu
- createKeyServerOperaMenu();
key_server_opera_button->setMenu(keyServerOperaMenu);
advance_h_box_layout->addWidget(key_server_opera_button);
@@ -230,6 +237,48 @@ void KeyPairDetailTab::slotExportPublicKey() {
}
}
+void KeyPairDetailTab::slotExportShortPrivateKey() {
+ // Show a information box with explanation about private key
+ int ret = QMessageBox::information(
+ this, _("Exporting short private Key"),
+ "<h3>" + QString(_("You are about to export your")) +
+ "<font color=\"red\">" + _(" PRIVATE KEY ") + "</font>!</h3>\n" +
+ _("This is NOT your Public Key, so DON'T give it away.") + "<br />" +
+ _("Do you REALLY want to export your PRIVATE KEY in a Minimum "
+ "Size?") +
+ "<br />" +
+ _("For OpenPGP keys it removes all signatures except for the latest "
+ "self-signatures."),
+ QMessageBox::Cancel | QMessageBox::Ok);
+
+ // export key, if ok was clicked
+ if (ret == QMessageBox::Ok) {
+ ByteArrayPtr keyArray = nullptr;
+
+ if (!GpgKeyImportExportor::GetInstance().ExportSecretKeyShortest(
+ mKey, keyArray)) {
+ QMessageBox::critical(
+ this, _("Error"),
+ _("An error occurred during the export operation."));
+ return;
+ }
+ auto fileString = mKey.name() + " " + mKey.email() + "(" + mKey.id() +
+ ")_short_secret.asc";
+ auto fileName =
+ QFileDialog::getSaveFileName(
+ this, _("Export Key To File"), QString::fromStdString(fileString),
+ QString(_("Key Files")) + " (*.asc *.txt);;All Files (*)")
+ .toStdString();
+
+ if (!write_buffer_to_file(fileName, *keyArray)) {
+ QMessageBox::critical(
+ this, _("Export Error"),
+ QString(_("Couldn't open %1 for writing")).arg(fileName.c_str()));
+ return;
+ }
+ }
+}
+
void KeyPairDetailTab::slotExportPrivateKey() {
// Show a information box with explanation about private key
int ret = QMessageBox::information(
@@ -250,8 +299,8 @@ void KeyPairDetailTab::slotExportPrivateKey() {
_("An error occurred during the export operation."));
return;
}
- auto fileString =
- mKey.name() + " " + mKey.email() + "(" + mKey.id() + ")_secret.asc";
+ auto fileString = mKey.name() + " " + mKey.email() + "(" + mKey.id() +
+ ")_full_secret.asc";
auto fileName =
QFileDialog::getSaveFileName(
this, _("Export Key To File"), QString::fromStdString(fileString),
@@ -370,7 +419,7 @@ void KeyPairDetailTab::slotRefreshKeyInfo() {
}
}
-void KeyPairDetailTab::createKeyServerOperaMenu() {
+void KeyPairDetailTab::createOperaMenu() {
keyServerOperaMenu = new QMenu(this);
auto* uploadKeyPair = new QAction(_("Upload Key Pair to Key Server"), this);
@@ -384,6 +433,21 @@ void KeyPairDetailTab::createKeyServerOperaMenu() {
keyServerOperaMenu->addAction(uploadKeyPair);
keyServerOperaMenu->addAction(updateKeyPair);
+
+ secretKeyExportOperaMenu = new QMenu(this);
+
+ auto* exportFullSecretKey = new QAction(_("Export Full Secret Key"), this);
+ connect(exportFullSecretKey, SIGNAL(triggered()), this,
+ SLOT(slotExportPrivateKey()));
+ if (!mKey.is_private_key()) exportFullSecretKey->setDisabled(true);
+
+ auto* exportShortestSecretKey =
+ new QAction(_("Export Shortest Secret Key"), this);
+ connect(exportShortestSecretKey, SIGNAL(triggered()), this,
+ SLOT(slotExportShortPrivateKey()));
+
+ secretKeyExportOperaMenu->addAction(exportFullSecretKey);
+ secretKeyExportOperaMenu->addAction(exportShortestSecretKey);
}
void KeyPairDetailTab::slotUploadKeyToServer() {
@@ -403,7 +467,7 @@ void KeyPairDetailTab::slotUpdateKeyFromServer() {
}
void KeyPairDetailTab::slotGenRevokeCert() {
- auto literal = QStringLiteral("%1 (*.rev)").arg(_("Revocation Certificates"));
+ auto literal = QString("%1 (*.rev)").arg(_("Revocation Certificates"));
QString m_output_file_name;
QFileDialog dialog(this, "Generate revocation certificate", QString(),
diff --git a/src/ui/keypair_details/KeyPairDetailTab.h b/src/ui/keypair_details/KeyPairDetailTab.h
index 68ca1ebd..3e2f2298 100644
--- a/src/ui/keypair_details/KeyPairDetailTab.h
+++ b/src/ui/keypair_details/KeyPairDetailTab.h
@@ -36,7 +36,7 @@ namespace GpgFrontend::UI {
class KeyPairDetailTab : public QWidget {
Q_OBJECT
- void createKeyServerOperaMenu();
+ void createOperaMenu();
private slots:
@@ -45,6 +45,8 @@ class KeyPairDetailTab : public QWidget {
*/
void slotExportPrivateKey();
+ void slotExportShortPrivateKey();
+
void slotExportPublicKey();
/**
@@ -95,6 +97,7 @@ class KeyPairDetailTab : public QWidget {
QLabel* expLabel;
QMenu* keyServerOperaMenu{};
+ QMenu* secretKeyExportOperaMenu{};
public:
explicit KeyPairDetailTab(const std::string& key_id,
diff --git a/src/ui/keypair_details/KeyPairSubkeyTab.cpp b/src/ui/keypair_details/KeyPairSubkeyTab.cpp
index 93e07875..cb71c09f 100644
--- a/src/ui/keypair_details/KeyPairSubkeyTab.cpp
+++ b/src/ui/keypair_details/KeyPairSubkeyTab.cpp
@@ -64,7 +64,7 @@ KeyPairSubkeyTab::KeyPairSubkeyTab(const std::string& key_id, QWidget* parent)
subkeyDetailLayout->addWidget(new QLabel(QString(_("Usage")) + ": "), 3, 0);
subkeyDetailLayout->addWidget(new QLabel(QString(_("Expires On")) + ": "), 4,
0);
- subkeyDetailLayout->addWidget(new QLabel(QString(_("Last Update")) + ": "), 5,
+ subkeyDetailLayout->addWidget(new QLabel(QString(_("Create Date")) + ": "), 5,
0);
subkeyDetailLayout->addWidget(new QLabel(QString(_("Existence")) + ": "), 6,
0);
@@ -80,14 +80,23 @@ KeyPairSubkeyTab::KeyPairSubkeyTab(const std::string& key_id, QWidget* parent)
masterKeyExistVarLabel = new QLabel();
fingerPrintVarLabel = new QLabel();
- subkeyDetailLayout->addWidget(keyidVarLabel, 0, 1);
- subkeyDetailLayout->addWidget(keySizeVarLabel, 2, 1);
- subkeyDetailLayout->addWidget(expireVarLabel, 4, 1);
- subkeyDetailLayout->addWidget(algorithmVarLabel, 1, 1);
- subkeyDetailLayout->addWidget(createdVarLabel, 5, 1);
- subkeyDetailLayout->addWidget(usageVarLabel, 3, 1);
- subkeyDetailLayout->addWidget(masterKeyExistVarLabel, 6, 1);
- subkeyDetailLayout->addWidget(fingerPrintVarLabel, 7, 1);
+ subkeyDetailLayout->addWidget(keyidVarLabel, 0, 1, 1, 1);
+ subkeyDetailLayout->addWidget(keySizeVarLabel, 2, 1, 1, 2);
+ subkeyDetailLayout->addWidget(expireVarLabel, 4, 1, 1, 2);
+ subkeyDetailLayout->addWidget(algorithmVarLabel, 1, 1, 1, 2);
+ subkeyDetailLayout->addWidget(createdVarLabel, 5, 1, 1, 2);
+ subkeyDetailLayout->addWidget(usageVarLabel, 3, 1, 1, 2);
+ subkeyDetailLayout->addWidget(masterKeyExistVarLabel, 6, 1, 1, 2);
+ subkeyDetailLayout->addWidget(fingerPrintVarLabel, 7, 1, 1, 2);
+
+ auto* copyKeyIdButton = new QPushButton(_("Copy"));
+ copyKeyIdButton->setFlat(true);
+ subkeyDetailLayout->addWidget(copyKeyIdButton, 0, 2);
+ connect(copyKeyIdButton, &QPushButton::clicked, this, [=]() {
+ QString fpr = keyidVarLabel->text().trimmed();
+ QClipboard* cb = QApplication::clipboard();
+ cb->setText(fpr);
+ });
listBox->setLayout(subkeyListLayout);
listBox->setContentsMargins(0, 12, 0, 0);
diff --git a/src/ui/widgets/FilePage.cpp b/src/ui/widgets/FilePage.cpp
index f73d9104..0cd7c1a8 100644
--- a/src/ui/widgets/FilePage.cpp
+++ b/src/ui/widgets/FilePage.cpp
@@ -32,11 +32,13 @@
#include "ui/MainWindow.h"
#include "ui/SignalStation.h"
+#include "ui_FilePage.h"
namespace GpgFrontend::UI {
-FilePage::FilePage(QWidget* parent) : QWidget(parent), Ui_FilePage() {
- setupUi(this);
+FilePage::FilePage(QWidget* parent)
+ : QWidget(parent), ui(std::make_shared<Ui_FilePage>()) {
+ ui->setupUi(this);
firstParent = parent;
@@ -44,35 +46,37 @@ FilePage::FilePage(QWidget* parent) : QWidget(parent), Ui_FilePage() {
dirModel->setRootPath(QDir::currentPath());
dirModel->setFilter(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);
- fileTreeView->setModel(dirModel);
- fileTreeView->setColumnWidth(0, 320);
- fileTreeView->sortByColumn(0, Qt::AscendingOrder);
+ ui->fileTreeView->setModel(dirModel);
+ ui->fileTreeView->setColumnWidth(0, 320);
+ ui->fileTreeView->sortByColumn(0, Qt::AscendingOrder);
mPath = boost::filesystem::path(dirModel->rootPath().toStdString());
createPopupMenu();
- connect(upPathButton, &QPushButton::clicked, this, &FilePage::slotUpLevel);
- connect(refreshButton, &QPushButton::clicked, this, &FilePage::slotGoPath);
- optionsButton->setMenu(optionPopUpMenu);
+ connect(ui->upPathButton, &QPushButton::clicked, this,
+ &FilePage::slotUpLevel);
+ connect(ui->refreshButton, &QPushButton::clicked, this,
+ &FilePage::slotGoPath);
+ ui->optionsButton->setMenu(optionPopUpMenu);
- pathEdit->setText(dirModel->rootPath());
+ ui->pathEdit->setText(dirModel->rootPath());
pathEditCompleter = new QCompleter(this);
pathCompleteModel = new QStringListModel();
pathEditCompleter->setModel(pathCompleteModel);
pathEditCompleter->setCaseSensitivity(Qt::CaseInsensitive);
pathEditCompleter->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
- pathEdit->setCompleter(pathEditCompleter);
+ ui->pathEdit->setCompleter(pathEditCompleter);
- connect(fileTreeView, &QTreeView::clicked, this,
+ connect(ui->fileTreeView, &QTreeView::clicked, this,
&FilePage::fileTreeViewItemClicked);
- connect(fileTreeView, &QTreeView::doubleClicked, this,
+ connect(ui->fileTreeView, &QTreeView::doubleClicked, this,
&FilePage::fileTreeViewItemDoubleClicked);
- connect(fileTreeView, &QTreeView::customContextMenuRequested, this,
+ connect(ui->fileTreeView, &QTreeView::customContextMenuRequested, this,
&FilePage::onCustomContextMenu);
- connect(pathEdit, &QLineEdit::textChanged, [=]() {
- auto path = pathEdit->text();
+ connect(ui->pathEdit, &QLineEdit::textChanged, [=]() {
+ auto path = ui->pathEdit->text();
auto dir = QDir(path);
if (path.endsWith("/") && dir.isReadable()) {
auto dir_list = dir.entryInfoList(QDir::AllEntries);
@@ -99,7 +103,7 @@ void FilePage::fileTreeViewItemClicked(const QModelIndex& index) {
}
void FilePage::slotUpLevel() {
- QModelIndex currentRoot = fileTreeView->rootIndex();
+ QModelIndex currentRoot = ui->fileTreeView->rootIndex();
auto utf8_path =
dirModel->fileInfo(currentRoot).absoluteFilePath().toStdString();
@@ -117,7 +121,7 @@ void FilePage::slotUpLevel() {
if (mPath.has_parent_path() && !mPath.parent_path().empty()) {
mPath = mPath.parent_path();
LOG(INFO) << "parent path" << mPath;
- pathEdit->setText(mPath.string().c_str());
+ ui->pathEdit->setText(mPath.string().c_str());
this->slotGoPath();
}
}
@@ -127,7 +131,7 @@ void FilePage::fileTreeViewItemDoubleClicked(const QModelIndex& index) {
if (file_info.isFile()) {
slotOpenItem();
} else {
- pathEdit->setText(file_info.filePath());
+ ui->pathEdit->setText(file_info.filePath());
slotGoPath();
}
}
@@ -137,7 +141,7 @@ QString FilePage::getSelected() const {
}
void FilePage::slotGoPath() {
- const auto path_edit = pathEdit->text().toStdString();
+ const auto path_edit = ui->pathEdit->text().toStdString();
#ifdef WINDOWS
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>> converter;
@@ -152,12 +156,12 @@ void FilePage::slotGoPath() {
if (fileInfo.isDir() && fileInfo.isReadable() && fileInfo.isExecutable()) {
mPath = boost::filesystem::path(fileInfo.filePath().toStdString());
LOG(INFO) << "set path" << mPath;
- fileTreeView->setRootIndex(dirModel->index(fileInfo.filePath()));
+ ui->fileTreeView->setRootIndex(dirModel->index(fileInfo.filePath()));
dirModel->setRootPath(fileInfo.filePath());
for (int i = 1; i < dirModel->columnCount(); ++i) {
- fileTreeView->resizeColumnToContents(i);
+ ui->fileTreeView->resizeColumnToContents(i);
}
- pathEdit->setText(mPath.generic_path().string().c_str());
+ ui->pathEdit->setText(mPath.generic_path().string().c_str());
} else {
QMessageBox::critical(
this, _("Error"),
@@ -240,7 +244,7 @@ void FilePage::createPopupMenu() {
}
void FilePage::onCustomContextMenu(const QPoint& point) {
- QModelIndex index = fileTreeView->indexAt(point);
+ QModelIndex index = ui->fileTreeView->indexAt(point);
selectedPath = boost::filesystem::path(
dirModel->fileInfo(index).absoluteFilePath().toStdString());
LOG(INFO) << "right click" << selectedPath;
@@ -272,7 +276,7 @@ void FilePage::onCustomContextMenu(const QPoint& point) {
verifyItemAct->setEnabled(false);
hashCalculateAct->setEnabled(false);
}
- popUpMenu->exec(fileTreeView->viewport()->mapToGlobal(point));
+ popUpMenu->exec(ui->fileTreeView->viewport()->mapToGlobal(point));
}
void FilePage::slotOpenItem() {
@@ -281,7 +285,7 @@ void FilePage::slotOpenItem() {
if (info.isReadable() && info.isExecutable()) {
const auto file_path = info.filePath().toStdString();
LOG(INFO) << "set path" << file_path;
- pathEdit->setText(info.filePath());
+ ui->pathEdit->setText(info.filePath());
slotGoPath();
} else {
QMessageBox::critical(this, _("Error"),
@@ -325,8 +329,8 @@ void FilePage::slotRenameItem() {
}
void FilePage::slotDeleteItem() {
- QModelIndex index = fileTreeView->currentIndex();
- QVariant data = fileTreeView->model()->data(index);
+ QModelIndex index = ui->fileTreeView->currentIndex();
+ QVariant data = ui->fileTreeView->model()->data(index);
auto ret = QMessageBox::warning(this, _("Warning"),
_("Are you sure you want to delete it?"),
@@ -412,7 +416,7 @@ void FilePage::slotCalculateHash() {
}
void FilePage::slotMkdir() {
- auto index = fileTreeView->rootIndex();
+ auto index = ui->fileTreeView->rootIndex();
QString new_dir_name;
bool ok;
@@ -450,10 +454,10 @@ void FilePage::slotCreateEmptyFile() {
void FilePage::keyPressEvent(QKeyEvent* event) {
LOG(INFO) << "Key Press" << event->key();
- if (pathEdit->hasFocus() &&
+ if (ui->pathEdit->hasFocus() &&
(event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)) {
slotGoPath();
- } else if (fileTreeView->currentIndex().isValid()) {
+ } else if (ui->fileTreeView->currentIndex().isValid()) {
if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
slotOpenItem();
else if (event->key() == Qt::Key_Delete ||
diff --git a/src/ui/widgets/FilePage.h b/src/ui/widgets/FilePage.h
index d9492f6e..03caf36b 100644
--- a/src/ui/widgets/FilePage.h
+++ b/src/ui/widgets/FilePage.h
@@ -29,11 +29,12 @@
#include "ui/GpgFrontendUI.h"
#include "ui/widgets/InfoBoardWidget.h"
-#include "ui_FilePage.h"
+
+class Ui_FilePage;
namespace GpgFrontend::UI {
-class FilePage : public QWidget, private Ui_FilePage {
+class FilePage : public QWidget {
Q_OBJECT
public:
explicit FilePage(QWidget* parent = nullptr);
@@ -75,6 +76,8 @@ class FilePage : public QWidget, private Ui_FilePage {
private:
void createPopupMenu();
+ std::shared_ptr<Ui_FilePage> ui;
+
QFileSystemModel* dirModel;
QCompleter* pathEditCompleter;
QStringListModel* pathCompleteModel;
diff --git a/src/ui/widgets/InfoBoardWidget.cpp b/src/ui/widgets/InfoBoardWidget.cpp
index 7bb47bb6..1b7dbda0 100644
--- a/src/ui/widgets/InfoBoardWidget.cpp
+++ b/src/ui/widgets/InfoBoardWidget.cpp
@@ -31,14 +31,21 @@
namespace GpgFrontend::UI {
InfoBoardWidget::InfoBoardWidget(QWidget* parent)
- : QWidget(parent), Ui_InfoBoard() {
- setupUi(this);
-
- actionButtonLayout->addStretch();
- actionLabel->setText(_("Actions Menu"));
- copyButton->setText(_("Copy"));
- saveButton->setText(_("Save"));
- clearButton->setText(_("Clear"));
+ : QWidget(parent), ui(std::make_shared<Ui_InfoBoard>()) {
+ ui->setupUi(this);
+
+ ui->actionButtonLayout->addStretch();
+ ui->actionLabel->setText(_("InfoBoard's Actions Menu"));
+ ui->copyButton->setText(_("Copy"));
+ ui->saveButton->setText(_("Save"));
+ ui->clearButton->setText(_("Clear"));
+
+ connect(ui->copyButton, &QPushButton::clicked, this,
+ &InfoBoardWidget::slotCopy);
+ connect(ui->saveButton, &QPushButton::clicked, this,
+ &InfoBoardWidget::slotSave);
+ connect(ui->clearButton, &QPushButton::clicked, this,
+ &InfoBoardWidget::slotReset);
connect(SignalStation::GetInstance(), &SignalStation::signalRefreshInfoBoard,
this, &InfoBoardWidget::slotRefresh);
@@ -47,7 +54,7 @@ InfoBoardWidget::InfoBoardWidget(QWidget* parent)
void InfoBoardWidget::setInfoBoard(const QString& text,
InfoBoardStatus verifyLabelStatus) {
QString color;
- infoBoard->clear();
+ ui->infoBoard->clear();
switch (verifyLabelStatus) {
case INFO_ERROR_OK:
color = "#008000";
@@ -61,12 +68,12 @@ void InfoBoardWidget::setInfoBoard(const QString& text,
default:
break;
}
- infoBoard->append(text);
+ ui->infoBoard->append(text);
- infoBoard->setAutoFillBackground(true);
- QPalette status = infoBoard->palette();
+ ui->infoBoard->setAutoFillBackground(true);
+ QPalette status = ui->infoBoard->palette();
status.setColor(QPalette::Text, color);
- infoBoard->setPalette(status);
+ ui->infoBoard->setPalette(status);
auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
@@ -78,13 +85,13 @@ void InfoBoardWidget::setInfoBoard(const QString& text,
} catch (...) {
LOG(ERROR) << _("Setting Operation Error") << _("info_font_size");
}
- infoBoard->setFont(QFont("Times", info_font_size));
+ ui->infoBoard->setFont(QFont("Times", info_font_size));
}
void InfoBoardWidget::slotRefresh(const QString& text, InfoBoardStatus status) {
- infoBoard->clear();
+ ui->infoBoard->clear();
setInfoBoard(text, status);
- infoBoard->verticalScrollBar()->setValue(0);
+ ui->infoBoard->verticalScrollBar()->setValue(0);
}
void InfoBoardWidget::associateTextEdit(QTextEdit* edit) {
@@ -115,10 +122,10 @@ void InfoBoardWidget::addOptionalAction(const QString& name,
auto actionButton = new QPushButton(name);
auto layout = new QHBoxLayout();
layout->setContentsMargins(5, 0, 5, 0);
- infoBoard->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ ui->infoBoard->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
// set margin from surroundings
layout->addWidget(actionButton);
- actionButtonLayout->addLayout(layout);
+ ui->actionButtonLayout->addLayout(layout);
connect(actionButton, &QPushButton::clicked, this, [=]() { action(); });
}
@@ -127,11 +134,11 @@ void InfoBoardWidget::addOptionalAction(const QString& name,
*/
void InfoBoardWidget::resetOptionActionsMenu() {
// skip stretch
- deleteWidgetsInLayout(actionButtonLayout, 1);
+ deleteWidgetsInLayout(ui->actionButtonLayout, 1);
}
void InfoBoardWidget::slotReset() {
- this->infoBoard->clear();
+ ui->infoBoard->clear();
resetOptionActionsMenu();
}
@@ -153,4 +160,24 @@ void InfoBoardWidget::deleteWidgetsInLayout(QLayout* layout, int start_index) {
}
}
+void InfoBoardWidget::slotCopy() {
+ auto* clipboard = QGuiApplication::clipboard();
+ clipboard->setText(ui->infoBoard->toPlainText());
+}
+
+void InfoBoardWidget::slotSave() {
+ auto file_path = QFileDialog::getSaveFileName(
+ this, _("Save Information Board's Content"), {}, tr("Text (*.txt)"));
+ LOG(INFO) << "file path" << file_path.toStdString();
+ QFile file(file_path);
+ if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ file.write(ui->infoBoard->toPlainText().toUtf8());
+ } else {
+ QMessageBox::critical(
+ this, _("Error"),
+ _("The file path is not exists, unprivileged or unreachable."));
+ }
+ file.close();
+}
+
} // namespace GpgFrontend::UI
diff --git a/src/ui/widgets/InfoBoardWidget.h b/src/ui/widgets/InfoBoardWidget.h
index 05a3b345..8d37be6c 100644
--- a/src/ui/widgets/InfoBoardWidget.h
+++ b/src/ui/widgets/InfoBoardWidget.h
@@ -28,7 +28,8 @@
#include "EditorPage.h"
#include "gpg/result_analyse/VerifyResultAnalyse.h"
#include "ui/details/VerifyDetailsDialog.h"
-#include "ui_InfoBoard.h"
+
+class Ui_InfoBoard;
namespace GpgFrontend::UI {
@@ -45,7 +46,7 @@ typedef enum {
/**
* @brief Class for handling the verifylabel shown at buttom of a textedit-page
*/
-class InfoBoardWidget : public QWidget, private Ui_InfoBoard {
+class InfoBoardWidget : public QWidget {
Q_OBJECT
public:
/**
@@ -82,7 +83,14 @@ class InfoBoardWidget : public QWidget, private Ui_InfoBoard {
*/
void slotRefresh(const QString& text, InfoBoardStatus status);
+ private slots:
+
+ void slotCopy();
+
+ void slotSave();
+
private:
+ std::shared_ptr<Ui_InfoBoard> ui;
QTextEdit* mTextPage{nullptr}; /** TextEdit associated to the notification */
QTabWidget* mTabWidget{nullptr};
diff --git a/ui/VerifyDetails.ui b/ui/VerifyDetails.ui
new file mode 100644
index 00000000..3f88984d
--- /dev/null
+++ b/ui/VerifyDetails.ui
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>VerifyDetailsDialog</class>
+ <widget class="QDialog" name="VerifyDetailsDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>635</width>
+ <height>829</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item alignment="Qt::AlignTop">
+ <widget class="QWidget" name="horizontalWidget" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item alignment="Qt::AlignTop">
+ <widget class="QLabel" name="titleLabel">
+ <property name="text">
+ <string>Verify Details</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::AutoText</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignTop">
+ <widget class="QWidget" name="verticalWidget_2" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item alignment="Qt::AlignTop">
+ <widget class="QWidget" name="horizontalWidget" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item alignment="Qt::AlignLeft|Qt::AlignTop">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Date: </string>
+ </property>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignTop">
+ <widget class="QLabel" name="label_2">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="horizontalWidget" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item alignment="Qt::AlignLeft">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Status: </string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_4">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Signer(s) List: </string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTabWidget" name="tabWidget">
+ <property name="currentIndex">
+ <number>1</number>
+ </property>
+ <widget class="QWidget" name="tab">
+ <attribute name="title">
+ <string>Tab 1</string>
+ </attribute>
+ </widget>
+ <widget class="QWidget" name="tab_2">
+ <attribute name="title">
+ <string>Tab 2</string>
+ </attribute>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>