]> gitweb.stoutner.com Git - PrivacyBrowserPC.git/blob - src/windows/BrowserWindow.cpp
Add option to auto update the download directory. https://redmine.stoutner.com/issue...
[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, `true` opens the new tabs in an adjacent tab.  `false` does not load a background tab.
629             for (QString url : *folderUrlsListPointer)
630                 tabWidgetPointer->addTab(true, 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` opens the new tabs in an adjacent tab.  `true` loads a background tab.
642             for (QString url : *folderUrlsListPointer)
643                 tabWidgetPointer->addTab(true, 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, `false` does not load the new tabs in adjacent tabs.  `true` loads a background tab.
660             for (int i = 1; i < folderUrls; ++i)
661                 browserWindowPointer->tabWidgetPointer->addTab(true, false, 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, `true` opens the new tab in an adjacent tab.  `false` does not load a background tab.
1326                     tabWidgetPointer->addTab(true, 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` opens the new tab in an adjacent tab.  `true` loads a background tab.
1337                     tabWidgetPointer->addTab(true, 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::showDownloadDirectoryBrowseDialog() const
1450 {
1451     // Get the current download directory.
1452     QString currentDownloadDirectory = downloadDirectoryComboBoxPointer->currentText();
1453
1454     // Resolve the system download directory if specified.
1455     if (currentDownloadDirectory == QStringLiteral("System Download Directory"))
1456         currentDownloadDirectory = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
1457
1458     // Get the new download directory.
1459     QString newDownloadDirectory = QFileDialog::getExistingDirectory(configDialogPointer, i18nc("Select download directory dialog caption", "Select Download Directory"),
1460                                                                      currentDownloadDirectory);
1461
1462     // Populate the download directory combo box according to the new download location.
1463     if (newDownloadDirectory == QStandardPaths::writableLocation(QStandardPaths::DownloadLocation))  // The default download location was selected.
1464     {
1465         // Populate the download location with the default text.
1466         downloadDirectoryComboBoxPointer->setCurrentText("System Download Directory");
1467     }
1468     else if (newDownloadDirectory != QStringLiteral(""))  // A different directory was selected.
1469     {
1470         // Populate the download location.
1471         downloadDirectoryComboBoxPointer->setCurrentText(newDownloadDirectory);
1472     }
1473 }
1474
1475 void BrowserWindow::showDomainSettingsDialog() const
1476 {
1477     // Remove the focus from the URL line edit.
1478     urlLineEditPointer->clearFocus();
1479
1480     // Instantiate the domain settings dialog.
1481     DomainSettingsDialog *domainSettingsDialogPointer = new DomainSettingsDialog();
1482
1483     // Reload the tabs when domain settings are updated.
1484     connect(domainSettingsDialogPointer, SIGNAL(domainSettingsUpdated()), tabWidgetPointer, SLOT(applyDomainSettingsAndReload()));
1485
1486     // Show the dialog.
1487     domainSettingsDialogPointer->show();
1488 }
1489
1490 void BrowserWindow::showFindTextActions() const
1491 {
1492     // Show the find text actions.
1493     findTextLineEditActionPointer->setVisible(true);
1494     findTextLabelActionPointer->setVisible(true);
1495     findNextActionPointer->setVisible(true);
1496     findPreviousActionPointer->setVisible(true);
1497     findCaseSensitiveActionPointer->setVisible(true);
1498     hideFindTextActionPointer->setVisible(true);
1499
1500     // Set the focus on the find line edit.
1501     findTextLineEditPointer->setFocus();
1502
1503     // Select all the text in the find line edit.
1504     findTextLineEditPointer->selectAll();
1505 }
1506
1507 void BrowserWindow::showProgressBar(const int &progress) const
1508 {
1509     // Set the progress bar value.
1510     progressBarPointer->setValue(progress);
1511
1512     // Show the progress bar.
1513     progressBarPointer->show();
1514
1515     // Disable and hide the refresh action.
1516     refreshActionPointer->setEnabled(false);
1517     refreshActionPointer->setVisible(false);
1518
1519     // Enable and show the stop action.
1520     stopActionPointer->setEnabled(true);
1521     stopActionPointer->setVisible(true);
1522 }
1523
1524 void BrowserWindow::showSettingsDialog()
1525 {
1526     // Create the settings widgets.
1527     QWidget *privacySettingsWidgetPointer = new QWidget;
1528     QWidget *generalSettingsWidgetPointer = new QWidget;
1529     QWidget *spellCheckSettingsWidgetPointer = new QWidget;
1530
1531     // Instantiate the settings UI.
1532     Ui::PrivacySettings privacySettingsUi;
1533     Ui::GeneralSettings generalSettingsUi;
1534     Ui::SpellCheckSettings spellCheckSettingsUi;
1535
1536     // Setup the UI to display the settings widgets.
1537     privacySettingsUi.setupUi(privacySettingsWidgetPointer);
1538     generalSettingsUi.setupUi(generalSettingsWidgetPointer);
1539     spellCheckSettingsUi.setupUi(spellCheckSettingsWidgetPointer);
1540
1541     // Get handles for the widgets.
1542     QComboBox *userAgentComboBoxPointer = privacySettingsUi.kcfg_userAgent;
1543     userAgentLabelPointer = privacySettingsUi.userAgentLabel;
1544     QComboBox *searchEngineComboBoxPointer = generalSettingsUi.kcfg_searchEngine;
1545     searchEngineLabelPointer = generalSettingsUi.searchEngineLabel;
1546     downloadDirectoryComboBoxPointer = generalSettingsUi.kcfg_downloadDirectory;
1547     QPushButton *browseButtonPointer = generalSettingsUi.browseButton;
1548     QListWidget *spellCheckListWidgetPointer = spellCheckSettingsUi.spellCheckListWidget;
1549
1550     // Populate the combo box labels.
1551     updateUserAgentLabel(userAgentComboBoxPointer->currentText());
1552     updateSearchEngineLabel(searchEngineComboBoxPointer->currentText());
1553
1554     // Update the labels when the combo boxes change.
1555     connect(userAgentComboBoxPointer, SIGNAL(currentTextChanged(const QString)), this, SLOT(updateUserAgentLabel(const QString)));
1556     connect(searchEngineComboBoxPointer, SIGNAL(currentTextChanged(const QString)), this, SLOT(updateSearchEngineLabel(const QString)));
1557
1558     // Connect the download directory directory browse button.
1559     connect(browseButtonPointer, SIGNAL(clicked()), this, SLOT(showDownloadDirectoryBrowseDialog()));
1560
1561     // Create a dictionaries QDir from the `QTWEBENGINE_DICTIONARIES_PATH` environment variable.
1562     QDir dictionariesDir = QDir(qEnvironmentVariable("QTWEBENGINE_DICTIONARIES_PATH"));
1563
1564     // Get a dictionaries string list.
1565     QStringList dictionariesStringList = dictionariesDir.entryList(QStringList(QLatin1String("*.bdic")), QDir::Files | QDir::NoSymLinks);
1566
1567     // Remove the `.bdic` file extensions from the dictionaries list.
1568     dictionariesStringList.replaceInStrings(QLatin1String(".bdic"), QLatin1String(""));
1569
1570     // Get a list of the enabled spell check languages.
1571     QStringList enabledSpellCheckLanguagesList = Settings::spellCheckLanguages();
1572
1573     // Add each dictionary to the spell check list widget.
1574     foreach(QString dictionaryString, dictionariesStringList)
1575     {
1576         // Create a new list widget item pointer.
1577         QListWidgetItem *listWidgetItemPointer = new QListWidgetItem();
1578
1579         // Create a dictionary check box widget with the name of the dictionary string.
1580         QCheckBox *dictionaryCheckBoxWidget = new QCheckBox(dictionaryString);
1581
1582         // Check the language if it is currently enabled.
1583         if (enabledSpellCheckLanguagesList.contains(dictionaryString))
1584             dictionaryCheckBoxWidget->setCheckState(Qt::Checked);
1585         else
1586             dictionaryCheckBoxWidget->setCheckState(Qt::Unchecked);
1587
1588         // Add the list widget item to the spell check list widget.
1589         spellCheckListWidgetPointer->addItem(listWidgetItemPointer);
1590
1591         // Set the list widget item check box widget.
1592         spellCheckListWidgetPointer->setItemWidget(listWidgetItemPointer, dictionaryCheckBoxWidget);
1593     }
1594
1595     // Get a handle for the KConfig skeleton.
1596     KConfigSkeleton *kConfigSkeletonPointer = Settings::self();
1597
1598     // Instantiate a settings config dialog from the settings.kcfg file.
1599     configDialogPointer = new KConfigDialog(this, QLatin1String("settings"), kConfigSkeletonPointer);
1600
1601     // Create a settings icon string.
1602     QString settingsIconString;
1603
1604     // Get a settings icon that matches the theme.
1605     if (QIcon::hasThemeIcon("breeze-settings"))
1606     {
1607         // KDE uses breeze-settings.
1608         settingsIconString = QLatin1String("breeze-settings");
1609     }
1610     else
1611     {
1612         // Gnome uses preferences-desktop.
1613         settingsIconString = QLatin1String("preferences-desktop");
1614     }
1615
1616     // Add the settings widgets as config dialog pages.
1617     configDialogPointer->addPage(privacySettingsWidgetPointer, i18nc("Settings tab title", "Privacy"), QLatin1String("privacybrowser"));
1618     configDialogPointer->addPage(generalSettingsWidgetPointer, i18nc("Settings tab title", "General"), settingsIconString);
1619     configDialogPointer->addPage(spellCheckSettingsWidgetPointer, i18nc("Settings tab title", "Spell Check"), QLatin1String("tools-check-spelling"));
1620
1621     // Get handles for the buttons.
1622     QPushButton *applyButtonPointer = configDialogPointer->button(QDialogButtonBox::Apply);
1623     QPushButton *okButtonPointer = configDialogPointer->button(QDialogButtonBox::Ok);
1624
1625     // Prevent interaction with the parent window while the dialog is open.
1626     configDialogPointer->setWindowModality(Qt::WindowModal);
1627
1628     // Make it so.
1629     configDialogPointer->show();
1630
1631     // TODO.  KConfigDialog does not respect expanding size policies.  <https://redmine.stoutner.com/issues/823>
1632     //configDialogPointer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
1633     //privacySettingsWidgetPointer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
1634     //generalSettingsWidgetPointer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
1635     //configDialogPointer->adjustSize();
1636
1637     // Expand the config dialog.
1638     configDialogPointer->resize(1000, 500);
1639
1640     // Create a save spell check languages lambda.
1641     auto saveSpellCheckLanguages = [spellCheckListWidgetPointer, kConfigSkeletonPointer, this] ()
1642     {
1643         // Create a list of enabled languages.
1644         QStringList newSpellCheckLanguages = QStringList();
1645
1646         // Get a count of all the languages.
1647         int allLanguagesCount = spellCheckListWidgetPointer->count();
1648
1649         // Get a list of all the checked languages.
1650         for (int i = 0; i < allLanguagesCount; ++i) {
1651             // Get the language item.
1652             QListWidgetItem *languageItemPointer = spellCheckListWidgetPointer->item(i);
1653
1654             // Get the language check box.
1655             QCheckBox *languageCheckBoxPointer = qobject_cast<QCheckBox*>(spellCheckListWidgetPointer->itemWidget(languageItemPointer));
1656
1657             // Add the item to the enabled languages if it is checked.
1658             if (languageCheckBoxPointer->checkState() == Qt::Checked)
1659             {
1660                 // Get the text.
1661                 QString languageString = languageCheckBoxPointer->text();
1662
1663                 // Remove all instances of `&`, which may have been added automatically when creating the check box text.
1664                 languageString.remove(QChar('&'));
1665
1666                 // Add the language string to the list.
1667                 newSpellCheckLanguages.append(languageString);
1668             }
1669         }
1670
1671         // Update the spell check languages.
1672         if (Settings::spellCheckLanguages() != newSpellCheckLanguages)
1673         {
1674             // Update the spell check languages.
1675             Settings::setSpellCheckLanguages(newSpellCheckLanguages);
1676
1677             // Write the settings to disk.
1678             kConfigSkeletonPointer->save();
1679         }
1680
1681         // Apply the spell check languages.
1682         tabWidgetPointer->applySpellCheckLanguages();
1683     };
1684
1685     // Process
1686     connect(applyButtonPointer, &QPushButton::clicked, this, saveSpellCheckLanguages);
1687     connect(okButtonPointer, &QPushButton::clicked, this, saveSpellCheckLanguages);
1688
1689     // Apply the settings handled by KConfig.
1690     connect(configDialogPointer, SIGNAL(settingsChanged(QString)), tabWidgetPointer, SLOT(applyApplicationSettings()));
1691     connect(configDialogPointer, SIGNAL(settingsChanged(QString)), tabWidgetPointer, SLOT(applyDomainSettingsAndReload()));
1692 }
1693
1694 QSize BrowserWindow::sizeHint() const
1695 {
1696     // Return the default window size.
1697     return QSize(1500, 1200);
1698 }
1699
1700 void BrowserWindow::toggleBookmark()
1701 {
1702     // Remove the focus from the URL line edit, which will have been focused when the user clicked on the bookmarked icon.
1703     urlLineEditPointer->clearFocus();
1704
1705     // Create or delete the bookmark
1706     if (bookmarkedActionPointer->isChecked())  // The user checked the toggle.  Create a bookmark.
1707     {
1708         // Create a bookmark struct.
1709         BookmarkStruct *bookmarkStructPointer = new BookmarkStruct;
1710
1711         // Populate the bookmark struct.
1712         bookmarkStructPointer->name = tabWidgetPointer->getCurrentTabTitle();
1713         bookmarkStructPointer->url = tabWidgetPointer->getCurrentTabUrl();
1714         bookmarkStructPointer->parentFolderId = 0;
1715         bookmarkStructPointer->favoriteIcon = tabWidgetPointer->getCurrentTabFavoritIcon();
1716
1717         // Add the bookmark.
1718         BookmarksDatabase::addBookmark(bookmarkStructPointer);
1719     }
1720     else  // The user unchecked the toggle.  Delete all related bookmarks.
1721     {
1722         // Delete the bookmarks.
1723         BookmarksDatabase::deleteBookmarks(urlLineEditPointer->text());
1724
1725
1726     }
1727
1728     // Repopulate the bookmarks.
1729     populateBookmarksInAllWindows();
1730 }
1731
1732 void BrowserWindow::toggleDeveloperTools() const
1733 {
1734     // Toggle the developer tools.
1735     tabWidgetPointer->toggleDeveloperTools(developerToolsActionPointer->isChecked());
1736 }
1737
1738 void BrowserWindow::toggleDomStorage() const
1739 {
1740     // Remove the focus from the URL line edit.
1741     urlLineEditPointer->clearFocus();
1742
1743     // Toggle DOM storage.
1744     tabWidgetPointer->toggleDomStorage();
1745 }
1746
1747 void BrowserWindow::toggleFindCaseSensitive() const
1748 {
1749     // Get the current find string.
1750     const QString findString = findTextLineEditPointer->text();
1751
1752     // Toggle find case sensitive.
1753     tabWidgetPointer->toggleFindCaseSensitive(findString);
1754 }
1755
1756 void BrowserWindow::toggleJavaScript() const
1757 {
1758     // Remove the focus from the URL line edit.
1759     urlLineEditPointer->clearFocus();
1760
1761     // Toggle JavaScript.
1762     tabWidgetPointer->toggleJavaScript();
1763 }
1764
1765 void BrowserWindow::toggleLocalStorage() const
1766 {
1767     // Remove the focus from the URL line edit.
1768     urlLineEditPointer->clearFocus();
1769
1770     // Toggle local storage.
1771     tabWidgetPointer->toggleLocalStorage();
1772 }
1773
1774 void BrowserWindow::toggleFullScreen()
1775 {
1776     // Toggle the full screen status.
1777     fullScreenRequested(fullScreenActionPointer->isChecked());
1778 }
1779
1780 void BrowserWindow::toggleViewSource() const
1781 {
1782     // Get the current URL.
1783     QString url = urlLineEditPointer->text();
1784
1785     // Toggle the URL.
1786     if (url.startsWith(QLatin1String("view-source:")))  // The source is currently being viewed.
1787     {
1788         // Remove `view-source:` from the URL.
1789         url = url.remove(0, 12);
1790     }
1791     else  // The source is not currently being viewed.
1792     {
1793         // Prepend `view-source:` from the URL.
1794         url = url.prepend(QLatin1String("view-source:"));
1795     }
1796
1797     // Make it so.
1798     loadUrlFromLineEdit(url);
1799 }
1800
1801 void BrowserWindow::toggleViewBookmarksToolBar()
1802 {
1803     // Store the current status of the bookmarks toolbar, which is used when exiting full screen browsing.
1804     bookmarksToolBarIsVisible = viewBookmarksToolBarActionPointer->isChecked();
1805
1806     // Update the visibility of the bookmarks toolbar.
1807     bookmarksToolBarPointer->setVisible(bookmarksToolBarIsVisible);
1808 }
1809
1810 void BrowserWindow::toggleViewSourceInNewTab() const
1811 {
1812     // Get the current URL.
1813     QString url = urlLineEditPointer->text();
1814
1815     // Toggle the URL.
1816     if (url.startsWith(QLatin1String("view-source:")))  // The source is currently being viewed.
1817     {
1818         // Remove `view-source:` from the URL.
1819         url = url.remove(0, 12);
1820     }
1821     else  // The source is not currently being viewed.
1822     {
1823         // Prepend `view-source:` from the URL.
1824         url = url.prepend(QLatin1String("view-source:"));
1825     }
1826
1827     // Add the new tab.  `true` removes the URL line edit focus, `true` opens the new tab in an adjacent tab.  `false` does not open a background tab.
1828     tabWidgetPointer->addTab(true, true, false, url);
1829 }
1830
1831 void BrowserWindow::updateBookmarkedAction() const
1832 {
1833     // Update the bookmarked action to reflect the current state.
1834     if (bookmarkedActionPointer->isChecked())
1835         bookmarkedActionPointer->setIcon(QIcon::fromTheme("starred-symbolic"));
1836     else
1837         bookmarkedActionPointer->setIcon(QIcon::fromTheme("non-starred-symbolic"));
1838 }
1839
1840 void BrowserWindow::updateCookiesAction(const int numberOfCookies) const
1841 {
1842     // Update the action text.
1843     cookiesActionPointer->setText(i18nc("The Cookies action, which also displays the number of cookies", "Cookies - %1", numberOfCookies));
1844 }
1845
1846 void BrowserWindow::updateDefaultZoomFactor(const double newDefaultZoomFactor)
1847 {
1848     // Store the new default zoom factor.
1849     defaultZoomFactor = newDefaultZoomFactor;
1850 }
1851
1852 void BrowserWindow::updateDomStorageAction(const bool &isEnabled) const
1853 {
1854     // Set the action checked status.
1855     domStorageActionPointer->setChecked(isEnabled);
1856 }
1857
1858 void BrowserWindow::updateDomainSettingsIndicator(const bool status)
1859 {
1860     // Set the domain palette according to the status.
1861     if (status)
1862         urlLineEditPointer->setPalette(positiveBackgroundPalette);
1863     else
1864         urlLineEditPointer->setPalette(normalBackgroundPalette);
1865 }
1866
1867 void BrowserWindow::updateFindText(const QString &text, const bool findCaseSensitive) const
1868 {
1869     // Set the text.
1870     findTextLineEditPointer->setText(text);
1871
1872     // Set the find case sensitive action checked status.
1873     findCaseSensitiveActionPointer->setChecked(findCaseSensitive);
1874 }
1875
1876 void BrowserWindow::updateFindTextResults(const QWebEngineFindTextResult &findTextResult) const
1877 {
1878     // Update the find text label.
1879     findTextLabelPointer->setText(QStringLiteral("  %1/%2  ").arg(findTextResult.activeMatch()).arg(findTextResult.numberOfMatches()));
1880
1881     // Set the background color according to the find status.
1882     if (findTextLineEditPointer->text().isEmpty())
1883         findTextLineEditPointer->setPalette(normalBackgroundPalette);
1884     else if (findTextResult.numberOfMatches() == 0)
1885         findTextLineEditPointer->setPalette(negativeBackgroundPalette);
1886     else
1887         findTextLineEditPointer->setPalette(positiveBackgroundPalette);
1888 }
1889
1890 void BrowserWindow::updateJavaScriptAction(const bool &isEnabled)
1891 {
1892     // Update the JavaScript status.
1893     javaScriptEnabled = isEnabled;
1894
1895     // Set the icon according to the status.
1896     if (javaScriptEnabled)
1897         javaScriptActionPointer->setIcon(QIcon(QLatin1String(":/icons/javascript-warning.svg")));
1898     else
1899         javaScriptActionPointer->setIcon(QIcon(QLatin1String(":/icons/privacy-mode.svg")));
1900
1901     // Set the action checked status.
1902     javaScriptActionPointer->setChecked(javaScriptEnabled);
1903
1904     // Update the status of the DOM storage action.
1905     domStorageActionPointer->setEnabled(javaScriptEnabled & localStorageEnabled);
1906 }
1907
1908 void BrowserWindow::updateLocalStorageAction(const bool &isEnabled)
1909 {
1910     // Update the local storage status.
1911     localStorageEnabled = isEnabled;
1912
1913     // 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.
1914     if (localStorageEnabled)
1915         localStorageActionPointer->setIcon(QIcon::fromTheme(QLatin1String("disk-quota-high"), QIcon(QLatin1String("/usr/share/icons/gnome/32x32/actions/document-save-as.png"))));
1916     else
1917         localStorageActionPointer->setIcon(QIcon::fromTheme(QLatin1String("disk-quota"), QIcon(QLatin1String("/usr/share/icons/gnome/32x32/apps/kfm.png"))));
1918
1919     // Set the action checked status.
1920     localStorageActionPointer->setChecked(localStorageEnabled);
1921
1922     // Update the status of the DOM storage action.
1923     domStorageActionPointer->setEnabled(localStorageEnabled & javaScriptEnabled);
1924 }
1925
1926 void BrowserWindow::updateSearchEngineActions(const QString &searchEngine, const bool &updateCustomSearchEngineStatus)
1927 {
1928     // Initialize the custom search engine flag.
1929     bool customSearchEngine = false;
1930
1931     if (searchEngine == "Mojeek")  // Mojeek.
1932     {
1933         // Check the Mojeek user agent action.
1934         searchEngineMojeekActionPointer->setChecked(true);
1935
1936         // Update the search engine menu action icon.
1937         searchEngineMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
1938
1939         // Update the search engine menu action text.
1940         searchEngineMenuActionPointer->setText(i18nc("The main search engine menu action", "Search Engine - Mojeek"));
1941     }
1942     else if (searchEngine == "Monocles")  // Monocles.
1943     {
1944         // Check the Monocles user agent action.
1945         searchEngineMonoclesActionPointer->setChecked(true);
1946
1947         // Update the search engine menu action icon.
1948         searchEngineMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
1949
1950         // Update the search engine menu action text.
1951         searchEngineMenuActionPointer->setText(i18nc("The main search engine menu action", "Search Engine - Monocles"));
1952     }
1953     else if (searchEngine == "MetaGer")  // MetaGer.
1954     {
1955         // Check the MetaGer user agent action.
1956         searchEngineMetagerActionPointer->setChecked(true);
1957
1958         // Update the search engine menu action icon.
1959         searchEngineMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
1960
1961         // Update the search engine menu action text.
1962         searchEngineMenuActionPointer->setText(i18nc("The main search engine menu action", "Search Engine - MetaGer"));
1963     }
1964     else if (searchEngine == "Google")  // Google.
1965     {
1966         // Check the Google user agent action.
1967         searchEngineGoogleActionPointer->setChecked(true);
1968
1969         // Update the search engine menu action icon.
1970         searchEngineMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("im-google"), QIcon::fromTheme(QLatin1String("edit-find"))));
1971
1972         // Update the search engine menu action text.
1973         searchEngineMenuActionPointer->setText(i18nc("The main search engine menu action", "Search Engine - Google"));
1974     }
1975     else if (searchEngine == "Bing")  // Bing.
1976     {
1977         // Check the Bing user agent action.
1978         searchEngineBingActionPointer->setChecked(true);
1979
1980         // Update the search engine menu action icon.
1981         searchEngineMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
1982
1983         // Update the search engine menu action text.
1984         searchEngineMenuActionPointer->setText(i18nc("The main search engine menu action", "Search Engine - Bing"));
1985     }
1986     else if (searchEngine == "Yahoo")  // Yahoo.
1987     {
1988         // Check the Yahoo user agent action.
1989         searchEngineYahooActionPointer->setChecked(true);
1990
1991         // Update the search engine menu action icon.
1992         searchEngineMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("im-yahoo"), QIcon::fromTheme(QLatin1String("edit-find"))));
1993
1994         // Update the search engine menu action text.
1995         searchEngineMenuActionPointer->setText(i18nc("The main search engine menu action", "Search Engine - Yahoo"));
1996     }
1997     else  // Custom search engine.
1998     {
1999         // Check the user agent.
2000         searchEngineCustomActionPointer->setChecked(true);
2001
2002         // Update the search engine menu action icon.
2003         searchEngineMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
2004
2005         // Update the search engine menu action text.
2006         searchEngineMenuActionPointer->setText(i18nc("The main search engine menu action", "Search Engine - Custom"));
2007
2008         // Set the custom search engine text.
2009         searchEngineCustomActionPointer->setText(searchEngine);
2010
2011         // Set the custom search engine flag.
2012         customSearchEngine = true;
2013     }
2014
2015     // Update the custom search engine enabled boolean.
2016     if (updateCustomSearchEngineStatus)
2017         customSearchEngineEnabled = customSearchEngine;
2018
2019     // Format the custom search engine.
2020     if (customSearchEngineEnabled)
2021     {
2022         // Enable the custom search engine.
2023         searchEngineCustomActionPointer->setEnabled(true);
2024     }
2025     else
2026     {
2027         // Disable the custom search engine.
2028         searchEngineCustomActionPointer->setEnabled(false);
2029
2030         // Reset the custom search engine text.
2031         searchEngineCustomActionPointer->setText(i18nc("@action", "Custom"));
2032     }
2033 }
2034
2035 void BrowserWindow::updateSearchEngineLabel(const QString &searchEngineString) const
2036 {
2037     // Update the search engine label.
2038     searchEngineLabelPointer->setText(SearchEngineHelper::getSearchUrl(searchEngineString));
2039 }
2040
2041 void BrowserWindow::updateUrlLineEdit(const QUrl &newUrl)
2042 {
2043     // Get the new URL string in encoded form, which displays punycode.
2044     QString newUrlString = newUrl.toEncoded();
2045
2046     // Update the view source actions.
2047     if (newUrlString.startsWith(QLatin1String("view-source:")))  // The source is currently being viewed.
2048     {
2049         // Mark the view source checkbox.
2050         viewSourceActionPointer->setChecked(true);
2051
2052         // Update the view in new tab action text.
2053         viewSourceInNewTabActionPointer->setText(i18nc("View rendered website in new tab action", "View Rendered Website in New Tab"));
2054     }
2055     else  // The source is not currently being viewed.
2056     {
2057         // Unmark the view source checkbox.
2058         viewSourceActionPointer->setChecked(false);
2059
2060         // Update the view in new tab action text.
2061         viewSourceInNewTabActionPointer->setText(i18nc("View source in new tab action", "View Source in New Tab"));
2062     }
2063
2064     // Update the URL line edit if it does not have focus.
2065     if (!urlLineEditPointer->hasFocus())
2066     {
2067         // Update the URL line edit.
2068         urlLineEditPointer->setText(newUrlString);
2069
2070         // Set the bookmarked action status.
2071         bookmarkedActionPointer->setChecked(BookmarksDatabase::isBookmarked(newUrlString));
2072
2073         // Update the bookmarked action.
2074         updateBookmarkedAction();
2075
2076         // Set the focus if the new URL is blank.
2077         if (newUrlString == QStringLiteral(""))
2078             urlLineEditPointer->setFocus();
2079     }
2080
2081     // Store the current URL.
2082     currentUrl = newUrl;
2083 }
2084
2085 void BrowserWindow::updateUserAgentActions(const QString &userAgent, const bool &updateCustomUserAgentStatus)
2086 {
2087     // Initialize the custom user agent flag.
2088     bool customUserAgent = false;
2089
2090     // Check the indicated on-the-fly user agent.
2091     if (userAgent == UserAgentHelper::PRIVACY_BROWSER_USER_AGENT)  // Privacy Browser.
2092     {
2093         // Check the Privacy Browser user agent action.
2094         userAgentPrivacyBrowserActionPointer->setChecked(true);
2095
2096         // Update the user agent menu action icon.
2097         userAgentMenuActionPointer->setIcon(QIcon(":/icons/privacy-mode.svg"));
2098
2099         // Update the user agent menu action text.
2100         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Privacy Browser"));
2101     }
2102     else if (userAgent == TabWidget::webEngineDefaultUserAgent)  // WebEngine default.
2103     {
2104         // check the WebEngine default user agent action.
2105         userAgentWebEngineDefaultActionPointer->setChecked(true);
2106
2107         // Update the user agent menu action icon.
2108         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("qtlogo"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new")))));
2109
2110         // Update the user agent menu action text.
2111         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - WebEngine default"));
2112     }
2113     else if (userAgent == UserAgentHelper::FIREFOX_LINUX_USER_AGENT)  // Firefox on Linux.
2114     {
2115         // Check the Firefox on Linux user agent action.
2116         userAgentFirefoxLinuxActionPointer->setChecked(true);
2117
2118         // Update the user agent menu action icon.
2119         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("firefox-esr"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new")))));
2120
2121         // Update the user agent menu action text.
2122         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Firefox on Linux"));
2123     }
2124     else if (userAgent == UserAgentHelper::CHROMIUM_LINUX_USER_AGENT)  // Chromium on Linux.
2125     {
2126         // Check the Chromium on Linux user agent action.
2127         userAgentChromiumLinuxActionPointer->setChecked(true);
2128
2129         // Update the user agent menu action icon.
2130         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("chromium"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new")))));
2131
2132         // Update the user agent menu action text.
2133         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Chromium on Linux"));
2134     }
2135     else if (userAgent == UserAgentHelper::FIREFOX_WINDOWS_USER_AGENT)  // Firefox on Windows.
2136     {
2137         // Check the Firefox on Windows user agent action.
2138         userAgentFirefoxWindowsActionPointer->setChecked(true);
2139
2140         // Update the user agent menu action icon.
2141         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("firefox-esr"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new")))));
2142
2143         // Update the user agent menu action text.
2144         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Firefox on Windows"));
2145     }
2146     else if (userAgent == UserAgentHelper::CHROME_WINDOWS_USER_AGENT)  // Chrome on Windows.
2147     {
2148         // Check the Chrome on Windows user agent action.
2149         userAgentChromeWindowsActionPointer->setChecked(true);
2150
2151         // Update the user agent menu action icon.
2152         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("chromium"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new")))));
2153
2154         // Update the user agent menu action text.
2155         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Chrome on Windows"));
2156     }
2157     else if (userAgent == UserAgentHelper::EDGE_WINDOWS_USER_AGENT)  // Edge on Windows.
2158     {
2159         // Check the Edge on Windows user agent action.
2160         userAgentEdgeWindowsActionPointer->setChecked(true);
2161
2162         // Update the user agent menu action icon.
2163         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new"))));
2164
2165         // Update the user agent menu action text.
2166         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Edge on Windows"));
2167     }
2168     else if (userAgent == UserAgentHelper::SAFARI_MACOS_USER_AGENT)  // Safari on macOS.
2169     {
2170         // Check the Safari on macOS user agent action.
2171         userAgentSafariMacosActionPointer->setChecked(true);
2172
2173         // Update the user agent menu action icon.
2174         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new"))));
2175
2176         // Update the user agent menu action text.
2177         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Safari on macOS"));
2178     }
2179     else  // Custom user agent.
2180     {
2181         // Check the user agent.
2182         userAgentCustomActionPointer->setChecked(true);
2183
2184         // Update the user agent menu action icon.
2185         userAgentMenuActionPointer->setIcon(QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new"))));
2186
2187         // Update the user agent menu action text.
2188         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Custom"));
2189
2190         // Set the custom user agent text.
2191         userAgentCustomActionPointer->setText(userAgent);
2192
2193         // Set the custom user agent flag.
2194         customUserAgent = true;
2195     }
2196
2197     // Update the custom user agent enabled boolean.
2198     // 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.
2199     if (updateCustomUserAgentStatus)
2200         customUserAgentEnabled = customUserAgent;
2201
2202
2203     // Format the custom user agent.
2204     if (customUserAgentEnabled)
2205     {
2206         // Enable the custom user agent.
2207         userAgentCustomActionPointer->setEnabled(true);
2208     }
2209     else
2210     {
2211         // Disable the custom user agent.
2212         userAgentCustomActionPointer->setEnabled(false);
2213
2214         // Reset the custom user agent text.
2215         userAgentCustomActionPointer->setText(i18nc("@action", "Custom"));
2216     }
2217 }
2218
2219 void BrowserWindow::updateUserAgentLabel(const QString &userAgentDatabaseName) const
2220 {
2221     // Update the user agent label.
2222     userAgentLabelPointer->setText(UserAgentHelper::getUserAgentFromDatabaseName(userAgentDatabaseName));
2223 }
2224
2225 void BrowserWindow::updateViewBookmarksToolBarCheckbox(const bool visible)
2226 {
2227     // Update the view bookmarks toolbar checkbox.
2228     viewBookmarksToolBarActionPointer->setChecked(visible);
2229
2230     // Initialize the bookmarks toolbar visibility tracker if Privacy Browser has just launched.
2231     if (bookmarksToolBarUninitialized)
2232     {
2233         // Set the initialization flag.
2234         bookmarksToolBarUninitialized = false;
2235
2236         // Store the current status of the bookmarks toolbar, which is used when exiting full screen browsing.
2237         bookmarksToolBarIsVisible = visible;
2238     }
2239 }
2240
2241 void BrowserWindow::updateWindowTitle(const QString &title)
2242 {
2243     // Update the window title.
2244     setWindowTitle(title);
2245 }
2246
2247 void BrowserWindow::updateZoomActions(const double &zoomFactor)
2248 {
2249     // Set the current zoom factor.
2250     currentZoomFactor = zoomFactor;
2251
2252     // Set the status of the default zoom action.
2253     zoomDefaultActionPointer->setEnabled(currentZoomFactor != defaultZoomFactor);
2254
2255     // Set the status of the zoom in action and button.
2256     zoomInActionPointer->setEnabled(currentZoomFactor <= 4.99);
2257     zoomPlusButtonPointer->setEnabled(currentZoomFactor <= 4.99);
2258
2259     // Set the status of the zoom out action and button.
2260     zoomMinusButtonPointer->setEnabled(currentZoomFactor > 0.25);
2261     zoomOutActionPointer->setEnabled(currentZoomFactor > 0.25);
2262
2263
2264     // 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.
2265     zoomFactorActionPointer->setText(ki18nc("The zoom factor action", "Zoom Factor - %1").subs(zoomFactor, 0, '0', 2).toString());
2266
2267     // Update the status bar zoom factor label.
2268     currentZoomButtonPointer->setText(ki18nc("The status bar zoom, which is just the formatted zoom factor", "%1").subs(zoomFactor, 0, '0', 2).toString());
2269 }
2270
2271 void BrowserWindow::zoomDefault()
2272 {
2273     // Set the new zoom factor.
2274     tabWidgetPointer->applyOnTheFlyZoomFactor(defaultZoomFactor);
2275
2276     // Update the on-the-fly action text.
2277     updateZoomActions(defaultZoomFactor);
2278 }