1 /************************************************************************
2 **
3 **  Copyright (C) 2015-2021 Kevin B. Hendricks, Stratford, Ontario
4 **  Copyright (C) 2009-2011 Strahinja Markovic  <strahinja.markovic@gmail.com>
5 **
6 **  This file is part of Sigil.
7 **
8 **  Sigil is free software: you can redistribute it and/or modify
9 **  it under the terms of the GNU General Public License as published by
10 **  the Free Software Foundation, either version 3 of the License, or
11 **  (at your option) any later version.
12 **
13 **  Sigil is distributed in the hope that it will be useful,
14 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 **  GNU General Public License for more details.
17 **
18 **  You should have received a copy of the GNU General Public License
19 **  along with Sigil.  If not, see <http://www.gnu.org/licenses/>.
20 **
21 *************************************************************************/
22 
23 #pragma once
24 #ifndef TABMANAGER_H
25 #define TABMANAGER_H
26 
27 #include <QtCore/QUrl>
28 #include <QtWidgets/QTabWidget>
29 
30 #include "MainUI/MainWindow.h"
31 #include "Tabs/ContentTab.h"
32 
33 class Resource;
34 class HTMLResource;
35 class WellFormedContent;
36 
37 /**
38  * Manages the tabs shown in the main UI.
39  * Handles open resource requests, tab switching, closing etc.
40  */
41 class TabManager : public QTabWidget
42 {
43     Q_OBJECT
44 
45 public:
46 
47     /**
48      * Constructor.
49      *
50      * @param parent The QObject's parent.
51      */
52     TabManager(QWidget *parent = 0);
53 
54     /**
55      * Returns a reference to the current content tab.
56      *
57      * @return A reference to the current content tab.
58      */
59     ContentTab *GetCurrentContentTab();
60 
61     QList<ContentTab *> GetContentTabs();
62 
63     QList<Resource *> GetTabResources();
64 
65     QList<Resource *> GetTabResourcesOfType(Resource::ResourceType resource_type);
66 
67     int GetTabCount();
68 
69     void CloseAllTabs(bool all=false);
70     void CloseTabForResource(const Resource *resource, bool force=false);
71 
72     /**
73      * Returns \c true if all open tabs data is well-formed.
74      * If an issue occurs, user is notified of the problem with a
75      * dialog and the offending tab is switched to automatically.
76      *
77      * @return \c true if the tab data is well-formed.
78      */
79     bool IsAllTabDataWellFormed();
80 
81     void ReloadTabDataForResources(const QList<Resource *> &resources);
82 
83     /**
84      * Close and reopen all tabs
85      */
86     void ReopenTabs();
87 
88     void UpdateTabDisplay();
89 
90     /**
91      * Close the OPF tab if it's currently open.
92      * Returns true if the OPF had to be closed.
93      */
94     bool CloseOPFTabIfOpen();
95 
96 public slots:
97 
98     /**
99      * Saves any unsaved data in the all the open tabs.
100      */
101     void SaveTabData();
102 
103     /**
104      * Opens the specified resource in a new tab.
105      * If the resource is already opened, it becomes the current one.
106      *
107      * @param resource - The resource that should be opened.
108      * @param line_to_scroll_to - To which line should the resource scroll (CV).
109      * @param position_to_scroll_to - To which position should the resource scroll (CV).
110      * @param caret_location_to_scroll_to - To which stored caret location should the resource scroll (BV/PV).
111      * @param fragment - The fragment ID to which the new tab should be scrolled to.
112      * @param precede_current_tab - Should the new tab precede the currently opened one.
113      */
114     void OpenResource(Resource *resource,
115                       int line_to_scroll_to = -1,
116                       int position_to_scroll_to = -1,
117                       const QString &caret_location_to_scroll_to = QString(),
118                       const QUrl &fragment = QUrl(),
119                       bool precede_current_tab = false);
120 
121     /**
122      * Makes the next (right) tab the current one.
123      * Wraps around if necessary.
124      */
125     void NextTab();
126 
127     /**
128      * Makes the previous (left) tab the current one.
129      * Wraps around if necessary.
130      */
131     void PreviousTab();
132 
133     /**
134      * Closes the current tab.
135      * If there is only one tab opened, the command is ignored.
136      */
137     void CloseTab();
138 
139     /**
140      * Removes the current tab, may leave no tabs in windows
141      */
142     void RemoveTab();
143 
144     /**
145      * Closes all tabs except the current tab.
146      * If there is only one tab opened, the command is ignored.
147      */
148     void CloseOtherTabs();
149 
150     void CloseOtherTabs(int index);
151 
152     /**
153      * Makes the tab the central (shown) tab of the UI.
154      *
155      * @param tab The tab to make central.
156      */
157     void MakeCentralTab(ContentTab *tab);
158 
159     void LinkClicked(const QUrl &url);
160 
161 signals:
162     /**
163      * Emitted whenever the user switches from one tab to the next.
164      *
165      * @param old_tab The tab \e from which the user is switching.
166      * @param new_tab The tab \e to which the user is switching.
167      */
168     void TabChanged(ContentTab *old_tab, ContentTab *new_tab);
169 
170     void UpdatePreviewAfterExistingTabSwitch();
171 
172     void TabCountChanged();
173 
174     /**
175      * Emitted whenever one of the tabs wants to open an URL.
176      *
177      * @param url The URL to open.
178      */
179     void OpenUrlRequest(const QUrl &url);
180 
181     /**
182      * Wired to the current FlowTab::OldTabRequest signal.
183      */
184     void OldTabRequest(QString content, HTMLResource *originating_resource);
185 
186     void ShowStatusMessageRequest(const QString &message, int duration = 5000);
187 
188 protected:
189     virtual void tabInserted(int index);
190 
191 private slots:
192 
193     /**
194      * Emits the TabChanged signal.
195      */
196     void EmitTabChanged(int new_index);
197 
198     /**
199      * Deletes the specified tab.
200      *
201      * @param tab_to_delete The tab to delete.
202      */
203     void DeleteTab(ContentTab *tab_to_delete);
204 
205     /**
206      * Closes the tab at the specified index.
207      * If there is only one tab left, the command is ignored.
208      *
209      * @param tab_index The index of the tab to close.
210      * @param force Ignore checks that would prevent a tab from closing.
211      */
212     void CloseTab(int tab_index, bool force=false);
213 
214     /**
215      * Updates the name/header text of the specified tab.
216      *
217      * @param renamed_tab The renamed tab.
218      */
219     void UpdateTabName(ContentTab *renamed_tab);
220 
221     void SetFocusInTab();
222 
223 private:
224 
225     /**
226      * Returns the element of the UI that houses well-formed XML data.
227      *
228      * @note CAN BE NULL! This means the main tab has no XML data.
229      * @param index The index of the tab to retrieve.
230      * @return The element with XML data.
231      */
232     WellFormedContent *GetWellFormedContent(int index);
233 
234     /**
235      * Returns the index of tab in which the resource is loaded.
236      * If the resource is not currently loaded, -1 is returned.
237      *
238      * @param resource The resource whose tab index we want.
239      * @return The index of the resource.
240      */
241     int ResourceTabIndex(const Resource *resource) const;
242 
243     /**
244      * Returns true if we have succeeded in switching to the tab of the provided resource.
245      *
246      * @param resource The resource we want to switch to.
247      * @param fragment The fragment ID to which the tab should scroll.
248      * @param line_to_scroll_to To which line should the resource scroll.
249      * @return \c true if we succeeded in switching.
250      */
251     bool SwitchedToExistingTab(const Resource *resource,
252                                int line_to_scroll_to,
253                                int position_to_scroll_to,
254                                const QString &caret_location_to_scroll_to,
255                                const QUrl &fragment);
256 
257     /**
258      * Creates a tab for the specified resource.
259      *
260      * @param resource The resource for which we want to create a tab.
261      * @param line_to_scroll_to To which line should the resource scroll.
262      * @param fragment The fragment ID to which the tab should scroll after load.
263      * @return The newly created tab.
264      */
265     ContentTab *CreateTabForResource(Resource *resource,
266                                      int line_to_scroll_to,
267                                      int position_to_scroll_to,
268                                      const QString &caret_location_to_scroll_to,
269                                      const QUrl &fragment,
270                                      bool grab_focus = true);
271 
272     /**
273      * Adds a new content tab to the displayed tabs.
274      * If precede_current_tab is false, the new tab is appended
275      * and becomes the current one. Otherwise, it's added just before
276      * the current one and does \e not become the current one.
277      *
278      * @param new_tab The tab to add.
279      * @param precede_current_tab Should the new tab precede the current one.
280      * @return \c true if the tab was successfully added.
281      */
282     bool AddNewContentTab(ContentTab *new_tab, bool precede_current_tab);
283 
284     ///////////////////////////////
285     // PRIVATE MEMBER VARIABLES
286     ///////////////////////////////
287 
288     /**
289      * Stores a reference to the tab used before the current one.
290      * Needed for the TabChanged signal.
291      */
292     ContentTab* m_LastContentTab;
293 
294     bool m_CheckWellFormedErrors;
295 
296     QList<ContentTab*> m_TabsToDelete;
297     bool m_tabs_deletion_in_use;
298     ContentTab * m_newTab;
299 };
300 
301 #endif // TABMANAGER_H
302 
303 
304