diff options
author | Saturneric <[email protected]> | 2021-07-12 09:03:12 +0000 |
---|---|---|
committer | Saturneric <[email protected]> | 2021-07-12 09:03:12 +0000 |
commit | 4ada913c515cf090c65d9d155aa9880a50501591 (patch) | |
tree | 72043033991b643a2cce437f22497a961d73a745 /src | |
parent | Update Documents; Update UI (diff) | |
download | GpgFrontend-4ada913c515cf090c65d9d155aa9880a50501591.tar.gz GpgFrontend-4ada913c515cf090c65d9d155aa9880a50501591.zip |
Project structure adjustment;
Project configuration adjustment;
Add version detection;
UI interface improvements;
Introduce JSON processing library;
Update Documents;
Diffstat (limited to 'src')
-rw-r--r-- | src/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/MainWindow.cpp | 388 | ||||
-rw-r--r-- | src/main.cpp | 1 | ||||
-rw-r--r-- | src/ui/AboutDialog.cpp | 94 | ||||
-rw-r--r-- | src/ui/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/ui/help/AboutDialog.cpp | 208 | ||||
-rw-r--r-- | src/ui/help/VersionCheckThread.cpp | 50 | ||||
-rw-r--r-- | src/ui/keygen/SubkeyGenerateThread.cpp | 2 | ||||
-rw-r--r-- | src/ui/main_window/MainWindowSlotFunction.cpp | 42 | ||||
-rw-r--r-- | src/ui/main_window/MainWindowSlotUI.cpp | 6 | ||||
-rw-r--r-- | src/ui/main_window/MainWindowUI.cpp | 14 | ||||
-rw-r--r-- | src/ui/widgets/EditorPage.cpp | 3 | ||||
-rw-r--r-- | src/ui/widgets/FilePage.cpp | 7 | ||||
-rw-r--r-- | src/ui/widgets/TextEdit.cpp | 7 |
14 files changed, 526 insertions, 298 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index deeabadb..eadce626 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -44,6 +44,7 @@ add_custom_target(translations DEPENDS ${QON_QM_FILES}) # Set Build Information configure_file(${CMAKE_SOURCE_DIR}/include/GpgFrontend.h.in ${CMAKE_SOURCE_DIR}/include/GpgFrontend.h @ONLY) +configure_file(${CMAKE_SOURCE_DIR}/include/GpgFrontendBuildInfo.h.in ${CMAKE_SOURCE_DIR}/include/GpgFrontendBuildInfo.h @ONLY) # Copy Resource Files file(COPY ${CMAKE_SOURCE_DIR}/resource/css DESTINATION ${RESOURCE_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index eeedad7c..08433da9 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -23,209 +23,223 @@ */ #include "MainWindow.h" +#include "ui/help/VersionCheckThread.h" MainWindow::MainWindow() - : appPath(qApp->applicationDirPath()), - settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", - QSettings::IniFormat) { - - auto waitingDialog = new WaitingDialog("Loading Gnupg", this); - - auto ctx_thread = QThread::create([&]() { mCtx = new GpgME::GpgContext(); }); - - ctx_thread->start(); - - while (ctx_thread->isRunning()) - QApplication::processEvents(); - - waitingDialog->close(); - - - if (!mCtx->isGood()) { - QMessageBox::critical( - nullptr, tr("ENV Loading Failed"), - tr("Gnupg is not installed correctly, please follow the ReadME " - "instructions to install gnupg and then open GPGFrontend.")); - QCoreApplication::quit(); - exit(0); - } - - /* get path were app was started */ - setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea); - setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea); - - qDebug() << "Main Window" << this; - - edit = new TextEdit(this); - setCentralWidget(edit); - - /* the list of Keys available*/ - mKeyList = new KeyList(mCtx, KeyListRow::SECRET_OR_PUBLIC_KEY, - KeyListColumn::TYPE | KeyListColumn::NAME | - KeyListColumn::EmailAddress | - KeyListColumn::Usage | KeyListColumn::Validity, - this); - mKeyList->setFilter([](const GpgKey &key) -> bool { - if (key.revoked || key.disabled || key.expired) - return false; - else - return true; - }); - mKeyList->slotRefresh(); - - infoBoard = new InfoBoardWidget(this, mCtx, mKeyList); - - /* List of binary Attachments */ - attachmentDockCreated = false; - - /* Variable containing if restart is needed */ - this->slotSetRestartNeeded(false); - - keyMgmt = new KeyMgmt(mCtx, this); - keyMgmt->hide(); - /* test attachmentdir for files alll 15s */ - auto *timer = new QTimer(this); - connect(timer, SIGNAL(timeout()), this, SLOT(slotCheckAttachmentFolder())); - timer->start(5000); - - createActions(); - createMenus(); - createToolBars(); - createStatusBar(); - createDockWindows(); - - connect(edit->tabWidget, SIGNAL(currentChanged(int)), this, - SLOT(slotDisableTabActions(int))); - - mKeyList->addMenuAction(appendSelectedKeysAct); - mKeyList->addMenuAction(copyMailAddressToClipboardAct); - mKeyList->addMenuAction(showKeyDetailsAct); - mKeyList->addSeparator(); - mKeyList->addMenuAction(refreshKeysFromKeyserverAct); - mKeyList->addMenuAction(uploadKeyToServerAct); - - restoreSettings(); - - // open filename if provided as first command line parameter - QStringList args = qApp->arguments(); - if (args.size() > 1) { - if (!args[1].startsWith("-")) { - if (QFile::exists(args[1])) - edit->loadFile(args[1]); + : appPath(qApp->applicationDirPath()), + settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", + QSettings::IniFormat) { + + networkAccessManager = new QNetworkAccessManager(this); + + auto waitingDialog = new WaitingDialog("Loading Gnupg", this); + + // Init Gnupg + auto ctx_thread = QThread::create([&]() { mCtx = new GpgME::GpgContext(); }); + ctx_thread->start(); + while (ctx_thread->isRunning()) + QApplication::processEvents(); + waitingDialog->close(); + ctx_thread->deleteLater(); + + QString baseUrl = "https://api.github.com/repos/saturneric/gpgfrontend/releases/latest"; + + QNetworkRequest request; + request.setUrl(QUrl(baseUrl)); + + QNetworkReply *replay = networkAccessManager->get(request); + + auto version_thread = new VersionCheckThread(replay); + + connect(version_thread, SIGNAL(finished(QPrivateSignal)), version_thread, SLOT(deleteLater())); + connect(version_thread, SIGNAL(upgradeVersion(const QString &, const QString &)), this, SLOT(slotVersionUpgrade(const QString &, const QString &))); + + version_thread->start(); + + // Check Context Status + if (!mCtx->isGood()) { + QMessageBox::critical( + nullptr, tr("ENV Loading Failed"), + tr("Gnupg is not installed correctly, please follow the ReadME " + "instructions to install gnupg and then open GPGFrontend.")); + QCoreApplication::quit(); + exit(0); + } + + /* get path were app was started */ + setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea); + setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea); + + edit = new TextEdit(this); + setCentralWidget(edit); + + /* the list of Keys available*/ + mKeyList = new KeyList(mCtx, KeyListRow::SECRET_OR_PUBLIC_KEY, + KeyListColumn::TYPE | KeyListColumn::NAME | + KeyListColumn::EmailAddress | + KeyListColumn::Usage | KeyListColumn::Validity, + this); + mKeyList->setFilter([](const GpgKey &key) -> bool { + if (key.revoked || key.disabled || key.expired) + return false; + else + return true; + }); + mKeyList->slotRefresh(); + + infoBoard = new InfoBoardWidget(this, mCtx, mKeyList); + + /* List of binary Attachments */ + attachmentDockCreated = false; + + /* Variable containing if restart is needed */ + this->slotSetRestartNeeded(false); + + keyMgmt = new KeyMgmt(mCtx, this); + keyMgmt->hide(); + /* test attachmentdir for files alll 15s */ + auto *timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(slotCheckAttachmentFolder())); + timer->start(5000); + + createActions(); + createMenus(); + createToolBars(); + createStatusBar(); + createDockWindows(); + + connect(edit->tabWidget, SIGNAL(currentChanged(int)), this, + SLOT(slotDisableTabActions(int))); + + mKeyList->addMenuAction(appendSelectedKeysAct); + mKeyList->addMenuAction(copyMailAddressToClipboardAct); + mKeyList->addMenuAction(showKeyDetailsAct); + mKeyList->addSeparator(); + mKeyList->addMenuAction(refreshKeysFromKeyserverAct); + mKeyList->addMenuAction(uploadKeyToServerAct); + + restoreSettings(); + + // open filename if provided as first command line parameter + QStringList args = qApp->arguments(); + if (args.size() > 1) { + if (!args[1].startsWith("-")) { + if (QFile::exists(args[1])) + edit->loadFile(args[1]); + } + } + edit->curTextPage()->setFocus(); + this->setMinimumSize(1200, 700); + this->setWindowTitle(qApp->applicationName()); + this->show(); + + // Show wizard, if the don't show wizard message box wasn't checked + // and keylist doesn't contain a private key + qDebug() << "wizard/showWizard" + << settings.value("wizard/showWizard", true).toBool(); + qDebug() << "wizard/nextPage" << settings.value("wizard/nextPage").isNull(); + if (settings.value("wizard/showWizard", true).toBool() || + !settings.value("wizard/nextPage").isNull()) { + slotStartWizard(); } - } - edit->curTextPage()->setFocus(); - this->setMinimumSize(1200, 700); - this->setWindowTitle(qApp->applicationName()); - this->show(); - - // Show wizard, if the don't show wizard message box wasn't checked - // and keylist doesn't contain a private key - qDebug() << "wizard/showWizard" - << settings.value("wizard/showWizard", true).toBool(); - qDebug() << "wizard/nextPage" << settings.value("wizard/nextPage").isNull(); - if (settings.value("wizard/showWizard", true).toBool() || - !settings.value("wizard/nextPage").isNull()) { - slotStartWizard(); - } } void MainWindow::restoreSettings() { - // state sets pos & size of dock-widgets - this->restoreState(settings.value("window/windowState").toByteArray()); - - // Restore window size & location - if (settings.value("window/windowSave").toBool()) { - QPoint pos = settings.value("window/pos", QPoint(100, 100)).toPoint(); - QSize size = settings.value("window/size", QSize(800, 450)).toSize(); - this->resize(size); - this->move(pos); - } else { - this->resize(QSize(800, 450)); - this->move(QPoint(100, 100)); - } - - // Iconsize - QSize iconSize = settings.value("toolbar/iconsize", QSize(24, 24)).toSize(); - this->setIconSize(iconSize); - - importButton->setIconSize(iconSize); - fileEncButton->setIconSize(iconSize); - // set list of keyserver if not defined - QStringList *keyServerDefaultList; - keyServerDefaultList = new QStringList("http://keys.gnupg.net"); - keyServerDefaultList->append("https://keyserver.ubuntu.com"); - keyServerDefaultList->append("http://pool.sks-keyservers.net"); - - QStringList keyServerList = - settings.value("keyserver/keyServerList", *keyServerDefaultList) - .toStringList(); - settings.setValue("keyserver/keyServerList", keyServerList); - - // set default keyserver, if it's not set - QString defaultKeyServer = settings - .value("keyserver/defaultKeyServer", - QString("https://keyserver.ubuntu.com")) - .toString(); - settings.setValue("keyserver/defaultKeyServer", defaultKeyServer); - - // Iconstyle - Qt::ToolButtonStyle buttonStyle = static_cast<Qt::ToolButtonStyle>( - settings.value("toolbar/iconstyle", Qt::ToolButtonTextUnderIcon) - .toUInt()); - this->setToolButtonStyle(buttonStyle); - importButton->setToolButtonStyle(buttonStyle); - fileEncButton->setToolButtonStyle(buttonStyle); - - // Checked Keys - if (settings.value("keys/saveKeyChecked").toBool()) { - QStringList keyIds = - settings.value("keys/savedCheckedKeyList").toStringList(); - mKeyList->setChecked(&keyIds); - } + // state sets pos & size of dock-widgets + this->restoreState(settings.value("window/windowState").toByteArray()); + + // Restore window size & location + if (settings.value("window/windowSave").toBool()) { + QPoint pos = settings.value("window/pos", QPoint(100, 100)).toPoint(); + QSize size = settings.value("window/size", QSize(800, 450)).toSize(); + this->resize(size); + this->move(pos); + } else { + this->resize(QSize(800, 450)); + this->move(QPoint(100, 100)); + } + + // Iconsize + QSize iconSize = settings.value("toolbar/iconsize", QSize(24, 24)).toSize(); + this->setIconSize(iconSize); + + importButton->setIconSize(iconSize); + fileEncButton->setIconSize(iconSize); + // set list of keyserver if not defined + QStringList *keyServerDefaultList; + keyServerDefaultList = new QStringList("http://keys.gnupg.net"); + keyServerDefaultList->append("https://keyserver.ubuntu.com"); + keyServerDefaultList->append("http://pool.sks-keyservers.net"); + + QStringList keyServerList = + settings.value("keyserver/keyServerList", *keyServerDefaultList) + .toStringList(); + settings.setValue("keyserver/keyServerList", keyServerList); + + // set default keyserver, if it's not set + QString defaultKeyServer = settings + .value("keyserver/defaultKeyServer", + QString("https://keyserver.ubuntu.com")) + .toString(); + settings.setValue("keyserver/defaultKeyServer", defaultKeyServer); + + // Iconstyle + Qt::ToolButtonStyle buttonStyle = static_cast<Qt::ToolButtonStyle>( + settings.value("toolbar/iconstyle", Qt::ToolButtonTextUnderIcon) + .toUInt()); + this->setToolButtonStyle(buttonStyle); + importButton->setToolButtonStyle(buttonStyle); + fileEncButton->setToolButtonStyle(buttonStyle); + + // Checked Keys + if (settings.value("keys/saveKeyChecked").toBool()) { + QStringList keyIds = + settings.value("keys/savedCheckedKeyList").toStringList(); + mKeyList->setChecked(&keyIds); + } } void MainWindow::saveSettings() { - // window position and size - settings.setValue("window/windowState", saveState()); - settings.setValue("window/pos", pos()); - settings.setValue("window/size", size()); - - // keyid-list of private checked keys - if (settings.value("keys/saveKeyChecked").toBool()) { - QStringList *keyIds = mKeyList->getChecked(); - if (!keyIds->isEmpty()) { - settings.setValue("keys/savedCheckedKeyList", *keyIds); + // window position and size + settings.setValue("window/windowState", saveState()); + settings.setValue("window/pos", pos()); + settings.setValue("window/size", size()); + + // keyid-list of private checked keys + if (settings.value("keys/saveKeyChecked").toBool()) { + QStringList *keyIds = mKeyList->getChecked(); + if (!keyIds->isEmpty()) { + settings.setValue("keys/savedCheckedKeyList", *keyIds); + } else { + settings.setValue("keys/savedCheckedKeyList", ""); + } } else { - settings.setValue("keys/savedCheckedKeyList", ""); + settings.remove("keys/savedCheckedKeyList"); } - } else { - settings.remove("keys/savedCheckedKeyList"); - } } void MainWindow::closeAttachmentDock() { - if (!attachmentDockCreated) { - return; - } - attachmentDock->close(); - attachmentDock->deleteLater(); - attachmentDockCreated = false; + if (!attachmentDockCreated) { + return; + } + attachmentDock->close(); + attachmentDock->deleteLater(); + attachmentDockCreated = false; } void MainWindow::closeEvent(QCloseEvent *event) { - /* - * ask to save changes, if there are - * modified documents in any tab - */ - if (edit->maybeSaveAnyTab()) { - saveSettings(); - event->accept(); - } else { - event->ignore(); - } - - // clear password from memory - mCtx->clearPasswordCache(); + /* + * ask to save changes, if there are + * modified documents in any tab + */ + if (edit->maybeSaveAnyTab()) { + saveSettings(); + event->accept(); + } else { + event->ignore(); + } + + // clear password from memory + mCtx->clearPasswordCache(); } diff --git a/src/main.cpp b/src/main.cpp index 00ab2738..3e14a425 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,6 +23,7 @@ */ #include "MainWindow.h" +#include "GpgFrontendBuildInfo.h" int main(int argc, char *argv[]) { diff --git a/src/ui/AboutDialog.cpp b/src/ui/AboutDialog.cpp deleted file mode 100644 index e51f225d..00000000 --- a/src/ui/AboutDialog.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/** - * This file is part of GPGFrontend. - * - * GPGFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Foobar is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from gpg4usb-team. - * Their source code version also complies with GNU General Public License. - * - * The source code version of this software was modified and released - * by Saturneric<[email protected]> starting on May 12, 2021. - * - */ - -#include "ui/AboutDialog.h" - -AboutDialog::AboutDialog(QWidget *parent) - : QDialog(parent) { - this->setWindowTitle(tr("About ") + qApp->applicationName()); - - auto *tabWidget = new QTabWidget; - auto *infoTab = new InfoTab; - auto *translatorsTab = new TranslatorsTab; - - tabWidget->addTab(infoTab, tr("General")); - tabWidget->addTab(translatorsTab, tr("Translators")); - - auto *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(close())); - - auto *mainLayout = new QVBoxLayout; - mainLayout->addWidget(tabWidget); - mainLayout->addWidget(buttonBox); - setLayout(mainLayout); - - this->exec(); -} - -InfoTab::InfoTab(QWidget *parent) - : QWidget(parent) { - auto *pixmap = new QPixmap(":gpgfrontend-logo.png"); - auto *text = new QString("<center><h2>" + qApp->applicationName() + "</h2></center>" - + "<center><b>" + qApp->applicationVersion() + "</b></center>" - + "<center>" + GIT_VERSION + "</center>" - + tr("<br><center>GPGFrontend is an easy-to-use, compact, <br>" - "cross-platform, and installation-free gpg front-end tool.<br>" - "It visualizes most of the common operations of gpg commands.<br>" - "It's licensed under the GPL v3<br><br>" - "<b>Developer:</b><br>" - "Saturneric<br><br>" - "If you have any questions or suggestions, raise an issue<br/>" - "at <a href=\"https://github.com/saturneric/GpgFrontend\">GitHub</a> or send a mail to my mailing list at <a href=\"mailto:[email protected]\">[email protected]</a>.") + - tr("<br><br> Built with Qt ") + qVersion() - + tr(" and GPGME ") + GpgME::GpgContext::getGpgmeVersion() + - tr("<br>Built at ") + BUILD_TIMESTAMP + "</center>"); - - auto *layout = new QGridLayout(); - auto *pixmapLabel = new QLabel(); - pixmapLabel->setPixmap(*pixmap); - layout->addWidget(pixmapLabel, 0, 0, 1, -1, Qt::AlignCenter); - auto *aboutLabel = new QLabel(); - aboutLabel->setText(*text); - aboutLabel->setOpenExternalLinks(true); - layout->addWidget(aboutLabel, 1, 0, 1, -1); - layout->addItem(new QSpacerItem(20, 10, QSizePolicy::Minimum, - QSizePolicy::Fixed), 2, 1, 1, 1); - - setLayout(layout); -} - -TranslatorsTab::TranslatorsTab(QWidget *parent) - : QWidget(parent) { - QFile translatorsFile; - translatorsFile.setFileName(qApp->applicationDirPath() + "/About"); - translatorsFile.open(QIODevice::ReadOnly); - QByteArray inBuffer = translatorsFile.readAll(); - - auto *label = new QLabel(inBuffer); - auto *mainLayout = new QVBoxLayout(this); - mainLayout->addWidget(label); - - setLayout(mainLayout); -} - diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 68f57b81..618b5d28 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -3,6 +3,7 @@ aux_source_directory(./keypair_details UI_SOURCE) aux_source_directory(./widgets UI_SOURCE) aux_source_directory(./keygen UI_SOURCE) aux_source_directory(./main_window UI_SOURCE) +aux_source_directory(./help UI_SOURCE) add_library(gpgfrontend-ui STATIC ${UI_SOURCE}) diff --git a/src/ui/help/AboutDialog.cpp b/src/ui/help/AboutDialog.cpp new file mode 100644 index 00000000..4c9b54c9 --- /dev/null +++ b/src/ui/help/AboutDialog.cpp @@ -0,0 +1,208 @@ +/** + * This file is part of GPGFrontend. + * + * GPGFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "ui/help/AboutDialog.h" +#include "GpgFrontendBuildInfo.h" + +#include "rapidjson/document.h" +#include "rapidjson/writer.h" + +using namespace rapidjson; + +AboutDialog::AboutDialog(int defaultIndex, QWidget *parent) + : QDialog(parent) { + this->setWindowTitle(tr("About ") + qApp->applicationName()); + + auto *tabWidget = new QTabWidget; + auto *infoTab = new InfoTab(); + auto *translatorsTab = new TranslatorsTab(); + auto *updateTab = new UpdateTab(); + + tabWidget->addTab(infoTab, tr("General")); + tabWidget->addTab(translatorsTab, tr("Translators")); + tabWidget->addTab(updateTab, tr("Update")); + + connect(tabWidget, &QTabWidget::currentChanged, this, [&](int index) { + qDebug() << "Current Index" << index; + if(index == 2) { + updateTab->getLatestVersion(); + } + }); + + if(defaultIndex < tabWidget->count() && defaultIndex >= 0) { + tabWidget->setCurrentIndex(defaultIndex); + } + + auto *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok); + connect(buttonBox, SIGNAL(accepted()), this, SLOT(close())); + + auto *mainLayout = new QVBoxLayout; + mainLayout->addWidget(tabWidget); + mainLayout->addWidget(buttonBox); + setLayout(mainLayout); + + this->exec(); +} + +InfoTab::InfoTab(QWidget *parent) + : QWidget(parent) { + auto *pixmap = new QPixmap(":gpgfrontend-logo.png"); + auto *text = new QString("<center><h2>" + qApp->applicationName() + "</h2></center>" + + "<center><b>" + qApp->applicationVersion() + "</b></center>" + + "<center>" + GIT_VERSION + "</center>" + + tr("<br><center>GPGFrontend is an easy-to-use, compact, cross-platform, <br>" + "and installation-free gpg front-end tool.<br>" + "It visualizes most of the common operations of gpg commands.<br>" + "It's licensed under the GPL v3<br><br>" + "<b>Developer:</b><br>" + "Saturneric<br><br>" + "If you have any questions or suggestions, raise an issue<br/>" + "at <a href=\"https://github.com/saturneric/GpgFrontend\">GitHub</a> or send a mail to my mailing list at <a href=\"mailto:[email protected]\">[email protected]</a>.") + + tr("<br><br> Built with Qt ") + qVersion() + + tr(" and GPGME ") + GpgME::GpgContext::getGpgmeVersion() + + tr("<br>Built at ") + BUILD_TIMESTAMP + "</center>"); + + auto *layout = new QGridLayout(); + auto *pixmapLabel = new QLabel(); + pixmapLabel->setPixmap(*pixmap); + layout->addWidget(pixmapLabel, 0, 0, 1, -1, Qt::AlignCenter); + auto *aboutLabel = new QLabel(); + aboutLabel->setText(*text); + aboutLabel->setOpenExternalLinks(true); + layout->addWidget(aboutLabel, 1, 0, 1, -1); + layout->addItem(new QSpacerItem(20, 10, QSizePolicy::Minimum, + QSizePolicy::Fixed), 2, 1, 1, 1); + + setLayout(layout); +} + +TranslatorsTab::TranslatorsTab(QWidget *parent) + : QWidget(parent) { + QFile translatorsFile; + translatorsFile.setFileName(qApp->applicationDirPath() + "/About"); + translatorsFile.open(QIODevice::ReadOnly); + QByteArray inBuffer = translatorsFile.readAll(); + + auto *label = new QLabel(inBuffer); + auto *mainLayout = new QVBoxLayout(this); + mainLayout->addWidget(label); + + setLayout(mainLayout); +} + +UpdateTab::UpdateTab(QWidget *parent) { + auto *pixmap = new QPixmap(":gpgfrontend-logo.png"); + auto *layout = new QGridLayout(); + auto *pixmapLabel = new QLabel(); + pixmapLabel->setPixmap(*pixmap); + layout->addWidget(pixmapLabel, 0, 0, 1, -1, Qt::AlignCenter); + + currentVersion = "v" + QString::number(VERSION_MAJOR) + "." + + QString::number(VERSION_MINOR) + "." + + QString::number(VERSION_PATCH); + + auto tipsLabel = new QLabel(); + tipsLabel->setText("<center>" + + tr("It is recommended that you always check the version of GpgFrontend and upgrade to the latest version.") + + "</center><br><center>" + + tr("New versions not only represent new features, but also often represent functional and security fixes.") + "</center>"); + tipsLabel->setWordWrap(true); + + currentVersionLabel = new QLabel(); + currentVersionLabel->setText("<center>" + tr("Current Version: ") + "<b>" + currentVersion + "</b></center>"); + currentVersionLabel->setWordWrap(true); + + latestVersionLabel = new QLabel(); + latestVersionLabel->setWordWrap(true); + + upgradeLabel = new QLabel(); + upgradeLabel->setText("<center>" + + tr("The current version is inconsistent with the latest version on github.") + + "</center><br><center>" + + tr("Please click <a href=\"https://github.com/saturneric/GpgFrontend/releases\">here</a> to download the latest version.") + "</center>"); + upgradeLabel->setWordWrap(true); + upgradeLabel->setOpenExternalLinks(true); + upgradeLabel->setHidden(true); + + pb = new QProgressBar(); + pb->setRange(0, 0); + pb->setTextVisible(false); + + layout->addWidget(tipsLabel, 1, 0, 1, -1); + layout->addWidget(currentVersionLabel, 2, 0, 1, -1); + layout->addWidget(latestVersionLabel, 3, 0, 1, -1); + layout->addWidget(upgradeLabel, 4, 0, 1, -1); + layout->addWidget(pb, 5, 0, 1, -1); + layout->addItem(new QSpacerItem(20, 10, QSizePolicy::Minimum, + QSizePolicy::Fixed), 2, 1, 1, 1); + + setLayout(layout); +} + +void UpdateTab::getLatestVersion() { + + this->pb->setHidden(false); + + qDebug() << "Try to get latest version"; + + QString baseUrl = "https://api.github.com/repos/saturneric/gpgfrontend/releases/latest"; + + auto manager = new QNetworkAccessManager(this); + + QNetworkRequest request; + request.setUrl(QUrl(baseUrl)); + + QNetworkReply *replay = manager->get(request); + + while(replay->isRunning()) { + QApplication::processEvents(); + } + + this->pb->setHidden(true); + + QByteArray bytes = replay->readAll(); + + Document d; + d.Parse(bytes.constData()); + + QString latestVersion = d["tag_name"].GetString(); + + qDebug() << "Latest Version From Github" << latestVersion; + + QRegularExpression re("^[vV](\\d+\\.)?(\\d+\\.)?(\\*|\\d+)"); + QRegularExpressionMatch match = re.match(latestVersion); + if (match.hasMatch()) { + latestVersion = match.captured(0); // matched == "23 def" + qDebug() << "Latest Version Matched" << latestVersion; + } else { + latestVersion = "Unknown"; + } + + latestVersionLabel->setText("<center><b>" + tr("Latest Version From Github: ") + latestVersion + "</b></center>"); + + if(latestVersion > currentVersion) { + upgradeLabel->setHidden(false); + } + +} diff --git a/src/ui/help/VersionCheckThread.cpp b/src/ui/help/VersionCheckThread.cpp new file mode 100644 index 00000000..7bd0eb8f --- /dev/null +++ b/src/ui/help/VersionCheckThread.cpp @@ -0,0 +1,50 @@ +// +// Created by Administrator on 2021/7/12. +// + +#include "ui/help/VersionCheckThread.h" +#include "GpgFrontendBuildInfo.h" +#include "rapidjson/document.h" +#include "rapidjson/writer.h" + +using namespace rapidjson; + +void VersionCheckThread::run() { + qDebug() << "Start Version Thread to get latest version from Github"; + + auto currentVersion = "v" + QString::number(VERSION_MAJOR) + "." + + QString::number(VERSION_MINOR) + "." + + QString::number(VERSION_PATCH); + + while(mNetworkReply->isRunning()) { + QApplication::processEvents(); + } + + QByteArray bytes = mNetworkReply->readAll(); + + Document d; + d.Parse(bytes.constData()); + + QString latestVersion = d["tag_name"].GetString(); + + qDebug() << "Latest Version From Github" << latestVersion; + + QRegularExpression re("^[vV](\\d+\\.)?(\\d+\\.)?(\\*|\\d+)"); + QRegularExpressionMatch match = re.match(latestVersion); + if (match.hasMatch()) { + latestVersion = match.captured(0); // matched == "23 def" + qDebug() << "Latest Version Matched" << latestVersion; + } else { + latestVersion = currentVersion; + qDebug() << "Latest Version Unknown" << latestVersion; + } + + if(latestVersion != currentVersion) { + emit upgradeVersion(currentVersion, latestVersion); + } + +} + +VersionCheckThread::VersionCheckThread(QNetworkReply *networkReply):mNetworkReply(networkReply) { + +} diff --git a/src/ui/keygen/SubkeyGenerateThread.cpp b/src/ui/keygen/SubkeyGenerateThread.cpp index 4f19ac1f..125f35f8 100644 --- a/src/ui/keygen/SubkeyGenerateThread.cpp +++ b/src/ui/keygen/SubkeyGenerateThread.cpp @@ -24,8 +24,6 @@ #include "ui/keygen/SubkeyGenerateThread.h" -#include <utility> - SubkeyGenerateThread::SubkeyGenerateThread(GpgKey key, GenKeyInfo *keyGenParams, GpgME::GpgContext *ctx) : mKey(std::move(key)), keyGenParams(keyGenParams) , mCtx(ctx) { connect(this, &SubkeyGenerateThread::finished, this, &SubkeyGenerateThread::deleteLater); diff --git a/src/ui/main_window/MainWindowSlotFunction.cpp b/src/ui/main_window/MainWindowSlotFunction.cpp index 21d0af0d..0bddb9b2 100644 --- a/src/ui/main_window/MainWindowSlotFunction.cpp +++ b/src/ui/main_window/MainWindowSlotFunction.cpp @@ -58,7 +58,7 @@ void MainWindow::slotEncrypt() { auto thread = QThread::create([&]() { error = mCtx->encrypt(keys, edit->curTextPage()->toPlainText().toUtf8(), tmp, &result); }); - + connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater())); thread->start(); auto *dialog = new WaitingDialog(tr("Encrypting"), this); @@ -122,6 +122,7 @@ void MainWindow::slotSign() { auto thread = QThread::create([&]() { error = mCtx->sign(keys, edit->curTextPage()->toPlainText().toUtf8(), tmp, false, &result); }); + connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater())); thread->start(); auto *dialog = new WaitingDialog(tr("Signing"), this); @@ -165,6 +166,7 @@ void MainWindow::slotDecrypt() { // try decrypt, if fail do nothing, especially don't replace text error = mCtx->decrypt(text, decrypted, &result); }); + connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater())); thread->start(); auto *dialog = new WaitingDialog(tr("Decrypting"), this); @@ -224,6 +226,7 @@ void MainWindow::slotVerify() { auto thread = QThread::create([&]() { error = mCtx->verify(&text, nullptr, &result); }); + connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater())); thread->start(); auto *dialog = new WaitingDialog(tr("Verifying"), this); @@ -312,6 +315,7 @@ void MainWindow::slotEncryptSign() { error = mCtx->encryptSign(keys, edit->curTextPage()->toPlainText().toUtf8(), tmp, &encr_result, &sign_result); }); + connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater())); thread->start(); auto *dialog = new WaitingDialog(tr("Encrypting and Signing"), this); @@ -364,6 +368,7 @@ void MainWindow::slotDecryptVerify() { auto thread = QThread::create([&]() { error = mCtx->decryptVerify(text, decrypted, &d_result, &v_result); }); + connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater())); thread->start(); WaitingDialog *dialog = new WaitingDialog(tr("Decrypting and Verifying"), this); @@ -516,6 +521,7 @@ void MainWindow::slotFileEncrypt() { if_error = true; } }); + connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater())); thread->start(); auto *dialog = new WaitingDialog(tr("Encrypting"), this); @@ -524,7 +530,7 @@ void MainWindow::slotFileEncrypt() { } dialog->close(); - if(!if_error) { + if (!if_error) { auto resultAnalyse = new EncryptResultAnalyse(error, result); auto &reportText = resultAnalyse->getResultReport(); infoBoard->associateTabWidget(edit->tabWidget); @@ -596,6 +602,7 @@ void MainWindow::slotFileDecrypt() { if_error = true; } }); + connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater())); thread->start(); auto *dialog = new WaitingDialog("Decrypting", this); @@ -605,7 +612,7 @@ void MainWindow::slotFileDecrypt() { dialog->close(); - if(!if_error) { + if (!if_error) { auto resultAnalyse = new DecryptResultAnalyse(mCtx, error, result); auto &reportText = resultAnalyse->getResultReport(); infoBoard->associateTabWidget(edit->tabWidget); @@ -691,6 +698,7 @@ void MainWindow::slotFileSign() { if_error = true; } }); + connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater())); thread->start(); auto *dialog = new WaitingDialog(tr("Signing"), this); @@ -700,7 +708,7 @@ void MainWindow::slotFileSign() { dialog->close(); - if(!if_error) { + if (!if_error) { auto resultAnalyse = new SignResultAnalyse(error, result); auto &reportText = resultAnalyse->getResultReport(); @@ -775,6 +783,7 @@ void MainWindow::slotFileVerify() { if_error = true; } }); + connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater())); thread->start(); auto *dialog = new WaitingDialog(tr("Verifying"), this); @@ -894,6 +903,7 @@ void MainWindow::slotFileEncryptSign() { if_error = true; } }); + connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater())); thread->start(); WaitingDialog *dialog = new WaitingDialog(tr("Encrypting and Signing"), this); @@ -902,7 +912,7 @@ void MainWindow::slotFileEncryptSign() { } dialog->close(); - if(!if_error) { + if (!if_error) { auto resultAnalyseEncr = new EncryptResultAnalyse(error, encr_result); auto resultAnalyseSign = new SignResultAnalyse(error, sign_result); @@ -970,15 +980,17 @@ void MainWindow::slotFileDecryptVerify() { if_error = true; } }); + connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater())); thread->start(); + auto *dialog = new WaitingDialog(tr("Decrypting and Verifying"), this); while (thread->isRunning()) { QApplication::processEvents(); } dialog->close(); - if(!if_error) { + if (!if_error) { infoBoard->associateFileTreeView(edit->curFilePage()); auto resultAnalyseDecrypt = new DecryptResultAnalyse(mCtx, error, d_result); @@ -1036,3 +1048,21 @@ void MainWindow::slotFileVerifyCustom() { void MainWindow::slotOpenFile(QString &path) { edit->slotOpenFile(path); } + +void MainWindow::slotVersionUpgrade(const QString ¤tVersion, const QString &latestVersion) { + if(currentVersion < latestVersion) { + QMessageBox::warning(this, + tr("Outdated Version"), + tr("This version(%1) is out of date, please update the latest version in time. ").arg( + currentVersion) + + tr("You can download the latest version(%1) on Github Releases Page.<br/>").arg( + latestVersion)); + } else if(currentVersion > latestVersion) { + QMessageBox::warning(this, + tr("Unreleased Version"), + tr("This version(%1) has not been officially released and is not recommended for use in a production environment. <br/>").arg( + currentVersion) + + tr("You can download the latest version(%1) on Github Releases Page.<br/>").arg( + latestVersion)); + } +} diff --git a/src/ui/main_window/MainWindowSlotUI.cpp b/src/ui/main_window/MainWindowSlotUI.cpp index 189ead53..d95a9bfe 100644 --- a/src/ui/main_window/MainWindowSlotUI.cpp +++ b/src/ui/main_window/MainWindowSlotUI.cpp @@ -25,7 +25,11 @@ #include "MainWindow.h" void MainWindow::slotAbout() { - new AboutDialog(this); + new AboutDialog(0, this); +} + +void MainWindow::slotCheckUpdate() { + new AboutDialog(2, this); } void MainWindow::slotSetStatusBarText(const QString &text) { diff --git a/src/ui/main_window/MainWindowUI.cpp b/src/ui/main_window/MainWindowUI.cpp index 01c9fdde..0f7f1040 100644 --- a/src/ui/main_window/MainWindowUI.cpp +++ b/src/ui/main_window/MainWindowUI.cpp @@ -209,18 +209,27 @@ void MainWindow::createActions() { importKeyFromEditAct->setToolTip(tr("Import New Key From Editor")); connect(importKeyFromEditAct, SIGNAL(triggered()), this, SLOT(slotImportKeyFromEdit())); - openKeyManagementAct = new QAction(tr("Manage &keys"), this); + openKeyManagementAct = new QAction(tr("Manage &Keys"), this); openKeyManagementAct->setIcon(QIcon(":keymgmt.png")); openKeyManagementAct->setToolTip(tr("Open Keymanagement")); connect(openKeyManagementAct, SIGNAL(triggered()), this, SLOT(slotOpenKeyManagement())); - /* About Menu + /* + * About Menu */ aboutAct = new QAction(tr("&About"), this); aboutAct->setIcon(QIcon(":help.png")); aboutAct->setToolTip(tr("Show the application's About box")); connect(aboutAct, SIGNAL(triggered()), this, SLOT(slotAbout())); + /* + * Check Update Menu + */ + checkUpdateAct = new QAction(tr("&Check for Updates"), this); + checkUpdateAct->setIcon(QIcon(":help.png")); + checkUpdateAct->setToolTip(tr("Check for updates")); + connect(checkUpdateAct, SIGNAL(triggered()), this, SLOT(slotCheckUpdate())); + startWizardAct = new QAction(tr("Open &Wizard"), this); startWizardAct->setToolTip(tr("Open the wizard")); connect(startWizardAct, SIGNAL(triggered()), this, SLOT(slotStartWizard())); @@ -340,6 +349,7 @@ void MainWindow::createMenus() { helpMenu = menuBar()->addMenu(tr("&Help")); helpMenu->addAction(startWizardAct); helpMenu->addSeparator(); + helpMenu->addAction(checkUpdateAct); helpMenu->addAction(aboutAct); } diff --git a/src/ui/widgets/EditorPage.cpp b/src/ui/widgets/EditorPage.cpp index 8a51b721..05d5cbea 100644 --- a/src/ui/widgets/EditorPage.cpp +++ b/src/ui/widgets/EditorPage.cpp @@ -42,6 +42,9 @@ EditorPage::EditorPage(QString filePath, QWidget *parent) : QWidget(parent), setAttribute(Qt::WA_DeleteOnClose); textPage->setFocus(); + // Front in same width + this->setFont({"Courier"}); + connect(textPage, SIGNAL(textChanged()), this, SLOT(formatGpgHeader())); } diff --git a/src/ui/widgets/FilePage.cpp b/src/ui/widgets/FilePage.cpp index e330eb68..65755509 100644 --- a/src/ui/widgets/FilePage.cpp +++ b/src/ui/widgets/FilePage.cpp @@ -50,11 +50,15 @@ FilePage::FilePage(QWidget *parent) : QWidget(parent) { upLevelButton = new QPushButton(); connect(upLevelButton, SIGNAL(clicked(bool)), this, SLOT(slotUpLevel())); + QString buttonStyle = "QPushButton{border:none;background-color:rgba(255, 255, 255,100);}"; + + auto upPixmap = QPixmap(":up.png"); upPixmap = upPixmap.scaled(18, 18, Qt::KeepAspectRatio, Qt::SmoothTransformation); QIcon upButtonIcon(upPixmap); upLevelButton->setIcon(upButtonIcon); upLevelButton->setIconSize(upPixmap.rect().size()); + upLevelButton->setStyleSheet(buttonStyle); refreshButton = new QPushButton("Refresh"); connect(refreshButton, SIGNAL(clicked(bool)), this, SLOT(slotGoPath())); @@ -67,6 +71,7 @@ FilePage::FilePage(QWidget *parent) : QWidget(parent) { QIcon updateButtonIcon(updatePixmap); goPathButton->setIcon(updateButtonIcon); goPathButton->setIconSize(updatePixmap.rect().size()); + goPathButton->setStyleSheet(buttonStyle); pathEdit = new QLineEdit(); pathEdit->setText(dirModel->rootPath()); @@ -75,7 +80,7 @@ FilePage::FilePage(QWidget *parent) : QWidget(parent) { menuLayout->addWidget(upLevelButton); menuLayout->setStretchFactor(upLevelButton, 1); menuLayout->addWidget(pathEdit); - menuLayout->setStretchFactor(pathEdit, 8); + menuLayout->setStretchFactor(pathEdit, 10); menuLayout->addWidget(goPathButton); menuLayout->setStretchFactor(goPathButton, 1); // menuLayout->addWidget(refreshButton); diff --git a/src/ui/widgets/TextEdit.cpp b/src/ui/widgets/TextEdit.cpp index f06b3a45..c9968565 100644 --- a/src/ui/widgets/TextEdit.cpp +++ b/src/ui/widgets/TextEdit.cpp @@ -37,9 +37,6 @@ TextEdit::TextEdit(QWidget *parent) : QWidget(parent) { layout->setSpacing(0); setLayout(layout); - // Front in same width - this->setFont({"Courier"}); - connect(tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(removeTab(int))); connect(this, &TextEdit::insertTargetTextPage, this, @@ -73,7 +70,7 @@ 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, "[File Browser]"); + tabWidget->addTab(page, "[Browser]"); tabWidget->setCurrentIndex(tabWidget->count() - 1); connect(page, SIGNAL(pathChanged(const QString &)), this, SLOT(slotFilePagePathChanged(const QString &))); @@ -646,7 +643,7 @@ void TextEdit::slotFilePagePathChanged(const QString &path) { } else { mPath = tPath; } - mPath.prepend("[File Browser] "); + mPath.prepend("[Browser] "); mPath.append("/"); tabWidget->setTabText(index, mPath); } |