summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorjcivelli@chromium.org <jcivelli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-10 16:54:49 +0000
committerjcivelli@chromium.org <jcivelli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-10 16:54:49 +0000
commitba70d082593f9e20ab059b7f09495d94c0856005 (patch)
treee56ce8065866ebde7de1ad8137b2fe2ccc7cf8c2 /chrome
parentba62fbd428232eee1815d4b4d63fc65cb3ead566 (diff)
downloadchromium_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.cc7
-rw-r--r--chrome/browser/extensions/extension_host.h5
-rw-r--r--chrome/browser/file_select_helper.cc242
-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.cc2
-rw-r--r--chrome/browser/renderer_host/render_view_host_delegate.h1
-rw-r--r--chrome/browser/tab_contents/tab_contents.cc4
-rw-r--r--chrome/browser/tab_contents/tab_contents.h6
-rw-r--r--chrome/chrome_browser.gypi4
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 &params) {
+ 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',