blob: fa0004ccb2edabad900f27e883d9b98fbe83c6a6 [file] [log] [blame]
[email protected]5626b0892012-02-20 14:46:581// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ba70d082010-09-10 16:54:492// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/file_select_helper.h"
6
[email protected]5ac950b2010-12-09 21:34:257#include <string>
[email protected]b7b4beb2013-07-09 14:06:508#include <utility>
[email protected]5ac950b2010-12-09 21:34:259
[email protected]9f054aa12011-09-29 19:13:4510#include "base/bind.h"
[email protected]25a4c1c2013-06-08 04:53:3611#include "base/files/file_enumerator.h"
thestig18dfb7a52014-08-26 10:44:0412#include "base/files/file_util.h"
[email protected]1988e1c2013-02-28 20:27:4213#include "base/strings/string_split.h"
[email protected]d8830562013-06-10 22:01:5414#include "base/strings/string_util.h"
[email protected]112158af2013-06-07 23:46:1815#include "base/strings/utf_string_conversions.h"
[email protected]ba70d082010-09-10 16:54:4916#include "chrome/browser/platform_util.h"
[email protected]8ecad5e2010-12-02 21:18:3317#include "chrome/browser/profiles/profile.h"
[email protected]d9898912011-04-15 21:10:0018#include "chrome/browser/ui/browser.h"
19#include "chrome/browser/ui/browser_list.h"
[email protected]6e1fcd12012-07-02 17:14:2020#include "chrome/browser/ui/chrome_select_file_policy.h"
[email protected]af39f002014-08-22 10:18:1821#include "chrome/grit/generated_resources.h"
[email protected]6a1c98e02012-10-24 21:49:4322#include "content/public/browser/browser_thread.h"
[email protected]6c2381d2011-10-19 02:52:5323#include "content/public/browser/notification_details.h"
24#include "content/public/browser/notification_source.h"
[email protected]0d6e9bd2011-10-18 04:29:1625#include "content/public/browser/notification_types.h"
[email protected]9c1662b2012-03-06 15:44:3326#include "content/public/browser/render_view_host.h"
[email protected]5626b0892012-02-20 14:46:5827#include "content/public/browser/render_widget_host_view.h"
[email protected]33f8ad52012-05-22 18:10:1328#include "content/public/browser/web_contents.h"
[email protected]8caadeb2011-11-22 02:45:2329#include "content/public/common/file_chooser_params.h"
[email protected]b3841c502011-03-09 01:21:3130#include "net/base/mime_util.h"
[email protected]c051a1b2011-01-21 23:30:1731#include "ui/base/l10n/l10n_util.h"
[email protected]4344a3c2013-01-17 23:49:2032#include "ui/shell_dialogs/selected_file_info.h"
[email protected]ba70d082010-09-10 16:54:4933
[email protected]631bb742011-11-02 11:29:3934using content::BrowserThread;
[email protected]33f8ad52012-05-22 18:10:1335using content::FileChooserParams;
[email protected]eaabba22012-03-07 15:02:1136using content::RenderViewHost;
37using content::RenderWidgetHost;
[email protected]ea049a02011-12-25 21:37:0938using content::WebContents;
[email protected]631bb742011-11-02 11:29:3939
[email protected]600ea402011-04-12 00:01:5140namespace {
41
42// There is only one file-selection happening at any given time,
43// so we allocate an enumeration ID for that purpose. All IDs from
44// the renderer must start at 0 and increase.
[email protected]459fba82011-10-13 02:48:5045const int kFileSelectEnumerationId = -1;
46
47void NotifyRenderViewHost(RenderViewHost* render_view_host,
[email protected]ddb034b2012-06-26 20:31:3948 const std::vector<ui::SelectedFileInfo>& files,
[email protected]bfcf1e92013-07-11 04:37:2549 FileChooserParams::Mode dialog_mode) {
50 render_view_host->FilesSelectedInChooser(files, dialog_mode);
[email protected]459fba82011-10-13 02:48:5051}
[email protected]fb11b6a42012-03-14 07:25:1252
[email protected]53f04c82012-07-26 02:31:0953// Converts a list of FilePaths to a list of ui::SelectedFileInfo.
54std::vector<ui::SelectedFileInfo> FilePathListToSelectedFileInfoList(
[email protected]650b2d52013-02-10 03:41:4555 const std::vector<base::FilePath>& paths) {
[email protected]ddb034b2012-06-26 20:31:3956 std::vector<ui::SelectedFileInfo> selected_files;
[email protected]fb11b6a42012-03-14 07:25:1257 for (size_t i = 0; i < paths.size(); ++i) {
58 selected_files.push_back(
[email protected]53f04c82012-07-26 02:31:0959 ui::SelectedFileInfo(paths[i], paths[i]));
[email protected]fb11b6a42012-03-14 07:25:1260 }
61 return selected_files;
[email protected]600ea402011-04-12 00:01:5162}
63
[email protected]fb11b6a42012-03-14 07:25:1264} // namespace
65
[email protected]485a5272011-04-12 00:49:2966struct FileSelectHelper::ActiveDirectoryEnumeration {
[email protected]d45f7512011-06-21 21:18:2767 ActiveDirectoryEnumeration() : rvh_(NULL) {}
[email protected]485a5272011-04-12 00:49:2968
69 scoped_ptr<DirectoryListerDispatchDelegate> delegate_;
[email protected]05a814182011-04-27 19:50:3470 scoped_ptr<net::DirectoryLister> lister_;
[email protected]485a5272011-04-12 00:49:2971 RenderViewHost* rvh_;
[email protected]650b2d52013-02-10 03:41:4572 std::vector<base::FilePath> results_;
[email protected]485a5272011-04-12 00:49:2973};
74
[email protected]ba70d082010-09-10 16:54:4975FileSelectHelper::FileSelectHelper(Profile* profile)
76 : profile_(profile),
77 render_view_host_(NULL),
[email protected]ea049a02011-12-25 21:37:0978 web_contents_(NULL),
[email protected]ba70d082010-09-10 16:54:4979 select_file_dialog_(),
[email protected]9f054aa12011-09-29 19:13:4580 select_file_types_(),
[email protected]bfcf1e92013-07-11 04:37:2581 dialog_type_(ui::SelectFileDialog::SELECT_OPEN_FILE),
82 dialog_mode_(FileChooserParams::Open) {
[email protected]ba70d082010-09-10 16:54:4983}
84
85FileSelectHelper::~FileSelectHelper() {
86 // There may be pending file dialogs, we need to tell them that we've gone
87 // away so they don't try and call back to us.
88 if (select_file_dialog_.get())
89 select_file_dialog_->ListenerDestroyed();
90
[email protected]600ea402011-04-12 00:01:5191 // Stop any pending directory enumeration, prevent a callback, and free
92 // allocated memory.
93 std::map<int, ActiveDirectoryEnumeration*>::iterator iter;
94 for (iter = directory_enumerations_.begin();
95 iter != directory_enumerations_.end();
96 ++iter) {
[email protected]05a814182011-04-27 19:50:3497 iter->second->lister_.reset();
[email protected]600ea402011-04-12 00:01:5198 delete iter->second;
[email protected]ba70d082010-09-10 16:54:4999 }
100}
101
[email protected]23827ec2012-08-10 22:08:08102void FileSelectHelper::DirectoryListerDispatchDelegate::OnListFile(
103 const net::DirectoryLister::DirectoryListerData& data) {
104 parent_->OnListFile(id_, data);
105}
106
107void FileSelectHelper::DirectoryListerDispatchDelegate::OnListDone(int error) {
108 parent_->OnListDone(id_, error);
109}
110
[email protected]650b2d52013-02-10 03:41:45111void FileSelectHelper::FileSelected(const base::FilePath& path,
[email protected]ba70d082010-09-10 16:54:49112 int index, void* params) {
[email protected]53f04c82012-07-26 02:31:09113 FileSelectedWithExtraInfo(ui::SelectedFileInfo(path, path), index, params);
[email protected]fb11b6a42012-03-14 07:25:12114}
115
116void FileSelectHelper::FileSelectedWithExtraInfo(
[email protected]ddb034b2012-06-26 20:31:39117 const ui::SelectedFileInfo& file,
[email protected]fb11b6a42012-03-14 07:25:12118 int index,
119 void* params) {
[email protected]ba70d082010-09-10 16:54:49120 if (!render_view_host_)
121 return;
122
[email protected]53f04c82012-07-26 02:31:09123 profile_->set_last_selected_directory(file.file_path.DirName());
[email protected]ba70d082010-09-10 16:54:49124
[email protected]650b2d52013-02-10 03:41:45125 const base::FilePath& path = file.local_path;
[email protected]6bedbef2013-07-31 06:33:49126 if (dialog_type_ == ui::SelectFileDialog::SELECT_UPLOAD_FOLDER) {
[email protected]600ea402011-04-12 00:01:51127 StartNewEnumeration(path, kFileSelectEnumerationId, render_view_host_);
[email protected]ba70d082010-09-10 16:54:49128 return;
129 }
130
[email protected]ddb034b2012-06-26 20:31:39131 std::vector<ui::SelectedFileInfo> files;
[email protected]fb11b6a42012-03-14 07:25:12132 files.push_back(file);
[email protected]bfcf1e92013-07-11 04:37:25133 NotifyRenderViewHost(render_view_host_, files, dialog_mode_);
[email protected]9f054aa12011-09-29 19:13:45134
[email protected]3a29a6e2011-08-24 18:26:21135 // No members should be accessed from here on.
[email protected]9f054aa12011-09-29 19:13:45136 RunFileChooserEnd();
[email protected]ba70d082010-09-10 16:54:49137}
138
[email protected]650b2d52013-02-10 03:41:45139void FileSelectHelper::MultiFilesSelected(
140 const std::vector<base::FilePath>& files,
141 void* params) {
[email protected]ddb034b2012-06-26 20:31:39142 std::vector<ui::SelectedFileInfo> selected_files =
[email protected]53f04c82012-07-26 02:31:09143 FilePathListToSelectedFileInfoList(files);
144
[email protected]fb11b6a42012-03-14 07:25:12145 MultiFilesSelectedWithExtraInfo(selected_files, params);
146}
147
148void FileSelectHelper::MultiFilesSelectedWithExtraInfo(
[email protected]ddb034b2012-06-26 20:31:39149 const std::vector<ui::SelectedFileInfo>& files,
[email protected]fb11b6a42012-03-14 07:25:12150 void* params) {
[email protected]ba70d082010-09-10 16:54:49151 if (!files.empty())
[email protected]53f04c82012-07-26 02:31:09152 profile_->set_last_selected_directory(files[0].file_path.DirName());
[email protected]ba70d082010-09-10 16:54:49153 if (!render_view_host_)
154 return;
155
[email protected]bfcf1e92013-07-11 04:37:25156 NotifyRenderViewHost(render_view_host_, files, dialog_mode_);
[email protected]9f054aa12011-09-29 19:13:45157
[email protected]3a29a6e2011-08-24 18:26:21158 // No members should be accessed from here on.
[email protected]9f054aa12011-09-29 19:13:45159 RunFileChooserEnd();
[email protected]ba70d082010-09-10 16:54:49160}
161
162void FileSelectHelper::FileSelectionCanceled(void* params) {
163 if (!render_view_host_)
164 return;
165
166 // If the user cancels choosing a file to upload we pass back an
167 // empty vector.
[email protected]459fba82011-10-13 02:48:50168 NotifyRenderViewHost(
[email protected]ddb034b2012-06-26 20:31:39169 render_view_host_, std::vector<ui::SelectedFileInfo>(),
[email protected]bfcf1e92013-07-11 04:37:25170 dialog_mode_);
[email protected]ba70d082010-09-10 16:54:49171
[email protected]3a29a6e2011-08-24 18:26:21172 // No members should be accessed from here on.
[email protected]9f054aa12011-09-29 19:13:45173 RunFileChooserEnd();
[email protected]ba70d082010-09-10 16:54:49174}
175
[email protected]650b2d52013-02-10 03:41:45176void FileSelectHelper::StartNewEnumeration(const base::FilePath& path,
[email protected]600ea402011-04-12 00:01:51177 int request_id,
178 RenderViewHost* render_view_host) {
179 scoped_ptr<ActiveDirectoryEnumeration> entry(new ActiveDirectoryEnumeration);
180 entry->rvh_ = render_view_host;
181 entry->delegate_.reset(new DirectoryListerDispatchDelegate(this, request_id));
[email protected]05a814182011-04-27 19:50:34182 entry->lister_.reset(new net::DirectoryLister(path,
183 true,
184 net::DirectoryLister::NO_SORT,
185 entry->delegate_.get()));
[email protected]600ea402011-04-12 00:01:51186 if (!entry->lister_->Start()) {
187 if (request_id == kFileSelectEnumerationId)
188 FileSelectionCanceled(NULL);
189 else
190 render_view_host->DirectoryEnumerationFinished(request_id,
191 entry->results_);
192 } else {
193 directory_enumerations_[request_id] = entry.release();
194 }
[email protected]ba70d082010-09-10 16:54:49195}
196
197void FileSelectHelper::OnListFile(
[email protected]600ea402011-04-12 00:01:51198 int id,
[email protected]ba70d082010-09-10 16:54:49199 const net::DirectoryLister::DirectoryListerData& data) {
[email protected]600ea402011-04-12 00:01:51200 ActiveDirectoryEnumeration* entry = directory_enumerations_[id];
201
[email protected]2c718a0d2014-03-24 02:42:22202 // Directory upload only cares about files.
[email protected]25a4c1c2013-06-08 04:53:36203 if (data.info.IsDirectory())
[email protected]2c718a0d2014-03-24 02:42:22204 return;
205
206 entry->results_.push_back(data.path);
[email protected]ba70d082010-09-10 16:54:49207}
208
[email protected]600ea402011-04-12 00:01:51209void FileSelectHelper::OnListDone(int id, int error) {
210 // This entry needs to be cleaned up when this function is done.
211 scoped_ptr<ActiveDirectoryEnumeration> entry(directory_enumerations_[id]);
212 directory_enumerations_.erase(id);
213 if (!entry->rvh_)
[email protected]ba70d082010-09-10 16:54:49214 return;
[email protected]ba70d082010-09-10 16:54:49215 if (error) {
216 FileSelectionCanceled(NULL);
217 return;
218 }
[email protected]fb11b6a42012-03-14 07:25:12219
[email protected]ddb034b2012-06-26 20:31:39220 std::vector<ui::SelectedFileInfo> selected_files =
[email protected]53f04c82012-07-26 02:31:09221 FilePathListToSelectedFileInfoList(entry->results_);
[email protected]fb11b6a42012-03-14 07:25:12222
[email protected]600ea402011-04-12 00:01:51223 if (id == kFileSelectEnumerationId)
[email protected]bfcf1e92013-07-11 04:37:25224 NotifyRenderViewHost(entry->rvh_, selected_files, dialog_mode_);
[email protected]600ea402011-04-12 00:01:51225 else
226 entry->rvh_->DirectoryEnumerationFinished(id, entry->results_);
[email protected]9f054aa12011-09-29 19:13:45227
228 EnumerateDirectoryEnd();
[email protected]ba70d082010-09-10 16:54:49229}
230
[email protected]479cce782012-09-15 20:15:53231scoped_ptr<ui::SelectFileDialog::FileTypeInfo>
[email protected]92f54082012-07-31 01:43:14232FileSelectHelper::GetFileTypesFromAcceptType(
[email protected]d2065e062013-12-12 23:49:52233 const std::vector<base::string16>& accept_types) {
[email protected]479cce782012-09-15 20:15:53234 scoped_ptr<ui::SelectFileDialog::FileTypeInfo> base_file_type(
235 new ui::SelectFileDialog::FileTypeInfo());
[email protected]ba70d082010-09-10 16:54:49236 if (accept_types.empty())
[email protected]479cce782012-09-15 20:15:53237 return base_file_type.Pass();
[email protected]ba70d082010-09-10 16:54:49238
[email protected]ba70d082010-09-10 16:54:49239 // Create FileTypeInfo and pre-allocate for the first extension list.
[email protected]92f54082012-07-31 01:43:14240 scoped_ptr<ui::SelectFileDialog::FileTypeInfo> file_type(
[email protected]479cce782012-09-15 20:15:53241 new ui::SelectFileDialog::FileTypeInfo(*base_file_type));
[email protected]ba70d082010-09-10 16:54:49242 file_type->include_all_files = true;
243 file_type->extensions.resize(1);
[email protected]650b2d52013-02-10 03:41:45244 std::vector<base::FilePath::StringType>* extensions =
245 &file_type->extensions.back();
[email protected]ba70d082010-09-10 16:54:49246
[email protected]f9a4c41a2012-05-30 00:05:32247 // Find the corresponding extensions.
[email protected]ba70d082010-09-10 16:54:49248 int valid_type_count = 0;
249 int description_id = 0;
[email protected]3314c2b12011-11-02 08:05:46250 for (size_t i = 0; i < accept_types.size(); ++i) {
[email protected]74f778e2014-03-14 21:11:46251 std::string ascii_type = base::UTF16ToASCII(accept_types[i]);
[email protected]f9a4c41a2012-05-30 00:05:32252 if (!IsAcceptTypeValid(ascii_type))
253 continue;
[email protected]ba70d082010-09-10 16:54:49254
255 size_t old_extension_size = extensions->size();
[email protected]f9a4c41a2012-05-30 00:05:32256 if (ascii_type[0] == '.') {
257 // If the type starts with a period it is assumed to be a file extension
258 // so we just have to add it to the list.
[email protected]650b2d52013-02-10 03:41:45259 base::FilePath::StringType ext(ascii_type.begin(), ascii_type.end());
[email protected]f9a4c41a2012-05-30 00:05:32260 extensions->push_back(ext.substr(1));
[email protected]ba70d082010-09-10 16:54:49261 } else {
[email protected]4a66fa0e2012-09-10 06:45:20262 if (ascii_type == "image/*")
263 description_id = IDS_IMAGE_FILES;
264 else if (ascii_type == "audio/*")
265 description_id = IDS_AUDIO_FILES;
266 else if (ascii_type == "video/*")
267 description_id = IDS_VIDEO_FILES;
268
[email protected]f9a4c41a2012-05-30 00:05:32269 net::GetExtensionsForMimeType(ascii_type, extensions);
[email protected]ba70d082010-09-10 16:54:49270 }
271
272 if (extensions->size() > old_extension_size)
273 valid_type_count++;
274 }
275
[email protected]cbcd12ed2010-12-16 23:42:57276 // If no valid extension is added, bail out.
277 if (valid_type_count == 0)
[email protected]479cce782012-09-15 20:15:53278 return base_file_type.Pass();
[email protected]cbcd12ed2010-12-16 23:42:57279
[email protected]ba70d082010-09-10 16:54:49280 // Use a generic description "Custom Files" if either of the following is
281 // true:
282 // 1) There're multiple types specified, like "audio/*,video/*"
283 // 2) There're multiple extensions for a MIME type without parameter, like
284 // "ehtml,shtml,htm,html" for "text/html". On Windows, the select file
285 // dialog uses the first extension in the list to form the description,
286 // like "EHTML Files". This is not what we want.
287 if (valid_type_count > 1 ||
288 (valid_type_count == 1 && description_id == 0 && extensions->size() > 1))
289 description_id = IDS_CUSTOM_FILES;
290
291 if (description_id) {
292 file_type->extension_description_overrides.push_back(
293 l10n_util::GetStringUTF16(description_id));
294 }
295
[email protected]479cce782012-09-15 20:15:53296 return file_type.Pass();
[email protected]ba70d082010-09-10 16:54:49297}
298
[email protected]33f8ad52012-05-22 18:10:13299// static
300void FileSelectHelper::RunFileChooser(content::WebContents* tab,
301 const FileChooserParams& params) {
302 Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext());
303 // FileSelectHelper will keep itself alive until it sends the result message.
304 scoped_refptr<FileSelectHelper> file_select_helper(
305 new FileSelectHelper(profile));
306 file_select_helper->RunFileChooser(tab->GetRenderViewHost(), tab, params);
307}
308
309// static
310void FileSelectHelper::EnumerateDirectory(content::WebContents* tab,
311 int request_id,
[email protected]650b2d52013-02-10 03:41:45312 const base::FilePath& path) {
[email protected]33f8ad52012-05-22 18:10:13313 Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext());
314 // FileSelectHelper will keep itself alive until it sends the result message.
315 scoped_refptr<FileSelectHelper> file_select_helper(
316 new FileSelectHelper(profile));
317 file_select_helper->EnumerateDirectory(
318 request_id, tab->GetRenderViewHost(), path);
319}
320
321void FileSelectHelper::RunFileChooser(RenderViewHost* render_view_host,
322 content::WebContents* web_contents,
323 const FileChooserParams& params) {
[email protected]ba70d082010-09-10 16:54:49324 DCHECK(!render_view_host_);
[email protected]ea049a02011-12-25 21:37:09325 DCHECK(!web_contents_);
[email protected]ba70d082010-09-10 16:54:49326 render_view_host_ = render_view_host;
[email protected]ea049a02011-12-25 21:37:09327 web_contents_ = web_contents;
[email protected]ba70d082010-09-10 16:54:49328 notification_registrar_.RemoveAll();
[email protected]432115822011-07-10 15:52:27329 notification_registrar_.Add(
330 this, content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED,
[email protected]6c2381d2011-10-19 02:52:53331 content::Source<RenderWidgetHost>(render_view_host_));
[email protected]9f054aa12011-09-29 19:13:45332 notification_registrar_.Add(
[email protected]ea049a02011-12-25 21:37:09333 this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
334 content::Source<WebContents>(web_contents_));
[email protected]9f054aa12011-09-29 19:13:45335
336 BrowserThread::PostTask(
337 BrowserThread::FILE, FROM_HERE,
338 base::Bind(&FileSelectHelper::RunFileChooserOnFileThread, this, params));
339
340 // Because this class returns notifications to the RenderViewHost, it is
341 // difficult for callers to know how long to keep a reference to this
342 // instance. We AddRef() here to keep the instance alive after we return
343 // to the caller, until the last callback is received from the file dialog.
344 // At that point, we must call RunFileChooserEnd().
345 AddRef();
346}
347
348void FileSelectHelper::RunFileChooserOnFileThread(
[email protected]33f8ad52012-05-22 18:10:13349 const FileChooserParams& params) {
[email protected]479cce782012-09-15 20:15:53350 select_file_types_ = GetFileTypesFromAcceptType(params.accept_types);
[email protected]9f054aa12011-09-29 19:13:45351
352 BrowserThread::PostTask(
353 BrowserThread::UI, FROM_HERE,
354 base::Bind(&FileSelectHelper::RunFileChooserOnUIThread, this, params));
355}
356
357void FileSelectHelper::RunFileChooserOnUIThread(
[email protected]33f8ad52012-05-22 18:10:13358 const FileChooserParams& params) {
[email protected]ea049a02011-12-25 21:37:09359 if (!render_view_host_ || !web_contents_) {
[email protected]b95b08d2011-12-15 20:23:16360 // If the renderer was destroyed before we started, just cancel the
361 // operation.
362 RunFileChooserEnd();
[email protected]9f054aa12011-09-29 19:13:45363 return;
[email protected]b95b08d2011-12-15 20:23:16364 }
[email protected]ba70d082010-09-10 16:54:49365
[email protected]92f54082012-07-31 01:43:14366 select_file_dialog_ = ui::SelectFileDialog::Create(
[email protected]6e1fcd12012-07-02 17:14:20367 this, new ChromeSelectFilePolicy(web_contents_));
dcheng319a21952014-08-26 22:52:40368 if (!select_file_dialog_.get())
[email protected]6910cb242014-03-20 14:33:01369 return;
[email protected]ba70d082010-09-10 16:54:49370
[email protected]bfcf1e92013-07-11 04:37:25371 dialog_mode_ = params.mode;
[email protected]ba70d082010-09-10 16:54:49372 switch (params.mode) {
[email protected]33f8ad52012-05-22 18:10:13373 case FileChooserParams::Open:
[email protected]92f54082012-07-31 01:43:14374 dialog_type_ = ui::SelectFileDialog::SELECT_OPEN_FILE;
[email protected]ba70d082010-09-10 16:54:49375 break;
[email protected]33f8ad52012-05-22 18:10:13376 case FileChooserParams::OpenMultiple:
[email protected]92f54082012-07-31 01:43:14377 dialog_type_ = ui::SelectFileDialog::SELECT_OPEN_MULTI_FILE;
[email protected]ba70d082010-09-10 16:54:49378 break;
[email protected]6bedbef2013-07-31 06:33:49379 case FileChooserParams::UploadFolder:
380 dialog_type_ = ui::SelectFileDialog::SELECT_UPLOAD_FOLDER;
[email protected]ba70d082010-09-10 16:54:49381 break;
[email protected]33f8ad52012-05-22 18:10:13382 case FileChooserParams::Save:
[email protected]92f54082012-07-31 01:43:14383 dialog_type_ = ui::SelectFileDialog::SELECT_SAVEAS_FILE;
[email protected]ba70d082010-09-10 16:54:49384 break;
385 default:
[email protected]92f54082012-07-31 01:43:14386 // Prevent warning.
387 dialog_type_ = ui::SelectFileDialog::SELECT_OPEN_FILE;
[email protected]ba70d082010-09-10 16:54:49388 NOTREACHED();
389 }
[email protected]4e9149a2012-08-15 20:43:59390
[email protected]650b2d52013-02-10 03:41:45391 base::FilePath default_file_name = params.default_file_name.IsAbsolute() ?
[email protected]4e9149a2012-08-15 20:43:59392 params.default_file_name :
393 profile_->last_selected_directory().Append(params.default_file_name);
[email protected]ba70d082010-09-10 16:54:49394
395 gfx::NativeWindow owning_window =
[email protected]9f76c1e2012-03-05 15:15:58396 platform_util::GetTopLevel(render_view_host_->GetView()->GetNativeView());
[email protected]d9898912011-04-15 21:10:00397
[email protected]2d02a2002012-09-18 21:47:56398#if defined(OS_ANDROID)
399 // Android needs the original MIME types and an additional capture value.
[email protected]d2065e062013-12-12 23:49:52400 std::pair<std::vector<base::string16>, bool> accept_types =
[email protected]b7b4beb2013-07-09 14:06:50401 std::make_pair(params.accept_types, params.capture);
[email protected]2d02a2002012-09-18 21:47:56402#endif
403
[email protected]9f054aa12011-09-29 19:13:45404 select_file_dialog_->SelectFile(
405 dialog_type_,
406 params.title,
407 default_file_name,
408 select_file_types_.get(),
[email protected]007b3f82013-04-09 08:46:45409 select_file_types_.get() && !select_file_types_->extensions.empty()
410 ? 1
411 : 0, // 1-based index of default extension to show.
412 base::FilePath::StringType(),
[email protected]9f054aa12011-09-29 19:13:45413 owning_window,
[email protected]b8452fa2012-06-15 01:41:41414#if defined(OS_ANDROID)
[email protected]2d02a2002012-09-18 21:47:56415 &accept_types);
[email protected]b8452fa2012-06-15 01:41:41416#else
[email protected]9f054aa12011-09-29 19:13:45417 NULL);
[email protected]b8452fa2012-06-15 01:41:41418#endif
[email protected]9f054aa12011-09-29 19:13:45419
420 select_file_types_.reset();
421}
422
423// 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
425// in RunFileChooser().
426void FileSelectHelper::RunFileChooserEnd() {
427 render_view_host_ = NULL;
[email protected]ea049a02011-12-25 21:37:09428 web_contents_ = NULL;
[email protected]9f054aa12011-09-29 19:13:45429 Release();
[email protected]ba70d082010-09-10 16:54:49430}
431
[email protected]600ea402011-04-12 00:01:51432void FileSelectHelper::EnumerateDirectory(int request_id,
433 RenderViewHost* render_view_host,
[email protected]650b2d52013-02-10 03:41:45434 const base::FilePath& path) {
[email protected]9f054aa12011-09-29 19:13:45435
436 // Because this class returns notifications to the RenderViewHost, it is
437 // difficult for callers to know how long to keep a reference to this
438 // instance. We AddRef() here to keep the instance alive after we return
439 // to the caller, until the last callback is received from the enumeration
440 // code. At that point, we must call EnumerateDirectoryEnd().
441 AddRef();
[email protected]600ea402011-04-12 00:01:51442 StartNewEnumeration(path, request_id, render_view_host);
443}
444
[email protected]9f054aa12011-09-29 19:13:45445// This method is called when we receive the last callback from the enumeration
446// code. Perform any cleanup and release the reference we added in
447// EnumerateDirectory().
448void FileSelectHelper::EnumerateDirectoryEnd() {
449 Release();
450}
451
[email protected]432115822011-07-10 15:52:27452void FileSelectHelper::Observe(int type,
[email protected]6c2381d2011-10-19 02:52:53453 const content::NotificationSource& source,
454 const content::NotificationDetails& details) {
[email protected]9f054aa12011-09-29 19:13:45455 switch (type) {
456 case content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED: {
[email protected]6c2381d2011-10-19 02:52:53457 DCHECK(content::Source<RenderWidgetHost>(source).ptr() ==
458 render_view_host_);
[email protected]9f054aa12011-09-29 19:13:45459 render_view_host_ = NULL;
460 break;
461 }
462
[email protected]ea049a02011-12-25 21:37:09463 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: {
464 DCHECK(content::Source<WebContents>(source).ptr() == web_contents_);
465 web_contents_ = NULL;
[email protected]9f054aa12011-09-29 19:13:45466 break;
467 }
468
469 default:
470 NOTREACHED();
471 }
[email protected]ba70d082010-09-10 16:54:49472}
[email protected]f9a4c41a2012-05-30 00:05:32473
474// static
475bool FileSelectHelper::IsAcceptTypeValid(const std::string& accept_type) {
476 // 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
478 // of an extension or a "/" in the case of a MIME type).
479 std::string unused;
480 if (accept_type.length() <= 1 ||
[email protected]cb1f4ac2014-08-07 16:55:42481 base::StringToLowerASCII(accept_type) != accept_type ||
[email protected]8af69c6c2014-03-03 19:05:31482 base::TrimWhitespaceASCII(accept_type, base::TRIM_ALL, &unused) !=
483 base::TRIM_NONE) {
[email protected]f9a4c41a2012-05-30 00:05:32484 return false;
485 }
486 return true;
487}