]> cloud.milkyroute.net Git - dolphin.git/commitdiff
Re-arrange the contents of the hamburger menu
authorFelix Ernst <fe.a.ernst@gmail.com>
Thu, 13 May 2021 16:49:27 +0000 (16:49 +0000)
committerNate Graham <nate@kde.org>
Thu, 13 May 2021 16:49:27 +0000 (16:49 +0000)
To improve usability, the entries in the hamburger menu are
changed. Maybe the biggest fault of the previous menu contents were
that there were too many actions.

The new menu contents are composed of all the actions which are
necessary to use Dolphin and those which are very useful and should
be of interest for most users. Some menu contents change depending
on the state of the application. We can be more bold in only
showing what really seems necessary because this commit activates
the special sub-menu of KHamburgerMenu that helps users discover
all further features of Dolphin.

The hamburger menu is from now on also added to the context menus
in the view when both the menu bar and toolbar are hidden. This
allows users to hide both of them and still use all features of
Dolphin.

src/dolphincontextmenu.cpp
src/dolphinmainwindow.cpp
src/dolphinmainwindow.h
src/views/dolphinviewactionhandler.cpp
src/views/dolphinviewactionhandler.h

index ed6db0c124becb54106c94b24c8d4b4d7165a271..4b287981c9f286ddfdabf23456838dded649a4f0 100644 (file)
@@ -22,6 +22,7 @@
 #include <KActionCollection>
 #include <KFileItemActions>
 #include <KFileItemListProperties>
+#include <KHamburgerMenu>
 #include <KIO/EmptyTrashJob>
 #include <KIO/JobUiDelegate>
 #include <KIO/Paste>
@@ -64,6 +65,9 @@ DolphinContextMenu::DolphinContextMenu(DolphinMainWindow* parent,
     m_selectedItems = view->selectedItems();
 
     installEventFilter(this);
+
+    static_cast<KHamburgerMenu *>(m_mainWindow->actionCollection()->
+                action(QStringLiteral("hamburger_menu")))->addToMenu(this);
 }
 
 DolphinContextMenu::~DolphinContextMenu()
@@ -149,8 +153,6 @@ void DolphinContextMenu::openTrashContextMenu()
     QAction* propertiesAction = m_mainWindow->actionCollection()->action(QStringLiteral("properties"));
     addAction(propertiesAction);
 
-    addShowMenuBarAction();
-
     if (exec(m_pos) == emptyTrashAction) {
         Trash::empty(m_mainWindow);
     }
@@ -361,8 +363,6 @@ void DolphinContextMenu::openViewportContextMenu()
     QAction* propertiesAction = m_mainWindow->actionCollection()->action(QStringLiteral("properties"));
     addAction(propertiesAction);
 
-    addShowMenuBarAction();
-
     exec(m_pos);
 }
 
@@ -423,16 +423,6 @@ void DolphinContextMenu::insertDefaultItemActions(const KFileItemListProperties&
     }
 }
 
