diff --git a/applets/notifications/package/contents/ui/ThumbnailStrip.qml b/applets/notifications/package/contents/ui/ThumbnailStrip.qml --- a/applets/notifications/package/contents/ui/ThumbnailStrip.qml +++ b/applets/notifications/package/contents/ui/ThumbnailStrip.qml @@ -192,5 +192,13 @@ } } } + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.RightButton + onPressed: { + thumbnailer.showContextMenu(mouse.x, mouse.y, modelData, this) + } + } } } diff --git a/applets/notifications/plugin/CMakeLists.txt b/applets/notifications/plugin/CMakeLists.txt --- a/applets/notifications/plugin/CMakeLists.txt +++ b/applets/notifications/plugin/CMakeLists.txt @@ -9,7 +9,8 @@ Qt5::Gui Qt5::Qml Qt5::Quick - KF5::KIOWidgets # PreviewJob + KF5::KIOWidgets + KF5::I18n ) install(TARGETS notificationshelperplugin DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/plasma/private/notifications) diff --git a/applets/notifications/plugin/thumbnailer.h b/applets/notifications/plugin/thumbnailer.h --- a/applets/notifications/plugin/thumbnailer.h +++ b/applets/notifications/plugin/thumbnailer.h @@ -25,6 +25,8 @@ #include #include +class QQuickItem; + class Thumbnailer : public QObject, public QQmlParserStatus { Q_OBJECT @@ -55,6 +57,8 @@ QString iconName() const; + Q_INVOKABLE void showContextMenu(int x, int y, const QString &path, QQuickItem *ctx); + void classBegin() override; void componentComplete() override; diff --git a/applets/notifications/plugin/thumbnailer.cpp b/applets/notifications/plugin/thumbnailer.cpp --- a/applets/notifications/plugin/thumbnailer.cpp +++ b/applets/notifications/plugin/thumbnailer.cpp @@ -20,8 +20,22 @@ #include +#include +#include #include #include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include Thumbnailer::Thumbnailer(QObject *parent) : QObject(parent) { @@ -91,6 +105,61 @@ return m_iconName; } +void Thumbnailer::showContextMenu(int x, int y, const QString &path, QQuickItem *ctx) +{ + if (!ctx || !ctx->window()) { + return; + } + + const QUrl url(path); + if (!url.isValid()) { + return; + } + + KFileItem fileItem(url); + + QMenu *menu = new QMenu(); + menu->setAttribute(Qt::WA_DeleteOnClose, true); + + if (KProtocolManager::supportsListing(url)) { + QAction *openContainingFolderAction = menu->addAction(QIcon::fromTheme("folder-open"), i18n("Open Containing Folder")); + connect(openContainingFolderAction, &QAction::triggered, [url] { + KIO::highlightInFileManager({url}); + }); + } + + menu->addSeparator(); + + // KStandardAction? But then the Ctrl+C shortcut makes no sense in this context + QAction *copyAction = menu->addAction(QIcon::fromTheme(QStringLiteral("edit-copy")), i18n("&Copy")); + connect(copyAction, &QAction::triggered, [fileItem] { + // inspired by KDirModel::mimeData() + QMimeData *data = new QMimeData(); // who cleans it up? + KUrlMimeData::setUrls({fileItem.url()}, {fileItem.mostLocalUrl()}, data); + QApplication::clipboard()->setMimeData(data); + }); + + KFileItemActions *actions = new KFileItemActions(menu); + KFileItemListProperties itemProperties(KFileItemList({fileItem})); + actions->setItemListProperties(itemProperties); + + actions->addOpenWithActionsTo(menu); + actions->addServiceActionsTo(menu); + actions->addPluginActionsTo(menu); + + if (menu->isEmpty()) { + delete menu; + return; + } + + if (ctx->window()->mouseGrabberItem()) { + ctx->window()->mouseGrabberItem()->ungrabMouse(); + } + + const QPoint pos = ctx->mapToGlobal(QPointF(x, y)).toPoint(); + menu->popup(pos); +} + void Thumbnailer::generatePreview() { if (!m_inited) {