diff --git a/src/dolphinmainwindow.cpp b/src/dolphinmainwindow.cpp index 75a340f0a..d9adde66b 100644 --- a/src/dolphinmainwindow.cpp +++ b/src/dolphinmainwindow.cpp @@ -1,1592 +1,1592 @@ /*************************************************************************** * Copyright (C) 2006 by Peter Penz * * Copyright (C) 2006 by Stefan Monov * * Copyright (C) 2006 by Cvetoslav Ludmiloff * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * ***************************************************************************/ #include "dolphinmainwindow.h" #include "global.h" #include "dolphindockwidget.h" #include "dolphincontextmenu.h" #include "dolphinnewfilemenu.h" #include "dolphinrecenttabsmenu.h" #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" #include "panels/terminal/terminalpanel.h" #include "settings/dolphinsettingsdialog.h" #include "statusbar/dolphinstatusbar.h" #include "views/dolphinviewactionhandler.h" #include "views/dolphinremoteencoding.h" #include "views/draganddrophelper.h" #include "views/viewproperties.h" #include "views/dolphinnewfilemenuobserver.h" #include "dolphin_generalsettings.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { // Used for GeneralSettings::version() to determine whether // an updated version of Dolphin is running. const int CurrentDolphinVersion = 200; } DolphinMainWindow::DolphinMainWindow() : KXmlGuiWindow(nullptr), m_newFileMenu(nullptr), m_tabWidget(nullptr), m_activeViewContainer(nullptr), m_actionHandler(nullptr), m_remoteEncoding(nullptr), m_settingsDialog(), m_controlButton(nullptr), m_updateToolBarTimer(nullptr), m_lastHandleUrlStatJob(nullptr), m_terminalPanel(nullptr), m_placesPanel(nullptr), m_tearDownFromPlacesRequested(false) { Q_INIT_RESOURCE(dolphin); setComponentName(QStringLiteral("dolphin"), QGuiApplication::applicationDisplayName()); setObjectName(QStringLiteral("Dolphin#")); connect(&DolphinNewFileMenuObserver::instance(), &DolphinNewFileMenuObserver::errorMessage, this, &DolphinMainWindow::showErrorMessage); KIO::FileUndoManager* undoManager = KIO::FileUndoManager::self(); undoManager->setUiInterface(new UndoUiInterface()); connect(undoManager, static_cast(&KIO::FileUndoManager::undoAvailable), this, &DolphinMainWindow::slotUndoAvailable); connect(undoManager, &KIO::FileUndoManager::undoTextChanged, this, &DolphinMainWindow::slotUndoTextChanged); connect(undoManager, &KIO::FileUndoManager::jobRecordingStarted, this, &DolphinMainWindow::clearStatusBar); connect(undoManager, &KIO::FileUndoManager::jobRecordingFinished, this, &DolphinMainWindow::showCommand); GeneralSettings* generalSettings = GeneralSettings::self(); const bool firstRun = (generalSettings->version() < 200); if (firstRun) { generalSettings->setViewPropsTimestamp(QDateTime::currentDateTime()); } setAcceptDrops(true); m_tabWidget = new DolphinTabWidget(this); m_tabWidget->setObjectName("tabWidget"); connect(m_tabWidget, &DolphinTabWidget::activeViewChanged, this, &DolphinMainWindow::activeViewChanged); connect(m_tabWidget, &DolphinTabWidget::tabCountChanged, this, &DolphinMainWindow::tabCountChanged); connect(m_tabWidget, &DolphinTabWidget::currentUrlChanged, this, &DolphinMainWindow::updateWindowTitle); setCentralWidget(m_tabWidget); setupActions(); m_actionHandler = new DolphinViewActionHandler(actionCollection(), this); connect(m_actionHandler, &DolphinViewActionHandler::actionBeingHandled, this, &DolphinMainWindow::clearStatusBar); - connect(m_actionHandler, &DolphinViewActionHandler::createDirectory, this, &DolphinMainWindow::createDirectory); + connect(m_actionHandler, &DolphinViewActionHandler::createDirectoryTriggered, this, &DolphinMainWindow::createDirectory); m_remoteEncoding = new DolphinRemoteEncoding(this, m_actionHandler); connect(this, &DolphinMainWindow::urlChanged, m_remoteEncoding, &DolphinRemoteEncoding::slotAboutToOpenUrl); setupDockWidgets(); setupGUI(Keys | Save | Create | ToolBar); stateChanged(QStringLiteral("new_file")); QClipboard* clipboard = QApplication::clipboard(); connect(clipboard, &QClipboard::dataChanged, this, &DolphinMainWindow::updatePasteAction); QAction* showFilterBarAction = actionCollection()->action(QStringLiteral("show_filter_bar")); showFilterBarAction->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(); } // 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() { } void DolphinMainWindow::openDirectories(const QList& dirs, bool splitView) { m_tabWidget->openDirectories(dirs, splitView); } void DolphinMainWindow::openFiles(const QList& files, bool splitView) { m_tabWidget->openFiles(files, splitView); } void DolphinMainWindow::showCommand(CommandType command) { DolphinStatusBar* statusBar = m_activeViewContainer->statusBar(); switch (command) { case KIO::FileUndoManager::Copy: statusBar->setText(i18nc("@info:status", "Successfully copied.")); break; case KIO::FileUndoManager::Move: statusBar->setText(i18nc("@info:status", "Successfully moved.")); break; case KIO::FileUndoManager::Link: statusBar->setText(i18nc("@info:status", "Successfully linked.")); break; case KIO::FileUndoManager::Trash: statusBar->setText(i18nc("@info:status", "Successfully moved to trash.")); break; case KIO::FileUndoManager::Rename: statusBar->setText(i18nc("@info:status", "Successfully renamed.")); break; case KIO::FileUndoManager::Mkdir: statusBar->setText(i18nc("@info:status", "Created folder.")); break; default: break; } } void DolphinMainWindow::pasteIntoFolder() { m_activeViewContainer->view()->pasteIntoFolder(); } void DolphinMainWindow::changeUrl(const QUrl &url) { if (!KProtocolManager::supportsListing(url)) { // The URL navigator only checks for validity, not // if the URL can be listed. An error message is // shown due to DolphinViewContainer::restoreView(). return; } m_activeViewContainer->setUrl(url); updateEditActions(); updatePasteAction(); updateViewActions(); updateGoActions(); emit urlChanged(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); } void DolphinMainWindow::slotEditableStateChanged(bool editable) { KToggleAction* editableLocationAction = static_cast(actionCollection()->action(QStringLiteral("editable_location"))); editableLocationAction->setChecked(editable); } void DolphinMainWindow::slotSelectionChanged(const KFileItemList& selection) { updateEditActions(); const int selectedUrlsCount = m_tabWidget->currentTabPage()->selectedItemsCount(); QAction* compareFilesAction = actionCollection()->action(QStringLiteral("compare_files")); if (selectedUrlsCount == 2) { compareFilesAction->setEnabled(isKompareInstalled()); } else { compareFilesAction->setEnabled(false); } emit selectionChanged(selection); } void DolphinMainWindow::updateHistory() { const KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator(); const int index = urlNavigator->historyIndex(); QAction* backAction = actionCollection()->action(KStandardAction::name(KStandardAction::Back)); if (backAction) { backAction->setToolTip(i18nc("@info", "Go back")); backAction->setEnabled(index < urlNavigator->historySize() - 1); } QAction* forwardAction = actionCollection()->action(KStandardAction::name(KStandardAction::Forward)); if (forwardAction) { forwardAction->setToolTip(i18nc("@info", "Go forward")); forwardAction->setEnabled(index > 0); } } void DolphinMainWindow::updateFilterBarAction(bool show) { QAction* showFilterBarAction = actionCollection()->action(QStringLiteral("show_filter_bar")); showFilterBarAction->setChecked(show); } void DolphinMainWindow::openNewMainWindow() { Dolphin::openNewWindow({m_activeViewContainer->url()}, this); } void DolphinMainWindow::openNewActivatedTab() { m_tabWidget->openNewActivatedTab(); } void DolphinMainWindow::openNewTab(const QUrl& url) { m_tabWidget->openNewTab(url); } void DolphinMainWindow::openInNewTab() { const KFileItemList& list = m_activeViewContainer->view()->selectedItems(); 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() { QUrl newWindowUrl; const KFileItemList list = m_activeViewContainer->view()->selectedItems(); if (list.isEmpty()) { newWindowUrl = m_activeViewContainer->url(); } else if (list.count() == 1) { const KFileItem& item = list.first(); newWindowUrl = DolphinView::openItemAsFolderUrl(item); } if (!newWindowUrl.isEmpty()) { Dolphin::openNewWindow({newWindowUrl}, this); } } void DolphinMainWindow::showTarget() { const auto link = m_activeViewContainer->view()->selectedItems().at(0); const auto linkLocationDir = QFileInfo(link.localPath()).absoluteDir(); auto linkDestination = link.linkDest(); if (QFileInfo(linkDestination).isRelative()) { linkDestination = linkLocationDir.filePath(linkDestination); } if (QFileInfo::exists(linkDestination)) { KIO::highlightInFileManager({QUrl::fromLocalFile(linkDestination).adjusted(QUrl::StripTrailingSlash)}); } else { m_activeViewContainer->showMessage(xi18nc("@info", "Could not access %1.", linkDestination), DolphinViewContainer::Warning); } } void DolphinMainWindow::showEvent(QShowEvent* event) { KXmlGuiWindow::showEvent(event); if (!event->spontaneous()) { m_activeViewContainer->view()->setFocus(); } } void DolphinMainWindow::closeEvent(QCloseEvent* event) { // Find out if Dolphin is closed directly by the user or // by the session manager because the session is closed bool closedByUser = true; if (qApp->isSavingSession()) { closedByUser = false; } if (m_tabWidget->count() > 1 && GeneralSettings::confirmClosingMultipleTabs() && closedByUser) { // Ask the user if he really wants to quit and close all tabs. // Open a confirmation dialog with 3 buttons: // QDialogButtonBox::Yes -> Quit // QDialogButtonBox::No -> Close only the current tab // QDialogButtonBox::Cancel -> do nothing QDialog *dialog = new QDialog(this, Qt::Dialog); dialog->setWindowTitle(i18nc("@title:window", "Confirmation")); dialog->setModal(true); QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Yes | QDialogButtonBox::No | QDialogButtonBox::Cancel); KGuiItem::assign(buttons->button(QDialogButtonBox::Yes), KGuiItem(i18nc("@action:button 'Quit Dolphin' button", "&Quit %1", QGuiApplication::applicationDisplayName()), QIcon::fromTheme(QStringLiteral("application-exit")))); KGuiItem::assign(buttons->button(QDialogButtonBox::No), KGuiItem(i18n("C&lose Current Tab"), QIcon::fromTheme(QStringLiteral("tab-close")))); KGuiItem::assign(buttons->button(QDialogButtonBox::Cancel), KStandardGuiItem::cancel()); buttons->button(QDialogButtonBox::Yes)->setDefault(true); bool doNotAskAgainCheckboxResult = false; const int result = KMessageBox::createKMessageBox(dialog, buttons, QMessageBox::Warning, i18n("You have multiple tabs open in this window, are you sure you want to quit?"), QStringList(), i18n("Do not ask again"), &doNotAskAgainCheckboxResult, KMessageBox::Notify); if (doNotAskAgainCheckboxResult) { GeneralSettings::setConfirmClosingMultipleTabs(false); } switch (result) { case QDialogButtonBox::Yes: // Quit break; case QDialogButtonBox::No: // Close only the current tab m_tabWidget->closeTab(); Q_FALLTHROUGH(); default: event->ignore(); return; } } GeneralSettings::setVersion(CurrentDolphinVersion); GeneralSettings::self()->save(); KXmlGuiWindow::closeEvent(event); } void DolphinMainWindow::saveProperties(KConfigGroup& group) { m_tabWidget->saveProperties(group); } void DolphinMainWindow::readProperties(const KConfigGroup& group) { m_tabWidget->readProperties(group); } void DolphinMainWindow::updateNewMenu() { m_newFileMenu->setViewShowsHiddenFiles(activeViewContainer()->view()->hiddenFilesShown()); m_newFileMenu->checkUpToDate(); m_newFileMenu->setPopupFiles(activeViewContainer()->url()); } void DolphinMainWindow::createDirectory() { m_newFileMenu->setViewShowsHiddenFiles(activeViewContainer()->view()->hiddenFilesShown()); m_newFileMenu->setPopupFiles(activeViewContainer()->url()); m_newFileMenu->createDirectory(); } void DolphinMainWindow::quit() { close(); } void DolphinMainWindow::showErrorMessage(const QString& message) { m_activeViewContainer->showMessage(message, DolphinViewContainer::Error); } void DolphinMainWindow::slotUndoAvailable(bool available) { QAction* undoAction = actionCollection()->action(KStandardAction::name(KStandardAction::Undo)); if (undoAction) { undoAction->setEnabled(available); } } void DolphinMainWindow::slotUndoTextChanged(const QString& text) { QAction* undoAction = actionCollection()->action(KStandardAction::name(KStandardAction::Undo)); if (undoAction) { undoAction->setText(text); } } void DolphinMainWindow::undo() { clearStatusBar(); KIO::FileUndoManager::self()->uiInterface()->setParentWidget(this); KIO::FileUndoManager::self()->undo(); } void DolphinMainWindow::cut() { m_activeViewContainer->view()->cutSelectedItems(); } void DolphinMainWindow::copy() { m_activeViewContainer->view()->copySelectedItems(); } void DolphinMainWindow::paste() { m_activeViewContainer->view()->paste(); } void DolphinMainWindow::find() { m_activeViewContainer->setSearchModeEnabled(true); } void DolphinMainWindow::updatePasteAction() { QAction* pasteAction = actionCollection()->action(KStandardAction::name(KStandardAction::Paste)); QPair pasteInfo = m_activeViewContainer->view()->pasteInfo(); pasteAction->setEnabled(pasteInfo.first); pasteAction->setText(pasteInfo.second); } void DolphinMainWindow::slotDirectoryLoadingCompleted() { updatePasteAction(); } void DolphinMainWindow::slotToolBarActionMiddleClicked(QAction *action) { if (action == actionCollection()->action(KStandardAction::name(KStandardAction::Back))) { goBackInNewTab(); } else if (action == actionCollection()->action(KStandardAction::name(KStandardAction::Forward))) { goForwardInNewTab(); } else if (action == actionCollection()->action(QStringLiteral("go_up"))) { goUpInNewTab(); } else if (action == actionCollection()->action(QStringLiteral("go_home"))) { goHomeInNewTab(); } } void DolphinMainWindow::selectAll() { clearStatusBar(); // if the URL navigator is editable and focused, select the whole // URL instead of all items of the view KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator(); QLineEdit* lineEdit = urlNavigator->editor()->lineEdit(); // krazy:exclude=qclasses const bool selectUrl = urlNavigator->isUrlEditable() && lineEdit->hasFocus(); if (selectUrl) { lineEdit->selectAll(); } else { m_activeViewContainer->view()->selectAll(); } } void DolphinMainWindow::invertSelection() { clearStatusBar(); m_activeViewContainer->view()->invertSelection(); } void DolphinMainWindow::toggleSplitView() { DolphinTabPage* tabPage = m_tabWidget->currentTabPage(); tabPage->setSplitViewEnabled(!tabPage->splitViewEnabled()); updateViewActions(); } void DolphinMainWindow::toggleSplitStash() { DolphinTabPage* tabPage = m_tabWidget->currentTabPage(); tabPage->setSplitViewEnabled(false); tabPage->setSplitViewEnabled(true, QUrl("stash:/")); } void DolphinMainWindow::reloadView() { clearStatusBar(); m_activeViewContainer->reload(); m_activeViewContainer->statusBar()->updateSpaceInfo(); } void DolphinMainWindow::stopLoading() { m_activeViewContainer->view()->stopLoading(); } void DolphinMainWindow::enableStopAction() { actionCollection()->action(QStringLiteral("stop"))->setEnabled(true); } void DolphinMainWindow::disableStopAction() { actionCollection()->action(QStringLiteral("stop"))->setEnabled(false); } void DolphinMainWindow::showFilterBar() { m_activeViewContainer->setFilterBarVisible(true); } void DolphinMainWindow::toggleEditLocation() { clearStatusBar(); QAction* action = actionCollection()->action(QStringLiteral("editable_location")); KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator(); urlNavigator->setUrlEditable(action->isChecked()); } void DolphinMainWindow::replaceLocation() { KUrlNavigator* navigator = m_activeViewContainer->urlNavigator(); navigator->setUrlEditable(true); navigator->setFocus(); // select the whole text of the combo box editor QLineEdit* lineEdit = navigator->editor()->lineEdit(); // krazy:exclude=qclasses lineEdit->selectAll(); } void DolphinMainWindow::togglePanelLockState() { const bool newLockState = !GeneralSettings::lockPanels(); foreach (QObject* child, children()) { DolphinDockWidget* dock = qobject_cast(child); if (dock) { dock->setLocked(newLockState); } } GeneralSettings::setLockPanels(newLockState); } void DolphinMainWindow::slotTerminalPanelVisibilityChanged() { if (m_terminalPanel->isHiddenInVisibleWindow()) { m_activeViewContainer->view()->setFocus(); } } void DolphinMainWindow::goBack() { KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator(); urlNavigator->goBack(); if (urlNavigator->locationState().isEmpty()) { // An empty location state indicates a redirection URL, // which must be skipped too urlNavigator->goBack(); } } void DolphinMainWindow::goForward() { m_activeViewContainer->urlNavigator()->goForward(); } void DolphinMainWindow::goUp() { m_activeViewContainer->urlNavigator()->goUp(); } void DolphinMainWindow::goHome() { m_activeViewContainer->urlNavigator()->goHome(); } void DolphinMainWindow::goBackInNewTab() { KUrlNavigator* urlNavigator = activeViewContainer()->urlNavigator(); const int index = urlNavigator->historyIndex() + 1; openNewTab(urlNavigator->locationUrl(index)); } void DolphinMainWindow::goForwardInNewTab() { KUrlNavigator* urlNavigator = activeViewContainer()->urlNavigator(); const int index = urlNavigator->historyIndex() - 1; openNewTab(urlNavigator->locationUrl(index)); } void DolphinMainWindow::goUpInNewTab() { const QUrl currentUrl = activeViewContainer()->urlNavigator()->locationUrl(); openNewTab(KIO::upUrl(currentUrl)); } void DolphinMainWindow::goHomeInNewTab() { openNewTab(Dolphin::homeUrl()); } void DolphinMainWindow::compareFiles() { const KFileItemList items = m_tabWidget->currentTabPage()->selectedItems(); if (items.count() != 2) { // The action is disabled in this case, but it could have been triggered // via D-Bus, see https://bugs.kde.org/show_bug.cgi?id=325517 return; } QUrl urlA = items.at(0).url(); QUrl urlB = items.at(1).url(); QString command(QStringLiteral("kompare -c \"")); command.append(urlA.toDisplayString(QUrl::PreferLocalFile)); command.append("\" \""); command.append(urlB.toDisplayString(QUrl::PreferLocalFile)); command.append('\"'); KRun::runCommand(command, QStringLiteral("Kompare"), QStringLiteral("kompare"), this); } void DolphinMainWindow::toggleShowMenuBar() { const bool visible = menuBar()->isVisible(); menuBar()->setVisible(!visible); if (visible) { createControlButton(); } else { deleteControlButton(); } } void DolphinMainWindow::openTerminal() { QString dir(QDir::homePath()); // If the given directory is not local, it can still be the URL of an // ioslave using UDS_LOCAL_PATH which to be converted first. KIO::StatJob* statJob = KIO::mostLocalUrl(m_activeViewContainer->url()); KJobWidgets::setWindow(statJob, this); statJob->exec(); QUrl url = statJob->mostLocalUrl(); //If the URL is local after the above conversion, set the directory. if (url.isLocalFile()) { dir = url.toLocalFile(); } KToolInvocation::invokeTerminal(QString(), dir); } void DolphinMainWindow::editSettings() { if (!m_settingsDialog) { DolphinViewContainer* container = activeViewContainer(); container->view()->writeSettings(); const QUrl url = container->url(); DolphinSettingsDialog* settingsDialog = new DolphinSettingsDialog(url, this); connect(settingsDialog, &DolphinSettingsDialog::settingsChanged, this, &DolphinMainWindow::refreshViews); settingsDialog->setAttribute(Qt::WA_DeleteOnClose); settingsDialog->show(); m_settingsDialog = settingsDialog; } else { m_settingsDialog.data()->raise(); } } void DolphinMainWindow::handleUrl(const QUrl& url) { delete m_lastHandleUrlStatJob; m_lastHandleUrlStatJob = nullptr; if (url.isLocalFile() && QFileInfo(url.toLocalFile()).isDir()) { activeViewContainer()->setUrl(url); } else if (KProtocolManager::supportsListing(url)) { // stat the URL to see if it is a dir or not m_lastHandleUrlStatJob = KIO::stat(url, KIO::HideProgressInfo); if (m_lastHandleUrlStatJob->uiDelegate()) { KJobWidgets::setWindow(m_lastHandleUrlStatJob, this); } connect(m_lastHandleUrlStatJob, &KIO::Job::result, this, &DolphinMainWindow::slotHandleUrlStatFinished); } else { new KRun(url, this); // Automatically deletes itself after being finished } } void DolphinMainWindow::slotHandleUrlStatFinished(KJob* job) { m_lastHandleUrlStatJob = nullptr; const KIO::UDSEntry entry = static_cast(job)->statResult(); const QUrl url = static_cast(job)->url(); if (entry.isDir()) { activeViewContainer()->setUrl(url); } else { new KRun(url, this); // Automatically deletes itself after being finished } } void DolphinMainWindow::slotWriteStateChanged(bool isFolderWritable) { // trash:/ is writable but we don't want to create new items in it. // TODO: remove the trash check once https://phabricator.kde.org/T8234 is implemented newFileMenu()->setEnabled(isFolderWritable && m_activeViewContainer->url().scheme() != QLatin1String("trash")); } void DolphinMainWindow::openContextMenu(const QPoint& pos, const KFileItem& item, const QUrl& url, const QList& customActions) { QPointer contextMenu = new DolphinContextMenu(this, pos, item, url); contextMenu.data()->setCustomActions(customActions); const DolphinContextMenu::Command command = contextMenu.data()->open(); switch (command) { case DolphinContextMenu::OpenParentFolder: changeUrl(KIO::upUrl(item.url())); m_activeViewContainer->view()->markUrlsAsSelected({item.url()}); m_activeViewContainer->view()->markUrlAsCurrent(item.url()); break; case DolphinContextMenu::OpenParentFolderInNewWindow: Dolphin::openNewWindow({item.url()}, this, Dolphin::OpenNewWindowFlag::Select); break; case DolphinContextMenu::OpenParentFolderInNewTab: openNewTab(KIO::upUrl(item.url())); break; case DolphinContextMenu::None: default: break; } // Delete the menu, unless it has been deleted in its own nested event loop already. if (contextMenu) { contextMenu->deleteLater(); } } void DolphinMainWindow::updateControlMenu() { 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(); // Add "Create New" menu menu->addMenu(m_newFileMenu->menu()); menu->addSeparator(); // Add "Edit" actions bool added = addActionToMenu(ac->action(KStandardAction::name(KStandardAction::Undo)), menu) | addActionToMenu(ac->action(KStandardAction::name(KStandardAction::Find)), menu) | addActionToMenu(ac->action(KStandardAction::name(KStandardAction::SelectAll)), menu) | addActionToMenu(ac->action(QStringLiteral("invert_selection")), menu); if (added) { menu->addSeparator(); } // Add "View" actions if (!GeneralSettings::showZoomSlider()) { addActionToMenu(ac->action(KStandardAction::name(KStandardAction::ZoomIn)), menu); addActionToMenu(ac->action(KStandardAction::name(KStandardAction::ZoomOut)), menu); menu->addSeparator(); } added = addActionToMenu(ac->action(QStringLiteral("sort")), menu) | addActionToMenu(ac->action(QStringLiteral("view_mode")), menu) | addActionToMenu(ac->action(QStringLiteral("additional_info")), menu) | addActionToMenu(ac->action(QStringLiteral("show_preview")), menu) | addActionToMenu(ac->action(QStringLiteral("show_in_groups")), menu) | addActionToMenu(ac->action(QStringLiteral("show_hidden_files")), menu); if (added) { menu->addSeparator(); } added = addActionToMenu(ac->action(QStringLiteral("split_view")), menu) | addActionToMenu(ac->action(KStandardAction::name(KStandardAction::Redisplay)), menu) | addActionToMenu(ac->action(QStringLiteral("view_properties")), menu); if (added) { menu->addSeparator(); } addActionToMenu(ac->action(QStringLiteral("panels")), menu); QMenu* locationBarMenu = new QMenu(i18nc("@action:inmenu", "Location Bar"), menu); locationBarMenu->addAction(ac->action(QStringLiteral("editable_location"))); locationBarMenu->addAction(ac->action(QStringLiteral("replace_location"))); menu->addMenu(locationBarMenu); menu->addSeparator(); // Add "Go" menu QMenu* goMenu = new QMenu(i18nc("@action:inmenu", "Go"), menu); goMenu->addAction(ac->action(KStandardAction::name(KStandardAction::Back))); goMenu->addAction(ac->action(KStandardAction::name(KStandardAction::Forward))); goMenu->addAction(ac->action(KStandardAction::name(KStandardAction::Up))); goMenu->addAction(ac->action(KStandardAction::name(KStandardAction::Home))); goMenu->addAction(ac->action(QStringLiteral("closed_tabs"))); menu->addMenu(goMenu); // Add "Tool" menu QMenu* toolsMenu = new QMenu(i18nc("@action:inmenu", "Tools"), menu); toolsMenu->addAction(ac->action(QStringLiteral("show_filter_bar"))); toolsMenu->addAction(ac->action(QStringLiteral("compare_files"))); toolsMenu->addAction(ac->action(QStringLiteral("open_terminal"))); toolsMenu->addAction(ac->action(QStringLiteral("change_remote_encoding"))); menu->addMenu(toolsMenu); // 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); // Add "Help" menu auto helpMenu = new KHelpMenu(menu); menu->addMenu(helpMenu->menu()); menu->addSeparator(); addActionToMenu(ac->action(KStandardAction::name(KStandardAction::ShowMenubar)), menu); } void DolphinMainWindow::updateToolBar() { if (!menuBar()->isVisible()) { createControlButton(); } } void DolphinMainWindow::slotControlButtonDeleted() { m_controlButton = nullptr; m_updateToolBarTimer->start(); } void DolphinMainWindow::slotPlaceActivated(const QUrl& url) { DolphinViewContainer* view = activeViewContainer(); if (view->url() == 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(); } else { changeUrl(url); } } void DolphinMainWindow::closedTabsCountChanged(unsigned int count) { actionCollection()->action(QStringLiteral("undo_close_tab"))->setEnabled(count > 0); } void DolphinMainWindow::activeViewChanged(DolphinViewContainer* viewContainer) { DolphinViewContainer* oldViewContainer = m_activeViewContainer; Q_ASSERT(viewContainer); m_activeViewContainer = viewContainer; if (oldViewContainer) { // Disconnect all signals between the old view container (container, // view and url navigator) and main window. oldViewContainer->disconnect(this); oldViewContainer->view()->disconnect(this); oldViewContainer->urlNavigator()->disconnect(this); } connectViewSignals(viewContainer); m_actionHandler->setCurrentView(viewContainer->view()); updateHistory(); updateEditActions(); updatePasteAction(); updateViewActions(); updateGoActions(); const QUrl url = viewContainer->url(); emit urlChanged(url); } void DolphinMainWindow::tabCountChanged(int count) { const bool enableTabActions = (count > 1); actionCollection()->action(KStandardAction::name(KStandardAction::Close))->setEnabled(enableTabActions); actionCollection()->action(QStringLiteral("activate_next_tab"))->setEnabled(enableTabActions); actionCollection()->action(QStringLiteral("activate_prev_tab"))->setEnabled(enableTabActions); } void DolphinMainWindow::updateWindowTitle() { setWindowTitle(m_activeViewContainer->caption()); } 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 m_newFileMenu = new DolphinNewFileMenu(actionCollection(), this); m_newFileMenu->setObjectName("newFileMenu"); 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"))); m_newFileMenu->setDelayed(false); connect(menu, &QMenu::aboutToShow, this, &DolphinMainWindow::updateNewMenu); QAction* newWindow = KStandardAction::openNew(this, &DolphinMainWindow::openNewMainWindow, actionCollection()); newWindow->setText(i18nc("@action:inmenu File", "New &Window")); QAction* newTab = actionCollection()->addAction(QStringLiteral("new_tab")); newTab->setIcon(QIcon::fromTheme(QStringLiteral("tab-new"))); newTab->setText(i18nc("@action:inmenu File", "New Tab")); actionCollection()->setDefaultShortcuts(newTab, {Qt::CTRL + Qt::Key_T, Qt::CTRL + Qt::SHIFT + Qt::Key_N}); connect(newTab, &QAction::triggered, this, static_cast(&DolphinMainWindow::openNewActivatedTab)); QAction* closeTab = KStandardAction::close( m_tabWidget, static_cast(&DolphinTabWidget::closeTab), actionCollection()); closeTab->setText(i18nc("@action:inmenu File", "Close Tab")); closeTab->setEnabled(false); KStandardAction::quit(this, &DolphinMainWindow::quit, actionCollection()); // setup 'Edit' menu KStandardAction::undo(this, &DolphinMainWindow::undo, 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, &DolphinMainWindow::find, actionCollection()); KStandardAction::selectAll(this, &DolphinMainWindow::selectAll, actionCollection()); QAction* invertSelection = actionCollection()->addAction(QStringLiteral("invert_selection")); invertSelection->setText(i18nc("@action:inmenu Edit", "Invert Selection")); invertSelection->setIcon(QIcon::fromTheme(QStringLiteral("edit-select-invert"))); actionCollection()->setDefaultShortcut(invertSelection, Qt::CTRL + Qt::SHIFT + Qt::Key_A); connect(invertSelection, &QAction::triggered, this, &DolphinMainWindow::invertSelection); // setup 'View' menu // (note that most of it is set up in DolphinViewActionHandler) QAction* split = actionCollection()->addAction(QStringLiteral("split_view")); actionCollection()->setDefaultShortcut(split, Qt::Key_F3); connect(split, &QAction::triggered, this, &DolphinMainWindow::toggleSplitView); QAction* stashSplit = actionCollection()->addAction(QStringLiteral("split_stash")); 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")); connect(stashSplit, &QAction::triggered, this, &DolphinMainWindow::toggleSplitStash); KStandardAction::redisplay(this, &DolphinMainWindow::reloadView, actionCollection()); QAction* stop = actionCollection()->addAction(QStringLiteral("stop")); stop->setText(i18nc("@action:inmenu View", "Stop")); stop->setToolTip(i18nc("@info", "Stop loading")); stop->setIcon(QIcon::fromTheme(QStringLiteral("process-stop"))); connect(stop, &QAction::triggered, this, &DolphinMainWindow::stopLoading); KToggleAction* editableLocation = actionCollection()->add(QStringLiteral("editable_location")); editableLocation->setText(i18nc("@action:inmenu Navigation Bar", "Editable Location")); actionCollection()->setDefaultShortcut(editableLocation, Qt::Key_F6); connect(editableLocation, &KToggleAction::triggered, this, &DolphinMainWindow::toggleEditLocation); QAction* replaceLocation = actionCollection()->addAction(QStringLiteral("replace_location")); replaceLocation->setText(i18nc("@action:inmenu Navigation Bar", "Replace Location")); actionCollection()->setDefaultShortcut(replaceLocation, Qt::CTRL + Qt::Key_L); connect(replaceLocation, &QAction::triggered, this, &DolphinMainWindow::replaceLocation); // setup 'Go' menu QAction* backAction = KStandardAction::back(this, &DolphinMainWindow::goBack, actionCollection()); auto backShortcuts = backAction->shortcuts(); backShortcuts.append(QKeySequence(Qt::Key_Backspace)); actionCollection()->setDefaultShortcuts(backAction, backShortcuts); DolphinRecentTabsMenu* recentTabsMenu = new DolphinRecentTabsMenu(this); actionCollection()->addAction(QStringLiteral("closed_tabs"), recentTabsMenu); connect(m_tabWidget, &DolphinTabWidget::rememberClosedTab, recentTabsMenu, &DolphinRecentTabsMenu::rememberClosedTab); connect(recentTabsMenu, &DolphinRecentTabsMenu::restoreClosedTab, m_tabWidget, &DolphinTabWidget::restoreClosedTab); connect(recentTabsMenu, &DolphinRecentTabsMenu::closedTabsCountChanged, this, &DolphinMainWindow::closedTabsCountChanged); QAction* undoCloseTab = actionCollection()->addAction(QStringLiteral("undo_close_tab")); undoCloseTab->setText(i18nc("@action:inmenu File", "Undo close tab")); 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); auto undoAction = actionCollection()->action(KStandardAction::name(KStandardAction::Undo)); undoAction->setEnabled(false); // undo should be disabled by default KStandardAction::forward(this, &DolphinMainWindow::goForward, actionCollection()); KStandardAction::up(this, &DolphinMainWindow::goUp, actionCollection()); KStandardAction::home(this, &DolphinMainWindow::goHome, actionCollection()); // setup 'Tools' menu 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()->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"))); compareFiles->setEnabled(false); connect(compareFiles, &QAction::triggered, this, &DolphinMainWindow::compareFiles); #ifndef Q_OS_WIN if (KAuthorized::authorize(QStringLiteral("shell_access"))) { QAction* openTerminal = actionCollection()->addAction(QStringLiteral("open_terminal")); openTerminal->setText(i18nc("@action:inmenu Tools", "Open Terminal")); openTerminal->setIcon(QIcon::fromTheme(QStringLiteral("utilities-terminal"))); actionCollection()->setDefaultShortcut(openTerminal, Qt::SHIFT + Qt::Key_F4); connect(openTerminal, &QAction::triggered, this, &DolphinMainWindow::openTerminal); } #endif // setup 'Settings' menu KToggleAction* showMenuBar = KStandardAction::showMenubar(nullptr, nullptr, actionCollection()); connect(showMenuBar, &KToggleAction::triggered, // Fixes #286822 this, &DolphinMainWindow::toggleShowMenuBar, Qt::QueuedConnection); KStandardAction::preferences(this, &DolphinMainWindow::editSettings, actionCollection()); // not in menu actions QList nextTabKeys = KStandardShortcut::tabNext(); nextTabKeys.append(QKeySequence(Qt::CTRL + Qt::Key_Tab)); QList prevTabKeys = KStandardShortcut::tabPrev(); prevTabKeys.append(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Tab)); QAction* activateNextTab = actionCollection()->addAction(QStringLiteral("activate_next_tab")); activateNextTab->setIconText(i18nc("@action:inmenu", "Next Tab")); activateNextTab->setText(i18nc("@action:inmenu", "Activate Next Tab")); activateNextTab->setEnabled(false); connect(activateNextTab, &QAction::triggered, m_tabWidget, &DolphinTabWidget::activateNextTab); actionCollection()->setDefaultShortcuts(activateNextTab, nextTabKeys); QAction* activatePrevTab = actionCollection()->addAction(QStringLiteral("activate_prev_tab")); activatePrevTab->setIconText(i18nc("@action:inmenu", "Previous Tab")); activatePrevTab->setText(i18nc("@action:inmenu", "Activate Previous Tab")); activatePrevTab->setEnabled(false); connect(activatePrevTab, &QAction::triggered, m_tabWidget, &DolphinTabWidget::activatePrevTab); actionCollection()->setDefaultShortcuts(activatePrevTab, prevTabKeys); // for context menu QAction* showTarget = actionCollection()->addAction(QStringLiteral("show_target")); showTarget->setText(i18nc("@action:inmenu", "Show Target")); showTarget->setIcon(QIcon::fromTheme(QStringLiteral("document-open-folder"))); showTarget->setEnabled(false); connect(showTarget, &QAction::triggered, this, &DolphinMainWindow::showTarget); QAction* openInNewTab = actionCollection()->addAction(QStringLiteral("open_in_new_tab")); openInNewTab->setText(i18nc("@action:inmenu", "Open in New Tab")); openInNewTab->setIcon(QIcon::fromTheme(QStringLiteral("tab-new"))); connect(openInNewTab, &QAction::triggered, this, &DolphinMainWindow::openInNewTab); QAction* openInNewTabs = actionCollection()->addAction(QStringLiteral("open_in_new_tabs")); openInNewTabs->setText(i18nc("@action:inmenu", "Open in New Tabs")); openInNewTabs->setIcon(QIcon::fromTheme(QStringLiteral("tab-new"))); connect(openInNewTabs, &QAction::triggered, this, &DolphinMainWindow::openInNewTab); QAction* openInNewWindow = actionCollection()->addAction(QStringLiteral("open_in_new_window")); openInNewWindow->setText(i18nc("@action:inmenu", "Open in New Window")); openInNewWindow->setIcon(QIcon::fromTheme(QStringLiteral("window-new"))); connect(openInNewWindow, &QAction::triggered, this, &DolphinMainWindow::openInNewWindow); } void DolphinMainWindow::setupDockWidgets() { const bool lock = GeneralSettings::lockPanels(); KDualAction* lockLayoutAction = actionCollection()->add(QStringLiteral("lock_panels")); lockLayoutAction->setActiveText(i18nc("@action:inmenu Panels", "Unlock Panels")); lockLayoutAction->setActiveIcon(QIcon::fromTheme(QStringLiteral("object-unlocked"))); lockLayoutAction->setInactiveText(i18nc("@action:inmenu Panels", "Lock Panels")); lockLayoutAction->setInactiveIcon(QIcon::fromTheme(QStringLiteral("object-locked"))); lockLayoutAction->setActive(lock); connect(lockLayoutAction, &KDualAction::triggered, this, &DolphinMainWindow::togglePanelLockState); // Setup "Information" DolphinDockWidget* infoDock = new DolphinDockWidget(i18nc("@title:window", "Information")); infoDock->setLocked(lock); infoDock->setObjectName(QStringLiteral("infoDock")); infoDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); #ifdef HAVE_BALOO InformationPanel* infoPanel = new InformationPanel(infoDock); infoPanel->setCustomContextMenuActions({lockLayoutAction}); connect(infoPanel, &InformationPanel::urlActivated, this, &DolphinMainWindow::handleUrl); infoDock->setWidget(infoPanel); QAction* infoAction = infoDock->toggleViewAction(); createPanelAction(QIcon::fromTheme(QStringLiteral("dialog-information")), Qt::Key_F11, infoAction, QStringLiteral("show_information_panel")); addDockWidget(Qt::RightDockWidgetArea, infoDock); connect(this, &DolphinMainWindow::urlChanged, infoPanel, &InformationPanel::setUrl); connect(this, &DolphinMainWindow::selectionChanged, infoPanel, &InformationPanel::setSelection); connect(this, &DolphinMainWindow::requestItemInfo, infoPanel, &InformationPanel::requestDelayedItemInfo); #endif // Setup "Folders" DolphinDockWidget* foldersDock = new DolphinDockWidget(i18nc("@title:window", "Folders")); foldersDock->setLocked(lock); foldersDock->setObjectName(QStringLiteral("foldersDock")); foldersDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); FoldersPanel* foldersPanel = new FoldersPanel(foldersDock); foldersPanel->setCustomContextMenuActions({lockLayoutAction}); foldersDock->setWidget(foldersPanel); QAction* foldersAction = foldersDock->toggleViewAction(); createPanelAction(QIcon::fromTheme(QStringLiteral("folder")), Qt::Key_F7, foldersAction, QStringLiteral("show_folders_panel")); addDockWidget(Qt::LeftDockWidgetArea, foldersDock); connect(this, &DolphinMainWindow::urlChanged, foldersPanel, &FoldersPanel::setUrl); connect(foldersPanel, &FoldersPanel::folderActivated, this, &DolphinMainWindow::changeUrl); connect(foldersPanel, &FoldersPanel::folderMiddleClicked, this, &DolphinMainWindow::openNewTab); connect(foldersPanel, &FoldersPanel::errorMessage, this, &DolphinMainWindow::showErrorMessage); // Setup "Terminal" #ifndef Q_OS_WIN if (KAuthorized::authorize(QStringLiteral("shell_access"))) { DolphinDockWidget* terminalDock = new DolphinDockWidget(i18nc("@title:window Shell terminal", "Terminal")); terminalDock->setLocked(lock); terminalDock->setObjectName(QStringLiteral("terminalDock")); m_terminalPanel = new TerminalPanel(terminalDock); m_terminalPanel->setCustomContextMenuActions({lockLayoutAction}); terminalDock->setWidget(m_terminalPanel); connect(m_terminalPanel, &TerminalPanel::hideTerminalPanel, terminalDock, &DolphinDockWidget::hide); connect(m_terminalPanel, &TerminalPanel::changeUrl, this, &DolphinMainWindow::slotTerminalDirectoryChanged); connect(terminalDock, &DolphinDockWidget::visibilityChanged, m_terminalPanel, &TerminalPanel::dockVisibilityChanged); connect(terminalDock, &DolphinDockWidget::visibilityChanged, this, &DolphinMainWindow::slotTerminalPanelVisibilityChanged); 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, m_terminalPanel, &TerminalPanel::setUrl); if (GeneralSettings::version() < 200) { terminalDock->hide(); } } #endif if (GeneralSettings::version() < 200) { infoDock->hide(); foldersDock->hide(); } // Setup "Places" DolphinDockWidget* placesDock = new DolphinDockWidget(i18nc("@title:window", "Places")); placesDock->setLocked(lock); placesDock->setObjectName(QStringLiteral("placesDock")); placesDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); m_placesPanel = new PlacesPanel(placesDock); m_placesPanel->setCustomContextMenuActions({lockLayoutAction}); placesDock->setWidget(m_placesPanel); QAction *placesAction = placesDock->toggleViewAction(); createPanelAction(QIcon::fromTheme(QStringLiteral("bookmarks")), 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::openNewTab); connect(m_placesPanel, &PlacesPanel::errorMessage, this, &DolphinMainWindow::showErrorMessage); connect(this, &DolphinMainWindow::urlChanged, m_placesPanel, &PlacesPanel::setUrl); connect(placesDock, &DolphinDockWidget::visibilityChanged, m_tabWidget, &DolphinTabWidget::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); m_tabWidget->slotPlacesPanelVisibilityChanged(m_placesPanel->isVisible()); // Add actions into the "Panels" menu KActionMenu* panelsMenu = new KActionMenu(i18nc("@action:inmenu View", "Panels"), this); actionCollection()->addAction(QStringLiteral("panels"), panelsMenu); panelsMenu->setDelayed(false); const KActionCollection* ac = actionCollection(); panelsMenu->addAction(ac->action(QStringLiteral("show_places_panel"))); #ifdef HAVE_BALOO panelsMenu->addAction(ac->action(QStringLiteral("show_information_panel"))); #endif panelsMenu->addAction(ac->action(QStringLiteral("show_folders_panel"))); panelsMenu->addAction(ac->action(QStringLiteral("show_terminal_panel"))); panelsMenu->addSeparator(); panelsMenu->addAction(lockLayoutAction); } void DolphinMainWindow::updateEditActions() { const KFileItemList list = m_activeViewContainer->view()->selectedItems(); if (list.isEmpty()) { stateChanged(QStringLiteral("has_no_selection")); } else { stateChanged(QStringLiteral("has_selection")); KActionCollection* col = actionCollection(); 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 QAction* showTarget = col->action(QStringLiteral("show_target")); KFileItemListProperties capabilities(list); const bool enableMoveToTrash = capabilities.isLocal() && capabilities.supportsMoving(); renameAction->setEnabled(capabilities.supportsMoving()); moveToTrashAction->setEnabled(enableMoveToTrash); deleteAction->setEnabled(capabilities.supportsDeleting()); deleteWithTrashShortcut->setEnabled(capabilities.supportsDeleting() && !enableMoveToTrash); cutAction->setEnabled(capabilities.supportsMoving()); showTarget->setEnabled(list.length() == 1 && list.at(0).isLink()); } } void DolphinMainWindow::updateViewActions() { m_actionHandler->updateViewActions(); QAction* showFilterBarAction = actionCollection()->action(QStringLiteral("show_filter_bar")); showFilterBarAction->setChecked(m_activeViewContainer->isFilterBarVisible()); updateSplitAction(); QAction* editableLocactionAction = actionCollection()->action(QStringLiteral("editable_location")); const KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator(); editableLocactionAction->setChecked(urlNavigator->isUrlEditable()); } void DolphinMainWindow::updateGoActions() { QAction* goUpAction = actionCollection()->action(KStandardAction::name(KStandardAction::Up)); const QUrl currentUrl = m_activeViewContainer->url(); goUpAction->setEnabled(KIO::upUrl(currentUrl) != currentUrl); } void DolphinMainWindow::createControlButton() { if (m_controlButton) { return; } Q_ASSERT(!m_controlButton); m_controlButton = new QToolButton(this); m_controlButton->setIcon(QIcon::fromTheme(QStringLiteral("application-menu"))); m_controlButton->setText(i18nc("@action", "Control")); m_controlButton->setPopupMode(QToolButton::InstantPopup); m_controlButton->setToolButtonStyle(toolBar()->toolButtonStyle()); QMenu* controlMenu = new QMenu(m_controlButton); connect(controlMenu, &QMenu::aboutToShow, this, &DolphinMainWindow::updateControlMenu); m_controlButton->setMenu(controlMenu); toolBar()->addWidget(m_controlButton); connect(toolBar(), &KToolBar::iconSizeChanged, m_controlButton, &QToolButton::setIconSize); connect(toolBar(), &KToolBar::toolButtonStyleChanged, m_controlButton, &QToolButton::setToolButtonStyle); // 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(); foreach (const QWidget* widget, action->associatedWidgets()) { if (widget == toolBarWidget) { return false; } } menu->addAction(action); return true; } void DolphinMainWindow::refreshViews() { m_tabWidget->refreshViews(); if (GeneralSettings::modifiedStartupSettings()) { // 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); updateSplitAction(); updateWindowTitle(); } emit settingsChanged(); } void DolphinMainWindow::clearStatusBar() { m_activeViewContainer->statusBar()->resetToDefaultText(); } void DolphinMainWindow::connectViewSignals(DolphinViewContainer* container) { connect(container, &DolphinViewContainer::showFilterBarChanged, this, &DolphinMainWindow::updateFilterBarAction); connect(container, &DolphinViewContainer::writeStateChanged, this, &DolphinMainWindow::slotWriteStateChanged); const DolphinView* view = container->view(); connect(view, &DolphinView::selectionChanged, this, &DolphinMainWindow::slotSelectionChanged); connect(view, &DolphinView::requestItemInfo, this, &DolphinMainWindow::requestItemInfo); connect(view, &DolphinView::tabRequested, this, &DolphinMainWindow::openNewTab); connect(view, &DolphinView::requestContextMenu, this, &DolphinMainWindow::openContextMenu); connect(view, &DolphinView::directoryLoadingStarted, this, &DolphinMainWindow::enableStopAction); connect(view, &DolphinView::directoryLoadingCompleted, this, &DolphinMainWindow::disableStopAction); connect(view, &DolphinView::directoryLoadingCompleted, this, &DolphinMainWindow::slotDirectoryLoadingCompleted); connect(view, &DolphinView::goBackRequested, this, static_cast(&DolphinMainWindow::goBack)); connect(view, &DolphinView::goForwardRequested, this, static_cast(&DolphinMainWindow::goForward)); connect(view, &DolphinView::urlActivated, this, &DolphinMainWindow::handleUrl); const KUrlNavigator* navigator = container->urlNavigator(); connect(navigator, &KUrlNavigator::urlChanged, this, &DolphinMainWindow::changeUrl); connect(navigator, &KUrlNavigator::historyChanged, this, &DolphinMainWindow::updateHistory); connect(navigator, &KUrlNavigator::editableStateChanged, this, &DolphinMainWindow::slotEditableStateChanged); connect(navigator, &KUrlNavigator::tabRequested, this, &DolphinMainWindow::openNewTab); } void DolphinMainWindow::updateSplitAction() { QAction* splitAction = actionCollection()->action(QStringLiteral("split_view")); const DolphinTabPage* tabPage = m_tabWidget->currentTabPage(); if (tabPage->splitViewEnabled()) { if (tabPage->primaryViewActive()) { splitAction->setText(i18nc("@action:intoolbar Close left view", "Close")); splitAction->setToolTip(i18nc("@info", "Close left view")); splitAction->setIcon(QIcon::fromTheme(QStringLiteral("view-left-close"))); } else { splitAction->setText(i18nc("@action:intoolbar Close right view", "Close")); splitAction->setToolTip(i18nc("@info", "Close right view")); splitAction->setIcon(QIcon::fromTheme(QStringLiteral("view-right-close"))); } } else { splitAction->setText(i18nc("@action:intoolbar Split view", "Split")); splitAction->setToolTip(i18nc("@info", "Split view")); splitAction->setIcon(QIcon::fromTheme(QStringLiteral("view-right-new"))); } } bool DolphinMainWindow::isKompareInstalled() const { static bool initialized = false; static bool installed = false; if (!initialized) { // TODO: maybe replace this approach later by using a menu // plugin like kdiff3plugin.cpp installed = !QStandardPaths::findExecutable(QStringLiteral("kompare")).isEmpty(); initialized = true; } return installed; } void DolphinMainWindow::createPanelAction(const QIcon& icon, const QKeySequence& shortcut, QAction* dockAction, const QString& actionName) { QAction* panelAction = actionCollection()->addAction(actionName); panelAction->setCheckable(true); panelAction->setChecked(dockAction->isChecked()); panelAction->setText(dockAction->text()); panelAction->setIcon(icon); actionCollection()->setDefaultShortcut(panelAction, shortcut); connect(panelAction, &QAction::triggered, dockAction, &QAction::trigger); connect(dockAction, &QAction::toggled, panelAction, &QAction::setChecked); } DolphinMainWindow::UndoUiInterface::UndoUiInterface() : KIO::FileUndoManager::UiInterface() { } DolphinMainWindow::UndoUiInterface::~UndoUiInterface() { } void DolphinMainWindow::UndoUiInterface::jobError(KIO::Job* job) { DolphinMainWindow* mainWin= qobject_cast(parentWidget()); if (mainWin) { DolphinViewContainer* container = mainWin->activeViewContainer(); container->showMessage(job->errorString(), DolphinViewContainer::Error); } else { KIO::FileUndoManager::UiInterface::jobError(job); } } diff --git a/src/dolphinpart.cpp b/src/dolphinpart.cpp index 2e7f7639f..f5d4f95b6 100644 --- a/src/dolphinpart.cpp +++ b/src/dolphinpart.cpp @@ -1,614 +1,614 @@ /* This file is part of the KDE project Copyright (c) 2007 David Faure This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "dolphinpart.h" #include "dolphindebug.h" #include "dolphinnewfilemenu.h" #include "dolphinpart_ext.h" #include "dolphinremoveaction.h" #include "kitemviews/kfileitemmodel.h" #include "kitemviews/private/kfileitemmodeldirlister.h" #include "views/dolphinnewfilemenuobserver.h" #include "views/dolphinremoteencoding.h" #include "views/dolphinview.h" #include "views/dolphinviewactionhandler.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY(DolphinPartFactory, registerPlugin();) DolphinPart::DolphinPart(QWidget* parentWidget, QObject* parent, const QVariantList& args) : KParts::ReadOnlyPart(parent) ,m_openTerminalAction(nullptr) ,m_removeAction(nullptr) { Q_UNUSED(args) setComponentData(*createAboutData(), false); m_extension = new DolphinPartBrowserExtension(this); // make sure that other apps using this part find Dolphin's view-file-columns icons KIconLoader::global()->addAppDir(QStringLiteral("dolphin")); m_view = new DolphinView(QUrl(), parentWidget); m_view->setTabsForFilesEnabled(true); setWidget(m_view); connect(&DolphinNewFileMenuObserver::instance(), &DolphinNewFileMenuObserver::errorMessage, this, &DolphinPart::slotErrorMessage); connect(m_view, &DolphinView::directoryLoadingCompleted, this, static_cast(&DolphinPart::completed)); connect(m_view, &DolphinView::directoryLoadingCompleted, this, &DolphinPart::updatePasteAction); connect(m_view, &DolphinView::directoryLoadingProgress, this, &DolphinPart::updateProgress); connect(m_view, &DolphinView::errorMessage, this, &DolphinPart::slotErrorMessage); setXMLFile(QStringLiteral("dolphinpart.rc")); connect(m_view, &DolphinView::infoMessage, this, &DolphinPart::slotMessage); connect(m_view, &DolphinView::operationCompletedMessage, this, &DolphinPart::slotMessage); connect(m_view, &DolphinView::errorMessage, this, &DolphinPart::slotErrorMessage); connect(m_view, &DolphinView::itemActivated, this, &DolphinPart::slotItemActivated); connect(m_view, &DolphinView::itemsActivated, this, &DolphinPart::slotItemsActivated); connect(m_view, &DolphinView::tabRequested, this, &DolphinPart::createNewWindow); connect(m_view, &DolphinView::requestContextMenu, this, &DolphinPart::slotOpenContextMenu); connect(m_view, &DolphinView::selectionChanged, m_extension, static_cast(&DolphinPartBrowserExtension::selectionInfo)); connect(m_view, &DolphinView::selectionChanged, this, &DolphinPart::slotSelectionChanged); connect(m_view, &DolphinView::requestItemInfo, this, &DolphinPart::slotRequestItemInfo); connect(m_view, &DolphinView::modeChanged, this, &DolphinPart::viewModeChanged); // relay signal connect(m_view, &DolphinView::redirection, this, &DolphinPart::slotDirectoryRedirection); // Watch for changes that should result in updates to the // status bar text. connect(m_view, &DolphinView::itemCountChanged, this, &DolphinPart::updateStatusBar); connect(m_view, &DolphinView::selectionChanged, this, &DolphinPart::updateStatusBar); m_actionHandler = new DolphinViewActionHandler(actionCollection(), this); m_actionHandler->setCurrentView(m_view); - connect(m_actionHandler, &DolphinViewActionHandler::createDirectory, this, &DolphinPart::createDirectory); + connect(m_actionHandler, &DolphinViewActionHandler::createDirectoryTriggered, this, &DolphinPart::createDirectory); m_remoteEncoding = new DolphinRemoteEncoding(this, m_actionHandler); connect(this, &DolphinPart::aboutToOpenURL, m_remoteEncoding, &DolphinRemoteEncoding::slotAboutToOpenUrl); QClipboard* clipboard = QApplication::clipboard(); connect(clipboard, &QClipboard::dataChanged, this, &DolphinPart::updatePasteAction); // Create file info and listing filter extensions. // NOTE: Listing filter needs to be instantiated after the creation of the view. new DolphinPartFileInfoExtension(this); new DolphinPartListingFilterExtension(this); KDirLister* lister = m_view->m_model->m_dirLister; if (lister) { DolphinPartListingNotificationExtension* notifyExt = new DolphinPartListingNotificationExtension(this); connect(lister, &KDirLister::newItems, notifyExt, &DolphinPartListingNotificationExtension::slotNewItems); connect(lister, &KDirLister::itemsDeleted, notifyExt, &DolphinPartListingNotificationExtension::slotItemsDeleted); } else { qCWarning(DolphinDebug) << "NULL KDirLister object! KParts::ListingNotificationExtension will NOT be supported"; } createActions(); m_actionHandler->updateViewActions(); slotSelectionChanged(KFileItemList()); // initially disable selection-dependent actions // Listen to events from the app so we can update the remove key by // checking for a Shift key press. qApp->installEventFilter(this); // TODO there was a "always open a new window" (when clicking on a directory) setting in konqueror // (sort of spacial navigation) loadPlugins(this, this, componentData()); } DolphinPart::~DolphinPart() { } void DolphinPart::createActions() { // Edit menu m_newFileMenu = new DolphinNewFileMenu(actionCollection(), this); m_newFileMenu->setParentWidget(widget()); connect(m_newFileMenu->menu(), &QMenu::aboutToShow, this, &DolphinPart::updateNewMenu); QAction *editMimeTypeAction = actionCollection()->addAction( QStringLiteral("editMimeType") ); editMimeTypeAction->setText( i18nc("@action:inmenu Edit", "&Edit File Type..." ) ); connect(editMimeTypeAction, &QAction::triggered, this, &DolphinPart::slotEditMimeType); QAction* selectItemsMatching = actionCollection()->addAction(QStringLiteral("select_items_matching")); selectItemsMatching->setText(i18nc("@action:inmenu Edit", "Select Items Matching...")); actionCollection()->setDefaultShortcut(selectItemsMatching, Qt::CTRL + Qt::Key_S); connect(selectItemsMatching, &QAction::triggered, this, &DolphinPart::slotSelectItemsMatchingPattern); QAction* unselectItemsMatching = actionCollection()->addAction(QStringLiteral("unselect_items_matching")); unselectItemsMatching->setText(i18nc("@action:inmenu Edit", "Unselect Items Matching...")); connect(unselectItemsMatching, &QAction::triggered, this, &DolphinPart::slotUnselectItemsMatchingPattern); KStandardAction::selectAll(m_view, &DolphinView::selectAll, actionCollection()); QAction* unselectAll = actionCollection()->addAction(QStringLiteral("unselect_all")); unselectAll->setText(i18nc("@action:inmenu Edit", "Unselect All")); connect(unselectAll, &QAction::triggered, m_view, &DolphinView::clearSelection); QAction* invertSelection = actionCollection()->addAction(QStringLiteral("invert_selection")); invertSelection->setText(i18nc("@action:inmenu Edit", "Invert Selection")); actionCollection()->setDefaultShortcut(invertSelection, Qt::CTRL + Qt::SHIFT + Qt::Key_A); connect(invertSelection, &QAction::triggered, m_view, &DolphinView::invertSelection); // View menu: all done by DolphinViewActionHandler // Go menu QActionGroup* goActionGroup = new QActionGroup(this); connect(goActionGroup, &QActionGroup::triggered, this, &DolphinPart::slotGoTriggered); createGoAction("go_applications", "start-here-kde", i18nc("@action:inmenu Go", "App&lications"), QStringLiteral("programs:/"), goActionGroup); createGoAction("go_network_folders", "folder-remote", i18nc("@action:inmenu Go", "&Network Folders"), QStringLiteral("remote:/"), goActionGroup); createGoAction("go_settings", "preferences-system", i18nc("@action:inmenu Go", "Sett&ings"), QStringLiteral("settings:/"), goActionGroup); createGoAction("go_trash", "user-trash", i18nc("@action:inmenu Go", "Trash"), QStringLiteral("trash:/"), goActionGroup); createGoAction("go_autostart", "", i18nc("@action:inmenu Go", "Autostart"), QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/autostart", goActionGroup); // Tools menu m_findFileAction = KStandardAction::find(this, &DolphinPart::slotFindFile, actionCollection()); m_findFileAction->setText(i18nc("@action:inmenu Tools", "Find File...")); #ifndef Q_OS_WIN if (KAuthorized::authorize(QStringLiteral("shell_access"))) { m_openTerminalAction = actionCollection()->addAction(QStringLiteral("open_terminal")); m_openTerminalAction->setIcon(QIcon::fromTheme(QStringLiteral("utilities-terminal"))); m_openTerminalAction->setText(i18nc("@action:inmenu Tools", "Open &Terminal")); connect(m_openTerminalAction, &QAction::triggered, this, &DolphinPart::slotOpenTerminal); actionCollection()->setDefaultShortcut(m_openTerminalAction, Qt::Key_F4); } #endif } void DolphinPart::createGoAction(const char* name, const char* iconName, const QString& text, const QString& url, QActionGroup* actionGroup) { QAction* action = actionCollection()->addAction(name); action->setIcon(QIcon::fromTheme(iconName)); action->setText(text); action->setData(url); action->setActionGroup(actionGroup); } void DolphinPart::slotGoTriggered(QAction* action) { const QString url = action->data().toString(); emit m_extension->openUrlRequest(QUrl(url)); } void DolphinPart::slotSelectionChanged(const KFileItemList& selection) { const bool hasSelection = !selection.isEmpty(); QAction* renameAction = actionCollection()->action(KStandardAction::name(KStandardAction::RenameFile)); QAction* moveToTrashAction = actionCollection()->action(KStandardAction::name(KStandardAction::MoveToTrash)); QAction* deleteAction = actionCollection()->action(KStandardAction::name(KStandardAction::DeleteFile)); QAction* editMimeTypeAction = actionCollection()->action(QStringLiteral("editMimeType")); QAction* propertiesAction = actionCollection()->action(QStringLiteral("properties")); QAction* deleteWithTrashShortcut = actionCollection()->action(QStringLiteral("delete_shortcut")); // see DolphinViewActionHandler if (!hasSelection) { stateChanged(QStringLiteral("has_no_selection")); emit m_extension->enableAction("cut", false); emit m_extension->enableAction("copy", false); deleteWithTrashShortcut->setEnabled(false); editMimeTypeAction->setEnabled(false); } else { stateChanged(QStringLiteral("has_selection")); // TODO share this code with DolphinMainWindow::updateEditActions (and the desktop code) // in libkonq KFileItemListProperties capabilities(selection); const bool enableMoveToTrash = capabilities.isLocal() && capabilities.supportsMoving(); renameAction->setEnabled(capabilities.supportsMoving()); moveToTrashAction->setEnabled(enableMoveToTrash); deleteAction->setEnabled(capabilities.supportsDeleting()); deleteWithTrashShortcut->setEnabled(capabilities.supportsDeleting() && !enableMoveToTrash); editMimeTypeAction->setEnabled(true); propertiesAction->setEnabled(true); emit m_extension->enableAction("cut", capabilities.supportsMoving()); emit m_extension->enableAction("copy", true); } } void DolphinPart::updatePasteAction() { QPair pasteInfo = m_view->pasteInfo(); emit m_extension->enableAction( "paste", pasteInfo.first ); emit m_extension->setActionText( "paste", pasteInfo.second ); } KAboutData* DolphinPart::createAboutData() { return new KAboutData(QStringLiteral("dolphinpart"), i18nc("@title", "Dolphin Part"), QStringLiteral("0.1")); } bool DolphinPart::openUrl(const QUrl &url) { bool reload = arguments().reload(); // A bit of a workaround so that changing the namefilter works: force reload. // Otherwise DolphinView wouldn't relist the URL, so nothing would happen. if (m_nameFilter != m_view->nameFilter()) reload = true; if (m_view->url() == url && !reload) { // DolphinView won't do anything in that case, so don't emit started return true; } setUrl(url); // remember it at the KParts level QUrl visibleUrl(url); if (!m_nameFilter.isEmpty()) { visibleUrl.setPath(visibleUrl.path() + '/' + m_nameFilter); } QString prettyUrl = visibleUrl.toDisplayString(QUrl::PreferLocalFile); emit setWindowCaption(prettyUrl); emit m_extension->setLocationBarUrl(prettyUrl); emit started(nullptr); // get the wheel to spin m_view->setNameFilter(m_nameFilter); m_view->setUrl(url); updatePasteAction(); emit aboutToOpenURL(); if (reload) m_view->reload(); // Disable "Find File" and "Open Terminal" actions for non-file URLs, // e.g. ftp, smb, etc. #279283 const bool isLocalUrl = url.isLocalFile(); m_findFileAction->setEnabled(isLocalUrl); if (m_openTerminalAction) { m_openTerminalAction->setEnabled(isLocalUrl); } return true; } void DolphinPart::slotMessage(const QString& msg) { emit setStatusBarText(msg); } void DolphinPart::slotErrorMessage(const QString& msg) { qCDebug(DolphinDebug) << msg; emit canceled(msg); //KMessageBox::error(m_view, msg); } void DolphinPart::slotRequestItemInfo(const KFileItem& item) { emit m_extension->mouseOverInfo(item); if (item.isNull()) { updateStatusBar(); } else { const QString escapedText = Qt::convertFromPlainText(item.getStatusBarInfo()); emit ReadOnlyPart::setStatusBarText(QStringLiteral("%1").arg(escapedText)); } } void DolphinPart::slotItemActivated(const KFileItem& item) { KParts::OpenUrlArguments args; // Forget about the known mimetype if a target URL is used. // Testcase: network:/ with a item (mimetype "inode/some-foo-service") pointing to a http URL (html) if (item.targetUrl() == item.url()) { args.setMimeType(item.mimetype()); } // Ideally, konqueror should be changed to not require trustedSource for directory views, // since the idea was not to need BrowserArguments for non-browser stuff... KParts::BrowserArguments browserArgs; browserArgs.trustedSource = true; emit m_extension->openUrlRequest(item.targetUrl(), args, browserArgs); } void DolphinPart::slotItemsActivated(const KFileItemList& items) { foreach (const KFileItem& item, items) { slotItemActivated(item); } } void DolphinPart::createNewWindow(const QUrl& url) { // TODO: Check issue N176832 for the missing QAIV signal; task 177399 - maybe this code // should be moved into DolphinPart::slotItemActivated() emit m_extension->createNewWindow(url); } void DolphinPart::slotOpenContextMenu(const QPoint& pos, const KFileItem& _item, const QUrl &, const QList& customActions) { KParts::BrowserExtension::PopupFlags popupFlags = KParts::BrowserExtension::DefaultPopupItems | KParts::BrowserExtension::ShowProperties | KParts::BrowserExtension::ShowUrlOperations; KFileItem item(_item); if (item.isNull()) { // viewport context menu item = m_view->rootItem(); if (item.isNull()) item = KFileItem(url()); else item.setUrl(url()); // ensure we use the view url, not the canonical path (#213799) } // TODO: We should change the signature of the slots (and signals) for being able // to tell for which items we want a popup. KFileItemList items; if (m_view->selectedItems().isEmpty()) { items.append(item); } else { items = m_view->selectedItems(); } KFileItemListProperties capabilities(items); KParts::BrowserExtension::ActionGroupMap actionGroups; QList editActions; editActions += m_view->versionControlActions(m_view->selectedItems()); editActions += customActions; if (!_item.isNull()) { // only for context menu on one or more items const bool supportsMoving = capabilities.supportsMoving(); if (capabilities.supportsDeleting()) { const bool showDeleteAction = (KSharedConfig::openConfig()->group("KDE").readEntry("ShowDeleteCommand", false) || !item.isLocalFile()); const bool showMoveToTrashAction = capabilities.isLocal() && supportsMoving; if (showDeleteAction && showMoveToTrashAction) { delete m_removeAction; m_removeAction = nullptr; editActions.append(actionCollection()->action(KStandardAction::name(KStandardAction::MoveToTrash))); editActions.append(actionCollection()->action(KStandardAction::name(KStandardAction::DeleteFile))); } else if (showDeleteAction && !showMoveToTrashAction) { editActions.append(actionCollection()->action(KStandardAction::name(KStandardAction::DeleteFile))); } else { if (!m_removeAction) m_removeAction = new DolphinRemoveAction(this, actionCollection()); editActions.append(m_removeAction); m_removeAction->update(); } } else { popupFlags |= KParts::BrowserExtension::NoDeletion; } if (supportsMoving) { editActions.append(actionCollection()->action(KStandardAction::name(KStandardAction::RenameFile))); } // Normally KonqPopupMenu only shows the "Create new" submenu in the current view // since otherwise the created file would not be visible. // But in treeview mode we should allow it. if (m_view->itemsExpandable()) popupFlags |= KParts::BrowserExtension::ShowCreateDirectory; } actionGroups.insert(QStringLiteral("editactions"), editActions); emit m_extension->popupMenu(pos, items, KParts::OpenUrlArguments(), KParts::BrowserArguments(), popupFlags, actionGroups); } void DolphinPart::slotDirectoryRedirection(const QUrl &oldUrl, const QUrl &newUrl) { qCDebug(DolphinDebug) << oldUrl << newUrl << "currentUrl=" << url(); if (oldUrl.matches(url(), QUrl::StripTrailingSlash /* #207572 */)) { KParts::ReadOnlyPart::setUrl(newUrl); const QString prettyUrl = newUrl.toDisplayString(QUrl::PreferLocalFile); emit m_extension->setLocationBarUrl(prettyUrl); } } void DolphinPart::slotEditMimeType() { const KFileItemList items = m_view->selectedItems(); if (!items.isEmpty()) { KMimeTypeEditor::editMimeType(items.first().mimetype(), m_view); } } void DolphinPart::slotSelectItemsMatchingPattern() { openSelectionDialog(i18nc("@title:window", "Select"), i18n("Select all items matching this pattern:"), true); } void DolphinPart::slotUnselectItemsMatchingPattern() { openSelectionDialog(i18nc("@title:window", "Unselect"), i18n("Unselect all items matching this pattern:"), false); } void DolphinPart::openSelectionDialog(const QString& title, const QString& text, bool selectItems) { bool okClicked; const QString pattern = QInputDialog::getText(m_view, title, text, QLineEdit::Normal, QStringLiteral("*"), &okClicked); if (okClicked && !pattern.isEmpty()) { QRegExp patternRegExp(pattern, Qt::CaseSensitive, QRegExp::Wildcard); m_view->selectItems(patternRegExp, selectItems); } } void DolphinPart::setCurrentViewMode(const QString& viewModeName) { QAction* action = actionCollection()->action(viewModeName); Q_ASSERT(action); action->trigger(); } QString DolphinPart::currentViewMode() const { return m_actionHandler->currentViewModeActionName(); } void DolphinPart::setNameFilter(const QString& nameFilter) { // This is the "/home/dfaure/*.diff" kind of name filter (KDirLister::setNameFilter) // which is unrelated to DolphinView::setNameFilter which is substring filtering in a proxy. m_nameFilter = nameFilter; // TODO save/restore name filter in saveState/restoreState like KonqDirPart did in kde3? } void DolphinPart::slotOpenTerminal() { QString dir(QDir::homePath()); QUrl u(url()); // If the given directory is not local, it can still be the URL of an // ioslave using UDS_LOCAL_PATH which to be converted first. KIO::StatJob* statJob = KIO::mostLocalUrl(u); KJobWidgets::setWindow(statJob, widget()); statJob->exec(); u = statJob->mostLocalUrl(); //If the URL is local after the above conversion, set the directory. if (u.isLocalFile()) { dir = u.toLocalFile(); } KToolInvocation::invokeTerminal(QString(), dir); } void DolphinPart::slotFindFile() { KRun::run(QStringLiteral("kfind"), {url()}, widget()); } void DolphinPart::updateNewMenu() { // As requested by KNewFileMenu : m_newFileMenu->checkUpToDate(); m_newFileMenu->setViewShowsHiddenFiles(m_view->hiddenFilesShown()); // And set the files that the menu apply on : m_newFileMenu->setPopupFiles(url()); } void DolphinPart::updateStatusBar() { const QString escapedText = Qt::convertFromPlainText(m_view->statusBarText()); emit ReadOnlyPart::setStatusBarText(QStringLiteral("%1").arg(escapedText)); } void DolphinPart::updateProgress(int percent) { emit m_extension->loadingProgress(percent); } void DolphinPart::createDirectory() { m_newFileMenu->setViewShowsHiddenFiles(m_view->hiddenFilesShown()); m_newFileMenu->setPopupFiles(url()); m_newFileMenu->createDirectory(); } void DolphinPart::setFilesToSelect(const QList& files) { if (files.isEmpty()) { return; } m_view->markUrlsAsSelected(files); m_view->markUrlAsCurrent(files.at(0)); } bool DolphinPart::eventFilter(QObject* obj, QEvent* event) { using ShiftState = DolphinRemoveAction::ShiftState; const int type = event->type(); if ((type == QEvent::KeyPress || type == QEvent::KeyRelease) && m_removeAction) { QMenu* menu = qobject_cast(obj); if (menu && menu->parent() == m_view) { QKeyEvent* ev = static_cast(event); if (ev->key() == Qt::Key_Shift) { m_removeAction->update(type == QEvent::KeyPress ? ShiftState::Pressed : ShiftState::Released); } } } return KParts::ReadOnlyPart::eventFilter(obj, event); } #include "dolphinpart.moc" diff --git a/src/views/dolphinviewactionhandler.cpp b/src/views/dolphinviewactionhandler.cpp index 95c140cc5..5697c7f41 100644 --- a/src/views/dolphinviewactionhandler.cpp +++ b/src/views/dolphinviewactionhandler.cpp @@ -1,598 +1,598 @@ /*************************************************************************** * Copyright (C) 2008 by David Faure * * Copyright (C) 2012 by Peter Penz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * ***************************************************************************/ #include "dolphinviewactionhandler.h" #include "dolphindebug.h" #include "kitemviews/kfileitemmodel.h" #include "settings/viewpropertiesdialog.h" #include "views/zoomlevelinfo.h" #ifdef HAVE_BALOO #include #endif #include #include #include #include #include #include #include #include DolphinViewActionHandler::DolphinViewActionHandler(KActionCollection* collection, QObject* parent) : QObject(parent), m_actionCollection(collection), m_currentView(nullptr), m_sortByActions(), m_visibleRoles() { Q_ASSERT(m_actionCollection); createActions(); } void DolphinViewActionHandler::setCurrentView(DolphinView* view) { Q_ASSERT(view); if (m_currentView) { disconnect(m_currentView, nullptr, this, nullptr); } m_currentView = view; connect(view, &DolphinView::modeChanged, this, &DolphinViewActionHandler::updateViewActions); connect(view, &DolphinView::previewsShownChanged, this, &DolphinViewActionHandler::slotPreviewsShownChanged); connect(view, &DolphinView::sortOrderChanged, this, &DolphinViewActionHandler::slotSortOrderChanged); connect(view, &DolphinView::sortFoldersFirstChanged, this, &DolphinViewActionHandler::slotSortFoldersFirstChanged); connect(view, &DolphinView::visibleRolesChanged, this, &DolphinViewActionHandler::slotVisibleRolesChanged); connect(view, &DolphinView::groupedSortingChanged, this, &DolphinViewActionHandler::slotGroupedSortingChanged); connect(view, &DolphinView::hiddenFilesShownChanged, this, &DolphinViewActionHandler::slotHiddenFilesShownChanged); connect(view, &DolphinView::sortRoleChanged, this, &DolphinViewActionHandler::slotSortRoleChanged); connect(view, &DolphinView::zoomLevelChanged, this, &DolphinViewActionHandler::slotZoomLevelChanged); connect(view, &DolphinView::writeStateChanged, this, &DolphinViewActionHandler::slotWriteStateChanged); } DolphinView* DolphinViewActionHandler::currentView() { return m_currentView; } void DolphinViewActionHandler::createActions() { // This action doesn't appear in the GUI, it's for the shortcut only. // KNewFileMenu takes care of the GUI stuff. QAction* newDirAction = m_actionCollection->addAction(QStringLiteral("create_dir")); newDirAction->setText(i18nc("@action", "Create Folder...")); m_actionCollection->setDefaultShortcut(newDirAction, Qt::Key_F10); newDirAction->setIcon(QIcon::fromTheme(QStringLiteral("folder-new"))); newDirAction->setEnabled(false); // Will be enabled in slotWriteStateChanged(bool) if the current URL is writable - connect(newDirAction, &QAction::triggered, this, &DolphinViewActionHandler::createDirectory); + connect(newDirAction, &QAction::triggered, this, &DolphinViewActionHandler::createDirectoryTriggered); // File menu KStandardAction::renameFile(this, &DolphinViewActionHandler::slotRename, m_actionCollection); auto trashAction = KStandardAction::moveToTrash(this, &DolphinViewActionHandler::slotTrashActivated, m_actionCollection); auto trashShortcuts = trashAction->shortcuts(); if (!trashShortcuts.contains(QKeySequence::Delete)) { trashShortcuts.append(QKeySequence::Delete); m_actionCollection->setDefaultShortcuts(trashAction, trashShortcuts); } auto deleteAction = KStandardAction::deleteFile(this, &DolphinViewActionHandler::slotDeleteItems, m_actionCollection); auto deleteShortcuts = deleteAction->shortcuts(); if (!deleteShortcuts.contains(Qt::SHIFT | Qt::Key_Delete)) { deleteShortcuts.append(Qt::SHIFT | Qt::Key_Delete); m_actionCollection->setDefaultShortcuts(deleteAction, deleteShortcuts); } // This action is useful for being enabled when KStandardAction::MoveToTrash should be // disabled and KStandardAction::DeleteFile is enabled (e.g. non-local files), so that Key_Del // can be used for deleting the file (#76016). It needs to be a separate action // so that the Edit menu isn't affected. QAction* deleteWithTrashShortcut = m_actionCollection->addAction(QStringLiteral("delete_shortcut")); // The descriptive text is just for the shortcuts editor. deleteWithTrashShortcut->setText(i18nc("@action \"Move to Trash\" for non-local files, etc.", "Delete (using shortcut for Trash)")); m_actionCollection->setDefaultShortcuts(deleteWithTrashShortcut, KStandardShortcut::moveToTrash()); deleteWithTrashShortcut->setEnabled(false); connect(deleteWithTrashShortcut, &QAction::triggered, this, &DolphinViewActionHandler::slotDeleteItems); QAction *propertiesAction = m_actionCollection->addAction( QStringLiteral("properties") ); // Well, it's the File menu in dolphinmainwindow and the Edit menu in dolphinpart... :) propertiesAction->setText( i18nc("@action:inmenu File", "Properties") ); propertiesAction->setIcon(QIcon::fromTheme(QStringLiteral("document-properties"))); m_actionCollection->setDefaultShortcuts(propertiesAction, {Qt::ALT + Qt::Key_Return, Qt::ALT + Qt::Key_Enter}); connect(propertiesAction, &QAction::triggered, this, &DolphinViewActionHandler::slotProperties); // View menu KToggleAction* iconsAction = iconsModeAction(); KToggleAction* compactAction = compactModeAction(); KToggleAction* detailsAction = detailsModeAction(); KSelectAction* viewModeActions = m_actionCollection->add(QStringLiteral("view_mode")); viewModeActions->setText(i18nc("@action:intoolbar", "View Mode")); viewModeActions->addAction(iconsAction); viewModeActions->addAction(compactAction); viewModeActions->addAction(detailsAction); viewModeActions->setToolBarMode(KSelectAction::MenuMode); connect(viewModeActions, static_cast(&KSelectAction::triggered), this, &DolphinViewActionHandler::slotViewModeActionTriggered); KStandardAction::zoomIn(this, &DolphinViewActionHandler::zoomIn, m_actionCollection); KStandardAction::zoomOut(this, &DolphinViewActionHandler::zoomOut, m_actionCollection); KToggleAction* showPreview = m_actionCollection->add(QStringLiteral("show_preview")); showPreview->setText(i18nc("@action:intoolbar", "Preview")); showPreview->setToolTip(i18nc("@info", "Show preview of files and folders")); showPreview->setIcon(QIcon::fromTheme(QStringLiteral("view-preview"))); connect(showPreview, &KToggleAction::triggered, this, &DolphinViewActionHandler::togglePreview); KToggleAction* sortDescending = m_actionCollection->add(QStringLiteral("descending")); sortDescending->setText(i18nc("@action:inmenu Sort", "Descending")); connect(sortDescending, &KToggleAction::triggered, this, &DolphinViewActionHandler::toggleSortOrder); KToggleAction* sortFoldersFirst = m_actionCollection->add(QStringLiteral("folders_first")); sortFoldersFirst->setText(i18nc("@action:inmenu Sort", "Folders First")); connect(sortFoldersFirst, &KToggleAction::triggered, this, &DolphinViewActionHandler::toggleSortFoldersFirst); // View -> Sort By QActionGroup* sortByActionGroup = createFileItemRolesActionGroup(QStringLiteral("sort_by_")); KActionMenu* sortByActionMenu = m_actionCollection->add(QStringLiteral("sort")); sortByActionMenu->setText(i18nc("@action:inmenu View", "Sort By")); sortByActionMenu->setDelayed(false); foreach (QAction* action, sortByActionGroup->actions()) { sortByActionMenu->addAction(action); } sortByActionMenu->addSeparator(); sortByActionMenu->addAction(sortDescending); sortByActionMenu->addAction(sortFoldersFirst); // View -> Additional Information QActionGroup* visibleRolesGroup = createFileItemRolesActionGroup(QStringLiteral("show_")); KActionMenu* visibleRolesMenu = m_actionCollection->add(QStringLiteral("additional_info")); visibleRolesMenu->setText(i18nc("@action:inmenu View", "Additional Information")); visibleRolesMenu->setDelayed(false); foreach (QAction* action, visibleRolesGroup->actions()) { visibleRolesMenu->addAction(action); } KToggleAction* showInGroups = m_actionCollection->add(QStringLiteral("show_in_groups")); showInGroups->setIcon(QIcon::fromTheme(QStringLiteral("view-group"))); showInGroups->setText(i18nc("@action:inmenu View", "Show in Groups")); connect(showInGroups, &KToggleAction::triggered, this, &DolphinViewActionHandler::toggleGroupedSorting); KToggleAction* showHiddenFiles = m_actionCollection->add(QStringLiteral("show_hidden_files")); showHiddenFiles->setText(i18nc("@action:inmenu View", "Hidden Files")); showHiddenFiles->setToolTip(i18nc("@info", "Visibility of hidden files and folders")); m_actionCollection->setDefaultShortcuts(showHiddenFiles, {Qt::ALT + Qt::Key_Period, Qt::CTRL + Qt::Key_H, Qt::Key_F8}); connect(showHiddenFiles, &KToggleAction::triggered, this, &DolphinViewActionHandler::toggleShowHiddenFiles); QAction* adjustViewProps = m_actionCollection->addAction(QStringLiteral("view_properties")); adjustViewProps->setText(i18nc("@action:inmenu View", "Adjust View Properties...")); connect(adjustViewProps, &QAction::triggered, this, &DolphinViewActionHandler::slotAdjustViewProperties); } QActionGroup* DolphinViewActionHandler::createFileItemRolesActionGroup(const QString& groupPrefix) { const bool isSortGroup = (groupPrefix == QLatin1String("sort_by_")); Q_ASSERT(isSortGroup || (!isSortGroup && groupPrefix == QLatin1String("show_"))); QActionGroup* rolesActionGroup = new QActionGroup(m_actionCollection); rolesActionGroup->setExclusive(isSortGroup); if (isSortGroup) { connect(rolesActionGroup, &QActionGroup::triggered, this, &DolphinViewActionHandler::slotSortTriggered); } else { connect(rolesActionGroup, &QActionGroup::triggered, this, &DolphinViewActionHandler::toggleVisibleRole); } QString groupName; KActionMenu* groupMenu = nullptr; QActionGroup* groupMenuGroup = nullptr; bool indexingEnabled = false; #ifdef HAVE_BALOO Baloo::IndexerConfig config; indexingEnabled = config.fileIndexingEnabled(); #endif const QList rolesInfo = KFileItemModel::rolesInformation(); foreach (const KFileItemModel::RoleInfo& info, rolesInfo) { if (!isSortGroup && info.role == "text") { // It should not be possible to hide the "text" role continue; } KToggleAction* action = nullptr; const QString name = groupPrefix + info.role; if (info.group.isEmpty()) { action = m_actionCollection->add(name); action->setActionGroup(rolesActionGroup); } else { if (!groupMenu || info.group != groupName) { groupName = info.group; groupMenu = m_actionCollection->add(groupName); groupMenu->setText(groupName); groupMenu->setActionGroup(rolesActionGroup); groupMenuGroup = new QActionGroup(groupMenu); groupMenuGroup->setExclusive(isSortGroup); if (isSortGroup) { connect(groupMenuGroup, &QActionGroup::triggered, this, &DolphinViewActionHandler::slotSortTriggered); } else { connect(groupMenuGroup, &QActionGroup::triggered, this, &DolphinViewActionHandler::toggleVisibleRole); } } action = new KToggleAction(groupMenu); action->setActionGroup(groupMenuGroup); groupMenu->addAction(action); } action->setText(info.translation); action->setData(info.role); const bool enable = (!info.requiresBaloo && !info.requiresIndexer) || (info.requiresBaloo) || (info.requiresIndexer && indexingEnabled); action->setEnabled(enable); if (isSortGroup) { m_sortByActions.insert(info.role, action); } else { m_visibleRoles.insert(info.role, action); } } return rolesActionGroup; } void DolphinViewActionHandler::slotViewModeActionTriggered(QAction* action) { const DolphinView::Mode mode = action->data().value(); m_currentView->setMode(mode); QAction* viewModeMenu = m_actionCollection->action(QStringLiteral("view_mode")); viewModeMenu->setIcon(action->icon()); } void DolphinViewActionHandler::slotRename() { emit actionBeingHandled(); m_currentView->renameSelectedItems(); } void DolphinViewActionHandler::slotTrashActivated() { emit actionBeingHandled(); m_currentView->trashSelectedItems(); } void DolphinViewActionHandler::slotDeleteItems() { emit actionBeingHandled(); m_currentView->deleteSelectedItems(); } void DolphinViewActionHandler::togglePreview(bool show) { emit actionBeingHandled(); m_currentView->setPreviewsShown(show); } void DolphinViewActionHandler::slotPreviewsShownChanged(bool shown) { Q_UNUSED(shown); // It is not enough to update the 'Show Preview' action, also // the 'Zoom In' and 'Zoom Out' actions must be adapted. updateViewActions(); } QString DolphinViewActionHandler::currentViewModeActionName() const { switch (m_currentView->mode()) { case DolphinView::IconsView: return QStringLiteral("icons"); case DolphinView::DetailsView: return QStringLiteral("details"); case DolphinView::CompactView: return QStringLiteral("compact"); default: Q_ASSERT(false); break; } return QString(); // can't happen } KActionCollection* DolphinViewActionHandler::actionCollection() { return m_actionCollection; } void DolphinViewActionHandler::updateViewActions() { QAction* viewModeAction = m_actionCollection->action(currentViewModeActionName()); if (viewModeAction) { viewModeAction->setChecked(true); QAction* viewModeMenu = m_actionCollection->action(QStringLiteral("view_mode")); viewModeMenu->setIcon(viewModeAction->icon()); } QAction* showPreviewAction = m_actionCollection->action(QStringLiteral("show_preview")); showPreviewAction->setChecked(m_currentView->previewsShown()); slotSortOrderChanged(m_currentView->sortOrder()); slotSortFoldersFirstChanged(m_currentView->sortFoldersFirst()); slotVisibleRolesChanged(m_currentView->visibleRoles(), QList()); slotGroupedSortingChanged(m_currentView->groupedSorting()); slotSortRoleChanged(m_currentView->sortRole()); slotZoomLevelChanged(m_currentView->zoomLevel(), -1); // Updates the "show_hidden_files" action state and icon slotHiddenFilesShownChanged(m_currentView->hiddenFilesShown()); } void DolphinViewActionHandler::zoomIn() { const int level = m_currentView->zoomLevel(); m_currentView->setZoomLevel(level + 1); updateViewActions(); } void DolphinViewActionHandler::zoomOut() { const int level = m_currentView->zoomLevel(); m_currentView->setZoomLevel(level - 1); updateViewActions(); } void DolphinViewActionHandler::toggleSortOrder() { const Qt::SortOrder order = (m_currentView->sortOrder() == Qt::AscendingOrder) ? Qt::DescendingOrder : Qt::AscendingOrder; m_currentView->setSortOrder(order); } void DolphinViewActionHandler::toggleSortFoldersFirst() { const bool sortFirst = m_currentView->sortFoldersFirst(); m_currentView->setSortFoldersFirst(!sortFirst); } void DolphinViewActionHandler::slotSortOrderChanged(Qt::SortOrder order) { QAction* descending = m_actionCollection->action(QStringLiteral("descending")); const bool sortDescending = (order == Qt::DescendingOrder); descending->setChecked(sortDescending); } void DolphinViewActionHandler::slotSortFoldersFirstChanged(bool foldersFirst) { m_actionCollection->action(QStringLiteral("folders_first"))->setChecked(foldersFirst); } void DolphinViewActionHandler::toggleVisibleRole(QAction* action) { emit actionBeingHandled(); const QByteArray toggledRole = action->data().toByteArray(); QList roles = m_currentView->visibleRoles(); const bool show = action->isChecked(); const int index = roles.indexOf(toggledRole); const bool containsInfo = (index >= 0); if (show && !containsInfo) { roles.append(toggledRole); m_currentView->setVisibleRoles(roles); } else if (!show && containsInfo) { roles.removeAt(index); m_currentView->setVisibleRoles(roles); Q_ASSERT(roles.indexOf(toggledRole) < 0); } } void DolphinViewActionHandler::slotVisibleRolesChanged(const QList& current, const QList& previous) { Q_UNUSED(previous); const QSet checkedRoles = current.toSet(); QHashIterator it(m_visibleRoles); while (it.hasNext()) { it.next(); const QByteArray& role = it.key(); KToggleAction* action = it.value(); action->setChecked(checkedRoles.contains(role)); } } void DolphinViewActionHandler::toggleGroupedSorting(bool grouped) { m_currentView->setGroupedSorting(grouped); } void DolphinViewActionHandler::slotGroupedSortingChanged(bool groupedSorting) { QAction* showInGroupsAction = m_actionCollection->action(QStringLiteral("show_in_groups")); showInGroupsAction->setChecked(groupedSorting); } void DolphinViewActionHandler::toggleShowHiddenFiles(bool show) { emit actionBeingHandled(); m_currentView->setHiddenFilesShown(show); } void DolphinViewActionHandler::slotHiddenFilesShownChanged(bool shown) { QAction* showHiddenFilesAction = m_actionCollection->action(QStringLiteral("show_hidden_files")); showHiddenFilesAction->setChecked(shown); // #374508: don't overwrite custom icons. const QString iconName = showHiddenFilesAction->icon().name(); if (!iconName.isEmpty() && iconName != QLatin1String("visibility") && iconName != QLatin1String("hint")) { return; } showHiddenFilesAction->setIcon(QIcon::fromTheme(shown ? QStringLiteral("visibility") : QStringLiteral("hint"))); } void DolphinViewActionHandler::slotWriteStateChanged(bool isFolderWritable) { m_actionCollection->action(QStringLiteral("create_dir"))->setEnabled(isFolderWritable && KProtocolManager::supportsMakeDir(currentView()->url())); } KToggleAction* DolphinViewActionHandler::iconsModeAction() { KToggleAction* iconsView = m_actionCollection->add(QStringLiteral("icons")); iconsView->setText(i18nc("@action:inmenu View Mode", "Icons")); iconsView->setToolTip(i18nc("@info", "Icons view mode")); m_actionCollection->setDefaultShortcut(iconsView, Qt::CTRL + Qt::Key_1); iconsView->setIcon(QIcon::fromTheme(QStringLiteral("view-list-icons"))); iconsView->setData(QVariant::fromValue(DolphinView::IconsView)); return iconsView; } KToggleAction* DolphinViewActionHandler::compactModeAction() { KToggleAction* iconsView = m_actionCollection->add(QStringLiteral("compact")); iconsView->setText(i18nc("@action:inmenu View Mode", "Compact")); iconsView->setToolTip(i18nc("@info", "Compact view mode")); m_actionCollection->setDefaultShortcut(iconsView, Qt::CTRL + Qt::Key_2); iconsView->setIcon(QIcon::fromTheme(QStringLiteral("view-list-details"))); // TODO: discuss with Oxygen-team the wrong (?) name iconsView->setData(QVariant::fromValue(DolphinView::CompactView)); return iconsView; } KToggleAction* DolphinViewActionHandler::detailsModeAction() { KToggleAction* detailsView = m_actionCollection->add(QStringLiteral("details")); detailsView->setText(i18nc("@action:inmenu View Mode", "Details")); detailsView->setToolTip(i18nc("@info", "Details view mode")); m_actionCollection->setDefaultShortcut(detailsView, Qt::CTRL + Qt::Key_3); detailsView->setIcon(QIcon::fromTheme(QStringLiteral("view-list-tree"))); detailsView->setData(QVariant::fromValue(DolphinView::DetailsView)); return detailsView; } void DolphinViewActionHandler::slotSortRoleChanged(const QByteArray& role) { KToggleAction* action = m_sortByActions.value(role); if (action) { action->setChecked(true); if (!action->icon().isNull()) { QAction* sortByMenu = m_actionCollection->action(QStringLiteral("sort")); sortByMenu->setIcon(action->icon()); } } } void DolphinViewActionHandler::slotZoomLevelChanged(int current, int previous) { Q_UNUSED(previous); QAction* zoomInAction = m_actionCollection->action(KStandardAction::name(KStandardAction::ZoomIn)); if (zoomInAction) { zoomInAction->setEnabled(current < ZoomLevelInfo::maximumLevel()); } QAction* zoomOutAction = m_actionCollection->action(KStandardAction::name(KStandardAction::ZoomOut)); if (zoomOutAction) { zoomOutAction->setEnabled(current > ZoomLevelInfo::minimumLevel()); } } void DolphinViewActionHandler::slotSortTriggered(QAction* action) { // The radiobuttons of the "Sort By"-menu are split between the main-menu // and several sub-menus. Because of this they don't have a common // action-group that assures an exclusive toggle-state between the main-menu // actions and the sub-menu-actions. If an action gets checked, it must // be assured that all other actions get unchecked. QAction* sortByMenu = m_actionCollection->action(QStringLiteral("sort")); foreach (QAction* groupAction, sortByMenu->menu()->actions()) { KActionMenu* actionMenu = qobject_cast(groupAction); if (actionMenu) { foreach (QAction* subAction, actionMenu->menu()->actions()) { subAction->setChecked(false); } } else if (groupAction->actionGroup()) { groupAction->setChecked(false); } } action->setChecked(true); // Apply the activated sort-role to the view const QByteArray role = action->data().toByteArray(); m_currentView->setSortRole(role); } void DolphinViewActionHandler::slotAdjustViewProperties() { emit actionBeingHandled(); QPointer dialog = new ViewPropertiesDialog(m_currentView); dialog->exec(); delete dialog; } void DolphinViewActionHandler::slotProperties() { KPropertiesDialog* dialog = nullptr; const KFileItemList list = m_currentView->selectedItems(); if (list.isEmpty()) { const QUrl url = m_currentView->url(); dialog = new KPropertiesDialog(url, m_currentView); } else { dialog = new KPropertiesDialog(list, m_currentView); } dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->show(); dialog->raise(); dialog->activateWindow(); } diff --git a/src/views/dolphinviewactionhandler.h b/src/views/dolphinviewactionhandler.h index be2273917..fa0487e1b 100644 --- a/src/views/dolphinviewactionhandler.h +++ b/src/views/dolphinviewactionhandler.h @@ -1,259 +1,259 @@ /*************************************************************************** * Copyright (C) 2008 by David Faure * * Copyright (C) 2012 by Peter Penz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * ***************************************************************************/ #ifndef DOLPHINVIEWACTIONHANDLER_H #define DOLPHINVIEWACTIONHANDLER_H #include "dolphin_export.h" #include "views/dolphinview.h" #include class KToggleAction; class QAction; class QActionGroup; class DolphinView; class KActionCollection; /** * @short Handles all actions for DolphinView * * The action handler owns all the actions and slots related to DolphinView, * but can the view that is acts upon can be switched to another one * (this is used in the case of split views). * * The purpose of this class is also to share this code between DolphinMainWindow * and DolphinPart. * * @see DolphinView * @see DolphinMainWindow * @see DolphinPart */ class DOLPHIN_EXPORT DolphinViewActionHandler : public QObject { Q_OBJECT public: explicit DolphinViewActionHandler(KActionCollection* collection, QObject* parent); /** * Sets the view that this action handler should work on. */ void setCurrentView(DolphinView* view); /** * Returns the view that this action handler should work on. */ DolphinView* currentView(); /** * Returns the name of the action for the current viewmode */ QString currentViewModeActionName() const; /** * Returns m_actionCollection */ KActionCollection* actionCollection(); public Q_SLOTS: /** * Update all actions in the 'View' menu, i.e. those that depend on the * settings in the current view. */ void updateViewActions(); Q_SIGNALS: /** * Emitted by DolphinViewActionHandler when the user triggered an action. * This is only used for clearining the statusbar in DolphinMainWindow. */ void actionBeingHandled(); /** * Emitted if the user requested creating a new directory by the F10 key. * The receiver of the signal (DolphinMainWindow or DolphinPart) invokes * the method createDirectory of their KNewFileMenu instance. */ - void createDirectory(); + void createDirectoryTriggered(); private Q_SLOTS: /** * Emitted when the user requested a change of view mode */ void slotViewModeActionTriggered(QAction*); /** * Let the user input a name for the selected item(s) and trigger * a renaming afterwards. */ void slotRename(); /** * Moves the selected items of the active view to the trash. * This methods adds "shift means del" handling. */ void slotTrashActivated(); /** * Deletes the selected items of the active view. */ void slotDeleteItems(); /** * Switches between showing a preview of the file content and showing the icon. */ void togglePreview(bool); /** Updates the state of the 'Show preview' menu action. */ void slotPreviewsShownChanged(bool shown); /** Increases the size of the current set view mode. */ void zoomIn(); /** Decreases the size of the current set view mode. */ void zoomOut(); /** Switches between an ascending and descending sorting order. */ void toggleSortOrder(); /** Switches between a separate sorting and a mixed sorting of files and folders. */ void toggleSortFoldersFirst(); /** * Updates the state of the 'Sort Ascending/Descending' action. */ void slotSortOrderChanged(Qt::SortOrder order); /** * Updates the state of the 'Sort Folders First' action. */ void slotSortFoldersFirstChanged(bool foldersFirst); /** * Updates the state of the 'Sort by' actions. */ void slotSortRoleChanged(const QByteArray& role); /** * Updates the state of the 'Zoom In' and 'Zoom Out' actions. */ void slotZoomLevelChanged(int current, int previous); /** * Switches on or off the displaying of additional information * as specified by \a action. */ void toggleVisibleRole(QAction* action); /** * Changes the sorting of the current view. */ void slotSortTriggered(QAction*); /** * Updates the state of the 'Additional Information' actions. */ void slotVisibleRolesChanged(const QList& current, const QList& previous); /** * Switches between sorting by groups or not. */ void toggleGroupedSorting(bool); /** * Updates the state of the 'Categorized sorting' menu action. */ void slotGroupedSortingChanged(bool sortCategorized); /** * Switches between showing and hiding of hidden marked files */ void toggleShowHiddenFiles(bool); /** * Updates the state of the 'Show hidden files' menu action. */ void slotHiddenFilesShownChanged(bool shown); /** * Updates the state of the 'Create Folder...' action. */ void slotWriteStateChanged(bool isFolderWritable); /** * Opens the view properties dialog, which allows to modify the properties * of the currently active view. */ void slotAdjustViewProperties(); /** * Connected to the "properties" action. * Opens the properties dialog for the selected items of the * active view. The properties dialog shows information * like name, size and permissions. */ void slotProperties(); private: /** * Create all the actions. * This is called only once (by the constructor) */ void createActions(); /** * Creates an action-group out of all roles from KFileItemModel. * Dependent on the group-prefix either a radiobutton-group is * created for sorting (prefix is "sort_by_") or a checkbox-group * is created for additional information (prefix is "show_"). * The changes of actions are reported to slotSortTriggered() or * toggleAdditionalInfo(). */ QActionGroup* createFileItemRolesActionGroup(const QString& groupPrefix); /** * Returns the "switch to icons mode" action. * Helper method for createActions(); */ KToggleAction* iconsModeAction(); /** * Returns the "switch to compact mode" action. * Helper method for createActions(); */ KToggleAction* compactModeAction(); /** * Returns the "switch to details mode" action. * Helper method for createActions(); */ KToggleAction* detailsModeAction(); KActionCollection* m_actionCollection; DolphinView* m_currentView; QHash m_sortByActions; QHash m_visibleRoles; }; #endif /* DOLPHINVIEWACTIONHANDLER_H */