]> gitweb.stoutner.com Git - PrivacyBrowserPC.git/blob - src/MainView.cpp
Improve initialization order.
[PrivacyBrowserPC.git] / src / MainView.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 "BrowserWindow.h"
22 #include "MainView.h"
23 #include "MouseEventFilter.h"
24 #include "Settings.h"
25 #include "ui_MainView.h"
26 #include "UrlRequestInterceptor.h"
27 #include "helpers/SearchEngineHelper.h"
28 #include "helpers/UserAgentHelper.h"
29
30 // Qt framework headers.
31 #include <QAction>
32 #include <QWebEngineProfile>
33
34 MainView::MainView(QWidget *parent) : QWidget(parent)
35 {
36     // Instantiate the mainview UI.
37     Ui::MainView mainViewUi;
38
39     // Setup the UI.
40     mainViewUi.setupUi(this);
41
42     // Get handles for the views.
43     backButtonPointer = mainViewUi.backButton;
44     forwardButtonPointer = mainViewUi.forwardButton;
45     QPushButton *refreshButtonPointer = mainViewUi.refreshButton;
46     QPushButton *homeButtonPointer = mainViewUi.homeButton;
47     urlLineEditPointer = mainViewUi.urlLineEdit;
48     javaScriptButtonPointer = mainViewUi.javaScript;
49     webEngineViewPointer = mainViewUi.webEngineView;
50
51     // Get handles for the aspects of the WebEngine.
52     QWebEnginePage *webEnginePagePointer = webEngineViewPointer->page();
53     webEngineHistoryPointer = webEnginePagePointer->history();
54     webEngineProfilePointer = webEnginePagePointer->profile();
55     webEngineSettingsPointer = webEngineViewPointer->settings();
56
57     // Update the webengine view from the URL line edit.
58     connect(urlLineEditPointer, SIGNAL(returnKeyPressed(const QString)), this, SLOT(loadUrlFromTextBox(const QString)));
59
60     // Update the URL line edit form the webengine view.
61     connect(webEngineViewPointer, SIGNAL(loadStarted()), this, SLOT(updateInterface()));
62     connect(webEngineViewPointer, SIGNAL(loadProgress(const int)), this, SLOT(updateInterface()));
63     connect(webEngineViewPointer, SIGNAL(loadFinished(const bool)), this, SLOT(updateInterface()));
64
65     // Setup the URL bar buttons.
66     connect(backButtonPointer, SIGNAL(clicked()), webEngineViewPointer, SLOT(back()));
67     connect(forwardButtonPointer, SIGNAL(clicked()), webEngineViewPointer, SLOT(forward()));
68     connect(refreshButtonPointer, SIGNAL(clicked()), webEngineViewPointer, SLOT(reload()));
69     connect(homeButtonPointer, SIGNAL(clicked()), this, SLOT(goHome()));
70     connect(javaScriptButtonPointer, SIGNAL(clicked()), this, SLOT(toggleJavaScript()));
71
72     // Instantiate the mouse event pointer.
73     MouseEventFilter *mouseEventFilterPointer = new MouseEventFilter(webEngineViewPointer);
74
75     // Install the mouse event filter.
76     qApp->installEventFilter(mouseEventFilterPointer);
77
78     // Listen for hovered link URLs.
79     connect(webEnginePagePointer, SIGNAL(linkHovered(const QString)), this, SLOT(pageLinkHovered(const QString)));
80
81     // Instantiate the URL request interceptor.
82     UrlRequestInterceptor *urlRequestInterceptorPointer = new UrlRequestInterceptor();
83
84     // Set the URL request interceptor.
85     webEngineProfilePointer->setUrlRequestInterceptor(urlRequestInterceptorPointer);
86
87     // Reapply the domain settings when the host changes.
88     connect(urlRequestInterceptorPointer, SIGNAL(applyDomainSettings()), this, SLOT(applyDomainSettingsWithoutReloading()));
89
90     // Disable the cache.
91     webEngineProfilePointer->setHttpCacheType(QWebEngineProfile::NoCache);
92
93     // Don't allow JavaScript to open windows.
94     webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, false);
95
96     // Set the focus on the WebEngine view.
97     webEngineViewPointer->setFocus();
98 }
99
100 void MainView::applyApplicationSettings()
101 {
102     // Set the search engine URL.
103     searchEngineUrl = SearchEngineHelper::getSearchUrl(Settings::searchEngine());
104
105     // Emit the search engine updated signal, which causes the on-the-fly menu to be updated.
106     emit searchEngineUpdated(Settings::searchEngine());
107 }
108
109 // 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.
110 void MainView::applyDomainSettingsAndReload() const
111 {
112     // Apply the domain settings.  `true` reloads the website.
113     applyDomainSettings(true);
114 }
115
116 // 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.
117 void MainView::applyDomainSettingsWithoutReloading() const
118 {
119     // Apply the domain settings  `false` does not reload the website.
120     applyDomainSettings(false);
121 }
122
123 void MainView::applyDomainSettings(bool reloadWebsite) const
124 {
125     // Set the JavaScript status.
126     webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, Settings::javaScript());
127
128     // Update the JavaScript button.
129     if (Settings::javaScript())
130     {
131         javaScriptButtonPointer->setIcon(QIcon(":/icons/javascript-warning"));
132     }
133     else
134     {
135         javaScriptButtonPointer->setIcon(QIcon(":/icons/privacy-mode"));
136     }
137
138     // Apply the user agent.
139     webEngineProfilePointer->setHttpUserAgent(UserAgentHelper::getUserAgent(Settings::userAgent()));
140
141     // Set the zoom factor.
142     webEngineViewPointer->setZoomFactor(Settings::zoomFactor());
143
144     // Emit the on-the-fly menu update signals.
145     emit userAgentUpdated(Settings::userAgent());
146     emit zoomFactorUpdated(Settings::zoomFactor());
147
148     // Reload the website if requested.
149     if (reloadWebsite)
150     {
151         webEngineViewPointer->reload();
152     }
153 }
154
155 void MainView::applyOnTheFlySearchEngine(QAction *searchEngineActionPointer)
156 {
157     // Store the search engine name.
158     QString searchEngineName = searchEngineActionPointer->text();
159
160     // Strip out any `&` characters.
161     searchEngineName.remove('&');
162
163     // Store the search engine string.
164     searchEngineUrl = SearchEngineHelper::getSearchUrl(searchEngineName);
165 }
166
167 void MainView::applyOnTheFlyUserAgent(QAction *userAgentActionPointer) const
168 {
169     // Get the user agent name.
170     QString userAgentName = userAgentActionPointer->text();
171
172     // Strip out any `&` characters.
173     userAgentName.remove('&');
174
175     // Apply the user agent.
176     webEngineProfilePointer->setHttpUserAgent(UserAgentHelper::getUserAgent(userAgentName));
177
178     // Reload the website.
179     webEngineViewPointer->reload();
180 }
181
182 void MainView::applyOnTheFlyZoomFactor(const double &zoomFactor) const
183 {
184     // Set the zoom factor.
185     webEngineViewPointer->setZoomFactor(zoomFactor);
186 }
187
188 void MainView::goHome() const
189 {
190     // Load the homepage.
191     webEngineViewPointer->setUrl(QUrl::fromUserInput(Settings::homepage()));
192 }
193
194 void MainView::loadInitialWebsite()
195 {
196     // Apply the application settings.
197     applyApplicationSettings();
198
199     // Get the arguments.
200     QStringList argumentsStringList = qApp->arguments();
201
202     // Check to see if the arguments lists contains a URL.
203     if (argumentsStringList.size() > 1)
204     {
205         // Load the URL from the arguments list.
206         webEngineViewPointer->setUrl(QUrl::fromUserInput(argumentsStringList.at(1)));
207     }
208     else
209     {
210         // Load the homepage.
211         goHome();
212     }
213 }
214
215 void MainView::loadUrlFromTextBox(QString urlFromUser) const
216 {
217     // Remove the focus from the URL line edit.
218     urlLineEditPointer->clearFocus();
219
220     // Decide if the text is more likely to be a URL or a search.
221     if (urlFromUser.contains("."))  // The text is likely a URL.
222     {
223         // Check if the URL does not start with a valid protocol.
224         if (!urlFromUser.startsWith("http") && !urlFromUser.startsWith("file://"))
225         {
226             // Add `https://` to the beginning of the URL.
227             urlFromUser = "https://" + urlFromUser;
228         }
229
230         // Load the URL.
231         webEngineViewPointer->setUrl(QUrl::fromUserInput(urlFromUser));
232     }
233     else  // The text is likely a search.
234     {
235         // Load the search.
236         webEngineViewPointer->setUrl(QUrl::fromUserInput(searchEngineUrl + urlFromUser));
237     }
238 }
239
240 void MainView::pageLinkHovered(const QString &linkUrl) const
241 {
242     // Emit a signal so that the browser window can update the status bar.
243     emit linkHovered(linkUrl);
244 }
245
246 void MainView::toggleJavaScript() const
247 {
248     // Toggle JavaScript.
249     webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, !webEngineSettingsPointer->testAttribute(QWebEngineSettings::JavascriptEnabled));
250
251     // Update the JavaScript button.
252     if (webEngineSettingsPointer->testAttribute(QWebEngineSettings::JavascriptEnabled))
253     {
254         javaScriptButtonPointer->setIcon(QIcon(":/icons/javascript-warning"));
255     }
256     else
257     {
258         javaScriptButtonPointer->setIcon(QIcon(":/icons/privacy-mode"));
259     }
260
261     // Reload the website.
262     webEngineViewPointer->reload();
263 }
264
265 void MainView::updateInterface() const
266 {
267     // Update the URL line edit if it does not have focus.
268     if (!urlLineEditPointer->hasFocus())
269     {
270         // Update the URL line edit.
271         urlLineEditPointer->setText(webEngineViewPointer->url().toString());
272     }
273
274     // Update the status of the forward and back buttons.
275     backButtonPointer->setEnabled(webEngineHistoryPointer->canGoBack());
276     forwardButtonPointer->setEnabled(webEngineHistoryPointer->canGoForward());
277
278     // 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>
279     webEngineViewPointer->setZoomFactor(Settings::zoomFactor());
280 }