]> gitweb.stoutner.com Git - PrivacyBrowserPC.git/blob - src/windows/BrowserWindow.cpp
Add an stop action. https://redmine.stoutner.com/issues/1141
[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 "databases/BookmarksDatabase.h"
27 #include "dialogs/AddBookmarkDialog.h"
28 #include "dialogs/AddFolderDialog.h"
29 #include "dialogs/BookmarksDialog.h"
30 #include "dialogs/CookiesDialog.h"
31 #include "dialogs/DomainSettingsDialog.h"
32 #include "dialogs/EditBookmarkDialog.h"
33 #include "dialogs/EditFolderDialog.h"
34 #include "helpers/SearchEngineHelper.h"
35 #include "helpers/UserAgentHelper.h"
36 #include "structs/BookmarkStruct.h"
37
38 // KDE Frameworks headers.
39 #include <KActionCollection>
40 #include <KColorScheme>
41 #include <KXMLGUIFactory>
42
43 // Qt toolkit headers.
44 #include <QClipboard>
45 #include <QContextMenuEvent>
46 #include <QDBusConnection>
47 #include <QDBusConnectionInterface>
48 #include <QDBusMessage>
49 #include <QFileDialog>
50 #include <QInputDialog>
51 #include <QNetworkCookie>
52 #include <QMenuBar>
53 #include <QMessageBox>
54 #include <QShortcut>
55 #include <QStatusBar>
56 #include <QWebEngineFindTextResult>
57
58 // Construct the class.
59 BrowserWindow::BrowserWindow(bool firstWindow, QString *initialUrlStringPointer) : KXmlGuiWindow()
60 {
61     // Initialize the variables.
62     javaScriptEnabled = false;
63     localStorageEnabled = false;
64
65     // Instantiate the privacy tab widget pointer.
66     tabWidgetPointer = new TabWidget(this);
67
68     // Set the privacy tab widget as the central widget.
69     setCentralWidget(tabWidgetPointer);
70
71     // Get a handle for the action collection.
72     actionCollectionPointer = this->actionCollection();
73
74     // Add the standard actions.
75     KStandardAction::print(tabWidgetPointer, SLOT(print()), actionCollectionPointer);
76     QAction *printPreviewActionPointer = KStandardAction::printPreview(tabWidgetPointer, SLOT(printPreview()), actionCollectionPointer);
77     KStandardAction::quit(qApp, SLOT(closeAllWindows()), actionCollectionPointer);
78     zoomInActionPointer = KStandardAction::zoomIn(this, SLOT(incrementZoom()), actionCollectionPointer);
79     zoomOutActionPointer = KStandardAction::zoomOut(this, SLOT(decrementZoom()), actionCollectionPointer);
80     refreshActionPointer = KStandardAction::redisplay(this, SLOT(refresh()), actionCollectionPointer);
81     fullScreenActionPointer = KStandardAction::fullScreen(this, SLOT(toggleFullScreen()), this, actionCollectionPointer);
82     QAction *backActionPointer = KStandardAction::back(this, SLOT(back()), actionCollectionPointer);
83     QAction *forwardActionPointer = KStandardAction::forward(this, SLOT(forward()), actionCollectionPointer);
84     KStandardAction::home(this, SLOT(home()), actionCollectionPointer);
85     QAction *editBookmarksActionPointer = KStandardAction::editBookmarks(this, SLOT(editBookmarks()), actionCollectionPointer);
86     KStandardAction::preferences(this, SLOT(showSettingsDialog()), actionCollectionPointer);
87     KStandardAction::find(this, SLOT(showFindTextActions()), actionCollectionPointer);
88     findNextActionPointer = KStandardAction::findNext(this, SLOT(findNext()), actionCollectionPointer);
89     findPreviousActionPointer = KStandardAction::findPrev(this, SLOT(findPrevious()), actionCollectionPointer);
90
91     // Add the custom actions.
92     QAction *newTabActionPointer = actionCollectionPointer->addAction(QLatin1String("new_tab"));
93     QAction *newWindowActionPointer = actionCollectionPointer->addAction(QLatin1String("new_window"));
94     QAction *saveArchiveActionPointer = actionCollectionPointer->addAction(QLatin1String("save_archive"));
95     zoomDefaultActionPointer = actionCollectionPointer->addAction(QLatin1String("zoom_default"));
96     QAction *reloadAndBypassCacheActionPointer = actionCollectionPointer->addAction(QLatin1String("reload_and_bypass_cache"));
97     stopActionPointer = actionCollectionPointer->addAction(QLatin1String("stop"));
98     viewSourceActionPointer = actionCollectionPointer->addAction(QLatin1String("view_source"));
99     viewSourceInNewTabActionPointer = actionCollectionPointer->addAction(QLatin1String("view_source_in_new_tab"));
100     developerToolsActionPointer = actionCollectionPointer->addAction(QLatin1String("developer_tools"));
101     javaScriptActionPointer = actionCollectionPointer->addAction(QLatin1String("javascript"));
102     localStorageActionPointer = actionCollectionPointer->addAction(QLatin1String("local_storage"));
103     domStorageActionPointer = actionCollectionPointer->addAction(QLatin1String("dom_storage"));
104     userAgentPrivacyBrowserActionPointer = actionCollectionPointer->addAction(QLatin1String("user_agent_privacy_browser"));
105     userAgentWebEngineDefaultActionPointer = actionCollectionPointer->addAction(QLatin1String("user_agent_webengine_default"));
106     userAgentFirefoxLinuxActionPointer = actionCollectionPointer->addAction(QLatin1String("user_agent_firefox_linux"));
107     userAgentChromiumLinuxActionPointer = actionCollectionPointer->addAction(QLatin1String("user_agent_chromium_linux"));
108     userAgentFirefoxWindowsActionPointer = actionCollectionPointer->addAction(QLatin1String("user_agent_firefox_windows"));
109     userAgentChromeWindowsActionPointer = actionCollectionPointer->addAction(QLatin1String("user_agent_chrome_windows"));
110     userAgentEdgeWindowsActionPointer = actionCollectionPointer->addAction(QLatin1String("user_agent_edge_windows"));
111     userAgentSafariMacosActionPointer = actionCollectionPointer->addAction(QLatin1String("user_agent_safari_macos"));
112     userAgentCustomActionPointer = actionCollectionPointer->addAction(QLatin1String("user_agent_custom"));
113     zoomFactorActionPointer = actionCollectionPointer->addAction(QLatin1String("zoom_factor"));
114     searchEngineMojeekActionPointer = actionCollectionPointer->addAction(QLatin1String("search_engine_mojeek"));
115     searchEngineMonoclesActionPointer = actionCollectionPointer->addAction(QLatin1String("search_engine_monocles"));
116     searchEngineMetagerActionPointer = actionCollectionPointer->addAction(QLatin1String("search_engine_metager"));
117     searchEngineGoogleActionPointer = actionCollectionPointer->addAction(QLatin1String("search_engine_google"));
118     searchEngineBingActionPointer = actionCollectionPointer->addAction(QLatin1String("search_engine_bing"));
119     searchEngineYahooActionPointer = actionCollectionPointer->addAction(QLatin1String("search_engine_yahoo"));
120     searchEngineCustomActionPointer = actionCollectionPointer->addAction(QLatin1String("search_engine_custom"));
121     viewBookmarksToolBarActionPointer = actionCollectionPointer->addAction(QLatin1String("view_bookmarks_toolbar"));
122     QAction *domainSettingsActionPointer = actionCollectionPointer->addAction(QLatin1String("domain_settings"));
123     cookiesActionPointer = actionCollectionPointer->addAction(QLatin1String("cookies"));
124     findCaseSensitiveActionPointer = actionCollectionPointer->addAction(QLatin1String("find_case_sensitive"));
125     hideFindTextActionPointer = actionCollectionPointer->addAction(QLatin1String("hide_find_actions"));
126
127     // Create the action groups
128     QActionGroup *userAgentActionGroupPointer = new QActionGroup(this);
129     QActionGroup *searchEngineActionGroupPointer = new QActionGroup(this);
130
131     // Add the actions to the groups.
132     userAgentActionGroupPointer->addAction(userAgentPrivacyBrowserActionPointer);
133     userAgentActionGroupPointer->addAction(userAgentWebEngineDefaultActionPointer);
134     userAgentActionGroupPointer->addAction(userAgentFirefoxLinuxActionPointer);
135     userAgentActionGroupPointer->addAction(userAgentChromiumLinuxActionPointer);
136     userAgentActionGroupPointer->addAction(userAgentFirefoxWindowsActionPointer);
137     userAgentActionGroupPointer->addAction(userAgentChromeWindowsActionPointer);
138     userAgentActionGroupPointer->addAction(userAgentEdgeWindowsActionPointer);
139     userAgentActionGroupPointer->addAction(userAgentSafariMacosActionPointer);
140     userAgentActionGroupPointer->addAction(userAgentCustomActionPointer);
141     searchEngineActionGroupPointer->addAction(searchEngineMojeekActionPointer);
142     searchEngineActionGroupPointer->addAction(searchEngineMonoclesActionPointer);
143     searchEngineActionGroupPointer->addAction(searchEngineMetagerActionPointer);
144     searchEngineActionGroupPointer->addAction(searchEngineGoogleActionPointer);
145     searchEngineActionGroupPointer->addAction(searchEngineBingActionPointer);
146     searchEngineActionGroupPointer->addAction(searchEngineYahooActionPointer);
147     searchEngineActionGroupPointer->addAction(searchEngineCustomActionPointer);
148
149     // Set some actions to be checkable.
150     javaScriptActionPointer->setCheckable(true);
151     localStorageActionPointer->setCheckable(true);
152     domStorageActionPointer->setCheckable(true);
153     findCaseSensitiveActionPointer->setCheckable(true);
154     viewSourceActionPointer->setCheckable(true);
155     developerToolsActionPointer->setCheckable(true);
156     userAgentPrivacyBrowserActionPointer->setCheckable(true);
157     userAgentWebEngineDefaultActionPointer->setCheckable(true);
158     userAgentFirefoxLinuxActionPointer->setCheckable(true);
159     userAgentChromiumLinuxActionPointer->setCheckable(true);
160     userAgentFirefoxWindowsActionPointer->setCheckable(true);
161     userAgentChromeWindowsActionPointer->setCheckable(true);
162     userAgentEdgeWindowsActionPointer->setCheckable(true);
163     userAgentSafariMacosActionPointer->setCheckable(true);
164     userAgentCustomActionPointer->setCheckable(true);
165     searchEngineMojeekActionPointer->setCheckable(true);
166     searchEngineMonoclesActionPointer->setCheckable(true);
167     searchEngineMetagerActionPointer->setCheckable(true);
168     searchEngineGoogleActionPointer->setCheckable(true);
169     searchEngineBingActionPointer->setCheckable(true);
170     searchEngineYahooActionPointer->setCheckable(true);
171     searchEngineCustomActionPointer->setCheckable(true);
172     viewBookmarksToolBarActionPointer->setCheckable(true);
173
174     // Instantiate the user agent helper.
175     UserAgentHelper *userAgentHelperPointer = new UserAgentHelper();
176
177     // Set the action text.
178     newTabActionPointer->setText(i18nc("New tab action", "New Tab"));
179     newWindowActionPointer->setText(i18nc("New window action", "New Window"));
180     saveArchiveActionPointer->setText(i18nc("Save archive action", "Save Archive"));
181     zoomDefaultActionPointer->setText(i18nc("Zoom default action", "Zoom Default"));
182     reloadAndBypassCacheActionPointer->setText(i18nc("Reload and bypass cache action", "Reload and Bypass Cache"));
183     stopActionPointer->setText(i18nc("Stop action", "Stop"));
184     viewSourceActionPointer->setText(i18nc("View source action", "View Source"));
185     viewSourceInNewTabActionPointer->setText(i18nc("View source in new tab action", "View Source in New Tab"));
186     developerToolsActionPointer->setText(i18nc("Developer tools action", "Developer Tools"));
187     javaScriptActionPointer->setText(i18nc("JavaScript action", "JavaScript"));
188     localStorageActionPointer->setText(i18nc("The Local Storage action", "Local Storage"));
189     domStorageActionPointer->setText(i18nc("DOM Storage action", "DOM Storage"));
190     userAgentPrivacyBrowserActionPointer->setText(userAgentHelperPointer->PRIVACY_BROWSER_TRANSLATED);
191     userAgentWebEngineDefaultActionPointer->setText(userAgentHelperPointer->WEB_ENGINE_DEFAULT_TRANSLATED);
192     userAgentFirefoxLinuxActionPointer->setText(userAgentHelperPointer->FIREFOX_LINUX_TRANSLATED);
193     userAgentChromiumLinuxActionPointer->setText(userAgentHelperPointer->CHROMIUM_LINUX_TRANSLATED);
194     userAgentFirefoxWindowsActionPointer->setText(userAgentHelperPointer->FIREFOX_WINDOWS_TRANSLATED);
195     userAgentChromeWindowsActionPointer->setText(userAgentHelperPointer->CHROME_WINDOWS_TRANSLATED);
196     userAgentEdgeWindowsActionPointer->setText(userAgentHelperPointer->EDGE_WINDOWS_TRANSLATED);
197     userAgentSafariMacosActionPointer->setText(userAgentHelperPointer->SAFARI_MACOS_TRANSLATED);
198     searchEngineMojeekActionPointer->setText(i18nc("Search engine", "Mojeek"));
199     searchEngineMonoclesActionPointer->setText(i18nc("Search engine", "Monocles"));
200     searchEngineMetagerActionPointer->setText(i18nc("Search engine", "MetaGer"));
201     searchEngineGoogleActionPointer->setText(i18nc("Search engine", "Google"));
202     searchEngineBingActionPointer->setText(i18nc("Search engine", "Bing"));
203     searchEngineYahooActionPointer->setText(i18nc("Search engine", "Yahoo"));
204     viewBookmarksToolBarActionPointer->setText(i18nc("View bookmarks toolbar", "View Bookmarks Toolbar"));
205     domainSettingsActionPointer->setText(i18nc("Domain Settings action", "Domain Settings"));
206     cookiesActionPointer->setText(i18nc("The Cookies action, which also displays the number of cookies", "Cookies - %1", 0));
207     findCaseSensitiveActionPointer->setText(i18nc("Find Case Sensitive action", "Find Case Sensitive"));
208     hideFindTextActionPointer->setText(i18nc("Hide Find Text action (the text should include the language-specific escape keyboard shortcut).", "Hide Find Text (Esc)"));
209
210     // Set the action icons.  Gnome doesn't contain some of the icons that KDE has.
211     // The toolbar icons don't pick up unless the size is explicit, probably because the toolbar ends up being an intermediate size.
212     newTabActionPointer->setIcon(QIcon::fromTheme(QLatin1String("tab-new")));
213     newWindowActionPointer->setIcon(QIcon::fromTheme(QLatin1String("window-new")));
214     saveArchiveActionPointer->setIcon(QIcon::fromTheme(QLatin1String("document-save")));
215     zoomDefaultActionPointer->setIcon(QIcon::fromTheme(QLatin1String("zoom-fit-best")));
216     reloadAndBypassCacheActionPointer->setIcon(QIcon::fromTheme(QLatin1String("view-refresh")));
217     stopActionPointer->setIcon(QIcon::fromTheme(QLatin1String("process-stop")));
218     viewSourceActionPointer->setIcon(QIcon::fromTheme(QLatin1String("view-choose"), QIcon::fromTheme(QLatin1String("accessories-text-editor"))));
219     viewSourceInNewTabActionPointer->setIcon(QIcon::fromTheme(QLatin1String("view-choose"), QIcon::fromTheme(QLatin1String("accessories-text-editor"))));
220     developerToolsActionPointer->setIcon(QIcon::fromTheme(QLatin1String("add-subtitle"), QIcon::fromTheme("system-run")));
221     domStorageActionPointer->setIcon(QIcon::fromTheme(QLatin1String("code-class"), QIcon(QLatin1String("/usr/share/icons/gnome/32x32/actions/gtk-unindent-ltr.png"))));
222     userAgentPrivacyBrowserActionPointer->setIcon(QIcon(QLatin1String(":/icons/privacy-mode.svg")));
223     userAgentWebEngineDefaultActionPointer->setIcon(QIcon::fromTheme(QLatin1String("qtlogo"), QIcon::fromTheme(QLatin1String("user-group-properties"),
224                                                                                                                QIcon::fromTheme(QLatin1String("contact-new")))));
225     userAgentFirefoxLinuxActionPointer->setIcon(QIcon::fromTheme(QLatin1String("firefox-esr"), QIcon::fromTheme(QLatin1String("user-group-properties"),
226                                                                                                                 QIcon::fromTheme(QLatin1String("contact-new")))));
227     userAgentChromiumLinuxActionPointer->setIcon(QIcon::fromTheme(QLatin1String("chromium"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new")))));
228     userAgentFirefoxWindowsActionPointer->setIcon(QIcon::fromTheme(QLatin1String("firefox-esr"), QIcon::fromTheme(QLatin1String("user-group-properties"),
229                                                                                                                   QIcon::fromTheme(QLatin1String("contact-new")))));
230     userAgentChromeWindowsActionPointer->setIcon(QIcon::fromTheme(QLatin1String("chromium"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new")))));
231     userAgentEdgeWindowsActionPointer->setIcon(QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new"))));
232     userAgentSafariMacosActionPointer->setIcon(QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new"))));
233     userAgentCustomActionPointer->setIcon(QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new"))));
234     searchEngineMojeekActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
235     searchEngineMonoclesActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
236     searchEngineMetagerActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
237     searchEngineGoogleActionPointer->setIcon(QIcon::fromTheme(QLatin1String("im-google"), QIcon::fromTheme(QLatin1String("edit-find"))));
238     searchEngineBingActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
239     searchEngineYahooActionPointer->setIcon(QIcon::fromTheme(QLatin1String("im-yahoo"), QIcon::fromTheme(QLatin1String("edit-find"))));
240     searchEngineCustomActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
241     zoomFactorActionPointer->setIcon(QIcon::fromTheme(QLatin1String("zoom-fit-best")));
242     editBookmarksActionPointer->setIcon(QIcon::fromTheme(QLatin1String("bookmark-edit"), QIcon::fromTheme(QLatin1String("bookmark-new"))));
243     viewBookmarksToolBarActionPointer->setIcon(QIcon::fromTheme(QLatin1String("bookmarks"), QIcon::fromTheme(QLatin1String("bookmark-new"))));
244     domainSettingsActionPointer->setIcon(QIcon::fromTheme(QLatin1String("settings-configure"), QIcon::fromTheme(QLatin1String("preferences-desktop"))));
245     cookiesActionPointer->setIcon(QIcon::fromTheme(QLatin1String("preferences-web-browser-cookies"), QIcon::fromTheme(QLatin1String("appointment-new"))));
246     findCaseSensitiveActionPointer->setIcon(QIcon::fromTheme(QLatin1String("format-text-lowercase"), QIcon::fromTheme(QLatin1String("/usr/share/icons/gnome/32x32/apps/fonts.png"))));
247     hideFindTextActionPointer->setIcon(QIcon::fromTheme(QLatin1String("window-close-symbolic")));
248
249     // Create the key sequences.
250     QKeySequence ctrlTKeySequence = QKeySequence(i18nc("The open new tab key sequence.", "Ctrl+T"));
251     QKeySequence ctrlNKeySequence = QKeySequence(i18nc("The open new window key sequence.", "Ctrl+N"));
252     QKeySequence ctrlAKeySequence = QKeySequence(i18nc("The save archive key sequence.", "Ctrl+A"));
253     QKeySequence ctrl0KeySequence = QKeySequence(i18nc("The zoom default key sequence.", "Ctrl+0"));
254     QKeySequence ctrlF5KeySequence = QKeySequence(i18nc("The reload and bypass cache key sequence.", "Ctrl+F5"));
255     QKeySequence ctrlShiftXKeySequence = QKeySequence(i18nc("The stop key sequence.", "Ctrl+Shift+X"));
256     QKeySequence ctrlUKeySequence = QKeySequence(i18nc("The view source key sequence.", "Ctrl+U"));
257     QKeySequence ctrlShiftUKeySequence = QKeySequence(i18nc("The view source in new tab key sequence.", "Ctrl+Shift+U"));
258     QKeySequence f12KeySequence = QKeySequence(i18nc("The developer tools key sequence.", "F12"));
259     QKeySequence ctrlShiftPKeySequence = QKeySequence(i18nc("The print preview key sequence.", "Ctrl+Shift+P"));
260     QKeySequence ctrlJKeySequence = QKeySequence(i18nc("The JavaScript key sequence.", "Ctrl+J"));
261     QKeySequence ctrlLKeySequence = QKeySequence(i18nc("The local storage key sequence.", "Ctrl+L"));
262     QKeySequence ctrlDKeySequence = QKeySequence(i18nc("The DOM storage key sequence.", "Ctrl+D"));
263     QKeySequence ctrlSKeySequence = QKeySequence(i18nc("The find case sensitive key sequence.", "Ctrl+S"));
264     QKeySequence ctrlAltPKeySequence = QKeySequence(i18nc("The Privacy Browser user agent key sequence.", "Ctrl+Alt+P"));
265     QKeySequence ctrlAltWKeySequence = QKeySequence(i18nc("The WebEngine Default user agent key sequence.", "Ctrl+Alt+W"));
266     QKeySequence ctrlAltFKeySequence = QKeySequence(i18nc("The Firefox on Linux user agent key sequence.", "Ctrl+Alt+F"));
267     QKeySequence ctrlAltCKeySequence = QKeySequence(i18nc("The Chromium on Linux user agent key sequence.", "Ctrl+Alt+C"));
268     QKeySequence ctrlAltShiftFKeySequence = QKeySequence(i18nc("The Firefox on Windows user agent key sequence.", "Ctrl+Alt+Shift+F"));
269     QKeySequence ctrlAltShiftCKeySequence = QKeySequence(i18nc("The Chrome on Windows user agent key sequence.", "Ctrl+Alt+Shift+C"));
270     QKeySequence ctrlAltEKeySequence = QKeySequence(i18nc("The Edge on Windows user agent key sequence.", "Ctrl+Alt+E"));
271     QKeySequence ctrlAltSKeySequence = QKeySequence(i18nc("The Safari on macOS user agent key sequence.", "Ctrl+Alt+S"));
272     QKeySequence altShiftCKeySequence = QKeySequence(i18nc("The custom user agent key sequence.", "Alt+Shift+C"));
273     QKeySequence ctrlAltZKeySequence = QKeySequence(i18nc("The zoom factor key sequence.", "Ctrl+Alt+Z"));
274     QKeySequence ctrlShiftMKeySequence = QKeySequence(i18nc("The Mojeek search engine key sequence.", "Ctrl+Shift+M"));
275     QKeySequence ctrlShiftOKeySequence = QKeySequence(i18nc("The Monocles search engine key sequence.", "Ctrl+Shift+O"));
276     QKeySequence ctrlShiftEKeySequence = QKeySequence(i18nc("The MetaGer search engine key sequence.", "Ctrl+Shift+E"));
277     QKeySequence ctrlShiftGKeySequence = QKeySequence(i18nc("The Google search engine key sequence.", "Ctrl+Shift+G"));
278     QKeySequence ctrlShiftBKeySequence = QKeySequence(i18nc("The Bing search engine key sequence.", "Ctrl+Shift+B"));
279     QKeySequence ctrlShiftYKeySequence = QKeySequence(i18nc("The Yahoo search engine key sequence.", "Ctrl+Shift+Y"));
280     QKeySequence ctrlShiftCKeySequence = QKeySequence(i18nc("The custom search engine key sequence.", "Ctrl+Shift+C"));
281     QKeySequence ctrlAltShiftBKeySequence = QKeySequence(i18nc("The edit bookmarks key sequence.", "Ctrl+Alt+Shift+B"));
282     QKeySequence ctrlAltBKeySequence = QKeySequence(i18nc("The view bookmarks toolbar key sequence.", "Ctrl+Alt+B"));
283     QKeySequence ctrlShiftDKeySequence = QKeySequence(i18nc("The domain settings key sequence.", "Ctrl+Shift+D"));
284     QKeySequence ctrlSemicolonKeySequence = QKeySequence(i18nc("The cookies dialog key sequence.", "Ctrl+;"));
285
286     // Set the action key sequences.
287     actionCollectionPointer->setDefaultShortcut(newTabActionPointer, ctrlTKeySequence);
288     actionCollectionPointer->setDefaultShortcut(newWindowActionPointer, ctrlNKeySequence);
289     actionCollectionPointer->setDefaultShortcut(saveArchiveActionPointer, ctrlAKeySequence);
290     actionCollectionPointer->setDefaultShortcut(zoomDefaultActionPointer, ctrl0KeySequence);
291     actionCollectionPointer->setDefaultShortcut(reloadAndBypassCacheActionPointer, ctrlF5KeySequence);
292     actionCollectionPointer->setDefaultShortcut(stopActionPointer, ctrlShiftXKeySequence);
293     actionCollectionPointer->setDefaultShortcut(viewSourceActionPointer, ctrlUKeySequence);
294     actionCollectionPointer->setDefaultShortcut(viewSourceInNewTabActionPointer, ctrlShiftUKeySequence);
295     actionCollectionPointer->setDefaultShortcut(developerToolsActionPointer, f12KeySequence);
296     actionCollectionPointer->setDefaultShortcut(printPreviewActionPointer, ctrlShiftPKeySequence);
297     actionCollectionPointer->setDefaultShortcut(javaScriptActionPointer, ctrlJKeySequence);
298     actionCollectionPointer->setDefaultShortcut(localStorageActionPointer, ctrlLKeySequence);
299     actionCollectionPointer->setDefaultShortcut(domStorageActionPointer, ctrlDKeySequence);
300     actionCollectionPointer->setDefaultShortcut(findCaseSensitiveActionPointer, ctrlSKeySequence);
301     actionCollectionPointer->setDefaultShortcut(userAgentPrivacyBrowserActionPointer, ctrlAltPKeySequence);
302     actionCollectionPointer->setDefaultShortcut(userAgentWebEngineDefaultActionPointer, ctrlAltWKeySequence);
303     actionCollectionPointer->setDefaultShortcut(userAgentFirefoxLinuxActionPointer, ctrlAltFKeySequence);
304     actionCollectionPointer->setDefaultShortcut(userAgentChromiumLinuxActionPointer, ctrlAltCKeySequence);
305     actionCollectionPointer->setDefaultShortcut(userAgentFirefoxWindowsActionPointer, ctrlAltShiftFKeySequence);
306     actionCollectionPointer->setDefaultShortcut(userAgentChromeWindowsActionPointer, ctrlAltShiftCKeySequence);
307     actionCollectionPointer->setDefaultShortcut(userAgentEdgeWindowsActionPointer, ctrlAltEKeySequence);
308     actionCollectionPointer->setDefaultShortcut(userAgentSafariMacosActionPointer, ctrlAltSKeySequence);
309     actionCollectionPointer->setDefaultShortcut(userAgentCustomActionPointer, altShiftCKeySequence);
310     actionCollectionPointer->setDefaultShortcut(zoomFactorActionPointer, ctrlAltZKeySequence);
311     actionCollectionPointer->setDefaultShortcut(searchEngineMojeekActionPointer, ctrlShiftMKeySequence);
312     actionCollectionPointer->setDefaultShortcut(searchEngineMonoclesActionPointer, ctrlShiftOKeySequence);
313     actionCollectionPointer->setDefaultShortcut(searchEngineMetagerActionPointer, ctrlShiftEKeySequence);
314     actionCollectionPointer->setDefaultShortcut(searchEngineGoogleActionPointer, ctrlShiftGKeySequence);
315     actionCollectionPointer->setDefaultShortcut(searchEngineBingActionPointer, ctrlShiftBKeySequence);
316     actionCollectionPointer->setDefaultShortcut(searchEngineYahooActionPointer, ctrlShiftYKeySequence);
317     actionCollectionPointer->setDefaultShortcut(searchEngineCustomActionPointer, ctrlShiftCKeySequence);
318     actionCollectionPointer->setDefaultShortcut(editBookmarksActionPointer, ctrlAltShiftBKeySequence);
319     actionCollectionPointer->setDefaultShortcut(viewBookmarksToolBarActionPointer, ctrlAltBKeySequence);
320     actionCollectionPointer->setDefaultShortcut(domainSettingsActionPointer, ctrlShiftDKeySequence);
321     actionCollectionPointer->setDefaultShortcut(cookiesActionPointer, ctrlSemicolonKeySequence);
322
323     // Execute the actions.
324     connect(newTabActionPointer, SIGNAL(triggered()), tabWidgetPointer, SLOT(addTab()));
325     connect(newWindowActionPointer, SIGNAL(triggered()), this, SLOT(newWindow()));
326     connect(saveArchiveActionPointer, SIGNAL(triggered()), tabWidgetPointer, SLOT(saveArchive()));
327     connect(zoomDefaultActionPointer, SIGNAL(triggered()), this, SLOT(zoomDefault()));
328     connect(reloadAndBypassCacheActionPointer, SIGNAL(triggered()), this, SLOT(reloadAndBypassCache()));
329     connect(stopActionPointer, SIGNAL(triggered()), tabWidgetPointer, SLOT(stop()));
330     connect(viewSourceActionPointer, SIGNAL(triggered()), this, SLOT(toggleViewSource()));
331     connect(viewSourceInNewTabActionPointer, SIGNAL(triggered()), this, SLOT(toggleViewSourceInNewTab()));
332     connect(developerToolsActionPointer, SIGNAL(triggered()), this, SLOT(toggleDeveloperTools()));
333     connect(zoomFactorActionPointer, SIGNAL(triggered()), this, SLOT(getZoomFactorFromUser()));
334     connect(viewBookmarksToolBarActionPointer, SIGNAL(triggered()), this, SLOT(toggleViewBookmarksToolBar()));
335     connect(cookiesActionPointer, SIGNAL(triggered()), this, SLOT(showCookiesDialog()));
336     connect(domainSettingsActionPointer, SIGNAL(triggered()), this, SLOT(showDomainSettingsDialog()));
337
338     // Update the on-the-fly menus.
339     connect(tabWidgetPointer, SIGNAL(updateUserAgentActions(QString, bool)), this, SLOT(updateUserAgentActions(QString, bool)));
340     connect(tabWidgetPointer, SIGNAL(updateZoomActions(double)), this, SLOT(updateZoomActions(double)));
341     connect(tabWidgetPointer, SIGNAL(updateSearchEngineActions(QString, bool)), this, SLOT(updateSearchEngineActions(QString, bool)));
342
343     // Apply the on-the-fly settings when selected.
344     connect(userAgentActionGroupPointer, SIGNAL(triggered(QAction*)), tabWidgetPointer, SLOT(applyOnTheFlyUserAgent(QAction*)));
345     connect(searchEngineActionGroupPointer, SIGNAL(triggered(QAction*)), tabWidgetPointer, SLOT(applyOnTheFlySearchEngine(QAction*)));
346
347     // Process cookie changes.
348     connect(tabWidgetPointer, SIGNAL(updateCookiesAction(int)), this, SLOT(updateCookiesAction(int)));
349
350     // Store the default zoom factor.
351     connect(tabWidgetPointer, SIGNAL(updateDefaultZoomFactor(double)), this, SLOT(updateDefaultZoomFactor(double)));
352
353     // Connect the URL toolbar actions.
354     connect(javaScriptActionPointer, SIGNAL(triggered()), this, SLOT(toggleJavaScript()));
355     connect(localStorageActionPointer, SIGNAL(triggered()), this, SLOT(toggleLocalStorage()));
356     connect(domStorageActionPointer, SIGNAL(triggered()), this, SLOT(toggleDomStorage()));
357
358     // Update the actions from the tab widget.
359     connect(tabWidgetPointer, SIGNAL(updateDeveloperToolsAction(bool)), developerToolsActionPointer, SLOT(setChecked(bool)));
360     connect(tabWidgetPointer, SIGNAL(updateBackAction(bool)), backActionPointer, SLOT(setEnabled(bool)));
361     connect(tabWidgetPointer, SIGNAL(updateForwardAction(bool)), forwardActionPointer, SLOT(setEnabled(bool)));
362     connect(tabWidgetPointer, SIGNAL(updateJavaScriptAction(bool)), this, SLOT(updateJavaScriptAction(bool)));
363     connect(tabWidgetPointer, SIGNAL(updateLocalStorageAction(bool)), this, SLOT(updateLocalStorageAction(bool)));
364     connect(tabWidgetPointer, SIGNAL(updateDomStorageAction(bool)), this, SLOT(updateDomStorageAction(bool)));
365
366     // Connect the find text actions.
367     connect(findCaseSensitiveActionPointer, SIGNAL(triggered()), this, SLOT(toggleFindCaseSensitive()));
368     connect(hideFindTextActionPointer, SIGNAL(triggered()), this, SLOT(hideFindTextActions()));
369
370
371
372     // Setup the GUI based on the browserwindowui.rc file.
373     setupGUI(StandardWindowOption::Default, ("browserwindowui.rc"));
374
375     // Get lists of the actions' associated widgets.
376     QList<QWidget*> userAgentAssociatedWidgetsPointerList = userAgentPrivacyBrowserActionPointer->associatedWidgets();
377     QList<QWidget*> searchEngineAssociatedWidgetsPointerList = searchEngineMojeekActionPointer->associatedWidgets();
378
379     // Get the menu widget pointers.  It is the second entry, after the main window.
380     QWidget *userAgentMenuWidgetPointer = userAgentAssociatedWidgetsPointerList[1];
381     QWidget *searchEngineMenuWidgetPointer = searchEngineAssociatedWidgetsPointerList[1];
382
383     // Get the menu pointers.
384     QMenu *userAgentMenuPointer = qobject_cast<QMenu*>(userAgentMenuWidgetPointer);
385     QMenu *searchEngineMenuPointer = qobject_cast<QMenu*>(searchEngineMenuWidgetPointer);
386
387     // Get the menu actions.
388     userAgentMenuActionPointer = userAgentMenuPointer->menuAction();
389     searchEngineMenuActionPointer = searchEngineMenuPointer->menuAction();
390
391     // Get handles for the toolbars.
392     navigationToolBarPointer = toolBar(QLatin1String("navigation_toolbar"));
393     urlToolBarPointer = toolBar(QLatin1String("url_toolbar"));
394     bookmarksToolBarPointer = toolBar(QLatin1String("bookmarks_toolbar"));
395
396     // Populate the view bookmarks toolbar checkbox.
397     connect(bookmarksToolBarPointer, SIGNAL(visibilityChanged(bool)), this, SLOT(updateViewBookmarksToolBarCheckbox(bool)));
398
399     // Create the line edits.
400     urlLineEditPointer = new KLineEdit();
401     findTextLineEditPointer = new KLineEdit();
402
403     // Get the line edit size policies.
404     QSizePolicy urlLineEditSizePolicy = urlLineEditPointer->sizePolicy();
405     QSizePolicy findTextLineEditSizePolicy = findTextLineEditPointer->sizePolicy();
406
407     // Set the URL line edit horizontal stretch to be five times the find text line edit stretch.
408     urlLineEditSizePolicy.setHorizontalStretch(5);
409     findTextLineEditSizePolicy.setHorizontalStretch(1);
410
411     // Set the policies.
412     urlLineEditPointer->setSizePolicy(urlLineEditSizePolicy);
413     findTextLineEditPointer->setSizePolicy(findTextLineEditSizePolicy);
414
415     // Set the widths.
416     urlLineEditPointer->setMinimumWidth(350);
417     findTextLineEditPointer->setMinimumWidth(200);
418     findTextLineEditPointer->setMaximumWidth(350);
419
420     // Set the place holder text.
421     urlLineEditPointer->setPlaceholderText(i18nc("The URL line edit placeholder text", "URL or Search Terms"));
422     findTextLineEditPointer->setPlaceholderText(i18nc("The find line edit placeholder text", "Find Text"));
423
424     // Show the clear button on the find line edit.
425     findTextLineEditPointer->setClearButtonEnabled(true);
426
427     // Add the actions to the URL line edit.
428     bookmarkedActionPointer = urlLineEditPointer->addAction(QIcon::fromTheme("non-starred-symbolic"), QLineEdit::LeadingPosition);
429     QAction *addOrEditDomainSettingsActionPointer = urlLineEditPointer->addAction(QIcon::fromTheme("settings-configure", QIcon::fromTheme(QLatin1String("preferences-desktop"))),
430                                                                                   QLineEdit::TrailingPosition);
431
432     // Set the bookmarked action pointer to be checkable.
433     bookmarkedActionPointer->setCheckable(true);
434
435     // Connect the URL line edit actions.
436     connect(bookmarkedActionPointer, SIGNAL(triggered()), this, SLOT(toggleBookmark()));
437     connect(addOrEditDomainSettingsActionPointer, SIGNAL(triggered()), this, SLOT(addOrEditDomainSettings()));
438
439     // Create a find text label pointer.
440     findTextLabelPointer = new QLabel();
441
442     // Set the default label text.
443     findTextLabelPointer->setText(QLatin1String("  ") + i18nc("Default find results.", "0/0") + QLatin1String("  "));
444
445     // Insert the widgets into the toolbars.
446     urlToolBarPointer->insertWidget(javaScriptActionPointer, urlLineEditPointer);
447     findTextLineEditActionPointer = urlToolBarPointer->insertWidget(findNextActionPointer, findTextLineEditPointer);
448     findTextLabelActionPointer = urlToolBarPointer->insertWidget(findNextActionPointer, findTextLabelPointer);
449
450     // Initially hide the find text actions.
451     hideFindTextActions();
452
453     // Load a new URL from the URL line edit.
454     connect(urlLineEditPointer, SIGNAL(returnKeyPressed(const QString)), this, SLOT(loadUrlFromLineEdit(const QString)));
455
456     // Find text as it is typed.
457     connect(findTextLineEditPointer, SIGNAL(textEdited(const QString &)), tabWidgetPointer, SLOT(findText(const QString &)));
458
459     // Find next if the enter key is pressed.
460     connect(findTextLineEditPointer, SIGNAL(returnKeyPressed(const QString &)), tabWidgetPointer, SLOT(findText(const QString &)));
461
462     // Update find text when switching tabs.
463     connect(tabWidgetPointer, SIGNAL(updateFindText(const QString &, const bool)), this, SLOT(updateFindText(const QString &, const bool)));
464
465     // Update the find text results.
466     connect(tabWidgetPointer, SIGNAL(updateFindTextResults(const QWebEngineFindTextResult &)), this, SLOT(updateFindTextResults(const QWebEngineFindTextResult &)));
467
468     // Update the URL line edit on page loads.
469     connect(tabWidgetPointer, SIGNAL(updateUrlLineEdit(QUrl)), this, SLOT(updateUrlLineEdit(QUrl)));
470
471     // Update the window title.
472     connect(tabWidgetPointer, SIGNAL(updateWindowTitle(const QString)), this, SLOT(updateWindowTitle(const QString)));
473
474     // Get a handle for the status bar.
475     QStatusBar *statusBarPointer = statusBar();
476
477     // Create the status bar widgets.
478     progressBarPointer = new QProgressBar();
479     zoomMinusButtonPointer = new QPushButton();
480     currentZoomButtonPointer = new QPushButton();
481     zoomPlusButtonPointer = new QPushButton();
482
483     // Set the button icons.
484     zoomMinusButtonPointer->setIcon(QIcon::fromTheme(QStringLiteral("list-remove-symbolic")));
485     zoomPlusButtonPointer->setIcon(QIcon::fromTheme(QStringLiteral("list-add-symbolic")));
486
487     // Set the button icons to be flat (no borders).
488     zoomMinusButtonPointer->setFlat(true);
489     currentZoomButtonPointer->setFlat(true);
490     zoomPlusButtonPointer->setFlat(true);
491
492     // Handle clicks on the zoom buttons.
493     connect(zoomMinusButtonPointer, SIGNAL(clicked()), this, SLOT(decrementZoom()));
494     connect(currentZoomButtonPointer, SIGNAL(clicked()), this, SLOT(getZoomFactorFromUser()));
495     connect(zoomPlusButtonPointer, SIGNAL(clicked()), this, SLOT(incrementZoom()));
496
497     // Remove the padding around the current zoom button text.
498     currentZoomButtonPointer->setStyleSheet("padding: 0px;");
499
500     // Add the widgets to the far right of the status bar.
501     statusBarPointer->addPermanentWidget(progressBarPointer);
502     statusBarPointer->addPermanentWidget(zoomMinusButtonPointer);
503     statusBarPointer->addPermanentWidget(currentZoomButtonPointer);
504     statusBarPointer->addPermanentWidget(zoomPlusButtonPointer);
505
506     // Update the status bar with the URL when a link is hovered.
507     connect(tabWidgetPointer, SIGNAL(linkHovered(QString)), statusBarPointer, SLOT(showMessage(QString)));
508
509     // Update the progress bar.
510     connect(tabWidgetPointer, SIGNAL(showProgressBar(const int)), this, SLOT(showProgressBar(const int)));
511     connect(tabWidgetPointer, SIGNAL(hideProgressBar()), this, SLOT(hideProgressBar()));
512
513     // Update the URL line edit focus.
514     connect(tabWidgetPointer, SIGNAL(clearUrlLineEditFocus()), this, SLOT(clearUrlLineEditFocus()));
515
516     // Get the URL line edit palettes.
517     normalBackgroundPalette = urlLineEditPointer->palette();
518     negativeBackgroundPalette = normalBackgroundPalette;
519     positiveBackgroundPalette = normalBackgroundPalette;
520
521     // Modify the palettes.
522     KColorScheme::adjustBackground(negativeBackgroundPalette, KColorScheme::NegativeBackground);
523     KColorScheme::adjustBackground(positiveBackgroundPalette, KColorScheme::PositiveBackground);
524
525     // Update the applied palette.
526     connect(tabWidgetPointer, SIGNAL(updateDomainSettingsIndicator(const bool)), this, SLOT(updateDomainSettingsIndicator(const bool)));
527
528     // Process full screen requests.
529     connect(tabWidgetPointer, SIGNAL(fullScreenRequested(bool)), this, SLOT(fullScreenRequested(bool)));
530
531     // Create keyboard shortcuts.
532     QShortcut *f11ShortcutPointer = new QShortcut(QKeySequence(i18nc("The toggle full screen shortcut.", "F11")), this);
533     QShortcut *escapeShortcutPointer = new QShortcut(QKeySequence::Cancel, this);
534
535     // Connect the keyboard shortcuts.
536     connect(f11ShortcutPointer, SIGNAL(activated()), fullScreenActionPointer, SLOT(trigger()));
537     connect(escapeShortcutPointer, SIGNAL(activated()), this, SLOT(escape()));
538
539     // Get a handle for the Bookmarks menu.
540     bookmarksMenuPointer = qobject_cast<QMenu*>(guiFactory()->container("bookmarks", this));
541
542     // Add a separator to the bookmarks menu.
543     bookmarksMenuPointer->addSeparator();
544
545     // Initialize the current bookmarks lists.
546     finalBookmarkFolderMenuActionList = QList<QPair<QMenu *, QAction *> *>();
547     bookmarksMenuActionList = QList<QPair<QMenu *, QAction *> *>();
548     bookmarksMenuSubmenuList = QList<QPair<QMenu *, QMenu *> *>();
549     bookmarksToolBarActionList = QList<QAction*>();
550     bookmarksToolBarSubfolderActionList = QList<QPair<QMenu *, QAction * > *>();
551
552     // Set the bookmarks toolbar context menu policy.
553     bookmarksToolBarPointer->setContextMenuPolicy(Qt::CustomContextMenu);
554
555     // Show the custom bookmark context menu when requested.
556     connect(bookmarksToolBarPointer, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showBookmarkContextMenu(const QPoint&)));
557
558     // Populate the bookmarks in this window.
559     populateBookmarksInThisWindow();
560
561     // Populate the UI.
562     // 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.
563     updateJavaScriptAction(Settings::javaScriptEnabled());
564     updateLocalStorageAction(Settings::localStorageEnabled());
565     updateDomStorageAction(Settings::domStorageEnabled());
566     updateUserAgentActions(UserAgentHelper::getUserAgentFromDatabaseName(Settings::userAgent()), true);
567     updateZoomActions(Settings::zoomFactor());
568
569     // Populate the first tab.
570     if (firstWindow)  // This is the first window.
571     {
572         // Load the initial website.
573         tabWidgetPointer->loadInitialWebsite();
574     }
575     else if (initialUrlStringPointer)  // An initial URL was specified.
576     {
577         // Load the initial URL.
578         tabWidgetPointer->loadUrlFromLineEdit(*initialUrlStringPointer);
579     }
580 }
581
582 void BrowserWindow::addFinalBookmarkFolderMenuActions(QMenu *menuPointer, double folderId)
583 {
584     // Get the database ID.
585     int folderDatabaseId = BookmarksDatabase::getFolderDatabaseId(folderId);
586
587     // Add a separator.
588     menuPointer->addSeparator();
589
590     // Add the add bookmark action to the menu.
591     QAction *addBookmarkActionPointer = menuPointer->addAction(QIcon::fromTheme(QLatin1String("bookmark-new")), i18nc("The add bookmark action", "Add Bookmark"), [=]
592         {
593             // Instantiate an add bookmark dialog.
594             AddBookmarkDialog *addBookmarkDialogPointer = new AddBookmarkDialog(tabWidgetPointer->getCurrentTabTitle(), tabWidgetPointer->getCurrentTabUrl(),
595                                                                                 tabWidgetPointer->getCurrentTabFavoritIcon(), folderId);
596
597             // Update the displayed bookmarks when a new one is added.
598             connect(addBookmarkDialogPointer, SIGNAL(bookmarkAdded()), this, SLOT(populateBookmarksInAllWindows()));
599
600             // Show the dialog.
601             addBookmarkDialogPointer->show();
602         }
603     );
604
605     // Add the add folder action to the menu.
606     QAction *addFolderActionPointer = menuPointer->addAction(QIcon::fromTheme(QLatin1String("folder-add")), i18nc("The add folder action", "Add Folder"), [=]
607         {
608             // Instantiate an add folder dialog.
609             AddFolderDialog *addFolderDialogPointer = new AddFolderDialog(tabWidgetPointer->getCurrentTabFavoritIcon(), folderId);
610
611             // Update the displayed bookmarks when a folder is added.
612             connect(addFolderDialogPointer, SIGNAL(folderAdded()), this, SLOT(populateBookmarksInAllWindows()));
613
614             // Show the dialog.
615             addFolderDialogPointer->show();
616         }
617     );
618
619     // Add a separator.
620     menuPointer->addSeparator();
621
622     // Add the open folder in new tabs action to the menu.
623     QAction *openFolderInNewTabsActionPointer = menuPointer->addAction(QIcon::fromTheme(QLatin1String("tab-new")), i18nc("The open folder in new tabs action", "Open Folder in New Tabs"), [=]
624         {
625             // Get all the folder URLs.
626             QList<QString> *folderUrlsListPointer = BookmarksDatabase::getAllFolderUrls(folderId);
627
628             // Open the URLs in new tabs.  `true` removes the URL line edit focus, `false` does not load a background tab.
629             for (QString url : *folderUrlsListPointer)
630                 tabWidgetPointer->addTab(true, false, url);
631         }
632     );
633
634     // Add the open folder in background tabs action to the menu.
635     QAction *openFolderInBackgroundTabsActionPointer = menuPointer->addAction(QIcon::fromTheme(QLatin1String("tab-new")),
636                                                                               i18nc("The open folder in background tabs action", "Open Folder in Background Tabs"), [=]
637         {
638             // Get all the folder URLs.
639             QList<QString> *folderUrlsListPointer = BookmarksDatabase::getAllFolderUrls(folderId);
640
641             // Open the URLs in new tabs.  `true` removes the URL line edit focus, `true` loads a background tab.
642             for (QString url : *folderUrlsListPointer)
643                 tabWidgetPointer->addTab(true, true, url);
644         }
645     );
646
647     // Add the open folder in new window action to the menu.
648     QAction *openFolderInNewWindowActionPointer = menuPointer->addAction(QIcon::fromTheme(QLatin1String("window-new")), i18nc("The open folder in new window action", "Open Folder in New Window"), [=]
649         {
650             // Get all the folder URLs.
651             QList<QString> *folderUrlsListPointer = BookmarksDatabase::getAllFolderUrls(folderId);
652
653             // Create a new browser window.
654             BrowserWindow *browserWindowPointer = new BrowserWindow(false, &folderUrlsListPointer->first());
655
656             // Get a count of the folder URLs.
657             const int folderUrls = folderUrlsListPointer->count();
658
659             // Load all the other URLs.  `true` removes the URL line edit focus, `true` loads a background tab.
660             for (int i = 1; i < folderUrls; ++i)
661                 browserWindowPointer->tabWidgetPointer->addTab(true, true, folderUrlsListPointer->value(i));
662
663             // Show the new browser window.
664             browserWindowPointer->show();
665         }
666     );
667
668     // Add a separator.
669     menuPointer->addSeparator();
670
671     // Add the edit folder action to the menu if this is not the root bookmark menu.
672     if (folderId != 0)
673     {
674         QAction *editFolderActionPointer = menuPointer->addAction(QIcon::fromTheme(QLatin1String("document-edit")), i18nc("The edit folder action", "Edit Folder"), [=]
675             {
676                 // Get the current tab favorite icon.
677                 QIcon currentTabFavoriteIcon = tabWidgetPointer->getCurrentTabFavoritIcon();
678
679                 // Instantiate an edit folder dialog.
680                 QDialog *editFolderDialogPointer = new EditFolderDialog(folderDatabaseId, currentTabFavoriteIcon);
681
682                 // Show the dialog.
683                 editFolderDialogPointer->show();
684
685                 // Process bookmark events.
686                 connect(editFolderDialogPointer, SIGNAL(folderSaved()), this, SLOT(populateBookmarksInAllWindows()));
687             }
688         );
689
690         // Add the action to the beginning of the final bookmark folder menu action list.
691         finalBookmarkFolderMenuActionList.prepend(new QPair<QMenu *, QAction *>(menuPointer, editFolderActionPointer));
692     }
693
694     // Add the delete folder action to the menu.
695     QAction *deleteFolderActionPointer = menuPointer->addAction(QIcon::fromTheme(QLatin1String("edit-delete")), i18nc("Delete folder context menu entry", "Delete Folder"), [=]
696         {
697             // Create an items to delete list.
698             QList<int>* itemsToDeleteListPointer = new QList<int>;
699
700             // Add the folder to the list of items to delete if it is not the root folder.
701             if (folderId != 0)
702                 itemsToDeleteListPointer->append(folderDatabaseId);
703
704             // Add the folder contents to the list of items to delete.
705             itemsToDeleteListPointer->append(*BookmarksDatabase::getFolderContentsDatabaseIdsRecursively(folderId));
706
707             // Instantiate a delete dialog message box.
708             QMessageBox deleteDialogMessageBox;
709
710             // Set the icon.
711             deleteDialogMessageBox.setIcon(QMessageBox::Warning);
712
713             // Set the window title.
714             deleteDialogMessageBox.setWindowTitle(i18nc("Delete bookmarks dialog title", "Delete Bookmarks"));
715
716             // Set the text.
717             deleteDialogMessageBox.setText(i18ncp("Delete bookmarks dialog main message", "Delete %1 bookmark item?", "Delete %1 bookmark items?", itemsToDeleteListPointer->count()));
718
719             // Set the informative text.
720             deleteDialogMessageBox.setInformativeText(i18nc("Delete bookmarks dialog secondary message", "This cannot be undone."));
721
722             // Set the standard buttons.
723             deleteDialogMessageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
724
725             // Set the default button.
726             deleteDialogMessageBox.setDefaultButton(QMessageBox::No);
727
728             // Display the dialog and capture the return value.
729             int returnValue = deleteDialogMessageBox.exec();
730
731             // Delete the domain if instructed.
732             if (returnValue == QMessageBox::Yes)
733             {
734                 // Get the parent folder ID.
735                 double parentFolderId = BookmarksDatabase::getParentFolderId(folderDatabaseId);
736
737                 // Delete the folder and its contents.
738                 for (const int databaseId : *itemsToDeleteListPointer)
739                     BookmarksDatabase::deleteBookmark(databaseId);
740
741                 // Update the display order of the bookmarks in the parent folder.
742                 BookmarksDatabase::updateFolderContentsDisplayOrder(parentFolderId);
743
744                 // Repopulate the bookmarks.
745                 populateBookmarksInAllWindows();
746             }
747         }
748     );
749
750     // Add the key sequences if this is the root bookmarks menu.
751     if (folderId == 0)
752     {
753         // Create the key sequences.
754         QKeySequence ctrlBKeySequence = QKeySequence(i18nc("The add bookmark key sequence.", "Ctrl+B"));
755         QKeySequence metaFKeySequence = QKeySequence(i18nc("The add folder key sequence.", "Meta+F"));
756
757         // Set the action key sequences.
758         actionCollectionPointer->setDefaultShortcut(addBookmarkActionPointer, ctrlBKeySequence);
759         actionCollectionPointer->setDefaultShortcut(addFolderActionPointer, metaFKeySequence);
760     }
761
762     // Add the actions to the beginning of the final bookmark folder menu action list.
763     finalBookmarkFolderMenuActionList.prepend(new QPair<QMenu *, QAction *>(menuPointer, addBookmarkActionPointer));
764     finalBookmarkFolderMenuActionList.prepend(new QPair<QMenu *, QAction *>(menuPointer, addFolderActionPointer));
765     finalBookmarkFolderMenuActionList.prepend(new QPair<QMenu *, QAction *>(menuPointer, openFolderInNewTabsActionPointer));
766     finalBookmarkFolderMenuActionList.prepend(new QPair<QMenu *, QAction *>(menuPointer, openFolderInBackgroundTabsActionPointer));
767     finalBookmarkFolderMenuActionList.prepend(new QPair<QMenu *, QAction *>(menuPointer, openFolderInNewWindowActionPointer));
768     finalBookmarkFolderMenuActionList.prepend(new QPair<QMenu *, QAction *>(menuPointer, deleteFolderActionPointer));
769 }
770
771 void BrowserWindow::addOrEditDomainSettings() const
772 {
773     // Remove the focus from the URL line edit.
774     urlLineEditPointer->clearFocus();
775
776     // Create the domain settings dialog pointer.
777     DomainSettingsDialog *domainSettingsDialogPointer;
778
779     // Get the current domain settings name.
780     QString &currentDomainSettingsName = tabWidgetPointer->getDomainSettingsName();
781
782     // Run the commands according to the current domain settings status.
783     if (currentDomainSettingsName == QStringLiteral(""))  // Domain settings are not currently applied.
784     {
785         // Instruct the domain settings dialog to add a new domain.
786         domainSettingsDialogPointer = new DomainSettingsDialog(DomainSettingsDialog::ADD_DOMAIN, currentUrl.host());
787     }
788     else  // Domain settings are currently applied.
789     {
790         // Instruct the domain settings dialog to edit the current domain.
791         domainSettingsDialogPointer = new DomainSettingsDialog(DomainSettingsDialog::EDIT_DOMAIN, currentDomainSettingsName);
792     }
793
794     // Reload the tabs when domain settings are updated.
795     connect(domainSettingsDialogPointer, SIGNAL(domainSettingsUpdated()), tabWidgetPointer, SLOT(applyDomainSettingsAndReload()));
796
797     // Show the dialog.
798     domainSettingsDialogPointer->show();
799 }
800
801 void BrowserWindow::back() const
802 {
803     // Remove the focus from the URL line edit.
804     urlLineEditPointer->clearFocus();
805
806     // Go back.
807     tabWidgetPointer->back();
808 }
809
810 void BrowserWindow::clearUrlLineEditFocus() const
811 {
812     // Remove the focus from the URL line edit.
813     urlLineEditPointer->clearFocus();
814 }
815
816 void BrowserWindow::decrementZoom()
817 {
818     // Update the current zoom factor.
819     currentZoomFactor = currentZoomFactor - 0.25;
820
821     // Check to make sure the zoom factor is in the valid range (0.25 to 5.00).
822     if (currentZoomFactor < 0.25)
823         currentZoomFactor = 0.25;
824
825     // Set the new zoom factor.
826     tabWidgetPointer->applyOnTheFlyZoomFactor(currentZoomFactor);
827
828     // Update the on-the-fly action text.
829     updateZoomActions(currentZoomFactor);
830 }
831
832 void BrowserWindow::editBookmarks() const
833 {
834     // Instantiate an edit bookmarks dialog.
835     BookmarksDialog *bookmarksDialogPointer = new BookmarksDialog(tabWidgetPointer->getCurrentTabTitle(), tabWidgetPointer->getCurrentTabUrl(), tabWidgetPointer->getCurrentTabFavoritIcon());
836
837     // Update the displayed bookmarks when edited.
838     connect(bookmarksDialogPointer, SIGNAL(bookmarkUpdated()), this, SLOT(populateBookmarksInAllWindows()));
839
840     // Show the dialog.
841     bookmarksDialogPointer->show();
842 }
843
844 void BrowserWindow::escape() const
845 {
846     // Process the escape according to the status of the browser.
847     if (fullScreenActionPointer->isChecked())  // Full screen browsing is enabled.
848     {
849         // Exit full screen browsing.
850         fullScreenActionPointer->trigger();
851     }
852     else if (!findTextLineEditPointer->text().isEmpty())  // Find text is populated.
853     {
854         // Clear the find text line edit.
855         findTextLineEditPointer->clear();
856
857         // Clear the search in the WebEngine.
858         tabWidgetPointer->findText(QStringLiteral(""));
859     }
860     else if (findTextLineEditActionPointer->isVisible())  // Find text actions are visible.
861     {
862         // Hide the find text actions.
863         hideFindTextActions();
864     }
865 }
866
867 void BrowserWindow::findNext() const
868 {
869     // Get the find string.
870     const QString findString = findTextLineEditPointer->text();
871
872     // Search for the text if it is not empty.
873     if (!findString.isEmpty())
874         tabWidgetPointer->findText(findString);
875 }
876
877 void BrowserWindow::findPrevious() const
878 {
879     // Get the find string.
880     const QString findString = findTextLineEditPointer->text();
881
882     // Search for the text if it is not empty.
883     if (!findString.isEmpty())
884         tabWidgetPointer->findPrevious(findString);
885 }
886
887 void BrowserWindow::forward() const
888 {
889     // Remove the focus from the URL line edit.
890     urlLineEditPointer->clearFocus();
891
892     // Go forward.
893     tabWidgetPointer->forward();
894 }
895
896 void BrowserWindow::fullScreenRequested(const bool toggleOn)
897 {
898     // Toggle full screen mode.
899     if (toggleOn)  // Turn full screen mode on.
900     {
901         // Enable full screen mode.
902         fullScreenActionPointer->setFullScreen(window(), true);
903
904         // Hide the menu bar if specified.
905         if (Settings::fullScreenHideMenuBar())
906             menuBar()->setVisible(false);
907
908         // Hide the toolbars if specified.
909         if (Settings::fullScreenHideToolBars())
910         {
911             navigationToolBarPointer->setVisible(false);
912             urlToolBarPointer->setVisible(false);
913             bookmarksToolBarPointer->setVisible(false);
914         }
915
916         // Hide the tab bar if specified.
917         if (Settings::fullScreenHideTabBar())
918             tabWidgetPointer->setTabBarVisible(false);
919
920         // Hide the status bar if specified.
921         if (Settings::fullScreenHideStatusBar())
922             statusBar()->setVisible(false);
923     }
924     else  // Disable full screen browsing mode.
925     {
926         // Disable full screen mode.
927         fullScreenActionPointer->setFullScreen(window(), false);
928
929         // Show the menu bar.
930         menuBar()->setVisible(true);
931
932         // Show the toolbars.
933         navigationToolBarPointer->setVisible(true);
934         urlToolBarPointer->setVisible(true);
935
936         // Only show the bookmarks toolbar if it was previously visible.
937         if (bookmarksToolBarIsVisible)
938             bookmarksToolBarPointer->setVisible(true);
939
940         // Show the tab bar.
941         tabWidgetPointer->setTabBarVisible(true);
942
943         // Show the status bar.
944         statusBar()->setVisible(true);
945     }
946 }
947
948 void BrowserWindow::getZoomFactorFromUser()
949 {
950     // Create an OK flag.
951     bool okClicked;
952
953     // 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.
954     double newZoomFactor = QInputDialog::getDouble(this, i18nc("The on-the-fly zoom factor dialog title", "On-The-Fly Zoom Factor"),
955                                                    i18nc("The instruction text of the on-the-fly zoom factor dialog", "Enter a zoom factor between 0.25 and 5.00"),
956                                                    currentZoomFactor, .025, 5.00, 2, &okClicked, Qt::WindowFlags(), 0.25);
957
958     // Update the zoom factor if the user clicked OK.
959     if (okClicked)
960     {
961         // Set the new zoom factor.
962         tabWidgetPointer->applyOnTheFlyZoomFactor(newZoomFactor);
963
964         // Update the on-the-fly action text.
965         updateZoomActions(newZoomFactor);
966     }
967 }
968
969 void BrowserWindow::hideFindTextActions() const
970 {
971     // Hide the find text actions.
972     findTextLineEditActionPointer->setVisible(false);
973     findTextLabelActionPointer->setVisible(false);
974     findNextActionPointer->setVisible(false);
975     findPreviousActionPointer->setVisible(false);
976     findCaseSensitiveActionPointer->setVisible(false);
977     hideFindTextActionPointer->setVisible(false);
978 }
979
980 void BrowserWindow::home() const
981 {
982     // Remove the focus from the URL line edit.
983     urlLineEditPointer->clearFocus();
984
985     // Go home.
986     tabWidgetPointer->home();
987 }
988
989 void BrowserWindow::hideProgressBar() const
990 {
991     // Hide the progress bar.
992     progressBarPointer->hide();
993
994     // Disable and hide the stop action.
995     stopActionPointer->setEnabled(false);
996     stopActionPointer->setVisible(false);
997
998     // Enable and show the refresh action.
999     refreshActionPointer->setEnabled(true);
1000     refreshActionPointer->setVisible(true);
1001 }
1002
1003 void BrowserWindow::incrementZoom()
1004 {
1005     // Update the current zoom factor.
1006     currentZoomFactor = currentZoomFactor + 0.25;
1007
1008     // Check to make sure the zoom factor is in the valid range (0.25 to 5.00).
1009     if (currentZoomFactor > 5.0)
1010         currentZoomFactor = 5.0;
1011
1012     // Set the new zoom factor.
1013     tabWidgetPointer->applyOnTheFlyZoomFactor(currentZoomFactor);
1014
1015     // Update the on-the-fly action text.
1016     updateZoomActions(currentZoomFactor);
1017 }
1018
1019 void BrowserWindow::loadUrlFromLineEdit(const QString &url) const
1020 {
1021     // Remove the focus from the URL line edit.
1022     urlLineEditPointer->clearFocus();
1023
1024     // Load the URL.
1025     tabWidgetPointer->loadUrlFromLineEdit(url);
1026 }
1027
1028 void BrowserWindow::newWindow() const
1029 {
1030     // Create a new browser window.
1031     BrowserWindow *browserWindowPointer = new BrowserWindow();
1032
1033     // Show the new browser window.
1034     browserWindowPointer->show();
1035 }
1036
1037 void BrowserWindow::populateBookmarksInAllWindows() const
1038 {
1039     // Get a list of all the registered service names.
1040     QStringList registeredServiceNames = QDBusConnection::sessionBus().interface()->registeredServiceNames().value();
1041
1042     // Get a list of all the Privacy Browser windows, which will be `com.stoutner.privacybrowser-` with the PID appended.
1043     QStringList privacyBrowserServiceNames = registeredServiceNames.filter("com.stoutner.privacybrowser");
1044
1045     // Repopulate the bookmarks in each window.
1046     for (QString privacyBrowserServiceName : privacyBrowserServiceNames)
1047     {
1048         // Prepare the D-Bus message.
1049         QDBusMessage dBusMessage = QDBusMessage::createMethodCall(privacyBrowserServiceName, "/privacybrowser/MainWindow_1", "com.stoutner.privacybrowser.BrowserWindow", "populateBookmarksInThisWindow");
1050
1051         // Make it so.
1052         QDBusConnection::sessionBus().send(dBusMessage);
1053     }
1054 }
1055
1056 void BrowserWindow::populateBookmarksInThisWindow()
1057 {
1058     // Remove all the final bookmark folder menu actions.
1059     for (QPair<QMenu *, QAction *> *finalBookmarkFolderMenuActionPair : finalBookmarkFolderMenuActionList)
1060     {
1061         // Remove the action.
1062         finalBookmarkFolderMenuActionPair->first->removeAction(finalBookmarkFolderMenuActionPair->second);
1063     }
1064
1065     // Remove all the current menu bookmarks.
1066     for (QPair<QMenu *, QAction *> *bookmarkMenuActionPairPointer : bookmarksMenuActionList)
1067     {
1068         // Remove the bookmark.
1069         bookmarkMenuActionPairPointer->first->removeAction(bookmarkMenuActionPairPointer->second);
1070     }
1071
1072     // Remove all the current menu subfolders.
1073     for (QPair<QMenu *, QMenu *> *submenuPairPointer : bookmarksMenuSubmenuList)
1074     {
1075         // Remove the submenu from the parent menu.
1076         submenuPairPointer->first->removeAction(submenuPairPointer->second->menuAction());
1077     }
1078
1079     // Remove all the current toolbar subfolders.
1080     for (QPair<QMenu *, QAction *> *subfolderActionPairPointer : bookmarksToolBarSubfolderActionList)
1081     {
1082         // Remove the action from the subfolder.
1083         subfolderActionPairPointer->first->removeAction(subfolderActionPairPointer->second);
1084     }
1085
1086     // Remove all the current toolbar bookmarks.
1087     for (QAction *bookmarkAction : bookmarksToolBarActionList)
1088     {
1089         // Remove the bookmark.
1090         bookmarksToolBarPointer->removeAction(bookmarkAction);
1091     }
1092
1093     // Clear the current bookmark lists.
1094     bookmarksMenuActionList.clear();
1095     bookmarksMenuSubmenuList.clear();
1096     bookmarksToolBarActionList.clear();
1097     bookmarksToolBarSubfolderActionList.clear();
1098
1099     // Populate the bookmarks subfolders, beginning with the root folder (`0`);
1100     populateBookmarksMenuSubfolders(0, bookmarksMenuPointer);
1101
1102     // Populate the bookmarks toolbar.
1103     populateBookmarksToolBar();
1104
1105     // Get a handle for the bookmark toolbar layout.
1106     QLayout *bookmarksToolBarLayoutPointer = bookmarksToolBarPointer->layout();
1107
1108     // Get the count of the bookmarks.
1109     int bookmarkCount = bookmarksToolBarLayoutPointer->count();
1110
1111     // Set the layout of each bookmark to be left aligned.
1112     for(int i = 0; i < bookmarkCount; ++i)
1113         bookmarksToolBarLayoutPointer->itemAt(i)->setAlignment(Qt::AlignLeft);
1114
1115     // Update the bookmarked action.
1116     updateBookmarkedAction();
1117 }
1118
1119 void BrowserWindow::populateBookmarksMenuSubfolders(const double folderId, QMenu *menuPointer)
1120 {
1121     // Get the folder contents.
1122     QList<BookmarkStruct> *folderContentsListPointer = BookmarksDatabase::getFolderContents(folderId);
1123
1124     // Populate the bookmarks menu and toolbar.
1125     for (BookmarkStruct bookmarkStruct : *folderContentsListPointer)
1126     {
1127         // Process the item according to the type.
1128         if (bookmarkStruct.isFolder)  // This item is a folder.
1129         {
1130             // Add a submenu to the menu.
1131             QMenu *submenuPointer = menuPointer->addMenu(bookmarkStruct.favoriteIcon, bookmarkStruct.name);
1132
1133             // Add the submenu to the beginning of the list of menus to be deleted on repopulate.
1134             bookmarksMenuSubmenuList.prepend(new QPair<QMenu *, QMenu *>(menuPointer, submenuPointer));
1135
1136             // Populate any subfolders.
1137             populateBookmarksMenuSubfolders(bookmarkStruct.folderId, submenuPointer);
1138         }
1139         else  // This item is a bookmark.
1140         {
1141             // Add the bookmark to the menu.
1142             QAction *menuBookmarkActionPointer = menuPointer->addAction(bookmarkStruct.favoriteIcon, bookmarkStruct.name, [=]
1143                 {
1144                     // Remove the focus from the URL line edit.
1145                     urlLineEditPointer->clearFocus();
1146
1147                     // Load the URL.
1148                     tabWidgetPointer->loadUrlFromLineEdit(bookmarkStruct.url);
1149                 }
1150             );
1151
1152             // Add the actions to the beginning of the list of bookmarks to be deleted on repopulate.
1153             bookmarksMenuActionList.prepend(new QPair<QMenu *, QAction *>(menuPointer, menuBookmarkActionPointer));
1154         }
1155     }
1156
1157     // Add the extra items at the bottom of the menu.
1158     addFinalBookmarkFolderMenuActions(menuPointer, folderId);
1159 }
1160
1161 void BrowserWindow::populateBookmarksToolBar()
1162 {
1163     // Get the root folder contents (which has a folder ID of `0`).
1164     QList<BookmarkStruct> *folderContentsListPointer = BookmarksDatabase::getFolderContents(0);
1165
1166     // Populate the bookmarks toolbar.
1167     for (BookmarkStruct bookmarkStruct : *folderContentsListPointer)
1168     {
1169         // Process the item according to the type.
1170         if (bookmarkStruct.isFolder)  // This item is a folder.
1171         {
1172             // Add the subfolder action.
1173             QAction *toolBarSubfolderActionPointer = bookmarksToolBarPointer->addAction(bookmarkStruct.favoriteIcon, bookmarkStruct.name);
1174
1175             // Add the bookmark database ID to the toolbar action.
1176             toolBarSubfolderActionPointer->setData(bookmarkStruct.databaseId);
1177
1178             // Add the action to the beginning of the list of actions to be deleted on repopulate.
1179             bookmarksToolBarActionList.prepend(toolBarSubfolderActionPointer);
1180
1181             // Create a subfolder menu.
1182             QMenu *subfolderMenuPointer = new QMenu();
1183
1184             // Add the menu to the action.
1185             toolBarSubfolderActionPointer->setMenu(subfolderMenuPointer);
1186
1187             // Add the submenu to the toolbar menu list.
1188             bookmarksToolBarMenuList.append(new QPair<QMenu *, const double>(subfolderMenuPointer, bookmarkStruct.folderId));
1189
1190             // Set the popup mode for the menu.
1191             dynamic_cast<QToolButton *>(bookmarksToolBarPointer->widgetForAction(toolBarSubfolderActionPointer))->setPopupMode(QToolButton::InstantPopup);
1192
1193             // Populate the subfolder.
1194             populateBookmarksToolBarSubfolders(bookmarkStruct.folderId, subfolderMenuPointer);
1195         }
1196         else  // This item is a bookmark.
1197         {
1198             // Add the bookmark to the toolbar.
1199             QAction *toolBarBookmarkActionPointer = bookmarksToolBarPointer->addAction(bookmarkStruct.favoriteIcon, bookmarkStruct.name, [=]
1200                 {
1201                     // Remove the focus from the URL line edit.
1202                     urlLineEditPointer->clearFocus();
1203
1204                     // Load the URL.
1205                     tabWidgetPointer->loadUrlFromLineEdit(bookmarkStruct.url);
1206                 }
1207             );
1208
1209             // Add the bookmark database ID to the toolbar action.
1210             toolBarBookmarkActionPointer->setData(bookmarkStruct.databaseId);
1211
1212             // Add the actions to the beginning of the current bookmarks lists.
1213             bookmarksToolBarActionList.prepend(toolBarBookmarkActionPointer);
1214         }
1215     }
1216
1217     // Add the extra items to the toolbar folder menus.  The first item in the pair is the menu pointer.  The second is the folder ID.
1218     for (QPair<QMenu *, const double> *menuAndFolderIdPairPointer : bookmarksToolBarMenuList)
1219     {
1220         // Populate the final bookmarks menu entries.
1221         addFinalBookmarkFolderMenuActions(menuAndFolderIdPairPointer->first, menuAndFolderIdPairPointer->second);
1222     }
1223 }
1224
1225 void BrowserWindow::populateBookmarksToolBarSubfolders(const double folderId, QMenu *menuPointer)
1226 {
1227     // Get the folder contents.
1228     QList<BookmarkStruct> *folderContentsListPointer = BookmarksDatabase::getFolderContents(folderId);
1229
1230     // Populate the bookmarks folder.
1231     for (BookmarkStruct bookmarkStruct : *folderContentsListPointer)
1232     {
1233         // Get the bookmark URL.
1234         QString bookmarkUrl = bookmarkStruct.url;
1235
1236         // Process the item according to the type.
1237         if (bookmarkStruct.isFolder)  // This item is a folder.
1238         {
1239             // Add the subfolder action.
1240             QAction *toolBarSubfolderActionPointer = menuPointer->addAction(bookmarkStruct.favoriteIcon, bookmarkStruct.name);
1241
1242             // Add the action to the beginning of the list of actions to be deleted on repopulate.
1243             bookmarksToolBarSubfolderActionList.prepend(new QPair<QMenu *, QAction *>(menuPointer, toolBarSubfolderActionPointer));
1244
1245             // Create a subfolder menu.
1246             QMenu *subfolderMenuPointer = new QMenu();
1247
1248             // Add the submenu to the action.
1249             toolBarSubfolderActionPointer->setMenu(subfolderMenuPointer);
1250
1251             // Add the submenu to the toolbar menu list.
1252             bookmarksToolBarMenuList.append(new QPair<QMenu *, const double>(subfolderMenuPointer, bookmarkStruct.folderId));
1253
1254             // Populate the subfolder menu.
1255             populateBookmarksToolBarSubfolders(bookmarkStruct.folderId, subfolderMenuPointer);
1256         }
1257         else  // This item is a bookmark.
1258         {
1259             // Add the bookmark to the folder.
1260             QAction *toolBarBookmarkActionPointer = menuPointer->addAction(bookmarkStruct.favoriteIcon, bookmarkStruct.name, [=]
1261                 {
1262                     // Remove the focus from the URL line edit.
1263                     urlLineEditPointer->clearFocus();
1264
1265                     // Load the URL.
1266                     tabWidgetPointer->loadUrlFromLineEdit(bookmarkUrl);
1267                 }
1268             );
1269
1270             // Add the bookmark database ID to the toolbar action.
1271             toolBarBookmarkActionPointer->setData(bookmarkStruct.databaseId);
1272
1273             // Add the action to the beginning of the list of actions to be deleted on repopulate.
1274             bookmarksToolBarSubfolderActionList.prepend(new QPair<QMenu *, QAction *>(menuPointer, toolBarBookmarkActionPointer));
1275         }
1276     }
1277 }
1278
1279 void BrowserWindow::refresh() const
1280 {
1281     // Remove the focus from the URL line edit.
1282     urlLineEditPointer->clearFocus();
1283
1284     // Refresh the web page.
1285     tabWidgetPointer->refresh();
1286 }
1287
1288 void BrowserWindow::reloadAndBypassCache() const
1289 {
1290     // Remove the focus from the URL line edit.
1291     urlLineEditPointer->clearFocus();
1292
1293     // Refresh the web page.
1294     tabWidgetPointer->refresh();
1295 }
1296
1297 void BrowserWindow::showBookmarkContextMenu(const QPoint &point)
1298 {
1299     // Get the bookmark action.
1300     QAction *bookmarkActionPointer = bookmarksToolBarPointer->actionAt(point);
1301
1302     // Check to see if an action was clicked.
1303     if (bookmarkActionPointer)  // An action was clicked.
1304     {
1305         // Create a bookmark context menu.
1306         QMenu *bookmarkContextMenuPointer = new QMenu();
1307
1308         // Get the database ID from the action.
1309         int databaseId = bookmarkActionPointer->data().toInt();
1310
1311         // Create the menu according to the type.
1312         if (BookmarksDatabase::isFolder(databaseId))  // A folder was clicked.
1313         {
1314             // Populate the final bookmarks menu entries.
1315             addFinalBookmarkFolderMenuActions(bookmarkContextMenuPointer, BookmarksDatabase::getFolderId(databaseId));
1316         }
1317         else  // A bookmark was clicked.
1318         {
1319             // Add the open in new tab action to the menu.
1320             bookmarkContextMenuPointer->addAction(QIcon::fromTheme(QLatin1String("tab-new")), i18nc("Open bookmark in new tab context menu entry", "Open in New Tab"), [=]
1321                 {
1322                     // Get the bookmark.
1323                     BookmarkStruct *bookmarkStructPointer = BookmarksDatabase::getBookmark(databaseId);
1324
1325                     // Open the bookmark in a new tab.  `true` removes the URL line edit focus, `false` does not load a background tab.
1326                     tabWidgetPointer->addTab(true, false, bookmarkStructPointer->url);
1327                 }
1328             );
1329
1330             // Add the open in background tab action to the menu.
1331             bookmarkContextMenuPointer->addAction(QIcon::fromTheme(QLatin1String("tab-new")), i18nc("Open bookmark in background tab context menu entry", "Open in Background Tab"), [=]
1332                 {
1333                     // Get the bookmark.
1334                     BookmarkStruct *bookmarkStructPointer = BookmarksDatabase::getBookmark(databaseId);
1335
1336                     // Open the bookmark in a new tab.  `true` removes the URL line edit focus, `true` loads a background tab.
1337                     tabWidgetPointer->addTab(true, true, bookmarkStructPointer->url);
1338                 }
1339             );
1340
1341             // Add the open in new window action to the menu.
1342             bookmarkContextMenuPointer->addAction(QIcon::fromTheme(QLatin1String("window-new")), i18nc("Open bookmark in new window context menu entry", "Open in New Window"), [=]
1343                 {
1344                     // Get the bookmark.
1345                     BookmarkStruct *bookmarkStructPointer = BookmarksDatabase::getBookmark(databaseId);
1346
1347                     // Create a new browser window and load the first URL.  `false` indicates it is not the first browser window.
1348                     BrowserWindow *browserWindowPointer = new BrowserWindow(false, &bookmarkStructPointer->url);
1349
1350                     // Show the new browser window.
1351                     browserWindowPointer->show();
1352                 }
1353             );
1354
1355             // Add a separator.
1356             bookmarkContextMenuPointer->addSeparator();
1357
1358             // Add the edit action to the menu.
1359             bookmarkContextMenuPointer->addAction(QIcon::fromTheme(QLatin1String("document-edit")), i18nc("Edit bookmark context menu entry", "Edit"), [=]
1360                 {
1361                     // Get the current tab favorite icon.
1362                     QIcon currentTabFavoriteIcon = tabWidgetPointer->getCurrentTabFavoritIcon();
1363
1364                     // Instantiate an edit bookmark dialog.
1365                     QDialog *editBookmarkDialogPointer = new EditBookmarkDialog(databaseId, currentTabFavoriteIcon);
1366
1367                     // Show the dialog.
1368                     editBookmarkDialogPointer->show();
1369
1370                     // Process bookmark events.
1371                     connect(editBookmarkDialogPointer, SIGNAL(bookmarkSaved()), this, SLOT(populateBookmarksInAllWindows()));
1372                 }
1373             );
1374
1375             // Add the copy URL action to the menu.
1376             bookmarkContextMenuPointer->addAction(QIcon::fromTheme(QLatin1String("edit-copy")), i18nc("Copy bookmark URL context menu entry", "Copy URL"), [=]
1377                 {
1378                     // Get the bookmark.
1379                     BookmarkStruct *bookmarkStructPointer = BookmarksDatabase::getBookmark(databaseId);
1380
1381                     // Get a handle for the clipboard.
1382                     QClipboard *clipboard = QGuiApplication::clipboard();
1383
1384                     // Place the URL on the keyboard.
1385                     clipboard->setText(bookmarkStructPointer->url);
1386                 }
1387             );
1388
1389             // Add a separator.
1390             bookmarkContextMenuPointer->addSeparator();
1391
1392             // Add the delete action to the menu.
1393             bookmarkContextMenuPointer->addAction(QIcon::fromTheme(QLatin1String("edit-delete")), i18nc("Delete bookmark context menu entry", "Delete"), [=]
1394                 {
1395                     // Get the parent folder ID.
1396                     double parentFolderId = BookmarksDatabase::getParentFolderId(databaseId);
1397
1398                     // Delete the bookmark.
1399                     BookmarksDatabase::deleteBookmark(databaseId);
1400
1401                     // Update the display order of the bookmarks in the parent folder.
1402                     BookmarksDatabase::updateFolderContentsDisplayOrder(parentFolderId);
1403
1404                     // Repopulate the bookmarks.
1405                     populateBookmarksInAllWindows();
1406                 }
1407             );
1408         }
1409
1410         // Delete the menu from memory when it is closed.
1411         bookmarkContextMenuPointer->setAttribute(Qt::WA_DeleteOnClose);
1412
1413         // Display the context menu.
1414         bookmarkContextMenuPointer->popup(bookmarksToolBarPointer->mapToGlobal(point));
1415     }
1416     else  // The toolbar background was clicked.
1417     {
1418         // Temporarily set the context menu policy to the default.
1419         bookmarksToolBarPointer->setContextMenuPolicy(Qt::DefaultContextMenu);
1420
1421         // Create a context menu event with the same position.
1422         QContextMenuEvent *contextMenuEventPointer = new QContextMenuEvent(QContextMenuEvent::Mouse, point);
1423
1424         // Send the context menu event to the toolbar.
1425         QCoreApplication::sendEvent(bookmarksToolBarPointer, contextMenuEventPointer);
1426
1427         // Reset the context menu policy.
1428         bookmarksToolBarPointer->setContextMenuPolicy(Qt::CustomContextMenu);
1429     }
1430 }
1431
1432 void BrowserWindow::showCookiesDialog()
1433 {
1434     // Remove the focus from the URL line edit.
1435     urlLineEditPointer->clearFocus();
1436
1437     // Instantiate the cookie settings dialog.
1438     CookiesDialog *cookiesDialogPointer = new CookiesDialog(tabWidgetPointer->getCookieList());
1439
1440     // Show the dialog.
1441     cookiesDialogPointer->show();
1442
1443     // Connect the dialog signals.
1444     connect(cookiesDialogPointer, SIGNAL(addCookie(QNetworkCookie)), tabWidgetPointer, SLOT(addCookieToStore(QNetworkCookie)));
1445     connect(cookiesDialogPointer, SIGNAL(deleteAllCookies()), tabWidgetPointer, SLOT(deleteAllCookies()));
1446     connect(cookiesDialogPointer, SIGNAL(deleteCookie(QNetworkCookie)), tabWidgetPointer, SLOT(deleteCookieFromStore(QNetworkCookie)));
1447 }
1448
1449 void BrowserWindow::showDownloadLocationBrowseDialog() const
1450 {
1451     // Get the current download location.
1452     QString currentDownloadLocation = downloadLocationComboBoxPointer->currentText();
1453
1454     // Resolve the system download directory if specified.
1455     if (currentDownloadLocation == QStringLiteral("System Download Directory"))
1456         currentDownloadLocation = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
1457
1458     // Get the new download location.
1459     QString newDownloadLocation = QFileDialog::getExistingDirectory(configDialogPointer, i18nc("Select download location dialog caption", "Select Download Location"), currentDownloadLocation);
1460
1461     // Populate the download location combo box according to the new download location.
1462     if (newDownloadLocation == QStandardPaths::writableLocation(QStandardPaths::DownloadLocation))  // The default download location was selected.
1463     {
1464         // Populate the download location with the default text.
1465         downloadLocationComboBoxPointer->setCurrentText("System Download Directory");
1466     }
1467     else if (newDownloadLocation != QStringLiteral(""))  // A different directory was selected.
1468     {
1469         // Populate the download location.
1470         downloadLocationComboBoxPointer->setCurrentText(newDownloadLocation);
1471     }
1472 }
1473
1474 void BrowserWindow::showDomainSettingsDialog() const
1475 {
1476     // Remove the focus from the URL line edit.
1477     urlLineEditPointer->clearFocus();
1478
1479     // Instantiate the domain settings dialog.
1480     DomainSettingsDialog *domainSettingsDialogPointer = new DomainSettingsDialog();
1481
1482     // Reload the tabs when domain settings are updated.
1483     connect(domainSettingsDialogPointer, SIGNAL(domainSettingsUpdated()), tabWidgetPointer, SLOT(applyDomainSettingsAndReload()));
1484
1485     // Show the dialog.
1486     domainSettingsDialogPointer->show();
1487 }
1488
1489 void BrowserWindow::showFindTextActions() const
1490 {
1491     // Show the find text actions.
1492     findTextLineEditActionPointer->setVisible(true);
1493     findTextLabelActionPointer->setVisible(true);
1494     findNextActionPointer->setVisible(true);
1495     findPreviousActionPointer->setVisible(true);
1496     findCaseSensitiveActionPointer->setVisible(true);
1497     hideFindTextActionPointer->setVisible(true);
1498
1499     // Set the focus on the find line edit.
1500     findTextLineEditPointer->setFocus();
1501
1502     // Select all the text in the find line edit.
1503     findTextLineEditPointer->selectAll();
1504 }
1505
1506 void BrowserWindow::showProgressBar(const int &progress) const
1507 {
1508     // Set the progress bar value.
1509     progressBarPointer->setValue(progress);
1510
1511     // Show the progress bar.
1512     progressBarPointer->show();
1513
1514     // Disable and hide the refresh action.
1515     refreshActionPointer->setEnabled(false);
1516     refreshActionPointer->setVisible(false);
1517
1518     // Enable and show the stop action.
1519     stopActionPointer->setEnabled(true);
1520     stopActionPointer->setVisible(true);
1521 }
1522
1523 void BrowserWindow::showSettingsDialog()
1524 {
1525     // Create the settings widgets.
1526     QWidget *privacySettingsWidgetPointer = new QWidget;
1527     QWidget *generalSettingsWidgetPointer = new QWidget;
1528     QWidget *spellCheckSettingsWidgetPointer = new QWidget;
1529
1530     // Instantiate the settings UI.
1531     Ui::PrivacySettings privacySettingsUi;
1532     Ui::GeneralSettings generalSettingsUi;
1533     Ui::SpellCheckSettings spellCheckSettingsUi;
1534
1535     // Setup the UI to display the settings widgets.
1536     privacySettingsUi.setupUi(privacySettingsWidgetPointer);
1537     generalSettingsUi.setupUi(generalSettingsWidgetPointer);
1538     spellCheckSettingsUi.setupUi(spellCheckSettingsWidgetPointer);
1539
1540     // Get handles for the widgets.
1541     QComboBox *userAgentComboBoxPointer = privacySettingsUi.kcfg_userAgent;
1542     userAgentLabelPointer = privacySettingsUi.userAgentLabel;
1543     QComboBox *searchEngineComboBoxPointer = generalSettingsUi.kcfg_searchEngine;
1544     searchEngineLabelPointer = generalSettingsUi.searchEngineLabel;
1545     downloadLocationComboBoxPointer = generalSettingsUi.kcfg_downloadLocation;
1546     QPushButton *browseButtonPointer = generalSettingsUi.browseButton;
1547     QListWidget *spellCheckListWidgetPointer = spellCheckSettingsUi.spellCheckListWidget;
1548
1549     // Populate the combo box labels.
1550     updateUserAgentLabel(userAgentComboBoxPointer->currentText());
1551     updateSearchEngineLabel(searchEngineComboBoxPointer->currentText());
1552
1553     // Update the labels when the combo boxes change.
1554     connect(userAgentComboBoxPointer, SIGNAL(currentTextChanged(const QString)), this, SLOT(updateUserAgentLabel(const QString)));
1555     connect(searchEngineComboBoxPointer, SIGNAL(currentTextChanged(const QString)), this, SLOT(updateSearchEngineLabel(const QString)));
1556
1557     // Connect the download location directory browse button.
1558     connect(browseButtonPointer, SIGNAL(clicked()), this, SLOT(showDownloadLocationBrowseDialog()));
1559
1560     // Create a dictionaries QDir from the `QTWEBENGINE_DICTIONARIES_PATH` environment variable.
1561     QDir dictionariesDir = QDir(qEnvironmentVariable("QTWEBENGINE_DICTIONARIES_PATH"));
1562
1563     // Get a dictionaries string list.
1564     QStringList dictionariesStringList = dictionariesDir.entryList(QStringList(QLatin1String("*.bdic")), QDir::Files | QDir::NoSymLinks);
1565
1566     // Remove the `.bdic` file extensions from the dictionaries list.
1567     dictionariesStringList.replaceInStrings(QLatin1String(".bdic"), QLatin1String(""));
1568
1569     // Get a list of the enabled spell check languages.
1570     QStringList enabledSpellCheckLanguagesList = Settings::spellCheckLanguages();
1571
1572     // Add each dictionary to the spell check list widget.
1573     foreach(QString dictionaryString, dictionariesStringList)
1574     {
1575         // Create a new list widget item pointer.
1576         QListWidgetItem *listWidgetItemPointer = new QListWidgetItem();
1577
1578         // Create a dictionary check box widget with the name of the dictionary string.
1579         QCheckBox *dictionaryCheckBoxWidget = new QCheckBox(dictionaryString);
1580
1581         // Check the language if it is currently enabled.
1582         if (enabledSpellCheckLanguagesList.contains(dictionaryString))
1583             dictionaryCheckBoxWidget->setCheckState(Qt::Checked);
1584         else
1585             dictionaryCheckBoxWidget->setCheckState(Qt::Unchecked);
1586
1587         // Add the list widget item to the spell check list widget.
1588         spellCheckListWidgetPointer->addItem(listWidgetItemPointer);
1589
1590         // Set the list widget item check box widget.
1591         spellCheckListWidgetPointer->setItemWidget(listWidgetItemPointer, dictionaryCheckBoxWidget);
1592     }
1593
1594     // Get a handle for the KConfig skeleton.
1595     KConfigSkeleton *kConfigSkeletonPointer = Settings::self();
1596
1597     // Instantiate a settings config dialog from the settings.kcfg file.
1598     configDialogPointer = new KConfigDialog(this, QLatin1String("settings"), kConfigSkeletonPointer);
1599
1600     // Create a settings icon string.
1601     QString settingsIconString;
1602
1603     // Get a settings icon that matches the theme.
1604     if (QIcon::hasThemeIcon("breeze-settings"))
1605     {
1606         // KDE uses breeze-settings.
1607         settingsIconString = QLatin1String("breeze-settings");
1608     }
1609     else
1610     {
1611         // Gnome uses preferences-desktop.
1612         settingsIconString = QLatin1String("preferences-desktop");
1613     }
1614
1615     // Add the settings widgets as config dialog pages.
1616     configDialogPointer->addPage(privacySettingsWidgetPointer, i18nc("Settings tab title", "Privacy"), QLatin1String("privacybrowser"));
1617     configDialogPointer->addPage(generalSettingsWidgetPointer, i18nc("Settings tab title", "General"), settingsIconString);
1618     configDialogPointer->addPage(spellCheckSettingsWidgetPointer, i18nc("Settings tab title", "Spell Check"), QLatin1String("tools-check-spelling"));
1619
1620     // Get handles for the buttons.
1621     QPushButton *applyButtonPointer = configDialogPointer->button(QDialogButtonBox::Apply);
1622     QPushButton *okButtonPointer = configDialogPointer->button(QDialogButtonBox::Ok);
1623
1624     // Prevent interaction with the parent window while the dialog is open.
1625     configDialogPointer->setWindowModality(Qt::WindowModal);
1626
1627     // Make it so.
1628     configDialogPointer->show();
1629
1630     // TODO.  KConfigDialog does not respect expanding size policies.  <https://redmine.stoutner.com/issues/823>
1631     //configDialogPointer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
1632     //privacySettingsWidgetPointer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
1633     //generalSettingsWidgetPointer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
1634     //configDialogPointer->adjustSize();
1635
1636     // Expand the config dialog.
1637     configDialogPointer->resize(1000, 500);
1638
1639     // Create a save spell check languages lambda.
1640     auto saveSpellCheckLanguages = [spellCheckListWidgetPointer, kConfigSkeletonPointer, this] ()
1641     {
1642         // Create a list of enabled languages.
1643         QStringList newSpellCheckLanguages = QStringList();
1644
1645         // Get a count of all the languages.
1646         int allLanguagesCount = spellCheckListWidgetPointer->count();
1647
1648         // Get a list of all the checked languages.
1649         for (int i = 0; i < allLanguagesCount; ++i) {
1650             // Get the language item.
1651             QListWidgetItem *languageItemPointer = spellCheckListWidgetPointer->item(i);
1652
1653             // Get the language check box.
1654             QCheckBox *languageCheckBoxPointer = qobject_cast<QCheckBox*>(spellCheckListWidgetPointer->itemWidget(languageItemPointer));
1655
1656             // Add the item to the enabled languages if it is checked.
1657             if (languageCheckBoxPointer->checkState() == Qt::Checked)
1658             {
1659                 // Get the text.
1660                 QString languageString = languageCheckBoxPointer->text();
1661
1662                 // Remove all instances of `&`, which may have been added automatically when creating the check box text.
1663                 languageString.remove(QChar('&'));
1664
1665                 // Add the language string to the list.
1666                 newSpellCheckLanguages.append(languageString);
1667             }
1668         }
1669
1670         // Update the spell check languages.
1671         if (Settings::spellCheckLanguages() != newSpellCheckLanguages)
1672         {
1673             // Update the spell check languages.
1674             Settings::setSpellCheckLanguages(newSpellCheckLanguages);
1675
1676             // Write the settings to disk.
1677             kConfigSkeletonPointer->save();
1678         }
1679
1680         // Apply the spell check languages.
1681         tabWidgetPointer->applySpellCheckLanguages();
1682     };
1683
1684     // Process
1685     connect(applyButtonPointer, &QPushButton::clicked, this, saveSpellCheckLanguages);
1686     connect(okButtonPointer, &QPushButton::clicked, this, saveSpellCheckLanguages);
1687
1688     // Apply the settings handled by KConfig.
1689     connect(configDialogPointer, SIGNAL(settingsChanged(QString)), tabWidgetPointer, SLOT(applyApplicationSettings()));
1690     connect(configDialogPointer, SIGNAL(settingsChanged(QString)), tabWidgetPointer, SLOT(applyDomainSettingsAndReload()));
1691 }
1692
1693 QSize BrowserWindow::sizeHint() const
1694 {
1695     // Return the default window size.
1696     return QSize(1500, 1200);
1697 }
1698
1699 void BrowserWindow::toggleBookmark()
1700 {
1701     // Remove the focus from the URL line edit, which will have been focused when the user clicked on the bookmarked icon.
1702     urlLineEditPointer->clearFocus();
1703
1704     // Create or delete the bookmark
1705     if (bookmarkedActionPointer->isChecked())  // The user checked the toggle.  Create a bookmark.
1706     {
1707         // Create a bookmark struct.
1708         BookmarkStruct *bookmarkStructPointer = new BookmarkStruct;
1709
1710         // Populate the bookmark struct.
1711         bookmarkStructPointer->name = tabWidgetPointer->getCurrentTabTitle();
1712         bookmarkStructPointer->url = tabWidgetPointer->getCurrentTabUrl();
1713         bookmarkStructPointer->parentFolderId = 0;
1714         bookmarkStructPointer->favoriteIcon = tabWidgetPointer->getCurrentTabFavoritIcon();
1715
1716         // Add the bookmark.
1717         BookmarksDatabase::addBookmark(bookmarkStructPointer);
1718     }
1719     else  // The user unchecked the toggle.  Delete all related bookmarks.
1720     {
1721         // Delete the bookmarks.
1722         BookmarksDatabase::deleteBookmarks(urlLineEditPointer->text());
1723
1724
1725     }
1726
1727     // Repopulate the bookmarks.
1728     populateBookmarksInAllWindows();
1729 }
1730
1731 void BrowserWindow::toggleDeveloperTools() const
1732 {
1733     // Toggle the developer tools.
1734     tabWidgetPointer->toggleDeveloperTools(developerToolsActionPointer->isChecked());
1735 }
1736
1737 void BrowserWindow::toggleDomStorage() const
1738 {
1739     // Remove the focus from the URL line edit.
1740     urlLineEditPointer->clearFocus();
1741
1742     // Toggle DOM storage.
1743     tabWidgetPointer->toggleDomStorage();
1744 }
1745
1746 void BrowserWindow::toggleFindCaseSensitive() const
1747 {
1748     // Get the current find string.
1749     const QString findString = findTextLineEditPointer->text();
1750
1751     // Toggle find case sensitive.
1752     tabWidgetPointer->toggleFindCaseSensitive(findString);
1753 }
1754
1755 void BrowserWindow::toggleJavaScript() const
1756 {
1757     // Remove the focus from the URL line edit.
1758     urlLineEditPointer->clearFocus();
1759
1760     // Toggle JavaScript.
1761     tabWidgetPointer->toggleJavaScript();
1762 }
1763
1764 void BrowserWindow::toggleLocalStorage() const
1765 {
1766     // Remove the focus from the URL line edit.
1767     urlLineEditPointer->clearFocus();
1768
1769     // Toggle local storage.
1770     tabWidgetPointer->toggleLocalStorage();
1771 }
1772
1773 void BrowserWindow::toggleFullScreen()
1774 {
1775     // Toggle the full screen status.
1776     fullScreenRequested(fullScreenActionPointer->isChecked());
1777 }
1778
1779 void BrowserWindow::toggleViewSource() const
1780 {
1781     // Get the current URL.
1782     QString url = urlLineEditPointer->text();
1783
1784     // Toggle the URL.
1785     if (url.startsWith(QLatin1String("view-source:")))  // The source is currently being viewed.
1786     {
1787         // Remove `view-source:` from the URL.
1788         url = url.remove(0, 12);
1789     }
1790     else  // The source is not currently being viewed.
1791     {
1792         // Prepend `view-source:` from the URL.
1793         url = url.prepend(QLatin1String("view-source:"));
1794     }
1795
1796     // Make it so.
1797     loadUrlFromLineEdit(url);
1798 }
1799
1800 void BrowserWindow::toggleViewBookmarksToolBar()
1801 {
1802     // Store the current status of the bookmarks toolbar, which is used when exiting full screen browsing.
1803     bookmarksToolBarIsVisible = viewBookmarksToolBarActionPointer->isChecked();
1804
1805     // Update the visibility of the bookmarks toolbar.
1806     bookmarksToolBarPointer->setVisible(bookmarksToolBarIsVisible);
1807 }
1808
1809 void BrowserWindow::toggleViewSourceInNewTab() const
1810 {
1811     // Get the current URL.
1812     QString url = urlLineEditPointer->text();
1813
1814     // Toggle the URL.
1815     if (url.startsWith(QLatin1String("view-source:")))  // The source is currently being viewed.
1816     {
1817         // Remove `view-source:` from the URL.
1818         url = url.remove(0, 12);
1819     }
1820     else  // The source is not currently being viewed.
1821     {
1822         // Prepend `view-source:` from the URL.
1823         url = url.prepend(QLatin1String("view-source:"));
1824     }
1825
1826     // Add the new tab.  `true` removes the URL line edit focus, `false` does not open a background tab.
1827     tabWidgetPointer->addTab(true, false, url);
1828 }
1829
1830 void BrowserWindow::updateBookmarkedAction() const
1831 {
1832     // Update the bookmarked action to reflect the current state.
1833     if (bookmarkedActionPointer->isChecked())
1834         bookmarkedActionPointer->setIcon(QIcon::fromTheme("starred-symbolic"));
1835     else
1836         bookmarkedActionPointer->setIcon(QIcon::fromTheme("non-starred-symbolic"));
1837 }
1838
1839 void BrowserWindow::updateCookiesAction(const int numberOfCookies) const
1840 {
1841     // Update the action text.
1842     cookiesActionPointer->setText(i18nc("The Cookies action, which also displays the number of cookies", "Cookies - %1", numberOfCookies));
1843 }
1844
1845 void BrowserWindow::updateDefaultZoomFactor(const double newDefaultZoomFactor)
1846 {
1847     // Store the new default zoom factor.
1848     defaultZoomFactor = newDefaultZoomFactor;
1849 }
1850
1851 void BrowserWindow::updateDomStorageAction(const bool &isEnabled) const
1852 {
1853     // Set the action checked status.
1854     domStorageActionPointer->setChecked(isEnabled);
1855 }
1856
1857 void BrowserWindow::updateDomainSettingsIndicator(const bool status)
1858 {
1859     // Set the domain palette according to the status.
1860     if (status)
1861         urlLineEditPointer->setPalette(positiveBackgroundPalette);
1862     else
1863         urlLineEditPointer->setPalette(normalBackgroundPalette);
1864 }
1865
1866 void BrowserWindow::updateFindText(const QString &text, const bool findCaseSensitive) const
1867 {
1868     // Set the text.
1869     findTextLineEditPointer->setText(text);
1870
1871     // Set the find case sensitive action checked status.
1872     findCaseSensitiveActionPointer->setChecked(findCaseSensitive);
1873 }
1874
1875 void BrowserWindow::updateFindTextResults(const QWebEngineFindTextResult &findTextResult) const
1876 {
1877     // Update the find text label.
1878     findTextLabelPointer->setText(QStringLiteral("  %1/%2  ").arg(findTextResult.activeMatch()).arg(findTextResult.numberOfMatches()));
1879
1880     // Set the background color according to the find status.
1881     if (findTextLineEditPointer->text().isEmpty())
1882         findTextLineEditPointer->setPalette(normalBackgroundPalette);
1883     else if (findTextResult.numberOfMatches() == 0)
1884         findTextLineEditPointer->setPalette(negativeBackgroundPalette);
1885     else
1886         findTextLineEditPointer->setPalette(positiveBackgroundPalette);
1887 }
1888
1889 void BrowserWindow::updateJavaScriptAction(const bool &isEnabled)
1890 {
1891     // Update the JavaScript status.
1892     javaScriptEnabled = isEnabled;
1893
1894     // Set the icon according to the status.
1895     if (javaScriptEnabled)
1896         javaScriptActionPointer->setIcon(QIcon(QLatin1String(":/icons/javascript-warning.svg")));
1897     else
1898         javaScriptActionPointer->setIcon(QIcon(QLatin1String(":/icons/privacy-mode.svg")));
1899
1900     // Set the action checked status.
1901     javaScriptActionPointer->setChecked(javaScriptEnabled);
1902
1903     // Update the status of the DOM storage action.
1904     domStorageActionPointer->setEnabled(javaScriptEnabled & localStorageEnabled);
1905 }
1906
1907 void BrowserWindow::updateLocalStorageAction(const bool &isEnabled)
1908 {
1909     // Update the local storage status.
1910     localStorageEnabled = isEnabled;
1911
1912     // 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.
1913     if (localStorageEnabled)
1914         localStorageActionPointer->setIcon(QIcon::fromTheme(QLatin1String("disk-quota-high"), QIcon(QLatin1String("/usr/share/icons/gnome/32x32/actions/document-save-as.png"))));
1915     else
1916         localStorageActionPointer->setIcon(QIcon::fromTheme(QLatin1String("disk-quota"), QIcon(QLatin1String("/usr/share/icons/gnome/32x32/apps/kfm.png"))));
1917
1918     // Set the action checked status.
1919     localStorageActionPointer->setChecked(localStorageEnabled);
1920
1921     // Update the status of the DOM storage action.
1922     domStorageActionPointer->setEnabled(localStorageEnabled & javaScriptEnabled);
1923 }
1924
1925 void BrowserWindow::updateSearchEngineActions(const QString &searchEngine, const bool &updateCustomSearchEngineStatus)
1926 {
1927     // Initialize the custom search engine flag.
1928     bool customSearchEngine = false;
1929
1930     if (searchEngine == "Mojeek")  // Mojeek.
1931     {
1932         // Check the Mojeek user agent action.
1933         searchEngineMojeekActionPointer->setChecked(true);
1934
1935         // Update the search engine menu action icon.
1936         searchEngineMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
1937
1938         // Update the search engine menu action text.
1939         searchEngineMenuActionPointer->setText(i18nc("The main search engine menu action", "Search Engine - Mojeek"));
1940     }
1941     else if (searchEngine == "Monocles")  // Monocles.
1942     {
1943         // Check the Monocles user agent action.
1944         searchEngineMonoclesActionPointer->setChecked(true);
1945
1946         // Update the search engine menu action icon.
1947         searchEngineMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
1948
1949         // Update the search engine menu action text.
1950         searchEngineMenuActionPointer->setText(i18nc("The main search engine menu action", "Search Engine - Monocles"));
1951     }
1952     else if (searchEngine == "MetaGer")  // MetaGer.
1953     {
1954         // Check the MetaGer user agent action.
1955         searchEngineMetagerActionPointer->setChecked(true);
1956
1957         // Update the search engine menu action icon.
1958         searchEngineMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
1959
1960         // Update the search engine menu action text.
1961         searchEngineMenuActionPointer->setText(i18nc("The main search engine menu action", "Search Engine - MetaGer"));
1962     }
1963     else if (searchEngine == "Google")  // Google.
1964     {
1965         // Check the Google user agent action.
1966         searchEngineGoogleActionPointer->setChecked(true);
1967
1968         // Update the search engine menu action icon.
1969         searchEngineMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("im-google"), QIcon::fromTheme(QLatin1String("edit-find"))));
1970
1971         // Update the search engine menu action text.
1972         searchEngineMenuActionPointer->setText(i18nc("The main search engine menu action", "Search Engine - Google"));
1973     }
1974     else if (searchEngine == "Bing")  // Bing.
1975     {
1976         // Check the Bing user agent action.
1977         searchEngineBingActionPointer->setChecked(true);
1978
1979         // Update the search engine menu action icon.
1980         searchEngineMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
1981
1982         // Update the search engine menu action text.
1983         searchEngineMenuActionPointer->setText(i18nc("The main search engine menu action", "Search Engine - Bing"));
1984     }
1985     else if (searchEngine == "Yahoo")  // Yahoo.
1986     {
1987         // Check the Yahoo user agent action.
1988         searchEngineYahooActionPointer->setChecked(true);
1989
1990         // Update the search engine menu action icon.
1991         searchEngineMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("im-yahoo"), QIcon::fromTheme(QLatin1String("edit-find"))));
1992
1993         // Update the search engine menu action text.
1994         searchEngineMenuActionPointer->setText(i18nc("The main search engine menu action", "Search Engine - Yahoo"));
1995     }
1996     else  // Custom search engine.
1997     {
1998         // Check the user agent.
1999         searchEngineCustomActionPointer->setChecked(true);
2000
2001         // Update the search engine menu action icon.
2002         searchEngineMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
2003
2004         // Update the search engine menu action text.
2005         searchEngineMenuActionPointer->setText(i18nc("The main search engine menu action", "Search Engine - Custom"));
2006
2007         // Set the custom search engine text.
2008         searchEngineCustomActionPointer->setText(searchEngine);
2009
2010         // Set the custom search engine flag.
2011         customSearchEngine = true;
2012     }
2013
2014     // Update the custom search engine enabled boolean.
2015     if (updateCustomSearchEngineStatus)
2016         customSearchEngineEnabled = customSearchEngine;
2017
2018     // Format the custom search engine.
2019     if (customSearchEngineEnabled)
2020     {
2021         // Enable the custom search engine.
2022         searchEngineCustomActionPointer->setEnabled(true);
2023     }
2024     else
2025     {
2026         // Disable the custom search engine.
2027         searchEngineCustomActionPointer->setEnabled(false);
2028
2029         // Reset the custom search engine text.
2030         searchEngineCustomActionPointer->setText(i18nc("@action", "Custom"));
2031     }
2032 }
2033
2034 void BrowserWindow::updateSearchEngineLabel(const QString &searchEngineString) const
2035 {
2036     // Update the search engine label.
2037     searchEngineLabelPointer->setText(SearchEngineHelper::getSearchUrl(searchEngineString));
2038 }
2039
2040 void BrowserWindow::updateUrlLineEdit(const QUrl &newUrl)
2041 {
2042     // Get the new URL string in encoded form, which displays punycode.
2043     QString newUrlString = newUrl.toEncoded();
2044
2045     // Update the view source actions.
2046     if (newUrlString.startsWith(QLatin1String("view-source:")))  // The source is currently being viewed.
2047     {
2048         // Mark the view source checkbox.
2049         viewSourceActionPointer->setChecked(true);
2050
2051         // Update the view in new tab action text.
2052         viewSourceInNewTabActionPointer->setText(i18nc("View rendered website in new tab action", "View Rendered Website in New Tab"));
2053     }
2054     else  // The source is not currently being viewed.
2055     {
2056         // Unmark the view source checkbox.
2057         viewSourceActionPointer->setChecked(false);
2058
2059         // Update the view in new tab action text.
2060         viewSourceInNewTabActionPointer->setText(i18nc("View source in new tab action", "View Source in New Tab"));
2061     }
2062
2063     // Update the URL line edit if it does not have focus.
2064     if (!urlLineEditPointer->hasFocus())
2065     {
2066         // Update the URL line edit.
2067         urlLineEditPointer->setText(newUrlString);
2068
2069         // Set the bookmarked action status.
2070         bookmarkedActionPointer->setChecked(BookmarksDatabase::isBookmarked(newUrlString));
2071
2072         // Update the bookmarked action.
2073         updateBookmarkedAction();
2074
2075         // Set the focus if the new URL is blank.
2076         if (newUrlString == QStringLiteral(""))
2077             urlLineEditPointer->setFocus();
2078     }
2079
2080     // Store the current URL.
2081     currentUrl = newUrl;
2082 }
2083
2084 void BrowserWindow::updateUserAgentActions(const QString &userAgent, const bool &updateCustomUserAgentStatus)
2085 {
2086     // Initialize the custom user agent flag.
2087     bool customUserAgent = false;
2088
2089     // Check the indicated on-the-fly user agent.
2090     if (userAgent == UserAgentHelper::PRIVACY_BROWSER_USER_AGENT)  // Privacy Browser.
2091     {
2092         // Check the Privacy Browser user agent action.
2093         userAgentPrivacyBrowserActionPointer->setChecked(true);
2094
2095         // Update the user agent menu action icon.
2096         userAgentMenuActionPointer->setIcon(QIcon(":/icons/privacy-mode.svg"));
2097
2098         // Update the user agent menu action text.
2099         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Privacy Browser"));
2100     }
2101     else if (userAgent == TabWidget::webEngineDefaultUserAgent)  // WebEngine default.
2102     {
2103         // check the WebEngine default user agent action.
2104         userAgentWebEngineDefaultActionPointer->setChecked(true);
2105
2106         // Update the user agent menu action icon.
2107         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("qtlogo"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new")))));
2108
2109         // Update the user agent menu action text.
2110         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - WebEngine default"));
2111     }
2112     else if (userAgent == UserAgentHelper::FIREFOX_LINUX_USER_AGENT)  // Firefox on Linux.
2113     {
2114         // Check the Firefox on Linux user agent action.
2115         userAgentFirefoxLinuxActionPointer->setChecked(true);
2116
2117         // Update the user agent menu action icon.
2118         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("firefox-esr"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new")))));
2119
2120         // Update the user agent menu action text.
2121         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Firefox on Linux"));
2122     }
2123     else if (userAgent == UserAgentHelper::CHROMIUM_LINUX_USER_AGENT)  // Chromium on Linux.
2124     {
2125         // Check the Chromium on Linux user agent action.
2126         userAgentChromiumLinuxActionPointer->setChecked(true);
2127
2128         // Update the user agent menu action icon.
2129         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("chromium"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new")))));
2130
2131         // Update the user agent menu action text.
2132         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Chromium on Linux"));
2133     }
2134     else if (userAgent == UserAgentHelper::FIREFOX_WINDOWS_USER_AGENT)  // Firefox on Windows.
2135     {
2136         // Check the Firefox on Windows user agent action.
2137         userAgentFirefoxWindowsActionPointer->setChecked(true);
2138
2139         // Update the user agent menu action icon.
2140         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("firefox-esr"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new")))));
2141
2142         // Update the user agent menu action text.
2143         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Firefox on Windows"));
2144     }
2145     else if (userAgent == UserAgentHelper::CHROME_WINDOWS_USER_AGENT)  // Chrome on Windows.
2146     {
2147         // Check the Chrome on Windows user agent action.
2148         userAgentChromeWindowsActionPointer->setChecked(true);
2149
2150         // Update the user agent menu action icon.
2151         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("chromium"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new")))));
2152
2153         // Update the user agent menu action text.
2154         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Chrome on Windows"));
2155     }
2156     else if (userAgent == UserAgentHelper::EDGE_WINDOWS_USER_AGENT)  // Edge on Windows.
2157     {
2158         // Check the Edge on Windows user agent action.
2159         userAgentEdgeWindowsActionPointer->setChecked(true);
2160
2161         // Update the user agent menu action icon.
2162         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new"))));
2163
2164         // Update the user agent menu action text.
2165         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Edge on Windows"));
2166     }
2167     else if (userAgent == UserAgentHelper::SAFARI_MACOS_USER_AGENT)  // Safari on macOS.
2168     {
2169         // Check the Safari on macOS user agent action.
2170         userAgentSafariMacosActionPointer->setChecked(true);
2171
2172         // Update the user agent menu action icon.
2173         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new"))));
2174
2175         // Update the user agent menu action text.
2176         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Safari on macOS"));
2177     }
2178     else  // Custom user agent.
2179     {
2180         // Check the user agent.
2181         userAgentCustomActionPointer->setChecked(true);
2182
2183         // Update the user agent menu action icon.
2184         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new"))));
2185
2186         // Update the user agent menu action text.
2187         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Custom"));
2188
2189         // Set the custom user agent text.
2190         userAgentCustomActionPointer->setText(userAgent);
2191
2192         // Set the custom user agent flag.
2193         customUserAgent = true;
2194     }
2195
2196     // Update the custom user agent enabled boolean.
2197     // 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.
2198     if (updateCustomUserAgentStatus)
2199         customUserAgentEnabled = customUserAgent;
2200
2201
2202     // Format the custom user agent.
2203     if (customUserAgentEnabled)
2204     {
2205         // Enable the custom user agent.
2206         userAgentCustomActionPointer->setEnabled(true);
2207     }
2208     else
2209     {
2210         // Disable the custom user agent.
2211         userAgentCustomActionPointer->setEnabled(false);
2212
2213         // Reset the custom user agent text.
2214         userAgentCustomActionPointer->setText(i18nc("@action", "Custom"));
2215     }
2216 }
2217
2218 void BrowserWindow::updateUserAgentLabel(const QString &userAgentDatabaseName) const
2219 {
2220     // Update the user agent label.
2221     userAgentLabelPointer->setText(UserAgentHelper::getUserAgentFromDatabaseName(userAgentDatabaseName));
2222 }
2223
2224 void BrowserWindow::updateViewBookmarksToolBarCheckbox(const bool visible)
2225 {
2226     // Update the view bookmarks toolbar checkbox.
2227     viewBookmarksToolBarActionPointer->setChecked(visible);
2228
2229     // Initialize the bookmarks toolbar visibility tracker if Privacy Browser has just launched.
2230     if (bookmarksToolBarUninitialized)
2231     {
2232         // Set the initialization flag.
2233         bookmarksToolBarUninitialized = false;
2234
2235         // Store the current status of the bookmarks toolbar, which is used when exiting full screen browsing.
2236         bookmarksToolBarIsVisible = visible;
2237     }
2238 }
2239
2240 void BrowserWindow::updateWindowTitle(const QString &title)
2241 {
2242     // Update the window title.
2243     setWindowTitle(title);
2244 }
2245
2246 void BrowserWindow::updateZoomActions(const double &zoomFactor)
2247 {
2248     // Set the current zoom factor.
2249     currentZoomFactor = zoomFactor;
2250
2251     // Set the status of the default zoom action.
2252     zoomDefaultActionPointer->setEnabled(currentZoomFactor != defaultZoomFactor);
2253
2254     // Set the status of the zoom in action and button.
2255     zoomInActionPointer->setEnabled(currentZoomFactor <= 4.99);
2256     zoomPlusButtonPointer->setEnabled(currentZoomFactor <= 4.99);
2257
2258     // Set the status of the zoom out action and button.
2259     zoomMinusButtonPointer->setEnabled(currentZoomFactor > 0.25);
2260     zoomOutActionPointer->setEnabled(currentZoomFactor > 0.25);
2261
2262
2263     // Update the zoom factor action text, formatting the double with 2 decimal places.  `0` specifies no extra field width.  `'0'` sets the format to not use scientific notation.
2264     zoomFactorActionPointer->setText(ki18nc("The zoom factor action", "Zoom Factor - %1").subs(zoomFactor, 0, '0', 2).toString());
2265
2266     // Update the status bar zoom factor label.
2267     currentZoomButtonPointer->setText(ki18nc("The status bar zoom, which is just the formatted zoom factor", "%1").subs(zoomFactor, 0, '0', 2).toString());
2268 }
2269
2270 void BrowserWindow::zoomDefault()
2271 {
2272     // Set the new zoom factor.
2273     tabWidgetPointer->applyOnTheFlyZoomFactor(defaultZoomFactor);
2274
2275     // Update the on-the-fly action text.
2276     updateZoomActions(defaultZoomFactor);
2277 }