]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/dolphintabwidget.cpp
Add missing KF6::ColorScheme link
[dolphin.git] / src / dolphintabwidget.cpp
index 5a900701297d9158d44f94f3842b1316be535d07..b2f838a40ab7e44b4a4241fd893407c344d8cf56 100644 (file)
@@ -9,78 +9,86 @@
 #include "dolphin_generalsettings.h"
 #include "dolphintabbar.h"
 #include "dolphinviewcontainer.h"
+#include "views/draganddrophelper.h"
 
+#include <KAcceleratorManager>
 #include <KConfigGroup>
+#include <KIO/CommandLauncherJob>
+#include <KLocalizedString>
 #include <KShell>
+#include <KStringHandler>
 #include <kio/global.h>
-#include <KIO/CommandLauncherJob>
-#include <KAcceleratorManager>
 
 #include <QApplication>
 #include <QDropEvent>
+#include <QStackedWidget>
 
-DolphinTabWidget::DolphinTabWidget(DolphinNavigatorsWidgetAction *navigatorsWidget, QWidget* parent) :
-    QTabWidget(parent),
-    m_lastViewedTab(nullptr),
-    m_navigatorsWidget{navigatorsWidget}
+DolphinTabWidget::DolphinTabWidget(DolphinNavigatorsWidgetAction *navigatorsWidget, QWidget *parent)
+    : QTabWidget(parent)
+    , m_lastViewedTab(nullptr)
+    m_navigatorsWidget{navigatorsWidget}
 {
     KAcceleratorManager::setNoAccel(this);
 
-    connect(this, &DolphinTabWidget::tabCloseRequested,
-            this, QOverload<int>::of(&DolphinTabWidget::closeTab));
-    connect(this, &DolphinTabWidget::currentChanged,
-            this, &DolphinTabWidget::currentTabChanged);
+    connect(this, &DolphinTabWidget::tabCloseRequested, this, QOverload<int>::of(&DolphinTabWidget::closeTab));
+    connect(this, &DolphinTabWidget::currentChanged, this, &DolphinTabWidget::currentTabChanged);
 
-    DolphinTabBar* tabBar = new DolphinTabBar(this);
-    connect(tabBar, &DolphinTabBar::openNewActivatedTab,
-            this, QOverload<int>::of(&DolphinTabWidget::openNewActivatedTab));
-    connect(tabBar, &DolphinTabBar::tabDropEvent,
-            this, &DolphinTabWidget::tabDropEvent);
-    connect(tabBar, &DolphinTabBar::tabDetachRequested,
-            this, &DolphinTabWidget::detachTab);
-    tabBar->hide();
+    DolphinTabBar *tabBar = new DolphinTabBar(this);
+    connect(tabBar, &DolphinTabBar::openNewActivatedTab, this, QOverload<int>::of(&DolphinTabWidget::openNewActivatedTab));
+    connect(tabBar, &DolphinTabBar::tabDragMoveEvent, this, &DolphinTabWidget::tabDragMoveEvent);
+    connect(tabBar, &DolphinTabBar::tabDropEvent, this, &DolphinTabWidget::tabDropEvent);
+    connect(tabBar, &DolphinTabBar::tabDetachRequested, this, &DolphinTabWidget::detachTab);
+    connect(tabBar, &DolphinTabBar::tabRenamed, this, &DolphinTabWidget::renameTab);
 
     setTabBar(tabBar);
     setDocumentMode(true);
     setElideMode(Qt::ElideRight);
     setUsesScrollButtons(true);
+    setTabBarAutoHide(true);
+
+    auto stackWidget{findChild<QStackedWidget *>()};
+    // i18n: This accessible name will be announced any time the user moves keyboard focus e.g. from the toolbar or the places panel towards the main working
+    // area of Dolphin. It gives structure. This container does not only contain the main view but also the status bar, the search panel, filter, and selection
+    // mode bars, so calling it just a "View" is a bit wrong, but hopefully still gets the point across.
+    stackWidget->setAccessibleName(i18nc("accessible name of Dolphin's view container", "Location View")); // Without this call, the non-descript Qt provided
+                                                                                                           // "Layered Pane" role is announced.
 }
 
