Commit c217801a authored by Stefano Crocco's avatar Stefano Crocco

Fix download behavior when using webengine part

With KHTML and KWebKitPart, clicking on a download link would make
konqueror embed the downloaded file in the current view or in another
tab or window according to the user settings.

To have the same happen with WebEnginePart, the openUrlRequest signal
must be emitted by the part in response to
QWebEngineProfile::downloadRequested
signal.

To achieve this, a new class, WebEnginePartDownloadManager, is
introduced. This class connects to QWebProfile::downloadRequested signal
and to a new signal, navigationRequested, from each existing
WebEnginePage.

The navigationRequested signal (emitted by a web page's
acceptNavigationRequest method) allows the download manager to associate
each download request with a navigation request, and, consequently, with
the WebEnginePage which requested the download (this is necessary
because there's no way to associate the download request with a
QWebEnginePage automatically). At this point, the openUrlRequest is
emitted from the part corresponding to the page. Note that the download
is not performed using QWebEngineDownloadItem (that is,
QWebEngineDownloadItem::accept is not called).

Sometimes, a download is requested without a corresponding call to
acceptNavigationRequest: in this case, the signal is emitted from an
arbitrary part, specifying to open the file in a new window.

This process doesn't always work, expecially when downloads are started
from javascript or by clicking on links forcing a download or specifying
a _blank target. These issues need to be investigated further

