blob: 8b66e522c2d1068ff62f6fef9ba126be0bd38cd7 [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>
8
[email protected]9f054aa12011-09-29 19:13:459#include "base/bind.h"
[email protected]ba70d082010-09-10 16:54:4910#include "base/file_util.h"
[email protected]459fba82011-10-13 02:48:5011#include "base/platform_file.h"
[email protected]ba70d082010-09-10 16:54:4912#include "base/string_split.h"
13#include "base/string_util.h"
14#include "base/utf_string_conversions.h"
[email protected]ba70d082010-09-10 16:54:4915#include "chrome/browser/platform_util.h"
[email protected]8ecad5e2010-12-02 21:18:3316#include "chrome/browser/profiles/profile.h"
[email protected]d9898912011-04-15 21:10:0017#include "chrome/browser/ui/browser.h"
18#include "chrome/browser/ui/browser_list.h"
[email protected]6e1fcd12012-07-02 17:14:2019#include "chrome/browser/ui/chrome_select_file_policy.h"
[email protected]6a1c98e02012-10-24 21:49:4320#include "content/public/browser/browser_thread.h"
[email protected]6c2381d2011-10-19 02:52:5321#include "content/public/browser/notification_details.h"
22#include "content/public/browser/notification_source.h"
[email protected]0d6e9bd2011-10-18 04:29:1623#include "content/public/browser/notification_types.h"
[email protected]9c1662b2012-03-06 15:44:3324#include "content/public/browser/render_view_host.h"
[email protected]5626b0892012-02-20 14:46:5825#include "content/public/browser/render_widget_host_view.h"
[email protected]33f8ad52012-05-22 18:10:1326#include "content/public/browser/web_contents.h"
[email protected]8caadeb2011-11-22 02:45:2327#include "content/public/common/file_chooser_params.h"
[email protected]ba70d082010-09-10 16:54:4928#include "grit/generated_resources.h"
[email protected]b3841c502011-03-09 01:21:3129#include "net/base/mime_util.h"
[email protected]ddb034b2012-06-26 20:31:3930#include "ui/base/dialogs/selected_file_info.h"
[email protected]c051a1b2011-01-21 23:30:1731#include "ui/base/l10n/l10n_util.h"
[email protected]ba70d082010-09-10 16:54:4932
[email protected]631bb742011-11-02 11:29:3933using content::BrowserThread;
[email protected]33f8ad52012-05-22 18:10:1334using content::FileChooserParams;
[email protected]eaabba22012-03-07 15:02:1135using content::RenderViewHost;
36using content::RenderWidgetHost;
[email protected]ea049a02011-12-25 21:37:0937using content::WebContents;
[email protected]631bb742011-11-02 11:29:3938
[email protected]600ea402011-04-12 00:01:5139namespace {
40
41// There is only one file-selection happening at any given time,
42// so we allocate an enumeration ID for that purpose. All IDs from
43// the renderer must start at 0 and increase.
[email protected]459fba82011-10-13 02:48:5044const int kFileSelectEnumerationId = -1;
45
46void NotifyRenderViewHost(RenderViewHost* render_view_host,
[email protected]ddb034b2012-06-26 20:31:3947 const std::vector<ui::SelectedFileInfo>& files,
[email protected]92f54082012-07-31 01:43:1448 ui::SelectFileDialog::Type dialog_type) {
[email protected]459fba82011-10-13 02:48:5049 const int kReadFilePermissions =
50 base::PLATFORM_FILE_OPEN |
51 base::PLATFORM_FILE_READ |
52 base::PLATFORM_FILE_EXCLUSIVE_READ |
53 base::PLATFORM_FILE_ASYNC;
54
55 const int kWriteFilePermissions =
[email protected]3c688fac2011-10-14 02:29:1456 base::PLATFORM_FILE_CREATE |
57 base::PLATFORM_FILE_CREATE_ALWAYS |
58 base::PLATFORM_FILE_OPEN |
[email protected]459fba82011-10-13 02:48:5059 base::PLATFORM_FILE_OPEN_ALWAYS |
[email protected]3c688fac2011-10-14 02:29:1460 base::PLATFORM_FILE_OPEN_TRUNCATED |
[email protected]459fba82011-10-13 02:48:5061 base::PLATFORM_FILE_WRITE |
62 base::PLATFORM_FILE_WRITE_ATTRIBUTES |
63 base::PLATFORM_FILE_ASYNC;
64
65 int permissions = kReadFilePermissions;
[email protected]92f54082012-07-31 01:43:1466 if (dialog_type == ui::SelectFileDialog::SELECT_SAVEAS_FILE)
[email protected]459fba82011-10-13 02:48:5067 permissions = kWriteFilePermissions;
68 render_view_host->FilesSelectedInChooser(files, permissions);
69}
[email protected]fb11b6a42012-03-14 07:25:1270
[email protected]53f04c82012-07-26 02:31:0971// Converts a list of FilePaths to a list of ui::SelectedFileInfo.
72std::vector<ui::SelectedFileInfo> FilePathListToSelectedFileInfoList(
[email protected]62ce65b32012-03-20 02:15:3673 const std::vector<FilePath>& paths) {
[email protected]ddb034b2012-06-26 20:31:3974 std::vector<ui::SelectedFileInfo> selected_files;
[email protected]fb11b6a42012-03-14 07:25:1275 for (size_t i = 0; i < paths.size(); ++i) {
76 selected_files.push_back(
[email protected]53f04c82012-07-26 02:31:0977 ui::SelectedFileInfo(paths[i], paths[i]));
[email protected]fb11b6a42012-03-14 07:25:1278 }
79 return selected_files;
[email protected]600ea402011-04-12 00:01:5180}
81
[email protected]fb11b6a42012-03-14 07:25:1282} // namespace
83
[email protected]485a5272011-04-12 00:49:2984struct FileSelectHelper::ActiveDirectoryEnumeration {
[email protected]d45f7512011-06-21 21:18:2785 ActiveDirectoryEnumeration() : rvh_(NULL) {}
[email protected]485a5272011-04-12 00:49:2986
87 scoped_ptr<DirectoryListerDispatchDelegate> delegate_;
[email protected]05a814182011-04-27 19:50:3488 scoped_ptr<net::DirectoryLister> lister_;
[email protected]485a5272011-04-12 00:49:2989 RenderViewHost* rvh_;
90 std::vector<FilePath> results_;
91};
92
[email protected]ba70d082010-09-10 16:54:4993FileSelectHelper::FileSelectHelper(Profile* profile)
94 : profile_(profile),
95 render_view_host_(NULL),
[email protected]ea049a02011-12-25 21:37:0996 web_contents_(NULL),
[email protected]ba70d082010-09-10 16:54:4997 select_file_dialog_(),
[email protected]9f054aa12011-09-29 19:13:4598 select_file_types_(),
[email protected]92f54082012-07-31 01:43:1499 dialog_type_(ui::SelectFileDialog::SELECT_OPEN_FILE) {
[email protected]ba70d082010-09-10 16:54:49100}
101
102FileSelectHelper::~FileSelectHelper() {
103 // There may be pending file dialogs, we need to tell them that we've gone
104 // away so they don't try and call back to us.
105 if (select_file_dialog_.get())
106 select_file_dialog_->ListenerDestroyed();
107
[email protected]600ea402011-04-12 00:01:51108 // Stop any pending directory enumeration, prevent a callback, and free
109 // allocated memory.
110 std::map<int, ActiveDirectoryEnumeration*>::iterator iter;
111 for (iter = directory_enumerations_.begin();
112 iter != directory_enumerations_.end();
113 ++iter) {
[email protected]05a814182011-04-27 19:50:34114 iter->second->lister_.reset();
[email protected]600ea402011-04-12 00:01:51115 delete iter->second;
[email protected]ba70d082010-09-10 16:54:49116 }
117}
118
[email protected]23827ec2012-08-10 22:08:08119void FileSelectHelper::DirectoryListerDispatchDelegate::OnListFile(
120 const net::DirectoryLister::DirectoryListerData& data) {
121 parent_->OnListFile(id_, data);
122}
123
124void FileSelectHelper::DirectoryListerDispatchDelegate::OnListDone(int error) {
125 parent_->OnListDone(id_, error);
126}
127
[email protected]ba70d082010-09-10 16:54:49128void FileSelectHelper::FileSelected(const FilePath& path,
129 int index, void* params) {
[email protected]53f04c82012-07-26 02:31:09130 FileSelectedWithExtraInfo(ui::SelectedFileInfo(path, path), index, params);
[email protected]fb11b6a42012-03-14 07:25:12131}
132
133void FileSelectHelper::FileSelectedWithExtraInfo(
[email protected]ddb034b2012-06-26 20:31:39134 const ui::SelectedFileInfo& file,
[email protected]fb11b6a42012-03-14 07:25:12135 int index,
136 void* params) {
[email protected]ba70d082010-09-10 16:54:49137 if (!render_view_host_)
138 return;
139
[email protected]53f04c82012-07-26 02:31:09140 profile_->set_last_selected_directory(file.file_path.DirName());
[email protected]ba70d082010-09-10 16:54:49141
[email protected]53f04c82012-07-26 02:31:09142 const FilePath& path = file.local_path;
[email protected]92f54082012-07-31 01:43:14143 if (dialog_type_ == ui::SelectFileDialog::SELECT_FOLDER) {
[email protected]600ea402011-04-12 00:01:51144 StartNewEnumeration(path, kFileSelectEnumerationId, render_view_host_);
[email protected]ba70d082010-09-10 16:54:49145 return;
146 }
147
[email protected]ddb034b2012-06-26 20:31:39148 std::vector<ui::SelectedFileInfo> files;
[email protected]fb11b6a42012-03-14 07:25:12149 files.push_back(file);
[email protected]459fba82011-10-13 02:48:50150 NotifyRenderViewHost(render_view_host_, files, dialog_type_);
[email protected]9f054aa12011-09-29 19:13:45151
[email protected]3a29a6e2011-08-24 18:26:21152 // No members should be accessed from here on.
[email protected]9f054aa12011-09-29 19:13:45153 RunFileChooserEnd();
[email protected]ba70d082010-09-10 16:54:49154}
155
156void FileSelectHelper::MultiFilesSelected(const std::vector<FilePath>& files,
157 void* params) {
[email protected]ddb034b2012-06-26 20:31:39158 std::vector<ui::SelectedFileInfo> selected_files =
[email protected]53f04c82012-07-26 02:31:09159 FilePathListToSelectedFileInfoList(files);
160
[email protected]fb11b6a42012-03-14 07:25:12161 MultiFilesSelectedWithExtraInfo(selected_files, params);
162}
163
164void FileSelectHelper::MultiFilesSelectedWithExtraInfo(
[email protected]ddb034b2012-06-26 20:31:39165 const std::vector<ui::SelectedFileInfo>& files,
[email protected]fb11b6a42012-03-14 07:25:12166 void* params) {
[email protected]ba70d082010-09-10 16:54:49167 if (!files.empty())
[email protected]53f04c82012-07-26 02:31:09168 profile_->set_last_selected_directory(files[0].file_path.DirName());
[email protected]ba70d082010-09-10 16:54:49169 if (!render_view_host_)
170 return;
171
[email protected]459fba82011-10-13 02:48:50172 NotifyRenderViewHost(render_view_host_, files, dialog_type_);
[email protected]9f054aa12011-09-29 19:13:45173
[email protected]3a29a6e2011-08-24 18:26:21174 // No members should be accessed from here on.
[email protected]9f054aa12011-09-29 19:13:45175 RunFileChooserEnd();
[email protected]ba70d082010-09-10 16:54:49176}
177
178void FileSelectHelper::FileSelectionCanceled(void* params) {
179 if (!render_view_host_)
180 return;
181
182 // If the user cancels choosing a file to upload we pass back an
183 // empty vector.
[email protected]459fba82011-10-13 02:48:50184 NotifyRenderViewHost(
[email protected]ddb034b2012-06-26 20:31:39185 render_view_host_, std::vector<ui::SelectedFileInfo>(),
[email protected]fb11b6a42012-03-14 07:25:12186 dialog_type_);
[email protected]ba70d082010-09-10 16:54:49187
[email protected]3a29a6e2011-08-24 18:26:21188 // No members should be accessed from here on.
[email protected]9f054aa12011-09-29 19:13:45189 RunFileChooserEnd();
[email protected]ba70d082010-09-10 16:54:49190}
191
[email protected]600ea402011-04-12 00:01:51192void FileSelectHelper::StartNewEnumeration(const FilePath& path,
193 int request_id,
194 RenderViewHost* render_view_host) {
195 scoped_ptr<ActiveDirectoryEnumeration> entry(new ActiveDirectoryEnumeration);
196 entry->rvh_ = render_view_host;
197 entry->delegate_.reset(new DirectoryListerDispatchDelegate(this, request_id));
[email protected]05a814182011-04-27 19:50:34198 entry->lister_.reset(new net::DirectoryLister(path,
199 true,
200 net::DirectoryLister::NO_SORT,
201 entry->delegate_.get()));
[email protected]600ea402011-04-12 00:01:51202 if (!entry->lister_->Start()) {
203 if (request_id == kFileSelectEnumerationId)
204 FileSelectionCanceled(NULL);
205 else
206 render_view_host->DirectoryEnumerationFinished(request_id,
207 entry->results_);
208 } else {
209 directory_enumerations_[request_id] = entry.release();
210 }
[email protected]ba70d082010-09-10 16:54:49211}
212
213void FileSelectHelper::OnListFile(
[email protected]600ea402011-04-12 00:01:51214 int id,
[email protected]ba70d082010-09-10 16:54:49215 const net::DirectoryLister::DirectoryListerData& data) {
[email protected]600ea402011-04-12 00:01:51216 ActiveDirectoryEnumeration* entry = directory_enumerations_[id];
217
[email protected]9897e092011-02-04 22:09:11218 // Directory upload returns directories via a "." file, so that
219 // empty directories are included. This util call just checks
[email protected]ba70d082010-09-10 16:54:49220 // the flags in the structure; there's no file I/O going on.
221 if (file_util::FileEnumerator::IsDirectory(data.info))
[email protected]600ea402011-04-12 00:01:51222 entry->results_.push_back(data.path.Append(FILE_PATH_LITERAL(".")));
[email protected]9897e092011-02-04 22:09:11223 else
[email protected]600ea402011-04-12 00:01:51224 entry->results_.push_back(data.path);
[email protected]ba70d082010-09-10 16:54:49225}
226
[email protected]600ea402011-04-12 00:01:51227void FileSelectHelper::OnListDone(int id, int error) {
228 // This entry needs to be cleaned up when this function is done.
229 scoped_ptr<ActiveDirectoryEnumeration> entry(directory_enumerations_[id]);
230 directory_enumerations_.erase(id);
231 if (!entry->rvh_)
[email protected]ba70d082010-09-10 16:54:49232 return;
[email protected]ba70d082010-09-10 16:54:49233 if (error) {
234 FileSelectionCanceled(NULL);
235 return;
236 }
[email protected]fb11b6a42012-03-14 07:25:12237
[email protected]ddb034b2012-06-26 20:31:39238 std::vector<ui::SelectedFileInfo> selected_files =
[email protected]53f04c82012-07-26 02:31:09239 FilePathListToSelectedFileInfoList(entry->results_);
[email protected]fb11b6a42012-03-14 07:25:12240
[email protected]600ea402011-04-12 00:01:51241 if (id == kFileSelectEnumerationId)
[email protected]fb11b6a42012-03-14 07:25:12242 NotifyRenderViewHost(entry->rvh_, selected_files, dialog_type_);
[email protected]600ea402011-04-12 00:01:51243 else
244 entry->rvh_->DirectoryEnumerationFinished(id, entry->results_);
[email protected]9f054aa12011-09-29 19:13:45245
246 EnumerateDirectoryEnd();
[email protected]ba70d082010-09-10 16:54:49247}
248
[email protected]479cce782012-09-15 20:15:53249scoped_ptr<ui::SelectFileDialog::FileTypeInfo>
[email protected]92f54082012-07-31 01:43:14250FileSelectHelper::GetFileTypesFromAcceptType(
[email protected]3314c2b12011-11-02 08:05:46251 const std::vector<string16>& accept_types) {
[email protected]479cce782012-09-15 20:15:53252 scoped_ptr<ui::SelectFileDialog::FileTypeInfo> base_file_type(
253 new ui::SelectFileDialog::FileTypeInfo());
254 base_file_type->support_gdata = true;
[email protected]ba70d082010-09-10 16:54:49255 if (accept_types.empty())
[email protected]479cce782012-09-15 20:15:53256 return base_file_type.Pass();
[email protected]ba70d082010-09-10 16:54:49257
[email protected]ba70d082010-09-10 16:54:49258 // Create FileTypeInfo and pre-allocate for the first extension list.
[email protected]92f54082012-07-31 01:43:14259 scoped_ptr<ui::SelectFileDialog::FileTypeInfo> file_type(
[email protected]479cce782012-09-15 20:15:53260 new ui::SelectFileDialog::FileTypeInfo(*base_file_type));
[email protected]ba70d082010-09-10 16:54:49261 file_type->include_all_files = true;
262 file_type->extensions.resize(1);
263 std::vector<FilePath::StringType>* extensions = &file_type->extensions.back();
264
[email protected]f9a4c41a2012-05-30 00:05:32265 // Find the corresponding extensions.
[email protected]ba70d082010-09-10 16:54:49266 int valid_type_count = 0;
267 int description_id = 0;
[email protected]3314c2b12011-11-02 08:05:46268 for (size_t i = 0; i < accept_types.size(); ++i) {
[email protected]f9a4c41a2012-05-30 00:05:32269 std::string ascii_type = UTF16ToASCII(accept_types[i]);
270 if (!IsAcceptTypeValid(ascii_type))
271 continue;
[email protected]ba70d082010-09-10 16:54:49272
273 size_t old_extension_size = extensions->size();
[email protected]f9a4c41a2012-05-30 00:05:32274 if (ascii_type[0] == '.') {
275 // If the type starts with a period it is assumed to be a file extension
276 // so we just have to add it to the list.
277 FilePath::StringType ext(ascii_type.begin(), ascii_type.end());
278 extensions->push_back(ext.substr(1));
[email protected]ba70d082010-09-10 16:54:49279 } else {
[email protected]4a66fa0e2012-09-10 06:45:20280 if (ascii_type == "image/*")
281 description_id = IDS_IMAGE_FILES;
282 else if (ascii_type == "audio/*")
283 description_id = IDS_AUDIO_FILES;
284 else if (ascii_type == "video/*")
285 description_id = IDS_VIDEO_FILES;
286
[email protected]f9a4c41a2012-05-30 00:05:32287 net::GetExtensionsForMimeType(ascii_type, extensions);
[email protected]ba70d082010-09-10 16:54:49288 }
289
290 if (extensions->size() > old_extension_size)
291 valid_type_count++;
292 }
293
[email protected]cbcd12ed2010-12-16 23:42:57294 // If no valid extension is added, bail out.
295 if (valid_type_count == 0)
[email protected]479cce782012-09-15 20:15:53296 return base_file_type.Pass();
[email protected]cbcd12ed2010-12-16 23:42:57297
[email protected]ba70d082010-09-10 16:54:49298 // Use a generic description "Custom Files" if either of the following is
299 // true:
300 // 1) There're multiple types specified, like "audio/*,video/*"
301 // 2) There're multiple extensions for a MIME type without parameter, like
302 // "ehtml,shtml,htm,html" for "text/html". On Windows, the select file
303 // dialog uses the first extension in the list to form the description,
304 // like "EHTML Files". This is not what we want.
305 if (valid_type_count > 1 ||
306 (valid_type_count == 1 && description_id == 0 && extensions->size() > 1))
307 description_id = IDS_CUSTOM_FILES;
308
309 if (description_id) {
310 file_type->extension_description_overrides.push_back(
311 l10n_util::GetStringUTF16(description_id));
312 }
313
[email protected]479cce782012-09-15 20:15:53314 return file_type.Pass();
[email protected]ba70d082010-09-10 16:54:49315}
316
[email protected]33f8ad52012-05-22 18:10:13317// static
318void FileSelectHelper::RunFileChooser(content::WebContents* tab,
319 const FileChooserParams& params) {
320 Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext());
321 // FileSelectHelper will keep itself alive until it sends the result message.
322 scoped_refptr<FileSelectHelper> file_select_helper(
323 new FileSelectHelper(profile));
324 file_select_helper->RunFileChooser(tab->GetRenderViewHost(), tab, params);
325}
326
327// static
328void FileSelectHelper::EnumerateDirectory(content::WebContents* tab,
329 int request_id,
330 const FilePath& path) {
331 Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext());
332 // FileSelectHelper will keep itself alive until it sends the result message.
333 scoped_refptr<FileSelectHelper> file_select_helper(
334 new FileSelectHelper(profile));
335 file_select_helper->EnumerateDirectory(
336 request_id, tab->GetRenderViewHost(), path);
337}
338
339void FileSelectHelper::RunFileChooser(RenderViewHost* render_view_host,
340 content::WebContents* web_contents,
341 const FileChooserParams& params) {
[email protected]ba70d082010-09-10 16:54:49342 DCHECK(!render_view_host_);
[email protected]ea049a02011-12-25 21:37:09343 DCHECK(!web_contents_);
[email protected]ba70d082010-09-10 16:54:49344 render_view_host_ = render_view_host;
[email protected]ea049a02011-12-25 21:37:09345 web_contents_ = web_contents;
[email protected]ba70d082010-09-10 16:54:49346 notification_registrar_.RemoveAll();
[email protected]432115822011-07-10 15:52:27347 notification_registrar_.Add(
348 this, content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED,
[email protected]6c2381d2011-10-19 02:52:53349 content::Source<RenderWidgetHost>(render_view_host_));
[email protected]9f054aa12011-09-29 19:13:45350 notification_registrar_.Add(
[email protected]ea049a02011-12-25 21:37:09351 this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
352 content::Source<WebContents>(web_contents_));
[email protected]9f054aa12011-09-29 19:13:45353
354 BrowserThread::PostTask(
355 BrowserThread::FILE, FROM_HERE,
356 base::Bind(&FileSelectHelper::RunFileChooserOnFileThread, this, params));
357
358 // Because this class returns notifications to the RenderViewHost, it is
359 // difficult for callers to know how long to keep a reference to this
360 // instance. We AddRef() here to keep the instance alive after we return
361 // to the caller, until the last callback is received from the file dialog.
362 // At that point, we must call RunFileChooserEnd().
363 AddRef();
364}
365
366void FileSelectHelper::RunFileChooserOnFileThread(
[email protected]33f8ad52012-05-22 18:10:13367 const FileChooserParams& params) {
[email protected]479cce782012-09-15 20:15:53368 select_file_types_ = GetFileTypesFromAcceptType(params.accept_types);
[email protected]9f054aa12011-09-29 19:13:45369
370 BrowserThread::PostTask(
371 BrowserThread::UI, FROM_HERE,
372 base::Bind(&FileSelectHelper::RunFileChooserOnUIThread, this, params));
373}
374
375void FileSelectHelper::RunFileChooserOnUIThread(
[email protected]33f8ad52012-05-22 18:10:13376 const FileChooserParams& params) {
[email protected]ea049a02011-12-25 21:37:09377 if (!render_view_host_ || !web_contents_) {
[email protected]b95b08d2011-12-15 20:23:16378 // If the renderer was destroyed before we started, just cancel the
379 // operation.
380 RunFileChooserEnd();
[email protected]9f054aa12011-09-29 19:13:45381 return;
[email protected]b95b08d2011-12-15 20:23:16382 }
[email protected]ba70d082010-09-10 16:54:49383
[email protected]92f54082012-07-31 01:43:14384 select_file_dialog_ = ui::SelectFileDialog::Create(
[email protected]6e1fcd12012-07-02 17:14:20385 this, new ChromeSelectFilePolicy(web_contents_));
[email protected]ba70d082010-09-10 16:54:49386
387 switch (params.mode) {
[email protected]33f8ad52012-05-22 18:10:13388 case FileChooserParams::Open:
[email protected]92f54082012-07-31 01:43:14389 dialog_type_ = ui::SelectFileDialog::SELECT_OPEN_FILE;
[email protected]ba70d082010-09-10 16:54:49390 break;
[email protected]33f8ad52012-05-22 18:10:13391 case FileChooserParams::OpenMultiple:
[email protected]92f54082012-07-31 01:43:14392 dialog_type_ = ui::SelectFileDialog::SELECT_OPEN_MULTI_FILE;
[email protected]ba70d082010-09-10 16:54:49393 break;
[email protected]33f8ad52012-05-22 18:10:13394 case FileChooserParams::OpenFolder:
[email protected]92f54082012-07-31 01:43:14395 dialog_type_ = ui::SelectFileDialog::SELECT_FOLDER;
[email protected]ba70d082010-09-10 16:54:49396 break;
[email protected]33f8ad52012-05-22 18:10:13397 case FileChooserParams::Save:
[email protected]92f54082012-07-31 01:43:14398 dialog_type_ = ui::SelectFileDialog::SELECT_SAVEAS_FILE;
[email protected]ba70d082010-09-10 16:54:49399 break;
400 default:
[email protected]92f54082012-07-31 01:43:14401 // Prevent warning.
402 dialog_type_ = ui::SelectFileDialog::SELECT_OPEN_FILE;
[email protected]ba70d082010-09-10 16:54:49403 NOTREACHED();
404 }
[email protected]4e9149a2012-08-15 20:43:59405
406 FilePath default_file_name = params.default_file_name.IsAbsolute() ?
407 params.default_file_name :
408 profile_->last_selected_directory().Append(params.default_file_name);
[email protected]ba70d082010-09-10 16:54:49409
410 gfx::NativeWindow owning_window =
[email protected]9f76c1e2012-03-05 15:15:58411 platform_util::GetTopLevel(render_view_host_->GetView()->GetNativeView());
[email protected]d9898912011-04-15 21:10:00412
[email protected]2d02a2002012-09-18 21:47:56413#if defined(OS_ANDROID)
414 // Android needs the original MIME types and an additional capture value.
415 std::vector<string16> accept_types(params.accept_types);
416 accept_types.push_back(params.capture);
417#endif
418
[email protected]9f054aa12011-09-29 19:13:45419 select_file_dialog_->SelectFile(
420 dialog_type_,
421 params.title,
422 default_file_name,
423 select_file_types_.get(),
[email protected]479cce782012-09-15 20:15:53424 select_file_types_.get() && !select_file_types_->extensions.empty() ?
425 1 : 0, // 1-based index of default extension to show.
[email protected]9f054aa12011-09-29 19:13:45426 FILE_PATH_LITERAL(""),
[email protected]9f054aa12011-09-29 19:13:45427 owning_window,
[email protected]b8452fa2012-06-15 01:41:41428#if defined(OS_ANDROID)
[email protected]2d02a2002012-09-18 21:47:56429 &accept_types);
[email protected]b8452fa2012-06-15 01:41:41430#else
[email protected]9f054aa12011-09-29 19:13:45431 NULL);
[email protected]b8452fa2012-06-15 01:41:41432#endif
[email protected]9f054aa12011-09-29 19:13:45433
434 select_file_types_.reset();
435}
436
437// This method is called when we receive the last callback from the file
438// chooser dialog. Perform any cleanup and release the reference we added
439// in RunFileChooser().
440void FileSelectHelper::RunFileChooserEnd() {
441 render_view_host_ = NULL;
[email protected]ea049a02011-12-25 21:37:09442 web_contents_ = NULL;
[email protected]9f054aa12011-09-29 19:13:45443 Release();
[email protected]ba70d082010-09-10 16:54:49444}
445
[email protected]600ea402011-04-12 00:01:51446void FileSelectHelper::EnumerateDirectory(int request_id,
447 RenderViewHost* render_view_host,
448 const FilePath& path) {
[email protected]9f054aa12011-09-29 19:13:45449
450 // Because this class returns notifications to the RenderViewHost, it is
451 // difficult for callers to know how long to keep a reference to this
452 // instance. We AddRef() here to keep the instance alive after we return
453 // to the caller, until the last callback is received from the enumeration
454 // code. At that point, we must call EnumerateDirectoryEnd().
455 AddRef();
[email protected]600ea402011-04-12 00:01:51456 StartNewEnumeration(path, request_id, render_view_host);
457}
458
[email protected]9f054aa12011-09-29 19:13:45459// This method is called when we receive the last callback from the enumeration
460// code. Perform any cleanup and release the reference we added in
461// EnumerateDirectory().
462void FileSelectHelper::EnumerateDirectoryEnd() {
463 Release();
464}
465
[email protected]432115822011-07-10 15:52:27466void FileSelectHelper::Observe(int type,
[email protected]6c2381d2011-10-19 02:52:53467 const content::NotificationSource& source,
468 const content::NotificationDetails& details) {
[email protected]9f054aa12011-09-29 19:13:45469 switch (type) {
470 case content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED: {
[email protected]6c2381d2011-10-19 02:52:53471 DCHECK(content::Source<RenderWidgetHost>(source).ptr() ==
472 render_view_host_);
[email protected]9f054aa12011-09-29 19:13:45473 render_view_host_ = NULL;
474 break;
475 }
476
[email protected]ea049a02011-12-25 21:37:09477 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: {
478 DCHECK(content::Source<WebContents>(source).ptr() == web_contents_);
479 web_contents_ = NULL;
[email protected]9f054aa12011-09-29 19:13:45480 break;
481 }
482
483 default:
484 NOTREACHED();
485 }
[email protected]ba70d082010-09-10 16:54:49486}
[email protected]f9a4c41a2012-05-30 00:05:32487
488// static
489bool FileSelectHelper::IsAcceptTypeValid(const std::string& accept_type) {
490 // TODO(raymes): This only does some basic checks, extend to test more cases.
491 // A 1 character accept type will always be invalid (either a "." in the case
492 // of an extension or a "/" in the case of a MIME type).
493 std::string unused;
494 if (accept_type.length() <= 1 ||
495 StringToLowerASCII(accept_type) != accept_type ||
496 TrimWhitespaceASCII(accept_type, TRIM_ALL, &unused) != TRIM_NONE) {
497 return false;
498 }
499 return true;
500}