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