X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/42023831374496c62708ce7ad2cdd69104a1c820..98e1fb66d054d188a7c07683e7e6768b84f63605:/src/dolphinmainwindow.cpp diff --git a/src/dolphinmainwindow.cpp b/src/dolphinmainwindow.cpp index e3435685f..c2c4ae703 100644 --- a/src/dolphinmainwindow.cpp +++ b/src/dolphinmainwindow.cpp @@ -14,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" @@ -31,7 +32,6 @@ #include "views/draganddrophelper.h" #include "views/viewproperties.h" #include "views/dolphinnewfilemenuobserver.h" -#include "dolphinnavigatorswidgetaction.h" #include "dolphin_generalsettings.h" #include @@ -63,12 +63,14 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -82,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 @@ -106,8 +108,7 @@ DolphinMainWindow::DolphinMainWindow() : m_placesPanel(nullptr), m_tearDownFromPlacesRequested(false), m_backAction(nullptr), - m_forwardAction(nullptr), - m_updateHistoryConnection{} + m_forwardAction(nullptr) { Q_INIT_RESOURCE(dolphin); @@ -134,10 +135,9 @@ 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); @@ -169,31 +169,34 @@ DolphinMainWindow::DolphinMainWindow() : setupGUI(Keys | Save | Create | ToolBar); stateChanged(QStringLiteral("new_file")); - toolBar()->setAllowedAreas(Qt::TopToolBarArea | Qt::BottomToolBarArea); - toolBar()->setFloatable(false); - if (!toolBar()->actions().contains(navigatorsWidgetAction)) { - navigatorsWidgetAction->addToToolbarAndSave(this); - } QClipboard* clipboard = QApplication::clipboard(); 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->setShowMenuBarAction(showMenuBarAction); + 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); @@ -210,7 +213,7 @@ DolphinMainWindow::~DolphinMainWindow() { } -QVector DolphinMainWindow::viewContainers() const +QVector DolphinMainWindow::viewContainers() const { QVector viewContainers; @@ -261,7 +264,11 @@ bool DolphinMainWindow::isFoldersPanelEnabled() const 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) @@ -386,8 +393,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() @@ -397,7 +404,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() @@ -426,19 +437,9 @@ void DolphinMainWindow::addToPlaces() } } -void DolphinMainWindow::openNewTab(const QUrl& url, DolphinTabWidget::TabPlacement tabPlacement) +void DolphinMainWindow::openNewTab(const QUrl& url) { - 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) -{ - m_tabWidget->openNewTab(url, QUrl(), DolphinTabWidget::AfterLastTab); + m_tabWidget->openNewTab(url, QUrl()); } void DolphinMainWindow::openInNewTab() @@ -449,7 +450,7 @@ void DolphinMainWindow::openInNewTab() for (const KFileItem& item : list) { const QUrl& url = DolphinView::openItemAsFolderUrl(item); if (!url.isEmpty()) { - openNewTabAfterCurrentTab(url); + openNewTab(url); tabCreated = true; } } @@ -457,7 +458,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()); } } @@ -759,7 +760,7 @@ void DolphinMainWindow::slotBackForwardActionMiddleClicked(QAction* action) { if (action) { const KUrlNavigator *urlNavigator = activeViewContainer()->urlNavigatorInternalWithHistory(); - openNewTabAfterCurrentTab(urlNavigator->locationUrl(action->data().value())); + openNewTab(urlNavigator->locationUrl(action->data().value())); } } @@ -811,7 +812,7 @@ void DolphinMainWindow::invertSelection() void DolphinMainWindow::toggleSplitView() { DolphinTabPage* tabPage = m_tabWidget->currentTabPage(); - tabPage->setSplitViewEnabled(!tabPage->splitViewEnabled()); + tabPage->setSplitViewEnabled(!tabPage->splitViewEnabled(), WithAnimation); updateViewActions(); } @@ -819,8 +820,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() @@ -850,6 +851,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(); @@ -927,27 +937,27 @@ void DolphinMainWindow::goHome() void DolphinMainWindow::goBackInNewTab() { - KUrlNavigator* urlNavigator = activeViewContainer()->urlNavigatorInternalWithHistory(); + 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()->urlNavigatorInternalWithHistory(); + 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() @@ -977,11 +987,6 @@ void DolphinMainWindow::toggleShowMenuBar() { const bool visible = menuBar()->isVisible(); menuBar()->setVisible(!visible); - if (visible) { - createControlButton(); - } else { - deleteControlButton(); - } } QPointer DolphinMainWindow::preferredSearchTool() @@ -1033,7 +1038,7 @@ void DolphinMainWindow::openTerminal() const QUrl url = m_activeViewContainer->url(); if (url.isLocalFile()) { - KToolInvocation::invokeTerminal(QString(), url.toLocalFile()); + KToolInvocation::invokeTerminal(QString(), {}, url.toLocalFile()); return; } @@ -1047,14 +1052,14 @@ void DolphinMainWindow::openTerminal() statUrl = job->mostLocalUrl(); } - KToolInvocation::invokeTerminal(QString(), statUrl.isLocalFile() ? statUrl.toLocalFile() : QDir::homePath()); + KToolInvocation::invokeTerminal(QString(), {}, statUrl.isLocalFile() ? statUrl.toLocalFile() : QDir::homePath()); }); return; } // Nothing worked, just use $HOME - KToolInvocation::invokeTerminal(QString(), QDir::homePath()); + KToolInvocation::invokeTerminal(QString(), {}, QDir::homePath()); } void DolphinMainWindow::editSettings() @@ -1064,9 +1069,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, &DolphinUrlNavigator::slotReadSettings); + connect(settingsDialog, &DolphinSettingsDialog::settingsChanged, + &DolphinUrlNavigatorsController::slotReadSettings); settingsDialog->setAttribute(Qt::WA_DeleteOnClose); settingsDialog->show(); m_settingsDialog = settingsDialog; @@ -1085,7 +1091,7 @@ void DolphinMainWindow::handleUrl(const QUrl& url) } else { m_lastHandleUrlOpenJob = new KIO::OpenUrlJob(url); m_lastHandleUrlOpenJob->setUiDelegate(new KIO::JobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this)); - m_lastHandleUrlOpenJob->setRunExecutables(true); + m_lastHandleUrlOpenJob->setShowOpenOrExecuteDialog(true); connect(m_lastHandleUrlOpenJob, &KIO::OpenUrlJob::mimeTypeFound, this, [this, url](const QString &mimetype) { @@ -1133,7 +1139,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: @@ -1147,87 +1153,90 @@ 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(); - - 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->addSeparator(); - - // Add "Edit" actions - bool added = addActionToMenu(ac->action(KStandardAction::name(KStandardAction::Undo)), menu) | - addActionToMenu(ac->action(QString("copy_location")), menu) | - addActionToMenu(ac->action(QStringLiteral("copy_to_inactive_split_view")), menu) | - addActionToMenu(ac->action(QStringLiteral("move_to_inactive_split_view")), menu) | - addActionToMenu(ac->action(KStandardAction::name(KStandardAction::SelectAll)), menu) | - addActionToMenu(ac->action(QStringLiteral("invert_selection")), menu); - - if (added) { - menu->addSeparator(); + auto hamburgerMenu = static_cast( + ac->action(KStandardAction::name(KStandardAction::HamburgerMenu))); + auto menu = hamburgerMenu->menu(); + if (!menu) { + menu = new QMenu(this); + hamburgerMenu->setMenu(menu); + hamburgerMenu->hideActionsOf(ac->action(QStringLiteral("basic_actions"))->menu()); + hamburgerMenu->hideActionsOf(ac->action(QStringLiteral("zoom"))->menu()); + } else { + menu->clear(); } + const QList toolbarActions = toolBar()->actions(); - // 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); + if (!toolBar()->isVisible()) { + // If neither the menu bar nor the toolbar are visible, these actions should be available. + menu->addAction(ac->action(KStandardAction::name(KStandardAction::ShowMenubar))); + menu->addAction(toolBarMenuAction()); 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); + // This group of actions (until the next separator) contains all the most basic actions + // necessary to use Dolphin effectively. + menu->addAction(ac->action(QStringLiteral("go_back"))); + menu->addAction(ac->action(QStringLiteral("go_forward"))); - if (added) { - menu->addSeparator(); + menu->addMenu(m_newFileMenu->menu()); + menu->addAction(ac->action(QStringLiteral("basic_actions"))); + menu->addAction(ac->action(KStandardAction::name(KStandardAction::Undo))); + if (!toolBar()->isVisible() + || (!toolbarActions.contains(ac->action(QStringLiteral("toggle_search"))) + && !toolbarActions.contains(ac->action(QStringLiteral("open_preferred_search_tool")))) + ) { + menu->addAction(ac->action(KStandardAction::name(KStandardAction::Find))); + // This way a search action will only be added if none of the three available + // search actions is present on the toolbar. + } + if (!toolBar()->isVisible() + || !toolbarActions.contains(ac->action(QStringLiteral("toggle_filter"))) + ) { + menu->addAction(ac->action(QStringLiteral("show_filter_bar"))); + // This way a filter action will only be added if none of the two available + // filter actions is present on the toolbar. } - - // 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->addSeparator(); - // Add "Show Panels" menu - addActionToMenu(ac->action(QStringLiteral("panels")), menu); - - // 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(); + // The second group of actions (up until the next separator) contains actions for opening + // additional views to interact with the file system. + menu->addAction(ac->action(QStringLiteral("file_new"))); + menu->addAction(ac->action(QStringLiteral("new_tab"))); + if (ac->action(QStringLiteral("undo_close_tab"))->isEnabled()) { + menu->addAction(ac->action(QStringLiteral("closed_tabs"))); } -} + menu->addAction(ac->action(QStringLiteral("open_terminal"))); + menu->addSeparator(); -void DolphinMainWindow::slotControlButtonDeleted() -{ - m_controlButton = nullptr; - m_updateToolBarTimer->start(); + // The third group contains actions to change what one sees in the view + // and to change the more general UI. + if (!toolBar()->isVisible() + || (!toolbarActions.contains(ac->action(QStringLiteral("icons"))) + && !toolbarActions.contains(ac->action(QStringLiteral("compact"))) + && !toolbarActions.contains(ac->action(QStringLiteral("details"))) + && !toolbarActions.contains(ac->action(QStringLiteral("view_mode")))) + ) { + menu->addAction(ac->action(QStringLiteral("view_mode"))); + } + menu->addAction(ac->action(QStringLiteral("show_hidden_files"))); + menu->addAction(ac->action(QStringLiteral("additional_info"))); + if (!GeneralSettings::showStatusBar() || !GeneralSettings::showZoomSlider()) { + menu->addAction(ac->action(QStringLiteral("zoom"))); + } + menu->addAction(ac->action(QStringLiteral("panels"))); + + // The "Configure" menu is not added to the actionCollection() because there is hardly + // a good reason for users to put it on their toolbar. + auto configureMenu = menu->addMenu(QIcon::fromTheme(QStringLiteral("configure")), + i18nc("@action:inmenu menu for configure actions", "Configure")); + configureMenu->addAction(ac->action(KStandardAction::name(KStandardAction::SwitchApplicationLanguage))); + configureMenu->addAction(ac->action(KStandardAction::name(KStandardAction::KeyBindings))); + configureMenu->addAction(ac->action(KStandardAction::name(KStandardAction::ConfigureToolbars))); + configureMenu->addAction(ac->action(KStandardAction::name(KStandardAction::Preferences))); + hamburgerMenu->hideActionsOf(configureMenu); } void DolphinMainWindow::slotPlaceActivated(const QUrl& url) @@ -1239,7 +1248,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(); } } @@ -1263,6 +1274,7 @@ void DolphinMainWindow::activeViewChanged(DolphinViewContainer* viewContainer) // view and url navigator) and main window. oldViewContainer->disconnect(this); oldViewContainer->view()->disconnect(this); + oldViewContainer->urlNavigatorInternalWithHistory()->disconnect(this); auto navigators = static_cast (actionCollection()->action(QStringLiteral("url_navigators"))); navigators->primaryUrlNavigator()->disconnect(this); @@ -1349,6 +1361,8 @@ void DolphinMainWindow::setViewsToHomeIfMountPathOpen(const QString& mountPath) void DolphinMainWindow::setupActions() { + KStandardAction::hamburgerMenu(nullptr, nullptr, actionCollection()); + // setup 'File' menu m_newFileMenu = new DolphinNewFileMenu(actionCollection(), this); QMenu* menu = m_newFileMenu->menu(); @@ -1373,7 +1387,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")); @@ -1432,7 +1446,7 @@ void DolphinMainWindow::setupActions() "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 ); + 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")); @@ -1441,9 +1455,32 @@ void DolphinMainWindow::setupActions() "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 ); + 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")); @@ -1474,7 +1511,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 @@ -1489,12 +1526,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()); @@ -1524,7 +1561,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 @@ -1558,7 +1595,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); @@ -1599,16 +1636,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"))); @@ -1621,7 +1648,7 @@ 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); if (KAuthorized::authorize(QStringLiteral("shell_access"))) { @@ -1630,15 +1657,15 @@ void DolphinMainWindow::setupActions() 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 } @@ -1670,10 +1697,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)); @@ -1691,7 +1718,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")); @@ -1769,6 +1796,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. @@ -1809,7 +1838,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); @@ -1886,26 +1915,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, - &DolphinUrlNavigator::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); - DolphinUrlNavigator::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); @@ -2034,8 +2063,8 @@ 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(); } @@ -2057,65 +2086,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(); - const auto associatedWidgets = action->associatedWidgets(); - for (const QWidget* widget : associatedWidgets) { - if (widget == toolBarWidget) { - return false; - } - } - - menu->addAction(action); - return true; -} - void DolphinMainWindow::refreshViews() { m_tabWidget->refreshViews(); @@ -2124,7 +2094,7 @@ 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(); } @@ -2154,6 +2124,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, @@ -2173,26 +2145,24 @@ void DolphinMainWindow::connectViewSignals(DolphinViewContainer* container) connect(view, &DolphinView::goUpRequested, this, &DolphinMainWindow::goUp); + connect(container->urlNavigatorInternalWithHistory(), &KUrlNavigator::urlChanged, + this, &DolphinMainWindow::changeUrl); + connect(container->urlNavigatorInternalWithHistory(), &KUrlNavigator::historyChanged, + this, &DolphinMainWindow::updateHistory); + auto navigators = static_cast (actionCollection()->action(QStringLiteral("url_navigators"))); + const KUrlNavigator *navigator = m_tabWidget->currentTabPage()->primaryViewActive() ? + navigators->primaryUrlNavigator() : + navigators->secondaryUrlNavigator(); - KUrlNavigator *navigator = m_tabWidget->currentTabPage()->primaryViewActive() ? - navigators->primaryUrlNavigator() : - navigators->secondaryUrlNavigator(); - - connect(navigator, &KUrlNavigator::urlChanged, - this, &DolphinMainWindow::changeUrl); - QAction* editableLocactionAction = actionCollection()->action(QStringLiteral("editable_location")); + 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() @@ -2216,6 +2186,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; @@ -2400,6 +2385,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) { @@ -2423,6 +2431,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()) {