]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/dolphinmainwindow.cpp
Always focus the view after place activation
[dolphin.git] / src / dolphinmainwindow.cpp
index 10dc9375de0a6d0318c2979af8e75f3190aa4ca4..e52494c0a49d6c2049e5700392801f8f78f30818 100644 (file)
@@ -8,6 +8,7 @@
 
 #include "dolphinmainwindow.h"
 
+#include "admin/workerintegration.h"
 #include "dolphin_generalsettings.h"
 #include "dolphinbookmarkhandler.h"
 #include "dolphincontextmenu.h"
@@ -52,6 +53,8 @@
 #include <KMessageBox>
 #include <KProtocolInfo>
 #include <KProtocolManager>
+#include <KRecentFilesAction>
+#include <KRuntimePlatform>
 #include <KShell>
 #include <KShortcutsDialog>
 #include <KStandardAction>
@@ -183,12 +186,13 @@ DolphinMainWindow::DolphinMainWindow()
 
     m_disabledActionNotifier = new DisabledActionNotifier(this);
     connect(m_disabledActionNotifier, &DisabledActionNotifier::disabledActionTriggered, this, [this](const QAction *, QString reason) {
-        m_activeViewContainer->showMessage(reason, DolphinViewContainer::Warning);
+        m_activeViewContainer->showMessage(reason, KMessageWidget::Warning);
     });
 
     setupDockWidgets();
 
-    setupGUI(Save | Create | ToolBar);
+    const bool usePhoneUi{KRuntimePlatform::runtimePlatform().contains(QLatin1String("phone"))};
+    setupGUI(Save | Create | ToolBar, usePhoneUi ? QStringLiteral("dolphinuiforphones.rc") : QString() /* load the default dolphinui.rc file */);
     stateChanged(QStringLiteral("new_file"));
 
     QClipboard *clipboard = QApplication::clipboard();
@@ -199,6 +203,15 @@ DolphinMainWindow::DolphinMainWindow()
 
     if (firstRun) {
         menuBar()->setVisible(false);
+
+        if (usePhoneUi) {
+            Q_ASSERT(qobject_cast<QDockWidget *>(m_placesPanel->parent()));
+            m_placesPanel->parentWidget()->hide();
+            auto settings = GeneralSettings::self();
+            settings->setShowZoomSlider(false); // Zooming can be done with pinch gestures instead and we are short on horizontal space.
+            settings->setRenameInline(false); // This works around inline renaming currently not working well with virtual keyboards.
+            settings->save(); // Otherwise the RenameInline setting is not picked up for the first time Dolphin is used.
+        }
     }
 
     const bool showMenu = !menuBar()->isHidden();
@@ -239,6 +252,13 @@ 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);
+
+    // This fixes a crash in dolphinmainwindowtest where the connection below fires even though the KMainWindow destructor of this object is already running.
+    Q_CHECK_PTR(qobject_cast<DolphinDockWidget *>(m_placesPanel->parent()));
+    disconnect(static_cast<DolphinDockWidget *>(m_placesPanel->parent()),
+               &DolphinDockWidget::visibilityChanged,
+               this,
+               &DolphinMainWindow::slotPlacesPanelVisibilityChanged);
 }
 
 QVector<DolphinViewContainer *> DolphinMainWindow::viewContainers() const
@@ -364,6 +384,9 @@ void DolphinMainWindow::changeUrl(const QUrl &url)
     updateViewActions();
     updateGoActions();
 
+    // will signal used urls to activities manager, too
+    m_recentFiles->addUrl(url);
+
     Q_EMIT urlChanged(url);
 }
 
@@ -466,9 +489,9 @@ void DolphinMainWindow::addToPlaces()
     }
 }
 
-void DolphinMainWindow::openNewTab(const QUrl &url)
+DolphinTabPage *DolphinMainWindow::openNewTab(const QUrl &url)
 {
-    m_tabWidget->openNewTab(url, QUrl());
+    return m_tabWidget->openNewTab(url, QUrl());
 }
 
 void DolphinMainWindow::openNewTabAndActivate(const QUrl &url)
