]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/dolphinmainwindow.cpp
Properly use X11 startup ids
[dolphin.git] / src / dolphinmainwindow.cpp
index 62e347032be8604f65b8d29c0af7491230507834..f3ec70753ca4f502b10fda1a3ea2915602cbd460 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"
 #include "dolphinnavigatorswidgetaction.h"
 #include "dolphinnewfilemenu.h"
 #include "dolphinrecenttabsmenu.h"
+#include "dolphinplacesmodelsingleton.h"
 #include "dolphinurlnavigatorscontroller.h"
 #include "dolphinviewcontainer.h"
 #include "dolphintabpage.h"
 #include "middleclickactioneventfilter.h"
 #include "panels/folders/folderspanel.h"
-#include "panels/places/placesitemmodel.h"
 #include "panels/places/placespanel.h"
 #include "panels/terminal/terminalpanel.h"
+#include "selectionmode/actiontexthelper.h"
 #include "settings/dolphinsettingsdialog.h"
 #include "statusbar/dolphinstatusbar.h"
 #include "views/dolphinviewactionhandler.h"
 #include <KConfigGui>
 #include <KDualAction>
 #include <KFileItemListProperties>
-#include <KHelpMenu>
 #include <KIO/CommandLauncherJob>
+#include <kio_version.h>
+#if KIO_VERSION >= QT_VERSION_CHECK(5, 98, 0)
+#include <KIO/JobUiDelegateFactory>
+#else
 #include <KIO/JobUiDelegate>
+#endif
 #include <KIO/OpenFileManagerWindowJob>
 #include <KIO/OpenUrlJob>
 #include <KJobWidgets>
 #include <KLocalizedString>
 #include <KMessageBox>
-#include <KNS3/KMoreToolsMenuFactory>
+#include <KMoreToolsMenuFactory>
 #include <KProtocolInfo>
 #include <KProtocolManager>
 #include <KShell>
+#include <KShortcutsDialog>
 #include <KStandardAction>
 #include <KStartupInfo>
 #include <KSycoca>
+#include <KTerminalLauncherJob>
 #include <KToggleAction>
 #include <KToolBar>
 #include <KToolBarPopupAction>
-#include <KToolInvocation>
 #include <KUrlComboBox>
 #include <KUrlNavigator>
 #include <KWindowSystem>
 #include <KXMLGUIFactory>
 
+#include <kwidgetsaddons_version.h>
 #include <kio_version.h>
 
 #include <QApplication>
 #include <QStandardPaths>
 #include <QTimer>
 #include <QToolButton>
-#include <QWhatsThisClickedEvent>
 
 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
@@ -96,15 +103,12 @@ namespace {
 DolphinMainWindow::DolphinMainWindow() :
     KXmlGuiWindow(nullptr),
     m_newFileMenu(nullptr),
-    m_helpMenu(nullptr),
     m_tabWidget(nullptr),
     m_activeViewContainer(nullptr),
     m_actionHandler(nullptr),
     m_remoteEncoding(nullptr),
     m_settingsDialog(),
     m_bookmarkHandler(nullptr),
-    m_controlButton(nullptr),
-    m_updateToolBarTimer(nullptr),
     m_lastHandleUrlOpenJob(nullptr),
     m_terminalPanel(nullptr),
     m_placesPanel(nullptr),
@@ -122,13 +126,15 @@ DolphinMainWindow::DolphinMainWindow() :
     setComponentName(QStringLiteral("dolphin"), QGuiApplication::applicationDisplayName());
     setObjectName(QStringLiteral("Dolphin#"));
 
+    setStateConfigGroup("State");
+
     connect(&DolphinNewFileMenuObserver::instance(), &DolphinNewFileMenuObserver::errorMessage,
             this, &DolphinMainWindow::showErrorMessage);
 
     KIO::FileUndoManager* undoManager = KIO::FileUndoManager::self();
     undoManager->setUiInterface(new UndoUiInterface());
 
-    connect(undoManager, QOverload<bool>::of(&KIO::FileUndoManager::undoAvailable),
+    connect(undoManager, &KIO::FileUndoManager::undoAvailable,
             this, &DolphinMainWindow::slotUndoAvailable);
     connect(undoManager, &KIO::FileUndoManager::undoTextChanged,
             this, &DolphinMainWindow::slotUndoTextChanged);
@@ -156,11 +162,13 @@ DolphinMainWindow::DolphinMainWindow() :
             this, &DolphinMainWindow::updateWindowTitle);
     setCentralWidget(m_tabWidget);
 
+    m_actionTextHelper = new SelectionMode::ActionTextHelper(this);
     setupActions();
 
-    m_actionHandler = new DolphinViewActionHandler(actionCollection(), this);
+    m_actionHandler = new DolphinViewActionHandler(actionCollection(), m_actionTextHelper, this);
     connect(m_actionHandler, &DolphinViewActionHandler::actionBeingHandled, this, &DolphinMainWindow::clearStatusBar);
     connect(m_actionHandler, &DolphinViewActionHandler::createDirectoryTriggered, this, &DolphinMainWindow::createDirectory);
+    connect(m_actionHandler, &DolphinViewActionHandler::selectionModeChangeTriggered, this, &DolphinMainWindow::slotSetSelectionMode);
 
     m_remoteEncoding = new DolphinRemoteEncoding(this, m_actionHandler);
     connect(this, &DolphinMainWindow::urlChanged,
@@ -168,7 +176,7 @@ DolphinMainWindow::DolphinMainWindow() :
 
     setupDockWidgets();
 
-    setupGUI(Keys | Save | Create | ToolBar);
+    setupGUI(Save | Create | ToolBar);
     stateChanged(QStringLiteral("new_file"));
 
     QClipboard* clipboard = QApplication::clipboard();
@@ -206,7 +214,7 @@ DolphinMainWindow::DolphinMainWindow() :
 
     setupWhatsThis();
 
-    connect(KSycoca::self(), QOverload<>::of(&KSycoca::databaseChanged), this, &DolphinMainWindow::updateOpenPreferredSearchToolAction);
+    connect(KSycoca::self(), &KSycoca::databaseChanged, this, &DolphinMainWindow::updateOpenPreferredSearchToolAction);
 
     QTimer::singleShot(0, this, &DolphinMainWindow::updateOpenPreferredSearchToolAction);
 
@@ -214,6 +222,9 @@ DolphinMainWindow::DolphinMainWindow() :
     connect(&m_fileItemActions, &KFileItemActions::error, this, [this](const QString &errorMessage) {
         showErrorMessage(errorMessage);
     });
+
+    connect(GeneralSettings::self(), &GeneralSettings::splitViewChanged,
+            this, &DolphinMainWindow::slotSplitViewChanged);
 }
 
 DolphinMainWindow::~DolphinMainWindow()
@@ -259,7 +270,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;
@@ -271,11 +282,22 @@ void DolphinMainWindow::openFiles(const QStringList& files, bool splitView)
     openFiles(QUrl::fromStringList(files), splitView);
 }
 
