]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/dolphintabwidget.cpp
DolphinTrash: port away from deprecated KIO API
[dolphin.git] / src / dolphintabwidget.cpp
index 17fa0ff4e336b4c44364ea2abce42b9d87562b3a..13619a5f9984530aa791c192ff286d7e7ae0f569 100644 (file)
@@ -87,15 +87,8 @@ void DolphinTabWidget::readProperties(const KConfigGroup& group)
         if (i >= count()) {
             openNewActivatedTab();
         }
-        if (group.hasKey("Tab Data " % QString::number(i))) {
-            // Tab state created with Dolphin > 4.14.x
-            const QByteArray state = group.readEntry("Tab Data " % QString::number(i), QByteArray());
-            tabPageAt(i)->restoreState(state);
-        } else {
-            // Tab state created with Dolphin <= 4.14.x
-            const QByteArray state = group.readEntry("Tab " % QString::number(i), QByteArray());
-            tabPageAt(i)->restoreStateV1(state);
-        }
+        const QByteArray state = group.readEntry("Tab Data " % QString::number(i), QByteArray());
+        tabPageAt(i)->restoreState(state);
     }
 
     const int index = group.readEntry("Active Tab Index", 0);
@@ -121,7 +114,12 @@ void DolphinTabWidget::refreshViews()
 
 bool DolphinTabWidget::isUrlOpen(const QUrl &url) const
 {
-    return indexByUrl(url).first >= 0;
+    return viewOpenAtDirectory(url).has_value();
+}
+
+bool DolphinTabWidget::isItemVisibleInAnyView(const QUrl &urlOfItem) const
+{
+    return viewShowingItem(urlOfItem).has_value();
 }
 
 void DolphinTabWidget::openNewActivatedTab()
@@ -159,7 +157,7 @@ void DolphinTabWidget::openNewActivatedTab(const QUrl& primaryUrl, const QUrl& s
     }
 }
 
-void DolphinTabWidget::openNewTab(const QUrl& primaryUrl, const QUrl& secondaryUrl)
+void DolphinTabWidget::openNewTab(const QUrl& primaryUrl, const QUrl& secondaryUrl, DolphinTabWidget::NewTabPosition position)
 {
     QWidget* focusWidget = QApplication::focusWidget();
 
@@ -169,10 +167,25 @@ void DolphinTabWidget::openNewTab(const QUrl& primaryUrl, const QUrl& secondaryU
             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));
+    });
+
+    if (position == NewTabPosition::FollowSetting) {
+        if (GeneralSettings::openNewTabAfterLastTab()) {
+            position = NewTabPosition::AtEnd;
+        } else {
+            position = NewTabPosition::AfterCurrent;
+        }
+    }
+
     int newTabIndex = -1;