@@ -561,7 +584,7 @@ void DolphinMainWindow::showTarget()
         KIO::StatJob *statJob = static_cast<KIO::StatJob *>(job);
 
         if (statJob->error()) {
-            m_activeViewContainer->showMessage(job->errorString(), DolphinViewContainer::Error);
+            m_activeViewContainer->showMessage(job->errorString(), KMessageWidget::Error);
         } else {
             KIO::highlightInFileManager({destinationUrl});
         }
@@ -585,7 +608,7 @@ void DolphinMainWindow::showEvent(QShowEvent *event)
 {
     KXmlGuiWindow::showEvent(event);
 
-    if (!event->spontaneous()) {
+    if (!event->spontaneous() && m_activeViewContainer) {
         m_activeViewContainer->view()->setFocus();
     }
 }
@@ -783,8 +806,14 @@ void DolphinMainWindow::updateNewMenu()
 
 void DolphinMainWindow::createDirectory()
 {
-    m_newFileMenu->setWorkingDirectory(activeViewContainer()->url());
-    m_newFileMenu->createDirectory();
+    // When creating directory, namejob is being run. In network folders,
+    // this job can take long time, so instead of starting multiple namejobs,
+    // just check if we are already running one. This prevents opening multiple
+    // dialogs. BUG:481401
+    if (!m_newFileMenu->isCreateDirectoryRunning()) {
+        m_newFileMenu->setWorkingDirectory(activeViewContainer()->url());
+        m_newFileMenu->createDirectory();
+    }
 }
 
 void DolphinMainWindow::quit()
@@ -794,7 +823,7 @@ void DolphinMainWindow::quit()
 
 void DolphinMainWindow::showErrorMessage(const QString &message)
 {
-    m_activeViewContainer->showMessage(message, DolphinViewContainer::Error);
+    m_activeViewContainer->showMessage(message, KMessageWidget::Error);
 }
 
 void DolphinMainWindow::slotUndoAvailable(bool available)
@@ -997,8 +1026,15 @@ void DolphinMainWindow::invertSelection()
 
 void DolphinMainWindow::toggleSplitView()
 {
+    QUrl newSplitViewUrl;
+    const KFileItemList list = m_activeViewContainer->view()->selectedItems();
+    if (list.count() == 1) {
+        const KFileItem &item = list.first();
+        newSplitViewUrl = DolphinView::openItemAsFolderUrl(item);
+    }
+
     DolphinTabPage *tabPage = m_tabWidget->currentTabPage();
-    tabPage->setSplitViewEnabled(!tabPage->splitViewEnabled(), WithAnimation);
+    tabPage->setSplitViewEnabled(!tabPage->splitViewEnabled(), WithAnimation, newSplitViewUrl);
     m_tabWidget->updateTabName(m_tabWidget->indexOf(tabPage));
     updateViewActions();
 }
@@ -1100,8 +1136,10 @@ void DolphinMainWindow::replaceLocation()
 
     // If the text field currently has focus and everything is selected,
     // pressing the keyboard shortcut returns the whole thing to breadcrumb mode
+    // and goes back to the view, just like how it was before this action was triggered the first time.
     if (navigator->isUrlEditable() && lineEdit->hasFocus() && lineEdit->selectedText() == lineEdit->text()) {
         navigator->setUrlEditable(false);
+        m_activeViewContainer->view()->setFocus();
     } else {
         navigator->setUrlEditable(true);
         navigator->setFocus();
@@ -1125,11 +1163,21 @@ void DolphinMainWindow::togglePanelLockState()
     GeneralSettings::setLockPanels(newLockState);
 }
 
-void DolphinMainWindow::slotTerminalPanelVisibilityChanged()
+void DolphinMainWindow::slotTerminalPanelVisibilityChanged(bool visible)
 {
-    if (m_terminalPanel->isHiddenInVisibleWindow() && m_activeViewContainer) {
+    if (!visible && m_activeViewContainer) {
         m_activeViewContainer->view()->setFocus();
     }
+    // Putting focus to the Terminal is not handled here but in TerminalPanel::showEvent().
+}
+
+void DolphinMainWindow::slotPlacesPanelVisibilityChanged(bool visible)
+{
+    if (!visible && m_activeViewContainer) {
+        m_activeViewContainer->view()->setFocus();
+        return;
+    }
+    m_placesPanel->setFocus();
 }
 
 void DolphinMainWindow::goBack()
@@ -1515,6 +1563,8 @@ void DolphinMainWindow::slotPlaceActivated(const QUrl &url)
         // We can end up here if the user clicked a device in the Places Panel
         // which had been unmounted earlier, see https://bugs.kde.org/show_bug.cgi?id=161385.
         reloadView();
+
+        m_activeViewContainer->view()->setFocus(); // We always want the focus on the view after activating a place.
     } else {
         view->disableUrlNavigatorSelectionRequests();
         changeUrl(url);
@@ -1858,6 +1908,8 @@ void DolphinMainWindow::setupActions()
     // setup 'View' menu
     // (note that most of it is set up in DolphinViewActionHandler)
 
+    Admin::WorkerIntegration::createActAsAdminAction(actionCollection(), this);
+
     m_splitViewAction = actionCollection()->add<KActionMenu>(QStringLiteral("split_view"));
     m_splitViewMenuAction = actionCollection()->addAction(QStringLiteral("split_view_menu"));
 
@@ -2033,14 +2085,6 @@ void DolphinMainWindow::setupActions()
         openTerminalHere->setIcon(QIcon::fromTheme(QStringLiteral("utilities-terminal")));
         actionCollection()->setDefaultShortcut(openTerminalHere, Qt::SHIFT | Qt::ALT | Qt::Key_F4);
         connect(openTerminalHere, &QAction::triggered, this, &DolphinMainWindow::openTerminalHere);
-
-#if 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);
-        connect(focusTerminalPanel, &QAction::triggered, this, &DolphinMainWindow::focusTerminalPanel);
-#endif
     }
 
     // setup 'Bookmarks' menu
@@ -2148,6 +2192,8 @@ void DolphinMainWindow::setupActions()
     connect(openInSplitViewAction, &QAction::triggered, this, [this]() {
         openInSplitView(QUrl());
     });
+
+    m_recentFiles = new KRecentFilesAction(this);
 }
 
 void DolphinMainWindow::setupDockWidgets()
