1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CHROME_BROWSER_FILE_SELECT_HELPER_H_
6#define CHROME_BROWSER_FILE_SELECT_HELPER_H_
7
8#include <map>
9#include <vector>
10
11#include "base/compiler_specific.h"
12#include "base/gtest_prod_util.h"
13#include "content/public/browser/notification_observer.h"
14#include "content/public/browser/notification_registrar.h"
15#include "content/public/common/file_chooser_params.h"
16#include "net/base/directory_lister.h"
17#include "ui/shell_dialogs/select_file_dialog.h"
18
19class Profile;
20
21namespace content {
22class RenderViewHost;
23class WebContents;
24}
25
26namespace ui {
27struct SelectedFileInfo;
28}
29
30// This class handles file-selection requests coming from WebUI elements
31// (via the extensions::ExtensionHost class). It implements both the
32// initialisation and listener functions for file-selection dialogs.
33class FileSelectHelper
34    : public base::RefCountedThreadSafe<FileSelectHelper>,
35      public ui::SelectFileDialog::Listener,
36      public content::NotificationObserver {
37 public:
38
39  // Show the file chooser dialog.
40  static void RunFileChooser(content::WebContents* tab,
41                             const content::FileChooserParams& params);
42
43  // Enumerates all the files in directory.
44  static void EnumerateDirectory(content::WebContents* tab,
45                                 int request_id,
46                                 const base::FilePath& path);
47
48 private:
49  friend class base::RefCountedThreadSafe<FileSelectHelper>;
50  FRIEND_TEST_ALL_PREFIXES(FileSelectHelperTest, IsAcceptTypeValid);
51  explicit FileSelectHelper(Profile* profile);
52  virtual ~FileSelectHelper();
53
54  // Utility class which can listen for directory lister events and relay
55  // them to the main object with the correct tracking id.
56  class DirectoryListerDispatchDelegate
57      : public net::DirectoryLister::DirectoryListerDelegate {
58   public:
59    DirectoryListerDispatchDelegate(FileSelectHelper* parent, int id)
60        : parent_(parent),
61          id_(id) {}
62    virtual ~DirectoryListerDispatchDelegate() {}
63    virtual void OnListFile(
64        const net::DirectoryLister::DirectoryListerData& data) OVERRIDE;
65    virtual void OnListDone(int error) OVERRIDE;
66   private:
67    // This FileSelectHelper owns this object.
68    FileSelectHelper* parent_;
69    int id_;
70
71    DISALLOW_COPY_AND_ASSIGN(DirectoryListerDispatchDelegate);
72  };
73
74  void RunFileChooser(content::RenderViewHost* render_view_host,
75                      content::WebContents* web_contents,
76                      const content::FileChooserParams& params);
77  void RunFileChooserOnFileThread(
78      const content::FileChooserParams& params);
79  void RunFileChooserOnUIThread(
80      const content::FileChooserParams& params);
81
82  // Cleans up and releases this instance. This must be called after the last
83  // callback is received from the file chooser dialog.
84  void RunFileChooserEnd();
85
86  // SelectFileDialog::Listener overrides.
87  virtual void FileSelected(
88      const base::FilePath& path, int index, void* params) OVERRIDE;
89  virtual void FileSelectedWithExtraInfo(
90      const ui::SelectedFileInfo& file,
91      int index,
92      void* params) OVERRIDE;
93  virtual void MultiFilesSelected(const std::vector<base::FilePath>& files,
94                                  void* params) OVERRIDE;
95  virtual void MultiFilesSelectedWithExtraInfo(
96      const std::vector<ui::SelectedFileInfo>& files,
97      void* params) OVERRIDE;
98  virtual void FileSelectionCanceled(void* params) OVERRIDE;
99
100  // content::NotificationObserver overrides.
101  virtual void Observe(int type,
102                       const content::NotificationSource& source,
103                       const content::NotificationDetails& details) OVERRIDE;
104
105  void EnumerateDirectory(int request_id,
106                          content::RenderViewHost* render_view_host,
107                          const base::FilePath& path);
108
109  // Kicks off a new directory enumeration.
110  void StartNewEnumeration(const base::FilePath& path,
111                           int request_id,
112                           content::RenderViewHost* render_view_host);
113
114  // Callbacks from directory enumeration.
115  virtual void OnListFile(
116      int id,
117      const net::DirectoryLister::DirectoryListerData& data);
118  virtual void OnListDone(int id, int error);
119
120  // Cleans up and releases this instance. This must be called after the last
121  // callback is received from the enumeration code.
122  void EnumerateDirectoryEnd();
123
124  // Helper method to get allowed extensions for select file dialog from
125  // the specified accept types as defined in the spec:
126  //   http://whatwg.org/html/number-state.html#attr-input-accept
127  // |accept_types| contains only valid lowercased MIME types or file extensions
128  // beginning with a period (.).
129  static scoped_ptr<ui::SelectFileDialog::FileTypeInfo>
130      GetFileTypesFromAcceptType(
131          const std::vector<base::string16>& accept_types);
132
133  // Check the accept type is valid. It is expected to be all lower case with
134  // no whitespace.
135  static bool IsAcceptTypeValid(const std::string& accept_type);
136
137  // Profile used to set/retrieve the last used directory.
138  Profile* profile_;
139
140  // The RenderViewHost and WebContents for the page showing a file dialog
141  // (may only be one such dialog).
142  content::RenderViewHost* render_view_host_;
143  content::WebContents* web_contents_;
144
145  // Dialog box used for choosing files to upload from file form fields.
146  scoped_refptr<ui::SelectFileDialog> select_file_dialog_;
147  scoped_ptr<ui::SelectFileDialog::FileTypeInfo> select_file_types_;
148
149  // The type of file dialog last shown.
150  ui::SelectFileDialog::Type dialog_type_;
151
152  // The mode of file dialog last shown.
153  content::FileChooserParams::Mode dialog_mode_;
154
155  // Maintain a list of active directory enumerations.  These could come from
156  // the file select dialog or from drag-and-drop of directories, so there could
157  // be more than one going on at a time.
158  struct ActiveDirectoryEnumeration;
159  std::map<int, ActiveDirectoryEnumeration*> directory_enumerations_;
160
161  // Registrar for notifications regarding our RenderViewHost.
162  content::NotificationRegistrar notification_registrar_;
163
164  DISALLOW_COPY_AND_ASSIGN(FileSelectHelper);
165};
166
167#endif  // CHROME_BROWSER_FILE_SELECT_HELPER_H_
168