diff --git a/CMakeLists.txt b/CMakeLists.txt index c7af07003..9a3d87ae7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,209 +1,209 @@ # SPDX-FileCopyrightText: none # SPDX-License-Identifier: BSD-3-Clause cmake_minimum_required(VERSION 3.16 FATAL_ERROR) set(RELEASE_SERVICE_VERSION_MAJOR "22") set(RELEASE_SERVICE_VERSION_MINOR "03") set(RELEASE_SERVICE_VERSION_MICRO "70") # The RELEASE_SERVICE_VERSION is used by Gpg4win to add the Gpg4win version if (NOT RELEASE_SERVICE_VERSION) set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}") endif() if(RELEASE_SERVICE_VERSION_MICRO LESS 10) set(KDE_APPLICATIONS_COMPACT_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}${RELEASE_SERVICE_VERSION_MINOR}0${RELEASE_SERVICE_VERSION_MICRO}") else() set(KDE_APPLICATIONS_COMPACT_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}${RELEASE_SERVICE_VERSION_MINOR}${RELEASE_SERVICE_VERSION_MICRO}") endif() set(KLEOPATRA_VERSION_MAJOR "3") set(KLEOPATRA_VERSION_MINOR "1") set(KLEOPATRA_VERSION_MICRO "20") set(kleopatra_version "${KLEOPATRA_VERSION_MAJOR}.${KLEOPATRA_VERSION_MINOR}.${KLEOPATRA_VERSION_MICRO}.${KDE_APPLICATIONS_COMPACT_VERSION}") # The following is for Windows set(kleopatra_version_win "${KLEOPATRA_VERSION_MAJOR}.${KLEOPATRA_VERSION_MINOR}.${KLEOPATRA_VERSION_MICRO}") set(kleopatra_fileversion_win "${KLEOPATRA_VERSION_MAJOR},${KLEOPATRA_VERSION_MINOR},${KLEOPATRA_VERSION_MICRO},0") project(kleopatra VERSION ${kleopatra_version}) option(DISABLE_KWATCHGNUPG "Don't build the kwatchgnupg tool [default=OFF]" OFF) # Standalone build. Find / include everything necessary. set(KF5_MIN_VERSION "5.89.0") set(KMIME_VERSION "5.19.40") -set(LIBKLEO_VERSION "5.19.46") +set(LIBKLEO_VERSION "5.19.47") set(QT_REQUIRED_VERSION "5.15.2") set(GPGME_REQUIRED_VERSION "1.15.0") set(BOOST_REQUIRED_VERSION "1.58") if (WIN32) set(KF5_WANT_VERSION "5.70.0") set(KMIME_WANT_VERSION "5.12.0") else () set(KF5_WANT_VERSION ${KF5_MIN_VERSION}) set(KMIME_WANT_VERSION ${KMIME_VERSION}) endif () find_package(ECM ${KF5_WANT_VERSION} CONFIG REQUIRED) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules ${CMAKE_MODULE_PATH}) include(ECMInstallIcons) include(ECMSetupVersion) include(ECMAddTests) include(GenerateExportHeader) include(ECMGenerateHeaders) include(FeatureSummary) include(CheckFunctionExists) include(KDEInstallDirs) include(KDECMakeSettings) include(KDECompilerSettings NO_POLICY_SCOPE) include(ECMAddAppIcon) include(ECMQtDeclareLoggingCategory) # Find KF5 packages find_package(KF5WidgetsAddons ${KF5_WANT_VERSION} CONFIG REQUIRED) find_package(KF5ConfigWidgets ${KF5_WANT_VERSION} CONFIG REQUIRED) find_package(KF5CoreAddons ${KF5_WANT_VERSION} CONFIG REQUIRED) find_package(KF5Codecs ${KF5_WANT_VERSION} CONFIG REQUIRED) find_package(KF5Config ${KF5_WANT_VERSION} CONFIG REQUIRED) find_package(KF5I18n ${KF5_WANT_VERSION} CONFIG REQUIRED) find_package(KF5IconThemes ${KF5_WANT_VERSION} CONFIG REQUIRED) find_package(KF5ItemModels ${KF5_WANT_VERSION} CONFIG REQUIRED) find_package(KF5XmlGui ${KF5_WANT_VERSION} CONFIG REQUIRED) find_package(KF5WindowSystem ${KF5_WANT_VERSION} CONFIG REQUIRED) find_package(KF5DocTools ${KF5_WANT_VERSION} CONFIG) find_package(KF5Crash ${KF5_WANT_VERSION} REQUIRED) set_package_properties(KF5DocTools PROPERTIES DESCRIPTION "Documentation tools" PURPOSE "Required to generate Kleopatra documentation." TYPE OPTIONAL) # Optional packages if (WIN32) # Only a replacement available for Windows so this # is required on other platforms. find_package(KF5DBusAddons ${KF5_WANT_VERSION} CONFIG) set_package_properties(KF5DBusAddons PROPERTIES DESCRIPTION "Support library to work with DBus" PURPOSE "DBus session integration" URL "https://inqlude.org/libraries/kdbusaddons.html" TYPE OPTIONAL) else() find_package(KF5DBusAddons ${KF5_WANT_VERSION} CONFIG REQUIRED) set(_kleopatra_dbusaddons_libs KF5::DBusAddons) endif() set(HAVE_QDBUS ${Qt5DBus_FOUND}) find_package(Gpgmepp ${GPGME_REQUIRED_VERSION} CONFIG REQUIRED) if (Gpgmepp_VERSION VERSION_GREATER_EQUAL "1.16.0") set(GPGMEPP_SUPPORTS_TRUST_SIGNATURES 1) endif() find_package(QGpgme ${GPGME_REQUIRED_VERSION} CONFIG REQUIRED) if (QGpgme_VERSION VERSION_GREATER_EQUAL "1.16.0") set(QGPGME_SUPPORTS_TRUST_SIGNATURES 1) set(QGPGME_SUPPORTS_SIGNATURE_EXPIRATION 1) endif() if (QGpgme_VERSION VERSION_GREATER_EQUAL "1.16.1") set(QGPGME_SUPPORTS_CHANGING_EXPIRATION_OF_COMPLETE_KEY 1) set(QGPGME_CRYPTOCONFIGENTRY_HAS_DEFAULT_VALUE 1) set(QGPGME_SUPPORTS_WKDLOOKUP 1) set(QGPGME_SUPPORTS_IMPORT_WITH_FILTER 1) set(QGPGME_SUPPORTS_IMPORT_WITH_KEY_ORIGIN 1) endif() # Kdepimlibs packages find_package(KF5Libkleo ${LIBKLEO_VERSION} CONFIG REQUIRED) find_package(KF5Mime ${KMIME_WANT_VERSION} CONFIG REQUIRED) find_package(Qt5 ${QT_REQUIRED_VERSION} CONFIG REQUIRED Widgets Test Network PrintSupport) find_package(Assuan2 REQUIRED) find_package(Boost ${BOOST_REQUIRED_VERSION} MODULE REQUIRED) find_path(Boost_TOPOLOGICAL_SORT_DIR NAMES boost/graph/topological_sort.hpp PATHS ${Boost_INCLUDE_DIRS}) if(NOT Boost_TOPOLOGICAL_SORT_DIR) message(FATAL_ERROR "The Boost Topological_sort header was NOT found. Should be part of Boost graph module.") endif() set(kleopatra_release FALSE) if(NOT kleopatra_release) find_package(Git) if(GIT_FOUND) execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} RESULT_VARIABLE rc ERROR_QUIET) if(rc EQUAL 0) execute_process(COMMAND ${GIT_EXECUTABLE} log -1 --oneline --format=%h ${CMAKE_CURRENT_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} OUTPUT_VARIABLE Kleopatra_WC_REVISION) string(REGEX REPLACE "\n" "" Kleopatra_WC_REVISION "${Kleopatra_WC_REVISION}") execute_process(COMMAND ${GIT_EXECUTABLE} log -1 --oneline --format=%cI ${CMAKE_CURRENT_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} OUTPUT_VARIABLE Kleopatra_WC_LAST_CHANGED_DATE) string(REGEX REPLACE "^([0-9]+)-([0-9]+)-([0-9]+)T([0-9]+):([0-9]+):([0-9]+).*$" "\\1\\2\\3T\\4\\5\\6" Kleopatra_WC_LAST_CHANGED_DATE "${Kleopatra_WC_LAST_CHANGED_DATE}") set(kleopatra_version "${kleopatra_version}+git${Kleopatra_WC_LAST_CHANGED_DATE}~${Kleopatra_WC_REVISION}") endif() endif() endif() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version-kleopatra.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/version-kleopatra.h) include (ConfigureChecks.cmake) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config-kleopatra.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kleopatra.h) include_directories( ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${Boost_INCLUDE_DIRS} ${ASSUAN2_INCLUDES} ) add_definitions(-D_ASSUAN_ONLY_GPG_ERRORS) add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050e00) add_definitions(-DKF_DISABLE_DEPRECATED_BEFORE_AND_AT=0x055A00) if(CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-missing-braces -Wno-parentheses -Wno-ignored-qualifiers") endif() add_definitions(-DQT_NO_EMIT) remove_definitions(-DQT_NO_FOREACH) kde_enable_exceptions() option(USE_UNITY_CMAKE_SUPPORT "Use UNITY cmake support (speedup compile time)" OFF) set(COMPILE_WITH_UNITY_CMAKE_SUPPORT OFF) if (USE_UNITY_CMAKE_SUPPORT) set(COMPILE_WITH_UNITY_CMAKE_SUPPORT ON) endif() add_subdirectory(pics) add_subdirectory(src) if(BUILD_TESTING) add_subdirectory(tests) add_subdirectory(autotests) endif() ecm_qt_install_logging_categories( EXPORT KLEOPATRA FILE kleopatra.categories DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR} ) ki18n_install(po) if(KF5DocTools_FOUND) kdoctools_install(po) add_subdirectory(doc) endif() feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/src/kleopatra.rc b/src/kleopatra.rc index 13281f5de..8c11edd00 100644 --- a/src/kleopatra.rc +++ b/src/kleopatra.rc @@ -1,133 +1,136 @@ &File &View &Certificates &Tools &Settings &Window &Help - + + + + Main Toolbar &Certificates diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index b4dcfe141..707667eb6 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1,690 +1,702 @@ /* -*- mode: c++; c-basic-offset:4 -*- mainwindow.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "mainwindow.h" #include "aboutdata.h" #include "settings.h" #include "view/padwidget.h" #include "view/searchbar.h" #include "view/tabwidget.h" #include "view/keylistcontroller.h" #include "view/keycacheoverlay.h" #include "view/smartcardwidget.h" #include "view/welcomewidget.h" #include "commands/selftestcommand.h" #include "commands/importcrlcommand.h" #include "commands/importcertificatefromfilecommand.h" #include "commands/decryptverifyfilescommand.h" #include "commands/signencryptfilescommand.h" #include "commands/listreaderscommand.h" #include "conf/groupsconfigdialog.h" #include "utils/detail_p.h" #include #include "utils/action_data.h" #include "utils/filedialog.h" #include "utils/clipboardmenu.h" #include "dialogs/updatenotification.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kleopatra_debug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include using namespace std::chrono_literals; using namespace Kleo; using namespace Kleo::Commands; using namespace GpgME; static KGuiItem KStandardGuiItem_quit() { static const QString app = KAboutData::applicationData().componentName(); KGuiItem item = KStandardGuiItem::quit(); item.setText(i18nc("Quit [ApplicationName]", "&Quit %1", app)); return item; } static KGuiItem KStandardGuiItem_close() { KGuiItem item = KStandardGuiItem::close(); item.setText(i18n("Only &Close Window")); return item; } static bool isQuitting = false; namespace { static const std::vector mainViewActionNames = { QStringLiteral("view_certificate_overview"), QStringLiteral("manage_smartcard"), QStringLiteral("pad_view") }; } class MainWindow::Private { friend class ::MainWindow; MainWindow *const q; public: explicit Private(MainWindow *qq); ~Private(); template void createAndStart() { (new T(this->currentView(), &this->controller))->start(); } template void createAndStart(QAbstractItemView *view) { (new T(view, &this->controller))->start(); } template void createAndStart(const QStringList &a) { (new T(a, this->currentView(), &this->controller))->start(); } template void createAndStart(const QStringList &a, QAbstractItemView *view) { (new T(a, view, &this->controller))->start(); } void closeAndQuit() { const QString app = KAboutData::applicationData().componentName(); const int rc = KMessageBox::questionYesNoCancel(q, i18n("%1 may be used by other applications as a service.\n" "You may instead want to close this window without exiting %1.", app), i18n("Really Quit?"), KStandardGuiItem_close(), KStandardGuiItem_quit(), KStandardGuiItem::cancel(), QLatin1String("really-quit-") + app.toLower()); if (rc == KMessageBox::Cancel) { return; } isQuitting = true; if (!q->close()) { return; } // WARNING: 'this' might be deleted at this point! if (rc == KMessageBox::No) { qApp->quit(); } } void configureToolbars() { KEditToolBar dlg(q->factory()); dlg.exec(); } void editKeybindings() { KShortcutsDialog::showDialog(q->actionCollection(), KShortcutsEditor::LetterShortcutsAllowed, q); updateSearchBarClickMessage(); } void updateSearchBarClickMessage() { const QString shortcutStr = focusToClickSearchAction->shortcut().toString(); ui.searchBar->updateClickMessage(shortcutStr); } void updateStatusBar() { if (Kleo::gnupgUsesDeVsCompliance()) { auto statusBar = std::make_unique(); auto statusLbl = std::make_unique(Formatting::deVsString(Kleo::gnupgIsDeVsCompliant())); const auto color = KColorScheme(QPalette::Active, KColorScheme::View).foreground( Kleo::gnupgIsDeVsCompliant() ? KColorScheme::NormalText: KColorScheme::NegativeText ).color(); const auto background = KColorScheme(QPalette::Active, KColorScheme::View).background( Kleo::gnupgIsDeVsCompliant() ? KColorScheme::PositiveBackground : KColorScheme::NegativeBackground ).color(); statusLbl->setStyleSheet(QStringLiteral("QLabel { color: %1; background-color: %2; }"). arg(color.name()).arg(background.name())); statusBar->insertPermanentWidget(0, statusLbl.release()); q->setStatusBar(statusBar.release()); // QMainWindow takes ownership } else { q->setStatusBar(nullptr); } } void selfTest() { createAndStart(); } void configureGroups() { if (KConfigDialog::showDialog(GroupsConfigDialog::dialogName())) { return; } KConfigDialog *dialog = new GroupsConfigDialog(q); dialog->show(); } void showHandbook(); void gnupgLogViewer() { if (!QProcess::startDetached(QStringLiteral("kwatchgnupg"), QStringList())) KMessageBox::error(q, i18n("Could not start the GnuPG Log Viewer (kwatchgnupg). " "Please check your installation."), i18n("Error Starting KWatchGnuPG")); } void forceUpdateCheck() { UpdateNotification::forceUpdateCheck(q); } - void openCompendium() - { - QDir datadir(QCoreApplication::applicationDirPath() + QStringLiteral("/../share/gpg4win")); - const auto path = datadir.filePath(i18nc("The Gpg4win compendium is only available" - "at this point (24.7.2017) in german and english." - "Please check with Gpg4win before translating this filename.", - "gpg4win-compendium-en.pdf")); - qCDebug(KLEOPATRA_LOG) << "Opening Compendium at:" << path; - // The compendium is always installed. So this should work. Otherwise - // we have debug output. - QDesktopServices::openUrl(QUrl::fromLocalFile(path)); - } - void slotConfigCommitted(); void slotContextMenuRequested(QAbstractItemView *, const QPoint &p) { if (auto const menu = qobject_cast(q->factory()->container(QStringLiteral("listview_popup"), q))) { menu->exec(p); } else { qCDebug(KLEOPATRA_LOG) << "no \"listview_popup\" in kleopatra's ui.rc file"; } } void slotFocusQuickSearch() { ui.searchBar->lineEdit()->setFocus(); } void showView(const QString &actionName, QWidget *widget) { const auto coll = q->actionCollection(); if (coll) { for ( const QString &name : mainViewActionNames ) { if (auto action = coll->action(name)) { action->setChecked(name == actionName); } } } ui.stackWidget->setCurrentWidget(widget); } void showCertificateView() { showView(QStringLiteral("view_certificate_overview"), KeyCache::instance()->keys().empty() ? ui.welcomeWidget : ui.searchTab); } void showSmartcardView() { showView(QStringLiteral("manage_smartcard"), ui.scWidget); } void showPadView() { if (!ui.padWidget) { ui.padWidget = new PadWidget; ui.stackWidget->addWidget(ui.padWidget); } showView(QStringLiteral("pad_view"), ui.padWidget); ui.stackWidget->resize(ui.padWidget->sizeHint()); } void listSmartcardReaders() { auto command = new ListReadersCommand(q); command->start(); } private: void setupActions(); QAbstractItemView *currentView() const { return ui.tabWidget.currentView(); } void keyListingDone() { const auto curWidget = ui.stackWidget->currentWidget(); if (curWidget == ui.scWidget || curWidget == ui.padWidget) { return; } showCertificateView(); } private: Kleo::KeyListController controller; bool firstShow : 1; struct UI { QWidget *searchTab; TabWidget tabWidget; SearchBar *searchBar; PadWidget *padWidget; SmartCardWidget *scWidget; WelcomeWidget *welcomeWidget; QStackedWidget *stackWidget; explicit UI(MainWindow *q); } ui; QAction *focusToClickSearchAction; ClipboardMenu *clipboadMenu; }; MainWindow::Private::UI::UI(MainWindow *q) : tabWidget(q), padWidget(nullptr) { KDAB_SET_OBJECT_NAME(tabWidget); searchTab = new QWidget; auto vbox = new QVBoxLayout(searchTab); vbox->setSpacing(0); searchBar = new SearchBar; vbox->addWidget(searchBar); tabWidget.connectSearchBar(searchBar); vbox->addWidget(&tabWidget); auto mainWidget = new QWidget; auto mainLayout = new QVBoxLayout(mainWidget); stackWidget = new QStackedWidget; mainLayout->addWidget(stackWidget); stackWidget->addWidget(searchTab); new KeyCacheOverlay(mainWidget, q); scWidget = new SmartCardWidget(); stackWidget->addWidget(scWidget); welcomeWidget = new WelcomeWidget(); stackWidget->addWidget(welcomeWidget); q->setCentralWidget(mainWidget); } MainWindow::Private::Private(MainWindow *qq) : q(qq), controller(q), firstShow(true), ui(q) { KDAB_SET_OBJECT_NAME(controller); AbstractKeyListModel *flatModel = AbstractKeyListModel::createFlatKeyListModel(q); AbstractKeyListModel *hierarchicalModel = AbstractKeyListModel::createHierarchicalKeyListModel(q); KDAB_SET_OBJECT_NAME(flatModel); KDAB_SET_OBJECT_NAME(hierarchicalModel); controller.setFlatModel(flatModel); controller.setHierarchicalModel(hierarchicalModel); controller.setTabWidget(&ui.tabWidget); ui.tabWidget.setFlatModel(flatModel); ui.tabWidget.setHierarchicalModel(hierarchicalModel); setupActions(); ui.stackWidget->setCurrentWidget(ui.searchTab); if (auto action = q->actionCollection()->action(QStringLiteral("view_certificate_overview"))) { action->setChecked(true); } connect(&controller, SIGNAL(contextMenuRequested(QAbstractItemView*,QPoint)), q, SLOT(slotContextMenuRequested(QAbstractItemView*,QPoint))); connect(KeyCache::instance().get(), &KeyCache::keyListingDone, q, [this] () {keyListingDone();}); q->createGUI(QStringLiteral("kleopatra.rc")); q->setAcceptDrops(true); // set default window size q->resize(QSize(1024, 500)); q->setAutoSaveSettings(); updateSearchBarClickMessage(); updateStatusBar(); if (KeyCache::instance()->initialized()) { keyListingDone(); } } MainWindow::Private::~Private() {} MainWindow::MainWindow(QWidget *parent, Qt::WindowFlags flags) : KXmlGuiWindow(parent, flags), d(new Private(this)) {} MainWindow::~MainWindow() {} void MainWindow::Private::setupActions() { KActionCollection *const coll = q->actionCollection(); const std::vector action_data = { // most have been MOVED TO keylistcontroller.cpp // Tools menu #ifndef Q_OS_WIN { "tools_start_kwatchgnupg", i18n("GnuPG Log Viewer"), QString(), "kwatchgnupg", q, SLOT(gnupgLogViewer()), QString(), false, true }, #endif #ifdef Q_OS_WIN { "help_check_updates", i18n("Check for updates"), QString(), "gpg4win-compact", q, SLOT(forceUpdateCheck()), QString(), false, true }, - { - "help_show_compendium", i18n("Gpg4win Compendium"), QString(), - "gpg4win-compact", q, SLOT(openCompendium()), QString(), false, true - }, #endif { "view_certificate_overview", i18nc("@action show certificate overview", "Certificates"), i18n("Show certificate overview"), "view-certificate", q, SLOT(showCertificateView()), QString(), false, true }, { "pad_view", i18nc("@action show input / output area for encrypting/signing resp. decrypting/verifying text", "Notepad"), i18n("Show pad for encrypting/decrypting and signing/verifying text"), "note", q, SLOT(showPadView()), QString(), false, true }, // most have been MOVED TO keylistcontroller.cpp // Settings menu { "settings_self_test", i18n("Perform Self-Test"), QString(), nullptr, q, SLOT(selfTest()), QString(), false, true }, { "settings_list_readers", i18n("List Smartcard Readers"), QString(), nullptr, q, SLOT(listSmartcardReaders()), QString(), false, true }, { "configure_groups", i18n("Configure Groups..."), QString(), "group", q, SLOT(configureGroups()), QString(), false, true }, { "manage_smartcard", i18nc("@action show smartcard management view", "Smartcards"), i18n("Show smartcard management"), "auth-sim-locked", q, SLOT(showSmartcardView()), QString(), false, true } // most have been MOVED TO keylistcontroller.cpp }; make_actions_from_data(action_data, coll); if (!Settings().groupsEnabled()) { if (auto action = coll->action(QStringLiteral("configure_groups"))) { delete action; } } for ( const QString &name : mainViewActionNames ) { if (auto action = coll->action(name)) { action->setCheckable(true); } } if (QAction *action = coll->action(QStringLiteral("configure_backend"))) { action->setMenuRole(QAction::NoRole); //prevent Qt OS X heuristics for config* actions } KStandardAction::close(q, SLOT(close()), coll); KStandardAction::quit(q, SLOT(closeAndQuit()), coll); KStandardAction::configureToolbars(q, SLOT(configureToolbars()), coll); KStandardAction::keyBindings(q, SLOT(editKeybindings()), coll); KStandardAction::preferences(qApp, SLOT(openOrRaiseConfigDialog()), coll); focusToClickSearchAction = new QAction(i18n("Set Focus to Quick Search"), q); coll->addAction(QStringLiteral("focus_to_quickseach"), focusToClickSearchAction); coll->setDefaultShortcut(focusToClickSearchAction, QKeySequence(Qt::ALT | Qt::Key_Q)); connect(focusToClickSearchAction, SIGNAL(triggered(bool)), q, SLOT(slotFocusQuickSearch())); clipboadMenu = new ClipboardMenu(q); clipboadMenu->setMainWindow(q); clipboadMenu->clipboardMenu()->setIcon(QIcon::fromTheme(QStringLiteral("edit-paste"))); clipboadMenu->clipboardMenu()->setPopupMode(QToolButton::InstantPopup); coll->addAction(QStringLiteral("clipboard_menu"), clipboadMenu->clipboardMenu()); + /* Add additional help actions for documentation */ + const auto compendium = new DocAction(QIcon::fromTheme(QStringLiteral("gpg4win-compact")), i18n("Gpg4win Compendium"), + i18nc("The Gpg4win compendium is only available" + "at this point (24.7.2017) in german and english." + "Please check with Gpg4win before translating this filename.", + "gpg4win-compendium-en.pdf"), + QStringLiteral("../share/gpg4win")); + coll->addAction(QStringLiteral("help_doc_compendium"), compendium); + + /* Documentation centered around the german approved VS-NfD mode for official + * RESTRICTED communication. This is only available in some distributions with + * the focus on official communications. */ + const auto symguide = new DocAction(QIcon::fromTheme(QStringLiteral("help-hint")), i18n("Password-based encryption"), + i18nc("Only available in German and English. Leave to English for other languages.", + "handout_symmetric_encryption_gnupg_en.pdf"), + QStringLiteral("../share/doc/gnupg-vsd")); + coll->addAction(QStringLiteral("help_doc_symenc"), symguide); + + const auto quickguide = new DocAction(QIcon::fromTheme(QStringLiteral("help-hint")), i18n("Quickguide"), + i18nc("Only available in German and English. Leave to English for other languages.", + "handout_sign_encrypt_gnupg_en.pdf"), + QStringLiteral("../share/doc/gnupg-vsd")); + coll->addAction(QStringLiteral("help_doc_quickguide"), quickguide); + + const auto man_gpg = new DocAction(QIcon::fromTheme(QStringLiteral("help-hint")), i18n("GnuPG Manual"), + QStringLiteral("gnupg.pdf"), QStringLiteral("../share/doc/gnupg")); + coll->addAction(QStringLiteral("help_doc_gnupg"), man_gpg); + q->setStandardToolBarMenuEnabled(true); controller.createActions(coll); ui.tabWidget.createActions(coll); } void MainWindow::Private::slotConfigCommitted() { controller.updateConfig(); updateStatusBar(); } void MainWindow::closeEvent(QCloseEvent *e) { // KMainWindow::closeEvent() insists on quitting the application, // so do not let it touch the event... qCDebug(KLEOPATRA_LOG); if (d->controller.hasRunningCommands()) { if (d->controller.shutdownWarningRequired()) { const int ret = KMessageBox::warningContinueCancel(this, i18n("There are still some background operations ongoing. " "These will be terminated when closing the window. " "Proceed?"), i18n("Ongoing Background Tasks")); if (ret != KMessageBox::Continue) { e->ignore(); return; } } d->controller.cancelCommands(); if (d->controller.hasRunningCommands()) { // wait for them to be finished: setEnabled(false); QEventLoop ev; QTimer::singleShot(100ms, &ev, &QEventLoop::quit); connect(&d->controller, &KeyListController::commandsExecuting, &ev, &QEventLoop::quit); ev.exec(); if (d->controller.hasRunningCommands()) qCWarning(KLEOPATRA_LOG) << "controller still has commands running, this may crash now..."; setEnabled(true); } } if (isQuitting || qApp->isSavingSession()) { d->ui.tabWidget.saveViews(KSharedConfig::openConfig().data()); KConfigGroup grp(KConfigGroup(KSharedConfig::openConfig(), autoSaveGroup())); saveMainWindowSettings(grp); e->accept(); } else { e->ignore(); hide(); } } void MainWindow::showEvent(QShowEvent *e) { KXmlGuiWindow::showEvent(e); if (d->firstShow) { d->ui.tabWidget.loadViews(KSharedConfig::openConfig().data()); d->firstShow = false; } if (!savedGeometry.isEmpty()) { restoreGeometry(savedGeometry); } } void MainWindow::hideEvent(QHideEvent *e) { savedGeometry = saveGeometry(); KXmlGuiWindow::hideEvent(e); } void MainWindow::importCertificatesFromFile(const QStringList &files) { if (!files.empty()) { d->createAndStart(files); } } static QStringList extract_local_files(const QMimeData *data) { const QList urls = data->urls(); // begin workaround KDE/Qt misinterpretation of text/uri-list QList::const_iterator end = urls.end(); if (urls.size() > 1 && !urls.back().isValid()) { --end; } // end workaround QStringList result; std::transform(urls.begin(), end, std::back_inserter(result), std::mem_fn(&QUrl::toLocalFile)); result.erase(std::remove_if(result.begin(), result.end(), std::mem_fn(&QString::isEmpty)), result.end()); return result; } static bool can_decode_local_files(const QMimeData *data) { if (!data) { return false; } return !extract_local_files(data).empty(); } void MainWindow::dragEnterEvent(QDragEnterEvent *e) { qCDebug(KLEOPATRA_LOG); if (can_decode_local_files(e->mimeData())) { e->acceptProposedAction(); } } void MainWindow::dropEvent(QDropEvent *e) { qCDebug(KLEOPATRA_LOG); if (!can_decode_local_files(e->mimeData())) { return; } e->setDropAction(Qt::CopyAction); const QStringList files = extract_local_files(e->mimeData()); const unsigned int classification = classify(files); QMenu menu; QAction *const signEncrypt = menu.addAction(i18n("Sign/Encrypt...")); QAction *const decryptVerify = mayBeAnyMessageType(classification) ? menu.addAction(i18n("Decrypt/Verify...")) : nullptr; if (signEncrypt || decryptVerify) { menu.addSeparator(); } QAction *const importCerts = mayBeAnyCertStoreType(classification) ? menu.addAction(i18n("Import Certificates")) : nullptr; QAction *const importCRLs = mayBeCertificateRevocationList(classification) ? menu.addAction(i18n("Import CRLs")) : nullptr; if (importCerts || importCRLs) { menu.addSeparator(); } if (!signEncrypt && !decryptVerify && !importCerts && !importCRLs) { return; } menu.addAction(i18n("Cancel")); const QAction *const chosen = menu.exec(mapToGlobal(e->pos())); if (!chosen) { return; } if (chosen == signEncrypt) { d->createAndStart(files); } else if (chosen == decryptVerify) { d->createAndStart(files); } else if (chosen == importCerts) { d->createAndStart(files); } else if (chosen == importCRLs) { d->createAndStart(files); } e->accept(); } void MainWindow::readProperties(const KConfigGroup &cg) { qCDebug(KLEOPATRA_LOG); KXmlGuiWindow::readProperties(cg); setHidden(cg.readEntry("hidden", false)); } void MainWindow::saveProperties(KConfigGroup &cg) { qCDebug(KLEOPATRA_LOG); KXmlGuiWindow::saveProperties(cg); cg.writeEntry("hidden", isHidden()); } #include "moc_mainwindow.cpp" diff --git a/src/mainwindow.h b/src/mainwindow.h index e63dfdcb7..c0dc7286c 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -1,59 +1,58 @@ /* -*- mode: c++; c-basic-offset:4 -*- mainwindow.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB SPDX-FileCopyrightText: 2016 Bundesamt für Sicherheit in der Informationstechnik SPDX-FileContributor: Intevation GmbH SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include class MainWindow : public KXmlGuiWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = nullptr, Qt::WindowFlags f = {}); ~MainWindow() override; public Q_SLOTS: void importCertificatesFromFile(const QStringList &files); protected: QByteArray savedGeometry; void closeEvent(QCloseEvent *e) override; void showEvent(QShowEvent *e) override; void hideEvent(QHideEvent *e) override; void dragEnterEvent(QDragEnterEvent *) override; void dropEvent(QDropEvent *) override; void readProperties(const KConfigGroup &cg) override; void saveProperties(KConfigGroup &cg) override; private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT(d, void closeAndQuit()) Q_PRIVATE_SLOT(d, void selfTest()) Q_PRIVATE_SLOT(d, void configureToolbars()) Q_PRIVATE_SLOT(d, void configureGroups()) Q_PRIVATE_SLOT(d, void editKeybindings()) Q_PRIVATE_SLOT(d, void gnupgLogViewer()) Q_PRIVATE_SLOT(d, void slotConfigCommitted()) Q_PRIVATE_SLOT(d, void slotContextMenuRequested(QAbstractItemView *, QPoint)) Q_PRIVATE_SLOT(d, void slotFocusQuickSearch()) Q_PRIVATE_SLOT(d, void showCertificateView()) Q_PRIVATE_SLOT(d, void showPadView()) Q_PRIVATE_SLOT(d, void showSmartcardView()) Q_PRIVATE_SLOT(d, void forceUpdateCheck()) - Q_PRIVATE_SLOT(d, void openCompendium()) Q_PRIVATE_SLOT(d, void listSmartcardReaders()) };