]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/dolphinmainwindow.cpp
Fix scrolling during inline renaming causes rename of wrong file
[dolphin.git] / src / dolphinmainwindow.cpp
index 185db71936e207aceb50c2407d4e810f07c1a579..c35de766ccfd717df002025fc61e0df653b65ea3 100644 (file)
@@ -29,6 +29,7 @@
 #include "dolphintabwidget.h"
 #include "dolphinviewcontainer.h"
 #include "dolphintabpage.h"
+#include "middleclickactioneventfilter.h"
 #include "panels/folders/folderspanel.h"
 #include "panels/places/placespanel.h"
 #include "panels/information/informationpanel.h"
@@ -51,6 +52,7 @@
 #include <KAuthorized>
 #include <KConfig>
 #include <kdualaction.h>
+#include <KHelpMenu>
 #include <KJobWidgets>
 #include <QLineEdit>
 #include <KToolBar>
@@ -60,6 +62,7 @@
 #include <KProtocolInfo>
 #include <QMenu>
 #include <KMessageBox>
+#include <KFilePlacesModel>
 #include <KFileItemListProperties>
 #include <KRun>
 #include <KShell>
@@ -96,8 +99,15 @@ DolphinMainWindow::DolphinMainWindow() :
     m_settingsDialog(),
     m_controlButton(0),
     m_updateToolBarTimer(0),
