/*
- * Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
+ * Copyright 2022-2023 Soren Stoutner <soren@stoutner.com>.
*
* This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
*
#include "ui_AddTabWidget.h"
#include "ui_TabWidget.h"
#include "databases/CookiesDatabase.h"
-#include "databases/DomainsDatabase.h"
#include "dialogs/SaveDialog.h"
#include "filters/MouseEventFilter.h"
#include "helpers/SearchEngineHelper.h"
-#include "helpers/UserAgentHelper.h"
-#include "interceptors/UrlRequestInterceptor.h"
#include "windows/BrowserWindow.h"
// KDE Framework headers.
#include <KIO/FileCopyJob>
#include <KIO/JobUiDelegate>
+#include <KNotification>
// Qt toolkit headers.
#include <QAction>
#include <QFileDialog>
#include <QGraphicsScene>
#include <QGraphicsView>
+#include <QMessageBox>
#include <QPrintDialog>
#include <QPrintPreviewDialog>
#include <QPrinter>
// Initialize the public static variables.
-QString TabWidget::webEngineDefaultUserAgent = QStringLiteral("");
+QString TabWidget::webEngineDefaultUserAgent = QLatin1String("");
// Construct the class.
-TabWidget::TabWidget(QWidget *parent) : QWidget(parent)
+TabWidget::TabWidget(QWidget *windowPointer) : QWidget(windowPointer)
{
+ // Create a QProcess to check if KDE is running.
+ QProcess *checkIfRunningKdeQProcessPointer = new QProcess();
+
+ // Create an argument string list that contains `ksmserver` (KDE Session Manager).
+ QStringList argument = QStringList(QLatin1String("ksmserver"));
+
+ // Run `pidof` to check for the presence of `ksmserver`.
+ checkIfRunningKdeQProcessPointer->start(QLatin1String("pidof"), argument);
+
+ // Monitor any standard output.
+ connect(checkIfRunningKdeQProcessPointer, &QProcess::readyReadStandardOutput, [this]
+ {
+ // If there is any standard output, `ksmserver` is running.
+ isRunningKde = true;
+ });
+
+ // Instantiate the user agent helper.
+ userAgentHelperPointer = new UserAgentHelper();
+
// Instantiate the UIs.
Ui::TabWidget tabWidgetUi;
Ui::AddTabWidget addTabWidgetUi;
tabWidgetUi.setupUi(this);
// Get a handle for the tab widget.
- tabWidgetPointer = tabWidgetUi.tabWidget;
+ qTabWidgetPointer = tabWidgetUi.tabWidget;
// Setup the add tab UI.
- addTabWidgetUi.setupUi(tabWidgetPointer);
+ addTabWidgetUi.setupUi(qTabWidgetPointer);
// Get handles for the add tab widgets.
QWidget *addTabWidgetPointer = addTabWidgetUi.addTabQWidget;
QPushButton *addTabButtonPointer = addTabWidgetUi.addTabButton;
// Display the add tab widget.
- tabWidgetPointer->setCornerWidget(addTabWidgetPointer);
+ qTabWidgetPointer->setCornerWidget(addTabWidgetPointer);
+
+ // Create the loading favorite icon movie.
+ loadingFavoriteIconMoviePointer = new QMovie();
+
+ // Set the loading favorite icon movie file name.
+ loadingFavoriteIconMoviePointer->setFileName(QStringLiteral(":/icons/loading.gif"));
+
+ // 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.
+ connect(windowPointer, SIGNAL(destroyed()), this, SLOT(stopLoadingFavoriteIconMovie()));
// Add the first tab.
addFirstTab();
// Process tab events.
- connect(tabWidgetPointer, SIGNAL(currentChanged(int)), this, SLOT(updateUiWithTabSettings()));
+ connect(qTabWidgetPointer, SIGNAL(currentChanged(int)), this, SLOT(updateUiWithTabSettings()));
connect(addTabButtonPointer, SIGNAL(clicked()), this, SLOT(addTab()));
- connect(tabWidgetPointer, SIGNAL(tabCloseRequested(int)), this, SLOT(deleteTab(int)));
+ connect(qTabWidgetPointer, SIGNAL(tabCloseRequested(int)), this, SLOT(deleteTab(int)));
// Store a copy of the WebEngine default user agent.
webEngineDefaultUserAgent = currentWebEngineProfilePointer->httpUserAgent();
TabWidget::~TabWidget()
{
+ // Get the number of tabs.
+ int numberOfTabs = qTabWidgetPointer->count();
+
// Manually delete each WebEngine page.
- for (int i = 0; i < tabWidgetPointer->count(); ++i)
+ for (int i = 0; i < numberOfTabs; ++i)
{
// Get the privacy WebEngine view.
- PrivacyWebEngineView *privacyWebEngineViewPointer = qobject_cast<PrivacyWebEngineView *>(tabWidgetPointer->widget(i));
+ PrivacyWebEngineView *privacyWebEngineViewPointer = qobject_cast<PrivacyWebEngineView *>(qTabWidgetPointer->widget(i));
// Deletion the WebEngine page to prevent the following error: `Release of profile requested but WebEnginePage still not deleted. Expect troubles !`
delete privacyWebEngineViewPointer->page();
// 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.
void TabWidget::addCookieToStore(QNetworkCookie cookie, QWebEngineCookieStore *webEngineCookieStorePointer) const
{
- // Create a url.
+ // Create a URL.
QUrl url;
// 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>
- if (!cookie.domain().startsWith(QStringLiteral(".")))
+ if (!cookie.domain().startsWith(QLatin1String(".")))
{
// Populate the URL.
url.setHost(cookie.domain());
- url.setScheme(QStringLiteral("https"));
+ url.setScheme(QLatin1String("https"));
// Clear the domain from the cookie.
- cookie.setDomain(QStringLiteral(""));
+ cookie.setDomain(QLatin1String(""));
}
// Add the cookie to the store.
updateUiWithTabSettings();
// 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.
- tabWidgetPointer->currentWidget()->setFocus();
+ qTabWidgetPointer->currentWidget()->setFocus();
}
-PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const bool backgroundTab)
+PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const bool backgroundTab, const QString urlString)
{
// Create a privacy WebEngine view.
PrivacyWebEngineView *privacyWebEngineViewPointer = new PrivacyWebEngineView();
// Add a new tab.
- int newTabIndex = tabWidgetPointer->addTab(privacyWebEngineViewPointer, i18nc("New tab label.", "New Tab"));
+ int newTabIndex = qTabWidgetPointer->addTab(privacyWebEngineViewPointer, i18nc("New tab label.", "New Tab"));
// Set the default tab icon.
- tabWidgetPointer->setTabIcon(newTabIndex, defaultTabIcon);
-
- // Create an off-the-record profile (the default when no profile name is specified).
- QWebEngineProfile *webEngineProfilePointer = new QWebEngineProfile(QStringLiteral(""));
+ qTabWidgetPointer->setTabIcon(newTabIndex, defaultFavoriteIcon);
- // Create a WebEngine page.
- QWebEnginePage *webEnginePagePointer = new QWebEnginePage(webEngineProfilePointer);
-
- // Set the WebEngine page.
- privacyWebEngineViewPointer->setPage(webEnginePagePointer);
+ // Get handles for the WebEngine page and profile.
+ QWebEnginePage *webEnginePagePointer = privacyWebEngineViewPointer->page();
+ QWebEngineProfile *webEngineProfilePointer = webEnginePagePointer->profile();
// Get handles for the web engine elements.
QWebEngineCookieStore *webEngineCookieStorePointer = webEngineProfilePointer->cookieStore();
QWebEngineSettings *webEngineSettingsPointer = webEnginePagePointer->settings();
// Update the URL line edit when the URL changes.
- connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::urlChanged, [privacyWebEngineViewPointer, this] (const QUrl &newUrl)
+ connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::urlChanged, [this, privacyWebEngineViewPointer] (const QUrl &newUrl)
{
// Only update the UI if this is the current tab.
if (privacyWebEngineViewPointer == currentPrivacyWebEngineViewPointer)
emit updateBackAction(currentWebEngineHistoryPointer->canGoBack());
emit updateForwardAction(currentWebEngineHistoryPointer->canGoForward());
}
+ });
+
+ // Update the title when it changes.
+ connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::titleChanged, [this, privacyWebEngineViewPointer] (const QString &title)
+ {
+ // Get the index for this tab.
+ int tabIndex = qTabWidgetPointer->indexOf(privacyWebEngineViewPointer);
+
+ // Update the title for this tab.
+ qTabWidgetPointer->setTabText(tabIndex, title);
+
+ // Update the window title if this is the current tab.
+ if (tabIndex == qTabWidgetPointer->currentIndex())
+ emit updateWindowTitle(title);
+ });
+
+ // Connect the loading favorite icon movie to the tab icon.
+ connect(loadingFavoriteIconMoviePointer, &QMovie::frameChanged, [this, privacyWebEngineViewPointer]
+ {
+ // Get the index for this tab.
+ int tabIndex = qTabWidgetPointer->indexOf(privacyWebEngineViewPointer);
- // Reapply the zoom factor. This is a bug in QWebEngineView that resets the zoom with every load. It can be removed once <https://redmine.stoutner.com/issues/799> is fixed.
- privacyWebEngineViewPointer->setZoomFactor(currentZoomFactor);
+ // Display the loading favorite icon if this tab is loading.
+ if (privacyWebEngineViewPointer->isLoading)
+ qTabWidgetPointer->setTabIcon(tabIndex, loadingFavoriteIconMoviePointer->currentPixmap());
});
- // Update the progress bar when a load is started.
- connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::loadStarted, [privacyWebEngineViewPointer, this] ()
+ // Update the icon when it changes.
+ connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::iconChanged, [this, privacyWebEngineViewPointer] (const QIcon &newFavoriteIcon)
{
+ // Store the favorite icon in the privacy web engine view.
+ if (newFavoriteIcon.isNull())
+ privacyWebEngineViewPointer->favoriteIcon = defaultFavoriteIcon;
+ else
+ privacyWebEngineViewPointer->favoriteIcon = newFavoriteIcon;
+
+ // Get the index for this tab.
+ int tabIndex = qTabWidgetPointer->indexOf(privacyWebEngineViewPointer);
+
+ // Update the icon for this tab.
+ if (newFavoriteIcon.isNull())
+ qTabWidgetPointer->setTabIcon(tabIndex, defaultFavoriteIcon);
+ else
+ qTabWidgetPointer->setTabIcon(tabIndex, newFavoriteIcon);
+ });
+
+ // Update the progress bar and the favorite icon when a load is started.
+ connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::loadStarted, [this, privacyWebEngineViewPointer] ()
+ {
+ // Set the privacy web engine view to be loading.
+ privacyWebEngineViewPointer->isLoading = true;
+
// Store the load progress.
privacyWebEngineViewPointer->loadProgressInt = 0;
// Show the progress bar if this is the current tab.
if (privacyWebEngineViewPointer == currentPrivacyWebEngineViewPointer)
emit showProgressBar(0);
+
+ // Start the loading favorite icon movie.
+ loadingFavoriteIconMoviePointer->start();
});
// Update the progress bar when a load progresses.
- connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::loadProgress, [privacyWebEngineViewPointer, this] (const int progress)
+ connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::loadProgress, [this, privacyWebEngineViewPointer] (const int progress)
{
// Store the load progress.
privacyWebEngineViewPointer->loadProgressInt = progress;
});
// Update the progress bar when a load finishes.
- connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::loadFinished, [privacyWebEngineViewPointer, this] ()
+ connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::loadFinished, [this, privacyWebEngineViewPointer] ()
{
+ // Set the privacy web engine view to be not loading.
+ privacyWebEngineViewPointer->isLoading = false;
+
// Store the load progress.
privacyWebEngineViewPointer->loadProgressInt = -1;
// Hide the progress bar if this is the current tab.
if (privacyWebEngineViewPointer == currentPrivacyWebEngineViewPointer)
emit hideProgressBar();
+
+ // Get the index for this tab.
+ int tabIndex = qTabWidgetPointer->indexOf(privacyWebEngineViewPointer);
+
+ // Display the current favorite icon
+ qTabWidgetPointer->setTabIcon(tabIndex, privacyWebEngineViewPointer->favoriteIcon);
+
+ // Create a no tabs loading variable.
+ bool noTabsLoading = true;
+
+ // Get the number of tabs.
+ int numberOfTabs = qTabWidgetPointer->count();
+
+ // Check to see if any other tabs are loading.
+ for (int i = 0; i < numberOfTabs; i++)
+ {
+ // Get the privacy WebEngine view for the tab.
+ PrivacyWebEngineView *privacyWebEngineViewPointer = qobject_cast<PrivacyWebEngineView*>(qTabWidgetPointer->widget(i));
+
+ // 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.
+ if (privacyWebEngineViewPointer->isLoading)
+ noTabsLoading = false;
+ }
+
+ // Stop the loading favorite icon movie if there are no loading tabs.
+ if (noTabsLoading)
+ loadingFavoriteIconMoviePointer->stop();
+ });
+
+ // Display HTTP Ping blocked dialogs.
+ connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::displayHttpPingBlockedDialog, [this, privacyWebEngineViewPointer] (const QString &httpPingUrl)
+ {
+ // Only display the HTTP Ping blocked dialog if this is the current tab.
+ if (privacyWebEngineViewPointer == currentPrivacyWebEngineViewPointer)
+ {
+ // Instantiate an HTTP ping blocked message box.
+ QMessageBox httpPingBlockedMessageBox;
+
+ // Set the icon.
+ httpPingBlockedMessageBox.setIcon(QMessageBox::Information);
+
+ // Set the window title.
+ httpPingBlockedMessageBox.setWindowTitle(i18nc("HTTP Ping blocked dialog title", "HTTP Ping Blocked"));
+
+ // Set the text.
+ httpPingBlockedMessageBox.setText(i18nc("HTTP Ping blocked dialog text", "This request has been blocked because it sends a naughty HTTP ping to %1.", httpPingUrl));
+
+ // Set the standard button.
+ httpPingBlockedMessageBox.setStandardButtons(QMessageBox::Ok);
+
+ // Display the message box.
+ httpPingBlockedMessageBox.exec();
+ }
+ });
+
+ // Update the zoom actions when changed by CTRL-Scrolling. This can be modified when <https://redmine.stoutner.com/issues/845> is fixed.
+ connect(webEnginePagePointer, &QWebEnginePage::contentsSizeChanged, [webEnginePagePointer, this] ()
+ {
+ // Only update the zoom actions if this is the current tab.
+ if (webEnginePagePointer == currentWebEnginePagePointer)
+ emit updateZoomActions(webEnginePagePointer->zoomFactor());
});
// Display find text results.
// Handle file downloads.
connect(webEngineProfilePointer, SIGNAL(downloadRequested(QWebEngineDownloadItem *)), this, SLOT(showSaveDialog(QWebEngineDownloadItem *)));
- // Instantiate the URL request interceptor.
- UrlRequestInterceptor *urlRequestInterceptorPointer = new UrlRequestInterceptor();
-
- // Set the URL request interceptor.
- webEngineProfilePointer->setUrlRequestInterceptor(urlRequestInterceptorPointer);
-
- // Reapply the domain settings when the host changes.
- connect(urlRequestInterceptorPointer, SIGNAL(applyDomainSettings(QString)), this, SLOT(applyDomainSettingsWithoutReloading(QString)));
-
// Set the local storage filter.
webEngineCookieStorePointer->setCookieFilter([privacyWebEngineViewPointer](const QWebEngineCookieStore::FilterRequest &filterRequest)
{
return false;
});
- // Disable JavaScript by default (this prevetns JavaScript from being enabled on a new tab before domain settings are loaded).
+ // Disable JavaScript by default (this prevents JavaScript from being enabled on a new tab before domain settings are loaded).
webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, false);
// Don't allow JavaScript to open windows.
webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, false);
- // Allow keyboard navigation.
- webEngineSettingsPointer->setAttribute(QWebEngineSettings::SpatialNavigationEnabled, true);
+ // Allow keyboard navigation between links and input fields.
+ webEngineSettingsPointer->setAttribute(QWebEngineSettings::SpatialNavigationEnabled, Settings::spatialNavigation());
// Enable full screen support.
webEngineSettingsPointer->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, true);
// Limit WebRTC to public IP addresses.
webEngineSettingsPointer->setAttribute(QWebEngineSettings::WebRTCPublicInterfacesOnly, true);
+ // Enable the PDF viewer (it should be enabled by default, but it is nice to be explicit in case the defaults change).
+ webEngineSettingsPointer->setAttribute(QWebEngineSettings::PdfViewerEnabled, true);
+
+ // Plugins must be enabled for the PDF viewer to work. <https://doc.qt.io/qt-5/qtwebengine-features.html#pdf-file-viewing>
+ webEngineSettingsPointer->setAttribute(QWebEngineSettings::PluginsEnabled, true);
+
// Update the cookies action.
- connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::updateCookiesAction, [privacyWebEngineViewPointer, this] (const int numberOfCookies)
+ connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::updateCookiesAction, [this, privacyWebEngineViewPointer] (const int numberOfCookies)
{
// Update the cookie action if the specified privacy WebEngine view is the current privacy WebEngine view.
if (privacyWebEngineViewPointer == currentPrivacyWebEngineViewPointer)
for (QNetworkCookie *cookiePointer : *durableCookiesListPointer)
addCookieToStore(*cookiePointer, webEngineCookieStorePointer);
- // Update the title when it changes.
- connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::titleChanged, [this, privacyWebEngineViewPointer] (const QString &title)
- {
- // Get the index for this tab.
- int tabIndex = tabWidgetPointer->indexOf(privacyWebEngineViewPointer);
-
- // Update the title for this tab.
- tabWidgetPointer->setTabText(tabIndex, title);
-
- // Update the window title if this is the current tab.
- if (tabIndex == tabWidgetPointer->currentIndex())
- emit updateWindowTitle(title);
- });
-
- // Update the icon when it changes.
- connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::iconChanged, [privacyWebEngineViewPointer, this] (const QIcon &icon)
- {
- // Get the index for this tab.
- int tabIndex = tabWidgetPointer->indexOf(privacyWebEngineViewPointer);
-
- // Update the icon for this tab.
- if (icon.isNull())
- tabWidgetPointer->setTabIcon(tabIndex, defaultTabIcon);
- else
- tabWidgetPointer->setTabIcon(tabIndex, icon);
- });
-
// Enable spell checking.
webEngineProfilePointer->setSpellCheckEnabled(true);
// Set the spell check language.
- webEngineProfilePointer->setSpellCheckLanguages({QStringLiteral("en_US")});
+ webEngineProfilePointer->setSpellCheckLanguages(Settings::spellCheckLanguages());
// Populate the zoom factor. This is necessary if a URL is being loaded, like a local URL, that does not trigger `applyDomainSettings()`.
privacyWebEngineViewPointer->setZoomFactor(Settings::zoomFactor());
+ // Update the UI when domain settings are applied.
+ connect(privacyWebEngineViewPointer, SIGNAL(updateUi(const PrivacyWebEngineView*)), this, SLOT(updateUiFromWebEngineView(const PrivacyWebEngineView*)));
+
// Move to the new tab if it is not a background tab.
if (!backgroundTab)
- tabWidgetPointer->setCurrentIndex(newTabIndex);
+ qTabWidgetPointer->setCurrentIndex(newTabIndex);
// Clear the URL line edit focus so that it populates correctly when opening a new tab from the context menu.
if (removeUrlLineEditFocus)
emit clearUrlLineEditFocus();
+ if (urlString != nullptr)
+ privacyWebEngineViewPointer->load(QUrl::fromUserInput(urlString));
+
// Return the privacy WebEngine view pointer.
return privacyWebEngineViewPointer;
}
{
// Set the tab position.
if (Settings::tabsOnTop())
- tabWidgetPointer->setTabPosition(QTabWidget::North);
+ qTabWidgetPointer->setTabPosition(QTabWidget::North);
else
- tabWidgetPointer->setTabPosition(QTabWidget::South);
+ qTabWidgetPointer->setTabPosition(QTabWidget::South);
+
+ // Get the number of tabs.
+ int numberOfTabs = qTabWidgetPointer->count();
+
+ // Apply the spatial navigation settings to each WebEngine.
+ for (int i = 0; i < numberOfTabs; ++i) {
+ // Get the WebEngine view pointer.
+ PrivacyWebEngineView *privacyWebEngineViewPointer = qobject_cast<PrivacyWebEngineView *>(qTabWidgetPointer->widget(i));
+
+ // Apply the spatial navigation settings to each page.
+ privacyWebEngineViewPointer->page()->settings()->setAttribute(QWebEngineSettings::SpatialNavigationEnabled, Settings::spatialNavigation());
+ }
// Set the search engine URL.
searchEngineUrl = SearchEngineHelper::getSearchUrl(Settings::searchEngine());
emit updateSearchEngineActions(Settings::searchEngine(), true);
}
-// This exists as a separate function from `applyDomainSettings()` so it can be listed as a slot and function without the need for a boolean argument.
-// Once <https://redmine.stoutner.com/issues/799> has been resolved this can be `const`.
void TabWidget::applyDomainSettingsAndReload()
{
- // Apply the domain settings. `true` reloads the website.
- applyDomainSettings(currentPrivacyWebEngineViewPointer->url().host(), true);
-}
-
-// This exists as a separate function from `applyDomainSettings()` so it can be listed as a slot and function without the need for a boolean argument.
-// Once <https://redmine.stoutner.com/issues/799> has been resolved this can be `const`.
-void TabWidget::applyDomainSettingsWithoutReloading(const QString &hostname)
-{
- // Apply the domain settings `false` does not reload the website.
- applyDomainSettings(hostname, false);
-}
-
-// Once <https://redmine.stoutner.com/issues/799> has been resolved this can be `const`.
-void TabWidget::applyDomainSettings(const QString &hostname, const bool reloadWebsite)
-{
- // Get the record for the hostname.
- QSqlQuery domainQuery = DomainsDatabase::getDomainQuery(hostname);
-
- // Check if the hostname has domain settings.
- if (domainQuery.isValid()) // The hostname has domain settings.
- {
- // Get the domain record.
- QSqlRecord domainRecord = domainQuery.record();
-
- // Store the domain settings name.
- currentPrivacyWebEngineViewPointer->domainSettingsName = domainRecord.field(DomainsDatabase::DOMAIN_NAME).value().toString();
-
- // Set the JavaScript status.
- switch (domainRecord.field(DomainsDatabase::JAVASCRIPT).value().toInt())
- {
- // Set the default JavaScript status.
- case (DomainsDatabase::SYSTEM_DEFAULT):
- {
- currentWebEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, Settings::javaScriptEnabled());
-
- break;
- }
-
- // Disable JavaScript.
- case (DomainsDatabase::DISABLED):
- {
- currentWebEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, false);
-
- break;
- }
-
- // Enable JavaScript.
- case (DomainsDatabase::ENABLED):
- {
- currentWebEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, true);
-
- break;
- }
- }
-
- // Set the local storage status.
- switch (domainRecord.field(DomainsDatabase::LOCAL_STORAGE).value().toInt())
- {
- // Set the default local storage status.
- case (DomainsDatabase::SYSTEM_DEFAULT):
- {
- currentPrivacyWebEngineViewPointer->localStorageEnabled = Settings::localStorageEnabled();
-
- break;
- }
-
- // Disable local storage.
- case (DomainsDatabase::DISABLED):
- {
- currentPrivacyWebEngineViewPointer->localStorageEnabled = false;
-
- break;
- }
-
- // Enable local storage.
- case (DomainsDatabase::ENABLED):
- {
- currentPrivacyWebEngineViewPointer->localStorageEnabled = true;
-
- break;
- }
- }
-
- // Set the DOM storage status.
- switch (domainRecord.field(DomainsDatabase::DOM_STORAGE).value().toInt())
- {
- // Set the default DOM storage status.
- case (DomainsDatabase::SYSTEM_DEFAULT):
- {
- currentWebEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, Settings::domStorageEnabled());
-
- break;
- }
-
- // Disable DOM storage.
- case (DomainsDatabase::DISABLED):
- {
- currentWebEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, false);
-
- break;
- }
+ // Get the number of tabs.
+ int numberOfTabs = qTabWidgetPointer->count();
- // Enable DOM storage.
- case (DomainsDatabase::ENABLED):
- {
- currentWebEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, true);
-
- break;
- }
- }
-
- // Set the user agent.
- currentWebEngineProfilePointer->setHttpUserAgent(UserAgentHelper::getResultingDomainSettingsUserAgent(domainRecord.field(DomainsDatabase::USER_AGENT).value().toString()));
-
- // Check if a custom zoom factor is set.
- if (domainRecord.field(DomainsDatabase::ZOOM_FACTOR).value().toInt())
- {
- // Store the current zoom factor.
- currentZoomFactor = domainRecord.field(DomainsDatabase::CUSTOM_ZOOM_FACTOR).value().toDouble();
- }
- else
- {
- // Reset the current zoom factor.
- currentZoomFactor = Settings::zoomFactor();
- }
-
- // Set the zoom factor. The use of `currentZoomFactor` can be removed once <https://redmine.stoutner.com/issues/799> has been resolved.
- currentPrivacyWebEngineViewPointer->setZoomFactor(currentZoomFactor);
- }
- else // The hostname does not have domain settings.
- {
- // Reset the domain settings name.
- currentPrivacyWebEngineViewPointer->domainSettingsName = QStringLiteral("");
-
- // Set the JavaScript status.
- currentWebEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, Settings::javaScriptEnabled());
-
- // Set the local storage status.
- currentPrivacyWebEngineViewPointer->localStorageEnabled = Settings::localStorageEnabled();
-
- // Set DOM storage. In QWebEngineSettings it is called Local Storage.
- currentWebEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, Settings::domStorageEnabled());
-
- // Set the user agent.
- currentWebEngineProfilePointer->setHttpUserAgent(UserAgentHelper::getUserAgentFromDatabaseName(Settings::userAgent()));
+ // Apply the domain settings to each WebEngine.
+ for (int i = 0; i < numberOfTabs; ++i) {
+ // Get the WebEngine view pointer.
+ PrivacyWebEngineView *privacyWebEngineViewPointer = qobject_cast<PrivacyWebEngineView *>(qTabWidgetPointer->widget(i));
- // Store the current zoom factor. This can be removed once <https://redmine.stoutner.com/issues/799> has been resolved.
- currentZoomFactor = Settings::zoomFactor();
-
- // Set the zoom factor.
- currentPrivacyWebEngineViewPointer->setZoomFactor(Settings::zoomFactor());
+ // Apply the spatial navigation settings to each page.
+ privacyWebEngineViewPointer->applyDomainSettings(privacyWebEngineViewPointer->url().host(), true);
}
-
- // Update the UI.
- emit updateDomainSettingsIndicator(currentPrivacyWebEngineViewPointer->domainSettingsName != QStringLiteral(""));
- emit updateJavaScriptAction(currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::JavascriptEnabled));
- emit updateLocalStorageAction(currentPrivacyWebEngineViewPointer->localStorageEnabled);
- emit updateDomStorageAction(currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::LocalStorageEnabled));
- emit updateUserAgentActions(currentWebEngineProfilePointer->httpUserAgent(), true);
- emit updateZoomFactorAction(currentPrivacyWebEngineViewPointer->zoomFactor());
-
- // Reload the website if requested.
- if (reloadWebsite)
- currentPrivacyWebEngineViewPointer->reload();
}
void TabWidget::applyOnTheFlySearchEngine(QAction *searchEngineActionPointer)
// Store the search engine string.
searchEngineUrl = SearchEngineHelper::getSearchUrl(searchEngineName);
- // Update the search engine actionas.
+ // Update the search engine actions.
emit updateSearchEngineActions(searchEngineName, false);
}
userAgentName.remove('&');
// Apply the user agent.
- currentWebEngineProfilePointer->setHttpUserAgent(UserAgentHelper::getUserAgentFromTranslatedName(userAgentName));
+ currentWebEngineProfilePointer->setHttpUserAgent(userAgentHelperPointer->getUserAgentFromTranslatedName(userAgentName));
// Update the user agent actions.
emit updateUserAgentActions(currentWebEngineProfilePointer->httpUserAgent(), false);
currentPrivacyWebEngineViewPointer->reload();
}
-// This can be const once <https://redmine.stoutner.com/issues/799> has been resolved.
-void TabWidget::applyOnTheFlyZoomFactor(const double &zoomFactor)
+void TabWidget::applyOnTheFlyZoomFactor(const double &zoomFactor) const
{
- // Update the current zoom factor. This can be removed once <https://redmine.stoutner.com/issues/799> has been resolved.
- currentZoomFactor = zoomFactor;
-
// Set the zoom factor.
currentPrivacyWebEngineViewPointer->setZoomFactor(zoomFactor);
}
+void TabWidget::applySpellCheckLanguages() const
+{
+ // Get the number of tab.
+ int numberOfTabs = qTabWidgetPointer->count();
+
+ // Set the spell check languages for each tab.
+ for (int i = 0; i < numberOfTabs; ++i)
+ {
+ // Get the WebEngine view pointer.
+ PrivacyWebEngineView *privacyWebEngineViewPointer = qobject_cast<PrivacyWebEngineView *>(qTabWidgetPointer->widget(i));
+
+ // Get the WebEngine page pointer.
+ QWebEnginePage *webEnginePagePointer = privacyWebEngineViewPointer->page();
+
+ // Get the WebEngine profile pointer.
+ QWebEngineProfile *webEngineProfilePointer = webEnginePagePointer->profile();
+
+ // Set the spell check languages.
+ webEngineProfilePointer->setSpellCheckLanguages(Settings::spellCheckLanguages());
+ }
+}
+
void TabWidget::back() const
{
// Go back.
void TabWidget::deleteTab(const int tabIndex)
{
// Get the privacy WebEngine view.
- PrivacyWebEngineView *privacyWebEngineViewPointer = qobject_cast<PrivacyWebEngineView *>(tabWidgetPointer->widget(tabIndex));
+ PrivacyWebEngineView *privacyWebEngineViewPointer = qobject_cast<PrivacyWebEngineView *>(qTabWidgetPointer->widget(tabIndex));
- // Proccess the tab delete according to the number of tabs.
- if (tabWidgetPointer->count() > 1) // There is more than one tab.
+ // Process the tab delete according to the number of tabs.
+ if (qTabWidgetPointer->count() > 1) // There is more than one tab.
{
// Delete the tab.
- tabWidgetPointer->removeTab(tabIndex);
+ qTabWidgetPointer->removeTab(tabIndex);
// Delete the WebEngine page to prevent the following error: `Release of profile requested but WebEnginePage still not deleted. Expect troubles !`
delete privacyWebEngineViewPointer->page();
void TabWidget::findTextFinished(const QWebEngineFindTextResult &findTextResult)
{
- // Update the find text UI if it wasn't simply wiping the current find text selection. Otherwise the UI temporarially flashes `0/0`.
+ // Update the find text UI if it wasn't simply wiping the current find text selection. Otherwise the UI temporarily flashes `0/0`.
if (wipingCurrentFindTextSelection) // The current selection is being wiped.
{
// Reset the flag.
return currentPrivacyWebEngineViewPointer->cookieListPointer;
}
+QIcon TabWidget::getCurrentTabFavoritIcon() const
+{
+ // Return the current Privacy WebEngine favorite icon.
+ return currentPrivacyWebEngineViewPointer->favoriteIcon;
+}
+
+QString TabWidget::getCurrentTabTitle() const
+{
+ // Return the current Privacy WebEngine title.
+ return currentPrivacyWebEngineViewPointer->title();
+}
+
+QString TabWidget::getCurrentTabUrl() const
+{
+ // Return the current Privacy WebEngine URL as a string.
+ return currentPrivacyWebEngineViewPointer->url().toString();
+}
+
QString& TabWidget::getDomainSettingsName() const
{
// Return the domain settings name.
void TabWidget::loadUrlFromLineEdit(QString url) const
{
// Decide if the text is more likely to be a URL or a search.
- if (url.startsWith("file://")) // The text is likely a file URL.
+ if (url.startsWith("file://") || url.startsWith("view-source:")) // The text is likely a file or view source URL.
{
// Load the URL.
currentPrivacyWebEngineViewPointer->load(QUrl::fromUserInput(url));
emit linkHovered(linkUrl);
}
+void TabWidget::stopLoadingFavoriteIconMovie() const
+{
+ // 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>
+ loadingFavoriteIconMoviePointer->stop();
+}
+
void TabWidget::print() const
{
// Create a printer.
currentPrivacyWebEngineViewPointer->reload();
}
-void TabWidget::setTabBarVisible(const bool visible) const
+void TabWidget::reloadAndBypassCache() const
{
- // Set the tab bar visibility.
- tabWidgetPointer->tabBar()->setVisible(visible);
+ // Reload the website, bypassing the cache.
+ currentWebEnginePagePointer->triggerAction(QWebEnginePage::ReloadAndBypassCache);
}
-void TabWidget::showSaveDialog(QWebEngineDownloadItem *downloadItemPointer) const
+void TabWidget::saveArchive()
{
- // Instantiate the save dialog.
- SaveDialog *saveDialogPointer = new SaveDialog(downloadItemPointer);
-
- // Connect the save button.
- connect(saveDialogPointer, SIGNAL(showSaveFilePickerDialog(QUrl &, QString &)), this, SLOT(showSaveFilePickerDialog(QUrl &, QString &)));
+ // Get the suggested file name.
+ QString suggestedFileName = currentPrivacyWebEngineViewPointer->url().host() + ".mht";
- // Show the dialog.
- saveDialogPointer->show();
-}
-
-void TabWidget::showSaveFilePickerDialog(QUrl &downloadUrl, QString &suggestedFileName)
-{
- // Get the download location.
+ // Get the download directory.
QString downloadDirectory = Settings::downloadLocation();
// Resolve the system download directory if specified.
- if (downloadDirectory == QStringLiteral("System Download Directory"))
+ if (downloadDirectory == QLatin1String("System Download Directory"))
downloadDirectory = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
- // Create a save file dialog.
- QFileDialog *saveFileDialogPointer = new QFileDialog(this, i18nc("Save file dialog caption", "Save File"), downloadDirectory);
+ // Get a file path from the file picker.
+ QString saveFilePath = QFileDialog::getSaveFileName(this, i18nc("Save file dialog caption", "Save File"), downloadDirectory + QLatin1Char('/') + suggestedFileName);
- // Tell the dialog to use a save button.
- saveFileDialogPointer->setAcceptMode(QFileDialog::AcceptSave);
+ // Save the webpage as an archive if the file save path is populated.
+ if (!saveFilePath.isEmpty())
+ {
+ // Set the saving archive flag. Otherwise, a second download tries to run.
+ savingArchive = true;
- // Populate the file name from the download item pointer.
- saveFileDialogPointer->selectFile(suggestedFileName);
+ // Save the archive.
+ currentWebEnginePagePointer->save(saveFilePath);
+ }
+}
- // Prevent interaction with the parent window while the dialog is open.
- saveFileDialogPointer->setWindowModality(Qt::WindowModal);
+void TabWidget::setTabBarVisible(const bool visible) const
+{
+ // Set the tab bar visibility.
+ qTabWidgetPointer->tabBar()->setVisible(visible);
+}
- // Process the saving of the file. The save file dialog pointer must be captured directly instead of by reference or nasty crashes occur.
- auto saveFile = [saveFileDialogPointer, &downloadUrl] () {
- // Get the save location. The dialog box should only allow the selecting of one file location.
- QUrl saveLocation = saveFileDialogPointer->selectedUrls().value(0);
+void TabWidget::showSaveDialog(QWebEngineDownloadItem *webEngineDownloadItemPointer)
+{
+ // Only show the save dialog if an archive is not currently being saved. Otherwise, two save dialogs will be shown.
+ if (!savingArchive)
+ {
+ // Get the download attributes.
+ QUrl downloadUrl = webEngineDownloadItemPointer->url();
+ QString mimeTypeString = webEngineDownloadItemPointer->mimeType();
+ QString suggestedFileName = webEngineDownloadItemPointer->suggestedFileName();
+ int totalBytes = webEngineDownloadItemPointer->totalBytes();
+
+ // Check to see if Privacy Browser is not running KDE or if local storage (cookies) is enabled.
+ if (!isRunningKde || currentPrivacyWebEngineViewPointer->localStorageEnabled) // KDE is not running or local storage (cookies) is enabled. Use WebEngine's downloader.
+ {
+ // Instantiate the save dialog.
+ SaveDialog *saveDialogPointer = new SaveDialog(downloadUrl, mimeTypeString, totalBytes);
- // Create a file copy job. `-1` creates the file with default permissions.
- KIO::FileCopyJob *fileCopyJobPointer = KIO::file_copy(downloadUrl, saveLocation, -1, KIO::Overwrite);
+ // Display the save dialog.
+ int saveDialogResult = saveDialogPointer->exec();
- // Set the download job to display any error messages.
- fileCopyJobPointer->uiDelegate()->setAutoErrorHandlingEnabled(true);
+ // Process the save dialog results.
+ if (saveDialogResult == QDialog::Accepted) // Save was selected.
+ {
+ // Get the download directory.
+ QString downloadDirectory = Settings::downloadLocation();
- // Start the download.
- fileCopyJobPointer->start();
- };
+ // Resolve the system download directory if specified.
+ if (downloadDirectory == QLatin1String("System Download Directory"))
+ downloadDirectory = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
- // Handle clicks on the save button.
- connect(saveFileDialogPointer, &QDialog::accepted, this, saveFile);
+ // Get a file path from the file picker.
+ QString saveFilePath = QFileDialog::getSaveFileName(this, i18nc("Save file dialog caption", "Save File"), downloadDirectory + QLatin1Char('/') + suggestedFileName);
- // Show the dialog.
- saveFileDialogPointer->show();
+ // Process the save file path.
+ if (!saveFilePath.isEmpty()) // The file save path is populated.
+ {
+ // Create a save file path file info.
+ QFileInfo saveFilePathFileInfo = QFileInfo(saveFilePath);
+
+ // Get the canonical save path and file name.
+ QString absoluteSavePath = saveFilePathFileInfo.absolutePath();
+ QString saveFileName = saveFilePathFileInfo.fileName();
+
+ // Set the download directory and file name.
+ webEngineDownloadItemPointer->setDownloadDirectory(absoluteSavePath);
+ webEngineDownloadItemPointer->setDownloadFileName(saveFileName);
+
+ // Create a file download notification.
+ KNotification *fileDownloadNotificationPointer = new KNotification(QLatin1String("FileDownload"));
+
+ // Set the notification title.
+ fileDownloadNotificationPointer->setTitle(i18nc("Download notification title", "Download"));
+
+ // Set the notification text.
+ fileDownloadNotificationPointer->setText(i18nc("Downloading notification text", "Downloading %1", saveFileName));
+
+ // Get the download icon from the theme.
+ QIcon downloadIcon = QIcon::fromTheme(QLatin1String("download"), QIcon::fromTheme(QLatin1String("document-save")));
+
+ // Set the notification icon.
+ fileDownloadNotificationPointer->setIconName(downloadIcon.name());
+
+ // Set the action list cancel button.
+ fileDownloadNotificationPointer->setActions(QStringList({i18nc("Download notification action","Cancel")}));
+
+ // Prevent the notification from being autodeleted if it is closed. Otherwise, the updates to the notification below cause a crash.
+ fileDownloadNotificationPointer->setAutoDelete(false);
+
+ // Handle clicks on the cancel button.
+ connect(fileDownloadNotificationPointer, &KNotification::action1Activated, [webEngineDownloadItemPointer, saveFileName] ()
+ {
+ // Cancel the download.
+ webEngineDownloadItemPointer->cancel();
+
+ // Create a file download notification.
+ KNotification *canceledDownloadNotificationPointer = new KNotification(QLatin1String("FileDownload"));
+
+ // Set the notification title.
+ canceledDownloadNotificationPointer->setTitle(i18nc("Download notification title", "Download"));
+
+ // Set the new text.
+ canceledDownloadNotificationPointer->setText(i18nc("Download canceled notification", "%1 download canceled", saveFileName));
+
+ // Set the notification icon.
+ canceledDownloadNotificationPointer->setIconName(QLatin1String("download"));
+
+ // Display the notification.
+ canceledDownloadNotificationPointer->sendEvent();
+ });
+
+ // Update the notification when the download progresses.
+ connect(webEngineDownloadItemPointer, &QWebEngineDownloadItem::downloadProgress, [fileDownloadNotificationPointer, saveFileName] (qint64 bytesReceived, qint64 totalBytes)
+ {
+ // Set the new text. Total bytes will be 0 if the download size is unknown.
+ if (totalBytes > 0)
+ {
+ // Calculate the download percentage.
+ int downloadPercentage = 100 * bytesReceived / totalBytes;
+
+ // Set the file download notification text.
+ fileDownloadNotificationPointer->setText(i18nc("Download progress notification text", "%1\% of %2 downloaded (%3 of %4 bytes)", downloadPercentage, saveFileName,
+ bytesReceived, totalBytes));
+ }
+ else
+ {
+ // Set the file download notification text.
+ fileDownloadNotificationPointer->setText(i18nc("Download progress notification text", "%1: %2 bytes downloaded", saveFileName, bytesReceived));
+ }
+
+ // Display the updated notification.
+ fileDownloadNotificationPointer->update();
+ });
+
+ // Update the notification when the download finishes. The save file name must be copied into the lambda or a crash occurs.
+ connect(webEngineDownloadItemPointer, &QWebEngineDownloadItem::finished, [fileDownloadNotificationPointer, saveFileName, saveFilePath] ()
+ {
+ // Set the new text.
+ fileDownloadNotificationPointer->setText(i18nc("Download finished notification text", "%1 download finished", saveFileName));
+
+ // Set the URL so the file options will be displayed.
+ fileDownloadNotificationPointer->setUrls(QList<QUrl> {QUrl(saveFilePath)});
+
+ // Remove the actions from the notification.
+ fileDownloadNotificationPointer->setActions(QStringList());
+
+ // Set the notification to disappear after a timeout.
+ fileDownloadNotificationPointer->setFlags(KNotification::CloseOnTimeout);
+
+ // Display the updated notification.
+ fileDownloadNotificationPointer->update();
+ });
+
+ // Display the notification.
+ fileDownloadNotificationPointer->sendEvent();
+
+ // Start the download.
+ webEngineDownloadItemPointer->accept();
+ }
+ else // The file save path is not populated.
+ {
+ // Cancel the download.
+ webEngineDownloadItemPointer->cancel();
+ }
+ }
+ else // Cancel was selected.
+ {
+ // Cancel the download.
+ webEngineDownloadItemPointer->cancel();
+ }
+ }
+ else // KDE is running and local storage (cookies) is disabled. Use KDE's native downloader.
+ // 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.
+ {
+ // Instantiate the save dialog. `true` instructs it to use the native downloader
+ SaveDialog *saveDialogPointer = new SaveDialog(downloadUrl, mimeTypeString, totalBytes, suggestedFileName, true);
+
+ // Connect the save button.
+ connect(saveDialogPointer, SIGNAL(useNativeKdeDownloader(QUrl &, QString &)), this, SLOT(useNativeKdeDownloader(QUrl &, QString &)));
+
+ // Show the dialog.
+ saveDialogPointer->show();
+ }
+ }
+
+ // Reset the saving archive flag.
+ savingArchive = false;
}
void TabWidget::toggleDomStorage() const
wipingCurrentFindTextSelection = true;
// Wipe the previous search. Otherwise currently highlighted words will remain highlighted.
- findText(QStringLiteral(""));
+ findText(QLatin1String(""));
// Update the find text.
findText(text);
void TabWidget::toggleLocalStorage()
{
- // Toggle local storeage.
+ // Toggle local storage.
currentPrivacyWebEngineViewPointer->localStorageEnabled = !currentPrivacyWebEngineViewPointer->localStorageEnabled;
// Update the local storage action.
currentPrivacyWebEngineViewPointer->reload();
}
+void TabWidget::updateUiFromWebEngineView(const PrivacyWebEngineView *privacyWebEngineViewPointer) const
+{
+ // Only update the UI if the signal was emitted from the current privacy WebEngine.
+ if (privacyWebEngineViewPointer == currentPrivacyWebEngineViewPointer)
+ {
+ // Update the UI.
+ emit updateDefaultZoomFactor(currentPrivacyWebEngineViewPointer->defaultZoomFactor);
+ emit updateDomainSettingsIndicator(currentPrivacyWebEngineViewPointer->domainSettingsName != QLatin1String(""));
+ emit updateJavaScriptAction(currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::JavascriptEnabled));
+ emit updateLocalStorageAction(currentPrivacyWebEngineViewPointer->localStorageEnabled);
+ emit updateDomStorageAction(currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::LocalStorageEnabled));
+ emit updateUserAgentActions(currentWebEngineProfilePointer->httpUserAgent(), true);
+ emit updateZoomActions(currentPrivacyWebEngineViewPointer->zoomFactor());
+ }
+}
+
void TabWidget::updateUiWithTabSettings()
{
// Update the current WebEngine pointers.
- currentPrivacyWebEngineViewPointer = qobject_cast<PrivacyWebEngineView *>(tabWidgetPointer->currentWidget());
+ currentPrivacyWebEngineViewPointer = qobject_cast<PrivacyWebEngineView *>(qTabWidgetPointer->currentWidget());
currentWebEngineSettingsPointer = currentPrivacyWebEngineViewPointer->settings();
currentWebEnginePagePointer = currentPrivacyWebEngineViewPointer->page();
currentWebEngineProfilePointer = currentWebEnginePagePointer->profile();
emit clearUrlLineEditFocus();
// Update the actions.
+ emit updateDefaultZoomFactor(currentPrivacyWebEngineViewPointer->defaultZoomFactor);
emit updateBackAction(currentWebEngineHistoryPointer->canGoBack());
emit updateCookiesAction(currentPrivacyWebEngineViewPointer->cookieListPointer->size());
emit updateDomStorageAction(currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::LocalStorageEnabled));
emit updateJavaScriptAction(currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::JavascriptEnabled));
emit updateLocalStorageAction(currentPrivacyWebEngineViewPointer->localStorageEnabled);
emit updateUserAgentActions(currentWebEngineProfilePointer->httpUserAgent(), true);
- emit updateZoomFactorAction(currentPrivacyWebEngineViewPointer->zoomFactor());
+ emit updateZoomActions(currentPrivacyWebEngineViewPointer->zoomFactor());
// Update the URL.
emit updateWindowTitle(currentPrivacyWebEngineViewPointer->title());
- emit updateDomainSettingsIndicator(currentPrivacyWebEngineViewPointer->domainSettingsName != QStringLiteral(""));
+ emit updateDomainSettingsIndicator(currentPrivacyWebEngineViewPointer->domainSettingsName != QLatin1String(""));
emit updateUrlLineEdit(currentPrivacyWebEngineViewPointer->url());
// Update the find text.
else
emit hideProgressBar();
}
+
+void TabWidget::useNativeKdeDownloader(QUrl &downloadUrl, QString &suggestedFileName)
+{
+ // Get the download directory.
+ QString downloadDirectory = Settings::downloadLocation();
+
+ // Resolve the system download directory if specified.
+ if (downloadDirectory == QLatin1String("System Download Directory"))
+ downloadDirectory = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
+
+ // Create a save file dialog.
+ QFileDialog *saveFileDialogPointer = new QFileDialog(this, i18nc("Save file dialog caption", "Save File"), downloadDirectory);
+
+ // Tell the dialog to use a save button.
+ saveFileDialogPointer->setAcceptMode(QFileDialog::AcceptSave);
+
+ // Populate the file name from the download item pointer.
+ saveFileDialogPointer->selectFile(suggestedFileName);
+
+ // Prevent interaction with the parent window while the dialog is open.
+ saveFileDialogPointer->setWindowModality(Qt::WindowModal);
+
+ // Process the saving of the file. The save file dialog pointer must be captured directly instead of by reference or nasty crashes occur.
+ auto saveFile = [saveFileDialogPointer, downloadUrl] ()
+ {
+ // Get the save location. The dialog box should only allow the selecting of one file location.
+ QUrl saveLocation = saveFileDialogPointer->selectedUrls().value(0);
+
+ // Create a file copy job. `-1` creates the file with default permissions.
+ KIO::FileCopyJob *fileCopyJobPointer = KIO::file_copy(downloadUrl, saveLocation, -1, KIO::Overwrite);
+
+ // Set the download job to display any warning and error messages.
+ fileCopyJobPointer->uiDelegate()->setAutoWarningHandlingEnabled(true);
+ fileCopyJobPointer->uiDelegate()->setAutoErrorHandlingEnabled(true);
+
+ // Start the download.
+ fileCopyJobPointer->start();
+ };
+
+ // Handle clicks on the save button.
+ connect(saveFileDialogPointer, &QDialog::accepted, this, saveFile);
+
+ // Show the dialog.
+ saveFileDialogPointer->show();
+}