diff --git a/src/utils/headerview.cpp b/src/utils/headerview.cpp index 701135dec..32862e4e7 100644 --- a/src/utils/headerview.cpp +++ b/src/utils/headerview.cpp @@ -1,126 +1,126 @@ /* -*- mode: c++; c-basic-offset:4 -*- utils/headerview.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "headerview.h" #include #include #include "kleopatra_debug.h" //#define ENABLE_HEADERVIEW_DEBUG #ifdef ENABLE_HEADERVIEW_DEBUG # define hvDebug qDebug #else # define hvDebug if ( true ) {} else qDebug #endif using namespace Kleo; static std::vector section_sizes(const QHeaderView *view) { Q_ASSERT(view); std::vector result; result.reserve(view->count()); for (int i = 0, end = view->count(); i != end; ++i) { result.push_back(view->sectionSize(i)); } return result; } static void apply_section_sizes(QHeaderView *view, const std::vector &newSizes) { Q_ASSERT(view); for (unsigned int i = 0, end = newSizes.size(); i != end; ++i) { view->resizeSection(i, newSizes[i]); } } namespace { template inline typename T_container::value_type lookup(const T_container &c, unsigned int i, const typename T_container::value_type &defaultValue) { return i < c.size() ? c[i] : defaultValue; } } class HeaderView::Private { friend class ::Kleo::HeaderView; HeaderView *const q; public: Private(HeaderView *qq) : q(qq), mousePressed(false), sizes() { - connect(q, SIGNAL(sectionCountChanged(int,int)), q, SLOT(_klhv_slotSectionCountChanged(int,int))); - connect(q, SIGNAL(sectionResized(int,int,int)), q, SLOT(_klhv_slotSectionResized(int,int,int))); + connect(q, &QHeaderView::sectionCountChanged, q, [this](int oldCount, int newCount) { _klhv_slotSectionCountChanged(oldCount, newCount); }); + connect(q, &QHeaderView::sectionResized, q, [this](int idx, int oldSize, int newSize) { _klhv_slotSectionResized(idx, oldSize, newSize); }); } void _klhv_slotSectionCountChanged(int oldCount, int newCount) { if (newCount == oldCount) { return; } hvDebug() << oldCount << "->" << newCount; if (newCount < oldCount) { return; } ensureNumSections(newCount); apply_section_sizes(q, sizes); } void _klhv_slotSectionResized(int idx, int oldSize, int newSize) { hvDebug() << idx << ':' << oldSize << "->" << newSize; ensureNumSections(idx + 1); sizes[idx] = newSize; } void ensureNumSections(unsigned int num) { if (num > sizes.size()) { sizes.resize(num, q->defaultSectionSize()); } } bool mousePressed : 1; std::vector sizes; }; HeaderView::HeaderView(Qt::Orientation o, QWidget *p) : QHeaderView(o, p), d(new Private(this)) { } HeaderView::~HeaderView() {} void HeaderView::setSectionSizes(const std::vector &sizes) { hvDebug() << sizes; d->ensureNumSections(sizes.size()); d->sizes = sizes; apply_section_sizes(this, sizes); hvDebug() << "->" << sectionSizes(); } std::vector HeaderView::sectionSizes() const { return section_sizes(this); } #include "moc_headerview.cpp" diff --git a/src/utils/headerview.h b/src/utils/headerview.h index b8e3993a7..2d99d3e6d 100644 --- a/src/utils/headerview.h +++ b/src/utils/headerview.h @@ -1,44 +1,42 @@ /* -*- mode: c++; c-basic-offset:4 -*- utils/headerview.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include #include namespace Kleo { class HeaderView : public QHeaderView { Q_OBJECT public: explicit HeaderView(Qt::Orientation o, QWidget *parent = nullptr); ~HeaderView() override; void setSectionSizes(const std::vector &sizes); std::vector sectionSizes() const; private: //@{ /*! Defined, but not implemented, to catch at least some usage errors */ void setResizeMode(int, ResizeMode); //@} private: class Private; kdtools::pimpl_ptr d; - Q_PRIVATE_SLOT(d, void _klhv_slotSectionCountChanged(int, int)) - Q_PRIVATE_SLOT(d, void _klhv_slotSectionResized(int, int, int)) }; } diff --git a/src/utils/systemtrayicon.cpp b/src/utils/systemtrayicon.cpp index 90e03a4ac..bf9b4ee81 100644 --- a/src/utils/systemtrayicon.cpp +++ b/src/utils/systemtrayicon.cpp @@ -1,226 +1,226 @@ /* -*- mode: c++; c-basic-offset:4 -*- utils/systemtrayicon.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2007, 2009 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "systemtrayicon.h" #ifndef QT_NO_SYSTEMTRAYICON #include "kleopatra_debug.h" #include #include #include #include using namespace Kleo; static const int ATTENTION_ANIMATION_FRAMES_PER_SEC = 1; class SystemTrayIcon::Private { friend class ::SystemTrayIcon; SystemTrayIcon *const q; public: explicit Private(SystemTrayIcon *qq); ~Private(); private: bool attentionWanted() const { return attentionAnimationTimer.isActive(); } void setAttentionWantedImpl(bool on) { if (on) { attentionAnimationTimer.start(); } else { attentionAnimationTimer.stop(); attentionIconShown = false; q->setIcon(normalIcon); } } void slotActivated(ActivationReason reason) { if (reason == QSystemTrayIcon::Trigger) { q->doActivated(); } } void slotAttentionAnimationTimerTimout() { if (attentionIconShown) { attentionIconShown = false; q->setIcon(normalIcon); } else { attentionIconShown = true; q->setIcon(attentionIcon); } } private: bool attentionIconShown; QIcon normalIcon, attentionIcon; QTimer attentionAnimationTimer; QPointer mainWindow; QPointer attentionWindow; }; SystemTrayIcon::Private::Private(SystemTrayIcon *qq) : q(qq), attentionIconShown(false), attentionAnimationTimer(), mainWindow(), attentionWindow() { KDAB_SET_OBJECT_NAME(attentionAnimationTimer); attentionAnimationTimer.setSingleShot(false); attentionAnimationTimer.setInterval(1000 * ATTENTION_ANIMATION_FRAMES_PER_SEC / 2); - connect(q, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), q, SLOT(slotActivated(QSystemTrayIcon::ActivationReason))); - connect(&attentionAnimationTimer, SIGNAL(timeout()), q, SLOT(slotAttentionAnimationTimerTimout())); + connect(q, &QSystemTrayIcon::activated, q, [this](QSystemTrayIcon::ActivationReason reason) { slotActivated(reason); }); + connect(&attentionAnimationTimer, &QTimer::timeout, q, [this]() { slotAttentionAnimationTimerTimout(); }); } SystemTrayIcon::Private::~Private() {} SystemTrayIcon::SystemTrayIcon(QObject *p) : QSystemTrayIcon(p), d(new Private(this)) { } SystemTrayIcon::SystemTrayIcon(const QIcon &icon, QObject *p) : QSystemTrayIcon(icon, p), d(new Private(this)) { d->normalIcon = d->attentionIcon = icon; } SystemTrayIcon::~SystemTrayIcon() {} void SystemTrayIcon::setMainWindow(QWidget *mw) { if (d->mainWindow) { return; } d->mainWindow = mw; if (mw) { mw->installEventFilter(this); } doMainWindowSet(mw); slotEnableDisableActions(); } QWidget *SystemTrayIcon::mainWindow() const { return d->mainWindow; } void SystemTrayIcon::setAttentionWindow(QWidget *mw) { if (d->attentionWindow) { return; } d->attentionWindow = mw; if (mw) { mw->installEventFilter(this); } slotEnableDisableActions(); } QWidget *SystemTrayIcon::attentionWindow() const { return d->attentionWindow; } bool SystemTrayIcon::eventFilter(QObject *o, QEvent *e) { if (o == d->mainWindow) switch (e->type()) { case QEvent::Close: doMainWindowClosed(static_cast(o)); // fall through: Q_FALLTHROUGH(); case QEvent::Show: case QEvent::DeferredDelete: QMetaObject::invokeMethod(this, "slotEnableDisableActions", Qt::QueuedConnection); default:; } else if (o == d->attentionWindow) switch (e->type()) { case QEvent::Close: doAttentionWindowClosed(static_cast(o)); // fall through: Q_FALLTHROUGH(); case QEvent::Show: case QEvent::DeferredDelete: QMetaObject::invokeMethod(this, "slotEnableDisableActions", Qt::QueuedConnection); default:; } return false; } void SystemTrayIcon::setAttentionWanted(bool on) { if (d->attentionWanted() == on) { return; } qCDebug(KLEOPATRA_LOG) << d->attentionWanted() << "->" << on; d->setAttentionWantedImpl(on); } bool SystemTrayIcon::attentionWanted() const { return d->attentionWanted(); } void SystemTrayIcon::setNormalIcon(const QIcon &icon) { if (d->normalIcon.cacheKey() == icon.cacheKey()) { return; } d->normalIcon = icon; if (!d->attentionWanted() || !d->attentionIconShown) { setIcon(icon); } } QIcon SystemTrayIcon::normalIcon() const { return d->normalIcon; } void SystemTrayIcon::setAttentionIcon(const QIcon &icon) { if (d->attentionIcon.cacheKey() == icon.cacheKey()) { return; } d->attentionIcon = icon; if (d->attentionWanted() && d->attentionIconShown) { setIcon(icon); } } QIcon SystemTrayIcon::attentionIcon() const { return d->attentionIcon; } void SystemTrayIcon::doMainWindowSet(QWidget *) {} void SystemTrayIcon::doMainWindowClosed(QWidget *) {} void SystemTrayIcon::doAttentionWindowClosed(QWidget *) {} #include "moc_systemtrayicon.cpp" #endif // QT_NO_SYSTEMTRAYICON diff --git a/src/utils/systemtrayicon.h b/src/utils/systemtrayicon.h index 060ca5714..6ff811a6b 100644 --- a/src/utils/systemtrayicon.h +++ b/src/utils/systemtrayicon.h @@ -1,66 +1,64 @@ /* -*- mode: c++; c-basic-offset:4 -*- systemtrayicon.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2007, 2009 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #ifndef QT_NO_SYSTEMTRAYICON #include namespace Kleo { class SystemTrayIcon : public QSystemTrayIcon { Q_OBJECT public: explicit SystemTrayIcon(QObject *parent = nullptr); explicit SystemTrayIcon(const QIcon &icon, QObject *parent = nullptr); ~SystemTrayIcon() override; void setMainWindow(QWidget *w); QWidget *mainWindow() const; void setAttentionWindow(QWidget *w); QWidget *attentionWindow() const; QIcon attentionIcon() const; QIcon normalIcon() const; bool attentionWanted() const; public Q_SLOTS: void setAttentionIcon(const QIcon &icon); void setNormalIcon(const QIcon &icon); void setAttentionWanted(bool); protected Q_SLOTS: virtual void slotEnableDisableActions() = 0; private: virtual void doMainWindowSet(QWidget *); virtual void doMainWindowClosed(QWidget *); virtual void doAttentionWindowClosed(QWidget *); virtual void doActivated() = 0; private: bool eventFilter(QObject *, QEvent *) override; private: class Private; kdtools::pimpl_ptr d; - Q_PRIVATE_SLOT(d, void slotAttentionAnimationTimerTimout()) - Q_PRIVATE_SLOT(d, void slotActivated(QSystemTrayIcon::ActivationReason)) }; } // namespace Kleo #endif // QT_NO_SYSTEMTRAYICON diff --git a/src/view/keylistcontroller.cpp b/src/view/keylistcontroller.cpp index 7ba1ce188..15fbdbb6e 100644 --- a/src/view/keylistcontroller.cpp +++ b/src/view/keylistcontroller.cpp @@ -1,850 +1,846 @@ /* -*- mode: c++; c-basic-offset:4 -*- controllers/keylistcontroller.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 "keylistcontroller.h" #include "tabwidget.h" #include #include #include #include "tooltippreferences.h" #include "kleopatra_debug.h" #include "commands/exportcertificatecommand.h" #include "commands/exportopenpgpcertstoservercommand.h" #ifdef QGPGME_SUPPORTS_SECRET_KEY_EXPORT # include "commands/exportsecretkeycommand.h" #else # include "commands/exportsecretkeycommand_old.h" #endif #include "commands/importcertificatefromfilecommand.h" #include "commands/changepassphrasecommand.h" #include "commands/lookupcertificatescommand.h" #include "commands/reloadkeyscommand.h" #include "commands/refreshx509certscommand.h" #include "commands/refreshopenpgpcertscommand.h" #include "commands/detailscommand.h" #include "commands/deletecertificatescommand.h" #include "commands/decryptverifyfilescommand.h" #include "commands/signencryptfilescommand.h" #include "commands/signencryptfoldercommand.h" #include "commands/clearcrlcachecommand.h" #include "commands/dumpcrlcachecommand.h" #include "commands/dumpcertificatecommand.h" #include "commands/importcrlcommand.h" #include "commands/changeexpirycommand.h" #include "commands/changeownertrustcommand.h" #include "commands/changeroottrustcommand.h" #include "commands/certifycertificatecommand.h" #include "commands/revokecertificationcommand.h" #include "commands/adduseridcommand.h" #include "commands/newcertificatecommand.h" #include "commands/checksumverifyfilescommand.h" #include "commands/checksumcreatefilescommand.h" #include "commands/exportpaperkeycommand.h" #include "commands/revokekeycommand.h" #include #include #include #include #include #include #include #include #include #include #include #include using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::SmartCard; using namespace GpgME; #ifndef QGPGME_SUPPORTS_SECRET_KEY_EXPORT using Kleo::Commands::Compat::ExportSecretKeyCommand; #endif class KeyListController::Private { friend class ::Kleo::KeyListController; KeyListController *const q; public: explicit Private(KeyListController *qq); ~Private(); void connectView(QAbstractItemView *view); void connectCommand(Command *cmd); void connectTabWidget(); void disconnectTabWidget(); void addCommand(Command *cmd) { connectCommand(cmd); commands.insert(std::lower_bound(commands.begin(), commands.end(), cmd), cmd); } void addView(QAbstractItemView *view) { connectView(view); views.insert(std::lower_bound(views.begin(), views.end(), view), view); } void removeView(QAbstractItemView *view) { view->disconnect(q); view->selectionModel()->disconnect(q); views.erase(std::remove(views.begin(), views.end(), view), views.end()); } public: void slotDestroyed(QObject *o) { qCDebug(KLEOPATRA_LOG) << (void *)o; views.erase(std::remove(views.begin(), views.end(), o), views.end()); commands.erase(std::remove(commands.begin(), commands.end(), o), commands.end()); } void slotDoubleClicked(const QModelIndex &idx); void slotActivated(const QModelIndex &idx); void slotSelectionChanged(const QItemSelection &old, const QItemSelection &new_); void slotContextMenu(const QPoint &pos); void slotCommandFinished(); void slotAddKey(const Key &key); void slotAboutToRemoveKey(const Key &key); void slotProgress(const QString &what, int current, int total) { Q_EMIT q->progress(current, total); if (!what.isEmpty()) { Q_EMIT q->message(what); } } void slotActionTriggered(); void slotCurrentViewChanged(QAbstractItemView *view) { if (view && !std::binary_search(views.cbegin(), views.cend(), view)) { qCDebug(KLEOPATRA_LOG) << "you need to register view" << view << "before trying to set it as the current view!"; addView(view); } currentView = view; q->enableDisableActions(view ? view->selectionModel() : nullptr); } private: int toolTipOptions() const; private: static Command::Restrictions calculateRestrictionsMask(const QItemSelectionModel *sm); private: struct action_item { QPointer action; Command::Restrictions restrictions; Command *(*createCommand)(QAbstractItemView *, KeyListController *); }; std::vector actions; std::vector views; std::vector commands; QPointer parentWidget; QPointer tabWidget; QPointer currentView; QPointer flatModel, hierarchicalModel; }; KeyListController::Private::Private(KeyListController *qq) : q(qq), actions(), views(), commands(), parentWidget(), tabWidget(), flatModel(), hierarchicalModel() { - connect(KeyCache::mutableInstance().get(), SIGNAL(added(GpgME::Key)), - q, SLOT(slotAddKey(GpgME::Key))); - connect(KeyCache::mutableInstance().get(), SIGNAL(aboutToRemove(GpgME::Key)), - q, SLOT(slotAboutToRemoveKey(GpgME::Key))); + connect(KeyCache::mutableInstance().get(), &KeyCache::added, q, [this](const GpgME::Key &key) { slotAddKey(key); }); + connect(KeyCache::mutableInstance().get(), &KeyCache::aboutToRemove, q, [this](const GpgME::Key &key) { slotAboutToRemoveKey(key); }); } KeyListController::Private::~Private() {} KeyListController::KeyListController(QObject *p) : QObject(p), d(new Private(this)) { } KeyListController::~KeyListController() {} void KeyListController::Private::slotAddKey(const Key &key) { // ### make model act on keycache directly... if (flatModel) { flatModel->addKey(key); } if (hierarchicalModel) { hierarchicalModel->addKey(key); } } void KeyListController::Private::slotAboutToRemoveKey(const Key &key) { // ### make model act on keycache directly... if (flatModel) { flatModel->removeKey(key); } if (hierarchicalModel) { hierarchicalModel->removeKey(key); } } void KeyListController::addView(QAbstractItemView *view) { if (!view || std::binary_search(d->views.cbegin(), d->views.cend(), view)) { return; } d->addView(view); } void KeyListController::removeView(QAbstractItemView *view) { if (!view || !std::binary_search(d->views.cbegin(), d->views.cend(), view)) { return; } d->removeView(view); } void KeyListController::setCurrentView(QAbstractItemView *view) { d->slotCurrentViewChanged(view); } std::vector KeyListController::views() const { return d->views; } void KeyListController::setFlatModel(AbstractKeyListModel *model) { if (model == d->flatModel) { return; } d->flatModel = model; if (model) { model->clear(); if (KeyCache::instance()->initialized()) { model->addKeys(KeyCache::instance()->keys()); } model->setToolTipOptions(d->toolTipOptions()); } } void KeyListController::setHierarchicalModel(AbstractKeyListModel *model) { if (model == d->hierarchicalModel) { return; } d->hierarchicalModel = model; if (model) { model->clear(); if (KeyCache::instance()->initialized()) { model->addKeys(KeyCache::instance()->keys()); } model->setToolTipOptions(d->toolTipOptions()); } } void KeyListController::setTabWidget(TabWidget *tabWidget) { if (tabWidget == d->tabWidget) { return; } d->disconnectTabWidget(); d->tabWidget = tabWidget; d->connectTabWidget(); d->slotCurrentViewChanged(tabWidget ? tabWidget->currentView() : nullptr); } void KeyListController::setParentWidget(QWidget *parent) { d->parentWidget = parent; } QWidget *KeyListController::parentWidget() const { return d->parentWidget; } static const struct { const char *signal; const char *slot; } tabs2controller[] = { { SIGNAL(viewAdded(QAbstractItemView*)), SLOT(addView(QAbstractItemView*)) }, { SIGNAL(viewAboutToBeRemoved(QAbstractItemView*)), SLOT(removeView(QAbstractItemView*)) }, { SIGNAL(currentViewChanged(QAbstractItemView*)), SLOT(slotCurrentViewChanged(QAbstractItemView*)) }, }; static const unsigned int numTabs2Controller = sizeof tabs2controller / sizeof * tabs2controller; void KeyListController::Private::connectTabWidget() { if (!tabWidget) { return; } const auto views = tabWidget->views(); std::for_each(views.cbegin(), views.cend(), [this](QAbstractItemView *view) { addView(view); }); for (unsigned int i = 0; i < numTabs2Controller; ++i) { connect(tabWidget, tabs2controller[i].signal, q, tabs2controller[i].slot); } } void KeyListController::Private::disconnectTabWidget() { if (!tabWidget) { return; } for (unsigned int i = 0; i < numTabs2Controller; ++i) { disconnect(tabWidget, tabs2controller[i].signal, q, tabs2controller[i].slot); } const auto views = tabWidget->views(); std::for_each(views.cbegin(), views.cend(), [this](QAbstractItemView *view) { removeView(view); }); } AbstractKeyListModel *KeyListController::flatModel() const { return d->flatModel; } AbstractKeyListModel *KeyListController::hierarchicalModel() const { return d->hierarchicalModel; } QAbstractItemView *KeyListController::currentView() const { return d->currentView; } TabWidget *KeyListController::tabWidget() const { return d->tabWidget; } void KeyListController::createActions(KActionCollection *coll) { static const std::vector common_and_openpgp_action_data = { // File menu { "file_new_certificate", i18n("New Key Pair..."), QString(), "view-certificate-add", nullptr, nullptr, QStringLiteral("Ctrl+N"), false, true }, { "file_export_certificates", i18n("Export..."), i18n("Export the selected certificate (public key) to a file"), "view-certificate-export", nullptr, nullptr, QStringLiteral("Ctrl+E"), false, true }, { "file_export_certificates_to_server", i18n("Publish on Server..."), i18n("Publish the selected certificate (public key) on a public keyserver"), "view-certificate-export-server", nullptr, nullptr, QStringLiteral("Ctrl+Shift+E"), false, true }, { "file_export_secret_keys", i18n("Backup Secret Keys..."), QString(), "view-certificate-export-secret", nullptr, nullptr, QString(), false, true }, { "file_export_paper_key", i18n("Print Secret Key..."), QString(), "document-print", nullptr, nullptr, QString(), false, true }, { "file_lookup_certificates", i18n("Lookup on Server..."), i18n("Search for certificates online using a public keyserver"), "edit-find", nullptr, nullptr, QStringLiteral("Shift+Ctrl+I"), false, true }, { "file_import_certificates", i18n("Import..."), i18n("Import a certificate from a file"), "view-certificate-import", nullptr, nullptr, QStringLiteral("Ctrl+I"), false, true }, { "file_decrypt_verify_files", i18n("Decrypt/Verify..."), i18n("Decrypt and/or verify files"), "document-edit-decrypt-verify", nullptr, nullptr, QString(), false, true }, { "file_sign_encrypt_files", i18n("Sign/Encrypt..."), i18n("Encrypt and/or sign files"), "document-edit-sign-encrypt", nullptr, nullptr, QString(), false, true }, { "file_sign_encrypt_folder", i18n("Sign/Encrypt Folder..."), i18n("Encrypt and/or sign folders"), nullptr/*"folder-edit-sign-encrypt"*/, nullptr, nullptr, QString(), false, true }, { "file_checksum_create_files", i18n("Create Checksum Files..."), QString(), nullptr/*"document-checksum-create"*/, nullptr, nullptr, QString(), false, true }, { "file_checksum_verify_files", i18n("Verify Checksum Files..."), QString(), nullptr/*"document-checksum-verify"*/, nullptr, nullptr, QString(), false, true }, // View menu { "view_redisplay", i18n("Redisplay"), QString(), "view-refresh", nullptr, nullptr, QStringLiteral("F5"), false, true }, { "view_stop_operations", i18n("Stop Operation"), QString(), "process-stop", this, SLOT(cancelCommands()), QStringLiteral("Escape"), false, false }, { "view_certificate_details", i18n("Details"), QString(), "dialog-information", nullptr, nullptr, QString(), false, true }, // Certificate menu #ifdef QGPGME_SUPPORTS_KEY_REVOCATION { "certificates_revoke", i18n("Revoke Certificate..."), i18n("Revoke the selected OpenPGP certificate"), "view-certificate-revoke", nullptr, nullptr, {}, false, true }, #endif { "certificates_delete", i18n("Delete"), i18n("Delete selected certificates"), "edit-delete", nullptr, nullptr, QStringLiteral("Delete"), false, true }, { "certificates_certify_certificate", i18n("Certify..."), i18n("Certify the validity of the selected certificate"), "view-certificate-sign", nullptr, nullptr, QString(), false, true }, { "certificates_revoke_certification", i18n("Revoke Certification..."), i18n("Revoke the certification of the selected certificate"), "view-certificate-revoke", nullptr, nullptr, QString(), false, true }, { "certificates_change_expiry", i18n("Change Expiry Date..."), QString(), nullptr, nullptr, nullptr, QString(), false, true }, { "certificates_change_owner_trust", i18n("Change Certification Trust..."), QString(), nullptr, nullptr, nullptr, QString(), false, true }, { "certificates_change_passphrase", i18n("Change Passphrase..."), QString(), nullptr, nullptr, nullptr, QString(), false, true }, { "certificates_add_userid", i18n("Add User ID..."), QString(), nullptr, nullptr, nullptr, QString(), false, true }, // Tools menu { "tools_refresh_openpgp_certificates", i18n("Refresh OpenPGP Certificates"), QString(), "view-refresh", nullptr, nullptr, QString(), false, true }, // Window menu // (come from TabWidget) // Help menu // (come from MainWindow) }; static const std::vector cms_action_data = { // Certificate menu { "certificates_trust_root", i18n("Trust Root Certificate"), QString(), nullptr, nullptr, nullptr, QString(), false, true }, { "certificates_distrust_root", i18n("Distrust Root Certificate"), QString(), nullptr, nullptr, nullptr, QString(), false, true }, { "certificates_dump_certificate", i18n("Technical Details"), QString(), nullptr, nullptr, nullptr, QString(), false, true }, // Tools menu { "tools_refresh_x509_certificates", i18n("Refresh S/MIME Certificates"), QString(), "view-refresh", nullptr, nullptr, QString(), false, true }, { "crl_clear_crl_cache", i18n("Clear CRL Cache"), QString(), nullptr, nullptr, nullptr, QString(), false, true }, { "crl_dump_crl_cache", i18n("Dump CRL Cache"), QString(), nullptr, nullptr, nullptr, QString(), false, true }, { "crl_import_crl", i18n("Import CRL From File..."), QString(), nullptr, nullptr, nullptr, QString(), false, true }, }; std::vector action_data = common_and_openpgp_action_data; if (Settings{}.cmsEnabled()) { action_data.reserve(action_data.size() + cms_action_data.size()); std::copy(std::begin(cms_action_data), std::end(cms_action_data), std::back_inserter(action_data)); } make_actions_from_data(action_data, coll); if (QAction *action = coll->action(QStringLiteral("view_stop_operations"))) { connect(this, &KeyListController::commandsExecuting, action, &QAction::setEnabled); } // ### somehow make this better... registerActionForCommand(coll->action(QStringLiteral("file_new_certificate"))); //--- registerActionForCommand(coll->action(QStringLiteral("file_lookup_certificates"))); registerActionForCommand(coll->action(QStringLiteral("file_import_certificates"))); //--- registerActionForCommand(coll->action(QStringLiteral("file_export_certificates"))); registerActionForCommand(coll->action(QStringLiteral("file_export_secret_keys"))); registerActionForCommand(coll->action(QStringLiteral("file_export_paper_key"))); registerActionForCommand(coll->action(QStringLiteral("file_export_certificates_to_server"))); //--- registerActionForCommand(coll->action(QStringLiteral("file_decrypt_verify_files"))); registerActionForCommand(coll->action(QStringLiteral("file_sign_encrypt_files"))); registerActionForCommand(coll->action(QStringLiteral("file_sign_encrypt_folder"))); //--- registerActionForCommand(coll->action(QStringLiteral("file_checksum_create_files"))); registerActionForCommand(coll->action(QStringLiteral("file_checksum_verify_files"))); registerActionForCommand(coll->action(QStringLiteral("view_redisplay"))); //coll->action( "view_stop_operations" ) <-- already dealt with in make_actions_from_data() registerActionForCommand(coll->action(QStringLiteral("view_certificate_details"))); registerActionForCommand(coll->action(QStringLiteral("certificates_change_owner_trust"))); registerActionForCommand(coll->action(QStringLiteral("certificates_trust_root"))); registerActionForCommand(coll->action(QStringLiteral("certificates_distrust_root"))); //--- registerActionForCommand(coll->action(QStringLiteral("certificates_certify_certificate"))); if (RevokeCertificationCommand::isSupported()) { registerActionForCommand(coll->action(QStringLiteral("certificates_revoke_certification"))); } //--- registerActionForCommand(coll->action(QStringLiteral("certificates_change_expiry"))); registerActionForCommand(coll->action(QStringLiteral("certificates_change_passphrase"))); registerActionForCommand(coll->action(QStringLiteral("certificates_add_userid"))); //--- #ifdef QGPGME_SUPPORTS_KEY_REVOCATION registerActionForCommand(coll->action(QStringLiteral("certificates_revoke"))); #endif registerActionForCommand(coll->action(QStringLiteral("certificates_delete"))); //--- registerActionForCommand(coll->action(QStringLiteral("certificates_dump_certificate"))); registerActionForCommand(coll->action(QStringLiteral("tools_refresh_x509_certificates"))); registerActionForCommand(coll->action(QStringLiteral("tools_refresh_openpgp_certificates"))); //--- registerActionForCommand(coll->action(QStringLiteral("crl_import_crl"))); //--- registerActionForCommand(coll->action(QStringLiteral("crl_clear_crl_cache"))); registerActionForCommand(coll->action(QStringLiteral("crl_dump_crl_cache"))); enableDisableActions(nullptr); } void KeyListController::registerAction(QAction *action, Command::Restrictions restrictions, Command * (*create)(QAbstractItemView *, KeyListController *)) { if (!action) { return; } Q_ASSERT(!action->isCheckable()); // can be added later, for now, disallow const Private::action_item ai = { action, restrictions, create }; connect(action, SIGNAL(triggered()), this, SLOT(slotActionTriggered())); d->actions.push_back(ai); } void KeyListController::registerCommand(Command *cmd) { if (!cmd || std::binary_search(d->commands.cbegin(), d->commands.cend(), cmd)) { return; } d->addCommand(cmd); qCDebug(KLEOPATRA_LOG) << (void *)cmd; if (d->commands.size() == 1) { Q_EMIT commandsExecuting(true); } } bool KeyListController::hasRunningCommands() const { return !d->commands.empty(); } bool KeyListController::shutdownWarningRequired() const { return std::any_of(d->commands.cbegin(), d->commands.cend(), std::mem_fn(&Command::warnWhenRunningAtShutdown)); } // slot void KeyListController::cancelCommands() { std::for_each(d->commands.begin(), d->commands.end(), std::mem_fn(&Command::cancel)); } void KeyListController::Private::connectView(QAbstractItemView *view) { - connect(view, SIGNAL(destroyed(QObject*)), - q, SLOT(slotDestroyed(QObject*))); - connect(view, SIGNAL(doubleClicked(QModelIndex)), - q, SLOT(slotDoubleClicked(QModelIndex))); - connect(view, SIGNAL(activated(QModelIndex)), - q, SLOT(slotActivated(QModelIndex))); - connect(view->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), - q, SLOT(slotSelectionChanged(QItemSelection,QItemSelection))); + connect(view, &QObject::destroyed, q, [this](QObject *obj) { slotDestroyed(obj); }); + connect(view, &QAbstractItemView::doubleClicked, q, [this](const QModelIndex &index) { slotDoubleClicked(index); }); + connect(view, &QAbstractItemView::activated, q, [this](const QModelIndex &index) { slotActivated(index); }); + connect(view->selectionModel(), &QItemSelectionModel::selectionChanged, + q, [this](const QItemSelection &oldSel, const QItemSelection &newSel) { + slotSelectionChanged(oldSel, newSel); + }); view->setContextMenuPolicy(Qt::CustomContextMenu); - connect(view, SIGNAL(customContextMenuRequested(QPoint)), - q, SLOT(slotContextMenu(QPoint))); + connect(view, &QWidget::customContextMenuRequested, q, [this](const QPoint &pos) { slotContextMenu(pos); }); } void KeyListController::Private::connectCommand(Command *cmd) { if (!cmd) { return; } - connect(cmd, SIGNAL(destroyed(QObject*)), q, SLOT(slotDestroyed(QObject*))); - connect(cmd, SIGNAL(finished()), q, SLOT(slotCommandFinished())); + connect(cmd, &QObject::destroyed, q, [this](QObject *obj) { slotDestroyed(obj); }); + connect(cmd, &Command::finished, q, [this] { slotCommandFinished(); }); //connect( cmd, SIGNAL(canceled()), q, SLOT(slotCommandCanceled()) ); connect(cmd, &Command::info, q, &KeyListController::message); - connect(cmd, SIGNAL(progress(QString,int,int)), q, SLOT(slotProgress(QString,int,int))); + connect(cmd, &Command::progress, q, [this](const QString &message, int current, int total) { slotProgress(message, current, total); }); } void KeyListController::Private::slotDoubleClicked(const QModelIndex &idx) { QAbstractItemView *const view = qobject_cast(q->sender()); if (!view || !std::binary_search(views.cbegin(), views.cend(), view)) { return; } DetailsCommand *const c = new DetailsCommand(view, q); if (parentWidget) { c->setParentWidget(parentWidget); } c->setIndex(idx); c->start(); } void KeyListController::Private::slotActivated(const QModelIndex &idx) { Q_UNUSED(idx) QAbstractItemView *const view = qobject_cast(q->sender()); if (!view || !std::binary_search(views.cbegin(), views.cend(), view)) { return; } } void KeyListController::Private::slotSelectionChanged(const QItemSelection &old, const QItemSelection &new_) { Q_UNUSED(old) Q_UNUSED(new_) const QItemSelectionModel *const sm = qobject_cast(q->sender()); if (!sm) { return; } q->enableDisableActions(sm); } void KeyListController::Private::slotContextMenu(const QPoint &p) { QAbstractItemView *const view = qobject_cast(q->sender()); if (view && std::binary_search(views.cbegin(), views.cend(), view)) { Q_EMIT q->contextMenuRequested(view, view->viewport()->mapToGlobal(p)); } else { qCDebug(KLEOPATRA_LOG) << "sender is not a QAbstractItemView*!"; } } void KeyListController::Private::slotCommandFinished() { Command *const cmd = qobject_cast(q->sender()); if (!cmd || !std::binary_search(commands.cbegin(), commands.cend(), cmd)) { return; } qCDebug(KLEOPATRA_LOG) << (void *)cmd; if (commands.size() == 1) { Q_EMIT q->commandsExecuting(false); } } void KeyListController::enableDisableActions(const QItemSelectionModel *sm) const { const Command::Restrictions restrictionsMask = d->calculateRestrictionsMask(sm); for (const Private::action_item &ai : std::as_const(d->actions)) if (ai.action) { ai.action->setEnabled(ai.restrictions == (ai.restrictions & restrictionsMask)); } } static bool all_secret_are_not_owner_trust_ultimate(const std::vector &keys) { for (const Key &key : keys) if (key.hasSecret() && key.ownerTrust() == Key::Ultimate) { return false; } return true; } Command::Restrictions find_root_restrictions(const std::vector &keys) { bool trusted = false, untrusted = false; for (const Key &key : keys) if (key.isRoot()) if (key.userID(0).validity() == UserID::Ultimate) { trusted = true; } else { untrusted = true; } else { return Command::NoRestriction; } if (trusted) if (untrusted) { return Command::NoRestriction; } else { return Command::MustBeTrustedRoot; } else if (untrusted) { return Command::MustBeUntrustedRoot; } else { return Command::NoRestriction; } } Command::Restrictions KeyListController::Private::calculateRestrictionsMask(const QItemSelectionModel *sm) { if (!sm) { return Command::NoRestriction; } const KeyListModelInterface *const m = dynamic_cast(sm->model()); if (!m) { return Command::NoRestriction; } const std::vector keys = m->keys(sm->selectedRows()); if (keys.empty()) { return Command::NoRestriction; } Command::Restrictions result = Command::NeedSelection; if (keys.size() == 1) { result |= Command::OnlyOneKey; } #if GPGME_VERSION_NUMBER >= 0x011102 // 1.17.2 // we need to check the primary subkey because Key::hasSecret() is also true if just the secret key stub of an offline key is available const auto primaryKeyCanBeUsedForSecretKeyOperations = [](const auto &k) { return k.subkey(0).isSecret(); }; #else // older versions of GpgME did not always set the secret flag for card keys const auto primaryKeyCanBeUsedForSecretKeyOperations = [](const auto &k) { return k.subkey(0).isSecret() || k.subkey(0).isCardKey(); }; #endif if (std::all_of(keys.cbegin(), keys.cend(), primaryKeyCanBeUsedForSecretKeyOperations)) { result |= Command::NeedSecretKey; } if (std::all_of(std::begin(keys), std::end(keys), [](const auto &k) { return k.subkey(0).isSecret() && !k.subkey(0).isCardKey(); })) { result |= Command::NeedSecretKeyData; } if (std::all_of(keys.cbegin(), keys.cend(), [](const Key &key) { return key.protocol() == OpenPGP; })) { result |= Command::MustBeOpenPGP; } else if (std::all_of(keys.cbegin(), keys.cend(), [](const Key &key) { return key.protocol() == CMS; })) { result |= Command::MustBeCMS; } if (all_secret_are_not_owner_trust_ultimate(keys)) { result |= Command::MayOnlyBeSecretKeyIfOwnerTrustIsNotYetUltimate; } result |= find_root_restrictions(keys); if (const ReaderStatus *rs = ReaderStatus::instance()) { if (!rs->firstCardWithNullPin().empty()) { result |= Command::AnyCardHasNullPin; } if (rs->anyCardCanLearnKeys()) { result |= Command::AnyCardCanLearnKeys; } } return result; } void KeyListController::Private::slotActionTriggered() { if (const QObject *const s = q->sender()) { const auto it = std::find_if(actions.cbegin(), actions.cend(), [this](const action_item &item) { return item.action == q->sender(); }); if (it != actions.end()) if (Command *const c = it->createCommand(this->currentView, q)) { if (parentWidget) { c->setParentWidget(parentWidget); } c->start(); } else qCDebug(KLEOPATRA_LOG) << "createCommand() == NULL for action(?) \"" << qPrintable(s->objectName()) << "\""; else { qCDebug(KLEOPATRA_LOG) << "I don't know anything about action(?) \"%s\"", qPrintable(s->objectName()); } } else { qCDebug(KLEOPATRA_LOG) << "not called through a signal/slot connection (sender() == NULL)"; } } int KeyListController::Private::toolTipOptions() const { using namespace Kleo::Formatting; static const int validityFlags = Validity | Issuer | ExpiryDates | CertificateUsage; static const int ownerFlags = Subject | UserIDs | OwnerTrust; static const int detailsFlags = StorageLocation | CertificateType | SerialNumber | Fingerprint; const TooltipPreferences prefs; int flags = KeyID; flags |= prefs.showValidity() ? validityFlags : 0; flags |= prefs.showOwnerInformation() ? ownerFlags : 0; flags |= prefs.showCertificateDetails() ? detailsFlags : 0; return flags; } void KeyListController::updateConfig() { const int opts = d->toolTipOptions(); if (d->flatModel) { d->flatModel->setToolTipOptions(opts); } if (d->hierarchicalModel) { d->hierarchicalModel->setToolTipOptions(opts); } } #include "moc_keylistcontroller.cpp" diff --git a/src/view/keylistcontroller.h b/src/view/keylistcontroller.h index 7c8b7b5a1..e9bbbcd89 100644 --- a/src/view/keylistcontroller.h +++ b/src/view/keylistcontroller.h @@ -1,113 +1,104 @@ /* -*- mode: c++; c-basic-offset:4 -*- controllers/keylistcontroller.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include #include #include class QAbstractItemView; class QAction; class QPoint; class QItemSelectionModel; class KActionCollection; namespace Kleo { class AbstractKeyListModel; class Command; class TabWidget; class KeyListController : public QObject { Q_OBJECT public: explicit KeyListController(QObject *parent = nullptr); ~KeyListController() override; std::vector views() const; void setFlatModel(AbstractKeyListModel *model); AbstractKeyListModel *flatModel() const; void setHierarchicalModel(AbstractKeyListModel *model); AbstractKeyListModel *hierarchicalModel() const; void setParentWidget(QWidget *parent); QWidget *parentWidget() const; QAbstractItemView *currentView() const; void setTabWidget(TabWidget *tabs); TabWidget *tabWidget() const; void registerCommand(Command *cmd); void createActions(KActionCollection *collection); template void registerActionForCommand(QAction *action) { this->registerAction(action, T_Command::restrictions(), &KeyListController::template create); } void enableDisableActions(const QItemSelectionModel *sm) const; bool hasRunningCommands() const; bool shutdownWarningRequired() const; private: void registerAction(QAction *action, Command::Restrictions restrictions, Command * (*create)(QAbstractItemView *, KeyListController *)); template static Command *create(QAbstractItemView *v, KeyListController *c) { return new T_Command(v, c); } public Q_SLOTS: void addView(QAbstractItemView *view); void removeView(QAbstractItemView *view); void setCurrentView(QAbstractItemView *view); void cancelCommands(); void updateConfig(); Q_SIGNALS: void progress(int current, int total); void message(const QString &msg, int timeout = 0); void commandsExecuting(bool); void contextMenuRequested(QAbstractItemView *view, const QPoint &p); private: class Private; kdtools::pimpl_ptr d; - Q_PRIVATE_SLOT(d, void slotDestroyed(QObject *)) - Q_PRIVATE_SLOT(d, void slotDoubleClicked(QModelIndex)) - Q_PRIVATE_SLOT(d, void slotActivated(QModelIndex)) - Q_PRIVATE_SLOT(d, void slotSelectionChanged(QItemSelection, QItemSelection)) - Q_PRIVATE_SLOT(d, void slotContextMenu(QPoint)) - Q_PRIVATE_SLOT(d, void slotCommandFinished()) - Q_PRIVATE_SLOT(d, void slotAddKey(GpgME::Key)) - Q_PRIVATE_SLOT(d, void slotAboutToRemoveKey(GpgME::Key)) - Q_PRIVATE_SLOT(d, void slotProgress(QString, int, int)) Q_PRIVATE_SLOT(d, void slotActionTriggered()) Q_PRIVATE_SLOT(d, void slotCurrentViewChanged(QAbstractItemView *)) }; } diff --git a/src/view/searchbar.cpp b/src/view/searchbar.cpp index 9925ce076..aab65f2c5 100644 --- a/src/view/searchbar.cpp +++ b/src/view/searchbar.cpp @@ -1,226 +1,226 @@ /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; -*- view/searchbar.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB SPDX-FileCopyrightText: 2022 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "searchbar.h" #include #include #include #include #include #include #include #include #include #include #include #include "kleopatra_debug.h" using namespace Kleo; namespace { class ProxyModel : public QSortFilterProxyModel { Q_OBJECT public: using QSortFilterProxyModel::QSortFilterProxyModel; protected: bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override { const QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); const auto matchContexts = qvariant_cast(sourceModel()->data(index, KeyFilterManager::FilterMatchContextsRole)); return matchContexts & KeyFilter::Filtering; } }; } class SearchBar::Private { friend class ::Kleo::SearchBar; SearchBar *const q; public: explicit Private(SearchBar *qq); ~Private(); private: void slotKeyFilterChanged(int idx) { Q_EMIT q->keyFilterChanged(keyFilter(idx)); } std::shared_ptr keyFilter(int idx) const { const QModelIndex mi = proxyModel->mapToSource(proxyModel->index(idx, 0)); return KeyFilterManager::instance()->fromModelIndex(mi); } std::shared_ptr currentKeyFilter() const { return keyFilter(combo->currentIndex()); } QString currentKeyFilterID() const { if (const std::shared_ptr f = currentKeyFilter()) { return f->id(); } else { return QString(); } } static auto notCertifiedKeysFilterId() { static const QString filterId = QStringLiteral("not-certified-certificates"); return filterId; } void listNotCertifiedKeys() const { lineEdit->clear(); combo->setCurrentIndex(combo->findData(notCertifiedKeysFilterId())); Q_EMIT q->keyFilterChanged(keyFilter(combo->currentIndex())); } void showOrHideCertifyButton() const { if (!KeyCache::instance()->initialized()) { return; } const auto filter = KeyFilterManager::instance()->keyFilterByID(notCertifiedKeysFilterId()); if (filter) { if (Kleo::any_of(KeyCache::instance()->keys(), [filter](const auto &key) { return filter->matches(key, KeyFilter::Filtering); })) { certifyButton->show(); return; } } else { qCDebug(KLEOPATRA_LOG) << __func__ << "Key filter with id" << notCertifiedKeysFilterId() << "not found"; } certifyButton->hide(); } private: ProxyModel *proxyModel; QLineEdit *lineEdit; QComboBox *combo; QPushButton *certifyButton; }; SearchBar::Private::Private(SearchBar *qq) : q(qq) { auto layout = new QHBoxLayout(q); layout->setContentsMargins(0, 0, 0, 0); lineEdit = new QLineEdit(q); lineEdit->setClearButtonEnabled(true); lineEdit->setPlaceholderText(i18n("Search...")); lineEdit->setAccessibleName(i18n("Filter certificates by text")); lineEdit->setToolTip(i18n("Show only certificates that match the entered search term.")); layout->addWidget(lineEdit, /*stretch=*/1); combo = new QComboBox(q); combo->setAccessibleName(i18n("Filter certificates by category")); combo->setToolTip(i18n("Show only certificates that belong to the selected category.")); layout->addWidget(combo); certifyButton = new QPushButton(q); certifyButton->setIcon(QIcon::fromTheme(QStringLiteral("security-medium"))); certifyButton->setAccessibleName(i18n("Show not certified certificates")); certifyButton->setToolTip(i18n("Some certificates are not yet certified. " "Click here to see a list of these certificates." "

