diff --git a/src/gpgolgui/CMakeLists.txt b/src/gpgolgui/CMakeLists.txt index fbcd376..0841031 100644 --- a/src/gpgolgui/CMakeLists.txt +++ b/src/gpgolgui/CMakeLists.txt @@ -1,39 +1,40 @@ # Copyright (C) 2018 Intevation GmbH # # This file is Free Software under the GNU GPL (v>=2) # and comes with ABSOLUTELY NO WARRANTY! # See LICENSE.txt for details. set(EXECUTABLE_NAME "gpgolgui") set(EXECUTABLE_SRC main.cpp gpgolgui-options.h gpgolgui.cpp gpgolconfigpage.cpp + cryptoconfigpage.cpp ${CMAKE_SOURCE_DIR}/src/img/icon.rc ${CMAKE_SOURCE_DIR}/src/util/strhelp.c ${CMAKE_SOURCE_DIR}/src/util/w32-util.cpp ${CMAKE_SOURCE_DIR}/src/util/w32-gettext.c ) qt5_add_resources(EXECUTABLE_SRC gpgolgui.qrc) add_executable(${EXECUTABLE_NAME} ${_add_executable_params} ${EXECUTABLE_SRC} ) target_link_libraries(${EXECUTABLE_NAME} Qt5::Widgets KF5::WidgetsAddons KF5::Libkleo Gpgmepp QGpgme ) if (WIN32) set_target_properties(${EXECUTABLE_NAME} PROPERTIES LINK_FLAGS "-municode") endif(WIN32) install(TARGETS ${EXECUTABLE_NAME} DESTINATION bin) diff --git a/src/gpgolgui/cryptoconfigpage.cpp b/src/gpgolgui/cryptoconfigpage.cpp new file mode 100644 index 0000000..e6beac7 --- /dev/null +++ b/src/gpgolgui/cryptoconfigpage.cpp @@ -0,0 +1,134 @@ +/* Copyright (C) 2018 by Intevation GmbH + * + * This file is Free Software under the GNU GPL (v>=2) + * and comes with ABSOLUTELY NO WARRANTY! + * See LICENSE.txt for details. + */ + +#include "cryptoconfigpage.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include + +void clearLayout(QLayout* layout, bool deleteWidgets = true) +{ + while (QLayoutItem* item = layout->takeAt(0)) + { + if (deleteWidgets) + { + if (QWidget* widget = item->widget()) + widget->deleteLater(); + } + if (QLayout* childLayout = item->layout()) + clearLayout(childLayout, deleteWidgets); + delete item; + } +} + +class DelayLoader: public QThread +{ + Q_OBJECT + void run() override { + QGpgME::CryptoConfig *config = QGpgME::cryptoConfig(); + + /* Grab an entry to force the load */ + auto entry = config->entry(QStringLiteral("gpg"), + QStringLiteral("Keyserver"), + QStringLiteral("keyserver")); + Q_UNUSED(entry); + + emit resultReady(config); + deleteLater(); + } +signals: + void resultReady(QGpgME::CryptoConfig *config); +}; + +void CryptoConfigPage::delayLoadFinished(QGpgME::CryptoConfig *config) +{ + mConfigWidget = new Kleo::CryptoConfigModule(config, + Kleo::CryptoConfigModule::TabbedLayout); + auto lay = layout(); + clearLayout(lay, true); + delete lay; + auto newLay = new QVBoxLayout(this); + newLay->addWidget(mConfigWidget); + connect(mConfigWidget, &Kleo::CryptoConfigModule::changed, + this, [this] () { + mCryptoConfigChanged = true; + }); +} + +CryptoConfigPage::CryptoConfigPage(QWidget *parent): + QWidget(parent), + mConfigWidget(nullptr), + mCryptoConfigChanged(false) +{ + auto loader = new DelayLoader; + auto vLay = new QVBoxLayout(this); + auto bar = new QProgressBar; + auto label = new QLabel; + label->setText(QStringLiteral("

Loading module...

