diff --git a/share/translations/keepassxc_en.ts b/share/translations/keepassxc_en.ts
index 800916cb2..d7f3c41f3 100644
--- a/share/translations/keepassxc_en.ts
+++ b/share/translations/keepassxc_en.ts
@@ -3997,6 +3997,13 @@ Error: %1
Reset to defaults
+
+ + %1 entry(s)...
+
+
+
+
+
ExportDialog
diff --git a/src/gui/entry/EntryView.cpp b/src/gui/entry/EntryView.cpp
index 0df283f65..868250a66 100644
--- a/src/gui/entry/EntryView.cpp
+++ b/src/gui/entry/EntryView.cpp
@@ -19,12 +19,18 @@
#include "EntryView.h"
#include
+#include
+#include
#include
+#include
#include
#include
+#include
#include
#include
+#include
+#include "gui/Icons.h"
#include "gui/SortFilterHideProxyModel.h"
#define ICON_ONLY_SECTION_SIZE 26
@@ -507,6 +513,74 @@ void EntryView::showEvent(QShowEvent* event)
}
}
+void EntryView::startDrag(Qt::DropActions supportedActions)
+{
+ auto selectedIndexes = selectionModel()->selectedRows(EntryModel::Title);
+ if (selectedIndexes.isEmpty()) {
+ return;
+ }
+
+ // Create a mime data object for the selected rows
+ auto mimeData = m_sortModel->mimeData(selectedIndexes);
+ if (!mimeData) {
+ return;
+ }
+
+ // Create a temporary list widget to display the dragged items
+ int i = 0;
+ QListWidget listWidget;
+ for (auto& index : selectedIndexes) {
+ if (++i > 4) {
+ int remaining = selectedIndexes.size() - i + 1;
+ listWidget.addItem(tr("+ %1 entry(s)...", nullptr, remaining).arg(remaining));
+ break;
+ }
+
+ QIcon icon;
+ icon.addPixmap(m_sortModel->data(index, Qt::DecorationRole).value());
+
+ auto item = new QListWidgetItem;
+ item->setText(m_sortModel->data(index, Qt::DisplayRole).toString());
+ item->setIcon(icon);
+ listWidget.addItem(item);
+ }
+
+ listWidget.setStyleSheet("QListWidget { background-color: palette(highlight); border: 1px solid palette(dark); "
+ "padding: 4px; color: palette(highlighted-text); }");
+ auto width = listWidget.sizeHintForColumn(0) + 2 * listWidget.frameWidth();
+ auto height = listWidget.sizeHintForRow(0) * listWidget.count() + 2 * listWidget.frameWidth();
+ listWidget.setFixedWidth(width);
+ listWidget.setFixedHeight(height);
+
+ // Grab the screen pixel ratio where the window resides
+ // TODO: Use direct call to screen() when moving to Qt 6
+#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
+ auto screen = QGuiApplication::screenAt(window()->geometry().center());
+ if (!screen) {
+ screen = QGuiApplication::primaryScreen();
+ }
+#else
+ auto screen = QGuiApplication::primaryScreen();
+ if (windowHandle()) {
+ screen = windowHandle()->screen();
+ }
+#endif
+
+ auto pixelRatio = screen->devicePixelRatio();
+
+ // Render the list widget to a pixmap
+ QPixmap pixmap(QSize(width, height) * pixelRatio);
+ pixmap.fill(Qt::transparent);
+ pixmap.setDevicePixelRatio(pixelRatio);
+ listWidget.render(&pixmap);
+
+ // Create a drag object and start the drag
+ auto drag = new QDrag(this);
+ drag->setMimeData(mimeData);
+ drag->setPixmap(pixmap);
+ drag->exec(supportedActions, defaultDropAction());
+}
+
bool EntryView::isColumnHidden(int logicalIndex)
{
return header()->isSectionHidden(logicalIndex) || header()->sectionSize(logicalIndex) == 0;
diff --git a/src/gui/entry/EntryView.h b/src/gui/entry/EntryView.h
index c7136383a..3a0cc1d60 100644
--- a/src/gui/entry/EntryView.h
+++ b/src/gui/entry/EntryView.h
@@ -61,6 +61,7 @@ protected:
void keyPressEvent(QKeyEvent* event) override;
void focusInEvent(QFocusEvent* event) override;
void showEvent(QShowEvent* event) override;
+ void startDrag(Qt::DropActions supportedActions) override;
private slots:
void emitEntryActivated(const QModelIndex& index);