1 /*
2  * SPDX-FileCopyrightText: 2006 Peter Penz <peter.penz19@gmail.com>
3  * SPDX-FileCopyrightText: 2006 Stefan Monov <logixoul@gmail.com>
4  * SPDX-FileCopyrightText: 2006 Cvetoslav Ludmiloff <ludmiloff@gmail.com>
5  *
6  * SPDX-License-Identifier: GPL-2.0-or-later
7  */
8 
9 #ifndef DOLPHIN_MAINWINDOW_H
10 #define DOLPHIN_MAINWINDOW_H
11 
12 #include "dolphintabwidget.h"
13 #include <config-baloo.h>
14 #include <KFileItemActions>
15 #include <kio/fileundomanager.h>
16 #include <kxmlguiwindow.h>
17 
18 #ifdef HAVE_BALOO
19     #include "panels/information/informationpanel.h"
20 #endif
21 
22 #include <QIcon>
23 #include <QList>
24 #include <QMenu>
25 #include <QPointer>
26 #include <QUrl>
27 #include <QVector>
28 
29 typedef KIO::FileUndoManager::CommandType CommandType;
30 
31 class DolphinBookmarkHandler;
32 class DolphinViewActionHandler;
33 class DolphinSettingsDialog;
34 class DolphinViewContainer;
35 class DolphinRemoteEncoding;
36 class DolphinTabWidget;
37 class KFileItem;
38 class KFileItemList;
39 class KJob;
40 class KNewFileMenu;
41 class KHelpMenu;
42 class KToolBarPopupAction;
43 class QToolButton;
44 class PlacesPanel;
45 class TerminalPanel;
46 
47 namespace KIO {
48     class OpenUrlJob;
49 }
50 
51 /**
52  * @short Main window for Dolphin.
53  *
54  * Handles the menus, toolbars and Dolphin views.
55  */
56 class DolphinMainWindow: public KXmlGuiWindow
57 {
58     Q_OBJECT
59     Q_CLASSINFO("D-Bus Interface", "org.kde.dolphin.MainWindow")
60 
61 public:
62     DolphinMainWindow();
63     ~DolphinMainWindow() override;
64 
65     /**
66      * Returns the currently active view.
67      * All menu actions are applied to this view. When
68      * having a split view setup, the nonactive view
69      * is usually shown in darker colors.
70      */
71     DolphinViewContainer* activeViewContainer() const;
72 
73     /**
74      * Returns view container for all tabs
75      */
76     QVector<DolphinViewContainer*> viewContainers() const;
77 
78     /**
79      * Opens each directory in \p dirs in a separate tab. If \a splitView is set,
80      * 2 directories are collected within one tab.
81      * \pre \a dirs must contain at least one url.
82      */
83     void openDirectories(const QList<QUrl> &dirs, bool splitView);
84 
85     /**
86      * Opens the directories which contain the files \p files and selects all files.
87      * If \a splitView is set, 2 directories are collected within one tab.
88      * \pre \a files must contain at least one url.
89      */
90     void openFiles(const QList<QUrl>& files, bool splitView);
91 
92     /**
93      * Returns the 'Create New...' sub menu which also can be shared
94      * with other menus (e. g. a context menu).
95      */
96     KNewFileMenu* newFileMenu() const;
97 
98     /**
99      * Switch the window's view containers' locations to display the home path
100      * for any which are currently displaying a location corresponding to or
101      * within mountPath.
102      *
103      * This typically done after unmounting a disk at mountPath to ensure that
104      * the window is not displaying an invalid location.
105      */
106     void setViewsToHomeIfMountPathOpen(const QString& mountPath);
107 
108     bool isFoldersPanelEnabled() const;
109     bool isInformationPanelEnabled() const;
110 
111 public Q_SLOTS:
112     /**
113      * Opens each directory in \p dirs in a separate tab. If \a splitView is set,
114      * 2 directories are collected within one tab.
115      * \pre \a dirs must contain at least one url.
116      *
117      * @note this function is overloaded so that it is callable via DBus.
118      */
119     void openDirectories(const QStringList &dirs, bool splitView);
120 
121     /**
122      * Opens the directories which contain the files \p files and selects all files.
123      * If \a splitView is set, 2 directories are collected within one tab.
124      * \pre \a files must contain at least one url.
125      *
126      * @note this is overloaded so that this function is callable via DBus.
127      */
128     void openFiles(const QStringList &files, bool splitView);
129 
130     /**
131      * Tries to raise/activate the Dolphin window.
132      */
133     void activateWindow();
134 
135     /**
136      * Determines if a URL is open in any tab.
137      * @note Use of QString instead of QUrl is required to be callable via DBus.
138      *
139      * @param url URL to look for
140      * @returns true if url is currently open in a tab, false otherwise.
141      */
142     bool isUrlOpen(const QString &url);
143 
144 
145     /**
146      * Pastes the clipboard data into the currently selected folder
147      * of the active view. If not exactly one folder is selected,
148      * no pasting is done at all.
149      */
150     void pasteIntoFolder();
151 
152     /**
153      * Implementation of the MainWindowAdaptor/QDBusAbstractAdaptor interface.
154      * Inform all affected dolphin components (panels, views) of an URL
155      * change.
156      */
157     void changeUrl(const QUrl& url);
158 
159     /**
160      * The current directory of the Terminal Panel has changed, probably because
161      * the user entered a 'cd' command. This slot calls changeUrl(url) and makes
162      * sure that the panel keeps the keyboard focus.
163      */
164     void slotTerminalDirectoryChanged(const QUrl& url);
165 
166     /** Stores all settings and quits Dolphin. */
167     void quit();
168 
169     /**
170      * Opens a new tab in the background showing the URL \a url.
171      */
172     void openNewTab(const QUrl& url);
173 
174     /** @see GeneralSettings::splitViewChanged() */
175     void slotSplitViewChanged();
176 
177 Q_SIGNALS:
178     /**
179      * Is sent if the selection of the currently active view has
180      * been changed.
181      */
182     void selectionChanged(const KFileItemList& selection);
183 
184     /**
185      * Is sent if the url of the currently active view has
186      * been changed.
187      */
188     void urlChanged(const QUrl& url);
189 
190     /**
191      * Is emitted if information of an item is requested to be shown e. g. in the panel.
192      * If item is null, no item information request is pending.
193      */
194     void requestItemInfo(const KFileItem& item);
195 
196     /**
197      * It is emitted when in the current view, files are changed,
198      * or dirs have files/removed from them.
199      */
200     void fileItemsChanged(const KFileItemList &changedFileItems);
201 
202     /**
203      * Is emitted if the settings have been changed.
204      */
205     void settingsChanged();
206 
207 protected:
208     /** @see QWidget::showEvent() */
209     void showEvent(QShowEvent* event) override;
210 
211     /** @see QMainWindow::closeEvent() */
212     void closeEvent(QCloseEvent* event) override;
213 
214     /** @see KMainWindow::saveProperties() */
215     void saveProperties(KConfigGroup& group) override;
216 
217     /** @see KMainWindow::readProperties() */
218     void readProperties(const KConfigGroup& group) override;
219 
220     /** Handles QWhatsThisClickedEvent and passes all others on. */
221     bool event(QEvent* event) override;
222     /** Handles QWhatsThisClickedEvent and passes all others on. */
223     bool eventFilter(QObject*, QEvent*) override;
224 
225     /** Sets a sane initial window size **/
226     QSize sizeHint() const override;
227 
228 protected Q_SLOTS:
229     /**
230      * Calls the base method KXmlGuiWindow::saveNewToolbarConfig().
231      * Is also used to set toolbar constraints and UrlNavigator position
232      * based on the newly changed toolbar configuration.
233      */
234     void saveNewToolbarConfig() override;
235 
236 private Q_SLOTS:
237     /**
238      * Refreshes the views of the main window by recreating them according to
239      * the given Dolphin settings.
240      */
241     void refreshViews();
242 
243     void clearStatusBar();
244 
245     /** Updates the 'Create New...' sub menu. */
246     void updateNewMenu();
247 
248     void createDirectory();
249 
250     /** Shows the error message in the status bar of the active view. */
251     void showErrorMessage(const QString& message);
252 
253     /**
254      * Updates the state of the 'Undo' menu action dependent
255      * on the parameter \a available.
256      */
257     void slotUndoAvailable(bool available);
258 
259     /** Sets the text of the 'Undo' menu action to \a text. */
260     void slotUndoTextChanged(const QString& text);
261 
262     /** Performs the current undo operation. */
263     void undo();
264 
265     /**
266      * Copies all selected items to the clipboard and marks
267      * the items as cut.
268      */
269     void cut();
270 
271     /** Copies all selected items to the clipboard. */
272     void copy();
273 
274     /** Pastes the clipboard data to the active view. */
275     void paste();
276 
277     /** Replaces the URL navigator by a search box to find files. */
278     void find();
279 
280     /** Updates the state of the search action according to the view container. */
281     void updateSearchAction();
282 
283     /**
284      * Updates the text of the paste action dependent on
285      * the number of items which are in the clipboard.
286      */
287     void updatePasteAction();
288 
289     /** Selects all items from the active view. */
290     void selectAll();
291 
292     /**
293      * Inverts the selection of all items of the active view:
294      * Selected items get nonselected and nonselected items get
295      * selected.
296      */
297     void invertSelection();
298 
299     /**
300      * Switches between one and two views:
301      * If one view is visible, it will get split into two views.
302      * If already two views are visible, the active view gets closed.
303      */
304     void toggleSplitView();
305 
306     /** Dedicated action to open the stash:/ ioslave in split view. */
307     void toggleSplitStash();
308 
309     /** Reloads the currently active view. */
310     void reloadView();
311 
312     /** Stops the loading process for the currently active view. */
313     void stopLoading();
314 
315     void enableStopAction();
316     void disableStopAction();
317 
318     void showFilterBar();
319     void toggleFilterBar();
320 
321     /**
322      * Toggles between edit and browse mode of the navigation bar.
323      */
324     void toggleEditLocation();
325 
326     /**
327      * Switches to the edit mode of the navigation bar and selects
328      * the whole URL, so that it can be replaced by the user. If the edit mode is
329      * already active, it is assured that the navigation bar get focused.
330      */
331     void replaceLocation();
332 
333     /**
334      * Toggles the state of the panels between a locked and unlocked layout.
335      */
336     void togglePanelLockState();
337 
338     /**
339      * Is invoked if the Terminal panel got visible/invisible and takes care
340      * that the active view has the focus if the Terminal panel is invisible.
341      */
342     void slotTerminalPanelVisibilityChanged();
343 
344     /** Goes back one step of the URL history. */
345     void goBack();
346 
347     /** Goes forward one step of the URL history. */
348     void goForward();
349 
350     /** Goes up one hierarchy of the current URL. */
351     void goUp();
352 
353     /** Changes the location to the home URL. */
354     void goHome();
355 
356     /** Open the previous URL in the URL history in a new tab. */
357     void goBackInNewTab();
358 
359     /** Open the next URL in the URL history in a new tab. */
360     void goForwardInNewTab();
361 
362     /** Open the URL one hierarchy above the current URL in a new tab. */
363     void goUpInNewTab();
364 
365     /** * Open the home URL in a new tab. */
366     void goHomeInNewTab();
367 
368     /** Opens Kompare for 2 selected files. */
369     void compareFiles();
370 
371     /**
372      * Hides the menu bar if it is visible, makes the menu bar
373      * visible if it is hidden.
374      */
375     void toggleShowMenuBar();
376 
377     /** Updates "Open Preferred Search Tool" action. */
378     void updateOpenPreferredSearchToolAction();
379 
380     /** Opens preferred search tool for the current location. */
381     void openPreferredSearchTool();
382 
383     /** Opens a terminal window for the current location. */
384     void openTerminal();
385 
386     /** Focus a Terminal Panel. */
387     void focusTerminalPanel();
388 
389     /** Opens the settings dialog for Dolphin. */
390     void editSettings();
391 
392     /** Updates the state of the 'Show Full Location' action. */
393     void slotEditableStateChanged(bool editable);
394 
395     /**
396      * Updates the state of the 'Edit' menu actions and emits
397      * the signal selectionChanged().
398      */
399     void slotSelectionChanged(const KFileItemList& selection);
400 
401     /**
402      * Updates the state of the 'Back' and 'Forward' menu
403      * actions corresponding to the current history.
404      */
405     void updateHistory();
406 
407     /** Updates the state of the 'Show filter bar' menu action. */
408     void updateFilterBarAction(bool show);
409 
410     /** Open a new main window. */
411     void openNewMainWindow();
412 
413     /**
414      * Opens a new view with the current URL that is part of a tab and
415      * activates it.
416      */
417     void openNewActivatedTab();
418 
419     /**
420      * Adds the current URL as an entry to the Places panel
421      */
422     void addToPlaces();
423 
424     /**
425      * Opens the selected folder in a new tab.
426      */
427     void openInNewTab();
428 
429     /**
430      * Opens the selected folder in a new window.
431      */
432     void openInNewWindow();
433 
434     /**
435      * Show the target of the selected symlink
436      */
437     void showTarget();
438 
439     /**
440      * Indicates in the statusbar that the execution of the command \a command
441      * has been finished.
442      */
443     void showCommand(CommandType command);
444 
445     /**
446      * If the URL can be listed, open it in the current view, otherwise
447      * run it through KRun.
448      */
449     void handleUrl(const QUrl& url);
450 
451     /**
452      * Is invoked when the write state of a folder has been changed and
453      * enables/disables the "Create New..." menu entry.
454      */
455     void slotWriteStateChanged(bool isFolderWritable);
456 
457     /**
458      * Opens the context menu on the current mouse position.
459      * @pos           Position in screen coordinates.
460      * @item          File item context. If item is null, the context menu
461      *                should be applied to \a url.
462      * @url           URL which contains \a item.
463      * @customActions Actions that should be added to the context menu,
464      *                if the file item is null.
465      */
466     void openContextMenu(const QPoint& pos,
467                          const KFileItem& item,
468                          const QUrl& url,
469                          const QList<QAction*>& customActions);
470 
471     /**
472      * Updates the menu that is by default at the right end of the toolbar.
473      *
474      * In true "simple by default" fashion, the menu only contains the most important
475      * and necessary actions to be able to use Dolphin. This is supposed to hold true even
476      * if the user does not know how to open a context menu. More advanced actions can be
477      * discovered through a sub-menu (@see KConfigWidgets::KHamburgerMenu::setMenuBarAdvertised()).
478      */
479     void updateHamburgerMenu();
480 
481     /**
482      * Is called if the user clicked an item in the Places Panel.
483      * Reloads the view if \a url is the current URL already, and changes the
484      * current URL otherwise.
485      */
486     void slotPlaceActivated(const QUrl& url);
487 
488     /**
489      * Is called if the another view has been activated by changing the current
490      * tab or activating another view in split-view mode.
491      *
492      * Activates the given view, which means that all menu actions are applied
493      * to this view. When having a split view setup, the nonactive view is
494      * usually shown in darker colors.
495      */
496     void activeViewChanged(DolphinViewContainer* viewContainer);
497 
498     void closedTabsCountChanged(unsigned int count);
499 
500     /**
501      * Is called if a new tab has been opened or a tab has been closed to
502      * enable/disable the tab actions.
503      */
504     void tabCountChanged(int count);
505 
506     /**
507      * Updates the Window Title with the caption from the active view container
508      */
509     void updateWindowTitle();
510 
511     /**
512      * This slot is called when the user requested to unmount a removable media
513      * from the places menu
514      */
515     void slotStorageTearDownFromPlacesRequested(const QString& mountPath);
516 
517     /**
518      * This slot is called when the user requested to unmount a removable media
519      * _not_ from the dolphin's places menu (from the notification area for e.g.)
520      * This slot is basically connected to each removable device's
521      * Solid::StorageAccess::teardownRequested(const QString & udi)
522      * signal through the places panel.
523      */
524     void slotStorageTearDownExternallyRequested(const QString& mountPath);
525 
526     /**
527      * Is called when the view has finished loading the directory.
528      */
529     void slotDirectoryLoadingCompleted();
530 
531     /**
532      * Is called when the user middle clicks a toolbar button.
533      *
534      * Here middle clicking Back/Forward/Up/Home will open the resulting
535      * folder in a new tab.
536      */
537     void slotToolBarActionMiddleClicked(QAction *action);
538 
539     /**
540      * Is called before the Back popup menu is shown. This slot will populate
541      * the menu with history data
542      */
543     void slotAboutToShowBackPopupMenu();
544 
545     /**
546       * This slot is used by the Back Popup Menu to go back to a specific
547       * history index. The QAction::data will carry an int with the index
548       * to go to.
549       */
550     void slotGoBack(QAction* action);
551 
552     /**
553      * Middle clicking Back/Forward will open the resulting folder in a new tab.
554      */
555     void slotBackForwardActionMiddleClicked(QAction *action);
556 
557     /**
558      * Is called before the Forward popup menu is shown. This slot will populate
559      * the menu with history data
560      */
561     void slotAboutToShowForwardPopupMenu();
562 
563     /**
564       * This slot is used by the Forward Popup Menu to go forward to a specific
565       * history index. The QAction::data will carry an int with the index
566       * to go to.
567       */
568     void slotGoForward(QAction* action);
569 private:
570     /**
571      * Sets up the various menus and actions and connects them.
572      */
573     void setupActions();
574 
575     /**
576      * Sets up the dock widgets and their panels.
577      */
578     void setupDockWidgets();
579 
580     void updateFileAndEditActions();
581     void updateViewActions();
582     void updateGoActions();
583 
584     /**
585      * Connects the signals from the created DolphinView with
586      * the DolphinViewContainer \a container with the corresponding slots of
587      * the DolphinMainWindow. This method must be invoked each
588      * time a DolphinView has been created.
589      */
590     void connectViewSignals(DolphinViewContainer* container);
591 
592     /**
593      * Updates the text of the split action:
594      * If two views are shown, the text is set to "Split",
595      * otherwise the text is set to "Join". The icon
596      * is updated to match with the text and the currently active view.
597      */
598     void updateSplitAction();
599 
600     /**
601      * Sets the window sides the toolbar may be moved to based on toolbar contents.
602      */
603     void updateAllowedToolbarAreas();
604 
605     bool isKompareInstalled() const;
606 
607     /**
608      * Creates an action for showing/hiding a panel, that is accessible
609      * in "Configure toolbars..." and "Configure shortcuts...". This is necessary
610      * as the action for toggling the dock visibility is done by Qt which
611      * is no KAction instance.
612      */
613     void createPanelAction(const QIcon &icon,
614                            const QKeySequence& shortcut,
615                            QAction* dockAction,
616                            const QString& actionName);
617 
618     /** Adds "What's This?" texts to many widgets and StandardActions. */
619     void setupWhatsThis();
620 
621     /** Returns preferred search tool as configured in "More Search Tools" menu. */
622     QPointer<QAction> preferredSearchTool();
623 
624     /**
625      * Adds this action to the mainWindow's toolbar and saves the change
626      * in the users ui configuration file.
627      * This method is only needed for migration and should be removed once we can expect
628      * that pretty much all users have been migrated. Remove in 2026 because that's when
629      * even the most risk-averse distros will already have been forced to upgrade.
630      * @return true if successful. Otherwise false.
631      */
632     bool addHamburgerMenuToToolbar();
633 
634 private:
635     /**
636      * Implements a custom error handling for the undo manager. This
637      * assures that all errors are shown in the status bar of Dolphin
638      * instead as modal error dialog with an OK button.
639      */
640     class UndoUiInterface : public KIO::FileUndoManager::UiInterface
641     {
642     public:
643         UndoUiInterface();
644         ~UndoUiInterface() override;
645         void jobError(KIO::Job* job) override;
646     };
647 
648     KNewFileMenu* m_newFileMenu;
649     KHelpMenu* m_helpMenu;
650     DolphinTabWidget* m_tabWidget;
651     DolphinViewContainer* m_activeViewContainer;
652 
653     DolphinViewActionHandler* m_actionHandler;
654     DolphinRemoteEncoding* m_remoteEncoding;
655     QPointer<DolphinSettingsDialog> m_settingsDialog;
656     DolphinBookmarkHandler* m_bookmarkHandler;
657 
658     // Members for the toolbar menu that is shown when the menubar is hidden:
659     QToolButton* m_controlButton;
660     QTimer* m_updateToolBarTimer;
661 
662     KIO::OpenUrlJob *m_lastHandleUrlOpenJob;
663 
664     TerminalPanel* m_terminalPanel;
665     PlacesPanel* m_placesPanel;
666     bool m_tearDownFromPlacesRequested;
667 
668     KToolBarPopupAction* m_backAction;
669     KToolBarPopupAction* m_forwardAction;
670 
671     QMenu m_searchTools;
672     KFileItemActions m_fileItemActions;
673 
674 };
675 
activeViewContainer()676 inline DolphinViewContainer* DolphinMainWindow::activeViewContainer() const
677 {
678     return m_activeViewContainer;
679 }
680 
newFileMenu()681 inline KNewFileMenu* DolphinMainWindow::newFileMenu() const
682 {
683     return m_newFileMenu;
684 }
685 
686 #endif // DOLPHIN_MAINWINDOW_H
687 
688