")); + bar->setRange(0, 0); + vLay->addStretch(1); + + auto subLay1 = new QVBoxLayout; + auto subLay3 = new QHBoxLayout; + subLay3->addStretch(0.5); + subLay3->addWidget(label); + subLay3->addStretch(1); + subLay1->addLayout(subLay3); + subLay1->addWidget(bar); + + auto subLay2 = new QHBoxLayout; + subLay2->addStretch(0.1); + subLay2->addLayout(subLay1); + subLay2->addStretch(0.1); + + vLay->addLayout(subLay2); + + vLay->addStretch(1); + + connect(loader, SIGNAL(resultReady(QGpgME::CryptoConfig *)), + this, SLOT(delayLoadFinished(QGpgME::CryptoConfig *))); + + /* + connect(loader, &DelayLoader::resultReady, [this] (QGpgME::CryptoConfig *config) { + qDebug() << "Creating config widget"; + mConfigWidget = new Kleo::CryptoConfigModule(config, + Kleo::CryptoConfigModule::TabbedLayout); + delete layout(); + auto newLay = new QVBoxLayout(this); + newLay->addWidget(mConfigWidget); + connect(mConfigWidget, &Kleo::CryptoConfigModule::changed, + this, [this] () { + mCryptoConfigChanged = true; + }); + }); + */ + loader->start(); +} + +void CryptoConfigPage::save() +{ + if (mConfigWidget && mCryptoConfigChanged) { + mConfigWidget->save(); + } +} + +void CryptoConfigPage::defaults() +{ + if (mConfigWidget) { + mConfigWidget->defaults(); + } +} + +#include "cryptoconfigpage.moc" diff --git a/src/gpgolgui/cryptoconfigpage.h b/src/gpgolgui/cryptoconfigpage.h new file mode 100644 index 0000000..405d12a --- /dev/null +++ b/src/gpgolgui/cryptoconfigpage.h @@ -0,0 +1,41 @@ +/* Copyright (C) 2018 by Intevation GmbH + * + * This file is Free Software under the GNU GPL (v>=2) + * and comes with ABSOLUTELY NO WARRANTY! + * See LICENSE.txt for details. + */ + +#ifndef CRYPTOCONFIGPAGE_H +#define CRYPTOCONFIGPAGE_H + +#include + +namespace Kleo +{ + class CryptoConfigModule; +} // namespace Kleo + +namespace QGpgME +{ + class CryptoConfig; +} + +class CryptoConfigPage: public QWidget +{ + Q_OBJECT + +public: + explicit CryptoConfigPage(QWidget *parent = nullptr); + + void save(); + void load(); + void defaults(); + +private Q_SLOTS: + void delayLoadFinished(QGpgME::CryptoConfig *config); + +private: + Kleo::CryptoConfigModule *mConfigWidget; + bool mCryptoConfigChanged; +}; +#endif diff --git a/src/gpgolgui/gpgolconfigpage.cpp b/src/gpgolgui/gpgolconfigpage.cpp index 1131570..e941bde 100644 --- a/src/gpgolgui/gpgolconfigpage.cpp +++ b/src/gpgolgui/gpgolconfigpage.cpp @@ -1,137 +1,264 @@ /* Copyright (C) 2018 by Intevation GmbH * * This file is Free Software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include "gpgolconfigpage.h" #include "w32-gettext.h" #include "w32-util.h" #include #include #include #include #include +#include +#include +#include +/* +class ExplainingChkBox: public QWidget +{ + Q_OBJECT +public: + explicit ExplainingChkBox(const QString &text, const QString &explanation): + mChkBox(new QCheckBox(text)), + mExplanation(explanation) + { + auto hBox = new QHBoxLayout(this); + + hBox->addWidget(mChkBox); + + auto infoBtn = new QPushButton; + infoBtn->setIcon(QIcon::fromTheme("help-contextual")); + hBox->addWidget(infoBtn); + hBox->addStretch(1); + + connect(infoBtn, &QPushButton::clicked, this, [this, infoBtn] () { + QToolTip::showText(infoBtn->mapToGlobal(QPoint()), mExplanation, infoBtn); + }); + } + + void setChecked(bool value) + { + mChkBox->setChecked(value); + } +private: + QCheckBox *mChkBox; + QString mExplanation; +}; +*/ GpgOLConfigPage::GpgOLConfigPage(QWidget *parent): QWidget(parent) { setupGUI(); load(); } -void GpgOLConfigPage::setVersion(const QString &version) +/* Helper to build an "About" style layout. +static QLayout *buildAboutLayout(const QString &version) { - mVersionLabel->setText(version); + auto hLay = new QHBoxLayout; + auto vLay = new QVBoxLayout; + hLay->addLayout(vLay); + hLay->addStretch(1); + + auto iconLbl = new QLabel; + iconLbl->setPixmap(QIcon(":/gpgol-logo.png").pixmap(128, 80)); + auto versionLbl = new QLabel(QStringLiteral(" ") + QString::fromUtf8(_("Version ")) + version); + vLay->addWidget(iconLbl); + vLay->addWidget(versionLbl); + + return hLay; } +*/ void GpgOLConfigPage::setupGUI() { auto baseLay = new QVBoxLayout(this); mSMIMEGrp = new QGroupBox(_("Enable the S/MIME support")); mSMIMEGrp->setCheckable(true); mSMIMEGrp->setAlignment(Qt::AlignLeft); auto smimeLay = new QVBoxLayout(mSMIMEGrp); mPreferSMIMEChk = new QCheckBox(_("Prefer S/MIME when autoresolving recipients")); + mPreferSMIMEChk->setToolTip(_("If automatic resolution is enabled, prefer S/MIME over OpenPGP if both are possible.")); smimeLay->addWidget(mPreferSMIMEChk); baseLay->addWidget(mSMIMEGrp); // The general group auto generalGrp = new QGroupBox(_("General")); auto generalLay = new QVBoxLayout(generalGrp); generalGrp->setAlignment(Qt::AlignLeft); mAlwaysSigChk = new QCheckBox(_("&Sign new messages by default")); + mAlwaysSigChk->setToolTip(_("Toggles the sign option for all new mails.")); mAlwaysEncChk = new QCheckBox(_("&Encrypt new messages by default")); + mAlwaysSigChk->setToolTip(_("Toggles the encrypt option for all new mails.")); + + mReplyCryptChk = new QCheckBox(_("S&elect crypto settings automatically " + "for reply and forward")); + mReplyCryptChk->setToolTip(_("Toggles sign, encrypt options if the original mail was signed or encrypted.")); + + mInlinePGPChk = new QCheckBox(_("&Send OpenPGP mails without attachments as PGP/Inline")); + mInlinePGPChk->setToolTip(_("Instead of using the PGP/MIME format, " + "which properly handles attachments and encoding, " + "the deprecated PGP/Inline is used.\n" + "This can be useful for compatibility but should generally not " + "be used.")); generalLay->addWidget(mAlwaysSigChk); generalLay->addWidget(mAlwaysEncChk); + generalLay->addWidget(mReplyCryptChk); + generalLay->addWidget(mInlinePGPChk); baseLay->addWidget(generalGrp); // The automation checkboxes mAutomationGrp = new QGroupBox(_("Automation")); mAutomationGrp->setToolTip(_("Enable or disable any automated key handling.")); auto autoLayout = new QVBoxLayout(mAutomationGrp); mAutomationGrp->setCheckable(true); - mAutoTrustChk = new QCheckBox(QStringLiteral("%1 (%2)").arg(_("Automate OpenPGP trust based on communication history")).arg(_("experimental"))); - mAutoTrustChk->setToolTip(_("This changes the trust model to \"tofu+pgp\" which tracks the history of key usage. Automated trust can never exceed level 2.")); + mAutoResolveChk = new QCheckBox(_("&Resolve recipient keys automatically")); + autoLayout->addWidget(mAutoResolveChk); - mAutoSecureChk = new QCheckBox(_("Automatically secure messages")); + auto subLay = new QHBoxLayout; + mAutoSecureChk = new QCheckBox(_("Automatically secure &messages")); mAutoSecureChk->setToolTip(_("Automatically toggles secure if keys with at least level 1 trust were found for all recipients.")); + subLay->addSpacing(20); + subLay->addWidget(mAutoSecureChk); + autoLayout->addLayout(subLay); - autoLayout->addWidget(mAutoSecureChk); + mAutoTrustChk = new QCheckBox(QStringLiteral("%1 (%2)").arg(_("Include OpenPGP &trust based on communication history")).arg(_("experimental"))); + mAutoTrustChk->setToolTip(_("This changes the trust model to \"tofu+pgp\" which tracks the history of key usage. " + "Automated trust can never exceed level 2.")); autoLayout->addWidget(mAutoTrustChk); + baseLay->addWidget(mAutomationGrp); + + // baseLay->addLayout(buildAboutLayout(mVersion)); + baseLay->addStretch(1); + + connect(mAutoResolveChk, &QCheckBox::toggled, [this] (bool on) { + mAutoSecureChk->setEnabled(on); + mPreferSMIMEChk->setEnabled(mSMIMEGrp->isChecked() && on); + }); + connect(mSMIMEGrp, &QGroupBox::toggled, [this] (bool on) { + mPreferSMIMEChk->setEnabled(mAutoSecureChk->isChecked() && on); + }); } static bool strToBool(const std::string &str, bool defaultVal = false) { if (str.empty()) { return defaultVal; } if (str == "1") { return true; } if (str == "0") { return false; } qDebug() << "Unknown bool val" << str.c_str(); return defaultVal; } static bool loadBool(const char *name, bool defaultVal) { return strToBool(W32::readRegStr(nullptr, GPGOL_REG_PATH, name), defaultVal); } +/* Bump this if you remove a config value */ +#define CONFIG_VERSION "1" + static const QMap defaultMap { { QStringLiteral("enableSmime"), false }, { QStringLiteral("encryptDefault"), false }, { QStringLiteral("signDefault"), false }, { QStringLiteral("inlinePGP"), false }, { QStringLiteral("replyCrypt"), true }, { QStringLiteral("preferSmime"), false }, { QStringLiteral("debugGPGME"), false }, { QStringLiteral("automation"), true }, + { QStringLiteral("autoresolve"), true }, { QStringLiteral("autosecure"), true }, { QStringLiteral("autotrust"), false }, - { QStringLiteral("import-autocrypt"), true }, }; void GpgOLConfigPage::updateGUI(const QMap &values) { bool smimeEnabled = values["enableSmime"]; mSMIMEGrp->setChecked(smimeEnabled); + mPreferSMIMEChk->setChecked(values["preferSmime"]); + + mAlwaysEncChk->setChecked(values["encryptDefault"]); + mAlwaysSigChk->setChecked(values["signDefault"]); + mInlinePGPChk->setChecked(values["inlinePGP"]); + mReplyCryptChk->setChecked(values["replyCrypt"]); mAutomationGrp->setChecked(values["automation"]); mAutoSecureChk->setChecked(values["autosecure"]); mAutoTrustChk->setChecked(values["autotrust"]); - mPreferSMIMEChk->setChecked(values["preferSmime"]); + mAutoResolveChk->setChecked(values["autoresolve"]); + + mAutoSecureChk->setEnabled(mAutoResolveChk->isChecked()); + mPreferSMIMEChk->setEnabled(mAutoResolveChk->isChecked() && smimeEnabled); } void GpgOLConfigPage::load() { QMap confValues; for (const auto &key: defaultMap.keys()) { confValues[key] = loadBool(key.toLocal8Bit().constData(), defaultMap[key]); } updateGUI(confValues); + + const std::string version = W32::readRegStr(nullptr, GPGOL_REG_PATH, "config-version"); + if (version != CONFIG_VERSION) { + qDebug() << "Config update. Cleaning old values"; + } +} + +void GpgOLConfigPage::defaults() +{ + updateGUI(defaultMap); +} + +static void saveBool(const char *name, bool value) +{ + const char *val = value ? "1" : "0"; + + if (!W32::writeRegStr(nullptr, GPGOL_REG_PATH, name, val)) { + qWarning() << "Failed to write registry value for" << name; + } } void GpgOLConfigPage::save() const { + saveBool("enableSmime", mSMIMEGrp->isChecked()); + saveBool("preferSmime", mPreferSMIMEChk->isChecked()); + + saveBool("encryptDefault", mAlwaysEncChk->isChecked()); + saveBool("signDefault", mAlwaysSigChk->isChecked()); + saveBool("inlinePGP", mInlinePGPChk->isChecked()); + saveBool("replyCrypt", mReplyCryptChk->isChecked()); + saveBool("automation", mAutomationGrp->isChecked()); + saveBool("autosecure", mAutoSecureChk->isChecked()); + saveBool("autotrust", mAutoTrustChk->isChecked()); + + W32::writeRegStr(nullptr, GPGOL_REG_PATH, "config-version", CONFIG_VERSION); } + +#include "gpgolconfigpage.moc" diff --git a/src/gpgolgui/gpgolconfigpage.h b/src/gpgolgui/gpgolconfigpage.h index 923642e..5209c78 100644 --- a/src/gpgolgui/gpgolconfigpage.h +++ b/src/gpgolgui/gpgolconfigpage.h @@ -1,45 +1,46 @@ #ifndef GPGOLCONFIGPAGE_H #define GPGOLCONFIGPAGE_H /* Copyright (C) 2018 by Intevation GmbH * * This file is Free Software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include #include #include class QGroupBox; class QCheckBox; class QLabel; +class ExplainingChkBox; class GpgOLConfigPage: public QWidget { Q_OBJECT public: explicit GpgOLConfigPage(QWidget *parent = nullptr); void save() const; void load(); void defaults(); - void setVersion(const QString &version); - protected: void setupGUI(); void updateGUI(const QMap &values); private: QGroupBox *mSMIMEGrp, *mAutomationGrp; QCheckBox *mPreferSMIMEChk, *mAutoSecureChk, - *mAutoTrustChk, *mAlwaysEncChk, - *mAlwaysSigChk; - QLabel *mVersionLabel; + *mAlwaysSigChk, + *mInlinePGPChk, + *mAutoTrustChk, + *mAutoResolveChk, + *mReplyCryptChk; }; #endif diff --git a/src/gpgolgui/gpgolgui-options.h b/src/gpgolgui/gpgolgui-options.h index 65c71a9..e2874a6 100644 --- a/src/gpgolgui/gpgolgui-options.h +++ b/src/gpgolgui/gpgolgui-options.h @@ -1,36 +1,39 @@ #ifndef GPGOLGUI_OPTIONS #define GPGOLGUI_OPTIONS /* Copyright (C) 2018 by Intevation GmbH * * This file is Free Software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include #include /** @file Commandline options*/ static void options(QCommandLineParser &parser) { QList options; options << QCommandLineOption(QStringList() << QStringLiteral("debug"), QStringLiteral("Print debug output.")) << QCommandLineOption(QStringLiteral("hwnd"), QStringLiteral("Parent Window"), QStringLiteral("windows window handle")) << QCommandLineOption(QStringLiteral("lang"), QStringLiteral("Language"), QStringLiteral("Language to be used e.g. de_DE")) + << QCommandLineOption(QStringLiteral("gpgol-version"), + QStringLiteral("Version string"), + QStringLiteral("GpgOL's Version")) << QCommandLineOption(QStringLiteral("alwaysShow"), QStringLiteral("Should always be shown")); for (const auto &opt: options) { parser.addOption(opt); } parser.addVersionOption(); parser.addHelpOption(); } #endif diff --git a/src/gpgolgui/gpgolgui.cpp b/src/gpgolgui/gpgolgui.cpp index bda92db..91c1049 100644 --- a/src/gpgolgui/gpgolgui.cpp +++ b/src/gpgolgui/gpgolgui.cpp @@ -1,90 +1,106 @@ /* Copyright (C) 2018 by Intevation GmbH * * This file is Free Software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include "gpgolgui.h" #include "w32-gettext.h" +#include "w32-util.h" #include "gpgolconfigpage.h" +#include "cryptoconfigpage.h" #include #include #include #include #include - -#include -#include +#include +#include #include #include #include -#include - -GpgOLGUI::GpgOLGUI(const QCommandLineParser &parser): KPageDialog(nullptr) +GpgOLGUI::GpgOLGUI(const QCommandLineParser &parser): + KPageDialog(nullptr) { + setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint)); + setWindowTitle(_("Configure GpgOL")); - setupGUI(); - setWindowIcon(QIcon(":/gpgolicon.svg")); + setWindowIcon(QIcon(":/gpgol-icon.svg")); + + const auto hwnd = parser.value(QStringLiteral("hwnd")); + if (!hwnd.isEmpty()) { + bool ok; + WId id = (WId) hwnd.toInt(&ok); + if (!ok) { + qDebug() << "invalid hwnd value"; + } else { + W32::setupForeignParent(id, this, true); + setModal(true); + } + } + + if (parser.isSet("gpgol-version")) { + mVersion = parser.value("gpgol-version"); + } else { + mVersion = QStringLiteral("unknown version"); + } + + setupGUI(); resize(800, 500); } void GpgOLGUI::setupGUI() { setFaceType(KPageDialog::List); QDialogButtonBox *buttonBox = new QDialogButtonBox(); buttonBox->setStandardButtons(QDialogButtonBox::RestoreDefaults | QDialogButtonBox::Cancel | QDialogButtonBox::Ok); KGuiItem::assign(buttonBox->button(QDialogButtonBox::Ok), KStandardGuiItem::ok()); KGuiItem::assign(buttonBox->button(QDialogButtonBox::Cancel), KStandardGuiItem::cancel()); KGuiItem::assign(buttonBox->button(QDialogButtonBox::RestoreDefaults), KStandardGuiItem::defaults()); setButtonBox(buttonBox); - QGpgME::CryptoConfig *const config = QGpgME::cryptoConfig(); - - auto cryptoConfWidget = new Kleo::CryptoConfigModule(config, - Kleo::CryptoConfigModule::TabbedLayout); - + auto cryptoConfWidget = new CryptoConfigPage; auto gpgolConfWidget = new GpgOLConfigPage; - connect(cryptoConfWidget, &Kleo::CryptoConfigModule::changed, - this, [this] () { - mCryptoConfigChanged = true; - }); - connect(buttonBox->button(QDialogButtonBox::Ok), &QAbstractButton::clicked, - this, [this, cryptoConfWidget] () { - if (mCryptoConfigChanged) { - cryptoConfWidget->save(); - } + this, [this, cryptoConfWidget, gpgolConfWidget] () { + cryptoConfWidget->save(); + gpgolConfWidget->save(); close(); }); connect(buttonBox->button(QDialogButtonBox::RestoreDefaults), &QAbstractButton::clicked, - this, [this, cryptoConfWidget] () { - cryptoConfWidget->defaults(); - mCryptoConfigChanged = true; + this, [this, cryptoConfWidget, gpgolConfWidget] () { + + if (currentPage()->widget() == cryptoConfWidget) { + cryptoConfWidget->defaults(); + } else { + gpgolConfWidget->defaults(); + } }); connect(buttonBox->button(QDialogButtonBox::Cancel), &QAbstractButton::clicked, this, [this] () { close(); }); KPageWidgetItem *page = new KPageWidgetItem(gpgolConfWidget, _("GpgOL")); - page->setHeader(_("Configure GpgOL")); - page->setIcon(QIcon(":/gpgolicon.svg")); + page->setHeader(QStringLiteral("%1 - %2%3").arg(_("Configure GpgOL")).arg( + _("Version ")).arg(mVersion)); + page->setIcon(QIcon(":/gpgol-icon.svg")); addPage(page); page = new KPageWidgetItem(cryptoConfWidget, QStringLiteral("%1\n%2").arg(_("GnuPG System")).arg(_("(Technical)"))); page->setHeader(_("Configuration of GnuPG System options")); page->setIcon(QIcon::fromTheme("document-encrypt")); addPage(page); } diff --git a/src/gpgolgui/gpgolgui.h b/src/gpgolgui/gpgolgui.h index d6781dd..439ac66 100644 --- a/src/gpgolgui/gpgolgui.h +++ b/src/gpgolgui/gpgolgui.h @@ -1,28 +1,30 @@ #ifndef GPGOLGUI_H #define GPGOLGUI_H /* Copyright (C) 2018 by Intevation GmbH * * This file is Free Software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include +#include class QCommandLineParser; class GpgOLGUI: public KPageDialog { Q_OBJECT public: GpgOLGUI(const QCommandLineParser &parser); protected: /** @brief UI setup */ void setupGUI(); private: bool mCryptoConfigChanged; + QString mVersion; }; #endif // GPGOLGUI_H diff --git a/src/gpgolgui/gpgolgui.qrc b/src/gpgolgui/gpgolgui.qrc index 4a15572..278d101 100644 --- a/src/gpgolgui/gpgolgui.qrc +++ b/src/gpgolgui/gpgolgui.qrc @@ -1,5 +1,6 @@ - ../img/lock.svg + ../img/lock.svg + ../img/gpgol-logo.png diff --git a/src/img/gpgol-logo.png b/src/img/gpgol-logo.png new file mode 100644 index 0000000..8f29f98 Binary files /dev/null and b/src/img/gpgol-logo.png differ diff --git a/src/img/gpgol-logo.svg b/src/img/gpgol-logo.svg new file mode 100644 index 0000000..2666e87 --- /dev/null +++ b/src/img/gpgol-logo.svg @@ -0,0 +1,174 @@ + + + + + + image/svg+xml + + GpgOL finnished Logo + + + + + + + + + + GpgOL finnished Logo + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/overlayer/CMakeLists.txt b/src/overlayer/CMakeLists.txt index 73928ca..fecb0a0 100644 --- a/src/overlayer/CMakeLists.txt +++ b/src/overlayer/CMakeLists.txt @@ -1,31 +1,32 @@ # Copyright (C) 2018 Intevation GmbH # # This file is Free Software under the GNU GPL (v>=2) # and comes with ABSOLUTELY NO WARRANTY! # See LICENSE.txt for details. set(EXECUTABLE_NAME "overlayer") set(EXECUTABLE_SRC main.cpp quitter.cpp ${CMAKE_SOURCE_DIR}/src/img/icon.rc + ${CMAKE_SOURCE_DIR}/src/util/w32-util.cpp ${CMAKE_SOURCE_DIR}/src/util/overlay.cpp ${CMAKE_SOURCE_DIR}/src/util/strhelp.c ) add_executable(${EXECUTABLE_NAME} ${_add_executable_params} ${EXECUTABLE_SRC} ) target_link_libraries(${EXECUTABLE_NAME} Qt5::Widgets ) if (WIN32) set_target_properties(${EXECUTABLE_NAME} PROPERTIES LINK_FLAGS "-municode") endif(WIN32) install(TARGETS ${EXECUTABLE_NAME} DESTINATION bin) diff --git a/src/resolver/CMakeLists.txt b/src/resolver/CMakeLists.txt index 6c0358a..86cb52c 100644 --- a/src/resolver/CMakeLists.txt +++ b/src/resolver/CMakeLists.txt @@ -1,33 +1,34 @@ # Copyright (C) 2018 Intevation GmbH # # This file is Free Software under the GNU GPL (v>=2) # and comes with ABSOLUTELY NO WARRANTY! # See LICENSE.txt for details. set(EXECUTABLE_NAME "resolver") set(EXECUTABLE_SRC main.cpp resolver.cpp ${CMAKE_SOURCE_DIR}/src/img/icon.rc ${CMAKE_SOURCE_DIR}/src/util/overlay.cpp + ${CMAKE_SOURCE_DIR}/src/util/w32-util.cpp ${CMAKE_SOURCE_DIR}/src/util/strhelp.c ) add_executable(${EXECUTABLE_NAME} ${_add_executable_params} ${EXECUTABLE_SRC} ) target_link_libraries(${EXECUTABLE_NAME} Qt5::Widgets KF5::Libkleo Gpgmepp QGpgme ) if (WIN32) set_target_properties(${EXECUTABLE_NAME} PROPERTIES LINK_FLAGS "-municode") endif(WIN32) install(TARGETS ${EXECUTABLE_NAME} DESTINATION bin) diff --git a/src/util/overlay.cpp b/src/util/overlay.cpp index 2ee0405..8858485 100644 --- a/src/util/overlay.cpp +++ b/src/util/overlay.cpp @@ -1,143 +1,138 @@ /* Copyright (C) 2018 by Intevation GmbH * * This file is Free Software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include "overlay.h" #include #include #include #include #include #include #include #include #include #include #include #include #include +#include "w32-util.h" + #include #ifdef Q_OS_WIN #include class Overlay::Private { public: Private(Overlay *qq, WId id, const QString &text): q(qq) { m_target = (HWND) id; q->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint); q->setAttribute(Qt::WA_TransparentForMouseEvents); q->setAttribute(Qt::WA_TranslucentBackground); - // This does not seem to make a difference so we still use the always - // on top hint. - auto foreignWindow = QWindow::fromWinId(id); - q->winId(); - auto parentHandle = q->windowHandle(); - if (parentHandle && foreignWindow) { - parentHandle->setTransientParent(foreignWindow); - q->setWindowModality(Qt::WindowModal); - } + W32::setupForeignParent(id, q, true); + auto vLay = new QVBoxLayout(q); auto bar = new QProgressBar; auto label = new QLabel; label->setText(QStringLiteral("