-DolphinTabPageDolphinTabWidget::currentTabPage() const
+DolphinTabPage *DolphinTabWidget::currentTabPage() const
 {
     return tabPageAt(currentIndex());
 }
 
-DolphinTabPageDolphinTabWidget::nextTabPage() const
+DolphinTabPage *DolphinTabWidget::nextTabPage() const
 {
     const int index = currentIndex() + 1;
     return tabPageAt(index < count() ? index : 0);
 }
 
-DolphinTabPageDolphinTabWidget::prevTabPage() const
+DolphinTabPage *DolphinTabWidget::prevTabPage() const
 {
     const int index = currentIndex() - 1;
     return tabPageAt(index >= 0 ? index : (count() - 1));
 }
 
-DolphinTabPageDolphinTabWidget::tabPageAt(const int index) const
+DolphinTabPage *DolphinTabWidget::tabPageAt(const int index) const
 {
-    return static_cast<DolphinTabPage*>(widget(index));
+    return static_cast<DolphinTabPage *>(widget(index));
 }
 
-void DolphinTabWidget::saveProperties(KConfigGroupgroup) const
+void DolphinTabWidget::saveProperties(KConfigGroup &group) const
 {
     const int tabCount = count();
     group.writeEntry("Tab Count", tabCount);
     group.writeEntry("Active Tab Index", currentIndex());
 
     for (int i = 0; i < tabCount; ++i) {
-        const DolphinTabPagetabPage = tabPageAt(i);
+        const DolphinTabPage *tabPage = tabPageAt(i);
         group.writeEntry("Tab Data " % QString::number(i), tabPage->saveState());
     }
 }
 
-void DolphinTabWidget::readProperties(const KConfigGroupgroup)
+void DolphinTabWidget::readProperties(const KConfigGroup &group)
 {
     const int tabCount = group.readEntry("Tab Count", 0);
     for (int i = 0; i < tabCount; ++i) {
@@ -107,11 +115,24 @@ void DolphinTabWidget::refreshViews()
 
     const int tabCount = count();
     for (int i = 0; i < tabCount; ++i) {
-        tabBar()->setTabText(i, tabName(tabPageAt(i)));
+        updateTabName(i);
         tabPageAt(i)->refreshViews();
     }
 }
 
+void DolphinTabWidget::updateTabName(int index)
+{
+    Q_ASSERT(index >= 0);
+
+    if (!tabPageAt(index)->customLabel().isEmpty()) {
+        QString name = tabPageAt(index)->customLabel();
+        tabBar()->setTabText(index, name);
+        return;
+    }
+
+    tabBar()->setTabText(index, tabName(tabPageAt(index)));
+}
+
 bool DolphinTabWidget::isUrlOpen(const QUrl &url) const
 {
     return viewOpenAtDirectory(url).has_value();
@@ -131,12 +152,12 @@ void DolphinTabWidget::openNewActivatedTab()
         oldNavigatorState = m_navigatorsWidget->secondaryUrlNavigator()->visualState();
     }
 
-    const DolphinViewContaineroldActiveViewContainer = currentTabPage()->activeViewContainer();
+    const DolphinViewContainer *oldActiveViewContainer = currentTabPage()->activeViewContainer();
     Q_ASSERT(oldActiveViewContainer);
 
     openNewActivatedTab(oldActiveViewContainer->url());
 
-    DolphinViewContainernewActiveViewContainer = currentTabPage()->activeViewContainer();
+    DolphinViewContainer *newActiveViewContainer = currentTabPage()->activeViewContainer();
     Q_ASSERT(newActiveViewContainer);
 
     // The URL navigator of the new tab should have the same editable state
@@ -147,7 +168,7 @@ void DolphinTabWidget::openNewActivatedTab()
     newActiveViewContainer->view()->setFocus();
 }
 
