diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index bc267b34b..38defd940 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -1,1003 +1,1003 @@
 /* -*- 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 <config-kleopatra.h>
 
 #include "aboutdata.h"
 #include "kleopatraapplication.h"
 #include "mainwindow.h"
 #include "settings.h"
 
 #include <interfaces/focusfirstchild.h>
 
 #include "view/keycacheoverlay.h"
 #include "view/keylistcontroller.h"
 #include "view/padwidget.h"
 #include "view/searchbar.h"
 #include "view/smartcardwidget.h"
 #include "view/tabwidget.h"
 #include "view/welcomewidget.h"
 
 #include "commands/decryptverifyfilescommand.h"
 #include "commands/importcertificatefromfilecommand.h"
 #include "commands/importcrlcommand.h"
 #include "commands/selftestcommand.h"
 #include "commands/signencryptfilescommand.h"
 
 #include "utils/action_data.h"
 #include "utils/clipboardmenu.h"
 #include "utils/detail_p.h"
 #include "utils/filedialog.h"
 #include "utils/gui-helper.h"
 #include "utils/keyexportdraghandler.h"
 #include "utils/userinfo.h"
 
 #include <Libkleo/GnuPG>
 
 #include "dialogs/debugdialog.h"
 #include "dialogs/updatenotification.h"
 
 // needed for GPGME_VERSION_NUMBER
 #include <gpgme.h>
 
 #include "kleopatra_debug.h"
 #include <KAboutApplicationDialog>
 #include <KAboutData>
 #include <KActionCollection>
 #include <KActionMenu>
 #include <KColorScheme>
 #include <KConfigDialog>
 #include <KConfigGroup>
 #include <KEditToolBar>
 #include <KHelpMenu>
 #include <KLocalizedString>
 #include <KMessageBox>
 #include <KShortcutsDialog>
 #include <KStandardAction>
 #include <KStandardGuiItem>
 #include <KToolBar>
 #include <KXMLGUIFactory>
 #include <QAction>
 #include <QApplication>
 #include <QLineEdit>
 #include <QSize>
 
 #include <QAbstractItemView>
 #include <QCloseEvent>
 #include <QDesktopServices>
 #include <QDir>
 #include <QLabel>
 #include <QMenu>
 #include <QMimeData>
 #include <QPixmap>
 #include <QProcess>
 #include <QSettings>
 #include <QStackedWidget>
 #include <QStatusBar>
 #include <QTimer>
 #include <QVBoxLayout>
 
 #include <Libkleo/Classify>
 #include <Libkleo/Compliance>
 #include <Libkleo/DocAction>
 #include <Libkleo/Formatting>
 #include <Libkleo/GnuPG>
 #include <Libkleo/KeyCache>
 #include <Libkleo/KeyListModel>
 #include <Libkleo/KeyListSortFilterProxyModel>
 #include <Libkleo/Stl_Util>
 #include <Libkleo/SystemInfo>
 
 #include <KSharedConfig>
 
 #ifdef Q_OS_UNIX
 #include <KWaylandExtras>
 #endif
 
 #include <chrono>
 #include <vector>
 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().displayName();
     KGuiItem item = KStandardGuiItem::quit();
     item.setText(xi18nc("@action:button", "&Quit <application>%1</application>", app));
     return item;
 }
 
 static KGuiItem KStandardGuiItem_close()
 {
     KGuiItem item = KStandardGuiItem::close();
     item.setText(i18nc("@action:button", "Only &Close Window"));
     return item;
 }
 
 static bool isQuitting = false;
 
 namespace
 {
 static const std::vector<QString> mainViewActionNames = {
     QStringLiteral("view_certificate_overview"),
     QStringLiteral("manage_smartcard"),
     QStringLiteral("pad_view"),
 };
 
 class CertificateView : public QWidget, public FocusFirstChild
 {
     Q_OBJECT
 public:
     CertificateView(QWidget *parent = nullptr)
         : QWidget{parent}
         , ui{this}
     {
     }
 
     SearchBar *searchBar() const
     {
         return ui.searchBar;
     }
 
     TabWidget *tabWidget() const
     {
         return ui.tabWidget;
     }
 
     void focusFirstChild(Qt::FocusReason reason) override
     {
         ui.searchBar->lineEdit()->setFocus(reason);
     }
 
 private:
     struct UI {
         TabWidget *tabWidget = nullptr;
         SearchBar *searchBar = nullptr;
         explicit UI(CertificateView *q)
         {
             auto vbox = new QVBoxLayout{q};
             vbox->setSpacing(0);
 
             searchBar = new SearchBar{q};
             vbox->addWidget(searchBar);
-            tabWidget = new TabWidget{q};
+            tabWidget = new TabWidget{KeyTreeView::Option::NoDefaultContextMenu, q};
             vbox->addWidget(tabWidget);
 
             tabWidget->connectSearchBar(searchBar);
         }
     } ui;
 };
 
 }
 
 class MainWindow::Private
 {
     friend class ::MainWindow;
     MainWindow *const q;
 
 public:
     explicit Private(MainWindow *qq);
     ~Private();
 
     template<typename T>
     void createAndStart()
     {
         (new T(this->currentView(), &this->controller))->start();
     }
     template<typename T>
     void createAndStart(QAbstractItemView *view)
     {
         (new T(view, &this->controller))->start();
     }
     template<typename T>
     void createAndStart(const QStringList &a)
     {
         (new T(a, this->currentView(), &this->controller))->start();
     }
     template<typename T>
     void createAndStart(const QStringList &a, QAbstractItemView *view)
     {
         (new T(a, view, &this->controller))->start();
     }
 
     void closeAndQuit()
     {
         if (Kleo::userIsElevated()) {
             // For users running Kleo with elevated permissions on Windows we
             // always quit the application to avoid some problems.
             qApp->quit();
         }
 
         const QString app = KAboutData::applicationData().displayName();
         const int rc = KMessageBox::questionTwoActionsCancel(q,
                                                              xi18n("<application>%1</application> may be used by other applications as a service.<nl/>"
                                                                    "You may instead want to close this window without exiting <application>%1</application>.",
                                                                    app),
                                                              i18nc("@title:window", "Really Quit?"),
                                                              KStandardGuiItem_close(),
                                                              KStandardGuiItem_quit(),
                                                              KStandardGuiItem::cancel(),
                                                              QLatin1StringView("really-quit-") + app.toLower());
         if (rc == KMessageBox::Cancel) {
             return;
         }
         isQuitting = rc == KMessageBox::ButtonCode::SecondaryAction;
         if (!q->close()) {
             return;
         }
         // WARNING: 'this' might be deleted at this point!
         if (rc == KMessageBox::ButtonCode::SecondaryAction) {
             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(QKeySequence::NativeText);
         ui.searchTab->searchBar()->updateClickMessage(shortcutStr);
     }
 
     void updateStatusBar()
     {
         auto statusBar = std::make_unique<QStatusBar>();
         auto settings = KleopatraApplication::instance()->distributionSettings();
         bool showStatusbar = false;
         if (settings) {
             const QString statusline = settings->value(QStringLiteral("statusline"), {}).toString();
             if (!statusline.isEmpty()) {
                 auto customStatusLbl = new QLabel(statusline);
                 statusBar->insertWidget(0, customStatusLbl);
                 showStatusbar = true;
             }
         }
         if (DeVSCompliance::isActive()) {
             auto statusLbl = std::make_unique<QLabel>(DeVSCompliance::name());
             if (!SystemInfo::isHighContrastModeActive()) {
                 const auto color = KColorScheme(QPalette::Active, KColorScheme::View)
                                        .foreground(DeVSCompliance::isCompliant() ? KColorScheme::NormalText : KColorScheme::NegativeText)
                                        .color();
                 const auto background = KColorScheme(QPalette::Active, KColorScheme::View)
                                             .background(DeVSCompliance::isCompliant() ? 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());
             showStatusbar = true;
         }
 
         if (showStatusbar) {
             q->setStatusBar(statusBar.release()); // QMainWindow takes ownership
         } else {
             q->setStatusBar(nullptr);
         }
     }
 
     void selfTest()
     {
         createAndStart<SelfTestCommand>();
     }
 
     void configureGroups()
     {
         // open groups config dialog as independent top-level window
         KleopatraApplication::instance()->openOrRaiseGroupsConfigDialog(nullptr);
     }
 
     void showHandbook();
 
     void gnupgLogViewer()
     {
         // Warning: Don't assume that the program needs to be in PATH. On Windows, it will also be found next to the calling process.
         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 slotConfigCommitted();
     void slotContextMenuRequested(QAbstractItemView *, const QPoint &p)
     {
         if (auto const menu = qobject_cast<QMenu *>(q->factory()->container(QStringLiteral("listview_popup"), q))) {
             menu->exec(p);
         } else {
             qCDebug(KLEOPATRA_LOG) << "no \"listview_popup\" <Menu> in kleopatra's ui.rc file";
         }
     }
 
     void slotFocusQuickSearch()
     {
         ui.searchTab->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);
         if (auto ffci = dynamic_cast<Kleo::FocusFirstChild *>(widget)) {
             ffci->focusFirstChild(Qt::TabFocusReason);
         }
     }
 
     void showCertificateView()
     {
         if (KeyCache::instance()->keys().empty()) {
             showView(QStringLiteral("view_certificate_overview"), ui.welcomeWidget);
         } else {
             showView(QStringLiteral("view_certificate_overview"), 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 restartDaemons()
     {
         Kleo::restartGpgAgent();
     }
 
     void showAboutDialog()
     {
         // we show the About dialog ourselves so that we can pass up-to-date about data to it;
         // KXmlGuiWindow takes a copy of the about data on creation and this copy might not
         // contain the backend version information that's set by a background thread
         if (!aboutDialog) {
             qCDebug(KLEOPATRA_LOG) << __func__ << "Creating About dialog";
             aboutDialog = new KAboutApplicationDialog(KAboutData::applicationData(), q);
             aboutDialog->setAttribute(Qt::WA_DeleteOnClose);
         }
         if (aboutDialog->isMinimized()) {
             qCDebug(KLEOPATRA_LOG) << __func__ << "Unminimizing About dialog";
             aboutDialog->setWindowState((aboutDialog->windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
         }
         qCDebug(KLEOPATRA_LOG) << __func__ << "Showing About dialog";
         aboutDialog->show();
     }
 
 private:
     void setupActions();
 
     QAbstractItemView *currentView() const
     {
         return ui.searchTab->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 {
         CertificateView *searchTab = nullptr;
         PadWidget *padWidget = nullptr;
         SmartCardWidget *scWidget = nullptr;
         WelcomeWidget *welcomeWidget = nullptr;
         QStackedWidget *stackWidget = nullptr;
         explicit UI(MainWindow *q);
     } ui;
     QAction *focusToClickSearchAction = nullptr;
     ClipboardMenu *clipboadMenu = nullptr;
     QPointer<KAboutApplicationDialog> aboutDialog;
 };
 
 MainWindow::Private::UI::UI(MainWindow *q)
     : padWidget(nullptr)
 {
     auto mainWidget = new QWidget{q};
     auto mainLayout = new QVBoxLayout(mainWidget);
     mainLayout->setContentsMargins({});
     stackWidget = new QStackedWidget{q};
 
     searchTab = new CertificateView{q};
     stackWidget->addWidget(searchTab);
 
     new KeyCacheOverlay(mainWidget, q);
 
     scWidget = new SmartCardWidget{q};
     stackWidget->addWidget(scWidget);
 
     welcomeWidget = new WelcomeWidget{q};
     stackWidget->addWidget(welcomeWidget);
 
     mainLayout->addWidget(stackWidget);
 
     q->setCentralWidget(mainWidget);
 }
 
 MainWindow::Private::Private(MainWindow *qq)
     : q(qq)
     , controller(q)
     , firstShow(true)
     , ui(q)
 {
     Q_SET_OBJECT_NAME(controller);
 
     AbstractKeyListModel *flatModel = AbstractKeyListModel::createFlatKeyListModel(q);
     AbstractKeyListModel *hierarchicalModel = AbstractKeyListModel::createHierarchicalKeyListModel(q);
 
     Q_SET_OBJECT_NAME(flatModel);
     Q_SET_OBJECT_NAME(hierarchicalModel);
 
 #if GPGME_VERSION_NUMBER >= 0x011800 // 1.24.0
     auto keyExportDragHandler = std::make_shared<KeyExportDragHandler>();
     flatModel->setDragHandler(keyExportDragHandler);
     hierarchicalModel->setDragHandler(keyExportDragHandler);
 #endif
 
     controller.setFlatModel(flatModel);
     controller.setHierarchicalModel(hierarchicalModel);
     controller.setTabWidget(ui.searchTab->tabWidget());
 
     ui.searchTab->tabWidget()->setFlatModel(flatModel);
     ui.searchTab->tabWidget()->setHierarchicalModel(hierarchicalModel);
 
 #ifdef Q_OS_UNIX
     connect(KWaylandExtras::self(), &KWaylandExtras::windowExported, q, [this](const auto &window, const auto &token) {
         if (window == q->windowHandle()) {
             qputenv("PINENTRY_GEOM_HINT", QUrl::toPercentEncoding(token));
         }
     });
     q->exportWindow();
 #endif
 
     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"));
 
     if (auto helpMenu = q->findChild<KHelpMenu *>()) {
         qCDebug(KLEOPATRA_LOG) << "Hook into the help menu to show the About dialog ourselves";
         connect(helpMenu, &KHelpMenu::showAboutApplication, q, [this]() {
             showAboutDialog();
         });
     }
 
     // make toolbar buttons accessible by keyboard
     auto toolbar = q->findChild<KToolBar *>();
     if (toolbar) {
         auto toolbarButtons = toolbar->findChildren<QToolButton *>();
         for (auto b : toolbarButtons) {
             b->setFocusPolicy(Qt::TabFocus);
         }
         // move toolbar and its child widgets before the central widget in the tab order;
         // this is necessary to make Shift+Tab work as expected
         forceSetTabOrder(q, toolbar);
         auto toolbarChildren = toolbar->findChildren<QWidget *>();
         std::for_each(std::rbegin(toolbarChildren), std::rend(toolbarChildren), [toolbar](auto w) {
             forceSetTabOrder(toolbar, w);
         });
     }
 
     if (auto action = q->actionCollection()->action(QStringLiteral("help_whats_this"))) {
         delete action;
     }
 
     q->setAcceptDrops(true);
 
     // set default window size
     q->resize(QSize(1024, 500));
     q->setAutoSaveSettings();
 
     updateSearchBarClickMessage();
     updateStatusBar();
 
     if (KeyCache::instance()->initialized()) {
         keyListingDone();
     }
 
     // delay setting the models to use the key cache so that the UI (including
     // the "Loading certificate cache..." overlay) is shown before the
     // blocking key cache initialization happens
     QMetaObject::invokeMethod(
         q,
         [flatModel, hierarchicalModel]() {
             flatModel->useKeyCache(true, KeyList::AllKeys);
             hierarchicalModel->useKeyCache(true, KeyList::AllKeys);
         },
         Qt::QueuedConnection);
 }
 
 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> action_data = {
     // see keylistcontroller.cpp for more actions
     // Tools menu
 #ifndef Q_OS_WIN
         {
             "tools_start_kwatchgnupg",
             i18n("GnuPG Log Viewer"),
             QString(),
             "kwatchgnupg",
             q,
             [this](bool) {
                 gnupgLogViewer();
             },
             QString(),
         },
 #endif
         {
             "tools_debug_view",
             i18n("Debug View"),
             QString(),
             "",
             q,
             [this](bool) {
                 auto dialog = new DebugDialog(q);
                 dialog->setAttribute(Qt::WA_DeleteOnClose);
                 dialog->open();
             },
             QString(),
         },
         {
             "tools_restart_backend",
             i18nc("@action:inmenu", "Restart Background Processes"),
             i18nc("@info:tooltip", "Restart the background processes, e.g. after making changes to the configuration."),
             "view-refresh",
             q,
             [this](bool) {
                 restartDaemons();
             },
             {},
         },
     // Help menu
 #ifdef Q_OS_WIN
         {
             "help_check_updates",
             i18n("Check for updates"),
             QString(),
             "gpg4win-compact",
             q,
             [this](bool) {
                 forceUpdateCheck();
             },
             QString(),
         },
 #endif
         // View menu
         {
             "view_certificate_overview",
             i18nc("@action show certificate overview", "Certificates"),
             i18n("Show certificate overview"),
             "view-certificate",
             q,
             [this](bool) {
                 showCertificateView();
             },
             QString(),
         },
         {
             "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,
             [this](bool) {
                 showPadView();
             },
             QString(),
         },
         {
             "manage_smartcard",
             i18nc("@action show smartcard management view", "Smartcards"),
             i18n("Show smartcard management"),
             "auth-sim-locked",
             q,
             [this](bool) {
                 showSmartcardView();
             },
             QString(),
         },
         // Settings menu
         {
             "settings_self_test",
             i18n("Perform Self-Test"),
             QString(),
             nullptr,
             q,
             [this](bool) {
                 selfTest();
             },
             QString(),
         },
         {
             "configure_groups",
             i18n("Configure Groups..."),
             QString(),
             "group",
             q,
             [this](bool) {
                 configureGroups();
             },
             QString(),
         },
         // Toolbar
         {
             "configure_groups_toolbar",
             i18nc("@action:intoolbar", "Groups"),
             QString(),
             "group",
             q,
             [this](bool) {
                 configureGroups();
             },
             QString(),
         }};
 
     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);
         }
     }
 
     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(i18nc("@action", "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"),
                                           QUrl(),
                                           coll);
     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 quickguide =
         new DocAction(QIcon::fromTheme(QStringLiteral("help-contextual")),
                       i18n("&Quick Guide Encrypt and Sign"),
                       i18nc("Only available in German and English. Leave to English for other languages.", "encrypt_and_sign_gnupgvsd_en.pdf"),
                       QStringLiteral("../share/doc/gnupg-vsd"),
                       QUrl(),
                       coll);
     coll->addAction(QStringLiteral("help_doc_quickguide"), quickguide);
 
     const auto symguide =
         new DocAction(QIcon::fromTheme(QStringLiteral("help-contextual")),
                       i18n("&Password-based Encryption"),
                       i18nc("Only available in German and English. Leave to English for other languages.", "symmetric_encryption_gnupgvsd_en.pdf"),
                       QStringLiteral("../share/doc/gnupg-vsd"),
                       QUrl(),
                       coll);
     coll->addAction(QStringLiteral("help_doc_symenc"), symguide);
 
     const auto groups = new DocAction(QIcon::fromTheme(QStringLiteral("help-contextual")),
                                       i18n("Certificate &Groups"),
                                       i18nc("Only available in German and English. Leave to English for other languages.", "groupfeature_gnupgvsd_en.pdf"),
                                       QStringLiteral("../share/doc/gnupg-vsd"),
                                       QUrl(),
                                       coll);
     coll->addAction(QStringLiteral("help_doc_groups"), groups);
 
 #ifdef Q_OS_WIN
     const auto gpgol =
         new DocAction(QIcon::fromTheme(QStringLiteral("help-contextual")),
                       i18n("&Mail Encryption in Outlook"),
                       i18nc("Only available in German and English. Leave to English for other languages. Only shown on Windows.", "gpgol_outlook_addin_en.pdf"),
                       QStringLiteral("../share/doc/gnupg-vsd"),
                       QUrl(),
                       coll);
     coll->addAction(QStringLiteral("help_doc_gpgol"), gpgol);
 #endif
 
     /* The submenu with advanced topics */
     const auto certmngmnt =
         new DocAction(QIcon::fromTheme(QStringLiteral("help-contextual")),
                       i18n("&Certification Management"),
                       i18nc("Only available in German and English. Leave to English for other languages.", "certification_management_gnupgvsd_en.pdf"),
                       QStringLiteral("../share/doc/gnupg-vsd"),
                       QUrl(),
                       coll);
     coll->addAction(QStringLiteral("help_doc_cert_management"), certmngmnt);
 
     const auto smartcard =
         new DocAction(QIcon::fromTheme(QStringLiteral("help-contextual")),
                       i18n("&Smartcard Setup"),
                       i18nc("Only available in German and English. Leave to English for other languages.", "smartcard_setup_gnupgvsd_en.pdf"),
                       QStringLiteral("../share/doc/gnupg-vsd"),
                       QUrl(),
                       coll);
     coll->addAction(QStringLiteral("help_doc_smartcard"), smartcard);
 
     const auto man_gnupg = new DocAction(QIcon::fromTheme(QStringLiteral("help-contextual")),
                                          i18n("GnuPG Command&line"),
                                          QStringLiteral("gnupg_manual_en.pdf"),
                                          QStringLiteral("../share/doc/gnupg-vsd"),
                                          QUrl(QStringLiteral("https://gnupg.org/documentation/manuals/gnupg/")),
                                          coll);
     coll->addAction(QStringLiteral("help_doc_gnupg"), man_gnupg);
 
     /* The secops */
     const auto approvalmanual =
         new DocAction(QIcon::fromTheme(QStringLiteral("dvipdf")),
                       i18n("Manual for VS-NfD Approval (German)"),
                       i18nc("Only available in German. Keep German file name for all languages", "Handbuch-Zulassung-gnupgvsd-v3.2.pdf"),
                       QStringLiteral("../share/doc/gnupg-vsd"),
                       QUrl(),
                       coll);
     coll->addAction(QStringLiteral("help_doc_approval_manual"), approvalmanual);
 
     const auto vsa10573 =
         new DocAction(QIcon::fromTheme(QStringLiteral("dvipdf")),
                       i18n("SecOps VSA-10573"),
                       i18nc("Only available in German and English. Leave to English for other languages.", "BSI-VSA-10573-ENG_secops-20220207.pdf"),
                       QStringLiteral("../share/doc/gnupg-vsd"),
                       QUrl(),
                       coll);
     coll->addAction(QStringLiteral("help_doc_vsa10573"), vsa10573);
 
     const auto vsa10584 =
         new DocAction(QIcon::fromTheme(QStringLiteral("dvipdf")),
                       i18n("SecOps VSA-10584"),
                       i18nc("Only available in German and English. Leave to English for other languages.", "BSI-VSA-10584-ENG_secops-20220207.pdf"),
                       QStringLiteral("../share/doc/gnupg-vsd"),
                       QUrl(),
                       coll);
     coll->addAction(QStringLiteral("help_doc_vsa10584"), vsa10584);
 
     q->setStandardToolBarMenuEnabled(true);
 
     controller.createActions(coll);
 
     ui.searchTab->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);
         }
     }
     unexportWindow();
     if (isQuitting || qApp->isSavingSession() || Kleo::userIsElevated()) {
         d->ui.searchTab->tabWidget()->saveViews();
         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.searchTab->tabWidget()->loadViews(KSharedConfig::openStateConfig(), QStringLiteral("KeyList"));
         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<ImportCertificateFromFileCommand>(files);
     }
 }
 
 static QStringList extract_local_files(const QMimeData *data)
 {
     const QList<QUrl> urls = data->urls();
     // begin workaround KDE/Qt misinterpretation of text/uri-list
     QList<QUrl>::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());
 
     KleopatraApplication::instance()->handleFiles(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());
 }
 
 void MainWindow::exportWindow()
 {
 #ifdef Q_OS_UNIX
     (void)winId(); // Ensures that windowHandle() returns the window
     KWaylandExtras::self()->exportWindow(windowHandle());
 #endif
 }
 
 void MainWindow::unexportWindow()
 {
 #ifdef Q_OS_UNIX
     KWaylandExtras::self()->unexportWindow(windowHandle());
 #endif
 }
 
 KeyListController *MainWindow::keyListController()
 {
     return &d->controller;
 }
 
 #include "mainwindow.moc"
 #include "moc_mainwindow.cpp"
