1// Copyright (c) 2013 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 UI_SHELL_DIALOGS_SELECT_FILE_DIALOG_H_
6#define UI_SHELL_DIALOGS_SELECT_FILE_DIALOG_H_
7
8#include <string>
9#include <vector>
10
11#include "base/basictypes.h"
12#include "base/callback_forward.h"
13#include "base/files/file_path.h"
14#include "base/memory/ref_counted.h"
15#include "base/memory/scoped_ptr.h"
16#include "base/strings/string16.h"
17#include "ui/gfx/native_widget_types.h"
18#include "ui/shell_dialogs/base_shell_dialog.h"
19#include "ui/shell_dialogs/shell_dialogs_export.h"
20
21namespace ui {
22class SelectFileDialogFactory;
23class SelectFilePolicy;
24struct SelectedFileInfo;
25class ShellDialogsDelegate;
26
27// Shows a dialog box for selecting a file or a folder.
28class SHELL_DIALOGS_EXPORT SelectFileDialog
29    : public base::RefCountedThreadSafe<SelectFileDialog>,
30      public BaseShellDialog {
31 public:
32  enum Type {
33    SELECT_NONE,
34
35    // For opening a folder.
36    SELECT_FOLDER,
37
38    // Like SELECT_FOLDER, but the dialog UI should explicitly show it's
39    // specifically for "upload".
40    SELECT_UPLOAD_FOLDER,
41
42    // For saving into a file, allowing a nonexistent file to be selected.
43    SELECT_SAVEAS_FILE,
44
45    // For opening a file.
46    SELECT_OPEN_FILE,
47
48    // Like SELECT_OPEN_FILE, but allowing multiple files to open.
49    SELECT_OPEN_MULTI_FILE
50  };
51
52  // An interface implemented by a Listener object wishing to know about the
53  // the result of the Select File/Folder action. These callbacks must be
54  // re-entrant.
55  class SHELL_DIALOGS_EXPORT Listener {
56   public:
57    // Notifies the Listener that a file/folder selection has been made. The
58    // file/folder path is in |path|. |params| is contextual passed to
59    // SelectFile. |index| specifies the index of the filter passed to the
60    // the initial call to SelectFile.
61    virtual void FileSelected(const base::FilePath& path,
62                              int index, void* params) = 0;
63
64    // Similar to FileSelected() but takes SelectedFileInfo instead of
65    // base::FilePath. Used for passing extra information (ex. display name).
66    //
67    // If not overridden, calls FileSelected() with path from |file|.
68    virtual void FileSelectedWithExtraInfo(
69        const SelectedFileInfo& file,
70        int index,
71        void* params);
72
73    // Notifies the Listener that many files have been selected. The
74    // files are in |files|. |params| is contextual passed to SelectFile.
75    virtual void MultiFilesSelected(
76        const std::vector<base::FilePath>& files, void* params) {}
77
78    // Similar to MultiFilesSelected() but takes SelectedFileInfo instead of
79    // base::FilePath. Used for passing extra information (ex. display name).
80    //
81    // If not overridden, calls MultiFilesSelected() with paths from |files|.
82    virtual void MultiFilesSelectedWithExtraInfo(
83        const std::vector<SelectedFileInfo>& files,
84        void* params);
85
86    // Notifies the Listener that the file/folder selection was aborted (via
87    // the  user canceling or closing the selection dialog box, for example).
88    // |params| is contextual passed to SelectFile.
89    virtual void FileSelectionCanceled(void* params) {}
90
91   protected:
92    virtual ~Listener() {}
93  };
94
95  // Sets the factory that creates SelectFileDialog objects, overriding default
96  // behaviour.
97  //
98  // This is optional and should only be used by components that have to live
99  // elsewhere in the tree due to layering violations. (For example, because of
100  // a dependency on chrome's extension system.)
101  static void SetFactory(SelectFileDialogFactory* factory);
102
103  // Creates a dialog box helper. This is an inexpensive wrapper around the
104  // platform-native file selection dialog. |policy| is an optional class that
105  // can prevent showing a dialog.
106  static scoped_refptr<SelectFileDialog> Create(Listener* listener,
107                                                SelectFilePolicy* policy);
108
109  // Holds information about allowed extensions on a file save dialog.
110  struct SHELL_DIALOGS_EXPORT FileTypeInfo {
111    FileTypeInfo();
112    ~FileTypeInfo();
113
114    // A list of allowed extensions. For example, it might be
115    //
116    //   { { "htm", "html" }, { "txt" } }
117    //
118    // Only pass more than one extension in the inner vector if the extensions
119    // are equivalent. Do NOT include leading periods.
120    std::vector<std::vector<base::FilePath::StringType> > extensions;
121
122    // Overrides the system descriptions of the specified extensions. Entries
123    // correspond to |extensions|; if left blank the system descriptions will
124    // be used.
125    std::vector<base::string16> extension_description_overrides;
126
127    // Specifies whether there will be a filter added for all files (i.e. *.*).
128    bool include_all_files;
129
130    // Specifies whether the caller can directly support file paths pointing to
131    // files/folders on Google Drive. If the flag is true, the file dialog does
132    // nothing special; just returns a Drive path. If it is false, the dialog
133    // creates a local replica of the Drive file and returns its path, so that
134    // the caller can use it without any difference than when it were local.
135    bool support_drive;
136  };
137
138  // Selects a File.
139  // Before doing anything this function checks if FileBrowsing is forbidden
140  // by Policy. If so, it tries to show an InfoBar and behaves as though no File
141  // was selected (the user clicked `Cancel` immediately).
142  // Otherwise it will start displaying the dialog box. This will also
143  // block the calling window until the dialog box is complete. The listener
144  // associated with this object will be notified when the selection is
145  // complete.
146  // |type| is the type of file dialog to be shown, see Type enumeration above.
147  // |title| is the title to be displayed in the dialog. If this string is
148  //   empty, the default title is used.
149  // |default_path| is the default path and suggested file name to be shown in
150  //   the dialog. This only works for SELECT_SAVEAS_FILE and SELECT_OPEN_FILE.
151  //   Can be an empty string to indicate the platform default.
152  // |file_types| holds the information about the file types allowed. Pass NULL
153  //   to get no special behavior
154  // |file_type_index| is the 1-based index into the file type list in
155  //   |file_types|. Specify 0 if you don't need to specify extension behavior.
156  // |default_extension| is the default extension to add to the file if the
157  //   user doesn't type one. This should NOT include the '.'. On Windows, if
158  //   you specify this you must also specify |file_types|.
159  // |owning_window| is the window the dialog is modal to, or NULL for a
160  //   modeless dialog.
161  // |params| is data from the calling context which will be passed through to
162  //   the listener. Can be NULL.
163  // NOTE: only one instance of any shell dialog can be shown per owning_window
164  //       at a time (for obvious reasons).
165  void SelectFile(Type type,
166                  const base::string16& title,
167                  const base::FilePath& default_path,
168                  const FileTypeInfo* file_types,
169                  int file_type_index,
170                  const base::FilePath::StringType& default_extension,
171                  gfx::NativeWindow owning_window,
172                  void* params);
173  bool HasMultipleFileTypeChoices();
174
175  // Sets the global ShellDialogsDelegate. Defaults to NULL.
176  static void SetShellDialogsDelegate(ShellDialogsDelegate* delegate);
177
178 protected:
179  friend class base::RefCountedThreadSafe<SelectFileDialog>;
180  explicit SelectFileDialog(Listener* listener, SelectFilePolicy* policy);
181  virtual ~SelectFileDialog();
182
183  // Displays the actual file-selection dialog.
184  // This is overridden in the platform-specific descendants of FileSelectDialog
185  // and gets called from SelectFile after testing the
186  // AllowFileSelectionDialogs-Policy.
187  virtual void SelectFileImpl(
188      Type type,
189      const base::string16& title,
190      const base::FilePath& default_path,
191      const FileTypeInfo* file_types,
192      int file_type_index,
193      const base::FilePath::StringType& default_extension,
194      gfx::NativeWindow owning_window,
195      void* params) = 0;
196
197  // Returns the global ShellDialogsDelegate instance if any.
198  ShellDialogsDelegate* GetShellDialogsDelegate();
199
200  // The listener to be notified of selection completion.
201  Listener* listener_;
202
203 private:
204  // Tests if the file selection dialog can be displayed by
205  // testing if the AllowFileSelectionDialogs-Policy is
206  // either unset or set to true.
207  bool CanOpenSelectFileDialog();
208
209  // Informs the |listener_| that the file selection dialog was canceled. Moved
210  // to a function for being able to post it to the message loop.
211  void CancelFileSelection(void* params);
212
213  // Returns true if the dialog has multiple file type choices.
214  virtual bool HasMultipleFileTypeChoicesImpl() = 0;
215
216  scoped_ptr<SelectFilePolicy> select_file_policy_;
217
218  DISALLOW_COPY_AND_ASSIGN(SelectFileDialog);
219};
220
221}  // namespace ui
222
223#endif  // UI_SHELL_DIALOGS_SELECT_FILE_DIALOG_H_
224