summaryrefslogtreecommitdiffstats
path: root/chrome/browser/download/drag_download_file.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/download/drag_download_file.cc')
-rw-r--r--chrome/browser/download/drag_download_file.cc223
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