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