[frameworks/kio] src/widgets: kfileitemactions: Correctly count actionsMenu actions

Antti Savolainen <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit 148b9253db6bec16244db2d55d73270a918dd87c by Antti Savolainen.
Committed on 05/08/2026 at 22:44.
Pushed by asavolainen into branch 'master'.

kfileitemactions: Correctly count actionsMenu actions

kio used to rely on predictive heuristics for how many actions the
Actions menu would contain:

if (s.user.count() + s.userSubmenus.count() + s.userPriority.count() +
s.userPrioritySubmenus.count() + additionalActions.count() > 3) {

This however didn't take into account plugins that insert actions to the
right click menu. Predicting them is hard because a plugin can insert
0, 1, 2, or more actions. This change inserts the actions into a holder
and decides if a submenu is needed after it has been generated.

M  +48   -29   src/widgets/kfileitemactions.cpp
M  +2    -2    src/widgets/kfileitemactions_p.h

https://invent.kde.org/frameworks/kio/-/commit/148b9253db6bec16244db2d55d73270a918dd87c

diff --git a/src/widgets/kfileitemactions.cpp b/src/widgets/kfileitemactions.cpp
index 3885cf4f82..b1446eff47 100644
--- a/src/widgets/kfileitemactions.cpp
+++ b/src/widgets/kfileitemactions.cpp
@@ -309,20 +309,41 @@ void KFileItemActions::setItemListProperties(const KFileItemListProperties &item
     }
 }
 
-void KFileItemActions::addActionsTo(QMenu *menu, MenuActionSources sources, const QList<QAction *> &additionalActions, const QStringList &excludeList)
+void KFileItemActions::addActionsTo(QMenu *mainMenu, MenuActionSources sources, const QList<QAction *> &additionalActions, const QStringList &excludeList)
 {
-    QMenu *actionsMenu = menu;
+    QMenu *mainMenuHolder = new QMenu();
+    QMenu *actionsMenuHolder = new QMenu();
     if (sources & MenuActionSource::Services) {
-        actionsMenu = d->addServiceActionsTo(menu, additionalActions, excludeList).menu;
+        d->addServiceActionsTo(mainMenuHolder, actionsMenuHolder, additionalActions, excludeList);
     } else {
         // Since we didn't call addServiceActionsTo(), we have to add additional actions manually
         for (QAction *action : additionalActions) {
-            actionsMenu->addAction(action);
+            actionsMenuHolder->addAction(action);
         }
     }
     if (sources & MenuActionSource::Plugins) {
-        d->addPluginActionsTo(menu, actionsMenu, excludeList);
+        d->addPluginActionsTo(mainMenuHolder, actionsMenuHolder, excludeList);
     }
+
+    QMenu *actionsMenu;
+    if (actionsMenuHolder->actions().size() > 4) {
+        actionsMenu = new QMenu(i18nc("@title:menu", "&Actions"), mainMenu);
+        actionsMenu->setIcon(QIcon::fromTheme(QStringLiteral("view-more-symbolic")));
+        actionsMenu->menuAction()->setObjectName(QStringLiteral("actions_submenu")); // for the unittest
+        mainMenu->addMenu(actionsMenu);
+    } else {
+        actionsMenu = mainMenu;
+    }
+
+    for (QAction *action : actionsMenuHolder->actions()) {
+        actionsMenu->addAction(action);
+    }
+    for (QAction *action : mainMenuHolder->actions()) {
+        mainMenu->addAction(action);
+    }
+
+    delete mainMenuHolder;
+    delete actionsMenuHolder;
 }
 
 // static
@@ -524,8 +545,10 @@ bool KFileItemActionsPrivate::checkTypesMatch(const KConfigGroup &cfg) const
     });
 }
 
-KFileItemActionsPrivate::ServiceActionInfo
-KFileItemActionsPrivate::addServiceActionsTo(QMenu *mainMenu, const QList<QAction *> &additionalActions, const QStringList &excludeList)
+void KFileItemActionsPrivate::addServiceActionsTo(QMenu *mainMenuHolder,
+                                                  QMenu *actionsMenuHolder,
+                                                  const QList<QAction *> &additionalActions,
+                                                  const QStringList &excludeList)
 {
     const KFileItemList items = m_props.items();
     const KFileItem &firstItem = items.first();
@@ -579,32 +602,23 @@ KFileItemActionsPrivate::addServiceActionsTo(QMenu *mainMenu, const QList<QActio
         }
     }
 
-    QMenu *actionMenu = mainMenu;
     int userItemCount = 0;
