From 15b8b5d92f6a73577625f099df0b5adf9b1a5c78 Mon Sep 17 00:00:00 2001 From: Jonathan White Date: Tue, 4 Jul 2023 07:15:39 -0400 Subject: [PATCH] Significantly improve visual when dragging entries to copy/move * Fixes #6079 --- share/translations/keepassxc_en.ts | 7 +++ src/gui/entry/EntryView.cpp | 74 ++++++++++++++++++++++++++++++ src/gui/entry/EntryView.h | 1 + 3 files changed, 82 insertions(+) diff --git a/share/translations/keepassxc_en.ts b/share/translations/keepassxc_en.ts index 865a42344..cd05345ae 100644 --- a/share/translations/keepassxc_en.ts +++ b/share/translations/keepassxc_en.ts @@ -3965,6 +3965,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);