]> gitweb.stoutner.com Git - PrivacyBrowserPC.git/blob - src/widgets/PrivacyWebEngineView.cpp
Add a default folder icon to the edit folder dialog. https://redmine.stoutner.com...
[PrivacyBrowserPC.git] / src / widgets / PrivacyWebEngineView.cpp
1 /*
2  * Copyright 2022-2024 Soren Stoutner <soren@stoutner.com>.
3  *
4  * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
5  *
6  * Privacy Browser PC is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Privacy Browser PC is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 // Application headers.
21 #include "PrivacyWebEngineView.h"
22 #include "Settings.h"
23 #include "ui_HttpAuthenticationDialog.h"
24 #include "databases/CookiesDatabase.h"
25 #include "databases/DomainsDatabase.h"
26 #include "dialogs/HttpAuthenticationDialog.h"
27 #include "interceptors/UrlRequestInterceptor.h"
28 #include "windows/BrowserWindow.h"
29
30 // Qt toolkit headers.
31 #include <QContextMenuEvent>
32 #include <QMenu>
33
34 // Construct the class.
35 PrivacyWebEngineView::PrivacyWebEngineView(QWidget *parentWidgetPointer) : QWebEngineView(parentWidgetPointer)
36 {
37     // Create an off-the-record profile (the default when no profile name is specified).
38     webEngineProfilePointer = new QWebEngineProfile(QLatin1String(""));
39
40     // Create a WebEngine page.
41     QWebEnginePage *webEnginePagePointer = new QWebEnginePage(webEngineProfilePointer);
42
43     // Set the WebEngine page.
44     setPage(webEnginePagePointer);
45
46     // Get handles for the various aspects of the WebEngine.
47     webEngineSettingsPointer = webEnginePagePointer->settings();
48
49     // Instantiate the URL request interceptor.
50     UrlRequestInterceptor *urlRequestInterceptorPointer = new UrlRequestInterceptor(this);
51
52     // Set the URL request interceptor.
53     webEngineProfilePointer->setUrlRequestInterceptor(urlRequestInterceptorPointer);
54
55     // Reapply the domain settings when the host changes.
56     connect(urlRequestInterceptorPointer, SIGNAL(applyDomainSettings(const QString&)), this, SLOT(applyDomainSettingsWithoutReloading(const QString&)));
57
58     // Display HTTP Ping blocked dialogs.
59     connect(urlRequestInterceptorPointer, SIGNAL(displayHttpPingDialog(const QString&)), this, SLOT(displayHttpPingDialog(const QString&)));
60
61     // Handle HTTP authentication requests.
62     connect(webEnginePagePointer, SIGNAL(authenticationRequired(const QUrl&, QAuthenticator*)), this, SLOT(handleAuthenticationRequest(const QUrl&, QAuthenticator*)));
63 }
64
65 void PrivacyWebEngineView::addCookieToList(const QNetworkCookie &cookie) const
66 {
67     //qDebug() << "Add cookie:  " << cookie.toRawForm();
68
69     // Add the new cookie to the list.
70     cookieListPointer->push_front(cookie);
71
72     // Update the cookie if it is durable and has new data.
73     if (CookiesDatabase::isUpdate(cookie))
74         CookiesDatabase::updateCookie(cookie);
75
76     // Update the cookies action.
77     emit updateCookiesAction(cookieListPointer->size());
78 }
79
80 void PrivacyWebEngineView::applyDomainSettingsWithoutReloading(const QString &hostname)
81 {
82     // Apply the domain settings  `false` does not reload the website.
83     applyDomainSettings(hostname, false);
84 }
85
86 void PrivacyWebEngineView::applyDomainSettings(const QString &hostname, const bool reloadWebsite)
87 {
88     // Get the record for the hostname.
89     QSqlQuery domainQuery = DomainsDatabase::getDomainQuery(hostname);
90
91     // Check if the hostname has domain settings.
92     if (domainQuery.isValid())  // The hostname has domain settings.
93     {
94         // Store the domain settings name.
95         domainSettingsName = domainQuery.value(DomainsDatabase::DOMAIN_NAME).toString();
96
97         // Set the JavaScript status.
98         switch (domainQuery.value(DomainsDatabase::JAVASCRIPT).toInt())
99         {
100             // Set the default JavaScript status.
101             case (DomainsDatabase::SYSTEM_DEFAULT):
102             {
103                 webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, Settings::javaScriptEnabled());
104
105                 break;
106             }
107
108             // Enable JavaScript.
109             case (DomainsDatabase::ENABLED):
110             {
111                 webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, true);
112
113                 break;
114             }
115
116             // Disable JavaScript.
117             case (DomainsDatabase::DISABLED):
118             {
119                 webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, false);
120
121                 break;
122             }
123         }
124
125         // Set the local storage status.
126         switch (domainQuery.value(DomainsDatabase::LOCAL_STORAGE).toInt())
127         {
128             // Set the default local storage status.
129             case (DomainsDatabase::SYSTEM_DEFAULT):
130             {
131                 localStorageEnabled = Settings::localStorageEnabled();
132
133                 break;
134             }
135
136             // Enable local storage.
137             case (DomainsDatabase::ENABLED):
138             {
139                 localStorageEnabled = true;
140
141                 break;
142             }
143
144             // Disable local storage.
145             case (DomainsDatabase::DISABLED):
146             {
147                 localStorageEnabled = false;
148
149                 break;
150             }
151         }
152
153         // Set the DOM storage status.
154         switch (domainQuery.value(DomainsDatabase::DOM_STORAGE).toInt())
155         {
156             // Set the default DOM storage status.  QWebEngineSettings confusingly calls this local storage.
157             case (DomainsDatabase::SYSTEM_DEFAULT):
158             {
159                 webEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, Settings::domStorageEnabled());
160
161                 break;
162             }
163
164             // Enable DOM storage.  QWebEngineSettings confusingly calls this local storage.
165             case (DomainsDatabase::ENABLED):
166             {
167                 webEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, true);
168
169                 break;
170             }
171
172             // Disable DOM storage.  QWebEngineSettings confusingly calls this local storage.
173             case (DomainsDatabase::DISABLED):
174             {
175                 webEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, false);
176
177                 break;
178             }
179         }
180
181         // Set the user agent.
182         webEngineProfilePointer->setHttpUserAgent(UserAgentHelper::getResultingDomainSettingsUserAgent(domainQuery.value(DomainsDatabase::USER_AGENT).toString()));
183
184         // Check if a custom zoom factor is set.
185         if (domainQuery.value(DomainsDatabase::ZOOM_FACTOR).toInt())
186         {
187             // Store the current zoom factor.
188             defaultZoomFactor = domainQuery.value(DomainsDatabase::CUSTOM_ZOOM_FACTOR).toDouble();
189         }
190         else
191         {
192             // Store the current zoom factor.
193             defaultZoomFactor = Settings::zoomFactor();
194         }
195     }
196     else  // The hostname does not have domain settings.
197     {
198         // Reset the domain settings name.
199         domainSettingsName = QLatin1String("");
200
201         // Set the JavaScript status.
202         webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, Settings::javaScriptEnabled());
203
204         // Set the local storage status.
205         localStorageEnabled = Settings::localStorageEnabled();
206
207         // Set DOM storage.  In QWebEngineSettings it is called Local Storage.
208         webEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, Settings::domStorageEnabled());
209
210         // Set the user agent.
211         webEngineProfilePointer->setHttpUserAgent(UserAgentHelper::getUserAgentFromDatabaseName(Settings::userAgent()));
212
213         // Store the zoom factor.
214         defaultZoomFactor = Settings::zoomFactor();
215     }
216
217     // Set the current zoom factor.
218     setZoomFactor(defaultZoomFactor);
219
220     // Reload the website if requested.
221     if (reloadWebsite)
222         reload();
223
224     // Reset the HTTP authentication dialog counter.
225     httpAuthenticationDialogsDisplayed = 0;
226
227     // Update the UI.
228     emit updateUi(this);
229 }
230
231 void PrivacyWebEngineView::contextMenuEvent(QContextMenuEvent *contextMenuEvent) {
232     // Get a handle for the
233     QWebEnginePage *webEnginePagePointer = page();
234
235     // Get a handle for the menu.
236     QMenu *contextMenu = webEnginePagePointer->createStandardContextMenu();
237
238     // Get the list of context menu actions.
239     const QList<QAction *> contextMenuActionsList = contextMenu->actions();
240
241     // Add the open link in new background tab action if the context menu already contains the open link in new window action.
242     if (contextMenuActionsList.contains(webEnginePagePointer->action(QWebEnginePage::OpenLinkInNewWindow)))
243     {
244         // Move the open in new tab action to the top of the list.
245         contextMenu->insertAction(webEnginePagePointer->action(QWebEnginePage::Back), webEnginePagePointer->action(QWebEnginePage::OpenLinkInNewTab));
246
247         // Add the open link in background tab action below the open in new tab action.
248         contextMenu->insertAction(webEnginePagePointer->action(QWebEnginePage::Back), webEnginePagePointer->action(QWebEnginePage::OpenLinkInNewBackgroundTab));
249
250         // Move the open in new window action below the open in background tab action.
251         contextMenu->insertAction(webEnginePagePointer->action(QWebEnginePage::Back), webEnginePagePointer->action(QWebEnginePage::OpenLinkInNewWindow));
252
253         // Add a separator below the open in new window action.
254         contextMenu->insertSeparator(webEnginePagePointer->action(QWebEnginePage::Back));
255     }
256
257     // Display the menu using the location in the context menu event.
258     contextMenu->popup(contextMenuEvent->globalPos());
259 }
260
261 QWebEngineView* PrivacyWebEngineView::createWindow(QWebEnginePage::WebWindowType webWindowType) {
262     // Get a handle for the browser window.
263     BrowserWindow *browserWindowPointer = qobject_cast<BrowserWindow*>(window());
264
265     // Create the requested window type.
266     switch (webWindowType)
267     {
268         case QWebEnginePage::WebBrowserTab:
269         {
270             // Create the new tab and return the privacy WebEngine view pointer.  `true` removes the focus from the blank URL line edit.  `true` adds the new tab adjacent to the current tab.
271             // The new privacy WebEngine view pointer is returned so it can be populated with the link from the context menu.
272             return browserWindowPointer->tabWidgetPointer->addTab(true, true);
273         }
274
275         case QWebEnginePage::WebBrowserWindow:
276         {
277             // Create a new browser window.
278             BrowserWindow *newBrowserWindowPointer = new BrowserWindow();
279
280             // Show the new browser window.
281             newBrowserWindowPointer->show();
282
283             // The new privacy WebEngine view pointer is returned so it can be populated with the link from the context menu.
284             return newBrowserWindowPointer->tabWidgetPointer->loadBlankInitialWebsite();
285         }
286
287         case QWebEnginePage::WebBrowserBackgroundTab:
288         {
289             // Create the new tab and return the privacy WebEngine view pointer.  `false` does not clear the URL line edit.  `true` adds the new tab adjacent to the current tab.
290             // `true` creates a background tab.
291             // The new privacy WebEngine view pointer is returned so it can be populated with the link from the context menu.
292             return browserWindowPointer->tabWidgetPointer->addTab(false, true, true);
293         }
294
295         default:
296         {
297             // Return a null pointer for opening a web dialog.
298             return nullptr;
299         }
300     }
301 }
302
303 void PrivacyWebEngineView::displayHttpPingDialog(const QString &httpPingUrl) const
304 {
305     // Display the HTTP Ping blocked dialog.
306     emit displayHttpPingBlockedDialog(httpPingUrl);
307 }
308
309 void PrivacyWebEngineView::handleAuthenticationRequest(const QUrl &requestUrl, QAuthenticator *authenticatorPointer)
310 {
311     // Only display the HTTP authentication dialog if it hasn't already been displayed three times for this URL.
312     if (httpAuthenticationDialogsDisplayed < 3) {
313         // Increment the HTTP authentication dialog display counter.
314         ++httpAuthenticationDialogsDisplayed;
315
316         // Instantiate an HTTP authentication dialog.
317         HttpAuthenticationDialog *httpAuthenticationDialogPointer = new HttpAuthenticationDialog(parentWidget(), requestUrl, authenticatorPointer);
318
319         // Display the dialog.  This must be `exec()` instead of `show()` so that the website doesn't proceed before populating the authentication pointer.
320         httpAuthenticationDialogPointer->exec();
321     }
322 }
323
324 void PrivacyWebEngineView::removeCookieFromList(const QNetworkCookie &cookie) const
325 {
326     //qDebug() << "Remove cookie:  " << cookie.toRawForm();
327
328     // Remove the cookie from the list.
329     cookieListPointer->remove(cookie);
330
331     // Update the cookies action.
332     emit updateCookiesAction(cookieListPointer->size());
333 }