┌   ┐
54
└   ┘

summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlbert Mkhitaryan <[email protected]>2026-02-20 08:48:54 +0000
committerMéven Car <[email protected]>2026-02-20 08:48:54 +0000
commitdb49ac4e1916f87143574b064b36ec86f8407145 (patch)
tree9620cb68a243caf018473f93833da8e52c57973e /src
parent2438a457bf7499c91e3b035ed10ade41ac632660 (diff)
Add keyboard shortcut support for service menu actions
Introduce ServiceMenuShortcutManager, which registers all service menu actions with KActionCollection at startup allowing users to assign keyboard shortcuts in Configure Keyboard Shorcuts. Save/Load of configs happens via KXMLGUI in dolphinui.rc. Notes: - Manager initializes before setupGUI() for shortcut restoration - Execution and validation handled entirely by KFileItemAction in KIO. BUG: 260266
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt7
-rw-r--r--src/dolphincontextmenu.cpp2
-rw-r--r--src/dolphinmainwindow.cpp22
-rw-r--r--src/dolphinmainwindow.h2
-rw-r--r--src/servicemenushortcutmanager.cpp81
-rw-r--r--src/servicemenushortcutmanager.h42
6 files changed, 152 insertions, 4 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 3cf10f486..4faabe9d5 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -457,6 +457,13 @@ if(HAVE_KUSERFEEDBACK)
)
endif()
+if(KF6KIO_VERSION VERSION_GREATER_EQUAL "6.24.0")
+ target_sources(dolphinstatic PRIVATE
+ servicemenushortcutmanager.cpp
+ servicemenushortcutmanager.h
+ )
+endif()
+
kconfig_add_kcfg_files(dolphinstatic
panels/folders/dolphin_folderspanelsettings.kcfgc
panels/places/dolphin_placespanelsettings.kcfgc
diff --git a/src/dolphincontextmenu.cpp b/src/dolphincontextmenu.cpp
index 577990e19..6fb362039 100644
--- a/src/dolphincontextmenu.cpp
+++ b/src/dolphincontextmenu.cpp
@@ -268,8 +268,6 @@ void DolphinContextMenu::addItemContextMenu()
const KFileItemListProperties &selectedItemsProps = selectedItemsProperties();
- m_fileItemActions->setItemListProperties(selectedItemsProps);
-
if (m_selectedItems.count() == 1) {
// single files
if (m_fileInfo.isDir()) {
diff --git a/src/dolphinmainwindow.cpp b/src/dolphinmainwindow.cpp
index 62ff2fa45..110bef2f3 100644
--- a/src/dolphinmainwindow.cpp
+++ b/src/dolphinmainwindow.cpp
@@ -28,6 +28,9 @@
#include "panels/terminal/terminalpanel.h"
#include "search/dolphinquery.h"
#include "selectionmode/actiontexthelper.h"
+#if KIO_VERSION >= QT_VERSION_CHECK(6, 24, 0)
+#include "servicemenushortcutmanager.h"
+#endif
#include "settings/dolphinsettingsdialog.h"
#include "statusbar/diskspaceusagemenu.h"
#include "statusbar/dolphinstatusbar.h"
@@ -206,6 +209,11 @@ DolphinMainWindow::DolphinMainWindow()
setupDockWidgets();
+#if KIO_VERSION >= QT_VERSION_CHECK(6, 24, 0)
+ m_serviceMenuShortcutManager = new ServiceMenuShortcutManager(actionCollection(), this);
+#endif
+ setupFileItemActions();
+
const bool usePhoneUi{KRuntimePlatform::runtimePlatform().contains(QLatin1String("phone"))};
setupGUI(Save | Create | ToolBar, usePhoneUi ? QStringLiteral("dolphinuiforphones.rc") : QString() /* load the default dolphinui.rc file */);
stateChanged(QStringLiteral("new_file"));
@@ -256,8 +264,6 @@ DolphinMainWindow::DolphinMainWindow()
QTimer::singleShot(0, this, &DolphinMainWindow::updateOpenPreferredSearchToolAction);
- setupFileItemActions();
-
m_serviceMenuConfigWatcher = KConfigWatcher::create(KSharedConfig::openConfig(QStringLiteral("kservicemenurc")));
connect(m_serviceMenuConfigWatcher.data(), &KConfigWatcher::configChanged, this, [this](const KConfigGroup & /*group*/, const QByteArrayList & /*names*/) {
setupFileItemActions();
@@ -431,6 +437,10 @@ void DolphinMainWindow::slotSelectionChanged(const KFileItemList &selection)
{
updateFileAndEditActions();
+ if (m_fileItemActions) {
+ m_fileItemActions->setItemListProperties(KFileItemListProperties(selection));
+ }
+
const int selectedUrlsCount = m_tabWidget->currentTabPage()->selectedItemsCount();
QAction *compareFilesAction = actionCollection()->action(QStringLiteral("compare_files"));
@@ -1783,6 +1793,10 @@ void DolphinMainWindow::slotStorageTearDownExternallyRequested(const QString &mo
void DolphinMainWindow::slotKeyBindings()
{
+#if KIO_VERSION >= QT_VERSION_CHECK(6, 24, 0)
+ m_serviceMenuShortcutManager->cleanupStaleShortcuts(this);
+#endif
+
KShortcutsDialog dialog(KShortcutsEditor::AllActions, KShortcutsEditor::LetterShortcutsAllowed, this);
dialog.addCollection(actionCollection());
if (m_terminalPanel) {
@@ -2624,6 +2638,10 @@ void DolphinMainWindow::setupFileItemActions()
connect(m_fileItemActions, &KFileItemActions::error, this, [this](const QString &errorMessage) {
showErrorMessage(errorMessage);
});
+
+#if KIO_VERSION >= QT_VERSION_CHECK(6, 24, 0)
+ m_serviceMenuShortcutManager->refresh(m_fileItemActions);
+#endif
}
void DolphinMainWindow::updateFileAndEditActions()
diff --git a/src/dolphinmainwindow.h b/src/dolphinmainwindow.h
index a03d566d0..cd9f238aa 100644
--- a/src/dolphinmainwindow.h
+++ b/src/dolphinmainwindow.h
@@ -49,6 +49,7 @@ class KToolBarPopupAction;
class QToolButton;
class PlacesPanel;
class TerminalPanel;
+class ServiceMenuShortcutManager;
/** Used to identify that a custom command should be triggered on a view background double-click.*/
constexpr QLatin1String customCommand{"CUSTOM_COMMAND"};
@@ -801,6 +802,7 @@ private:
QMenu m_searchTools;
KConfigWatcher::Ptr m_serviceMenuConfigWatcher;
KFileItemActions *m_fileItemActions = nullptr;
+ ServiceMenuShortcutManager *m_serviceMenuShortcutManager = nullptr;
QTimer *m_sessionSaveTimer;
QFutureWatcher<void> *m_sessionSaveWatcher;
diff --git a/src/servicemenushortcutmanager.cpp b/src/servicemenushortcutmanager.cpp
new file mode 100644
index 000000000..ea13fc5f8
--- /dev/null
+++ b/src/servicemenushortcutmanager.cpp
@@ -0,0 +1,81 @@
+/*
+ * SPDX-FileCopyrightText: 2026 Albert Mkhitaryan <[email protected]>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <servicemenushortcutmanager.h>
+
+#include <KActionCategory>
+#include <KActionCollection>
+#include <KDesktopFileAction>
+#include <KFileItemActions>
+#include <KLocalizedString>
+#include <KXMLGUIClient>
+#include <KXMLGUIFactory>
+
+#include <QAction>
+#include <QDomDocument>
+#include <QFileInfo>
+
+static constexpr QLatin1String serviceMenuNamePrefix("servicemenu_");
+
+ServiceMenuShortcutManager::ServiceMenuShortcutManager(KActionCollection *actionCollection, QObject *parent)
+ : QObject(parent)
+ , m_actionCollection(actionCollection)
+ , m_category(new KActionCategory(i18nc("@title:group", "Context Menu Actions"), actionCollection))
+{
+}
+
+void ServiceMenuShortcutManager::refresh(KFileItemActions *fileItemActions)
+{
+ // Uses takeAction() to remove without deleting. Actions are owned by KFileItemActions
+ // and are deleted when called createServiceMenuActions() or destroyed
+ for (const QString &name : std::as_const(m_actionNames)) {
+ m_actionCollection->takeAction(m_actionCollection->action(name));
+ }
+ m_actionNames.clear();
+
+ // Get action->execution mapping from KIO
+ const QList<QAction *> actions = fileItemActions->createServiceMenuActions();
+
+ for (QAction *action : actions) {
+ const auto desktopAction = action->data().value<KDesktopFileAction>();
+ const QString fileName = QFileInfo(desktopAction.desktopFilePath()).fileName();
+ const QString name = serviceMenuNamePrefix + fileName + QLatin1String("::") + desktopAction.actionsKey();
+ m_category->addAction(name, action);
+ m_actionNames.append(name);
+ }
+}
+
+void ServiceMenuShortcutManager::cleanupStaleShortcuts(KXMLGUIClient *client)
+{
+ const QString file = client->localXMLFile();
+ if (file.isEmpty()) {
+ return;
+ }
+
+ const QString xml = KXMLGUIFactory::readConfigFile(file, client->componentName());
+ if (xml.isEmpty()) {
+ return;
+ }
+
+ QDomDocument doc;
+ doc.setContent(xml);
+ QDomElement actionPropElement = KXMLGUIFactory::actionPropertiesElement(doc);
+
+ bool modified = false;
+ for (QDomElement e = actionPropElement.firstChildElement(); !e.isNull();) {
+ QDomElement next = e.nextSiblingElement();
+ const QString name = e.attribute(QStringLiteral("name"));
+ if (name.startsWith(serviceMenuNamePrefix) && !m_actionNames.contains(name)) {
+ actionPropElement.removeChild(e);
+ modified = true;
+ }
+ e = next;
+ }
+
+ if (modified) {
+ KXMLGUIFactory::saveConfigFile(doc, file, client->componentName());
+ }
+} \ No newline at end of file
diff --git a/src/servicemenushortcutmanager.h b/src/servicemenushortcutmanager.h
new file mode 100644
index 000000000..10502c341
--- /dev/null
+++ b/src/servicemenushortcutmanager.h
@@ -0,0 +1,42 @@
+/*
+ * SPDX-FileCopyrightText: 2026 Albert Mkhitaryan <[email protected]>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef SERVICEMENUSHORTCUTMANAGER_H
+#define SERVICEMENUSHORTCUTMANAGER_H
+
+#include <QObject>
+#include <QStringList>
+
+class KActionCategory;
+class KActionCollection;
+class KFileItemActions;
+class KXMLGUIClient;
+
+/**
+ * @brief Registers service menu actions with KActionCollection for keyboard shortcuts.
+ *
+ * This lightweight manager bridges KIO's service menu actions with Dolphin's
+ * shortcut system. Actions are obtained from KFileItemActions and registered
+ * with the action collection. Execution is handled entirely by KFileItemActions.
+ *
+ */
+class ServiceMenuShortcutManager : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit ServiceMenuShortcutManager(KActionCollection *actionCollection, QObject *parent = nullptr);
+
+ void refresh(KFileItemActions *fileItemaActions);
+ void cleanupStaleShortcuts(KXMLGUIClient *client);
+
+private:
+ KActionCollection *m_actionCollection;
+ KActionCategory *m_category;
+ QStringList m_actionNames;
+};
+
+#endif // SERVICEMENUSHORTCUTMANAGER_H