]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/dolphinmainwindow.cpp
Keep working towards a reviewable state
[dolphin.git] / src / dolphinmainwindow.cpp
index 166091ca7e9ef70cf909952a365d141d02894ab1..fae30761e927e2b345f9b5a742f909c3c5ef712c 100644 (file)
@@ -9,7 +9,6 @@
 #include "dolphinmainwindow.h"
 
 #include "dolphinmainwindowadaptor.h"
-#include "config-terminal.h"
 #include "global.h"
 #include "dolphinbookmarkhandler.h"
 #include "dolphindockwidget.h"
@@ -49,7 +48,7 @@
 #include <KJobWidgets>
 #include <KLocalizedString>
 #include <KMessageBox>
-#include <KNS3/KMoreToolsMenuFactory>
+#include <KMoreToolsMenuFactory>
 #include <KProtocolInfo>
 #include <KProtocolManager>
 #include <KShell>
 
 namespace {
     // Used for GeneralSettings::version() to determine whether
-    // an updated version of Dolphin is running.
-    const int CurrentDolphinVersion = 201;
+    // an updated version of Dolphin is running, so as to migrate
+    // removed/renamed ...etc config entries; increment it in such
+    // cases
+    const int CurrentDolphinVersion = 202;
     // The maximum number of entries in the back/forward popup menu
     const int MaxNumberOfNavigationentries = 12;
     // The maximum number of "Activate Tab" shortcuts
@@ -164,6 +165,7 @@ DolphinMainWindow::DolphinMainWindow() :
     m_actionHandler = new DolphinViewActionHandler(actionCollection(), this);
     connect(m_actionHandler, &DolphinViewActionHandler::actionBeingHandled, this, &DolphinMainWindow::clearStatusBar);
     connect(m_actionHandler, &DolphinViewActionHandler::createDirectoryTriggered, this, &DolphinMainWindow::createDirectory);
+    connect(m_actionHandler, &DolphinViewActionHandler::setSelectionMode, this, &DolphinMainWindow::slotSetSelectionMode);
 
     m_remoteEncoding = new DolphinRemoteEncoding(this, m_actionHandler);
     connect(this, &DolphinMainWindow::urlChanged,
@@ -265,7 +267,7 @@ bool DolphinMainWindow::isFoldersPanelEnabled() const
 
 bool DolphinMainWindow::isInformationPanelEnabled() const
 {
-#ifdef HAVE_BALOO
+#if HAVE_BALOO
     return actionCollection()->action(QStringLiteral("show_information_panel"))->isChecked();
 #else
     return false;
@@ -284,6 +286,11 @@ void DolphinMainWindow::activateWindow()
     KWindowSystem::activateWindow(window()->effectiveWinId());
 }
 
+bool DolphinMainWindow::isActiveWindow()
+{
+    return window()->isActiveWindow();
+}
+
 void DolphinMainWindow::showCommand(CommandType command)
 {
     DolphinStatusBar* statusBar = m_activeViewContainer->statusBar();
@@ -655,12 +662,20 @@ void DolphinMainWindow::readProperties(const KConfigGroup& group)
 void DolphinMainWindow::updateNewMenu()
 {
     m_newFileMenu->checkUpToDate();
+#if KIO_VERSION >= QT_VERSION_CHECK(5, 97, 0)
+    m_newFileMenu->setWorkingDirectory(activeViewContainer()->url());
+#else
     m_newFileMenu->setPopupFiles(QList<QUrl>() << activeViewContainer()->url());
+#endif
 }
 
 void DolphinMainWindow::createDirectory()
 {
+#if KIO_VERSION >= QT_VERSION_CHECK(5, 97, 0)
+    m_newFileMenu->setWorkingDirectory(activeViewContainer()->url());
+#else
     m_newFileMenu->setPopupFiles(QList<QUrl>() << activeViewContainer()->url());
+#endif
     m_newFileMenu->createDirectory();
 }
 
@@ -699,12 +714,22 @@ void DolphinMainWindow::undo()
 
 void DolphinMainWindow::cut()
 {
-    m_activeViewContainer->view()->cutSelectedItemsToClipboard();
+    if (m_activeViewContainer->view()->selectedItems().isEmpty()) {
+        m_activeViewContainer->setSelectionModeEnabled(true, actionCollection(), SelectionModeBottomBar::Contents::CutContents);
+    } else {
+        m_activeViewContainer->view()->cutSelectedItemsToClipboard();
+        m_activeViewContainer->setSelectionModeEnabled(false);
+    }
 }
 
 void DolphinMainWindow::copy()
 {
-    m_activeViewContainer->view()->copySelectedItemsToClipboard();
+    if (m_activeViewContainer->view()->selectedItems().isEmpty()) {
+        m_activeViewContainer->setSelectionModeEnabled(true, actionCollection(), SelectionModeBottomBar::Contents::CopyContents);
+    } else {
+        m_activeViewContainer->view()->copySelectedItemsToClipboard();
+        m_activeViewContainer->setSelectionModeEnabled(false);
+    }
 }
 
 void DolphinMainWindow::paste()
@@ -749,13 +774,45 @@ void DolphinMainWindow::slotToolBarActionMiddleClicked(QAction *action)
     }
 }
 
+QAction *DolphinMainWindow::urlNavigatorHistoryAction(const KUrlNavigator *urlNavigator, int historyIndex, QObject *parent)
+{
+    const QUrl url = urlNavigator->locationUrl(historyIndex);
+
+    QString text = url.toDisplayString(QUrl::PreferLocalFile);
+
+    if (!urlNavigator->showFullPath()) {
+        const KFilePlacesModel *placesModel = DolphinPlacesModelSingleton::instance().placesModel();
+
+        const QModelIndex closestIdx = placesModel->closestItem(url);
+        if (closestIdx.isValid()) {
+            const QUrl placeUrl = placesModel->url(closestIdx);
+
+            text = placesModel->text(closestIdx);
+
+            QString pathInsidePlace = url.path().mid(placeUrl.path().length());
+
+            if (!pathInsidePlace.isEmpty() && !pathInsidePlace.startsWith(QLatin1Char('/'))) {
+                pathInsidePlace.prepend(QLatin1Char('/'));
+            }
+
+            if (pathInsidePlace != QLatin1Char('/')) {
+                text.append(pathInsidePlace);
+            }
+        }
+    }
+
+    QAction *action = new QAction(QIcon::fromTheme(KIO::iconNameForUrl(url)), text, parent);
+    action->setData(historyIndex);
+    return action;
+}
+
 void DolphinMainWindow::slotAboutToShowBackPopupMenu()
 {
     const KUrlNavigator *urlNavigator = m_activeViewContainer->urlNavigatorInternalWithHistory();
     int entries = 0;
     m_backAction->menu()->clear();
     for (int i = urlNavigator->historyIndex() + 1; i < urlNavigator->historySize() && entries < MaxNumberOfNavigationentries; ++i, ++entries) {
-        QAction* action = new QAction(urlNavigator->locationUrl(i).toDisplayString(QUrl::PreferLocalFile), m_backAction->menu());
+        QAction *action = urlNavigatorHistoryAction(urlNavigator, i, m_backAction->menu());
         action->setData(i);
         m_backAction->menu()->addAction(action);
     }
@@ -784,7 +841,7 @@ void DolphinMainWindow::slotAboutToShowForwardPopupMenu()
     int entries = 0;
     m_forwardAction->menu()->clear();
     for (int i = urlNavigator->historyIndex() - 1; i >= 0 && entries < MaxNumberOfNavigationentries; --i, ++entries) {
-        QAction* action = new QAction(urlNavigator->locationUrl(i).toDisplayString(QUrl::PreferLocalFile), m_forwardAction->menu());
+        QAction *action = urlNavigatorHistoryAction(urlNavigator, i, m_forwardAction->menu());
         action->setData(i);
         m_forwardAction->menu()->addAction(action);
     }
@@ -799,6 +856,11 @@ void DolphinMainWindow::slotGoForward(QAction* action)
     }
 }
 