-void DolphinMainWindow::activateWindow()
+void DolphinMainWindow::activateWindow(const QString &activationToken)
 {
     window()->setAttribute(Qt::WA_NativeWindow, true);
-    KStartupInfo::setNewStartupId(window()->windowHandle(), KStartupInfo::startupId());
-    KWindowSystem::activateWindow(window()->effectiveWinId());
+
+    if (KWindowSystem::isPlatformWayland()) {
+        KWindowSystem::setCurrentXdgActivationToken(activationToken);
+    } else {
+        KStartupInfo::setNewStartupId(window()->windowHandle(), activationToken.toUtf8());
+    }
+
+    KWindowSystem::activateWindow(window()->windowHandle());
+}
+
+bool DolphinMainWindow::isActiveWindow()
+{
+    return window()->isActiveWindow();
 }
 
 void DolphinMainWindow::showCommand(CommandType command)
@@ -421,14 +443,13 @@ void DolphinMainWindow::addToPlaces()
         name = dirToAdd.name();
     }
     if (url.isValid()) {
-        PlacesItemModel model;
         QString icon;
         if (m_activeViewContainer->isSearchModeEnabled()) {
             icon = QStringLiteral("folder-saved-search-symbolic");
         } else {
             icon = KIO::iconNameForUrl(url);
         }
-        model.createPlacesItem(name, url, icon);
+        DolphinPlacesModelSingleton::instance().placesModel()->addPlace(name, url, icon);
     }
 }
 
@@ -437,6 +458,22 @@ void DolphinMainWindow::openNewTab(const QUrl& url)
     m_tabWidget->openNewTab(url, QUrl());
 }
 
+void DolphinMainWindow::openNewTabAndActivate(const QUrl &url)
+{
+    m_tabWidget->openNewActivatedTab(url, QUrl());
+}
+
+void DolphinMainWindow::openNewWindow(const QUrl &url)
+{
+    Dolphin::openNewWindow({url}, this);
+}
+
+void DolphinMainWindow::slotSplitViewChanged()
+{
+    m_tabWidget->currentTabPage()->setSplitViewEnabled(GeneralSettings::splitView(), WithAnimation);
+    updateSplitAction();
+}
+
 void DolphinMainWindow::openInNewTab()
 {
     const KFileItemList& list = m_activeViewContainer->view()->selectedItems();
@@ -633,15 +670,21 @@ void DolphinMainWindow::readProperties(const KConfigGroup& group)
 
 void DolphinMainWindow::updateNewMenu()
 {
-    m_newFileMenu->setViewShowsHiddenFiles(activeViewContainer()->view()->hiddenFilesShown());
     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()
 {
-    m_newFileMenu->setViewShowsHiddenFiles(activeViewContainer()->view()->hiddenFilesShown());
+#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();
 }
 
@@ -680,12 +723,22 @@ void DolphinMainWindow::undo()
 
 void DolphinMainWindow::cut()
 {
-    m_activeViewContainer->view()->cutSelectedItemsToClipboard();
+    if (m_activeViewContainer->view()->selectedItems().isEmpty()) {
+        m_activeViewContainer->setSelectionModeEnabled(true, actionCollection(), SelectionMode::BottomBar::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(), SelectionMode::BottomBar::Contents::CopyContents);
+    } else {
+        m_activeViewContainer->view()->copySelectedItemsToClipboard();
+        m_activeViewContainer->setSelectionModeEnabled(false);
+    }
 }
 
 void DolphinMainWindow::paste()
@@ -730,14 +783,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).toString(QUrl::PreferLocalFile), m_backAction->menu());
-        action->setData(i);
+        QAction *action = urlNavigatorHistoryAction(urlNavigator, i, m_backAction->menu());
         m_backAction->menu()->addAction(action);
     }
 }
@@ -765,8 +849,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).toString(QUrl::PreferLocalFile), m_forwardAction->menu());
-        action->setData(i);
+        QAction *action = urlNavigatorHistoryAction(urlNavigator, i, m_forwardAction->menu());
         m_forwardAction->menu()->addAction(action);
     }
 }
@@ -780,6 +863,11 @@ void DolphinMainWindow::slotGoForward(QAction* action)
     }
 }
 
+void DolphinMainWindow::slotSetSelectionMode(bool enabled, SelectionMode::BottomBar::Contents bottomBarContents)
+{
+    m_activeViewContainer->setSelectionModeEnabled(enabled, actionCollection(), bottomBarContents);
+}
+
 void DolphinMainWindow::selectAll()
 {
     clearStatusBar();
@@ -819,6 +907,26 @@ void DolphinMainWindow::toggleSplitStash()
     tabPage->setSplitViewEnabled(true, WithAnimation, QUrl("stash:/"));
 }
 
