| Index: chrome/browser/file_select_helper.cc
|
| diff --git a/chrome/browser/file_select_helper.cc b/chrome/browser/file_select_helper.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..6ee0b737e4134d97afdc69a646980e9b820dd4d4
|
| --- /dev/null
|
| +++ b/chrome/browser/file_select_helper.cc
|
| @@ -0,0 +1,242 @@
|
| +// Copyright (c) 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/file_select_helper.h"
|
| +
|
| +#include "app/l10n_util.h"
|
| +#include "base/file_util.h"
|
| +#include "base/string_split.h"
|
| +#include "base/string_util.h"
|
| +#include "base/utf_string_conversions.h"
|
| +#include "net/base/mime_util.h"
|
| +#include "chrome/browser/platform_util.h"
|
| +#include "chrome/browser/profile.h"
|
| +#include "chrome/browser/renderer_host/render_view_host.h"
|
| +#include "chrome/browser/renderer_host/render_widget_host_view.h"
|
| +#include "chrome/browser/shell_dialogs.h"
|
| +#include "chrome/browser/tab_contents/tab_contents.h"
|
| +#include "chrome/browser/tab_contents/tab_contents_view.h"
|
| +#include "chrome/common/notification_details.h"
|
| +#include "chrome/common/notification_source.h"
|
| +#include "chrome/common/render_messages_params.h"
|
| +#include "grit/generated_resources.h"
|
| +
|
| +FileSelectHelper::FileSelectHelper(Profile* profile)
|
| + : profile_(profile),
|
| + render_view_host_(NULL),
|
| + select_file_dialog_(),
|
| + dialog_type_(SelectFileDialog::SELECT_OPEN_FILE) {
|
| +}
|
| +
|
| +FileSelectHelper::~FileSelectHelper() {
|
| + // There may be pending file dialogs, we need to tell them that we've gone
|
| + // away so they don't try and call back to us.
|
| + if (select_file_dialog_.get())
|
| + select_file_dialog_->ListenerDestroyed();
|
| +
|
| + // Stop any pending directory enumeration and prevent a callback.
|
| + if (directory_lister_.get()) {
|
| + directory_lister_->set_delegate(NULL);
|
| + directory_lister_->Cancel();
|
| + }
|
| +}
|
| +
|
| +void FileSelectHelper::FileSelected(const FilePath& path,
|
| + int index, void* params) {
|
| + if (!render_view_host_)
|
| + return;
|
| +
|
| + profile_->set_last_selected_directory(path.DirName());
|
| +
|
| + if (dialog_type_ == SelectFileDialog::SELECT_FOLDER) {
|
| + DirectorySelected(path);
|
| + return;
|
| + }
|
| +
|
| + std::vector<FilePath> files;
|
| + files.push_back(path);
|
| + render_view_host_->FilesSelectedInChooser(files);
|
| + // We are done with this showing of the dialog.
|
| + render_view_host_ = NULL;
|
| +}
|
| +
|
| +void FileSelectHelper::MultiFilesSelected(const std::vector<FilePath>& files,
|
| + void* params) {
|
| + if (!files.empty())
|
| + profile_->set_last_selected_directory(files[0].DirName());
|
| + if (!render_view_host_)
|
| + return;
|
| +
|
| + render_view_host_->FilesSelectedInChooser(files);
|
| + // We are done with this showing of the dialog.
|
| + render_view_host_ = NULL;
|
| +}
|
| +
|
| +void FileSelectHelper::FileSelectionCanceled(void* params) {
|
| + if (!render_view_host_)
|
| + return;
|
| +
|
| + // If the user cancels choosing a file to upload we pass back an
|
| + // empty vector.
|
| + render_view_host_->FilesSelectedInChooser(std::vector<FilePath>());
|
| +
|
| + // We are done with this showing of the dialog.
|
| + render_view_host_ = NULL;
|
| +}
|
| +
|
| +void FileSelectHelper::DirectorySelected(const FilePath& path) {
|
| + directory_lister_ = new net::DirectoryLister(path,
|
| + true,
|
| + net::DirectoryLister::NO_SORT,
|
| + this);
|
| + if (!directory_lister_->Start())
|
| + FileSelectionCanceled(NULL);
|
| +}
|
| +
|
| +void FileSelectHelper::OnListFile(
|
| + const net::DirectoryLister::DirectoryListerData& data) {
|
| + // Directory upload only cares about files. This util call just checks
|
| + // the flags in the structure; there's no file I/O going on.
|
| + if (file_util::FileEnumerator::IsDirectory(data.info))
|
| + return;
|
| +
|
| + directory_lister_results_.push_back(data.path);
|
| +}
|
| +
|
| +void FileSelectHelper::OnListDone(int error) {
|
| + if (!render_view_host_)
|
| + return;
|
| +
|
| + if (error) {
|
| + FileSelectionCanceled(NULL);
|
| + return;
|
| + }
|
| +
|
| + render_view_host_->FilesSelectedInChooser(directory_lister_results_);
|
| + render_view_host_ = NULL;
|
| + directory_lister_ = NULL;
|
| + directory_lister_results_.clear();
|
| +}
|
| +
|
| +SelectFileDialog::FileTypeInfo* FileSelectHelper::GetFileTypesFromAcceptType(
|
| + const string16& accept_types) {
|
| + if (accept_types.empty())
|
| + return NULL;
|
| +
|
| + // Split the accept-type string on commas.
|
| + std::vector<string16> mime_types;
|
| + base::SplitStringUsingSubstr(accept_types, ASCIIToUTF16(","), &mime_types);
|
| + if (mime_types.empty())
|
| + return NULL;
|
| +
|
| + // Create FileTypeInfo and pre-allocate for the first extension list.
|
| + scoped_ptr<SelectFileDialog::FileTypeInfo> file_type(
|
| + new SelectFileDialog::FileTypeInfo());
|
| + file_type->include_all_files = true;
|
| + file_type->extensions.resize(1);
|
| + std::vector<FilePath::StringType>* extensions = &file_type->extensions.back();
|
| +
|
| + // Find the correspondinge extensions.
|
| + int valid_type_count = 0;
|
| + int description_id = 0;
|
| + for (size_t i = 0; i < mime_types.size(); ++i) {
|
| + string16 mime_type = mime_types[i];
|
| + std::string ascii_mime_type = StringToLowerASCII(UTF16ToASCII(mime_type));
|
| +
|
| + TrimWhitespace(ascii_mime_type, TRIM_ALL, &ascii_mime_type);
|
| + if (ascii_mime_type.empty())
|
| + continue;
|
| +
|
| + size_t old_extension_size = extensions->size();
|
| + if (ascii_mime_type == "image/*") {
|
| + description_id = IDS_IMAGE_FILES;
|
| + net::GetImageExtensions(extensions);
|
| + } else if (ascii_mime_type == "audio/*") {
|
| + description_id = IDS_AUDIO_FILES;
|
| + net::GetAudioExtensions(extensions);
|
| + } else if (ascii_mime_type == "video/*") {
|
| + description_id = IDS_VIDEO_FILES;
|
| + net::GetVideoExtensions(extensions);
|
| + } else {
|
| + net::GetExtensionsForMimeType(ascii_mime_type, extensions);
|
| + }
|
| +
|
| + if (extensions->size() > old_extension_size)
|
| + valid_type_count++;
|
| + }
|
| +
|
| + // Use a generic description "Custom Files" if either of the following is
|
| + // true:
|
| + // 1) There're multiple types specified, like "audio/*,video/*"
|
| + // 2) There're multiple extensions for a MIME type without parameter, like
|
| + // "ehtml,shtml,htm,html" for "text/html". On Windows, the select file
|
| + // dialog uses the first extension in the list to form the description,
|
| + // like "EHTML Files". This is not what we want.
|
| + if (valid_type_count > 1 ||
|
| + (valid_type_count == 1 && description_id == 0 && extensions->size() > 1))
|
| + description_id = IDS_CUSTOM_FILES;
|
| +
|
| + if (description_id) {
|
| + file_type->extension_description_overrides.push_back(
|
| + l10n_util::GetStringUTF16(description_id));
|
| + }
|
| +
|
| + return file_type.release();
|
| +}
|
| +
|
| +void FileSelectHelper::RunFileChooser(
|
| + RenderViewHost* render_view_host,
|
| + const ViewHostMsg_RunFileChooser_Params ¶ms) {
|
| + DCHECK(!render_view_host_);
|
| + render_view_host_ = render_view_host;
|
| + notification_registrar_.RemoveAll();
|
| + notification_registrar_.Add(this,
|
| + NotificationType::RENDER_WIDGET_HOST_DESTROYED,
|
| + Source<RenderViewHost>(render_view_host));
|
| +
|
| + if (!select_file_dialog_.get())
|
| + select_file_dialog_ = SelectFileDialog::Create(this);
|
| +
|
| + switch (params.mode) {
|
| + case ViewHostMsg_RunFileChooser_Params::Open:
|
| + dialog_type_ = SelectFileDialog::SELECT_OPEN_FILE;
|
| + break;
|
| + case ViewHostMsg_RunFileChooser_Params::OpenMultiple:
|
| + dialog_type_ = SelectFileDialog::SELECT_OPEN_MULTI_FILE;
|
| + break;
|
| + case ViewHostMsg_RunFileChooser_Params::OpenFolder:
|
| + dialog_type_ = SelectFileDialog::SELECT_FOLDER;
|
| + break;
|
| + case ViewHostMsg_RunFileChooser_Params::Save:
|
| + dialog_type_ = SelectFileDialog::SELECT_SAVEAS_FILE;
|
| + break;
|
| + default:
|
| + dialog_type_ = SelectFileDialog::SELECT_OPEN_FILE; // Prevent warning.
|
| + NOTREACHED();
|
| + }
|
| + scoped_ptr<SelectFileDialog::FileTypeInfo> file_types(
|
| + GetFileTypesFromAcceptType(params.accept_types));
|
| + FilePath default_file_name = params.default_file_name;
|
| + if (default_file_name.empty())
|
| + default_file_name = profile_->last_selected_directory();
|
| +
|
| + gfx::NativeWindow owning_window =
|
| + platform_util::GetTopLevel(render_view_host_->view()->GetNativeView());
|
| + select_file_dialog_->SelectFile(dialog_type_,
|
| + params.title,
|
| + default_file_name,
|
| + file_types.get(),
|
| + 0,
|
| + FILE_PATH_LITERAL(""),
|
| + owning_window,
|
| + NULL);
|
| +}
|
| +
|
| +void FileSelectHelper::Observe(NotificationType type,
|
| + const NotificationSource& source,
|
| + const NotificationDetails& details) {
|
| + DCHECK(type == NotificationType::RENDER_WIDGET_HOST_DESTROYED);
|
| + DCHECK(Details<RenderViewHost>(details).ptr() == render_view_host_);
|
| + render_view_host_ = NULL;
|
| +}
|
|
|