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