To display the requested web page again, "
"the browser needs to resend information you have "
"previously submitted.
"
"If you were shopping online and made a purchase, "
"click the Cancel button to prevent a duplicate purchase."
"Otherwise, click the Continue button to display the web"
"page again.
"),
i18n("Resubmit Information")) == KMessageBox::Cancel) {
return false;
}
break;
#endif
case QWebEnginePage::NavigationTypeBackForward:
// If history navigation is locked, ignore all such requests...
if (property("HistoryNavigationLocked").toBool()) {
setProperty("HistoryNavigationLocked", QVariant());
qDebug() << "Rejected history navigation because 'HistoryNavigationLocked' property is set!";
return false;
}
//kDebug() << "Navigating to item (" << history()->currentItemIndex()
// << "of" << history()->count() << "):" << history()->currentItem().url();
inPageRequest = false;
break;
case QWebEnginePage::NavigationTypeReload:
// setRequestMetaData(QL1S("cache"), QL1S("reload"));
inPageRequest = false;
break;
case QWebEnginePage::NavigationTypeOther: // triggered by javascript
qDebug() << "Triggered by javascript";
inPageRequest = !isTypedUrl;
break;
default:
break;
}
if (inPageRequest) {
// if (!checkLinkSecurity(request, type))
// return false;
// if (m_sslInfo.isValid())
// setRequestMetaData(QL1S("ssl_was_in_use"), QL1S("TRUE"));
}
// 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);
}
#if 0
static int errorCodeFromReply(QNetworkReply* reply)
{
// First check if there is a KIO error code sent back and use that,
// if not attempt to convert QNetworkReply's NetworkError to KIO::Error.
QVariant attr = reply->attribute(static_cast(KIO::AccessManager::KioError));
if (attr.isValid() && attr.type() == QVariant::Int)
return attr.toInt();
switch (reply->error()) {
case QNetworkReply::ConnectionRefusedError:
return KIO::ERR_COULD_NOT_CONNECT;
case QNetworkReply::HostNotFoundError:
return KIO::ERR_UNKNOWN_HOST;
case QNetworkReply::TimeoutError:
return KIO::ERR_SERVER_TIMEOUT;
case QNetworkReply::OperationCanceledError:
return KIO::ERR_USER_CANCELED;
case QNetworkReply::ProxyNotFoundError:
return KIO::ERR_UNKNOWN_PROXY_HOST;
case QNetworkReply::ContentAccessDenied:
return KIO::ERR_ACCESS_DENIED;
case QNetworkReply::ContentOperationNotPermittedError:
return KIO::ERR_WRITE_ACCESS_DENIED;
case QNetworkReply::ContentNotFoundError:
return KIO::ERR_NO_CONTENT;
case QNetworkReply::AuthenticationRequiredError:
return KIO::ERR_COULD_NOT_AUTHENTICATE;
case QNetworkReply::ProtocolUnknownError:
return KIO::ERR_UNSUPPORTED_PROTOCOL;
case QNetworkReply::ProtocolInvalidOperationError:
return KIO::ERR_UNSUPPORTED_ACTION;
case QNetworkReply::UnknownNetworkError:
return KIO::ERR_UNKNOWN;
case QNetworkReply::NoError:
default:
break;
}
return 0;
}
#endif
WebEnginePart* WebEnginePage::part() const
{
return m_part.data();
}
void WebEnginePage::setPart(WebEnginePart* part)
{
m_part = part;
}
void WebEnginePage::slotLoadFinished(bool ok)
{
QUrl requestUrl = url();
requestUrl.setUserInfo(QString());
const bool shouldResetSslInfo = (m_sslInfo.isValid() && !domainSchemeMatch(requestUrl, m_sslInfo.url()));
#if 0
QWebFrame* frame = qobject_cast(reply->request().originatingObject());
if (!frame)
return;
const bool isMainFrameRequest = (frame == mainFrame());
#else
// PORTING_TODO
const bool isMainFrameRequest = true;
#endif
#if 0
// Only deal with non-redirect responses...
const QVariant redirectVar = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
if (isMainFrameRequest && redirectVar.isValid()) {
m_sslInfo.restoreFrom(reply->attribute(static_cast(KIO::AccessManager::MetaData)),
reply->url(), shouldResetSslInfo);
return;
}
const int errCode = errorCodeFromReply(reply);
kDebug() << frame << "is main frame request?" << isMainFrameRequest << requestUrl;
#endif
if (ok) {
if (isMainFrameRequest) {
#if 0
m_sslInfo.restoreFrom(reply->attribute(static_cast(KIO::AccessManager::MetaData)),
reply->url(), shouldResetSslInfo);
#endif
setPageJScriptPolicy(url());
}
} else {
// Handle any error...
#if 0
switch (errCode) {
case 0:
case KIO::ERR_NO_CONTENT:
break;
case KIO::ERR_ABORTED:
case KIO::ERR_USER_CANCELED: // Do nothing if request is cancelled/aborted
//kDebug() << "User aborted request!";
m_ignoreError = true;
emit loadAborted(QUrl());
return;
// Handle the user clicking on a link that refers to a directory
// Since KIO cannot automatically convert a GET request to a LISTDIR one.
case KIO::ERR_IS_DIRECTORY:
m_ignoreError = true;
emit loadAborted(reply->url());
return;
default:
// Make sure the saveFrameStateRequested signal is emitted so
// the page can restored properly.
if (isMainFrameRequest)
emit saveFrameStateRequested(frame, 0);
m_ignoreError = (reply->attribute(QNetworkRequest::User).toInt() == QNetworkReply::ContentAccessDenied);
m_kioErrorCode = errCode;
break;
#endif
}
if (isMainFrameRequest) {
const WebEnginePageSecurity security = (m_sslInfo.isValid() ? PageEncrypted : PageUnencrypted);
emit m_part->browserExtension()->setPageSecurity(security);
}
}
void WebEnginePage::slotUnsupportedContent(QNetworkReply* reply)
{
#if 0
//kDebug() << reply->url();
QString mimeType;
KIO::MetaData metaData;
KIO::AccessManager::putReplyOnHold(reply);
QString downloadCmd;
checkForDownloadManager(view(), downloadCmd);
if (!downloadCmd.isEmpty()) {
reply->setProperty("DownloadManagerExe", downloadCmd);
}
if (QWePage::handleReply(reply, &mimeType, &metaData)) {
reply->deleteLater();
if (qobject_cast(this) && isBlankUrl(m_part->url())) {
m_part->closeUrl();
if (m_part->arguments().metaData().contains(QL1S("new-window"))) {
m_part->widget()->topLevelWidget()->close();
} else {
delete m_part;
}
}
return;
}
//kDebug() << "mimetype=" << mimeType << "metadata:" << metaData;
if (reply->request().originatingObject() == this->mainFrame()) {
KParts::OpenUrlArguments args;
args.setMimeType(mimeType);
args.metaData() = metaData;
emit m_part->browserExtension()->openUrlRequest(reply->url(), args, KParts::BrowserArguments());
return;
}
#endif
reply->deleteLater();
}
void WebEnginePage::slotFeaturePermissionRequested(const QUrl& url, QWebEnginePage::Feature feature)
{
if (url == this->url()) {
part()->slotShowFeaturePermissionBar(feature);
return;
}
switch(feature) {
case QWebEnginePage::Notifications:
// FIXME: We should have a setting to tell if this is enabled, but so far it is always enabled.
setFeaturePermission(url, feature, QWebEnginePage::PermissionGrantedByUser);
break;
case QWebEnginePage::Geolocation:
if (KMessageBox::warningContinueCancel(0, i18n("This site is attempting to "
"access information about your "
"physical location.\n"
"Do you want to allow it access?"),
i18n("Network Transmission"),
KGuiItem(i18n("Allow access")),
KStandardGuiItem::cancel(),
QStringLiteral("WarnGeolocation")) == KMessageBox::Cancel) {
setFeaturePermission(url, feature, QWebEnginePage::PermissionDeniedByUser);
} else {
setFeaturePermission(url, feature, QWebEnginePage::PermissionGrantedByUser);
}
break;
default:
setFeaturePermission(url, feature, QWebEnginePage::PermissionUnknown);
break;
}
}
void WebEnginePage::slotGeometryChangeRequested(const QRect & rect)
{
const QString host = url().host();
// NOTE: If a new window was created from another window which is in
// maximized mode and its width and/or height were not specified at the
// time of its creation, which is always the case in QWebEnginePage::createWindow,
// then any move operation will seem not to work. That is because the new
// window will be in maximized mode where moving it will not be possible...
if (WebEngineSettings::self()->windowMovePolicy(host) == KParts::HtmlSettingsInterface::JSWindowMoveAllow &&
(view()->x() != rect.x() || view()->y() != rect.y()))
emit m_part->browserExtension()->moveTopLevelWidget(rect.x(), rect.y());
const int height = rect.height();
const int width = rect.width();
// parts of following code are based on kjs_window.cpp
// Security check: within desktop limits and bigger than 100x100 (per spec)
if (width < 100 || height < 100) {
qWarning() << "Window resize refused, window would be too small (" << width << "," << height << ")";
return;
}
QRect sg = QApplication::desktop()->screenGeometry(view());
if (width > sg.width() || height > sg.height()) {
qWarning() << "Window resize refused, window would be too big (" << width << "," << height << ")";
return;
}
if (WebEngineSettings::self()->windowResizePolicy(host) == KParts::HtmlSettingsInterface::JSWindowResizeAllow) {
//kDebug() << "resizing to " << width << "x" << height;
emit m_part->browserExtension()->resizeTopLevelWidget(width, height);
}
// If the window is out of the desktop, move it up/left
// (maybe we should use workarea instead of sg, otherwise the window ends up below kicker)
const int right = view()->x() + view()->frameGeometry().width();
const int bottom = view()->y() + view()->frameGeometry().height();
int moveByX = 0, moveByY = 0;
if (right > sg.right())
moveByX = - right + sg.right(); // always <0
if (bottom > sg.bottom())
moveByY = - bottom + sg.bottom(); // always <0
if ((moveByX || moveByY) && WebEngineSettings::self()->windowMovePolicy(host) == KParts::HtmlSettingsInterface::JSWindowMoveAllow)
emit m_part->browserExtension()->moveTopLevelWidget(view()->x() + moveByX, view()->y() + moveByY);
}
bool WebEnginePage::checkLinkSecurity(const QNetworkRequest &req, NavigationType type) const
{
// Check whether the request is authorized or not...
if (!KUrlAuthorized::authorizeUrlAction(QStringLiteral("redirect"), url(), req.url())) {
//kDebug() << "*** Failed security check: base-url=" << mainFrame()->url() << ", dest-url=" << req.url();
QString buttonText, title, message;
int response = KMessageBox::Cancel;
QUrl linkUrl (req.url());
if (type == QWebEnginePage::NavigationTypeLinkClicked) {
message = i18n("This untrusted page links to
%1."
"
Do you want to follow the link?", linkUrl.url());
title = i18n("Security Warning");
buttonText = i18nc("follow link despite of security warning", "Follow");
} else {
title = i18n("Security Alert");
message = i18n("Access by untrusted page to
%1
denied.",
linkUrl.toDisplayString().toHtmlEscaped());
}
if (buttonText.isEmpty()) {
KMessageBox::error( 0, message, title);
} else {
// Dangerous flag makes the Cancel button the default
response = KMessageBox::warningContinueCancel(0, message, title,
KGuiItem(buttonText),
KStandardGuiItem::cancel(),
QString(), // no don't ask again info
KMessageBox::Notify | KMessageBox::Dangerous);
}
return (response == KMessageBox::Continue);
}
return true;
}
bool WebEnginePage::checkFormData(const QNetworkRequest &req) const
{
const QString scheme (req.url().scheme());
if (m_sslInfo.isValid() &&
!scheme.compare(QL1S("https")) && !scheme.compare(QL1S("mailto")) &&
(KMessageBox::warningContinueCancel(0,
i18n("Warning: This is a secure form "
"but it is attempting to send "
"your data back unencrypted.\n"
"A third party may be able to "
"intercept and view this "
"information.\nAre you sure you "
"want to send the data unencrypted?"),
i18n("Network Transmission"),
KGuiItem(i18n("&Send Unencrypted"))) == KMessageBox::Cancel)) {
return false;
}
if (scheme.compare(QL1S("mailto")) == 0 &&
(KMessageBox::warningContinueCancel(0, i18n("This site is attempting to "
"submit form data via email.\n"
"Do you want to continue?"),
i18n("Network Transmission"),
KGuiItem(i18n("&Send Email")),
KStandardGuiItem::cancel(),
QStringLiteral("WarnTriedEmailSubmit")) == KMessageBox::Cancel)) {
return false;
}
return true;
}
// Sanitizes the "mailto:" url, e.g. strips out any "attach" parameters.
static QUrl sanitizeMailToUrl(const QUrl &url, QStringList& files) {
QUrl sanitizedUrl;
// NOTE: This is necessary to ensure we can properly use QUrl's query
// related APIs to process 'mailto:' urls of form 'mailto:foo@bar.com'.
if (url.hasQuery())
sanitizedUrl = url;
else
sanitizedUrl = QUrl(url.scheme() + QL1S(":?") + url.path());
QUrlQuery query(sanitizedUrl);
const QList > items (query.queryItems());
QUrlQuery sanitizedQuery;
for(auto queryItem : items) {
if (queryItem.first.contains(QL1C('@')) && queryItem.second.isEmpty()) {
// ### DF: this hack breaks mailto:faure@kde.org, kmail doesn't expect mailto:?to=faure@kde.org
queryItem.second = queryItem.first;
queryItem.first = QStringLiteral("to");
} else if (QString::compare(queryItem.first, QL1S("attach"), Qt::CaseInsensitive) == 0) {
files << queryItem.second;
continue;
}
sanitizedQuery.addQueryItem(queryItem.first, queryItem.second);
}
sanitizedUrl.setQuery(sanitizedQuery);
return sanitizedUrl;
}
bool WebEnginePage::handleMailToUrl (const QUrl &url, NavigationType type) const
{
if (url.scheme() == QL1S("mailto")) {
QStringList files;
QUrl mailtoUrl (sanitizeMailToUrl(url, files));
switch (type) {
case QWebEnginePage::NavigationTypeLinkClicked:
if (!files.isEmpty() && KMessageBox::warningContinueCancelList(0,
i18n("Do you want to allow this site to attach "
"the following files to the email message?"),
files, i18n("Email Attachment Confirmation"),
KGuiItem(i18n("&Allow attachments")),
KGuiItem(i18n("&Ignore attachments")), QL1S("WarnEmailAttachment")) == KMessageBox::Continue) {
// Re-add the attachments...
QStringListIterator filesIt (files);
QUrlQuery query(mailtoUrl);
while (filesIt.hasNext()) {
query.addQueryItem(QL1S("attach"), filesIt.next());
}
mailtoUrl.setQuery(query);
}
break;
case QWebEnginePage::NavigationTypeFormSubmitted:
//case QWebEnginePage::NavigationTypeFormResubmitted:
if (!files.isEmpty()) {
KMessageBox::information(0, i18n("This site attempted to attach a file from your "
"computer in the form submission. The attachment "
"was removed for your protection."),
i18n("Attachment Removed"), QStringLiteral("InfoTriedAttach"));
}
break;
default:
break;
}
//kDebug() << "Emitting openUrlRequest with " << mailtoUrl;
emit m_part->browserExtension()->openUrlRequest(mailtoUrl);
return true;
}
return false;
}
void WebEnginePage::setPageJScriptPolicy(const QUrl &url)
{
const QString hostname (url.host());
settings()->setAttribute(QWebEngineSettings::JavascriptEnabled,
WebEngineSettings::self()->isJavaScriptEnabled(hostname));
const KParts::HtmlSettingsInterface::JSWindowOpenPolicy policy = WebEngineSettings::self()->windowOpenPolicy(hostname);
settings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows,
(policy != KParts::HtmlSettingsInterface::JSWindowOpenDeny &&
policy != KParts::HtmlSettingsInterface::JSWindowOpenSmart));
}
void WebEnginePage::slotAuthenticationRequired(const QUrl &requestUrl, QAuthenticator *auth)
{
KIO::AuthInfo info;
info.url = requestUrl;
info.username = auth->user();
info.realmValue = auth->realm();
// If no realm metadata, then make sure path matching is turned on.
info.verifyPath = info.realmValue.isEmpty();
const QString errorMsg = QString();
#if KIO_VERSION >= QT_VERSION_CHECK(5, 30, 0)
const int ret = m_passwdServerClient->queryAuthInfo(&info, errorMsg, view()->window()->winId(), KUserTimestamp::userTimestamp());
#else
const int ret = 1; // no KPasswdServerClient until 5.30
#endif
if (ret == KJob::NoError) {
auth->setUser(info.username);
auth->setPassword(info.password);
} else {
// Set authenticator null if dialog is cancelled
// or if we couldn't communicate with kpasswdserver
*auth = QAuthenticator();
}
}
/************************************* Begin NewWindowPage ******************************************/
NewWindowPage::NewWindowPage(WebWindowType type, WebEnginePart* part, QWidget* parent)
:WebEnginePage(part, parent) , m_type(type) , m_createNewWindow(true)
{
Q_ASSERT_X (part, "NewWindowPage", "Must specify a valid KPart");
connect(this, SIGNAL(menuBarVisibilityChangeRequested(bool)),
this, SLOT(slotMenuBarVisibilityChangeRequested(bool)));
connect(this, SIGNAL(toolBarVisibilityChangeRequested(bool)),
this, SLOT(slotToolBarVisibilityChangeRequested(bool)));
connect(this, SIGNAL(statusBarVisibilityChangeRequested(bool)),
this, SLOT(slotStatusBarVisibilityChangeRequested(bool)));
connect(this, SIGNAL(loadFinished(bool)), this, SLOT(slotLoadFinished(bool)));
#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 7, 0)
if (m_type == WebBrowserBackgroundTab) {
m_windowArgs.setLowerWindow(true);
}
#endif
}
NewWindowPage::~NewWindowPage()
{
}
static KParts::BrowserArguments browserArgs(WebEnginePage::WebWindowType type)
{
KParts::BrowserArguments bargs;
switch (type) {
case WebEnginePage::WebDialog:
case WebEnginePage::WebBrowserWindow:
bargs.setForcesNewWindow(true);
break;
case WebEnginePage::WebBrowserTab:
#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 7, 0)
case WebEnginePage::WebBrowserBackgroundTab:
#endif
// let konq decide, based on user configuration
//bargs.setNewTab(true);
break;
}
return bargs;
}
bool NewWindowPage::acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame)
{
//qDebug() << "url:" << url << ", type:" << type << ", isMainFrame:" << isMainFrame << "m_createNewWindow=" << m_createNewWindow;
if (m_createNewWindow) {
const QUrl reqUrl (url);
const bool actionRequestedByUser = type != QWebEnginePage::NavigationTypeOther;
if (actionRequestedByUser) {
if (!part() && !isMainFrame) {
return false;
}
const KParts::HtmlSettingsInterface::JSWindowOpenPolicy policy = WebEngineSettings::self()->windowOpenPolicy(reqUrl.host());
switch (policy) {
case KParts::HtmlSettingsInterface::JSWindowOpenDeny:
// TODO: Implement support for dealing with blocked pop up windows.
this->deleteLater();
return false;
case KParts::HtmlSettingsInterface::JSWindowOpenAsk: {
const QString message = (reqUrl.isEmpty() ?
i18n("This site is requesting to open a new popup window.\n"
"Do you want to allow this?") :
i18n("This site is requesting to open a popup window to"
"%1
Do you want to allow this?",
KStringHandler::rsqueeze(reqUrl.toDisplayString().toHtmlEscaped(), 100)));
if (KMessageBox::questionYesNo(view(), message,
i18n("Javascript Popup Confirmation"),
KGuiItem(i18n("Allow")),
KGuiItem(i18n("Do Not Allow"))) == KMessageBox::No) {
// TODO: Implement support for dealing with blocked pop up windows.
this->deleteLater();
return false;
}
break;
}
default:
break;
}
}
// Browser args...
KParts::BrowserArguments bargs = browserArgs(m_type);
// OpenUrl args...
KParts::OpenUrlArguments uargs;
uargs.setMimeType(QL1S("text/html"));
uargs.setActionRequestedByUser(actionRequestedByUser);
// Window args...
KParts::WindowArgs wargs (m_windowArgs);
KParts::ReadOnlyPart* newWindowPart =0;
part()->browserExtension()->createNewWindow(QUrl(), uargs, bargs, wargs, &newWindowPart);
qDebug() << "Created new window" << newWindowPart;
if (!newWindowPart) {
return false;
} else if (newWindowPart->widget()->topLevelWidget() != part()->widget()->topLevelWidget()) {
KParts::OpenUrlArguments args;
args.metaData().insert(QL1S("new-window"), QL1S("true"));
newWindowPart->setArguments(args);
}
// Get the webview...
WebEnginePart* webenginePart = qobject_cast(newWindowPart);
WebEngineView* webView = webenginePart ? qobject_cast(webenginePart->view()) : 0;
// If the newly created window is NOT a webenginepart...
if (!webView) {
qDebug() << "Opening URL on" << newWindowPart;
newWindowPart->openUrl(reqUrl);
this->deleteLater();
return false;
}
// Reparent this page to the new webview to prevent memory leaks.
setParent(webView);
// Replace the webpage of the new webview with this one. Nice trick...
webView->setPage(this);
// Set the new part as the one this page will use going forward.
setPart(webenginePart);
// Connect all the signals from this page to the slots in the new part.
webenginePart->connectWebEnginePageSignals(this);
//Set the create new window flag to false...
m_createNewWindow = false;
- }
+ }
+ emit navigationRequested(this, url);
return WebEnginePage::acceptNavigationRequest(url, type, isMainFrame);
}
void NewWindowPage::slotGeometryChangeRequested(const QRect & rect)
{
if (!rect.isValid())
return;
if (!m_createNewWindow) {
WebEnginePage::slotGeometryChangeRequested(rect);
return;
}
m_windowArgs.setX(rect.x());
m_windowArgs.setY(rect.y());
m_windowArgs.setWidth(qMax(rect.width(), 100));
m_windowArgs.setHeight(qMax(rect.height(), 100));
}
void NewWindowPage::slotMenuBarVisibilityChangeRequested(bool visible)
{
//kDebug() << visible;
m_windowArgs.setMenuBarVisible(visible);
}
void NewWindowPage::slotStatusBarVisibilityChangeRequested(bool visible)
{
//kDebug() << visible;
m_windowArgs.setStatusBarVisible(visible);
}
void NewWindowPage::slotToolBarVisibilityChangeRequested(bool visible)
{
//kDebug() << visible;
m_windowArgs.setToolBarsVisible(visible);
}
// When is this called? (and acceptNavigationRequest is not called?)
// The only case I found is Ctrl+click on link to data URL (like in konqviewmgrtest), that's quite specific...
// Everything else seems to work with this method being commented out...
void NewWindowPage::slotLoadFinished(bool ok)
{
Q_UNUSED(ok)
qDebug() << ok;
if (!m_createNewWindow)
return;
const bool actionRequestedByUser = true; // ### we don't have the information here, unlike in acceptNavigationRequest
// Browser args...
KParts::BrowserArguments bargs = browserArgs(m_type);
//bargs.frameName = mainFrame()->frameName();
// OpenUrl args...
KParts::OpenUrlArguments uargs;
uargs.setMimeType(QL1S("text/html"));
uargs.setActionRequestedByUser(actionRequestedByUser);
// Window args...
KParts::WindowArgs wargs (m_windowArgs);
KParts::ReadOnlyPart* newWindowPart =0;
part()->browserExtension()->createNewWindow(QUrl(), uargs, bargs, wargs, &newWindowPart);
qDebug() << "Created new window or tab" << newWindowPart;
// Get the webview...
WebEnginePart* webenginePart = newWindowPart ? qobject_cast(newWindowPart) : 0;
WebEngineView* webView = webenginePart ? qobject_cast(webenginePart->view()) : 0;
if (webView) {
// if a new window is created, set a new window meta-data flag.
if (newWindowPart->widget()->topLevelWidget() != part()->widget()->topLevelWidget()) {
KParts::OpenUrlArguments args;
args.metaData().insert(QL1S("new-window"), QL1S("true"));
newWindowPart->setArguments(args);
}
// Reparent this page to the new webview to prevent memory leaks.
setParent(webView);
// Replace the webpage of the new webview with this one. Nice trick...
webView->setPage(this);
// Set the new part as the one this page will use going forward.
setPart(webenginePart);
// Connect all the signals from this page to the slots in the new part.
webenginePart->connectWebEnginePageSignals(this);
}
//Set the create new window flag to false...
m_createNewWindow = false;
}
/****************************** End NewWindowPage *************************************************/
diff --git a/webenginepart/src/webenginepage.h b/webenginepart/src/webenginepage.h
index 2665d33be..8fa038665 100644
--- a/webenginepart/src/webenginepage.h
+++ b/webenginepart/src/webenginepage.h
@@ -1,168 +1,163 @@
/*
* This file is part of the KDE project.
*
* Copyright (C) 2008 Dirk Mueller
* Copyright (C) 2008 Urs Wolfer
* Copyright (C) 2009 Dawit Alemayehu
*
* 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 .
*
*/
#ifndef WEBENGINEPAGE_H
#define WEBENGINEPAGE_H
#include "websslinfo.h"
#include
#include
#include
#include
#include
#include
#include
class QAuthenticator;
class QUrl;
class WebSslInfo;
class WebEnginePart;
class QWebEngineDownloadItem;
class KPasswdServerClient;
class WebEnginePage : public QWebEnginePage
{
Q_OBJECT
public:
explicit WebEnginePage(WebEnginePart *wpart, QWidget *parent = Q_NULLPTR);
~WebEnginePage();
/**
* Returns the SSL information for the current page.
*
* @see WebSslInfo.
*/
const WebSslInfo& sslInfo() const;
/**
* Sets the page's SSL information to @p other.
*
* @see WebSslInfo
*/
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:
/**
* This signal is emitted whenever a user cancels/aborts a load resource
* request.
*/
void loadAborted(const QUrl &url);
+ void navigationRequested(WebEnginePage* page, const QUrl& url);
+
protected:
/**
* Returns the webengine part in use by this object.
* @internal
*/
WebEnginePart* part() const;
/**
* Sets the webengine part to be used by this object.
* @internal
*/
void setPart(WebEnginePart*);
/**
* Reimplemented for internal reasons, the API is not affected.
* @internal
*/
QWebEnginePage* createWindow(WebWindowType type) Q_DECL_OVERRIDE;
/**
* Reimplemented for internal reasons, the API is not affected.
* @internal
*/
bool acceptNavigationRequest(const QUrl& request, NavigationType type, bool isMainFrame) Q_DECL_OVERRIDE;
protected Q_SLOTS:
void slotLoadFinished(bool ok);
void slotUnsupportedContent(QNetworkReply* reply);
virtual void slotGeometryChangeRequested(const QRect& rect);
void slotFeaturePermissionRequested(const QUrl& url, QWebEnginePage::Feature feature);
void slotAuthenticationRequired(const QUrl &requestUrl, QAuthenticator *auth);
private:
bool checkLinkSecurity(const QNetworkRequest& req, NavigationType type) const;
bool checkFormData(const QNetworkRequest& req) const;
bool handleMailToUrl (const QUrl& , NavigationType type) const;
void setPageJScriptPolicy(const QUrl& url);
private:
enum WebEnginePageSecurity { PageUnencrypted, PageEncrypted, PageMixed };
int m_kioErrorCode;
bool m_ignoreError;
WebSslInfo m_sslInfo;
QPointer m_part;
QScopedPointer m_passwdServerClient;
-
};
/**
* This is a fake implementation of WebEnginePage to workaround the ugly API used
* to request for the creation of a new window from javascript in QtWebEngine. PORTING_TODO
*
* The KPart API for creating new windows requires all the information about the
* new window up front. Unfortunately QWebEnginePage::createWindow function does not
* provide any of these necessary information except for the window type. All
* the other necessary information is emitted as signals instead! Hence, the
* need for this class to collect all of the necessary information, such as
* window name, size and position, before calling KPart's createNewWindow
* function.
*/
class NewWindowPage : public WebEnginePage
{
Q_OBJECT
public:
NewWindowPage(WebWindowType windowType, WebEnginePart* part,
QWidget* parent = Q_NULLPTR);
virtual ~NewWindowPage();
protected:
bool acceptNavigationRequest(const QUrl& request, NavigationType type, bool isMainFrame) Q_DECL_OVERRIDE;
private Q_SLOTS:
void slotGeometryChangeRequested(const QRect& rect) override;
void slotMenuBarVisibilityChangeRequested(bool visible);
void slotStatusBarVisibilityChangeRequested(bool visible);
void slotToolBarVisibilityChangeRequested(bool visible);
void slotLoadFinished(bool);
private:
KParts::WindowArgs m_windowArgs;
WebWindowType m_type;
bool m_createNewWindow;
};
#endif // WEBENGINEPAGE_H
diff --git a/webenginepart/src/webenginepartdownloadmanager.cpp b/webenginepart/src/webenginepartdownloadmanager.cpp
new file mode 100644
index 000000000..1bffcc9c1
--- /dev/null
+++ b/webenginepart/src/webenginepartdownloadmanager.cpp
@@ -0,0 +1,88 @@
+/*
+ * This file is part of the KDE project.
+ *
+ * Copyright (C) 2017 Stefano Crocco
+ *
+ * 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 .
+ *
+ */
+
+#include "webenginepartdownloadmanager.h"
+
+#include "webenginepage.h"
+
+#include
+#include
+#include
+#include
+
+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(page));
+ m_requests.remove(url);
+ m_pages.removeOne(static_cast(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;
+}
diff --git a/webenginepart/src/webenginepartdownloadmanager.h b/webenginepart/src/webenginepartdownloadmanager.h
new file mode 100644
index 000000000..c565dbf11
--- /dev/null
+++ b/webenginepart/src/webenginepartdownloadmanager.h
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the KDE project.
+ *
+ * Copyright (C) 2017 Stefano Crocco
+ *
+ * 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 .
+ *
+ */
+
+#ifndef WEBENGINEPARTDOWNLOADMANAGER_H
+#define WEBENGINEPARTDOWNLOADMANAGER_H
+
+#include
+#include
+#include
+
+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 m_pages;
+ QHash m_requests;
+};
+
+#endif // WEBENGINEPARTDOWNLOADMANAGER_H