diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b6108f5d1..458ea62fd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -186,9 +186,9 @@ jobs: - name: Build run: | md build/client - copy ${{ env.VCPKG_ROOT }}\installed\x64-windows\bin\*.dll build\client\ + copy ${{ env.RUNVCPKG_VCPKG_ROOT }}\installed\x64-windows\bin\*.dll build\client\ cmake "-GNinja" -DCMAKE_BUILD_TYPE=RelWithDebInfo ` - -DCMAKE_TOOLCHAIN_FILE=${{ env.VCPKG_ROOT }}/scripts/buildsystems/vcpkg.cmake ` + -DCMAKE_TOOLCHAIN_FILE=${{ env.RUNVCPKG_VCPKG_ROOT }}/scripts/buildsystems/vcpkg.cmake ` "-DLIBDIGIDOCPP_LIBRARY=libs/libdigidocpp/x64/digidocpp.lib" ` "-DLIBDIGIDOCPP_INCLUDE_DIR=libs/libdigidocpp/include" -B build -S . cmake --build build --target msi diff --git a/client/Application.cpp b/client/Application.cpp index e0f27006b..307dd7cf3 100644 --- a/client/Application.cpp +++ b/client/Application.cpp @@ -162,6 +162,7 @@ class DigidocConf final: public digidoc::XmlConfCurrent std::vector list = toCerts(QLatin1String("CERT-BUNDLE")); if(digidoc::X509Cert cert = toCert(fromBase64(QVariant(Settings::TSA_CERT)))) list.push_back(cert); + list.emplace_back(); // Make sure that TSA cert pinning is enabled return list; } @@ -192,6 +193,7 @@ class DigidocConf final: public digidoc::XmlConfCurrent std::vector list = toCerts(QLatin1String("CERT-BUNDLE")); if(digidoc::X509Cert cert = verifyServiceCert()) list.push_back(cert); + list.emplace_back(); // Make sure that TSA cert pinning is enabled return list; } std::string verifyServiceUri() const final @@ -279,8 +281,8 @@ class DigidocConf final: public digidoc::XmlConfCurrent std::vector certs; for(const auto &cert: Application::confValue(key).toArray()) { - QByteArray der = fromBase64(cert); - certs.emplace_back((const unsigned char*)der.constData(), size_t(der.size())); + if(QByteArray der = fromBase64(cert); !der.isEmpty()) + certs.emplace_back((const unsigned char*)der.constData(), size_t(der.size())); } return certs; } @@ -321,7 +323,7 @@ Application::Application( int &argc, char **argv ) sendMessage(args.join(QStringLiteral("\", \""))); return; } - connect( this, SIGNAL(messageReceived(QString)), SLOT(parseArgs(QString)) ); + connect(this, &Application::messageReceived, this, qOverload(&Application::parseArgs)); #endif #ifdef CONFIG_URL @@ -390,7 +392,7 @@ Application::Application( int &argc, char **argv ) connect(d->closeAction, &QAction::triggered, this, &Application::closeWindow); d->newClientAction = new QAction( tr("New Window"), this ); d->newClientAction->setShortcut( Qt::CTRL + Qt::Key_N ); - connect(d->newClientAction, &QAction::triggered, this, [&]{ showClient({}, false, false, true); }); + connect(d->newClientAction, &QAction::triggered, this, []{ showClient({}, false, false, true); }); // This is needed to release application from memory (Windows) setQuitOnLastWindowClosed( true ); @@ -400,14 +402,6 @@ Application::Application( int &argc, char **argv ) #ifdef Q_OS_MAC d->bar = std::make_unique(); - connect(d->bar->addAction(MacMenuBar::AboutAction), &QAction::triggered, this, [] { - if(auto *w = qobject_cast(mainWindow())) - w->showSettings(SettingsDialog::LicenseSettings); - }); - connect(d->bar->addAction(MacMenuBar::PreferencesAction), &QAction::triggered, this, [] { - if(auto *w = qobject_cast(mainWindow())) - w->showSettings(SettingsDialog::GeneralSettings); - }); d->bar->fileMenu()->addAction( d->newClientAction ); d->bar->fileMenu()->addAction( d->closeAction ); d->bar->dockMenu()->addAction( d->newClientAction ); @@ -458,13 +452,11 @@ Application::Application( int &argc, char **argv ) } QTimer::singleShot(0, this, [this] { - QWidget *parent = mainWindow(); #ifdef Q_OS_MAC if(!Settings::PLUGINS.isSet()) { - auto *dlg = new WarningDialog(tr( - "In order to authenticate and sign in e-services with an ID-card you need to install the web browser components."), parent); - dlg->setAttribute(Qt::WA_DeleteOnClose); + auto *dlg = WarningDialog::show(tr( + "In order to authenticate and sign in e-services with an ID-card you need to install the web browser components.")); dlg->setCancelText(tr("Ignore forever").toUpper()); dlg->addButton(tr("Remind later").toUpper(), QMessageBox::Ignore); dlg->addButton(tr("Install").toUpper(), QMessageBox::Open); @@ -476,13 +468,12 @@ Application::Application( int &argc, char **argv ) default: Settings::PLUGINS = QStringLiteral("ignore"); } }); - dlg->open(); } #endif if(Settings::SHOW_INTRO) { Settings::SHOW_INTRO = false; - auto *dlg = new FirstRun(parent); + auto *dlg = new FirstRun(mainWindow()); connect(dlg, &FirstRun::langChanged, this, [this](const QString& lang) { loadTranslation( lang ); }); dlg->open(); } @@ -629,7 +620,7 @@ bool Application::event(QEvent *event) case QEvent::FileOpen: { QString fileName = static_cast(event)->file().normalized(QString::NormalizationForm_C); - QTimer::singleShot(0, this, [this, fileName] { + QTimer::singleShot(0, this, [fileName] { parseArgs({ fileName }); }); return true; @@ -672,10 +663,9 @@ void Application::mailTo( const QUrl &url ) { QUrlQuery q(url); #if defined(Q_OS_WIN) - QString file = q.queryItemValue( "attachment", QUrl::FullyDecoded ); - QLibrary lib("mapi32"); - if( LPMAPISENDMAILW mapi = LPMAPISENDMAILW(lib.resolve("MAPISendMailW")) ) + if(QLibrary lib("mapi32"); LPMAPISENDMAILW mapi = LPMAPISENDMAILW(lib.resolve("MAPISendMailW"))) { + QString file = q.queryItemValue( "attachment", QUrl::FullyDecoded ); QString filePath = QDir::toNativeSeparators( file ); QString fileName = QFileInfo( file ).fileName(); QString subject = q.queryItemValue( "subject", QUrl::FullyDecoded ); @@ -754,39 +744,15 @@ void Application::mailTo( const QUrl &url ) QWidget* Application::mainWindow() { - QWidget* win = activeWindow(); - QWidget* first = nullptr; - QWidget* root = nullptr; - - if (!win) - { - // Prefer main window; on Mac also the menu is top level window - for (QWidget *widget: topLevelWidgets()) - { - if (widget->isWindow()) - { - if (!first) - first = widget; - - if(qobject_cast(widget)) - { - win = widget; - break; - } - } - } - } - - if(!win) - win = first; - - while(win) - { - root = win; - win = win->parentWidget(); - } - - return root; + if(QWidget *win = qobject_cast(activeWindow())) + return win; + auto list = topLevelWidgets(); + // Prefer main window; on Mac also the menu is top level window + if(auto i = std::find_if(list.cbegin(), list.cend(), + [](QWidget *widget) { return qobject_cast(widget); }); + i != list.cend()) + return *i; + return list.value(0); } bool Application::notify(QObject *object, QEvent *event) @@ -932,7 +898,7 @@ void Application::showClient(const QStringList ¶ms, bool crypto, bool sign, #ifdef Q_OS_LINUX else { - if(QScreen *screen = QGuiApplication::screenAt(w->pos())) + if(QScreen *screen = screenAt(w->pos())) w->move(screen->availableGeometry().center() - w->frameGeometry().adjusted(0, 0, 10, 40).center()); } #endif @@ -941,7 +907,6 @@ void Application::showClient(const QStringList ¶ms, bool crypto, bool sign, // Required for restoring minimized window on macOS w->setWindowState(Qt::WindowActive); #endif - w->addAction(d->closeAction); w->activateWindow(); w->show(); w->raise(); @@ -951,7 +916,7 @@ void Application::showClient(const QStringList ¶ms, bool crypto, bool sign, void Application::showTSLWarning(QEventLoop *e) { - auto *dlg = WarningDialog::show(mainWindow(), tr( + auto *dlg = WarningDialog::show(tr( "The renewal of Trust Service status List, used for digital signature validation, has failed. " "Please check your internet connection and make sure you have the latest ID-software version " "installed. An expired Trust Service List (TSL) will be used for signature validation. " diff --git a/client/Application.h b/client/Application.h index 4d918d155..1dc02e485 100644 --- a/client/Application.h +++ b/client/Application.h @@ -74,13 +74,9 @@ class Application final: public Common static void openHelp(); static uint readTSLVersion(const QString &path); static void setConfValue( ConfParameter parameter, const QVariant &value ); - -public Q_SLOTS: - void showClient(const QStringList ¶ms = {}, bool crypto = false, bool sign = false, bool newWindow = false); + static void showClient(const QStringList ¶ms = {}, bool crypto = false, bool sign = false, bool newWindow = false); private Q_SLOTS: - void parseArgs(const QString &msg = {}); - void parseArgs(QStringList args); static void browse(const QUrl &url); static void mailTo(const QUrl &url); static void showTSLWarning( QEventLoop *e ); @@ -91,6 +87,8 @@ private Q_SLOTS: private: bool event(QEvent *event) final; static void closeWindow(); + static void parseArgs(const QString &msg = {}); + static void parseArgs(QStringList args); static void showWarning(const QString &msg, const digidoc::Exception &e); static QWidget* uniqueRoot(); #if defined(Q_OS_MAC) diff --git a/client/Application_mac.mm b/client/Application_mac.mm index f5f075156..b9c151d8a 100644 --- a/client/Application_mac.mm +++ b/client/Application_mac.mm @@ -41,7 +41,7 @@ - (void)openClient:(NSPasteboard *)pboard userData:(NSString *)data error:(NSStr QStringList result; for( NSString *filename in [pboard propertyListForType:NSFilenamesPboardType] ) result.append(QString::fromNSString(filename).normalized(QString::NormalizationForm_C)); - QMetaObject::invokeMethod( qApp, "showClient", Q_ARG(QStringList,result) ); + Application::showClient(result); } - (void)signClient:(NSPasteboard *)pboard userData:(NSString *)data error:(NSString **)error @@ -51,7 +51,7 @@ - (void)signClient:(NSPasteboard *)pboard userData:(NSString *)data error:(NSStr QStringList result; for(NSString *filename in [pboard propertyListForType:NSFilenamesPboardType]) result.append(QString::fromNSString(filename).normalized(QString::NormalizationForm_C)); - QMetaObject::invokeMethod(qApp, "showClient", Q_ARG(QStringList,result), Q_ARG(bool,false), Q_ARG(bool,true)); + Application::showClient(result, false, true); } - (void)openCrypto:(NSPasteboard *)pboard userData:(NSString *)data error:(NSString **)error @@ -61,7 +61,7 @@ - (void)openCrypto:(NSPasteboard *)pboard userData:(NSString *)data error:(NSStr QStringList result; for( NSString *filename in [pboard propertyListForType:NSFilenamesPboardType] ) result.append(QString::fromNSString(filename).normalized(QString::NormalizationForm_C)); - QMetaObject::invokeMethod( qApp, "showClient", Q_ARG(QStringList,result), Q_ARG(bool,true) ); + Application::showClient(result, true); } @end diff --git a/client/MacMenuBar.cpp b/client/MacMenuBar.cpp index 8aa6323e4..9e8662d29 100644 --- a/client/MacMenuBar.cpp +++ b/client/MacMenuBar.cpp @@ -19,63 +19,39 @@ #include "MacMenuBar.h" +#include "Application.h" +#include "MainWindow.h" +#include "dialogs/SettingsDialog.h" + #include -#include MacMenuBar::MacMenuBar() : file(addMenu(tr("&File"))) , help(addMenu(tr("&Help"))) + , dock(new QMenu(this)) { qApp->installEventFilter(this); dock->setAsDockMenu(); + file->addAction(QString(), [] { + if(auto *w = qobject_cast(Application::mainWindow())) + w->showSettings(SettingsDialog::LicenseSettings); + })->setMenuRole(QAction::AboutRole); + file->addAction(QString(), [] { + if(auto *w = qobject_cast(Application::mainWindow())) + w->showSettings(SettingsDialog::GeneralSettings); + })->setMenuRole(QAction::PreferencesRole); } -MacMenuBar::~MacMenuBar() -{ - //delete dock; -} - -QAction* MacMenuBar::addAction(ActionType type) -{ - QAction *a = file->addAction(typeName(type)); - switch(type) - { - case AboutAction: a->setMenuRole(QAction::AboutRole); break; - case CloseAction: a->setShortcut(Qt::CTRL + Qt::Key_W); break; - case PreferencesAction: a->setMenuRole(QAction::PreferencesRole); break; - default: break; - } - actions[type] = a; - return a; -} - +QMenu* MacMenuBar::fileMenu() const { return file; } +QMenu* MacMenuBar::helpMenu() const { return help; } QMenu* MacMenuBar::dockMenu() const { return dock; } bool MacMenuBar::eventFilter(QObject *o, QEvent *e) { - switch(e->type()) + if(e->type() == QEvent::LanguageChange) { - case QEvent::LanguageChange: file->setTitle(tr("&File")); help->setTitle(tr("&Help")); - for(auto i = actions.constBegin(); i != actions.constEnd(); ++i) - i.value()->setText(typeName(i.key())); - break; - default: break; } return QMenuBar::eventFilter(o, e); } - -QMenu* MacMenuBar::fileMenu() const { return file; } -QMenu* MacMenuBar::helpMenu() const { return help; } - -QString MacMenuBar::typeName(ActionType type) -{ - switch(type) - { - case AboutAction: return tr("Info"); - case CloseAction: return tr("Close"); - case PreferencesAction: return tr("Settings"); - default: return {}; - } -} diff --git a/client/MacMenuBar.h b/client/MacMenuBar.h index 56244d09c..f031ade95 100644 --- a/client/MacMenuBar.h +++ b/client/MacMenuBar.h @@ -25,28 +25,16 @@ class MacMenuBar final: public QMenuBar { Q_OBJECT public: - enum ActionType - { - AboutAction, - CloseAction, - PreferencesAction, - HelpAction - }; - explicit MacMenuBar(); - ~MacMenuBar(); - QAction* addAction(ActionType type); QMenu* fileMenu() const; QMenu* helpMenu() const; QMenu* dockMenu() const; private: bool eventFilter(QObject *o, QEvent *e) final; - static QString typeName(ActionType type); - QMenu *file = nullptr; - QMenu *help = nullptr; - QHash actions; - QMenu *dock = new QMenu; + QMenu *file {}; + QMenu *help {}; + QMenu *dock {}; }; diff --git a/client/translations/en.ts b/client/translations/en.ts index 19caaea0e..69f62ed02 100644 --- a/client/translations/en.ts +++ b/client/translations/en.ts @@ -1366,18 +1366,6 @@ LDAP server is unavailable. &File &File - - Info - About - - - Close - Close - - - Settings - Settings - &Help &Help diff --git a/client/translations/et.ts b/client/translations/et.ts index 859e7025f..357bdbf30 100644 --- a/client/translations/et.ts +++ b/client/translations/et.ts @@ -1366,18 +1366,6 @@ LDAP serveriga ei saa ühendust. &File &Fail - - Info - Info - - - Close - Sulge - - - Settings - Seaded - &Help &Abi diff --git a/client/translations/ru.ts b/client/translations/ru.ts index 2afd33b69..50c197eca 100644 --- a/client/translations/ru.ts +++ b/client/translations/ru.ts @@ -1366,18 +1366,6 @@ LDAP сервер недоступен. &File &Файл - - Info - Информация - - - Close - Закрыть - - - Settings - Настройки - &Help &Помощь