diff --git a/src/view/keytreeview.cpp b/src/view/keytreeview.cpp
index 8a0ab79c6..b5bc9e215 100644
--- a/src/view/keytreeview.cpp
+++ b/src/view/keytreeview.cpp
@@ -1,677 +1,698 @@
 /* -*- mode: c++; c-basic-offset:4 -*-
     view/keytreeview.cpp
 
     This file is part of Kleopatra, the KDE keymanager
     SPDX-FileCopyrightText: 2009 Klarälvdalens Datakonsult AB
 
     SPDX-License-Identifier: GPL-2.0-or-later
 */
 
 #include <config-kleopatra.h>
 
 #include "keytreeview.h"
 #include "searchbar.h"
 
 #include <Libkleo/KeyList>
 #include <Libkleo/KeyListModel>
 #include <Libkleo/KeyListSortFilterProxyModel>
 #include <Libkleo/KeyRearrangeColumnsProxyModel>
 #include <Libkleo/Predicates>
 #include <Libkleo/TreeView>
 
 #include "utils/headerview.h"
 #include "utils/tags.h"
 
 #include <Libkleo/KeyCache>
 #include <Libkleo/KeyFilter>
 #include <Libkleo/Stl_Util>
 
 #include <gpgme++/key.h>
 
 #include "kleopatra_debug.h"
 #include <QAction>
 #include <QClipboard>
 #include <QContextMenuEvent>
 #include <QEvent>
 #include <QGuiApplication>
 #include <QHeaderView>
 #include <QItemSelection>
 #include <QItemSelectionModel>
 #include <QLayout>
 #include <QList>
 #include <QMenu>
 #include <QTimer>
 
 #include <KLocalizedString>
 #include <KSharedConfig>