-void DolphinContextMenu::addShowMenuBarAction()
-{
-    const KActionCollection* ac = m_mainWindow->actionCollection();
-    QAction* showMenuBar = ac->action(KStandardAction::name(KStandardAction::ShowMenubar));
-    if (!m_mainWindow->menuBar()->isVisible() && !m_mainWindow->toolBar()->isVisible()) {
-        addSeparator();
-        addAction(showMenuBar);
-    }
-}
-
 bool DolphinContextMenu::placeExists(const QUrl& url) const
 {
     const KFilePlacesModel* placesModel = DolphinPlacesModelSingleton::instance().placesModel();
index e9c0c3813f5e5b55b7414381475e2b9f624844c2..87deb8ca610850050f726c68c18bb3d0e2188e87 100644 (file)
@@ -187,8 +187,7 @@ DolphinMainWindow::DolphinMainWindow() :
     auto hamburgerMenu = static_cast<KHamburgerMenu *>(actionCollection()->action(
                                     KStandardAction::name(KStandardAction::HamburgerMenu)));
     hamburgerMenu->setMenuBar(menuBar());
-    hamburgerMenu->setMenuBarAdvertised(false); // This line will soon be removed when the
-                                                // hamburger menu contents are re-arranged.
+    hamburgerMenu->setShowMenuBarAction(showMenuBarAction);
     connect(hamburgerMenu, &KHamburgerMenu::aboutToShowMenu,
             this, &DolphinMainWindow::updateHamburgerMenu);
     hamburgerMenu->hideActionsOf(toolBar());
@@ -1163,58 +1162,81 @@ void DolphinMainWindow::updateHamburgerMenu()
     if (!menu) {
         menu = new QMenu(this);
         hamburgerMenu->setMenu(menu);
+        hamburgerMenu->hideActionsOf(ac->action(QStringLiteral("basic_actions"))->menu());
+        hamburgerMenu->hideActionsOf(ac->action(QStringLiteral("zoom"))->menu());
     } else {
         menu->clear();
     }
+    const QList<QAction *> toolbarActions = toolBar()->actions();
 
-    menu->addMenu(m_newFileMenu->menu());
-    menu->addAction(ac->action(QStringLiteral("file_new")));
-    menu->addAction(ac->action(QStringLiteral("new_tab")));
-    menu->addAction(ac->action(QStringLiteral("closed_tabs")));
-
-    menu->addSeparator();
-
-    // Add "Edit" actions
-    menu->addAction(ac->action(KStandardAction::name(KStandardAction::Undo)));
-    menu->addAction(ac->action(QString("copy_location")));
-    menu->addAction(ac->action(QStringLiteral("copy_to_inactive_split_view")));
-    menu->addAction(ac->action(QStringLiteral("move_to_inactive_split_view")));
-    menu->addAction(ac->action(KStandardAction::name(KStandardAction::SelectAll)));
-    menu->addAction(ac->action(QStringLiteral("invert_selection")));
-
-    menu->addSeparator();
-
-    // Add "View" actions
-    if (!GeneralSettings::showZoomSlider()) {
-        menu->addAction(ac->action(KStandardAction::name(KStandardAction::ZoomIn)));
-        menu->addAction(ac->action(QStringLiteral("view_zoom_reset")));
-        menu->addAction(ac->action(KStandardAction::name(KStandardAction::ZoomOut)));
+    if (!toolBar()->isVisible()) {
+        // If neither the menu bar nor the toolbar are visible, these actions should be available.
+        menu->addAction(ac->action(KStandardAction::name(KStandardAction::ShowMenubar)));
+        menu->addAction(toolBarMenuAction());
         menu->addSeparator();
     }
 
-    menu->addAction(ac->action(QStringLiteral("show_preview")));
-    menu->addAction(ac->action(QStringLiteral("show_in_groups")));
-    menu->addAction(ac->action(QStringLiteral("show_hidden_files")));
-    menu->addAction(ac->action(QStringLiteral("additional_info")));
-    menu->addAction(ac->action(QStringLiteral("view_properties")));
+    // This group of actions (until the next separator) contains all the most basic actions
+    // necessary to use Dolphin effectively.
+    menu->addAction(ac->action(QStringLiteral("go_back")));
+    menu->addAction(ac->action(QStringLiteral("go_forward")));
 
+    menu->addMenu(m_newFileMenu->menu());
+    menu->addAction(ac->action(QStringLiteral("basic_actions")));
+    menu->addAction(ac->action(KStandardAction::name(KStandardAction::Undo)));
+    if (!toolBar()->isVisible()
+        || (!toolbarActions.contains(ac->action(QStringLiteral("toggle_search")))
+            && !toolbarActions.contains(ac->action(QStringLiteral("open_preferred_search_tool"))))
+    ) {
+        menu->addAction(ac->action(KStandardAction::name(KStandardAction::Find)));
+        // This way a search action will only be added if none of the three available
+        // search actions is present on the toolbar.
+    }
+    if (!toolBar()->isVisible()
+        || !toolbarActions.contains(ac->action(QStringLiteral("toggle_filter")))
+    ) {
+        menu->addAction(ac->action(QStringLiteral("show_filter_bar")));
+        // This way a filter action will only be added if none of the two available
+        // filter actions is present on the toolbar.
+    }
     menu->addSeparator();
 
-    // Add a curated assortment of items from the "Tools" menu
-    menu->addAction(ac->action(QStringLiteral("show_filter_bar")));
-    menu->addAction(ac->action(QStringLiteral("open_preferred_search_tool")));
+    // The second group of actions (up until the next separator) contains actions for opening
+    // additional views to interact with the file system.
+    menu->addAction(ac->action(QStringLiteral("file_new")));
+    menu->addAction(ac->action(QStringLiteral("new_tab")));
+    if (ac->action(QStringLiteral("undo_close_tab"))->isEnabled()) {
+        menu->addAction(ac->action(QStringLiteral("closed_tabs")));
+    }
     menu->addAction(ac->action(QStringLiteral("open_terminal")));
-
     menu->addSeparator();
 
-    // Add "Show Panels" menu
+    // The third group contains actions to change what one sees in the view
+    // and to change the more general UI.
+    if (!toolBar()->isVisible()
+        || (!toolbarActions.contains(ac->action(QStringLiteral("icons")))
+            && !toolbarActions.contains(ac->action(QStringLiteral("compact")))
+            && !toolbarActions.contains(ac->action(QStringLiteral("details")))
+            && !toolbarActions.contains(ac->action(QStringLiteral("view_mode"))))
+    ) {
+        menu->addAction(ac->action(QStringLiteral("view_mode")));
+    }
+    menu->addAction(ac->action(QStringLiteral("show_hidden_files")));
+    menu->addAction(ac->action(QStringLiteral("additional_info")));
+    if (!GeneralSettings::showStatusBar() || !GeneralSettings::showZoomSlider()) {
+        menu->addAction(ac->action(QStringLiteral("zoom")));
+    }
     menu->addAction(ac->action(QStringLiteral("panels")));
 
-    // Add "Settings" menu entries
-    menu->addAction(ac->action(KStandardAction::name(KStandardAction::KeyBindings)));
-    menu->addAction(ac->action(KStandardAction::name(KStandardAction::ConfigureToolbars)));
-    menu->addAction(ac->action(KStandardAction::name(KStandardAction::Preferences)));
-    menu->addAction(ac->action(KStandardAction::name(KStandardAction::ShowMenubar)));
+    // The "Configure" menu is not added to the actionCollection() because there is hardly
+    // a good reason for users to put it on their toolbar.
+    auto configureMenu = menu->addMenu(QIcon::fromTheme(QStringLiteral("configure")),
+                            i18nc("@action:inmenu menu for configure actions", "Configure"));
+    configureMenu->addAction(ac->action(KStandardAction::name(KStandardAction::SwitchApplicationLanguage)));
+    configureMenu->addAction(ac->action(KStandardAction::name(KStandardAction::KeyBindings)));
+    configureMenu->addAction(ac->action(KStandardAction::name(KStandardAction::ConfigureToolbars)));
+    configureMenu->addAction(ac->action(KStandardAction::name(KStandardAction::Preferences)));
+    hamburgerMenu->hideActionsOf(configureMenu);
 }
 
 void DolphinMainWindow::slotPlaceActivated(const QUrl& url)
index 3c83b21789afd16b6722bc9f73e8145e1b2b6b29..2b8165ea418c2cfc52e26e681827157d5d87595a 100644 (file)
@@ -473,6 +473,11 @@ private Q_SLOTS:
 
     /**
      * Updates the menu that is by default at the right end of the toolbar.
+     *
+     * In true "simple by default" fashion, the menu only contains the most important
+     * and necessary actions to be able to use Dolphin. This is supposed to hold true even
+     * if the user does not know how to open a context menu. More advanced actions can be
+     * discovered through a sub-menu (@see KConfigWidgets::KHamburgerMenu::setMenuBarAdvertised()).
      */
     void updateHamburgerMenu();
 
index 236daed5f7dd3b2dbe58bbe32a034e32c759a665..4acc420b023ca1ba7920d767a839d26ad2dc47f7 100644 (file)
@@ -18,6 +18,7 @@
 #endif
 #include <KActionCollection>
 #include <KActionMenu>
+#include <KFileItemListProperties>
 #include <KLocalizedString>
 #include <KNewFileMenu>
 #include <KPropertiesDialog>
@@ -68,6 +69,9 @@ void DolphinViewActionHandler::setCurrentView(DolphinView* view)
             this, &DolphinViewActionHandler::slotZoomLevelChanged);
     connect(view, &DolphinView::writeStateChanged,
             this, &DolphinViewActionHandler::slotWriteStateChanged);
