X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/a85863befd616fe86669ac363d74fa7f466ca523..aeb704851d3b33f88eb601d597c2b0743d4e08df:/src/dolphinmainwindow.cpp diff --git a/src/dolphinmainwindow.cpp b/src/dolphinmainwindow.cpp index 744ad8f0a..56fc37e4c 100644 --- a/src/dolphinmainwindow.cpp +++ b/src/dolphinmainwindow.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -48,13 +49,11 @@ #include #include #include -#include #include #include #include #include #include -#include #include #include #include @@ -64,7 +63,8 @@ #include #include #include -#include + +#include #include #include @@ -80,9 +80,14 @@ #include #include #include +#include #include +#if HAVE_X11 +#include +#endif + namespace { // Used for GeneralSettings::version() to determine whether @@ -92,7 +97,7 @@ namespace const int CurrentDolphinVersion = 202; // The maximum number of entries in the back/forward popup menu const int MaxNumberOfNavigationentries = 12; -// The maximum number of "Activate Tab" shortcuts +// The maximum number of "Go to Tab" shortcuts const int MaxActivateTabShortcuts = 9; } @@ -111,6 +116,11 @@ DolphinMainWindow::DolphinMainWindow() , m_tearDownFromPlacesRequested(false) , m_backAction(nullptr) , m_forwardAction(nullptr) + , m_splitViewAction(nullptr) + , m_splitViewMenuAction(nullptr) + , m_sessionSaveTimer(nullptr) + , m_sessionSaveWatcher(nullptr) + , m_sessionSaveScheduled(false) { Q_INIT_RESOURCE(dolphin); @@ -124,6 +134,8 @@ DolphinMainWindow::DolphinMainWindow() setStateConfigGroup("State"); + new KColorSchemeManager(this); + connect(&DolphinNewFileMenuObserver::instance(), &DolphinNewFileMenuObserver::errorMessage, this, &DolphinMainWindow::showErrorMessage); KIO::FileUndoManager *undoManager = KIO::FileUndoManager::self(); @@ -158,6 +170,9 @@ DolphinMainWindow::DolphinMainWindow() connect(m_actionHandler, &DolphinViewActionHandler::createDirectoryTriggered, this, &DolphinMainWindow::createDirectory); connect(m_actionHandler, &DolphinViewActionHandler::selectionModeChangeTriggered, this, &DolphinMainWindow::slotSetSelectionMode); + Q_CHECK_PTR(actionCollection()->action(QStringLiteral("create_dir"))); + m_newFileMenu->setNewFolderShortcutAction(actionCollection()->action(QStringLiteral("create_dir"))); + m_remoteEncoding = new DolphinRemoteEncoding(this, m_actionHandler); connect(this, &DolphinMainWindow::urlChanged, m_remoteEncoding, &DolphinRemoteEncoding::slotAboutToOpenUrl); @@ -276,8 +291,10 @@ void DolphinMainWindow::activateWindow(const QString &activationToken) if (KWindowSystem::isPlatformWayland()) { KWindowSystem::setCurrentXdgActivationToken(activationToken); - } else { + } else if (KWindowSystem::isPlatformX11()) { +#if HAVE_X11 KStartupInfo::setNewStartupId(window()->windowHandle(), activationToken.toUtf8()); +#endif } KWindowSystem::activateWindow(window()->windowHandle()); @@ -457,7 +474,7 @@ void DolphinMainWindow::openNewWindow(const QUrl &url) void DolphinMainWindow::slotSplitViewChanged() { m_tabWidget->currentTabPage()->setSplitViewEnabled(GeneralSettings::splitView(), WithAnimation); - updateSplitAction(); + updateSplitActions(); } void DolphinMainWindow::openInNewTab() @@ -528,7 +545,7 @@ void DolphinMainWindow::showTarget() const KFileItem link = m_activeViewContainer->view()->selectedItems().at(0); const QUrl destinationUrl = link.url().resolved(QUrl(link.linkDest())); - auto job = KIO::statDetails(destinationUrl, KIO::StatJob::SourceSide, KIO::StatNoDetails); + auto job = KIO::stat(destinationUrl, KIO::StatJob::SourceSide, KIO::StatNoDetails); connect(job, &KJob::finished, this, [this, destinationUrl](KJob *job) { KIO::StatJob *statJob = static_cast(job); @@ -668,18 +685,74 @@ void DolphinMainWindow::closeEvent(QCloseEvent *event) } } - if (GeneralSettings::rememberOpenedTabs()) { + if (m_sessionSaveTimer && (m_sessionSaveTimer->isActive() || m_sessionSaveWatcher->isRunning())) { + const bool sessionSaveTimerActive = m_sessionSaveTimer->isActive(); + + m_sessionSaveTimer->stop(); + m_sessionSaveWatcher->disconnect(); + m_sessionSaveWatcher->waitForFinished(); + + if (sessionSaveTimerActive || m_sessionSaveScheduled) { + slotSaveSession(); + } + } + + GeneralSettings::setVersion(CurrentDolphinVersion); + GeneralSettings::self()->save(); + + KXmlGuiWindow::closeEvent(event); +} + +void DolphinMainWindow::slotSaveSession() +{ + m_sessionSaveScheduled = false; + + if (m_sessionSaveWatcher->isRunning()) { + // The previous session is still being saved - schedule another save. + m_sessionSaveWatcher->disconnect(); + connect(m_sessionSaveWatcher, &QFutureWatcher::finished, this, &DolphinMainWindow::slotSaveSession, Qt::SingleShotConnection); + m_sessionSaveScheduled = true; + } else if (!m_sessionSaveTimer->isActive()) { + // No point in saving the session if the timer is running (since it will save the session again when it times out). KConfigGui::setSessionConfig(QStringLiteral("dolphin"), QStringLiteral("dolphin")); KConfig *config = KConfigGui::sessionConfig(); saveGlobalProperties(config); savePropertiesInternal(config, 1); - config->sync(); + + auto future = QtConcurrent::run([config]() { + config->sync(); + }); + m_sessionSaveWatcher->setFuture(future); } +} - GeneralSettings::setVersion(CurrentDolphinVersion); - GeneralSettings::self()->save(); +void DolphinMainWindow::setSessionAutoSaveEnabled(bool enable) +{ + if (enable) { + if (!m_sessionSaveTimer) { + m_sessionSaveTimer = new QTimer(this); + m_sessionSaveWatcher = new QFutureWatcher(this); + m_sessionSaveTimer->setSingleShot(true); + m_sessionSaveTimer->setInterval(22000); - KXmlGuiWindow::closeEvent(event); + connect(m_sessionSaveTimer, &QTimer::timeout, this, &DolphinMainWindow::slotSaveSession); + } + + connect(m_tabWidget, &DolphinTabWidget::urlChanged, m_sessionSaveTimer, qOverload<>(&QTimer::start), Qt::UniqueConnection); + connect(m_tabWidget, &DolphinTabWidget::tabCountChanged, m_sessionSaveTimer, qOverload<>(&QTimer::start), Qt::UniqueConnection); + connect(m_tabWidget, &DolphinTabWidget::activeViewChanged, m_sessionSaveTimer, qOverload<>(&QTimer::start), Qt::UniqueConnection); + } else if (m_sessionSaveTimer) { + m_sessionSaveTimer->stop(); + m_sessionSaveWatcher->disconnect(); + m_sessionSaveScheduled = false; + + m_sessionSaveWatcher->waitForFinished(); + + m_sessionSaveTimer->deleteLater(); + m_sessionSaveWatcher->deleteLater(); + m_sessionSaveTimer = nullptr; + m_sessionSaveWatcher = nullptr; + } } void DolphinMainWindow::saveProperties(KConfigGroup &group) @@ -835,10 +908,11 @@ void DolphinMainWindow::slotAboutToShowBackPopupMenu() { const KUrlNavigator *urlNavigator = m_activeViewContainer->urlNavigatorInternalWithHistory(); int entries = 0; - m_backAction->menu()->clear(); + QMenu *menu = m_backAction->popupMenu(); + menu->clear(); for (int i = urlNavigator->historyIndex() + 1; i < urlNavigator->historySize() && entries < MaxNumberOfNavigationentries; ++i, ++entries) { - QAction *action = urlNavigatorHistoryAction(urlNavigator, i, m_backAction->menu()); - m_backAction->menu()->addAction(action); + QAction *action = urlNavigatorHistoryAction(urlNavigator, i, menu); + menu->addAction(action); } } @@ -863,10 +937,10 @@ void DolphinMainWindow::slotAboutToShowForwardPopupMenu() { const KUrlNavigator *urlNavigator = m_activeViewContainer->urlNavigatorInternalWithHistory(); int entries = 0; - m_forwardAction->menu()->clear(); + QMenu *menu = m_forwardAction->popupMenu(); for (int i = urlNavigator->historyIndex() - 1; i >= 0 && entries < MaxNumberOfNavigationentries; --i, ++entries) { - QAction *action = urlNavigatorHistoryAction(urlNavigator, i, m_forwardAction->menu()); - m_forwardAction->menu()->addAction(action); + QAction *action = urlNavigatorHistoryAction(urlNavigator, i, menu); + menu->addAction(action); } } @@ -911,9 +985,20 @@ void DolphinMainWindow::toggleSplitView() { DolphinTabPage *tabPage = m_tabWidget->currentTabPage(); tabPage->setSplitViewEnabled(!tabPage->splitViewEnabled(), WithAnimation); + m_tabWidget->updateTabName(m_tabWidget->indexOf(tabPage)); updateViewActions(); } +void DolphinMainWindow::popoutSplitView() +{ + DolphinTabPage *tabPage = m_tabWidget->currentTabPage(); + if (!tabPage->splitViewEnabled()) + return; + openNewWindow((GeneralSettings::closeActiveSplitView() ? tabPage->activeViewContainer() : tabPage->inactiveViewContainer())->url()); + tabPage->setSplitViewEnabled(false, WithAnimation); + updateSplitActions(); +} + void DolphinMainWindow::toggleSplitStash() { DolphinTabPage *tabPage = m_tabWidget->currentTabPage(); @@ -1117,15 +1202,21 @@ void DolphinMainWindow::toggleShowMenuBar() QPointer DolphinMainWindow::preferredSearchTool() { m_searchTools.clear(); - KMoreToolsMenuFactory("dolphin/search-tools").fillMenuFromGroupingNames(&m_searchTools, {"files-find"}, m_activeViewContainer->url()); - QList actions = m_searchTools.actions(); - if (actions.isEmpty()) { - return nullptr; - } - QAction *action = actions.first(); - if (action->isSeparator()) { + + KService::Ptr kfind = KService::serviceByDesktopName(QStringLiteral("org.kde.kfind")); + + if (!kfind) { return nullptr; } + + auto *action = new QAction(QIcon::fromTheme(kfind->icon()), kfind->name(), this); + + connect(action, &QAction::triggered, this, [this, kfind] { + auto *job = new KIO::ApplicationLauncherJob(kfind); + job->setUrls({m_activeViewContainer->url()}); + job->start(); + }); + return action; } @@ -1295,7 +1386,7 @@ void DolphinMainWindow::slotWriteStateChanged(bool isFolderWritable) void DolphinMainWindow::openContextMenu(const QPoint &pos, const KFileItem &item, const KFileItemList &selectedItems, const QUrl &url) { QPointer contextMenu = new DolphinContextMenu(this, item, selectedItems, url, &m_fileItemActions); - contextMenu.data()->exec(pos); + contextMenu->exec(pos); // Delete the menu, unless it has been deleted in its own nested event loop already. if (contextMenu) { @@ -1539,7 +1630,8 @@ void DolphinMainWindow::setupActions() auto hamburgerMenuAction = KStandardAction::hamburgerMenu(nullptr, nullptr, actionCollection()); // setup 'File' menu - m_newFileMenu = new DolphinNewFileMenu(actionCollection(), this); + m_newFileMenu = new DolphinNewFileMenu(nullptr, this); + actionCollection()->addAction(QStringLiteral("new_menu"), m_newFileMenu); QMenu *menu = m_newFileMenu->menu(); menu->setTitle(i18nc("@title:menu Create new folder, file, link, etc.", "Create New")); menu->setIcon(QIcon::fromTheme(QStringLiteral("list-add"))); @@ -1551,7 +1643,7 @@ void DolphinMainWindow::setupActions() newWindow->setToolTip(i18nc("@info", "Open a new Dolphin window")); newWindow->setWhatsThis(xi18nc("@info:whatsthis", "This opens a new " - "window just like this one with the current location and view." + "window just like this one with the current location." "You can drag and drop items between windows.")); newWindow->setIcon(QIcon::fromTheme(QStringLiteral("window-new"))); @@ -1560,10 +1652,10 @@ void DolphinMainWindow::setupActions() newTab->setText(i18nc("@action:inmenu File", "New Tab")); newTab->setWhatsThis(xi18nc("@info:whatsthis", "This opens a new " - "Tab with the current location and view." - "A tab is an additional view within this window. " + "Tab with the current location." + "Tabs allow you to quickly switch between multiple locations and views 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()->setDefaultShortcut(newTab, Qt::CTRL | Qt::Key_T); connect(newTab, &QAction::triggered, this, &DolphinMainWindow::openNewActivatedTab); QAction *addToPlaces = actionCollection()->addAction(QStringLiteral("add_to_places")); @@ -1576,10 +1668,11 @@ void DolphinMainWindow::setupActions() QAction *closeTab = KStandardAction::close(m_tabWidget, QOverload<>::of(&DolphinTabWidget::closeTab), actionCollection()); closeTab->setText(i18nc("@action:inmenu File", "Close Tab")); + closeTab->setToolTip(i18nc("@info", "Close Tab")); closeTab->setWhatsThis(i18nc("@info:whatsthis", "This closes the " - "currently viewed tab. If no more tabs are left this window " - "will close instead.")); + "currently viewed tab. If no more tabs are left, this closes " + "the whole window instead.")); QAction *quitAction = KStandardAction::quit(this, &DolphinMainWindow::quit, actionCollection()); quitAction->setWhatsThis(i18nc("@info:whatsthis quit", "This closes this window.")); @@ -1630,9 +1723,10 @@ void DolphinMainWindow::setupActions() m_actionTextHelper->registerTextWhenNothingIsSelected(copyToOtherViewAction, i18nc("@action:inmenu", "Copy to Other View…")); copyToOtherViewAction->setWhatsThis(xi18nc("@info:whatsthis Copy", "This copies the selected items from " - "the active view to the inactive split view.")); + "the view in focus to the other view. " + "(Only available while in Split View mode.)")); copyToOtherViewAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-copy"))); - copyToOtherViewAction->setIconText(i18nc("@action:inmenu Edit", "Copy to Inactive Split View")); + copyToOtherViewAction->setIconText(i18nc("@action:inmenu Edit", "Copy to Other View")); actionCollection()->setDefaultShortcut(copyToOtherViewAction, Qt::SHIFT | Qt::Key_F5); connect(copyToOtherViewAction, &QAction::triggered, this, &DolphinMainWindow::copyToInactiveSplitView); @@ -1641,9 +1735,10 @@ void DolphinMainWindow::setupActions() m_actionTextHelper->registerTextWhenNothingIsSelected(moveToOtherViewAction, i18nc("@action:inmenu", "Move to Other View…")); moveToOtherViewAction->setWhatsThis(xi18nc("@info:whatsthis Move", "This moves the selected items from " - "the active view to the inactive split view.")); + "the view in focus to the other view. " + "(Only available while in Split View mode.)")); moveToOtherViewAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-cut"))); - moveToOtherViewAction->setIconText(i18nc("@action:inmenu Edit", "Move to Inactive Split View")); + moveToOtherViewAction->setIconText(i18nc("@action:inmenu Edit", "Move to Other View")); actionCollection()->setDefaultShortcut(moveToOtherViewAction, Qt::SHIFT | Qt::Key_F6); connect(moveToOtherViewAction, &QAction::triggered, this, &DolphinMainWindow::moveToInactiveSplitView); @@ -1653,7 +1748,7 @@ void DolphinMainWindow::setupActions() 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. " + "There you can enter 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}); @@ -1676,10 +1771,10 @@ void DolphinMainWindow::setupActions() searchAction->setToolTip(i18nc("@info:tooltip", "Search for files and folders")); searchAction->setWhatsThis(xi18nc("@info:whatsthis find", "This helps you " - "find files and folders by opening a find bar. " + "find files and folders by opening a search bar. " "There you can enter search terms and specify settings to find the " - "objects you are looking for.Use this help again on " - "the find bar so we can have a look at it while the settings are " + "items you are looking for.Use this help again on " + "the search bar so we can have a look at it while the settings are " "explained.")); // toggle_search acts as a copy of the main searchAction to be used mainly @@ -1707,7 +1802,7 @@ void DolphinMainWindow::setupActions() "")); toggleSelectionModeAction->setIcon(QIcon::fromTheme(QStringLiteral("quickwizard"))); toggleSelectionModeAction->setCheckable(true); - actionCollection()->setDefaultShortcut(toggleSelectionModeAction, Qt::Key_Space ); + actionCollection()->setDefaultShortcut(toggleSelectionModeAction, Qt::Key_Space); connect(toggleSelectionModeAction, &QAction::triggered, this, &DolphinMainWindow::toggleSelectionMode); // A special version of the toggleSelectionModeAction for the toolbar that also contains a menu @@ -1718,7 +1813,7 @@ void DolphinMainWindow::setupActions() toggleSelectionModeToolBarAction->setWhatsThis(toggleSelectionModeAction->whatsThis()); actionCollection()->addAction(QStringLiteral("toggle_selection_mode_tool_bar"), toggleSelectionModeToolBarAction); toggleSelectionModeToolBarAction->setCheckable(true); - toggleSelectionModeToolBarAction->setPopupMode(QToolButton::DelayedPopup); + toggleSelectionModeToolBarAction->setPopupMode(KToolBarPopupAction::DelayedPopup); connect(toggleSelectionModeToolBarAction, &QAction::triggered, toggleSelectionModeAction, &QAction::trigger); connect(toggleSelectionModeAction, &QAction::toggled, toggleSelectionModeToolBarAction, &QAction::setChecked); @@ -1731,7 +1826,7 @@ void DolphinMainWindow::setupActions() invertSelection->setText(i18nc("@action:inmenu Edit", "Invert Selection")); invertSelection->setWhatsThis(xi18nc("@info:whatsthis invert", "This selects all " - "objects that you have currently not selected instead.")); + "items 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); connect(invertSelection, &QAction::triggered, this, &DolphinMainWindow::invertSelection); @@ -1744,14 +1839,30 @@ void DolphinMainWindow::setupActions() // setup 'View' menu // (note that most of it is set up in DolphinViewActionHandler) - QAction *split = actionCollection()->addAction(QStringLiteral("split_view")); - split->setWhatsThis(xi18nc("@info:whatsthis find", - "This splits " - "the folder view below into two autonomous views.This " - "way you can see two locations at once and move items between them " - "quickly.Click this again afterwards to recombine the views.")); - actionCollection()->setDefaultShortcut(split, Qt::Key_F3); - connect(split, &QAction::triggered, this, &DolphinMainWindow::toggleSplitView); + m_splitViewAction = actionCollection()->add(QStringLiteral("split_view")); + m_splitViewMenuAction = actionCollection()->addAction(QStringLiteral("split_view_menu")); + + m_splitViewAction->setWhatsThis(xi18nc("@info:whatsthis split", + "This presents " + "a second view side-by-side with the current view, so you can see " + "the contents of two folders at once and easily move items between " + "them.The view that is not \"in focus\" will be dimmed. " + "Click this button again to close one of the views.")); + m_splitViewMenuAction->setWhatsThis(m_splitViewAction->whatsThis()); + + // only set it for the menu version + actionCollection()->setDefaultShortcut(m_splitViewMenuAction, Qt::Key_F3); + + connect(m_splitViewAction, &QAction::triggered, this, &DolphinMainWindow::toggleSplitView); + connect(m_splitViewMenuAction, &QAction::triggered, this, &DolphinMainWindow::toggleSplitView); + + QAction *popoutSplit = actionCollection()->addAction(QStringLiteral("popout_split_view")); + popoutSplit->setWhatsThis(xi18nc("@info:whatsthis", + "If the view has been split, this will pop the view in focus " + "out into a new window.")); + popoutSplit->setIcon(QIcon::fromTheme(QStringLiteral("window-new"))); + actionCollection()->setDefaultShortcut(popoutSplit, Qt::SHIFT | Qt::Key_F3); + connect(popoutSplit, &QAction::triggered, this, &DolphinMainWindow::popoutSplitView); QAction *stashSplit = actionCollection()->addAction(QStringLiteral("split_stash")); actionCollection()->setDefaultShortcut(stashSplit, Qt::CTRL | Qt::Key_S); @@ -1807,10 +1918,10 @@ void DolphinMainWindow::setupActions() m_backAction->setObjectName(backAction->objectName()); m_backAction->setShortcuts(backAction->shortcuts()); } - m_backAction->setPopupMode(QToolButton::DelayedPopup); + m_backAction->setPopupMode(KToolBarPopupAction::DelayedPopup); connect(m_backAction, &QAction::triggered, this, &DolphinMainWindow::goBack); - connect(m_backAction->menu(), &QMenu::aboutToShow, this, &DolphinMainWindow::slotAboutToShowBackPopupMenu); - connect(m_backAction->menu(), &QMenu::triggered, this, &DolphinMainWindow::slotGoBack); + connect(m_backAction->popupMenu(), &QMenu::aboutToShow, this, &DolphinMainWindow::slotAboutToShowBackPopupMenu); + connect(m_backAction->popupMenu(), &QMenu::triggered, this, &DolphinMainWindow::slotGoBack); actionCollection()->addAction(m_backAction->objectName(), m_backAction); auto backShortcuts = m_backAction->shortcuts(); @@ -1836,10 +1947,10 @@ void DolphinMainWindow::setupActions() undoAction->setWhatsThis(xi18nc("@info:whatsthis", "This undoes " "the last change you made to files or folders." - "Such changes include creating, renaming " + "Such changes include creating, renaming " "and moving them to a different location " - "or to the Trash. Changes that can't " - "be undone will ask for your confirmation.")); + "or to the Trash. Any changes that cannot be undone " + "will ask for your confirmation beforehand.")); undoAction->setEnabled(false); // undo should be disabled by default { @@ -1848,25 +1959,25 @@ void DolphinMainWindow::setupActions() m_forwardAction->setObjectName(forwardAction->objectName()); m_forwardAction->setShortcuts(forwardAction->shortcuts()); } - m_forwardAction->setPopupMode(QToolButton::DelayedPopup); + m_forwardAction->setPopupMode(KToolBarPopupAction::DelayedPopup); connect(m_forwardAction, &QAction::triggered, this, &DolphinMainWindow::goForward); - connect(m_forwardAction->menu(), &QMenu::aboutToShow, this, &DolphinMainWindow::slotAboutToShowForwardPopupMenu); - connect(m_forwardAction->menu(), &QMenu::triggered, this, &DolphinMainWindow::slotGoForward); + connect(m_forwardAction->popupMenu(), &QMenu::aboutToShow, this, &DolphinMainWindow::slotAboutToShowForwardPopupMenu); + connect(m_forwardAction->popupMenu(), &QMenu::triggered, this, &DolphinMainWindow::slotGoForward); actionCollection()->addAction(m_forwardAction->objectName(), m_forwardAction); actionCollection()->setDefaultShortcuts(m_forwardAction, m_forwardAction->shortcuts()); // enable middle-click to open in a new tab auto *middleClickEventFilter = new MiddleClickActionEventFilter(this); connect(middleClickEventFilter, &MiddleClickActionEventFilter::actionMiddleClicked, this, &DolphinMainWindow::slotBackForwardActionMiddleClicked); - m_backAction->menu()->installEventFilter(middleClickEventFilter); - m_forwardAction->menu()->installEventFilter(middleClickEventFilter); + m_backAction->popupMenu()->installEventFilter(middleClickEventFilter); + m_forwardAction->popupMenu()->installEventFilter(middleClickEventFilter); KStandardAction::up(this, &DolphinMainWindow::goUp, actionCollection()); QAction *homeAction = KStandardAction::home(this, &DolphinMainWindow::goHome, actionCollection()); homeAction->setWhatsThis(xi18nc("@info:whatsthis", "Go to your " "Home folder.Every user account " - "has their own Home that contains their data " - "including folders that contain personal application data.")); + "has their own Home that contains their personal files, " + "as well as hidden folders for their applications' data and configuration files.")); // setup 'Tools' menu QAction *compareFiles = actionCollection()->addAction(QStringLiteral("compare_files")); @@ -1889,7 +2000,7 @@ void DolphinMainWindow::setupActions() 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.")); + "To learn more about terminals use the help features in the terminal application.")); openTerminal->setIcon(QIcon::fromTheme(QStringLiteral("utilities-terminal"))); actionCollection()->setDefaultShortcut(openTerminal, Qt::SHIFT | Qt::Key_F4); connect(openTerminal, &QAction::triggered, this, &DolphinMainWindow::openTerminal); @@ -1899,7 +2010,7 @@ void DolphinMainWindow::setupActions() openTerminalHere->setText(i18nc("@action:inmenu Tools", "Open Terminal Here")); openTerminalHere->setWhatsThis(xi18nc("@info:whatsthis", "This opens terminal applications for the selected items' locations." - "To learn more about terminals use the help in the terminal application.")); + "To learn more about terminals use the help features in the terminal application.")); openTerminalHere->setIcon(QIcon::fromTheme(QStringLiteral("utilities-terminal"))); actionCollection()->setDefaultShortcut(openTerminalHere, Qt::SHIFT | Qt::ALT | Qt::Key_F4); connect(openTerminalHere, &QAction::triggered, this, &DolphinMainWindow::openTerminalHere); @@ -1925,10 +2036,10 @@ void DolphinMainWindow::setupActions() KToggleAction *showMenuBar = KStandardAction::showMenubar(nullptr, nullptr, actionCollection()); showMenuBar->setWhatsThis(xi18nc("@info:whatsthis", "This switches between having a Menubar " - "and having a %1 button. Both " + "and having an %1 button. Both " "contain mostly the same actions and configuration options." - "The Menubar takes up more space but allows for fast and organised access to all " - "actions an application has to offer.The %1 button " + "The Menubar takes up more space but allows for fast and organized access to all " + "actions an application has to offer.The %1 button " "is simpler and small which makes triggering advanced actions more time consuming.", hamburgerMenuAction->text().replace('&', ""))); connect(showMenuBar, @@ -1957,7 +2068,7 @@ void DolphinMainWindow::setupActions() for (int i = 0; i < MaxActivateTabShortcuts; ++i) { QAction *activateTab = actionCollection()->addAction(QStringLiteral("activate_tab_%1").arg(i)); - activateTab->setText(i18nc("@action:inmenu", "Activate Tab %1", i + 1)); + activateTab->setText(i18nc("@action:inmenu", "Go to Tab %1", i + 1)); activateTab->setEnabled(false); connect(activateTab, &QAction::triggered, this, [this, i]() { m_tabWidget->activateTab(i); @@ -1970,21 +2081,22 @@ void DolphinMainWindow::setupActions() } QAction *activateLastTab = actionCollection()->addAction(QStringLiteral("activate_last_tab")); - activateLastTab->setText(i18nc("@action:inmenu", "Activate Last Tab")); + activateLastTab->setIconText(i18nc("@action:inmenu", "Last Tab")); + activateLastTab->setText(i18nc("@action:inmenu", "Go to Last Tab")); activateLastTab->setEnabled(false); connect(activateLastTab, &QAction::triggered, m_tabWidget, &DolphinTabWidget::activateLastTab); actionCollection()->setDefaultShortcut(activateLastTab, Qt::ALT | Qt::Key_0); QAction *activateNextTab = actionCollection()->addAction(QStringLiteral("activate_next_tab")); activateNextTab->setIconText(i18nc("@action:inmenu", "Next Tab")); - activateNextTab->setText(i18nc("@action:inmenu", "Activate Next Tab")); + activateNextTab->setText(i18nc("@action:inmenu", "Go to Next Tab")); activateNextTab->setEnabled(false); connect(activateNextTab, &QAction::triggered, m_tabWidget, &DolphinTabWidget::activateNextTab); actionCollection()->setDefaultShortcuts(activateNextTab, nextTabKeys); QAction *activatePrevTab = actionCollection()->addAction(QStringLiteral("activate_prev_tab")); activatePrevTab->setIconText(i18nc("@action:inmenu", "Previous Tab")); - activatePrevTab->setText(i18nc("@action:inmenu", "Activate Previous Tab")); + activatePrevTab->setText(i18nc("@action:inmenu", "Go to Previous Tab")); activatePrevTab->setEnabled(false); connect(activatePrevTab, &QAction::triggered, m_tabWidget, &DolphinTabWidget::activatePrevTab); actionCollection()->setDefaultShortcuts(activatePrevTab, prevTabKeys); @@ -2051,14 +2163,14 @@ void DolphinMainWindow::setupDockWidgets() connect(infoPanel, &InformationPanel::urlActivated, this, &DolphinMainWindow::handleUrl); infoDock->setWidget(infoPanel); - QAction *infoAction = infoDock->toggleViewAction(); - createPanelAction(QIcon::fromTheme(QStringLiteral("dialog-information")), Qt::Key_F11, infoAction, QStringLiteral("show_information_panel")); + createPanelAction(QIcon::fromTheme(QStringLiteral("dialog-information")), Qt::Key_F11, infoDock, QStringLiteral("show_information_panel")); addDockWidget(Qt::RightDockWidgetArea, infoDock); connect(this, &DolphinMainWindow::urlChanged, infoPanel, &InformationPanel::setUrl); connect(this, &DolphinMainWindow::selectionChanged, infoPanel, &InformationPanel::setSelection); connect(this, &DolphinMainWindow::requestItemInfo, infoPanel, &InformationPanel::requestDelayedItemInfo); connect(this, &DolphinMainWindow::fileItemsChanged, infoPanel, &InformationPanel::slotFilesItemChanged); + connect(this, &DolphinMainWindow::settingsChanged, infoPanel, &InformationPanel::readSettings); #endif // i18n: This is the last paragraph for the "What's This"-texts of all four panels. @@ -2095,8 +2207,7 @@ void DolphinMainWindow::setupDockWidgets() foldersPanel->setCustomContextMenuActions({lockLayoutAction}); foldersDock->setWidget(foldersPanel); - QAction *foldersAction = foldersDock->toggleViewAction(); - createPanelAction(QIcon::fromTheme(QStringLiteral("folder")), Qt::Key_F7, foldersAction, QStringLiteral("show_folders_panel")); + createPanelAction(QIcon::fromTheme(QStringLiteral("folder")), Qt::Key_F7, foldersDock, QStringLiteral("show_folders_panel")); addDockWidget(Qt::LeftDockWidgetArea, foldersDock); connect(this, &DolphinMainWindow::urlChanged, foldersPanel, &FoldersPanel::setUrl); @@ -2126,6 +2237,7 @@ void DolphinMainWindow::setupDockWidgets() DolphinDockWidget *terminalDock = new DolphinDockWidget(i18nc("@title:window Shell terminal", "Terminal")); terminalDock->setLocked(lock); terminalDock->setObjectName(QStringLiteral("terminalDock")); + terminalDock->setContentsMargins(0, 0, 0, 0); m_terminalPanel = new TerminalPanel(terminalDock); m_terminalPanel->setCustomContextMenuActions({lockLayoutAction}); terminalDock->setWidget(m_terminalPanel); @@ -2135,8 +2247,7 @@ void DolphinMainWindow::setupDockWidgets() connect(terminalDock, &DolphinDockWidget::visibilityChanged, m_terminalPanel, &TerminalPanel::dockVisibilityChanged); connect(terminalDock, &DolphinDockWidget::visibilityChanged, this, &DolphinMainWindow::slotTerminalPanelVisibilityChanged); - QAction *terminalAction = terminalDock->toggleViewAction(); - createPanelAction(QIcon::fromTheme(QStringLiteral("dialog-scripts")), Qt::Key_F4, terminalAction, QStringLiteral("show_terminal_panel")); + createPanelAction(QIcon::fromTheme(QStringLiteral("dialog-scripts")), Qt::Key_F4, terminalDock, QStringLiteral("show_terminal_panel")); addDockWidget(Qt::BottomDockWidgetArea, terminalDock); connect(this, &DolphinMainWindow::urlChanged, m_terminalPanel, &TerminalPanel::setUrl); @@ -2153,7 +2264,7 @@ void DolphinMainWindow::setupDockWidgets() "The location in the terminal will always match the folder " "view so you can navigate using either.The terminal " "panel is not needed for basic computer usage but can be useful " - "for advanced tasks. To learn more about terminals use the help " + "for advanced tasks. To learn more about terminals use the help features " "in a standalone terminal application like Konsole.")); terminalDock->setWhatsThis(xi18nc("@info:whatsthis", "This is " @@ -2161,7 +2272,7 @@ void DolphinMainWindow::setupDockWidgets() "normal terminal but will match the location of the folder view " "so you can navigate using either.The terminal panel " "is not needed for basic computer usage but can be useful for " - "advanced tasks. To learn more about terminals use the help in a " + "advanced tasks. To learn more about terminals use the help features in a " "standalone terminal application like Konsole.") + panelWhatsThis); } @@ -2182,8 +2293,7 @@ void DolphinMainWindow::setupDockWidgets() m_placesPanel->setCustomContextMenuActions({lockLayoutAction}); placesDock->setWidget(m_placesPanel); - QAction *placesAction = placesDock->toggleViewAction(); - createPanelAction(QIcon::fromTheme(QStringLiteral("compass")), Qt::Key_F9, placesAction, QStringLiteral("show_places_panel")); + createPanelAction(QIcon::fromTheme(QStringLiteral("compass")), Qt::Key_F9, placesDock, QStringLiteral("show_places_panel")); addDockWidget(Qt::LeftDockWidgetArea, placesDock); connect(m_placesPanel, &PlacesPanel::placeActivated, this, &DolphinMainWindow::slotPlaceActivated); @@ -2207,9 +2317,9 @@ void DolphinMainWindow::setupDockWidgets() actionShowAllPlaces->setWhatsThis(i18nc("@info:whatsthis", "This displays " "all places in the places panel that have been hidden. They will " - "appear semi-transparent unless you uncheck their hide property.")); + "appear semi-transparent and allow you to uncheck their \"Hide\" property.")); - connect(actionShowAllPlaces, &QAction::triggered, this, [actionShowAllPlaces, this](bool checked) { + connect(actionShowAllPlaces, &QAction::triggered, this, [this](bool checked) { m_placesPanel->setShowAll(checked); }); connect(m_placesPanel, &PlacesPanel::allPlacesShownChanged, actionShowAllPlaces, &QAction::setChecked); @@ -2253,7 +2363,7 @@ void DolphinMainWindow::setupDockWidgets() panelsMenu->addAction(actionShowAllPlaces); panelsMenu->addAction(lockLayoutAction); - connect(panelsMenu->menu(), &QMenu::aboutToShow, this, [actionShowAllPlaces, this] { + connect(panelsMenu->menu(), &QMenu::aboutToShow, this, [actionShowAllPlaces] { actionShowAllPlaces->setEnabled(DolphinPlacesModelSingleton::instance().placesModel()->hiddenCount()); }); } @@ -2344,7 +2454,7 @@ void DolphinMainWindow::updateViewActions() QAction *toggleFilterBarAction = actionCollection()->action(QStringLiteral("toggle_filter")); toggleFilterBarAction->setChecked(m_activeViewContainer->isFilterBarVisible()); - updateSplitAction(); + updateSplitActions(); } void DolphinMainWindow::updateGoActions() @@ -2373,7 +2483,7 @@ void DolphinMainWindow::refreshViews() updateWindowTitle(); } - updateSplitAction(); + updateSplitActions(); Q_EMIT settingsChanged(); } @@ -2387,6 +2497,7 @@ void DolphinMainWindow::connectViewSignals(DolphinViewContainer *container) { connect(container, &DolphinViewContainer::showFilterBarChanged, this, &DolphinMainWindow::updateFilterBarAction); connect(container, &DolphinViewContainer::writeStateChanged, this, &DolphinMainWindow::slotWriteStateChanged); + slotWriteStateChanged(container->view()->isFolderWritable()); connect(container, &DolphinViewContainer::searchModeEnabledChanged, this, &DolphinMainWindow::updateSearchAction); connect(container, &DolphinViewContainer::captionChanged, this, &DolphinMainWindow::updateWindowTitle); connect(container, &DolphinViewContainer::tabRequested, this, &DolphinMainWindow::openNewTab); @@ -2431,25 +2542,56 @@ void DolphinMainWindow::connectViewSignals(DolphinViewContainer *container) connect(navigator, &KUrlNavigator::newWindowRequested, this, &DolphinMainWindow::openNewWindow); } -void DolphinMainWindow::updateSplitAction() +void DolphinMainWindow::updateSplitActions() { - QAction *splitAction = actionCollection()->action(QStringLiteral("split_view")); + QAction *popoutSplitAction = actionCollection()->action(QStringLiteral("popout_split_view")); + + auto setActionPopupMode = [this](KActionMenu *action, QToolButton::ToolButtonPopupMode popupMode) { + action->setPopupMode(popupMode); + if (auto *buttonForAction = qobject_cast(toolBar()->widgetForAction(action))) { + buttonForAction->setPopupMode(popupMode); + } + }; + const DolphinTabPage *tabPage = m_tabWidget->currentTabPage(); if (tabPage->splitViewEnabled()) { if (GeneralSettings::closeActiveSplitView() ? tabPage->primaryViewActive() : !tabPage->primaryViewActive()) { - splitAction->setText(i18nc("@action:intoolbar Close left view", "Close")); - splitAction->setToolTip(i18nc("@info", "Close left view")); - splitAction->setIcon(QIcon::fromTheme(QStringLiteral("view-left-close"))); + m_splitViewAction->setText(i18nc("@action:intoolbar Close left view", "Close")); + m_splitViewAction->setToolTip(i18nc("@info", "Close left view")); + m_splitViewAction->setIcon(QIcon::fromTheme(QStringLiteral("view-left-close"))); + popoutSplitAction->setText(i18nc("@action:intoolbar Move left view to a new window", "Pop out Left View")); + popoutSplitAction->setToolTip(i18nc("@info", "Move left view to a new window")); } else { - splitAction->setText(i18nc("@action:intoolbar Close right view", "Close")); - splitAction->setToolTip(i18nc("@info", "Close right view")); - splitAction->setIcon(QIcon::fromTheme(QStringLiteral("view-right-close"))); + m_splitViewAction->setText(i18nc("@action:intoolbar Close right view", "Close")); + m_splitViewAction->setToolTip(i18nc("@info", "Close right view")); + m_splitViewAction->setIcon(QIcon::fromTheme(QStringLiteral("view-right-close"))); + popoutSplitAction->setText(i18nc("@action:intoolbar Move right view to a new window", "Pop out Right View")); + popoutSplitAction->setToolTip(i18nc("@info", "Move right view to a new window")); + } + popoutSplitAction->setEnabled(true); + if (!m_splitViewAction->menu()) { + setActionPopupMode(m_splitViewAction, QToolButton::MenuButtonPopup); + m_splitViewAction->setMenu(new QMenu); + m_splitViewAction->addAction(popoutSplitAction); } } else { - splitAction->setText(i18nc("@action:intoolbar Split view", "Split")); - splitAction->setToolTip(i18nc("@info", "Split view")); - splitAction->setIcon(QIcon::fromTheme(QStringLiteral("view-right-new"))); + m_splitViewAction->setText(i18nc("@action:intoolbar Split view", "Split")); + m_splitViewAction->setToolTip(i18nc("@info", "Split view")); + m_splitViewAction->setIcon(QIcon::fromTheme(QStringLiteral("view-right-new"))); + popoutSplitAction->setText(i18nc("@action:intoolbar Move view in focus to a new window", "Pop out")); + popoutSplitAction->setEnabled(false); + if (m_splitViewAction->menu()) { + m_splitViewAction->removeAction(popoutSplitAction); + m_splitViewAction->menu()->deleteLater(); + m_splitViewAction->setMenu(nullptr); + setActionPopupMode(m_splitViewAction, QToolButton::DelayedPopup); + } } + + // Update state from toolbar action + m_splitViewMenuAction->setText(m_splitViewAction->text()); + m_splitViewMenuAction->setToolTip(m_splitViewAction->toolTip()); + m_splitViewMenuAction->setIcon(m_splitViewAction->icon()); } void DolphinMainWindow::updateAllowedToolbarAreas() @@ -2478,18 +2620,14 @@ bool DolphinMainWindow::isKompareInstalled() const return installed; } -void DolphinMainWindow::createPanelAction(const QIcon &icon, const QKeySequence &shortcut, QAction *dockAction, const QString &actionName) +void DolphinMainWindow::createPanelAction(const QIcon &icon, const QKeySequence &shortcut, QDockWidget *dockWidget, const QString &actionName) { - QAction *panelAction = actionCollection()->addAction(actionName); - panelAction->setCheckable(true); - panelAction->setChecked(dockAction->isChecked()); - panelAction->setText(dockAction->text()); - panelAction->setIcon(icon); + auto dockAction = dockWidget->toggleViewAction(); dockAction->setIcon(icon); - actionCollection()->setDefaultShortcut(panelAction, shortcut); + dockAction->setEnabled(true); - connect(panelAction, &QAction::triggered, dockAction, &QAction::trigger); - connect(dockAction, &QAction::toggled, panelAction, &QAction::setChecked); + QAction *panelAction = actionCollection()->addAction(actionName, dockAction); + actionCollection()->setDefaultShortcut(panelAction, shortcut); } // clang-format off void DolphinMainWindow::setupWhatsThis()