+#include <KStandardAction>
+#include <qnamespace.h>
 
 static int tagsColumn;
 
 using namespace Kleo;
 using namespace GpgME;
 
 Q_DECLARE_METATYPE(GpgME::Key)
 
 namespace
 {
 
 class TreeViewInternal : public Kleo::TreeView
 {
 public:
     explicit TreeViewInternal(QWidget *parent = nullptr)
         : Kleo::TreeView{parent}
     {
         connect(this, &TreeView::columnEnabled, this, [this](int column) {
             if (column == tagsColumn) {
                 Tags::enableTags();
             }
         });
     }
 
     QSize minimumSizeHint() const override
     {
         const QSize min = QTreeView::minimumSizeHint();
         return QSize(min.width(), min.height() + 5 * fontMetrics().height());
     }
 
 protected:
     void focusInEvent(QFocusEvent *event) override
     {
         QTreeView::focusInEvent(event);
         // queue the invokation, so that it happens after the widget itself got focus
         QMetaObject::invokeMethod(this, &TreeViewInternal::forceAccessibleFocusEventForCurrentItem, Qt::QueuedConnection);
     }
 
 private:
     void forceAccessibleFocusEventForCurrentItem()
     {
         // force Qt to send a focus event for the current item to accessibility
         // tools; otherwise, the user has no idea which item is selected when the
         // list gets keyboard input focus
         const auto current = currentIndex();
         setCurrentIndex({});
         setCurrentIndex(current);
     }
 
 private:
     QMenu *mHeaderPopup = nullptr;
 
     QList<QAction *> mColumnActions;
 };
 
 const KeyListModelInterface *keyListModel(const QTreeView &view)
 {
     const KeyListModelInterface *const klmi = dynamic_cast<KeyListModelInterface *>(view.model());
     Q_ASSERT(klmi);
     return klmi;
 }
 
 } // anon namespace
 
 KeyTreeView::KeyTreeView(QWidget *parent)
     : QWidget(parent)
     , m_proxy(new KeyListSortFilterProxyModel(this))
     , m_additionalProxy(nullptr)
     , m_view(new TreeViewInternal(this))
     , m_flatModel(nullptr)
     , m_hierarchicalModel(nullptr)
     , m_stringFilter()
     , m_keyFilter()
     , m_isHierarchical(true)