+    connect(view, &DolphinView::selectionChanged,
+            this, &DolphinViewActionHandler::slotSelectionChanged);
+    slotSelectionChanged(m_currentView->selectedItems());
 }
 
 DolphinView* DolphinViewActionHandler::currentView()
@@ -155,6 +159,25 @@ void DolphinViewActionHandler::createActions()
     m_actionCollection->setDefaultShortcuts(copyPathAction, {Qt::CTRL | Qt::ALT | Qt::Key_C});
     connect(copyPathAction, &QAction::triggered, this, &DolphinViewActionHandler::slotCopyPath);
 
+    // This menu makes sure that users who don't know how to open a context menu and haven't
+    // figured out how to enable the menu bar can still perform basic file manipulation.
+    // This only works if they know how to select a file.
+    // The text when nothing is selected at least implies that a selection can /somehow/ be made.
+    // This menu is by default only used in the hamburger menu but created here so users can put
+    // it on their toolbar.
+    KActionMenu *basicActionsMenu = m_actionCollection->add<KActionMenu>(QStringLiteral("basic_actions"), this);
+    // The text is set later depending on the selection in the currently active view.
+    basicActionsMenu->setPopupMode(QToolButton::InstantPopup);
+    basicActionsMenu->addAction(m_actionCollection->action(KStandardAction::name(KStandardAction::Cut)));
+    basicActionsMenu->addAction(m_actionCollection->action(KStandardAction::name(KStandardAction::Copy)));
+    basicActionsMenu->addAction(m_actionCollection->action(KStandardAction::name(KStandardAction::Paste)));
+    basicActionsMenu->addSeparator();
+    basicActionsMenu->addAction(m_actionCollection->action(KStandardAction::name(KStandardAction::RenameFile)));
+    basicActionsMenu->addAction(m_actionCollection->action(KStandardAction::name(KStandardAction::MoveToTrash)));
+    basicActionsMenu->addSeparator();
+    basicActionsMenu->addAction(m_actionCollection->action(QStringLiteral("properties")));
+    basicActionsMenu->addSeparator(); // We add one more separator because we sometimes add contextual
+                                      // actions in slotSelectionChanged() after the static ones above.
 
     // View menu
     KToggleAction* iconsAction = iconsModeAction();
