1 | // Copyright (C) 2017 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "qquickwebview_p.h" |
5 | #include "qquickwebviewloadrequest_p.h" |
6 | #include "qquickwebviewsettings_p.h" |
7 | #include <QtWebView/private/qwebviewloadrequest_p.h> |
8 | #include <QtQml/qqmlengine.h> |
9 | #include <QtCore/qmutex.h> |
10 | |
11 | namespace { |
12 | |
13 | class CallbackStorage |
14 | { |
15 | public: |
16 | int insertCallback(const QJSValue &callback) |
17 | { |
18 | QMutexLocker locker(&m_mtx); |
19 | const int nextId = qMax(a: ++m_counter, b: 0); |
20 | if (nextId == 0) |
21 | m_counter = 1; |
22 | |
23 | m_callbacks.insert(key: nextId, value: callback); |
24 | return nextId; |
25 | } |
26 | |
27 | QJSValue takeCallback(int callbackId) |
28 | { |
29 | QMutexLocker lock(&m_mtx); |
30 | return m_callbacks.take(key: callbackId); |
31 | } |
32 | |
33 | private: |
34 | QMutex m_mtx; |
35 | int m_counter; |
36 | QHash<int, QJSValue> m_callbacks; |
37 | }; |
38 | |
39 | } // namespace |
40 | |
41 | Q_GLOBAL_STATIC(CallbackStorage, callbacks) |
42 | |
43 | /*! |
44 | \qmltype WebView |
45 | \inqmlmodule QtWebView |
46 | \ingroup qtwebview |
47 | \brief A component for displaying web content. |
48 | |
49 | WebView is a component for displaying web content which is implemented using native |
50 | APIs on the platforms where this is available, thus it does not necessarily require |
51 | including a full web browser stack as part of the application. |
52 | |
53 | To make the Qt WebView module function correctly across all platforms, it is necessary |
54 | to call \l {qtwebview-initialize}{QtWebView::initialize}() right after creating the |
55 | QGuiApplication instance. |
56 | |
57 | \note Due to platform limitations overlapping the WebView and other QML components |
58 | is not supported. |
59 | */ |
60 | |
61 | QQuickWebView::QQuickWebView(QQuickItem *parent) |
62 | : QQuickViewController(parent) |
63 | , m_webView(new QWebView(this)) |
64 | , m_settings(new QQuickWebViewSettings(m_webView->getSettings(), this)) |
65 | { |
66 | setView(m_webView); |
67 | connect(sender: m_webView, signal: &QWebView::titleChanged, context: this, slot: &QQuickWebView::titleChanged); |
68 | connect(sender: m_webView, signal: &QWebView::urlChanged, context: this, slot: &QQuickWebView::urlChanged); |
69 | connect(sender: m_webView, signal: &QWebView::loadProgressChanged, context: this, slot: &QQuickWebView::loadProgressChanged); |
70 | connect(sender: m_webView, signal: &QWebView::loadingChanged, context: this, slot: &QQuickWebView::onLoadingChanged); |
71 | connect(sender: m_webView, signal: &QWebView::requestFocus, context: this, slot: &QQuickWebView::onFocusRequest); |
72 | connect(sender: m_webView, signal: &QWebView::javaScriptResult, context: this, slot: &QQuickWebView::onRunJavaScriptResult); |
73 | connect(sender: m_webView, signal: &QWebView::httpUserAgentChanged, context: this, slot: &QQuickWebView::httpUserAgentChanged); |
74 | connect(sender: m_webView, signal: &QWebView::cookieAdded, context: this, slot: &QQuickWebView::cookieAdded); |
75 | connect(sender: m_webView, signal: &QWebView::cookieRemoved, context: this, slot: &QQuickWebView::cookieRemoved); |
76 | } |
77 | |
78 | QQuickWebView::~QQuickWebView() { } |
79 | |
80 | /*! |
81 | \qmlproperty url QtWebView::WebView::httpUserAgent |
82 | \since QtWebView 1.14 |
83 | The user agent in use. |
84 | |
85 | \note on WinRT, this property affects all WebViews of the application. |
86 | */ |
87 | |
88 | void QQuickWebView::setHttpUserAgent(const QString &userAgent) |
89 | { |
90 | m_webView->setHttpUserAgent(userAgent); |
91 | } |
92 | |
93 | QString QQuickWebView::httpUserAgent() const |
94 | { |
95 | return m_webView->httpUserAgent(); |
96 | } |
97 | |
98 | /*! |
99 | \qmlproperty url QtWebView::WebView::url |
100 | |
101 | The URL of currently loaded web page. Changing this will trigger |
102 | loading new content. |
103 | |
104 | The URL is used as-is. URLs that originate from user input should |
105 | be parsed with QUrl::fromUserInput(). |
106 | |
107 | \note The WebView does not support loading content through the Qt Resource system. |
108 | */ |
109 | |
110 | void QQuickWebView::setUrl(const QUrl &url) |
111 | { |
112 | m_webView->setUrl(url); |
113 | } |
114 | |
115 | /*! |
116 | \qmlproperty string QtWebView::WebView::title |
117 | \readonly |
118 | |
119 | The title of the currently loaded web page. |
120 | */ |
121 | |
122 | QString QQuickWebView::title() const |
123 | { |
124 | return m_webView->title(); |
125 | } |
126 | |
127 | QUrl QQuickWebView::url() const |
128 | { |
129 | return m_webView->url(); |
130 | } |
131 | |
132 | /*! |
133 | \qmlproperty bool QtWebView::WebView::canGoBack |
134 | \readonly |
135 | |
136 | Holds \c true if it's currently possible to navigate back in the web history. |
137 | */ |
138 | |
139 | bool QQuickWebView::canGoBack() const |
140 | { |
141 | return m_webView->canGoBack(); |
142 | } |
143 | |
144 | /*! |
145 | \qmlproperty bool QtWebView::WebView::canGoForward |
146 | \readonly |
147 | |
148 | Holds \c true if it's currently possible to navigate forward in the web history. |
149 | */ |
150 | |
151 | bool QQuickWebView::canGoForward() const |
152 | { |
153 | return m_webView->canGoForward(); |
154 | } |
155 | |
156 | /*! |
157 | \qmlproperty int QtWebView::WebView::loadProgress |
158 | \readonly |
159 | |
160 | The current load progress of the web content, represented as |
161 | an integer between 0 and 100. |
162 | */ |
163 | int QQuickWebView::loadProgress() const |
164 | { |
165 | return m_webView->loadProgress(); |
166 | } |
167 | |
168 | /*! |
169 | \qmlproperty bool QtWebView::WebView::loading |
170 | \readonly |
171 | |
172 | Holds \c true if the WebView is currently in the process of loading |
173 | new content, \c false otherwise. |
174 | |
175 | \sa loadingChanged() |
176 | */ |
177 | |
178 | /*! |
179 | \qmlsignal QtWebView::WebView::loadingChanged(WebViewLoadRequest loadRequest) |
180 | |
181 | This signal is emitted when the state of loading the web content changes. |
182 | By handling this signal it's possible, for example, to react to page load |
183 | errors. |
184 | |
185 | The \a loadRequest parameter holds the \e url and \e status of the request, |
186 | as well as an \e errorString containing an error message for a failed |
187 | request. |
188 | |
189 | \sa WebViewLoadRequest |
190 | */ |
191 | bool QQuickWebView::isLoading() const |
192 | { |
193 | return m_webView->isLoading(); |
194 | } |
195 | |
196 | /*! |
197 | \qmlmethod void QtWebView::WebView::goBack() |
198 | |
199 | Navigates back in the web history. |
200 | */ |
201 | void QQuickWebView::goBack() |
202 | { |
203 | m_webView->goBack(); |
204 | } |
205 | |
206 | /*! |
207 | \qmlmethod void QtWebView::WebView::goForward() |
208 | |
209 | Navigates forward in the web history. |
210 | */ |
211 | void QQuickWebView::goForward() |
212 | { |
213 | m_webView->goForward(); |
214 | } |
215 | |
216 | /*! |
217 | \qmlmethod void QtWebView::WebView::reload() |
218 | |
219 | Reloads the current \l url. |
220 | */ |
221 | void QQuickWebView::reload() |
222 | { |
223 | m_webView->reload(); |
224 | } |
225 | |
226 | /*! |
227 | \qmlmethod void QtWebView::WebView::stop() |
228 | |
229 | Stops loading the current \l url. |
230 | */ |
231 | void QQuickWebView::stop() |
232 | { |
233 | m_webView->stop(); |
234 | } |
235 | |
236 | /*! |
237 | \qmlmethod void QtWebView::WebView::loadHtml(string html, url baseUrl) |
238 | |
239 | Loads the specified \a html content to the web view. |
240 | |
241 | This method offers a lower-level alternative to the \l url property, |
242 | which references HTML pages via URL. |
243 | |
244 | External objects such as stylesheets or images referenced in the HTML |
245 | document should be located relative to \a baseUrl. For example, if \a html |
246 | is retrieved from \c http://www.example.com/documents/overview.html, which |
247 | is the base URL, then an image referenced with the relative url, \c diagram.png, |
248 | should be at \c{http://www.example.com/documents/diagram.png}. |
249 | |
250 | \note The WebView does not support loading content through the Qt Resource system. |
251 | |
252 | \sa url |
253 | */ |
254 | void QQuickWebView::loadHtml(const QString &html, const QUrl &baseUrl) |
255 | { |
256 | m_webView->loadHtml(html, baseUrl); |
257 | } |
258 | |
259 | /*! |
260 | \qmlmethod void QtWebView::WebView::runJavaScript(string script, variant callback) |
261 | |
262 | Runs the specified JavaScript. |
263 | In case a \a callback function is provided, it will be invoked after the \a script |
264 | finished running. |
265 | |
266 | \badcode |
267 | runJavaScript("document.title", function(result) { console.log(result); }); |
268 | \endcode |
269 | */ |
270 | void QQuickWebView::runJavaScript(const QString &script, const QJSValue &callback) |
271 | { |
272 | const int callbackId = callback.isCallable() ? callbacks->insertCallback(callback) : -1; |
273 | runJavaScriptPrivate(script, callbackId); |
274 | } |
275 | |
276 | void QQuickWebView::runJavaScriptPrivate(const QString &script, int callbackId) |
277 | { |
278 | m_webView->runJavaScriptPrivate(script, callbackId); |
279 | } |
280 | |
281 | /*! |
282 | \qmlmethod void QtWebView::WebView::setCookie(string domain, string name, string value) |
283 | \since QtWebView 6.3 |
284 | Adds a cookie with the specified \a domain, \a name and \a value. |
285 | |
286 | The \l cookieAdded signal will be emitted when the cookie is added. |
287 | */ |
288 | /*! |
289 | \qmlsignal QtWebView::WebView::cookieAdded(string domain, string name) |
290 | |
291 | This signal is emitted when a cookie is added. |
292 | |
293 | The parameters provide information about the \a domain and the \a name of the added cookie. |
294 | |
295 | \note When Qt WebEngine module is used as backend, cookieAdded signal will be emitted for any |
296 | cookie added to the underlying QWebEngineCookieStore, including those added by websites. |
297 | In other cases cookieAdded signal is only emitted for cookies explicitly added with \l setCookie(). |
298 | */ |
299 | void QQuickWebView::setCookie(const QString &domain, const QString &name, const QString &value) |
300 | { |
301 | m_webView->setCookie(domain, name, value); |
302 | } |
303 | |
304 | /*! |
305 | \qmlmethod void QtWebView::WebView::deleteCookie(string domain, string name) |
306 | \since QtWebView 6.3 |
307 | Deletes a cookie with the specified \a domain and \a name. |
308 | |
309 | The \l cookieRemoved signal will be emitted when the cookie is deleted. |
310 | */ |
311 | /*! |
312 | \qmlsignal QtWebView::WebView::cookieRemoved(string domain, string name) |
313 | |
314 | This signal is emitted when a cookie is deleted. |
315 | |
316 | The parameters provide information about the \a domain and the \a name of the deleted cookie. |
317 | */ |
318 | void QQuickWebView::deleteCookie(const QString &domain, const QString &name) |
319 | { |
320 | m_webView->deleteCookie(domain, name); |
321 | } |
322 | |
323 | /*! |
324 | \qmlmethod void QtWebView::WebView::deleteAllCookies() |
325 | \since QtWebView 6.3 |
326 | Deletes all the cookies. |
327 | */ |
328 | void QQuickWebView::deleteAllCookies() |
329 | { |
330 | m_webView->deleteAllCookies(); |
331 | } |
332 | |
333 | void QQuickWebView::itemChange(ItemChange change, const ItemChangeData &value) |
334 | { |
335 | if (change == QQuickItem::ItemActiveFocusHasChanged) { |
336 | m_webView->setFocus(value.boolValue); |
337 | } |
338 | QQuickItem::itemChange(change, value); |
339 | } |
340 | |
341 | void QQuickWebView::onRunJavaScriptResult(int id, const QVariant &variant) |
342 | { |
343 | if (id == -1) |
344 | return; |
345 | |
346 | QJSValue callback = callbacks->takeCallback(callbackId: id); |
347 | if (callback.isUndefined()) |
348 | return; |
349 | |
350 | QQmlEngine *engine = qmlEngine(this); |
351 | if (engine == 0) { |
352 | qWarning(msg: "No JavaScript engine, unable to handle JavaScript callback!" ); |
353 | return; |
354 | } |
355 | |
356 | QJSValueList args; |
357 | args.append(t: engine->toScriptValue(value: variant)); |
358 | callback.call(args); |
359 | } |
360 | |
361 | void QQuickWebView::onFocusRequest(bool focus) |
362 | { |
363 | setFocus(focus); |
364 | } |
365 | |
366 | void QQuickWebView::onLoadingChanged(const QWebViewLoadRequestPrivate &loadRequest) |
367 | { |
368 | QQuickWebViewLoadRequest qqLoadRequest(loadRequest); |
369 | Q_EMIT loadingChanged(loadRequest: &qqLoadRequest); |
370 | } |
371 | |
372 | QJSValue QQuickWebView::takeCallback(int id) |
373 | { |
374 | return callbacks->takeCallback(callbackId: id); |
375 | } |
376 | |
377 | /*! |
378 | \qmlproperty WebViewSettings WebView::settings |
379 | \readonly |
380 | \since QtWebView 6.5 |
381 | |
382 | Settings object for the WebView. |
383 | |
384 | \sa WebViewSettings |
385 | */ |
386 | |
387 | QQuickWebViewSettings *QQuickWebView::settings() const |
388 | { |
389 | return m_settings; |
390 | } |
391 | |