diff --git a/src/dolphinmainwindow.h b/src/dolphinmainwindow.h --- a/src/dolphinmainwindow.h +++ b/src/dolphinmainwindow.h @@ -46,6 +46,8 @@ class KNewFileMenu; class QToolButton; class QIcon; +class PlacesPanel; +class TerminalPanel; /** * @short Main window for Dolphin. @@ -90,6 +92,8 @@ */ KNewFileMenu* newFileMenu() const; + void setTabsToHomeIfMountPathOpen(const QString& mountPath); + public slots: /** * Pastes the clipboard data into the currently selected folder @@ -409,6 +413,21 @@ */ void setUrlAsCaption(const QUrl& url); + /** + * This slot is called when the user requested to unmount a removable media + * from the places menu + */ + void slotStorageTearDownFromPlacesRequested(const QString& mountPath); + + /** + * This slot is called when the user requested to unmount a removable media + * _not_ from the dolphin's places menu (from the notification area for e.g.) + * This slot is basically connected to each removable device's + * Solid::StorageAccess::teardownRequested(const QString & udi) + * signal through the places panel. + */ + void slotStorageTearDownExternallyRequested(const QString& mountPath); + /** * Is called when the view has finished loading the directory. */ @@ -496,6 +515,10 @@ QTimer* m_updateToolBarTimer; KIO::Job* m_lastHandleUrlStatJob; + + TerminalPanel* m_terminalPanel; + PlacesPanel* m_placesPanel; + bool m_tearDownFromPlacesRequested; }; inline DolphinViewContainer* DolphinMainWindow::activeViewContainer() const diff --git a/src/dolphinmainwindow.cpp b/src/dolphinmainwindow.cpp --- a/src/dolphinmainwindow.cpp +++ b/src/dolphinmainwindow.cpp @@ -99,7 +99,10 @@ m_settingsDialog(), m_controlButton(0), m_updateToolBarTimer(0), - m_lastHandleUrlStatJob(0) + m_lastHandleUrlStatJob(0), + m_terminalPanel(0), + m_placesPanel(0), + m_tearDownFromPlacesRequested(false) { Q_INIT_RESOURCE(dolphin); @@ -247,6 +250,11 @@ 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); @@ -994,6 +1002,25 @@ setWindowTitle(schemePrefix + fileName); } +void DolphinMainWindow::slotStorageTearDownFromPlacesRequested(const QString& mountPath) +{ + if (m_terminalPanel->currentWorkingDirectory().startsWith(mountPath)) { + m_tearDownFromPlacesRequested = true; + m_terminalPanel->goHome(); + // m_placesPanel->proceedWithTearDown() will be called in slotTerminalDirectoryChanged + } else { + m_placesPanel->proceedWithTearDown(); + } +} + +void DolphinMainWindow::slotStorageTearDownExternallyRequested(const QString& mountPath) +{ + if (m_terminalPanel->currentWorkingDirectory().startsWith(mountPath)) { + m_tearDownFromPlacesRequested = false; + m_terminalPanel->goHome(); + } +} + void DolphinMainWindow::setupActions() { // setup 'File' menu @@ -1246,21 +1273,21 @@ 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(); @@ -1279,28 +1306,31 @@ 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); - QAction* placesAction = 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); diff --git a/src/panels/places/placesitem.h b/src/panels/places/placesitem.h --- a/src/panels/places/placesitem.h +++ b/src/panels/places/placesitem.h @@ -79,6 +79,8 @@ static KBookmark createDeviceBookmark(KBookmarkManager* manager, const QString& udi); + PlacesItemSignalHandler* signalHandler() const; + protected: virtual void onDataValueChanged(const QByteArray& role, const QVariant& current, diff --git a/src/panels/places/placesitem.cpp b/src/panels/places/placesitem.cpp --- a/src/panels/places/placesitem.cpp +++ b/src/panels/places/placesitem.cpp @@ -272,6 +272,8 @@ setUrl(QUrl::fromLocalFile(m_access->filePath())); QObject::connect(m_access.data(), &Solid::StorageAccess::accessibilityChanged, m_signalHandler.data(), &PlacesItemSignalHandler::onAccessibilityChanged); + QObject::connect(m_access.data(), &Solid::StorageAccess::teardownRequested, + m_signalHandler.data(), &PlacesItemSignalHandler::onTearDownRequested); } else if (m_disc && (m_disc->availableContent() & Solid::OpticalDisc::Audio) != 0) { Solid::Block *block = m_device.as(); if (block) { @@ -335,3 +337,8 @@ return QString::number(QDateTime::currentDateTimeUtc().toTime_t()) + '/' + QString::number(count++) + " (V2)"; } + +PlacesItemSignalHandler *PlacesItem::signalHandler() const +{ + return m_signalHandler.data(); +} diff --git a/src/panels/places/placesitemmodel.h b/src/panels/places/placesitemmodel.h --- a/src/panels/places/placesitemmodel.h +++ b/src/panels/places/placesitemmodel.h @@ -102,7 +102,7 @@ QAction* teardownAction(int index) const; void requestEject(int index); - void requestTeardown(int index); + void requestTearDown(int index); bool storageSetupNeeded(int index) const; void requestStorageSetup(int index); @@ -123,6 +123,8 @@ virtual void clear() Q_DECL_OVERRIDE; + void proceedWithTearDown(); + /** * Saves the bookmarks and indicates to other applications that the * state of the bookmarks has been changed. Is only called by the @@ -133,6 +135,8 @@ signals: void errorMessage(const QString& message); void storageSetupDone(int index, bool success); + void storageTearDownRequested(const QString& mountPath); + void storageTearDownExternallyRequested(const QString& mountPath); protected: virtual void onItemInserted(int index) Q_DECL_OVERRIDE; @@ -142,7 +146,7 @@ private slots: void slotDeviceAdded(const QString& udi); void slotDeviceRemoved(const QString& udi); - void slotStorageTeardownDone(Solid::ErrorType error, const QVariant& errorData); + void slotStorageTearDownDone(Solid::ErrorType error, const QVariant& errorData); void slotStorageSetupDone(Solid::ErrorType error, const QVariant& errorData, const QString& udi); void hideItem(); @@ -281,6 +285,8 @@ // removing an item is not allowed. int m_hiddenItemToRemove; + Solid::StorageAccess *m_deviceToTearDown; + QTimer* m_updateBookmarksTimer; QHash m_storageSetupInProgress; diff --git a/src/panels/places/placesitemmodel.cpp b/src/panels/places/placesitemmodel.cpp --- a/src/panels/places/placesitemmodel.cpp +++ b/src/panels/places/placesitemmodel.cpp @@ -22,6 +22,7 @@ ***************************************************************************/ #include "placesitemmodel.h" +#include "placesitemsignalhandler.h" #include "dolphin_generalsettings.h" @@ -77,6 +78,7 @@ m_systemBookmarksIndexes(), m_bookmarkedItems(), m_hiddenItemToRemove(-1), + m_deviceToTearDown(0), m_updateBookmarksTimer(0), m_storageSetupInProgress() { @@ -306,7 +308,7 @@ Solid::OpticalDrive* drive = item->device().parent().as(); if (drive) { connect(drive, &Solid::OpticalDrive::ejectDone, - this, &PlacesItemModel::slotStorageTeardownDone); + this, &PlacesItemModel::slotStorageTearDownDone); drive->eject(); } else { const QString label = item->text(); @@ -316,15 +318,19 @@ } } -void PlacesItemModel::requestTeardown(int index) +void PlacesItemModel::requestTearDown(int index) { const PlacesItem* item = placesItem(index); if (item) { - Solid::StorageAccess* access = item->device().as(); - if (access) { - connect(access, &Solid::StorageAccess::teardownDone, - this, &PlacesItemModel::slotStorageTeardownDone); - access->teardown(); + Solid::StorageAccess *tmp = item->device().as(); + if (tmp) { + m_deviceToTearDown = tmp; + // disconnect the Solid::StorageAccess::teardownRequested + // to prevent emitting PlacesItemModel::storageTearDownExternallyRequested + // after we have emitted PlacesItemModel::storageTearDownRequested + disconnect(tmp, &Solid::StorageAccess::teardownRequested, + item->signalHandler(), &PlacesItemSignalHandler::onTearDownRequested); + emit storageTearDownRequested(tmp->filePath()); } } } @@ -550,7 +556,11 @@ m_availableDevices << udi; const KBookmark bookmark = PlacesItem::createDeviceBookmark(m_bookmarkManager, udi); - appendItem(new PlacesItem(bookmark)); + + PlacesItem *item = new PlacesItem(bookmark); + appendItem(item); + connect(item->signalHandler(), &PlacesItemSignalHandler::tearDownExternallyRequested, + this, &PlacesItemModel::storageTearDownExternallyRequested); } void PlacesItemModel::slotDeviceRemoved(const QString& udi) @@ -576,11 +586,13 @@ } } -void PlacesItemModel::slotStorageTeardownDone(Solid::ErrorType error, const QVariant& errorData) +void PlacesItemModel::slotStorageTearDownDone(Solid::ErrorType error, const QVariant& errorData) { if (error && errorData.isValid()) { emit errorMessage(errorData.toString()); } + m_deviceToTearDown->disconnect(); + m_deviceToTearDown = nullptr; } void PlacesItemModel::slotStorageSetupDone(Solid::ErrorType error, @@ -786,7 +798,10 @@ devicesItems.reserve(devicesItems.count() + devices.count()); foreach (const QString& udi, devices) { const KBookmark bookmark = PlacesItem::createDeviceBookmark(m_bookmarkManager, udi); - devicesItems.append(new PlacesItem(bookmark)); + PlacesItem *item = new PlacesItem(bookmark); + devicesItems.append(item); + connect(item->signalHandler(), &PlacesItemSignalHandler::tearDownExternallyRequested, + this, &PlacesItemModel::storageTearDownExternallyRequested); } QList items; @@ -940,6 +955,15 @@ KStandardItemModel::clear(); } +void PlacesItemModel::proceedWithTearDown() +{ + Q_ASSERT(m_deviceToTearDown); + + connect(m_deviceToTearDown, &Solid::StorageAccess::teardownDone, + this, &PlacesItemModel::slotStorageTearDownDone); + m_deviceToTearDown->teardown(); +} + void PlacesItemModel::initializeAvailableDevices() { QString predicate(QStringLiteral("[[[[ StorageVolume.ignored == false AND [ StorageVolume.usage == 'FileSystem' OR StorageVolume.usage == 'Encrypted' ]]" diff --git a/src/panels/places/placesitemsignalhandler.h b/src/panels/places/placesitemsignalhandler.h --- a/src/panels/places/placesitemsignalhandler.h +++ b/src/panels/places/placesitemsignalhandler.h @@ -61,6 +61,11 @@ */ void onTrashDirListerCompleted(); + void onTearDownRequested(const QString& udi); + +signals: + void tearDownExternallyRequested(const QString& udi); + private: PlacesItem* m_item; }; diff --git a/src/panels/places/placesitemsignalhandler.cpp b/src/panels/places/placesitemsignalhandler.cpp --- a/src/panels/places/placesitemsignalhandler.cpp +++ b/src/panels/places/placesitemsignalhandler.cpp @@ -47,3 +47,15 @@ } } +void PlacesItemSignalHandler::onTearDownRequested(const QString& udi) +{ + Q_UNUSED(udi) + if (m_item) { + Solid::StorageAccess *tmp = m_item->device().as(); + if (tmp) { + QString mountPath = tmp->filePath(); + emit tearDownExternallyRequested(mountPath); + } + } +} + diff --git a/src/panels/places/placespanel.h b/src/panels/places/placespanel.h --- a/src/panels/places/placespanel.h +++ b/src/panels/places/placespanel.h @@ -41,11 +41,14 @@ public: PlacesPanel(QWidget* parent); virtual ~PlacesPanel(); + void proceedWithTearDown(); signals: void placeActivated(const QUrl& url); void placeMiddleClicked(const QUrl& url); void errorMessage(const QString& error); + void storageTearDownRequested(const QString& mountPath); + void storageTearDownExternallyRequested(const QString& mountPath); protected: virtual bool urlChanged() Q_DECL_OVERRIDE; diff --git a/src/panels/places/placespanel.cpp b/src/panels/places/placespanel.cpp --- a/src/panels/places/placespanel.cpp +++ b/src/panels/places/placespanel.cpp @@ -72,6 +72,11 @@ { } +void PlacesPanel::proceedWithTearDown() +{ + m_model->proceedWithTearDown(); +} + bool PlacesPanel::urlChanged() { if (!url().isValid() || url().scheme().contains(QStringLiteral("search"))) { @@ -110,6 +115,10 @@ m_model->setGroupedSorting(true); connect(m_model, &PlacesItemModel::errorMessage, this, &PlacesPanel::errorMessage); + connect(m_model, &PlacesItemModel::storageTearDownRequested, + this, &PlacesPanel::storageTearDownRequested); + connect(m_model, &PlacesItemModel::storageTearDownExternallyRequested, + this, &PlacesPanel::storageTearDownExternallyRequested); m_view = new PlacesView(); m_view->setWidgetCreator(new KItemListWidgetCreator()); @@ -241,7 +250,7 @@ // emit the slotItemMiddleClicked signal, because of Qt::MiddleButton. triggerItem(index, Qt::MiddleButton); } else if (action == teardownAction) { - m_model->requestTeardown(index); + m_model->requestTearDown(index); } else if (action == ejectAction) { m_model->requestEject(index); } diff --git a/src/panels/terminal/terminalpanel.h b/src/panels/terminal/terminalpanel.h --- a/src/panels/terminal/terminalpanel.h +++ b/src/panels/terminal/terminalpanel.h @@ -48,6 +48,13 @@ TerminalPanel(QWidget* parent = 0); virtual ~TerminalPanel(); + /** + * @brief This function is used to set the terminal panels's cwd to + * home when an unmounting request is receieved. + */ + void goHome(); + QString currentWorkingDirectory(); + public slots: void terminalExited(); void dockVisibilityChanged(); @@ -70,8 +77,13 @@ void slotKonsolePartCurrentDirectoryChanged(const QString& dir); private: + enum class HistoryPolicy { + AddToHistory, + SkipHistory + }; + void changeDir(const QUrl& url); - void sendCdToTerminal(const QString& path); + void sendCdToTerminal(const QString& path, HistoryPolicy addToHistory = HistoryPolicy::AddToHistory); private: bool m_clearTerminal; diff --git a/src/panels/terminal/terminalpanel.cpp b/src/panels/terminal/terminalpanel.cpp --- a/src/panels/terminal/terminalpanel.cpp +++ b/src/panels/terminal/terminalpanel.cpp @@ -54,6 +54,19 @@ { } +void TerminalPanel::goHome() +{ + sendCdToTerminal(QDir::homePath(), HistoryPolicy::SkipHistory); +} + +QString TerminalPanel::currentWorkingDirectory() +{ + if (m_terminal) { + return m_terminal->currentWorkingDirectory(); + } + return QString(); +} + void TerminalPanel::terminalExited() { m_terminal = 0; @@ -144,7 +157,7 @@ } } -void TerminalPanel::sendCdToTerminal(const QString& dir) +void TerminalPanel::sendCdToTerminal(const QString& dir, HistoryPolicy addToHistory) { if (dir == m_konsolePartCurrentDirectory) { m_clearTerminal = false; @@ -168,7 +181,8 @@ // the directory change, because this directory change is not caused by a "cd" command that the // user entered in the panel. Therefore, we have to remember 'dir'. Note that it could also be // a symbolic link -> remember the 'canonical' path. - m_sendCdToTerminalHistory.enqueue(QDir(dir).canonicalPath()); + if (addToHistory == HistoryPolicy::AddToHistory) + m_sendCdToTerminalHistory.enqueue(QDir(dir).canonicalPath()); if (m_clearTerminal) { m_terminal->sendInput(QStringLiteral(" clear\n"));