diff options
author | jcivelli@chromium.org <jcivelli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-10 16:54:49 +0000 |
---|---|---|
committer | jcivelli@chromium.org <jcivelli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-10 16:54:49 +0000 |
commit | ba70d082593f9e20ab059b7f09495d94c0856005 (patch) | |
tree | e56ce8065866ebde7de1ad8137b2fe2ccc7cf8c2 /chrome | |
parent | ba62fbd428232eee1815d4b4d63fc65cb3ead566 (diff) | |
download | chromium_src-ba70d082593f9e20ab059b7f09495d94c0856005.zip chromium_src-ba70d082593f9e20ab059b7f09495d94c0856005.tar.gz chromium_src-ba70d082593f9e20ab059b7f09495d94c0856005.tar.bz2 |
Input file type now supported in extension popups.
To do this, this CL generalize the TabContentsFileSelectHelper (renamed FileSelectHelper) so it is associated with a RenderViewHost rather than a TabContents.
This allows the extension popups which don't use a TabContents to use it.
As part of that, I also moved GetTopLevelNativeWindow() from TabContentsView to TabContent, as it can be implemented in a non-platform specific way.
BUG=28829
TEST=Make sure you can still open file on web pages (such as http://www.cs.tut.fi/~jkorpela/forms/file.html.
Create an extension with a popup that contains an input file tag. Make sure it does open a file dialog and lets you choose a file.
Review URL: http://codereview.chromium.org/3209002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@59105 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/extensions/extension_host.cc | 7 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_host.h | 5 | ||||
-rw-r--r-- | chrome/browser/file_select_helper.cc | 242 | ||||
-rw-r--r-- | chrome/browser/file_select_helper.h (renamed from chrome/browser/tab_contents/tab_contents_file_select_helper.h) | 42 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_view_host.cc | 2 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_view_host_delegate.h | 1 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents.cc | 4 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents.h | 6 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 4 |
9 files changed, 289 insertions, 24 deletions
diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc index ba74da8..13619ff 100644 --- a/chrome/browser/extensions/extension_host.cc +++ b/chrome/browser/extensions/extension_host.cc @@ -22,6 +22,7 @@ #include "chrome/browser/extensions/extension_message_service.h" #include "chrome/browser/extensions/extension_tabs_module.h" #include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/file_select_helper.h" #include "chrome/browser/in_process_webkit/dom_storage_context.h" #include "chrome/browser/in_process_webkit/webkit_context.h" #include "chrome/browser/message_box_handler.h" @@ -677,6 +678,12 @@ void ExtensionHost::RenderViewCreated(RenderViewHost* render_view_host) { } } +RenderViewHostDelegate::FileSelect* ExtensionHost::GetFileSelectDelegate() { + if (file_select_helper_.get() == NULL) + file_select_helper_.reset(new FileSelectHelper(profile())); + return file_select_helper_.get(); +} + int ExtensionHost::GetBrowserWindowID() const { // Hosts not attached to any browser window have an id of -1. This includes // those mentioned below, and background pages. diff --git a/chrome/browser/extensions/extension_host.h b/chrome/browser/extensions/extension_host.h index 0148dfa..80dbf14 100644 --- a/chrome/browser/extensions/extension_host.h +++ b/chrome/browser/extensions/extension_host.h @@ -26,6 +26,7 @@ class Browser; class Extension; +class FileSelectHelper; class RenderProcessHost; class RenderWidgetHostView; class TabContents; @@ -115,6 +116,7 @@ class ExtensionHost : public RenderViewHostDelegate, virtual const GURL& GetURL() const { return url_; } virtual void RenderViewCreated(RenderViewHost* render_view_host); virtual ViewType::Type GetRenderViewType() const; + virtual FileSelect* GetFileSelectDelegate(); virtual int GetBrowserWindowID() const; virtual void RenderViewGone(RenderViewHost* render_view_host); virtual void DidNavigate(RenderViewHost* render_view_host, @@ -268,6 +270,9 @@ class ExtensionHost : public RenderViewHostDelegate, // Used to measure how long it's been since the host was created. PerfTimer since_created_; + // FileSelectHelper, lazily created. + scoped_ptr<FileSelectHelper> file_select_helper_; + DISALLOW_COPY_AND_ASSIGN(ExtensionHost); }; diff --git a/chrome/browser/file_select_helper.cc b/chrome/browser/file_select_helper.cc new file mode 100644 index 0000000..6ee0b73 --- /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; +} diff --git a/chrome/browser/tab_contents/tab_contents_file_select_helper.h b/chrome/browser/file_select_helper.h index e8e9b43..ba8441b 100644 --- a/chrome/browser/tab_contents/tab_contents_file_select_helper.h +++ b/chrome/browser/file_select_helper.h @@ -2,28 +2,30 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_TAB_CONTENTS_TAB_CONTENTS_FILE_SELECT_HELPER_H_ -#define CHROME_BROWSER_TAB_CONTENTS_TAB_CONTENTS_FILE_SELECT_HELPER_H_ +#ifndef CHROME_BROWSER_FILE_SELECT_HELPER_H_ +#define CHROME_BROWSER_FILE_SELECT_HELPER_H_ #pragma once #include <vector> #include "chrome/browser/shell_dialogs.h" #include "chrome/browser/renderer_host/render_view_host_delegate.h" +#include "chrome/common/notification_observer.h" +#include "chrome/common/notification_registrar.h" #include "net/base/directory_lister.h" +class Profile; class RenderViewHost; -class TabContents; struct ViewHostMsg_RunFileChooser_Params; -class TabContentsFileSelectHelper +class FileSelectHelper : public SelectFileDialog::Listener, public net::DirectoryLister::DirectoryListerDelegate, - public RenderViewHostDelegate::FileSelect { + public RenderViewHostDelegate::FileSelect, + public NotificationObserver { public: - explicit TabContentsFileSelectHelper(TabContents* tab_contents); - - ~TabContentsFileSelectHelper(); + explicit FileSelectHelper(Profile* profile); + ~FileSelectHelper(); // SelectFileDialog::Listener virtual void FileSelected(const FilePath& path, int index, void* params); @@ -37,11 +39,14 @@ class TabContentsFileSelectHelper virtual void OnListDone(int error); // RenderViewHostDelegate::FileSelect - virtual void RunFileChooser(const ViewHostMsg_RunFileChooser_Params& params); + virtual void RunFileChooser(RenderViewHost* render_view_host, + const ViewHostMsg_RunFileChooser_Params& params); private: - // Returns the RenderViewHost of tab_contents_. - RenderViewHost* GetRenderViewHost(); + // NotificationObserver implementation. + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); // Helper method for handling the SelectFileDialog::Listener callbacks. void DirectorySelected(const FilePath& path); @@ -52,9 +57,11 @@ class TabContentsFileSelectHelper SelectFileDialog::FileTypeInfo* GetFileTypesFromAcceptType( const string16& accept_types); - // The tab contents this class is helping. |tab_contents_| owns this object, - // so this pointer is guaranteed to be valid. - TabContents* tab_contents_; + // Profile used to set/retrieve the last used directory. + Profile* profile_; + + // The RenderViewHost for the page we are associated with. + RenderViewHost* render_view_host_; // Dialog box used for choosing files to upload from file form fields. scoped_refptr<SelectFileDialog> select_file_dialog_; @@ -69,7 +76,10 @@ class TabContentsFileSelectHelper // as the listing proceeds. std::vector<FilePath> directory_lister_results_; - DISALLOW_COPY_AND_ASSIGN(TabContentsFileSelectHelper); + // Registrar for notifications regarding our RenderViewHost. + NotificationRegistrar notification_registrar_; + + DISALLOW_COPY_AND_ASSIGN(FileSelectHelper); }; -#endif // CHROME_BROWSER_TAB_CONTENTS_TAB_CONTENTS_FILE_SELECT_HELPER_H_ +#endif // CHROME_BROWSER_FILE_SELECT_HELPER_H_ diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc index 4152008..9d06007 100644 --- a/chrome/browser/renderer_host/render_view_host.cc +++ b/chrome/browser/renderer_host/render_view_host.cc @@ -1383,7 +1383,7 @@ void RenderViewHost::OnMsgRunFileChooser( RenderViewHostDelegate::FileSelect* file_select_delegate = delegate()->GetFileSelectDelegate(); if (file_select_delegate) - file_select_delegate->RunFileChooser(params); + file_select_delegate->RunFileChooser(this, params); } void RenderViewHost::OnMsgRunJavaScriptMessage( diff --git a/chrome/browser/renderer_host/render_view_host_delegate.h b/chrome/browser/renderer_host/render_view_host_delegate.h index dd414b9..27f9dc8 100644 --- a/chrome/browser/renderer_host/render_view_host_delegate.h +++ b/chrome/browser/renderer_host/render_view_host_delegate.h @@ -605,6 +605,7 @@ class RenderViewHostDelegate { public: // A file chooser should be shown. virtual void RunFileChooser( + RenderViewHost* render_view_host, const ViewHostMsg_RunFileChooser_Params& params) = 0; protected: diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc index 4a1511ed..3c35e61 100644 --- a/chrome/browser/tab_contents/tab_contents.cc +++ b/chrome/browser/tab_contents/tab_contents.cc @@ -45,6 +45,7 @@ #include "chrome/browser/history/history_types.h" #include "chrome/browser/history/top_sites.h" #include "chrome/browser/favicon_service.h" +#include "chrome/browser/file_select_helper.h" #include "chrome/browser/find_bar_state.h" #include "chrome/browser/google/google_util.h" #include "chrome/browser/host_content_settings_map.h" @@ -79,7 +80,6 @@ #include "chrome/browser/tab_contents/navigation_entry.h" #include "chrome/browser/tab_contents/provisional_load_details.h" #include "chrome/browser/tab_contents/tab_contents_delegate.h" -#include "chrome/browser/tab_contents/tab_contents_file_select_helper.h" #include "chrome/browser/tab_contents/tab_contents_ssl_helper.h" #include "chrome/browser/tab_contents/tab_contents_view.h" #include "chrome/browser/tab_contents/thumbnail_generator.h" @@ -2297,7 +2297,7 @@ RenderViewHostDelegate::SSL* TabContents::GetSSLDelegate() { RenderViewHostDelegate::FileSelect* TabContents::GetFileSelectDelegate() { if (file_select_helper_.get() == NULL) - file_select_helper_.reset(new TabContentsFileSelectHelper(this)); + file_select_helper_.reset(new FileSelectHelper(profile())); return file_select_helper_.get(); } diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h index 0dd05cf..94b2ca7 100644 --- a/chrome/browser/tab_contents/tab_contents.h +++ b/chrome/browser/tab_contents/tab_contents.h @@ -69,6 +69,7 @@ class BlockedPopupContainer; class DOMUI; class DownloadItem; class Extension; +class FileSelectHelper; class InfoBarDelegate; class LoadNotificationDetails; class MatchPreview; @@ -82,7 +83,6 @@ class SiteInstance; class SkBitmap; class TabContents; class TabContentsDelegate; -class TabContentsFileSelectHelper; class TabContentsSSLHelper; class TabContentsView; class URLPattern; @@ -1074,8 +1074,8 @@ class TabContents : public PageNavigator, // BlockedPluginManager, lazily created. scoped_ptr<BlockedPluginManager> blocked_plugin_manager_; - // TabContentsFileSelectHelper, lazily created. - scoped_ptr<TabContentsFileSelectHelper> file_select_helper_; + // FileSelectHelper, lazily created. + scoped_ptr<FileSelectHelper> file_select_helper_; // Handles drag and drop event forwarding to extensions. BookmarkDrag* bookmark_drag_; diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 195316a..07da92f 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1513,6 +1513,8 @@ 'browser/file_path_watcher_inotify.cc', 'browser/file_path_watcher_mac.cc', 'browser/file_path_watcher_win.cc', + 'browser/file_select_helper.cc', + 'browser/file_select_helper.h', 'browser/file_system/file_system_dispatcher_host.cc', 'browser/file_system/file_system_dispatcher_host.h', 'browser/file_system/file_system_host_context.cc', @@ -2680,8 +2682,6 @@ 'browser/tab_contents/tab_contents.h', 'browser/tab_contents/tab_contents_delegate.cc', 'browser/tab_contents/tab_contents_delegate.h', - 'browser/tab_contents/tab_contents_file_select_helper.cc', - 'browser/tab_contents/tab_contents_file_select_helper.h', 'browser/tab_contents/tab_contents_ssl_helper.cc', 'browser/tab_contents/tab_contents_ssl_helper.h', 'browser/tab_contents/tab_contents_view.cc', |