+void DolphinMainWindow::copyToInactiveSplitView()
+{
+    if (m_activeViewContainer->view()->selectedItems().isEmpty()) {
+        m_activeViewContainer->setSelectionModeEnabled(true, actionCollection(), SelectionMode::BottomBar::Contents::CopyToOtherViewContents);
+    } else {
+        m_tabWidget->copyToInactiveSplitView();
+        m_activeViewContainer->setSelectionModeEnabled(false);
+    }
+}
+
+void DolphinMainWindow::moveToInactiveSplitView()
+{
+    if (m_activeViewContainer->view()->selectedItems().isEmpty()) {
+        m_activeViewContainer->setSelectionModeEnabled(true, actionCollection(), SelectionMode::BottomBar::Contents::MoveToOtherViewContents);
+    } else {
+        m_tabWidget->moveToInactiveSplitView();
+        m_activeViewContainer->setSelectionModeEnabled(false);
+    }
+}
+
 void DolphinMainWindow::reloadView()
 {
     clearStatusBar();
@@ -841,6 +949,14 @@ void DolphinMainWindow::disableStopAction()
     actionCollection()->action(QStringLiteral("stop"))->setEnabled(false);
 }
 
+void DolphinMainWindow::toggleSelectionMode()
+{
+    const bool checked = !m_activeViewContainer->isSelectionModeEnabled();
+
+    m_activeViewContainer->setSelectionModeEnabled(checked, actionCollection(), SelectionMode::BottomBar::Contents::GeneralContents);
+    actionCollection()->action(QStringLiteral("toggle_selection_mode"))->setChecked(checked);
+}
+
 void DolphinMainWindow::showFilterBar()
 {
     m_activeViewContainer->setFilterBarVisible(true);
@@ -893,6 +1009,8 @@ void DolphinMainWindow::togglePanelLockState()
         }
     }
 
+    DolphinPlacesModelSingleton::instance().placesModel()->setPanelsLocked(newLockState);
+
     GeneralSettings::setLockPanels(newLockState);
 }
 
@@ -1011,7 +1129,11 @@ void DolphinMainWindow::updateOpenPreferredSearchToolAction()
     if (tool) {
         openPreferredSearchTool->setVisible(true);
         openPreferredSearchTool->setText(i18nc("@action:inmenu Tools", "Open %1", tool->text()));
-        openPreferredSearchTool->setIcon(tool->icon());
+        // Only override with the app icon if it is the default, i.e. the user hasn't configured one manually
+        // https://bugs.kde.org/show_bug.cgi?id=442815
+        if (openPreferredSearchTool->icon().name() == QLatin1String("search")) {
+            openPreferredSearchTool->setIcon(tool->icon());
+        }
     } else {
         openPreferredSearchTool->setVisible(false);
         // still visible in Shortcuts configuration window
@@ -1030,10 +1152,60 @@ 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());
+#if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0)
+        const int answer = KMessageBox::warningTwoActions(this, question, {},
+#else
+        const int answer = KMessageBox::warningYesNo(this, question, {},
+#endif
+                                                     KGuiItem(i18ncp("@action:button", "Open %1 Terminal", "Open %1 Terminals", urls.count()),
+                                                              QStringLiteral("utilities-terminal")),
+                                                     KStandardGuiItem::cancel());
+#if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0)
+        if (answer != KMessageBox::PrimaryAction) {
+#else
+        if (answer != KMessageBox::Yes) {
+#endif
+            return;
+        }
+    }
+
+    for (const QUrl& url : urls) {
+        openTerminalJob(url);
+    }
+}
 
+void DolphinMainWindow::openTerminalJob(const QUrl& url)
+{
     if (url.isLocalFile()) {
-        KToolInvocation::invokeTerminal(QString(), {}, url.toLocalFile());
+        auto job = new KTerminalLauncherJob(QString());
+        job->setWorkingDirectory(url.toLocalFile());
+        job->start();
         return;
     }
 
@@ -1047,14 +1219,18 @@ void DolphinMainWindow::openTerminal()
                 statUrl = job->mostLocalUrl();
             }
 
-            KToolInvocation::invokeTerminal(QString(), {}, statUrl.isLocalFile() ? statUrl.toLocalFile() : QDir::homePath());
+            auto job = new KTerminalLauncherJob(QString());
+            job->setWorkingDirectory(statUrl.isLocalFile() ? statUrl.toLocalFile() : QDir::homePath());
+            job->start();
         });
 
         return;
     }
 
     // Nothing worked, just use $HOME
-    KToolInvocation::invokeTerminal(QString(), {}, QDir::homePath());
+    auto job = new KTerminalLauncherJob(QString());
+    job->setWorkingDirectory(QDir::homePath());
+    job->start();
 }
 
 void DolphinMainWindow::editSettings()
@@ -1085,7 +1261,11 @@ void DolphinMainWindow::handleUrl(const QUrl& url)
         activeViewContainer()->setUrl(url);
     } else {
         m_lastHandleUrlOpenJob = new KIO::OpenUrlJob(url);
+#if KIO_VERSION >= QT_VERSION_CHECK(5, 98, 0)
+        m_lastHandleUrlOpenJob->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this));
+#else
         m_lastHandleUrlOpenJob->setUiDelegate(new KIO::JobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this));
+#endif
         m_lastHandleUrlOpenJob->setShowOpenOrExecuteDialog(true);
 
         connect(m_lastHandleUrlOpenJob, &KIO::OpenUrlJob::mimeTypeFound, this,
@@ -1115,32 +1295,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) {
@@ -1148,6 +1307,16 @@ void DolphinMainWindow::openContextMenu(const QPoint& pos,
     }
 }
 
