]> gitweb.stoutner.com Git - PrivacyBrowserPC.git/blob - src/windows/BrowserWindow.cpp
Add GNOME edit current domain settings icon. https://redmine.stoutner.com/issues/999
[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", QIcon::fromTheme(QLatin1String("preferences-desktop"))),
343                                                                                   QLineEdit::TrailingPosition);
344
345     // Add or edit the current domain settings.
346     connect(addOrEditDomainSettingsActionPointer, SIGNAL(triggered()), this, SLOT(addOrEditDomainSettings()));
347
348     // Create a find text label pointer.
349     findTextLabelPointer = new QLabel();
350
351     // Set the default label text.
352     findTextLabelPointer->setText(QLatin1String("  ") + i18nc("Default find results.", "0/0") + QLatin1String("  "));
353
354     // Insert the widgets into the toolbars.
355     urlToolBarPointer->insertWidget(javaScriptActionPointer, urlLineEditPointer);
356     findTextLineEditActionPointer = urlToolBarPointer->insertWidget(findNextActionPointer, findTextLineEditPointer);
357     findTextLabelActionPointer = urlToolBarPointer->insertWidget(findNextActionPointer, findTextLabelPointer);
358
359     // Initially hide the find text actions.
360     hideFindTextActions();
361
362     // Load a new URL from the URL line edit.
363     connect(urlLineEditPointer, SIGNAL(returnKeyPressed(const QString)), this, SLOT(loadUrlFromLineEdit(const QString)));
364
365     // Find text as it is typed.
366     connect(findTextLineEditPointer, SIGNAL(textEdited(const QString &)), tabWidgetPointer, SLOT(findText(const QString &)));
367
368     // Find next if the enter key is pressed.
369     connect(findTextLineEditPointer, SIGNAL(returnKeyPressed(const QString &)), tabWidgetPointer, SLOT(findText(const QString &)));
370
371     // Update find text when switching tabs.
372     connect(tabWidgetPointer, SIGNAL(updateFindText(const QString &, const bool)), this, SLOT(updateFindText(const QString &, const bool)));
373
374     // Update the find text results.
375     connect(tabWidgetPointer, SIGNAL(updateFindTextResults(const QWebEngineFindTextResult &)), this, SLOT(updateFindTextResults(const QWebEngineFindTextResult &)));
376
377     // Update the URL line edit on page loads.
378     connect(tabWidgetPointer, SIGNAL(updateUrlLineEdit(QUrl)), this, SLOT(updateUrlLineEdit(QUrl)));
379
380     // Update the window title.
381     connect(tabWidgetPointer, SIGNAL(updateWindowTitle(const QString)), this, SLOT(updateWindowTitle(const QString)));
382
383     // Get a handle for the status bar.
384     QStatusBar *statusBarPointer = statusBar();
385
386     // Create a progress bar.
387     progressBarPointer = new QProgressBar();
388
389     // Add the progress bar to to the status bar.
390     statusBarPointer->addPermanentWidget(progressBarPointer);
391
392     // Update the status bar with the URL when a link is hovered.
393     connect(tabWidgetPointer, SIGNAL(linkHovered(QString)), statusBarPointer, SLOT(showMessage(QString)));
394
395     // Update the progress bar.
396     connect(tabWidgetPointer, SIGNAL(showProgressBar(const int)), this, SLOT(showProgressBar(const int)));
397     connect(tabWidgetPointer, SIGNAL(hideProgressBar()), progressBarPointer, SLOT(hide()));
398
399     // Update the URL line edit focus.
400     connect(tabWidgetPointer, SIGNAL(clearUrlLineEditFocus()), this, SLOT(clearUrlLineEditFocus()));
401
402     // Get the URL line edit palettes.
403     normalBackgroundPalette = urlLineEditPointer->palette();
404     negativeBackgroundPalette = normalBackgroundPalette;
405     positiveBackgroundPalette = normalBackgroundPalette;
406
407     // Modify the palettes.
408     KColorScheme::adjustBackground(negativeBackgroundPalette, KColorScheme::NegativeBackground);
409     KColorScheme::adjustBackground(positiveBackgroundPalette, KColorScheme::PositiveBackground);
410
411     // Update the applied palette.
412     connect(tabWidgetPointer, SIGNAL(updateDomainSettingsIndicator(const bool)), this, SLOT(updateDomainSettingsIndicator(const bool)));
413
414     // Process full screen requests.
415     connect(tabWidgetPointer, SIGNAL(fullScreenRequested(bool)), this, SLOT(fullScreenRequested(bool)));
416
417     // Create keyboard shortcuts.
418     QShortcut *f11ShortcutPointer = new QShortcut(QKeySequence(i18nc("The toggle full screen shortcut.", "F11")), this);
419     QShortcut *escapeShortcutPointer = new QShortcut(QKeySequence::Cancel, this);
420
421     // Connect the keyboard shortcuts.
422     connect(f11ShortcutPointer, SIGNAL(activated()), fullScreenActionPointer, SLOT(trigger()));
423     connect(escapeShortcutPointer, SIGNAL(activated()), this, SLOT(escape()));
424
425     // Populate the UI.
426     // 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.
427     updateJavaScriptAction(Settings::javaScriptEnabled());
428     updateLocalStorageAction(Settings::localStorageEnabled());
429     updateDomStorageAction(Settings::domStorageEnabled());
430     updateUserAgentActions(UserAgentHelper::getUserAgentFromDatabaseName(Settings::userAgent()), true);
431     updateZoomFactorAction(Settings::zoomFactor());
432
433     // Load the initial website if this is the first window.
434     if (firstWindow)
435         tabWidgetPointer->loadInitialWebsite();
436 }
437
438 void BrowserWindow::addOrEditDomainSettings() const
439 {
440     // Remove the focus from the URL line edit.
441     urlLineEditPointer->clearFocus();
442
443     // Create the domain settings dialog pointer.
444     DomainSettingsDialog *domainSettingsDialogPointer;
445
446     // Get the current domain settings name.
447     QString &currentDomainSettingsName = tabWidgetPointer->getDomainSettingsName();
448
449     // Run the commands according to the current domain settings status.
450     if (currentDomainSettingsName == QStringLiteral(""))  // Domain settings are not currently applied.
451     {
452         // Instruct the domain settings dialog to add a new domain.
453         domainSettingsDialogPointer = new DomainSettingsDialog(DomainSettingsDialog::ADD_DOMAIN, currentUrl.host());
454     }
455     else  // Domain settings are currently applied.
456     {
457         // Instruct the domain settings dialog to edit the current domain.
458         domainSettingsDialogPointer = new DomainSettingsDialog(DomainSettingsDialog::EDIT_DOMAIN, currentDomainSettingsName);
459     }
460
461     // Set the dialog window title.
462     domainSettingsDialogPointer->setWindowTitle(i18nc("The domain settings dialog title", "Domain Settings"));
463
464     // Set the modality.
465     domainSettingsDialogPointer->setWindowModality(Qt::WindowModality::WindowModal);;
466
467     // Show the dialog.
468     domainSettingsDialogPointer->show();
469
470     // Reload the tabs when domain settings are updated.
471     connect(domainSettingsDialogPointer, SIGNAL(domainSettingsUpdated()), tabWidgetPointer, SLOT(applyDomainSettingsAndReload()));
472 }
473
474 void BrowserWindow::back() const
475 {
476     // Remove the focus from the URL line edit.
477     urlLineEditPointer->clearFocus();
478
479     // Go back.
480     tabWidgetPointer->back();
481 }
482
483 void BrowserWindow::clearUrlLineEditFocus() const
484 {
485     // Remove the focus from the URL line edit.
486     urlLineEditPointer->clearFocus();
487 }
488
489 void BrowserWindow::escape() const
490 {
491     // Process the escape according to the status of the browser.
492     if (fullScreenActionPointer->isChecked())  // Full screen browsing is enabled.
493     {
494         // Exit full screen browsing.
495         fullScreenActionPointer->trigger();
496     }
497     else if (!findTextLineEditPointer->text().isEmpty())  // Find text is populated.
498     {
499         // Clear the find text line edit.
500         findTextLineEditPointer->clear();
501
502         // Clear the search in the WebEngine.
503         tabWidgetPointer->findText(QStringLiteral(""));
504     }
505     else if (findTextLineEditActionPointer->isVisible())  // Find text actions are visible.
506     {
507         // Hide the find text actions.
508         hideFindTextActions();
509     }
510 }
511
512 void BrowserWindow::findNext() const
513 {
514     // Get the find string.
515     const QString findString = findTextLineEditPointer->text();
516
517     // Search for the text if it is not empty.
518     if (!findString.isEmpty())
519         tabWidgetPointer->findText(findString);
520 }
521
522 void BrowserWindow::findPrevious() const
523 {
524     // Get the find string.
525     const QString findString = findTextLineEditPointer->text();
526
527     // Search for the text if it is not empty.
528     if (!findString.isEmpty())
529         tabWidgetPointer->findPrevious(findString);
530 }
531
532 void BrowserWindow::forward() const
533 {
534     // Remove the focus from the URL line edit.
535     urlLineEditPointer->clearFocus();
536
537     // Go forward.
538     tabWidgetPointer->forward();
539 }
540
541 void BrowserWindow::fullScreenRequested(const bool toggleOn)
542 {
543     // Toggle full screen mode.
544     if (toggleOn)  // Turn full screen mode on.
545     {
546         // Set the window to be full screen.
547         fullScreenActionPointer->setFullScreen(window(), true);
548
549         // Hide all the bars.
550         menuBar()->setVisible(false);
551         navigationToolBarPointer->setVisible(false);
552         urlToolBarPointer->setVisible(false);
553         tabWidgetPointer->setTabBarVisible(false);
554         statusBar()->setVisible(false);
555     }
556     else  // Turn full screen mode off.
557     {
558         // Set the window to not be full screen.
559         fullScreenActionPointer->setFullScreen(window(), false);
560
561         // Show all the bars.
562         menuBar()->setVisible(true);
563         navigationToolBarPointer->setVisible(true);
564         urlToolBarPointer->setVisible(true);
565         tabWidgetPointer->setTabBarVisible(true);
566         statusBar()->setVisible(true);
567     }
568 }
569
570 void BrowserWindow::getZoomFactorFromUser()
571 {
572     // Create an OK flag.
573     bool okClicked;
574
575     // 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.
576     double newZoomFactor = QInputDialog::getDouble(this, i18nc("The on-the-fly zoom factor dialog title", "On-The-Fly Zoom Factor"),
577                                                    i18nc("The instruction text of the on-the-fly zoom factor dialog", "Enter a zoom factor between 0.25 and 5.00"),
578                                                    currentZoomFactor, .025, 5.00, 2, &okClicked, Qt::WindowFlags(), 0.25);
579
580     // Update the zoom factor if the user clicked OK.
581     if (okClicked)
582     {
583         // Update the current zoom factor.
584         currentZoomFactor = newZoomFactor;
585
586         // Set the new zoom factor.
587         tabWidgetPointer->applyOnTheFlyZoomFactor(newZoomFactor);
588
589         // Update the on-the-fly action text.
590         updateZoomFactorAction(newZoomFactor);
591     }
592 }
593
594 void BrowserWindow::hideFindTextActions() const
595 {
596     // Hide the find text actions.
597     findTextLineEditActionPointer->setVisible(false);
598     findTextLabelActionPointer->setVisible(false);
599     findNextActionPointer->setVisible(false);
600     findPreviousActionPointer->setVisible(false);
601     findCaseSensitiveActionPointer->setVisible(false);
602     hideFindTextActionPointer->setVisible(false);
603 }
604
605 void BrowserWindow::home() const
606 {
607     // Remove the focus from the URL line edit.
608     urlLineEditPointer->clearFocus();
609
610     // Go home.
611     tabWidgetPointer->home();
612 }
613
614 void BrowserWindow::loadUrlFromLineEdit(const QString &url) const
615 {
616     // Remove the focus from the URL line edit.
617     urlLineEditPointer->clearFocus();
618
619     // Load the URL.
620     tabWidgetPointer->loadUrlFromLineEdit(url);
621 }
622
623 void BrowserWindow::newWindow() const
624 {
625     // Display a new instance of Privacy Browser.
626     (new BrowserWindow)->show();
627 }
628
629 void BrowserWindow::refresh() const
630 {
631     // Remove the focus from the URL line edit.
632     urlLineEditPointer->clearFocus();
633
634     // Refresh the web page.
635     tabWidgetPointer->refresh();
636 }
637
638 void BrowserWindow::showCookiesDialog()
639 {
640     // Remove the focus from the URL line edit.
641     urlLineEditPointer->clearFocus();
642
643     // Instantiate the cookie settings dialog.
644     CookiesDialog *cookiesDialogPointer = new CookiesDialog(tabWidgetPointer->getCookieList());
645
646     // Show the dialog.
647     cookiesDialogPointer->show();
648
649     // Connect the dialog signals.
650     connect(cookiesDialogPointer, SIGNAL(addCookie(QNetworkCookie)), tabWidgetPointer, SLOT(addCookieToStore(QNetworkCookie)));
651     connect(cookiesDialogPointer, SIGNAL(deleteAllCookies()), tabWidgetPointer, SLOT(deleteAllCookies()));
652     connect(cookiesDialogPointer, SIGNAL(deleteCookie(QNetworkCookie)), tabWidgetPointer, SLOT(deleteCookieFromStore(QNetworkCookie)));
653 }
654
655 void BrowserWindow::showDownloadLocationBrowseDialog() const
656 {
657     // Get the current download location.
658     QString currentDownloadLocation = downloadLocationComboBoxPointer->currentText();
659
660     // Resolve the system download directory if specified.
661     if (currentDownloadLocation == QStringLiteral("System Download Directory"))
662         currentDownloadLocation = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
663
664     // Get the new download location.
665     QString newDownloadLocation = QFileDialog::getExistingDirectory(configDialogPointer, i18nc("Select download location dialog caption", "Select Download Location"), currentDownloadLocation);
666
667     // Populate the download location combo box according to the new download location.
668     if (newDownloadLocation == QStandardPaths::writableLocation(QStandardPaths::DownloadLocation))  // The default download location was selected.
669     {
670         // Populate the download location with the default text.
671         downloadLocationComboBoxPointer->setCurrentText("System Download Directory");
672     }
673     else if (newDownloadLocation != QStringLiteral(""))  // A different directory was selected.
674     {
675         // Populate the download location.
676         downloadLocationComboBoxPointer->setCurrentText(newDownloadLocation);
677     }
678 }
679
680 void BrowserWindow::showDomainSettingsDialog() const
681 {
682     // Remove the focus from the URL line edit.
683     urlLineEditPointer->clearFocus();
684
685     // Instantiate the domain settings dialog.
686     DomainSettingsDialog *domainSettingsDialogPointer = new DomainSettingsDialog();
687
688     // Show the dialog.
689     domainSettingsDialogPointer->show();
690
691     // Reload the tabs when domain settings are updated.
692     connect(domainSettingsDialogPointer, SIGNAL(domainSettingsUpdated()), tabWidgetPointer, SLOT(applyDomainSettingsAndReload()));
693 }
694
695 void BrowserWindow::showFindTextActions() const
696 {
697     // Show the find text actions.
698     findTextLineEditActionPointer->setVisible(true);
699     findTextLabelActionPointer->setVisible(true);
700     findNextActionPointer->setVisible(true);
701     findPreviousActionPointer->setVisible(true);
702     findCaseSensitiveActionPointer->setVisible(true);
703     hideFindTextActionPointer->setVisible(true);
704
705     // Set the focus on the find line edit.
706     findTextLineEditPointer->setFocus();
707
708     // Select all the text in the find line edit.
709     findTextLineEditPointer->selectAll();
710 }
711
712 void BrowserWindow::showProgressBar(const int &progress) const
713 {
714     // Set the progress bar value.
715     progressBarPointer->setValue(progress);
716
717     // Show the progress bar.
718     progressBarPointer->show();
719 }
720
721 void BrowserWindow::showSettingsDialog()
722 {
723     // Create the settings widgets.
724     QWidget *privacySettingsWidgetPointer = new QWidget;
725     QWidget *generalSettingsWidgetPointer = new QWidget;
726     QWidget *spellCheckSettingsWidgetPointer = new QWidget;
727
728     // Instantiate the settings UI.
729     Ui::PrivacySettings privacySettingsUi;
730     Ui::GeneralSettings generalSettingsUi;
731     Ui::SpellCheckSettings spellCheckSettingsUi;
732
733     // Setup the UI to display the settings widgets.
734     privacySettingsUi.setupUi(privacySettingsWidgetPointer);
735     generalSettingsUi.setupUi(generalSettingsWidgetPointer);
736     spellCheckSettingsUi.setupUi(spellCheckSettingsWidgetPointer);
737
738     // Get handles for the widgets.
739     QComboBox *userAgentComboBoxPointer = privacySettingsUi.kcfg_userAgent;
740     userAgentLabelPointer = privacySettingsUi.userAgentLabel;
741     QComboBox *searchEngineComboBoxPointer = generalSettingsUi.kcfg_searchEngine;
742     searchEngineLabelPointer = generalSettingsUi.searchEngineLabel;
743     downloadLocationComboBoxPointer = generalSettingsUi.kcfg_downloadLocation;
744     QPushButton *browseButtonPointer = generalSettingsUi.browseButton;
745     QListWidget *spellCheckListWidgetPointer = spellCheckSettingsUi.spellCheckListWidget;
746
747     // Populate the combo box labels.
748     updateUserAgentLabel(userAgentComboBoxPointer->currentText());
749     updateSearchEngineLabel(searchEngineComboBoxPointer->currentText());
750
751     // Update the labels when the combo boxes change.
752     connect(userAgentComboBoxPointer, SIGNAL(currentTextChanged(const QString)), this, SLOT(updateUserAgentLabel(const QString)));
753     connect(searchEngineComboBoxPointer, SIGNAL(currentTextChanged(const QString)), this, SLOT(updateSearchEngineLabel(const QString)));
754
755     // Connect the download location directory browse button.
756     connect(browseButtonPointer, SIGNAL(clicked()), this, SLOT(showDownloadLocationBrowseDialog()));
757
758     // Create a dictionaries QDir from the `QTWEBENGINE_DICTIONARIES_PATH` environment variable.
759     QDir dictionariesDir = QDir(qEnvironmentVariable("QTWEBENGINE_DICTIONARIES_PATH"));
760
761     // Get a dictionaries string list.
762     QStringList dictionariesStringList = dictionariesDir.entryList(QStringList(QLatin1String("*.bdic")), QDir::Files | QDir::NoSymLinks);
763
764     // Remove the `.bdic` file extensions from the dictionaries list.
765     dictionariesStringList.replaceInStrings(QLatin1String(".bdic"), QLatin1String(""));
766
767     // Get a list of the enabled spell check languages.
768     QStringList enabledSpellCheckLanguagesList = Settings::spellCheckLanguages();
769
770     // Add each dictionary to the spell check list widget.
771     foreach(QString dictionaryString, dictionariesStringList)
772     {
773         // Create a new list widget item pointer.
774         QListWidgetItem *listWidgetItemPointer = new QListWidgetItem();
775
776         // Create a dictionary check box widget with the name of the dictionary string.
777         QCheckBox *dictionaryCheckBoxWidget = new QCheckBox(dictionaryString);
778
779         // Check the language if it is currently enabled.
780         if (enabledSpellCheckLanguagesList.contains(dictionaryString))
781             dictionaryCheckBoxWidget->setCheckState(Qt::Checked);
782         else
783             dictionaryCheckBoxWidget->setCheckState(Qt::Unchecked);
784
785         // Add the list widget item to the spell check list widget.
786         spellCheckListWidgetPointer->addItem(listWidgetItemPointer);
787
788         // Set the list widget item check box widget.
789         spellCheckListWidgetPointer->setItemWidget(listWidgetItemPointer, dictionaryCheckBoxWidget);
790     }
791
792     // Get a handle for the KConfig skeleton.
793     KConfigSkeleton *kConfigSkeletonPointer = Settings::self();
794
795     // Instantiate a settings config dialog from the settings.kcfg file.
796     configDialogPointer = new KConfigDialog(this, QLatin1String("settings"), kConfigSkeletonPointer);
797
798     // Create a settings icon string.
799     QString settingsIconString;
800
801     // Get a settings icon that matches the theme.
802     if (QIcon::hasThemeIcon("breeze-settings"))
803     {
804         // KDE uses breeze-settings.
805         settingsIconString = QLatin1String("breeze-settings");
806     }
807     else
808     {
809         // Gnome uses preferences-desktop.
810         settingsIconString = QLatin1String("preferences-desktop");
811     }
812
813     // Add the settings widgets as config dialog pages.
814     configDialogPointer->addPage(privacySettingsWidgetPointer, i18nc("Settings tab title", "Privacy"), QLatin1String("privacybrowser"));
815     configDialogPointer->addPage(generalSettingsWidgetPointer, i18nc("Settings tab title", "General"), settingsIconString);
816     configDialogPointer->addPage(spellCheckSettingsWidgetPointer, i18nc("Settings tab title", "Spell Check"), QLatin1String("tools-check-spelling"));
817
818     // Get handles for the buttons.
819     QPushButton *applyButtonPointer = configDialogPointer->button(QDialogButtonBox::Apply);
820     QPushButton *okButtonPointer = configDialogPointer->button(QDialogButtonBox::Ok);
821
822     // Prevent interaction with the parent window while the dialog is open.
823     configDialogPointer->setWindowModality(Qt::WindowModal);
824
825     // Make it so.
826     configDialogPointer->show();
827
828     // TODO.  KConfigDialog does not respect expanding size policies.  <https://redmine.stoutner.com/issues/823>
829     //configDialogPointer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
830     //privacySettingsWidgetPointer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
831     //generalSettingsWidgetPointer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
832     //configDialogPointer->adjustSize();
833
834     // Expand the config dialog.
835     configDialogPointer->resize(1000, 500);
836
837     // Create a save spell check languages lambda.
838     auto saveSpellCheckLanguages = [spellCheckListWidgetPointer, kConfigSkeletonPointer, this] ()
839     {
840         // Create a list of enabled languages.
841         QStringList newSpellCheckLanguages = QStringList();
842
843         // Get a count of all the languages.
844         int allLanguagesCount = spellCheckListWidgetPointer->count();
845
846         // Get a list of all the checked languages.
847         for (int i = 0; i < allLanguagesCount; ++i) {
848             // Get the language item.
849             QListWidgetItem *languageItemPointer = spellCheckListWidgetPointer->item(i);
850
851             // Get the language check box.
852             QCheckBox *languageCheckBoxPointer = qobject_cast<QCheckBox*>(spellCheckListWidgetPointer->itemWidget(languageItemPointer));
853
854             // Add the item to the enabled languages if it is checked.
855             if (languageCheckBoxPointer->checkState() == Qt::Checked)
856             {
857                 // Get the text.
858                 QString languageString = languageCheckBoxPointer->text();
859
860                 // Remove all instances of `&`, which may have been added automatically when creating the check box text.
861                 languageString.remove(QChar('&'));
862
863                 // Add the language string to the list.
864                 newSpellCheckLanguages.append(languageString);
865             }
866         }
867
868         // Update the spell check languages.
869         if (Settings::spellCheckLanguages() != newSpellCheckLanguages)
870         {
871             // Update the spell check languages.
872             Settings::setSpellCheckLanguages(newSpellCheckLanguages);
873
874             // Write the settings to disk.
875             kConfigSkeletonPointer->save();
876         }
877
878         // Apply the spell check languages.
879         tabWidgetPointer->applySpellCheckLanguages();
880     };
881
882     // Process
883     connect(applyButtonPointer, &QPushButton::clicked, this, saveSpellCheckLanguages);
884     connect(okButtonPointer, &QPushButton::clicked, this, saveSpellCheckLanguages);
885
886     // Apply the settings handled by KConfig.
887     connect(configDialogPointer, SIGNAL(settingsChanged(QString)), tabWidgetPointer, SLOT(applyApplicationSettings()));
888     connect(configDialogPointer, SIGNAL(settingsChanged(QString)), tabWidgetPointer, SLOT(applyDomainSettingsAndReload()));
889 }
890
891 QSize BrowserWindow::sizeHint() const
892 {
893     // Return the default window size.
894     return QSize(1500, 1200);
895 }
896
897 void BrowserWindow::toggleDomStorage() const
898 {
899     // Remove the focus from the URL line edit.
900     urlLineEditPointer->clearFocus();
901
902     // Toggle DOM storage.
903     tabWidgetPointer->toggleDomStorage();
904 }
905
906 void BrowserWindow::toggleFindCaseSensitive() const
907 {
908     // Get the current find string.
909     const QString findString = findTextLineEditPointer->text();
910
911     // Toggle find case sensitive.
912     tabWidgetPointer->toggleFindCaseSensitive(findString);
913 }
914
915 void BrowserWindow::toggleJavaScript() const
916 {
917     // Remove the focus from the URL line edit.
918     urlLineEditPointer->clearFocus();
919
920     // Toggle JavaScript.
921     tabWidgetPointer->toggleJavaScript();
922 }
923
924 void BrowserWindow::toggleLocalStorage() const
925 {
926     // Remove the focus from the URL line edit.
927     urlLineEditPointer->clearFocus();
928
929     // Toggle local storage.
930     tabWidgetPointer->toggleLocalStorage();
931 }
932
933 void BrowserWindow::toggleFullScreen()
934 {
935     // Toggle the full screen status.
936     if (fullScreenActionPointer->isChecked())  // Enable full screen browsing mode.
937     {
938         // Enable full screen mode.
939         fullScreenActionPointer->setFullScreen(window(), true);
940
941         // Hide the menu bar if specified.
942         if (Settings::fullScreenHideMenuBar())
943             menuBar()->setVisible(false);
944
945         // Hide the toolbars if specified.
946         if (Settings::fullScreenHideToolBars())
947         {
948             navigationToolBarPointer->setVisible(false);
949             urlToolBarPointer->setVisible(false);
950         }
951
952         // Hide the tab bar if specified.
953         if (Settings::fullScreenHideTabBar())
954             tabWidgetPointer->setTabBarVisible(false);
955
956         // Hide the status bar if specified.
957         if (Settings::fullScreenHideStatusBar())
958             statusBar()->setVisible(false);
959     }
960     else  // Disable full screen browsing mode.
961     {
962         // Disable full screen mode.
963         fullScreenActionPointer->setFullScreen(window(), false);
964
965         // Show the menu bar.
966         menuBar()->setVisible(true);
967
968         // Show the toolbars.
969         navigationToolBarPointer->setVisible(true);
970         urlToolBarPointer->setVisible(true);
971
972         // Show the tab bar.
973         tabWidgetPointer->setTabBarVisible(true);
974
975         // Show the status bar.
976         statusBar()->setVisible(true);
977     }
978 }
979
980 void BrowserWindow::updateCookiesAction(const int numberOfCookies) const
981 {
982     // Update the action text.
983     cookiesActionPointer->setText(i18nc("The Cookies action, which also displays the number of cookies", "Cookies - %1", numberOfCookies));
984 }
985
986 void BrowserWindow::updateDomStorageAction(const bool &isEnabled) const
987 {
988     // Set the action checked status.
989     domStorageActionPointer->setChecked(isEnabled);
990 }
991
992 void BrowserWindow::updateDomainSettingsIndicator(const bool status)
993 {
994     // Set the domain palette according to the status.
995     if (status)
996         urlLineEditPointer->setPalette(positiveBackgroundPalette);
997     else
998         urlLineEditPointer->setPalette(normalBackgroundPalette);
999 }
1000
1001 void BrowserWindow::updateFindText(const QString &text, const bool findCaseSensitive) const
1002 {
1003     // Set the text.
1004     findTextLineEditPointer->setText(text);
1005
1006     // Set the find case sensitive action checked status.
1007     findCaseSensitiveActionPointer->setChecked(findCaseSensitive);
1008 }
1009
1010 void BrowserWindow::updateFindTextResults(const QWebEngineFindTextResult &findTextResult) const
1011 {
1012     // Update the find text label.
1013     findTextLabelPointer->setText(QStringLiteral("  %1/%2  ").arg(findTextResult.activeMatch()).arg(findTextResult.numberOfMatches()));
1014
1015     // Set the background color according to the find status.
1016     if (findTextLineEditPointer->text().isEmpty())
1017         findTextLineEditPointer->setPalette(normalBackgroundPalette);
1018     else if (findTextResult.numberOfMatches() == 0)
1019         findTextLineEditPointer->setPalette(negativeBackgroundPalette);
1020     else
1021         findTextLineEditPointer->setPalette(positiveBackgroundPalette);
1022 }
1023
1024 void BrowserWindow::updateJavaScriptAction(const bool &isEnabled)
1025 {
1026     // Update the JavaScript status.
1027     javaScriptEnabled = isEnabled;
1028
1029     // Set the icon according to the status.
1030     if (javaScriptEnabled)
1031         javaScriptActionPointer->setIcon(QIcon(QLatin1String(":/icons/javascript-warning.svg")));
1032     else
1033         javaScriptActionPointer->setIcon(QIcon(QLatin1String(":/icons/privacy-mode.svg")));
1034
1035     // Set the action checked status.
1036     javaScriptActionPointer->setChecked(javaScriptEnabled);
1037
1038     // Update the status of the DOM storage action.
1039     domStorageActionPointer->setEnabled(javaScriptEnabled & localStorageEnabled);
1040 }
1041
1042 void BrowserWindow::updateLocalStorageAction(const bool &isEnabled)
1043 {
1044     // Update the local storage status.
1045     localStorageEnabled = isEnabled;
1046
1047     // 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.
1048     if (localStorageEnabled)
1049         localStorageActionPointer->setIcon(QIcon::fromTheme(QLatin1String("disk-quota-high"), QIcon(QLatin1String("/usr/share/icons/gnome/32x32/actions/filesaveas.png"))));
1050     else
1051         localStorageActionPointer->setIcon(QIcon::fromTheme(QLatin1String("disk-quota"), QIcon(QLatin1String("/usr/share/icons/gnome/32x32/apps/kfm.png"))));
1052
1053     // Set the action checked status.
1054     localStorageActionPointer->setChecked(localStorageEnabled);
1055
1056     // Update the status of the DOM storage action.
1057     domStorageActionPointer->setEnabled(localStorageEnabled & javaScriptEnabled);
1058 }
1059
1060 void BrowserWindow::updateSearchEngineActions(const QString &searchEngine, const bool &updateCustomSearchEngineStatus)
1061 {
1062     // Initialize the custom search engine flag.
1063     bool customSearchEngine = false;
1064
1065     if (searchEngine == "Mojeek")  // Mojeek.
1066     {
1067         // Check the Mojeek user agent action.
1068         searchEngineMojeekActionPointer->setChecked(true);
1069
1070         // Update the search engine menu action icon.
1071         searchEngineMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
1072
1073         // Update the search engine menu action text.
1074         searchEngineMenuActionPointer->setText(i18nc("The main search engine menu action", "Search Engine - Mojeek"));
1075     }
1076     else if (searchEngine == "Monocles")  // Monocles.
1077     {
1078         // Check the Monocles user agent action.
1079         searchEngineMonoclesActionPointer->setChecked(true);
1080
1081         // Update the search engine menu action icon.
1082         searchEngineMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
1083
1084         // Update the search engine menu action text.
1085         searchEngineMenuActionPointer->setText(i18nc("The main search engine menu action", "Search Engine - Monocles"));
1086     }
1087     else if (searchEngine == "MetaGer")  // MetaGer.
1088     {
1089         // Check the MetaGer user agent action.
1090         searchEngineMetagerActionPointer->setChecked(true);
1091
1092         // Update the search engine menu action icon.
1093         searchEngineMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
1094
1095         // Update the search engine menu action text.
1096         searchEngineMenuActionPointer->setText(i18nc("The main search engine menu action", "Search Engine - MetaGer"));
1097     }
1098     else if (searchEngine == "Google")  // Google.
1099     {
1100         // Check the Google user agent action.
1101         searchEngineGoogleActionPointer->setChecked(true);
1102
1103         // Update the search engine menu action icon.
1104         searchEngineMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("im-google"), QIcon::fromTheme(QLatin1String("edit-find"))));
1105
1106         // Update the search engine menu action text.
1107         searchEngineMenuActionPointer->setText(i18nc("The main search engine menu action", "Search Engine - Google"));
1108     }
1109     else if (searchEngine == "Bing")  // Bing.
1110     {
1111         // Check the Bing user agent action.
1112         searchEngineBingActionPointer->setChecked(true);
1113
1114         // Update the search engine menu action icon.
1115         searchEngineMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
1116
1117         // Update the search engine menu action text.
1118         searchEngineMenuActionPointer->setText(i18nc("The main search engine menu action", "Search Engine - Bing"));
1119     }
1120     else if (searchEngine == "Yahoo")  // Yahoo.
1121     {
1122         // Check the Yahoo user agent action.
1123         searchEngineYahooActionPointer->setChecked(true);
1124
1125         // Update the search engine menu action icon.
1126         searchEngineMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("im-yahoo"), QIcon::fromTheme(QLatin1String("edit-find"))));
1127
1128         // Update the search engine menu action text.
1129         searchEngineMenuActionPointer->setText(i18nc("The main search engine menu action", "Search Engine - Yahoo"));
1130     }
1131     else  // Custom search engine.
1132     {
1133         // Check the user agent.
1134         searchEngineCustomActionPointer->setChecked(true);
1135
1136         // Update the search engine menu action icon.
1137         searchEngineMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
1138
1139         // Update the search engine menu action text.
1140         searchEngineMenuActionPointer->setText(i18nc("The main search engine menu action", "Search Engine - Custom"));
1141
1142         // Set the custom search engine text.
1143         searchEngineCustomActionPointer->setText(searchEngine);
1144
1145         // Set the custom search engine flag.
1146         customSearchEngine = true;
1147     }
1148
1149     // Update the custom search engine enabled boolean.
1150     if (updateCustomSearchEngineStatus)
1151         customSearchEngineEnabled = customSearchEngine;
1152
1153     // Format the custom search engine.
1154     if (customSearchEngineEnabled)
1155     {
1156         // Enable the custom search engine.
1157         searchEngineCustomActionPointer->setEnabled(true);
1158     }
1159     else
1160     {
1161         // Disable the custom search engine.
1162         searchEngineCustomActionPointer->setEnabled(false);
1163
1164         // Reset the custom search engine text.
1165         searchEngineCustomActionPointer->setText(i18nc("@action", "Custom"));
1166     }
1167 }
1168
1169 void BrowserWindow::updateUserAgentActions(const QString &userAgent, const bool &updateCustomUserAgentStatus)
1170 {
1171     // Initialize the custom user agent flag.
1172     bool customUserAgent = false;
1173
1174     // Check the indicated on-the-fly user agent.
1175     if (userAgent == UserAgentHelper::PRIVACY_BROWSER_USER_AGENT)  // Privacy Browser.
1176     {
1177         // Check the Privacy Browser user agent action.
1178         userAgentPrivacyBrowserActionPointer->setChecked(true);
1179
1180         // Update the user agent menu action icon.
1181         userAgentMenuActionPointer->setIcon(QIcon(":/icons/privacy-mode.svg"));
1182
1183         // Update the user agent menu action text.
1184         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Privacy Browser"));
1185     }
1186     else if (userAgent == TabWidget::webEngineDefaultUserAgent)  // WebEngine default.
1187     {
1188         // check the WebEngine default user agent action.
1189         userAgentWebEngineDefaultActionPointer->setChecked(true);
1190
1191         // Update the user agent menu action icon.
1192         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("qtlogo"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new")))));
1193
1194         // Update the user agent menu action text.
1195         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - WebEngine default"));
1196     }
1197     else if (userAgent == UserAgentHelper::FIREFOX_LINUX_USER_AGENT)  // Firefox on Linux.
1198     {
1199         // Check the Firefox on Linux user agent action.
1200         userAgentFirefoxLinuxActionPointer->setChecked(true);
1201
1202         // Update the user agent menu action icon.
1203         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("firefox-esr"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new")))));
1204
1205         // Update the user agent menu action text.
1206         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Firefox on Linux"));
1207     }
1208     else if (userAgent == UserAgentHelper::CHROMIUM_LINUX_USER_AGENT)  // Chromium on Linux.
1209     {
1210         // Check the Chromium on Linux user agent action.
1211         userAgentChromiumLinuxActionPointer->setChecked(true);
1212
1213         // Update the user agent menu action icon.
1214         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("chromium"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new")))));
1215
1216         // Update the user agent menu action text.
1217         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Chromium on Linux"));
1218     }
1219     else if (userAgent == UserAgentHelper::FIREFOX_WINDOWS_USER_AGENT)  // Firefox on Windows.
1220     {
1221         // Check the Firefox on Windows user agent action.
1222         userAgentFirefoxWindowsActionPointer->setChecked(true);
1223
1224         // Update the user agent menu action icon.
1225         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("firefox-esr"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new")))));
1226
1227         // Update the user agent menu action text.
1228         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Firefox on Windows"));
1229     }
1230     else if (userAgent == UserAgentHelper::CHROME_WINDOWS_USER_AGENT)  // Chrome on Windows.
1231     {
1232         // Check the Chrome on Windows user agent action.
1233         userAgentChromeWindowsActionPointer->setChecked(true);
1234
1235         // Update the user agent menu action icon.
1236         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("chromium"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new")))));
1237
1238         // Update the user agent menu action text.
1239         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Chrome on Windows"));
1240     }
1241     else if (userAgent == UserAgentHelper::EDGE_WINDOWS_USER_AGENT)  // Edge on Windows.
1242     {
1243         // Check the Edge on Windows user agent action.
1244         userAgentEdgeWindowsActionPointer->setChecked(true);
1245
1246         // Update the user agent menu action icon.
1247         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new"))));
1248
1249         // Update the user agent menu action text.
1250         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Edge on Windows"));
1251     }
1252     else if (userAgent == UserAgentHelper::SAFARI_MACOS_USER_AGENT)  // Safari on macOS.
1253     {
1254         // Check the Safari on macOS user agent action.
1255         userAgentSafariMacosActionPointer->setChecked(true);
1256
1257         // Update the user agent menu action icon.
1258         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new"))));
1259
1260         // Update the user agent menu action text.
1261         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Safari on macOS"));
1262     }
1263     else  // Custom user agent.
1264     {
1265         // Check the user agent.
1266         userAgentCustomActionPointer->setChecked(true);
1267
1268         // Update the user agent menu action icon.
1269         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new"))));
1270
1271         // Update the user agent menu action text.
1272         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Custom"));
1273
1274         // Set the custom user agent text.
1275         userAgentCustomActionPointer->setText(userAgent);
1276
1277         // Set the custom user agent flag.
1278         customUserAgent = true;
1279     }
1280
1281     // Update the custom user agent enabled boolean.
1282     // 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.
1283     if (updateCustomUserAgentStatus)
1284         customUserAgentEnabled = customUserAgent;
1285
1286
1287     // Format the custom user agent.
1288     if (customUserAgentEnabled)
1289     {
1290         // Enable the custom user agent.
1291         userAgentCustomActionPointer->setEnabled(true);
1292     }
1293     else
1294     {
1295         // Disable the custom user agent.
1296         userAgentCustomActionPointer->setEnabled(false);
1297
1298         // Reset the custom user agent text.
1299         userAgentCustomActionPointer->setText(i18nc("@action", "Custom"));
1300     }
1301 }
1302
1303 void BrowserWindow::updateZoomFactorAction(const double &zoomFactor)
1304 {
1305     // Set the current zoom factor.
1306     currentZoomFactor = zoomFactor;
1307
1308     // Update the zoom factor action text, formatting the double with 2 decimal places.
1309     zoomFactorActionPointer->setText(ki18nc("@action", "Zoom Factor - %1").subs(zoomFactor, 0, '0', 2).toString());
1310 }
1311
1312 void BrowserWindow::updateSearchEngineLabel(const QString &searchEngineString) const
1313 {
1314     // Update the search engine label.
1315     searchEngineLabelPointer->setText(SearchEngineHelper::getSearchUrl(searchEngineString));
1316 }
1317
1318 void BrowserWindow::updateUrlLineEdit(const QUrl &newUrl)
1319 {
1320     // Update the URL line edit if it does not have focus.
1321     if (!urlLineEditPointer->hasFocus())
1322     {
1323         // Get the new URL string.
1324         QString newUrlString = newUrl.toString();
1325
1326         // Update the URL line edit.
1327         urlLineEditPointer->setText(newUrlString);
1328
1329         // Set the focus if the new URL is blank.
1330         if (newUrlString == QStringLiteral(""))
1331             urlLineEditPointer->setFocus();
1332     }
1333
1334     // Store the current URL.
1335     currentUrl = newUrl;
1336 }
1337
1338 void BrowserWindow::updateUserAgentLabel(const QString &userAgentDatabaseName) const
1339 {
1340     // Update the user agent label.
1341     userAgentLabelPointer->setText(UserAgentHelper::getUserAgentFromDatabaseName(userAgentDatabaseName));
1342 }
1343
1344 void BrowserWindow::updateWindowTitle(const QString &title)
1345 {
1346     // Update the window title.
1347     setWindowTitle(title);
1348 }