-    if (!GeneralSettings::openNewTabAfterLastTab()) {
+    if (position == NewTabPosition::AfterCurrent || (position == NewTabPosition::FollowSetting && !GeneralSettings::openNewTabAfterLastTab())) {
         newTabIndex = currentIndex() + 1;
     }
+
     insertTab(newTabIndex, tabPage, QIcon() /* loaded in tabInserted */, tabName(tabPage));
 
     if (focusWidget) {
@@ -191,26 +204,14 @@ void DolphinTabWidget::openDirectories(const QList<QUrl>& dirs, bool splitView)
     QList<QUrl>::const_iterator it = dirs.constBegin();
     while (it != dirs.constEnd()) {
         const QUrl& primaryUrl = *(it++);
-        const QPair<int, bool> indexInfo = indexByUrl(primaryUrl);
-        const int index = indexInfo.first;
-        const bool isInPrimaryView = indexInfo.second;
+        const std::optional<ViewIndex> viewIndexAtDirectory = viewOpenAtDirectory(primaryUrl);
 
-        // When the user asks for a URL that's already open, activate it instead
-        // of opening a second copy
-        if (index >= 0) {
+        // When the user asks for a URL that's already open,
+        // activate it instead of opening a new tab
+        if (viewIndexAtDirectory.has_value()) {
             somethingWasAlreadyOpen = true;
-            activateTab(index);
-            const auto tabPage = tabPageAt(index);
-            if (isInPrimaryView) {
-                tabPage->primaryViewContainer()->setActive(true);
-            } else {
-                tabPage->secondaryViewContainer()->setActive(true);
-            }
-            // BUG: 417230
-            // Required for updateViewState() call in openFiles() to work as expected
-            // If there is a selection, updateViewState() calls are effectively a no-op
-            tabPage->activeViewContainer()->view()->clearSelection();
-        } else if (splitView) {
+            activateViewContainerAt(viewIndexAtDirectory.value());
+        } else if (splitView && (it != dirs.constEnd())) {
             const QUrl& secondaryUrl = *(it++);
             if (somethingWasAlreadyOpen) {
                 openNewTab(primaryUrl, secondaryUrl);
@@ -231,19 +232,34 @@ void DolphinTabWidget::openFiles(const QList<QUrl>& files, bool splitView)
 {
     Q_ASSERT(files.size() > 0);
 
-    // Get all distinct directories from 'files' and open a tab
-    // for each directory. If the "split view" option is enabled, two
-    // directories are shown inside one tab (see openDirectories()).
-    QList<QUrl> dirs;
-    for (const QUrl& url : files) {
-        const QUrl dir(url.adjusted(QUrl::RemoveFilename));
-        if (!dirs.contains(dir)) {
-            dirs.append(dir);
+    // Get all distinct directories from 'files'.
+    QList<QUrl> dirsThatNeedToBeOpened;
+    QList<QUrl> dirsThatWereAlreadyOpen;
+    for (const QUrl& file : files) {
+        const QUrl dir(file.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash));
+        if (dirsThatNeedToBeOpened.contains(dir) || dirsThatWereAlreadyOpen.contains(dir)) {
+            continue;
+        }
+
+        // The selecting of files that we do later will not work in views that already have items selected.
+        // So we check if dir is already open and clear the selection if it is. BUG: 417230
+        // We also make sure the view will be activated.
+        auto viewIndex = viewShowingItem(file);
+        if (viewIndex.has_value()) {
+            viewContainerAt(viewIndex.value())->view()->clearSelection();
+            activateViewContainerAt(viewIndex.value());
+            dirsThatWereAlreadyOpen.append(dir);
+        } else {
+            dirsThatNeedToBeOpened.append(dir);
         }
     }
 
     const int oldTabCount = count();
-    openDirectories(dirs, splitView);
+    // Open a tab for each directory. If the "split view" option is enabled,
+    // two directories are shown inside one tab (see openDirectories()).
+    if (dirsThatNeedToBeOpened.size() > 0) {
+        openDirectories(dirsThatNeedToBeOpened, splitView);
+    }
     const int tabCount = count();
 
     // Select the files. Although the files can be split between several
@@ -380,6 +396,17 @@ 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);
+            connect(job, &KJob::result, this, [this, job]() {
+                if (!job->error() && job->statResult().isDir()) {
+                    openNewTab(job->url(), QUrl(), NewTabPosition::AtEnd);
+                }
+            });
+        }
     }
 }
 
@@ -390,7 +417,9 @@ void DolphinTabWidget::tabUrlChanged(const QUrl& url)
         tabBar()->setTabText(index, tabName(tabPageAt(index)));
         tabBar()->setTabToolTip(index, url.toDisplayString(QUrl::PreferLocalFile));
         if (tabBar()->isVisible()) {
-            tabBar()->setTabIcon(index, QIcon::fromTheme(KIO::iconNameForUrl(url)));
+            // ensure the path url ends with a slash to have proper folder icon for remote folders
+            const QUrl pathUrl = QUrl(url.adjusted(QUrl::StripTrailingSlash).toString(QUrl::FullyEncoded).append("/"));
+            tabBar()->setTabIcon(index, QIcon::fromTheme(KIO::iconNameForUrl(pathUrl)));
         } else {
             // Mark as dirty, actually load once the tab bar actually gets shown
             tabBar()->setTabIcon(index, QIcon());
@@ -434,7 +463,9 @@ void DolphinTabWidget::tabInserted(int index)
         for (int i = 0; i < count(); ++i) {
             const QUrl url = tabPageAt(i)->activeViewContainer()->url();
             if (tabBar()->tabIcon(i).isNull()) {
-                tabBar()->setTabIcon(i, QIcon::fromTheme(KIO::iconNameForUrl(url)));
+                // ensure the path url ends with a slash to have proper folder icon for remote folders
+                const QUrl pathUrl = QUrl(url.adjusted(QUrl::StripTrailingSlash).toString(QUrl::FullyEncoded).append("/"));
+                tabBar()->setTabIcon(i, QIcon::fromTheme(KIO::iconNameForUrl(pathUrl)));
             }
             if (tabBar()->tabToolTip(i).isEmpty()) {
                 tabBar()->setTabToolTip(index, url.toDisplayString(QUrl::PreferLocalFile));
@@ -471,17 +502,90 @@ QString DolphinTabWidget::tabName(DolphinTabPage* tabPage) const
     return name.replace('&', QLatin1String("&&"));
 }
 
-QPair<int, bool> DolphinTabWidget::indexByUrl(const QUrl& url) const
+DolphinViewContainer *DolphinTabWidget::viewContainerAt(DolphinTabWidget::ViewIndex viewIndex) const
 {
-    for (int i = 0; i < count(); i++) {
+    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) {
+        return std::nullopt;
+    }
+    // loop over the tabs starting from the current one
+    do {
         const auto tabPage = tabPageAt(i);
-        if (url == tabPage->primaryViewContainer()->url()) {
-            return qMakePair(i, true);
+        if (tabPage->primaryViewContainer()->url() == directory) {
+            return std::optional(ViewIndex{i, true});
         }
 
-        if (tabPage->splitViewEnabled() && url == tabPage->secondaryViewContainer()->url()) {
-            return qMakePair(i, false);
+        if (tabPage->splitViewEnabled() && tabPage->secondaryViewContainer()->url() == directory) {
+            return std::optional(ViewIndex{i, false});
         }
+
+        i = (i + 1) % count();
+    }
+    while (i != currentIndex());
+
+    return std::nullopt;
+}
+
+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.
+    const QUrl dirContainingItem(item.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash));
+
+    // The dirContainingItem is either open directly or expanded in a tree-style view mode.
+    // Is dirContainingitem the base url of a view?
+    auto viewOpenAtContainingDirectory = viewOpenAtDirectory(dirContainingItem);
+    if (viewOpenAtContainingDirectory.has_value()) {
+        return viewOpenAtContainingDirectory;
     }
-    return qMakePair(-1, false);
+
+    // Is dirContainingItem expanded in some tree-style view?
+    // The rest of this method is about figuring this out.
+
+    int i = currentIndex();
+    if (i < 0) {
+        return std::nullopt;
+    }
+    // loop over the tabs starting from the current one
+    do {
+        const auto tabPage = tabPageAt(i);
+        if (tabPage->primaryViewContainer()->url().isParentOf(item)) {
+            const KFileItem fileItemContainingItem = tabPage->primaryViewContainer()->view()->items().findByUrl(dirContainingItem);
+            if (!fileItemContainingItem.isNull() && tabPage->primaryViewContainer()->view()->isExpanded(fileItemContainingItem)) {
+                return std::optional(ViewIndex{i, true});
+            }
+        }
+
+        if (tabPage->splitViewEnabled() && tabPage->secondaryViewContainer()->url().isParentOf(item)) {
+            const KFileItem fileItemContainingItem = tabPage->secondaryViewContainer()->view()->items().findByUrl(dirContainingItem);
+            if (!fileItemContainingItem.isNull() && tabPage->secondaryViewContainer()->view()->isExpanded(fileItemContainingItem)) {
+                return std::optional(ViewIndex{i, false});
+            }
+        }
+
+        i = (i + 1) % count();
+    }
+    while (i != currentIndex());
+
+    return std::nullopt;
 }