+QMenu *DolphinMainWindow::createPopupMenu()
+{
+    QMenu *menu = KXmlGuiWindow::createPopupMenu();
+
+    menu->addSeparator();
+    menu->addAction(actionCollection()->action(QStringLiteral("lock_panels")));
+
+    return menu;
+}
+
 void DolphinMainWindow::updateHamburgerMenu()
 {
     KActionCollection* ac = actionCollection();
@@ -1177,6 +1346,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()
@@ -1281,6 +1455,10 @@ void DolphinMainWindow::activeViewChanged(DolphinViewContainer* viewContainer)
         // except the requestItemInfo so that on hover the information panel can still be updated
         connect(oldViewContainer->view(), &DolphinView::requestItemInfo,
                 this, &DolphinMainWindow::requestItemInfo);
+
+        // Disconnect other slots.
+        disconnect(nullptr, &DolphinViewContainer::selectionModeChanged,
+                   actionCollection()->action(QStringLiteral("toggle_selection_mode")), &QAction::setChecked);
     }
 
     connectViewSignals(viewContainer);
@@ -1344,6 +1522,19 @@ void DolphinMainWindow::slotStorageTearDownExternallyRequested(const QString& mo
     }
 }
 
+void DolphinMainWindow::slotKeyBindings()
+{
+    KShortcutsDialog dialog(KShortcutsEditor::AllActions, KShortcutsEditor::LetterShortcutsAllowed, this);
+    dialog.addCollection(actionCollection());
+    if (m_terminalPanel) {
+        KActionCollection *konsolePartActionCollection = m_terminalPanel->actionCollection();
+        if (konsolePartActionCollection) {
+            dialog.addCollection(konsolePartActionCollection, QStringLiteral("KonsolePart"));
+        }
+    }
+    dialog.configure();
+}
+
 void DolphinMainWindow::setViewsToHomeIfMountPathOpen(const QString& mountPath)
 {
     const QVector<DolphinViewContainer*> theViewContainers = viewContainers();
@@ -1357,7 +1548,7 @@ void DolphinMainWindow::setViewsToHomeIfMountPathOpen(const QString& mountPath)
 
 void DolphinMainWindow::setupActions()
 {
-    KStandardAction::hamburgerMenu(nullptr, nullptr, actionCollection());
+    auto hamburgerMenuAction = KStandardAction::hamburgerMenu(nullptr, nullptr, actionCollection());
 
     // setup 'File' menu
     m_newFileMenu = new DolphinNewFileMenu(actionCollection(), this);
@@ -1416,12 +1607,14 @@ void DolphinMainWindow::setupActions()
         "next to each other on the keyboard: <shortcut>Ctrl+X</shortcut>, "
         "<shortcut>Ctrl+C</shortcut> and <shortcut>Ctrl+V</shortcut>.</para>");
     QAction* cutAction = KStandardAction::cut(this, &DolphinMainWindow::cut, actionCollection());
+    m_actionTextHelper->registerTextWhenNothingIsSelected(cutAction, i18nc("@action", "Cut…"));
     cutAction->setWhatsThis(xi18nc("@info:whatsthis cut", "This copies the items "
         "in your current selection to the <emphasis>clipboard</emphasis>.<nl/>"
         "Use the <emphasis>Paste</emphasis> action afterwards to copy them from "
         "the clipboard to a new location. The items will be removed from their "
         "initial location.") + cutCopyPastePara);
     QAction* copyAction = KStandardAction::copy(this, &DolphinMainWindow::copy, actionCollection());
+    m_actionTextHelper->registerTextWhenNothingIsSelected(copyAction, i18nc("@action", "Copy…"));
     copyAction->setWhatsThis(xi18nc("@info:whatsthis copy", "This copies the "
         "items in your current selection to the <emphasis>clipboard</emphasis>."
         "<nl/>Use the <emphasis>Paste</emphasis> action afterwards to copy them "
@@ -1438,25 +1631,27 @@ void DolphinMainWindow::setupActions()
 
     QAction* copyToOtherViewAction = actionCollection()->addAction(QStringLiteral("copy_to_inactive_split_view"));
     copyToOtherViewAction->setText(i18nc("@action:inmenu", "Copy to Inactive Split View"));
+    m_actionTextHelper->registerTextWhenNothingIsSelected(copyToOtherViewAction, i18nc("@action:inmenu", "Copy to Inactive Split View…"));
     copyToOtherViewAction->setWhatsThis(xi18nc("@info:whatsthis Copy", "This copies the selected items from "
         "the <emphasis>active</emphasis> view to the inactive split view."));
     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"));
+    m_actionTextHelper->registerTextWhenNothingIsSelected(moveToOtherViewAction, i18nc("@action:inmenu", "Move to Inactive Split View…"));
     moveToOtherViewAction->setWhatsThis(xi18nc("@info:whatsthis Move", "This moves the selected items from "
         "the <emphasis>active</emphasis> view to the inactive split view."));
     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..."));
-    showFilterBar->setToolTip(i18nc("@info:tooltip", "Toggle Filter Bar"));
+    showFilterBar->setToolTip(i18nc("@info:tooltip", "Show Filter Bar"));
     showFilterBar->setWhatsThis(xi18nc("@info:whatsthis", "This opens the "
         "<emphasis>Filter Bar</emphasis> at the bottom of the window.<nl/> "
         "There you can enter a text to filter the files and folders currently displayed. "
@@ -1498,6 +1693,32 @@ 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.
+    // 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."));
@@ -1510,6 +1731,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)
 
@@ -1656,7 +1882,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")));
@@ -1676,24 +1912,25 @@ void DolphinMainWindow::setupActions()
     // setup 'Settings' menu
     KToggleAction* showMenuBar = KStandardAction::showMenubar(nullptr, nullptr, actionCollection());
     showMenuBar->setWhatsThis(xi18nc("@info:whatsthis",
-            "This switches between having a <emphasis>Menubar</emphasis> "
-            "and having a <interface>Control</interface> button. Both "
-            "contain mostly the same commands and configuration options."));
+            "<para>This switches between having a <emphasis>Menubar</emphasis> "
+            "and having a <interface>%1</interface> button. Both "
+            "contain mostly the same actions and configuration options.</para>"
+            "<para>The Menubar takes up more space but allows for fast and organised access to all "
+            "actions an application has to offer.</para><para>The <interface>%1</interface> button "
+            "is simpler and small which makes triggering advanced actions more time consuming.</para>", hamburgerMenuAction->text().replace('&', "")));
     connect(showMenuBar, &KToggleAction::triggered,                   // Fixes #286822
             this, &DolphinMainWindow::toggleShowMenuBar, Qt::QueuedConnection);
-    KStandardAction::preferences(this, &DolphinMainWindow::editSettings, actionCollection());
 
-    // setup 'Help' menu for the m_controlButton. The other one is set up in the base class.
-    m_helpMenu = new KHelpMenu(nullptr);
-    m_helpMenu->menu()->installEventFilter(this);
-    // remove duplicate shortcuts
-    auto removeHelpActionShortcut = [this](KHelpMenu::MenuId menuId) {
-        if (auto *action = m_helpMenu->action(menuId)) {
-            action->setShortcut(QKeySequence());
-        }
-    };
-    removeHelpActionShortcut(KHelpMenu::menuHelpContents);
-    removeHelpActionShortcut(KHelpMenu::menuWhatsThis);
+    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());
 
     // not in menu actions
     QList<QKeySequence> nextTabKeys = KStandardShortcut::tabNext();
@@ -1761,6 +1998,8 @@ void DolphinMainWindow::setupDockWidgets()
 {
     const bool lock = GeneralSettings::lockPanels();
 
+    DolphinPlacesModelSingleton::instance().placesModel()->setPanelsLocked(lock);
+
     KDualAction* lockLayoutAction = actionCollection()->add<KDualAction>(QStringLiteral("lock_panels"));
     lockLayoutAction->setActiveText(i18nc("@action:inmenu Panels", "Unlock Panels"));
     lockLayoutAction->setActiveIcon(QIcon::fromTheme(QStringLiteral("object-unlocked")));
@@ -1780,7 +2019,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);
@@ -1802,9 +2041,9 @@ void DolphinMainWindow::setupDockWidgets()
 
     // i18n: This is the last paragraph for the "What's This"-texts of all four panels.
     const QString panelWhatsThis = xi18nc("@info:whatsthis", "<para>To show or "
-        "hide panels like this go to <interface>Control|Panels</interface> "
+        "hide panels like this go to <interface>Menu|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 "
@@ -1837,8 +2076,10 @@ void DolphinMainWindow::setupDockWidgets()
             foldersPanel, &FoldersPanel::setUrl);
     connect(foldersPanel, &FoldersPanel::folderActivated,
             this, &DolphinMainWindow::changeUrl);
-    connect(foldersPanel, &FoldersPanel::folderMiddleClicked,
+    connect(foldersPanel, &FoldersPanel::folderInNewTab,
             this, &DolphinMainWindow::openNewTab);
+    connect(foldersPanel, &FoldersPanel::folderInNewActiveTab,
+            this, &DolphinMainWindow::openNewTabAndActivate);
     connect(foldersPanel, &FoldersPanel::errorMessage,
             this, &DolphinMainWindow::showErrorMessage);
 
@@ -1854,7 +2095,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);
@@ -1920,8 +2161,13 @@ void DolphinMainWindow::setupDockWidgets()
     addDockWidget(Qt::LeftDockWidgetArea, placesDock);
     connect(m_placesPanel, &PlacesPanel::placeActivated,
             this, &DolphinMainWindow::slotPlaceActivated);
-    connect(m_placesPanel, &PlacesPanel::placeMiddleClicked,
+    connect(m_placesPanel, &PlacesPanel::tabRequested,
             this, &DolphinMainWindow::openNewTab);
+    connect(m_placesPanel, &PlacesPanel::activeTabRequested,
+            this, &DolphinMainWindow::openNewTabAndActivate);
+    connect(m_placesPanel, &PlacesPanel::newWindowRequested, this, [this](const QUrl &url) {
+        Dolphin::openNewWindow({url}, this);
+    });
     connect(m_placesPanel, &PlacesPanel::errorMessage,
             this, &DolphinMainWindow::showErrorMessage);
     connect(this, &DolphinMainWindow::urlChanged,
@@ -1944,14 +2190,9 @@ void DolphinMainWindow::setupDockWidgets()
         "appear semi-transparent unless you uncheck their hide property."));
 
     connect(actionShowAllPlaces, &QAction::triggered, this, [actionShowAllPlaces, this](bool checked){
-        actionShowAllPlaces->setIcon(QIcon::fromTheme(checked ? QStringLiteral("view-visible") : QStringLiteral("view-hidden")));
-        m_placesPanel->showHiddenEntries(checked);
+        m_placesPanel->setShowAll(checked);
     });
-
-    connect(m_placesPanel, &PlacesPanel::showHiddenEntriesChanged, this, [actionShowAllPlaces] (bool checked){
-        actionShowAllPlaces->setChecked(checked);
-        actionShowAllPlaces->setIcon(QIcon::fromTheme(checked ? QStringLiteral("view-visible") : QStringLiteral("view-hidden")));
-   });
+    connect(m_placesPanel, &PlacesPanel::allPlacesShownChanged, actionShowAllPlaces, &QAction::setChecked);
 
     actionCollection()->action(QStringLiteral("show_places_panel"))
         ->setWhatsThis(xi18nc("@info:whatsthis", "<para>This toggles the "
@@ -1979,7 +2220,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")));
@@ -1989,7 +2230,7 @@ void DolphinMainWindow::setupDockWidgets()
     panelsMenu->addAction(lockLayoutAction);
 
     connect(panelsMenu->menu(), &QMenu::aboutToShow, this, [actionShowAllPlaces, this]{
-        actionShowAllPlaces->setEnabled(m_placesPanel->hiddenListCount());
+        actionShowAllPlaces->setEnabled(DolphinPlacesModelSingleton::instance().placesModel()->hiddenCount());
     });
 }
 
@@ -2000,7 +2241,12 @@ void DolphinMainWindow::updateFileAndEditActions()
     const KActionCollection* col = actionCollection();
     KFileItemListProperties capabilitiesSource(list);
 
-    QAction* addToPlacesAction = col->action(QStringLiteral("add_to_places"));
+    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"));
     QAction* copyLocation            = col->action(QString("copy_location"));
@@ -2008,20 +2254,23 @@ 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);
+        // Them triggering selection mode and not directly acting on selected items is signified by adding "…" to their text.
+        m_actionTextHelper->textsWhenNothingIsSelectedEnabled(true);
+
     } else {
+        m_actionTextHelper->textsWhenNothingIsSelectedEnabled(false);
         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);