+void DolphinMainWindow::slotSetSelectionMode(bool enabled, SelectionModeBottomBar::Contents bottomBarContents)
+{
+    m_activeViewContainer->setSelectionModeEnabled(enabled, actionCollection(), bottomBarContents);
+}
+
 void DolphinMainWindow::selectAll()
 {
     clearStatusBar();
@@ -838,6 +900,26 @@ void DolphinMainWindow::toggleSplitStash()
     tabPage->setSplitViewEnabled(true, WithAnimation, QUrl("stash:/"));
 }
 
+void DolphinMainWindow::copyToInactiveSplitView()
+{
+    if (m_activeViewContainer->view()->selectedItems().isEmpty()) {
+        m_activeViewContainer->setSelectionModeEnabled(true, actionCollection(), SelectionModeBottomBar::Contents::CopyToOtherViewContents);
+    } else {
+        m_tabWidget->copyToInactiveSplitView();
+        m_activeViewContainer->setSelectionModeEnabled(false);
+    }
+}
+
+void DolphinMainWindow::moveToInactiveSplitView()
+{
+    if (m_activeViewContainer->view()->selectedItems().isEmpty()) {
+        m_activeViewContainer->setSelectionModeEnabled(true, actionCollection(), SelectionModeBottomBar::Contents::MoveToOtherViewContents);
+    } else {
+        m_tabWidget->moveToInactiveSplitView();
+        m_activeViewContainer->setSelectionModeEnabled(false);
+    }
+}
+
 void DolphinMainWindow::reloadView()
 {
     clearStatusBar();
@@ -860,6 +942,14 @@ void DolphinMainWindow::disableStopAction()
     actionCollection()->action(QStringLiteral("stop"))->setEnabled(false);
 }
 
