X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/29e6cf01df755724a629203964c9b61cd2f383c4..c836cf010c12858a7f3a4943c06f9de2b9f31a14:/src/dolphinmainwindow.cpp diff --git a/src/dolphinmainwindow.cpp b/src/dolphinmainwindow.cpp index dd1dcdac5..e9c0c3813 100644 --- a/src/dolphinmainwindow.cpp +++ b/src/dolphinmainwindow.cpp @@ -1,23 +1,10 @@ -/*************************************************************************** - * Copyright (C) 2006 by Peter Penz * - * Copyright (C) 2006 by Stefan Monov * - * Copyright (C) 2006 by Cvetoslav Ludmiloff * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ +/* + * SPDX-FileCopyrightText: 2006 Peter Penz + * SPDX-FileCopyrightText: 2006 Stefan Monov + * SPDX-FileCopyrightText: 2006 Cvetoslav Ludmiloff + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ #include "dolphinmainwindow.h" @@ -27,15 +14,16 @@ #include "dolphinbookmarkhandler.h" #include "dolphindockwidget.h" #include "dolphincontextmenu.h" +#include "dolphinnavigatorswidgetaction.h" #include "dolphinnewfilemenu.h" #include "dolphinrecenttabsmenu.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/information/informationpanel.h" #include "panels/terminal/terminalpanel.h" #include "settings/dolphinsettingsdialog.h" #include "statusbar/dolphinstatusbar.h" @@ -50,18 +38,20 @@ #include #include #include +#include #include #include #include +#include #include #include +#include #include #include #include #include #include #include -#include #include #include #include @@ -73,15 +63,16 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include -#include #include #include #include @@ -93,7 +84,7 @@ namespace { // Used for GeneralSettings::version() to determine whether // an updated version of Dolphin is running. - const int CurrentDolphinVersion = 200; + const int CurrentDolphinVersion = 201; // The maximum number of entries in the back/forward popup menu const int MaxNumberOfNavigationentries = 12; // The maximum number of "Activate Tab" shortcuts @@ -112,7 +103,7 @@ DolphinMainWindow::DolphinMainWindow() : m_bookmarkHandler(nullptr), m_controlButton(nullptr), m_updateToolBarTimer(nullptr), - m_lastHandleUrlStatJob(nullptr), + m_lastHandleUrlOpenJob(nullptr), m_terminalPanel(nullptr), m_placesPanel(nullptr), m_tearDownFromPlacesRequested(false), @@ -144,15 +135,16 @@ DolphinMainWindow::DolphinMainWindow() : connect(undoManager, &KIO::FileUndoManager::jobRecordingFinished, this, &DolphinMainWindow::showCommand); - GeneralSettings* generalSettings = GeneralSettings::self(); - const bool firstRun = (generalSettings->version() < 200); + const bool firstRun = (GeneralSettings::version() < 200); if (firstRun) { - generalSettings->setViewPropsTimestamp(QDateTime::currentDateTime()); + GeneralSettings::setViewPropsTimestamp(QDateTime::currentDateTime()); } setAcceptDrops(true); - m_tabWidget = new DolphinTabWidget(this); + auto *navigatorsWidgetAction = new DolphinNavigatorsWidgetAction(this); + actionCollection()->addAction(QStringLiteral("url_navigators"), navigatorsWidgetAction); + m_tabWidget = new DolphinTabWidget(navigatorsWidgetAction, this); m_tabWidget->setObjectName("tabWidget"); connect(m_tabWidget, &DolphinTabWidget::activeViewChanged, this, &DolphinMainWindow::activeViewChanged); @@ -181,22 +173,31 @@ DolphinMainWindow::DolphinMainWindow() : connect(clipboard, &QClipboard::dataChanged, this, &DolphinMainWindow::updatePasteAction); - QAction* showFilterBarAction = actionCollection()->action(QStringLiteral("show_filter_bar")); - showFilterBarAction->setChecked(generalSettings->filterBar()); + QAction* toggleFilterBarAction = actionCollection()->action(QStringLiteral("toggle_filter")); + toggleFilterBarAction->setChecked(GeneralSettings::filterBar()); if (firstRun) { menuBar()->setVisible(false); - // Assure a proper default size if Dolphin runs the first time - resize(750, 500); } const bool showMenu = !menuBar()->isHidden(); QAction* showMenuBarAction = actionCollection()->action(KStandardAction::name(KStandardAction::ShowMenubar)); showMenuBarAction->setChecked(showMenu); // workaround for bug #171080 - if (!showMenu) { - createControlButton(); + + auto hamburgerMenu = static_cast(actionCollection()->action( + KStandardAction::name(KStandardAction::HamburgerMenu))); + hamburgerMenu->setMenuBar(menuBar()); + hamburgerMenu->setMenuBarAdvertised(false); // This line will soon be removed when the + // hamburger menu contents are re-arranged. + connect(hamburgerMenu, &KHamburgerMenu::aboutToShowMenu, + this, &DolphinMainWindow::updateHamburgerMenu); + hamburgerMenu->hideActionsOf(toolBar()); + if (GeneralSettings::version() < 201 && !toolBar()->actions().contains(hamburgerMenu)) { + addHamburgerMenuToToolbar(); } + updateAllowedToolbarAreas(); + // enable middle-click on back/forward/up to open in a new tab auto *middleClickEventFilter = new MiddleClickActionEventFilter(this); connect(middleClickEventFilter, &MiddleClickActionEventFilter::actionMiddleClicked, this, &DolphinMainWindow::slotToolBarActionMiddleClicked); @@ -216,13 +217,32 @@ DolphinMainWindow::~DolphinMainWindow() QVector DolphinMainWindow::viewContainers() const { QVector viewContainers; - viewContainers.reserve(m_tabWidget->count()); + for (int i = 0; i < m_tabWidget->count(); ++i) { - viewContainers << m_tabWidget->tabPageAt(i)->activeViewContainer(); + DolphinTabPage *tabPage = m_tabWidget->tabPageAt(i); + + viewContainers << tabPage->primaryViewContainer(); + if (tabPage->splitViewEnabled()) { + viewContainers << tabPage->secondaryViewContainer(); + } } return viewContainers; } +void DolphinMainWindow::setViewsWithInvalidPathsToHome() +{ + const QVector theViewContainers = viewContainers(); + for (DolphinViewContainer *viewContainer : theViewContainers) { + + // Only consider local dirs, not remote locations and abstract protocols + if (viewContainer->url().isLocalFile()) { + if (!QFileInfo::exists(viewContainer->url().toLocalFile())) { + viewContainer->setUrl(QUrl::fromLocalFile(QDir::homePath())); + } + } + } +} + void DolphinMainWindow::openDirectories(const QList& dirs, bool splitView) { m_tabWidget->openDirectories(dirs, splitView); @@ -238,6 +258,20 @@ void DolphinMainWindow::openFiles(const QList& files, bool splitView) m_tabWidget->openFiles(files, splitView); } +bool DolphinMainWindow::isFoldersPanelEnabled() const +{ + return actionCollection()->action(QStringLiteral("show_folders_panel"))->isChecked(); +} + +bool DolphinMainWindow::isInformationPanelEnabled() const +{ +#ifdef HAVE_BALOO + return actionCollection()->action(QStringLiteral("show_information_panel"))->isChecked(); +#else + return false; +#endif +} + void DolphinMainWindow::openFiles(const QStringList& files, bool splitView) { openFiles(QUrl::fromStringList(files), splitView); @@ -299,7 +333,7 @@ void DolphinMainWindow::changeUrl(const QUrl &url) updateViewActions(); updateGoActions(); - emit urlChanged(url); + Q_EMIT urlChanged(url); } void DolphinMainWindow::slotTerminalDirectoryChanged(const QUrl& url) @@ -334,12 +368,12 @@ void DolphinMainWindow::slotSelectionChanged(const KFileItemList& selection) compareFilesAction->setEnabled(false); } - emit selectionChanged(selection); + Q_EMIT selectionChanged(selection); } void DolphinMainWindow::updateHistory() { - const KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator(); + const KUrlNavigator *urlNavigator = m_activeViewContainer->urlNavigatorInternalWithHistory(); const int index = urlNavigator->historyIndex(); QAction* backAction = actionCollection()->action(KStandardAction::name(KStandardAction::Back)); @@ -360,8 +394,8 @@ void DolphinMainWindow::updateHistory() void DolphinMainWindow::updateFilterBarAction(bool show) { - QAction* showFilterBarAction = actionCollection()->action(QStringLiteral("show_filter_bar")); - showFilterBarAction->setChecked(show); + QAction* toggleFilterBarAction = actionCollection()->action(QStringLiteral("toggle_filter")); + toggleFilterBarAction->setChecked(show); } void DolphinMainWindow::openNewMainWindow() @@ -371,7 +405,11 @@ void DolphinMainWindow::openNewMainWindow() void DolphinMainWindow::openNewActivatedTab() { + // keep browsers compatibility, new tab is always after last one + auto openNewTabAfterLastTabConfigured = GeneralSettings::openNewTabAfterLastTab(); + GeneralSettings::setOpenNewTabAfterLastTab(true); m_tabWidget->openNewActivatedTab(); + GeneralSettings::setOpenNewTabAfterLastTab(openNewTabAfterLastTabConfigured); } void DolphinMainWindow::addToPlaces() @@ -400,19 +438,9 @@ void DolphinMainWindow::addToPlaces() } } -void DolphinMainWindow::openNewTab(const QUrl& url, DolphinTabWidget::TabPlacement tabPlacement) -{ - m_tabWidget->openNewTab(url, QUrl(), tabPlacement); -} - -void DolphinMainWindow::openNewTabAfterCurrentTab(const QUrl& url) -{ - m_tabWidget->openNewTab(url, QUrl(), DolphinTabWidget::AfterCurrentTab); -} - -void DolphinMainWindow::openNewTabAfterLastTab(const QUrl& url) +void DolphinMainWindow::openNewTab(const QUrl& url) { - m_tabWidget->openNewTab(url, QUrl(), DolphinTabWidget::AfterLastTab); + m_tabWidget->openNewTab(url, QUrl()); } void DolphinMainWindow::openInNewTab() @@ -420,10 +448,10 @@ void DolphinMainWindow::openInNewTab() const KFileItemList& list = m_activeViewContainer->view()->selectedItems(); bool tabCreated = false; - foreach (const KFileItem& item, list) { + for (const KFileItem& item : list) { const QUrl& url = DolphinView::openItemAsFolderUrl(item); if (!url.isEmpty()) { - openNewTabAfterCurrentTab(url); + openNewTab(url); tabCreated = true; } } @@ -431,7 +459,7 @@ void DolphinMainWindow::openInNewTab() // if no new tab has been created from the selection // open the current directory in a new tab if (!tabCreated) { - openNewTabAfterCurrentTab(m_activeViewContainer->url()); + openNewTab(m_activeViewContainer->url()); } } @@ -486,7 +514,10 @@ void DolphinMainWindow::closeEvent(QCloseEvent* event) closedByUser = false; } - if (m_tabWidget->count() > 1 && GeneralSettings::confirmClosingMultipleTabs() && closedByUser) { + if (m_tabWidget->count() > 1 + && GeneralSettings::confirmClosingMultipleTabs() + && !GeneralSettings::rememberOpenedTabs() + && closedByUser) { // Ask the user if he really wants to quit and close all tabs. // Open a confirmation dialog with 3 buttons: // QDialogButtonBox::Yes -> Quit @@ -582,6 +613,14 @@ void DolphinMainWindow::closeEvent(QCloseEvent* event) } } + if (GeneralSettings::rememberOpenedTabs()) { + KConfigGui::setSessionConfig(QStringLiteral("dolphin"), QStringLiteral("dolphin")); + KConfig *config = KConfigGui::sessionConfig(); + saveGlobalProperties(config); + savePropertiesInternal(config, 1); + config->sync(); + } + GeneralSettings::setVersion(CurrentDolphinVersion); GeneralSettings::self()->save(); @@ -647,12 +686,12 @@ void DolphinMainWindow::undo() void DolphinMainWindow::cut() { - m_activeViewContainer->view()->cutSelectedItems(); + m_activeViewContainer->view()->cutSelectedItemsToClipboard(); } void DolphinMainWindow::copy() { - m_activeViewContainer->view()->copySelectedItems(); + m_activeViewContainer->view()->copySelectedItemsToClipboard(); } void DolphinMainWindow::paste() @@ -699,7 +738,7 @@ void DolphinMainWindow::slotToolBarActionMiddleClicked(QAction *action) void DolphinMainWindow::slotAboutToShowBackPopupMenu() { - KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator(); + 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) { @@ -712,7 +751,7 @@ void DolphinMainWindow::slotAboutToShowBackPopupMenu() void DolphinMainWindow::slotGoBack(QAction* action) { int gotoIndex = action->data().value(); - KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator(); + const KUrlNavigator *urlNavigator = m_activeViewContainer->urlNavigatorInternalWithHistory(); for (int i = gotoIndex - urlNavigator->historyIndex(); i > 0; --i) { goBack(); } @@ -721,14 +760,14 @@ void DolphinMainWindow::slotGoBack(QAction* action) void DolphinMainWindow::slotBackForwardActionMiddleClicked(QAction* action) { if (action) { - KUrlNavigator* urlNavigator = activeViewContainer()->urlNavigator(); - openNewTabAfterCurrentTab(urlNavigator->locationUrl(action->data().value())); + const KUrlNavigator *urlNavigator = activeViewContainer()->urlNavigatorInternalWithHistory(); + openNewTab(urlNavigator->locationUrl(action->data().value())); } } void DolphinMainWindow::slotAboutToShowForwardPopupMenu() { - KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator(); + const KUrlNavigator *urlNavigator = m_activeViewContainer->urlNavigatorInternalWithHistory(); int entries = 0; m_forwardAction->menu()->clear(); for (int i = urlNavigator->historyIndex() - 1; i >= 0 && entries < MaxNumberOfNavigationentries; --i, ++entries) { @@ -741,7 +780,7 @@ void DolphinMainWindow::slotAboutToShowForwardPopupMenu() void DolphinMainWindow::slotGoForward(QAction* action) { int gotoIndex = action->data().value(); - KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator(); + const KUrlNavigator *urlNavigator = m_activeViewContainer->urlNavigatorInternalWithHistory(); for (int i = urlNavigator->historyIndex() - gotoIndex; i > 0; --i) { goForward(); } @@ -774,7 +813,7 @@ void DolphinMainWindow::invertSelection() void DolphinMainWindow::toggleSplitView() { DolphinTabPage* tabPage = m_tabWidget->currentTabPage(); - tabPage->setSplitViewEnabled(!tabPage->splitViewEnabled()); + tabPage->setSplitViewEnabled(!tabPage->splitViewEnabled(), WithAnimation); updateViewActions(); } @@ -782,8 +821,8 @@ void DolphinMainWindow::toggleSplitView() void DolphinMainWindow::toggleSplitStash() { DolphinTabPage* tabPage = m_tabWidget->currentTabPage(); - tabPage->setSplitViewEnabled(false); - tabPage->setSplitViewEnabled(true, QUrl("stash:/")); + tabPage->setSplitViewEnabled(false, WithAnimation); + tabPage->setSplitViewEnabled(true, WithAnimation, QUrl("stash:/")); } void DolphinMainWindow::reloadView() @@ -813,6 +852,15 @@ void DolphinMainWindow::showFilterBar() m_activeViewContainer->setFilterBarVisible(true); } +void DolphinMainWindow::toggleFilterBar() +{ + const bool checked = !m_activeViewContainer->isFilterBarVisible(); + m_activeViewContainer->setFilterBarVisible(checked); + + QAction* toggleFilterBarAction = actionCollection()->action(QStringLiteral("toggle_filter")); + toggleFilterBarAction->setChecked(checked); +} + void DolphinMainWindow::toggleEditLocation() { clearStatusBar(); @@ -843,7 +891,8 @@ void DolphinMainWindow::replaceLocation() void DolphinMainWindow::togglePanelLockState() { const bool newLockState = !GeneralSettings::lockPanels(); - foreach (QObject* child, children()) { + const auto childrenObjects = children(); + for (QObject* child : childrenObjects) { DolphinDockWidget* dock = qobject_cast(child); if (dock) { dock->setLocked(newLockState); @@ -862,7 +911,7 @@ void DolphinMainWindow::slotTerminalPanelVisibilityChanged() void DolphinMainWindow::goBack() { - KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator(); + DolphinUrlNavigator *urlNavigator = m_activeViewContainer->urlNavigatorInternalWithHistory(); urlNavigator->goBack(); if (urlNavigator->locationState().isEmpty()) { @@ -874,42 +923,42 @@ void DolphinMainWindow::goBack() void DolphinMainWindow::goForward() { - m_activeViewContainer->urlNavigator()->goForward(); + m_activeViewContainer->urlNavigatorInternalWithHistory()->goForward(); } void DolphinMainWindow::goUp() { - m_activeViewContainer->urlNavigator()->goUp(); + m_activeViewContainer->urlNavigatorInternalWithHistory()->goUp(); } void DolphinMainWindow::goHome() { - m_activeViewContainer->urlNavigator()->goHome(); + m_activeViewContainer->urlNavigatorInternalWithHistory()->goHome(); } void DolphinMainWindow::goBackInNewTab() { - KUrlNavigator* urlNavigator = activeViewContainer()->urlNavigator(); + const KUrlNavigator* urlNavigator = activeViewContainer()->urlNavigatorInternalWithHistory(); const int index = urlNavigator->historyIndex() + 1; - openNewTabAfterCurrentTab(urlNavigator->locationUrl(index)); + openNewTab(urlNavigator->locationUrl(index)); } void DolphinMainWindow::goForwardInNewTab() { - KUrlNavigator* urlNavigator = activeViewContainer()->urlNavigator(); + const KUrlNavigator* urlNavigator = activeViewContainer()->urlNavigatorInternalWithHistory(); const int index = urlNavigator->historyIndex() - 1; - openNewTabAfterCurrentTab(urlNavigator->locationUrl(index)); + openNewTab(urlNavigator->locationUrl(index)); } void DolphinMainWindow::goUpInNewTab() { const QUrl currentUrl = activeViewContainer()->urlNavigator()->locationUrl(); - openNewTabAfterCurrentTab(KIO::upUrl(currentUrl)); + openNewTab(KIO::upUrl(currentUrl)); } void DolphinMainWindow::goHomeInNewTab() { - openNewTabAfterCurrentTab(Dolphin::homeUrl()); + openNewTab(Dolphin::homeUrl()); } void DolphinMainWindow::compareFiles() @@ -929,30 +978,16 @@ void DolphinMainWindow::compareFiles() command.append("\" \""); command.append(urlB.toDisplayString(QUrl::PreferLocalFile)); command.append('\"'); - KRun::runCommand(command, QStringLiteral("Kompare"), QStringLiteral("kompare"), this); + + KIO::CommandLauncherJob *job = new KIO::CommandLauncherJob(command, this); + job->setDesktopName(QStringLiteral("org.kde.kompare")); + job->start(); } void DolphinMainWindow::toggleShowMenuBar() { const bool visible = menuBar()->isVisible(); menuBar()->setVisible(!visible); - if (visible) { - createControlButton(); - } else { - deleteControlButton(); - } -} - -QString DolphinMainWindow::activeContainerLocalPath() -{ - KIO::StatJob* statJob = KIO::mostLocalUrl(m_activeViewContainer->url()); - KJobWidgets::setWindow(statJob, this); - statJob->exec(); - QUrl url = statJob->mostLocalUrl(); - if (url.isLocalFile()) { - return url.toLocalFile(); - } - return QDir::homePath(); } QPointer DolphinMainWindow::preferredSearchTool() @@ -1001,7 +1036,31 @@ void DolphinMainWindow::openPreferredSearchTool() void DolphinMainWindow::openTerminal() { - KToolInvocation::invokeTerminal(QString(), activeContainerLocalPath()); + const QUrl url = m_activeViewContainer->url(); + + if (url.isLocalFile()) { + KToolInvocation::invokeTerminal(QString(), {}, url.toLocalFile()); + return; + } + + // Not a local file, with protocol Class ":local", try stat'ing + if (KProtocolInfo::protocolClass(url.scheme()) == QLatin1String(":local")) { + KIO::StatJob *job = KIO::mostLocalUrl(url); + KJobWidgets::setWindow(job, this); + connect(job, &KJob::result, this, [job]() { + QUrl statUrl; + if (!job->error()) { + statUrl = job->mostLocalUrl(); + } + + KToolInvocation::invokeTerminal(QString(), {}, statUrl.isLocalFile() ? statUrl.toLocalFile() : QDir::homePath()); + }); + + return; + } + + // Nothing worked, just use $HOME + KToolInvocation::invokeTerminal(QString(), {}, QDir::homePath()); } void DolphinMainWindow::editSettings() @@ -1011,8 +1070,10 @@ void DolphinMainWindow::editSettings() container->view()->writeSettings(); const QUrl url = container->url(); - DolphinSettingsDialog* settingsDialog = new DolphinSettingsDialog(url, this); + DolphinSettingsDialog* settingsDialog = new DolphinSettingsDialog(url, this, actionCollection()); connect(settingsDialog, &DolphinSettingsDialog::settingsChanged, this, &DolphinMainWindow::refreshViews); + connect(settingsDialog, &DolphinSettingsDialog::settingsChanged, + &DolphinUrlNavigatorsController::slotReadSettings); settingsDialog->setAttribute(Qt::WA_DeleteOnClose); settingsDialog->show(); m_settingsDialog = settingsDialog; @@ -1023,34 +1084,31 @@ void DolphinMainWindow::editSettings() void DolphinMainWindow::handleUrl(const QUrl& url) { - delete m_lastHandleUrlStatJob; - m_lastHandleUrlStatJob = nullptr; + delete m_lastHandleUrlOpenJob; + m_lastHandleUrlOpenJob = nullptr; if (url.isLocalFile() && QFileInfo(url.toLocalFile()).isDir()) { activeViewContainer()->setUrl(url); - } else if (KProtocolManager::supportsListing(url)) { - // stat the URL to see if it is a dir or not - m_lastHandleUrlStatJob = KIO::stat(url, KIO::HideProgressInfo); - if (m_lastHandleUrlStatJob->uiDelegate()) { - KJobWidgets::setWindow(m_lastHandleUrlStatJob, this); - } - connect(m_lastHandleUrlStatJob, &KIO::Job::result, - this, &DolphinMainWindow::slotHandleUrlStatFinished); - } else { - new KRun(url, this); // Automatically deletes itself after being finished - } -} + m_lastHandleUrlOpenJob = new KIO::OpenUrlJob(url); + m_lastHandleUrlOpenJob->setUiDelegate(new KIO::JobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this)); + m_lastHandleUrlOpenJob->setShowOpenOrExecuteDialog(true); -void DolphinMainWindow::slotHandleUrlStatFinished(KJob* job) -{ - m_lastHandleUrlStatJob = nullptr; - const KIO::UDSEntry entry = static_cast(job)->statResult(); - const QUrl url = static_cast(job)->url(); - if (entry.isDir()) { - activeViewContainer()->setUrl(url); - } else { - new KRun(url, this); // Automatically deletes itself after being finished + connect(m_lastHandleUrlOpenJob, &KIO::OpenUrlJob::mimeTypeFound, this, + [this, url](const QString &mimetype) { + if (mimetype == QLatin1String("inode/directory")) { + // If it's a dir, we'll take it from here + m_lastHandleUrlOpenJob->kill(); + m_lastHandleUrlOpenJob = nullptr; + activeViewContainer()->setUrl(url); + } + }); + + connect(m_lastHandleUrlOpenJob, &KIO::OpenUrlJob::result, this, [this]() { + m_lastHandleUrlOpenJob = nullptr; + }); + + m_lastHandleUrlOpenJob->start(); } } @@ -1082,7 +1140,7 @@ void DolphinMainWindow::openContextMenu(const QPoint& pos, break; case DolphinContextMenu::OpenParentFolderInNewTab: - openNewTabAfterLastTab(KIO::upUrl(item.url())); + openNewTab(KIO::upUrl(item.url())); break; case DolphinContextMenu::None: @@ -1096,84 +1154,67 @@ void DolphinMainWindow::openContextMenu(const QPoint& pos, } } -void DolphinMainWindow::updateControlMenu() +void DolphinMainWindow::updateHamburgerMenu() { - QMenu* menu = qobject_cast(sender()); - Q_ASSERT(menu); - - // All actions get cleared by QMenu::clear(). This includes the sub-menus - // because 'menu' is their parent. - menu->clear(); - KActionCollection* ac = actionCollection(); + auto hamburgerMenu = static_cast( + ac->action(KStandardAction::name(KStandardAction::HamburgerMenu))); + auto menu = hamburgerMenu->menu(); + if (!menu) { + menu = new QMenu(this); + hamburgerMenu->setMenu(menu); + } else { + menu->clear(); + } menu->addMenu(m_newFileMenu->menu()); - addActionToMenu(ac->action(QStringLiteral("file_new")), menu); - addActionToMenu(ac->action(QStringLiteral("new_tab")), menu); - addActionToMenu(ac->action(QStringLiteral("closed_tabs")), menu); + menu->addAction(ac->action(QStringLiteral("file_new"))); + menu->addAction(ac->action(QStringLiteral("new_tab"))); + menu->addAction(ac->action(QStringLiteral("closed_tabs"))); menu->addSeparator(); // Add "Edit" actions - bool added = addActionToMenu(ac->action(KStandardAction::name(KStandardAction::Undo)), menu) | - addActionToMenu(ac->action(KStandardAction::name(KStandardAction::SelectAll)), menu) | - addActionToMenu(ac->action(QStringLiteral("invert_selection")), menu); + menu->addAction(ac->action(KStandardAction::name(KStandardAction::Undo))); + menu->addAction(ac->action(QString("copy_location"))); + menu->addAction(ac->action(QStringLiteral("copy_to_inactive_split_view"))); + menu->addAction(ac->action(QStringLiteral("move_to_inactive_split_view"))); + menu->addAction(ac->action(KStandardAction::name(KStandardAction::SelectAll))); + menu->addAction(ac->action(QStringLiteral("invert_selection"))); - if (added) { - menu->addSeparator(); - } + menu->addSeparator(); // Add "View" actions if (!GeneralSettings::showZoomSlider()) { - addActionToMenu(ac->action(KStandardAction::name(KStandardAction::ZoomIn)), menu); - addActionToMenu(ac->action(QStringLiteral("view_zoom_reset")), menu); - addActionToMenu(ac->action(KStandardAction::name(KStandardAction::ZoomOut)), menu); + menu->addAction(ac->action(KStandardAction::name(KStandardAction::ZoomIn))); + menu->addAction(ac->action(QStringLiteral("view_zoom_reset"))); + menu->addAction(ac->action(KStandardAction::name(KStandardAction::ZoomOut))); menu->addSeparator(); } - added = addActionToMenu(ac->action(QStringLiteral("show_preview")), menu) | - addActionToMenu(ac->action(QStringLiteral("show_in_groups")), menu) | - addActionToMenu(ac->action(QStringLiteral("show_hidden_files")), menu) | - addActionToMenu(ac->action(QStringLiteral("additional_info")), menu) | - addActionToMenu(ac->action(QStringLiteral("view_properties")), menu); + menu->addAction(ac->action(QStringLiteral("show_preview"))); + menu->addAction(ac->action(QStringLiteral("show_in_groups"))); + menu->addAction(ac->action(QStringLiteral("show_hidden_files"))); + menu->addAction(ac->action(QStringLiteral("additional_info"))); + menu->addAction(ac->action(QStringLiteral("view_properties"))); - if (added) { - menu->addSeparator(); - } + menu->addSeparator(); // Add a curated assortment of items from the "Tools" menu - addActionToMenu(ac->action(QStringLiteral("show_filter_bar")), menu); - addActionToMenu(ac->action(QStringLiteral("open_preferred_search_tool")), menu); - addActionToMenu(ac->action(QStringLiteral("open_terminal")), menu); + menu->addAction(ac->action(QStringLiteral("show_filter_bar"))); + menu->addAction(ac->action(QStringLiteral("open_preferred_search_tool"))); + menu->addAction(ac->action(QStringLiteral("open_terminal"))); menu->addSeparator(); // Add "Show Panels" menu - addActionToMenu(ac->action(QStringLiteral("panels")), menu); + menu->addAction(ac->action(QStringLiteral("panels"))); // Add "Settings" menu entries - addActionToMenu(ac->action(KStandardAction::name(KStandardAction::KeyBindings)), menu); - addActionToMenu(ac->action(KStandardAction::name(KStandardAction::ConfigureToolbars)), menu); - addActionToMenu(ac->action(KStandardAction::name(KStandardAction::Preferences)), menu); - addActionToMenu(ac->action(KStandardAction::name(KStandardAction::ShowMenubar)), menu); - - // Add "Help" menu - auto helpMenu = m_helpMenu->menu(); - helpMenu->setIcon(QIcon::fromTheme(QStringLiteral("system-help"))); - menu->addMenu(helpMenu); -} - -void DolphinMainWindow::updateToolBar() -{ - if (!menuBar()->isVisible()) { - createControlButton(); - } -} - -void DolphinMainWindow::slotControlButtonDeleted() -{ - m_controlButton = nullptr; - m_updateToolBarTimer->start(); + menu->addAction(ac->action(KStandardAction::name(KStandardAction::KeyBindings))); + menu->addAction(ac->action(KStandardAction::name(KStandardAction::ConfigureToolbars))); + menu->addAction(ac->action(KStandardAction::name(KStandardAction::Preferences))); + menu->addAction(ac->action(KStandardAction::name(KStandardAction::ShowMenubar))); } void DolphinMainWindow::slotPlaceActivated(const QUrl& url) @@ -1185,7 +1226,9 @@ void DolphinMainWindow::slotPlaceActivated(const QUrl& url) // which had been unmounted earlier, see https://bugs.kde.org/show_bug.cgi?id=161385. reloadView(); } else { + view->disableUrlNavigatorSelectionRequests(); changeUrl(url); + view->enableUrlNavigatorSelectionRequests(); } } @@ -1209,7 +1252,12 @@ void DolphinMainWindow::activeViewChanged(DolphinViewContainer* viewContainer) // view and url navigator) and main window. oldViewContainer->disconnect(this); oldViewContainer->view()->disconnect(this); - oldViewContainer->urlNavigator()->disconnect(this); + auto navigators = static_cast + (actionCollection()->action(QStringLiteral("url_navigators"))); + navigators->primaryUrlNavigator()->disconnect(this); + if (auto secondaryUrlNavigator = navigators->secondaryUrlNavigator()) { + secondaryUrlNavigator->disconnect(this); + } // except the requestItemInfo so that on hover the information panel can still be updated connect(oldViewContainer->view(), &DolphinView::requestItemInfo, @@ -1228,7 +1276,7 @@ void DolphinMainWindow::activeViewChanged(DolphinViewContainer* viewContainer) updateSearchAction(); const QUrl url = viewContainer->url(); - emit urlChanged(url); + Q_EMIT urlChanged(url); } void DolphinMainWindow::tabCountChanged(int count) @@ -1244,7 +1292,7 @@ void DolphinMainWindow::tabCountChanged(int count) void DolphinMainWindow::updateWindowTitle() { - const QString newTitle = m_activeViewContainer->caption(); + const QString newTitle = m_activeViewContainer->captionWindowTitle(); if (windowTitle() != newTitle) { setWindowTitle(newTitle); } @@ -1252,6 +1300,10 @@ void DolphinMainWindow::updateWindowTitle() void DolphinMainWindow::slotStorageTearDownFromPlacesRequested(const QString& mountPath) { + connect(m_placesPanel, &PlacesPanel::storageTearDownSuccessful, this, [this, mountPath]() { + setViewsToHomeIfMountPathOpen(mountPath); + }); + if (m_terminalPanel && m_terminalPanel->currentWorkingDirectory().startsWith(mountPath)) { m_tearDownFromPlacesRequested = true; m_terminalPanel->goHome(); @@ -1263,14 +1315,31 @@ void DolphinMainWindow::slotStorageTearDownFromPlacesRequested(const QString& mo void DolphinMainWindow::slotStorageTearDownExternallyRequested(const QString& mountPath) { + connect(m_placesPanel, &PlacesPanel::storageTearDownSuccessful, this, [this, mountPath]() { + setViewsToHomeIfMountPathOpen(mountPath); + }); + if (m_terminalPanel && m_terminalPanel->currentWorkingDirectory().startsWith(mountPath)) { m_tearDownFromPlacesRequested = false; m_terminalPanel->goHome(); } } +void DolphinMainWindow::setViewsToHomeIfMountPathOpen(const QString& mountPath) +{ + const QVector theViewContainers = viewContainers(); + for (DolphinViewContainer *viewContainer : theViewContainers) { + if (viewContainer && viewContainer->url().toLocalFile().startsWith(mountPath)) { + viewContainer->setUrl(QUrl::fromLocalFile(QDir::homePath())); + } + } + disconnect(m_placesPanel, &PlacesPanel::storageTearDownSuccessful, nullptr, nullptr); +} + void DolphinMainWindow::setupActions() { + KStandardAction::hamburgerMenu(nullptr, nullptr, actionCollection()); + // setup 'File' menu m_newFileMenu = new DolphinNewFileMenu(actionCollection(), this); QMenu* menu = m_newFileMenu->menu(); @@ -1295,7 +1364,7 @@ void DolphinMainWindow::setupActions() "Tab with the current location and view." "A tab is an additional view within this window. " "You can drag and drop items between tabs.")); - actionCollection()->setDefaultShortcuts(newTab, {Qt::CTRL + Qt::Key_T, Qt::CTRL + Qt::SHIFT + Qt::Key_N}); + actionCollection()->setDefaultShortcuts(newTab, {Qt::CTRL | Qt::Key_T, Qt::CTRL | Qt::SHIFT | Qt::Key_N}); connect(newTab, &QAction::triggered, this, &DolphinMainWindow::openNewActivatedTab); QAction* addToPlaces = actionCollection()->addAction(QStringLiteral("add_to_places")); @@ -1348,6 +1417,47 @@ void DolphinMainWindow::setupActions() "If the items were added to the clipboard by the Cut " "action they are removed from their old location.") + cutCopyPastePara); + QAction* copyToOtherViewAction = actionCollection()->addAction(QStringLiteral("copy_to_inactive_split_view")); + copyToOtherViewAction->setText(i18nc("@action:inmenu", "Copy to Inactive Split View")); + copyToOtherViewAction->setWhatsThis(xi18nc("@info:whatsthis Copy", "This copies the selected items from " + "the active 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); + + QAction* moveToOtherViewAction = actionCollection()->addAction(QStringLiteral("move_to_inactive_split_view")); + moveToOtherViewAction->setText(i18nc("@action:inmenu", "Move to Inactive Split View")); + moveToOtherViewAction->setWhatsThis(xi18nc("@info:whatsthis Move", "This moves the selected items from " + "the active 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); + + QAction* showFilterBar = actionCollection()->addAction(QStringLiteral("show_filter_bar")); + showFilterBar->setText(i18nc("@action:inmenu Tools", "Filter...")); + showFilterBar->setToolTip(i18nc("@info:tooltip", "Toggle Filter Bar")); + showFilterBar->setWhatsThis(xi18nc("@info:whatsthis", "This opens the " + "Filter Bar at the bottom of the window. " + "There you can enter a text to filter the files and folders currently displayed. " + "Only those that contain the text in their name will be kept in view.")); + showFilterBar->setIcon(QIcon::fromTheme(QStringLiteral("view-filter"))); + actionCollection()->setDefaultShortcuts(showFilterBar, {Qt::CTRL | Qt::Key_I, Qt::Key_Slash}); + connect(showFilterBar, &QAction::triggered, this, &DolphinMainWindow::showFilterBar); + + // toggle_filter acts as a copy of the main showFilterBar to be used mainly + // in the toolbar, with no default shortcut attached, to avoid messing with + // existing workflows (filter bar always open and Ctrl-I to focus) + QAction *toggleFilter = actionCollection()->addAction(QStringLiteral("toggle_filter")); + toggleFilter->setText(i18nc("@action:inmenu", "Toggle Filter Bar")); + toggleFilter->setIconText(i18nc("@action:intoolbar", "Filter")); + toggleFilter->setIcon(showFilterBar->icon()); + toggleFilter->setToolTip(showFilterBar->toolTip()); + toggleFilter->setWhatsThis(showFilterBar->whatsThis()); + toggleFilter->setCheckable(true); + connect(toggleFilter, &QAction::triggered, this, &DolphinMainWindow::toggleFilterBar); + QAction *searchAction = KStandardAction::find(this, &DolphinMainWindow::find, actionCollection()); searchAction->setText(i18n("Search...")); searchAction->setToolTip(i18nc("@info:tooltip", "Search for files and folders")); @@ -1378,7 +1488,7 @@ void DolphinMainWindow::setupActions() invertSelection->setWhatsThis(xi18nc("@info:whatsthis invert", "This selects all " "objects that you have currently not selected instead.")); invertSelection->setIcon(QIcon::fromTheme(QStringLiteral("edit-select-invert"))); - actionCollection()->setDefaultShortcut(invertSelection, Qt::CTRL + Qt::SHIFT + Qt::Key_A); + actionCollection()->setDefaultShortcut(invertSelection, Qt::CTRL | Qt::SHIFT | Qt::Key_A); connect(invertSelection, &QAction::triggered, this, &DolphinMainWindow::invertSelection); // setup 'View' menu @@ -1393,12 +1503,12 @@ void DolphinMainWindow::setupActions() connect(split, &QAction::triggered, this, &DolphinMainWindow::toggleSplitView); QAction* stashSplit = actionCollection()->addAction(QStringLiteral("split_stash")); - actionCollection()->setDefaultShortcut(stashSplit, Qt::CTRL + Qt::Key_S); + actionCollection()->setDefaultShortcut(stashSplit, Qt::CTRL | Qt::Key_S); stashSplit->setText(i18nc("@action:intoolbar Stash", "Stash")); stashSplit->setToolTip(i18nc("@info", "Opens the stash virtual directory in a split window")); stashSplit->setIcon(QIcon::fromTheme(QStringLiteral("folder-stash"))); stashSplit->setCheckable(false); - stashSplit->setVisible(KProtocolInfo::isKnownProtocol("stash")); + stashSplit->setVisible(QDBusConnection::sessionBus().interface()->isServiceRegistered(QStringLiteral("org.kde.kio.StashNotifier"))); connect(stashSplit, &QAction::triggered, this, &DolphinMainWindow::toggleSplitStash); KStandardAction::redisplay(this, &DolphinMainWindow::reloadView, actionCollection()); @@ -1428,7 +1538,7 @@ void DolphinMainWindow::setupActions() replaceLocation->setWhatsThis(xi18nc("@info:whatsthis", "This switches to editing the location and selects it " "so you can quickly enter a different location.")); - actionCollection()->setDefaultShortcut(replaceLocation, Qt::CTRL + Qt::Key_L); + actionCollection()->setDefaultShortcut(replaceLocation, Qt::CTRL | Qt::Key_L); connect(replaceLocation, &QAction::triggered, this, &DolphinMainWindow::replaceLocation); // setup 'Go' menu @@ -1462,7 +1572,7 @@ void DolphinMainWindow::setupActions() undoCloseTab->setText(i18nc("@action:inmenu File", "Undo close tab")); undoCloseTab->setWhatsThis(i18nc("@info:whatsthis undo close tab", "This returns you to the previously closed tab.")); - actionCollection()->setDefaultShortcut(undoCloseTab, Qt::CTRL + Qt::SHIFT + Qt::Key_T); + actionCollection()->setDefaultShortcut(undoCloseTab, Qt::CTRL | Qt::SHIFT | Qt::Key_T); undoCloseTab->setIcon(QIcon::fromTheme(QStringLiteral("edit-undo"))); undoCloseTab->setEnabled(false); connect(undoCloseTab, &QAction::triggered, recentTabsMenu, &DolphinRecentTabsMenu::undoCloseTab); @@ -1503,16 +1613,6 @@ void DolphinMainWindow::setupActions() "including folders that contain personal application data.")); // setup 'Tools' menu - QAction* showFilterBar = actionCollection()->addAction(QStringLiteral("show_filter_bar")); - showFilterBar->setText(i18nc("@action:inmenu Tools", "Show Filter Bar")); - showFilterBar->setWhatsThis(xi18nc("@info:whatsthis", "This opens the " - "Filter Bar at the bottom of the window. " - "There you can enter a text to filter the files and folders currently displayed. " - "Only those that contain the text in their name will be kept in view.")); - showFilterBar->setIcon(QIcon::fromTheme(QStringLiteral("view-filter"))); - actionCollection()->setDefaultShortcuts(showFilterBar, {Qt::CTRL + Qt::Key_I, Qt::Key_Slash}); - connect(showFilterBar, &QAction::triggered, this, &DolphinMainWindow::showFilterBar); - QAction* compareFiles = actionCollection()->addAction(QStringLiteral("compare_files")); compareFiles->setText(i18nc("@action:inmenu Tools", "Compare Files")); compareFiles->setIcon(QIcon::fromTheme(QStringLiteral("kompare"))); @@ -1525,27 +1625,27 @@ void DolphinMainWindow::setupActions() "This opens a preferred search tool for the viewed location." "Use More Search Tools menu to configure it.")); openPreferredSearchTool->setIcon(QIcon::fromTheme(QStringLiteral("search"))); - actionCollection()->setDefaultShortcut(openPreferredSearchTool, Qt::CTRL + Qt::SHIFT + Qt::Key_F); + actionCollection()->setDefaultShortcut(openPreferredSearchTool, Qt::CTRL | Qt::SHIFT | Qt::Key_F); connect(openPreferredSearchTool, &QAction::triggered, this, &DolphinMainWindow::openPreferredSearchTool); -#ifdef HAVE_TERMINAL if (KAuthorized::authorize(QStringLiteral("shell_access"))) { QAction* openTerminal = actionCollection()->addAction(QStringLiteral("open_terminal")); openTerminal->setText(i18nc("@action:inmenu Tools", "Open Terminal")); openTerminal->setWhatsThis(xi18nc("@info:whatsthis", "This opens a terminal application for the viewed location." "To learn more about terminals use the help in the terminal application.")); - openTerminal->setIcon(QIcon::fromTheme(QStringLiteral("dialog-scripts"))); - actionCollection()->setDefaultShortcut(openTerminal, Qt::SHIFT + Qt::Key_F4); + openTerminal->setIcon(QIcon::fromTheme(QStringLiteral("utilities-terminal"))); + actionCollection()->setDefaultShortcut(openTerminal, Qt::SHIFT | Qt::Key_F4); connect(openTerminal, &QAction::triggered, this, &DolphinMainWindow::openTerminal); +#ifdef 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"))); - actionCollection()->setDefaultShortcut(focusTerminalPanel, Qt::CTRL + Qt::SHIFT + Qt::Key_F4); + actionCollection()->setDefaultShortcut(focusTerminalPanel, Qt::CTRL | Qt::SHIFT | Qt::Key_F4); connect(focusTerminalPanel, &QAction::triggered, this, &DolphinMainWindow::focusTerminalPanel); - } #endif + } // setup 'Bookmarks' menu KActionMenu *bookmarkMenu = new KActionMenu(i18nc("@title:menu", "&Bookmarks"), this); @@ -1574,10 +1674,10 @@ void DolphinMainWindow::setupActions() // not in menu actions QList nextTabKeys = KStandardShortcut::tabNext(); - nextTabKeys.append(QKeySequence(Qt::CTRL + Qt::Key_Tab)); + nextTabKeys.append(QKeySequence(Qt::CTRL | Qt::Key_Tab)); QList prevTabKeys = KStandardShortcut::tabPrev(); - prevTabKeys.append(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Tab)); + prevTabKeys.append(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_Tab)); for (int i = 0; i < MaxActivateTabShortcuts; ++i) { QAction* activateTab = actionCollection()->addAction(QStringLiteral("activate_tab_%1").arg(i)); @@ -1595,7 +1695,7 @@ void DolphinMainWindow::setupActions() activateLastTab->setText(i18nc("@action:inmenu", "Activate Last Tab")); activateLastTab->setEnabled(false); connect(activateLastTab, &QAction::triggered, m_tabWidget, &DolphinTabWidget::activateLastTab); - actionCollection()->setDefaultShortcut(activateLastTab, Qt::ALT + Qt::Key_0); + actionCollection()->setDefaultShortcut(activateLastTab, Qt::ALT | Qt::Key_0); QAction* activateNextTab = actionCollection()->addAction(QStringLiteral("activate_next_tab")); activateNextTab->setIconText(i18nc("@action:inmenu", "Next Tab")); @@ -1673,6 +1773,8 @@ void DolphinMainWindow::setupDockWidgets() infoPanel, &InformationPanel::setSelection); connect(this, &DolphinMainWindow::requestItemInfo, infoPanel, &InformationPanel::requestDelayedItemInfo); + connect(this, &DolphinMainWindow::fileItemsChanged, + infoPanel, &InformationPanel::slotFilesItemChanged); #endif // i18n: This is the last paragraph for the "What's This"-texts of all four panels. @@ -1713,7 +1815,7 @@ void DolphinMainWindow::setupDockWidgets() connect(foldersPanel, &FoldersPanel::folderActivated, this, &DolphinMainWindow::changeUrl); connect(foldersPanel, &FoldersPanel::folderMiddleClicked, - this, &DolphinMainWindow::openNewTabAfterCurrentTab); + this, &DolphinMainWindow::openNewTab); connect(foldersPanel, &FoldersPanel::errorMessage, this, &DolphinMainWindow::showErrorMessage); @@ -1790,26 +1892,26 @@ void DolphinMainWindow::setupDockWidgets() placesDock->setWidget(m_placesPanel); QAction *placesAction = placesDock->toggleViewAction(); - createPanelAction(QIcon::fromTheme(QStringLiteral("bookmarks")), Qt::Key_F9, placesAction, QStringLiteral("show_places_panel")); + createPanelAction(QIcon::fromTheme(QStringLiteral("compass")), Qt::Key_F9, placesAction, QStringLiteral("show_places_panel")); addDockWidget(Qt::LeftDockWidgetArea, placesDock); connect(m_placesPanel, &PlacesPanel::placeActivated, this, &DolphinMainWindow::slotPlaceActivated); connect(m_placesPanel, &PlacesPanel::placeMiddleClicked, - this, &DolphinMainWindow::openNewTabAfterCurrentTab); + this, &DolphinMainWindow::openNewTab); connect(m_placesPanel, &PlacesPanel::errorMessage, this, &DolphinMainWindow::showErrorMessage); connect(this, &DolphinMainWindow::urlChanged, m_placesPanel, &PlacesPanel::setUrl); connect(placesDock, &DolphinDockWidget::visibilityChanged, - m_tabWidget, &DolphinTabWidget::slotPlacesPanelVisibilityChanged); + &DolphinUrlNavigatorsController::slotPlacesPanelVisibilityChanged); connect(this, &DolphinMainWindow::settingsChanged, m_placesPanel, &PlacesPanel::readSettings); connect(m_placesPanel, &PlacesPanel::storageTearDownRequested, this, &DolphinMainWindow::slotStorageTearDownFromPlacesRequested); connect(m_placesPanel, &PlacesPanel::storageTearDownExternallyRequested, this, &DolphinMainWindow::slotStorageTearDownExternallyRequested); - m_tabWidget->slotPlacesPanelVisibilityChanged(m_placesPanel->isVisible()); + DolphinUrlNavigatorsController::slotPlacesPanelVisibilityChanged(m_placesPanel->isVisible()); auto actionShowAllPlaces = new QAction(QIcon::fromTheme(QStringLiteral("view-hidden")), i18nc("@item:inmenu", "Show Hidden Places"), this); actionShowAllPlaces->setCheckable(true); @@ -1873,12 +1975,20 @@ void DolphinMainWindow::updateFileAndEditActions() { const KFileItemList list = m_activeViewContainer->view()->selectedItems(); const KActionCollection* col = actionCollection(); + KFileItemListProperties capabilitiesSource(list); + 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")); if (list.isEmpty()) { stateChanged(QStringLiteral("has_no_selection")); addToPlacesAction->setEnabled(true); + copyToOtherViewAction->setEnabled(false); + moveToOtherViewAction->setEnabled(false); + copyLocation->setEnabled(false); } else { stateChanged(QStringLiteral("has_selection")); @@ -1896,16 +2006,33 @@ void DolphinMainWindow::updateFileAndEditActions() addToPlacesAction->setEnabled(false); } - KFileItemListProperties capabilities(list); - const bool enableMoveToTrash = capabilities.isLocal() && capabilities.supportsMoving(); + 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(capabilities.supportsMoving()); + renameAction->setEnabled(capabilitiesSource.supportsMoving()); moveToTrashAction->setEnabled(enableMoveToTrash); - deleteAction->setEnabled(capabilities.supportsDeleting()); - deleteWithTrashShortcut->setEnabled(capabilities.supportsDeleting() && !enableMoveToTrash); - cutAction->setEnabled(capabilities.supportsMoving()); + deleteAction->setEnabled(capabilitiesSource.supportsDeleting()); + deleteWithTrashShortcut->setEnabled(capabilitiesSource.supportsDeleting() && !enableMoveToTrash); + cutAction->setEnabled(capabilitiesSource.supportsMoving()); + copyLocation->setEnabled(list.length() == 1); showTarget->setEnabled(list.length() == 1 && list.at(0).isLink()); - duplicateAction->setEnabled(capabilities.supportsWriting()); + duplicateAction->setEnabled(capabilitiesSource.supportsWriting()); } } @@ -1913,14 +2040,10 @@ void DolphinMainWindow::updateViewActions() { m_actionHandler->updateViewActions(); - QAction* showFilterBarAction = actionCollection()->action(QStringLiteral("show_filter_bar")); - showFilterBarAction->setChecked(m_activeViewContainer->isFilterBarVisible()); + QAction* toggleFilterBarAction = actionCollection()->action(QStringLiteral("toggle_filter")); + toggleFilterBarAction->setChecked(m_activeViewContainer->isFilterBarVisible()); updateSplitAction(); - - QAction* editableLocactionAction = actionCollection()->action(QStringLiteral("editable_location")); - const KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator(); - editableLocactionAction->setChecked(urlNavigator->isUrlEditable()); } void DolphinMainWindow::updateGoActions() @@ -1940,64 +2063,6 @@ void DolphinMainWindow::updateGoActions() goUpAction->setEnabled(KIO::upUrl(currentUrl) != currentUrl); } -void DolphinMainWindow::createControlButton() -{ - if (m_controlButton) { - return; - } - Q_ASSERT(!m_controlButton); - - m_controlButton = new QToolButton(this); - m_controlButton->setAccessibleName(i18nc("@action:intoolbar", "Control")); - m_controlButton->setIcon(QIcon::fromTheme(QStringLiteral("application-menu"))); - m_controlButton->setToolTip(i18nc("@action", "Show menu")); - m_controlButton->setAttribute(Qt::WidgetAttribute::WA_CustomWhatsThis); - m_controlButton->setPopupMode(QToolButton::InstantPopup); - - QMenu* controlMenu = new QMenu(m_controlButton); - connect(controlMenu, &QMenu::aboutToShow, this, &DolphinMainWindow::updateControlMenu); - controlMenu->installEventFilter(this); - - m_controlButton->setMenu(controlMenu); - - toolBar()->addWidget(m_controlButton); - connect(toolBar(), &KToolBar::iconSizeChanged, - m_controlButton, &QToolButton::setIconSize); - - // The added widgets are owned by the toolbar and may get deleted when e.g. the toolbar - // gets edited. In this case we must add them again. The adding is done asynchronously by - // m_updateToolBarTimer. - connect(m_controlButton, &QToolButton::destroyed, this, &DolphinMainWindow::slotControlButtonDeleted); - m_updateToolBarTimer = new QTimer(this); - m_updateToolBarTimer->setInterval(500); - connect(m_updateToolBarTimer, &QTimer::timeout, this, &DolphinMainWindow::updateToolBar); -} - -void DolphinMainWindow::deleteControlButton() -{ - delete m_controlButton; - m_controlButton = nullptr; - - delete m_updateToolBarTimer; - m_updateToolBarTimer = nullptr; -} - -bool DolphinMainWindow::addActionToMenu(QAction* action, QMenu* menu) -{ - Q_ASSERT(action); - Q_ASSERT(menu); - - const KToolBar* toolBarWidget = toolBar(); - foreach (const QWidget* widget, action->associatedWidgets()) { - if (widget == toolBarWidget) { - return false; - } - } - - menu->addAction(action); - return true; -} - void DolphinMainWindow::refreshViews() { m_tabWidget->refreshViews(); @@ -2006,12 +2071,12 @@ void DolphinMainWindow::refreshViews() // 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); + m_tabWidget->currentTabPage()->setSplitViewEnabled(splitView, WithAnimation); updateSplitAction(); updateWindowTitle(); } - emit settingsChanged(); + Q_EMIT settingsChanged(); } void DolphinMainWindow::clearStatusBar() @@ -2036,6 +2101,8 @@ void DolphinMainWindow::connectViewSignals(DolphinViewContainer* container) this, &DolphinMainWindow::slotSelectionChanged); connect(view, &DolphinView::requestItemInfo, this, &DolphinMainWindow::requestItemInfo); + connect(view, &DolphinView::fileItemsChanged, + this, &DolphinMainWindow::fileItemsChanged); connect(view, &DolphinView::tabRequested, this, &DolphinMainWindow::openNewTab); connect(view, &DolphinView::requestContextMenu, @@ -2052,16 +2119,29 @@ void DolphinMainWindow::connectViewSignals(DolphinViewContainer* container) this, &DolphinMainWindow::goForward); connect(view, &DolphinView::urlActivated, this, &DolphinMainWindow::handleUrl); + connect(view, &DolphinView::goUpRequested, + this, &DolphinMainWindow::goUp); + + auto navigators = static_cast + (actionCollection()->action(QStringLiteral("url_navigators"))); + + const KUrlNavigator *navigator = m_tabWidget->currentTabPage()->primaryViewActive() ? + navigators->primaryUrlNavigator() : + navigators->secondaryUrlNavigator(); - const KUrlNavigator* navigator = container->urlNavigator(); connect(navigator, &KUrlNavigator::urlChanged, this, &DolphinMainWindow::changeUrl); - connect(navigator, &KUrlNavigator::historyChanged, - this, &DolphinMainWindow::updateHistory); + QAction *editableLocactionAction = actionCollection()->action(QStringLiteral("editable_location")); + editableLocactionAction->setChecked(navigator->isUrlEditable()); connect(navigator, &KUrlNavigator::editableStateChanged, this, &DolphinMainWindow::slotEditableStateChanged); connect(navigator, &KUrlNavigator::tabRequested, - this, &DolphinMainWindow::openNewTabAfterLastTab); + this, &DolphinMainWindow::openNewTab); + + disconnect(m_updateHistoryConnection); + m_updateHistoryConnection = connect( + container->urlNavigatorInternalWithHistory(), &KUrlNavigator::historyChanged, + this, &DolphinMainWindow::updateHistory); } void DolphinMainWindow::updateSplitAction() @@ -2085,6 +2165,21 @@ void DolphinMainWindow::updateSplitAction() } } +void DolphinMainWindow::updateAllowedToolbarAreas() +{ + auto navigators = static_cast + (actionCollection()->action(QStringLiteral("url_navigators"))); + if (toolBar()->actions().contains(navigators)) { + toolBar()->setAllowedAreas(Qt::TopToolBarArea | Qt::BottomToolBarArea); + if (toolBarArea(toolBar()) == Qt::LeftToolBarArea || + toolBarArea(toolBar()) == Qt::RightToolBarArea) { + addToolBar(Qt::TopToolBarArea, toolBar()); + } + } else { + toolBar()->setAllowedAreas(Qt::AllToolBarAreas); + } +} + bool DolphinMainWindow::isKompareInstalled() const { static bool initialized = false; @@ -2269,6 +2364,29 @@ void DolphinMainWindow::setupWhatsThis() m_helpMenu->action(KHelpMenu::menuAboutKDE)->setWhatsThis(whatsThisAboutKDE); } +bool DolphinMainWindow::addHamburgerMenuToToolbar() +{ + QDomDocument domDocument = KXMLGUIClient::domDocument(); + if (domDocument.isNull()) { + return false; + } + QDomNode toolbar = domDocument.elementsByTagName(QStringLiteral("ToolBar")).at(0); + if (toolbar.isNull()) { + return false; + } + + QDomElement hamburgerMenuElement = domDocument.createElement(QStringLiteral("Action")); + hamburgerMenuElement.setAttribute(QStringLiteral("name"), QStringLiteral("hamburger_menu")); + toolbar.appendChild(hamburgerMenuElement); + + KXMLGUIFactory::saveConfigFile(domDocument, xmlFile()); + reloadXML(); + createGUI(); + return true; + // Make sure to also remove the and include + // whenever this method is removed (maybe in the year ~2026). +} + bool DolphinMainWindow::event(QEvent *event) { if (event->type() == QEvent::WhatsThisClicked) { @@ -2292,6 +2410,27 @@ bool DolphinMainWindow::eventFilter(QObject* obj, QEvent* event) return false; } +// Set a sane initial window size +QSize DolphinMainWindow::sizeHint() const +{ + return KXmlGuiWindow::sizeHint().expandedTo(QSize(760, 550)); +} + +void DolphinMainWindow::saveNewToolbarConfig() +{ + KXmlGuiWindow::saveNewToolbarConfig(); // Applies the new config. This has to be called first + // because the rest of this method decides things + // based on the new config. + auto navigators = static_cast + (actionCollection()->action(QStringLiteral("url_navigators"))); + if (!toolBar()->actions().contains(navigators)) { + m_tabWidget->currentTabPage()->insertNavigatorsWidget(navigators); + } + updateAllowedToolbarAreas(); + (static_cast(actionCollection()->action(KStandardAction::name( + KStandardAction::HamburgerMenu))))->hideActionsOf(toolBar()); +} + void DolphinMainWindow::focusTerminalPanel() { if (m_terminalPanel->isVisible()) {