+ 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('\"');
+
+ KIO::CommandLauncherJob *job = new KIO::CommandLauncherJob(command, this);
+ job->setDesktopName(QStringLiteral("org.kde.kompare"));
+ job->start();
+}
+
+void DolphinMainWindow::toggleShowMenuBar()
+{
+ const bool visible = menuBar()->isVisible();
+ menuBar()->setVisible(!visible);
+}
+
+QPointer<QAction> DolphinMainWindow::preferredSearchTool()
+{
+ m_searchTools.clear();
+ KMoreToolsMenuFactory("dolphin/search-tools").fillMenuFromGroupingNames(&m_searchTools, {"files-find"}, m_activeViewContainer->url());
+ QList<QAction *> actions = m_searchTools.actions();
+ if (actions.isEmpty()) {
+ return nullptr;
+ }
+ QAction *action = actions.first();
+ if (action->isSeparator()) {
+ return nullptr;
+ }
+ return action;
+}
+
+void DolphinMainWindow::updateOpenPreferredSearchToolAction()
+{
+ QAction *openPreferredSearchTool = actionCollection()->action(QStringLiteral("open_preferred_search_tool"));
+ if (!openPreferredSearchTool) {
+ return;
+ }
+ QPointer<QAction> tool = preferredSearchTool();
+ if (tool) {
+ openPreferredSearchTool->setVisible(true);
+ openPreferredSearchTool->setText(i18nc("@action:inmenu Tools", "Open %1", tool->text()));
+ // Only override with the app icon if it is the default, i.e. the user hasn't configured one manually
+ // https://bugs.kde.org/show_bug.cgi?id=442815
+ if (openPreferredSearchTool->icon().name() == QLatin1String("search")) {
+ openPreferredSearchTool->setIcon(tool->icon());
+ }
+ } else {
+ openPreferredSearchTool->setVisible(false);
+ // still visible in Shortcuts configuration window
+ openPreferredSearchTool->setText(i18nc("@action:inmenu Tools", "Open Preferred Search Tool"));
+ openPreferredSearchTool->setIcon(QIcon::fromTheme(QStringLiteral("search")));
+ }
+}
+
+void DolphinMainWindow::openPreferredSearchTool()
+{
+ QPointer<QAction> tool = preferredSearchTool();
+ if (tool) {
+ tool->trigger();
+ }
+}
+
+void DolphinMainWindow::openTerminal()
+{
+ 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());
+#if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0)
+ const int answer = KMessageBox::warningTwoActions(
+ this,
+ question,
+ {},
+#else
+ const int answer = KMessageBox::warningYesNo(
+ this,
+ question,
+ {},
+#endif
+ KGuiItem(i18ncp("@action:button", "Open %1 Terminal", "Open %1 Terminals", urls.count()), QStringLiteral("utilities-terminal")),
+ KStandardGuiItem::cancel());
+#if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0)
+ if (answer != KMessageBox::PrimaryAction) {
+#else
+ if (answer != KMessageBox::Yes) {
+#endif
+ 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());
+ job->start();
+ return;
+ }
+
+ // Not a local file, with protocol Class ":local", try stat'ing
+ if (KProtocolInfo::protocolClass(url.scheme()) == QLatin1String(":local")) {
+ KIO::StatJob *job = KIO::mostLocalUrl(url);
+ KJobWidgets::setWindow(job, this);
+ connect(job, &KJob::result, this, [job]() {
+ QUrl statUrl;
+ if (!job->error()) {
+ statUrl = job->mostLocalUrl();
+ }
+
+ auto job = new KTerminalLauncherJob(QString());
+ job->setWorkingDirectory(statUrl.isLocalFile() ? statUrl.toLocalFile() : QDir::homePath());
+ job->start();
+ });
+
+ return;
+ }
+
+ // Nothing worked, just use $HOME
+ auto job = new KTerminalLauncherJob(QString());
+ job->setWorkingDirectory(QDir::homePath());
+ job->start();
+}
+
+void DolphinMainWindow::editSettings()
+{
+ if (!m_settingsDialog) {
+ DolphinViewContainer *container = activeViewContainer();
+ container->view()->writeSettings();
+
+ const QUrl url = container->url();
+ DolphinSettingsDialog *settingsDialog = new DolphinSettingsDialog(url, this, actionCollection());
+ connect(settingsDialog, &DolphinSettingsDialog::settingsChanged, this, &DolphinMainWindow::refreshViews);
+ connect(settingsDialog, &DolphinSettingsDialog::settingsChanged, &DolphinUrlNavigatorsController::slotReadSettings);
+ settingsDialog->setAttribute(Qt::WA_DeleteOnClose);
+ settingsDialog->show();
+ m_settingsDialog = settingsDialog;
+ } else {
+ m_settingsDialog.data()->raise();
+ }
+}
+
+void DolphinMainWindow::handleUrl(const QUrl &url)
+{
+ delete m_lastHandleUrlOpenJob;
+ m_lastHandleUrlOpenJob = nullptr;
+
+ if (url.isLocalFile() && QFileInfo(url.toLocalFile()).isDir()) {
+ 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, [this, url](const QString &mimetype) {
+ if (mimetype == QLatin1String("inode/directory")) {
+ // If it's a dir, we'll take it from here
+ m_lastHandleUrlOpenJob->kill();
+ m_lastHandleUrlOpenJob = nullptr;
+ activeViewContainer()->setUrl(url);
+ }
+ });
+
+ connect(m_lastHandleUrlOpenJob, &KIO::OpenUrlJob::result, this, [this]() {
+ m_lastHandleUrlOpenJob = nullptr;
+ });
+
+ m_lastHandleUrlOpenJob->start();
+ }
+}
+
+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 KFileItemList &selectedItems, const QUrl &url)
+{
+ 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) {
+ contextMenu->deleteLater();
+ }
+}
+
+QMenu *DolphinMainWindow::createPopupMenu()
+{
+ QMenu *menu = KXmlGuiWindow::createPopupMenu();
+
+ menu->addSeparator();
+ menu->addAction(actionCollection()->action(QStringLiteral("lock_panels")));
+
+ return menu;
+}
+
+void DolphinMainWindow::updateHamburgerMenu()
+{
+ KActionCollection *ac = actionCollection();
+ auto hamburgerMenu = static_cast<KHamburgerMenu *>(ac->action(KStandardAction::name(KStandardAction::HamburgerMenu)));
+ auto menu = hamburgerMenu->menu();
+ if (!menu) {
+ menu = new QMenu(this);
+ hamburgerMenu->setMenu(menu);
+ hamburgerMenu->hideActionsOf(ac->action(QStringLiteral("basic_actions"))->menu());
+ hamburgerMenu->hideActionsOf(ac->action(QStringLiteral("zoom"))->menu());
+ } else {
+ menu->clear();
+ }
+ const QList<QAction *> toolbarActions = toolBar()->actions();
+
+ if (!toolBar()->isVisible()) {
+ // If neither the menu bar nor the toolbar are visible, these actions should be available.
+ menu->addAction(ac->action(KStandardAction::name(KStandardAction::ShowMenubar)));
+ menu->addAction(toolBarMenuAction());
+ menu->addSeparator();
+ }
+
+ // This group of actions (until the next separator) contains all the most basic actions
+ // necessary to use Dolphin effectively.
+ menu->addAction(ac->action(QStringLiteral("go_back")));
+ 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()
+ || (!toolbarActions.contains(ac->action(QStringLiteral("toggle_search")))
+ && !toolbarActions.contains(ac->action(QStringLiteral("open_preferred_search_tool"))))) {
+ menu->addAction(ac->action(KStandardAction::name(KStandardAction::Find)));
+ // This way a search action will only be added if none of the three available
+ // search actions is present on the toolbar.
+ }
+ if (!toolBar()->isVisible() || !toolbarActions.contains(ac->action(QStringLiteral("toggle_filter")))) {
+ menu->addAction(ac->action(QStringLiteral("show_filter_bar")));
+ // This way a filter action will only be added if none of the two available
+ // filter actions is present on the toolbar.
+ }
+ menu->addSeparator();
+
+ // The second group of actions (up until the next separator) contains actions for opening
+ // additional views to interact with the file system.
+ menu->addAction(ac->action(QStringLiteral("file_new")));
+ menu->addAction(ac->action(QStringLiteral("new_tab")));
+ if (ac->action(QStringLiteral("undo_close_tab"))->isEnabled()) {
+ menu->addAction(ac->action(QStringLiteral("closed_tabs")));
+ }
+ menu->addAction(ac->action(QStringLiteral("open_terminal")));
+ menu->addSeparator();
+
+ // The third group contains actions to change what one sees in the view
+ // and to change the more general UI.
+ if (!toolBar()->isVisible()
+ || (!toolbarActions.contains(ac->action(QStringLiteral("icons"))) && !toolbarActions.contains(ac->action(QStringLiteral("compact")))
+ && !toolbarActions.contains(ac->action(QStringLiteral("details"))) && !toolbarActions.contains(ac->action(QStringLiteral("view_mode"))))) {
+ menu->addAction(ac->action(QStringLiteral("view_mode")));
+ }
+ menu->addAction(ac->action(QStringLiteral("show_hidden_files")));
+ menu->addAction(ac->action(QStringLiteral("sort")));
+ menu->addAction(ac->action(QStringLiteral("additional_info")));
+ if (!GeneralSettings::showStatusBar() || !GeneralSettings::showZoomSlider()) {
+ menu->addAction(ac->action(QStringLiteral("zoom")));
+ }
+ menu->addAction(ac->action(QStringLiteral("panels")));
+
+ // The "Configure" menu is not added to the actionCollection() because there is hardly
+ // a good reason for users to put it on their toolbar.
+ auto configureMenu = menu->addMenu(QIcon::fromTheme(QStringLiteral("configure")), i18nc("@action:inmenu menu for configure actions", "Configure"));
+ configureMenu->addAction(ac->action(KStandardAction::name(KStandardAction::SwitchApplicationLanguage)));
+ configureMenu->addAction(ac->action(KStandardAction::name(KStandardAction::KeyBindings)));
+ configureMenu->addAction(ac->action(KStandardAction::name(KStandardAction::ConfigureToolbars)));
+ configureMenu->addAction(ac->action(KStandardAction::name(KStandardAction::Preferences)));
+ hamburgerMenu->hideActionsOf(configureMenu);
+}
+
+void DolphinMainWindow::slotPlaceActivated(const QUrl &url)
+{
+ DolphinViewContainer *view = activeViewContainer();
+
+ if (view->url() == url) {
+ view->clearFilterBar(); // Fixes bug 259382.
+
+ // 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 {
+ view->disableUrlNavigatorSelectionRequests();
+ changeUrl(url);
+ view->enableUrlNavigatorSelectionRequests();
+ }
+}
+
+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);
+