-void DolphinTabWidget::openNewActivatedTab(const QUrl& primaryUrl, const QUrl& secondaryUrl)
+void DolphinTabWidget::openNewActivatedTab(const QUrl &primaryUrl, const QUrl &secondaryUrl)
 {
     openNewTab(primaryUrl, secondaryUrl);
     if (GeneralSettings::openNewTabAfterLastTab()) {
@@ -157,20 +178,16 @@ void DolphinTabWidget::openNewActivatedTab(const QUrl& primaryUrl, const QUrl& s
     }
 }
 
-void DolphinTabWidget::openNewTab(const QUrl& primaryUrl, const QUrl& secondaryUrl, DolphinTabWidget::NewTabPosition position)
+DolphinTabPage *DolphinTabWidget::openNewTab(const QUrl &primaryUrl, const QUrl &secondaryUrl, DolphinTabWidget::NewTabPosition position)
 {
-    QWidgetfocusWidget = QApplication::focusWidget();
+    QWidget *focusWidget = QApplication::focusWidget();
 
-    DolphinTabPagetabPage = new DolphinTabPage(primaryUrl, secondaryUrl, this);
+    DolphinTabPage *tabPage = new DolphinTabPage(primaryUrl, secondaryUrl, this);
     tabPage->setActive(false);
-    connect(tabPage, &DolphinTabPage::activeViewChanged,
-            this, &DolphinTabWidget::activeViewChanged);
-    connect(tabPage, &DolphinTabPage::activeViewUrlChanged,
-            this, &DolphinTabWidget::tabUrlChanged);
+    connect(tabPage, &DolphinTabPage::activeViewChanged, this, &DolphinTabWidget::activeViewChanged);
+    connect(tabPage, &DolphinTabPage::activeViewUrlChanged, this, &DolphinTabWidget::tabUrlChanged);
     connect(tabPage->activeViewContainer(), &DolphinViewContainer::captionChanged, this, [this, tabPage]() {
-        const int tabIndex = indexOf(tabPage);
-        Q_ASSERT(tabIndex >= 0);
-        tabBar()->setTabText(tabIndex, tabName(tabPage));
+        updateTabName(indexOf(tabPage));
     });
 
     if (position == NewTabPosition::FollowSetting) {
@@ -193,9 +210,10 @@ void DolphinTabWidget::openNewTab(const QUrl& primaryUrl, const QUrl& secondaryU
         // in background, assure that the previous focused widget gets the focus back.
         focusWidget->setFocus();
     }
+    return tabPage;
 }
 
-void DolphinTabWidget::openDirectories(const QList<QUrl>dirs, bool splitView)
+void DolphinTabWidget::openDirectories(const QList<QUrl> &dirs, bool splitView)
 {
     Q_ASSERT(dirs.size() > 0);
 
@@ -203,22 +221,16 @@ void DolphinTabWidget::openDirectories(const QList<QUrl>& dirs, bool splitView)
 
     QList<QUrl>::const_iterator it = dirs.constBegin();
     while (it != dirs.constEnd()) {
-        const QUrlprimaryUrl = *(it++);
-        const std::optional<ViewIndex> alreadyOpenDirectory = viewOpenAtDirectory(primaryUrl);
+        const QUrl &primaryUrl = *(it++);
+        const std::optional<ViewIndex> viewIndexAtDirectory = viewOpenAtDirectory(primaryUrl);
 
         // When the user asks for a URL that's already open,
         // activate it instead of opening a new tab
-        if (alreadyOpenDirectory.has_value()) {
+        if (viewIndexAtDirectory.has_value()) {
             somethingWasAlreadyOpen = true;
-            activateTab(alreadyOpenDirectory->tabIndex);
-            const auto tabPage = tabPageAt(alreadyOpenDirectory->tabIndex);
-            if (alreadyOpenDirectory->isInPrimaryView) {
-                tabPage->primaryViewContainer()->setActive(true);
-            } else {
-                tabPage->secondaryViewContainer()->setActive(true);
-            }
+            activateViewContainerAt(viewIndexAtDirectory.value());
         } else if (splitView && (it != dirs.constEnd())) {
-            const QUrlsecondaryUrl = *(it++);
+            const QUrl &secondaryUrl = *(it++);
             if (somethingWasAlreadyOpen) {
                 openNewTab(primaryUrl, secondaryUrl);
             } else {
@@ -234,14 +246,14 @@ void DolphinTabWidget::openDirectories(const QList<QUrl>& dirs, bool splitView)
     }
 }
 
-void DolphinTabWidget::openFiles(const QList<QUrl>files, bool splitView)
+void DolphinTabWidget::openFiles(const QList<QUrl> &files, bool splitView)
 {
     Q_ASSERT(files.size() > 0);
 
     // Get all distinct directories from 'files'.
     QList<QUrl> dirsThatNeedToBeOpened;
     QList<QUrl> dirsThatWereAlreadyOpen;
-    for (const QUrlfile : files) {
+    for (const QUrl &file : files) {
         const QUrl dir(file.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash));
         if (dirsThatNeedToBeOpened.contains(dir) || dirsThatWereAlreadyOpen.contains(dir)) {
             continue;
@@ -252,14 +264,8 @@ void DolphinTabWidget::openFiles(const QList<QUrl>& files, bool splitView)
         // We also make sure the view will be activated.
         auto viewIndex = viewShowingItem(file);
         if (viewIndex.has_value()) {
-            activateTab(viewIndex->tabIndex);
-            if (viewIndex->isInPrimaryView) {
-                tabPageAt(viewIndex->tabIndex)->primaryViewContainer()->view()->clearSelection();
-                tabPageAt(viewIndex->tabIndex)->primaryViewContainer()->setActive(true);
-            } else {
-                tabPageAt(viewIndex->tabIndex)->secondaryViewContainer()->view()->clearSelection();
-                tabPageAt(viewIndex->tabIndex)->secondaryViewContainer()->setActive(true);
-            }
+            viewContainerAt(viewIndex.value())->view()->clearSelection();
+            activateViewContainerAt(viewIndex.value());
             dirsThatWereAlreadyOpen.append(dir);
         } else {
             dirsThatNeedToBeOpened.append(dir);
@@ -278,7 +284,7 @@ void DolphinTabWidget::openFiles(const QList<QUrl>& files, bool splitView)
     // tabs, there is no need to split 'files' accordingly, as
     // the DolphinView will just ignore invalid selections.
     for (int i = 0; i < tabCount; ++i) {
-        DolphinTabPagetabPage = tabPageAt(i);
+        DolphinTabPage *tabPage = tabPageAt(i);
         tabPage->markUrlsAsSelected(files);
         tabPage->markUrlAsCurrent(files.first());
         if (i < oldTabCount) {
@@ -304,7 +310,7 @@ void DolphinTabWidget::closeTab(const int index)
         return;
     }
 
-    DolphinTabPagetabPage = tabPageAt(index);
+    DolphinTabPage *tabPage = tabPageAt(index);
     Q_EMIT rememberClosedTab(tabPage->activeViewContainer()->url(), tabPage->saveState());
 
     removeTab(index);
@@ -335,7 +341,7 @@ void DolphinTabWidget::activatePrevTab()
     setCurrentIndex(index >= 0 ? index : (count() - 1));
 }
 
-void DolphinTabWidget::restoreClosedTab(const QByteArraystate)
+void DolphinTabWidget::restoreClosedTab(const QByteArray &state)
 {
     openNewActivatedTab();
     currentTabPage()->restoreState(state);
@@ -343,36 +349,34 @@ void DolphinTabWidget::restoreClosedTab(const QByteArray& state)
 
 void DolphinTabWidget::copyToInactiveSplitView()
 {
-    const DolphinTabPage* tabPage = tabPageAt(currentIndex());
-    DolphinViewContainer* activeViewContainer = currentTabPage()->activeViewContainer();
-    if (!tabPage->splitViewEnabled() || activeViewContainer->view()->selectedItems().isEmpty()) {
+    const DolphinTabPage *tabPage = currentTabPage();
+    if (!tabPage->splitViewEnabled()) {
         return;
     }
 
-    if (tabPage->primaryViewActive()) {
-        // copy from left panel to right
-        activeViewContainer->view()->copySelectedItems(activeViewContainer->view()->selectedItems(), tabPage->secondaryViewContainer()->url());
-    } else {
-        // copy from right panel to left
-        activeViewContainer->view()->copySelectedItems(activeViewContainer->view()->selectedItems(), tabPage->primaryViewContainer()->url());
+    const KFileItemList selectedItems = tabPage->activeViewContainer()->view()->selectedItems();
+    if (selectedItems.isEmpty()) {
+        return;
     }
+
+    DolphinView *const inactiveView = tabPage->inactiveViewContainer()->view();
+    inactiveView->copySelectedItems(selectedItems, inactiveView->url());
 }
 
 void DolphinTabWidget::moveToInactiveSplitView()
 {
-    const DolphinTabPage* tabPage = tabPageAt(currentIndex());
-    DolphinViewContainer* activeViewContainer = currentTabPage()->activeViewContainer();
-    if (!tabPage->splitViewEnabled() || activeViewContainer->view()->selectedItems().isEmpty()) {
+    const DolphinTabPage *tabPage = currentTabPage();
+    if (!tabPage->splitViewEnabled()) {
         return;
     }
 
-    if (tabPage->primaryViewActive()) {
-        // move from left panel to right
-        activeViewContainer->view()->moveSelectedItems(activeViewContainer->view()->selectedItems(), tabPage->secondaryViewContainer()->url());
-    } else {
-        // move from right panel to left
-        activeViewContainer->view()->moveSelectedItems(activeViewContainer->view()->selectedItems(), tabPage->primaryViewContainer()->url());
+    const KFileItemList selectedItems = tabPage->activeViewContainer()->view()->selectedItems();
+    if (selectedItems.isEmpty()) {
+        return;
     }
+
+    DolphinView *const inactiveView = tabPage->inactiveViewContainer()->view();
+    inactiveView->moveSelectedItems(selectedItems, inactiveView->url());
 }
 
 void DolphinTabWidget::detachTab(int index)
@@ -381,7 +385,7 @@ void DolphinTabWidget::detachTab(int index)
 
     QStringList args;
 
-    const DolphinTabPagetabPage = tabPageAt(index);
+    const DolphinTabPage *tabPage = tabPageAt(index);
     args << tabPage->primaryViewContainer()->url().url();
     if (tabPage->splitViewEnabled()) {
         args << tabPage->secondaryViewContainer()->url().url();
@@ -399,20 +403,28 @@ void DolphinTabWidget::detachTab(int index)
 void DolphinTabWidget::openNewActivatedTab(int index)
 {
     Q_ASSERT(index >= 0);
-    const DolphinTabPagetabPage = tabPageAt(index);
+    const DolphinTabPage *tabPage = tabPageAt(index);
     openNewActivatedTab(tabPage->activeViewContainer()->url());
 }
 
-void DolphinTabWidget::tabDropEvent(int index, QDropEvent* event)
+void DolphinTabWidget::tabDragMoveEvent(int index, QDragMoveEvent *event)
 {
     if (index >= 0) {
-        DolphinView* view = tabPageAt(index)->activeViewContainer()->view();
+        DolphinView *view = tabPageAt(index)->activeViewContainer()->view();
+        DragAndDropHelper::updateDropAction(event, view->url());
+    }
+}
+
+void DolphinTabWidget::tabDropEvent(int index, QDropEvent *event)
+{
+    if (index >= 0) {
+        DolphinView *view = tabPageAt(index)->activeViewContainer()->view();
         view->dropUrls(view->url(), event, view);
     } else {
         const auto urls = event->mimeData()->urls();
 
         for (const QUrl &url : urls) {
-            auto *job = KIO::statDetails(url, KIO::StatJob::SourceSide, KIO::StatDetail::StatBasic, KIO::JobFlag::HideProgressInfo);
+            auto *job = KIO::stat(url, KIO::StatJob::SourceSide, KIO::StatDetail::StatBasic, KIO::JobFlag::HideProgressInfo);
             connect(job, &KJob::result, this, [this, job]() {
                 if (!job->error() && job->statResult().isDir()) {
                     openNewTab(job->url(), QUrl(), NewTabPosition::AtEnd);
@@ -422,11 +434,11 @@ void DolphinTabWidget::tabDropEvent(int index, QDropEvent* event)
     }
 }
 
-void DolphinTabWidget::tabUrlChanged(const QUrlurl)
+void DolphinTabWidget::tabUrlChanged(const QUrl &url)
 {
-    const int index = indexOf(qobject_cast<QWidget*>(sender()));
+    const int index = indexOf(qobject_cast<QWidget *>(sender()));
     if (index >= 0) {
-        tabBar()->setTabText(index, tabName(tabPageAt(index)));
+        updateTabName(index);
         tabBar()->setTabToolTip(index, url.toDisplayString(QUrl::PreferLocalFile));
         if (tabBar()->isVisible()) {
             // ensure the path url ends with a slash to have proper folder icon for remote folders
@@ -441,6 +453,8 @@ void DolphinTabWidget::tabUrlChanged(const QUrl& url)
         if (index == currentIndex()) {
             Q_EMIT currentUrlChanged(url);
         }
+
+        Q_EMIT urlChanged(url);
     }
 }
 
@@ -457,7 +471,7 @@ void DolphinTabWidget::currentTabChanged(int index)
     if (tabPage->splitViewEnabled() && !m_navigatorsWidget->secondaryUrlNavigator()) {
         m_navigatorsWidget->createSecondaryUrlNavigator();
     }
-    DolphinViewContainerviewContainer = tabPage->activeViewContainer();
+    DolphinViewContainer *viewContainer = tabPage->activeViewContainer();
     Q_EMIT activeViewChanged(viewContainer);
     Q_EMIT currentUrlChanged(viewContainer->url());
     tabPage->setActive(true);
@@ -466,11 +480,17 @@ void DolphinTabWidget::currentTabChanged(int index)
     m_lastViewedTab = tabPage;
 }
 
+void DolphinTabWidget::renameTab(int index, const QString &name)
+{
+    tabPageAt(index)->setCustomLabel(name);
+    updateTabName(index);
+}
+
 void DolphinTabWidget::tabInserted(int index)
 {
     QTabWidget::tabInserted(index);
 
-    if (count() > 1) {
+    if (tabBar()->isVisible()) {
         // Resolve all pending tab icons
         for (int i = 0; i < count(); ++i) {
             const QUrl url = tabPageAt(i)->activeViewContainer()->url();
@@ -483,8 +503,6 @@ void DolphinTabWidget::tabInserted(int index)
                 tabBar()->setTabToolTip(index, url.toDisplayString(QUrl::PreferLocalFile));
             }
         }
-
-        tabBar()->show();
     }
 
     Q_EMIT tabCountChanged(count());
@@ -494,27 +512,57 @@ void DolphinTabWidget::tabRemoved(int index)
 {
     QTabWidget::tabRemoved(index);
 
-    // If only one tab is left, then remove the tab entry so that
-    // closing the last tab is not possible.
-    if (count() < 2) {
-        tabBar()->hide();
-    }
-
     Q_EMIT tabCountChanged(count());
 }
 
-QString DolphinTabWidget::tabName(DolphinTabPagetabPage) const
+QString DolphinTabWidget::tabName(DolphinTabPage *tabPage) const
 {
     if (!tabPage) {
         return QString();
     }
-    QString name = tabPage->activeViewContainer()->caption();
+    // clang-format off
+    QString name;
+    if (tabPage->splitViewEnabled()) {
+        if (tabPage->primaryViewActive()) {
+            // i18n: %1 is the primary view and %2 the secondary view. For left to right languages the primary view is on the left so we also want it to be on the
+            // left in the tab name. In right to left languages the primary view would be on the right so the tab name should match.
+            name = i18nc("@title:tab Active primary view | (Inactive secondary view)", "%1 | (%2)", tabPage->primaryViewContainer()->caption(), tabPage->secondaryViewContainer()->caption());
+        } else {
+            // i18n: %1 is the primary view and %2 the secondary view. For left to right languages the primary view is on the left so we also want it to be on the
+            // left in the tab name. In right to left languages the primary view would be on the right so the tab name should match.
+            name = i18nc("@title:tab (Inactive primary view) | Active secondary view", "(%1) | %2", tabPage->primaryViewContainer()->caption(), tabPage->secondaryViewContainer()->caption());
+        }
+    } else {
+        name = tabPage->activeViewContainer()->caption();
+    }
+    // clang-format on
+
     // Make sure that a '&' inside the directory name is displayed correctly
     // and not misinterpreted as a keyboard shortcut in QTabBar::setTabText()
-    return name.replace('&', QLatin1String("&&"));
+    return KStringHandler::rsqueeze(name.replace('&', QLatin1String("&&")), 40 /* default maximum visible folder name visible */);
 }
 
-const std::optional<const DolphinTabWidget::ViewIndex> DolphinTabWidget::viewOpenAtDirectory(const QUrl& directory) const
+DolphinViewContainer *DolphinTabWidget::viewContainerAt(DolphinTabWidget::ViewIndex viewIndex) const
+{
+    const auto tabPage = tabPageAt(viewIndex.tabIndex);
+    if (!tabPage) {
+        return nullptr;
+    }
+    return viewIndex.isInPrimaryView ? tabPage->primaryViewContainer() : tabPage->secondaryViewContainer();
+}
+
+DolphinViewContainer *DolphinTabWidget::activateViewContainerAt(DolphinTabWidget::ViewIndex viewIndex)
+{
+    activateTab(viewIndex.tabIndex);
+    auto viewContainer = viewContainerAt(viewIndex);
+    if (!viewContainer) {
+        return nullptr;
+    }
+    viewContainer->setActive(true);
+    return viewContainer;
+}
+
+const std::optional<const DolphinTabWidget::ViewIndex> DolphinTabWidget::viewOpenAtDirectory(const QUrl &directory) const
 {
     int i = currentIndex();
     if (i < 0) {
@@ -532,13 +580,12 @@ const std::optional<const DolphinTabWidget::ViewIndex> DolphinTabWidget::viewOpe
         }
 
         i = (i + 1) % count();
-    }
-    while (i != currentIndex());
+    } while (i != currentIndex());
 
     return std::nullopt;
 }
 
-const std::optional<const DolphinTabWidget::ViewIndex> DolphinTabWidget::viewShowingItem(const QUrlitem) const
+const std::optional<const DolphinTabWidget::ViewIndex> DolphinTabWidget::viewShowingItem(const QUrl &item) const
 {
     // The item might not be loaded yet even though it exists. So instead
     // we check if the folder containing the item is showing its contents.
@@ -576,8 +623,9 @@ const std::optional<const DolphinTabWidget::ViewIndex> DolphinTabWidget::viewSho
         }
 
         i = (i + 1) % count();
-    }
-    while (i != currentIndex());
+    } while (i != currentIndex());
 
     return std::nullopt;
 }
+
+#include "moc_dolphintabwidget.cpp"