+    , m_showDefaultContextMenu(true)
 {
     init();
 }
 
 KeyTreeView::KeyTreeView(const KeyTreeView &other)
     : QWidget(nullptr)
     , m_proxy(new KeyListSortFilterProxyModel(this))
     , m_additionalProxy(other.m_additionalProxy ? other.m_additionalProxy->clone() : nullptr)
     , m_view(new TreeViewInternal(this))
     , m_flatModel(other.m_flatModel)
     , m_hierarchicalModel(other.m_hierarchicalModel)
     , m_stringFilter(other.m_stringFilter)
     , m_keyFilter(other.m_keyFilter)
     , m_group(other.m_group)
     , m_isHierarchical(other.m_isHierarchical)
+    , m_showDefaultContextMenu(other.m_showDefaultContextMenu)
 {
     init();
     setColumnSizes(other.columnSizes());
     setSortColumn(other.sortColumn(), other.sortOrder());
 }
 
 KeyTreeView::KeyTreeView(const QString &text,
                          const std::shared_ptr<KeyFilter> &kf,
                          AbstractKeyListSortFilterProxyModel *proxy,
                          QWidget *parent,
-                         const KConfigGroup &group)
+                         const KConfigGroup &group,
+                         Options options)
     : QWidget(parent)
     , m_proxy(new KeyListSortFilterProxyModel(this))
     , m_additionalProxy(proxy)
     , m_view(new TreeViewInternal(this))
     , m_flatModel(nullptr)
     , m_hierarchicalModel(nullptr)
     , m_stringFilter(text)
     , m_keyFilter(kf)
     , m_group(group)
     , m_isHierarchical(true)
     , m_onceResized(false)