%1

").arg(text)); bar->setRange(0, 0); vLay->addStretch(1); auto cancelBtn = new QPushButton; cancelBtn->setIcon(q->style()->standardPixmap(QStyle::SP_TitleBarCloseButton)); cancelBtn->setFlat(true); auto subLay1 = new QVBoxLayout; auto subLay3 = new QHBoxLayout; subLay3->addStretch(0.5); subLay3->addWidget(label); subLay3->addStretch(1); subLay3->addWidget(cancelBtn); subLay1->addLayout(subLay3); subLay1->addWidget(bar); auto subLay2 = new QHBoxLayout; subLay2->addStretch(0.1); subLay2->addLayout(subLay1); subLay2->addStretch(0.1); vLay->addLayout(subLay2); vLay->addStretch(1); connect(cancelBtn, &QPushButton::clicked, q, [this] () { std::cout << "cancel" << std::endl; qApp->quit(); }); auto refreshTimer = new QTimer(q); connect(refreshTimer, &QTimer::timeout, q, [this] () { RECT rect; if (GetWindowRect(m_target, &rect)) { #if 0 HWND myself = (HWND) q->winId(); if (!SetWindowPos(myself, HWND_NOTOPMOST, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_SHOWWINDOW)) { qDebug() << "Set Window pos failed."; UpdateWindow(m_target); } #endif q->setGeometry(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); } else { //maybe window was closed OutputDebugStringA ("Overlay GetWindowRect failed."); std::cout << "cancel" << std::endl; qApp->quit(); } }); refreshTimer->start(50); // update interval in milliseconds q->show(); } HWND m_target; Overlay *q; }; Overlay::Overlay (WId id, const QString &text): d(new Private(this, id, text)) { } #else Overlay::Overlay (WId id, const QString &text) { } #endif void Overlay::paintEvent(QPaintEvent *e) { QPainter painter(this); int width = size().width(); int height = size().height(); QLinearGradient gradient(0, 0, 0, height); gradient.setColorAt(0, Qt::transparent); gradient.setColorAt(0.5, Qt::white); gradient.setColorAt(1, Qt::transparent); QBrush brush(gradient); painter.fillRect(0, 0, width, height, gradient); QWidget::paintEvent(e); } diff --git a/src/util/w32-util.cpp b/src/util/w32-util.cpp index c080c59..a0814a3 100644 --- a/src/util/w32-util.cpp +++ b/src/util/w32-util.cpp @@ -1,185 +1,204 @@ /* Copyright (C) 2018 by Intevation GmbH * * This file is Free Software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include #include "w32-util.h" #include #ifdef _WIN32 # include #endif +#include + #define SLDIR "\\share\\locale" namespace W32 { std::string getGpg4winLocaleDir() { const auto instdir = getGpg4winDir(); if (instdir.empty()) { return std::string(); } return instdir + SLDIR; } std::string getGpg4winDir() { const auto tmp = readRegStr(nullptr, GPG4WIN_REGKEY_3, "Install Directory"); if (tmp.empty()) { return std::string(); } if (!access(tmp.c_str(), R_OK)) { return tmp; } else { fprintf (stderr, "Failed to access: %s\n", tmp.c_str()); } return std::string(); } /* Helper for read_w32_registry_string(). */ #ifdef _WIN32 static HKEY get_root_key(const char *root) { HKEY root_key; if( !root ) root_key = HKEY_CURRENT_USER; else if( !strcmp( root, "HKEY_CLASSES_ROOT" ) ) root_key = HKEY_CLASSES_ROOT; else if( !strcmp( root, "HKEY_CURRENT_USER" ) ) root_key = HKEY_CURRENT_USER; else if( !strcmp( root, "HKEY_LOCAL_MACHINE" ) ) root_key = HKEY_LOCAL_MACHINE; else if( !strcmp( root, "HKEY_USERS" ) ) root_key = HKEY_USERS; else if( !strcmp( root, "HKEY_PERFORMANCE_DATA" ) ) root_key = HKEY_PERFORMANCE_DATA; else if( !strcmp( root, "HKEY_CURRENT_CONFIG" ) ) root_key = HKEY_CURRENT_CONFIG; else return nullptr; return root_key; } #endif std::string readRegStr (const char *root, const char *dir, const char *name) { #ifndef _WIN32 (void)root; (void)dir; (void)name; return std::string(); #else HKEY root_key, key_handle; DWORD n1, nbytes, type; std::string ret; if (!(root_key = get_root_key(root))) { return ret; } if (RegOpenKeyExA(root_key, dir, 0, KEY_READ, &key_handle)) { if (root) { /* no need for a RegClose, so return direct */ return ret; } /* Fallback to HKLM */ if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle)) { return ret; } } nbytes = 1; if (RegQueryValueExA(key_handle, name, 0, nullptr, nullptr, &nbytes)) { if (root) { RegCloseKey (key_handle); return ret; } /* Try to fallback to HKLM also vor a missing value. */ RegCloseKey (key_handle); if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle)) { return ret; } if (RegQueryValueExA(key_handle, name, 0, nullptr, nullptr, &nbytes)) { RegCloseKey(key_handle); return ret; } } n1 = nbytes+1; char result[n1]; if (RegQueryValueExA(key_handle, name, 0, &type, (LPBYTE)result, &n1)) { RegCloseKey(key_handle); return ret; } RegCloseKey(key_handle); result[nbytes] = 0; /* make sure it is really a string */ ret = result; if (type == REG_EXPAND_SZ && strchr (result, '%')) { n1 += 1000; char tmp[n1 +1]; nbytes = ExpandEnvironmentStringsA(ret.c_str(), tmp, n1); if (nbytes && nbytes > n1) { n1 = nbytes; char tmp2[n1 +1]; nbytes = ExpandEnvironmentStringsA(result, tmp2, n1); if (nbytes && nbytes > n1) { /* oops - truncated, better don't expand at all */ return ret; } tmp2[nbytes] = 0; ret = tmp2; } else if (nbytes) { /* okay, reduce the length */ tmp[nbytes] = 0; ret = tmp; } } return ret; #endif } bool writeRegStr(const char *root, const char *path, const char *key, const char *val) { #ifndef _WIN32 (void) root; (void) path; (void) key; (void) val; return false; #else HKEY h, hk; int type; int ec; hk = get_root_key (root); if (!hk) { fprintf(stderr, "Failed to find root key.\n"); } ec = RegCreateKeyExA(hk, path, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &h, NULL); if (ec != ERROR_SUCCESS) { fprintf (stderr, "creating/opening registry key `%s' failed\n", path); return false; } type = strchr (val, '%')? REG_EXPAND_SZ : REG_SZ; ec = RegSetValueExA(h, key, 0, type, (const BYTE*)val, strlen (val)); if (ec != ERROR_SUCCESS) { fprintf (stderr, "saving registry key `%s'->`%s' failed\n", path, key); RegCloseKey(h); return false; } RegCloseKey(h); return true; #endif } + +void setupForeignParent(WId id, QWidget *widget, bool modal) +{ + if (!widget || !id) { + return; + } + + auto foreignWindow = QWindow::fromWinId(id); + widget->winId(); + auto parentHandle = widget->windowHandle(); + if (parentHandle && foreignWindow) { + parentHandle->setTransientParent(foreignWindow); + if (modal) { + widget->setWindowModality(Qt::WindowModal); + } + } +} }// namespace diff --git a/src/util/w32-util.h b/src/util/w32-util.h index ff5dacb..3dd2eed 100644 --- a/src/util/w32-util.h +++ b/src/util/w32-util.h @@ -1,52 +1,56 @@ /* Copyright (C) 2018 by Intevation GmbH * * This file is Free Software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include +#include + /* The Registry key used by Gpg4win. */ #ifdef _WIN64 # define GPG4WIN_REGKEY_2 "Software\\Wow6432Node\\GNU\\GnuPG" #else # define GPG4WIN_REGKEY_2 "Software\\GNU\\GnuPG" #endif #ifdef _WIN64 # define GPG4WIN_REGKEY_3 "Software\\Wow6432Node\\Gpg4win" #else # define GPG4WIN_REGKEY_3 "Software\\Gpg4win" #endif #define GPGOL_REG_PATH "Software\\GNU\\GpgOL" namespace W32 { /* Get the locale dir of Gpg4win. */ std::string getGpg4winLocaleDir(); /** Get the Gpg4win Install directory. * * Looks for the Gpg4win 3.x registry key. * And checks that the directory can be read. * * @returns an empty string if no dir could be found. * **/ std::string getGpg4winDir(); /** Read a registry string value. If root is null first * HKEY_CURRENT_USER is searched and then it falls back * to HKEY_LOCAL_MACHINE . */ std::string readRegStr(const char *root, const char *path, const char *key); bool writeRegStr(const char *root, const char *path, const char *key, const char *val); +void setupForeignParent(WId id, QWidget *widget, bool modal); + } // namespace W32