@@ -2029,23 +2278,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());
@@ -2057,6 +2289,23 @@ 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()
@@ -2091,11 +2340,6 @@ void DolphinMainWindow::refreshViews()
     m_tabWidget->refreshViews();
 
     if (GeneralSettings::modifiedStartupSettings()) {
-        // The startup settings have been changed by the user (see bug #254947).
-        // Synchronize the split-view setting with the active view:
-        const bool splitView = GeneralSettings::splitView();
-        m_tabWidget->currentTabPage()->setSplitViewEnabled(splitView, WithAnimation);
-        updateSplitAction();
         updateWindowTitle();
     }
 
@@ -2115,10 +2359,22 @@ void DolphinMainWindow::connectViewSignals(DolphinViewContainer* container)
             this, &DolphinMainWindow::slotWriteStateChanged);
     connect(container, &DolphinViewContainer::searchModeEnabledChanged,
             this, &DolphinMainWindow::updateSearchAction);
+    connect(container, &DolphinViewContainer::captionChanged,
+            this, &DolphinMainWindow::updateWindowTitle);
+    connect(container, &DolphinViewContainer::tabRequested,
+            this, &DolphinMainWindow::openNewTab);
+    connect(container, &DolphinViewContainer::activeTabRequested,
+            this, &DolphinMainWindow::openNewTabAndActivate);
 
     const QAction* toggleSearchAction = actionCollection()->action(QStringLiteral("toggle_search"));
     connect(toggleSearchAction, &QAction::triggered, container, &DolphinViewContainer::setSearchModeEnabled);
 
