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 Qt Assistant 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 "helpviewer.h" |
30 | #include "helpviewer_p.h" |
31 | |
32 | #include "helpenginewrapper.h" |
33 | #include "tracer.h" |
34 | |
35 | #include <QtCore/QCoreApplication> |
36 | #include <QtCore/QFileInfo> |
37 | #include <QtCore/QStringBuilder> |
38 | #include <QtCore/QTemporaryFile> |
39 | #include <QtCore/QUrl> |
40 | |
41 | #include <QtGui/QDesktopServices> |
42 | #include <QtGui/QMouseEvent> |
43 | |
44 | #include <QtHelp/QHelpEngineCore> |
45 | |
46 | QT_BEGIN_NAMESPACE |
47 | |
48 | const QString HelpViewer::AboutBlank = |
49 | QCoreApplication::translate(context: "HelpViewer" , key: "<title>about:blank</title>" ); |
50 | |
51 | const QString HelpViewer::LocalHelpFile = QLatin1String("qthelp://" |
52 | "org.qt-project.assistantinternal-1.0.0/assistant/assistant-quick-guide.html" ); |
53 | |
54 | const QString HelpViewer::PageNotFoundMessage = |
55 | QCoreApplication::translate(context: "HelpViewer" , key: "<title>Error 404...</title><div " |
56 | "align=\"center\"><br><br><h1>The page could not be found.</h1><br><h3>'%1'" |
57 | "</h3></div>" ); |
58 | |
59 | struct ExtensionMap { |
60 | const char *extension; |
61 | const char *mimeType; |
62 | } extensionMap[] = { |
63 | { .extension: ".bmp" , .mimeType: "image/bmp" }, |
64 | { .extension: ".css" , .mimeType: "text/css" }, |
65 | { .extension: ".gif" , .mimeType: "image/gif" }, |
66 | { .extension: ".html" , .mimeType: "text/html" }, |
67 | { .extension: ".htm" , .mimeType: "text/html" }, |
68 | { .extension: ".ico" , .mimeType: "image/x-icon" }, |
69 | { .extension: ".jpeg" , .mimeType: "image/jpeg" }, |
70 | { .extension: ".jpg" , .mimeType: "image/jpeg" }, |
71 | { .extension: ".js" , .mimeType: "application/x-javascript" }, |
72 | { .extension: ".mng" , .mimeType: "video/x-mng" }, |
73 | { .extension: ".pbm" , .mimeType: "image/x-portable-bitmap" }, |
74 | { .extension: ".pgm" , .mimeType: "image/x-portable-graymap" }, |
75 | { .extension: ".pdf" , .mimeType: nullptr }, |
76 | { .extension: ".png" , .mimeType: "image/png" }, |
77 | { .extension: ".ppm" , .mimeType: "image/x-portable-pixmap" }, |
78 | { .extension: ".rss" , .mimeType: "application/rss+xml" }, |
79 | { .extension: ".svg" , .mimeType: "image/svg+xml" }, |
80 | { .extension: ".svgz" , .mimeType: "image/svg+xml" }, |
81 | { .extension: ".text" , .mimeType: "text/plain" }, |
82 | { .extension: ".tif" , .mimeType: "image/tiff" }, |
83 | { .extension: ".tiff" , .mimeType: "image/tiff" }, |
84 | { .extension: ".txt" , .mimeType: "text/plain" }, |
85 | { .extension: ".xbm" , .mimeType: "image/x-xbitmap" }, |
86 | { .extension: ".xml" , .mimeType: "text/xml" }, |
87 | { .extension: ".xpm" , .mimeType: "image/x-xpm" }, |
88 | { .extension: ".xsl" , .mimeType: "text/xsl" }, |
89 | { .extension: ".xhtml" , .mimeType: "application/xhtml+xml" }, |
90 | { .extension: ".wml" , .mimeType: "text/vnd.wap.wml" }, |
91 | { .extension: ".wmlc" , .mimeType: "application/vnd.wap.wmlc" }, |
92 | { .extension: "about:blank" , .mimeType: nullptr }, |
93 | { .extension: nullptr, .mimeType: nullptr } |
94 | }; |
95 | |
96 | HelpViewer::~HelpViewer() |
97 | { |
98 | TRACE_OBJ |
99 | delete d; |
100 | } |
101 | |
102 | bool HelpViewer::isLocalUrl(const QUrl &url) |
103 | { |
104 | TRACE_OBJ |
105 | const QString &scheme = url.scheme(); |
106 | return scheme.isEmpty() |
107 | || scheme == QLatin1String("file" ) |
108 | || scheme == QLatin1String("qrc" ) |
109 | || scheme == QLatin1String("data" ) |
110 | || scheme == QLatin1String("qthelp" ) |
111 | || scheme == QLatin1String("about" ); |
112 | } |
113 | |
114 | bool HelpViewer::canOpenPage(const QString &path) |
115 | { |
116 | TRACE_OBJ |
117 | return !mimeFromUrl(url: QUrl::fromLocalFile(localfile: path)).isEmpty(); |
118 | } |
119 | |
120 | QString HelpViewer::mimeFromUrl(const QUrl &url) |
121 | { |
122 | TRACE_OBJ |
123 | const QString &path = url.path(); |
124 | const int index = path.lastIndexOf(c: QLatin1Char('.')); |
125 | const QByteArray &ext = path.mid(position: index).toUtf8().toLower(); |
126 | |
127 | const ExtensionMap *e = extensionMap; |
128 | while (e->extension) { |
129 | if (ext == e->extension) |
130 | return QLatin1String(e->mimeType); |
131 | ++e; |
132 | } |
133 | return QLatin1String("application/octet-stream" ); |
134 | } |
135 | |
136 | bool HelpViewer::launchWithExternalApp(const QUrl &url) |
137 | { |
138 | TRACE_OBJ |
139 | if (isLocalUrl(url)) { |
140 | const HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); |
141 | const QUrl &resolvedUrl = helpEngine.findFile(url); |
142 | if (!resolvedUrl.isValid()) |
143 | return false; |
144 | |
145 | const QString& path = resolvedUrl.toLocalFile(); |
146 | if (!canOpenPage(path)) { |
147 | QTemporaryFile tmpTmpFile; |
148 | if (!tmpTmpFile.open()) |
149 | return false; |
150 | |
151 | const QString &extension = QFileInfo(path).completeSuffix(); |
152 | QFile actualTmpFile(tmpTmpFile.fileName() % QLatin1String("." ) |
153 | % extension); |
154 | if (!actualTmpFile.open(flags: QIODevice::ReadWrite | QIODevice::Truncate)) |
155 | return false; |
156 | |
157 | actualTmpFile.write(data: helpEngine.fileData(url: resolvedUrl)); |
158 | actualTmpFile.close(); |
159 | return QDesktopServices::openUrl(url: QUrl::fromLocalFile(localfile: actualTmpFile.fileName())); |
160 | } |
161 | return false; |
162 | } |
163 | return QDesktopServices::openUrl(url); |
164 | } |
165 | |
166 | // -- public slots |
167 | |
168 | void HelpViewer::home() |
169 | { |
170 | TRACE_OBJ |
171 | setSource(HelpEngineWrapper::instance().homePage()); |
172 | } |
173 | |
174 | // -- private slots |
175 | |
176 | void HelpViewer::setLoadStarted() |
177 | { |
178 | d->m_loadFinished = false; |
179 | } |
180 | |
181 | void HelpViewer::setLoadFinished(bool ok) |
182 | { |
183 | d->m_loadFinished = ok; |
184 | emit sourceChanged(source()); |
185 | } |
186 | |
187 | // -- private |
188 | |
189 | bool HelpViewer::handleForwardBackwardMouseButtons(QMouseEvent *event) |
190 | { |
191 | TRACE_OBJ |
192 | if (event->button() == Qt::XButton1) { |
193 | backward(); |
194 | return true; |
195 | } |
196 | |
197 | if (event->button() == Qt::XButton2) { |
198 | forward(); |
199 | return true; |
200 | } |
201 | |
202 | return false; |
203 | } |
204 | |
205 | QT_END_NAMESPACE |
206 | |