@@ -2182,7 +2228,7 @@ void DolphinMainWindow::setupDockWidgets()
     connect(infoPanel, &InformationPanel::urlActivated, this, &DolphinMainWindow::handleUrl);
     infoDock->setWidget(infoPanel);
 
-    createPanelAction(QIcon::fromTheme(QStringLiteral("dialog-information")), Qt::Key_F11, infoDock, QStringLiteral("show_information_panel"));
+    createPanelAction(QIcon::fromTheme(QStringLiteral("documentinfo")), Qt::Key_F11, infoDock, QStringLiteral("show_information_panel"));
 
     addDockWidget(Qt::RightDockWidgetArea, infoDock);
     connect(this, &DolphinMainWindow::urlChanged, infoPanel, &InformationPanel::setUrl);
@@ -2294,8 +2340,15 @@ void DolphinMainWindow::setupDockWidgets()
                                           "advanced tasks. To learn more about terminals use the help features in a "
                                           "standalone terminal application like Konsole.</para>")
                                    + panelWhatsThis);
-    }
-#endif
+
+        QAction *focusTerminalPanel = actionCollection()->addAction(QStringLiteral("focus_terminal_panel"));
+        focusTerminalPanel->setText(i18nc("@action:inmenu Tools", "Focus Terminal Panel"));
+        focusTerminalPanel->setToolTip(i18nc("@info:tooltip", "Move keyboard focus to and from the Terminal panel."));
+        focusTerminalPanel->setIcon(QIcon::fromTheme(QStringLiteral("swap-panels")));
+        actionCollection()->setDefaultShortcut(focusTerminalPanel, Qt::CTRL | Qt::SHIFT | Qt::Key_F4);
+        connect(focusTerminalPanel, &QAction::triggered, this, &DolphinMainWindow::toggleTerminalPanelFocus);
+    } // endif "shell_access" allowed
+#endif // HAVE_TERMINAL
 
     if (GeneralSettings::version() < 200) {
         infoDock->hide();
@@ -2325,6 +2378,7 @@ void DolphinMainWindow::setupDockWidgets()
     connect(m_placesPanel, &PlacesPanel::errorMessage, this, &DolphinMainWindow::showErrorMessage);
     connect(this, &DolphinMainWindow::urlChanged, m_placesPanel, &PlacesPanel::setUrl);
     connect(placesDock, &DolphinDockWidget::visibilityChanged, &DolphinUrlNavigatorsController::slotPlacesPanelVisibilityChanged);
+    connect(placesDock, &DolphinDockWidget::visibilityChanged, this, &DolphinMainWindow::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);
@@ -2366,6 +2420,13 @@ void DolphinMainWindow::setupDockWidgets()
                                     "</interface> to display it again.</para>")
                              + panelWhatsThis);
 
