1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Assistant module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | #include "openpagesmanager.h" |
30 | |
31 | #include "centralwidget.h" |
32 | #include "helpenginewrapper.h" |
33 | #include "helpviewer.h" |
34 | #include "openpagesmodel.h" |
35 | #include "openpagesswitcher.h" |
36 | #include "openpageswidget.h" |
37 | #include "tracer.h" |
38 | #include "../shared/collectionconfiguration.h" |
39 | |
40 | #include <QtWidgets/QApplication> |
41 | #include <QtWidgets/QTreeView> |
42 | |
43 | QT_BEGIN_NAMESPACE |
44 | |
45 | OpenPagesManager *OpenPagesManager::m_instance = nullptr; |
46 | |
47 | OpenPagesManager *OpenPagesManager::createInstance(QObject *parent, |
48 | bool defaultCollection, const QUrl &cmdLineUrl) |
49 | { |
50 | TRACE_OBJ |
51 | Q_ASSERT(!m_instance); |
52 | m_instance = new OpenPagesManager(parent, defaultCollection, cmdLineUrl); |
53 | return m_instance; |
54 | } |
55 | |
56 | OpenPagesManager *OpenPagesManager::instance() |
57 | { |
58 | TRACE_OBJ |
59 | Q_ASSERT(m_instance); |
60 | return m_instance; |
61 | } |
62 | |
63 | OpenPagesManager::OpenPagesManager(QObject *parent, bool defaultCollection, |
64 | const QUrl &cmdLineUrl) |
65 | : QObject(parent) |
66 | , m_model(new OpenPagesModel(this)) |
67 | { |
68 | TRACE_OBJ |
69 | m_openPagesWidget = new OpenPagesWidget(m_model); |
70 | m_openPagesWidget->setFrameStyle(QFrame::NoFrame); |
71 | connect(sender: m_openPagesWidget, signal: &OpenPagesWidget::setCurrentPage, |
72 | receiver: this, slot: QOverload<const QModelIndex &>::of(ptr: &OpenPagesManager::setCurrentPage)); |
73 | connect(sender: m_openPagesWidget, signal: &OpenPagesWidget::closePage, |
74 | receiver: this, slot: QOverload<const QModelIndex &>::of(ptr: &OpenPagesManager::closePage)); |
75 | connect(sender: m_openPagesWidget, signal: &OpenPagesWidget::closePagesExcept, |
76 | receiver: this, slot: &OpenPagesManager::closePagesExcept); |
77 | |
78 | m_openPagesSwitcher = new OpenPagesSwitcher(m_model); |
79 | connect(sender: m_openPagesSwitcher, signal: &OpenPagesSwitcher::closePage, |
80 | receiver: this, slot: QOverload<const QModelIndex &>::of(ptr: &OpenPagesManager::closePage)); |
81 | connect(sender: m_openPagesSwitcher, signal: &OpenPagesSwitcher::setCurrentPage, |
82 | receiver: this, slot: QOverload<const QModelIndex &>::of(ptr: &OpenPagesManager::setCurrentPage)); |
83 | |
84 | setupInitialPages(defaultCollection, cmdLineUrl); |
85 | } |
86 | |
87 | OpenPagesManager ::~OpenPagesManager() |
88 | { |
89 | TRACE_OBJ |
90 | m_instance = nullptr; |
91 | delete m_openPagesSwitcher; |
92 | } |
93 | |
94 | int OpenPagesManager::pageCount() const |
95 | { |
96 | TRACE_OBJ |
97 | return m_model->rowCount(); |
98 | } |
99 | |
100 | void OpenPagesManager::setupInitialPages(bool defaultCollection, |
101 | const QUrl &cmdLineUrl) |
102 | { |
103 | TRACE_OBJ |
104 | if (cmdLineUrl.isValid()) { |
105 | createPage(url: cmdLineUrl); |
106 | return; |
107 | } |
108 | |
109 | HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); |
110 | int initialPage = 0; |
111 | switch (helpEngine.startOption()) { |
112 | case ShowHomePage: |
113 | m_model->addPage(url: helpEngine.homePage()); |
114 | break; |
115 | case ShowBlankPage: |
116 | m_model->addPage(url: QUrl(QLatin1String("about:blank" ))); |
117 | break; |
118 | case ShowLastPages: { |
119 | const QStringList &lastShownPageList = helpEngine.lastShownPages(); |
120 | const int pageCount = lastShownPageList.count(); |
121 | if (pageCount == 0) { |
122 | if (defaultCollection) |
123 | m_model->addPage(url: QUrl(QLatin1String("help" ))); |
124 | else |
125 | m_model->addPage(url: QUrl(QLatin1String("about:blank" ))); |
126 | } else { |
127 | QStringList zoomFactors = helpEngine.lastZoomFactors(); |
128 | while (zoomFactors.count() < pageCount) |
129 | zoomFactors.append(t: CollectionConfiguration::DefaultZoomFactor); |
130 | initialPage = helpEngine.lastTabPage(); |
131 | if (initialPage >= pageCount) { |
132 | qWarning(msg: "Initial page set to %d, maximum possible value is %d" , |
133 | initialPage, pageCount - 1); |
134 | initialPage = 0; |
135 | } |
136 | for (int curPage = 0; curPage < pageCount; ++curPage) { |
137 | const QString &curFile = lastShownPageList.at(i: curPage); |
138 | if (helpEngine.findFile(url: curFile).isValid() |
139 | || curFile == QLatin1String("about:blank" )) { |
140 | m_model->addPage(url: curFile, zoom: zoomFactors.at(i: curPage).toFloat()); |
141 | } else if (curPage <= initialPage && initialPage > 0) |
142 | --initialPage; |
143 | } |
144 | } |
145 | break; |
146 | } |
147 | default: |
148 | Q_ASSERT(0); |
149 | } |
150 | |
151 | if (m_model->rowCount() == 0) |
152 | m_model->addPage(url: helpEngine.homePage()); |
153 | for (int i = 0; i < m_model->rowCount(); ++i) |
154 | CentralWidget::instance()->addPage(page: m_model->pageAt(index: i)); |
155 | setCurrentPage((initialPage >= m_model->rowCount()) |
156 | ? m_model->rowCount() - 1 : initialPage); |
157 | m_openPagesSwitcher->selectCurrentPage(); |
158 | } |
159 | |
160 | HelpViewer *OpenPagesManager::createBlankPage() |
161 | { |
162 | TRACE_OBJ |
163 | return createPage(url: QUrl(QLatin1String("about:blank" ))); |
164 | } |
165 | |
166 | void OpenPagesManager::closeCurrentPage() |
167 | { |
168 | TRACE_OBJ |
169 | Q_ASSERT(m_model->rowCount() > 1); |
170 | const QModelIndexList selectedIndexes |
171 | = m_openPagesWidget->selectionModel()->selectedRows(); |
172 | if (selectedIndexes.isEmpty()) |
173 | return; |
174 | Q_ASSERT(selectedIndexes.count() == 1); |
175 | removePage(index: selectedIndexes.first().row()); |
176 | } |
177 | |
178 | HelpViewer *OpenPagesManager::createPage(const QUrl &url, bool fromSearch) |
179 | { |
180 | TRACE_OBJ |
181 | if (HelpViewer::launchWithExternalApp(url)) |
182 | return nullptr; |
183 | |
184 | emit aboutToAddPage(); |
185 | |
186 | m_model->addPage(url); |
187 | const int index = m_model->rowCount() - 1; |
188 | HelpViewer * const page = m_model->pageAt(index); |
189 | CentralWidget::instance()->addPage(page, fromSearch); |
190 | setCurrentPage(index); |
191 | |
192 | emit pageAdded(index); |
193 | return page; |
194 | } |
195 | |
196 | HelpViewer *OpenPagesManager::createNewPageFromSearch(const QUrl &url) |
197 | { |
198 | TRACE_OBJ |
199 | return createPage(url, fromSearch: true); |
200 | } |
201 | |
202 | void OpenPagesManager::closePage(HelpViewer *viewer) |
203 | { |
204 | TRACE_OBJ |
205 | for (int i = 0; i < m_model->rowCount(); ++i) { |
206 | if (m_model->pageAt(index: i) == viewer) { |
207 | removePage(index: i); |
208 | break; |
209 | } |
210 | } |
211 | } |
212 | |
213 | void OpenPagesManager::closePage(const QModelIndex &index) |
214 | { |
215 | TRACE_OBJ |
216 | if (index.isValid()) |
217 | removePage(index: index.row()); |
218 | } |
219 | |
220 | void OpenPagesManager::closePages(const QString &nameSpace) |
221 | { |
222 | TRACE_OBJ |
223 | closeOrReloadPages(nameSpace, tryReload: false); |
224 | } |
225 | |
226 | void OpenPagesManager::reloadPages(const QString &nameSpace) |
227 | { |
228 | TRACE_OBJ |
229 | closeOrReloadPages(nameSpace, tryReload: true); |
230 | m_openPagesWidget->selectCurrentPage(); |
231 | } |
232 | |
233 | void OpenPagesManager::closeOrReloadPages(const QString &nameSpace, bool tryReload) |
234 | { |
235 | TRACE_OBJ |
236 | for (int i = m_model->rowCount() - 1; i >= 0; --i) { |
237 | HelpViewer *page = m_model->pageAt(index: i); |
238 | if (page->source().host() != nameSpace) |
239 | continue; |
240 | if (tryReload && HelpEngineWrapper::instance().findFile(url: page->source()).isValid()) |
241 | page->reload(); |
242 | else if (m_model->rowCount() == 1) |
243 | page->setSource(QUrl(QLatin1String("about:blank" ))); |
244 | else |
245 | removePage(index: i); |
246 | } |
247 | } |
248 | |
249 | bool OpenPagesManager::pagesOpenForNamespace(const QString &nameSpace) const |
250 | { |
251 | TRACE_OBJ |
252 | for (int i = 0; i < m_model->rowCount(); ++i) |
253 | if (m_model->pageAt(index: i)->source().host() == nameSpace) |
254 | return true; |
255 | return false; |
256 | } |
257 | |
258 | void OpenPagesManager::setCurrentPage(const QModelIndex &index) |
259 | { |
260 | TRACE_OBJ |
261 | if (index.isValid()) |
262 | setCurrentPage(index.row()); |
263 | } |
264 | |
265 | void OpenPagesManager::setCurrentPage(int index) |
266 | { |
267 | TRACE_OBJ |
268 | setCurrentPage(m_model->pageAt(index)); |
269 | } |
270 | |
271 | void OpenPagesManager::setCurrentPage(HelpViewer *page) |
272 | { |
273 | TRACE_OBJ |
274 | CentralWidget::instance()->setCurrentPage(page); |
275 | m_openPagesWidget->selectCurrentPage(); |
276 | } |
277 | |
278 | void OpenPagesManager::removePage(int index) |
279 | { |
280 | TRACE_OBJ |
281 | emit aboutToClosePage(index); |
282 | |
283 | CentralWidget::instance()->removePage(index); |
284 | m_model->removePage(index); |
285 | m_openPagesWidget->selectCurrentPage(); |
286 | |
287 | emit pageClosed(); |
288 | } |
289 | |
290 | |
291 | void OpenPagesManager::closePagesExcept(const QModelIndex &index) |
292 | { |
293 | TRACE_OBJ |
294 | if (!index.isValid()) |
295 | return; |
296 | |
297 | int i = 0; |
298 | HelpViewer *viewer = m_model->pageAt(index: index.row()); |
299 | while (m_model->rowCount() > 1) { |
300 | if (m_model->pageAt(index: i) != viewer) |
301 | removePage(index: i); |
302 | else |
303 | ++i; |
304 | } |
305 | } |
306 | |
307 | QAbstractItemView *OpenPagesManager::openPagesWidget() const |
308 | { |
309 | TRACE_OBJ |
310 | return m_openPagesWidget; |
311 | } |
312 | |
313 | void OpenPagesManager::nextPage() |
314 | { |
315 | TRACE_OBJ |
316 | nextOrPreviousPage(offset: 1); |
317 | } |
318 | |
319 | void OpenPagesManager::nextPageWithSwitcher() |
320 | { |
321 | TRACE_OBJ |
322 | if (!m_openPagesSwitcher->isVisible()) { |
323 | m_openPagesSwitcher->selectCurrentPage(); |
324 | m_openPagesSwitcher->gotoNextPage(); |
325 | showSwitcherOrSelectPage(); |
326 | } else { |
327 | m_openPagesSwitcher->gotoNextPage(); |
328 | } |
329 | } |
330 | |
331 | void OpenPagesManager::previousPage() |
332 | { |
333 | TRACE_OBJ |
334 | nextOrPreviousPage(offset: -1); |
335 | } |
336 | |
337 | void OpenPagesManager::previousPageWithSwitcher() |
338 | { |
339 | TRACE_OBJ |
340 | if (!m_openPagesSwitcher->isVisible()) { |
341 | m_openPagesSwitcher->selectCurrentPage(); |
342 | m_openPagesSwitcher->gotoPreviousPage(); |
343 | showSwitcherOrSelectPage(); |
344 | } else { |
345 | m_openPagesSwitcher->gotoPreviousPage(); |
346 | } |
347 | } |
348 | |
349 | void OpenPagesManager::nextOrPreviousPage(int offset) |
350 | { |
351 | TRACE_OBJ |
352 | setCurrentPage((CentralWidget::instance()->currentIndex() + offset |
353 | + m_model->rowCount()) % m_model->rowCount()); |
354 | } |
355 | |
356 | void OpenPagesManager::showSwitcherOrSelectPage() const |
357 | { |
358 | TRACE_OBJ |
359 | if (QApplication::keyboardModifiers() != Qt::NoModifier) { |
360 | const int width = CentralWidget::instance()->width(); |
361 | const int height = CentralWidget::instance()->height(); |
362 | const QPoint p(CentralWidget::instance()->mapToGlobal(QPoint(0, 0))); |
363 | m_openPagesSwitcher->move(ax: (width - m_openPagesSwitcher->width()) / 2 + p.x(), |
364 | ay: (height - m_openPagesSwitcher->height()) / 2 + p.y()); |
365 | m_openPagesSwitcher->setVisible(true); |
366 | } else { |
367 | m_openPagesSwitcher->selectAndHide(); |
368 | } |
369 | } |
370 | |
371 | QT_END_NAMESPACE |
372 | |