]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/dolphinmainwindow.cpp
Merge branch 'release/21.04'
[dolphin.git] / src / dolphinmainwindow.cpp
index f14849e6d437eeac1c877da122881b6d9ae32493..737856b23dd00e115ec82b6b71ea2e66397d5569 100644 (file)
 #include <KUrlComboBox>
 #include <KUrlNavigator>
 #include <KWindowSystem>
+#include <KXMLGUIFactory>
 
 #include <QApplication>
 #include <QClipboard>
 #include <QCloseEvent>
 #include <QDesktopServices>
 #include <QDialog>
+#include <QDomDocument>
 #include <QFileInfo>
 #include <QLineEdit>
 #include <QMenuBar>
@@ -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
@@ -176,15 +178,21 @@ DolphinMainWindow::DolphinMainWindow() :
 
     if (firstRun) {
         menuBar()->setVisible(false);
-        // Assure a proper default size if Dolphin runs the first time
-        resize(760, 550);
     }
 
     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<KHamburgerMenu *>(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();
@@ -203,6 +211,8 @@ DolphinMainWindow::DolphinMainWindow() :
 
 DolphinMainWindow::~DolphinMainWindow()
 {
+    // This fixes a crash on Wayland when closing the mainwindow while another dialog is open.
+    disconnect(QGuiApplication::clipboard(), &QClipboard::dataChanged, this, &DolphinMainWindow::updatePasteAction);
 }
 
 QVector<DolphinViewContainer*> DolphinMainWindow::viewContainers() const
@@ -979,11 +989,6 @@ void DolphinMainWindow::toggleShowMenuBar()
 {
     const bool visible = menuBar()->isVisible();
     menuBar()->setVisible(!visible);
-    if (visible) {
-        createControlButton();
-    } else {
-        deleteControlButton();
-    }
 }
 
 QPointer<QAction> DolphinMainWindow::preferredSearchTool()
@@ -1150,87 +1155,91 @@ void DolphinMainWindow::openContextMenu(const QPoint& pos,
     }
 }
 
-void DolphinMainWindow::updateControlMenu()
+void DolphinMainWindow::updateHamburgerMenu()
 {
-    QMenu* menu = qobject_cast<QMenu*>(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<KHamburgerMenu *>(
+                    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<QAction *> 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("sort")));
+    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)
@@ -1268,6 +1277,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<DolphinNavigatorsWidgetAction *>
                           (actionCollection()->action(QStringLiteral("url_navigators")));
         navigators->primaryUrlNavigator()->disconnect(this);
@@ -1354,11 +1364,13 @@ 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();
     menu->setTitle(i18nc("@title:menu Create new folder, file, link, etc.", "Create New"));
-    menu->setIcon(QIcon::fromTheme(QStringLiteral("document-new")));
+    menu->setIcon(QIcon::fromTheme(QStringLiteral("list-add")));
     m_newFileMenu->setDelayed(false);
     connect(menu, &QMenu::aboutToShow,
             this, &DolphinMainWindow::updateNewMenu);
@@ -2077,65 +2089,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();
@@ -2195,15 +2148,17 @@ 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<DolphinNavigatorsWidgetAction *>
         (actionCollection()->action(QStringLiteral("url_navigators")));
-
     const KUrlNavigator *navigator = m_tabWidget->currentTabPage()->primaryViewActive() ?
                                      navigators->primaryUrlNavigator() :
                                      navigators->secondaryUrlNavigator();
 
-    connect(navigator, &KUrlNavigator::urlChanged,
-            this, &DolphinMainWindow::changeUrl);
     QAction *editableLocactionAction = actionCollection()->action(QStringLiteral("editable_location"));
     editableLocactionAction->setChecked(navigator->isUrlEditable());
     connect(navigator, &KUrlNavigator::editableStateChanged,
@@ -2211,10 +2166,6 @@ void DolphinMainWindow::connectViewSignals(DolphinViewContainer* container)
     connect(navigator, &KUrlNavigator::tabRequested,
             this, &DolphinMainWindow::openNewTab);
 
-    disconnect(m_updateHistoryConnection);
-    m_updateHistoryConnection = connect(
-            container->urlNavigatorInternalWithHistory(), &KUrlNavigator::historyChanged,
-            this, &DolphinMainWindow::updateHistory);
 }
 
 void DolphinMainWindow::updateSplitAction()
@@ -2437,6 +2388,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 <KXMLGUIFactory> and <QDomDocument> include
+    // whenever this method is removed (maybe in the year ~2026).
+}
+
 bool DolphinMainWindow::event(QEvent *event)
 {
     if (event->type() == QEvent::WhatsThisClicked) {
@@ -2460,6 +2434,12 @@ 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
@@ -2471,6 +2451,8 @@ void DolphinMainWindow::saveNewToolbarConfig()
         m_tabWidget->currentTabPage()->insertNavigatorsWidget(navigators);
     }
     updateAllowedToolbarAreas();
+    (static_cast<KHamburgerMenu *>(actionCollection()->action(KStandardAction::name(
+                            KStandardAction::HamburgerMenu))))->hideActionsOf(toolBar());
 }
 
 void DolphinMainWindow::focusTerminalPanel()