" "Certification is required to make sure that the certificates " "actually belong to the identity they claim to belong to.")); certifyButton->hide(); layout->addWidget(certifyButton); proxyModel = new ProxyModel{q}; proxyModel->setSourceModel(KeyFilterManager::instance()->model()); proxyModel->sort(0, Qt::AscendingOrder); combo->setModel(proxyModel); KDAB_SET_OBJECT_NAME(layout); KDAB_SET_OBJECT_NAME(lineEdit); KDAB_SET_OBJECT_NAME(combo); KDAB_SET_OBJECT_NAME(certifyButton); connect(lineEdit, &QLineEdit::textChanged, q, &SearchBar::stringFilterChanged); - connect(combo, SIGNAL(currentIndexChanged(int)), q, SLOT(slotKeyFilterChanged(int))); - connect(certifyButton, SIGNAL(clicked()), q, SLOT(listNotCertifiedKeys())); + connect(combo, qOverload(&QComboBox::currentIndexChanged), q, [this](int index) { slotKeyFilterChanged(index); }); + connect(certifyButton, &QPushButton::clicked, q, [this]() { listNotCertifiedKeys(); }); connect(KeyCache::instance().get(), &KeyCache::keyListingDone, q, [this]() { showOrHideCertifyButton(); }); showOrHideCertifyButton(); } SearchBar::Private::~Private() {} SearchBar::SearchBar(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f), d(new Private(this)) { } SearchBar::~SearchBar() {} void SearchBar::updateClickMessage(const QString &shortcutStr) { d->lineEdit->setPlaceholderText(i18n("Search...<%1>", shortcutStr)); } // slot void SearchBar::setStringFilter(const QString &filter) { d->lineEdit->setText(filter); } // slot void SearchBar::setKeyFilter(const std::shared_ptr &kf) { const QModelIndex sourceIndex = KeyFilterManager::instance()->toModelIndex(kf); const QModelIndex proxyIndex = d->proxyModel->mapFromSource(sourceIndex); if (proxyIndex.isValid()) { d->combo->setCurrentIndex(proxyIndex.row()); } else { d->combo->setCurrentIndex(0); } } // slot void SearchBar::setChangeStringFilterEnabled(bool on) { d->lineEdit->setEnabled(on); } // slot void SearchBar::setChangeKeyFilterEnabled(bool on) { d->combo->setEnabled(on); } QLineEdit *SearchBar::lineEdit() const { return d->lineEdit; } #include "moc_searchbar.cpp" #include "searchbar.moc" diff --git a/src/view/searchbar.h b/src/view/searchbar.h index 081670cc0..e483e868a 100644 --- a/src/view/searchbar.h +++ b/src/view/searchbar.h @@ -1,58 +1,56 @@ /* -*- mode: c++; c-basic-offset:4 -*- view/searchbar.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include #include class QLineEdit; namespace Kleo { class KeyFilter; class SearchBar : public QWidget { Q_OBJECT public: explicit SearchBar(QWidget *parent = nullptr, Qt::WindowFlags f = {}); ~SearchBar() override; const std::shared_ptr &keyFilter() const; QLineEdit *lineEdit() const; void updateClickMessage(const QString &shortcutStr); public Q_SLOTS: void setStringFilter(const QString &text); void setKeyFilter(const std::shared_ptr &filter); void setChangeStringFilterEnabled(bool enable); void setChangeKeyFilterEnabled(bool enable); Q_SIGNALS: void stringFilterChanged(const QString &text); void keyFilterChanged(const std::shared_ptr &filter); private: class Private; kdtools::pimpl_ptr d; - Q_PRIVATE_SLOT(d, void slotKeyFilterChanged(int)) - Q_PRIVATE_SLOT(d, void listNotCertifiedKeys()) Q_PRIVATE_SLOT(d, void showOrHideCertifyButton()) }; } diff --git a/src/view/tabwidget.cpp b/src/view/tabwidget.cpp index 92b48ffa1..b71bb7d8b 100644 --- a/src/view/tabwidget.cpp +++ b/src/view/tabwidget.cpp @@ -1,1010 +1,1004 @@ /* -*- mode: c++; c-basic-offset:4 -*- view/tabwidget.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 "searchbar.h" #include "tabwidget.h" #include "keytreeview.h" #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 using namespace Kleo; using namespace GpgME; namespace { class Page : public Kleo::KeyTreeView { Q_OBJECT Page(const Page &other); public: Page(const QString &title, const QString &id, const QString &text, AbstractKeyListSortFilterProxyModel *proxy = nullptr, const QString &toolTip = QString(), QWidget *parent = nullptr, const KConfigGroup &group = KConfigGroup()); Page(const KConfigGroup &group, QWidget *parent = nullptr); ~Page() override; void setTemporary(bool temporary); bool isTemporary() const { return m_isTemporary; } void setHierarchicalView(bool hierarchical) override; void setStringFilter(const QString &filter) override; void setKeyFilter(const std::shared_ptr &filter) override; QString title() const { return m_title.isEmpty() && keyFilter() ? keyFilter()->name() : m_title; } void setTitle(const QString &title); QString toolTip() const { return m_toolTip.isEmpty() ? title() : m_toolTip; } // not used void setToolTip(const QString &tip); bool canBeClosed() const { return m_canBeClosed; } bool canBeRenamed() const { return m_canBeRenamed; } bool canChangeStringFilter() const { return m_canChangeStringFilter; } bool canChangeKeyFilter() const { return m_canChangeKeyFilter && !m_isTemporary; } bool canChangeHierarchical() const { return m_canChangeHierarchical; } void saveTo(KConfigGroup &group) const; Page *clone() const override { return new Page(*this); } void liftAllRestrictions() { m_canBeClosed = m_canBeRenamed = m_canChangeStringFilter = m_canChangeKeyFilter = m_canChangeHierarchical = true; } Q_SIGNALS: void titleChanged(const QString &title); private: void init(); private: QString m_title; QString m_toolTip; bool m_isTemporary : 1; bool m_canBeClosed : 1; bool m_canBeRenamed : 1; bool m_canChangeStringFilter : 1; bool m_canChangeKeyFilter : 1; bool m_canChangeHierarchical : 1; }; } // anon namespace Page::Page(const Page &other) : KeyTreeView(other), m_title(other.m_title), m_toolTip(other.m_toolTip), m_isTemporary(other.m_isTemporary), m_canBeClosed(other.m_canBeClosed), m_canBeRenamed(other.m_canBeRenamed), m_canChangeStringFilter(other.m_canChangeStringFilter), m_canChangeKeyFilter(other.m_canChangeKeyFilter), m_canChangeHierarchical(other.m_canChangeHierarchical) { init(); } Page::Page(const QString &title, const QString &id, const QString &text, AbstractKeyListSortFilterProxyModel *proxy, const QString &toolTip, QWidget *parent, const KConfigGroup &group) : KeyTreeView(text, KeyFilterManager::instance()->keyFilterByID(id), proxy, parent, group), m_title(title), m_toolTip(toolTip), m_isTemporary(false), m_canBeClosed(true), m_canBeRenamed(true), m_canChangeStringFilter(true), m_canChangeKeyFilter(true), m_canChangeHierarchical(true) { init(); } static const char TITLE_ENTRY[] = "title"; static const char STRING_FILTER_ENTRY[] = "string-filter"; static const char KEY_FILTER_ENTRY[] = "key-filter"; static const char HIERARCHICAL_VIEW_ENTRY[] = "hierarchical-view"; static const char COLUMN_SIZES[] = "column-sizes"; static const char SORT_COLUMN[] = "sort-column"; static const char SORT_DESCENDING[] = "sort-descending"; Page::Page(const KConfigGroup &group, QWidget *parent) : KeyTreeView(group.readEntry(STRING_FILTER_ENTRY), KeyFilterManager::instance()->keyFilterByID(group.readEntry(KEY_FILTER_ENTRY)), nullptr, parent, group), m_title(group.readEntry(TITLE_ENTRY)), m_toolTip(), m_isTemporary(false), m_canBeClosed(!group.isImmutable()), m_canBeRenamed(!group.isEntryImmutable(TITLE_ENTRY)), m_canChangeStringFilter(!group.isEntryImmutable(STRING_FILTER_ENTRY)), m_canChangeKeyFilter(!group.isEntryImmutable(KEY_FILTER_ENTRY)), m_canChangeHierarchical(!group.isEntryImmutable(HIERARCHICAL_VIEW_ENTRY)) { init(); setHierarchicalView(group.readEntry(HIERARCHICAL_VIEW_ENTRY, true)); const QList settings = group.readEntry(COLUMN_SIZES, QList()); std::vector sizes; sizes.reserve(settings.size()); std::copy(settings.cbegin(), settings.cend(), std::back_inserter(sizes)); setColumnSizes(sizes); setSortColumn(group.readEntry(SORT_COLUMN, 0), group.readEntry(SORT_DESCENDING, true) ? Qt::DescendingOrder : Qt::AscendingOrder); } void Page::init() { } Page::~Page() {} void Page::saveTo(KConfigGroup &group) const { group.writeEntry(TITLE_ENTRY, m_title); group.writeEntry(STRING_FILTER_ENTRY, stringFilter()); group.writeEntry(KEY_FILTER_ENTRY, keyFilter() ? keyFilter()->id() : QString()); group.writeEntry(HIERARCHICAL_VIEW_ENTRY, isHierarchicalView()); QList settings; const auto sizes = columnSizes(); settings.reserve(sizes.size()); std::copy(sizes.cbegin(), sizes.cend(), std::back_inserter(settings)); group.writeEntry(COLUMN_SIZES, settings); group.writeEntry(SORT_COLUMN, sortColumn()); group.writeEntry(SORT_DESCENDING, sortOrder() == Qt::DescendingOrder); } void Page::setStringFilter(const QString &filter) { if (!m_canChangeStringFilter) { return; } KeyTreeView::setStringFilter(filter); } void Page::setKeyFilter(const std::shared_ptr &filter) { if (!canChangeKeyFilter()) { return; } const QString oldTitle = title(); KeyTreeView::setKeyFilter(filter); const QString newTitle = title(); if (oldTitle != newTitle) { Q_EMIT titleChanged(newTitle); } } void Page::setTitle(const QString &t) { if (t == m_title) { return; } if (!m_canBeRenamed) { return; } const QString oldTitle = title(); m_title = t; const QString newTitle = title(); if (oldTitle != newTitle) { Q_EMIT titleChanged(newTitle); } } #if 0 // not used void Page::setToolTip(const QString &tip) { if (tip == m_toolTip) { return; } if (!m_canBeRenamed) { return; } const QString oldTip = toolTip(); m_toolTip = tip; const QString newTip = toolTip(); if (oldTip != newTip) { Q_EMIT titleChanged(title()); } } #endif void Page::setHierarchicalView(bool on) { if (!m_canChangeHierarchical) { return; } KeyTreeView::setHierarchicalView(on); } void Page::setTemporary(bool on) { if (on == m_isTemporary) { return; } m_isTemporary = on; if (on) { setKeyFilter(std::shared_ptr()); } } namespace { class Actions { public: constexpr static const char *Rename = "window_rename_tab"; constexpr static const char *Duplicate = "window_duplicate_tab"; constexpr static const char *Close = "window_close_tab"; constexpr static const char *MoveLeft = "window_move_tab_left"; constexpr static const char *MoveRight = "window_move_tab_right"; constexpr static const char *Hierarchical = "window_view_hierarchical"; constexpr static const char *ExpandAll = "window_expand_all"; constexpr static const char *CollapseAll = "window_collapse_all"; explicit Actions() {} void insert(const std::string &name, QAction *action) { actions.insert({name, action}); } auto get(const std::string &name) const { const auto it = actions.find(name); return (it != actions.end()) ? it->second : nullptr; } void setChecked(const std::string &name, bool checked) const { if (auto action = get(name)) { action->setChecked(checked); } } void setEnabled(const std::string &name, bool enabled) const { if (auto action = get(name)) { action->setEnabled(enabled); } } void setVisible(const std::string &name, bool visible) const { if (auto action = get(name)) { action->setVisible(visible); } } private: std::map actions; }; } // // // TabWidget // // class TabWidget::Private { friend class ::Kleo::TabWidget; TabWidget *const q; public: explicit Private(TabWidget *qq); ~Private() {} private: void slotContextMenu(const QPoint &p); void currentIndexChanged(int index); void slotPageTitleChanged(const QString &title); void slotPageKeyFilterChanged(const std::shared_ptr &filter); void slotPageStringFilterChanged(const QString &filter); void slotPageHierarchyChanged(bool on); #ifndef QT_NO_INPUTDIALOG void slotRenameCurrentTab() { renamePage(currentPage()); } #endif // QT_NO_INPUTDIALOG void slotNewTab(); void slotDuplicateCurrentTab() { duplicatePage(currentPage()); } void slotCloseCurrentTab() { closePage(currentPage()); } void slotMoveCurrentTabLeft() { movePageLeft(currentPage()); } void slotMoveCurrentTabRight() { movePageRight(currentPage()); } void slotToggleHierarchicalView(bool on) { toggleHierarchicalView(currentPage(), on); } void slotExpandAll() { expandAll(currentPage()); } void slotCollapseAll() { collapseAll(currentPage()); } #ifndef QT_NO_INPUTDIALOG void renamePage(Page *page); #endif void duplicatePage(Page *page); void closePage(Page *page); void movePageLeft(Page *page); void movePageRight(Page *page); void toggleHierarchicalView(Page *page, bool on); void expandAll(Page *page); void collapseAll(Page *page); void enableDisableCurrentPageActions(); void enableDisablePageActions(const Actions &actions, const Page *page); Page *currentPage() const { Q_ASSERT(!tabWidget->currentWidget() || qobject_cast(tabWidget->currentWidget())); return static_cast(tabWidget->currentWidget()); } Page *page(unsigned int idx) const { Q_ASSERT(!tabWidget->widget(idx) || qobject_cast(tabWidget->widget(idx))); return static_cast(tabWidget->widget(idx)); } Page *senderPage() const { QObject *const sender = q->sender(); Q_ASSERT(!sender || qobject_cast(sender)); return static_cast(sender); } bool isSenderCurrentPage() const { Page *const sp = senderPage(); return sp && sp == currentPage(); } QTreeView *addView(Page *page, Page *columnReference); private: AbstractKeyListModel *flatModel = nullptr; AbstractKeyListModel *hierarchicalModel = nullptr; QToolButton *newTabButton = nullptr; QToolButton *closeTabButton = nullptr; QTabWidget *tabWidget = nullptr; QAction *newAction = nullptr; Actions currentPageActions; Actions otherPageActions; bool actionsCreated = false; }; TabWidget::Private::Private(TabWidget *qq) : q{qq} { auto layout = new QVBoxLayout{q}; layout->setContentsMargins(0, 0, 0, 0); // create "New Tab" button before tab widget to ensure correct tab order newTabButton = new QToolButton{q}; tabWidget = new QTabWidget{q}; KDAB_SET_OBJECT_NAME(tabWidget); layout->addWidget(tabWidget); tabWidget->setMovable(true); tabWidget->tabBar()->setContextMenuPolicy(Qt::CustomContextMenu); // create "Close Tab" button after tab widget to ensure correct tab order closeTabButton = new QToolButton{q}; - connect(tabWidget, SIGNAL(currentChanged(int)), q, SLOT(currentIndexChanged(int))); + connect(tabWidget, &QTabWidget::currentChanged, q, [this](int index) { currentIndexChanged(index); }); connect(tabWidget->tabBar(), &QWidget::customContextMenuRequested, q, [this](const QPoint & p) { slotContextMenu(p); }); } void TabWidget::Private::slotContextMenu(const QPoint &p) { const int tabUnderPos = tabWidget->tabBar()->tabAt(p); Page *const contextMenuPage = static_cast(tabWidget->widget(tabUnderPos)); const Page *const current = currentPage(); const auto actions = contextMenuPage == current ? currentPageActions : otherPageActions; enableDisablePageActions(actions, contextMenuPage); QMenu menu; if (auto action = actions.get(Actions::Rename)) { menu.addAction(action); } menu.addSeparator(); menu.addAction(newAction); if (auto action = actions.get(Actions::Duplicate)) { menu.addAction(action); } menu.addSeparator(); if (auto action = actions.get(Actions::MoveLeft)) { menu.addAction(action); } if (auto action = actions.get(Actions::MoveRight)) { menu.addAction(action); } menu.addSeparator(); if (auto action = actions.get(Actions::Close)) { menu.addAction(action); } const QAction *const action = menu.exec(tabWidget->tabBar()->mapToGlobal(p)); if (!action) { return; } if (contextMenuPage == current || action == newAction) { return; // performed through signal/slot connections... } #ifndef QT_NO_INPUTDIALOG if (action == otherPageActions.get(Actions::Rename)) { renamePage(contextMenuPage); } #endif // QT_NO_INPUTDIALOG else if (action == otherPageActions.get(Actions::Duplicate)) { duplicatePage(contextMenuPage); } else if (action == otherPageActions.get(Actions::Close)) { closePage(contextMenuPage); } else if (action == otherPageActions.get(Actions::MoveLeft)) { movePageLeft(contextMenuPage); } else if (action == otherPageActions.get(Actions::MoveRight)) { movePageRight(contextMenuPage); } } void TabWidget::Private::currentIndexChanged(int index) { const Page *const page = this->page(index); Q_EMIT q->currentViewChanged(page ? page->view() : nullptr); Q_EMIT q->keyFilterChanged(page ? page->keyFilter() : std::shared_ptr()); Q_EMIT q->stringFilterChanged(page ? page->stringFilter() : QString()); enableDisableCurrentPageActions(); } void TabWidget::Private::enableDisableCurrentPageActions() { const Page *const page = currentPage(); Q_EMIT q->enableChangeStringFilter(page && page->canChangeStringFilter()); Q_EMIT q->enableChangeKeyFilter(page && page->canChangeKeyFilter()); enableDisablePageActions(currentPageActions, page); } void TabWidget::Private::enableDisablePageActions(const Actions &actions, const Page *p) { actions.setEnabled(Actions::Rename, p && p->canBeRenamed()); actions.setEnabled(Actions::Duplicate, p); actions.setEnabled(Actions::Close, p && p->canBeClosed() && tabWidget->count() > 1); actions.setEnabled(Actions::MoveLeft, p && tabWidget->indexOf(const_cast(p)) != 0); actions.setEnabled(Actions::MoveRight, p && tabWidget->indexOf(const_cast(p)) != tabWidget->count() - 1); actions.setEnabled(Actions::Hierarchical, p && p->canChangeHierarchical()); actions.setChecked(Actions::Hierarchical, p && p->isHierarchicalView()); actions.setVisible(Actions::Hierarchical, Kleo::Settings{}.cmsEnabled()); actions.setEnabled(Actions::ExpandAll, p && p->isHierarchicalView()); actions.setEnabled(Actions::CollapseAll, p && p->isHierarchicalView()); } void TabWidget::Private::slotPageTitleChanged(const QString &) { if (Page *const page = senderPage()) { const int idx = tabWidget->indexOf(page); tabWidget->setTabText(idx, page->title()); tabWidget->setTabToolTip(idx, page->toolTip()); } } void TabWidget::Private::slotPageKeyFilterChanged(const std::shared_ptr &kf) { if (isSenderCurrentPage()) { Q_EMIT q->keyFilterChanged(kf); } } void TabWidget::Private::slotPageStringFilterChanged(const QString &filter) { if (isSenderCurrentPage()) { Q_EMIT q->stringFilterChanged(filter); } } void TabWidget::Private::slotPageHierarchyChanged(bool) { enableDisableCurrentPageActions(); } void TabWidget::Private::slotNewTab() { const KConfigGroup group = KSharedConfig::openConfig()->group(QString::asprintf("View #%u", tabWidget->count())); Page *page = new Page(QString(), QStringLiteral("all-certificates"), QString(), nullptr, QString(), nullptr, group); addView(page, currentPage()); tabWidget->setCurrentIndex(tabWidget->count() - 1); } void TabWidget::Private::renamePage(Page *page) { if (!page) { return; } bool ok; const QString text = QInputDialog::getText(q, i18n("Rename Tab"), i18n("New tab title:"), QLineEdit::Normal, page->title(), &ok); if (!ok) { return; } page->setTitle(text); } void TabWidget::Private::duplicatePage(Page *page) { if (!page) { return; } Page *const clone = page->clone(); Q_ASSERT(clone); clone->liftAllRestrictions(); addView(clone, page); } void TabWidget::Private::closePage(Page *page) { if (!page || !page->canBeClosed() || tabWidget->count() <= 1) { return; } Q_EMIT q->viewAboutToBeRemoved(page->view()); tabWidget->removeTab(tabWidget->indexOf(page)); enableDisableCurrentPageActions(); } void TabWidget::Private::movePageLeft(Page *page) { if (!page) { return; } const int idx = tabWidget->indexOf(page); if (idx <= 0) { return; } tabWidget->tabBar()->moveTab(idx, idx - 1); enableDisableCurrentPageActions(); } void TabWidget::Private::movePageRight(Page *page) { if (!page) { return; } const int idx = tabWidget->indexOf(page); if (idx < 0 || idx >= tabWidget->count() - 1) { return; } tabWidget->tabBar()->moveTab(idx, idx + 1); enableDisableCurrentPageActions(); } void TabWidget::Private::toggleHierarchicalView(Page *page, bool on) { if (!page) { return; } page->setHierarchicalView(on); } void TabWidget::Private::expandAll(Page *page) { if (!page || !page->view()) { return; } page->view()->expandAll(); } void TabWidget::Private::collapseAll(Page *page) { if (!page || !page->view()) { return; } page->view()->collapseAll(); } TabWidget::TabWidget(QWidget *p, Qt::WindowFlags f) : QWidget(p, f), d(new Private(this)) { - } TabWidget::~TabWidget() { saveViews(KSharedConfig::openConfig().data()); } void TabWidget::setFlatModel(AbstractKeyListModel *model) { if (model == d->flatModel) { return; } d->flatModel = model; for (unsigned int i = 0, end = count(); i != end; ++i) if (Page *const page = d->page(i)) { page->setFlatModel(model); } } AbstractKeyListModel *TabWidget::flatModel() const { return d->flatModel; } void TabWidget::setHierarchicalModel(AbstractKeyListModel *model) { if (model == d->hierarchicalModel) { return; } d->hierarchicalModel = model; for (unsigned int i = 0, end = count(); i != end; ++i) if (Page *const page = d->page(i)) { page->setHierarchicalModel(model); } } AbstractKeyListModel *TabWidget::hierarchicalModel() const { return d->hierarchicalModel; } QString TabWidget::stringFilter() const { return d->currentPage() ? d->currentPage()->stringFilter() : QString{}; } void TabWidget::setStringFilter(const QString &filter) { if (Page *const page = d->currentPage()) { page->setStringFilter(filter); } } void TabWidget::setKeyFilter(const std::shared_ptr &filter) { if (!filter) { qCDebug(KLEOPATRA_LOG) << "TabWidget::setKeyFilter() trial to set filter=NULL"; return; } if (Page *const page = d->currentPage()) { page->setKeyFilter(filter); } } std::vector TabWidget::views() const { std::vector result; const unsigned int N = count(); result.reserve(N); for (unsigned int i = 0; i != N; ++i) if (const Page *const p = d->page(i)) { result.push_back(p->view()); } return result; } QAbstractItemView *TabWidget::currentView() const { if (Page *const page = d->currentPage()) { return page->view(); } else { return nullptr; } } KeyListModelInterface *TabWidget::currentModel() const { const QAbstractItemView *const view = currentView(); if (!view) { return nullptr; } auto const proxy = qobject_cast(view->model()); if (!proxy) { return nullptr; } return dynamic_cast(proxy); } unsigned int TabWidget::count() const { return d->tabWidget->count(); } void TabWidget::setMultiSelection(bool on) { for (unsigned int i = 0, end = count(); i != end; ++i) if (const Page *const p = d->page(i)) if (QTreeView *const view = p->view()) { view->setSelectionMode(on ? QAbstractItemView::ExtendedSelection : QAbstractItemView::SingleSelection); } } void TabWidget::createActions(KActionCollection *coll) { if (!coll) { return; } const action_data actionDataNew = { "window_new_tab", i18n("New Tab"), i18n("Open a new tab"), "tab-new-background", this, SLOT(slotNewTab()), QStringLiteral("CTRL+SHIFT+N"), false, true }; d->newAction = make_action_from_data(actionDataNew, coll); const std::vector actionData = { { Actions::Rename, i18n("Rename Tab..."), i18n("Rename this tab"), "edit-rename", this, SLOT(slotRenameCurrentTab()), QStringLiteral("CTRL+SHIFT+R"), false, false }, { Actions::Duplicate, i18n("Duplicate Tab"), i18n("Duplicate this tab"), "tab-duplicate", this, SLOT(slotDuplicateCurrentTab()), QStringLiteral("CTRL+SHIFT+D"), false, true }, { Actions::Close, i18n("Close Tab"), i18n("Close this tab"), "tab-close", this, SLOT(slotCloseCurrentTab()), QStringLiteral("CTRL+SHIFT+W"), false, false }, // ### CTRL-W when available { Actions::MoveLeft, i18n("Move Tab Left"), i18n("Move this tab left"), nullptr, this, SLOT(slotMoveCurrentTabLeft()), QStringLiteral("CTRL+SHIFT+LEFT"), false, false }, { Actions::MoveRight, i18n("Move Tab Right"), i18n("Move this tab right"), nullptr, this, SLOT(slotMoveCurrentTabRight()), QStringLiteral("CTRL+SHIFT+RIGHT"), false, false }, { Actions::Hierarchical, i18n("Hierarchical Certificate List"), QString(), nullptr, this, SLOT(slotToggleHierarchicalView(bool)), QString(), true, false }, { Actions::ExpandAll, i18n("Expand All"), QString(), nullptr, this, SLOT(slotExpandAll()), QStringLiteral("CTRL+."), false, false }, { Actions::CollapseAll, i18n("Collapse All"), QString(), nullptr, this, SLOT(slotCollapseAll()), QStringLiteral("CTRL+,"), false, false }, }; for (const auto &ad : actionData) { d->currentPageActions.insert(ad.name, make_action_from_data(ad, coll)); } for (const auto &ad : actionData) { // create actions for the context menu of the currently not active tabs, // but do not add those actions to the action collection auto action = new QAction(ad.text, coll); if (ad.icon) { action->setIcon(QIcon::fromTheme(QLatin1String(ad.icon))); } action->setEnabled(ad.enabled); d->otherPageActions.insert(ad.name, action); } d->newTabButton->setDefaultAction(d->newAction); d->tabWidget->setCornerWidget(d->newTabButton, Qt::TopLeftCorner); if (auto action = d->currentPageActions.get(Actions::Close)) { d->closeTabButton->setDefaultAction(action); d->tabWidget->setCornerWidget(d->closeTabButton, Qt::TopRightCorner); } else { d->closeTabButton->setVisible(false); } d->actionsCreated = true; } QAbstractItemView *TabWidget::addView(const QString &title, const QString &id, const QString &text) { const KConfigGroup group = KSharedConfig::openConfig()->group(QString::asprintf("View #%u", d->tabWidget->count())); Page *page = new Page(title, id, text, nullptr, QString(), nullptr, group); return d->addView(page, d->currentPage()); } QAbstractItemView *TabWidget::addView(const KConfigGroup &group) { return d->addView(new Page(group), nullptr); } QAbstractItemView *TabWidget::addTemporaryView(const QString &title, AbstractKeyListSortFilterProxyModel *proxy, const QString &tabToolTip) { const KConfigGroup group = KSharedConfig::openConfig()->group("KeyTreeView_default"); Page *const page = new Page(title, QString(), QString(), proxy, tabToolTip, nullptr, group); page->setTemporary(true); QAbstractItemView *v = d->addView(page, d->currentPage()); d->tabWidget->setCurrentIndex(d->tabWidget->count() - 1); return v; } QTreeView *TabWidget::Private::addView(Page *page, Page *columnReference) { if (!page) { return nullptr; } if (!actionsCreated) { auto coll = new KActionCollection(q); q->createActions(coll); } page->setFlatModel(flatModel); page->setHierarchicalModel(hierarchicalModel); - connect(page, SIGNAL(titleChanged(QString)), q, SLOT(slotPageTitleChanged(QString))); - connect(page, SIGNAL(keyFilterChanged(std::shared_ptr)), q, SLOT(slotPageKeyFilterChanged(std::shared_ptr))); - connect(page, SIGNAL(stringFilterChanged(QString)), q, SLOT(slotPageStringFilterChanged(QString))); - connect(page, SIGNAL(hierarchicalChanged(bool)), q, SLOT(slotPageHierarchyChanged(bool))); + connect(page, &Page::titleChanged, q, [this](const QString &text) { slotPageTitleChanged(text); }); + connect(page, &Page::keyFilterChanged, q, [this](const std::shared_ptr &filter) { slotPageKeyFilterChanged(filter); }); + connect(page, &Page::stringFilterChanged, q, [this](const QString &text) { slotPageStringFilterChanged(text); }); + connect(page, &Page::hierarchicalChanged, q, [this](bool on) { slotPageHierarchyChanged(on); }); if (columnReference) { page->setColumnSizes(columnReference->columnSizes()); page->setSortColumn(columnReference->sortColumn(), columnReference->sortOrder()); } QAbstractItemView *const previous = q->currentView(); const int tabIndex = tabWidget->addTab(page, page->title()); setTabOrder(closeTabButton, page->view()); tabWidget->setTabToolTip(tabIndex, page->toolTip()); // work around a bug in QTabWidget (tested with 4.3.2) not emitting currentChanged() when the first widget is inserted QAbstractItemView *const current = q->currentView(); if (previous != current) { currentIndexChanged(tabWidget->currentIndex()); } enableDisableCurrentPageActions(); QTreeView *view = page->view(); Q_EMIT q->viewAdded(view); return view; } static QStringList extractViewGroups(const KConfig *config) { return config ? config->groupList().filter(QRegularExpression(QStringLiteral("^View #\\d+$"))) : QStringList(); } // work around deleteGroup() not deleting groups out of groupList(): static const bool KCONFIG_DELETEGROUP_BROKEN = true; void TabWidget::loadViews(const KConfig *config) { if (config) { QStringList groupList = extractViewGroups(config); groupList.sort(); for (const QString &group : std::as_const(groupList)) { const KConfigGroup kcg(config, group); if (!KCONFIG_DELETEGROUP_BROKEN || kcg.readEntry("magic", 0U) == 0xFA1AFE1U) { addView(kcg); } } } if (!count()) { // add default view: addView(i18n("All Certificates"), QStringLiteral("all-certificates")); } } void TabWidget::saveViews(KConfig *config) const { if (!config) { return; } const auto extraView{extractViewGroups(config)}; for (const QString &group : extraView) { config->deleteGroup(group); } unsigned int vg = 0; for (unsigned int i = 0, end = count(); i != end; ++i) { if (const Page *const p = d->page(i)) { if (p->isTemporary()) { continue; } KConfigGroup group(config, QString::asprintf("View #%u", vg++)); p->saveTo(group); if (KCONFIG_DELETEGROUP_BROKEN) { group.writeEntry("magic", 0xFA1AFE1U); } } } } -static void xconnect(const QObject *o1, const char *signal, const QObject *o2, const char *slot) +void TabWidget::connectSearchBar(SearchBar *sb) { - QObject::connect(o1, signal, o2, slot); - QObject::connect(o2, signal, o1, slot); -} + connect(sb, &SearchBar::stringFilterChanged, this, &TabWidget::setStringFilter); + connect(this, &TabWidget::stringFilterChanged, sb, &SearchBar::setStringFilter); -void TabWidget::connectSearchBar(QObject *sb) -{ - xconnect(sb, SIGNAL(stringFilterChanged(QString)), - this, SLOT(setStringFilter(QString))); - xconnect(sb, SIGNAL(keyFilterChanged(std::shared_ptr)), - this, SLOT(setKeyFilter(std::shared_ptr))); - connect(this, SIGNAL(enableChangeStringFilter(bool)), - sb, SLOT(setChangeStringFilterEnabled(bool))); - connect(this, SIGNAL(enableChangeKeyFilter(bool)), - sb, SLOT(setChangeKeyFilterEnabled(bool))); + connect(sb, &SearchBar::keyFilterChanged, this, &TabWidget::setKeyFilter); + connect(this, &TabWidget::keyFilterChanged, sb, &SearchBar::setKeyFilter); + + connect(this, &TabWidget::enableChangeStringFilter, sb, &SearchBar::setChangeStringFilterEnabled); + connect(this, &TabWidget::enableChangeKeyFilter, sb, &SearchBar::setChangeKeyFilterEnabled); } #include "moc_tabwidget.cpp" #include "tabwidget.moc" diff --git a/src/view/tabwidget.h b/src/view/tabwidget.h index da4db7cc9..d135f991d 100644 --- a/src/view/tabwidget.h +++ b/src/view/tabwidget.h @@ -1,102 +1,98 @@ /* -*- mode: c++; c-basic-offset:4 -*- view/tabwidget.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include #include #include class QAbstractItemView; class KConfigGroup; class KActionCollection; class KConfig; namespace Kleo { class AbstractKeyListModel; class AbstractKeyListSortFilterProxyModel; class KeyFilter; class KeyListModelInterface; +class SearchBar; class TabWidget : public QWidget { Q_OBJECT public: explicit TabWidget(QWidget *parent = nullptr, Qt::WindowFlags f = {}); ~TabWidget() override; void setFlatModel(AbstractKeyListModel *model); AbstractKeyListModel *flatModel() const; void setHierarchicalModel(AbstractKeyListModel *model); AbstractKeyListModel *hierarchicalModel() const; QAbstractItemView *addView(const QString &title = QString(), const QString &keyFilterID = QString(), const QString &searchString = QString()); QAbstractItemView *addView(const KConfigGroup &group); QAbstractItemView *addTemporaryView(const QString &title = QString(), AbstractKeyListSortFilterProxyModel *proxy = nullptr, const QString &tabToolTip = QString()); void loadViews(const KConfig *cfg); void saveViews(KConfig *cfg) const; std::vector views() const; QAbstractItemView *currentView() const; KeyListModelInterface *currentModel() const; unsigned int count() const; void createActions(KActionCollection *collection); - void connectSearchBar(QObject *sb); + void connectSearchBar(SearchBar *sb); void setMultiSelection(bool on); QString stringFilter() const; public Q_SLOTS: void setKeyFilter(const std::shared_ptr &filter); void setStringFilter(const QString &filter); Q_SIGNALS: void viewAdded(QAbstractItemView *view); void viewAboutToBeRemoved(QAbstractItemView *view); void currentViewChanged(QAbstractItemView *view); void stringFilterChanged(const QString &filter); void keyFilterChanged(const std::shared_ptr &filter); void enableChangeStringFilter(bool enable); void enableChangeKeyFilter(bool enable); private: class Private; kdtools::pimpl_ptr d; - Q_PRIVATE_SLOT(d, void currentIndexChanged(int)) - Q_PRIVATE_SLOT(d, void slotPageTitleChanged(const QString &)) - Q_PRIVATE_SLOT(d, void slotPageKeyFilterChanged(const std::shared_ptr &)) - Q_PRIVATE_SLOT(d, void slotPageStringFilterChanged(const QString &)) - Q_PRIVATE_SLOT(d, void slotPageHierarchyChanged(bool)) Q_PRIVATE_SLOT(d, void slotRenameCurrentTab()) Q_PRIVATE_SLOT(d, void slotNewTab()) Q_PRIVATE_SLOT(d, void slotDuplicateCurrentTab()) Q_PRIVATE_SLOT(d, void slotCloseCurrentTab()) Q_PRIVATE_SLOT(d, void slotMoveCurrentTabLeft()) Q_PRIVATE_SLOT(d, void slotMoveCurrentTabRight()) Q_PRIVATE_SLOT(d, void slotToggleHierarchicalView(bool)) Q_PRIVATE_SLOT(d, void slotExpandAll()) Q_PRIVATE_SLOT(d, void slotCollapseAll()) }; }