-    m_lastHandleUrlStatJob(0)
+    m_lastHandleUrlStatJob(0),
+#ifndef Q_OS_WIN
+    m_terminalPanel(0),
+#endif
+    m_placesPanel(0),
+    m_tearDownFromPlacesRequested(false)
 {
+    Q_INIT_RESOURCE(dolphin);
+
     setObjectName(QStringLiteral("Dolphin#"));
 
     connect(&DolphinNewFileMenuObserver::instance(), &DolphinNewFileMenuObserver::errorMessage,
@@ -124,6 +134,7 @@ DolphinMainWindow::DolphinMainWindow() :
     setAcceptDrops(true);
 
     m_tabWidget = new DolphinTabWidget(this);
+    m_tabWidget->setObjectName("tabWidget");
     connect(m_tabWidget, &DolphinTabWidget::activeViewChanged,
             this, &DolphinMainWindow::activeViewChanged);
     connect(m_tabWidget, &DolphinTabWidget::tabCountChanged,
@@ -166,6 +177,11 @@ DolphinMainWindow::DolphinMainWindow() :
     if (!showMenu) {
         createControlButton();
     }
+
+    // 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);
+    toolBar()->installEventFilter(middleClickEventFilter);
 }
 
 DolphinMainWindow::~DolphinMainWindow()
@@ -236,6 +252,11 @@ void DolphinMainWindow::changeUrl(const QUrl &url)
 
 void DolphinMainWindow::slotTerminalDirectoryChanged(const QUrl& url)
 {
+    if (m_tearDownFromPlacesRequested && url == QUrl::fromLocalFile(QDir::homePath())) {
+        m_placesPanel->proceedWithTearDown();
+        m_tearDownFromPlacesRequested = false;
+    }
+
     m_activeViewContainer->setAutoGrabFocus(false);
     changeUrl(url);
     m_activeViewContainer->setAutoGrabFocus(true);
@@ -290,7 +311,7 @@ void DolphinMainWindow::updateFilterBarAction(bool show)
 
 void DolphinMainWindow::openNewMainWindow()
 {
-    KRun::run(QStringLiteral("dolphin %u"), QList<QUrl>(), this);
+    Dolphin::openNewWindow({m_activeViewContainer->url()}, this);
 }
 
 void DolphinMainWindow::openNewActivatedTab()
@@ -306,16 +327,21 @@ void DolphinMainWindow::openNewTab(const QUrl& url)
 void DolphinMainWindow::openInNewTab()
 {
     const KFileItemList& list = m_activeViewContainer->view()->selectedItems();
-    if (list.isEmpty()) {
-        openNewTab(m_activeViewContainer->url());
-    } else {
-        foreach (const KFileItem& item, list) {
-            const QUrl& url = DolphinView::openItemAsFolderUrl(item);
-            if (!url.isEmpty()) {
-                openNewTab(url);
-            }
+    bool tabCreated = false;
+
+    foreach (const KFileItem& item, list) {
+        const QUrl& url = DolphinView::openItemAsFolderUrl(item);
+        if (!url.isEmpty()) {
+            openNewTab(url);
+            tabCreated = true;
         }
     }
+
+    // if no new tab has been created from the selection
+    // open the current directory in a new tab
+    if (!tabCreated) {
+        openNewTab(m_activeViewContainer->url());
+    }
 }
 
 void DolphinMainWindow::openInNewWindow()
@@ -331,7 +357,7 @@ void DolphinMainWindow::openInNewWindow()
     }
 
     if (!newWindowUrl.isEmpty()) {
-        KRun::run(QStringLiteral("dolphin %u"), {newWindowUrl}, this);
+        Dolphin::openNewWindow({newWindowUrl}, this);
     }
 }
 
@@ -492,6 +518,19 @@ void DolphinMainWindow::slotDirectoryLoadingCompleted()
     updatePasteAction();
 }
 
+void DolphinMainWindow::slotToolBarActionMiddleClicked(QAction *action)
+{
+    if (action == actionCollection()->action(QStringLiteral("go_back"))) {
+        goBackInNewTab();
+    } else if (action == actionCollection()->action(QStringLiteral("go_forward"))) {
+        goForwardInNewTab();
+    } else if (action == actionCollection()->action(QStringLiteral("go_up"))) {
+        goUpInNewTab();
+    } else if (action == actionCollection()->action(QStringLiteral("go_home"))) {
+        goHomeInNewTab();
+    }
+}
+
 void DolphinMainWindow::selectAll()
 {
     clearStatusBar();
@@ -552,9 +591,9 @@ void DolphinMainWindow::disableStopAction()
     actionCollection()->action(QStringLiteral("stop"))->setEnabled(false);
 }
 
-void DolphinMainWindow::showFilterBar(bool show)
+void DolphinMainWindow::showFilterBar()
 {
-    m_activeViewContainer->setFilterBarVisible(show);
+    m_activeViewContainer->setFilterBarVisible(true);
 }
 
 void DolphinMainWindow::toggleEditLocation()
@@ -617,40 +656,29 @@ void DolphinMainWindow::goHome()
     m_activeViewContainer->urlNavigator()->goHome();
 }
 
-void DolphinMainWindow::goBack(Qt::MouseButtons buttons)
+void DolphinMainWindow::goBackInNewTab()
 {
-    // The default case (left button pressed) is handled in goBack().
-    if (buttons == Qt::MiddleButton) {
-        KUrlNavigator* urlNavigator = activeViewContainer()->urlNavigator();
-        const int index = urlNavigator->historyIndex() + 1;
-        openNewTab(urlNavigator->locationUrl(index));
-    }
+    KUrlNavigator* urlNavigator = activeViewContainer()->urlNavigator();
+    const int index = urlNavigator->historyIndex() + 1;
+    openNewTab(urlNavigator->locationUrl(index));
 }
 
-void DolphinMainWindow::goForward(Qt::MouseButtons buttons)
+void DolphinMainWindow::goForwardInNewTab()
 {
-    // The default case (left button pressed) is handled in goForward().
-    if (buttons == Qt::MiddleButton) {
-        KUrlNavigator* urlNavigator = activeViewContainer()->urlNavigator();
-        const int index = urlNavigator->historyIndex() - 1;
-        openNewTab(urlNavigator->locationUrl(index));
-    }
+    KUrlNavigator* urlNavigator = activeViewContainer()->urlNavigator();
+    const int index = urlNavigator->historyIndex() - 1;
+    openNewTab(urlNavigator->locationUrl(index));
 }
 
-void DolphinMainWindow::goUp(Qt::MouseButtons buttons)
+void DolphinMainWindow::goUpInNewTab()
 {
-    // The default case (left button pressed) is handled in goUp().
-    if (buttons == Qt::MiddleButton) {
-        openNewTab(KIO::upUrl(activeViewContainer()->url()));
-    }
+    const QUrl currentUrl = activeViewContainer()->urlNavigator()->locationUrl();
+    openNewTab(KIO::upUrl(currentUrl));
 }
 
-void DolphinMainWindow::goHome(Qt::MouseButtons buttons)
+void DolphinMainWindow::goHomeInNewTab()
 {
-    // The default case (left button pressed) is handled in goHome().
-    if (buttons == Qt::MiddleButton) {
-        openNewTab(Dolphin::homeUrl());
-    }
+    openNewTab(Dolphin::homeUrl());
 }
 
 void DolphinMainWindow::compareFiles()
@@ -772,11 +800,9 @@ void DolphinMainWindow::openContextMenu(const QPoint& pos,
         changeUrl(KIO::upUrl(item.url()));
         break;
 
-    case DolphinContextMenu::OpenParentFolderInNewWindow: {
-
-        KRun::run(QStringLiteral("dolphin %u"), {KIO::upUrl(item.url())}, this);
+    case DolphinContextMenu::OpenParentFolderInNewWindow:
+        Dolphin::openNewWindow({KIO::upUrl(item.url())}, this);
         break;
-    }
 
     case DolphinContextMenu::OpenParentFolderInNewTab:
         openNewTab(KIO::upUrl(item.url()));
@@ -870,19 +896,8 @@ void DolphinMainWindow::updateControlMenu()
     addActionToMenu(ac->action(KStandardAction::name(KStandardAction::Preferences)), menu);
 
     // Add "Help" menu
-    QMenu* helpMenu = new QMenu(i18nc("@action:inmenu", "Help"), menu);
-    helpMenu->addAction(ac->action(KStandardAction::name(KStandardAction::HelpContents)));
-    helpMenu->addAction(ac->action(KStandardAction::name(KStandardAction::WhatsThis)));
-    helpMenu->addSeparator();
-    helpMenu->addAction(ac->action(KStandardAction::name(KStandardAction::ReportBug)));
-    helpMenu->addSeparator();
-    helpMenu->addAction(ac->action(KStandardAction::name(KStandardAction::Donate)));
-    helpMenu->addSeparator();
-    helpMenu->addAction(ac->action(KStandardAction::name(KStandardAction::SwitchApplicationLanguage)));
-    helpMenu->addSeparator();
-    helpMenu->addAction(ac->action(KStandardAction::name(KStandardAction::AboutApp)));
-    helpMenu->addAction(ac->action(KStandardAction::name(KStandardAction::AboutKDE)));
-    menu->addMenu(helpMenu);
+    auto helpMenu = new KHelpMenu(menu);
+    menu->addMenu(helpMenu->menu());
 
     menu->addSeparator();
     addActionToMenu(ac->action(KStandardAction::name(KStandardAction::ShowMenubar)), menu);
@@ -958,26 +973,58 @@ void DolphinMainWindow::tabCountChanged(int count)
 
 void DolphinMainWindow::setUrlAsCaption(const QUrl& url)
 {
-    QString caption;
+    static KFilePlacesModel s_placesModel;
+
+    QString schemePrefix;
     if (!url.isLocalFile()) {
-        caption.append(url.scheme() + " - ");
+        schemePrefix.append(url.scheme() + " - ");
         if (!url.host().isEmpty()) {
-            caption.append(url.host() + " - ");
+            schemePrefix.append(url.host() + " - ");
         }
     }
 
     if (GeneralSettings::showFullPathInTitlebar()) {
         const QString path = url.adjusted(QUrl::StripTrailingSlash).path();
-        caption.append(path);
+        setWindowTitle(schemePrefix + path);
+        return;
+    }
+
+    const auto& matchedPlaces = s_placesModel.match(s_placesModel.index(0,0), KFilePlacesModel::UrlRole, url, 1, Qt::MatchExactly);
+
+    if (!matchedPlaces.isEmpty()) {
+        setWindowTitle(s_placesModel.text(matchedPlaces.first()));
+        return;
+    }
+
+    QString fileName = url.adjusted(QUrl::StripTrailingSlash).fileName();
+    if (fileName.isEmpty()) {
+        fileName = '/';
+    }
+
+    setWindowTitle(schemePrefix + fileName);
+}
+
+void DolphinMainWindow::slotStorageTearDownFromPlacesRequested(const QString& mountPath)
+{
+#ifndef Q_OS_WIN
+    if (m_terminalPanel->currentWorkingDirectory().startsWith(mountPath)) {
+        m_tearDownFromPlacesRequested = true;
+        m_terminalPanel->goHome();
+        // m_placesPanel->proceedWithTearDown() will be called in slotTerminalDirectoryChanged
     } else {
-        QString fileName = url.adjusted(QUrl::StripTrailingSlash).fileName();
-        if (fileName.isEmpty()) {
-            fileName = '/';
-        }
-        caption.append(fileName);
+        m_placesPanel->proceedWithTearDown();
     }
+#endif
+}
 
-    setWindowTitle(caption);
+void DolphinMainWindow::slotStorageTearDownExternallyRequested(const QString& mountPath)
+{
+#ifndef Q_OS_WIN
+    if (m_terminalPanel->currentWorkingDirectory().startsWith(mountPath)) {
+        m_tearDownFromPlacesRequested = false;
+        m_terminalPanel->goHome();
+    }
+#endif
 }
 
 void DolphinMainWindow::setupActions()
@@ -1010,27 +1057,23 @@ void DolphinMainWindow::setupActions()
     closeTab->setEnabled(false);
     connect(closeTab, &QAction::triggered, m_tabWidget, static_cast<void(DolphinTabWidget::*)()>(&DolphinTabWidget::closeTab));
 
-    KStandardAction::quit(this, SLOT(quit()), actionCollection());
+    KStandardAction::quit(this, &DolphinMainWindow::quit, actionCollection());
 
     // setup 'Edit' menu
     KStandardAction::undo(this,
-                          SLOT(undo()),
+                          &DolphinMainWindow::undo,
                           actionCollection());
 
-    // need to remove shift+del from cut action, else the shortcut for deletejob
-    // doesn't work
-    QAction* cut = KStandardAction::cut(this, SLOT(cut()), actionCollection());
-    auto cutShortcuts = cut->shortcuts();
-    cutShortcuts.removeAll(QKeySequence(Qt::SHIFT | Qt::Key_Delete));
-    actionCollection()->setDefaultShortcuts(cut, cutShortcuts);
-    KStandardAction::copy(this, SLOT(copy()), actionCollection());
-    QAction* paste = KStandardAction::paste(this, SLOT(paste()), actionCollection());
+
+    KStandardAction::cut(this, &DolphinMainWindow::cut, actionCollection());
+    KStandardAction::copy(this, &DolphinMainWindow::copy, actionCollection());
+    QAction* paste = KStandardAction::paste(this, &DolphinMainWindow::paste, actionCollection());
     // The text of the paste-action is modified dynamically by Dolphin
     // (e. g. to "Paste One Folder"). To prevent that the size of the toolbar changes
     // due to the long text, the text "Paste" is used:
     paste->setIconText(i18nc("@action:inmenu Edit", "Paste"));
 
-    KStandardAction::find(this, SLOT(find()), actionCollection());
+    KStandardAction::find(this, &DolphinMainWindow::find, actionCollection());
 
     QAction* selectAll = actionCollection()->addAction(QStringLiteral("select_all"));
     selectAll->setText(i18nc("@action:inmenu Edit", "Select All"));
@@ -1053,7 +1096,7 @@ void DolphinMainWindow::setupActions()
     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-visiting")));
+    stashSplit->setIcon(QIcon::fromTheme(QStringLiteral("folder-stash")));
     stashSplit->setCheckable(false);
     stashSplit->setVisible(KProtocolInfo::isKnownProtocol("stash"));
     connect(stashSplit, &QAction::triggered, this, &DolphinMainWindow::toggleSplitStash);
@@ -1081,7 +1124,7 @@ void DolphinMainWindow::setupActions()
     connect(replaceLocation, &QAction::triggered, this, &DolphinMainWindow::replaceLocation);
 
     // setup 'Go' menu
-    QAction* backAction = KStandardAction::back(this, SLOT(goBack()), actionCollection());
+    QAction* backAction = KStandardAction::back(this, &DolphinMainWindow::goBack, actionCollection());
     auto backShortcuts = backAction->shortcuts();
     backShortcuts.append(QKeySequence(Qt::Key_Backspace));
     actionCollection()->setDefaultShortcuts(backAction, backShortcuts);
@@ -1105,12 +1148,12 @@ void DolphinMainWindow::setupActions()
     auto undoAction = actionCollection()->action(KStandardAction::name(KStandardAction::Undo));
     undoAction->setEnabled(false); // undo should be disabled by default
 
-    KStandardAction::forward(this, SLOT(goForward()), actionCollection());
-    KStandardAction::up(this, SLOT(goUp()), actionCollection());
-    KStandardAction::home(this, SLOT(goHome()), actionCollection());
+    KStandardAction::forward(this, &DolphinMainWindow::goForward, actionCollection());
+    KStandardAction::up(this, &DolphinMainWindow::goUp, actionCollection());
+    KStandardAction::home(this, &DolphinMainWindow::goHome, actionCollection());
 
     // setup 'Tools' menu
-    KToggleAction* showFilterBar = actionCollection()->add<KToggleAction>(QStringLiteral("show_filter_bar"));
+    QAction* showFilterBar = actionCollection()->addAction(QStringLiteral("show_filter_bar"));
     showFilterBar->setText(i18nc("@action:inmenu Tools", "Show Filter Bar"));
     showFilterBar->setIcon(QIcon::fromTheme(QStringLiteral("view-filter")));
     actionCollection()->setDefaultShortcut(showFilterBar, Qt::CTRL | Qt::Key_I);
@@ -1236,21 +1279,21 @@ void DolphinMainWindow::setupDockWidgets()
         terminalDock->setLocked(lock);
         terminalDock->setObjectName(QStringLiteral("terminalDock"));
         terminalDock->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
-        TerminalPanel* terminalPanel = new TerminalPanel(terminalDock);
-        terminalPanel->setCustomContextMenuActions({lockLayoutAction});
-        terminalDock->setWidget(terminalPanel);
+        m_terminalPanel = new TerminalPanel(terminalDock);
+        m_terminalPanel->setCustomContextMenuActions({lockLayoutAction});
+        terminalDock->setWidget(m_terminalPanel);
 
-        connect(terminalPanel, &TerminalPanel::hideTerminalPanel, terminalDock, &DolphinDockWidget::hide);
-        connect(terminalPanel, &TerminalPanel::changeUrl, this, &DolphinMainWindow::slotTerminalDirectoryChanged);
+        connect(m_terminalPanel, &TerminalPanel::hideTerminalPanel, terminalDock, &DolphinDockWidget::hide);
+        connect(m_terminalPanel, &TerminalPanel::changeUrl, this, &DolphinMainWindow::slotTerminalDirectoryChanged);
         connect(terminalDock, &DolphinDockWidget::visibilityChanged,
-                terminalPanel, &TerminalPanel::dockVisibilityChanged);
+                m_terminalPanel, &TerminalPanel::dockVisibilityChanged);
 
         QAction* terminalAction = terminalDock->toggleViewAction();
         createPanelAction(QIcon::fromTheme(QStringLiteral("utilities-terminal")), Qt::Key_F4, terminalAction, QStringLiteral("show_terminal_panel"));
 
         addDockWidget(Qt::BottomDockWidgetArea, terminalDock);
         connect(this, &DolphinMainWindow::urlChanged,
-                terminalPanel, &TerminalPanel::setUrl);
+                m_terminalPanel, &TerminalPanel::setUrl);
 
         if (GeneralSettings::version() < 200) {
             terminalDock->hide();
@@ -1269,28 +1312,31 @@ void DolphinMainWindow::setupDockWidgets()
     placesDock->setObjectName(QStringLiteral("placesDock"));
     placesDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
 
-    PlacesPanel* placesPanel = new PlacesPanel(placesDock);
-    placesPanel->setCustomContextMenuActions({lockLayoutAction});
-    placesDock->setWidget(placesPanel);
+    m_placesPanel = new PlacesPanel(placesDock);
+    m_placesPanel->setCustomContextMenuActions({lockLayoutAction});
+    placesDock->setWidget(m_placesPanel);
 
-    QActionplacesAction = placesDock->toggleViewAction();
+    QAction *placesAction = placesDock->toggleViewAction();
     createPanelAction(QIcon::fromTheme(QStringLiteral("bookmarks")), Qt::Key_F9, placesAction, QStringLiteral("show_places_panel"));
 
     addDockWidget(Qt::LeftDockWidgetArea, placesDock);
-    connect(placesPanel, &PlacesPanel::placeActivated,
+    connect(m_placesPanel, &PlacesPanel::placeActivated,
             this, &DolphinMainWindow::slotPlaceActivated);
-    connect(placesPanel, &PlacesPanel::placeMiddleClicked,
+    connect(m_placesPanel, &PlacesPanel::placeMiddleClicked,
             this, &DolphinMainWindow::openNewTab);
-    connect(placesPanel, &PlacesPanel::errorMessage,
+    connect(m_placesPanel, &PlacesPanel::errorMessage,
             this, &DolphinMainWindow::showErrorMessage);
     connect(this, &DolphinMainWindow::urlChanged,
-            placesPanel, &PlacesPanel::setUrl);
+            m_placesPanel, &PlacesPanel::setUrl);
     connect(placesDock, &DolphinDockWidget::visibilityChanged,
             m_tabWidget, &DolphinTabWidget::slotPlacesPanelVisibilityChanged);
     connect(this, &DolphinMainWindow::settingsChanged,
-           placesPanel, &PlacesPanel::readSettings);
-
-    m_tabWidget->slotPlacesPanelVisibilityChanged(placesPanel->isVisible());
+        m_placesPanel, &PlacesPanel::readSettings);
+    connect(m_placesPanel, &PlacesPanel::storageTearDownRequested,
+            this, &DolphinMainWindow::slotStorageTearDownFromPlacesRequested);
+    connect(m_placesPanel, &PlacesPanel::storageTearDownExternallyRequested,
+            this, &DolphinMainWindow::slotStorageTearDownExternallyRequested);
+    m_tabWidget->slotPlacesPanelVisibilityChanged(m_placesPanel->isVisible());
 
     // Add actions into the "Panels" menu
     KActionMenu* panelsMenu = new KActionMenu(i18nc("@action:inmenu View", "Panels"), this);
@@ -1316,9 +1362,9 @@ void DolphinMainWindow::updateEditActions()
         stateChanged(QStringLiteral("has_selection"));
 
         KActionCollection* col = actionCollection();
-        QAction* renameAction      = col->action(QStringLiteral("rename"));
-        QAction* moveToTrashAction = col->action(QStringLiteral("move_to_trash"));
-        QAction* deleteAction      = col->action(QStringLiteral("delete"));
+        QAction* renameAction      = col->action(KStandardAction::name(KStandardAction::RenameFile));
+        QAction* moveToTrashAction = col->action(KStandardAction::name(KStandardAction::MoveToTrash));
+        QAction* deleteAction      = col->action(KStandardAction::name(KStandardAction::DeleteFile));
         QAction* cutAction         = col->action(KStandardAction::name(KStandardAction::Cut));
         QAction* deleteWithTrashShortcut = col->action(QStringLiteral("delete_shortcut")); // see DolphinViewActionHandler
 
@@ -1459,6 +1505,8 @@ void DolphinMainWindow::connectViewSignals(DolphinViewContainer* container)
             this, static_cast<void(DolphinMainWindow::*)()>(&DolphinMainWindow::goBack));
     connect(view, &DolphinView::goForwardRequested,
             this, static_cast<void(DolphinMainWindow::*)()>(&DolphinMainWindow::goForward));
+    connect(view, &DolphinView::urlActivated,
+            this, &DolphinMainWindow::handleUrl);
 
     const KUrlNavigator* navigator = container->urlNavigator();
     connect(navigator, &KUrlNavigator::urlChanged,