From e6a74159cebdbfec575f40469c216c90ee8651c1 Mon Sep 17 00:00:00 2001 From: Andras Becsi Date: Thu, 11 Dec 2014 19:57:58 +0100 Subject: Add QML download API This patch exposes downloadStarted and downloadFinished signals on the WebEngineProfile to notify about downloads. The WebEngineDownloadItem exposes a subset of Chromium's content::DownloadItem functionality. For now we expose minimal requirements to be able to control downloads in QML but this can be extended in the future. This patch also adds a DownloadView to quicktestbrowser to demonstrate the usage of the new API. [ChangeLog][QtWebEngineQML] Add QtQuick download API Change-Id: I8d8f0daf02c4e0151000427fc2a4b37d28b9db52 Reviewed-by: Jocelyn Turcotte --- src/core/browser_context_adapter.cpp | 22 +++ src/core/browser_context_adapter.h | 10 + src/core/browser_context_adapter_client.h | 63 ++++++ src/core/browser_context_qt.cpp | 4 +- src/core/browser_context_qt.h | 4 +- src/core/core_gyp_generator.pro | 1 + src/core/download_manager_delegate_qt.cpp | 216 +++++++-------------- src/core/download_manager_delegate_qt.h | 46 ++--- src/webengine/api/qquickwebenginedownloaditem.cpp | 134 +++++++++++++ src/webengine/api/qquickwebenginedownloaditem_p.h | 91 +++++++++ .../api/qquickwebenginedownloaditem_p_p.h | 67 +++++++ src/webengine/api/qquickwebengineprofile.cpp | 83 ++++++++ src/webengine/api/qquickwebengineprofile_p.h | 4 + src/webengine/api/qquickwebengineprofile_p_p.h | 20 +- src/webengine/api/qquickwebenginesingleton_p.h | 1 - src/webengine/plugin/experimental/plugin.cpp | 5 +- src/webengine/webengine.pro | 3 + tests/quicktestbrowser/DownloadView.qml | 165 ++++++++++++++++ tests/quicktestbrowser/quicktestbrowser.pro | 1 + tests/quicktestbrowser/quickwindow.qml | 27 ++- tests/quicktestbrowser/resources.qrc | 1 + 21 files changed, 783 insertions(+), 185 deletions(-) create mode 100644 src/core/browser_context_adapter_client.h create mode 100644 src/webengine/api/qquickwebenginedownloaditem.cpp create mode 100644 src/webengine/api/qquickwebenginedownloaditem_p.h create mode 100644 src/webengine/api/qquickwebenginedownloaditem_p_p.h create mode 100644 tests/quicktestbrowser/DownloadView.qml diff --git a/src/core/browser_context_adapter.cpp b/src/core/browser_context_adapter.cpp index 637003f96..95ddc4d87 100644 --- a/src/core/browser_context_adapter.cpp +++ b/src/core/browser_context_adapter.cpp @@ -36,8 +36,10 @@ #include "browser_context_adapter.h" +#include "content/public/browser/browser_thread.h" #include "browser_context_qt.h" #include "content_client_qt.h" +#include "download_manager_delegate_qt.h" #include "web_engine_context.h" #include "web_engine_visited_links_manager.h" #include "url_request_context_getter_qt.h" @@ -67,6 +69,7 @@ BrowserContextAdapter::BrowserContextAdapter(bool offTheRecord) , m_httpCacheType(DiskHttpCache) , m_persistentCookiesPolicy(AllowPersistentCookies) , m_visitedLinksPolicy(TrackVisitedLinksOnDisk) + , m_client(0) , m_httpCacheMaxSize(0) { } @@ -84,6 +87,8 @@ BrowserContextAdapter::BrowserContextAdapter(const QString &storageName) BrowserContextAdapter::~BrowserContextAdapter() { + if (m_downloadManagerDelegate) + content::BrowserThread::DeleteSoon(content::BrowserThread::UI, FROM_HERE, m_downloadManagerDelegate.take()); } void BrowserContextAdapter::setStorageName(const QString &storageName) @@ -118,6 +123,23 @@ WebEngineVisitedLinksManager *BrowserContextAdapter::visitedLinksManager() return m_visitedLinksManager.data(); } +DownloadManagerDelegateQt *BrowserContextAdapter::downloadManagerDelegate() +{ + if (!m_downloadManagerDelegate) + m_downloadManagerDelegate.reset(new DownloadManagerDelegateQt(this)); + return m_downloadManagerDelegate.data(); +} + +void BrowserContextAdapter::setClient(BrowserContextAdapterClient *adapterClient) +{ + m_client = adapterClient; +} + +void BrowserContextAdapter::cancelDownload(quint32 downloadId) +{ + downloadManagerDelegate()->cancelDownload(downloadId); +} + BrowserContextAdapter* BrowserContextAdapter::defaultContext() { return WebEngineContext::current()->defaultBrowserContext(); diff --git a/src/core/browser_context_adapter.h b/src/core/browser_context_adapter.h index 8f03f2094..1c12c465d 100644 --- a/src/core/browser_context_adapter.h +++ b/src/core/browser_context_adapter.h @@ -43,7 +43,9 @@ #include #include +class BrowserContextAdapterClient; class BrowserContextQt; +class DownloadManagerDelegateQt; class WebEngineVisitedLinksManager; class QWEBENGINE_EXPORT BrowserContextAdapter : public QSharedData @@ -57,6 +59,12 @@ public: static BrowserContextAdapter* offTheRecordContext(); WebEngineVisitedLinksManager *visitedLinksManager(); + DownloadManagerDelegateQt *downloadManagerDelegate(); + + BrowserContextAdapterClient* client() { return m_client; } + + void setClient(BrowserContextAdapterClient *adapterClient); + void cancelDownload(quint32 downloadId); BrowserContextQt *browserContext(); @@ -116,12 +124,14 @@ private: bool m_offTheRecord; QScopedPointer m_browserContext; QScopedPointer m_visitedLinksManager; + QScopedPointer m_downloadManagerDelegate; QString m_dataPath; QString m_cachePath; QString m_httpUserAgent; HttpCacheType m_httpCacheType; PersistentCookiesPolicy m_persistentCookiesPolicy; VisitedLinksPolicy m_visitedLinksPolicy; + BrowserContextAdapterClient *m_client; int m_httpCacheMaxSize; Q_DISABLE_COPY(BrowserContextAdapter) diff --git a/src/core/browser_context_adapter_client.h b/src/core/browser_context_adapter_client.h new file mode 100644 index 000000000..2b6b4f434 --- /dev/null +++ b/src/core/browser_context_adapter_client.h @@ -0,0 +1,63 @@ + /**************************************************************************** +** +** Copyright (C) 2014 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 BROWSER_CONTEXT_ADAPTER_CLIENT_H +#define BROWSER_CONTEXT_ADAPTER_CLIENT_H + +#include "qtwebenginecoreglobal.h" +#include + +class QWEBENGINE_EXPORT BrowserContextAdapterClient +{ +public: + // Keep in sync with content::DownloadItem::DownloadState + enum DownloadState { + // Download is actively progressing. + DownloadInProgress = 0, + // Download is completely finished. + DownloadCompleted, + // Download has been cancelled. + DownloadCancelled, + // This state indicates that the download has been interrupted. + DownloadInterrupted + }; + virtual ~BrowserContextAdapterClient() { } + + virtual void downloadRequested(quint32 downloadId, QString &downloadPath, bool &cancelled) = 0; + virtual void downloadUpdated(quint32 downloadId, int downloadState, int percentComplete) = 0; +}; + +#endif // BROWSER_CONTEXT_ADAPTER_CLIENT_H diff --git a/src/core/browser_context_qt.cpp b/src/core/browser_context_qt.cpp index 9337b6b6b..4661f59fc 100644 --- a/src/core/browser_context_qt.cpp +++ b/src/core/browser_context_qt.cpp @@ -37,12 +37,12 @@ #include "browser_context_qt.h" #include "browser_context_adapter.h" +#include "download_manager_delegate_qt.h" #include "type_conversion.h" #include "qtwebenginecoreglobal.h" #include "resource_context_qt.h" #include "url_request_context_getter_qt.h" -#include "base/files/scoped_temp_dir.h" #include "base/time/time.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/storage_partition.h" @@ -108,7 +108,7 @@ content::ResourceContext *BrowserContextQt::GetResourceContext() content::DownloadManagerDelegate *BrowserContextQt::GetDownloadManagerDelegate() { - return downloadManagerDelegate.get(); + return m_adapter->downloadManagerDelegate(); } content::BrowserPluginGuestManager *BrowserContextQt::GetGuestManager() diff --git a/src/core/browser_context_qt.h b/src/core/browser_context_qt.h index c11a234ab..8ab6024ae 100644 --- a/src/core/browser_context_qt.h +++ b/src/core/browser_context_qt.h @@ -41,7 +41,8 @@ #include "content/public/browser/content_browser_client.h" #include "content/public/browser/resource_context.h" #include "net/url_request/url_request_context.h" -#include "download_manager_delegate_qt.h" + +#include // Needed for Q_DECL_OVERRIDE class BrowserContextAdapter; class URLRequestContextGetterQt; @@ -72,7 +73,6 @@ public: private: scoped_ptr resourceContext; scoped_refptr url_request_getter_; - scoped_ptr downloadManagerDelegate; BrowserContextAdapter *m_adapter; friend class BrowserContextAdapter; diff --git a/src/core/core_gyp_generator.pro b/src/core/core_gyp_generator.pro index 4514475ec..90a665e84 100644 --- a/src/core/core_gyp_generator.pro +++ b/src/core/core_gyp_generator.pro @@ -86,6 +86,7 @@ HEADERS = \ browser_accessibility_manager_qt.h \ browser_accessibility_qt.h \ browser_context_adapter.h \ + browser_context_adapter_client.h \ browser_context_qt.h \ certificate_error_controller_p.h \ certificate_error_controller.h \ diff --git a/src/core/download_manager_delegate_qt.cpp b/src/core/download_manager_delegate_qt.cpp index 3df03ffa3..3f6ec7bcc 100644 --- a/src/core/download_manager_delegate_qt.cpp +++ b/src/core/download_manager_delegate_qt.cpp @@ -36,6 +36,7 @@ #include "download_manager_delegate_qt.h" +#include "content/public/browser/download_manager.h" #include "content/public/browser/download_item.h" #include "content/public/browser/save_page_type.h" #include "content/public/browser/web_contents.h" @@ -46,115 +47,21 @@ #include #include +#include "browser_context_adapter.h" +#include "browser_context_adapter_client.h" +#include "browser_context_qt.h" #include "type_conversion.h" #include "qtwebenginecoreglobal.h" -// Helper class to track currently ongoing downloads to prevent file name -// clashes / overwriting of files. -class DownloadTargetHelper : public content::DownloadItem::Observer { -public: - DownloadTargetHelper() - : m_defaultDownloadDirectory(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation)) - { - - } - virtual ~DownloadTargetHelper() {} - - bool determineDownloadTarget(content::DownloadItem *item, const content::DownloadTargetCallback &callback); - - virtual void OnDownloadUpdated(content::DownloadItem *download) Q_DECL_OVERRIDE; - virtual void OnDownloadDestroyed(content::DownloadItem *download) Q_DECL_OVERRIDE; -private: - bool isPathAvailable(const QString& path); - - QDir m_defaultDownloadDirectory; - QMap m_ongoingDownloads; -}; - -bool DownloadTargetHelper::isPathAvailable(const QString& path) -{ - return !m_ongoingDownloads.values().contains(path) && !QFile::exists(path); -} - -bool DownloadTargetHelper::determineDownloadTarget(content::DownloadItem *item, const content::DownloadTargetCallback &callback) -{ - std::string suggestedFilename = item->GetSuggestedFilename(); - - if (suggestedFilename.empty()) - suggestedFilename = item->GetTargetFilePath().AsUTF8Unsafe(); - - if (suggestedFilename.empty()) - suggestedFilename = item->GetURL().ExtractFileName(); - - if (suggestedFilename.empty()) - suggestedFilename = "qwe_download"; - - if (!m_defaultDownloadDirectory.exists() && !m_defaultDownloadDirectory.mkpath(m_defaultDownloadDirectory.absolutePath())) - return false; - - QString suggestedFilePath = m_defaultDownloadDirectory.absoluteFilePath(QString::fromStdString(suggestedFilename)); - if (!isPathAvailable(suggestedFilePath)) { - int i = 1; - for (; i < 99; i++) { - QFileInfo tmpFile(suggestedFilePath); - QString tmpFilePath = QString("%1%2%3(%4).%5").arg(tmpFile.absolutePath()).arg(QDir::separator()).arg(tmpFile.baseName()).arg(i).arg(tmpFile.completeSuffix()); - if (isPathAvailable(tmpFilePath)) { - suggestedFilePath = tmpFilePath; - break; - } - } - if (i >= 99) { - callback.Run(base::FilePath(), content::DownloadItem::TARGET_DISPOSITION_PROMPT, content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT, base::FilePath()); - return false; - } - } - - m_ongoingDownloads.insert(item, suggestedFilePath); - item->AddObserver(this); - - base::FilePath filePathForCallback(toFilePathString(suggestedFilePath)); - callback.Run(filePathForCallback, content::DownloadItem::TARGET_DISPOSITION_OVERWRITE, - content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT, filePathForCallback.AddExtension(toFilePathString("download"))); - return true; -} - -void DownloadTargetHelper::OnDownloadUpdated(content::DownloadItem *download) +DownloadManagerDelegateQt::DownloadManagerDelegateQt(BrowserContextAdapter *contextAdapter) + : m_currentId(0) + , m_contextAdapter(contextAdapter) { - switch (download->GetState()) { - case content::DownloadItem::COMPLETE: - case content::DownloadItem::CANCELLED: - case content::DownloadItem::INTERRUPTED: - download->RemoveObserver(this); - m_ongoingDownloads.remove(download); - break; - case content::DownloadItem::IN_PROGRESS: - default: - break; - } -} - -void DownloadTargetHelper::OnDownloadDestroyed(content::DownloadItem *download) -{ - download->RemoveObserver(this); - m_ongoingDownloads.remove(download); -} - -DownloadManagerDelegateQt::DownloadManagerDelegateQt() - : m_targetHelper(new DownloadTargetHelper()) - , m_currentId(0) -{ - + Q_ASSERT(m_contextAdapter); } DownloadManagerDelegateQt::~DownloadManagerDelegateQt() { - delete m_targetHelper; -} - - -void DownloadManagerDelegateQt::Shutdown() -{ - QT_NOT_YET_IMPLEMENTED } void DownloadManagerDelegateQt::GetNextId(const content::DownloadIdCallback& callback) @@ -162,24 +69,17 @@ void DownloadManagerDelegateQt::GetNextId(const content::DownloadIdCallback& cal callback.Run(++m_currentId); } -bool DownloadManagerDelegateQt::ShouldOpenFileBasedOnExtension(const base::FilePath& path) -{ - QT_NOT_YET_IMPLEMENTED - return false; -} - -bool DownloadManagerDelegateQt::ShouldCompleteDownload(content::DownloadItem* item, - const base::Closure& complete_callback) +void DownloadManagerDelegateQt::cancelDownload(const content::DownloadTargetCallback& callback) { - QT_NOT_YET_IMPLEMENTED - return true; + callback.Run(base::FilePath(), content::DownloadItem::TARGET_DISPOSITION_PROMPT, content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT, base::FilePath()); } -bool DownloadManagerDelegateQt::ShouldOpenDownload(content::DownloadItem* item, - const content::DownloadOpenDelayedCallback& callback) +void DownloadManagerDelegateQt::cancelDownload(quint32 downloadId) { - QT_NOT_YET_IMPLEMENTED - return false; + content::DownloadManager* dlm = content::BrowserContext::GetDownloadManager(m_contextAdapter->browserContext()); + content::DownloadItem *download = dlm->GetDownload(downloadId); + if (download) + download->Cancel(/* user_cancel */ true); } bool DownloadManagerDelegateQt::DetermineDownloadTarget(content::DownloadItem* item, @@ -194,41 +94,55 @@ bool DownloadManagerDelegateQt::DetermineDownloadTarget(content::DownloadItem* i return true; } - // Let the target helper determine the download target path. - return m_targetHelper->determineDownloadTarget(item, callback); -} + std::string suggestedFilename = item->GetSuggestedFilename(); -bool DownloadManagerDelegateQt::GenerateFileHash() -{ - QT_NOT_YET_IMPLEMENTED - return false; -} + if (suggestedFilename.empty()) + suggestedFilename = item->GetTargetFilePath().AsUTF8Unsafe(); -void DownloadManagerDelegateQt::ChooseSavePath( - content::WebContents* web_contents, - const base::FilePath& suggested_path, - const base::FilePath::StringType& default_extension, - bool can_save_as_complete, - const content::SavePackagePathPickedCallback& callback) -{ - QT_NOT_YET_IMPLEMENTED -} + if (suggestedFilename.empty()) + suggestedFilename = item->GetURL().ExtractFileName(); -void DownloadManagerDelegateQt::OpenDownload(content::DownloadItem* download) -{ - QT_NOT_YET_IMPLEMENTED -} + if (suggestedFilename.empty()) + suggestedFilename = "qwe_download"; -void DownloadManagerDelegateQt::ShowDownloadInShell(content::DownloadItem* download) -{ - QT_NOT_YET_IMPLEMENTED -} + QDir defaultDownloadDirectory = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); -void DownloadManagerDelegateQt::CheckForFileExistence( - content::DownloadItem* download, - const content::CheckForFileExistenceCallback& callback) -{ - QT_NOT_YET_IMPLEMENTED + QFileInfo suggestedFile(defaultDownloadDirectory.absoluteFilePath(QString::fromStdString(suggestedFilename))); + QString suggestedFilePath = suggestedFile.absoluteFilePath(); + QString tmpFileBase = QString("%1%2%3").arg(suggestedFile.absolutePath()).arg(QDir::separator()).arg(suggestedFile.baseName()); + + for (int i = 1; QFileInfo::exists(suggestedFilePath); ++i) { + suggestedFilePath = QString("%1(%2).%3").arg(tmpFileBase).arg(i).arg(suggestedFile.completeSuffix()); + if (i >= 99) { + suggestedFilePath = suggestedFile.absoluteFilePath(); + break; + } + } + + item->AddObserver(this); + quint32 downloadId = item->GetId(); + if (m_contextAdapter->client()) { + bool cancelled = false; + m_contextAdapter->client()->downloadRequested(downloadId, suggestedFilePath, cancelled); + suggestedFile.setFile(suggestedFilePath); + + if (!cancelled && !suggestedFile.absoluteDir().mkpath(suggestedFile.absolutePath())) { + qWarning("Creating download path failed, download cancelled: %s", suggestedFile.absolutePath().toUtf8().data()); + cancelled = true; + } + + if (cancelled) { + cancelDownload(callback); + return true; + } + + base::FilePath filePathForCallback(toFilePathString(suggestedFile.absoluteFilePath())); + callback.Run(filePathForCallback, content::DownloadItem::TARGET_DISPOSITION_OVERWRITE, + content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT, filePathForCallback.AddExtension(toFilePathString("download"))); + } else + cancelDownload(callback); + + return true; } void DownloadManagerDelegateQt::GetSaveDir(content::BrowserContext* browser_context, @@ -242,4 +156,16 @@ void DownloadManagerDelegateQt::GetSaveDir(content::BrowserContext* browser_cont *skip_dir_check = true; } +void DownloadManagerDelegateQt::OnDownloadUpdated(content::DownloadItem *download) +{ + const quint32 downloadId = download->GetId(); + + if (m_contextAdapter->client()) + m_contextAdapter->client()->downloadUpdated(downloadId, download->GetState(), download->PercentComplete()); +} +void DownloadManagerDelegateQt::OnDownloadDestroyed(content::DownloadItem *download) +{ + download->RemoveObserver(this); + download->Cancel(/* user_cancel */ false); +} diff --git a/src/core/download_manager_delegate_qt.h b/src/core/download_manager_delegate_qt.h index 4c838363f..007f2e580 100644 --- a/src/core/download_manager_delegate_qt.h +++ b/src/core/download_manager_delegate_qt.h @@ -39,7 +39,7 @@ #include "content/public/browser/download_manager_delegate.h" -#include +#include // Needed for Q_DECL_OVERRIDE namespace base { class FilePath; @@ -51,46 +51,38 @@ class DownloadItem; class WebContents; } -class DownloadTargetHelper; - -class DownloadManagerDelegateQt : public content::DownloadManagerDelegate +class BrowserContextAdapter; +class DownloadManagerDelegateInstance; +class DownloadManagerDelegateQt + : public content::DownloadManagerDelegate + , public content::DownloadItem::Observer { public: - DownloadManagerDelegateQt(); - virtual ~DownloadManagerDelegateQt(); - - void Shutdown() Q_DECL_OVERRIDE; + DownloadManagerDelegateQt(BrowserContextAdapter *contextAdapter); + ~DownloadManagerDelegateQt(); void GetNextId(const content::DownloadIdCallback& callback) Q_DECL_OVERRIDE; - bool ShouldOpenFileBasedOnExtension(const base::FilePath& path) Q_DECL_OVERRIDE; - bool ShouldCompleteDownload(content::DownloadItem* item, - const base::Closure& complete_callback) Q_DECL_OVERRIDE; - - bool ShouldOpenDownload(content::DownloadItem* item, - const content::DownloadOpenDelayedCallback& callback) Q_DECL_OVERRIDE; bool DetermineDownloadTarget(content::DownloadItem* item, const content::DownloadTargetCallback& callback) Q_DECL_OVERRIDE; - bool GenerateFileHash() Q_DECL_OVERRIDE; - void ChooseSavePath(content::WebContents* web_contents, - const base::FilePath& suggested_path, - const base::FilePath::StringType& default_extension, - bool can_save_as_complete, - const content::SavePackagePathPickedCallback& callback) Q_DECL_OVERRIDE; - - void OpenDownload(content::DownloadItem* download) Q_DECL_OVERRIDE; - void ShowDownloadInShell(content::DownloadItem* download) Q_DECL_OVERRIDE; - void CheckForFileExistence(content::DownloadItem* download, - const content::CheckForFileExistenceCallback& callback) Q_DECL_OVERRIDE; - void GetSaveDir(content::BrowserContext* browser_context, base::FilePath* website_save_dir, base::FilePath* download_save_dir, bool* skip_dir_check) Q_DECL_OVERRIDE; + void cancelDownload(quint32 downloadId); + + // Inherited from content::DownloadItem::Observer + void OnDownloadUpdated(content::DownloadItem *download) Q_DECL_OVERRIDE; + void OnDownloadDestroyed(content::DownloadItem *download) Q_DECL_OVERRIDE; + private: - DownloadTargetHelper* m_targetHelper; + void cancelDownload(const content::DownloadTargetCallback& callback); + BrowserContextAdapter *m_contextAdapter; + uint64 m_currentId; + + friend class DownloadManagerDelegateInstance; DISALLOW_COPY_AND_ASSIGN(DownloadManagerDelegateQt); }; diff --git a/src/webengine/api/qquickwebenginedownloaditem.cpp b/src/webengine/api/qquickwebenginedownloaditem.cpp new file mode 100644 index 000000000..729cb0d3f --- /dev/null +++ b/src/webengine/api/qquickwebenginedownloaditem.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2014 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 "qquickwebenginedownloaditem_p.h" +#include "qquickwebenginedownloaditem_p_p.h" + +QT_BEGIN_NAMESPACE + +QQuickWebEngineDownloadItemPrivate::QQuickWebEngineDownloadItemPrivate(QQuickWebEngineProfilePrivate *p) + : profile(p) + , downloadStarted(false) + , downloadId(-1) + , downloadState(QQuickWebEngineDownloadItem::DownloadCancelled) + , downloadProgress(0) +{ +} + +QQuickWebEngineDownloadItemPrivate::~QQuickWebEngineDownloadItemPrivate() +{ + Q_Q(QQuickWebEngineDownloadItem); + q->cancel(); +} + +void QQuickWebEngineDownloadItemPrivate::update(QQuickWebEngineDownloadItem::DownloadState state, int progress) +{ + Q_Q(QQuickWebEngineDownloadItem); + if (state != downloadState) { + downloadState = state; + Q_EMIT q->stateChanged(); + } + if (progress != downloadProgress) { + downloadProgress = progress; + Q_EMIT q->progressChanged(); + } +} + +void QQuickWebEngineDownloadItem::cancel() +{ + Q_D(QQuickWebEngineDownloadItem); + + if (d->downloadState == QQuickWebEngineDownloadItem::DownloadCompleted + || d->downloadState == QQuickWebEngineDownloadItem::DownloadCancelled) + return; + + d->update(QQuickWebEngineDownloadItem::DownloadCancelled, d->downloadProgress); + + // We directly cancel the download if the user cancels before + // it even started, so no need to notify the profile here. + if (d->downloadStarted) + d->profile->cancelDownload(d->downloadId); +} + +quint32 QQuickWebEngineDownloadItem::id() +{ + Q_D(QQuickWebEngineDownloadItem); + return d->downloadId; +} + +QQuickWebEngineDownloadItem::DownloadState QQuickWebEngineDownloadItem::state() +{ + Q_D(QQuickWebEngineDownloadItem); + return d->downloadState; +} + +int QQuickWebEngineDownloadItem::progress() +{ + Q_D(QQuickWebEngineDownloadItem); + return d->downloadProgress; +} + +QString QQuickWebEngineDownloadItem::path() +{ + Q_D(QQuickWebEngineDownloadItem); + return d->downloadPath; +} + +void QQuickWebEngineDownloadItem::setPath(QString path) +{ + Q_D(QQuickWebEngineDownloadItem); + if (d->downloadStarted) { + qWarning("Setting the download path is not allowed after the download has been started."); + return; + } + if (d->downloadPath != path) { + d->downloadPath = path; + Q_EMIT pathChanged(); + } +} + +QQuickWebEngineDownloadItem::QQuickWebEngineDownloadItem(QQuickWebEngineDownloadItemPrivate *p, QObject *parent) + : QObject(parent) + , d_ptr(p) +{ + p->q_ptr = this; +} + +QQuickWebEngineDownloadItem::~QQuickWebEngineDownloadItem() +{ +} + +QT_END_NAMESPACE diff --git a/src/webengine/api/qquickwebenginedownloaditem_p.h b/src/webengine/api/qquickwebenginedownloaditem_p.h new file mode 100644 index 000000000..8ea9f0850 --- /dev/null +++ b/src/webengine/api/qquickwebenginedownloaditem_p.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2014 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 QQUICKWEBENGINEDOWNLOADITEM_P_H +#define QQUICKWEBENGINEDOWNLOADITEM_P_H + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QQuickWebEngineDownloadItemPrivate; +class QQuickWebEngineProfilePrivate; + +class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineDownloadItem: public QObject { + Q_OBJECT +public: + ~QQuickWebEngineDownloadItem(); + enum DownloadState { + DownloadInProgress, + DownloadCompleted, + DownloadCancelled, + DownloadInterrupted + }; + Q_ENUMS(DownloadState) + + Q_PROPERTY(quint32 id READ id() CONSTANT FINAL) + Q_PROPERTY(DownloadState state READ state NOTIFY stateChanged) + Q_PROPERTY(int progress READ progress NOTIFY progressChanged) + Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged) + + Q_INVOKABLE void cancel(); + + quint32 id(); + DownloadState state(); + int progress(); + QString path(); + void setPath(QString path); + +Q_SIGNALS: + void stateChanged(); + void progressChanged(); + void pathChanged(); + +private: + QQuickWebEngineDownloadItem(QQuickWebEngineDownloadItemPrivate*, QObject *parent = 0); + Q_DISABLE_COPY(QQuickWebEngineDownloadItem) + Q_DECLARE_PRIVATE(QQuickWebEngineDownloadItem) + friend class QQuickWebEngineProfilePrivate; + + QScopedPointer d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QQUICKWEBENGINEDOWNLOADITEM_P_H diff --git a/src/webengine/api/qquickwebenginedownloaditem_p_p.h b/src/webengine/api/qquickwebenginedownloaditem_p_p.h new file mode 100644 index 000000000..6b724b4c9 --- /dev/null +++ b/src/webengine/api/qquickwebenginedownloaditem_p_p.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2014 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 QQUICKWEBENGINEDOWNLOADITEM_P_P_H +#define QQUICKWEBENGINEDOWNLOADITEM_P_P_H + +#include "qquickwebenginedownloaditem_p.h" +#include "qquickwebengineprofile_p_p.h" +#include +#include + +QT_BEGIN_NAMESPACE + +class QQuickWebEngineDownloadItemPrivate { + QQuickWebEngineDownloadItem *q_ptr; + QQuickWebEngineProfilePrivate* profile; + friend class QQuickWebEngineProfilePrivate; +public: + Q_DECLARE_PUBLIC(QQuickWebEngineDownloadItem) + QQuickWebEngineDownloadItemPrivate(QQuickWebEngineProfilePrivate *p); + ~QQuickWebEngineDownloadItemPrivate(); + + bool downloadStarted; + quint32 downloadId; + QQuickWebEngineDownloadItem::DownloadState downloadState; + int downloadProgress; + QString downloadPath; + + void update(QQuickWebEngineDownloadItem::DownloadState state, int progress); +}; + +QT_END_NAMESPACE + +#endif // QQUICKWEBENGINEDOWNLOADITEM_P_P_H diff --git a/src/webengine/api/qquickwebengineprofile.cpp b/src/webengine/api/qquickwebengineprofile.cpp index 64d9805d6..9eecae073 100644 --- a/src/webengine/api/qquickwebengineprofile.cpp +++ b/src/webengine/api/qquickwebengineprofile.cpp @@ -36,31 +36,114 @@ #include "qquickwebengineprofile_p.h" +#include "qquickwebenginedownloaditem_p.h" +#include "qquickwebenginedownloaditem_p_p.h" #include "qquickwebengineprofile_p_p.h" +#include #include "browser_context_adapter.h" QT_BEGIN_NAMESPACE +static inline QQuickWebEngineDownloadItem::DownloadState toDownloadState(int state) { + switch (state) { + case BrowserContextAdapterClient::DownloadInProgress: + return QQuickWebEngineDownloadItem::DownloadInProgress; + case BrowserContextAdapterClient::DownloadCompleted: + return QQuickWebEngineDownloadItem::DownloadCompleted; + case BrowserContextAdapterClient::DownloadCancelled: + return QQuickWebEngineDownloadItem::DownloadCancelled; + case BrowserContextAdapterClient::DownloadInterrupted: + return QQuickWebEngineDownloadItem::DownloadInterrupted; + default: + Q_UNREACHABLE(); + return QQuickWebEngineDownloadItem::DownloadCancelled; + } +} + QQuickWebEngineProfilePrivate::QQuickWebEngineProfilePrivate(BrowserContextAdapter* browserContext, bool ownsContext) : m_browserContext(browserContext) { if (ownsContext) m_browserContextRef = browserContext; + + m_browserContext->setClient(this); } QQuickWebEngineProfilePrivate::~QQuickWebEngineProfilePrivate() { + m_browserContext->setClient(0); + + Q_FOREACH (QQuickWebEngineDownloadItem* download, m_ongoingDownloads) { + if (download) + download->cancel(); + } + + m_ongoingDownloads.clear(); +} + +void QQuickWebEngineProfilePrivate::cancelDownload(quint32 downloadId) +{ + m_browserContext->cancelDownload(downloadId); +} + +void QQuickWebEngineProfilePrivate::downloadDestroyed(quint32 downloadId) +{ + m_ongoingDownloads.remove(downloadId); +} + +void QQuickWebEngineProfilePrivate::downloadRequested(quint32 downloadId, QString &downloadPath, bool &cancelled) +{ + Q_Q(QQuickWebEngineProfile); + + Q_ASSERT(!m_ongoingDownloads.contains(downloadId)); + QQuickWebEngineDownloadItemPrivate *itemPrivate = new QQuickWebEngineDownloadItemPrivate(this); + itemPrivate->downloadId = downloadId; + itemPrivate->downloadState = QQuickWebEngineDownloadItem::DownloadInProgress; + itemPrivate->downloadPath = downloadPath; + + QQuickWebEngineDownloadItem *download = new QQuickWebEngineDownloadItem(itemPrivate, q); + + m_ongoingDownloads.insert(downloadId, download); + + QQmlEngine::setObjectOwnership(download, QQmlEngine::JavaScriptOwnership); + Q_EMIT q->downloadStarted(download); + download->d_func()->downloadStarted = true; + + downloadPath = download->path(); + cancelled = download->state() == QQuickWebEngineDownloadItem::DownloadCancelled; +} + +void QQuickWebEngineProfilePrivate::downloadUpdated(quint32 downloadId, int downloadState, int percentComplete) +{ + Q_Q(QQuickWebEngineProfile); + + Q_ASSERT(m_ongoingDownloads.contains(downloadId)); + QQuickWebEngineDownloadItem* download = m_ongoingDownloads.value(downloadId).data(); + + if (!download) { + cancelDownload(downloadId); + return; + } + + download->d_func()->update(toDownloadState(downloadState), percentComplete); + + if (downloadState != BrowserContextAdapterClient::DownloadInProgress) { + Q_EMIT q->downloadFinished(download); + m_ongoingDownloads.remove(downloadId); + } } QQuickWebEngineProfile::QQuickWebEngineProfile() : d_ptr(new QQuickWebEngineProfilePrivate(new BrowserContextAdapter(false), true)) { + d_ptr->q_ptr = this; } QQuickWebEngineProfile::QQuickWebEngineProfile(QQuickWebEngineProfilePrivate *privatePtr) : d_ptr(privatePtr) { + d_ptr->q_ptr = this; } QQuickWebEngineProfile::~QQuickWebEngineProfile() diff --git a/src/webengine/api/qquickwebengineprofile_p.h b/src/webengine/api/qquickwebengineprofile_p.h index 936573e8f..b8d7c8652 100644 --- a/src/webengine/api/qquickwebengineprofile_p.h +++ b/src/webengine/api/qquickwebengineprofile_p.h @@ -45,6 +45,7 @@ QT_BEGIN_NAMESPACE +class QQuickWebEngineDownloadItem; class QQuickWebEngineProfilePrivate; class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineProfile : public QObject { @@ -110,6 +111,9 @@ signals: void persistentCookiesPolicyChanged(); void httpCacheMaxSizeChanged(); + void downloadStarted(QQuickWebEngineDownloadItem *download); + void downloadFinished(QQuickWebEngineDownloadItem *download); + private: Q_DECLARE_PRIVATE(QQuickWebEngineProfile); QQuickWebEngineProfile(QQuickWebEngineProfilePrivate *); diff --git a/src/webengine/api/qquickwebengineprofile_p_p.h b/src/webengine/api/qquickwebengineprofile_p_p.h index d71dcfda9..18ccfc467 100644 --- a/src/webengine/api/qquickwebengineprofile_p_p.h +++ b/src/webengine/api/qquickwebengineprofile_p_p.h @@ -39,21 +39,37 @@ class BrowserContextAdapter; +#include "browser_context_adapter_client.h" +#include "qquickwebengineprofile_p.h" + #include +#include +#include QT_BEGIN_NAMESPACE - -class QQuickWebEngineProfilePrivate { +class QQuickWebEngineDownloadItem; +class QQuickWebEngineProfilePrivate + : public BrowserContextAdapterClient +{ public: + Q_DECLARE_PUBLIC(QQuickWebEngineProfile) QQuickWebEngineProfilePrivate(BrowserContextAdapter* browserContext, bool ownsContext); ~QQuickWebEngineProfilePrivate(); BrowserContextAdapter *browserContext() const { return m_browserContext; } + void cancelDownload(quint32 downloadId); + void downloadDestroyed(quint32 downloadId); + + void downloadRequested(quint32 downloadId, QString &downloadPath, bool &cancelled) Q_DECL_OVERRIDE; + void downloadUpdated(quint32 downloadId, int downloadState, int percentComplete) Q_DECL_OVERRIDE; + private: friend class QQuickWebEngineViewPrivate; + QQuickWebEngineProfile *q_ptr; BrowserContextAdapter *m_browserContext; QExplicitlySharedDataPointer m_browserContextRef; + QMap > m_ongoingDownloads; }; QT_END_NAMESPACE diff --git a/src/webengine/api/qquickwebenginesingleton_p.h b/src/webengine/api/qquickwebenginesingleton_p.h index 3bc1a9700..f983d0ffb 100644 --- a/src/webengine/api/qquickwebenginesingleton_p.h +++ b/src/webengine/api/qquickwebenginesingleton_p.h @@ -43,7 +43,6 @@ QT_BEGIN_NAMESPACE class QQuickWebEngineProfile; class QQuickWebEngineSettings; - class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineSingleton : public QObject { Q_OBJECT Q_PROPERTY(QQuickWebEngineSettings* settings READ settings CONSTANT FINAL) diff --git a/src/webengine/plugin/experimental/plugin.cpp b/src/webengine/plugin/experimental/plugin.cpp index 883ebc598..f522478ab 100644 --- a/src/webengine/plugin/experimental/plugin.cpp +++ b/src/webengine/plugin/experimental/plugin.cpp @@ -36,6 +36,7 @@ #include +#include "qquickwebenginedownloaditem_p.h" #include "qquickwebenginehistory_p.h" #include "qquickwebenginesettings_p.h" #include "qquickwebenginesingleton_p.h" @@ -80,7 +81,9 @@ public: QObject::tr("Cannot create a separate instance of NavigationHistory")); qmlRegisterUncreatableType(uri, 1, 0, "WebEngineSettings", QObject::tr("Cannot create a separate instance of WebEngineSettings")); - qmlRegisterSingletonType(uri, 1, 0, "WebEngine", webEngineSingletonProvider); + qmlRegisterUncreatableType(uri, 1, 1, "WebEngineDownloadItem", + QObject::tr("Cannot create a separate instance of WebEngineDownloadItem")); + qmlRegisterSingletonType(uri, 1, 1, "WebEngine", webEngineSingletonProvider); } }; diff --git a/src/webengine/webengine.pro b/src/webengine/webengine.pro index 11ec95c05..6d17fd2eb 100644 --- a/src/webengine/webengine.pro +++ b/src/webengine/webengine.pro @@ -13,6 +13,7 @@ QMAKE_DOCS = $$PWD/doc/qtwebengine.qdocconf INCLUDEPATH += $$PWD api ../core SOURCES = \ + api/qquickwebenginedownloaditem.cpp \ api/qquickwebenginehistory.cpp \ api/qquickwebengineloadrequest.cpp \ api/qquickwebenginenavigationrequest.cpp \ @@ -29,6 +30,8 @@ SOURCES = \ HEADERS = \ api/qtwebengineglobal.h \ api/qtwebengineglobal_p.h \ + api/qquickwebenginedownloaditem_p.h \ + api/qquickwebenginedownloaditem_p_p.h \ api/qquickwebenginehistory_p.h \ api/qquickwebengineloadrequest_p.h \ api/qquickwebenginenavigationrequest_p.h \ diff --git a/tests/quicktestbrowser/DownloadView.qml b/tests/quicktestbrowser/DownloadView.qml new file mode 100644 index 000000000..da24c0142 --- /dev/null +++ b/tests/quicktestbrowser/DownloadView.qml @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** Copyright (C) 2014 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:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.1 +import QtQuick.Controls 1.0 +import QtQuick.Controls.Styles 1.0 +import QtWebEngine 1.0 +import QtWebEngine.experimental 1.1 +import QtQuick.Layouts 1.0 + +Rectangle { + id: downloadView + color: "lightgray" + + ListModel { + id: downloadModel + property var downloads: [] + } + + function append(download) { + downloadModel.append(download) + downloadModel.downloads.push(download) + } + + Component { + id: downloadItemDelegate + + Rectangle { + width: listView.width + height: childrenRect.height + anchors.margins: 10 + radius: 3 + color: "transparent" + border.color: "black" + Rectangle { + id: progressBar + + property int progress: downloadModel.downloads[index] ? downloadModel.downloads[index].progress : 0 + + radius: 3 + color: width == listView.width ? "green" : "#2b74c7" + width: listView.width / 100 * progress + height: cancelButton.height + + Behavior on width { + SmoothedAnimation { duration: 100 } + } + } + Rectangle { + anchors { + left: parent.left + right: parent.right + leftMargin: 20 + } + Label { + id: label + text: path + anchors { + verticalCenter: cancelButton.verticalCenter + left: parent.left + right: cancelButton.left + } + } + Button { + id: cancelButton + anchors.right: parent.right + iconSource: "icons/process-stop.png" + onClicked: { + var download = downloadModel.downloads[index] + + download.cancel() + + downloadModel.downloads = downloadModel.downloads.filter(function (el) { + return el.id !== download.id; + }); + downloadModel.remove(index) + } + } + } + } + + } + ListView { + id: listView + anchors { + topMargin: 10 + top: parent.top + bottom: parent.bottom + horizontalCenter: parent.horizontalCenter + } + width: parent.width - 20 + spacing: 5 + + model: downloadModel + delegate: downloadItemDelegate + + Text { + visible: !listView.count + horizontalAlignment: Text.AlignHCenter + height: 30 + anchors { + top: parent.top + left: parent.left + right: parent.right + } + font.pixelSize: 20 + text: "No active downloads." + } + + Rectangle { + color: "gray" + anchors { + bottom: parent.bottom + left: parent.left + right: parent.right + } + height: 30 + Button { + id: okButton + text: "OK" + anchors.centerIn: parent + onClicked: { + downloadView.visible = false + } + } + } + } +} diff --git a/tests/quicktestbrowser/quicktestbrowser.pro b/tests/quicktestbrowser/quicktestbrowser.pro index ac8fe74b3..1da197590 100644 --- a/tests/quicktestbrowser/quicktestbrowser.pro +++ b/tests/quicktestbrowser/quicktestbrowser.pro @@ -10,6 +10,7 @@ SOURCES = quickwindow.cpp \ OTHER_FILES += ButtonWithMenu.qml \ ContextMenuExtras.qml \ + DownloadView.qml \ FeaturePermissionBar.qml \ quickwindow.qml diff --git a/tests/quicktestbrowser/quickwindow.qml b/tests/quicktestbrowser/quickwindow.qml index 7bc9dd289..92bd048d4 100644 --- a/tests/quicktestbrowser/quickwindow.qml +++ b/tests/quicktestbrowser/quickwindow.qml @@ -40,7 +40,7 @@ import QtQuick 2.1 import QtWebEngine 1.1 -import QtWebEngine.experimental 1.0 +import QtWebEngine.experimental 1.1 import QtQuick.Controls 1.0 import QtQuick.Controls.Styles 1.0 @@ -74,14 +74,18 @@ ApplicationWindow { } WebEngineProfile { - id: testProfile; - storageName: "Test"; + id: testProfile + storageName: "Test" httpCacheType: httpDiskCacheEnabled.checked ? WebEngineProfile.DiskHttpCache : WebEngineProfile.MemoryHttpCache; + onDownloadStarted: { + downloadView.visible = true + downloadView.append(download) + } } WebEngineProfile { - id: otrProfile; - offTheRecord: true; + id: otrProfile + offTheRecord: true } // Make sure the Qt.WindowFullscreenButtonHint is set on Mac. @@ -92,6 +96,12 @@ ApplicationWindow { StyleItem { id: styleItem } property bool platformIsMac: styleItem.style == "mac" + Action { + shortcut: "Ctrl+D" + onTriggered: { + downloadView.visible = !downloadView.visible + } + } Action { id: focus @@ -435,6 +445,13 @@ ApplicationWindow { } } } + + DownloadView { + id: downloadView + visible: false + anchors.fill: parent + } + ZoomController { id: zoomController y: parent.mapFromItem(currentWebView, 0 , 0).y - 4 diff --git a/tests/quicktestbrowser/resources.qrc b/tests/quicktestbrowser/resources.qrc index 4880b3d65..3c9fd5dd7 100644 --- a/tests/quicktestbrowser/resources.qrc +++ b/tests/quicktestbrowser/resources.qrc @@ -4,6 +4,7 @@ ContextMenuExtras.qml FeaturePermissionBar.qml ButtonWithMenu.qml + DownloadView.qml ZoomController.qml -- cgit v1.2.3