diff options
Diffstat (limited to 'chrome/browser/download/drag_download_file.cc')
-rw-r--r-- | chrome/browser/download/drag_download_file.cc | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/chrome/browser/download/drag_download_file.cc b/chrome/browser/download/drag_download_file.cc new file mode 100644 index 0000000..4b2b370 --- /dev/null +++ b/chrome/browser/download/drag_download_file.cc @@ -0,0 +1,223 @@ +// Copyright (c) 2009-2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/download/drag_download_file.h" + +#include "base/file_util.h" +#include "base/message_loop.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/download/download_file.h" +#include "chrome/browser/download/download_item.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "net/base/file_stream.h" + +DragDownloadFile::DragDownloadFile( + const FilePath& file_name_or_path, + linked_ptr<net::FileStream> file_stream, + const GURL& url, + const GURL& referrer, + const std::string& referrer_encoding, + TabContents* tab_contents) + : file_stream_(file_stream), + url_(url), + referrer_(referrer), + referrer_encoding_(referrer_encoding), + tab_contents_(tab_contents), + drag_message_loop_(MessageLoop::current()), + is_started_(false), + is_successful_(false), + download_manager_(NULL), + download_item_observer_added_(false) { +#if defined(OS_WIN) + DCHECK(!file_name_or_path.empty() && !file_stream.get()); + file_name_ = file_name_or_path; +#elif defined(OS_POSIX) + DCHECK(!file_name_or_path.empty() && file_stream.get()); + file_path_ = file_name_or_path; +#endif +} + +DragDownloadFile::~DragDownloadFile() { + AssertCurrentlyOnDragThread(); + + // Since the target application can still hold and use the dragged file, + // we do not know the time that it can be safely deleted. To solve this + // problem, we schedule it to be removed after the system is restarted. +#if defined(OS_WIN) + if (!temp_dir_path_.empty()) { + if (!file_path_.empty()) + file_util::DeleteAfterReboot(file_path_); + file_util::DeleteAfterReboot(temp_dir_path_); + } +#endif + + if (download_manager_) + download_manager_->RemoveObserver(this); +} + +bool DragDownloadFile::Start(DownloadFileObserver* observer) { + AssertCurrentlyOnDragThread(); + + if (is_started_) + return true; + is_started_ = true; + + DCHECK(!observer_.get()); + observer_ = observer; + + if (!file_stream_.get()) { + // Create a temporary directory to save the temporary download file. We do + // not want to use the default download directory since we do not want the + // twisted file name shown in the download shelf if the file with the same + // name already exists. + if (!file_util::CreateNewTempDirectory(FILE_PATH_LITERAL("chrome"), + &temp_dir_path_)) + return false; + + file_path_ = temp_dir_path_.Append(file_name_); + } + + InitiateDownload(); + + // On Windows, we need to wait till the download file is completed. +#if defined(OS_WIN) + StartNestedMessageLoop(); +#endif + + return is_successful_; +} + +void DragDownloadFile::Stop() { +} + +void DragDownloadFile::InitiateDownload() { +#if defined(OS_WIN) + // DownloadManager could only be invoked from the UI thread. + if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) { + ChromeThread::PostTask( + ChromeThread::UI, FROM_HERE, + NewRunnableMethod(this, + &DragDownloadFile::InitiateDownload)); + return; + } +#endif + + download_manager_ = tab_contents_->profile()->GetDownloadManager(); + download_manager_->AddObserver(this); + + DownloadSaveInfo save_info; + save_info.file_path = file_path_; + save_info.file_stream = file_stream_; + download_manager_->DownloadUrlToFile(url_, + referrer_, + referrer_encoding_, + save_info, + tab_contents_); +} + +void DragDownloadFile::DownloadCompleted(bool is_successful) { +#if defined(OS_WIN) + // If not in drag-and-drop thread, defer the running to it. + if (drag_message_loop_ != MessageLoop::current()) { + drag_message_loop_->PostTask( + FROM_HERE, + NewRunnableMethod(this, + &DragDownloadFile::DownloadCompleted, + is_successful)); + return; + } +#endif + + is_successful_ = is_successful; + + // Call the observer. + DCHECK(observer_); + if (is_successful) + observer_->OnDownloadCompleted(file_path_); + else + observer_->OnDownloadAborted(); + + // Release the observer since we do not need it any more. + observer_ = NULL; + + // On Windows, we need to stop the waiting. +#if defined(OS_WIN) + QuitNestedMessageLoop(); +#endif +} + +void DragDownloadFile::ModelChanged() { + AssertCurrentlyOnUIThread(); + + download_manager_->GetTemporaryDownloads(this, file_path_.DirName()); +} + +void DragDownloadFile::SetDownloads(std::vector<DownloadItem*>& downloads) { + AssertCurrentlyOnUIThread(); + + std::vector<DownloadItem*>::const_iterator it = downloads.begin(); + for (; it != downloads.end(); ++it) { + if (!download_item_observer_added_ && (*it)->url() == url_) { + download_item_observer_added_ = true; + (*it)->AddObserver(this); + } + } +} + +void DragDownloadFile::OnDownloadUpdated(DownloadItem* download) { + AssertCurrentlyOnUIThread(); + + if (download->state() == DownloadItem::CANCELLED) { + download->RemoveObserver(this); + download_manager_->RemoveObserver(this); + + DownloadCompleted(false); + } +} + +void DragDownloadFile::OnDownloadFileCompleted(DownloadItem* download) { + AssertCurrentlyOnUIThread(); + DCHECK(download->state() == DownloadItem::COMPLETE); + + download->RemoveObserver(this); + download_manager_->RemoveObserver(this); + + DownloadCompleted(true); +} + +void DragDownloadFile::AssertCurrentlyOnDragThread() { + // Only do the check on Windows where two threads are involved. +#if defined(OS_WIN) + DCHECK(drag_message_loop_ == MessageLoop::current()); +#endif +} + +void DragDownloadFile::AssertCurrentlyOnUIThread() { + // Only do the check on Windows where two threads are involved. +#if defined(OS_WIN) + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); +#endif +} + +#if defined(OS_WIN) +void DragDownloadFile::StartNestedMessageLoop() { + AssertCurrentlyOnDragThread(); + + bool old_state = MessageLoop::current()->NestableTasksAllowed(); + MessageLoop::current()->SetNestableTasksAllowed(true); + is_running_nested_message_loop_ = true; + MessageLoop::current()->Run(); + MessageLoop::current()->SetNestableTasksAllowed(old_state); +} + +void DragDownloadFile::QuitNestedMessageLoop() { + AssertCurrentlyOnDragThread(); + + if (is_running_nested_message_loop_) { + is_running_nested_message_loop_ = false; + MessageLoop::current()->Quit(); + } +} +#endif |