1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/download/drag_download_file.h"
7 #include "base/file_util.h"
8 #include "base/message_loop.h"
9 #include "content/browser/browser_context.h"
10 #include "content/browser/browser_thread.h"
11 #include "content/browser/download/download_item.h"
12 #include "content/browser/download/download_stats.h"
13 #include "content/browser/tab_contents/tab_contents.h"
14 #include "net/base/file_stream.h"
16 DragDownloadFile::DragDownloadFile(
17 const FilePath
& file_name_or_path
,
18 linked_ptr
<net::FileStream
> file_stream
,
21 const std::string
& referrer_encoding
,
22 TabContents
* tab_contents
)
23 : file_stream_(file_stream
),
26 referrer_encoding_(referrer_encoding
),
27 tab_contents_(tab_contents
),
28 drag_message_loop_(MessageLoop::current()),
30 is_successful_(false),
31 download_manager_(NULL
),
32 download_manager_observer_added_(false),
33 download_item_(NULL
) {
35 DCHECK(!file_name_or_path
.empty() && !file_stream
.get());
36 file_name_
= file_name_or_path
;
37 #elif defined(OS_POSIX)
38 DCHECK(!file_name_or_path
.empty() && file_stream
.get());
39 file_path_
= file_name_or_path
;
43 DragDownloadFile::~DragDownloadFile() {
44 AssertCurrentlyOnDragThread();
46 // Since the target application can still hold and use the dragged file,
47 // we do not know the time that it can be safely deleted. To solve this
48 // problem, we schedule it to be removed after the system is restarted.
50 if (!temp_dir_path_
.empty()) {
51 if (!file_path_
.empty())
52 file_util::DeleteAfterReboot(file_path_
);
53 file_util::DeleteAfterReboot(temp_dir_path_
);
60 void DragDownloadFile::RemoveObservers() {
62 download_item_
->RemoveObserver(this);
63 download_item_
= NULL
;
66 if (download_manager_observer_added_
) {
67 download_manager_observer_added_
= false;
68 download_manager_
->RemoveObserver(this);
72 bool DragDownloadFile::Start(ui::DownloadFileObserver
* observer
) {
73 AssertCurrentlyOnDragThread();
79 DCHECK(!observer_
.get());
82 if (!file_stream_
.get()) {
83 // Create a temporary directory to save the temporary download file. We do
84 // not want to use the default download directory since we do not want the
85 // twisted file name shown in the download shelf if the file with the same
86 // name already exists.
87 if (!file_util::CreateNewTempDirectory(FILE_PATH_LITERAL("chrome"),
91 file_path_
= temp_dir_path_
.Append(file_name_
);
96 // On Windows, we need to wait till the download file is completed.
98 StartNestedMessageLoop();
101 return is_successful_
;
104 void DragDownloadFile::Stop() {
107 void DragDownloadFile::InitiateDownload() {
109 // DownloadManager could only be invoked from the UI thread.
110 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
111 BrowserThread::PostTask(
112 BrowserThread::UI
, FROM_HERE
,
113 NewRunnableMethod(this,
114 &DragDownloadFile::InitiateDownload
));
119 download_manager_
= tab_contents_
->browser_context()->GetDownloadManager();
120 download_manager_observer_added_
= true;
121 download_manager_
->AddObserver(this);
123 DownloadSaveInfo save_info
;
124 save_info
.file_path
= file_path_
;
125 save_info
.file_stream
= file_stream_
;
126 download_manager_
->DownloadUrlToFile(url_
,
131 download_stats::RecordDownloadCount(
132 download_stats::INITIATED_BY_DRAG_N_DROP_COUNT
);
135 void DragDownloadFile::DownloadCompleted(bool is_successful
) {
137 // If not in drag-and-drop thread, defer the running to it.
138 if (drag_message_loop_
!= MessageLoop::current()) {
139 drag_message_loop_
->PostTask(
141 NewRunnableMethod(this,
142 &DragDownloadFile::DownloadCompleted
,
148 is_successful_
= is_successful
;
150 // Call the observer.
153 observer_
->OnDownloadCompleted(file_path_
);
155 observer_
->OnDownloadAborted();
157 // Release the observer since we do not need it any more.
160 // On Windows, we need to stop the waiting.
162 QuitNestedMessageLoop();
166 void DragDownloadFile::ModelChanged() {
167 AssertCurrentlyOnUIThread();
172 std::vector
<DownloadItem
*> downloads
;
173 download_manager_
->GetTemporaryDownloads(file_path_
.DirName(), &downloads
);
174 for (std::vector
<DownloadItem
*>::const_iterator i
= downloads
.begin();
175 i
!= downloads
.end(); ++i
) {
176 if ((*i
)->original_url() == url_
) {
178 download_item_
->AddObserver(this);
184 void DragDownloadFile::OnDownloadUpdated(DownloadItem
* download
) {
185 AssertCurrentlyOnUIThread();
186 if (download
->IsCancelled() || download
->state() == DownloadItem::REMOVING
) {
188 DownloadCompleted(false);
189 } else if (download
->IsComplete()) {
191 DownloadCompleted(true);
193 // Ignore other states.
196 void DragDownloadFile::AssertCurrentlyOnDragThread() {
197 // Only do the check on Windows where two threads are involved.
199 DCHECK(drag_message_loop_
== MessageLoop::current());
203 void DragDownloadFile::AssertCurrentlyOnUIThread() {
204 // Only do the check on Windows where two threads are involved.
206 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
211 void DragDownloadFile::StartNestedMessageLoop() {
212 AssertCurrentlyOnDragThread();
214 bool old_state
= MessageLoop::current()->NestableTasksAllowed();
215 MessageLoop::current()->SetNestableTasksAllowed(true);
216 is_running_nested_message_loop_
= true;
217 MessageLoop::current()->Run();
218 MessageLoop::current()->SetNestableTasksAllowed(old_state
);
221 void DragDownloadFile::QuitNestedMessageLoop() {
222 AssertCurrentlyOnDragThread();
224 if (is_running_nested_message_loop_
) {
225 is_running_nested_message_loop_
= false;
226 MessageLoop::current()->Quit();