+    // Make the toggled state of the selection mode actions visually follow the selection mode state of the view.
+    auto toggleSelectionModeAction = actionCollection()->action(QStringLiteral("toggle_selection_mode"));
+    toggleSelectionModeAction->setChecked(m_activeViewContainer->isSelectionModeEnabled());
+    connect(m_activeViewContainer, &DolphinViewContainer::selectionModeChanged,
+            toggleSelectionModeAction, &QAction::setChecked);
+
     const DolphinView* view = container->view();
     connect(view, &DolphinView::selectionChanged,
             this, &DolphinMainWindow::slotSelectionChanged);
@@ -2128,6 +2384,10 @@ void DolphinMainWindow::connectViewSignals(DolphinViewContainer* container)
             this, &DolphinMainWindow::fileItemsChanged);
     connect(view, &DolphinView::tabRequested,
             this, &DolphinMainWindow::openNewTab);
+    connect(view, &DolphinView::activeTabRequested,
+            this, &DolphinMainWindow::openNewTabAndActivate);
+    connect(view, &DolphinView::windowRequested,
+            this, &DolphinMainWindow::openNewWindow);
     connect(view, &DolphinView::requestContextMenu,
             this, &DolphinMainWindow::openContextMenu);
     connect(view, &DolphinView::directoryLoadingStarted,
@@ -2162,6 +2422,10 @@ void DolphinMainWindow::connectViewSignals(DolphinViewContainer* container)
             this, &DolphinMainWindow::slotEditableStateChanged);
     connect(navigator, &KUrlNavigator::tabRequested,
             this, &DolphinMainWindow::openNewTab);
+    connect(navigator, &KUrlNavigator::activeTabRequested,
+            this, &DolphinMainWindow::openNewTabAndActivate);
+    connect(navigator, &KUrlNavigator::newWindowRequested,
+            this, &DolphinMainWindow::openNewWindow);
 
 }
 
@@ -2224,6 +2488,7 @@ void DolphinMainWindow::createPanelAction(const QIcon& icon,
     panelAction->setChecked(dockAction->isChecked());
     panelAction->setText(dockAction->text());
     panelAction->setIcon(icon);
+    dockAction->setIcon(icon);
     actionCollection()->setDefaultShortcut(panelAction, shortcut);
 
     connect(panelAction, &QAction::triggered, dockAction, &QAction::trigger);
@@ -2238,16 +2503,16 @@ void DolphinMainWindow::setupWhatsThis()
         "configuration options. Left-click on any of the menus on this "
         "bar to see its contents.</para><para>The Menubar can be hidden "
         "by unchecking <interface>Settings|Show Menubar</interface>. Then "
-        "most of its contents become available through a <interface>Control"
+        "most of its contents become available through a <interface>Menu"
         "</interface> button on the <emphasis>Toolbar</emphasis>.</para>"));
     toolBar()->setWhatsThis(xi18nc("@info:whatsthis", "<para>This is the "
         "<emphasis>Toolbar</emphasis>. It allows quick access to "
         "frequently used actions.</para><para>It is highly customizable. "
-        "All items you see in the <interface>Control</interface> menu or "
+        "All items you see in the <interface>Menu</interface> or "
         "in the <interface>Menubar</interface> can be placed on the "
         "Toolbar. Just right-click on it and select <interface>Configure "
-        "Toolbars…</interface> or find this action in the <interface>"
-        "Control</interface> or <interface>Settings</interface> menu."
+        "Toolbars…</interface> or find this action within the <interface>"
+        "menu</interface>."
         "</para><para>The location of the bar and the style of its "
         "buttons can also be changed in the right-click menu. Right-click "
         "a button if you want to show or hide its text.</para>"));