-    if (s.user.count() + s.userSubmenus.count() + s.userPriority.count() + s.userPrioritySubmenus.count() + additionalActions.count() > 3) {
-        // we have more than three items, so let's make a submenu
-        actionMenu = new QMenu(i18nc("@title:menu", "&Actions"), mainMenu);
-        actionMenu->setIcon(QIcon::fromTheme(QStringLiteral("view-more-symbolic")));
-        actionMenu->menuAction()->setObjectName(QStringLiteral("actions_submenu")); // for the unittest
-        mainMenu->addMenu(actionMenu);
-    }
-
     userItemCount += additionalActions.count();
     for (QAction *action : additionalActions) {
-        actionMenu->addAction(action);
+        actionsMenuHolder->addAction(action);
     }
-    userItemCount += insertServicesSubmenus(s.userPrioritySubmenus, actionMenu);
-    userItemCount += insertServices(s.userPriority, actionMenu);
-    userItemCount += insertServicesSubmenus(s.userSubmenus, actionMenu);
-    userItemCount += insertServices(s.user, actionMenu);
+    userItemCount += insertServicesSubmenus(s.userPrioritySubmenus, actionsMenuHolder);
+    userItemCount += insertServices(s.userPriority, actionsMenuHolder);
+    userItemCount += insertServicesSubmenus(s.userSubmenus, actionsMenuHolder);
+    userItemCount += insertServices(s.user, actionsMenuHolder);
 
-    userItemCount += insertServicesSubmenus(s.userToplevelSubmenus, mainMenu);
-    userItemCount += insertServices(s.userToplevel, mainMenu);
+    userItemCount += insertServicesSubmenus(s.userToplevelSubmenus, mainMenuHolder);
+    userItemCount += insertServices(s.userToplevel, mainMenuHolder);
 
-    return {userItemCount, actionMenu};
+    // return {userItemCount, actionMenu};
 }
 
-int KFileItemActionsPrivate::addPluginActionsTo(QMenu *mainMenu, QMenu *actionsMenu, const QStringList &excludeList)
+void KFileItemActionsPrivate::addPluginActionsTo(QMenu *mainMenuHolder, QMenu *actionsMenuHolder, const QStringList &excludeList)
 {
     QString commonMimeType = m_props.mimeType();
     if (commonMimeType.isEmpty() && m_props.isFile()) {
@@ -624,6 +638,7 @@ int KFileItemActionsPrivate::addPluginActionsTo(QMenu *mainMenu, QMenu *actionsM
         });
     });
 
+    QList<QAction *> iconAction;
     for (const auto &jsonMetadata : jsonPlugins) {
         // The plugin has been disabled
         const QString pluginId = jsonMetadata.pluginId();
@@ -646,14 +661,18 @@ int KFileItemActionsPrivate::addPluginActionsTo(QMenu *mainMenu, QMenu *actionsM
             const QList<QAction *> actions = abstractPlugin->actions(m_props, m_parentWidget);
             itemCount += actions.count();
             if (jsonMetadata.value(QStringLiteral("X-KDE-Show-In-Submenu"), false)) {
-                actionsMenu->addActions(actions);
+                if (pluginId == QLatin1String("setfoldericonitemaction")) {
+                    iconAction = actions;
+                } else {
+                    actionsMenuHolder->addActions(actions);
+                }
             } else {
-                mainMenu->addActions(actions);
+                mainMenuHolder->addActions(actions);
             }
         }
     }
-
-    return itemCount;
+    actionsMenuHolder->addActions(iconAction);
+    // return itemCount;
 }
 
 KService::List KFileItemActionsPrivate::associatedApplications(const QStringList &mimeTypeList, const QStringList &excludedDesktopEntryNames)
diff --git a/src/widgets/kfileitemactions_p.h b/src/widgets/kfileitemactions_p.h
index fdcd20b658..ae415f8505 100644
--- a/src/widgets/kfileitemactions_p.h
+++ b/src/widgets/kfileitemactions_p.h
@@ -57,8 +57,8 @@ public:
         int userItemCount = 0;
         QMenu *menu = nullptr;
     };
-    ServiceActionInfo addServiceActionsTo(QMenu *mainMenu, const QList<QAction *> &additionalActions, const QStringList &excludeList);
-    int addPluginActionsTo(QMenu *mainMenu, QMenu *actionsMenu, const QStringList &excludeList);
+    void addServiceActionsTo(QMenu *mainMenuHolder, QMenu *actionsMenuHolder, const QList<QAction *> &additionalActions, const QStringList &excludeList);
+    void addPluginActionsTo(QMenu *mainMenuHolder, QMenu *actionsMenuHolder, const QStringList &excludeList);
     void insertOpenWithActionsTo(QAction *before, QMenu *topMenu, const QStringList &excludedDesktopEntryNames);
     static KService::List associatedApplications(const QStringList &mimeTypeList, const QStringList &excludedDesktopEntryNames);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.