1 /* This file is part of the KDE project
2    SPDX-FileCopyrightText: 2001 Christoph Cullmann <cullmann@kde.org>
3    SPDX-FileCopyrightText: 2001 Joseph Wenninger <jowenn@kde.org>
4    SPDX-FileCopyrightText: 2001 Anders Lund <anders.lund@lund.tdcadsl.dk>
5 
6    SPDX-License-Identifier: LGPL-2.0-only
7 */
8 
9 #ifndef __KATE_MAINWINDOW_H__
10 #define __KATE_MAINWINDOW_H__
11 
12 #include "katemdi.h"
13 #include "kateviewmanager.h"
14 
15 #include <ktexteditor/document.h>
16 #include <ktexteditor/mainwindow.h>
17 #include <ktexteditor/view.h>
18 
19 #include <KParts/Part>
20 
21 #include <QDragEnterEvent>
22 #include <QDropEvent>
23 #include <QEvent>
24 #include <QHash>
25 #include <QModelIndex>
26 #include <QStackedLayout>
27 #include <QStackedWidget>
28 #include <QUrl>
29 #include <QVBoxLayout>
30 
31 class QMenu;
32 
33 namespace KIO
34 {
35 class UDSEntry;
36 typedef class QList<UDSEntry> UDSEntryList;
37 }
38 
39 class KFileItem;
40 class KRecentFilesAction;
41 
42 class KateOutputView;
43 class KateViewManager;
44 class KateMwModOnHdDialog;
45 
46 // Helper layout class to always provide minimum size
47 class KateContainerStackedLayout : public QStackedLayout
48 {
49     Q_OBJECT
50 public:
51     KateContainerStackedLayout(QWidget *parent);
52     QSize sizeHint() const override;
53     QSize minimumSize() const override;
54 };
55 
56 class KateMainWindow : public KateMDI::MainWindow, virtual public KParts::PartBase
57 {
58     Q_OBJECT
59 
60 public:
61     /**
62      * Construct the window and restore its state from given config if any
63      * @param sconfig session config for this window, 0 if none
64      * @param sgroup session config group to use
65      */
66     KateMainWindow(KConfig *sconfig, const QString &sgroup);
67 
68     /**
69      * Destruct the nice window
70      */
71     ~KateMainWindow() override;
72 
73     /**
74      * Accessor methodes for interface and child objects
75      */
76 public:
viewManager()77     KateViewManager *viewManager()
78     {
79         return m_viewManager;
80     }
81 
82     /**
83      * KTextEditor::MainWindow wrapper
84      * @return KTextEditor::MainWindow wrapper.
85      */
wrapper()86     KTextEditor::MainWindow *wrapper()
87     {
88         return m_wrapper;
89     }
90 
91 public:
92     /** Returns the URL of the current document.
93      * anders: I add this for use from the file selector. */
94     QUrl activeDocumentUrl();
95 
96     /** Enumeration to specify if files modified on disk should show up
97      * in the reload dialog even if not edited in this instance. */
98     enum ModOnDiskMode {
99         PromptEdited, ///< Do not list files that have not been edited
100         PromptAll, ///< Include all files modified on disk
101     };
102 
103     /**
104      * Prompts the user for what to do with files that are modified on disk if any.
105      * This is optionally run when the window receives focus, and when the last
106      * window is closed.
107      * @return true if no documents are modified on disk, or all documents were
108      * handled by the dialog; otherwise (the dialog was canceled) false.
109      */
110     bool showModOnDiskPrompt(ModOnDiskMode mode);
111 
112 public:
113     /*reimp*/ void readProperties(const KConfigGroup &config) override;
114     /*reimp*/ void saveProperties(KConfigGroup &config) override;
115     /*reimp*/ void saveGlobalProperties(KConfig *sessionConfig) override;
116 
117     void saveOpenRecent(KConfig *config);
118     void loadOpenRecent(const KConfig *config);
119 
120 public:
121     bool queryClose_internal(KTextEditor::Document *doc = nullptr);
122 
123     /**
124      * save the settings, size and state of this window in
125      * the provided config group
126      */
127     void saveWindowConfig(const KConfigGroup &);
128     /**
129      * restore the settings, size and state of this window from
130      * the provided config group.
131      */
132     void restoreWindowConfig(const KConfigGroup &);
133 
134     /**
135      * save some global options to katerc
136      */
137     void saveOptions();
138 
139 private:
140     /**
141      * Setup actions which pointers are needed already in setupMainWindow
142      */
143     void setupImportantActions();
144 
145     void setupMainWindow();
146     void setupActions();
147     bool queryClose() override;
148 
149     /**
150      * read some global options from katerc
151      */
152     void readOptions();
153 
154     void dragEnterEvent(QDragEnterEvent *) override;
155     void dropEvent(QDropEvent *) override;
156 
157 public Q_SLOTS:
158     void slotFileClose();
159     void slotFileQuit();
160     void queueModifiedOnDisc(KTextEditor::Document *doc);
161 
162     void slotFocusPrevTab();
163     void slotFocusNextTab();
164 
165     /**
166      * Show quick open
167      */
168     void slotQuickOpen();
169 
170     void slotCommandBarOpen();
171 
172     /**
173      * Overwrite size hint for better default window sizes
174      * @return size hint
175      */
176     QSize sizeHint() const override;
177 
178     /**
179      * slots used for actions in the menus/toolbars
180      * or internal signal connections
181      */
182 private Q_SLOTS:
183     void newWindow();
184 
185     void slotConfigure();
186 
187     void slotOpenWithMenuAction(QAction *a);
188 
189     void slotEditToolbars();
190     void slotNewToolbarConfig();
191     void slotUpdateOpenWith();
192     void slotUpdateActionsNeedingUrl();
193     void slotOpenDocument(const QUrl &);
194 
195     void slotDropEvent(QDropEvent *);
196     void editKeys();
197     void mSlotFixOpenWithMenu();
198     void reloadXmlGui();
199 
200     /* to update the caption */
201     void slotDocumentCreated(KTextEditor::Document *doc);
202     void updateCaption(KTextEditor::Document *doc);
203     // calls updateCaption(doc) with the current document
204     void updateCaption();
205 
206     void pluginHelp();
207     void slotFullScreen(bool);
208 
209     void slotListRecursiveEntries(KIO::Job *job, const KIO::UDSEntryList &list);
210 
211 private Q_SLOTS:
212     void toggleShowMenuBar(bool showMessage = true);
213     void toggleShowStatusBar();
214     void toggleShowTabBar();
215 
216 public:
217     bool showStatusBar();
218     bool showTabBar();
219 
220 Q_SIGNALS:
221     void statusBarToggled();
222     void tabBarToggled();
223     void unhandledShortcutOverride(QEvent *e);
224 
225 public:
226     void openUrl(const QString &name = QString());
227 
pluginViews()228     QHash<KTextEditor::Plugin *, QObject *> &pluginViews()
229     {
230         return m_pluginViews;
231     }
232 
bottomViewBarContainer()233     QWidget *bottomViewBarContainer()
234     {
235         return m_bottomViewBarContainer;
236     }
237 
addToBottomViewBarContainer(KTextEditor::View * view,QWidget * bar)238     void addToBottomViewBarContainer(KTextEditor::View *view, QWidget *bar)
239     {
240         m_bottomContainerStack->addWidget(bar);
241         m_bottomViewBarMapping[view] = BarState(bar);
242     }
243 
hideBottomViewBarForView(KTextEditor::View * view)244     void hideBottomViewBarForView(KTextEditor::View *view)
245     {
246         BarState &state = m_bottomViewBarMapping[view];
247         if (state.bar()) {
248             m_bottomContainerStack->setCurrentWidget(state.bar());
249             state.bar()->hide();
250             state.setState(false);
251         }
252         m_bottomViewBarContainer->hide();
253     }
254 
showBottomViewBarForView(KTextEditor::View * view)255     void showBottomViewBarForView(KTextEditor::View *view)
256     {
257         BarState &state = m_bottomViewBarMapping[view];
258         if (state.bar()) {
259             m_bottomContainerStack->setCurrentWidget(state.bar());
260             state.bar()->show();
261             state.setState(true);
262             m_bottomViewBarContainer->show();
263         }
264     }
265 
deleteBottomViewBarForView(KTextEditor::View * view)266     void deleteBottomViewBarForView(KTextEditor::View *view)
267     {
268         BarState state = m_bottomViewBarMapping.take(view);
269         if (state.bar()) {
270             if (m_bottomContainerStack->currentWidget() == state.bar()) {
271                 m_bottomViewBarContainer->hide();
272             }
273             delete state.bar();
274         }
275     }
276 
modNotificationEnabled()277     bool modNotificationEnabled() const
278     {
279         return m_modNotification;
280     }
281 
setModNotificationEnabled(bool e)282     void setModNotificationEnabled(bool e)
283     {
284         m_modNotification = e;
285     }
286 
modCloseAfterLast()287     bool modCloseAfterLast() const
288     {
289         return m_modCloseAfterLast;
290     }
291 
setModCloseAfterLast(bool e)292     void setModCloseAfterLast(bool e)
293     {
294         m_modCloseAfterLast = e;
295     }
296 
297     /**
298      * add given url to list of recently opened files
299      * @param url url that got opened
300      */
301     void addRecentOpenedFile(const QUrl &url);
302 
303     //
304     // KTextEditor::MainWindow interface, get called by invokeMethod from our wrapper object!
305     //
306 public Q_SLOTS:
307     /**
308      * get the toplevel widget.
309      * \return the real main window widget.
310      */
window()311     QWidget *window()
312     {
313         return this;
314     }
315 
316     /**
317      * Accessor to the XMLGUIFactory.
318      * \return the mainwindow's KXMLGUIFactory.
319      */
guiFactory()320     KXMLGUIFactory *guiFactory() override
321     {
322         return KateMDI::MainWindow::guiFactory();
323     }
324 
325     /**
326      * Get a list of all views for this main window.
327      * @return all views
328      */
views()329     QList<KTextEditor::View *> views()
330     {
331         return viewManager()->views();
332     }
333 
334     /**
335      * Access the active view.
336      * \return active view
337      */
activeView()338     KTextEditor::View *activeView()
339     {
340         return viewManager()->activeView();
341     }
342 
343     /**
344      * Activate the view with the corresponding \p document.
345      * If none exist for this document, create one
346      * \param document the document
347      * \return activated view of this document
348      */
activateView(KTextEditor::Document * document)349     KTextEditor::View *activateView(KTextEditor::Document *document)
350     {
351         return viewManager()->activateView(document);
352     }
353 
354     /**
355      * Open the document \p url with the given \p encoding.
356      * \param url the document's url
357      * \param encoding the preferred encoding. If encoding is QString() the
358      *        encoding will be guessed or the default encoding will be used.
359      * \return a pointer to the created view for the new document, if a document
360      *         with this url is already existing, its view will be activated
361      */
362     KTextEditor::View *openUrl(const QUrl &url, const QString &encoding = QString())
363     {
364         return viewManager()->openUrlWithView(url, encoding);
365     }
366 
367     /**
368      * Close selected view
369      * \param view the view
370      * \return true if view was closed
371      */
closeView(KTextEditor::View * view)372     bool closeView(KTextEditor::View *view)
373     {
374         m_viewManager->closeView(view);
375         return true;
376     }
377 
378     /**
379      * Close the split view where the given view is contained.
380      * \param view the view.
381      * \return true if the split view was closed.
382      */
closeSplitView(KTextEditor::View * view)383     bool closeSplitView(KTextEditor::View *view)
384     {
385         m_viewManager->closeViewSpace(view);
386         return true;
387     }
388 
389     /**
390      * @returns true if the two given views share the same split view,
391      * false otherwise.
392      */
viewsInSameSplitView(KTextEditor::View * view1,KTextEditor::View * view2)393     bool viewsInSameSplitView(KTextEditor::View *view1, KTextEditor::View *view2)
394     {
395         return m_viewManager->viewsInSameViewSpace(view1, view2);
396     }
397 
398     /**
399      * Split current view space according to \p orientation
400      * \param orientation in which line split the view
401      */
splitView(Qt::Orientation orientation)402     void splitView(Qt::Orientation orientation)
403     {
404         m_viewManager->splitViewSpace(nullptr, orientation);
405     }
406 
407     /**
408      * Try to create a view bar for the given view.
409      * Its parameter is the view for which we want a view bar
410      * @return suitable widget that can host view bars widgets or nullptr
411      */
createViewBar(KTextEditor::View *)412     QWidget *createViewBar(KTextEditor::View *)
413     {
414         return bottomViewBarContainer();
415     }
416 
417     /**
418      * Delete the view bar for the given view.
419      * @param view view for which we want an view bar
420      */
deleteViewBar(KTextEditor::View * view)421     void deleteViewBar(KTextEditor::View *view)
422     {
423         deleteBottomViewBarForView(view);
424     }
425 
426     /**
427      * Add a widget to the view bar.
428      * @param view view for which the view bar is used
429      * @param bar bar widget, shall have the viewBarParent() as parent widget
430      */
addWidgetToViewBar(KTextEditor::View * view,QWidget * bar)431     void addWidgetToViewBar(KTextEditor::View *view, QWidget *bar)
432     {
433         addToBottomViewBarContainer(view, bar);
434     }
435 
436     /**
437      * Show the view bar for the given view
438      * @param view view for which the view bar is used
439      */
showViewBar(KTextEditor::View * view)440     void showViewBar(KTextEditor::View *view)
441     {
442         showBottomViewBarForView(view);
443     }
444 
445     /**
446      * Hide the view bar for the given view
447      * @param view view for which the view bar is used
448      */
hideViewBar(KTextEditor::View * view)449     void hideViewBar(KTextEditor::View *view)
450     {
451         hideBottomViewBarForView(view);
452     }
453 
454     /**
455      * Create a new toolview with unique \p identifier at side \p pos
456      * with \p icon and caption \p text. Use the returned widget to embed
457      * your widgets.
458      * \param plugin which owns this tool view
459      * \param identifier unique identifier for this toolview
460      * \param pos position for the toolview, if we are in session restore,
461      *        this is only a preference
462      * \param icon icon to use in the sidebar for the toolview
463      * \param text translated text (i18n()) to use in addition to icon
464      * \return created toolview on success, otherwise NULL
465      */
466     QWidget *createToolView(KTextEditor::Plugin *plugin,
467                             const QString &identifier,
468                             KTextEditor::MainWindow::ToolViewPosition pos,
469                             const QIcon &icon,
470                             const QString &text);
471 
472     /**
473      * Move the toolview \p widget to position \p pos.
474      * \param widget the toolview to move, where the widget was constructed
475      *        by createToolView().
476      * \param pos new position to move widget to
477      * \return \e true on success, otherwise \e false
478      */
479     bool moveToolView(QWidget *widget, KTextEditor::MainWindow::ToolViewPosition pos);
480 
481     /**
482      * Show the toolview \p widget.
483      * \param widget the toolview to show, where the widget was constructed
484      *        by createToolView().
485      * \return \e true on success, otherwise \e false
486      * \todo add focus parameter: bool showToolView (QWidget *widget, bool giveFocus );
487      */
488     bool showToolView(QWidget *widget);
489 
490     /**
491      * Hide the toolview \p widget.
492      * \param widget the toolview to hide, where the widget was constructed
493      *        by createToolView().
494      * \return \e true on success, otherwise \e false
495      */
496     bool hideToolView(QWidget *widget);
497 
498     /**
499      * Shows the @p plugin's config page. The @p page specifies which
500      * config page will be shown, see KTextEditor::Plugin::configPages().
501      *
502      * \return \e true on success, otherwise \e false
503      * \since 5.63
504      */
505     bool showPluginConfigPage(KTextEditor::Plugin *configpageinterface, int id);
506 
507     /**
508      * Get a plugin view for the plugin with with identifier \p name.
509      * \param name the plugin's name
510      * \return pointer to the plugin view if a plugin with \p name is loaded and has a view for this mainwindow,
511      *         otherwise NULL
512      */
513     QObject *pluginView(const QString &name);
514 
515     void addWidgetAsTab(QWidget *widget);
516 
517 private Q_SLOTS:
518     void slotUpdateBottomViewBar();
519 
520 private Q_SLOTS:
521     void slotDocumentCloseAll();
522     void slotDocumentCloseOther();
523     void slotDocumentCloseOther(KTextEditor::Document *document);
524     void slotDocumentCloseSelected(const QList<KTextEditor::Document *> &);
525 
526 private:
527     /**
528      * Notify about file modifications from other processes?
529      */
530     bool m_modNotification = false;
531 
532     /**
533      * Shutdown Kate after last file is closed
534      */
535     bool m_modCloseAfterLast = false;
536 
537     /**
538      * stacked widget containing the central area, aka view manager, quickopen, ...
539      */
540     QStackedWidget *m_mainStackedWidget = nullptr;
541 
542     /**
543      * keeps track of views
544      */
545     KateViewManager *m_viewManager = nullptr;
546 
547     KRecentFilesAction *m_fileOpenRecent = nullptr;
548 
549     KActionMenu *documentOpenWith = nullptr;
550 
551     KToggleAction *settingsShowFileselector = nullptr;
552 
553     KToggleAction *m_showFullScreenAction = nullptr;
554 
555     bool m_modignore;
556 
557     // all plugin views for this mainwindow, used by the pluginmanager
558     QHash<KTextEditor::Plugin *, QObject *> m_pluginViews;
559 
560     // options: show statusbar + show path
561     KToggleAction *m_paShowPath = nullptr;
562     KToggleAction *m_paShowMenuBar = nullptr;
563     KToggleAction *m_paShowStatusBar = nullptr;
564     KToggleAction *m_paShowTabBar = nullptr;
565 
566     QWidget *m_bottomViewBarContainer = nullptr;
567     KateContainerStackedLayout *m_bottomContainerStack = nullptr;
568 
569     QVector<QString> m_lastUsedCmdBarActions;
570 
571     class BarState
572     {
573     public:
574         BarState() = default;
BarState(QWidget * bar)575         BarState(QWidget *bar)
576             : m_bar(bar)
577             , m_state(false)
578         {
579         }
~BarState()580         ~BarState()
581         {
582         }
bar()583         QWidget *bar()
584         {
585             return m_bar;
586         }
state()587         bool state()
588         {
589             return m_state;
590         }
setState(bool state)591         void setState(bool state)
592         {
593             m_state = state;
594         }
595 
596     private:
597         QWidget *m_bar = nullptr;
598         bool m_state = false;
599     };
600     QHash<KTextEditor::View *, BarState> m_bottomViewBarMapping;
601 
602     /**
603      * generic output tool view
604      */
605     QWidget *m_toolViewOutput = nullptr;
606 
607     /**
608      * output widget contained in above tool view
609      */
610     KateOutputView *m_outputView = nullptr;
611 
612 public:
613     /**
614      * Accessor for unique output view per main window.
615      * @return our output view, will always exist!
616      */
outputView()617     KateOutputView *outputView()
618     {
619         return m_outputView;
620     }
621 
622 public:
unsetModifiedOnDiscDialogIfIf(KateMwModOnHdDialog * diag)623     static void unsetModifiedOnDiscDialogIfIf(KateMwModOnHdDialog *diag)
624     {
625         if (s_modOnHdDialog == diag) {
626             s_modOnHdDialog = nullptr;
627         }
628     }
629 
630 private:
631     static KateMwModOnHdDialog *s_modOnHdDialog;
632 
633     /**
634      * Wrapper of main window for KTextEditor
635      */
636     KTextEditor::MainWindow *m_wrapper;
637 
638 public Q_SLOTS:
639     void slotWindowActivated();
640 
641 protected:
642     bool event(QEvent *e) override;
643     void mousePressEvent(QMouseEvent *e) override;
644 };
645 
646 #endif
647