@@ -2276,8 +2541,7 @@ void DolphinMainWindow::setupWhatsThis()
     actionCollection()->action(KStandardAction::name(KStandardAction::ConfigureToolbars))
         ->setWhatsThis(xi18nc("@info:whatsthis","<para>This opens a window in which "
         "you can change which buttons appear on the <emphasis>Toolbar</emphasis>.</para>"
-        "<para>All items you see in the <interface>Control</interface> menu "
-        "or in the <interface>Menubar</interface> can also be placed on the Toolbar.</para>"));
+        "<para>All items you see in the <interface>Menu</interface> can also be placed on the Toolbar.</para>"));
     actionCollection()->action(KStandardAction::name(KStandardAction::Preferences))
         ->setWhatsThis(xi18nc("@info:whatsthis","This opens a window where you can "
         "change a multitude of settings for this application. For an explanation "
@@ -2285,77 +2549,38 @@ void DolphinMainWindow::setupWhatsThis()
         "</emphasis> in <interface>Help|Dolphin Handbook</interface>."));
 
     // Help menu
-    // The whatsthis has to be set for the m_helpMenu and for the
-    // StandardAction separately because both are used in different locations.
-    // m_helpMenu is only used for createControlButton() button.
-
-    auto setStandardActionWhatsThis = [this](KStandardAction::StandardAction actionId,
-                                             const QString &whatsThis) {
-        if (auto *action = actionCollection()->action(KStandardAction::name(actionId))) {
-            action->setWhatsThis(whatsThis);
-        }
-    };
-    auto setHelpActionWhatsThis = [this](KHelpMenu::MenuId menuId, const QString &whatsThis) {
-        if (auto *action = m_helpMenu->action(menuId)) {
-            action->setWhatsThis(whatsThis);
-        }
-    };
-
-    // Links do not work within the Menubar so texts without links are provided there.
 
-    // i18n: If the external link isn't available in your language you should
-    // probably state the external link language at least in brackets to not
+    // i18n: If the external link isn't available in your language it might make
+    // sense to state the external link's language in brackets to not
     // frustrate the user. If there are multiple languages that the user might
     // know with a reasonable chance you might want to have 2 external links.