+    , m_showDefaultContextMenu(!(options & Option::NoDefaultContextMenu))
 {
     init();
 }
 
 void KeyTreeView::setColumnSizes(const std::vector<int> &sizes)
 {
     if (sizes.empty()) {
         return;
     }
     Q_ASSERT(m_view);
     Q_ASSERT(m_view->header());
     Q_ASSERT(qobject_cast<HeaderView *>(m_view->header()) == static_cast<HeaderView *>(m_view->header()));
     if (auto const hv = static_cast<HeaderView *>(m_view->header())) {
         hv->setSectionSizes(sizes);
     }
 }
 
 void KeyTreeView::setSortColumn(int sortColumn, Qt::SortOrder sortOrder)
 {
     Q_ASSERT(m_view);
     m_view->sortByColumn(sortColumn, sortOrder);
 }
 
 int KeyTreeView::sortColumn() const
 {
     Q_ASSERT(m_view);
     Q_ASSERT(m_view->header());
     return m_view->header()->sortIndicatorSection();
 }
 
 Qt::SortOrder KeyTreeView::sortOrder() const
 {
     Q_ASSERT(m_view);
     Q_ASSERT(m_view->header());
     return m_view->header()->sortIndicatorOrder();
 }
 
 std::vector<int> KeyTreeView::columnSizes() const
 {
     Q_ASSERT(m_view);
     Q_ASSERT(m_view->header());
     Q_ASSERT(qobject_cast<HeaderView *>(m_view->header()) == static_cast<HeaderView *>(m_view->header()));
     if (auto const hv = static_cast<HeaderView *>(m_view->header())) {
         return hv->sectionSizes();
     } else {
         return std::vector<int>();
     }
 }
 
 void KeyTreeView::restoreLayout(const KConfigGroup &group)
 {
     if (!group.isValid() || !m_view->restoreColumnLayout(group.name())) {
         // if config is empty then use default settings
         // The numbers have to be in line with the order in
         // setsSourceColumns above
         m_view->hideColumn(5);
 
         for (int i = 7; i < m_view->model()->columnCount(); ++i) {
             m_view->hideColumn(i);
         }
         if (KeyCache::instance()->initialized()) {
             QTimer::singleShot(0, this, &KeyTreeView::initializeColumnSizes);
         }
     } else {
         m_onceResized = true;
     }
     if (!m_view->isColumnHidden(tagsColumn)) {
         Tags::enableTags();
     }
 }
 
 void KeyTreeView::init()
 {
     Q_SET_OBJECT_NAME(m_proxy);
     Q_SET_OBJECT_NAME(m_view);
 
     if (m_group.isValid()) {
         // Reopen as non const
         KConfig *conf = m_group.config();
         m_group = conf->group(m_group.name());
     }
 
     if (m_additionalProxy && m_additionalProxy->objectName().isEmpty()) {
         Q_SET_OBJECT_NAME(m_additionalProxy);
     }
     QLayout *layout = new QVBoxLayout(this);
     Q_SET_OBJECT_NAME(layout);
     layout->setContentsMargins(0, 0, 0, 0);
     layout->addWidget(m_view);
 
     auto headerView = new HeaderView(Qt::Horizontal);
     Q_SET_OBJECT_NAME(headerView);
     headerView->installEventFilter(m_view);
     headerView->setSectionsMovable(true);
     m_view->setHeader(headerView);
 
     m_view->setSelectionBehavior(QAbstractItemView::SelectRows);
     m_view->setSelectionMode(QAbstractItemView::ExtendedSelection);
     m_view->setAllColumnsShowFocus(false);
     m_view->setSortingEnabled(true);
     m_view->setAccessibleName(i18n("Certificates"));
     m_view->setAccessibleDescription(m_isHierarchical ? i18n("Hierarchical list of certificates") : i18n("List of certificates"));
     // we show details on double-click
     m_view->setExpandsOnDoubleClick(false);
 
+    if (m_showDefaultContextMenu) {
+        m_view->setContextMenuPolicy(Qt::CustomContextMenu);
+        connect(m_view, &KeyTreeView::customContextMenuRequested, this, [this](const auto &pos) {
+            auto menu = new QMenu;
+            menu->setAttribute(Qt::WA_DeleteOnClose, true);
+            menu->addAction(KStandardAction::copy(
+                this,
+                [this]() {
+                    QGuiApplication::clipboard()->setText(m_view->currentIndex().data(KeyList::ClipboardRole).toString());
+                },
+                this));
+            menu->popup(m_view->mapToGlobal(pos));
+        });
+    }
+
     if (model()) {
         if (m_additionalProxy) {
             m_additionalProxy->setSourceModel(model());
         } else {
             m_proxy->setSourceModel(model());
         }
     }
     if (m_additionalProxy) {
         m_proxy->setSourceModel(m_additionalProxy);
         if (!m_additionalProxy->parent()) {
             m_additionalProxy->setParent(this);
         }
     }
 
     m_proxy->setFilterRegularExpression(QRegularExpression::escape(m_stringFilter.trimmed()));
     m_proxy->setKeyFilter(m_keyFilter);
     m_proxy->setSortCaseSensitivity(Qt::CaseInsensitive);
 
     auto rearangingModel = new KeyRearrangeColumnsProxyModel(this);
     rearangingModel->setSourceModel(m_proxy);
     QList<int> columns = {
         KeyList::PrettyName,
         KeyList::PrettyEMail,
         KeyList::Validity,
         KeyList::ValidFrom,
         KeyList::ValidUntil,
         KeyList::TechnicalDetails,
         KeyList::KeyID,
         KeyList::Fingerprint,
         KeyList::OwnerTrust,
         KeyList::Origin,
         KeyList::LastUpdate,
         KeyList::Issuer,
         KeyList::SerialNumber,
         KeyList::Remarks,
         KeyList::Algorithm,
         KeyList::Keygrip,
     };
     tagsColumn = columns.indexOf(KeyList::Remarks);
     rearangingModel->setSourceColumns(columns);
     m_view->setModel(rearangingModel);
 
     /* Handle expansion state */
     if (m_group.isValid()) {
         m_expandedKeys = m_group.readEntry("Expanded", QStringList());
     }
 
     connect(m_view, &QTreeView::expanded, this, [this](const QModelIndex &index) {
         if (!index.isValid()) {
             return;
         }
         const auto &key = index.data(KeyList::KeyRole).value<GpgME::Key>();
         if (key.isNull()) {
             return;
         }
         const auto fpr = QString::fromLatin1(key.primaryFingerprint());
 
         if (m_expandedKeys.contains(fpr)) {
             return;
         }
         m_expandedKeys << fpr;
         if (m_group.isValid()) {
             m_group.writeEntry("Expanded", m_expandedKeys);
         }
     });
 
     connect(m_view, &QTreeView::collapsed, this, [this](const QModelIndex &index) {
         if (!index.isValid()) {
             return;
         }
         const auto &key = index.data(KeyList::KeyRole).value<GpgME::Key>();
         if (key.isNull()) {
             return;
         }
         m_expandedKeys.removeAll(QString::fromLatin1(key.primaryFingerprint()));
         if (m_group.isValid()) {
             m_group.writeEntry("Expanded", m_expandedKeys);
         }
     });
 
     updateModelConnections(nullptr, model());
 }
 
 void KeyTreeView::restoreExpandState()
 {
     if (!KeyCache::instance()->initialized()) {
         qCWarning(KLEOPATRA_LOG) << "Restore expand state before keycache available. Aborting.";
         return;
     }
     for (const auto &fpr : std::as_const(m_expandedKeys)) {
         const KeyListModelInterface *const km = keyListModel(*m_view);
         if (!km) {
             qCWarning(KLEOPATRA_LOG) << "invalid model";
             return;
         }
         const auto key = KeyCache::instance()->findByFingerprint(fpr.toLatin1().constData());
         if (key.isNull()) {
             qCDebug(KLEOPATRA_LOG) << "Cannot find:" << fpr << "anymore in cache";
             m_expandedKeys.removeAll(fpr);
             return;
         }
         const auto idx = km->index(key);
         if (!idx.isValid()) {
             qCDebug(KLEOPATRA_LOG) << "Cannot find:" << fpr << "anymore in model";
             m_expandedKeys.removeAll(fpr);
             return;
         }
         m_view->expand(idx);
     }
 }
 
 void KeyTreeView::setUpTagKeys()
 {
     const auto tagKeys = Tags::tagKeys();
     if (m_hierarchicalModel) {
         m_hierarchicalModel->setRemarkKeys(tagKeys);
     }
     if (m_flatModel) {
         m_flatModel->setRemarkKeys(tagKeys);
     }
 }
 
 KeyTreeView::~KeyTreeView() = default;
 
 static QAbstractProxyModel *find_last_proxy(QAbstractProxyModel *pm)
 {
     Q_ASSERT(pm);
     while (auto const sm = qobject_cast<QAbstractProxyModel *>(pm->sourceModel())) {
         pm = sm;
     }
     return pm;
 }
 
 void KeyTreeView::updateModelConnections(AbstractKeyListModel *oldModel, AbstractKeyListModel *newModel)
 {
     if (oldModel == newModel) {
         return;
     }
     if (oldModel) {
         disconnect(oldModel, &QAbstractItemModel::modelAboutToBeReset, this, &KeyTreeView::saveStateBeforeModelChange);
         disconnect(oldModel, &QAbstractItemModel::modelReset, this, &KeyTreeView::restoreStateAfterModelChange);
         disconnect(oldModel, &QAbstractItemModel::rowsAboutToBeInserted, this, &KeyTreeView::saveStateBeforeModelChange);
         disconnect(oldModel, &QAbstractItemModel::rowsInserted, this, &KeyTreeView::restoreStateAfterModelChange);
         disconnect(oldModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &KeyTreeView::saveStateBeforeModelChange);
         disconnect(oldModel, &QAbstractItemModel::rowsRemoved, this, &KeyTreeView::restoreStateAfterModelChange);
     }
     if (newModel) {
         connect(newModel, &QAbstractItemModel::modelAboutToBeReset, this, &KeyTreeView::saveStateBeforeModelChange);
         connect(newModel, &QAbstractItemModel::modelReset, this, &KeyTreeView::restoreStateAfterModelChange);
         connect(newModel, &QAbstractItemModel::rowsAboutToBeInserted, this, &KeyTreeView::saveStateBeforeModelChange);
         connect(newModel, &QAbstractItemModel::rowsInserted, this, &KeyTreeView::restoreStateAfterModelChange);
         connect(newModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &KeyTreeView::saveStateBeforeModelChange);
         connect(newModel, &QAbstractItemModel::rowsRemoved, this, &KeyTreeView::restoreStateAfterModelChange);
     }
 }
 
 void KeyTreeView::setFlatModel(AbstractKeyListModel *model)
 {
     if (model == m_flatModel) {
         return;
     }
     auto oldModel = m_flatModel;
     m_flatModel = model;
     if (!m_isHierarchical)
     // TODO: this fails when called after setHierarchicalView( false )...
     {
         find_last_proxy(m_proxy)->setSourceModel(model);
         updateModelConnections(oldModel, model);
     }
 }
 
 void KeyTreeView::setHierarchicalModel(AbstractKeyListModel *model)
 {
     if (model == m_hierarchicalModel) {
         return;
     }
     auto oldModel = m_hierarchicalModel;
     m_hierarchicalModel = model;
     if (m_isHierarchical) {
         find_last_proxy(m_proxy)->setSourceModel(model);
         updateModelConnections(oldModel, model);
         m_view->expandAll();
         for (int column = 0; column < m_view->header()->count(); ++column) {
             m_view->header()->resizeSection(column, qMax(m_view->header()->sectionSize(column), m_view->header()->sectionSizeHint(column)));
         }
     }
 }
 
 void KeyTreeView::setStringFilter(const QString &filter)
 {
     if (filter == m_stringFilter) {
         return;
     }
     m_stringFilter = filter;
     m_proxy->setFilterRegularExpression(QRegularExpression::escape(filter.trimmed()));
     Q_EMIT stringFilterChanged(filter);
 }
 
 void KeyTreeView::setKeyFilter(const std::shared_ptr<KeyFilter> &filter)
 {
     if (filter == m_keyFilter || (filter && m_keyFilter && filter->id() == m_keyFilter->id())) {
         return;
     }
     m_keyFilter = filter;
     m_proxy->setKeyFilter(filter);
     Q_EMIT keyFilterChanged(filter);
 }
 
 namespace
 {
 QItemSelection itemSelectionFromKeys(const std::vector<Key> &keys, const QTreeView &view)
 {
     const QModelIndexList indexes = keyListModel(view)->indexes(keys);
     return std::accumulate(indexes.cbegin(), indexes.cend(), QItemSelection(), [](QItemSelection selection, const QModelIndex &index) {
         if (index.isValid()) {
             selection.merge(QItemSelection(index, index), QItemSelectionModel::Select);
         }
         return selection;
     });
 }
 }
 
 void KeyTreeView::selectKeys(const std::vector<Key> &keys)
 {
     m_view->selectionModel()->select(itemSelectionFromKeys(keys, *m_view), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
 }
 
 std::vector<Key> KeyTreeView::selectedKeys() const
 {
     return keyListModel(*m_view)->keys(m_view->selectionModel()->selectedRows());
 }
 
 void KeyTreeView::setHierarchicalView(bool on)
 {
     if (on == m_isHierarchical) {
         return;
     }
     if (on && !hierarchicalModel()) {
         qCWarning(KLEOPATRA_LOG) << "hierarchical view requested, but no hierarchical model set";
         return;
     }
     if (!on && !flatModel()) {
         qCWarning(KLEOPATRA_LOG) << "flat view requested, but no flat model set";
         return;
     }
     const std::vector<Key> selectedKeys = this->selectedKeys();
     const Key currentKey = keyListModel(*m_view)->key(m_view->currentIndex());
 
     auto oldModel = model();
     m_isHierarchical = on;
     find_last_proxy(m_proxy)->setSourceModel(model());
     updateModelConnections(oldModel, model());
     if (on) {
         m_view->expandAll();
     }
     selectKeys(selectedKeys);
     if (!currentKey.isNull()) {
         const QModelIndex currentIndex = keyListModel(*m_view)->index(currentKey);
         if (currentIndex.isValid()) {
             m_view->selectionModel()->setCurrentIndex(currentIndex, QItemSelectionModel::NoUpdate);
             m_view->scrollTo(currentIndex);
         }
     }
     m_view->setAccessibleDescription(m_isHierarchical ? i18n("Hierarchical list of certificates") : i18n("List of certificates"));
     Q_EMIT hierarchicalChanged(on);
 }
 
 void KeyTreeView::setKeys(const std::vector<Key> &keys, const std::vector<Key::Origin> &extraOrigins)
 {
     std::vector<Key> sorted = keys;
 
     if (extraOrigins.empty()) {
         _detail::sort_by_fpr(sorted);
         _detail::remove_duplicates_by_fpr(sorted);
     }
     m_keys = sorted;
     if (m_flatModel) {
         m_flatModel->setKeys(sorted, extraOrigins);
     }
     if (m_hierarchicalModel) {
         m_hierarchicalModel->setKeys(sorted, extraOrigins);
     }
 }
 
 void KeyTreeView::addKeysImpl(const std::vector<Key> &keys, bool select)
 {
     if (keys.empty()) {
         return;
     }
     if (m_keys.empty()) {
         setKeys(keys);
         return;
     }
 
     std::vector<Key> sorted = keys;
     _detail::sort_by_fpr(sorted);
     _detail::remove_duplicates_by_fpr(sorted);
 
     std::vector<Key> newKeys = _detail::union_by_fpr(sorted, m_keys);
     m_keys.swap(newKeys);
 
     if (m_flatModel) {
         m_flatModel->addKeys(sorted);
     }
     if (m_hierarchicalModel) {
         m_hierarchicalModel->addKeys(sorted);
     }
 
     if (select) {
         selectKeys(sorted);
     }
 }
 
 void KeyTreeView::addKeysSelected(const std::vector<Key> &keys)
 {
     addKeysImpl(keys, true);
 }
 
 void KeyTreeView::addKeysUnselected(const std::vector<Key> &keys)
 {
     addKeysImpl(keys, false);
 }
 
 void KeyTreeView::removeKeys(const std::vector<Key> &keys)
 {
     if (keys.empty()) {
         return;
     }
     std::vector<Key> sorted = keys;
     _detail::sort_by_fpr(sorted);
     _detail::remove_duplicates_by_fpr(sorted);
     std::vector<Key> newKeys;
     newKeys.reserve(m_keys.size());
     std::set_difference(m_keys.begin(), m_keys.end(), sorted.begin(), sorted.end(), std::back_inserter(newKeys), _detail::ByFingerprint<std::less>());
     m_keys.swap(newKeys);
 
     if (m_flatModel) {
         std::for_each(sorted.cbegin(), sorted.cend(), [this](const Key &key) {
             m_flatModel->removeKey(key);
         });
     }
     if (m_hierarchicalModel) {
         std::for_each(sorted.cbegin(), sorted.cend(), [this](const Key &key) {
             m_hierarchicalModel->removeKey(key);
         });
     }
 }
 
 void KeyTreeView::disconnectSearchBar()
 {
     for (const auto &connection : m_connections) {
         disconnect(connection);
     }
     m_connections.clear();
 }
 
 bool KeyTreeView::connectSearchBar(const SearchBar *bar)
 {
     m_connections.reserve(4);
     m_connections.push_back(connect(this, &KeyTreeView::stringFilterChanged, bar, &SearchBar::setStringFilter));
     m_connections.push_back(connect(bar, &SearchBar::stringFilterChanged, this, &KeyTreeView::setStringFilter));
     m_connections.push_back(connect(this, &KeyTreeView::keyFilterChanged, bar, &SearchBar::setKeyFilter));
     m_connections.push_back(connect(bar, &SearchBar::keyFilterChanged, this, &KeyTreeView::setKeyFilter));
 
     return std::all_of(m_connections.cbegin(), m_connections.cend(), [](const QMetaObject::Connection &conn) {
         return conn;
     });
 }
 
 void KeyTreeView::initializeColumnSizes()
 {
     if (m_onceResized || m_view->model()->rowCount() == 0) {
         return;
     }
     m_onceResized = true;
     m_view->setColumnWidth(KeyList::PrettyName, 260);
     m_view->setColumnWidth(KeyList::PrettyEMail, 260);
 
     for (int i = 2; i < m_view->model()->columnCount(); ++i) {
         m_view->resizeColumnToContents(i);
     }
 }
 
 void KeyTreeView::saveStateBeforeModelChange()
 {
     m_currentKey = keyListModel(*m_view)->key(m_view->currentIndex());
     m_selectedKeys = selectedKeys();
 }
 
 void KeyTreeView::restoreStateAfterModelChange()
 {
     restoreExpandState();
 
     selectKeys(m_selectedKeys);
     if (!m_currentKey.isNull()) {
         const QModelIndex currentIndex = keyListModel(*m_view)->index(m_currentKey);
         if (currentIndex.isValid()) {
             m_view->selectionModel()->setCurrentIndex(currentIndex, QItemSelectionModel::NoUpdate);
             m_view->scrollTo(currentIndex);
         }
     }
 
     setUpTagKeys();
     initializeColumnSizes();
 }
 
 void KeyTreeView::keyPressEvent(QKeyEvent *event)
 {
     if (event == QKeySequence::Copy) {
         QGuiApplication::clipboard()->setText(view()->currentIndex().data(KeyList::ClipboardRole).toString());
         event->accept();
     }
 }
 
 #include "moc_keytreeview.cpp"
diff --git a/src/view/keytreeview.h b/src/view/keytreeview.h
index 07cb3a1e4..68306870f 100644
--- a/src/view/keytreeview.h
+++ b/src/view/keytreeview.h
@@ -1,170 +1,180 @@
 /* -*- mode: c++; c-basic-offset:4 -*-
     view/keytreeview.h
 
     This file is part of Kleopatra, the KDE keymanager
     SPDX-FileCopyrightText: 2009 Klarälvdalens Datakonsult AB
 
     SPDX-License-Identifier: GPL-2.0-or-later
 */
 
 #pragma once
 
 #include <QWidget>
 
 #include <QString>
 #include <QStringList>
 
 #include <gpgme++/key.h>
 
 #include <memory>
 #include <vector>
 
 #include <KConfigGroup>
 
 #include <Libkleo/TreeView>
 
 class QTreeView;
 
 namespace Kleo
 {
 
 class KeyFilter;
 class AbstractKeyListModel;
 class AbstractKeyListSortFilterProxyModel;
 class KeyListSortFilterProxyModel;
 class SearchBar;
 
 class KeyTreeView : public QWidget
 {
     Q_OBJECT
+
+    Q_FLAGS(Options)
 public:
+    enum Option {
+        Default = 0x0,
+        NoDefaultContextMenu = 0x1,
+    };
+    Q_DECLARE_FLAGS(Options, Option)
+
     explicit KeyTreeView(QWidget *parent = nullptr);
     KeyTreeView(const QString &stringFilter,
                 const std::shared_ptr<KeyFilter> &keyFilter,
                 AbstractKeyListSortFilterProxyModel *additionalProxy,
                 QWidget *parent,
-                const KConfigGroup &group);
+                const KConfigGroup &group,
+                Options options = Option::Default);
     ~KeyTreeView() override;
 
     TreeView *view() const
     {
         return m_view;
     }
 
     AbstractKeyListModel *model() const
     {
         return m_isHierarchical ? hierarchicalModel() : flatModel();
     }
 
     AbstractKeyListModel *flatModel() const
     {
         return m_flatModel;
     }
     AbstractKeyListModel *hierarchicalModel() const
     {
         return m_hierarchicalModel;
     }
 
     void setFlatModel(AbstractKeyListModel *model);
     void setHierarchicalModel(AbstractKeyListModel *model);
 
     // extraOrigins contains additional origin information for the keys. It must be in the same order as the keys themselves.
     // For this reason, setKeys will NOT perform any sorting and filtering if extraOrigins is not empty.
     void setKeys(const std::vector<GpgME::Key> &keys, const std::vector<GpgME::Key::Origin> &extraOrigins = {});
     const std::vector<GpgME::Key> &keys() const
     {
         return m_keys;
     }
 
     void selectKeys(const std::vector<GpgME::Key> &keys);
     std::vector<GpgME::Key> selectedKeys() const;
 
     void addKeysUnselected(const std::vector<GpgME::Key> &keys);
     void addKeysSelected(const std::vector<GpgME::Key> &keys);
     void removeKeys(const std::vector<GpgME::Key> &keys);
 
 #if 0
     void setToolTipOptions(int options);
     int toolTipOptions() const;
 #endif
 
     QString stringFilter() const
     {
         return m_stringFilter;
     }
     const std::shared_ptr<KeyFilter> &keyFilter() const
     {
         return m_keyFilter;
     }
     bool isHierarchicalView() const
     {
         return m_isHierarchical;
     }
 
     void setColumnSizes(const std::vector<int> &sizes);
     std::vector<int> columnSizes() const;
 
     void setSortColumn(int sortColumn, Qt::SortOrder sortOrder);
     int sortColumn() const;
     Qt::SortOrder sortOrder() const;
 
     virtual KeyTreeView *clone() const
     {
         return new KeyTreeView(*this);
     }
 
     void disconnectSearchBar();
     bool connectSearchBar(const SearchBar *bar);
     void restoreLayout(const KConfigGroup &group);
 
 public Q_SLOTS:
     virtual void setStringFilter(const QString &text);
     virtual void setKeyFilter(const std::shared_ptr<Kleo::KeyFilter> &filter);
     virtual void setHierarchicalView(bool on);
 
 Q_SIGNALS:
     void stringFilterChanged(const QString &filter);
     void keyFilterChanged(const std::shared_ptr<Kleo::KeyFilter> &filter);
     void hierarchicalChanged(bool on);
 
 protected:
     KeyTreeView(const KeyTreeView &);
     void keyPressEvent(QKeyEvent *event) override;
 
 private:
     void init();
     void initializeColumnSizes();
     void addKeysImpl(const std::vector<GpgME::Key> &, bool);
     void restoreExpandState();
     void setUpTagKeys();
     void updateModelConnections(AbstractKeyListModel *oldModel, AbstractKeyListModel *newModel);
     void saveStateBeforeModelChange();
     void restoreStateAfterModelChange();
 
 private:
     std::vector<GpgME::Key> m_keys;
 
     KeyListSortFilterProxyModel *m_proxy;
     AbstractKeyListSortFilterProxyModel *m_additionalProxy;
 
     TreeView *m_view;
 
     AbstractKeyListModel *m_flatModel;
     AbstractKeyListModel *m_hierarchicalModel;
 
     QString m_stringFilter;
     std::shared_ptr<KeyFilter> m_keyFilter;
 
     QStringList m_expandedKeys;
     std::vector<GpgME::Key> m_selectedKeys;
     GpgME::Key m_currentKey;
 
     std::vector<QMetaObject::Connection> m_connections;
 
     KConfigGroup m_group;
 
     bool m_isHierarchical : 1;
     bool m_onceResized : 1;
+    bool m_showDefaultContextMenu : 1;
 };
 
 }
