This source file includes following definitions.
- weak_ptr_factory_
- InitiateDownload
- Cancel
- Delete
- DragDownloadFileUI
- OnDownloadStarted
- OnDownloadUpdated
- OnDownloadDestroyed
- weak_ptr_factory_
- Start
- Wait
- Stop
- DownloadCompleted
- CheckThread
#include "content/browser/download/drag_download_file.h"
#include "base/bind.h"
#include "base/files/file.h"
#include "base/message_loop/message_loop.h"
#include "content/browser/download/download_stats.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/download_item.h"
#include "content/public/browser/download_save_info.h"
#include "content/public/browser/download_url_parameters.h"
namespace content {
namespace {
typedef base::Callback<void(bool)> OnCompleted;
}
class DragDownloadFile::DragDownloadFileUI : public DownloadItem::Observer {
public:
DragDownloadFileUI(const GURL& url,
const Referrer& referrer,
const std::string& referrer_encoding,
WebContents* web_contents,
base::MessageLoop* on_completed_loop,
const OnCompleted& on_completed)
: on_completed_loop_(on_completed_loop),
on_completed_(on_completed),
url_(url),
referrer_(referrer),
referrer_encoding_(referrer_encoding),
web_contents_(web_contents),
download_item_(NULL),
weak_ptr_factory_(this) {
DCHECK(on_completed_loop_);
DCHECK(!on_completed_.is_null());
DCHECK(web_contents_);
}
void InitiateDownload(base::File file,
const base::FilePath& file_path) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DownloadManager* download_manager =
BrowserContext::GetDownloadManager(web_contents_->GetBrowserContext());
RecordDownloadSource(INITIATED_BY_DRAG_N_DROP);
scoped_ptr<content::DownloadUrlParameters> params(
DownloadUrlParameters::FromWebContents(web_contents_, url_));
params->set_referrer(referrer_);
params->set_referrer_encoding(referrer_encoding_);
params->set_callback(base::Bind(&DragDownloadFileUI::OnDownloadStarted,
weak_ptr_factory_.GetWeakPtr()));
params->set_file_path(file_path);
params->set_file(file.Pass());
download_manager->DownloadUrl(params.Pass());
}
void Cancel() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (download_item_)
download_item_->Cancel(true);
}
void Delete() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
delete this;
}
private:
virtual ~DragDownloadFileUI() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (download_item_)
download_item_->RemoveObserver(this);
}
void OnDownloadStarted(DownloadItem* item,
DownloadInterruptReason interrupt_reason) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (!item) {
DCHECK_NE(DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason);
on_completed_loop_->PostTask(FROM_HERE, base::Bind(on_completed_, false));
return;
}
DCHECK_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason);
download_item_ = item;
download_item_->AddObserver(this);
}
virtual void OnDownloadUpdated(DownloadItem* item) OVERRIDE {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK_EQ(download_item_, item);
DownloadItem::DownloadState state = download_item_->GetState();
if (state == DownloadItem::COMPLETE ||
state == DownloadItem::CANCELLED ||
state == DownloadItem::INTERRUPTED) {
if (!on_completed_.is_null()) {
on_completed_loop_->PostTask(FROM_HERE, base::Bind(
on_completed_, state == DownloadItem::COMPLETE));
on_completed_.Reset();
}
download_item_->RemoveObserver(this);
download_item_ = NULL;
}
}
virtual void OnDownloadDestroyed(DownloadItem* item) OVERRIDE {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK_EQ(download_item_, item);
if (!on_completed_.is_null()) {
const bool is_complete =
download_item_->GetState() == DownloadItem::COMPLETE;
on_completed_loop_->PostTask(FROM_HERE, base::Bind(
on_completed_, is_complete));
on_completed_.Reset();
}
download_item_->RemoveObserver(this);
download_item_ = NULL;
}
base::MessageLoop* on_completed_loop_;
OnCompleted on_completed_;
GURL url_;
Referrer referrer_;
std::string referrer_encoding_;
WebContents* web_contents_;
DownloadItem* download_item_;
base::WeakPtrFactory<DragDownloadFileUI> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(DragDownloadFileUI);
};
DragDownloadFile::DragDownloadFile(const base::FilePath& file_path,
base::File file,
const GURL& url,
const Referrer& referrer,
const std::string& referrer_encoding,
WebContents* web_contents)
: file_path_(file_path),
file_(file.Pass()),
drag_message_loop_(base::MessageLoop::current()),
state_(INITIALIZED),
drag_ui_(NULL),
weak_ptr_factory_(this) {
drag_ui_ = new DragDownloadFileUI(
url,
referrer,
referrer_encoding,
web_contents,
drag_message_loop_,
base::Bind(&DragDownloadFile::DownloadCompleted,
weak_ptr_factory_.GetWeakPtr()));
DCHECK(!file_path_.empty());
}
DragDownloadFile::~DragDownloadFile() {
CheckThread();
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
&DragDownloadFileUI::Delete, base::Unretained(drag_ui_)));
drag_ui_ = NULL;
}
void DragDownloadFile::Start(ui::DownloadFileObserver* observer) {
CheckThread();
if (state_ != INITIALIZED)
return;
state_ = STARTED;
DCHECK(!observer_.get());
observer_ = observer;
DCHECK(observer_.get());
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
&DragDownloadFileUI::InitiateDownload, base::Unretained(drag_ui_),
base::Passed(&file_), file_path_));
}
bool DragDownloadFile::Wait() {
CheckThread();
if (state_ == STARTED)
nested_loop_.Run();
return state_ == SUCCESS;
}
void DragDownloadFile::Stop() {
CheckThread();
if (drag_ui_) {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
&DragDownloadFileUI::Cancel, base::Unretained(drag_ui_)));
}
}
void DragDownloadFile::DownloadCompleted(bool is_successful) {
CheckThread();
state_ = is_successful ? SUCCESS : FAILURE;
if (is_successful)
observer_->OnDownloadCompleted(file_path_);
else
observer_->OnDownloadAborted();
observer_ = NULL;
if (nested_loop_.running())
nested_loop_.Quit();
}
void DragDownloadFile::CheckThread() {
#if defined(OS_WIN)
DCHECK(drag_message_loop_ == base::MessageLoop::current());
#else
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
#endif
}
}