diff --git a/src/view/keytreeview.cpp b/src/view/keytreeview.cpp
index afa8f652d..283137a07 100644
--- a/src/view/keytreeview.cpp
+++ b/src/view/keytreeview.cpp
@@ -1,766 +1,768 @@
 /* -*- 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/NavigatableTreeView>
 #include <Libkleo/Predicates>
 
 #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 <QContextMenuEvent>
 #include <QEvent>
 #include <QHeaderView>
 #include <QItemSelection>
 #include <QItemSelectionModel>
 #include <QLayout>
 #include <QList>
 #include <QMenu>
 #include <QTimer>
 
 #include <KLocalizedString>
 #include <KSharedConfig>
 
 #define TAGS_COLUMN 13
 
 using namespace Kleo;
 using namespace GpgME;
 
 Q_DECLARE_METATYPE(GpgME::Key)
 
 namespace
 {
 
 class TreeView : public NavigatableTreeView
 {
 public:
     explicit TreeView(QWidget *parent = nullptr)
         : NavigatableTreeView{parent}
     {
         header()->installEventFilter(this);
+        setDragDropMode(QAbstractItemView::DragOnly);
+        setDragEnabled(true);
     }
 
     QSize minimumSizeHint() const override
     {
         const QSize min = QTreeView::minimumSizeHint();
         return QSize(min.width(), min.height() + 5 * fontMetrics().height());
     }
 
 protected:
     bool eventFilter(QObject *watched, QEvent *event) override
     {
         Q_UNUSED(watched)
         if (event->type() == QEvent::ContextMenu) {
             auto e = static_cast<QContextMenuEvent *>(event);
 
             if (!mHeaderPopup) {
                 mHeaderPopup = new QMenu(this);
                 mHeaderPopup->setTitle(i18n("View Columns"));
                 for (int i = 0; i < model()->columnCount(); ++i) {
                     QAction *tmp = mHeaderPopup->addAction(model()->headerData(i, Qt::Horizontal).toString());
                     tmp->setData(QVariant(i));
                     tmp->setCheckable(true);
                     mColumnActions << tmp;
                 }
 
                 connect(mHeaderPopup, &QMenu::triggered, this, [this](QAction *action) {
                     const int col = action->data().toInt();
                     if ((col == TAGS_COLUMN) && action->isChecked()) {
                         Tags::enableTags();
                     }
                     if (action->isChecked()) {
                         showColumn(col);
                     } else {
                         hideColumn(col);
                     }
 
                     auto tv = qobject_cast<KeyTreeView *>(parent());
                     if (tv) {
                         tv->resizeColumns();
                     }
                 });
             }
 
             for (QAction *action : std::as_const(mColumnActions)) {
                 const int column = action->data().toInt();
                 action->setChecked(!isColumnHidden(column));
             }
 
             mHeaderPopup->popup(mapToGlobal(e->pos()));
             return true;
         }
 
         return false;
     }
 
     void focusInEvent(QFocusEvent *event) override
     {
         QTreeView::focusInEvent(event);
         // queue the invokation, so that it happens after the widget itself got focus
         QMetaObject::invokeMethod(this, &TreeView::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 TreeView(this))
     , m_flatModel(nullptr)
     , m_hierarchicalModel(nullptr)
     , m_stringFilter()
     , m_keyFilter()
     , m_isHierarchical(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 TreeView(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)
 {
     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)
     : QWidget(parent)
     , m_proxy(new KeyListSortFilterProxyModel(this))
     , m_additionalProxy(proxy)
     , m_view(new TreeView(this))
     , m_flatModel(nullptr)
     , m_hierarchicalModel(nullptr)
     , m_stringFilter(text)
     , m_keyFilter(kf)
     , m_group(group)
     , m_isHierarchical(true)
     , m_onceResized(false)
 {
     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::init()
 {
     KDAB_SET_OBJECT_NAME(m_proxy);
     KDAB_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()) {
         KDAB_SET_OBJECT_NAME(m_additionalProxy);
     }
     QLayout *layout = new QVBoxLayout(this);
     KDAB_SET_OBJECT_NAME(layout);
     layout->setContentsMargins(0, 0, 0, 0);
     layout->addWidget(m_view);
 
     auto headerView = new HeaderView(Qt::Horizontal);
     KDAB_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 (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));
     m_proxy->setKeyFilter(m_keyFilter);
     m_proxy->setSortCaseSensitivity(Qt::CaseInsensitive);
 
     auto rearangingModel = new KeyRearrangeColumnsProxyModel(this);
     rearangingModel->setSourceModel(m_proxy);
     rearangingModel->setSourceColumns(QVector<int>() << 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 //
                                                      // If a column is added before this TAGS_COLUMN define has to be updated accordingly
                                                      << KeyList::Remarks);
     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());
 
     resizeColumns();
     if (m_group.isValid()) {
         restoreLayout(m_group);
     }
 }
 
 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);
     }
 }
 
 void KeyTreeView::saveLayout(KConfigGroup &group)
 {
     QHeaderView *header = m_view->header();
 
     QVariantList columnVisibility;
     QVariantList columnOrder;
     QVariantList columnWidths;
     const int headerCount = header->count();
     columnVisibility.reserve(headerCount);
     columnWidths.reserve(headerCount);
     columnOrder.reserve(headerCount);
     for (int i = 0; i < headerCount; ++i) {
         columnVisibility << QVariant(!m_view->isColumnHidden(i));
         columnWidths << QVariant(header->sectionSize(i));
         columnOrder << QVariant(header->visualIndex(i));
     }
 
     group.writeEntry("ColumnVisibility", columnVisibility);
     group.writeEntry("ColumnOrder", columnOrder);
     group.writeEntry("ColumnWidths", columnWidths);
 
     group.writeEntry("SortAscending", (int)header->sortIndicatorOrder());
     if (header->isSortIndicatorShown()) {
         group.writeEntry("SortColumn", header->sortIndicatorSection());
     } else {
         group.writeEntry("SortColumn", -1);
     }
 }
 
 void KeyTreeView::restoreLayout(const KConfigGroup &group)
 {
     QHeaderView *header = m_view->header();
 
     QVariantList columnVisibility = group.readEntry("ColumnVisibility", QVariantList());
     QVariantList columnOrder = group.readEntry("ColumnOrder", QVariantList());
     QVariantList columnWidths = group.readEntry("ColumnWidths", QVariantList());
 
     if (columnVisibility.isEmpty()) {
         // 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::resizeColumns);
         }
     } else {
         for (int i = 0; i < header->count(); ++i) {
             if (i >= columnOrder.size() || i >= columnWidths.size() || i >= columnVisibility.size()) {
                 // An additional column that was not around last time we saved.
                 // We default to hidden.
                 m_view->hideColumn(i);
                 continue;
             }
             bool visible = columnVisibility[i].toBool();
             int width = columnWidths[i].toInt();
             int order = columnOrder[i].toInt();
 
             header->resizeSection(i, width ? width : 100);
             header->moveSection(header->visualIndex(i), order);
             if ((i == TAGS_COLUMN) && visible) {
                 Tags::enableTags();
             }
             if (!visible) {
                 m_view->hideColumn(i);
             }
         }
         m_onceResized = true;
     }
 
     int sortOrder = group.readEntry("SortAscending", (int)Qt::AscendingOrder);
     int sortColumn = group.readEntry("SortColumn", 0);
     if (sortColumn >= 0) {
         m_view->sortByColumn(sortColumn, (Qt::SortOrder)sortOrder);
     }
 }
 
 KeyTreeView::~KeyTreeView()
 {
     if (m_group.isValid()) {
         saveLayout(m_group);
     }
 }
 
 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));
     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)
 {
     std::vector<Key> sorted = keys;
     _detail::sort_by_fpr(sorted);
     _detail::remove_duplicates_by_fpr(sorted);
     m_keys = sorted;
     if (m_flatModel) {
         m_flatModel->setKeys(sorted);
     }
     if (m_hierarchicalModel) {
         m_hierarchicalModel->setKeys(sorted);
     }
 }
 
 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::resizeColumns()
 {
     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();
     if (!m_onceResized) {
         m_onceResized = true;
         resizeColumns();
     }
 }