From b4864da72e5861c3958c66cc9018aaf5b681320b Mon Sep 17 00:00:00 2001 From: Andras Becsi Date: Tue, 27 Jan 2015 13:11:06 +0100 Subject: Add widgets download API This patch adds a QWebEngineDownloadItem class to the widget API and extends QWebEngineProfile with a signal to notify about initiated downloads, similar to the QML API. [ChangeLog][QtWebEngineWidgets] Add widgets download API Change-Id: I532de640934e1e93d63dfc347efb4113cb4a3d66 Reviewed-by: Jocelyn Turcotte --- .../api/qwebenginedownloaditem.cpp | 302 +++++++++++++++++++++ src/webenginewidgets/api/qwebenginedownloaditem.h | 94 +++++++ .../api/qwebenginedownloaditem_p.h | 72 +++++ src/webenginewidgets/api/qwebengineprofile.cpp | 88 ++++++ src/webenginewidgets/api/qwebengineprofile.h | 4 + src/webenginewidgets/api/qwebengineprofile_p.h | 19 +- src/webenginewidgets/webenginewidgets.pro | 3 + 7 files changed, 580 insertions(+), 2 deletions(-) create mode 100644 src/webenginewidgets/api/qwebenginedownloaditem.cpp create mode 100644 src/webenginewidgets/api/qwebenginedownloaditem.h create mode 100644 src/webenginewidgets/api/qwebenginedownloaditem_p.h diff --git a/src/webenginewidgets/api/qwebenginedownloaditem.cpp b/src/webenginewidgets/api/qwebenginedownloaditem.cpp new file mode 100644 index 000000000..f97b25431 --- /dev/null +++ b/src/webenginewidgets/api/qwebenginedownloaditem.cpp @@ -0,0 +1,302 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwebenginedownloaditem.h" + +#include "qwebenginedownloaditem_p.h" +#include "qwebengineprofile_p.h" + +QT_BEGIN_NAMESPACE + +static inline QWebEngineDownloadItem::DownloadState toDownloadState(int state) +{ + switch (state) { + case BrowserContextAdapterClient::DownloadInProgress: + return QWebEngineDownloadItem::DownloadInProgress; + case BrowserContextAdapterClient::DownloadCompleted: + return QWebEngineDownloadItem::DownloadCompleted; + case BrowserContextAdapterClient::DownloadCancelled: + return QWebEngineDownloadItem::DownloadCancelled; + case BrowserContextAdapterClient::DownloadInterrupted: + return QWebEngineDownloadItem::DownloadInterrupted; + default: + Q_UNREACHABLE(); + return QWebEngineDownloadItem::DownloadCancelled; + } +} + +/*! + \class QWebEngineDownloadItem + \brief The QWebEngineDownloadItem class provides information about a download. + + \since 5.5 + + \inmodule QtWebEngineWidgets + + QWebEngineDownloadItem stores the state of a download to be used to manage requested downloads. +*/ + +QWebEngineDownloadItemPrivate::QWebEngineDownloadItemPrivate(QWebEngineProfilePrivate *p, const QUrl &url) + : profile(p) + , downloadFinished(false) + , downloadId(-1) + , downloadState(QWebEngineDownloadItem::DownloadCancelled) + , downloadUrl(url) + , totalBytes(-1) + , receivedBytes(0) +{ +} + +QWebEngineDownloadItemPrivate::~QWebEngineDownloadItemPrivate() +{ + profile->downloadDestroyed(downloadId); +} + +void QWebEngineDownloadItemPrivate::update(const BrowserContextAdapterClient::DownloadItemInfo &info) +{ + Q_Q(QWebEngineDownloadItem); + + Q_ASSERT(downloadState != QWebEngineDownloadItem::DownloadRequested); + + if (info.state != downloadState) { + downloadState = toDownloadState(info.state); + Q_EMIT q->stateChanged(downloadState); + } + + if (info.receivedBytes != receivedBytes || info.totalBytes != totalBytes) { + receivedBytes = info.receivedBytes; + totalBytes = info.totalBytes; + Q_EMIT q->downloadProgress(receivedBytes, totalBytes); + } + + downloadFinished = downloadState != QWebEngineDownloadItem::DownloadInProgress; + + if (downloadFinished) + Q_EMIT q->finished(); +} + +/*! + Accepts the current download request, which will start the download. + + \sa finished(), stateChanged() +*/ + +void QWebEngineDownloadItem::accept() +{ + Q_D(QWebEngineDownloadItem); + + if (d->downloadState != QWebEngineDownloadItem::DownloadRequested) + return; + + d->downloadState = QWebEngineDownloadItem::DownloadInProgress; + Q_EMIT stateChanged(d->downloadState); +} + +/*! + Cancels the current download. + + \sa finished(), stateChanged() +*/ + +void QWebEngineDownloadItem::cancel() +{ + Q_D(QWebEngineDownloadItem); + + QWebEngineDownloadItem::DownloadState state = d->downloadState; + + if (state == QWebEngineDownloadItem::DownloadCompleted + || state == QWebEngineDownloadItem::DownloadCancelled) + return; + + d->downloadState = QWebEngineDownloadItem::DownloadCancelled; + Q_EMIT stateChanged(d->downloadState); + + // We directly cancel the download request if the user cancels + // before it even started, so no need to notify the profile here. + if (state == QWebEngineDownloadItem::DownloadInProgress) + d->profile->cancelDownload(d->downloadId); +} + +/*! + Returns the download item's id. +*/ + +quint32 QWebEngineDownloadItem::id() +{ + Q_D(QWebEngineDownloadItem); + return d->downloadId; +} + +/*! + \fn QWebEngineDownloadItem::finished() + + This signal is emitted whenever the download finishes. + + \sa state(), isFinished() +*/ + +/*! + \fn QWebEngineDownloadItem::stateChanged(DownloadState state) + + This signal is emitted whenever the download's \a state changes. + + \sa state(), QWebEngineDownloadItem::DownloadState +*/ + +/*! + \fn QWebEngineDownloadItem::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) + + This signal is emitted whenever the download's \a bytesReceived or + \a bytesTotal changes. + + \sa totalBytes(), receivedBytes() +*/ + +/*! + \enum QWebEngineDownloadItem::DownloadState + + This enum describes the state in which the download is in. + + \value DownloadRequested The download has been requested, but has not been accepted yet. + \value DownloadInProgress The download is in progress. + \value DownloadCompleted The download completed successfully. + \value DownloadCancelled The download has been cancelled. + \value DownloadInterrupted The download has been interrupted (by the server or because of lost connectivity). +*/ + +/*! + Returns the download item's current state. + + \sa QWebEngineDownloadItem::DownloadState +*/ + +QWebEngineDownloadItem::DownloadState QWebEngineDownloadItem::state() +{ + Q_D(QWebEngineDownloadItem); + return d->downloadState; +} + +/*! + Returns the download's total size in bytes. + + -1 means the size is unknown. +*/ + +qint64 QWebEngineDownloadItem::totalBytes() +{ + Q_D(QWebEngineDownloadItem); + return d->totalBytes; +} + +/*! + Returns the download's bytes that have been received so far. + + -1 means the size is unknown. +*/ + +qint64 QWebEngineDownloadItem::receivedBytes() +{ + Q_D(QWebEngineDownloadItem); + return d->receivedBytes; +} + +/*! + Returns the download's origin url. +*/ + +QUrl QWebEngineDownloadItem::url() +{ + Q_D(QWebEngineDownloadItem); + return d->downloadUrl; +} + +/*! + Returns the download's full target path where it is being downloaded to. + + The path includes the file name. The default suggested path is the standard download location + and file name is deduced not to overwrite already existing files. +*/ + +QString QWebEngineDownloadItem::path() +{ + Q_D(QWebEngineDownloadItem); + return d->downloadPath; +} + +/*! + Sets the download's full target path, where the file should be downloaded to. + + The \a path should also include the file name. The download path can only be set in response + to the QWebEngineProfile::downloadRequested() signal before the download is accepted. + Past that point this function has no effect on the download item's state. +*/ +void QWebEngineDownloadItem::setPath(QString path) +{ + Q_D(QWebEngineDownloadItem); + if (d->downloadState != QWebEngineDownloadItem::DownloadRequested) { + qWarning("Setting the download path is not allowed after the download has been accepted."); + return; + } + + d->downloadPath = path; +} + +/*! + Returns whether this download is finished (not in progress). + + \sa finished(), state(), +*/ + +bool QWebEngineDownloadItem::isFinished() +{ + Q_D(QWebEngineDownloadItem); + return d->downloadFinished; +} + +QWebEngineDownloadItem::QWebEngineDownloadItem(QWebEngineDownloadItemPrivate *p, QObject *parent) + : QObject(parent) + , d_ptr(p) +{ + p->q_ptr = this; +} + +/*! \internal +*/ +QWebEngineDownloadItem::~QWebEngineDownloadItem() +{ +} + +QT_END_NAMESPACE diff --git a/src/webenginewidgets/api/qwebenginedownloaditem.h b/src/webenginewidgets/api/qwebenginedownloaditem.h new file mode 100644 index 000000000..1051d686c --- /dev/null +++ b/src/webenginewidgets/api/qwebenginedownloaditem.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWEBENGINEDOWNLOADITEM_H +#define QWEBENGINEDOWNLOADITEM_H + +#include "qtwebenginewidgetsglobal.h" + +#include + +QT_BEGIN_NAMESPACE + +class QWebEngineDownloadItemPrivate; +class QWebEngineProfilePrivate; + +class QWEBENGINEWIDGETS_EXPORT QWebEngineDownloadItem : public QObject +{ + Q_OBJECT +public: + ~QWebEngineDownloadItem(); + + enum DownloadState { + DownloadRequested, + DownloadInProgress, + DownloadCompleted, + DownloadCancelled, + DownloadInterrupted + }; + Q_ENUMS(DownloadState) + + quint32 id(); + DownloadState state(); + qint64 totalBytes(); + qint64 receivedBytes(); + QUrl url(); + QString path(); + void setPath(QString path); + bool isFinished(); + +public Q_SLOTS: + void accept(); + void cancel(); + +Q_SIGNALS: + void finished(); + void stateChanged(DownloadState state); + void downloadProgress(qint64 bytesReceived, qint64 bytesTotal); + +private: + Q_DISABLE_COPY(QWebEngineDownloadItem) + Q_DECLARE_PRIVATE(QWebEngineDownloadItem) + + friend class QWebEngineProfilePrivate; + + QWebEngineDownloadItem(QWebEngineDownloadItemPrivate*, QObject *parent = 0); + QScopedPointer d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINEDOWNLOADITEM_H diff --git a/src/webenginewidgets/api/qwebenginedownloaditem_p.h b/src/webenginewidgets/api/qwebenginedownloaditem_p.h new file mode 100644 index 000000000..a7e5b36e6 --- /dev/null +++ b/src/webenginewidgets/api/qwebenginedownloaditem_p.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWEBENGINEDOWNLOADITEM_P_H +#define QWEBENGINEDOWNLOADITEM_P_H + +#include "qtwebenginewidgetsglobal.h" + +#include "qwebenginedownloaditem_p.h" +#include "qwebengineprofile_p.h" +#include + +QT_BEGIN_NAMESPACE + +class QWebEngineDownloadItemPrivate { + QWebEngineDownloadItem *q_ptr; + QWebEngineProfilePrivate* profile; + friend class QWebEngineProfilePrivate; +public: + Q_DECLARE_PUBLIC(QWebEngineDownloadItem) + QWebEngineDownloadItemPrivate(QWebEngineProfilePrivate *p, const QUrl &url); + ~QWebEngineDownloadItemPrivate(); + + bool downloadFinished; + quint32 downloadId; + QWebEngineDownloadItem::DownloadState downloadState; + QString downloadPath; + const QUrl downloadUrl; + + qint64 totalBytes; + qint64 receivedBytes; + + void update(const BrowserContextAdapterClient::DownloadItemInfo &info); +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINEDOWNLOADITEM_P_H + diff --git a/src/webenginewidgets/api/qwebengineprofile.cpp b/src/webenginewidgets/api/qwebengineprofile.cpp index 9929ee657..eceee0fd3 100644 --- a/src/webenginewidgets/api/qwebengineprofile.cpp +++ b/src/webenginewidgets/api/qwebengineprofile.cpp @@ -36,6 +36,8 @@ #include "qwebengineprofile.h" +#include "qwebenginedownloaditem.h" +#include "qwebenginedownloaditem_p.h" #include "qwebenginepage.h" #include "qwebengineprofile_p.h" @@ -77,15 +79,98 @@ QT_BEGIN_NAMESPACE \value ForcePersistentCookies Both session and persistent cookies are save and restored from disk. */ +/*! + \fn QWebEngineProfile::downloadRequested(QWebEngineDownloadItem *download) + + \since 5.5 + + This signal is emitted whenever a download has been triggered. + The \a download argument holds the state of the download. + The \a download either has to be explicitly accepted with + QWebEngineDownloadItem::accept(), else the download will be + cancelled by default. + The download item is parented by the profile, but if not accepted + will be deleted immediately after the signal emission. + + \sa QWebEngineDownloadItem +*/ + QWebEngineProfilePrivate::QWebEngineProfilePrivate(BrowserContextAdapter* browserContext, bool ownsContext) : m_browserContext(browserContext) { if (ownsContext) m_browserContextRef = browserContext; + + m_browserContext->setClient(this); } QWebEngineProfilePrivate::~QWebEngineProfilePrivate() { + m_browserContext->setClient(0); + + Q_FOREACH (QWebEngineDownloadItem* download, m_ongoingDownloads) { + if (download) + download->cancel(); + } + + m_ongoingDownloads.clear(); +} + +void QWebEngineProfilePrivate::cancelDownload(quint32 downloadId) +{ + m_browserContext->cancelDownload(downloadId); +} + +void QWebEngineProfilePrivate::downloadDestroyed(quint32 downloadId) +{ + m_ongoingDownloads.remove(downloadId); +} + +void QWebEngineProfilePrivate::downloadRequested(DownloadItemInfo &info) +{ + Q_Q(QWebEngineProfile); + + Q_ASSERT(!m_ongoingDownloads.contains(info.id)); + QWebEngineDownloadItemPrivate *itemPrivate = new QWebEngineDownloadItemPrivate(this, info.url); + itemPrivate->downloadId = info.id; + itemPrivate->downloadState = QWebEngineDownloadItem::DownloadRequested; + itemPrivate->downloadPath = info.path; + + QWebEngineDownloadItem *download = new QWebEngineDownloadItem(itemPrivate, q); + + m_ongoingDownloads.insert(info.id, download); + + Q_EMIT q->downloadRequested(download); + + QWebEngineDownloadItem::DownloadState state = download->state(); + + info.path = download->path(); + info.cancelled = state == QWebEngineDownloadItem::DownloadCancelled; + + if (state == QWebEngineDownloadItem::DownloadRequested) { + // Delete unaccepted downloads. + info.cancelled = true; + m_ongoingDownloads.remove(info.id); + delete download; + } +} + +void QWebEngineProfilePrivate::downloadUpdated(const DownloadItemInfo &info) +{ + if (!m_ongoingDownloads.contains(info.id)) + return; + + QWebEngineDownloadItem* download = m_ongoingDownloads.value(info.id).data(); + + if (!download) { + downloadDestroyed(info.id); + return; + } + + download->d_func()->update(info); + + if (download->isFinished()) + m_ongoingDownloads.remove(info.id); } /*! @@ -101,6 +186,7 @@ QWebEngineProfile::QWebEngineProfile(QObject *parent) : QObject(parent) , d_ptr(new QWebEngineProfilePrivate(new BrowserContextAdapter(true), true)) { + d_ptr->q_ptr = this; } /*! @@ -117,6 +203,7 @@ QWebEngineProfile::QWebEngineProfile(const QString &storageName, QObject *parent : QObject(parent) , d_ptr(new QWebEngineProfilePrivate(new BrowserContextAdapter(storageName), true)) { + d_ptr->q_ptr = this; } /*! \internal @@ -124,6 +211,7 @@ QWebEngineProfile::QWebEngineProfile(const QString &storageName, QObject *parent QWebEngineProfile::QWebEngineProfile(QWebEngineProfilePrivate *privatePtr) : d_ptr(privatePtr) { + d_ptr->q_ptr = this; } /*! \internal diff --git a/src/webenginewidgets/api/qwebengineprofile.h b/src/webenginewidgets/api/qwebengineprofile.h index 0536d711f..f06c4ef88 100644 --- a/src/webenginewidgets/api/qwebengineprofile.h +++ b/src/webenginewidgets/api/qwebengineprofile.h @@ -47,6 +47,7 @@ QT_BEGIN_NAMESPACE class QObject; class QUrl; +class QWebEngineDownloadItem; class QWebEnginePage; class QWebEnginePagePrivate; class QWebEngineProfilePrivate; @@ -96,6 +97,9 @@ public: static QWebEngineProfile *defaultProfile(); +Q_SIGNALS: + void downloadRequested(QWebEngineDownloadItem *download); + private: Q_DECLARE_PRIVATE(QWebEngineProfile); QWebEngineProfile(QWebEngineProfilePrivate *); diff --git a/src/webenginewidgets/api/qwebengineprofile_p.h b/src/webenginewidgets/api/qwebengineprofile_p.h index 3a08b6b1e..d527f8f13 100644 --- a/src/webenginewidgets/api/qwebengineprofile_p.h +++ b/src/webenginewidgets/api/qwebengineprofile_p.h @@ -37,22 +37,37 @@ #ifndef QWEBENGINEPROFILE_P_H #define QWEBENGINEPROFILE_P_H +#include "browser_context_adapter_client.h" +#include "qwebengineprofile.h" +#include +#include + class BrowserContextAdapter; QT_BEGIN_NAMESPACE class QWebEngineSettings; - -class QWebEngineProfilePrivate { +class QWebEngineProfilePrivate + : public BrowserContextAdapterClient +{ public: + Q_DECLARE_PUBLIC(QWebEngineProfile) QWebEngineProfilePrivate(BrowserContextAdapter* browserContext, bool ownsContext); ~QWebEngineProfilePrivate(); BrowserContextAdapter *browserContext() const { return m_browserContext; } + void cancelDownload(quint32 downloadId); + void downloadDestroyed(quint32 downloadId); + + void downloadRequested(DownloadItemInfo &info) Q_DECL_OVERRIDE; + void downloadUpdated(const DownloadItemInfo &info) Q_DECL_OVERRIDE; + private: + QWebEngineProfile *q_ptr; BrowserContextAdapter *m_browserContext; QExplicitlySharedDataPointer m_browserContextRef; + QMap > m_ongoingDownloads; }; QT_END_NAMESPACE diff --git a/src/webenginewidgets/webenginewidgets.pro b/src/webenginewidgets/webenginewidgets.pro index 638535bbc..8d1930667 100644 --- a/src/webenginewidgets/webenginewidgets.pro +++ b/src/webenginewidgets/webenginewidgets.pro @@ -13,6 +13,7 @@ INCLUDEPATH += $$PWD api ../core ../webengine/api SOURCES = \ api/qtwebenginewidgetsglobal.cpp \ api/qwebenginecertificateerror.cpp \ + api/qwebenginedownloaditem.cpp \ api/qwebenginehistory.cpp \ api/qwebenginepage.cpp \ api/qwebengineprofile.cpp \ @@ -22,6 +23,8 @@ SOURCES = \ HEADERS = \ api/qtwebenginewidgetsglobal.h \ + api/qwebenginedownloaditem.h \ + api/qwebenginedownloaditem_p.h \ api/qwebenginecertificateerror.h \ api/qwebenginehistory.h \ api/qwebenginepage.h \ -- cgit v1.2.3