]> gitweb.stoutner.com Git - PrivacyBrowserPC.git/blob - src/views/BrowserView.cpp
Switch the Domain Settings implementation to a Dialog.
[PrivacyBrowserPC.git] / src / views / BrowserView.cpp
1 /*
2  * Copyright © 2022 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 "BrowserView.h"
22 #include "MouseEventFilter.h"
23 #include "Settings.h"
24 #include "ui_BrowserView.h"
25 #include "UrlRequestInterceptor.h"
26 #include "dialogs/DomainSettingsDialog.h"
27 #include "helpers/DomainsDatabaseHelper.h"
28 #include "helpers/SearchEngineHelper.h"
29 #include "helpers/UserAgentHelper.h"
30 #include "windows/BrowserWindow.h"
31
32 // Qt framework headers.
33 #include <QAction>
34 #include <QWebEngineProfile>
35
36 BrowserView::BrowserView(QWidget *parent) : QWidget(parent)
37 {
38     // Instantiate the browser view UI.
39     Ui::BrowserView browserViewUi;
40
41     // Setup the UI.
42     browserViewUi.setupUi(this);
43
44     // Get handles for the views.
45     backButtonPointer = browserViewUi.backButton;
46     forwardButtonPointer = browserViewUi.forwardButton;
47     QPushButton *refreshButtonPointer = browserViewUi.refreshButton;
48     QPushButton *homeButtonPointer = browserViewUi.homeButton;
49     urlLineEditPointer = browserViewUi.urlLineEdit;
50     javaScriptButtonPointer = browserViewUi.javaScript;
51     QPushButton *domainSettingsButtonPointer = browserViewUi.domainSettingsButton;
52     webEngineViewPointer = browserViewUi.webEngineView;
53
54     // Get handles for the aspects of the WebEngine.
55     QWebEnginePage *webEnginePagePointer = webEngineViewPointer->page();
56     webEngineHistoryPointer = webEnginePagePointer->history();
57     webEngineProfilePointer = webEnginePagePointer->profile();
58     webEngineSettingsPointer = webEngineViewPointer->settings();
59
60     // Update the webengine view from the URL line edit.
61     connect(urlLineEditPointer, SIGNAL(returnKeyPressed(const QString)), this, SLOT(loadUrlFromTextBox(const QString)));
62
63     // Update the URL line edit form the webengine view.
64     connect(webEngineViewPointer, SIGNAL(loadStarted()), this, SLOT(updateInterface()));
65     connect(webEngineViewPointer, SIGNAL(loadProgress(const int)), this, SLOT(updateInterface()));
66     connect(webEngineViewPointer, SIGNAL(loadFinished(const bool)), this, SLOT(updateInterface()));
67
68     // Setup the URL bar buttons.
69     connect(backButtonPointer, SIGNAL(clicked()), webEngineViewPointer, SLOT(back()));
70     connect(forwardButtonPointer, SIGNAL(clicked()), webEngineViewPointer, SLOT(forward()));
71     connect(refreshButtonPointer, SIGNAL(clicked()), webEngineViewPointer, SLOT(reload()));
72     connect(homeButtonPointer, SIGNAL(clicked()), this, SLOT(goHome()));
73     connect(javaScriptButtonPointer, SIGNAL(clicked()), this, SLOT(toggleJavaScript()));
74     connect(domainSettingsButtonPointer, SIGNAL(clicked()), this, SLOT(openDomainSettings()));
75
76     // Get the URL line edit palettes.
77     noDomainSettingsPalette = urlLineEditPointer->palette();
78     domainSettingsPalette = urlLineEditPointer->palette();
79
80     // Modify the domain settings palette.
81     domainSettingsPalette.setColor(QPalette::Base, Qt::green);
82
83     // Instantiate the mouse event pointer.
84     MouseEventFilter *mouseEventFilterPointer = new MouseEventFilter(webEngineViewPointer);
85
86     // Install the mouse event filter.
87     qApp->installEventFilter(mouseEventFilterPointer);
88
89     // Listen for hovered link URLs.
90     connect(webEnginePagePointer, SIGNAL(linkHovered(const QString)), this, SLOT(pageLinkHovered(const QString)));
91
92     // Instantiate the URL request interceptor.
93     UrlRequestInterceptor *urlRequestInterceptorPointer = new UrlRequestInterceptor();
94
95     // Set the URL request interceptor.
96     webEngineProfilePointer->setUrlRequestInterceptor(urlRequestInterceptorPointer);
97
98     // Reapply the domain settings when the host changes.
99     connect(urlRequestInterceptorPointer, SIGNAL(applyDomainSettings(QString)), this, SLOT(applyDomainSettingsWithoutReloading(QString)));
100
101     // Disable the cache.
102     webEngineProfilePointer->setHttpCacheType(QWebEngineProfile::NoCache);
103
104     // Don't allow JavaScript to open windows.
105     webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, false);
106
107     // Set the focus on the WebEngine view.
108     webEngineViewPointer->setFocus();
109 }
110
111 void BrowserView::applyApplicationSettings()
112 {
113     // Set the search engine URL.
114     searchEngineUrl = SearchEngineHelper::getSearchUrl(Settings::searchEngine());
115
116     // Emit the search engine updated signal, which causes the on-the-fly menu to be updated.
117     emit searchEngineUpdated(Settings::searchEngine());
118 }
119
120 // This exists as a separate function from `applyDomainSettings()` so it can be listed as a slot and function without the need for a boolean argument.
121 void BrowserView::applyDomainSettingsAndReload() const
122 {
123     // Apply the domain settings.  `true` reloads the website.
124     applyDomainSettings(webEngineViewPointer->url().host(), true);
125 }
126
127 // This exists as a separate function from `applyDomainSettings()` so it can be listed as a slot and function without the need for a boolean argument.
128 void BrowserView::applyDomainSettingsWithoutReloading(const QString &hostname) const
129 {
130     // Apply the domain settings  `false` does not reload the website.
131     applyDomainSettings(hostname, false);
132 }
133
134 void BrowserView::applyDomainSettings(const QString &hostname, const bool reloadWebsite) const
135 {
136     // Get the record for the hostname.
137     QSqlQuery domainQuery = DomainsDatabaseHelper::getDomainQuery(hostname);
138
139     // Check if the hostname has domain settings.
140     if (domainQuery.isValid())  // The hostname has domain settings.
141     {
142
143
144         // Get the domain record.
145         QSqlRecord domainRecord = domainQuery.record();
146
147         // Set the JavaScript status.
148         switch (domainRecord.field(DomainsDatabaseHelper::JAVASCRIPT).value().toInt())
149         {
150             case (DomainsDatabaseHelper::SYSTEM_DEFAULT):
151             {
152                 // Set the default JavaScript status.
153                 webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, Settings::javaScript());
154
155                 break;
156             }
157
158             case (DomainsDatabaseHelper::DISABLED):
159             {
160                 // Disable JavaScript.
161                 webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, false);
162
163                 break;
164             }
165
166             case (DomainsDatabaseHelper::ENABLED):
167             {
168                 // Enable JavaScript.
169                 webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, true);
170
171                 break;
172             }
173         }
174
175         // Apply the user agent.
176         webEngineProfilePointer->setHttpUserAgent(UserAgentHelper::getUserAgent(Settings::userAgent()));
177
178         // Set the zoom factor.
179         webEngineViewPointer->setZoomFactor(Settings::zoomFactor());
180
181         // Apply the domain settings palette to the URL line edit.
182         urlLineEditPointer->setPalette(domainSettingsPalette);
183     }
184     else  // The hostname does not have domain settings.
185     {
186         // Set the JavaScript status.
187         webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, Settings::javaScript());
188
189         // Apply the user agent.
190         webEngineProfilePointer->setHttpUserAgent(UserAgentHelper::getUserAgent(Settings::userAgent()));
191
192         // Set the zoom factor.
193         webEngineViewPointer->setZoomFactor(Settings::zoomFactor());
194
195         // Apply the no domain settings palette to the URL line edit.
196         urlLineEditPointer->setPalette(noDomainSettingsPalette);
197     }
198
199     // Update the JavaScript button.
200     if (webEngineSettingsPointer->testAttribute(QWebEngineSettings::JavascriptEnabled))
201     {
202         javaScriptButtonPointer->setIcon(QIcon(":/icons/javascript-warning"));
203     }
204     else
205     {
206         javaScriptButtonPointer->setIcon(QIcon(":/icons/privacy-mode"));
207     }
208
209     // Emit the on-the-fly menu update signals.
210     emit userAgentUpdated(Settings::userAgent());
211     emit zoomFactorUpdated(Settings::zoomFactor());
212
213     // Reload the website if requested.
214     if (reloadWebsite)
215     {
216         webEngineViewPointer->reload();
217     }
218 }
219
220 void BrowserView::applyOnTheFlySearchEngine(QAction *searchEngineActionPointer)
221 {
222     // Store the search engine name.
223     QString searchEngineName = searchEngineActionPointer->text();
224
225     // Strip out any `&` characters.
226     searchEngineName.remove('&');
227
228     // Store the search engine string.
229     searchEngineUrl = SearchEngineHelper::getSearchUrl(searchEngineName);
230 }
231
232 void BrowserView::applyOnTheFlyUserAgent(QAction *userAgentActionPointer) const
233 {
234     // Get the user agent name.
235     QString userAgentName = userAgentActionPointer->text();
236
237     // Strip out any `&` characters.
238     userAgentName.remove('&');
239
240     // Apply the user agent.
241     webEngineProfilePointer->setHttpUserAgent(UserAgentHelper::getUserAgent(userAgentName));
242
243     // Reload the website.
244     webEngineViewPointer->reload();
245 }
246
247 void BrowserView::applyOnTheFlyZoomFactor(const double &zoomFactor) const
248 {
249     // Set the zoom factor.
250     webEngineViewPointer->setZoomFactor(zoomFactor);
251 }
252
253 void BrowserView::goHome() const
254 {
255     // Load the homepage.
256     webEngineViewPointer->setUrl(QUrl::fromUserInput(Settings::homepage()));
257 }
258
259 void BrowserView::loadInitialWebsite()
260 {
261     // Apply the application settings.
262     applyApplicationSettings();
263
264     // Get the arguments.
265     QStringList argumentsStringList = qApp->arguments();
266
267     // Check to see if the arguments lists contains a URL.
268     if (argumentsStringList.size() > 1)
269     {
270         // Load the URL from the arguments list.
271         webEngineViewPointer->setUrl(QUrl::fromUserInput(argumentsStringList.at(1)));
272     }
273     else
274     {
275         // Load the homepage.
276         goHome();
277     }
278 }
279
280 void BrowserView::loadUrlFromTextBox(QString urlFromUser) const
281 {
282     // Remove the focus from the URL line edit.
283     urlLineEditPointer->clearFocus();
284
285     // Decide if the text is more likely to be a URL or a search.
286     if (urlFromUser.contains("."))  // The text is likely a URL.
287     {
288         // Check if the URL does not start with a valid protocol.
289         if (!urlFromUser.startsWith("http") && !urlFromUser.startsWith("file://"))
290         {
291             // Add `https://` to the beginning of the URL.
292             urlFromUser = "https://" + urlFromUser;
293         }
294
295         // Load the URL.
296         webEngineViewPointer->setUrl(QUrl::fromUserInput(urlFromUser));
297     }
298     else  // The text is likely a search.
299     {
300         // Load the search.
301         webEngineViewPointer->setUrl(QUrl::fromUserInput(searchEngineUrl + urlFromUser));
302     }
303 }
304
305 void BrowserView::openDomainSettings() const
306 {
307     // Instantiate the domain settings window.
308     DomainSettingsDialog *domainSettingsDialogPointer = new DomainSettingsDialog();
309
310     // Set the dialog window title.
311     domainSettingsDialogPointer->setWindowTitle(i18nc("The domain settings dialog title", "Domain Settings"));
312
313     // Resize the dialog window.
314     domainSettingsDialogPointer->resize(1500, 1000);
315
316     // Set the modality.
317     domainSettingsDialogPointer->setWindowModality(Qt::WindowModality::WindowModal);;
318
319     // Show the dialog.
320     domainSettingsDialogPointer->show();
321 }
322
323 void BrowserView::pageLinkHovered(const QString &linkUrl) const
324 {
325     // Emit a signal so that the browser window can update the status bar.
326     emit linkHovered(linkUrl);
327 }
328
329 void BrowserView::toggleJavaScript() const
330 {
331     // Toggle JavaScript.
332     webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, !webEngineSettingsPointer->testAttribute(QWebEngineSettings::JavascriptEnabled));
333
334     // Update the JavaScript button.
335     if (webEngineSettingsPointer->testAttribute(QWebEngineSettings::JavascriptEnabled))
336     {
337         javaScriptButtonPointer->setIcon(QIcon(":/icons/javascript-warning"));
338     }
339     else
340     {
341         javaScriptButtonPointer->setIcon(QIcon(":/icons/privacy-mode"));
342     }
343
344     // Reload the website.
345     webEngineViewPointer->reload();
346 }
347
348 void BrowserView::updateInterface() const
349 {
350     // Update the URL line edit if it does not have focus.
351     if (!urlLineEditPointer->hasFocus())
352     {
353         // Update the URL line edit.
354         urlLineEditPointer->setText(webEngineViewPointer->url().toString());
355     }
356
357     // Update the status of the forward and back buttons.
358     backButtonPointer->setEnabled(webEngineHistoryPointer->canGoBack());
359     forwardButtonPointer->setEnabled(webEngineHistoryPointer->canGoForward());
360
361     // Reapply the zoom factor.  This is a bug in QWebEngineView that resets the zoom with every load.  Hopefully it will be fixed in Qt6.  <https://bugreports.qt.io/browse/QTBUG-51992>
362     webEngineViewPointer->setZoomFactor(Settings::zoomFactor());
363 }