+    QAction *focusPlacesPanel = actionCollection()->addAction(QStringLiteral("focus_places_panel"));
+    focusPlacesPanel->setText(i18nc("@action:inmenu View", "Focus Places Panel"));
+    focusPlacesPanel->setToolTip(i18nc("@info:tooltip", "Move keyboard focus to and from the Places panel."));
+    focusPlacesPanel->setIcon(QIcon::fromTheme(QStringLiteral("swap-panels")));
+    actionCollection()->setDefaultShortcut(focusPlacesPanel, Qt::CTRL | Qt::Key_P);
+    connect(focusPlacesPanel, &QAction::triggered, this, &DolphinMainWindow::togglePlacesPanelFocus);
+
     // Add actions into the "Panels" menu
     KActionMenu *panelsMenu = new KActionMenu(i18nc("@action:inmenu View", "Show Panels"), this);
     actionCollection()->addAction(QStringLiteral("panels"), panelsMenu);
@@ -2379,8 +2440,11 @@ void DolphinMainWindow::setupDockWidgets()
     panelsMenu->addAction(ac->action(QStringLiteral("show_folders_panel")));
     panelsMenu->addAction(ac->action(QStringLiteral("show_terminal_panel")));
     panelsMenu->addSeparator();
-    panelsMenu->addAction(actionShowAllPlaces);
     panelsMenu->addAction(lockLayoutAction);
