]> gitweb.stoutner.com Git - PrivacyBrowserPC.git/blob - src/windows/BrowserWindow.cpp
Fix missing icons on Gnome. https://redmine.stoutner.com/issues/993
[PrivacyBrowserPC.git] / src / windows / BrowserWindow.cpp
1 /*
2  * Copyright 2022-2023 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_SettingsGeneral.h"
24 #include "ui_SettingsPrivacy.h"
25 #include "ui_SettingsSpellCheck.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 <KColorScheme>
34 #include <KToolBar>
35
36 // Qt toolkit headers.
37 #include <QFileDialog>
38 #include <QInputDialog>
39 #include <QNetworkCookie>
40 #include <QMenuBar>
41 #include <QShortcut>
42 #include <QStatusBar>
43 #include <QWebEngineFindTextResult>
44
45 // Construct the class.
46 BrowserWindow::BrowserWindow(bool firstWindow) : KXmlGuiWindow()
47 {
48     // Initialize the variables.
49     javaScriptEnabled = false;
50     localStorageEnabled = false;
51
52     // Instantiate the privacy tab widget pointer.
53     tabWidgetPointer = new TabWidget(this);
54
55     // Set the privacy tab widget as the central widget.
56     setCentralWidget(tabWidgetPointer);
57
58     // Get a handle for the action collection.
59     KActionCollection *actionCollectionPointer = this->actionCollection();
60
61     // Add the standard actions.
62     KStandardAction::print(tabWidgetPointer, SLOT(print()), actionCollectionPointer);
63     QAction *printPreviewActionPointer = KStandardAction::printPreview(tabWidgetPointer, SLOT(printPreview()), actionCollectionPointer);
64     KStandardAction::quit(qApp, SLOT(closeAllWindows()), actionCollectionPointer);
65     KStandardAction::redisplay(this, SLOT(refresh()), actionCollectionPointer);
66     fullScreenActionPointer = KStandardAction::fullScreen(this, SLOT(toggleFullScreen()), this, actionCollectionPointer);
67     QAction *backActionPointer = KStandardAction::back(this, SLOT(back()), actionCollectionPointer);
68     QAction *forwardActionPointer = KStandardAction::forward(this, SLOT(forward()), actionCollectionPointer);
69     KStandardAction::home(this, SLOT(home()), actionCollectionPointer);
70     KStandardAction::preferences(this, SLOT(showSettingsDialog()), actionCollectionPointer);
71     KStandardAction::find(this, SLOT(showFindTextActions()), actionCollectionPointer);
72     findNextActionPointer = KStandardAction::findNext(this, SLOT(findNext()), actionCollectionPointer);
73     findPreviousActionPointer = KStandardAction::findPrev(this, SLOT(findPrevious()), actionCollectionPointer);
74
75     // Add the custom actions.
76     QAction *newTabActionPointer = actionCollectionPointer->addAction(QLatin1String("new_tab"));
77     QAction *newWindowActionPointer = actionCollectionPointer->addAction(QLatin1String("new_window"));
78     userAgentPrivacyBrowserActionPointer = actionCollectionPointer->addAction(QLatin1String("user_agent_privacy_browser"));
79     userAgentWebEngineDefaultActionPointer = actionCollectionPointer->addAction(QLatin1String("user_agent_webengine_default"));
80     userAgentFirefoxLinuxActionPointer = actionCollectionPointer->addAction(QLatin1String("user_agent_firefox_linux"));
81     userAgentChromiumLinuxActionPointer = actionCollectionPointer->addAction(QLatin1String("user_agent_chromium_linux"));
82     userAgentFirefoxWindowsActionPointer = actionCollectionPointer->addAction(QLatin1String("user_agent_firefox_windows"));
83     userAgentChromeWindowsActionPointer = actionCollectionPointer->addAction(QLatin1String("user_agent_chrome_windows"));
84     userAgentEdgeWindowsActionPointer = actionCollectionPointer->addAction(QLatin1String("user_agent_edge_windows"));
85     userAgentSafariMacosActionPointer = actionCollectionPointer->addAction(QLatin1String("user_agent_safari_macos"));
86     userAgentCustomActionPointer = actionCollectionPointer->addAction(QLatin1String("user_agent_custom"));
87     zoomFactorActionPointer = actionCollectionPointer->addAction(QLatin1String("zoom_factor"));
88     searchEngineMojeekActionPointer = actionCollectionPointer->addAction(QLatin1String("search_engine_mojeek"));
89     searchEngineMonoclesActionPointer = actionCollectionPointer->addAction(QLatin1String("search_engine_monocles"));
90     searchEngineMetagerActionPointer = actionCollectionPointer->addAction(QLatin1String("search_engine_metager"));
91     searchEngineGoogleActionPointer = actionCollectionPointer->addAction(QLatin1String("search_engine_google"));
92     searchEngineBingActionPointer = actionCollectionPointer->addAction(QLatin1String("search_engine_bing"));
93     searchEngineYahooActionPointer = actionCollectionPointer->addAction(QLatin1String("search_engine_yahoo"));
94     searchEngineCustomActionPointer = actionCollectionPointer->addAction(QLatin1String("search_engine_custom"));
95     QAction *domainSettingsActionPointer = actionCollectionPointer->addAction(QLatin1String("domain_settings"));
96     cookiesActionPointer = actionCollectionPointer->addAction(QLatin1String("cookies"));
97     javaScriptActionPointer = actionCollectionPointer->addAction(QLatin1String("javascript"));
98     localStorageActionPointer = actionCollectionPointer->addAction(QLatin1String("local_storage"));
99     domStorageActionPointer = actionCollectionPointer->addAction(QLatin1String("dom_storage"));
100     findCaseSensitiveActionPointer = actionCollectionPointer->addAction(QLatin1String("find_case_sensitive"));
101     hideFindTextActionPointer = actionCollectionPointer->addAction(QLatin1String("hide_find_actions"));
102
103     // Create the action groups
104     QActionGroup *userAgentActionGroupPointer = new QActionGroup(this);
105     QActionGroup *searchEngineActionGroupPointer = new QActionGroup(this);
106
107     // Add the actions to the groups.
108     userAgentActionGroupPointer->addAction(userAgentPrivacyBrowserActionPointer);
109     userAgentActionGroupPointer->addAction(userAgentWebEngineDefaultActionPointer);
110     userAgentActionGroupPointer->addAction(userAgentFirefoxLinuxActionPointer);
111     userAgentActionGroupPointer->addAction(userAgentChromiumLinuxActionPointer);
112     userAgentActionGroupPointer->addAction(userAgentFirefoxWindowsActionPointer);
113     userAgentActionGroupPointer->addAction(userAgentChromeWindowsActionPointer);
114     userAgentActionGroupPointer->addAction(userAgentEdgeWindowsActionPointer);
115     userAgentActionGroupPointer->addAction(userAgentSafariMacosActionPointer);
116     userAgentActionGroupPointer->addAction(userAgentCustomActionPointer);
117     searchEngineActionGroupPointer->addAction(searchEngineMojeekActionPointer);
118     searchEngineActionGroupPointer->addAction(searchEngineMonoclesActionPointer);
119     searchEngineActionGroupPointer->addAction(searchEngineMetagerActionPointer);
120     searchEngineActionGroupPointer->addAction(searchEngineGoogleActionPointer);
121     searchEngineActionGroupPointer->addAction(searchEngineBingActionPointer);
122     searchEngineActionGroupPointer->addAction(searchEngineYahooActionPointer);
123     searchEngineActionGroupPointer->addAction(searchEngineCustomActionPointer);
124
125     // Set some actions to be checkable.
126     javaScriptActionPointer->setCheckable(true);
127     localStorageActionPointer->setCheckable(true);
128     domStorageActionPointer->setCheckable(true);
129     findCaseSensitiveActionPointer->setCheckable(true);
130     userAgentPrivacyBrowserActionPointer->setCheckable(true);
131     userAgentWebEngineDefaultActionPointer->setCheckable(true);
132     userAgentFirefoxLinuxActionPointer->setCheckable(true);
133     userAgentChromiumLinuxActionPointer->setCheckable(true);
134     userAgentFirefoxWindowsActionPointer->setCheckable(true);
135     userAgentChromeWindowsActionPointer->setCheckable(true);
136     userAgentEdgeWindowsActionPointer->setCheckable(true);
137     userAgentSafariMacosActionPointer->setCheckable(true);
138     userAgentCustomActionPointer->setCheckable(true);
139     searchEngineMojeekActionPointer->setCheckable(true);
140     searchEngineMonoclesActionPointer->setCheckable(true);
141     searchEngineMetagerActionPointer->setCheckable(true);
142     searchEngineGoogleActionPointer->setCheckable(true);
143     searchEngineBingActionPointer->setCheckable(true);
144     searchEngineYahooActionPointer->setCheckable(true);
145     searchEngineCustomActionPointer->setCheckable(true);
146
147     // Instantiate the user agent helper.
148     UserAgentHelper *userAgentHelperPointer = new UserAgentHelper();
149
150     // Set the action text.
151     newTabActionPointer->setText(i18nc("New tab action", "New Tab"));
152     newWindowActionPointer->setText(i18nc("New window action", "New Window"));
153     userAgentPrivacyBrowserActionPointer->setText(userAgentHelperPointer->PRIVACY_BROWSER_TRANSLATED);
154     userAgentWebEngineDefaultActionPointer->setText(userAgentHelperPointer->WEB_ENGINE_DEFAULT_TRANSLATED);
155     userAgentFirefoxLinuxActionPointer->setText(userAgentHelperPointer->FIREFOX_LINUX_TRANSLATED);
156     userAgentChromiumLinuxActionPointer->setText(userAgentHelperPointer->CHROMIUM_LINUX_TRANSLATED);
157     userAgentFirefoxWindowsActionPointer->setText(userAgentHelperPointer->FIREFOX_WINDOWS_TRANSLATED);
158     userAgentChromeWindowsActionPointer->setText(userAgentHelperPointer->CHROME_WINDOWS_TRANSLATED);
159     userAgentEdgeWindowsActionPointer->setText(userAgentHelperPointer->EDGE_WINDOWS_TRANSLATED);
160     userAgentSafariMacosActionPointer->setText(userAgentHelperPointer->SAFARI_MACOS_TRANSLATED);
161     searchEngineMojeekActionPointer->setText(i18nc("Search engine", "Mojeek"));
162     searchEngineMonoclesActionPointer->setText(i18nc("Search engine", "Monocles"));
163     searchEngineMetagerActionPointer->setText(i18nc("Search engine", "MetaGer"));
164     searchEngineGoogleActionPointer->setText(i18nc("Search engine", "Google"));
165     searchEngineBingActionPointer->setText(i18nc("Search engine", "Bing"));
166     searchEngineYahooActionPointer->setText(i18nc("Search engine", "Yahoo"));
167     domainSettingsActionPointer->setText(i18nc("Domain Settings action", "Domain Settings"));
168     cookiesActionPointer->setText(i18nc("The Cookies action, which also displays the number of cookies", "Cookies - %1", 0));
169     javaScriptActionPointer->setText(i18nc("JavaScript action", "JavaScript"));
170     localStorageActionPointer->setText(i18nc("The Local Storage action", "Local Storage"));
171     domStorageActionPointer->setText(i18nc("DOM Storage action", "DOM Storage"));
172     findCaseSensitiveActionPointer->setText(i18nc("Find Case Sensitive action", "Find Case Sensitive"));
173     hideFindTextActionPointer->setText(i18nc("Hide Find Text action", "Hide Find Text"));
174
175     // Set the action icons.  Gnome doesn't contain some of the icons that KDE has.
176     // The toolbar icons don't pick up unless the size is explicit, probably because the toolbar ends up being an intermediate size.
177     newTabActionPointer->setIcon(QIcon::fromTheme(QLatin1String("tab-new")));
178     newWindowActionPointer->setIcon(QIcon::fromTheme(QLatin1String("window-new")));
179     userAgentPrivacyBrowserActionPointer->setIcon(QIcon(":/icons/privacy-mode.svg"));
180     userAgentWebEngineDefaultActionPointer->setIcon(QIcon::fromTheme(QLatin1String("qtlogo"), QIcon::fromTheme(QLatin1String("user-group-properties"),
181                                                                                                                QIcon::fromTheme(QLatin1String("contact-new")))));
182     userAgentFirefoxLinuxActionPointer->setIcon(QIcon::fromTheme(QLatin1String("firefox-esr"), QIcon::fromTheme(QLatin1String("user-group-properties"),
183                                                                                                                 QIcon::fromTheme(QLatin1String("contact-new")))));
184     userAgentChromiumLinuxActionPointer->setIcon(QIcon::fromTheme(QLatin1String("chromium"), QIcon::fromTheme(QLatin1String("user-group-properties"),
185                                                                                                               QIcon::fromTheme(QLatin1String("contact-new")))));
186     userAgentFirefoxWindowsActionPointer->setIcon(QIcon::fromTheme(QLatin1String("firefox-esr"), QIcon::fromTheme(QLatin1String("user-group-properties"),
187                                                                                                                   QIcon::fromTheme(QLatin1String("contact-new")))));
188     userAgentChromeWindowsActionPointer->setIcon(QIcon::fromTheme(QLatin1String("chromium"), QIcon::fromTheme(QLatin1String("user-group-properties"),
189                                                                                                               QIcon::fromTheme(QLatin1String("contact-new")))));
190     userAgentEdgeWindowsActionPointer->setIcon(QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new"))));
191     userAgentSafariMacosActionPointer->setIcon(QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new"))));
192     userAgentCustomActionPointer->setIcon(QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new"))));
193     searchEngineMojeekActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
194     searchEngineMonoclesActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
195     searchEngineMetagerActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
196     searchEngineGoogleActionPointer->setIcon(QIcon::fromTheme(QLatin1String("im-google"), QIcon::fromTheme(QLatin1String("edit-find"))));
197     searchEngineBingActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
198     searchEngineYahooActionPointer->setIcon(QIcon::fromTheme(QLatin1String("im-yahoo"), QIcon::fromTheme(QLatin1String("edit-find"))));
199     searchEngineCustomActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
200     zoomFactorActionPointer->setIcon(QIcon::fromTheme(QLatin1String("zoom-fit-best")));
201     domainSettingsActionPointer->setIcon(QIcon::fromTheme(QLatin1String("settings-configure"), QIcon::fromTheme(QLatin1String("preferences-desktop"))));
202     cookiesActionPointer->setIcon(QIcon::fromTheme(QLatin1String("preferences-web-browser-cookies"), QIcon::fromTheme(QLatin1String("appointment-new"))));
203     domStorageActionPointer->setIcon(QIcon::fromTheme(QLatin1String("code-class"), QIcon(QLatin1String("/usr/share/icons/gnome/32x32/actions/gtk-unindent-ltr.png"))));
204     findCaseSensitiveActionPointer->setIcon(QIcon::fromTheme(QLatin1String("format-text-lowercase"), QIcon::fromTheme(QLatin1String("/usr/share/icons/gnome/32x32/apps/fonts.png"))));
205     hideFindTextActionPointer->setIcon(QIcon::fromTheme(QLatin1String("window-close-symbolic")));
206
207     // Create the key sequences.
208     QKeySequence ctrlTKeySequence = QKeySequence(i18nc("The open new tab key sequence.", "Ctrl+T"));
209     QKeySequence ctrlNKeySequence = QKeySequence(i18nc("The open new window key sequence.", "Ctrl+N"));
210     QKeySequence ctrlShiftPKeySequence = QKeySequence(i18nc("The print preview key sequence.", "Ctrl+Shift+P"));
211     QKeySequence ctrlAltPKeySequence = QKeySequence(i18nc("The Privacy Browser user agent key sequence.", "Ctrl+Alt+P"));
212     QKeySequence ctrlAltWKeySequence = QKeySequence(i18nc("The WebEngine Default user agent key sequence.", "Ctrl+Alt+W"));
213     QKeySequence ctrlAltFKeySequence = QKeySequence(i18nc("The Firefox on Linux user agent key sequence.", "Ctrl+Alt+F"));
214     QKeySequence ctrlAltCKeySequence = QKeySequence(i18nc("The Chromium on Linux user agent key sequence.", "Ctrl+Alt+C"));
215     QKeySequence ctrlAltShiftFKeySequence = QKeySequence(i18nc("The Firefox on Windows user agent key sequence.", "Ctrl+Alt+Shift+F"));
216     QKeySequence ctrlAltShiftCKeySequence = QKeySequence(i18nc("The Chrome on Windows user agent key sequence.", "Ctrl+Alt+Shift+C"));
217     QKeySequence ctrlAltEKeySequence = QKeySequence(i18nc("The Edge on Windows user agent key sequence.", "Ctrl+Alt+E"));
218     QKeySequence ctrlAltSKeySequence = QKeySequence(i18nc("The Safari on macOS user agent key sequence.", "Ctrl+Alt+S"));
219     QKeySequence altShiftCKeySequence = QKeySequence(i18nc("The custom user agent key sequence.", "Alt+Shift+C"));
220     QKeySequence ctrlAltZKeySequence = QKeySequence(i18nc("The zoom factor key sequence.", "Ctrl+Alt+Z"));
221     QKeySequence ctrlShiftMKeySequence = QKeySequence(i18nc("The Mojeek search engine key sequence.", "Ctrl+Shift+M"));
222     QKeySequence ctrlShiftOKeySequence = QKeySequence(i18nc("The Monocles search engine key sequence.", "Ctrl+Shift+O"));
223     QKeySequence ctrlShiftEKeySequence = QKeySequence(i18nc("The MetaGer search engine key sequence.", "Ctrl+Shift+E"));
224     QKeySequence ctrlShiftGKeySequence = QKeySequence(i18nc("The Google search engine key sequence.", "Ctrl+Shift+G"));
225     QKeySequence ctrlShiftBKeySequence = QKeySequence(i18nc("The Bing search engine key sequence.", "Ctrl+Shift+B"));
226     QKeySequence ctrlShiftYKeySequence = QKeySequence(i18nc("The Yahoo search engine key sequence.", "Ctrl+Shift+Y"));
227     QKeySequence ctrlShiftCKeySequence = QKeySequence(i18nc("The custom search engine key sequence.", "Ctrl+Shift+C"));
228     QKeySequence ctrlDKeySequence = QKeySequence(i18nc("The domain settings key sequence.", "Ctrl+D"));
229     QKeySequence ctrlSemicolonKeySequence = QKeySequence(i18nc("The cookies dialog key sequence.", "Ctrl+;"));
230
231     // Set the action key sequences.
232     actionCollectionPointer->setDefaultShortcut(newTabActionPointer, ctrlTKeySequence);
233     actionCollectionPointer->setDefaultShortcut(newWindowActionPointer, ctrlNKeySequence);
234     actionCollectionPointer->setDefaultShortcut(printPreviewActionPointer, ctrlShiftPKeySequence);
235     actionCollectionPointer->setDefaultShortcut(userAgentPrivacyBrowserActionPointer, ctrlAltPKeySequence);
236     actionCollectionPointer->setDefaultShortcut(userAgentWebEngineDefaultActionPointer, ctrlAltWKeySequence);
237     actionCollectionPointer->setDefaultShortcut(userAgentFirefoxLinuxActionPointer, ctrlAltFKeySequence);
238     actionCollectionPointer->setDefaultShortcut(userAgentChromiumLinuxActionPointer, ctrlAltCKeySequence);
239     actionCollectionPointer->setDefaultShortcut(userAgentFirefoxWindowsActionPointer, ctrlAltShiftFKeySequence);
240     actionCollectionPointer->setDefaultShortcut(userAgentChromeWindowsActionPointer, ctrlAltShiftCKeySequence);
241     actionCollectionPointer->setDefaultShortcut(userAgentEdgeWindowsActionPointer, ctrlAltEKeySequence);
242     actionCollectionPointer->setDefaultShortcut(userAgentSafariMacosActionPointer, ctrlAltSKeySequence);
243     actionCollectionPointer->setDefaultShortcut(userAgentCustomActionPointer, altShiftCKeySequence);
244     actionCollectionPointer->setDefaultShortcut(zoomFactorActionPointer, ctrlAltZKeySequence);
245     actionCollectionPointer->setDefaultShortcut(searchEngineMojeekActionPointer, ctrlShiftMKeySequence);
246     actionCollectionPointer->setDefaultShortcut(searchEngineMonoclesActionPointer, ctrlShiftOKeySequence);
247     actionCollectionPointer->setDefaultShortcut(searchEngineMetagerActionPointer, ctrlShiftEKeySequence);
248     actionCollectionPointer->setDefaultShortcut(searchEngineGoogleActionPointer, ctrlShiftGKeySequence);
249     actionCollectionPointer->setDefaultShortcut(searchEngineBingActionPointer, ctrlShiftBKeySequence);
250     actionCollectionPointer->setDefaultShortcut(searchEngineYahooActionPointer, ctrlShiftYKeySequence);
251     actionCollectionPointer->setDefaultShortcut(searchEngineCustomActionPointer, ctrlShiftCKeySequence);
252     actionCollectionPointer->setDefaultShortcut(domainSettingsActionPointer, ctrlDKeySequence);
253     actionCollectionPointer->setDefaultShortcut(cookiesActionPointer, ctrlSemicolonKeySequence);
254
255     // Execute the actions.
256     connect(newTabActionPointer, SIGNAL(triggered()), tabWidgetPointer, SLOT(addTab()));
257     connect(newWindowActionPointer, SIGNAL(triggered()), this, SLOT(newWindow()));
258     connect(zoomFactorActionPointer, SIGNAL(triggered()), this, SLOT(getZoomFactorFromUser()));
259     connect(cookiesActionPointer, SIGNAL(triggered()), this, SLOT(showCookiesDialog()));
260     connect(domainSettingsActionPointer, SIGNAL(triggered()), this, SLOT(showDomainSettingsDialog()));
261
262     // Update the on-the-fly menus.
263     connect(tabWidgetPointer, SIGNAL(updateUserAgentActions(QString, bool)), this, SLOT(updateUserAgentActions(QString, bool)));
264     connect(tabWidgetPointer, SIGNAL(updateZoomFactorAction(double)), this, SLOT(updateZoomFactorAction(double)));
265     connect(tabWidgetPointer, SIGNAL(updateSearchEngineActions(QString, bool)), this, SLOT(updateSearchEngineActions(QString, bool)));
266
267     // Apply the on-the-fly settings when selected.
268     connect(userAgentActionGroupPointer, SIGNAL(triggered(QAction*)), tabWidgetPointer, SLOT(applyOnTheFlyUserAgent(QAction*)));
269     connect(searchEngineActionGroupPointer, SIGNAL(triggered(QAction*)), tabWidgetPointer, SLOT(applyOnTheFlySearchEngine(QAction*)));
270
271     // Process cookie changes.
272     connect(tabWidgetPointer, SIGNAL(updateCookiesAction(int)), this, SLOT(updateCookiesAction(int)));
273
274     // Connect the URL toolbar actions.
275     connect(javaScriptActionPointer, SIGNAL(triggered()), this, SLOT(toggleJavaScript()));
276     connect(localStorageActionPointer, SIGNAL(triggered()), this, SLOT(toggleLocalStorage()));
277     connect(domStorageActionPointer, SIGNAL(triggered()), this, SLOT(toggleDomStorage()));
278
279     // Update the URL toolbar actions.
280     connect(tabWidgetPointer, SIGNAL(updateBackAction(bool)), backActionPointer, SLOT(setEnabled(bool)));
281     connect(tabWidgetPointer, SIGNAL(updateForwardAction(bool)), forwardActionPointer, SLOT(setEnabled(bool)));
282     connect(tabWidgetPointer, SIGNAL(updateJavaScriptAction(bool)), this, SLOT(updateJavaScriptAction(bool)));
283     connect(tabWidgetPointer, SIGNAL(updateLocalStorageAction(bool)), this, SLOT(updateLocalStorageAction(bool)));
284     connect(tabWidgetPointer, SIGNAL(updateDomStorageAction(bool)), this, SLOT(updateDomStorageAction(bool)));
285
286     // Connect the find text actions.
287     connect(findCaseSensitiveActionPointer, SIGNAL(triggered()), this, SLOT(toggleFindCaseSensitive()));
288     connect(hideFindTextActionPointer, SIGNAL(triggered()), this, SLOT(hideFindTextActions()));
289
290     // Setup the GUI based on the browserwindowui.rc file.
291     setupGUI(StandardWindowOption::Default, ("browserwindowui.rc"));
292
293     // Get lists of the actions' associated widgets.
294     QList<QWidget*> userAgentAssociatedWidgetsPointerList = userAgentPrivacyBrowserActionPointer->associatedWidgets();
295     QList<QWidget*> searchEngineAssociatedWidgetsPointerList = searchEngineMojeekActionPointer->associatedWidgets();
296
297     // Get the menu widget pointers.  It is the second entry, after the main window.
298     QWidget *userAgentMenuWidgetPointer = userAgentAssociatedWidgetsPointerList[1];
299     QWidget *searchEngineMenuWidgetPointer = searchEngineAssociatedWidgetsPointerList[1];
300
301     // Get the menu pointers.
302     QMenu *userAgentMenuPointer = qobject_cast<QMenu*>(userAgentMenuWidgetPointer);
303     QMenu *searchEngineMenuPointer = qobject_cast<QMenu*>(searchEngineMenuWidgetPointer);
304
305     // Get the menu actions.
306     userAgentMenuActionPointer = userAgentMenuPointer->menuAction();
307     searchEngineMenuActionPointer = searchEngineMenuPointer->menuAction();
308
309     // Get handles for the toolbars.
310     navigationToolBarPointer = toolBar(QLatin1String("navigation_toolbar"));
311     urlToolBarPointer = toolBar(QLatin1String("url_toolbar"));
312
313     // Create the line edits.
314     urlLineEditPointer = new KLineEdit();
315     findTextLineEditPointer = new KLineEdit();
316
317     // Get the line edit size policies.
318     QSizePolicy urlLineEditSizePolicy = urlLineEditPointer->sizePolicy();
319     QSizePolicy findTextLineEditSizePolicy = findTextLineEditPointer->sizePolicy();
320
321     // Set the URL line edit horizontal stretch to be five times the find text line edit stretch.
322     urlLineEditSizePolicy.setHorizontalStretch(5);
323     findTextLineEditSizePolicy.setHorizontalStretch(1);
324
325     // Set the policies.
326     urlLineEditPointer->setSizePolicy(urlLineEditSizePolicy);
327     findTextLineEditPointer->setSizePolicy(findTextLineEditSizePolicy);
328
329     // Set the widths.
330     urlLineEditPointer->setMinimumWidth(350);
331     findTextLineEditPointer->setMinimumWidth(200);
332     findTextLineEditPointer->setMaximumWidth(350);
333
334     // Set the place holder text.
335     urlLineEditPointer->setPlaceholderText(i18nc("The URL line edit placeholder text", "URL or Search Terms"));
336     findTextLineEditPointer->setPlaceholderText(i18nc("The find line edit placeholder text", "Find Text"));
337
338     // Show the clear button on the find line edit.
339     findTextLineEditPointer->setClearButtonEnabled(true);
340
341     // Add an edit or add domain settings action to the URL line edit.
342     QAction *addOrEditDomainSettingsActionPointer = urlLineEditPointer->addAction(QIcon::fromTheme("settings-configure"), QLineEdit::TrailingPosition);
343
344     // Add or edit the current domain settings.
345     connect(addOrEditDomainSettingsActionPointer, SIGNAL(triggered()), this, SLOT(addOrEditDomainSettings()));
346
347     // Create a find text label pointer.
348     findTextLabelPointer = new QLabel();
349
350     // Set the default label text.
351     findTextLabelPointer->setText(QLatin1String("  ") + i18nc("Default find results.", "0/0") + QLatin1String("  "));
352
353     // Insert the widgets into the toolbars.
354     urlToolBarPointer->insertWidget(javaScriptActionPointer, urlLineEditPointer);
355     findTextLineEditActionPointer = urlToolBarPointer->insertWidget(findNextActionPointer, findTextLineEditPointer);
356     findTextLabelActionPointer = urlToolBarPointer->insertWidget(findNextActionPointer, findTextLabelPointer);
357
358     // Initially hide the find text actions.
359     hideFindTextActions();
360
361     // Load a new URL from the URL line edit.
362     connect(urlLineEditPointer, SIGNAL(returnKeyPressed(const QString)), this, SLOT(loadUrlFromLineEdit(const QString)));
363
364     // Find text as it is typed.
365     connect(findTextLineEditPointer, SIGNAL(textEdited(const QString &)), tabWidgetPointer, SLOT(findText(const QString &)));
366
367     // Find next if the enter key is pressed.
368     connect(findTextLineEditPointer, SIGNAL(returnKeyPressed(const QString &)), tabWidgetPointer, SLOT(findText(const QString &)));
369
370     // Update find text when switching tabs.
371     connect(tabWidgetPointer, SIGNAL(updateFindText(const QString &, const bool)), this, SLOT(updateFindText(const QString &, const bool)));
372
373     // Update the find text results.
374     connect(tabWidgetPointer, SIGNAL(updateFindTextResults(const QWebEngineFindTextResult &)), this, SLOT(updateFindTextResults(const QWebEngineFindTextResult &)));
375
376     // Update the URL line edit on page loads.
377     connect(tabWidgetPointer, SIGNAL(updateUrlLineEdit(QUrl)), this, SLOT(updateUrlLineEdit(QUrl)));
378
379     // Update the window title.
380     connect(tabWidgetPointer, SIGNAL(updateWindowTitle(const QString)), this, SLOT(updateWindowTitle(const QString)));
381
382     // Get a handle for the status bar.
383     QStatusBar *statusBarPointer = statusBar();
384
385     // Create a progress bar.
386     progressBarPointer = new QProgressBar();
387
388     // Add the progress bar to to the status bar.
389     statusBarPointer->addPermanentWidget(progressBarPointer);
390
391     // Update the status bar with the URL when a link is hovered.
392     connect(tabWidgetPointer, SIGNAL(linkHovered(QString)), statusBarPointer, SLOT(showMessage(QString)));
393
394     // Update the progress bar.
395     connect(tabWidgetPointer, SIGNAL(showProgressBar(const int)), this, SLOT(showProgressBar(const int)));
396     connect(tabWidgetPointer, SIGNAL(hideProgressBar()), progressBarPointer, SLOT(hide()));
397
398     // Update the URL line edit focus.
399     connect(tabWidgetPointer, SIGNAL(clearUrlLineEditFocus()), this, SLOT(clearUrlLineEditFocus()));
400
401     // Get the URL line edit palettes.
402     normalBackgroundPalette = urlLineEditPointer->palette();
403     negativeBackgroundPalette = normalBackgroundPalette;
404     positiveBackgroundPalette = normalBackgroundPalette;
405
406     // Modify the palettes.
407     KColorScheme::adjustBackground(negativeBackgroundPalette, KColorScheme::NegativeBackground);
408     KColorScheme::adjustBackground(positiveBackgroundPalette, KColorScheme::PositiveBackground);
409
410     // Update the applied palette.
411     connect(tabWidgetPointer, SIGNAL(updateDomainSettingsIndicator(const bool)), this, SLOT(updateDomainSettingsIndicator(const bool)));
412
413     // Process full screen requests.
414     connect(tabWidgetPointer, SIGNAL(fullScreenRequested(bool)), this, SLOT(fullScreenRequested(bool)));
415
416     // Create keyboard shortcuts.
417     QShortcut *f11ShortcutPointer = new QShortcut(QKeySequence(i18nc("The toggle full screen shortcut.", "F11")), this);
418     QShortcut *escapeShortcutPointer = new QShortcut(QKeySequence::Cancel, this);
419
420     // Connect the keyboard shortcuts.
421     connect(f11ShortcutPointer, SIGNAL(activated()), fullScreenActionPointer, SLOT(trigger()));
422     connect(escapeShortcutPointer, SIGNAL(activated()), this, SLOT(escape()));
423
424     // Populate the UI.
425     // This must be done here, because otherwise, if a URL is loaded, like a local file, that does not trigger a call to TabWidget::applyDomainSettings, the UI will not be fully populated.
426     updateJavaScriptAction(Settings::javaScriptEnabled());
427     updateLocalStorageAction(Settings::localStorageEnabled());
428     updateDomStorageAction(Settings::domStorageEnabled());
429     updateUserAgentActions(UserAgentHelper::getUserAgentFromDatabaseName(Settings::userAgent()), true);
430     updateZoomFactorAction(Settings::zoomFactor());
431
432     // Load the initial website if this is the first window.
433     if (firstWindow)
434         tabWidgetPointer->loadInitialWebsite();
435 }
436
437 void BrowserWindow::addOrEditDomainSettings() const
438 {
439     // Remove the focus from the URL line edit.
440     urlLineEditPointer->clearFocus();
441
442     // Create the domain settings dialog pointer.
443     DomainSettingsDialog *domainSettingsDialogPointer;
444
445     // Get the current domain settings name.
446     QString &currentDomainSettingsName = tabWidgetPointer->getDomainSettingsName();
447
448     // Run the commands according to the current domain settings status.
449     if (currentDomainSettingsName == QStringLiteral(""))  // Domain settings are not currently applied.
450     {
451         // Instruct the domain settings dialog to add a new domain.
452         domainSettingsDialogPointer = new DomainSettingsDialog(DomainSettingsDialog::ADD_DOMAIN, currentUrl.host());
453     }
454     else  // Domain settings are currently applied.
455     {
456         // Instruct the domain settings dialog to edit the current domain.
457         domainSettingsDialogPointer = new DomainSettingsDialog(DomainSettingsDialog::EDIT_DOMAIN, currentDomainSettingsName);
458     }
459
460     // Set the dialog window title.
461     domainSettingsDialogPointer->setWindowTitle(i18nc("The domain settings dialog title", "Domain Settings"));
462
463     // Set the modality.
464     domainSettingsDialogPointer->setWindowModality(Qt::WindowModality::WindowModal);;
465
466     // Show the dialog.
467     domainSettingsDialogPointer->show();
468
469     // Reload the tabs when domain settings are updated.
470     connect(domainSettingsDialogPointer, SIGNAL(domainSettingsUpdated()), tabWidgetPointer, SLOT(applyDomainSettingsAndReload()));
471 }
472
473 void BrowserWindow::back() const
474 {
475     // Remove the focus from the URL line edit.
476     urlLineEditPointer->clearFocus();
477
478     // Go back.
479     tabWidgetPointer->back();
480 }
481
482 void BrowserWindow::clearUrlLineEditFocus() const
483 {
484     // Remove the focus from the URL line edit.
485     urlLineEditPointer->clearFocus();
486 }
487
488 void BrowserWindow::escape() const
489 {
490     // Process the escape according to the status of the browser.
491     if (fullScreenActionPointer->isChecked())  // Full screen browsing is enabled.
492     {
493         // Exit full screen browsing.
494         fullScreenActionPointer->trigger();
495     }
496     else if (!findTextLineEditPointer->text().isEmpty())  // Find text is populated.
497     {
498         // Clear the find text line edit.
499         findTextLineEditPointer->clear();
500
501         // Clear the search in the WebEngine.
502         tabWidgetPointer->findText(QStringLiteral(""));
503     }
504     else if (findTextLineEditActionPointer->isVisible())  // Find text actions are visible.
505     {
506         // Hide the find text actions.
507         hideFindTextActions();
508     }
509 }
510
511 void BrowserWindow::findNext() const
512 {
513     // Get the find string.
514     const QString findString = findTextLineEditPointer->text();
515
516     // Search for the text if it is not empty.
517     if (!findString.isEmpty())
518         tabWidgetPointer->findText(findString);
519 }
520
521 void BrowserWindow::findPrevious() const
522 {
523     // Get the find string.
524     const QString findString = findTextLineEditPointer->text();
525
526     // Search for the text if it is not empty.
527     if (!findString.isEmpty())
528         tabWidgetPointer->findPrevious(findString);
529 }
530
531 void BrowserWindow::forward() const
532 {
533     // Remove the focus from the URL line edit.
534     urlLineEditPointer->clearFocus();
535
536     // Go forward.
537     tabWidgetPointer->forward();
538 }
539
540 void BrowserWindow::fullScreenRequested(const bool toggleOn)
541 {
542     // Toggle full screen mode.
543     if (toggleOn)  // Turn full screen mode on.
544     {
545         // Set the window to be full screen.
546         fullScreenActionPointer->setFullScreen(window(), true);
547
548         // Hide all the bars.
549         menuBar()->setVisible(false);
550         navigationToolBarPointer->setVisible(false);
551         urlToolBarPointer->setVisible(false);
552         tabWidgetPointer->setTabBarVisible(false);
553         statusBar()->setVisible(false);
554     }
555     else  // Turn full screen mode off.
556     {
557         // Set the window to not be full screen.
558         fullScreenActionPointer->setFullScreen(window(), false);
559
560         // Show all the bars.
561         menuBar()->setVisible(true);
562         navigationToolBarPointer->setVisible(true);
563         urlToolBarPointer->setVisible(true);
564         tabWidgetPointer->setTabBarVisible(true);
565         statusBar()->setVisible(true);
566     }
567 }
568
569 void BrowserWindow::getZoomFactorFromUser()
570 {
571     // Create an OK flag.
572     bool okClicked;
573
574     // 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.
575     double newZoomFactor = QInputDialog::getDouble(this, i18nc("The on-the-fly zoom factor dialog title", "On-The-Fly Zoom Factor"),
576                                                    i18nc("The instruction text of the on-the-fly zoom factor dialog", "Enter a zoom factor between 0.25 and 5.00"),
577                                                    currentZoomFactor, .025, 5.00, 2, &okClicked, Qt::WindowFlags(), 0.25);
578
579     // Update the zoom factor if the user clicked OK.
580     if (okClicked)
581     {
582         // Update the current zoom factor.
583         currentZoomFactor = newZoomFactor;
584
585         // Set the new zoom factor.
586         tabWidgetPointer->applyOnTheFlyZoomFactor(newZoomFactor);
587
588         // Update the on-the-fly action text.
589         updateZoomFactorAction(newZoomFactor);
590     }
591 }
592
593 void BrowserWindow::hideFindTextActions() const
594 {
595     // Hide the find text actions.
596     findTextLineEditActionPointer->setVisible(false);
597     findTextLabelActionPointer->setVisible(false);
598     findNextActionPointer->setVisible(false);
599     findPreviousActionPointer->setVisible(false);
600     findCaseSensitiveActionPointer->setVisible(false);
601     hideFindTextActionPointer->setVisible(false);
602 }
603
604 void BrowserWindow::home() const
605 {
606     // Remove the focus from the URL line edit.
607     urlLineEditPointer->clearFocus();
608
609     // Go home.
610     tabWidgetPointer->home();
611 }
612
613 void BrowserWindow::loadUrlFromLineEdit(const QString &url) const
614 {
615     // Remove the focus from the URL line edit.
616     urlLineEditPointer->clearFocus();
617
618     // Load the URL.
619     tabWidgetPointer->loadUrlFromLineEdit(url);
620 }
621
622 void BrowserWindow::newWindow() const
623 {
624     // Display a new instance of Privacy Browser.
625     (new BrowserWindow)->show();
626 }
627
628 void BrowserWindow::refresh() const
629 {
630     // Remove the focus from the URL line edit.
631     urlLineEditPointer->clearFocus();
632
633     // Refresh the web page.
634     tabWidgetPointer->refresh();
635 }
636
637 void BrowserWindow::showCookiesDialog()
638 {
639     // Remove the focus from the URL line edit.
640     urlLineEditPointer->clearFocus();
641
642     // Instantiate the cookie settings dialog.
643     CookiesDialog *cookiesDialogPointer = new CookiesDialog(tabWidgetPointer->getCookieList());
644
645     // Show the dialog.
646     cookiesDialogPointer->show();
647
648     // Connect the dialog signals.
649     connect(cookiesDialogPointer, SIGNAL(addCookie(QNetworkCookie)), tabWidgetPointer, SLOT(addCookieToStore(QNetworkCookie)));
650     connect(cookiesDialogPointer, SIGNAL(deleteAllCookies()), tabWidgetPointer, SLOT(deleteAllCookies()));
651     connect(cookiesDialogPointer, SIGNAL(deleteCookie(QNetworkCookie)), tabWidgetPointer, SLOT(deleteCookieFromStore(QNetworkCookie)));
652 }
653
654 void BrowserWindow::showDownloadLocationBrowseDialog() const
655 {
656     // Get the current download location.
657     QString currentDownloadLocation = downloadLocationComboBoxPointer->currentText();
658
659     // Resolve the system download directory if specified.
660     if (currentDownloadLocation == QStringLiteral("System Download Directory"))
661         currentDownloadLocation = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
662
663     // Get the new download location.
664     QString newDownloadLocation = QFileDialog::getExistingDirectory(configDialogPointer, i18nc("Select download location dialog caption", "Select Download Location"), currentDownloadLocation);
665
666     // Populate the download location combo box according to the new download location.
667     if (newDownloadLocation == QStandardPaths::writableLocation(QStandardPaths::DownloadLocation))  // The default download location was selected.
668     {
669         // Populate the download location with the default text.
670         downloadLocationComboBoxPointer->setCurrentText("System Download Directory");
671     }
672     else if (newDownloadLocation != QStringLiteral(""))  // A different directory was selected.
673     {
674         // Populate the download location.
675         downloadLocationComboBoxPointer->setCurrentText(newDownloadLocation);
676     }
677 }
678
679 void BrowserWindow::showDomainSettingsDialog() const
680 {
681     // Remove the focus from the URL line edit.
682     urlLineEditPointer->clearFocus();
683
684     // Instantiate the domain settings dialog.
685     DomainSettingsDialog *domainSettingsDialogPointer = new DomainSettingsDialog();
686
687     // Show the dialog.
688     domainSettingsDialogPointer->show();
689
690     // Reload the tabs when domain settings are updated.
691     connect(domainSettingsDialogPointer, SIGNAL(domainSettingsUpdated()), tabWidgetPointer, SLOT(applyDomainSettingsAndReload()));
692 }
693
694 void BrowserWindow::showFindTextActions() const
695 {
696     // Show the find text actions.
697     findTextLineEditActionPointer->setVisible(true);
698     findTextLabelActionPointer->setVisible(true);
699     findNextActionPointer->setVisible(true);
700     findPreviousActionPointer->setVisible(true);
701     findCaseSensitiveActionPointer->setVisible(true);
702     hideFindTextActionPointer->setVisible(true);
703
704     // Set the focus on the find line edit.
705     findTextLineEditPointer->setFocus();
706
707     // Select all the text in the find line edit.
708     findTextLineEditPointer->selectAll();
709 }
710
711 void BrowserWindow::showProgressBar(const int &progress) const
712 {
713     // Set the progress bar value.
714     progressBarPointer->setValue(progress);
715
716     // Show the progress bar.
717     progressBarPointer->show();
718 }
719
720 void BrowserWindow::showSettingsDialog()
721 {
722     // Create the settings widgets.
723     QWidget *privacySettingsWidgetPointer = new QWidget;
724     QWidget *generalSettingsWidgetPointer = new QWidget;
725     QWidget *spellCheckSettingsWidgetPointer = new QWidget;
726
727     // Instantiate the settings UI.
728     Ui::PrivacySettings privacySettingsUi;
729     Ui::GeneralSettings generalSettingsUi;
730     Ui::SpellCheckSettings spellCheckSettingsUi;
731
732     // Setup the UI to display the settings widgets.
733     privacySettingsUi.setupUi(privacySettingsWidgetPointer);
734     generalSettingsUi.setupUi(generalSettingsWidgetPointer);
735     spellCheckSettingsUi.setupUi(spellCheckSettingsWidgetPointer);
736
737     // Get handles for the widgets.
738     QComboBox *userAgentComboBoxPointer = privacySettingsUi.kcfg_userAgent;
739     userAgentLabelPointer = privacySettingsUi.userAgentLabel;
740     QComboBox *searchEngineComboBoxPointer = generalSettingsUi.kcfg_searchEngine;
741     searchEngineLabelPointer = generalSettingsUi.searchEngineLabel;
742     downloadLocationComboBoxPointer = generalSettingsUi.kcfg_downloadLocation;
743     QPushButton *browseButtonPointer = generalSettingsUi.browseButton;
744     QListWidget *spellCheckListWidgetPointer = spellCheckSettingsUi.spellCheckListWidget;
745
746     // Populate the combo box labels.
747     updateUserAgentLabel(userAgentComboBoxPointer->currentText());
748     updateSearchEngineLabel(searchEngineComboBoxPointer->currentText());
749
750     // Update the labels when the combo boxes change.
751     connect(userAgentComboBoxPointer, SIGNAL(currentTextChanged(const QString)), this, SLOT(updateUserAgentLabel(const QString)));
752     connect(searchEngineComboBoxPointer, SIGNAL(currentTextChanged(const QString)), this, SLOT(updateSearchEngineLabel(const QString)));
753
754     // Connect the download location directory browse button.
755     connect(browseButtonPointer, SIGNAL(clicked()), this, SLOT(showDownloadLocationBrowseDialog()));
756
757     // Create a dictionaries QDir from the `QTWEBENGINE_DICTIONARIES_PATH` environment variable.
758     QDir dictionariesDir = QDir(qEnvironmentVariable("QTWEBENGINE_DICTIONARIES_PATH"));
759
760     // Get a dictionaries string list.
761     QStringList dictionariesStringList = dictionariesDir.entryList(QStringList(QLatin1String("*.bdic")), QDir::Files | QDir::NoSymLinks);
762
763     // Remove the `.bdic` file extensions from the dictionaries list.
764     dictionariesStringList.replaceInStrings(QLatin1String(".bdic"), QLatin1String(""));
765
766     // Get a list of the enabled spell check languages.
767     QStringList enabledSpellCheckLanguagesList = Settings::spellCheckLanguages();
768
769     // Add each dictionary to the spell check list widget.
770     foreach(QString dictionaryString, dictionariesStringList)
771     {
772         // Create a new list widget item pointer.
773         QListWidgetItem *listWidgetItemPointer = new QListWidgetItem();
774
775         // Create a dictionary check box widget with the name of the dictionary string.
776         QCheckBox *dictionaryCheckBoxWidget = new QCheckBox(dictionaryString);
777
778         // Check the language if it is currently enabled.
779         if (enabledSpellCheckLanguagesList.contains(dictionaryString))
780             dictionaryCheckBoxWidget->setCheckState(Qt::Checked);
781         else
782             dictionaryCheckBoxWidget->setCheckState(Qt::Unchecked);
783
784         // Add the list widget item to the spell check list widget.
785         spellCheckListWidgetPointer->addItem(listWidgetItemPointer);
786
787         // Set the list widget item check box widget.
788         spellCheckListWidgetPointer->setItemWidget(listWidgetItemPointer, dictionaryCheckBoxWidget);
789     }
790
791     // Get a handle for the KConfig skeleton.
792     KConfigSkeleton *kConfigSkeletonPointer = Settings::self();
793
794     // Instantiate a settings config dialog from the settings.kcfg file.
795     configDialogPointer = new KConfigDialog(this, QLatin1String("settings"), kConfigSkeletonPointer);
796
797     // Create a settings icon string.
798     QString settingsIconString;
799
800     // Get a settings icon that matches the theme.
801     if (QIcon::hasThemeIcon("breeze-settings"))
802     {
803         // KDE uses breeze-settings.
804         settingsIconString = QLatin1String("breeze-settings");
805     }
806     else
807     {
808         // Gnome uses preferences-desktop.
809         settingsIconString = QLatin1String("preferences-desktop");
810     }
811
812     // Add the settings widgets as config dialog pages.
813     configDialogPointer->addPage(privacySettingsWidgetPointer, i18nc("Settings tab title", "Privacy"), QLatin1String("privacybrowser"));
814     configDialogPointer->addPage(generalSettingsWidgetPointer, i18nc("Settings tab title", "General"), settingsIconString);
815     configDialogPointer->addPage(spellCheckSettingsWidgetPointer, i18nc("Settings tab title", "Spell Check"), QLatin1String("tools-check-spelling"));
816
817     // Get handles for the buttons.
818     QPushButton *applyButtonPointer = configDialogPointer->button(QDialogButtonBox::Apply);
819     QPushButton *okButtonPointer = configDialogPointer->button(QDialogButtonBox::Ok);
820
821     // Prevent interaction with the parent window while the dialog is open.
822     configDialogPointer->setWindowModality(Qt::WindowModal);
823
824     // Make it so.
825     configDialogPointer->show();
826
827     // TODO.  KConfigDialog does not respect expanding size policies.  <https://redmine.stoutner.com/issues/823>
828     //configDialogPointer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
829     //privacySettingsWidgetPointer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
830     //generalSettingsWidgetPointer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
831     //configDialogPointer->adjustSize();
832
833     // Expand the config dialog.
834     configDialogPointer->resize(1000, 500);
835
836     // Create a save spell check languages lambda.
837     auto saveSpellCheckLanguages = [spellCheckListWidgetPointer, kConfigSkeletonPointer, this] ()
838     {
839         // Create a list of enabled languages.
840         QStringList newSpellCheckLanguages = QStringList();
841
842         // Get a count of all the languages.
843         int allLanguagesCount = spellCheckListWidgetPointer->count();
844
845         // Get a list of all the checked languages.
846         for (int i = 0; i < allLanguagesCount; ++i) {
847             // Get the language item.
848             QListWidgetItem *languageItemPointer = spellCheckListWidgetPointer->item(i);
849
850             // Get the language check box.
851             QCheckBox *languageCheckBoxPointer = qobject_cast<QCheckBox*>(spellCheckListWidgetPointer->itemWidget(languageItemPointer));
852
853             // Add the item to the enabled languages if it is checked.
854             if (languageCheckBoxPointer->checkState() == Qt::Checked)
855             {
856                 // Get the text.
857                 QString languageString = languageCheckBoxPointer->text();
858
859                 // Remove all instances of `&`, which may have been added automatically when creating the check box text.
860                 languageString.remove(QChar('&'));
861
862                 // Add the language string to the list.
863                 newSpellCheckLanguages.append(languageString);
864             }
865         }
866
867         // Update the spell check languages.
868         if (Settings::spellCheckLanguages() != newSpellCheckLanguages)
869         {
870             // Update the spell check languages.
871             Settings::setSpellCheckLanguages(newSpellCheckLanguages);
872
873             // Write the settings to disk.
874             kConfigSkeletonPointer->save();
875         }
876
877         // Apply the spell check languages.
878         tabWidgetPointer->applySpellCheckLanguages();
879     };
880
881     // Process
882     connect(applyButtonPointer, &QPushButton::clicked, this, saveSpellCheckLanguages);
883     connect(okButtonPointer, &QPushButton::clicked, this, saveSpellCheckLanguages);
884
885     // Apply the settings handled by KConfig.
886     connect(configDialogPointer, SIGNAL(settingsChanged(QString)), tabWidgetPointer, SLOT(applyApplicationSettings()));
887     connect(configDialogPointer, SIGNAL(settingsChanged(QString)), tabWidgetPointer, SLOT(applyDomainSettingsAndReload()));
888 }
889
890 QSize BrowserWindow::sizeHint() const
891 {
892     // Return the default window size.
893     return QSize(1500, 1200);
894 }
895
896 void BrowserWindow::toggleDomStorage() const
897 {
898     // Remove the focus from the URL line edit.
899     urlLineEditPointer->clearFocus();
900
901     // Toggle DOM storage.
902     tabWidgetPointer->toggleDomStorage();
903 }
904
905 void BrowserWindow::toggleFindCaseSensitive() const
906 {
907     // Get the current find string.
908     const QString findString = findTextLineEditPointer->text();
909
910     // Toggle find case sensitive.
911     tabWidgetPointer->toggleFindCaseSensitive(findString);
912 }
913
914 void BrowserWindow::toggleJavaScript() const
915 {
916     // Remove the focus from the URL line edit.
917     urlLineEditPointer->clearFocus();
918
919     // Toggle JavaScript.
920     tabWidgetPointer->toggleJavaScript();
921 }
922
923 void BrowserWindow::toggleLocalStorage() const
924 {
925     // Remove the focus from the URL line edit.
926     urlLineEditPointer->clearFocus();
927
928     // Toggle local storage.
929     tabWidgetPointer->toggleLocalStorage();
930 }
931
932 void BrowserWindow::toggleFullScreen()
933 {
934     // Toggle the full screen status.
935     if (fullScreenActionPointer->isChecked())  // Enable full screen browsing mode.
936     {
937         // Enable full screen mode.
938         fullScreenActionPointer->setFullScreen(window(), true);
939
940         // Hide the menu bar if specified.
941         if (Settings::fullScreenHideMenuBar())
942             menuBar()->setVisible(false);
943
944         // Hide the toolbars if specified.
945         if (Settings::fullScreenHideToolBars())
946         {
947             navigationToolBarPointer->setVisible(false);
948             urlToolBarPointer->setVisible(false);
949         }
950
951         // Hide the tab bar if specified.
952         if (Settings::fullScreenHideTabBar())
953             tabWidgetPointer->setTabBarVisible(false);
954
955         // Hide the status bar if specified.
956         if (Settings::fullScreenHideStatusBar())
957             statusBar()->setVisible(false);
958     }
959     else  // Disable full screen browsing mode.
960     {
961         // Disable full screen mode.
962         fullScreenActionPointer->setFullScreen(window(), false);
963
964         // Show the menu bar.
965         menuBar()->setVisible(true);
966
967         // Show the toolbars.
968         navigationToolBarPointer->setVisible(true);
969         urlToolBarPointer->setVisible(true);
970
971         // Show the tab bar.
972         tabWidgetPointer->setTabBarVisible(true);
973
974         // Show the status bar.
975         statusBar()->setVisible(true);
976     }
977 }
978
979 void BrowserWindow::updateCookiesAction(const int numberOfCookies) const
980 {
981     // Update the action text.
982     cookiesActionPointer->setText(i18nc("The Cookies action, which also displays the number of cookies", "Cookies - %1", numberOfCookies));
983 }
984
985 void BrowserWindow::updateDomStorageAction(const bool &isEnabled) const
986 {
987     // Set the action checked status.
988     domStorageActionPointer->setChecked(isEnabled);
989 }
990
991 void BrowserWindow::updateDomainSettingsIndicator(const bool status)
992 {
993     // Set the domain palette according to the status.
994     if (status)
995         urlLineEditPointer->setPalette(positiveBackgroundPalette);
996     else
997         urlLineEditPointer->setPalette(normalBackgroundPalette);
998 }
999
1000 void BrowserWindow::updateFindText(const QString &text, const bool findCaseSensitive) const
1001 {
1002     // Set the text.
1003     findTextLineEditPointer->setText(text);
1004
1005     // Set the find case sensitive action checked status.
1006     findCaseSensitiveActionPointer->setChecked(findCaseSensitive);
1007 }
1008
1009 void BrowserWindow::updateFindTextResults(const QWebEngineFindTextResult &findTextResult) const
1010 {
1011     // Update the find text label.
1012     findTextLabelPointer->setText(QStringLiteral("  %1/%2  ").arg(findTextResult.activeMatch()).arg(findTextResult.numberOfMatches()));
1013
1014     // Set the background color according to the find status.
1015     if (findTextLineEditPointer->text().isEmpty())
1016         findTextLineEditPointer->setPalette(normalBackgroundPalette);
1017     else if (findTextResult.numberOfMatches() == 0)
1018         findTextLineEditPointer->setPalette(negativeBackgroundPalette);
1019     else
1020         findTextLineEditPointer->setPalette(positiveBackgroundPalette);
1021 }
1022
1023 void BrowserWindow::updateJavaScriptAction(const bool &isEnabled)
1024 {
1025     // Update the JavaScript status.
1026     javaScriptEnabled = isEnabled;
1027
1028     // Set the icon according to the status.
1029     if (javaScriptEnabled)
1030         javaScriptActionPointer->setIcon(QIcon(QLatin1String(":/icons/javascript-warning.svg")));
1031     else
1032         javaScriptActionPointer->setIcon(QIcon(QLatin1String(":/icons/privacy-mode.svg")));
1033
1034     // Set the action checked status.
1035     javaScriptActionPointer->setChecked(javaScriptEnabled);
1036
1037     // Update the status of the DOM storage action.
1038     domStorageActionPointer->setEnabled(javaScriptEnabled & localStorageEnabled);
1039 }
1040
1041 void BrowserWindow::updateLocalStorageAction(const bool &isEnabled)
1042 {
1043     // Update the local storage status.
1044     localStorageEnabled = isEnabled;
1045
1046     // Update the icon.  On Gnome, the toolbar icons don't pick up unless the size is explicit, probably because the toolbar ends up being an intermediate size.
1047     if (localStorageEnabled)
1048         localStorageActionPointer->setIcon(QIcon::fromTheme(QLatin1String("disk-quota-high"), QIcon(QLatin1String("/usr/share/icons/gnome/32x32/actions/filesaveas.png"))));
1049     else
1050         localStorageActionPointer->setIcon(QIcon::fromTheme(QLatin1String("disk-quota"), QIcon(QLatin1String("/usr/share/icons/gnome/32x32/apps/kfm.png"))));
1051
1052     // Set the action checked status.
1053     localStorageActionPointer->setChecked(localStorageEnabled);
1054
1055     // Update the status of the DOM storage action.
1056     domStorageActionPointer->setEnabled(localStorageEnabled & javaScriptEnabled);
1057 }
1058
1059 void BrowserWindow::updateSearchEngineActions(const QString &searchEngine, const bool &updateCustomSearchEngineStatus)
1060 {
1061     // Initialize the custom search engine flag.
1062     bool customSearchEngine = false;
1063
1064     if (searchEngine == "Mojeek")  // Mojeek.
1065     {
1066         // Check the Mojeek user agent action.
1067         searchEngineMojeekActionPointer->setChecked(true);
1068
1069         // Update the search engine menu action icon.
1070         searchEngineMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
1071
1072         // Update the search engine menu action text.
1073         searchEngineMenuActionPointer->setText(i18nc("The main search engine menu action", "Search Engine - Mojeek"));
1074     }
1075     else if (searchEngine == "Monocles")  // Monocles.
1076     {
1077         // Check the Monocles user agent action.
1078         searchEngineMonoclesActionPointer->setChecked(true);
1079
1080         // Update the search engine menu action icon.
1081         searchEngineMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
1082
1083         // Update the search engine menu action text.
1084         searchEngineMenuActionPointer->setText(i18nc("The main search engine menu action", "Search Engine - Monocles"));
1085     }
1086     else if (searchEngine == "MetaGer")  // MetaGer.
1087     {
1088         // Check the MetaGer user agent action.
1089         searchEngineMetagerActionPointer->setChecked(true);
1090
1091         // Update the search engine menu action icon.
1092         searchEngineMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
1093
1094         // Update the search engine menu action text.
1095         searchEngineMenuActionPointer->setText(i18nc("The main search engine menu action", "Search Engine - MetaGer"));
1096     }
1097     else if (searchEngine == "Google")  // Google.
1098     {
1099         // Check the Google user agent action.
1100         searchEngineGoogleActionPointer->setChecked(true);
1101
1102         // Update the search engine menu action icon.
1103         searchEngineMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("im-google"), QIcon::fromTheme(QLatin1String("edit-find"))));
1104
1105         // Update the search engine menu action text.
1106         searchEngineMenuActionPointer->setText(i18nc("The main search engine menu action", "Search Engine - Google"));
1107     }
1108     else if (searchEngine == "Bing")  // Bing.
1109     {
1110         // Check the Bing user agent action.
1111         searchEngineBingActionPointer->setChecked(true);
1112
1113         // Update the search engine menu action icon.
1114         searchEngineMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
1115
1116         // Update the search engine menu action text.
1117         searchEngineMenuActionPointer->setText(i18nc("The main search engine menu action", "Search Engine - Bing"));
1118     }
1119     else if (searchEngine == "Yahoo")  // Yahoo.
1120     {
1121         // Check the Yahoo user agent action.
1122         searchEngineYahooActionPointer->setChecked(true);
1123
1124         // Update the search engine menu action icon.
1125         searchEngineMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("im-yahoo"), QIcon::fromTheme(QLatin1String("edit-find"))));
1126
1127         // Update the search engine menu action text.
1128         searchEngineMenuActionPointer->setText(i18nc("The main search engine menu action", "Search Engine - Yahoo"));
1129     }
1130     else  // Custom search engine.
1131     {
1132         // Check the user agent.
1133         searchEngineCustomActionPointer->setChecked(true);
1134
1135         // Update the search engine menu action icon.
1136         searchEngineMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
1137
1138         // Update the search engine menu action text.
1139         searchEngineMenuActionPointer->setText(i18nc("The main search engine menu action", "Search Engine - Custom"));
1140
1141         // Set the custom search engine text.
1142         searchEngineCustomActionPointer->setText(searchEngine);
1143
1144         // Set the custom search engine flag.
1145         customSearchEngine = true;
1146     }
1147
1148     // Update the custom search engine enabled boolean.
1149     if (updateCustomSearchEngineStatus)
1150         customSearchEngineEnabled = customSearchEngine;
1151
1152     // Format the custom search engine.
1153     if (customSearchEngineEnabled)
1154     {
1155         // Enable the custom search engine.
1156         searchEngineCustomActionPointer->setEnabled(true);
1157     }
1158     else
1159     {
1160         // Disable the custom search engine.
1161         searchEngineCustomActionPointer->setEnabled(false);
1162
1163         // Reset the custom search engine text.
1164         searchEngineCustomActionPointer->setText(i18nc("@action", "Custom"));
1165     }
1166 }
1167
1168 void BrowserWindow::updateUserAgentActions(const QString &userAgent, const bool &updateCustomUserAgentStatus)
1169 {
1170     // Initialize the custom user agent flag.
1171     bool customUserAgent = false;
1172
1173     // Check the indicated on-the-fly user agent.
1174     if (userAgent == UserAgentHelper::PRIVACY_BROWSER_USER_AGENT)  // Privacy Browser.
1175     {
1176         // Check the Privacy Browser user agent action.
1177         userAgentPrivacyBrowserActionPointer->setChecked(true);
1178
1179         // Update the user agent menu action icon.
1180         userAgentMenuActionPointer->setIcon(QIcon(":/icons/privacy-mode.svg"));
1181
1182         // Update the user agent menu action text.
1183         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Privacy Browser"));
1184     }
1185     else if (userAgent == TabWidget::webEngineDefaultUserAgent)  // WebEngine default.
1186     {
1187         // check the WebEngine default user agent action.
1188         userAgentWebEngineDefaultActionPointer->setChecked(true);
1189
1190         // Update the user agent menu action icon.
1191         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("qtlogo"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new")))));
1192
1193         // Update the user agent menu action text.
1194         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - WebEngine default"));
1195     }
1196     else if (userAgent == UserAgentHelper::FIREFOX_LINUX_USER_AGENT)  // Firefox on Linux.
1197     {
1198         // Check the Firefox on Linux user agent action.
1199         userAgentFirefoxLinuxActionPointer->setChecked(true);
1200
1201         // Update the user agent menu action icon.
1202         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("firefox-esr"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new")))));
1203
1204         // Update the user agent menu action text.
1205         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Firefox on Linux"));
1206     }
1207     else if (userAgent == UserAgentHelper::CHROMIUM_LINUX_USER_AGENT)  // Chromium on Linux.
1208     {
1209         // Check the Chromium on Linux user agent action.
1210         userAgentChromiumLinuxActionPointer->setChecked(true);
1211
1212         // Update the user agent menu action icon.
1213         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("chromium"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new")))));
1214
1215         // Update the user agent menu action text.
1216         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Chromium on Linux"));
1217     }
1218     else if (userAgent == UserAgentHelper::FIREFOX_WINDOWS_USER_AGENT)  // Firefox on Windows.
1219     {
1220         // Check the Firefox on Windows user agent action.
1221         userAgentFirefoxWindowsActionPointer->setChecked(true);
1222
1223         // Update the user agent menu action icon.
1224         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("firefox-esr"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new")))));
1225
1226         // Update the user agent menu action text.
1227         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Firefox on Windows"));
1228     }
1229     else if (userAgent == UserAgentHelper::CHROME_WINDOWS_USER_AGENT)  // Chrome on Windows.
1230     {
1231         // Check the Chrome on Windows user agent action.
1232         userAgentChromeWindowsActionPointer->setChecked(true);
1233
1234         // Update the user agent menu action icon.
1235         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("chromium"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new")))));
1236
1237         // Update the user agent menu action text.
1238         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Chrome on Windows"));
1239     }
1240     else if (userAgent == UserAgentHelper::EDGE_WINDOWS_USER_AGENT)  // Edge on Windows.
1241     {
1242         // Check the Edge on Windows user agent action.
1243         userAgentEdgeWindowsActionPointer->setChecked(true);
1244
1245         // Update the user agent menu action icon.
1246         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new"))));
1247
1248         // Update the user agent menu action text.
1249         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Edge on Windows"));
1250     }
1251     else if (userAgent == UserAgentHelper::SAFARI_MACOS_USER_AGENT)  // Safari on macOS.
1252     {
1253         // Check the Safari on macOS user agent action.
1254         userAgentSafariMacosActionPointer->setChecked(true);
1255
1256         // Update the user agent menu action icon.
1257         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new"))));
1258
1259         // Update the user agent menu action text.
1260         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Safari on macOS"));
1261     }
1262     else  // Custom user agent.
1263     {
1264         // Check the user agent.
1265         userAgentCustomActionPointer->setChecked(true);
1266
1267         // Update the user agent menu action icon.
1268         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new"))));
1269
1270         // Update the user agent menu action text.
1271         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Custom"));
1272
1273         // Set the custom user agent text.
1274         userAgentCustomActionPointer->setText(userAgent);
1275
1276         // Set the custom user agent flag.
1277         customUserAgent = true;
1278     }
1279
1280     // Update the custom user agent enabled boolean.
1281     // This is not done when the current user agent is a custom one but it is temporarially being changed via on-the-fly settings so that the user can switch back to the custom user agent.
1282     if (updateCustomUserAgentStatus)
1283         customUserAgentEnabled = customUserAgent;
1284
1285
1286     // Format the custom user agent.
1287     if (customUserAgentEnabled)
1288     {
1289         // Enable the custom user agent.
1290         userAgentCustomActionPointer->setEnabled(true);
1291     }
1292     else
1293     {
1294         // Disable the custom user agent.
1295         userAgentCustomActionPointer->setEnabled(false);
1296
1297         // Reset the custom user agent text.
1298         userAgentCustomActionPointer->setText(i18nc("@action", "Custom"));
1299     }
1300 }
1301
1302 void BrowserWindow::updateZoomFactorAction(const double &zoomFactor)
1303 {
1304     // Set the current zoom factor.
1305     currentZoomFactor = zoomFactor;
1306
1307     // Update the zoom factor action text, formatting the double with 2 decimal places.
1308     zoomFactorActionPointer->setText(ki18nc("@action", "Zoom Factor - %1").subs(zoomFactor, 0, '0', 2).toString());
1309 }
1310
1311 void BrowserWindow::updateSearchEngineLabel(const QString &searchEngineString) const
1312 {
1313     // Update the search engine label.
1314     searchEngineLabelPointer->setText(SearchEngineHelper::getSearchUrl(searchEngineString));
1315 }
1316
1317 void BrowserWindow::updateUrlLineEdit(const QUrl &newUrl)
1318 {
1319     // Update the URL line edit if it does not have focus.
1320     if (!urlLineEditPointer->hasFocus())
1321     {
1322         // Get the new URL string.
1323         QString newUrlString = newUrl.toString();
1324
1325         // Update the URL line edit.
1326         urlLineEditPointer->setText(newUrlString);
1327
1328         // Set the focus if the new URL is blank.
1329         if (newUrlString == QStringLiteral(""))
1330             urlLineEditPointer->setFocus();
1331     }
1332
1333     // Store the current URL.
1334     currentUrl = newUrl;
1335 }
1336
1337 void BrowserWindow::updateUserAgentLabel(const QString &userAgentDatabaseName) const
1338 {
1339     // Update the user agent label.
1340     userAgentLabelPointer->setText(UserAgentHelper::getUserAgentFromDatabaseName(userAgentDatabaseName));
1341 }
1342
1343 void BrowserWindow::updateWindowTitle(const QString &title)
1344 {
1345     // Update the window title.
1346     setWindowTitle(title);
1347 }