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