#include "dolphinmainwindow.h"
#include "dolphinmainwindowadaptor.h"
-#include "config-terminal.h"
#include "global.h"
#include "dolphinbookmarkhandler.h"
#include "dolphindockwidget.h"
#include "panels/folders/folderspanel.h"
#include "panels/places/placespanel.h"
#include "panels/terminal/terminalpanel.h"
+#include "selectionmode/actiontexthelper.h"
#include "settings/dolphinsettingsdialog.h"
#include "statusbar/dolphinstatusbar.h"
#include "views/dolphinviewactionhandler.h"
#include <KConfigGui>
#include <KDualAction>
#include <KFileItemListProperties>
-#include <KHelpMenu>
#include <KIO/CommandLauncherJob>
+#include <kio_version.h>
+#if KIO_VERSION >= QT_VERSION_CHECK(5, 98, 0)
+#include <KIO/JobUiDelegateFactory>
+#else
#include <KIO/JobUiDelegate>
+#endif
#include <KIO/OpenFileManagerWindowJob>
#include <KIO/OpenUrlJob>
#include <KJobWidgets>
#include <KLocalizedString>
#include <KMessageBox>
-#include <KNS3/KMoreToolsMenuFactory>
+#include <KMoreToolsMenuFactory>
#include <KProtocolInfo>
#include <KProtocolManager>
#include <KShell>
#include <QStandardPaths>
#include <QTimer>
#include <QToolButton>
-#include <QWhatsThisClickedEvent>
namespace {
// Used for GeneralSettings::version() to determine whether
- // an updated version of Dolphin is running.
- const int CurrentDolphinVersion = 201;
+ // an updated version of Dolphin is running, so as to migrate
+ // removed/renamed ...etc config entries; increment it in such
+ // cases
+ const int CurrentDolphinVersion = 202;
// The maximum number of entries in the back/forward popup menu
const int MaxNumberOfNavigationentries = 12;
// The maximum number of "Activate Tab" shortcuts
DolphinMainWindow::DolphinMainWindow() :
KXmlGuiWindow(nullptr),
m_newFileMenu(nullptr),
- m_helpMenu(nullptr),
m_tabWidget(nullptr),
m_activeViewContainer(nullptr),
m_actionHandler(nullptr),
m_remoteEncoding(nullptr),
m_settingsDialog(),
m_bookmarkHandler(nullptr),
- m_controlButton(nullptr),
- m_updateToolBarTimer(nullptr),
m_lastHandleUrlOpenJob(nullptr),
m_terminalPanel(nullptr),
m_placesPanel(nullptr),
this, &DolphinMainWindow::updateWindowTitle);
setCentralWidget(m_tabWidget);
+ m_actionTextHelper = new SelectionMode::ActionTextHelper(this);
setupActions();
- m_actionHandler = new DolphinViewActionHandler(actionCollection(), this);
+ m_actionHandler = new DolphinViewActionHandler(actionCollection(), m_actionTextHelper, this);
connect(m_actionHandler, &DolphinViewActionHandler::actionBeingHandled, this, &DolphinMainWindow::clearStatusBar);
connect(m_actionHandler, &DolphinViewActionHandler::createDirectoryTriggered, this, &DolphinMainWindow::createDirectory);
+ connect(m_actionHandler, &DolphinViewActionHandler::selectionModeChangeTriggered, this, &DolphinMainWindow::slotSetSelectionMode);
m_remoteEncoding = new DolphinRemoteEncoding(this, m_actionHandler);
connect(this, &DolphinMainWindow::urlChanged,
bool DolphinMainWindow::isInformationPanelEnabled() const
{
-#ifdef HAVE_BALOO
+#if HAVE_BALOO
return actionCollection()->action(QStringLiteral("show_information_panel"))->isChecked();
#else
return false;
KWindowSystem::activateWindow(window()->effectiveWinId());
}
+bool DolphinMainWindow::isActiveWindow()
+{
+ return window()->isActiveWindow();
+}
+
void DolphinMainWindow::showCommand(CommandType command)
{
DolphinStatusBar* statusBar = m_activeViewContainer->statusBar();
void DolphinMainWindow::updateNewMenu()
{
m_newFileMenu->checkUpToDate();
+#if KIO_VERSION >= QT_VERSION_CHECK(5, 97, 0)
+ m_newFileMenu->setWorkingDirectory(activeViewContainer()->url());
+#else
m_newFileMenu->setPopupFiles(QList<QUrl>() << activeViewContainer()->url());
+#endif
}
void DolphinMainWindow::createDirectory()
{
+#if KIO_VERSION >= QT_VERSION_CHECK(5, 97, 0)
+ m_newFileMenu->setWorkingDirectory(activeViewContainer()->url());
+#else
m_newFileMenu->setPopupFiles(QList<QUrl>() << activeViewContainer()->url());
+#endif
m_newFileMenu->createDirectory();
}
void DolphinMainWindow::cut()
{
- m_activeViewContainer->view()->cutSelectedItemsToClipboard();
+ if (m_activeViewContainer->view()->selectedItems().isEmpty()) {
+ m_activeViewContainer->setSelectionModeEnabled(true, actionCollection(), SelectionMode::BottomBar::Contents::CutContents);
+ } else {
+ m_activeViewContainer->view()->cutSelectedItemsToClipboard();
+ m_activeViewContainer->setSelectionModeEnabled(false);
+ }
}
void DolphinMainWindow::copy()
{
- m_activeViewContainer->view()->copySelectedItemsToClipboard();
+ if (m_activeViewContainer->view()->selectedItems().isEmpty()) {
+ m_activeViewContainer->setSelectionModeEnabled(true, actionCollection(), SelectionMode::BottomBar::Contents::CopyContents);
+ } else {
+ m_activeViewContainer->view()->copySelectedItemsToClipboard();
+ m_activeViewContainer->setSelectionModeEnabled(false);
+ }
}
void DolphinMainWindow::paste()
}
}
+QAction *DolphinMainWindow::urlNavigatorHistoryAction(const KUrlNavigator *urlNavigator, int historyIndex, QObject *parent)
+{
+ const QUrl url = urlNavigator->locationUrl(historyIndex);
+
+ QString text = url.toDisplayString(QUrl::PreferLocalFile);
+
+ if (!urlNavigator->showFullPath()) {
+ const KFilePlacesModel *placesModel = DolphinPlacesModelSingleton::instance().placesModel();
+
+ const QModelIndex closestIdx = placesModel->closestItem(url);
+ if (closestIdx.isValid()) {
+ const QUrl placeUrl = placesModel->url(closestIdx);
+
+ text = placesModel->text(closestIdx);
+
+ QString pathInsidePlace = url.path().mid(placeUrl.path().length());
+
+ if (!pathInsidePlace.isEmpty() && !pathInsidePlace.startsWith(QLatin1Char('/'))) {
+ pathInsidePlace.prepend(QLatin1Char('/'));
+ }
+
+ if (pathInsidePlace != QLatin1Char('/')) {
+ text.append(pathInsidePlace);
+ }
+ }
+ }
+
+ QAction *action = new QAction(QIcon::fromTheme(KIO::iconNameForUrl(url)), text, parent);
+ action->setData(historyIndex);
+ return action;
+}
+
void DolphinMainWindow::slotAboutToShowBackPopupMenu()
{
const KUrlNavigator *urlNavigator = m_activeViewContainer->urlNavigatorInternalWithHistory();
int entries = 0;
m_backAction->menu()->clear();
for (int i = urlNavigator->historyIndex() + 1; i < urlNavigator->historySize() && entries < MaxNumberOfNavigationentries; ++i, ++entries) {
- QAction* action = new QAction(urlNavigator->locationUrl(i).toDisplayString(QUrl::PreferLocalFile), m_backAction->menu());
- action->setData(i);
+ QAction *action = urlNavigatorHistoryAction(urlNavigator, i, m_backAction->menu());
m_backAction->menu()->addAction(action);
}
}
int entries = 0;
m_forwardAction->menu()->clear();
for (int i = urlNavigator->historyIndex() - 1; i >= 0 && entries < MaxNumberOfNavigationentries; --i, ++entries) {
- QAction* action = new QAction(urlNavigator->locationUrl(i).toDisplayString(QUrl::PreferLocalFile), m_forwardAction->menu());
- action->setData(i);
+ QAction *action = urlNavigatorHistoryAction(urlNavigator, i, m_forwardAction->menu());
m_forwardAction->menu()->addAction(action);
}
}
}
}
+void DolphinMainWindow::slotSetSelectionMode(bool enabled, SelectionMode::BottomBar::Contents bottomBarContents)
+{
+ m_activeViewContainer->setSelectionModeEnabled(enabled, actionCollection(), bottomBarContents);
+}
+
void DolphinMainWindow::selectAll()
{
clearStatusBar();
tabPage->setSplitViewEnabled(true, WithAnimation, QUrl("stash:/"));
}
+void DolphinMainWindow::copyToInactiveSplitView()
+{
+ if (m_activeViewContainer->view()->selectedItems().isEmpty()) {
+ m_activeViewContainer->setSelectionModeEnabled(true, actionCollection(), SelectionMode::BottomBar::Contents::CopyToOtherViewContents);
+ } else {
+ m_tabWidget->copyToInactiveSplitView();
+ m_activeViewContainer->setSelectionModeEnabled(false);
+ }
+}
+
+void DolphinMainWindow::moveToInactiveSplitView()
+{
+ if (m_activeViewContainer->view()->selectedItems().isEmpty()) {
+ m_activeViewContainer->setSelectionModeEnabled(true, actionCollection(), SelectionMode::BottomBar::Contents::MoveToOtherViewContents);
+ } else {
+ m_tabWidget->moveToInactiveSplitView();
+ m_activeViewContainer->setSelectionModeEnabled(false);
+ }
+}
+
void DolphinMainWindow::reloadView()
{
clearStatusBar();
actionCollection()->action(QStringLiteral("stop"))->setEnabled(false);
}
+void DolphinMainWindow::toggleSelectionMode()
+{
+ const bool checked = !m_activeViewContainer->isSelectionModeEnabled();
+
+ m_activeViewContainer->setSelectionModeEnabled(checked, actionCollection(), SelectionMode::BottomBar::Contents::GeneralContents);
+ actionCollection()->action(QStringLiteral("toggle_selection_mode"))->setChecked(checked);
+}
+
void DolphinMainWindow::showFilterBar()
{
m_activeViewContainer->setFilterBarVisible(true);
void DolphinMainWindow::openTerminal()
{
- const QUrl url = m_activeViewContainer->url();
+ openTerminalJob(m_activeViewContainer->url());
+}
+
+void DolphinMainWindow::openTerminalHere()
+{
+ QList<QUrl> urls = {};
+
+ for (const KFileItem& item : m_activeViewContainer->view()->selectedItems()) {
+ QUrl url = item.targetUrl();
+ if (item.isFile()) {
+ url.setPath(QFileInfo(url.path()).absolutePath());
+ }
+ if (!urls.contains(url)) {
+ urls << url;
+ }
+ }
+
+ // No items are selected. Open a terminal window for the current location.
+ if (urls.count() == 0) {
+ openTerminal();
+ return;
+ }
+ if (urls.count() > 5) {
+ QString question = i18np("Are you sure you want to open 1 terminal window?",
+ "Are you sure you want to open %1 terminal windows?", urls.count());
+ const int answer = KMessageBox::warningYesNo(this, question, {},
+ KGuiItem(i18ncp("@action:button", "Open %1 Terminal", "Open %1 Terminals", urls.count()),
+ QStringLiteral("utilities-terminal")),
+ KStandardGuiItem::cancel());
+ if (answer != KMessageBox::Yes) {
+ return;
+ }
+ }
+
+ for (const QUrl& url : urls) {
+ openTerminalJob(url);
+ }
+}
+
+void DolphinMainWindow::openTerminalJob(const QUrl& url)
+{
if (url.isLocalFile()) {
auto job = new KTerminalLauncherJob(QString());
job->setWorkingDirectory(url.toLocalFile());
activeViewContainer()->setUrl(url);
} else {
m_lastHandleUrlOpenJob = new KIO::OpenUrlJob(url);
+#if KIO_VERSION >= QT_VERSION_CHECK(5, 98, 0)
+ m_lastHandleUrlOpenJob->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this));
+#else
m_lastHandleUrlOpenJob->setUiDelegate(new KIO::JobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this));
+#endif
m_lastHandleUrlOpenJob->setShowOpenOrExecuteDialog(true);
connect(m_lastHandleUrlOpenJob, &KIO::OpenUrlJob::mimeTypeFound, this,
void DolphinMainWindow::openContextMenu(const QPoint& pos,
const KFileItem& item,
- const QUrl& url,
- const QList<QAction*>& customActions)
+ const KFileItemList &selectedItems,
+ const QUrl& url)
{
- QPointer<DolphinContextMenu> contextMenu = new DolphinContextMenu(this, pos, item, url, &m_fileItemActions);
- 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;
- }
+ QPointer<DolphinContextMenu> contextMenu = new DolphinContextMenu(this, item, selectedItems, url, &m_fileItemActions);
+ contextMenu.data()->exec(pos);
// Delete the menu, unless it has been deleted in its own nested event loop already.
if (contextMenu) {
menu->addAction(ac->action(QStringLiteral("go_forward")));
menu->addMenu(m_newFileMenu->menu());
+ if (!toolBar()->isVisible()
+ || !toolbarActions.contains(ac->action(QStringLiteral("toggle_selection_mode_tool_bar")))
+ ) {
+ menu->addAction(ac->action(QStringLiteral("toggle_selection_mode")));
+ }
menu->addAction(ac->action(QStringLiteral("basic_actions")));
menu->addAction(ac->action(KStandardAction::name(KStandardAction::Undo)));
if (!toolBar()->isVisible()
// except the requestItemInfo so that on hover the information panel can still be updated
connect(oldViewContainer->view(), &DolphinView::requestItemInfo,
this, &DolphinMainWindow::requestItemInfo);
+
+ // Disconnect other slots.
+ disconnect(nullptr, &DolphinViewContainer::selectionModeChanged,
+ actionCollection()->action(QStringLiteral("toggle_selection_mode")), &QAction::setChecked);
}
connectViewSignals(viewContainer);
void DolphinMainWindow::setupActions()
{
- KStandardAction::hamburgerMenu(nullptr, nullptr, actionCollection());
+ auto hamburgerMenuAction = KStandardAction::hamburgerMenu(nullptr, nullptr, actionCollection());
// setup 'File' menu
m_newFileMenu = new DolphinNewFileMenu(actionCollection(), this);
"next to each other on the keyboard: <shortcut>Ctrl+X</shortcut>, "
"<shortcut>Ctrl+C</shortcut> and <shortcut>Ctrl+V</shortcut>.</para>");
QAction* cutAction = KStandardAction::cut(this, &DolphinMainWindow::cut, actionCollection());
+ m_actionTextHelper->registerTextWhenNothingIsSelected(cutAction, i18nc("@action", "Cut…"));
cutAction->setWhatsThis(xi18nc("@info:whatsthis cut", "This copies the items "
"in your current selection to the <emphasis>clipboard</emphasis>.<nl/>"
"Use the <emphasis>Paste</emphasis> action afterwards to copy them from "
"the clipboard to a new location. The items will be removed from their "
"initial location.") + cutCopyPastePara);
QAction* copyAction = KStandardAction::copy(this, &DolphinMainWindow::copy, actionCollection());
+ m_actionTextHelper->registerTextWhenNothingIsSelected(copyAction, i18nc("@action", "Copy…"));
copyAction->setWhatsThis(xi18nc("@info:whatsthis copy", "This copies the "
"items in your current selection to the <emphasis>clipboard</emphasis>."
"<nl/>Use the <emphasis>Paste</emphasis> action afterwards to copy them "
QAction* copyToOtherViewAction = actionCollection()->addAction(QStringLiteral("copy_to_inactive_split_view"));
copyToOtherViewAction->setText(i18nc("@action:inmenu", "Copy to Inactive Split View"));
+ m_actionTextHelper->registerTextWhenNothingIsSelected(copyToOtherViewAction, i18nc("@action:inmenu", "Copy to Inactive Split View…"));
copyToOtherViewAction->setWhatsThis(xi18nc("@info:whatsthis Copy", "This copies the selected items from "
"the <emphasis>active</emphasis> view to the inactive split view."));
copyToOtherViewAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-copy")));
copyToOtherViewAction->setIconText(i18nc("@action:inmenu Edit", "Copy to Inactive Split View"));
actionCollection()->setDefaultShortcut(copyToOtherViewAction, Qt::SHIFT | Qt::Key_F5 );
- connect(copyToOtherViewAction, &QAction::triggered, m_tabWidget, &DolphinTabWidget::copyToInactiveSplitView);
+ connect(copyToOtherViewAction, &QAction::triggered, this, &DolphinMainWindow::copyToInactiveSplitView);
QAction* moveToOtherViewAction = actionCollection()->addAction(QStringLiteral("move_to_inactive_split_view"));
moveToOtherViewAction->setText(i18nc("@action:inmenu", "Move to Inactive Split View"));
+ m_actionTextHelper->registerTextWhenNothingIsSelected(moveToOtherViewAction, i18nc("@action:inmenu", "Move to Inactive Split View…"));
moveToOtherViewAction->setWhatsThis(xi18nc("@info:whatsthis Move", "This moves the selected items from "
"the <emphasis>active</emphasis> view to the inactive split view."));
moveToOtherViewAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-cut")));
moveToOtherViewAction->setIconText(i18nc("@action:inmenu Edit", "Move to Inactive Split View"));
actionCollection()->setDefaultShortcut(moveToOtherViewAction, Qt::SHIFT | Qt::Key_F6 );
- connect(moveToOtherViewAction, &QAction::triggered, m_tabWidget, &DolphinTabWidget::moveToInactiveSplitView);
+ connect(moveToOtherViewAction, &QAction::triggered, this, &DolphinMainWindow::moveToInactiveSplitView);
QAction* showFilterBar = actionCollection()->addAction(QStringLiteral("show_filter_bar"));
showFilterBar->setText(i18nc("@action:inmenu Tools", "Filter..."));
toggleSearchAction->setWhatsThis(searchAction->whatsThis());
toggleSearchAction->setCheckable(true);
+ QAction *toggleSelectionModeAction = actionCollection()->addAction(QStringLiteral("toggle_selection_mode"));
+ // i18n: This action toggles a selection mode.
+ toggleSelectionModeAction->setText(i18nc("@action:inmenu", "Select Files and Folders"));
+ // i18n: Opens a selection mode for selecting files/folders.
+ // The text is kept so unspecific because it will be shown on the toolbar where space is at a premium.
+ toggleSelectionModeAction->setIconText(i18nc("@action:intoolbar", "Select"));
+ toggleSelectionModeAction->setWhatsThis(xi18nc("@info:whatsthis", "<para>This application only knows which files or folders should be acted on if they are"
+ " <emphasis>selected</emphasis> first. Press this to toggle a <emphasis>Selection Mode</emphasis> which makes selecting and deselecting as easy as "
+ "pressing an item once.</para><para>While in this mode, a quick access bar at the bottom shows available actions for the currently selected items."
+ "</para>"));
+ toggleSelectionModeAction->setIcon(QIcon::fromTheme(QStringLiteral("quickwizard")));
+ toggleSelectionModeAction->setCheckable(true);
+ actionCollection()->setDefaultShortcut(toggleSelectionModeAction, Qt::Key_Space );
+ connect(toggleSelectionModeAction, &QAction::triggered, this, &DolphinMainWindow::toggleSelectionMode);
+
+ // A special version of the toggleSelectionModeAction for the toolbar that also contains a menu
+ // with the selectAllAction and invertSelectionAction.
+ auto *toggleSelectionModeToolBarAction = new KToolBarPopupAction(toggleSelectionModeAction->icon(), toggleSelectionModeAction->iconText(), actionCollection());
+ toggleSelectionModeToolBarAction->setToolTip(toggleSelectionModeAction->text());
+ toggleSelectionModeToolBarAction->setWhatsThis(toggleSelectionModeAction->whatsThis());
+ actionCollection()->addAction(QStringLiteral("toggle_selection_mode_tool_bar"), toggleSelectionModeToolBarAction);
+ toggleSelectionModeToolBarAction->setCheckable(true);
+ toggleSelectionModeToolBarAction->setPopupMode(QToolButton::DelayedPopup);
+ connect(toggleSelectionModeToolBarAction, &QAction::triggered, toggleSelectionModeAction, &QAction::trigger);
+ connect(toggleSelectionModeAction, &QAction::toggled, toggleSelectionModeToolBarAction, &QAction::setChecked);
+
QAction* selectAllAction = KStandardAction::selectAll(this, &DolphinMainWindow::selectAll, actionCollection());
selectAllAction->setWhatsThis(xi18nc("@info:whatsthis", "This selects all "
"files and folders in the current location."));
actionCollection()->setDefaultShortcut(invertSelection, Qt::CTRL | Qt::SHIFT | Qt::Key_A);
connect(invertSelection, &QAction::triggered, this, &DolphinMainWindow::invertSelection);
+ QMenu *toggleSelectionModeActionMenu = new QMenu(this);
+ toggleSelectionModeActionMenu->addAction(selectAllAction);
+ toggleSelectionModeActionMenu->addAction(invertSelection);
+ toggleSelectionModeToolBarAction->setMenu(toggleSelectionModeActionMenu);
+
// setup 'View' menu
// (note that most of it is set up in DolphinViewActionHandler)
actionCollection()->setDefaultShortcut(openTerminal, Qt::SHIFT | Qt::Key_F4);
connect(openTerminal, &QAction::triggered, this, &DolphinMainWindow::openTerminal);
-#ifdef HAVE_TERMINAL
+ QAction* openTerminalHere = actionCollection()->addAction(QStringLiteral("open_terminal_here"));
+ // i18n: "Here" refers to the location(s) of the currently selected item(s) or the currently viewed location if nothing is selected.
+ openTerminalHere->setText(i18nc("@action:inmenu Tools", "Open Terminal Here"));
+ openTerminalHere->setWhatsThis(xi18nc("@info:whatsthis",
+ "<para>This opens <emphasis>terminal</emphasis> applications for the selected items' locations.</para>"
+ "<para>To learn more about terminals use the help in the terminal application.</para>"));
+ openTerminalHere->setIcon(QIcon::fromTheme(QStringLiteral("utilities-terminal")));
+ actionCollection()->setDefaultShortcut(openTerminalHere, Qt::SHIFT | Qt::ALT | Qt::Key_F4);
+ connect(openTerminalHere, &QAction::triggered, this, &DolphinMainWindow::openTerminalHere);
+
+#if HAVE_TERMINAL
QAction* focusTerminalPanel = actionCollection()->addAction(QStringLiteral("focus_terminal_panel"));
focusTerminalPanel->setText(i18nc("@action:inmenu Tools", "Focus Terminal Panel"));
focusTerminalPanel->setIcon(QIcon::fromTheme(QStringLiteral("swap-panels")));
// setup 'Settings' menu
KToggleAction* showMenuBar = KStandardAction::showMenubar(nullptr, nullptr, actionCollection());
showMenuBar->setWhatsThis(xi18nc("@info:whatsthis",
- "This switches between having a <emphasis>Menubar</emphasis> "
- "and having a <interface>Control</interface> button. Both "
- "contain mostly the same commands and configuration options."));
+ "<para>This switches between having a <emphasis>Menubar</emphasis> "
+ "and having a <interface>%1</interface> button. Both "
+ "contain mostly the same actions and configuration options.</para>"
+ "<para>The Menubar takes up more space but allows for fast and organised access to all "
+ "actions an application has to offer.</para><para>The <interface>%1</interface> button "
+ "is simpler and small which makes triggering advanced actions more time consuming.</para>", hamburgerMenuAction->text().replace('&', "")));
connect(showMenuBar, &KToggleAction::triggered, // Fixes #286822
this, &DolphinMainWindow::toggleShowMenuBar, Qt::QueuedConnection);
+
+ KToggleAction* showStatusBar = KStandardAction::showStatusbar(nullptr, nullptr, actionCollection());
+ showStatusBar->setChecked(GeneralSettings::showStatusBar());
+ connect(GeneralSettings::self(), &GeneralSettings::showStatusBarChanged, showStatusBar, &KToggleAction::setChecked);
+ connect(showStatusBar, &KToggleAction::triggered, this, [this](bool checked) {
+ GeneralSettings::setShowStatusBar(checked);
+ refreshViews();
+ });
+
KStandardAction::keyBindings(this, &DolphinMainWindow::slotKeyBindings, actionCollection());
KStandardAction::preferences(this, &DolphinMainWindow::editSettings, actionCollection());
- // setup 'Help' menu for the m_controlButton. The other one is set up in the base class.
- m_helpMenu = new KHelpMenu(nullptr);
- m_helpMenu->menu()->installEventFilter(this);
- // remove duplicate shortcuts
- auto removeHelpActionShortcut = [this](KHelpMenu::MenuId menuId) {
- if (auto *action = m_helpMenu->action(menuId)) {
- action->setShortcut(QKeySequence());
- }
- };
- removeHelpActionShortcut(KHelpMenu::menuHelpContents);
- removeHelpActionShortcut(KHelpMenu::menuWhatsThis);
-
// not in menu actions
QList<QKeySequence> nextTabKeys = KStandardShortcut::tabNext();
nextTabKeys.append(QKeySequence(Qt::CTRL | Qt::Key_Tab));
infoDock->setObjectName(QStringLiteral("infoDock"));
infoDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
-#ifdef HAVE_BALOO
+#if HAVE_BALOO
InformationPanel* infoPanel = new InformationPanel(infoDock);
infoPanel->setCustomContextMenuActions({lockLayoutAction});
connect(infoPanel, &InformationPanel::urlActivated, this, &DolphinMainWindow::handleUrl);
// i18n: This is the last paragraph for the "What's This"-texts of all four panels.
const QString panelWhatsThis = xi18nc("@info:whatsthis", "<para>To show or "
- "hide panels like this go to <interface>Control|Panels</interface> "
+ "hide panels like this go to <interface>Menu|Panels</interface> "
"or <interface>View|Panels</interface>.</para>");
-#ifdef HAVE_BALOO
+#if HAVE_BALOO
actionCollection()->action(QStringLiteral("show_information_panel"))
->setWhatsThis(xi18nc("@info:whatsthis", "<para> This toggles the "
"<emphasis>information</emphasis> panel at the right side of the "
"This allows quick switching between any folders.</para>") + panelWhatsThis);
// Setup "Terminal"
-#ifdef HAVE_TERMINAL
+#if HAVE_TERMINAL
if (KAuthorized::authorize(QStringLiteral("shell_access"))) {
DolphinDockWidget* terminalDock = new DolphinDockWidget(i18nc("@title:window Shell terminal", "Terminal"));
terminalDock->setLocked(lock);
panelsMenu->setPopupMode(QToolButton::InstantPopup);
const KActionCollection* ac = actionCollection();
panelsMenu->addAction(ac->action(QStringLiteral("show_places_panel")));
-#ifdef HAVE_BALOO
+#if HAVE_BALOO
panelsMenu->addAction(ac->action(QStringLiteral("show_information_panel")));
#endif
panelsMenu->addAction(ac->action(QStringLiteral("show_folders_panel")));
const KActionCollection* col = actionCollection();
KFileItemListProperties capabilitiesSource(list);
- QAction* addToPlacesAction = col->action(QStringLiteral("add_to_places"));
+ 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* duplicateAction = col->action(QStringLiteral("duplicate")); // see DolphinViewActionHandler
+ QAction* addToPlacesAction = col->action(QStringLiteral("add_to_places"));
QAction* copyToOtherViewAction = col->action(QStringLiteral("copy_to_inactive_split_view"));
QAction* moveToOtherViewAction = col->action(QStringLiteral("move_to_inactive_split_view"));
QAction* copyLocation = col->action(QString("copy_location"));
if (list.isEmpty()) {
stateChanged(QStringLiteral("has_no_selection"));
+ // All actions that need a selection to function can be enabled because they should trigger selection mode.
+ renameAction->setEnabled(true);
+ moveToTrashAction->setEnabled(true);
+ deleteAction->setEnabled(true);
+ cutAction->setEnabled(true);
+ duplicateAction->setEnabled(true);
addToPlacesAction->setEnabled(true);
- copyToOtherViewAction->setEnabled(false);
- moveToOtherViewAction->setEnabled(false);
- copyLocation->setEnabled(false);
+ copyLocation->setEnabled(true);
+ // Them triggering selection mode and not directly acting on selected items is signified by adding "…" to their text.
+ m_actionTextHelper->textsWhenNothingIsSelectedEnabled(true);
+
} else {
+ m_actionTextHelper->textsWhenNothingIsSelectedEnabled(false);
stateChanged(QStringLiteral("has_selection"));
- 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"));
- QAction* duplicateAction = col->action(QStringLiteral("duplicate")); // see DolphinViewActionHandler
if (list.length() == 1 && list.first().isDir()) {
addToPlacesAction->setEnabled(true);
addToPlacesAction->setEnabled(false);
}
- if (m_tabWidget->currentTabPage()->splitViewEnabled()) {
- DolphinTabPage* tabPage = m_tabWidget->currentTabPage();
- KFileItem capabilitiesDestination;
-
- if (tabPage->primaryViewActive()) {
- capabilitiesDestination = tabPage->secondaryViewContainer()->url();
- } else {
- capabilitiesDestination = tabPage->primaryViewContainer()->url();
- }
-
- copyToOtherViewAction->setEnabled(capabilitiesDestination.isWritable());
- moveToOtherViewAction->setEnabled(capabilitiesSource.supportsMoving() && capabilitiesDestination.isWritable());
- } else {
- copyToOtherViewAction->setEnabled(false);
- moveToOtherViewAction->setEnabled(false);
- }
-
const bool enableMoveToTrash = capabilitiesSource.isLocal() && capabilitiesSource.supportsMoving();
renameAction->setEnabled(capabilitiesSource.supportsMoving());
showTarget->setEnabled(list.length() == 1 && list.at(0).isLink());
duplicateAction->setEnabled(capabilitiesSource.supportsWriting());
}
+
+ if (m_tabWidget->currentTabPage()->splitViewEnabled()) {
+ DolphinTabPage* tabPage = m_tabWidget->currentTabPage();
+ KFileItem capabilitiesDestination;
+
+ if (tabPage->primaryViewActive()) {
+ capabilitiesDestination = tabPage->secondaryViewContainer()->url();
+ } else {
+ capabilitiesDestination = tabPage->primaryViewContainer()->url();
+ }
+
+ copyToOtherViewAction->setEnabled(capabilitiesDestination.isWritable());
+ moveToOtherViewAction->setEnabled((list.isEmpty() || capabilitiesSource.supportsMoving()) && capabilitiesDestination.isWritable());
+ } else {
+ copyToOtherViewAction->setEnabled(false);
+ moveToOtherViewAction->setEnabled(false);
+ }
}
void DolphinMainWindow::updateViewActions()
const QAction* toggleSearchAction = actionCollection()->action(QStringLiteral("toggle_search"));
connect(toggleSearchAction, &QAction::triggered, container, &DolphinViewContainer::setSearchModeEnabled);
+ // Make the toggled state of the selection mode actions visually follow the selection mode state of the view.
+ auto toggleSelectionModeAction = actionCollection()->action(QStringLiteral("toggle_selection_mode"));
+ toggleSelectionModeAction->setChecked(m_activeViewContainer->isSelectionModeEnabled());
+ connect(m_activeViewContainer, &DolphinViewContainer::selectionModeChanged,
+ toggleSelectionModeAction, &QAction::setChecked);
+
const DolphinView* view = container->view();
connect(view, &DolphinView::selectionChanged,
this, &DolphinMainWindow::slotSelectionChanged);
"configuration options. Left-click on any of the menus on this "
"bar to see its contents.</para><para>The Menubar can be hidden "
"by unchecking <interface>Settings|Show Menubar</interface>. Then "
- "most of its contents become available through a <interface>Control"
+ "most of its contents become available through a <interface>Menu"
"</interface> button on the <emphasis>Toolbar</emphasis>.</para>"));
toolBar()->setWhatsThis(xi18nc("@info:whatsthis", "<para>This is the "
"<emphasis>Toolbar</emphasis>. It allows quick access to "
"frequently used actions.</para><para>It is highly customizable. "
- "All items you see in the <interface>Control</interface> menu or "
+ "All items you see in the <interface>Menu</interface> or "
"in the <interface>Menubar</interface> can be placed on the "
"Toolbar. Just right-click on it and select <interface>Configure "
- "Toolbars…</interface> or find this action in the <interface>"
- "Control</interface> or <interface>Settings</interface> menu."
+ "Toolbars…</interface> or find this action within the <interface>"
+ "menu</interface>."
"</para><para>The location of the bar and the style of its "
"buttons can also be changed in the right-click menu. Right-click "
"a button if you want to show or hide its text.</para>"));
actionCollection()->action(KStandardAction::name(KStandardAction::ConfigureToolbars))
->setWhatsThis(xi18nc("@info:whatsthis","<para>This opens a window in which "
"you can change which buttons appear on the <emphasis>Toolbar</emphasis>.</para>"
- "<para>All items you see in the <interface>Control</interface> menu "
- "or in the <interface>Menubar</interface> can also be placed on the Toolbar.</para>"));
+ "<para>All items you see in the <interface>Menu</interface> can also be placed on the Toolbar.</para>"));
actionCollection()->action(KStandardAction::name(KStandardAction::Preferences))
->setWhatsThis(xi18nc("@info:whatsthis","This opens a window where you can "
"change a multitude of settings for this application. For an explanation "
"</emphasis> in <interface>Help|Dolphin Handbook</interface>."));
// Help menu
- // The whatsthis has to be set for the m_helpMenu and for the
- // StandardAction separately because both are used in different locations.
- // m_helpMenu is only used for createControlButton() button.
-
- auto setStandardActionWhatsThis = [this](KStandardAction::StandardAction actionId,
- const QString &whatsThis) {
- if (auto *action = actionCollection()->action(KStandardAction::name(actionId))) {
- action->setWhatsThis(whatsThis);
- }
- };
- auto setHelpActionWhatsThis = [this](KHelpMenu::MenuId menuId, const QString &whatsThis) {
- if (auto *action = m_helpMenu->action(menuId)) {
- action->setWhatsThis(whatsThis);
- }
- };
- // Links do not work within the Menubar so texts without links are provided there.
-
- // i18n: If the external link isn't available in your language you should
- // probably state the external link language at least in brackets to not
+ // i18n: If the external link isn't available in your language it might make
+ // sense to state the external link's language in brackets to not
// frustrate the user. If there are multiple languages that the user might
// know with a reasonable chance you might want to have 2 external links.
- // The same is in my opinion true for every external link you translate.
- const QString whatsThisHelpContents = xi18nc("@info:whatsthis handbook",
- "<para>This opens the Handbook for this application. It provides "
- "explanations for every part of <emphasis>Dolphin</emphasis>.</para>");
- setStandardActionWhatsThis(KStandardAction::HelpContents, whatsThisHelpContents
- + xi18nc("@info:whatsthis second half of handbook hb text without link",
- "<para>If you want more elaborate introductions to the "
- "different features of <emphasis>Dolphin</emphasis> "
- "go to the KDE UserBase Wiki.</para>"));
- setHelpActionWhatsThis(KHelpMenu::menuHelpContents, whatsThisHelpContents
- + xi18nc("@info:whatsthis second half of handbook text with link",
- "<para>If you want more elaborate introductions to the "
- "different features of <emphasis>Dolphin</emphasis> "
- "<link url='https://userbase.kde.org/Dolphin/File_Management'>click here</link>. "
- "It will open the dedicated page in the KDE UserBase Wiki.</para>"));
-
- const QString whatsThisWhatsThis = xi18nc("@info:whatsthis whatsthis button",
+ // The same might be true for any external link you translate.
+ actionCollection()->action(KStandardAction::name(KStandardAction::HelpContents))->setWhatsThis(xi18nc("@info:whatsthis handbook", "<para>This opens the Handbook for this application. It provides explanations for every part of <emphasis>Dolphin</emphasis>.</para><para>If you want more elaborate introductions to the different features of <emphasis>Dolphin</emphasis> <link url='https://userbase.kde.org/Dolphin/File_Management'>click here</link>. It will open the dedicated page in the KDE UserBase Wiki.</para>"));
+ // (The i18n call should be completely in the line following the i18n: comment without any line breaks within the i18n call or the comment might not be correctly extracted. See: https://commits.kde.org/kxmlgui/a31135046e1b3335b5d7bbbe6aa9a883ce3284c1 )
+
+ actionCollection()->action(KStandardAction::name(KStandardAction::WhatsThis))->setWhatsThis(
+ xi18nc("@info:whatsthis whatsthis button",
"<para>This is the button that invokes the help feature you are "
"using right now! Click it, then click any component of this "
"application to ask \"What's this?\" about it. The mouse cursor "
- "will change appearance if no help is available for a spot.</para>");
- setStandardActionWhatsThis(KStandardAction::WhatsThis, whatsThisWhatsThis
- + xi18nc("@info:whatsthis second half of whatsthis button text without link",
- "<para>There are two other ways to get help for this application: The "
- "<interface>Dolphin Handbook</interface> in the <interface>Help"
- "</interface> menu and the <emphasis>KDE UserBase Wiki</emphasis> "
- "article about <emphasis>File Management</emphasis> online."
- "</para><para>The \"What's this?\" help is "
- "missing in most other windows so don't get too used to this.</para>"));
- setHelpActionWhatsThis(KHelpMenu::menuWhatsThis, whatsThisWhatsThis
- + xi18nc("@info:whatsthis second half of whatsthis button text with link",
+ "will change appearance if no help is available for a spot.</para>"
"<para>There are two other ways to get help: "
"The <link url='help:/dolphin/index.html'>Dolphin Handbook</link> and "
"the <link url='https://userbase.kde.org/Dolphin/File_Management'>KDE "
"UserBase Wiki</link>.</para><para>The \"What's this?\" help is "
"missing in most other windows so don't get too used to this.</para>"));
- const QString whatsThisReportBug = xi18nc("@info:whatsthis","<para>This opens a "
+ actionCollection()->action(KStandardAction::name(KStandardAction::ReportBug))->setWhatsThis(
+ xi18nc("@info:whatsthis","<para>This opens a "
"window that will guide you through reporting errors or flaws "
- "in this application or in other KDE software.</para>");
- setStandardActionWhatsThis(KStandardAction::ReportBug, whatsThisReportBug);
- setHelpActionWhatsThis(KHelpMenu::menuReportBug, whatsThisReportBug
- + xi18nc("@info:whatsthis second half of reportbug text with link",
+ "in this application or in other KDE software.</para>"
"<para>High-quality bug reports are much appreciated. To learn "
"how to make your bug report as effective as possible "
"<link url='https://community.kde.org/Get_Involved/Bug_Reporting'>"
"click here</link>.</para>"));
- const QString whatsThisDonate = xi18nc("@info:whatsthis","<para>This opens a "
+ actionCollection()->action(KStandardAction::name(KStandardAction::Donate))->setWhatsThis(
+ xi18nc("@info:whatsthis", "<para>This opens a "
"<emphasis>web page</emphasis> where you can donate to "
"support the continued work on this application and many "
"other projects by the <emphasis>KDE</emphasis> community.</para>"
"free therefore your donation is needed to cover things that "
"require money like servers, contributor meetings, etc.</para>"
"<para><emphasis>KDE e.V.</emphasis> is the non-profit "
- "organization behind the KDE community.</para>");
- setStandardActionWhatsThis(KStandardAction::Donate, whatsThisDonate);
- setHelpActionWhatsThis(KHelpMenu::menuDonate, whatsThisDonate);
+ "organization behind the KDE community.</para>"));
- const QString whatsThisSwitchLanguage = xi18nc("@info:whatsthis",
+ actionCollection()->action(KStandardAction::name(KStandardAction::SwitchApplicationLanguage))->setWhatsThis(
+ xi18nc("@info:whatsthis",
"With this you can change the language this application uses."
"<nl/>You can even set secondary languages which will be used "
- "if texts are not available in your preferred language.");
- setStandardActionWhatsThis(KStandardAction::SwitchApplicationLanguage,
- whatsThisSwitchLanguage);
- setHelpActionWhatsThis(KHelpMenu::menuSwitchLanguage, whatsThisSwitchLanguage);
+ "if texts are not available in your preferred language."));
- const QString whatsThisAboutApp = xi18nc("@info:whatsthis","This opens a "
+ actionCollection()->action(KStandardAction::name(KStandardAction::AboutApp))->setWhatsThis(
+ xi18nc("@info:whatsthis","This opens a "
"window that informs you about the version, license, "
- "used libraries and maintainers of this application.");
- setStandardActionWhatsThis(KStandardAction::AboutApp, whatsThisAboutApp);
- setHelpActionWhatsThis(KHelpMenu::menuAboutApp, whatsThisAboutApp);
+ "used libraries and maintainers of this application."));
- const QString whatsThisAboutKDE = xi18nc("@info:whatsthis","This opens a "
+ actionCollection()->action(KStandardAction::name(KStandardAction::AboutKDE))->setWhatsThis(
+ xi18nc("@info:whatsthis","This opens a "
"window with information about <emphasis>KDE</emphasis>. "
"The KDE community are the people behind this free software."
"<nl/>If you like using this application but don't know "
- "about KDE or want to see a cute dragon have a look!");
- setStandardActionWhatsThis(KStandardAction::AboutKDE, whatsThisAboutKDE);
- setHelpActionWhatsThis(KHelpMenu::menuAboutKDE, whatsThisAboutKDE);
+ "about KDE or want to see a cute dragon have a look!"));
}
bool DolphinMainWindow::addHamburgerMenuToToolbar()
// whenever this method is removed (maybe in the year ~2026).
}
-bool DolphinMainWindow::event(QEvent *event)
-{
- if (event->type() == QEvent::WhatsThisClicked) {
- event->accept();
- QWhatsThisClickedEvent* whatsThisEvent = dynamic_cast<QWhatsThisClickedEvent*>(event);
- QDesktopServices::openUrl(QUrl(whatsThisEvent->href()));
- return true;
- }
- return KXmlGuiWindow::event(event);
-}
-
-bool DolphinMainWindow::eventFilter(QObject* obj, QEvent* event)
-{
- Q_UNUSED(obj)
- if (event->type() == QEvent::WhatsThisClicked) {
- event->accept();
- QWhatsThisClickedEvent* whatsThisEvent = dynamic_cast<QWhatsThisClickedEvent*>(event);
- QDesktopServices::openUrl(QUrl(whatsThisEvent->href()));
- return true;
- }
- return false;
-}
-
// Set a sane initial window size
QSize DolphinMainWindow::sizeHint() const
{
}
}
-bool DolphinMainWindow::isUrlOpen(const QString& url)
+bool DolphinMainWindow::isUrlOpen(const QString &url)
{
- return m_tabWidget->isUrlOpen(QUrl::fromUserInput((url)));
+ return m_tabWidget->isUrlOpen(QUrl::fromUserInput(url));
}
+bool DolphinMainWindow::isItemVisibleInAnyView(const QString &urlOfItem)
+{
+ return m_tabWidget->isItemVisibleInAnyView(QUrl::fromUserInput(urlOfItem));
+}