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
createInstance(QObject * parent,bool defaultCollection,const QUrl & cmdLineUrl)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
instance()56 OpenPagesManager *OpenPagesManager::instance()
57 {
58 TRACE_OBJ
59 Q_ASSERT(m_instance);
60 return m_instance;
61 }
62
OpenPagesManager(QObject * parent,bool defaultCollection,const QUrl & cmdLineUrl)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(m_openPagesWidget, &OpenPagesWidget::setCurrentPage,
72 this, QOverload<const QModelIndex &>::of(&OpenPagesManager::setCurrentPage));
73 connect(m_openPagesWidget, &OpenPagesWidget::closePage,
74 this, QOverload<const QModelIndex &>::of(&OpenPagesManager::closePage));
75 connect(m_openPagesWidget, &OpenPagesWidget::closePagesExcept,
76 this, &OpenPagesManager::closePagesExcept);
77
78 m_openPagesSwitcher = new OpenPagesSwitcher(m_model);
79 connect(m_openPagesSwitcher, &OpenPagesSwitcher::closePage,
80 this, QOverload<const QModelIndex &>::of(&OpenPagesManager::closePage));
81 connect(m_openPagesSwitcher, &OpenPagesSwitcher::setCurrentPage,
82 this, QOverload<const QModelIndex &>::of(&OpenPagesManager::setCurrentPage));
83
84 setupInitialPages(defaultCollection, cmdLineUrl);
85 }
86
~OpenPagesManager()87 OpenPagesManager ::~OpenPagesManager()
88 {
89 TRACE_OBJ
90 m_instance = nullptr;
91 delete m_openPagesSwitcher;
92 }
93
pageCount() const94 int OpenPagesManager::pageCount() const
95 {
96 TRACE_OBJ
97 return m_model->rowCount();
98 }
99
setupInitialPages(bool defaultCollection,const QUrl & cmdLineUrl)100 void OpenPagesManager::setupInitialPages(bool defaultCollection,
101 const QUrl &cmdLineUrl)
102 {
103 TRACE_OBJ
104 if (cmdLineUrl.isValid()) {
105 createPage(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(helpEngine.homePage());
114 break;
115 case ShowBlankPage:
116 m_model->addPage(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(QUrl(QLatin1String("help")));
124 else
125 m_model->addPage(QUrl(QLatin1String("about:blank")));
126 } else {
127 QStringList zoomFactors = helpEngine.lastZoomFactors();
128 while (zoomFactors.count() < pageCount)
129 zoomFactors.append(CollectionConfiguration::DefaultZoomFactor);
130 initialPage = helpEngine.lastTabPage();
131 if (initialPage >= pageCount) {
132 qWarning("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(curPage);
138 if (helpEngine.findFile(curFile).isValid()
139 || curFile == QLatin1String("about:blank")) {
140 m_model->addPage(curFile, zoomFactors.at(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(helpEngine.homePage());
153 for (int i = 0; i < m_model->rowCount(); ++i)
154 CentralWidget::instance()->addPage(m_model->pageAt(i));
155 setCurrentPage((initialPage >= m_model->rowCount())
156 ? m_model->rowCount() - 1 : initialPage);
157 m_openPagesSwitcher->selectCurrentPage();
158 }
159
createBlankPage()160 HelpViewer *OpenPagesManager::createBlankPage()
161 {
162 TRACE_OBJ
163 return createPage(QUrl(QLatin1String("about:blank")));
164 }
165
closeCurrentPage()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(selectedIndexes.first().row());
176 }
177
createPage(const QUrl & url,bool fromSearch)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
createNewPageFromSearch(const QUrl & url)196 HelpViewer *OpenPagesManager::createNewPageFromSearch(const QUrl &url)
197 {
198 TRACE_OBJ
199 return createPage(url, true);
200 }
201
closePage(HelpViewer * viewer)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(i) == viewer) {
207 removePage(i);
208 break;
209 }
210 }
211 }
212
closePage(const QModelIndex & index)213 void OpenPagesManager::closePage(const QModelIndex &index)
214 {
215 TRACE_OBJ
216 if (index.isValid())
217 removePage(index.row());
218 }
219
closePages(const QString & nameSpace)220 void OpenPagesManager::closePages(const QString &nameSpace)
221 {
222 TRACE_OBJ
223 closeOrReloadPages(nameSpace, false);
224 }
225
reloadPages(const QString & nameSpace)226 void OpenPagesManager::reloadPages(const QString &nameSpace)
227 {
228 TRACE_OBJ
229 closeOrReloadPages(nameSpace, true);
230 m_openPagesWidget->selectCurrentPage();
231 }
232
closeOrReloadPages(const QString & nameSpace,bool tryReload)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(i);
238 if (page->source().host() != nameSpace)
239 continue;
240 if (tryReload && HelpEngineWrapper::instance().findFile(page->source()).isValid())
241 page->reload();
242 else if (m_model->rowCount() == 1)
243 page->setSource(QUrl(QLatin1String("about:blank")));
244 else
245 removePage(i);
246 }
247 }
248
pagesOpenForNamespace(const QString & nameSpace) const249 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(i)->source().host() == nameSpace)
254 return true;
255 return false;
256 }
257
setCurrentPage(const QModelIndex & index)258 void OpenPagesManager::setCurrentPage(const QModelIndex &index)
259 {
260 TRACE_OBJ
261 if (index.isValid())
262 setCurrentPage(index.row());
263 }
264
setCurrentPage(int index)265 void OpenPagesManager::setCurrentPage(int index)
266 {
267 TRACE_OBJ
268 setCurrentPage(m_model->pageAt(index));
269 }
270
setCurrentPage(HelpViewer * page)271 void OpenPagesManager::setCurrentPage(HelpViewer *page)
272 {
273 TRACE_OBJ
274 CentralWidget::instance()->setCurrentPage(page);
275 m_openPagesWidget->selectCurrentPage();
276 }
277
removePage(int index)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
closePagesExcept(const QModelIndex & index)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.row());
299 while (m_model->rowCount() > 1) {
300 if (m_model->pageAt(i) != viewer)
301 removePage(i);
302 else
303 ++i;
304 }
305 }
306
openPagesWidget() const307 QAbstractItemView *OpenPagesManager::openPagesWidget() const
308 {
309 TRACE_OBJ
310 return m_openPagesWidget;
311 }
312
nextPage()313 void OpenPagesManager::nextPage()
314 {
315 TRACE_OBJ
316 nextOrPreviousPage(1);
317 }
318
nextPageWithSwitcher()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
previousPage()331 void OpenPagesManager::previousPage()
332 {
333 TRACE_OBJ
334 nextOrPreviousPage(-1);
335 }
336
previousPageWithSwitcher()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
nextOrPreviousPage(int offset)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
showSwitcherOrSelectPage() const356 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((width - m_openPagesSwitcher->width()) / 2 + p.x(),
364 (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