+void DolphinMainWindow::toggleSelectionMode()
+{
+    const bool checked = !m_activeViewContainer->isSelectionModeEnabled();
+
+    m_activeViewContainer->setSelectionModeEnabled(checked, actionCollection(), SelectionModeBottomBar::Contents::GeneralContents);
+    actionCollection()->action(QStringLiteral("toggle_selection_mode"))->setChecked(checked);
+}
+
 void DolphinMainWindow::showFilterBar()
 {
     m_activeViewContainer->setFilterBarVisible(true);
@@ -1055,8 +1145,48 @@ void DolphinMainWindow::openPreferredSearchTool()
 
 void DolphinMainWindow::openTerminal()
 {
-    const QUrl url = m_activeViewContainer->url();
+    openTerminalJob(m_activeViewContainer->url());
+}
+
+void DolphinMainWindow::openTerminalHere()
+{
+    QList<QUrl> urls = {};
+
+    for (const KFileItem& item : m_activeViewContainer->view()->selectedItems()) {
+        QUrl url = item.targetUrl();
+        if (item.isFile()) {
+            url.setPath(QFileInfo(url.path()).absolutePath());
+        }
+        if (!urls.contains(url)) {
+            urls << url;
+        }
+    }
+
+    // No items are selected. Open a terminal window for the current location.
+    if (urls.count() == 0) {
+        openTerminal();
+        return;
+    }
+
+    if (urls.count() > 5) {
+        QString question = i18np("Are you sure you want to open 1 terminal window?",
+                                 "Are you sure you want to open %1 terminal windows?", urls.count());
+        const int answer = KMessageBox::warningYesNo(this, question, {},
+                                                     KGuiItem(i18ncp("@action:button", "Open %1 Terminal", "Open %1 Terminals", urls.count()),
+                                                              QStringLiteral("utilities-terminal")),
+                                                     KStandardGuiItem::cancel());
+        if (answer != KMessageBox::Yes) {
+            return;
+        }
+    }
+
+    for (const QUrl& url : urls) {
+        openTerminalJob(url);
+    }
+}
 
+void DolphinMainWindow::openTerminalJob(const QUrl& url)
+{
     if (url.isLocalFile()) {
         auto job = new KTerminalLauncherJob(QString());
         job->setWorkingDirectory(url.toLocalFile());
@@ -1146,32 +1276,11 @@ void DolphinMainWindow::slotWriteStateChanged(bool isFolderWritable)
 
 void DolphinMainWindow::openContextMenu(const QPoint& pos,
                                         const KFileItem& item,
-                                        const QUrl& url,
-                                        const QList<QAction*>& customActions)
+                                        const KFileItemList &selectedItems,
+                                        const QUrl& url)
 {
-    QPointer<DolphinContextMenu> contextMenu = new DolphinContextMenu(this, pos, item, url, &m_fileItemActions);
-    contextMenu.data()->setCustomActions(customActions);
-    const DolphinContextMenu::Command command = contextMenu.data()->open();
-
-    switch (command) {
-    case DolphinContextMenu::OpenParentFolder:
-        changeUrl(KIO::upUrl(item.url()));
-        m_activeViewContainer->view()->markUrlsAsSelected({item.url()});
-        m_activeViewContainer->view()->markUrlAsCurrent(item.url());
-        break;
-
-    case DolphinContextMenu::OpenParentFolderInNewWindow:
-        Dolphin::openNewWindow({item.url()}, this, Dolphin::OpenNewWindowFlag::Select);
-        break;
-
-    case DolphinContextMenu::OpenParentFolderInNewTab:
-        openNewTab(KIO::upUrl(item.url()));
-        break;
-
-    case DolphinContextMenu::None:
-    default:
-        break;
-    }
+    QPointer<DolphinContextMenu> contextMenu = new DolphinContextMenu(this, item, selectedItems, url, &m_fileItemActions);
+    contextMenu.data()->exec(pos);
 
     // Delete the menu, unless it has been deleted in its own nested event loop already.
     if (contextMenu) {
@@ -1218,6 +1327,11 @@ void DolphinMainWindow::updateHamburgerMenu()
     menu->addAction(ac->action(QStringLiteral("go_forward")));
 
     menu->addMenu(m_newFileMenu->menu());
+    if (!toolBar()->isVisible()
+        || !toolbarActions.contains(ac->action(QStringLiteral("toggle_selection_mode_tool_bar")))
+    ) {
+        menu->addAction(ac->action(QStringLiteral("toggle_selection_mode")));
+    }
     menu->addAction(ac->action(QStringLiteral("basic_actions")));
     menu->addAction(ac->action(KStandardAction::name(KStandardAction::Undo)));
     if (!toolBar()->isVisible()
@@ -1497,7 +1611,7 @@ void DolphinMainWindow::setupActions()
     copyToOtherViewAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-copy")));
     copyToOtherViewAction->setIconText(i18nc("@action:inmenu Edit", "Copy to Inactive Split View"));
     actionCollection()->setDefaultShortcut(copyToOtherViewAction, Qt::SHIFT | Qt::Key_F5 );
-    connect(copyToOtherViewAction, &QAction::triggered, m_tabWidget, &DolphinTabWidget::copyToInactiveSplitView);
+    connect(copyToOtherViewAction, &QAction::triggered, this, &DolphinMainWindow::copyToInactiveSplitView);
 
     QAction* moveToOtherViewAction = actionCollection()->addAction(QStringLiteral("move_to_inactive_split_view"));
     moveToOtherViewAction->setText(i18nc("@action:inmenu", "Move to Inactive Split View"));
@@ -1506,7 +1620,7 @@ void DolphinMainWindow::setupActions()
     moveToOtherViewAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-cut")));
     moveToOtherViewAction->setIconText(i18nc("@action:inmenu Edit", "Move to Inactive Split View"));
     actionCollection()->setDefaultShortcut(moveToOtherViewAction, Qt::SHIFT | Qt::Key_F6 );
-    connect(moveToOtherViewAction, &QAction::triggered, m_tabWidget, &DolphinTabWidget::moveToInactiveSplitView);
+    connect(moveToOtherViewAction, &QAction::triggered, this, &DolphinMainWindow::moveToInactiveSplitView);
 
     QAction* showFilterBar = actionCollection()->addAction(QStringLiteral("show_filter_bar"));
     showFilterBar->setText(i18nc("@action:inmenu Tools", "Filter..."));
@@ -1552,6 +1666,33 @@ void DolphinMainWindow::setupActions()
     toggleSearchAction->setWhatsThis(searchAction->whatsThis());
     toggleSearchAction->setCheckable(true);
 
+    QAction *toggleSelectionModeAction = actionCollection()->addAction(QStringLiteral("toggle_selection_mode"));
+    // i18n: This action toggles a selection mode.
+    toggleSelectionModeAction->setText(i18nc("@action:inmenu", "Select Files and Folders"));
+    // i18n: Opens a selection mode for selecting files/folders and later selecting an action that acts on them.
+    // So in a way "Select" here is used to mean both "Select files" and also "Select what to do" but mostly the first.
+    // The text is kept so unspecific because it will be shown on the toolbar where space is at a premium.
+    toggleSelectionModeAction->setIconText(i18nc("@action:intoolbar", "Select"));
+    toggleSelectionModeAction->setWhatsThis(xi18nc("@info:whatsthis", "<para>This application only knows which files or folders should be acted on if they are"
+        " <emphasis>selected</emphasis> first. Press this to toggle a <emphasis>Selection Mode</emphasis> which makes selecting and deselecting as easy as "
+        "pressing an item once.</para><para>While in this mode, a quick access bar at the bottom shows available actions for the currently selected items."
+        "</para>"));
+    toggleSelectionModeAction->setIcon(QIcon::fromTheme(QStringLiteral("quickwizard")));
+    toggleSelectionModeAction->setCheckable(true);
+    actionCollection()->setDefaultShortcut(toggleSelectionModeAction, Qt::Key_Space );
+    connect(toggleSelectionModeAction, &QAction::triggered, this, &DolphinMainWindow::toggleSelectionMode);
+
+    // A special version of the toggleSelectionModeAction for the toolbar that also contains a menu
+    // with the selectAllAction and invertSelectionAction.
+    auto *toggleSelectionModeToolBarAction = new KToolBarPopupAction(toggleSelectionModeAction->icon(), toggleSelectionModeAction->iconText(), actionCollection());
+    toggleSelectionModeToolBarAction->setToolTip(toggleSelectionModeAction->text());
+    toggleSelectionModeToolBarAction->setWhatsThis(toggleSelectionModeAction->whatsThis());
+    actionCollection()->addAction(QStringLiteral("toggle_selection_mode_tool_bar"), toggleSelectionModeToolBarAction);
+    toggleSelectionModeToolBarAction->setCheckable(true);
+    toggleSelectionModeToolBarAction->setPopupMode(QToolButton::DelayedPopup);
+    connect(toggleSelectionModeToolBarAction, &QAction::triggered, toggleSelectionModeAction, &QAction::trigger);
+    connect(toggleSelectionModeAction, &QAction::toggled, toggleSelectionModeToolBarAction, &QAction::setChecked);
+
     QAction* selectAllAction = KStandardAction::selectAll(this, &DolphinMainWindow::selectAll, actionCollection());
     selectAllAction->setWhatsThis(xi18nc("@info:whatsthis", "This selects all "
         "files and folders in the current location."));
@@ -1564,6 +1705,11 @@ void DolphinMainWindow::setupActions()
     actionCollection()->setDefaultShortcut(invertSelection, Qt::CTRL | Qt::SHIFT | Qt::Key_A);
     connect(invertSelection, &QAction::triggered, this, &DolphinMainWindow::invertSelection);
 
+    QMenu *toggleSelectionModeActionMenu = new QMenu(this);
+    toggleSelectionModeActionMenu->addAction(selectAllAction);
+    toggleSelectionModeActionMenu->addAction(invertSelection);
+    toggleSelectionModeToolBarAction->setMenu(toggleSelectionModeActionMenu);
+
     // setup 'View' menu
     // (note that most of it is set up in DolphinViewActionHandler)
 
@@ -1710,7 +1856,17 @@ void DolphinMainWindow::setupActions()
         actionCollection()->setDefaultShortcut(openTerminal, Qt::SHIFT | Qt::Key_F4);
         connect(openTerminal, &QAction::triggered, this, &DolphinMainWindow::openTerminal);
 
-#ifdef HAVE_TERMINAL
+        QAction* openTerminalHere = actionCollection()->addAction(QStringLiteral("open_terminal_here"));
+        // i18n: "Here" refers to the location(s) of the currently selected item(s) or the currently viewed location if nothing is selected.
+        openTerminalHere->setText(i18nc("@action:inmenu Tools", "Open Terminal Here"));
+        openTerminalHere->setWhatsThis(xi18nc("@info:whatsthis",
+            "<para>This opens <emphasis>terminal</emphasis> applications for the selected items' locations.</para>"
+            "<para>To learn more about terminals use the help in the terminal application.</para>"));
+        openTerminalHere->setIcon(QIcon::fromTheme(QStringLiteral("utilities-terminal")));
+        actionCollection()->setDefaultShortcut(openTerminalHere, Qt::SHIFT | Qt::ALT | Qt::Key_F4);
+        connect(openTerminalHere, &QAction::triggered, this, &DolphinMainWindow::openTerminalHere);
+
+#if HAVE_TERMINAL
         QAction* focusTerminalPanel = actionCollection()->addAction(QStringLiteral("focus_terminal_panel"));
         focusTerminalPanel->setText(i18nc("@action:inmenu Tools", "Focus Terminal Panel"));
         focusTerminalPanel->setIcon(QIcon::fromTheme(QStringLiteral("swap-panels")));
@@ -1735,6 +1891,15 @@ void DolphinMainWindow::setupActions()
             "contain mostly the same commands and configuration options."));
     connect(showMenuBar, &KToggleAction::triggered,                   // Fixes #286822
             this, &DolphinMainWindow::toggleShowMenuBar, Qt::QueuedConnection);
+
+    KToggleAction* showStatusBar = KStandardAction::showStatusbar(nullptr, nullptr, actionCollection());
+    showStatusBar->setChecked(GeneralSettings::showStatusBar());
+    connect(GeneralSettings::self(), &GeneralSettings::showStatusBarChanged, showStatusBar, &KToggleAction::setChecked);
+    connect(showStatusBar, &KToggleAction::triggered, this, [this](bool checked) {
+        GeneralSettings::setShowStatusBar(checked);
+        refreshViews();
+    });
+
     KStandardAction::keyBindings(this, &DolphinMainWindow::slotKeyBindings, actionCollection());
     KStandardAction::preferences(this, &DolphinMainWindow::editSettings, actionCollection());
 
@@ -1837,7 +2002,7 @@ void DolphinMainWindow::setupDockWidgets()
     infoDock->setObjectName(QStringLiteral("infoDock"));
     infoDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
 
-#ifdef HAVE_BALOO
+#if HAVE_BALOO
     InformationPanel* infoPanel = new InformationPanel(infoDock);
     infoPanel->setCustomContextMenuActions({lockLayoutAction});
     connect(infoPanel, &InformationPanel::urlActivated, this, &DolphinMainWindow::handleUrl);
@@ -1861,7 +2026,7 @@ void DolphinMainWindow::setupDockWidgets()
     const QString panelWhatsThis = xi18nc("@info:whatsthis", "<para>To show or "
         "hide panels like this go to <interface>Control|Panels</interface> "
         "or <interface>View|Panels</interface>.</para>");
-#ifdef HAVE_BALOO
+#if HAVE_BALOO
     actionCollection()->action(QStringLiteral("show_information_panel"))
         ->setWhatsThis(xi18nc("@info:whatsthis", "<para> This toggles the "
         "<emphasis>information</emphasis> panel at the right side of the "
@@ -1913,7 +2078,7 @@ void DolphinMainWindow::setupDockWidgets()
         "This allows quick switching between any folders.</para>") + panelWhatsThis);
 
     // Setup "Terminal"
-#ifdef HAVE_TERMINAL
+#if HAVE_TERMINAL
     if (KAuthorized::authorize(QStringLiteral("shell_access"))) {
         DolphinDockWidget* terminalDock = new DolphinDockWidget(i18nc("@title:window Shell terminal", "Terminal"));
         terminalDock->setLocked(lock);
@@ -2038,7 +2203,7 @@ void DolphinMainWindow::setupDockWidgets()
     panelsMenu->setPopupMode(QToolButton::InstantPopup);
     const KActionCollection* ac = actionCollection();
     panelsMenu->addAction(ac->action(QStringLiteral("show_places_panel")));
-#ifdef HAVE_BALOO
+#if HAVE_BALOO
     panelsMenu->addAction(ac->action(QStringLiteral("show_information_panel")));
 #endif
     panelsMenu->addAction(ac->action(QStringLiteral("show_folders_panel")));
@@ -2059,6 +2224,11 @@ void DolphinMainWindow::updateFileAndEditActions()
     const KActionCollection* col = actionCollection();
     KFileItemListProperties capabilitiesSource(list);
 
+    QAction* renameAction            = col->action(KStandardAction::name(KStandardAction::RenameFile));
+    QAction* moveToTrashAction       = col->action(KStandardAction::name(KStandardAction::MoveToTrash));
+    QAction* deleteAction            = col->action(KStandardAction::name(KStandardAction::DeleteFile));
+    QAction* cutAction               = col->action(KStandardAction::name(KStandardAction::Cut));
+    QAction* duplicateAction         = col->action(QStringLiteral("duplicate")); // see DolphinViewActionHandler
     QAction* addToPlacesAction = col->action(QStringLiteral("add_to_places"));
     QAction* copyToOtherViewAction   = col->action(QStringLiteral("copy_to_inactive_split_view"));
     QAction* moveToOtherViewAction   = col->action(QStringLiteral("move_to_inactive_split_view"));
@@ -2067,20 +2237,19 @@ void DolphinMainWindow::updateFileAndEditActions()
     if (list.isEmpty()) {
         stateChanged(QStringLiteral("has_no_selection"));
 
+        // All actions that need a selection to function can be enabled because they should trigger selection mode.
+        renameAction->setEnabled(true);
+        moveToTrashAction->setEnabled(true);
+        deleteAction->setEnabled(true);
+        cutAction->setEnabled(true);
+        duplicateAction->setEnabled(true);
         addToPlacesAction->setEnabled(true);
-        copyToOtherViewAction->setEnabled(false);
-        moveToOtherViewAction->setEnabled(false);
-        copyLocation->setEnabled(false);
+        copyLocation->setEnabled(true);
     } else {
         stateChanged(QStringLiteral("has_selection"));
 
-        QAction* renameAction            = col->action(KStandardAction::name(KStandardAction::RenameFile));
-        QAction* moveToTrashAction       = col->action(KStandardAction::name(KStandardAction::MoveToTrash));
-        QAction* deleteAction            = col->action(KStandardAction::name(KStandardAction::DeleteFile));
-        QAction* cutAction               = col->action(KStandardAction::name(KStandardAction::Cut));
         QAction* deleteWithTrashShortcut = col->action(QStringLiteral("delete_shortcut")); // see DolphinViewActionHandler
         QAction* showTarget              = col->action(QStringLiteral("show_target"));
-        QAction* duplicateAction         = col->action(QStringLiteral("duplicate")); // see DolphinViewActionHandler
 
         if (list.length() == 1 && list.first().isDir()) {
             addToPlacesAction->setEnabled(true);
@@ -2088,23 +2257,6 @@ void DolphinMainWindow::updateFileAndEditActions()
             addToPlacesAction->setEnabled(false);
         }
 
-        if (m_tabWidget->currentTabPage()->splitViewEnabled()) {
-            DolphinTabPage* tabPage = m_tabWidget->currentTabPage();
-            KFileItem capabilitiesDestination;
-
-            if (tabPage->primaryViewActive()) {
-                capabilitiesDestination = tabPage->secondaryViewContainer()->url();
-            } else {
-                capabilitiesDestination = tabPage->primaryViewContainer()->url();
-            }
-
-            copyToOtherViewAction->setEnabled(capabilitiesDestination.isWritable());
-            moveToOtherViewAction->setEnabled(capabilitiesSource.supportsMoving() && capabilitiesDestination.isWritable());
-        } else {
-            copyToOtherViewAction->setEnabled(false);
-            moveToOtherViewAction->setEnabled(false);
-        }
-
         const bool enableMoveToTrash = capabilitiesSource.isLocal() && capabilitiesSource.supportsMoving();
 
         renameAction->setEnabled(capabilitiesSource.supportsMoving());
@@ -2116,12 +2268,36 @@ void DolphinMainWindow::updateFileAndEditActions()
         showTarget->setEnabled(list.length() == 1 && list.at(0).isLink());
         duplicateAction->setEnabled(capabilitiesSource.supportsWriting());
     }
+
+    if (m_tabWidget->currentTabPage()->splitViewEnabled()) {
+        DolphinTabPage* tabPage = m_tabWidget->currentTabPage();
+        KFileItem capabilitiesDestination;
+
+        if (tabPage->primaryViewActive()) {
+            capabilitiesDestination = tabPage->secondaryViewContainer()->url();
+        } else {
+            capabilitiesDestination = tabPage->primaryViewContainer()->url();
+        }
+
+        copyToOtherViewAction->setEnabled(capabilitiesDestination.isWritable());
+        moveToOtherViewAction->setEnabled((list.isEmpty() || capabilitiesSource.supportsMoving()) && capabilitiesDestination.isWritable());
+    } else {
+        copyToOtherViewAction->setEnabled(false);
+        moveToOtherViewAction->setEnabled(false);
+    }
 }
 
 void DolphinMainWindow::updateViewActions()
 {
     m_actionHandler->updateViewActions();
 
+    QAction *toggleSelectionModeAction = actionCollection()->action(QStringLiteral("toggle_selection_mode"));
+    disconnect(nullptr, &DolphinViewContainer::selectionModeChanged,
+               toggleSelectionModeAction, &QAction::setChecked);
+    toggleSelectionModeAction->setChecked(m_activeViewContainer->isSelectionModeEnabled());
+    connect(m_activeViewContainer, &DolphinViewContainer::selectionModeChanged,
+            toggleSelectionModeAction, &QAction::setChecked);
+
     QAction* toggleFilterBarAction = actionCollection()->action(QStringLiteral("toggle_filter"));
     toggleFilterBarAction->setChecked(m_activeViewContainer->isFilterBarVisible());
 
@@ -2563,8 +2739,12 @@ void DolphinMainWindow::UndoUiInterface::jobError(KIO::Job* job)
     }
 }
 
-bool DolphinMainWindow::isUrlOpen(const QStringurl)
+bool DolphinMainWindow::isUrlOpen(const QString &url)
 {
-    return m_tabWidget->isUrlOpen(QUrl::fromUserInput((url)));
+    return m_tabWidget->isUrlOpen(QUrl::fromUserInput(url));
 }
 
+bool DolphinMainWindow::isUrlOrParentOpen(const QString &url)
+{
+    return m_tabWidget->isUrlOrParentOpen(QUrl::fromUserInput(url));
+}