OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/file_select_helper.h" | 5 #include "chrome/browser/file_select_helper.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
54 std::vector<ui::SelectedFileInfo> FilePathListToSelectedFileInfoList( | 54 std::vector<ui::SelectedFileInfo> FilePathListToSelectedFileInfoList( |
55 const std::vector<base::FilePath>& paths) { | 55 const std::vector<base::FilePath>& paths) { |
56 std::vector<ui::SelectedFileInfo> selected_files; | 56 std::vector<ui::SelectedFileInfo> selected_files; |
57 for (size_t i = 0; i < paths.size(); ++i) { | 57 for (size_t i = 0; i < paths.size(); ++i) { |
58 selected_files.push_back( | 58 selected_files.push_back( |
59 ui::SelectedFileInfo(paths[i], paths[i])); | 59 ui::SelectedFileInfo(paths[i], paths[i])); |
60 } | 60 } |
61 return selected_files; | 61 return selected_files; |
62 } | 62 } |
63 | 63 |
| 64 void DeleteFiles(const std::vector<base::FilePath>& paths) { |
| 65 for (auto& file_path : paths) |
| 66 base::DeleteFile(file_path, false); |
| 67 } |
| 68 |
64 } // namespace | 69 } // namespace |
65 | 70 |
66 struct FileSelectHelper::ActiveDirectoryEnumeration { | 71 struct FileSelectHelper::ActiveDirectoryEnumeration { |
67 ActiveDirectoryEnumeration() : rvh_(NULL) {} | 72 ActiveDirectoryEnumeration() : rvh_(NULL) {} |
68 | 73 |
69 scoped_ptr<DirectoryListerDispatchDelegate> delegate_; | 74 scoped_ptr<DirectoryListerDispatchDelegate> delegate_; |
70 scoped_ptr<net::DirectoryLister> lister_; | 75 scoped_ptr<net::DirectoryLister> lister_; |
71 RenderViewHost* rvh_; | 76 RenderViewHost* rvh_; |
72 std::vector<base::FilePath> results_; | 77 std::vector<base::FilePath> results_; |
73 }; | 78 }; |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
110 | 115 |
111 void FileSelectHelper::FileSelected(const base::FilePath& path, | 116 void FileSelectHelper::FileSelected(const base::FilePath& path, |
112 int index, void* params) { | 117 int index, void* params) { |
113 FileSelectedWithExtraInfo(ui::SelectedFileInfo(path, path), index, params); | 118 FileSelectedWithExtraInfo(ui::SelectedFileInfo(path, path), index, params); |
114 } | 119 } |
115 | 120 |
116 void FileSelectHelper::FileSelectedWithExtraInfo( | 121 void FileSelectHelper::FileSelectedWithExtraInfo( |
117 const ui::SelectedFileInfo& file, | 122 const ui::SelectedFileInfo& file, |
118 int index, | 123 int index, |
119 void* params) { | 124 void* params) { |
120 if (!render_view_host_) | 125 profile_->set_last_selected_directory(file.file_path.DirName()); |
| 126 |
| 127 if (!render_view_host_) { |
| 128 RunFileChooserEnd(); |
121 return; | 129 return; |
122 | 130 } |
123 profile_->set_last_selected_directory(file.file_path.DirName()); | |
124 | 131 |
125 const base::FilePath& path = file.local_path; | 132 const base::FilePath& path = file.local_path; |
126 if (dialog_type_ == ui::SelectFileDialog::SELECT_UPLOAD_FOLDER) { | 133 if (dialog_type_ == ui::SelectFileDialog::SELECT_UPLOAD_FOLDER) { |
127 StartNewEnumeration(path, kFileSelectEnumerationId, render_view_host_); | 134 StartNewEnumeration(path, kFileSelectEnumerationId, render_view_host_); |
128 return; | 135 return; |
129 } | 136 } |
130 | 137 |
131 std::vector<ui::SelectedFileInfo> files; | 138 std::vector<ui::SelectedFileInfo> files; |
132 files.push_back(file); | 139 files.push_back(file); |
133 NotifyRenderViewHost(render_view_host_, files, dialog_mode_); | |
134 | 140 |
135 // No members should be accessed from here on. | 141 #if defined(OS_MACOSX) && !defined(OS_IOS) |
136 RunFileChooserEnd(); | 142 content::BrowserThread::PostTask( |
| 143 content::BrowserThread::FILE_USER_BLOCKING, |
| 144 FROM_HERE, |
| 145 base::Bind(&FileSelectHelper::ProcessSelectedFilesMac, this, files)); |
| 146 #else |
| 147 NotifyRenderViewHostAndEnd(files); |
| 148 #endif // defined(OS_MACOSX) && !defined(OS_IOS) |
137 } | 149 } |
138 | 150 |
139 void FileSelectHelper::MultiFilesSelected( | 151 void FileSelectHelper::MultiFilesSelected( |
140 const std::vector<base::FilePath>& files, | 152 const std::vector<base::FilePath>& files, |
141 void* params) { | 153 void* params) { |
142 std::vector<ui::SelectedFileInfo> selected_files = | 154 std::vector<ui::SelectedFileInfo> selected_files = |
143 FilePathListToSelectedFileInfoList(files); | 155 FilePathListToSelectedFileInfoList(files); |
144 | 156 |
145 MultiFilesSelectedWithExtraInfo(selected_files, params); | 157 MultiFilesSelectedWithExtraInfo(selected_files, params); |
146 } | 158 } |
147 | 159 |
148 void FileSelectHelper::MultiFilesSelectedWithExtraInfo( | 160 void FileSelectHelper::MultiFilesSelectedWithExtraInfo( |
149 const std::vector<ui::SelectedFileInfo>& files, | 161 const std::vector<ui::SelectedFileInfo>& files, |
150 void* params) { | 162 void* params) { |
151 if (!files.empty()) | 163 if (!files.empty()) |
152 profile_->set_last_selected_directory(files[0].file_path.DirName()); | 164 profile_->set_last_selected_directory(files[0].file_path.DirName()); |
153 if (!render_view_host_) | |
154 return; | |
155 | 165 |
156 NotifyRenderViewHost(render_view_host_, files, dialog_mode_); | 166 #if defined(OS_MACOSX) && !defined(OS_IOS) |
157 | 167 content::BrowserThread::PostTask( |
158 // No members should be accessed from here on. | 168 content::BrowserThread::FILE_USER_BLOCKING, |
159 RunFileChooserEnd(); | 169 FROM_HERE, |
| 170 base::Bind(&FileSelectHelper::ProcessSelectedFilesMac, this, files)); |
| 171 #else |
| 172 NotifyRenderViewHostAndEnd(files); |
| 173 #endif // defined(OS_MACOSX) && !defined(OS_IOS) |
160 } | 174 } |
161 | 175 |
162 void FileSelectHelper::FileSelectionCanceled(void* params) { | 176 void FileSelectHelper::FileSelectionCanceled(void* params) { |
163 if (!render_view_host_) | 177 NotifyRenderViewHostAndEnd(std::vector<ui::SelectedFileInfo>()); |
164 return; | |
165 | |
166 // If the user cancels choosing a file to upload we pass back an | |
167 // empty vector. | |
168 NotifyRenderViewHost( | |
169 render_view_host_, std::vector<ui::SelectedFileInfo>(), | |
170 dialog_mode_); | |
171 | |
172 // No members should be accessed from here on. | |
173 RunFileChooserEnd(); | |
174 } | 178 } |
175 | 179 |
176 void FileSelectHelper::StartNewEnumeration(const base::FilePath& path, | 180 void FileSelectHelper::StartNewEnumeration(const base::FilePath& path, |
177 int request_id, | 181 int request_id, |
178 RenderViewHost* render_view_host) { | 182 RenderViewHost* render_view_host) { |
179 scoped_ptr<ActiveDirectoryEnumeration> entry(new ActiveDirectoryEnumeration); | 183 scoped_ptr<ActiveDirectoryEnumeration> entry(new ActiveDirectoryEnumeration); |
180 entry->rvh_ = render_view_host; | 184 entry->rvh_ = render_view_host; |
181 entry->delegate_.reset(new DirectoryListerDispatchDelegate(this, request_id)); | 185 entry->delegate_.reset(new DirectoryListerDispatchDelegate(this, request_id)); |
182 entry->lister_.reset(new net::DirectoryLister(path, | 186 entry->lister_.reset(new net::DirectoryLister(path, |
183 true, | 187 true, |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
221 FilePathListToSelectedFileInfoList(entry->results_); | 225 FilePathListToSelectedFileInfoList(entry->results_); |
222 | 226 |
223 if (id == kFileSelectEnumerationId) | 227 if (id == kFileSelectEnumerationId) |
224 NotifyRenderViewHost(entry->rvh_, selected_files, dialog_mode_); | 228 NotifyRenderViewHost(entry->rvh_, selected_files, dialog_mode_); |
225 else | 229 else |
226 entry->rvh_->DirectoryEnumerationFinished(id, entry->results_); | 230 entry->rvh_->DirectoryEnumerationFinished(id, entry->results_); |
227 | 231 |
228 EnumerateDirectoryEnd(); | 232 EnumerateDirectoryEnd(); |
229 } | 233 } |
230 | 234 |
| 235 void FileSelectHelper::NotifyRenderViewHostAndEnd( |
| 236 const std::vector<ui::SelectedFileInfo>& files) { |
| 237 if (render_view_host_) |
| 238 NotifyRenderViewHost(render_view_host_, files, dialog_mode_); |
| 239 |
| 240 // No members should be accessed from here on. |
| 241 RunFileChooserEnd(); |
| 242 } |
| 243 |
| 244 void FileSelectHelper::DeleteTemporaryFiles() { |
| 245 BrowserThread::PostTask(BrowserThread::FILE, |
| 246 FROM_HERE, |
| 247 base::Bind(&DeleteFiles, temporary_files_)); |
| 248 temporary_files_.clear(); |
| 249 } |
| 250 |
231 scoped_ptr<ui::SelectFileDialog::FileTypeInfo> | 251 scoped_ptr<ui::SelectFileDialog::FileTypeInfo> |
232 FileSelectHelper::GetFileTypesFromAcceptType( | 252 FileSelectHelper::GetFileTypesFromAcceptType( |
233 const std::vector<base::string16>& accept_types) { | 253 const std::vector<base::string16>& accept_types) { |
234 scoped_ptr<ui::SelectFileDialog::FileTypeInfo> base_file_type( | 254 scoped_ptr<ui::SelectFileDialog::FileTypeInfo> base_file_type( |
235 new ui::SelectFileDialog::FileTypeInfo()); | 255 new ui::SelectFileDialog::FileTypeInfo()); |
236 if (accept_types.empty()) | 256 if (accept_types.empty()) |
237 return base_file_type.Pass(); | 257 return base_file_type.Pass(); |
238 | 258 |
239 // Create FileTypeInfo and pre-allocate for the first extension list. | 259 // Create FileTypeInfo and pre-allocate for the first extension list. |
240 scoped_ptr<ui::SelectFileDialog::FileTypeInfo> file_type( | 260 scoped_ptr<ui::SelectFileDialog::FileTypeInfo> file_type( |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
319 } | 339 } |
320 | 340 |
321 void FileSelectHelper::RunFileChooser(RenderViewHost* render_view_host, | 341 void FileSelectHelper::RunFileChooser(RenderViewHost* render_view_host, |
322 content::WebContents* web_contents, | 342 content::WebContents* web_contents, |
323 const FileChooserParams& params) { | 343 const FileChooserParams& params) { |
324 DCHECK(!render_view_host_); | 344 DCHECK(!render_view_host_); |
325 DCHECK(!web_contents_); | 345 DCHECK(!web_contents_); |
326 render_view_host_ = render_view_host; | 346 render_view_host_ = render_view_host; |
327 web_contents_ = web_contents; | 347 web_contents_ = web_contents; |
328 notification_registrar_.RemoveAll(); | 348 notification_registrar_.RemoveAll(); |
| 349 notification_registrar_.Add(this, |
| 350 content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED, |
| 351 content::Source<WebContents>(web_contents_)); |
329 notification_registrar_.Add( | 352 notification_registrar_.Add( |
330 this, content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED, | 353 this, |
| 354 content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED, |
331 content::Source<RenderWidgetHost>(render_view_host_)); | 355 content::Source<RenderWidgetHost>(render_view_host_)); |
332 notification_registrar_.Add( | 356 notification_registrar_.Add( |
333 this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, | 357 this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, |
334 content::Source<WebContents>(web_contents_)); | 358 content::Source<WebContents>(web_contents_)); |
335 | 359 |
336 BrowserThread::PostTask( | 360 BrowserThread::PostTask( |
337 BrowserThread::FILE, FROM_HERE, | 361 BrowserThread::FILE, FROM_HERE, |
338 base::Bind(&FileSelectHelper::RunFileChooserOnFileThread, this, params)); | 362 base::Bind(&FileSelectHelper::RunFileChooserOnFileThread, this, params)); |
339 | 363 |
340 // Because this class returns notifications to the RenderViewHost, it is | 364 // Because this class returns notifications to the RenderViewHost, it is |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
417 NULL); | 441 NULL); |
418 #endif | 442 #endif |
419 | 443 |
420 select_file_types_.reset(); | 444 select_file_types_.reset(); |
421 } | 445 } |
422 | 446 |
423 // This method is called when we receive the last callback from the file | 447 // This method is called when we receive the last callback from the file |
424 // chooser dialog. Perform any cleanup and release the reference we added | 448 // chooser dialog. Perform any cleanup and release the reference we added |
425 // in RunFileChooser(). | 449 // in RunFileChooser(). |
426 void FileSelectHelper::RunFileChooserEnd() { | 450 void FileSelectHelper::RunFileChooserEnd() { |
| 451 // If there are temporary files, then this instance needs to stick around |
| 452 // until web_contents_ is destroyed, so that this instance can delete the |
| 453 // temporary files. |
| 454 if (!temporary_files_.empty()) |
| 455 return; |
| 456 |
427 render_view_host_ = NULL; | 457 render_view_host_ = NULL; |
428 web_contents_ = NULL; | 458 web_contents_ = NULL; |
429 Release(); | 459 Release(); |
430 } | 460 } |
431 | 461 |
432 void FileSelectHelper::EnumerateDirectory(int request_id, | 462 void FileSelectHelper::EnumerateDirectory(int request_id, |
433 RenderViewHost* render_view_host, | 463 RenderViewHost* render_view_host, |
434 const base::FilePath& path) { | 464 const base::FilePath& path) { |
435 | 465 |
436 // Because this class returns notifications to the RenderViewHost, it is | 466 // Because this class returns notifications to the RenderViewHost, it is |
(...skipping 19 matching lines...) Expand all Loading... |
456 case content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED: { | 486 case content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED: { |
457 DCHECK(content::Source<RenderWidgetHost>(source).ptr() == | 487 DCHECK(content::Source<RenderWidgetHost>(source).ptr() == |
458 render_view_host_); | 488 render_view_host_); |
459 render_view_host_ = NULL; | 489 render_view_host_ = NULL; |
460 break; | 490 break; |
461 } | 491 } |
462 | 492 |
463 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: { | 493 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: { |
464 DCHECK(content::Source<WebContents>(source).ptr() == web_contents_); | 494 DCHECK(content::Source<WebContents>(source).ptr() == web_contents_); |
465 web_contents_ = NULL; | 495 web_contents_ = NULL; |
| 496 } |
| 497 |
| 498 // Intentional fall through. |
| 499 case content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED: |
| 500 if (!temporary_files_.empty()) { |
| 501 DeleteTemporaryFiles(); |
| 502 |
| 503 // Now that the temporary files have been scheduled for deletion, there |
| 504 // is no longer any reason to keep this instance around. |
| 505 Release(); |
| 506 } |
| 507 |
466 break; | 508 break; |
467 } | |
468 | 509 |
469 default: | 510 default: |
470 NOTREACHED(); | 511 NOTREACHED(); |
471 } | 512 } |
472 } | 513 } |
473 | 514 |
474 // static | 515 // static |
475 bool FileSelectHelper::IsAcceptTypeValid(const std::string& accept_type) { | 516 bool FileSelectHelper::IsAcceptTypeValid(const std::string& accept_type) { |
476 // TODO(raymes): This only does some basic checks, extend to test more cases. | 517 // TODO(raymes): This only does some basic checks, extend to test more cases. |
477 // A 1 character accept type will always be invalid (either a "." in the case | 518 // A 1 character accept type will always be invalid (either a "." in the case |
478 // of an extension or a "/" in the case of a MIME type). | 519 // of an extension or a "/" in the case of a MIME type). |
479 std::string unused; | 520 std::string unused; |
480 if (accept_type.length() <= 1 || | 521 if (accept_type.length() <= 1 || |
481 base::StringToLowerASCII(accept_type) != accept_type || | 522 base::StringToLowerASCII(accept_type) != accept_type || |
482 base::TrimWhitespaceASCII(accept_type, base::TRIM_ALL, &unused) != | 523 base::TrimWhitespaceASCII(accept_type, base::TRIM_ALL, &unused) != |
483 base::TRIM_NONE) { | 524 base::TRIM_NONE) { |
484 return false; | 525 return false; |
485 } | 526 } |
486 return true; | 527 return true; |
487 } | 528 } |
OLD | NEW |