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);