X-Git-Url: https://gitweb.stoutner.com/?p=PrivacyBrowserPC.git;a=blobdiff_plain;f=src%2Fwidgets%2FTabWidget.cpp;h=4edb304d0db6c45ed5d757a6d4a5f6cd20ad5596;hp=bd62f83beaa521343768bb9355fa3922359cd1f3;hb=06a69a2d38bf73c0c5219f94c345b19142bb1646;hpb=15219459baed09d03d17a12c72302595c135fd53 diff --git a/src/widgets/TabWidget.cpp b/src/widgets/TabWidget.cpp index bd62f83..4edb304 100644 --- a/src/widgets/TabWidget.cpp +++ b/src/widgets/TabWidget.cpp @@ -1,5 +1,5 @@ /* - * Copyright © 2022 Soren Stoutner . + * Copyright 2022 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -27,13 +27,13 @@ #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 #include +#include // Qt toolkit headers. #include @@ -45,11 +45,14 @@ #include // Initialize the public static variables. -QString TabWidget::webEngineDefaultUserAgent = QStringLiteral(""); +QString TabWidget::webEngineDefaultUserAgent = QLatin1String(""); // Construct the class. TabWidget::TabWidget(QWidget *parent) : QWidget(parent) { + // Instantiate the user agent helper. + userAgentHelperPointer = new UserAgentHelper(); + // Instantiate the UIs. Ui::TabWidget tabWidgetUi; Ui::AddTabWidget addTabWidgetUi; @@ -112,14 +115,14 @@ void TabWidget::addCookieToStore(QNetworkCookie cookie, QWebEngineCookieStore *w QUrl url; // Check to see if the domain does not start with a `.` because Qt makes this harder than it should be. - 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. @@ -153,7 +156,7 @@ PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const tabWidgetPointer->setTabIcon(newTabIndex, defaultTabIcon); // Create an off-the-record profile (the default when no profile name is specified). - QWebEngineProfile *webEngineProfilePointer = new QWebEngineProfile(QStringLiteral("")); + QWebEngineProfile *webEngineProfilePointer = new QWebEngineProfile(QLatin1String("")); // Create a WebEngine page. QWebEnginePage *webEnginePagePointer = new QWebEnginePage(webEngineProfilePointer); @@ -332,7 +335,7 @@ PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const webEngineProfilePointer->setSpellCheckEnabled(true); // Set the spell check language. - webEngineProfilePointer->setSpellCheckLanguages({QStringLiteral("en_US")}); + webEngineProfilePointer->setSpellCheckLanguages({QLatin1String("en_US")}); // 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()); @@ -454,7 +457,7 @@ void TabWidget::applyDomainSettings(const QString &hostname, const bool reloadWe // Set the DOM storage status. switch (domainRecord.field(DomainsDatabase::DOM_STORAGE).value().toInt()) { - // Set the default DOM storage status. + // Set the default DOM storage status. QWebEngineSettings confusingly calls this local storage. case (DomainsDatabase::SYSTEM_DEFAULT): { currentWebEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, Settings::domStorageEnabled()); @@ -462,7 +465,7 @@ void TabWidget::applyDomainSettings(const QString &hostname, const bool reloadWe break; } - // Disable DOM storage. + // Disable DOM storage. QWebEngineSettings confusingly calls this local storage. case (DomainsDatabase::DISABLED): { currentWebEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, false); @@ -470,7 +473,7 @@ void TabWidget::applyDomainSettings(const QString &hostname, const bool reloadWe break; } - // Enable DOM storage. + // Enable DOM storage. QWebEngineSettings confusingly calls this local storage. case (DomainsDatabase::ENABLED): { currentWebEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, true); @@ -500,7 +503,7 @@ void TabWidget::applyDomainSettings(const QString &hostname, const bool reloadWe else // The hostname does not have domain settings. { // Reset the domain settings name. - currentPrivacyWebEngineViewPointer->domainSettingsName = QStringLiteral(""); + currentPrivacyWebEngineViewPointer->domainSettingsName = QLatin1String(""); // Set the JavaScript status. currentWebEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, Settings::javaScriptEnabled()); @@ -522,7 +525,7 @@ void TabWidget::applyDomainSettings(const QString &hostname, const bool reloadWe } // Update the UI. - emit updateDomainSettingsIndicator(currentPrivacyWebEngineViewPointer->domainSettingsName != QStringLiteral("")); + emit updateDomainSettingsIndicator(currentPrivacyWebEngineViewPointer->domainSettingsName != QLatin1String("")); emit updateJavaScriptAction(currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::JavascriptEnabled)); emit updateLocalStorageAction(currentPrivacyWebEngineViewPointer->localStorageEnabled); emit updateDomStorageAction(currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::LocalStorageEnabled)); @@ -558,7 +561,7 @@ void TabWidget::applyOnTheFlyUserAgent(QAction *userAgentActionPointer) const 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); @@ -853,59 +856,159 @@ void TabWidget::setTabBarVisible(const bool visible) const tabWidgetPointer->tabBar()->setVisible(visible); } -void TabWidget::showSaveDialog(QWebEngineDownloadItem *downloadItemPointer) const +void TabWidget::showSaveDialog(QWebEngineDownloadItem *webEngineDownloadItemPointer) { - // Instantiate the save dialog. - SaveDialog *saveDialogPointer = new SaveDialog(downloadItemPointer); + // Get the download attributes. + QUrl downloadUrl = webEngineDownloadItemPointer->url(); + QString mimeTypeString = webEngineDownloadItemPointer->mimeType(); + QString suggestedFileName = webEngineDownloadItemPointer->suggestedFileName(); + int totalBytes = webEngineDownloadItemPointer->totalBytes(); + + // Check to see if local storage (cookies) is enabled. + if (currentPrivacyWebEngineViewPointer->localStorageEnabled) // Local storage (cookies) is enabled. Use WebEngine's downloader. + { + // Instantiate the save dialog. + SaveDialog *saveDialogPointer = new SaveDialog(downloadUrl, mimeTypeString, totalBytes); - // Connect the save button. - connect(saveDialogPointer, SIGNAL(showSaveFilePickerDialog(QUrl &, QString &)), this, SLOT(showSaveFilePickerDialog(QUrl &, QString &))); + // Display the save dialog. + int saveDialogResult = saveDialogPointer->exec(); - // Show the dialog. - saveDialogPointer->show(); -} + // Process the save dialog results. + if (saveDialogResult == QDialog::Accepted) // Save was selected. + { + // Get the download directory. + QString downloadDirectory = Settings::downloadLocation(); -void TabWidget::showSaveFilePickerDialog(QUrl &downloadUrl, QString &suggestedFileName) -{ - // Get the download location. - QString downloadDirectory = Settings::downloadLocation(); + // Resolve the system download directory if specified. + if (downloadDirectory == QLatin1String("System Download Directory")) + downloadDirectory = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); - // Resolve the system download directory if specified. - if (downloadDirectory == QStringLiteral("System Download Directory")) - downloadDirectory = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); + // Display a save file dialog. + QString saveFilePath = QFileDialog::getSaveFileName(this, i18nc("Save file dialog caption", "Save File"), downloadDirectory + QLatin1Char('/') + suggestedFileName); - // Create a save file dialog. - QFileDialog *saveFileDialogPointer = new QFileDialog(this, i18nc("Save file dialog caption", "Save File"), downloadDirectory); + // 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); - // Tell the dialog to use a save button. - saveFileDialogPointer->setAcceptMode(QFileDialog::AcceptSave); + // Get the canonical save path and file name. + QString absoluteSavePath = saveFilePathFileInfo.absolutePath(); + QString saveFileName = saveFilePathFileInfo.fileName(); - // Populate the file name from the download item pointer. - saveFileDialogPointer->selectFile(suggestedFileName); + // Set the download directory and file name. + webEngineDownloadItemPointer->setDownloadDirectory(absoluteSavePath); + webEngineDownloadItemPointer->setDownloadFileName(saveFileName); - // Prevent interaction with the parent window while the dialog is open. - saveFileDialogPointer->setWindowModality(Qt::WindowModal); + // Create a file download notification. + KNotification *fileDownloadNotificationPointer = new KNotification(QLatin1String("FileDownload")); - // 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); + // Set the notification title. + fileDownloadNotificationPointer->setTitle(i18nc("Download notification title", "Download")); - // 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 notification text. + fileDownloadNotificationPointer->setText(i18nc("Downloading notification text", "Downloading %1", saveFileName)); - // Set the download job to display any error messages. - fileCopyJobPointer->uiDelegate()->setAutoErrorHandlingEnabled(true); + // Set the notification icon. + fileDownloadNotificationPointer->setIconName(QLatin1String("download")); - // Start the download. - fileCopyJobPointer->start(); - }; + // Set the action list cancel button. + fileDownloadNotificationPointer->setActions(QStringList({i18nc("Download notification action","Cancel")})); - // Handle clicks on the save button. - connect(saveFileDialogPointer, &QDialog::accepted, this, saveFile); + // Set the notification to display indefinitely. + fileDownloadNotificationPointer->setFlags(KNotification::Persistent); - // Show the dialog. - saveFileDialogPointer->show(); + // Prevent the notification from being autodeleted if it is closed. Otherwise, the updates to the notification below cause a crash. + fileDownloadNotificationPointer->setAutoDelete(false); + + // Display the notification. + fileDownloadNotificationPointer->sendEvent(); + + // 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) + { + // Calculate the download percentage. + int downloadPercentage = 100 * bytesReceived / totalBytes; + + // Set the new text. Total bytes will be 0 if the download size is unknown. + if (totalBytes > 0) + fileDownloadNotificationPointer->setText(i18nc("Download progress notification text", "%1\% of %2 downloaded (%3 of %4 bytes)", downloadPercentage, saveFileName, + bytesReceived, totalBytes)); + else + 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(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(); + }); + + // 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 // 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(useNativeDownloader(QUrl &, QString &)), this, SLOT(useNativeDownloader(QUrl &, QString &))); + + // Show the dialog. + saveDialogPointer->show(); + } } void TabWidget::toggleDomStorage() const @@ -929,7 +1032,7 @@ void TabWidget::toggleFindCaseSensitive(const QString &text) wipingCurrentFindTextSelection = true; // Wipe the previous search. Otherwise currently highlighted words will remain highlighted. - findText(QStringLiteral("")); + findText(QLatin1String("")); // Update the find text. findText(text); @@ -984,7 +1087,7 @@ void TabWidget::updateUiWithTabSettings() // 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. @@ -997,3 +1100,47 @@ void TabWidget::updateUiWithTabSettings() else emit hideProgressBar(); } + +void TabWidget::useNativeDownloader(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 error messages. + 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(); +}