diff --git a/src/dolphinmainwindow.cpp b/src/dolphinmainwindow.cpp index 0b0f4f96ad..24da841326 100644 --- a/src/dolphinmainwindow.cpp +++ b/src/dolphinmainwindow.cpp @@ -285,6 +285,11 @@ void DolphinMainWindow::activateWindow() KWindowSystem::activateWindow(window()->effectiveWinId()); } +bool DolphinMainWindow::isActiveWindow() +{ + return window()->isActiveWindow(); +} + void DolphinMainWindow::showCommand(CommandType command) { DolphinStatusBar* statusBar = m_activeViewContainer->statusBar(); @@ -2627,3 +2632,7 @@ bool DolphinMainWindow::isUrlOpen(const QString &url) return m_tabWidget->isUrlOpen(QUrl::fromUserInput(url)); } +bool DolphinMainWindow::isUrlOrParentOpen(const QString &url) +{ + return m_tabWidget->isUrlOrParentOpen(QUrl::fromUserInput(url)); +} diff --git a/src/dolphinmainwindow.h b/src/dolphinmainwindow.h index 030c8bb28c..e26bf50dd4 100644 --- a/src/dolphinmainwindow.h +++ b/src/dolphinmainwindow.h @@ -138,6 +138,8 @@ public Q_SLOTS: */ void activateWindow(); + bool isActiveWindow(); + /** * Determines if a URL is open in any tab. * @note Use of QString instead of QUrl is required to be callable via DBus. @@ -147,6 +149,15 @@ public Q_SLOTS: */ bool isUrlOpen(const QString &url); + /** + * Determines if a URL or it's parent is open in any tab. + * @note Use of QString instead of QUrl is required to be callable via DBus. + * + * @param url URL to look for + * @returns true if url or it's parent is currently open in a tab, false otherwise. + */ + bool isUrlOrParentOpen(const QString &url); + /** * Pastes the clipboard data into the currently selected folder diff --git a/src/dolphintabwidget.cpp b/src/dolphintabwidget.cpp index 5586c9df26..de7a18db36 100644 --- a/src/dolphintabwidget.cpp +++ b/src/dolphintabwidget.cpp @@ -117,6 +117,11 @@ bool DolphinTabWidget::isUrlOpen(const QUrl &url) const return indexByUrl(url).first >= 0; } +bool DolphinTabWidget::isUrlOrParentOpen(const QUrl &url) const +{ + return indexByUrl(url, ReturnIndexForOpenedParentAlso).first >= 0; +} + void DolphinTabWidget::openNewActivatedTab() { std::unique_ptr oldNavigatorState; @@ -182,7 +187,7 @@ void DolphinTabWidget::openNewTab(const QUrl& primaryUrl, const QUrl& secondaryU } } -void DolphinTabWidget::openDirectories(const QList& dirs, bool splitView) +void DolphinTabWidget::openDirectories(const QList& dirs, bool splitView, bool skipChildUrls) { Q_ASSERT(dirs.size() > 0); @@ -191,12 +196,12 @@ void DolphinTabWidget::openDirectories(const QList& dirs, bool splitView) QList::const_iterator it = dirs.constBegin(); while (it != dirs.constEnd()) { const QUrl& primaryUrl = *(it++); - const QPair indexInfo = indexByUrl(primaryUrl); + const QPair indexInfo = indexByUrl(primaryUrl, skipChildUrls ? ReturnIndexForOpenedParentAlso : ReturnIndexForOpenedUrlOnly); const int index = indexInfo.first; const bool isInPrimaryView = indexInfo.second; - // When the user asks for a URL that's already open, activate it instead - // of opening a second copy + // When the user asks for a URL that's already open (or it's parent is open if skipChildUrls is set), + // activate it instead of opening a new tab if (index >= 0) { somethingWasAlreadyOpen = true; activateTab(index); @@ -243,7 +248,7 @@ void DolphinTabWidget::openFiles(const QList& files, bool splitView) } const int oldTabCount = count(); - openDirectories(dirs, splitView); + openDirectories(dirs, splitView, true); const int tabCount = count(); // Select the files. Although the files can be split between several @@ -475,17 +480,29 @@ QString DolphinTabWidget::tabName(DolphinTabPage* tabPage) const return name.replace('&', QLatin1String("&&")); } -QPair DolphinTabWidget::indexByUrl(const QUrl& url) const +QPair DolphinTabWidget::indexByUrl(const QUrl& url, ChildUrlBehavior childUrlBehavior) const { - for (int i = 0; i < count(); i++) { + int i = currentIndex(); + if (i < 0) { + return qMakePair(-1, false); + } + // loop over the tabs starting from the current one + do { const auto tabPage = tabPageAt(i); - if (url == tabPage->primaryViewContainer()->url()) { + if (tabPage->primaryViewContainer()->url() == url || + childUrlBehavior == ReturnIndexForOpenedParentAlso && tabPage->primaryViewContainer()->url().isParentOf(url)) { return qMakePair(i, true); } - if (tabPage->splitViewEnabled() && url == tabPage->secondaryViewContainer()->url()) { + if (tabPage->splitViewEnabled() && + (url == tabPage->secondaryViewContainer()->url() || + childUrlBehavior == ReturnIndexForOpenedParentAlso && tabPage->secondaryViewContainer()->url().isParentOf(url))) { return qMakePair(i, false); } + + i = (i + 1) % count(); } + while (i != currentIndex()); + return qMakePair(-1, false); } diff --git a/src/dolphintabwidget.h b/src/dolphintabwidget.h index e0146d7c71..7905912dac 100644 --- a/src/dolphintabwidget.h +++ b/src/dolphintabwidget.h @@ -60,11 +60,17 @@ public: void refreshViews(); /** - * @return Whether any of the tab pages contains @p url in their primary - * or secondary view. + * @return Whether any of the tab pages has @p url opened + * in their primary or secondary view. */ bool isUrlOpen(const QUrl& url) const; + /** + * @return Whether any of the tab pages has @p url or it's parent opened + * in their primary or secondary view. + */ + bool isUrlOrParentOpen(const QUrl& url) const; + Q_SIGNALS: /** * Is emitted when the active view has been changed, by changing the current @@ -110,11 +116,12 @@ public Q_SLOTS: void openNewTab(const QUrl &primaryUrl, const QUrl &secondaryUrl = QUrl()); /** - * Opens each directory in \p dirs in a separate tab. If \a splitView is set, - * 2 directories are collected within one tab. + * Opens each directory in \p dirs in a separate tab unless it is already open. + * If \a splitView is set, 2 directories are collected within one tab. + * If \a skipChildUrls is set, do not open a directory if it's parent is already open. * \pre \a dirs must contain at least one url. */ - void openDirectories(const QList& dirs, bool splitView); + void openDirectories(const QList& dirs, bool splitView, bool skipChildUrls = false); /** * Opens the directories which contain the files \p files and selects all files. @@ -205,15 +212,21 @@ private: */ QString tabName(DolphinTabPage* tabPage) const; + enum ChildUrlBehavior { + ReturnIndexForOpenedUrlOnly, + ReturnIndexForOpenedParentAlso + }; + /** * @param url The URL that we would like - * @return a QPair with first containing the index of the tab with the - * desired URL or -1 if not found. Second says true if URL is in primary - * view container, false otherwise. False means the URL is in the secondary - * view container, unless first == -1. In that case the value of second - * is meaningless. + * @param childUrlBehavior Whether a tab with opened parent of the URL can be returned too + * @return a QPair with: + * First containing the index of the tab with the desired URL or -1 if not found. + * Second says true if URL is in primary view container, false otherwise. + * False means the URL is in the secondary view container, unless first == -1. + * In that case the value of second is meaningless. */ - QPair indexByUrl(const QUrl& url) const; + QPair indexByUrl(const QUrl& url, ChildUrlBehavior childUrlBehavior = ReturnIndexForOpenedUrlOnly) const; private: QPointer m_lastViewedTab; diff --git a/src/global.cpp b/src/global.cpp index 0712aa173f..5d6d90b59e 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -71,33 +71,55 @@ bool Dolphin::attachToExistingInstance(const QList& inputUrls, bool openFi return false; } - QStringList newUrls; + int activeWindowIndex = -1; + for (const auto& interface: qAsConst(dolphinInterfaces)) { + ++activeWindowIndex; - // check to see if any instances already have any of the given URLs open + auto isActiveWindowReply = interface.first->isActiveWindow(); + isActiveWindowReply.waitForFinished(); + if (!isActiveWindowReply.isError() && isActiveWindowReply.value()) { + break; + } + } + + // check to see if any instances already have any of the given URLs or their parents open const auto urls = QUrl::toStringList(inputUrls); for (const QString& url : urls) { bool urlFound = false; - for (auto& interface: dolphinInterfaces) { - auto isUrlOpenReply = interface.first->isUrlOpen(url); + + // looping through the windows starting from the active one + int i = activeWindowIndex; + do { + auto &interface = dolphinInterfaces[i]; + + auto isUrlOpenReply = openFiles ? interface.first->isUrlOrParentOpen(url) : interface.first->isUrlOpen(url); isUrlOpenReply.waitForFinished(); if (!isUrlOpenReply.isError() && isUrlOpenReply.value()) { interface.second.append(url); urlFound = true; break; } + + i = (i + 1) % dolphinInterfaces.size(); } + while (i != activeWindowIndex); + if (!urlFound) { - newUrls.append(url); + dolphinInterfaces[activeWindowIndex].second.append(url); } } for (const auto& interface: qAsConst(dolphinInterfaces)) { - auto reply = openFiles ? interface.first->openFiles(newUrls, splitView) : interface.first->openDirectories(newUrls, splitView); + if (interface.second.isEmpty()) { + continue; + } + auto reply = openFiles ? + interface.first->openFiles(interface.second, splitView) : + interface.first->openDirectories(interface.second, splitView); reply.waitForFinished(); if (!reply.isError()) { interface.first->activateWindow(); attached = true; - break; } } return attached;