Home | History | Annotate | Download | only in browser
      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 
     19 class Profile;
     20 
     21 namespace content {
     22 class RenderViewHost;
     23 class WebContents;
     24 }
     25 
     26 namespace ui {
     27 struct 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.
     33 class 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