-    // The same is in my opinion true for every external link you translate.
-    const QString whatsThisHelpContents = xi18nc("@info:whatsthis handbook",
-        "<para>This opens the Handbook for this application. It provides "
-        "explanations for every part of <emphasis>Dolphin</emphasis>.</para>");
-    setStandardActionWhatsThis(KStandardAction::HelpContents, whatsThisHelpContents
-        + xi18nc("@info:whatsthis second half of handbook hb text without link",
-        "<para>If you want more elaborate introductions to the "
-        "different features of <emphasis>Dolphin</emphasis> "
-        "go to the KDE UserBase Wiki.</para>"));
-    setHelpActionWhatsThis(KHelpMenu::menuHelpContents, whatsThisHelpContents
-        + xi18nc("@info:whatsthis second half of handbook text with link",
-        "<para>If you want more elaborate introductions to the "
-        "different features of <emphasis>Dolphin</emphasis> "
-        "<link url='https://userbase.kde.org/Dolphin/File_Management'>click here</link>. "
-        "It will open the dedicated page in the KDE UserBase Wiki.</para>"));
-
-    const QString whatsThisWhatsThis = xi18nc("@info:whatsthis whatsthis button",
+    // The same might be true for any external link you translate.
+    actionCollection()->action(KStandardAction::name(KStandardAction::HelpContents))->setWhatsThis(xi18nc("@info:whatsthis handbook", "<para>This opens the Handbook for this application. It provides explanations for every part of <emphasis>Dolphin</emphasis>.</para><para>If you want more elaborate introductions to the different features of <emphasis>Dolphin</emphasis> <link url='https://userbase.kde.org/Dolphin/File_Management'>click here</link>. It will open the dedicated page in the KDE UserBase Wiki.</para>"));
+    // (The i18n call should be completely in the line following the i18n: comment without any line breaks within the i18n call or the comment might not be correctly extracted. See: https://commits.kde.org/kxmlgui/a31135046e1b3335b5d7bbbe6aa9a883ce3284c1 )
+
+    actionCollection()->action(KStandardAction::name(KStandardAction::WhatsThis))->setWhatsThis(
+        xi18nc("@info:whatsthis whatsthis button",
         "<para>This is the button that invokes the help feature you are "
         "using right now! Click it, then click any component of this "
         "application to ask \"What's this?\" about it. The mouse cursor "
-        "will change appearance if no help is available for a spot.</para>");
-    setStandardActionWhatsThis(KStandardAction::WhatsThis, whatsThisWhatsThis
-        + xi18nc("@info:whatsthis second half of whatsthis button text without link",
-        "<para>There are two other ways to get help for this application: The "
-        "<interface>Dolphin Handbook</interface> in the <interface>Help"
-        "</interface> menu and the <emphasis>KDE UserBase Wiki</emphasis> "
-        "article about <emphasis>File Management</emphasis> online."
-        "</para><para>The \"What's this?\" help is "
-        "missing in most other windows so don't get too used to this.</para>"));
-    setHelpActionWhatsThis(KHelpMenu::menuWhatsThis, whatsThisWhatsThis
-        + xi18nc("@info:whatsthis second half of whatsthis button text with link",
+        "will change appearance if no help is available for a spot.</para>"
         "<para>There are two other ways to get help: "
         "The <link url='help:/dolphin/index.html'>Dolphin Handbook</link> and "
         "the <link url='https://userbase.kde.org/Dolphin/File_Management'>KDE "
         "UserBase Wiki</link>.</para><para>The \"What's this?\" help is "
         "missing in most other windows so don't get too used to this.</para>"));
 
-    const QString whatsThisReportBug = xi18nc("@info:whatsthis","<para>This opens a "
+    actionCollection()->action(KStandardAction::name(KStandardAction::ReportBug))->setWhatsThis(
+        xi18nc("@info:whatsthis","<para>This opens a "
         "window that will guide you through reporting errors or flaws "
-        "in this application or in other KDE software.</para>");
-    setStandardActionWhatsThis(KStandardAction::ReportBug, whatsThisReportBug);
-    setHelpActionWhatsThis(KHelpMenu::menuReportBug, whatsThisReportBug
-        + xi18nc("@info:whatsthis second half of reportbug text with link",
+        "in this application or in other KDE software.</para>"
         "<para>High-quality bug reports are much appreciated. To learn "
         "how to make your bug report as effective as possible "
         "<link url='https://community.kde.org/Get_Involved/Bug_Reporting'>"
         "click here</link>.</para>"));
 
-    const QString whatsThisDonate = xi18nc("@info:whatsthis","<para>This opens a "
+    actionCollection()->action(KStandardAction::name(KStandardAction::Donate))->setWhatsThis(
+        xi18nc("@info:whatsthis", "<para>This opens a "
         "<emphasis>web page</emphasis> where you can donate to "
         "support the continued work on this application and many "
         "other projects by the <emphasis>KDE</emphasis> community.</para>"
@@ -2364,31 +2589,25 @@ void DolphinMainWindow::setupWhatsThis()
         "free therefore your donation is needed to cover things that "
         "require money like servers, contributor meetings, etc.</para>"
         "<para><emphasis>KDE e.V.</emphasis> is the non-profit "
-        "organization behind the KDE community.</para>");
-    setStandardActionWhatsThis(KStandardAction::Donate, whatsThisDonate);
-    setHelpActionWhatsThis(KHelpMenu::menuDonate, whatsThisDonate);
+        "organization behind the KDE community.</para>"));
 
-    const QString whatsThisSwitchLanguage = xi18nc("@info:whatsthis",
+    actionCollection()->action(KStandardAction::name(KStandardAction::SwitchApplicationLanguage))->setWhatsThis(
+        xi18nc("@info:whatsthis",
         "With this you can change the language this application uses."
         "<nl/>You can even set secondary languages which will be used "
-        "if texts are not available in your preferred language.");
-    setStandardActionWhatsThis(KStandardAction::SwitchApplicationLanguage,
-                               whatsThisSwitchLanguage);
-    setHelpActionWhatsThis(KHelpMenu::menuSwitchLanguage, whatsThisSwitchLanguage);
+        "if texts are not available in your preferred language."));
 
-    const QString whatsThisAboutApp = xi18nc("@info:whatsthis","This opens a "
+    actionCollection()->action(KStandardAction::name(KStandardAction::AboutApp))->setWhatsThis(
+        xi18nc("@info:whatsthis","This opens a "
         "window that informs you about the version, license, "
-        "used libraries and maintainers of this application.");
-    setStandardActionWhatsThis(KStandardAction::AboutApp, whatsThisAboutApp);
-    setHelpActionWhatsThis(KHelpMenu::menuAboutApp, whatsThisAboutApp);
+        "used libraries and maintainers of this application."));
 
-    const QString whatsThisAboutKDE = xi18nc("@info:whatsthis","This opens a "
+    actionCollection()->action(KStandardAction::name(KStandardAction::AboutKDE))->setWhatsThis(
+        xi18nc("@info:whatsthis","This opens a "
         "window with information about <emphasis>KDE</emphasis>. "
         "The KDE community are the people behind this free software."
         "<nl/>If you like using this application but don't know "
-        "about KDE or want to see a cute dragon have a look!");
-    setStandardActionWhatsThis(KStandardAction::AboutKDE, whatsThisAboutKDE);
-    setHelpActionWhatsThis(KHelpMenu::menuAboutKDE, whatsThisAboutKDE);
+        "about KDE or want to see a cute dragon have a look!"));
 }
 
 bool DolphinMainWindow::addHamburgerMenuToToolbar()
@@ -2414,29 +2633,6 @@ bool DolphinMainWindow::addHamburgerMenuToToolbar()
     // whenever this method is removed (maybe in the year ~2026).
 }
 
-bool DolphinMainWindow::event(QEvent *event)
-{
-    if (event->type() == QEvent::WhatsThisClicked) {
-        event->accept();
-        QWhatsThisClickedEvent* whatsThisEvent = dynamic_cast<QWhatsThisClickedEvent*>(event);
-        QDesktopServices::openUrl(QUrl(whatsThisEvent->href()));
-        return true;
-    }
-    return KXmlGuiWindow::event(event);
-}
-
-bool DolphinMainWindow::eventFilter(QObject* obj, QEvent* event)
-{
-    Q_UNUSED(obj)
-    if (event->type() == QEvent::WhatsThisClicked) {
-        event->accept();
-        QWhatsThisClickedEvent* whatsThisEvent = dynamic_cast<QWhatsThisClickedEvent*>(event);
-        QDesktopServices::openUrl(QUrl(whatsThisEvent->href()));
-        return true;
-    }
-    return false;
-}
-
 // Set a sane initial window size
 QSize DolphinMainWindow::sizeHint() const
 {
@@ -2494,8 +2690,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::isItemVisibleInAnyView(const QString &urlOfItem)
+{
+    return m_tabWidget->isItemVisibleInAnyView(QUrl::fromUserInput(urlOfItem));
+}