Differential Revision: https://phabricator.kde.org/D6781
parent 43ebc7d8
......@@ -7,6 +7,7 @@ set(kwebenginepartlib_LIB_SRCS
webenginepage.cpp
websslinfo.cpp
webhistoryinterface.cpp
webenginepartdownloadmanager.cpp
settings/webenginesettings.cpp
settings/webengine_filter.cpp
ui/searchbar.cpp
......
......@@ -26,6 +26,7 @@
#include "websslinfo.h"
#include "webengineview.h"
#include "settings/webenginesettings.h"
#include "webenginepartdownloadmanager.h"
#include <QWebEngineSettings>
#include <QWebEngineProfile>
......@@ -88,11 +89,11 @@ WebEnginePage::WebEnginePage(WebEnginePart *part, QWidget *parent)
this, &WebEnginePage::slotLoadFinished);
connect(this, &QWebEnginePage::authenticationRequired,
this, &WebEnginePage::slotAuthenticationRequired);
connect(this->profile(), &QWebEngineProfile::downloadRequested, this, &WebEnginePage::downloadRequest);
if(!this->profile()->httpUserAgent().contains(QLatin1String("Konqueror")))
{
this->profile()->setHttpUserAgent(this->profile()->httpUserAgent() + " Konqueror (WebEnginePart)");
}
WebEnginePartDownloadManager::instance()->addPage(this);
}
WebEnginePage::~WebEnginePage()
......@@ -131,10 +132,8 @@ static void checkForDownloadManager(QWidget* widget, QString& cmd)
cmd = exeName;
}
void WebEnginePage::downloadRequest(QWebEngineDownloadItem* request)
void WebEnginePage::download(const QUrl& url, bool newWindow)
{
const QUrl url(request->url());
// Integration with a download manager...
if (!url.isLocalFile()) {
QString managerExe;
......@@ -145,21 +144,9 @@ void WebEnginePage::downloadRequest(QWebEngineDownloadItem* request)
return;
}
}
// Ask the user where to save. We don't have a GUI like Firefox or Chrome to
// notify of something being saved to the Downloads directory.
QPointer<QFileDialog> dlg(new QFileDialog(view()));
dlg->setAcceptMode(QFileDialog::AcceptSave);
dlg->setWindowTitle(i18n("Save As"));
dlg->setConfirmOverwrite(true);
dlg->selectFile(request->path());
if (dlg->exec()) {
request->setPath(dlg->selectedFiles().at(0));
request->accept();
} else {
request->cancel();
}
delete dlg;
KParts::BrowserArguments bArgs;
bArgs.setForcesNewWindow(newWindow);
emit part()->browserExtension()->openUrlRequest(url, KParts::OpenUrlArguments(), bArgs);
}
QWebEnginePage *WebEnginePage::createWindow(WebWindowType type)
......@@ -271,7 +258,7 @@ bool WebEnginePage::acceptNavigationRequest(const QUrl& url, NavigationType type
// Honor the enabling/disabling of plugins per host.
settings()->setAttribute(QWebEngineSettings::PluginsEnabled, WebEngineSettings::self()->isPluginsEnabled(reqUrl.host()));
// Insert the request into the queue...
emit navigationRequested(this, url);
return QWebEnginePage::acceptNavigationRequest(url, type, isMainFrame);
}
......@@ -839,8 +826,9 @@ bool NewWindowPage::acceptNavigationRequest(const QUrl &url, NavigationType type
webenginePart->connectWebEnginePageSignals(this);
//Set the create new window flag to false...
m_createNewWindow = false;
}
}
emit navigationRequested(this, url);
return WebEnginePage::acceptNavigationRequest(url, type, isMainFrame);
}
......
......@@ -62,13 +62,7 @@ public:
*/
void setSslInfo (const WebSslInfo &other);
/**
* Reimplemented for internal reasons. The API is not affected.
*
* @internal
* @see KWebEnginePage::downloadRequest.
*/
void downloadRequest(QWebEngineDownloadItem* request);
void download(const QUrl &url, bool newWindow = false);
Q_SIGNALS:
/**
......@@ -77,6 +71,8 @@ Q_SIGNALS:
*/
void loadAborted(const QUrl &url);
void navigationRequested(WebEnginePage* page, const QUrl& url);
protected:
/**
* Returns the webengine part in use by this object.
......@@ -125,7 +121,6 @@ private:
QPointer<WebEnginePart> m_part;
QScopedPointer<KPasswdServerClient> m_passwdServerClient;
};
......
/*
* This file is part of the KDE project.
*
* Copyright (C) 2017 Stefano Crocco <posta@stefanocrocco.it>
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "webenginepartdownloadmanager.h"
#include "webenginepage.h"
#include <QWebEngineDownloadItem>
#include <QWebEngineView>
#include <QWebEngineProfile>
#include <QDebug>
WebEnginePartDownloadManager::WebEnginePartDownloadManager(): QObject()
{
connect(QWebEngineProfile::defaultProfile(), &QWebEngineProfile::downloadRequested, this, &WebEnginePartDownloadManager::performDownload);
}
WebEnginePartDownloadManager::~WebEnginePartDownloadManager()
{
m_requests.clear();
}
WebEnginePartDownloadManager * WebEnginePartDownloadManager::instance()
{
static WebEnginePartDownloadManager inst;
return &inst;
}
void WebEnginePartDownloadManager::addPage(WebEnginePage* page)
{
if (!m_pages.contains(page)) m_pages.append(page);
connect(page, &WebEnginePage::navigationRequested, this, &WebEnginePartDownloadManager::recordNavigationRequest);
connect(page, &QObject::destroyed, this, &WebEnginePartDownloadManager::removePage);
}
void WebEnginePartDownloadManager::removePage(QObject* page)
{
const QUrl url = m_requests.key(static_cast<WebEnginePage *>(page));
m_requests.remove(url);
m_pages.removeOne(static_cast<WebEnginePage*>(page));
}
void WebEnginePartDownloadManager::performDownload(QWebEngineDownloadItem* it)
{
WebEnginePage *page = m_requests.take(it->url());
bool forceNew = false;
if (!page && !m_pages.isEmpty()) {
qDebug() << "downloading" << it->url() << "in new window or tab";
page = m_pages.first();
forceNew = true;
}
else if (!page){
qDebug() << "Couldn't find a part wanting to download" << it->url();
return;
}
page->download(it->url(), forceNew);
}
void WebEnginePartDownloadManager::recordNavigationRequest(WebEnginePage *page, const QUrl& url)
{
qDebug() << "recordNavigatioRequest for" << url;
m_requests.insert(url, page);
}
WebEnginePage* WebEnginePartDownloadManager::pageForDownload(QWebEngineDownloadItem* it)
{
WebEnginePage *page = m_requests.value(it->url());
if(!page && !m_pages.isEmpty()) page = m_pages.first();
return page;
}
/*
* This file is part of the KDE project.
*
* Copyright (C) 2017 Stefano Crocco <posta@stefanocrocco.it>
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef WEBENGINEPARTDOWNLOADMANAGER_H
#define WEBENGINEPARTDOWNLOADMANAGER_H
#include <QObject>
#include <QHash>
#include <QVector>
class WebEnginePage;
class QWebEngineDownloadItem;
class WebEnginePartDownloadManager : public QObject
{
Q_OBJECT
public:
static WebEnginePartDownloadManager* instance();
~WebEnginePartDownloadManager();
public Q_SLOTS:
void addPage(WebEnginePage *page);
void removePage(QObject *page);
private:
WebEnginePartDownloadManager();
WebEnginePage* pageForDownload(QWebEngineDownloadItem *it);
private Q_SLOTS:
void performDownload(QWebEngineDownloadItem *it);
void recordNavigationRequest(WebEnginePage* page, const QUrl& url);
private:
QVector<WebEnginePage*> m_pages;
QHash<QUrl, WebEnginePage*> m_requests;
};
#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