1 /* SPDX-License-Identifier: GPL-3.0-or-later
2 * SPDX-FileCopyrightText: 2022-2025 Soren Stoutner <soren@stoutner.com>
4 * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc/>.
6 * This program is free software: you can redistribute it and/or modify it under
7 * the terms of the GNU General Public License as published by the Free Software
8 * Foundation, either version 3 of the License, or (at your option) any later
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <https://www.gnu.org/licenses/>.
20 // Application headers.
21 #include "DevToolsWebEngineView.h"
22 #include "TabWidget.h"
24 #include "ui_AddTabWidget.h"
25 #include "ui_TabWidget.h"
26 #include "databases/CookiesDatabase.h"
27 #include "dialogs/SaveDialog.h"
28 #include "filters/MouseEventFilter.h"
29 #include "helpers/SearchEngineHelper.h"
30 #include "windows/BrowserWindow.h"
32 // KDE Framework headers.
33 #include <KIO/FileCopyJob>
34 #include <KIO/JobUiDelegate>
35 #include <KNotification>
37 // Qt toolkit headers.
39 #include <QFileDialog>
40 #include <QGraphicsScene>
41 #include <QGraphicsView>
42 #include <QMessageBox>
43 #include <QPrintDialog>
44 #include <QPrintPreviewDialog>
47 // Initialize the public static variables.
48 QString TabWidget::webEngineDefaultUserAgent = QLatin1String("");
50 // Construct the class.
51 TabWidget::TabWidget(QWidget *windowPointer) : QWidget(windowPointer)
53 // Create a QProcess to check if KDE is running.
54 QProcess *checkIfRunningKdeQProcessPointer = new QProcess();
56 // Create an argument string list that contains `ksmserver` (KDE Session Manager).
57 QStringList argument = QStringList(QLatin1String("ksmserver"));
59 // Run `pidof` to check for the presence of `ksmserver`.
60 checkIfRunningKdeQProcessPointer->start(QLatin1String("pidof"), argument);
62 // Monitor any standard output.
63 connect(checkIfRunningKdeQProcessPointer, &QProcess::readyReadStandardOutput, [this]
65 // If there is any standard output, `ksmserver` is running.
69 // Instantiate the user agent helper.
70 userAgentHelperPointer = new UserAgentHelper();
72 // Instantiate the UIs.
73 Ui::TabWidget tabWidgetUi;
74 Ui::AddTabWidget addTabWidgetUi;
77 tabWidgetUi.setupUi(this);
79 // Get a handle for the tab widget.
80 qTabWidgetPointer = tabWidgetUi.tabWidget;
82 // Setup the add tab UI.
83 addTabWidgetUi.setupUi(qTabWidgetPointer);
85 // Get handles for the add tab widgets.
86 QWidget *addTabWidgetPointer = addTabWidgetUi.addTabQWidget;
87 QPushButton *addTabButtonPointer = addTabWidgetUi.addTabButton;
89 // Display the add tab widget.
90 qTabWidgetPointer->setCornerWidget(addTabWidgetPointer);
92 // Create the loading favorite icon movie.
93 loadingFavoriteIconMoviePointer = new QMovie();
95 // Set the loading favorite icon movie file name.
96 loadingFavoriteIconMoviePointer->setFileName(QStringLiteral(":/icons/loading.gif"));
98 // Stop the loading favorite icon movie if the window is destroyed. Otherwise, the app will crash if there is more than one window open and a window is closed while at tab is loading.
99 connect(windowPointer, SIGNAL(destroyed()), this, SLOT(stopLoadingFavoriteIconMovie()));
101 // Add the first tab.
104 // Process tab events.
105 connect(qTabWidgetPointer, SIGNAL(currentChanged(int)), this, SLOT(updateUiWithTabSettings()));
106 connect(addTabButtonPointer, SIGNAL(clicked()), this, SLOT(addTab()));
107 connect(qTabWidgetPointer, SIGNAL(tabCloseRequested(int)), this, SLOT(deleteTab(int)));
109 // Store a copy of the WebEngine default user agent.
110 webEngineDefaultUserAgent = currentWebEngineProfilePointer->httpUserAgent();
112 // Instantiate the mouse event filter pointer.
113 MouseEventFilter *mouseEventFilterPointer = new MouseEventFilter();
115 // Install the mouse event filter.
116 qApp->installEventFilter(mouseEventFilterPointer);
118 // Process mouse forward and back commands.
119 connect(mouseEventFilterPointer, SIGNAL(mouseBack()), this, SLOT(mouseBack()));
120 connect(mouseEventFilterPointer, SIGNAL(mouseForward()), this, SLOT(mouseForward()));
123 TabWidget::~TabWidget()
125 // Get the number of tabs.
126 int numberOfTabs = qTabWidgetPointer->count();
128 // Manually delete each WebEngine page.
129 for (int i = 0; i < numberOfTabs; ++i)
131 // Get the tab splitter widget.
132 QWidget *tabSplitterWidgetPointer = qTabWidgetPointer->widget(i);
134 // Get the WebEngine views.
135 PrivacyWebEngineView *privacyWebEngineViewPointer = tabSplitterWidgetPointer->findChild<PrivacyWebEngineView *>();
136 DevToolsWebEngineView *devToolsWebEngineViewPointer = tabSplitterWidgetPointer->findChild<DevToolsWebEngineView *>();
138 // Deletion the WebEngine pages to prevent the following error: `Release of profile requested but WebEnginePage still not deleted. Expect troubles !`
139 delete privacyWebEngineViewPointer->page();
140 delete devToolsWebEngineViewPointer->page();
144 // The cookie is copied instead of referenced so that changes made to the cookie do not create a race condition with the display of the cookie in the dialog.
145 void TabWidget::addCookieToStore(QNetworkCookie cookie, QWebEngineCookieStore *webEngineCookieStorePointer) const
150 // Check to see if the domain does not start with a `.` because Qt makes this harder than it should be. <https://doc.qt.io/qt-5/qwebenginecookiestore.html#setCookie>
151 if (!cookie.domain().startsWith(QLatin1String(".")))
154 url.setHost(cookie.domain());
155 url.setScheme(QLatin1String("https"));
157 // Clear the domain from the cookie.
158 cookie.setDomain(QLatin1String(""));
161 // Add the cookie to the store.
162 if (webEngineCookieStorePointer == nullptr)
163 currentWebEngineCookieStorePointer->setCookie(cookie, url);
165 webEngineCookieStorePointer->setCookie(cookie, url);
168 void TabWidget::addFirstTab()
170 // Create the first tab.
173 // Update the UI with the tab settings.
174 updateUiWithTabSettings();
176 // Set the focus on the current tab widget. This prevents the tab bar from showing a blue bar under the label of the first tab.
177 qTabWidgetPointer->currentWidget()->setFocus();
180 PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const bool adjacent, const bool backgroundTab, const QString urlString)
182 // Create a splitter widget.
183 QSplitter *splitterPointer = new QSplitter();
185 // Set the splitter to be vertical.
186 splitterPointer->setOrientation(Qt::Vertical);
188 // Set the splitter handle size.
189 splitterPointer->setHandleWidth(5);
191 // Create the WebEngines.
192 PrivacyWebEngineView *privacyWebEngineViewPointer = new PrivacyWebEngineView();
193 DevToolsWebEngineView *devToolsWebEngineViewPointer = new DevToolsWebEngineView();
195 // Add the WebEngines to the splitter.
196 splitterPointer->addWidget(privacyWebEngineViewPointer);
197 splitterPointer->addWidget(devToolsWebEngineViewPointer);
199 // Initialize the new tab index.
203 if (adjacent) // Add the new tab adjacent to the current tab.
204 newTabIndex = qTabWidgetPointer->insertTab((qTabWidgetPointer->currentIndex() + 1), splitterPointer, i18nc("New tab label.", "New Tab"));
205 else // Add the new tab at the end of the list.
206 newTabIndex = qTabWidgetPointer->addTab(splitterPointer, i18nc("New tab label.", "New Tab"));
208 // Set the default tab icon.
209 qTabWidgetPointer->setTabIcon(newTabIndex, defaultFavoriteIcon);
211 // Get handles for the WebEngine components.
212 QWebEnginePage *webEnginePagePointer = privacyWebEngineViewPointer->page();
213 QWebEngineProfile *webEngineProfilePointer = webEnginePagePointer->profile();
214 QWebEngineCookieStore *webEngineCookieStorePointer = webEngineProfilePointer->cookieStore();
215 QWebEngineSettings *webEngineSettingsPointer = webEnginePagePointer->settings();
217 // Set the development tools WebEngine.
218 webEnginePagePointer->setDevToolsPage(devToolsWebEngineViewPointer->page());
220 // Initially hide the development tools WebEngine.
221 devToolsWebEngineViewPointer->setVisible(false);
223 // Initially disable the development tools WebEngine.
224 webEnginePagePointer->setDevToolsPage(nullptr);
226 // Disable JavaScript on the development tools WebEngine to prevent error messages from being written to the console.
227 devToolsWebEngineViewPointer->settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, false);
229 // Update the URL line edit when the URL changes.
230 connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::urlChanged, [this, privacyWebEngineViewPointer] (const QUrl &newUrl)
232 // Only update the UI if this is the current tab.
233 if (privacyWebEngineViewPointer == currentPrivacyWebEngineViewPointer)
235 // Update the URL line edit.
236 Q_EMIT updateUrlLineEdit(newUrl);
238 // Update the status of the forward and back buttons.
239 Q_EMIT updateBackAction(currentWebEngineHistoryPointer->canGoBack());
240 Q_EMIT updateForwardAction(currentWebEngineHistoryPointer->canGoForward());
244 // Update the title when it changes.
245 connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::titleChanged, [this, splitterPointer] (const QString &title)
247 // Get the index for this tab.
248 int tabIndex = qTabWidgetPointer->indexOf(splitterPointer);
250 // Update the title for this tab.
251 qTabWidgetPointer->setTabText(tabIndex, title);
253 // Update the window title if this is the current tab.
254 if (tabIndex == qTabWidgetPointer->currentIndex())
255 Q_EMIT updateWindowTitle(title);
258 // Connect the loading favorite icon movie to the tab icon.
259 connect(loadingFavoriteIconMoviePointer, &QMovie::frameChanged, [this, splitterPointer, privacyWebEngineViewPointer]
261 // Get the index for this tab.
262 int tabIndex = qTabWidgetPointer->indexOf(splitterPointer);
264 // Display the loading favorite icon if this tab is loading.
265 if (privacyWebEngineViewPointer->isLoading)
266 qTabWidgetPointer->setTabIcon(tabIndex, loadingFavoriteIconMoviePointer->currentPixmap());
269 // Update the icon when it changes.
270 connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::iconChanged, [this, splitterPointer, privacyWebEngineViewPointer] (const QIcon &newFavoriteIcon)
272 // Store the favorite icon in the privacy web engine view.
273 if (newFavoriteIcon.isNull())
274 privacyWebEngineViewPointer->favoriteIcon = defaultFavoriteIcon;
276 privacyWebEngineViewPointer->favoriteIcon = newFavoriteIcon;
278 // Get the index for this tab.
279 int tabIndex = qTabWidgetPointer->indexOf(splitterPointer);
281 // Update the icon for this tab.
282 if (newFavoriteIcon.isNull())
283 qTabWidgetPointer->setTabIcon(tabIndex, defaultFavoriteIcon);
285 qTabWidgetPointer->setTabIcon(tabIndex, newFavoriteIcon);
288 // Update the progress bar and the favorite icon when a load is started.
289 connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::loadStarted, [this, privacyWebEngineViewPointer] ()
291 // Set the privacy web engine view to be loading.
292 privacyWebEngineViewPointer->isLoading = true;
294 // Store the load progress.
295 privacyWebEngineViewPointer->loadProgressInt = 0;
297 // Show the progress bar if this is the current tab.
298 if (privacyWebEngineViewPointer == currentPrivacyWebEngineViewPointer)
299 Q_EMIT showProgressBar(0);
301 // Start the loading favorite icon movie.
302 loadingFavoriteIconMoviePointer->start();
305 // Update the progress bar when a load progresses.
306 connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::loadProgress, [this, privacyWebEngineViewPointer] (const int progress)
308 // Store the load progress.
309 privacyWebEngineViewPointer->loadProgressInt = progress;
311 // Update the progress bar if this is the current tab.
312 if (privacyWebEngineViewPointer == currentPrivacyWebEngineViewPointer)
313 Q_EMIT showProgressBar(progress);
316 // Update the progress bar when a load finishes.
317 connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::loadFinished, [this, splitterPointer, privacyWebEngineViewPointer] ()
319 // Set the privacy web engine view to be not loading.
320 privacyWebEngineViewPointer->isLoading = false;
322 // Store the load progress.
323 privacyWebEngineViewPointer->loadProgressInt = -1;
325 // Hide the progress bar if this is the current tab.
326 if (privacyWebEngineViewPointer == currentPrivacyWebEngineViewPointer)
327 Q_EMIT hideProgressBar();
329 // Get the index for this tab.
330 int tabIndex = qTabWidgetPointer->indexOf(splitterPointer);
332 // Display the current favorite icon
333 qTabWidgetPointer->setTabIcon(tabIndex, privacyWebEngineViewPointer->favoriteIcon);
335 // Create a no tabs loading variable.
336 bool noTabsLoading = true;
338 // Get the number of tabs.
339 int numberOfTabs = qTabWidgetPointer->count();
341 // Check to see if any other tabs are loading.
342 for (int i = 0; i < numberOfTabs; i++)
344 // Get the privacy WebEngine view for the tab.
345 PrivacyWebEngineView *privacyWebEngineViewPointer = qTabWidgetPointer->widget(i)->findChild<PrivacyWebEngineView *>();
347 // Check to see if it is currently loading. If at least one tab is loading, this flag will end up being marked `false` when the for loop has finished.
348 if (privacyWebEngineViewPointer->isLoading)
349 noTabsLoading = false;
352 // Stop the loading favorite icon movie if there are no loading tabs.
354 loadingFavoriteIconMoviePointer->stop();
357 // Display HTTP Ping blocked dialogs.
358 connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::displayHttpPingBlockedDialog, [this, privacyWebEngineViewPointer] (const QString &httpPingUrl)
360 // Only display the HTTP Ping blocked dialog if this is the current tab.
361 if (privacyWebEngineViewPointer == currentPrivacyWebEngineViewPointer)
363 // Instantiate an HTTP ping blocked message box.
364 QMessageBox httpPingBlockedMessageBox;
367 httpPingBlockedMessageBox.setIcon(QMessageBox::Information);
369 // Set the window title.
370 httpPingBlockedMessageBox.setWindowTitle(i18nc("HTTP Ping blocked dialog title", "HTTP Ping Blocked"));
373 httpPingBlockedMessageBox.setText(i18nc("HTTP Ping blocked dialog text", "This request has been blocked because it sends a naughty HTTP ping to %1.", httpPingUrl));
375 // Set the standard button.
376 httpPingBlockedMessageBox.setStandardButtons(QMessageBox::Ok);
378 // Display the message box.
379 httpPingBlockedMessageBox.exec();
383 // Update the zoom actions when they are changed.
384 connect(webEnginePagePointer, &QWebEnginePage::zoomFactorChanged, [webEnginePagePointer, this] (const qreal newZoomFactor)
386 // Only update the zoom actions if this is the current tab.
387 if (webEnginePagePointer == currentWebEnginePagePointer)
388 Q_EMIT updateZoomActions(newZoomFactor);
391 // Display find text results.
392 connect(webEnginePagePointer, SIGNAL(findTextFinished(const QWebEngineFindTextResult &)), this, SLOT(findTextFinished(const QWebEngineFindTextResult &)));
394 // Handle full screen requests.
395 connect(webEnginePagePointer, SIGNAL(fullScreenRequested(QWebEngineFullScreenRequest)), this, SLOT(fullScreenRequested(QWebEngineFullScreenRequest)));
397 // Listen for hovered link URLs.
398 connect(webEnginePagePointer, SIGNAL(linkHovered(const QString)), this, SLOT(pageLinkHovered(const QString)));
400 // Handle file downloads.
401 connect(webEngineProfilePointer, SIGNAL(downloadRequested(QWebEngineDownloadRequest *)), this, SLOT(showSaveDialog(QWebEngineDownloadRequest *)));
403 // Set the local storage filter.
404 webEngineCookieStorePointer->setCookieFilter([privacyWebEngineViewPointer](const QWebEngineCookieStore::FilterRequest &filterRequest)
406 // Block all third party local storage requests, including the sneaky ones that don't register a first party URL.
407 if (filterRequest.thirdParty || (filterRequest.firstPartyUrl == QUrl(QLatin1String(""))))
409 //qDebug().noquote().nospace() << "Third-party request blocked: " << filterRequest.origin;
415 // Allow the request if local storage is enabled.
416 if (privacyWebEngineViewPointer->localStorageEnabled)
418 //qDebug().noquote().nospace() << "Request allowed by local storage: " << filterRequest.origin;
424 //qDebug().noquote().nospace() << "Request blocked by default: " << filterRequest.origin;
426 // Block any remaining local storage requests.
430 // Disable JavaScript by default (this prevents JavaScript from being enabled on a new tab before domain settings are loaded).
431 webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, false);
433 // Don't allow JavaScript to open windows.
434 webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, false);
436 // Allow keyboard navigation between links and input fields.
437 webEngineSettingsPointer->setAttribute(QWebEngineSettings::SpatialNavigationEnabled, Settings::spatialNavigation());
439 // Enable full screen support.
440 webEngineSettingsPointer->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, true);
442 // Require user interaction to play media.
443 webEngineSettingsPointer->setAttribute(QWebEngineSettings::PlaybackRequiresUserGesture, true);
445 // Limit WebRTC to public IP addresses.
446 webEngineSettingsPointer->setAttribute(QWebEngineSettings::WebRTCPublicInterfacesOnly, true);
448 // Enable the PDF viewer (it should be enabled by default, but it is nice to be explicit in case the defaults change).
449 webEngineSettingsPointer->setAttribute(QWebEngineSettings::PdfViewerEnabled, true);
451 // Plugins must be enabled for the PDF viewer to work. <https://doc.qt.io/qt-5/qtwebengine-features.html#pdf-file-viewing>
452 webEngineSettingsPointer->setAttribute(QWebEngineSettings::PluginsEnabled, true);
454 // Allow JavaScript to paste to (but not copy from) the clipboard, but only with user interaction.
455 webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptCanAccessClipboard, true);
457 // Update the blocked requests action.
458 connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::requestBlocked, [this, privacyWebEngineViewPointer] (const QVector<int> blockedRequestsVector)
460 // Update the blocked requests action if the specified privacy WebEngine view is the current privacy WebEngine view.
461 if (privacyWebEngineViewPointer == currentPrivacyWebEngineViewPointer)
462 Q_EMIT blockedRequestsUpdated(blockedRequestsVector);
465 // Update the cookies action.
466 connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::numberOfCookiesChanged, [this, privacyWebEngineViewPointer] (const int numberOfCookies)
468 // Update the cookie action if the specified privacy WebEngine view is the current privacy WebEngine view.
469 if (privacyWebEngineViewPointer == currentPrivacyWebEngineViewPointer)
470 Q_EMIT cookiesChanged(numberOfCookies);
473 // Process cookie changes.
474 connect(webEngineCookieStorePointer, SIGNAL(cookieAdded(QNetworkCookie)), privacyWebEngineViewPointer, SLOT(addCookieToList(QNetworkCookie)));
475 connect(webEngineCookieStorePointer, SIGNAL(cookieRemoved(QNetworkCookie)), privacyWebEngineViewPointer, SLOT(removeCookieFromList(QNetworkCookie)));
477 // Get a list of durable cookies.
478 QList<QNetworkCookie*> *durableCookiesListPointer = CookiesDatabase::getCookies();
480 // Add the durable cookies to the store.
481 for (QNetworkCookie *cookiePointer : *durableCookiesListPointer)
482 addCookieToStore(*cookiePointer, webEngineCookieStorePointer);
484 // Enable spell checking.
485 webEngineProfilePointer->setSpellCheckEnabled(true);
487 // Set the spell check language.
488 webEngineProfilePointer->setSpellCheckLanguages(Settings::spellCheckLanguages());
490 // Populate the zoom factor. This is necessary if a URL is being loaded, like a local URL, that does not trigger `applyDomainSettings()`.
491 privacyWebEngineViewPointer->setZoomFactor(Settings::zoomFactor());
493 // Update the UI when domain settings are applied.
494 connect(privacyWebEngineViewPointer, SIGNAL(updateUi(const PrivacyWebEngineView*)), this, SLOT(updateUiFromWebEngineView(const PrivacyWebEngineView*)));
496 // Move to the new tab if it is not a background tab.
498 qTabWidgetPointer->setCurrentIndex(newTabIndex);
500 // Clear the URL line edit focus so that it populates correctly when opening a new tab from the context menu.
501 if (removeUrlLineEditFocus)
502 Q_EMIT clearUrlLineEditFocus();
504 // Load the URL if it isn't blank.
505 if (urlString != QLatin1String(""))
506 privacyWebEngineViewPointer->load(QUrl::fromUserInput(urlString));
508 // Return the privacy WebEngine view pointer.
509 return privacyWebEngineViewPointer;
512 void TabWidget::applyApplicationSettings()
514 // Set the tab position.
515 if (Settings::tabsOnTop())
516 qTabWidgetPointer->setTabPosition(QTabWidget::North);
518 qTabWidgetPointer->setTabPosition(QTabWidget::South);
520 // Get the number of tabs.
521 int numberOfTabs = qTabWidgetPointer->count();
523 // Apply the spatial navigation settings to each WebEngine.
524 for (int i = 0; i < numberOfTabs; ++i) {
525 // Get the WebEngine view pointer.
526 PrivacyWebEngineView *privacyWebEngineViewPointer = qTabWidgetPointer->widget(i)->findChild<PrivacyWebEngineView *>();
528 // Apply the spatial navigation settings to each page.
529 privacyWebEngineViewPointer->page()->settings()->setAttribute(QWebEngineSettings::SpatialNavigationEnabled, Settings::spatialNavigation());
532 // Set the search engine URL.
533 searchEngineUrl = SearchEngineHelper::getSearchUrl(Settings::searchEngine());
535 // Emit the update search engine actions signal.
536 Q_EMIT updateSearchEngineActions(Settings::searchEngine(), true);
539 void TabWidget::applyDomainSettingsAndReload()
541 // Get the number of tabs.
542 int numberOfTabs = qTabWidgetPointer->count();
544 // Apply the domain settings to each WebEngine.
545 for (int i = 0; i < numberOfTabs; ++i) {
546 // Get the WebEngine view pointer.
547 PrivacyWebEngineView *privacyWebEngineViewPointer = qTabWidgetPointer->widget(i)->findChild<PrivacyWebEngineView *>();
549 // Apply the domain settings settings to each page. `false` indicates that history is not being navigated.
550 privacyWebEngineViewPointer->applyDomainSettings(privacyWebEngineViewPointer->url(), false);
554 void TabWidget::applyOnTheFlySearchEngine(QAction *searchEngineActionPointer)
556 // Store the search engine name.
557 QString searchEngineName = searchEngineActionPointer->text();
559 // Strip out any `&` characters.
560 searchEngineName.remove(QLatin1Char('&'));
562 // Store the search engine string.
563 searchEngineUrl = SearchEngineHelper::getSearchUrl(searchEngineName);
565 // Update the search engine actions.
566 Q_EMIT updateSearchEngineActions(searchEngineName, false);
569 void TabWidget::applyOnTheFlyUserAgent(QAction *userAgentActionPointer) const
571 // Get the user agent name.
572 QString userAgentName = userAgentActionPointer->text();
574 // Strip out any `&` characters.
575 userAgentName.remove(QLatin1Char('&'));
577 // Apply the user agent.
578 currentWebEngineProfilePointer->setHttpUserAgent(userAgentHelperPointer->getUserAgentFromTranslatedName(userAgentName));
580 // Update the user agent actions.
581 Q_EMIT updateUserAgentActions(currentWebEngineProfilePointer->httpUserAgent(), false);
583 // Reload the website.
584 currentPrivacyWebEngineViewPointer->reload();
587 void TabWidget::applyOnTheFlyZoomFactor(const double zoomFactorDouble) const
589 // Set the zoom factor.
590 currentPrivacyWebEngineViewPointer->setZoomFactor(zoomFactorDouble);
593 void TabWidget::applySpellCheckLanguages() const
595 // Get the number of tab.
596 int numberOfTabs = qTabWidgetPointer->count();
598 // Set the spell check languages for each tab.
599 for (int i = 0; i < numberOfTabs; ++i)
601 // Get the WebEngine view pointer.
602 PrivacyWebEngineView *privacyWebEngineViewPointer = qTabWidgetPointer->widget(i)->findChild<PrivacyWebEngineView *>();
604 // Get the WebEngine page pointer.
605 QWebEnginePage *webEnginePagePointer = privacyWebEngineViewPointer->page();
607 // Get the WebEngine profile pointer.
608 QWebEngineProfile *webEngineProfilePointer = webEnginePagePointer->profile();
610 // Set the spell check languages.
611 webEngineProfilePointer->setSpellCheckLanguages(Settings::spellCheckLanguages());
615 void TabWidget::back() const
618 currentPrivacyWebEngineViewPointer->back();
621 void TabWidget::deleteAllCookies() const
623 // Delete all the cookies.
624 currentWebEngineCookieStorePointer->deleteAllCookies();
627 void TabWidget::deleteCookieFromStore(const QNetworkCookie &cookie) const
629 // Delete the cookie.
630 currentWebEngineCookieStorePointer->deleteCookie(cookie);
633 void TabWidget::deleteTab(const int tabIndex)
635 // Get the tab splitter widget.
636 QWidget *tabSplitterWidgetPointer = qTabWidgetPointer->widget(tabIndex);
638 // Get the WebEngine views.
639 PrivacyWebEngineView *privacyWebEngineViewPointer = tabSplitterWidgetPointer->findChild<PrivacyWebEngineView *>();
640 DevToolsWebEngineView *devToolsWebEngineViewPointer = tabSplitterWidgetPointer->findChild<DevToolsWebEngineView *>();
642 // Process the tab delete according to the number of tabs.
643 if (qTabWidgetPointer->count() > 1) // There is more than one tab.
646 qTabWidgetPointer->removeTab(tabIndex);
648 // Delete the WebEngine pages to prevent the following error: `Release of profile requested but WebEnginePage still not deleted. Expect troubles !`
649 delete privacyWebEngineViewPointer->page();
650 delete devToolsWebEngineViewPointer->page();
652 // Delete the WebEngine views.
653 delete privacyWebEngineViewPointer;
654 delete devToolsWebEngineViewPointer;
656 // Delete the tab splitter widget.
657 delete tabSplitterWidgetPointer;
659 else // There is only one tab.
661 // Close Privacy Browser.
666 void TabWidget::findPrevious(const QString &text) const
668 // Store the current text.
669 currentPrivacyWebEngineViewPointer->findString = text;
671 // Find the previous text in the current privacy WebEngine.
672 if (currentPrivacyWebEngineViewPointer->findCaseSensitive)
673 currentPrivacyWebEngineViewPointer->findText(text, QWebEnginePage::FindCaseSensitively|QWebEnginePage::FindBackward);
675 currentPrivacyWebEngineViewPointer->findText(text, QWebEnginePage::FindBackward);
678 void TabWidget::findText(const QString &text) const
680 // Store the current text.
681 currentPrivacyWebEngineViewPointer->findString = text;
683 // Find the text in the current privacy WebEngine.
684 if (currentPrivacyWebEngineViewPointer->findCaseSensitive)
685 currentPrivacyWebEngineViewPointer->findText(text, QWebEnginePage::FindCaseSensitively);
687 currentPrivacyWebEngineViewPointer->findText(text);
689 // Clear the currently selected text in the WebEngine page if the find text is empty.
691 currentWebEnginePagePointer->action(QWebEnginePage::Unselect)->activate(QAction::Trigger);
694 void TabWidget::findTextFinished(const QWebEngineFindTextResult &findTextResult)
696 // Update the find text UI if it wasn't simply wiping the current find text selection. Otherwise the UI temporarily flashes `0/0`.
697 if (wipingCurrentFindTextSelection) // The current selection is being wiped.
700 wipingCurrentFindTextSelection = false;
702 else // A new search has been performed.
705 currentPrivacyWebEngineViewPointer->findTextResult = findTextResult;
708 Q_EMIT updateFindTextResults(findTextResult);
712 void TabWidget::forward() const
715 currentPrivacyWebEngineViewPointer->forward();
718 void TabWidget::fullScreenRequested(QWebEngineFullScreenRequest fullScreenRequest) const
721 Q_EMIT fullScreenRequested(fullScreenRequest.toggleOn());
723 // Accept the request.
724 fullScreenRequest.accept();
727 std::list<QNetworkCookie>* TabWidget::getCookieList() const
729 // Return the current cookie list.
730 return currentPrivacyWebEngineViewPointer->cookieListPointer;
733 QIcon TabWidget::getCurrentTabFavoritIcon() const
735 // Return the current Privacy WebEngine favorite icon.
736 return currentPrivacyWebEngineViewPointer->favoriteIcon;
739 QString TabWidget::getCurrentTabTitle() const
741 // Return the current Privacy WebEngine title.
742 return currentPrivacyWebEngineViewPointer->title();
745 QString TabWidget::getCurrentTabUrl() const
747 // Return the current Privacy WebEngine URL as a string.
748 return currentPrivacyWebEngineViewPointer->url().toString();
751 QString TabWidget::getCurrentUserAgent() const
753 // Return the current WebEngine user agent.
754 return currentWebEngineProfilePointer->httpUserAgent();
757 QString& TabWidget::getDomainSettingsName() const
759 // Return the domain settings name.
760 return currentPrivacyWebEngineViewPointer->domainSettingsName;
763 void TabWidget::home() const
765 // Load the homepage.
766 currentPrivacyWebEngineViewPointer->load(QUrl::fromUserInput(Settings::homepage()));
769 PrivacyWebEngineView* TabWidget::loadBlankInitialWebsite()
771 // Apply the application settings.
772 applyApplicationSettings();
774 // Return the current privacy WebEngine view pointer.
775 return currentPrivacyWebEngineViewPointer;
778 void TabWidget::loadInitialWebsite()
780 // Apply the application settings.
781 applyApplicationSettings();
783 // Get the arguments.
784 QStringList argumentsStringList = qApp->arguments();
786 // Check to see if the arguments lists contains a URL.
787 if (argumentsStringList.size() > 1)
789 // Load the URL from the arguments list.
790 currentPrivacyWebEngineViewPointer->load(QUrl::fromUserInput(argumentsStringList.at(1)));
794 // Load the homepage.
799 void TabWidget::loadUrlFromLineEdit(QString url) const
801 // Decide if the text is more likely to be a URL or a search.
802 if (url.startsWith(QLatin1String("file://")) || url.startsWith(QLatin1String("view-source:"))) // The text is likely a file or view source URL.
805 currentPrivacyWebEngineViewPointer->load(QUrl::fromUserInput(url));
807 else if (url.contains(QLatin1String("."))) // The text is likely a URL.
809 // Check if the URL does not start with a valid protocol.
810 if (!url.startsWith(QLatin1String("http")))
812 // Add `https://` to the beginning of the URL.
813 url = QLatin1String("https://") + url;
817 currentPrivacyWebEngineViewPointer->load(QUrl::fromUserInput(url));
819 else // The text is likely a search.
822 currentPrivacyWebEngineViewPointer->load(QUrl::fromUserInput(searchEngineUrl + url));
826 void TabWidget::mouseBack() const
828 // Go back if possible.
829 if (currentPrivacyWebEngineViewPointer->isActiveWindow() && currentWebEngineHistoryPointer->canGoBack())
831 // Clear the URL line edit focus.
832 Q_EMIT clearUrlLineEditFocus();
835 currentPrivacyWebEngineViewPointer->back();
839 void TabWidget::mouseForward() const
841 // Go forward if possible.
842 if (currentPrivacyWebEngineViewPointer->isActiveWindow() && currentWebEngineHistoryPointer->canGoForward())
844 // Clear the URL line edit focus.
845 Q_EMIT clearUrlLineEditFocus();
848 currentPrivacyWebEngineViewPointer->forward();
852 void TabWidget::pageLinkHovered(const QString &linkUrl) const
854 // Emit a signal so that the browser window can update the status bar.
855 Q_EMIT linkHovered(linkUrl);
858 void TabWidget::stopLoadingFavoriteIconMovie() const
860 // Stop the loading favorite icon movie. Otherwise, the browser will crash if a second window is closed while a tab in it is loading. <https://redmine.stoutner.com/issues/1010>
861 loadingFavoriteIconMoviePointer->stop();
864 void TabWidget::print() const
867 QPrinter *printerPointer = new QPrinter();
869 // Set the resolution to be 300 dpi.
870 printerPointer->setResolution(300);
872 // Create a printer dialog.
873 QPrintDialog printDialog(printerPointer, currentPrivacyWebEngineViewPointer);
875 // Display the dialog and print the page if instructed.
876 if (printDialog.exec() == QDialog::Accepted)
877 currentPrivacyWebEngineViewPointer->print(printerPointer);
880 void TabWidget::printPreview() const
883 QPrinter *printerPointer = new QPrinter();
885 // Set the resolution to be 300 dpi.
886 printerPointer->setResolution(300);
888 // Create a print preview dialog.
889 QPrintPreviewDialog printPreviewDialog(printerPointer, currentPrivacyWebEngineViewPointer);
891 // Generate the print preview.
892 auto generatePrintPreview = [this, printerPointer](){
893 // Create an event loop. The print preview must be generated in a loop or nothing is displayed.
894 QEventLoop eventLoop;
896 // Quit the event loop once the print preview has been generated.
897 connect(currentPrivacyWebEngineViewPointer, &QWebEngineView::printFinished, &eventLoop, &QEventLoop::quit);
899 // Generate the print preview for the current webpage.
900 currentPrivacyWebEngineViewPointer->print(printerPointer);
906 // Generate the preview.
907 connect(&printPreviewDialog, &QPrintPreviewDialog::paintRequested, this, generatePrintPreview);
909 // Display the dialog.
910 printPreviewDialog.exec();
913 void TabWidget::refresh() const
915 // Reset the HTTP authentication dialog counter.
916 currentPrivacyWebEngineViewPointer->httpAuthenticationDialogsDisplayed = 0;
918 // Reload the website.
919 currentPrivacyWebEngineViewPointer->reload();
922 void TabWidget::reloadAndBypassCache() const
924 // Reload the website, bypassing the cache.
925 currentWebEnginePagePointer->triggerAction(QWebEnginePage::ReloadAndBypassCache);
928 void TabWidget::saveArchive()
930 // Get the suggested file name.
931 QString suggestedFileName = currentPrivacyWebEngineViewPointer->title() + QLatin1String(".mht");
933 // Get the download directory.
934 QString downloadDirectory = Settings::downloadDirectory();
936 // Resolve the system download directory if specified.
937 if (downloadDirectory == QLatin1String("System Download Directory"))
938 downloadDirectory = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
940 // Get a file path from the file picker.
941 QString saveFilePath = QFileDialog::getSaveFileName(this, i18nc("Save file dialog caption", "Save File"), downloadDirectory + QLatin1Char('/') + suggestedFileName);
943 // Save the webpage as an archive if the file save path is populated.
944 if (!saveFilePath.isEmpty())
946 // Update the download directory if specified.
947 if (Settings::autoUpateDownloadDirectory())
948 updateDownloadDirectory(saveFilePath);
950 // Set the saving archive flag. Otherwise, a second download tries to run.
951 savingArchive = true;
954 currentWebEnginePagePointer->save(saveFilePath);
958 void TabWidget::setTabBarVisible(const bool visible) const
960 // Set the tab bar visibility.
961 qTabWidgetPointer->tabBar()->setVisible(visible);
964 void TabWidget::showSaveDialog(QWebEngineDownloadRequest *webEngineDownloadRequestPointer)
966 // Only show the save dialog if an archive is not currently being saved. Otherwise, two save dialogs will be shown.
969 // Get the download attributes.
970 QUrl downloadUrl = webEngineDownloadRequestPointer->url();
971 QString mimeTypeString = webEngineDownloadRequestPointer->mimeType();
972 QString suggestedFileName = webEngineDownloadRequestPointer->suggestedFileName();
973 int totalBytes = webEngineDownloadRequestPointer->totalBytes();
975 // Check to see if Privacy Browser is not running KDE or if local storage (cookies) is enabled.
976 if (!isRunningKde || currentPrivacyWebEngineViewPointer->localStorageEnabled) // KDE is not running or local storage (cookies) is enabled. Use WebEngine's downloader.
978 // Instantiate the save dialog.
979 SaveDialog *saveDialogPointer = new SaveDialog(this, downloadUrl, mimeTypeString, totalBytes);
981 // Display the save dialog.
982 int saveDialogResult = saveDialogPointer->exec();
984 // Process the save dialog results.
985 if (saveDialogResult == QDialog::Accepted) // Save was selected.
987 // Get the download directory.
988 QString downloadDirectory = Settings::downloadDirectory();
990 // Resolve the system download directory if specified.
991 if (downloadDirectory == QLatin1String("System Download Directory"))
992 downloadDirectory = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
994 // Get a file path from the file picker.
995 QString saveFilePath = QFileDialog::getSaveFileName(this, i18nc("Save file dialog caption", "Save File"), downloadDirectory + QLatin1Char('/') + suggestedFileName);
997 // Process the save file path.
998 if (!saveFilePath.isEmpty()) // The file save path is populated.
1000 // Update the download directory if specified.
1001 if (Settings::autoUpateDownloadDirectory())
1002 updateDownloadDirectory(saveFilePath);
1004 // Create a save file path file info.
1005 QFileInfo saveFilePathFileInfo = QFileInfo(saveFilePath);
1007 // Get the canonical save path and file name.
1008 QString absoluteSavePath = saveFilePathFileInfo.absolutePath();
1009 QString saveFileName = saveFilePathFileInfo.fileName();
1011 // Set the download directory and file name.
1012 webEngineDownloadRequestPointer->setDownloadDirectory(absoluteSavePath);
1013 webEngineDownloadRequestPointer->setDownloadFileName(saveFileName);
1015 // Create a file download notification.
1016 KNotification *fileDownloadNotificationPointer = new KNotification(QLatin1String("FileDownload"));
1018 // Set the notification title.
1019 fileDownloadNotificationPointer->setTitle(i18nc("Download notification title", "Download"));
1021 // Set the notification text.
1022 fileDownloadNotificationPointer->setText(i18nc("Downloading notification text", "Downloading %1", saveFileName));
1024 // Get the download icon from the theme.
1025 QIcon downloadIcon = QIcon::fromTheme(QLatin1String("download"), QIcon::fromTheme(QLatin1String("document-save")));
1027 // Set the notification icon.
1028 fileDownloadNotificationPointer->setIconName(downloadIcon.name());
1030 // Add the cancel action.
1031 KNotificationAction *cancelActionPointer = fileDownloadNotificationPointer->addDefaultAction(i18nc("Download notification action","Cancel"));
1033 // Prevent the notification from being autodeleted if it is closed. Otherwise, the updates to the notification below cause a crash.
1034 fileDownloadNotificationPointer->setAutoDelete(false);
1036 // Handle clicks on the cancel action.
1037 connect(cancelActionPointer, &KNotificationAction::activated, [webEngineDownloadRequestPointer, saveFileName] ()
1039 // Cancel the download.
1040 webEngineDownloadRequestPointer->cancel();
1042 // Create a file download notification.
1043 KNotification *canceledDownloadNotificationPointer = new KNotification(QLatin1String("FileDownload"));
1045 // Set the notification title.
1046 canceledDownloadNotificationPointer->setTitle(i18nc("Download notification title", "Download"));
1048 // Set the new text.
1049 canceledDownloadNotificationPointer->setText(i18nc("Download canceled notification", "%1 download canceled", saveFileName));
1051 // Set the notification icon.
1052 canceledDownloadNotificationPointer->setIconName(QLatin1String("download"));
1054 // Display the notification.
1055 canceledDownloadNotificationPointer->sendEvent();
1058 // Update the notification when the download progresses.
1059 connect(webEngineDownloadRequestPointer, &QWebEngineDownloadRequest::receivedBytesChanged, [webEngineDownloadRequestPointer, fileDownloadNotificationPointer, saveFileName] ()
1061 // Get the download request information.
1062 qint64 receivedBytes = webEngineDownloadRequestPointer->receivedBytes();
1063 qint64 totalBytes = webEngineDownloadRequestPointer->totalBytes();
1065 // Set the new text. Total bytes will be 0 if the download size is unknown.
1068 // Calculate the download percentage.
1069 int downloadPercentage = 100 * receivedBytes / totalBytes;
1071 // Set the file download notification text.
1072 fileDownloadNotificationPointer->setText(i18nc("Download progress notification text", "%1%% of %2 downloaded (%3 of %4 bytes)", downloadPercentage, saveFileName,
1073 receivedBytes, totalBytes));
1077 // Set the file download notification text.
1078 fileDownloadNotificationPointer->setText(i18nc("Download progress notification text", "%1: %2 bytes downloaded", saveFileName, receivedBytes));
1081 // Display the updated notification.
1082 fileDownloadNotificationPointer->sendEvent();
1085 // Update the notification when the download finishes. The save file name must be copied into the lambda or a crash occurs.
1086 connect(webEngineDownloadRequestPointer, &QWebEngineDownloadRequest::isFinishedChanged, [webEngineDownloadRequestPointer, fileDownloadNotificationPointer, saveFileName,
1089 // Update the notification if the download is finished.
1090 if (webEngineDownloadRequestPointer->isFinished())
1092 // Set the new text.
1093 fileDownloadNotificationPointer->setText(i18nc("Download finished notification text", "%1 download finished", saveFileName));
1095 // Set the URL so the file options will be displayed.
1096 fileDownloadNotificationPointer->setUrls(QList<QUrl> {QUrl(saveFilePath)});
1098 // Remove the actions from the notification.
1099 fileDownloadNotificationPointer->clearActions();
1101 // Set the notification to disappear after a timeout.
1102 fileDownloadNotificationPointer->setFlags(KNotification::CloseOnTimeout);
1104 // Display the updated notification.
1105 fileDownloadNotificationPointer->sendEvent();
1109 // Display the notification.
1110 fileDownloadNotificationPointer->sendEvent();
1112 // Start the download.
1113 webEngineDownloadRequestPointer->accept();
1115 else // The file save path is not populated.
1117 // Cancel the download.
1118 webEngineDownloadRequestPointer->cancel();
1121 else // Cancel was selected.
1123 // Cancel the download.
1124 webEngineDownloadRequestPointer->cancel();
1127 else // KDE is running and local storage (cookies) is disabled. Use KDE's native downloader.
1128 // This must use the show command to launch a separate dialog which cancels WebEngine's automatic background download of the file to a temporary location.
1130 // Instantiate the save dialog. `true` instructs it to use the native downloader
1131 SaveDialog *saveDialogPointer = new SaveDialog(this, downloadUrl, mimeTypeString, totalBytes, suggestedFileName, true);
1133 // Connect the save button.
1134 connect(saveDialogPointer, SIGNAL(useNativeKdeDownloader(QUrl &, QString &)), this, SLOT(useNativeKdeDownloader(QUrl &, QString &)));
1137 saveDialogPointer->show();
1141 // Reset the saving archive flag.
1142 savingArchive = false;
1145 void TabWidget::stop() const
1147 // Stop the loading of the current privacy WebEngine.
1148 currentPrivacyWebEngineViewPointer->stop();
1151 void TabWidget::storeCurrentUrlText(const QString &urlText) const
1153 // Store the current URL text in the privacy WebEngine view.
1154 currentPrivacyWebEngineViewPointer->currentUrlText = urlText;
1157 void TabWidget::toggleDeveloperTools(const bool enabled) const
1159 // Get handles for the current tab widgets.
1160 QSplitter *splitterPointer = qobject_cast<QSplitter*>(qTabWidgetPointer->currentWidget());
1161 DevToolsWebEngineView *devToolsWebEngineViewPointer = splitterPointer->findChild<DevToolsWebEngineView *>();
1165 // Set the zoom factor on the development tools WebEngine.
1166 devToolsWebEngineViewPointer->setZoomFactor(currentWebEnginePagePointer->zoomFactor());
1168 // Enable the development tools.
1169 currentWebEnginePagePointer->setDevToolsPage(devToolsWebEngineViewPointer->page());
1171 // Enable JavaScript on the development tools WebEngine.
1172 devToolsWebEngineViewPointer->settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, true);
1174 // Display the developer tools.
1175 devToolsWebEngineViewPointer->setVisible(true);
1177 // Split the visible space equally between the main WebEngine and the developer tools WebEngine.
1178 splitterPointer->setSizes(QList<int>({1, 1}));
1182 // Disable JavaScript on the development tools WebEngine to prevent error messages from being written to the console.
1183 devToolsWebEngineViewPointer->settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, false);
1185 // Disable the development tools.
1186 currentWebEnginePagePointer->setDevToolsPage(nullptr);
1188 // Hide the developer tools.
1189 devToolsWebEngineViewPointer->setVisible(false);
1193 void TabWidget::toggleDomStorage() const
1195 // Toggle DOM storage.
1196 currentWebEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, !currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::LocalStorageEnabled));
1198 // Update the DOM storage action.
1199 Q_EMIT updateDomStorageAction(currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::LocalStorageEnabled));
1201 // Reload the website.
1202 currentPrivacyWebEngineViewPointer->reload();
1205 void TabWidget::toggleEasyList() const
1208 currentPrivacyWebEngineViewPointer->easyListEnabled = !currentPrivacyWebEngineViewPointer->easyListEnabled;
1210 // Reload the website.
1211 currentPrivacyWebEngineViewPointer->reload();
1214 void TabWidget::toggleEasyPrivacy() const
1216 // Toggle EasyPrivacy.
1217 currentPrivacyWebEngineViewPointer->easyPrivacyEnabled = !currentPrivacyWebEngineViewPointer->easyPrivacyEnabled;
1219 // Reload the website.
1220 currentPrivacyWebEngineViewPointer->reload();
1223 void TabWidget::toggleFanboysAnnoyanceList() const
1225 // Toggle Fanboy's Annoyance List.
1226 currentPrivacyWebEngineViewPointer->fanboysAnnoyanceListEnabled = !currentPrivacyWebEngineViewPointer->fanboysAnnoyanceListEnabled;
1228 // Reload the website.
1229 currentPrivacyWebEngineViewPointer->reload();
1232 void TabWidget::toggleFindCaseSensitive(const QString &text)
1234 // Toggle find case sensitive.
1235 currentPrivacyWebEngineViewPointer->findCaseSensitive = !currentPrivacyWebEngineViewPointer->findCaseSensitive;
1237 // Set the wiping current find text selection flag.
1238 wipingCurrentFindTextSelection = true;
1240 // Wipe the previous search. Otherwise currently highlighted words will remain highlighted.
1241 findText(QLatin1String(""));
1243 // Update the find text.
1247 void TabWidget::toggleJavaScript() const
1249 // Toggle JavaScript.
1250 currentWebEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, !currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::JavascriptEnabled));
1252 // Update the JavaScript action.
1253 Q_EMIT updateJavaScriptAction(currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::JavascriptEnabled));
1255 // Reload the website.
1256 currentPrivacyWebEngineViewPointer->reload();
1259 void TabWidget::toggleLocalStorage()
1261 // Toggle local storage.
1262 currentPrivacyWebEngineViewPointer->localStorageEnabled = !currentPrivacyWebEngineViewPointer->localStorageEnabled;
1264 // Update the local storage action.
1265 Q_EMIT updateLocalStorageAction(currentPrivacyWebEngineViewPointer->localStorageEnabled);
1267 // Reload the website.
1268 currentPrivacyWebEngineViewPointer->reload();
1271 void TabWidget::toggleUltraList() const
1273 // Toggle UltraList.
1274 currentPrivacyWebEngineViewPointer->ultraListEnabled = !currentPrivacyWebEngineViewPointer->ultraListEnabled;
1276 // Reload the website.
1277 currentPrivacyWebEngineViewPointer->reload();
1280 void TabWidget::toggleUltraPrivacy() const
1282 // Toggle UltraPrivacy.
1283 currentPrivacyWebEngineViewPointer->ultraPrivacyEnabled = !currentPrivacyWebEngineViewPointer->ultraPrivacyEnabled;
1285 // Reload the website.
1286 currentPrivacyWebEngineViewPointer->reload();
1289 void TabWidget::updateDownloadDirectory(QString newDownloadDirectory) const
1291 // Remove the file name from the save file path.
1292 newDownloadDirectory.truncate(newDownloadDirectory.lastIndexOf(QLatin1Char('/')));
1294 // Update the download location.
1295 Settings::setDownloadDirectory(newDownloadDirectory);
1297 // Get a handle for the KConfig skeleton.
1298 KConfigSkeleton *kConfigSkeletonPointer = Settings::self();
1300 // Write the settings to disk.
1301 kConfigSkeletonPointer->save();
1304 void TabWidget::updateUiFromWebEngineView(const PrivacyWebEngineView *privacyWebEngineViewPointer) const
1306 // Only update the UI if the signal was emitted from the current privacy WebEngine.
1307 if (privacyWebEngineViewPointer == currentPrivacyWebEngineViewPointer)
1310 Q_EMIT easyListStatusChanged(currentPrivacyWebEngineViewPointer->easyListEnabled);
1311 Q_EMIT easyPrivacyStatusChanged(currentPrivacyWebEngineViewPointer->easyPrivacyEnabled);
1312 Q_EMIT fanboysAnnoyanceListStatusChanged(currentPrivacyWebEngineViewPointer->fanboysAnnoyanceListEnabled);
1313 Q_EMIT ultraListStatusChanged(currentPrivacyWebEngineViewPointer->ultraListEnabled);
1314 Q_EMIT ultraPrivacyStatusChanged(currentPrivacyWebEngineViewPointer->ultraPrivacyEnabled);
1315 Q_EMIT updateDefaultZoomFactor(currentPrivacyWebEngineViewPointer->defaultZoomFactor);
1316 Q_EMIT updateDomainSettingsIndicator(currentPrivacyWebEngineViewPointer->domainSettingsName != QLatin1String(""));
1317 Q_EMIT updateJavaScriptAction(currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::JavascriptEnabled));
1318 Q_EMIT updateLocalStorageAction(currentPrivacyWebEngineViewPointer->localStorageEnabled);
1319 Q_EMIT updateDomStorageAction(currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::LocalStorageEnabled));
1320 Q_EMIT updateUserAgentActions(currentWebEngineProfilePointer->httpUserAgent(), true);
1321 Q_EMIT updateZoomActions(currentPrivacyWebEngineViewPointer->zoomFactor());
1325 void TabWidget::updateUiWithTabSettings()
1327 // Clear the URL line edit focus.
1328 Q_EMIT clearUrlLineEditFocus();
1330 // Update the current WebEngine pointers.
1331 currentPrivacyWebEngineViewPointer = qTabWidgetPointer->currentWidget()->findChild<PrivacyWebEngineView *>();
1332 currentWebEngineSettingsPointer = currentPrivacyWebEngineViewPointer->settings();
1333 currentWebEnginePagePointer = currentPrivacyWebEngineViewPointer->page();
1334 currentWebEngineProfilePointer = currentWebEnginePagePointer->profile();
1335 currentWebEngineHistoryPointer = currentWebEnginePagePointer->history();
1336 currentWebEngineCookieStorePointer = currentWebEngineProfilePointer->cookieStore();
1338 // Get a handle for the development tools WebEngine view.
1339 DevToolsWebEngineView *devToolsWebEngineViewPointer = qTabWidgetPointer->currentWidget()->findChild<DevToolsWebEngineView *>();
1341 // Update the actions.
1342 Q_EMIT easyListStatusChanged(currentPrivacyWebEngineViewPointer->easyListEnabled);
1343 Q_EMIT easyPrivacyStatusChanged(currentPrivacyWebEngineViewPointer->easyPrivacyEnabled);
1344 Q_EMIT fanboysAnnoyanceListStatusChanged(currentPrivacyWebEngineViewPointer->fanboysAnnoyanceListEnabled);
1345 Q_EMIT ultraListStatusChanged(currentPrivacyWebEngineViewPointer->ultraListEnabled);
1346 Q_EMIT ultraPrivacyStatusChanged(currentPrivacyWebEngineViewPointer->ultraPrivacyEnabled);
1347 Q_EMIT blockedRequestsUpdated(currentPrivacyWebEngineViewPointer->blockedRequestsVector);
1348 Q_EMIT cookiesChanged(currentPrivacyWebEngineViewPointer->cookieListPointer->size());
1349 Q_EMIT updateBackAction(currentWebEngineHistoryPointer->canGoBack());
1350 Q_EMIT updateDefaultZoomFactor(currentPrivacyWebEngineViewPointer->defaultZoomFactor);
1351 Q_EMIT updateDeveloperToolsAction(devToolsWebEngineViewPointer->isVisible());
1352 Q_EMIT updateDomStorageAction(currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::LocalStorageEnabled));
1353 Q_EMIT updateForwardAction(currentWebEngineHistoryPointer->canGoForward());
1354 Q_EMIT updateJavaScriptAction(currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::JavascriptEnabled));
1355 Q_EMIT updateLocalStorageAction(currentPrivacyWebEngineViewPointer->localStorageEnabled);
1356 Q_EMIT updateUserAgentActions(currentWebEngineProfilePointer->httpUserAgent(), true);
1357 Q_EMIT updateZoomActions(currentPrivacyWebEngineViewPointer->zoomFactor());
1359 // Update the find text.
1360 Q_EMIT updateFindText(currentPrivacyWebEngineViewPointer->findString, currentPrivacyWebEngineViewPointer->findCaseSensitive);
1361 Q_EMIT updateFindTextResults(currentPrivacyWebEngineViewPointer->findTextResult);
1363 // Update the progress bar.
1364 if (currentPrivacyWebEngineViewPointer->loadProgressInt >= 0)
1365 Q_EMIT showProgressBar(currentPrivacyWebEngineViewPointer->loadProgressInt);
1367 Q_EMIT hideProgressBar();
1370 Q_EMIT updateWindowTitle(currentPrivacyWebEngineViewPointer->title());
1371 Q_EMIT updateDomainSettingsIndicator(currentPrivacyWebEngineViewPointer->domainSettingsName != QLatin1String(""));
1372 Q_EMIT updateUrlLineEdit(QUrl(currentPrivacyWebEngineViewPointer->currentUrlText));
1375 void TabWidget::useNativeKdeDownloader(QUrl &downloadUrl, QString &suggestedFileName)
1377 // Get the download directory.
1378 QString downloadDirectory = Settings::downloadDirectory();
1380 // Resolve the system download directory if specified.
1381 if (downloadDirectory == QLatin1String("System Download Directory"))
1382 downloadDirectory = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
1384 // Create a save file dialog.
1385 QFileDialog *saveFileDialogPointer = new QFileDialog(this, i18nc("Save file dialog caption", "Save File"), downloadDirectory);
1387 // Tell the dialog to use a save button.
1388 saveFileDialogPointer->setAcceptMode(QFileDialog::AcceptSave);
1390 // Populate the file name from the download item pointer.
1391 saveFileDialogPointer->selectFile(suggestedFileName);
1393 // Prevent interaction with the parent window while the dialog is open.
1394 saveFileDialogPointer->setWindowModality(Qt::WindowModal);
1396 // Process the saving of the file. The save file dialog pointer must be captured directly instead of by reference or nasty crashes occur.
1397 auto saveFile = [saveFileDialogPointer, downloadUrl, this] ()
1399 // Get the save location. The dialog box should only allow the selecting of one file location.
1400 QUrl saveLocation = saveFileDialogPointer->selectedUrls().value(0);
1402 // Update the download directory if specified.
1403 if (Settings::autoUpateDownloadDirectory())
1404 updateDownloadDirectory(saveLocation.toLocalFile());
1406 // Create a file copy job. `-1` creates the file with default permissions.
1407 KIO::FileCopyJob *fileCopyJobPointer = KIO::file_copy(downloadUrl, saveLocation, -1, KIO::Overwrite);
1409 // Set the download job to display any warning and error messages.
1410 fileCopyJobPointer->uiDelegate()->setAutoWarningHandlingEnabled(true);
1411 fileCopyJobPointer->uiDelegate()->setAutoErrorHandlingEnabled(true);
1413 // Start the download.
1414 fileCopyJobPointer->start();
1417 // Handle clicks on the save button.
1418 connect(saveFileDialogPointer, &QDialog::accepted, this, saveFile);
1421 saveFileDialogPointer->show();