+    panelsMenu->addSeparator();
+    panelsMenu->addAction(actionShowAllPlaces);
+    panelsMenu->addAction(focusPlacesPanel);
+    panelsMenu->addAction(ac->action(QStringLiteral("focus_terminal_panel")));
 
     connect(panelsMenu->menu(), &QMenu::aboutToShow, this, [actionShowAllPlaces] {
         actionShowAllPlaces->setEnabled(DolphinPlacesModelSingleton::instance().placesModel()->hiddenCount());
@@ -2401,7 +2465,7 @@ void DolphinMainWindow::updateFileAndEditActions()
     QAction *addToPlacesAction = col->action(QStringLiteral("add_to_places"));
     QAction *copyToOtherViewAction = col->action(QStringLiteral("copy_to_inactive_split_view"));
     QAction *moveToOtherViewAction = col->action(QStringLiteral("move_to_inactive_split_view"));
-    QAction *copyLocation = col->action(QString("copy_location"));
+    QAction *copyLocation = col->action(QStringLiteral("copy_location"));
 
     if (list.isEmpty()) {
         stateChanged(QStringLiteral("has_no_selection"));
@@ -2859,20 +2923,40 @@ void DolphinMainWindow::saveNewToolbarConfig()
     (static_cast<KHamburgerMenu *>(actionCollection()->action(KStandardAction::name(KStandardAction::HamburgerMenu))))->hideActionsOf(toolBar());
 }
 
-void DolphinMainWindow::focusTerminalPanel()
+void DolphinMainWindow::toggleTerminalPanelFocus()
 {
-    if (m_terminalPanel->isVisible()) {
-        if (m_terminalPanel->terminalHasFocus()) {
-            m_activeViewContainer->view()->setFocus(Qt::FocusReason::ShortcutFocusReason);
-            actionCollection()->action(QStringLiteral("focus_terminal_panel"))->setText(i18nc("@action:inmenu Tools", "Focus Terminal Panel"));
-        } else {
-            m_terminalPanel->setFocus(Qt::FocusReason::ShortcutFocusReason);
-            actionCollection()->action(QStringLiteral("focus_terminal_panel"))->setText(i18nc("@action:inmenu Tools", "Defocus Terminal Panel"));
-        }
-    } else {
-        actionCollection()->action(QStringLiteral("show_terminal_panel"))->trigger();
+    if (!m_terminalPanel->isVisible()) {
+        actionCollection()->action(QStringLiteral("show_terminal_panel"))->trigger(); // Also moves focus to the panel.
         actionCollection()->action(QStringLiteral("focus_terminal_panel"))->setText(i18nc("@action:inmenu Tools", "Defocus Terminal Panel"));
+        return;
+    }
+
+    if (m_terminalPanel->terminalHasFocus()) {
+        m_activeViewContainer->view()->setFocus(Qt::FocusReason::ShortcutFocusReason);
+        actionCollection()->action(QStringLiteral("focus_terminal_panel"))->setText(i18nc("@action:inmenu Tools", "Focus Terminal Panel"));
+        return;
+    }
+
+    m_terminalPanel->setFocus(Qt::FocusReason::ShortcutFocusReason);
+    actionCollection()->action(QStringLiteral("focus_terminal_panel"))->setText(i18nc("@action:inmenu Tools", "Defocus Terminal Panel"));
+}
+
+void DolphinMainWindow::togglePlacesPanelFocus()
+{
+    if (!m_placesPanel->isVisible()) {
+        actionCollection()->action(QStringLiteral("show_places_panel"))->trigger(); // Also moves focus to the panel.
+        actionCollection()->action(QStringLiteral("focus_places_panel"))->setText(i18nc("@action:inmenu View", "Defocus Terminal Panel"));
+        return;
+    }
+
+    if (m_placesPanel->hasFocus()) {
+        m_activeViewContainer->view()->setFocus(Qt::FocusReason::ShortcutFocusReason);
+        actionCollection()->action(QStringLiteral("focus_places_panel"))->setText(i18nc("@action:inmenu View", "Focus Places Panel"));
+        return;
     }
+
+    m_placesPanel->setFocus(Qt::FocusReason::ShortcutFocusReason);
+    actionCollection()->action(QStringLiteral("focus_places_panel"))->setText(i18nc("@action:inmenu View", "Defocus Places Panel"));
 }
 
 DolphinMainWindow::UndoUiInterface::UndoUiInterface()
@@ -2889,7 +2973,7 @@ void DolphinMainWindow::UndoUiInterface::jobError(KIO::Job *job)
     DolphinMainWindow *mainWin = qobject_cast<DolphinMainWindow *>(parentWidget());
     if (mainWin) {
         DolphinViewContainer *container = mainWin->activeViewContainer();
-        container->showMessage(job->errorString(), DolphinViewContainer::Error);
+        container->showMessage(job->errorString(), KMessageWidget::Error);
     } else {
         KIO::FileUndoManager::UiInterface::jobError(job);
     }
@@ -2907,7 +2991,10 @@ bool DolphinMainWindow::isItemVisibleInAnyView(const QString &urlOfItem)
 
 void DolphinMainWindow::slotDoubleClickViewBackground(Qt::MouseButton button)
 {
-    Q_UNUSED(button) // might be of use later
+    if (button != Qt::MouseButton::LeftButton) {
+        // only handle left mouse button for now
+        return;
+    }
 
     GeneralSettings *settings = GeneralSettings::self();
     QString clickAction = settings->doubleClickViewAction();