diff --git a/src/view/tabwidget.cpp b/src/view/tabwidget.cpp
index 804bf3b37..fa36167e8 100644
--- a/src/view/tabwidget.cpp
+++ b/src/view/tabwidget.cpp
@@ -1,1154 +1,1164 @@
 /* -*- 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 <config-kleopatra.h>
 
 #include "tabwidget.h"
 
 #include "keytreeview.h"
 #include "kleopatra_debug.h"
 #include "searchbar.h"
 
 #include <settings.h>
 
 #include <utils/action_data.h>
 
 #include <Libkleo/KeyFilter>
 #include <Libkleo/KeyFilterManager>
 #include <Libkleo/KeyListModel>
 #include <Libkleo/KeyListSortFilterProxyModel>
 #include <Libkleo/Stl_Util>
 #include <Libkleo/UserIDProxyModel>
 
 #include <gpgme++/key.h>
 // needed for GPGME_VERSION_NUMBER
 #include <gpgme.h>
 
 #include <KActionCollection>
 #include <KConfig>
 #include <KConfigGroup>
 #include <KLocalizedString>
 #include <KSharedConfig>
 #include <QAction>
 #include <QInputDialog>
 #include <QTabWidget>
 
 #include <QAbstractProxyModel>
 #include <QHeaderView>
 #include <QMenu>
 #include <QRegularExpression>
 #include <QTimer>
 #include <QToolButton>
 #include <QTreeView>
 #include <QVBoxLayout>
 
 #include <map>
 
 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);
+         const KConfigGroup &group = KConfigGroup(),
+         KeyTreeView::Options options = KeyTreeView::Default);
+    Page(const KConfigGroup &group, KeyTreeView::Options options = KeyTreeView::Default, 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<KeyFilter> &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;
     }
 
     Page *clone() const override
     {
         return new Page(*this);
     }
 
     void liftAllRestrictions()
     {
         m_canBeClosed = m_canBeRenamed = m_canChangeStringFilter = m_canChangeKeyFilter = m_canChangeHierarchical = true;
     }
 
     void closePage()
     {
         m_configGroup.deleteGroup();
         m_configGroup.sync();
     }
 
     KConfigGroup configGroup() const
     {
         return m_configGroup;
     }
 
 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;
     KConfigGroup m_configGroup;
 };
 } // 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)
     , m_configGroup(other.configGroup().config()->group(QUuid::createUuid().toString()))
 {
     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)
+           const KConfigGroup &group,
+           KeyTreeView::Options options)
+    : KeyTreeView(text, KeyFilterManager::instance()->keyFilterByID(id), proxy, parent, group, options)
     , m_title(title)
     , m_toolTip(toolTip)
     , m_isTemporary(false)
     , m_canBeClosed(true)
     , m_canBeRenamed(true)
     , m_canChangeStringFilter(true)
     , m_canChangeKeyFilter(true)
     , m_canChangeHierarchical(true)
     , m_configGroup(group)
 {
     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)
+Page::Page(const KConfigGroup &group, KeyTreeView::Options options, QWidget *parent)
+    : KeyTreeView(group.readEntry(STRING_FILTER_ENTRY),
+                  KeyFilterManager::instance()->keyFilterByID(group.readEntry(KEY_FILTER_ENTRY)),
+                  nullptr,
+                  parent,
+                  group,
+                  options)
     , 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))
     , m_configGroup(group)
 {
     init();
     setHierarchicalView(group.readEntry(HIERARCHICAL_VIEW_ENTRY, true));
     const QList<int> settings = group.readEntry(COLUMN_SIZES, QList<int>());
     std::vector<int> 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()
 {
 #if GPGME_VERSION_NUMBER >= 0x011800 // 1.24.0
     view()->setDragDropMode(QAbstractItemView::DragOnly);
     view()->setDragEnabled(true);
 #endif
 }
 
 Page::~Page()
 {
 }
 
 void Page::setStringFilter(const QString &filter)
 {
     if (!m_canChangeStringFilter) {
         return;
     }
     KeyTreeView::setStringFilter(filter);
     m_configGroup.writeEntry(STRING_FILTER_ENTRY, stringFilter());
     m_configGroup.sync();
 }
 
 void Page::setKeyFilter(const std::shared_ptr<KeyFilter> &filter)
 {
     if (!canChangeKeyFilter()) {
         return;
     }
     const QString oldTitle = title();
     KeyTreeView::setKeyFilter(filter);
     const QString newTitle = title();
     if (oldTitle != newTitle) {
         Q_EMIT titleChanged(newTitle);
     }
     m_configGroup.writeEntry(KEY_FILTER_ENTRY, keyFilter() ? keyFilter()->id() : QString());
     m_configGroup.sync();
 }
 
 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);
         m_configGroup.writeEntry(TITLE_ENTRY, m_title);
         m_configGroup.sync();
     }
 }
 
 #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);
     m_configGroup.writeEntry(HIERARCHICAL_VIEW_ENTRY, on);
     m_configGroup.sync();
 }
 
 void Page::setTemporary(bool on)
 {
     if (on == m_isTemporary) {
         return;
     }
     m_isTemporary = on;
     if (on) {
         setKeyFilter(std::shared_ptr<KeyFilter>());
     }
 }
 
 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<std::string, QAction *> actions;
 };
 }
 
 //
 //
 // TabWidget
 //
 //
 
 class TabWidget::Private
 {
     friend class ::Kleo::TabWidget;
     TabWidget *const q;
 
 public:
-    explicit Private(TabWidget *qq);
+    explicit Private(TabWidget *qq, KeyTreeView::Options options);
     ~Private()
     {
     }
 
 private:
     void slotContextMenu(const QPoint &p);
     void currentIndexChanged(int index);
     void slotPageTitleChanged(const QString &title);
     void slotPageKeyFilterChanged(const std::shared_ptr<KeyFilter> &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<Page *>(tabWidget->currentWidget()));
         return static_cast<Page *>(tabWidget->currentWidget());
     }
     Page *page(unsigned int idx) const
     {
         Q_ASSERT(!tabWidget->widget(idx) || qobject_cast<Page *>(tabWidget->widget(idx)));
         return static_cast<Page *>(tabWidget->widget(idx));
     }
 
     Page *senderPage() const
     {
         QObject *const sender = q->sender();
         Q_ASSERT(!sender || qobject_cast<Page *>(sender));
         return static_cast<Page *>(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;
     KSharedConfig::Ptr config;
     QString configKey;
+    KeyTreeView::Options keyTreeViewOptions;
 };
 
-TabWidget::Private::Private(TabWidget *qq)
+TabWidget::Private::Private(TabWidget *qq, KeyTreeView::Options options)
     : q{qq}
+    , keyTreeViewOptions(options)
 {
     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};
     Q_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, &QTabWidget::currentChanged, q, [this](int index) {
         currentIndexChanged(index);
     });
     connect(tabWidget->tabBar(), &QWidget::customContextMenuRequested, q, [this](const QPoint &p) {
         slotContextMenu(p);
     });
     connect(tabWidget->tabBar(), &QTabBar::tabMoved, q, [this]() {
         q->saveViews();
     });
 }
 
 void TabWidget::Private::slotContextMenu(const QPoint &p)
 {
     const int tabUnderPos = tabWidget->tabBar()->tabAt(p);
     Page *const contextMenuPage = static_cast<Page *>(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<KeyFilter>());
     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<Page *>(p)) != 0);
     actions.setEnabled(Actions::MoveRight, p && tabWidget->indexOf(const_cast<Page *>(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<KeyFilter> &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()
 {
     auto group = KSharedConfig::openStateConfig()->group(QStringLiteral("%1:View %2").arg(configKey, QUuid::createUuid().toString()));
-    Page *page = new Page(QString(), QStringLiteral("all-certificates"), QString(), nullptr, QString(), nullptr, group);
+    Page *page = new Page(QString(), QStringLiteral("all-certificates"), QString(), nullptr, QString(), nullptr, group, keyTreeViewOptions);
     group.writeEntry(KEY_FILTER_ENTRY, QStringLiteral("all-certificates"));
     group.sync();
     addView(page, currentPage());
     tabWidget->setCurrentIndex(tabWidget->count() - 1);
     q->saveViews();
 }
 
 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());
     page->closePage();
     tabWidget->removeTab(tabWidget->indexOf(page));
     q->saveViews();
     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)
+TabWidget::TabWidget(KeyTreeView::Options options, QWidget *p, Qt::WindowFlags f)
     : QWidget(p, f)
-    , d(new Private(this))
+    , d(new Private(this, options))
 {
 }
 
 TabWidget::~TabWidget()
 {
     saveViews();
 }
 
 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<KeyFilter> &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<QAbstractItemView *> TabWidget::views() const
 {
     std::vector<QAbstractItemView *> 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<QAbstractProxyModel *>(view->model());
     if (!proxy) {
         return nullptr;
     }
     return dynamic_cast<KeyListModelInterface *>(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,
         [this](bool) {
             d->slotNewTab();
         },
         QStringLiteral("CTRL+SHIFT+N"),
     };
 
     d->newAction = make_action_from_data(actionDataNew, coll);
 
     const std::vector<action_data> actionData = {
         {
             Actions::Rename,
             i18n("Rename Tab..."),
             i18n("Rename this tab"),
             "edit-rename",
             this,
             [this](bool) {
                 d->slotRenameCurrentTab();
             },
             QStringLiteral("CTRL+SHIFT+R"),
             RegularQAction,
             Disabled,
         },
         {
             Actions::Duplicate,
             i18n("Duplicate Tab"),
             i18n("Duplicate this tab"),
             "tab-duplicate",
             this,
             [this](bool) {
                 d->slotDuplicateCurrentTab();
             },
             QStringLiteral("CTRL+SHIFT+D"),
         },
         {
             Actions::Close,
             i18n("Close Tab"),
             i18n("Close this tab"),
             "tab-close",
             this,
             [this](bool) {
                 d->slotCloseCurrentTab();
             },
             QStringLiteral("CTRL+SHIFT+W"),
             RegularQAction,
             Disabled,
         }, // ### CTRL-W when available
         {
             Actions::MoveLeft,
             i18n("Move Tab Left"),
             i18n("Move this tab left"),
             nullptr,
             this,
             [this](bool) {
                 d->slotMoveCurrentTabLeft();
             },
             QStringLiteral("CTRL+SHIFT+LEFT"),
             RegularQAction,
             Disabled,
         },
         {
             Actions::MoveRight,
             i18n("Move Tab Right"),
             i18n("Move this tab right"),
             nullptr,
             this,
             [this](bool) {
                 d->slotMoveCurrentTabRight();
             },
             QStringLiteral("CTRL+SHIFT+RIGHT"),
             RegularQAction,
             Disabled,
         },
         {
             Actions::Hierarchical,
             i18n("Hierarchical Certificate List"),
             QString(),
             nullptr,
             this,
             [this](bool on) {
                 d->slotToggleHierarchicalView(on);
             },
             QString(),
             KFToggleAction,
             Disabled,
         },
         {
             Actions::ExpandAll,
             i18n("Expand All"),
             QString(),
             nullptr,
             this,
             [this](bool) {
                 d->slotExpandAll();
             },
             QStringLiteral("CTRL+."),
             RegularQAction,
             Disabled,
         },
         {
             Actions::CollapseAll,
             i18n("Collapse All"),
             QString(),
             nullptr,
             this,
             [this](bool) {
                 d->slotCollapseAll();
             },
             QStringLiteral("CTRL+,"),
             RegularQAction,
             Disabled,
         },
     };
 
     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(QLatin1StringView(ad.icon)));
         }
         action->setEnabled(ad.actionState == 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)
 {
     auto group = KSharedConfig::openStateConfig()->group(QStringLiteral("%1:View %2").arg(d->configKey, QUuid::createUuid().toString()));
-    Page *page = new Page(title, id, text, nullptr, QString(), nullptr, group);
+    Page *page = new Page(title, id, text, nullptr, QString(), nullptr, group, d->keyTreeViewOptions);
     group.writeEntry(KEY_FILTER_ENTRY, id);
     group.sync();
     return d->addView(page, d->currentPage());
 }
 
 QAbstractItemView *TabWidget::addView(const KConfigGroup &group, Options options)
 {
     Page *page = nullptr;
     if (options & ShowUserIDs) {
         page = new Page(group.readEntry(TITLE_ENTRY),
                         group.readEntry(KEY_FILTER_ENTRY),
                         group.readEntry(STRING_FILTER_ENTRY),
                         new UserIDProxyModel(this),
                         {},
                         nullptr,
-                        group);
+                        group,
+                        d->keyTreeViewOptions);
     } else {
-        page = new Page(group);
+        page = new Page(group, d->keyTreeViewOptions);
     }
     QMetaObject::invokeMethod(
         this,
         [page, group]() {
             page->restoreLayout(group);
         },
         Qt::QueuedConnection);
     return d->addView(page, nullptr);
 }
 
 QAbstractItemView *TabWidget::addTemporaryView(const QString &title, AbstractKeyListSortFilterProxyModel *proxy, const QString &tabToolTip)
 {
     const KConfigGroup group = KSharedConfig::openConfig()->group(QStringLiteral("KeyTreeView_default"));
-    Page *const page = new Page(title, QString(), QString(), proxy, tabToolTip, nullptr, group);
+    Page *const page = new Page(title, QString(), QString(), proxy, tabToolTip, nullptr, group, d->keyTreeViewOptions);
     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, &Page::titleChanged, q, [this](const QString &text) {
         slotPageTitleChanged(text);
     });
     connect(page, &Page::keyFilterChanged, q, [this](const std::shared_ptr<Kleo::KeyFilter> &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) {
         QMetaObject::invokeMethod(
             q,
             [=]() {
                 page->setColumnSizes(columnReference->columnSizes());
                 page->setSortColumn(columnReference->sortColumn(), columnReference->sortOrder());
                 page->view()->saveColumnLayout(page->configGroup().name());
             },
             Qt::QueuedConnection);
         for (auto i = 0; i < columnReference->view()->model()->columnCount(); i++) {
             page->view()->setColumnHidden(i, columnReference->view()->isColumnHidden(i));
             page->view()->header()->moveSection(page->view()->header()->visualIndex(i), columnReference->view()->header()->visualIndex(i));
         }
         for (auto row = 0; row < page->view()->model()->rowCount(); row++) {
             page->view()->setExpanded(page->view()->model()->index(row, 0),
                                       columnReference->view()->isExpanded(columnReference->view()->model()->index(row, 0)));
         }
     }
 
     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 KConfigGroup &config)
 {
     return config.readEntry("Tabs", QStringList());
 }
 
 void TabWidget::loadViews(const KSharedConfig::Ptr &config, const QString &configKey, Options options)
 {
     d->config = config;
     d->configKey = configKey;
     QStringList groupList = extractViewGroups(config->group(configKey));
     for (const QString &view : std::as_const(groupList)) {
         addView(KConfigGroup(config, view), options);
     }
     if (!count()) {
         // add default view:
         addView({}, QStringLiteral("all-certificates"));
     }
 }
 
 void TabWidget::saveViews()
 {
     if (!d->config) {
         return;
     }
     QStringList tabs;
     for (unsigned int i = 0, end = count(); i != end; ++i) {
         if (Page *const p = d->page(i)) {
             if (p->isTemporary()) {
                 continue;
             }
             tabs += p->configGroup().name();
         }
     }
     d->config->group(d->configKey).writeEntry("Tabs", tabs);
     d->config->sync();
 }
 
 void TabWidget::connectSearchBar(SearchBar *sb)
 {
     connect(sb, &SearchBar::stringFilterChanged, this, &TabWidget::setStringFilter);
     connect(this, &TabWidget::stringFilterChanged, sb, &SearchBar::setStringFilter);
 
     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 b1f53547d..3a99fba82 100644
--- a/src/view/tabwidget.h
+++ b/src/view/tabwidget.h
@@ -1,92 +1,94 @@
 /* -*- 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 "keytreeview.h"
+
 #include <KSharedConfig>
 
 #include <QWidget>
 
 #include <memory>
 #include <vector>
 
 class QAbstractItemView;
 
 class KConfigGroup;
 class KActionCollection;
 
 namespace Kleo
 {
 
 class AbstractKeyListModel;
 class AbstractKeyListSortFilterProxyModel;
 class KeyFilter;
 class KeyListModelInterface;
 class SearchBar;
 
 class TabWidget : public QWidget
 {
     Q_OBJECT
 public:
     enum Option {
         ShowKeys = 0x00,
         ShowUserIDs = 0x01,
     };
     Q_DECLARE_FLAGS(Options, Option)
 
-    explicit TabWidget(QWidget *parent = nullptr, Qt::WindowFlags f = {});
+    explicit TabWidget(KeyTreeView::Options options = KeyTreeView::Option::Default, 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, Options options);
     QAbstractItemView *
     addTemporaryView(const QString &title = QString(), AbstractKeyListSortFilterProxyModel *proxy = nullptr, const QString &tabToolTip = QString());
 
     void loadViews(const KSharedConfig::Ptr &config, const QString &configKeys, Options options = ShowKeys);
     void saveViews();
 
     std::vector<QAbstractItemView *> views() const;
     QAbstractItemView *currentView() const;
     KeyListModelInterface *currentModel() const;
 
     unsigned int count() const;
 
     void createActions(KActionCollection *collection);
     void connectSearchBar(SearchBar *sb);
 
     void setMultiSelection(bool on);
 
     QString stringFilter() const;
 
 public Q_SLOTS:
     void setKeyFilter(const std::shared_ptr<Kleo::KeyFilter> &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<Kleo::KeyFilter> &filter);
 
     void enableChangeStringFilter(bool enable);
     void enableChangeKeyFilter(bool enable);
 
 private:
     class Private;
     const std::unique_ptr<Private> d;
 };
 
 }