@@ -208,6 +231,14 @@ void DolphinViewActionHandler::createActions()
                              m_actionCollection);
     zoomOutAction->setWhatsThis(i18nc("@info:whatsthis zoom out", "This reduces the icon size."));
 
+    KActionMenu* zoomMenu = m_actionCollection->add<KActionMenu>(QStringLiteral("zoom"));
+    zoomMenu->setText(i18nc("@action:inmenu menu of zoom actions", "Zoom"));
+    zoomMenu->setIcon(QIcon::fromTheme(QStringLiteral("zoom")));
+    zoomMenu->setPopupMode(QToolButton::InstantPopup);
+    zoomMenu->addAction(zoomInAction);
+    zoomMenu->addAction(zoomResetAction);
+    zoomMenu->addAction(zoomOutAction);
+
     KToggleAction* showPreview = m_actionCollection->add<KToggleAction>(QStringLiteral("show_preview"));
     showPreview->setText(i18nc("@action:intoolbar", "Show Previews"));
     showPreview->setToolTip(i18nc("@info", "Show preview of files and folders"));
@@ -709,3 +740,69 @@ void DolphinViewActionHandler::slotCopyPath()
 {
     m_currentView->copyPathToClipboard();
 }
+
+void DolphinViewActionHandler::slotSelectionChanged(const KFileItemList& selection)
+{
+    QString basicActionsMenuText;
+    switch (selection.count()) {
+    case 0:
+        basicActionsMenuText =
+            i18nc("@action:inmenu menu with actions like copy, paste, rename. The user's selection is empty when this text is shown.",
+                  "Actions for Current View");
+        break;
+    case 1:
+        basicActionsMenuText =
+            i18nc("@action:inmenu menu with actions like copy, paste, rename. %1 is the name of the singular selected file/folder.",
+                  "Actions for \"%1\"", selection.first().name());
+        break;
+    case 2:
+        basicActionsMenuText =
+            i18nc("@action:inmenu menu with actions like copy, paste, rename. %1 and %2 are names of files/folders.",
+                  "Actions for \"%1\" and \"%2\"", selection.first().name(), selection.last().name());
+        break;
+    case 3:
+        basicActionsMenuText =
+            i18nc("@action:inmenu menu with actions like copy, paste, rename. %1, %2 and %3 are names of files/folders.",
+                  "Actions for \"%1\", \"%2\" and \"%3\"",
+                  selection.first().name(), selection.at(1).name(), selection.last().name());
+        break;
+    default:
+        basicActionsMenuText = QString();
+        break;
+    }
+
+    // At some point the added clarity from the text starts being less important than the menu width.
+    if (basicActionsMenuText.isEmpty() || basicActionsMenuText.length() > 40) {
+        const KFileItemListProperties properties(selection);
+        if (properties.isFile()) {
+            basicActionsMenuText =
+                i18ncp("@action:inmenu menu with actions like copy, paste, rename. %1 is the amount of selected files/folders.",
+                       "Actions for One Selected File", "Actions for %1 Selected Files", selection.count());
+        } else if (properties.isDirectory()) {
+            basicActionsMenuText =
+                i18ncp("@action:inmenu menu with actions like copy, paste, rename. %1 is the amount of selected files/folders.",
+                       "Actions for One Selected Folder", "Actions for %1 Selected Folders", selection.count());
+        } else {
+            basicActionsMenuText =
+                i18ncp("@action:inmenu menu with actions like copy, paste, rename. %1 is the amount of selected files/folders.",
+                       "Actions for One Selected Item", "Actions for %1 Selected Items", selection.count());
+        }
+    }
+
+    QAction *basicActionsMenu = m_actionCollection->action(QStringLiteral("basic_actions"));
+    basicActionsMenu->setText(basicActionsMenuText);
+
+    // Add or remove contextual actions
+    auto basicActionsMenuActions = basicActionsMenu->menu()->actions();
+    while (!basicActionsMenu->menu()->actions().constLast()->isSeparator()) {
+        basicActionsMenu->menu()->removeAction(basicActionsMenu->menu()->actions().last());
+    }
+    if (selection.count() == 1) {
+        if (selection.first().isLink()) {
+            basicActionsMenu->menu()->addAction(m_actionCollection->action(QStringLiteral("show_target")));
+        }
+        if (selection.first().isDir()) {
+            basicActionsMenu->menu()->addAction(m_actionCollection->action(QStringLiteral("add_to_places")));
+        }
+    }
+}
index 23b4e5f1ada5114b69e2d11f6e8ee82c524a5148..3f73153ea66f9d6b15c1c4efd5769358f1ab936e 100644 (file)
@@ -19,6 +19,7 @@ class QAction;
 class QActionGroup;
 class DolphinView;
 class KActionCollection;
+class KFileItemList;
 
 /**
  * @short Handles all actions for DolphinView
@@ -211,6 +212,13 @@ private Q_SLOTS:
      */
     void slotCopyPath();
 
+    /**
+     * Changes the name of the menu that contains basic actions like "Copy", "Rename", ...
+     * The name is changed to something like "Actions for 3 Selected Items" to be extra
+     * explicit of how these basic actions are used.
+     */
+    void slotSelectionChanged(const KFileItemList& selection);
+
 private:
     /**
      * Create all the actions.