Rename Local Storage to DOM Storage. https://redmine.stoutner.com/issues/852
[PrivacyBrowserPC.git] / src / windows / BrowserWindow.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 "Settings.h"
23 #include "ui_SettingsPrivacy.h"
24 #include "ui_SettingsGeneral.h"
25 #include "dialogs/CookiesDialog.h"
26 #include "dialogs/DomainSettingsDialog.h"
27 #include "helpers/SearchEngineHelper.h"
28 #include "helpers/UserAgentHelper.h"
29
30 // KDE Frameworks headers.
31 #include <KActionCollection>
32 #include <KToolBar>
33
34 // Qt toolkit headers.
35 #include <QInputDialog>
36 #include <QNetworkCookie>
37 #include <QStatusBar>
38
39 // Construct the class.
40 BrowserWindow::BrowserWindow() : KXmlGuiWindow()
41 {
42     // Initialize the variables.
43     cookieListPointer = new std::list<QNetworkCookie>;
44     cookiesEnabled = false;
45     javaScriptEnabled = false;
46
47     // Instantiate the main view pointer.
48     browserViewPointer = new BrowserView(this);
49
50     // Set the main view as the central widget.
51     setCentralWidget(browserViewPointer);
52
53     // Get a handle for the action collection.
54     KActionCollection *actionCollectionPointer = this->actionCollection();
55
56     // Add the standard actions.
57     QAction *backActionPointer = KStandardAction::back(this, SLOT(back()), actionCollectionPointer);
58     QAction *forwardActionPointer = KStandardAction::forward(this, SLOT(forward()), actionCollectionPointer);
59     KStandardAction::home(this, SLOT(home()), actionCollectionPointer);
60     KStandardAction::openNew(this, SLOT(fileNew()), actionCollectionPointer);
61     KStandardAction::quit(qApp, SLOT(closeAllWindows()), actionCollectionPointer);
62     KStandardAction::preferences(this, SLOT(settingsConfigure()), actionCollectionPointer);
63     KStandardAction::redisplay(this, SLOT(refresh()), actionCollectionPointer);
64
65     // Add the custom actions.
66     userAgentPrivacyBrowserActionPointer = actionCollectionPointer->addAction(QStringLiteral("user_agent_privacy_browser"));
67     userAgentWebEngineDefaultActionPointer = actionCollectionPointer->addAction(QStringLiteral("user_agent_webengine_default"));
68     userAgentFirefoxLinuxActionPointer = actionCollectionPointer->addAction(QStringLiteral("user_agent_firefox_linux"));
69     userAgentChromiumLinuxActionPointer = actionCollectionPointer->addAction(QStringLiteral("user_agent_chromium_linux"));
70     userAgentFirefoxWindowsActionPointer = actionCollectionPointer->addAction(QStringLiteral("user_agent_firefox_windows"));
71     userAgentChromeWindowsActionPointer = actionCollectionPointer->addAction(QStringLiteral("user_agent_chrome_windows"));
72     userAgentEdgeWindowsActionPointer = actionCollectionPointer->addAction(QStringLiteral("user_agent_edge_windows"));
73     userAgentSafariMacosActionPointer = actionCollectionPointer->addAction(QStringLiteral("user_agent_safari_macos"));
74     userAgentCustomActionPointer = actionCollectionPointer->addAction(QStringLiteral("user_agent_custom"));
75     zoomFactorActionPointer = actionCollectionPointer->addAction(QStringLiteral("zoom_factor"));
76     searchEngineMojeekActionPointer = actionCollectionPointer->addAction(QStringLiteral("search_engine_mojeek"));
77     searchEngineMonoclesActionPointer = actionCollectionPointer->addAction(QStringLiteral("search_engine_monocles"));
78     searchEngineMetagerActionPointer = actionCollectionPointer->addAction(QStringLiteral("search_engine_metager"));
79     searchEngineGoogleActionPointer = actionCollectionPointer->addAction(QStringLiteral("search_engine_google"));
80     searchEngineBingActionPointer = actionCollectionPointer->addAction(QStringLiteral("search_engine_bing"));
81     searchEngineYahooActionPointer = actionCollectionPointer->addAction(QStringLiteral("search_engine_yahoo"));
82     searchEngineCustomActionPointer = actionCollectionPointer->addAction(QStringLiteral("search_engine_custom"));
83     QAction *domainSettingsActionPointer = actionCollectionPointer->addAction(QStringLiteral("domain_settings"));
84     cookiesActionPointer = actionCollectionPointer->addAction(QStringLiteral("cookies"));
85     javaScriptActionPointer = actionCollectionPointer->addAction(QStringLiteral("javascript"));
86     onTheFlyCookiesActionPointer = actionCollectionPointer->addAction(QStringLiteral("on-the-fly_cookies"));
87     domStorageActionPointer = actionCollectionPointer->addAction(QStringLiteral("dom_storage"));
88
89     // Create the action groups
90     QActionGroup *userAgentActionGroupPointer = new QActionGroup(this);
91     QActionGroup *searchEngineActionGroupPointer = new QActionGroup(this);
92
93     // Add the actions to the groups.
94     userAgentActionGroupPointer->addAction(userAgentPrivacyBrowserActionPointer);
95     userAgentActionGroupPointer->addAction(userAgentWebEngineDefaultActionPointer);
96     userAgentActionGroupPointer->addAction(userAgentFirefoxLinuxActionPointer);
97     userAgentActionGroupPointer->addAction(userAgentChromiumLinuxActionPointer);
98     userAgentActionGroupPointer->addAction(userAgentFirefoxWindowsActionPointer);
99     userAgentActionGroupPointer->addAction(userAgentChromeWindowsActionPointer);
100     userAgentActionGroupPointer->addAction(userAgentEdgeWindowsActionPointer);
101     userAgentActionGroupPointer->addAction(userAgentSafariMacosActionPointer);
102     userAgentActionGroupPointer->addAction(userAgentCustomActionPointer);
103     searchEngineActionGroupPointer->addAction(searchEngineMojeekActionPointer);
104     searchEngineActionGroupPointer->addAction(searchEngineMonoclesActionPointer);
105     searchEngineActionGroupPointer->addAction(searchEngineMetagerActionPointer);
106     searchEngineActionGroupPointer->addAction(searchEngineGoogleActionPointer);
107     searchEngineActionGroupPointer->addAction(searchEngineBingActionPointer);
108     searchEngineActionGroupPointer->addAction(searchEngineYahooActionPointer);
109     searchEngineActionGroupPointer->addAction(searchEngineCustomActionPointer);
110
111     // Set some actions to be checkable.
112     userAgentPrivacyBrowserActionPointer->setCheckable(true);
113     userAgentWebEngineDefaultActionPointer->setCheckable(true);
114     userAgentFirefoxLinuxActionPointer->setCheckable(true);
115     userAgentChromiumLinuxActionPointer->setCheckable(true);
116     userAgentFirefoxWindowsActionPointer->setCheckable(true);
117     userAgentChromeWindowsActionPointer->setCheckable(true);
118     userAgentEdgeWindowsActionPointer->setCheckable(true);
119     userAgentSafariMacosActionPointer->setCheckable(true);
120     userAgentCustomActionPointer->setCheckable(true);
121     searchEngineMojeekActionPointer->setCheckable(true);
122     searchEngineMonoclesActionPointer->setCheckable(true);
123     searchEngineMetagerActionPointer->setCheckable(true);
124     searchEngineGoogleActionPointer->setCheckable(true);
125     searchEngineBingActionPointer->setCheckable(true);
126     searchEngineYahooActionPointer->setCheckable(true);
127     searchEngineCustomActionPointer->setCheckable(true);
128
129     // Get the number of cookies.
130     int numberOfCookies = cookieListPointer->size();
131
132     // Set the action text.
133     userAgentPrivacyBrowserActionPointer->setText(UserAgentHelper::PRIVACY_BROWSER_TRANSLATED);
134     userAgentWebEngineDefaultActionPointer->setText(UserAgentHelper::WEB_ENGINE_DEFAULT_TRANSLATED);
135     userAgentFirefoxLinuxActionPointer->setText(UserAgentHelper::FIREFOX_LINUX_TRANSLATED);
136     userAgentChromiumLinuxActionPointer->setText(UserAgentHelper::CHROMIUM_LINUX_TRANSLATED);
137     userAgentFirefoxWindowsActionPointer->setText(UserAgentHelper::FIREFOX_WINDOWS_TRANSLATED);
138     userAgentChromeWindowsActionPointer->setText(UserAgentHelper::CHROME_WINDOWS_TRANSLATED);
139     userAgentEdgeWindowsActionPointer->setText(UserAgentHelper::EDGE_WINDOWS_TRANSLATED);
140     userAgentSafariMacosActionPointer->setText(UserAgentHelper::SAFARI_MACOS_TRANSLATED);
141     searchEngineMojeekActionPointer->setText(i18nc("Search engine", "Mojeek"));
142     searchEngineMonoclesActionPointer->setText(i18nc("Search engine", "Monocles"));
143     searchEngineMetagerActionPointer->setText(i18nc("Search engine", "MetaGer"));
144     searchEngineGoogleActionPointer->setText(i18nc("Search engine", "Google"));
145     searchEngineBingActionPointer->setText(i18nc("Search engine", "Bing"));
146     searchEngineYahooActionPointer->setText(i18nc("Search engine", "Yahoo"));
147     domainSettingsActionPointer->setText(i18nc("Domain Settings action", "Domain Settings"));
148     cookiesActionPointer->setText(i18nc("The Cookies action, which also displays the number of cookies", "Cookies - %1", numberOfCookies));
149     javaScriptActionPointer->setText(i18nc("JavaScript action", "JavaScript"));
150     onTheFlyCookiesActionPointer->setText(i18nc("The On-The-Fly Cookies action, which also display the number of cookies", "Cookies - %1", numberOfCookies));
151     domStorageActionPointer->setText(i18nc("DOM Storage action", "DOM Storage"));
152
153     // Set the action icons.
154     userAgentPrivacyBrowserActionPointer->setIcon(QIcon(":/icons/privacy-mode"));
155     userAgentWebEngineDefaultActionPointer->setIcon(QIcon::fromTheme(QStringLiteral("user-group-properties")));
156     userAgentFirefoxLinuxActionPointer->setIcon(QIcon::fromTheme(QStringLiteral("firefox-esr")));
157     userAgentChromiumLinuxActionPointer->setIcon(QIcon::fromTheme(QStringLiteral("chromium")));
158     userAgentFirefoxWindowsActionPointer->setIcon(QIcon::fromTheme(QStringLiteral("firefox-esr")));
159     userAgentChromeWindowsActionPointer->setIcon(QIcon::fromTheme(QStringLiteral("chromium")));
160     userAgentEdgeWindowsActionPointer->setIcon(QIcon::fromTheme(QStringLiteral("user-group-properties")));
161     userAgentSafariMacosActionPointer->setIcon(QIcon::fromTheme(QStringLiteral("user-group-properties")));
162     userAgentCustomActionPointer->setIcon(QIcon::fromTheme(QStringLiteral("user-group-properties")));
163     searchEngineMojeekActionPointer->setIcon(QIcon::fromTheme(QStringLiteral("search")));
164     searchEngineMonoclesActionPointer->setIcon(QIcon::fromTheme(QStringLiteral("search")));
165     searchEngineMetagerActionPointer->setIcon(QIcon::fromTheme(QStringLiteral("search")));
166     searchEngineGoogleActionPointer->setIcon(QIcon::fromTheme(QStringLiteral("im-google")));
167     searchEngineBingActionPointer->setIcon(QIcon::fromTheme(QStringLiteral("search")));
168     searchEngineYahooActionPointer->setIcon(QIcon::fromTheme(QStringLiteral("im-yahoo")));
169     searchEngineCustomActionPointer->setIcon(QIcon::fromTheme(QStringLiteral("search")));
170     zoomFactorActionPointer->setIcon(QIcon::fromTheme(QStringLiteral("zoom")));
171     domainSettingsActionPointer->setIcon(QIcon::fromTheme(QStringLiteral("settings-configure")));
172     cookiesActionPointer->setIcon(QIcon::fromTheme(QStringLiteral("preferences-web-browser-cookies")));
173     onTheFlyCookiesActionPointer->setIcon(QIcon(":/icons/cookies-off"));
174
175     // Update the on-the-fly menus.
176     connect(browserViewPointer, SIGNAL(updateUserAgentActions(QString)), this, SLOT(updateUserAgentActions(QString)));
177     connect(browserViewPointer, SIGNAL(updateZoomFactorAction(double)), this, SLOT(updateZoomFactorAction(double)));
178     connect(browserViewPointer, SIGNAL(updateSearchEngineActions(QString)), this, SLOT(updateSearchEngineActions(QString)));
179
180     // Apply the on-the-fly settings when selected.
181     connect(userAgentActionGroupPointer, SIGNAL(triggered(QAction*)), browserViewPointer, SLOT(applyOnTheFlyUserAgent(QAction*)));
182     connect(searchEngineActionGroupPointer, SIGNAL(triggered(QAction*)), browserViewPointer, SLOT(applyOnTheFlySearchEngine(QAction*)));
183
184     // Display dialogs.
185     connect(zoomFactorActionPointer, SIGNAL(triggered()), this, SLOT(getZoomFactorFromUser()));
186     connect(cookiesActionPointer, SIGNAL(triggered()), this, SLOT(openCookiesDialog()));
187     connect(domainSettingsActionPointer, SIGNAL(triggered()), this, SLOT(openDomainSettings()));
188
189     // Connect the URL toolbar actions.
190     connect(javaScriptActionPointer, SIGNAL(triggered()), this, SLOT(toggleJavaScript()));
191     connect(onTheFlyCookiesActionPointer, SIGNAL(triggered()), this, SLOT(toggleCookies()));
192     connect(domStorageActionPointer, SIGNAL(triggered()), this, SLOT(toggleDomStorage()));
193
194     // Update the URL toolbar actions.
195     connect(browserViewPointer, SIGNAL(updateBackAction(bool)), backActionPointer, SLOT(setEnabled(bool)));
196     connect(browserViewPointer, SIGNAL(updateForwardAction(bool)), forwardActionPointer, SLOT(setEnabled(bool)));
197     connect(browserViewPointer, SIGNAL(updateJavaScriptAction(bool)), this, SLOT(updateJavaScriptAction(bool)));
198     connect(browserViewPointer, SIGNAL(updateCookiesAction(bool)), this, SLOT(updateCookiesAction(bool)));
199     connect(browserViewPointer, SIGNAL(updateDomStorageAction(bool)), this, SLOT(updateDomStorageAction(bool)));
200
201     // Setup the GUI based on the browser_ui.rc file.
202     setupGUI(StandardWindowOption::Default, ("browser_ui.rc"));
203
204     // Get a handle for the URL toolbar.
205     KToolBar *urlToolBarPointer = toolBar(QStringLiteral("url_toolbar"));
206
207     // Create a URL line edit.
208     urlLineEditPointer = new KLineEdit();
209
210     // Add an edit or add domain settings action to the URL line edit.
211     QAction *addOrEditDomainSettingsActionPointer = urlLineEditPointer->addAction(QIcon::fromTheme("settings-configure"), QLineEdit::TrailingPosition);
212
213     // Add or edit the current domain settings.
214     connect(addOrEditDomainSettingsActionPointer, SIGNAL(triggered()), this, SLOT(addOrEditDomainSettings()));
215
216     // Populate the URL toolbar.
217     urlToolBarPointer->insertWidget(javaScriptActionPointer, urlLineEditPointer);
218
219     // Load a new URL from the URL line edit.
220     connect(urlLineEditPointer, SIGNAL(returnKeyPressed(const QString)), this, SLOT(loadUrlFromLineEdit(const QString)));
221
222     // Update the URL line edit on page loads.
223     connect(browserViewPointer, SIGNAL(updateUrlLineEdit(QUrl)), this, SLOT(updateUrlLineEdit(QUrl)));
224
225     // Get a handle for the status bar.
226     QStatusBar *statusBarPointer = statusBar();
227
228     // Create a progress bar.
229     progressBarPointer = new QProgressBar();
230
231     // Add the progress bar to to the status bar.
232     statusBarPointer->addPermanentWidget(progressBarPointer);
233
234     // Update the status bar with the URL when a link is hovered.
235     connect(browserViewPointer, SIGNAL(linkHovered(QString)), statusBarPointer, SLOT(showMessage(QString)));
236
237     // Update the progress bar.
238     connect(browserViewPointer, SIGNAL(showProgressBar(const int)), this, SLOT(showProgressBar(const int)));
239     connect(browserViewPointer, SIGNAL(hideProgressBar()), progressBarPointer, SLOT(hide()));
240
241     // Clear the URL line edit focus when requested.
242     connect(browserViewPointer, SIGNAL(clearUrlLineEditFocus()), this, SLOT(clearUrlLineEditFocus()));
243
244     // Get the URL line edit palettes.
245     noDomainSettingsPalette = urlLineEditPointer->palette();
246     domainSettingsPalette = urlLineEditPointer->palette();
247
248     // Modify the domain settings palette.
249     domainSettingsPalette.setColor(QPalette::Base, QColor("#C8E6C9"));
250
251     // Update the applied palette.
252     connect(browserViewPointer, SIGNAL(updateDomainSettingsIndicator(bool, QString)), this, SLOT(updateDomainSettingsIndicator(bool, QString)));
253
254     // Process cookie changes.
255     connect(browserViewPointer, SIGNAL(addCookie(QNetworkCookie)), this, SLOT(addCookieToList(QNetworkCookie)));
256     connect(browserViewPointer, SIGNAL(removeCookie(QNetworkCookie)), this, SLOT(removeCookieFromList(QNetworkCookie)));
257
258     // Load the initial website.
259     browserViewPointer->loadInitialWebsite();
260 }
261
262 void BrowserWindow::addCookieToList(const QNetworkCookie &newCookie) const
263 {
264     qDebug() << "Add cookie:  " << newCookie.toRawForm();
265
266     // Add the new cookie to the list.
267     cookieListPointer->push_front(newCookie);
268
269     // Get the number of cookies.
270     int numberOfCookies = cookieListPointer->size();
271
272     // Update the action text.
273     cookiesActionPointer->setText(i18nc("The Cookies action, which also displays the number of cookies", "Cookies - %1", numberOfCookies));
274     onTheFlyCookiesActionPointer->setText(i18nc("The On-The-Fly Cookies action, which also display the number of cookies", "Cookies - %1", numberOfCookies));
275 }
276
277 void BrowserWindow::addOrEditDomainSettings() const
278 {
279     // Remove the focus from the URL line edit.
280     urlLineEditPointer->clearFocus();
281
282     // Create the domain settings dialog pointer.
283     DomainSettingsDialog *domainSettingsDialogPointer;
284
285     // Run the commands according to the current domain settings status.
286     if (currentDomainSettingsDomain == "")  // Domain settings are not currently applied.
287     {
288         // Instruct the domain settings dialog to add a new domain.
289         domainSettingsDialogPointer = new DomainSettingsDialog(DomainSettingsDialog::ADD_DOMAIN, currentUrl.host());
290     }
291     else  // Domain settings are currently applied.
292     {
293         // Instruct the domain settings dialog to edit the current domain.
294         domainSettingsDialogPointer = new DomainSettingsDialog(DomainSettingsDialog::EDIT_DOMAIN, currentDomainSettingsDomain);
295     }
296
297     // Set the dialog window title.
298     domainSettingsDialogPointer->setWindowTitle(i18nc("The domain settings dialog title", "Domain Settings"));
299
300     // Set the modality.
301     domainSettingsDialogPointer->setWindowModality(Qt::WindowModality::WindowModal);;
302
303     // Show the dialog.
304     domainSettingsDialogPointer->show();
305
306     // Reload the tabs when domain settings are updated.
307     connect(domainSettingsDialogPointer, SIGNAL(domainSettingsUpdated()), browserViewPointer, SLOT(applyDomainSettingsAndReload()));
308 }
309
310 void BrowserWindow::back() const
311 {
312     // Remove the focus from the URL line edit.
313     urlLineEditPointer->clearFocus();
314
315     // Go back.
316     browserViewPointer->back();
317 }
318
319 void BrowserWindow::clearUrlLineEditFocus() const
320 {
321     // Remove the focus from the URL line edit.
322     urlLineEditPointer->clearFocus();
323 }
324
325 void BrowserWindow::fileNew() const
326 {
327     // Display a new instance of Privacy Browser.
328     (new BrowserWindow)->show();
329 }
330
331 void BrowserWindow::forward() const
332 {
333     // Remove the focus from the URL line edit.
334     urlLineEditPointer->clearFocus();
335
336     // Go forward.
337     browserViewPointer->forward();
338 }
339
340 void BrowserWindow::getZoomFactorFromUser()
341 {
342     // Create an OK flag.
343     bool okClicked;
344
345     // Display a dialog to get the new zoom factor from the user.  Format the double to display two decimals and have a 0.25 step.
346     double newZoomFactor = QInputDialog::getDouble(this, i18nc("The on-the-fly zoom factor dialog title", "On-The-Fly Zoom Factor"),
347                                                    i18nc("The instruction text of the on-the-fly zoom factor dialog", "Enter a zoom factor between 0.25 and 5.00"),
348                                                    currentZoomFactor, .025, 5.00, 2, &okClicked, Qt::WindowFlags(), 0.25);
349
350     // Update the zoom factor if the user clicked OK.
351     if (okClicked)
352     {
353         // Update the current zoom factor.
354         currentZoomFactor = newZoomFactor;
355
356         // Set the new zoom factor.
357         browserViewPointer->applyOnTheFlyZoomFactor(newZoomFactor);
358
359         // Update the on-the-fly action text.
360         updateZoomFactorAction(newZoomFactor);
361     }
362 }
363
364 void BrowserWindow::home() const
365 {
366     // Remove the focus from the URL line edit.
367     urlLineEditPointer->clearFocus();
368
369     // Go home.
370     browserViewPointer->home();
371 }
372
373 void BrowserWindow::loadUrlFromLineEdit(const QString &url) const
374 {
375     // Remove the focus from the URL line edit.
376     urlLineEditPointer->clearFocus();
377
378     // Load the URL.
379     browserViewPointer->loadUrlFromLineEdit(url);
380 }
381
382 void BrowserWindow::openCookiesDialog()
383 {
384     // Remove the focus from the URL line edit.
385     urlLineEditPointer->clearFocus();
386
387     // Instantiate the cookie settings dialog.
388     CookiesDialog *cookiesDialogPointer = new CookiesDialog(cookieListPointer);
389
390     // Show the dialog.
391     cookiesDialogPointer->show();
392
393     // Connect the dialog signals.
394     connect(cookiesDialogPointer, SIGNAL(addCookie(QNetworkCookie)), browserViewPointer, SLOT(addCookieToStore(QNetworkCookie)));
395     connect(cookiesDialogPointer, SIGNAL(deleteAllCookies()), browserViewPointer, SLOT(deleteAllCookies()));
396     connect(cookiesDialogPointer, SIGNAL(deleteCookie(QNetworkCookie)), browserViewPointer, SLOT(deleteCookieFromStore(QNetworkCookie)));
397 }
398
399 void BrowserWindow::openDomainSettings() const
400 {
401     // Remove the focus from the URL line edit.
402     urlLineEditPointer->clearFocus();
403
404     // Instantiate the domain settings dialog.
405     DomainSettingsDialog *domainSettingsDialogPointer = new DomainSettingsDialog();
406
407     // Show the dialog.
408     domainSettingsDialogPointer->show();
409
410     // Reload the tabs when domain settings are updated.
411     connect(domainSettingsDialogPointer, SIGNAL(domainSettingsUpdated()), browserViewPointer, SLOT(applyDomainSettingsAndReload()));
412 }
413
414 void BrowserWindow::refresh() const
415 {
416     // Remove the focus from the URL line edit.
417     urlLineEditPointer->clearFocus();
418
419     // Refresh the web page.
420     browserViewPointer->refresh();
421 }
422
423 void BrowserWindow::removeCookieFromList(const QNetworkCookie &cookie) const
424 {
425     qDebug() << "Remove cookie:  " << cookie.toRawForm();
426
427     // Remove the cookie from the list.
428     cookieListPointer->remove(cookie);
429
430     // Get the number of cookies.
431     int numberOfCookies = cookieListPointer->size();
432
433     // Update the action text.
434     cookiesActionPointer->setText(i18nc("The Cookies action, which also displays the number of cookies", "Cookies - %1", numberOfCookies));
435     onTheFlyCookiesActionPointer->setText(i18nc("The On-The-Fly Cookies action, which also display the number of cookies", "Cookies - %1", numberOfCookies));
436 }
437
438 void BrowserWindow::showProgressBar(const int &progress) const
439 {
440     // Set the progress bar value.
441     progressBarPointer->setValue(progress);
442
443     // Show the progress bar.
444     progressBarPointer->show();
445 }
446
447 QSize BrowserWindow::sizeHint() const
448 {
449     // Return the default window size.
450     return QSize(1500, 1200);
451 }
452
453 void BrowserWindow::settingsConfigure()
454 {
455     // Check to make sure the dialog box isn't already displayed.
456     if (KConfigDialog::exists(QStringLiteral("settings")))
457     {
458         // Show the existing config dialog if it is hidden.
459         configDialogPointer->show();
460
461         // Raise the existing config dialog if it is below other windows.
462         configDialogPointer->raise();
463
464         // Restore the existing config dialog if it has been minimized.
465         if (configDialogPointer->isMinimized()) {
466             configDialogPointer->showNormal();
467         }
468
469         // Activate the existing config dialog, which brings its virtual desktop into focus.
470         configDialogPointer->activateWindow();
471     }
472     else
473     {
474         // Create the settings widgets.
475         QWidget *privacySettingsWidgetPointer = new QWidget;
476         QWidget *generalSettingsWidgetPointer = new QWidget;
477
478         // Instantiate the settings UI.
479         Ui::PrivacySettings privacySettingsUi;
480         Ui::GeneralSettings generalSettingsUi;
481
482         // Setup the UI to display the settings widgets.
483         privacySettingsUi.setupUi(privacySettingsWidgetPointer);
484         generalSettingsUi.setupUi(generalSettingsWidgetPointer);
485
486         // Get handles for the widgets.
487         QComboBox *userAgentComboBoxPointer = privacySettingsUi.kcfg_userAgent;
488         userAgentLabelPointer = privacySettingsUi.userAgentLabel;
489         QComboBox *searchEngineComboBoxPointer = generalSettingsUi.kcfg_searchEngine;
490         searchEngineLabelPointer = generalSettingsUi.searchEngineLabel;
491
492         // Populate the combo box labels.
493         updateUserAgentLabel(userAgentComboBoxPointer->currentText());
494         updateSearchEngineLabel(searchEngineComboBoxPointer->currentText());
495
496         // Update the labels when the combo boxes change.
497         connect(userAgentComboBoxPointer, SIGNAL(currentTextChanged(const QString)), this, SLOT(updateUserAgentLabel(const QString)));
498         connect(searchEngineComboBoxPointer, SIGNAL(currentTextChanged(const QString)), this, SLOT(updateSearchEngineLabel(const QString)));
499
500         // Instantiate a settings config dialog from the settings.kcfg file.
501         configDialogPointer = new KConfigDialog(this, QStringLiteral("settings"), Settings::self());
502
503         // Add the settings widgets as config dialog pages.
504         configDialogPointer->addPage(privacySettingsWidgetPointer, i18nc("@title:tab", "Privacy"), QStringLiteral("privacy-browser"));
505         configDialogPointer->addPage(generalSettingsWidgetPointer, i18nc("@title:tab", "General"), QStringLiteral("breeze-settings"));
506
507         // Delete the config dialog when it is closed.
508         configDialogPointer->setAttribute(Qt::WA_DeleteOnClose);
509
510         // Make it so.
511         configDialogPointer->show();
512
513         // TODO.  KConfigDialog does not respect expanding size policies.  <https://redmine.stoutner.com/issues/823>
514         //configDialogPointer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
515         //privacySettingsWidgetPointer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
516         //generalSettingsWidgetPointer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
517         //configDialogPointer->adjustSize();
518
519         // Expand the config dialog.
520         configDialogPointer->resize(1000, 500);
521
522         // Apply the settings when they are updated.
523         connect(configDialogPointer, SIGNAL(settingsChanged(QString)), browserViewPointer, SLOT(applyApplicationSettings()));
524         connect(configDialogPointer, SIGNAL(settingsChanged(QString)), browserViewPointer, SLOT(applyDomainSettingsAndReload()));
525     }
526 }
527
528 void BrowserWindow::toggleCookies() const
529 {
530     // Remove the focus from teh URL line edit.
531     urlLineEditPointer->clearFocus();
532
533     // Toggle cookies.
534     browserViewPointer->toggleCookies();
535 }
536
537 void BrowserWindow::toggleJavaScript() const
538 {
539     // Remove the focus from the URL line edit.
540     urlLineEditPointer->clearFocus();
541
542     // Toggle JavaScript.
543     browserViewPointer->toggleJavaScript();
544 }
545
546 void BrowserWindow::toggleDomStorage() const
547 {
548     // Remove the focus from the URL line edit.
549     urlLineEditPointer->clearFocus();
550
551     // Toggle DOM storage.
552     browserViewPointer->toggleDomStorage();
553 }
554
555 void BrowserWindow::updateCookiesAction(const bool &isEnabled)
556 {
557     // Update the cookies status.
558     cookiesEnabled = isEnabled;
559
560     // Update the icon.
561     if (cookiesEnabled)
562         onTheFlyCookiesActionPointer->setIcon(QIcon(":/icons/cookies-on"));
563     else
564         onTheFlyCookiesActionPointer->setIcon(QIcon(":/icons/cookies-off"));
565
566     // Update the status of the DOM storage action.
567     domStorageActionPointer->setEnabled(cookiesEnabled & javaScriptEnabled);
568 }
569
570 void BrowserWindow::updateDomainSettingsIndicator(const bool &status, const QString &domainSettingsDomain)
571 {
572     // Set the domain palette according to the status.
573     if (status)
574         urlLineEditPointer->setPalette(domainSettingsPalette);
575     else
576         urlLineEditPointer->setPalette(noDomainSettingsPalette);
577
578     // Store the domain.
579     currentDomainSettingsDomain = domainSettingsDomain;
580 }
581
582 void BrowserWindow::updateJavaScriptAction(const bool &isEnabled)
583 {
584     // Update the JavaScript status.
585     javaScriptEnabled = isEnabled;
586
587     // Set the icon according to the status.
588     if (javaScriptEnabled)
589         javaScriptActionPointer->setIcon(QIcon(":/icons/javascript-warning"));
590     else
591         javaScriptActionPointer->setIcon(QIcon(":/icons/privacy-mode"));
592
593     // Update the status of the DOM storage action.
594     domStorageActionPointer->setEnabled(javaScriptEnabled & cookiesEnabled);
595 }
596
597 void BrowserWindow::updateDomStorageAction(const bool &isEnabled) const
598 {
599     // Set the icon according to the status.
600     if (isEnabled)
601         domStorageActionPointer->setIcon(QIcon::fromTheme("disk-quota-low"));
602     else
603         domStorageActionPointer->setIcon(QIcon::fromTheme("disk-quota"));
604 }
605
606 void BrowserWindow::updateSearchEngineActions(const QString &searchEngine) const
607 {
608     // Initialize the custom search engine flag.
609     bool customSearchEngine = false;
610
611     if (searchEngine == "Mojeek")  // Mojeek.
612     {
613         searchEngineMojeekActionPointer->setChecked(true);
614     }
615     else if (searchEngine == "Monocles")  // Monocles.
616     {
617         searchEngineMonoclesActionPointer->setChecked(true);
618     }
619     else if (searchEngine == "MetaGer")  // MetaGer.
620     {
621         searchEngineMetagerActionPointer->setChecked(true);
622     }
623     else if (searchEngine == "Google")  // Google.
624     {
625         searchEngineGoogleActionPointer->setChecked(true);
626     }
627     else if (searchEngine == "Bing")  // Bing.
628     {
629         searchEngineBingActionPointer->setChecked(true);
630     }
631     else if (searchEngine == "Yahoo")  // Yahoo.
632     {
633         searchEngineYahooActionPointer->setChecked(true);
634     }
635     else  // Custom search engine.
636     {
637         // Check the user agent.
638         searchEngineCustomActionPointer->setChecked(true);
639
640         // Set the custom search engine flag.
641         customSearchEngine = true;
642     }
643
644     // Format the custom search engine.
645     if (customSearchEngine)
646     {
647         // Enable the custom search engine.
648         searchEngineCustomActionPointer->setEnabled(true);
649
650         // Set the custom search engine text.
651         searchEngineCustomActionPointer->setText(searchEngine);
652     }
653     else
654     {
655         // Disable the custom search engine.
656         searchEngineCustomActionPointer->setEnabled(false);
657
658         // Reset the custom search engine text.
659         searchEngineCustomActionPointer->setText(i18nc("@action", "Custom"));
660     }
661 }
662
663 void BrowserWindow::updateUserAgentActions(const QString &userAgent) const
664 {
665     // Initialize the custom user agent flag.
666     bool customUserAgent = false;
667
668     // Check the indicated on-the-fly user agent.
669     if (userAgent == UserAgentHelper::PRIVACY_BROWSER_USER_AGENT) userAgentPrivacyBrowserActionPointer->setChecked(true);  // Privacy Browser.
670     else if (userAgent == BrowserView::webEngineDefaultUserAgent) userAgentWebEngineDefaultActionPointer->setChecked(true);  // WebEngine default.
671     else if (userAgent == UserAgentHelper::FIREFOX_LINUX_USER_AGENT) userAgentFirefoxLinuxActionPointer->setChecked(true);  // Firefox Linux.
672     else if (userAgent == UserAgentHelper::CHROMIUM_LINUX_USER_AGENT) userAgentChromiumLinuxActionPointer->setChecked(true);  // Chromium Linux.
673     else if (userAgent == UserAgentHelper::FIREFOX_WINDOWS_USER_AGENT) userAgentFirefoxWindowsActionPointer->setChecked(true);  // Firefox Windows.
674     else if (userAgent == UserAgentHelper::CHROME_WINDOWS_USER_AGENT) userAgentChromeWindowsActionPointer->setChecked(true);  // Chrome Windows.
675     else if (userAgent == UserAgentHelper::EDGE_WINDOWS_USER_AGENT) userAgentEdgeWindowsActionPointer->setChecked(true);  // Edge Windows.
676     else if (userAgent == UserAgentHelper::SAFARI_MACOS_USER_AGENT) userAgentSafariMacosActionPointer->setChecked(true);  // Safara macOS.
677     else  // Custom user agent.
678     {
679         // Check the user agent.
680         userAgentCustomActionPointer->setChecked(true);
681
682         // Set the custom user agent flag.
683         customUserAgent = true;
684     }
685
686
687     // Format the custom user agent.
688     if (customUserAgent)
689     {
690         // Enable the custom user agent.
691         userAgentCustomActionPointer->setEnabled(true);
692
693         // Set the custom user agent text.
694         userAgentCustomActionPointer->setText(userAgent);
695     }
696     else
697     {
698         // Disable the custom user agent.
699         userAgentCustomActionPointer->setEnabled(false);
700
701         // Reset the custom user agent text.
702         userAgentCustomActionPointer->setText(i18nc("@action", "Custom"));
703     }
704 }
705
706 void BrowserWindow::updateZoomFactorAction(const double &zoomFactor)
707 {
708     // Set the current zoom factor.
709     currentZoomFactor = zoomFactor;
710
711     // Update the zoom factor action text, formatting the double with 2 decimal places.
712     zoomFactorActionPointer->setText(ki18nc("@action", "Zoom Factor - %1").subs(zoomFactor, 0, '0', 2).toString());
713 }
714
715 void BrowserWindow::updateSearchEngineLabel(const QString &searchEngineString) const
716 {
717     // Update the search engine label.
718     searchEngineLabelPointer->setText(SearchEngineHelper::getSearchUrl(searchEngineString));
719 }
720
721 void BrowserWindow::updateUrlLineEdit(const QUrl &newUrl)
722 {
723     // Update the URL line edit if it does not have focus.
724     if (!urlLineEditPointer->hasFocus())
725     {
726         // Update the URL line edit.
727         urlLineEditPointer->setText(newUrl.toString());
728     }
729
730     // Store the current URL.
731     currentUrl = newUrl;
732 }
733
734 void BrowserWindow::updateUserAgentLabel(const QString &userAgentDatabaseName) const
735 {
736     // Update the user agent label.
737     userAgentLabelPointer->setText(UserAgentHelper::getUserAgentFromDatabaseName(userAgentDatabaseName));
738 }