Commit cd500298 authored by Stefano Crocco's avatar Stefano Crocco
Browse files

Add support for BLOB URLs

parents 54c5bc93 1e9659be
......@@ -697,6 +697,9 @@ void KonqMainWindow::openUrl(KonqView *_view, const QUrl &_url,
KIO::ApplicationLauncherJob *job = new KIO::ApplicationLauncherJob(offer);
job->setUrls({url});
job->setUiDelegate(new KIO::JobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this));
if (req.tempFile) {
job->setRunFlags(KIO::ApplicationLauncherJob::DeleteTemporaryFiles);
}
job->start();
}
}
......@@ -1023,6 +1026,9 @@ void KonqMainWindow::openUrlRequestHelper(KonqView *childView, const QUrl &url,
//qCDebug(KONQUEROR_LOG) << "url=" << url;
KonqOpenURLRequest req;
req.args = args;
if (args.metaData().value("konq-temp-file") == "1") {
req.tempFile = true;
}
req.browserArgs = browserArgs;
openUrl(childView, url, args.mimeType(), req, browserArgs.trustedSource);
}
......
find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS Wallet)
find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS Notifications )
add_definitions(-DTRANSLATION_DOMAIN=\"webenginepart\")
......@@ -56,6 +57,7 @@ target_link_libraries(kwebenginepartlib
Qt5::WebEngineWidgets
KF5::Parts
KF5::Wallet
KF5::Notifications
PRIVATE
Qt5::PrintSupport
KF5::SonnetCore
......
......@@ -159,6 +159,16 @@ void WebEnginePage::download(const QUrl& url, bool newWindow)
emit part()->browserExtension()->openUrlRequest(url, KParts::OpenUrlArguments(), bArgs);
}
void WebEnginePage::requestOpenFileAsTemporary(const QUrl& url, const QString &mimeType, bool newWindow)
{
KParts::BrowserArguments bArgs;
bArgs.setForcesNewWindow(newWindow);
KParts::OpenUrlArguments oArgs;
oArgs.setMimeType(mimeType);
oArgs.metaData().insert("konq-temp-file", "1");
emit part()->browserExtension()->openUrlRequest(url, oArgs, bArgs);
}
QWebEnginePage *WebEnginePage::createWindow(WebWindowType type)
{
//qCDebug(WEBENGINEPART_LOG) << "window type:" << type;
......@@ -744,7 +754,12 @@ void WebEnginePage::changeFullScreenMode(QWebEngineFullScreenRequest req)
}
void WebEnginePage::setStatusBarText(const QString& text)
{
if (m_part) {
emit m_part->setStatusBarText(text);
}
}
/************************************* Begin NewWindowPage ******************************************/
......
......@@ -66,8 +66,12 @@ public:
void download(const QUrl &url, bool newWindow = false);
void requestOpenFileAsTemporary(const QUrl &url, const QString &mimeType = "", bool newWindow = false);
void setStatusBarText(const QString &text);
WebEngineWallet* wallet() const {return m_wallet;}
/**
* @brief Tells the page that the part has requested to load the given URL
*
......@@ -112,7 +116,7 @@ protected:
* @internal
*/
bool acceptNavigationRequest(const QUrl& request, NavigationType type, bool isMainFrame) override;
/**
* @brief Override of `QWebEnginePage::certificateError`
*
......@@ -157,7 +161,7 @@ private:
QScopedPointer<KPasswdServerClient> m_passwdServerClient;
WebEngineWallet *m_wallet;
/**
* @brief The last URL that the part requested to be loaded
*
......
......@@ -26,9 +26,24 @@
#include <QWebEngineDownloadItem>
#include <QWebEngineView>
#include <QWebEngineProfile>
#include <QFileDialog>
#include <QStandardPaths>
#include <QFileInfo>
#include <QMimeDatabase>
#include <QMimeType>
#include <QTimer>
#include <KLocalizedString>
#include <KNotificationJobUiDelegate>
#include <KParts/BrowserOpenOrSaveQuestion>
#include <KJobTrackerInterface>
#include <KIO/JobTracker>
#include <KIO/OpenUrlJob>
#include <KFileUtils>
#include <KIO/JobUiDelegate>
WebEnginePartDownloadManager::WebEnginePartDownloadManager()
: QObject()
: QObject(), m_tempDownloadDir(QDir(QDir::tempPath()).filePath("WebEnginePartDownloadManager"))
{
connect(QWebEngineProfile::defaultProfile(), &QWebEngineProfile::downloadRequested, this, &WebEnginePartDownloadManager::performDownload);
}
......@@ -83,7 +98,101 @@ void WebEnginePartDownloadManager::performDownload(QWebEngineDownloadItem* it)
qCDebug(WEBENGINEPART_LOG) << "Couldn't find a part wanting to download" << it->url();
return;
}
page->download(it->url(), forceNew);
if (it->url().scheme() != "blob") {
page->download(it->url(), forceNew);
} else {
downloadBlob(it);
}
}
void WebEnginePartDownloadManager::downloadBlob(QWebEngineDownloadItem* it)
{
WebEnginePage *p = qobject_cast<WebEnginePage*>(it->page());
QWidget *w = p ? p->view() : nullptr;
KParts::BrowserOpenOrSaveQuestion askDlg(w, it->url(), it->mimeType());
KParts::BrowserOpenOrSaveQuestion::Result ans = askDlg.askEmbedOrSave(KParts::BrowserOpenOrSaveQuestion::AttachmentDisposition);
switch (ans) {
case KParts::BrowserOpenOrSaveQuestion::Cancel:
it->cancel();
return;
case KParts::BrowserOpenOrSaveQuestion::Save:
saveBlob(it);
break;
case KParts::BrowserOpenOrSaveQuestion::Embed:
case KParts::BrowserOpenOrSaveQuestion::Open:
openBlob(it, p);
break;
}
}
void WebEnginePartDownloadManager::saveBlob(QWebEngineDownloadItem* it)
{
QWidget *w = it->page() ? it->page()->view() : nullptr;
QString downloadDir = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
QMimeDatabase db;
QMimeType type = db.mimeTypeForName(it->mimeType());
QFileDialog dlg(w, QString(), downloadDir);
dlg.setAcceptMode(QFileDialog::AcceptSave);
dlg.setMimeTypeFilters(QStringList{type.name(), "application/octet-stream"});
dlg.setSupportedSchemes(QStringList{"file"});
QDialog::DialogCode exitCode = static_cast<QDialog::DialogCode>(dlg.exec());
if (exitCode == QDialog::Rejected) {
it->cancel();
return;
}
QString file = dlg.selectedFiles().at(0);
QFileInfo info(file);
it->setDownloadFileName(info.fileName());
it->setDownloadDirectory(info.path());
it->accept();
it->pause();
WebEngineBlobDownloadJob *j = new WebEngineBlobDownloadJob(it, this);
KJobTrackerInterface *t = KIO::getJobTracker();
if (t) {
t->registerJob(j);
}
j->start();
}
void WebEnginePartDownloadManager::openBlob(QWebEngineDownloadItem* it, WebEnginePage *page)
{
QMimeDatabase db;
QMimeType type = db.mimeTypeForName(it->mimeType());
QString fileName = generateBlobTempFileName(it->suggestedFileName(), type.preferredSuffix());
it->setDownloadDirectory(m_tempDownloadDir.path());
it->setDownloadFileName(fileName);
connect(it, &QWebEngineDownloadItem::finished, this, [this, it, page](){blobDownloadedToFile(it, page);});
it->accept();
}
QString WebEnginePartDownloadManager::generateBlobTempFileName(const QString& suggestedName, const QString& ext) const
{
QString baseName(suggestedName);
if (baseName.isEmpty()) {
baseName = QString::number(QTime::currentTime().msecsSinceStartOfDay());
}
if (QFileInfo(baseName).completeSuffix().isEmpty() && !ext.isEmpty()) {
baseName.append("."+ext);
}
QString completeName = QDir(m_tempDownloadDir.path()).filePath(baseName);
if (QFileInfo::exists(completeName)) {
completeName = KFileUtils::suggestName(QUrl::fromLocalFile(m_tempDownloadDir.path()), baseName);
}
return completeName;
}
void WebEnginePartDownloadManager::blobDownloadedToFile(QWebEngineDownloadItem *it, WebEnginePage *page)
{
QString file = QDir(it->downloadDirectory()).filePath(it->downloadFileName());
if (page) {
page->requestOpenFileAsTemporary(QUrl::fromLocalFile(file), it->mimeType());
} else {
KIO::OpenUrlJob *j = new KIO::OpenUrlJob(QUrl::fromLocalFile(file), it->mimeType(), this);
QWidget *w = page->view();
j->setUiDelegate(new KIO::JobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, w ? w->window() : nullptr));
j->start();
}
}
#ifndef DOWNLOADITEM_KNOWS_PAGE
......@@ -103,3 +212,85 @@ WebEnginePage* WebEnginePartDownloadManager::pageForDownload(QWebEngineDownloadI
return page;
}
#endif
WebEngineBlobDownloadJob::WebEngineBlobDownloadJob(QWebEngineDownloadItem* it, QObject* parent) : KJob(parent), m_downloadItem(it)
{
setCapabilities(KJob::Killable|KJob::Suspendable);
setTotalAmount(KJob::Bytes, m_downloadItem->totalBytes());
connect(m_downloadItem, &QWebEngineDownloadItem::downloadProgress, this, &WebEngineBlobDownloadJob::downloadProgressed);
connect(m_downloadItem, &QWebEngineDownloadItem::finished, this, &WebEngineBlobDownloadJob::downloadFinished);
connect(m_downloadItem, &QWebEngineDownloadItem::stateChanged, this, &WebEngineBlobDownloadJob::stateChanged);
}
void WebEngineBlobDownloadJob::start()
{
QTimer::singleShot(0, this, &WebEngineBlobDownloadJob::startDownloading);
}
bool WebEngineBlobDownloadJob::doKill()
{
delete m_downloadItem;
m_downloadItem = nullptr;
return true;
}
bool WebEngineBlobDownloadJob::doResume()
{
if (m_downloadItem) {
m_downloadItem->resume();
}
return true;
}
bool WebEngineBlobDownloadJob::doSuspend()
{
if (m_downloadItem) {
m_downloadItem->pause();
}
return true;
}
void WebEngineBlobDownloadJob::downloadProgressed(quint64 received, quint64 total)
{
setPercent(received*100.0/total);
}
void WebEngineBlobDownloadJob::stateChanged(QWebEngineDownloadItem::DownloadState state)
{
if (state != QWebEngineDownloadItem::DownloadInterrupted) {
return;
}
setError(m_downloadItem->interruptReason() + UserDefinedError);
setErrorText(m_downloadItem->interruptReasonString());
}
QString WebEngineBlobDownloadJob::errorString() const
{
return i18n("An error occurred while saving the file: %1", errorText());
}
void WebEngineBlobDownloadJob::startDownloading()
{
if (m_downloadItem) {
m_startTime = QDateTime::currentDateTime();
emit description(this, i18nc("Notification about downloading a file", "Downloading"),
QPair<QString, QString>(i18nc("Source of a file being downloaded", "Source"), m_downloadItem->url().toString()),
QPair<QString, QString>(i18nc("Destination of a file download", "Destination"), m_downloadItem->downloadFileName()));
m_downloadItem->resume();
}
}
void WebEngineBlobDownloadJob::downloadFinished()
{
emitResult();
QDateTime now = QDateTime::currentDateTime();
if (m_startTime.msecsTo(now) < 500) {
if (m_downloadItem && m_downloadItem->page()) {
WebEnginePage *page = qobject_cast<WebEnginePage*>(m_downloadItem->page());
QString filePath = QDir(m_downloadItem->downloadDirectory()).filePath(m_downloadItem->downloadFileName());
emit page->setStatusBarText(i18nc("Finished saving BLOB URL", "Finished saving %1 as %2", m_downloadItem->url().toString(), filePath));
}
}
delete m_downloadItem;
m_downloadItem = nullptr;
}
......@@ -24,9 +24,14 @@
#include <QObject>
#include <QHash>
#include <QVector>
#include <QWebEngineDownloadItem>
#include <QTemporaryDir>
#include <QDateTime>
#include <KJob>
class WebEnginePage;
class QWebEngineDownloadItem;
class QFile;
class WebEnginePartDownloadManager : public QObject
{
......@@ -39,6 +44,8 @@ public:
private:
WebEnginePartDownloadManager();
void downloadBlob(QWebEngineDownloadItem *it);
QString generateBlobTempFileName(QString const &suggestedName, const QString &ext) const;
public Q_SLOTS:
void addPage(WebEnginePage *page);
......@@ -46,6 +53,9 @@ public Q_SLOTS:
private Q_SLOTS:
void performDownload(QWebEngineDownloadItem *it);
void saveBlob(QWebEngineDownloadItem *it);
void openBlob(QWebEngineDownloadItem *it, WebEnginePage *page);
void blobDownloadedToFile(QWebEngineDownloadItem *it, WebEnginePage *page);
#ifndef DOWNLOADITEM_KNOWS_PAGE
private:
......@@ -60,6 +70,36 @@ private:
#ifndef DOWNLOADITEM_KNOWS_PAGE
QHash<QUrl, WebEnginePage*> m_requests;
#endif
QTemporaryDir m_tempDownloadDir;
};
class WebEngineBlobDownloadJob : public KJob
{
Q_OBJECT
public:
WebEngineBlobDownloadJob(QWebEngineDownloadItem *it, QObject *parent = nullptr);
~WebEngineBlobDownloadJob(){}
void start() override;
QString errorString() const override;
protected:
bool doKill() override;
bool doResume() override;
bool doSuspend() override;
private slots:
void downloadProgressed(quint64 received, quint64 total);
void stateChanged(QWebEngineDownloadItem::DownloadState state);
void startDownloading();
void downloadFinished();
private:
QWebEngineDownloadItem *m_downloadItem;
QDateTime m_startTime;
};
#endif // WEBENGINEPARTDOWNLOADMANAGER_H
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment