1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
|
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_SHELL_DIALOGS_SELECT_FILE_DIALOG_H_
#define UI_SHELL_DIALOGS_SELECT_FILE_DIALOG_H_
#include <memory>
#include <string>
#include <vector>
#include "base/files/file_path.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "build/build_config.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/shell_dialogs/base_shell_dialog.h"
#include "ui/shell_dialogs/shell_dialogs_export.h"
class GURL;
namespace ui {
class SelectFileDialogFactory;
class SelectFilePolicy;
struct SelectedFileInfo;
// Shows a dialog box for selecting a file or a folder.
class SHELL_DIALOGS_EXPORT SelectFileDialog
: public base::RefCountedThreadSafe<SelectFileDialog>,
public BaseShellDialog {
public:
enum Type {
SELECT_NONE,
// For opening a folder.
SELECT_FOLDER,
// Like SELECT_FOLDER, but the dialog UI should explicitly show it's
// specifically for "upload".
SELECT_UPLOAD_FOLDER,
// Like SELECT_FOLDER, but folder creation is disabled, if possible.
SELECT_EXISTING_FOLDER,
// For saving into a file, allowing a nonexistent file to be selected.
SELECT_SAVEAS_FILE,
// For opening a file.
SELECT_OPEN_FILE,
// Like SELECT_OPEN_FILE, but allowing multiple files to open.
SELECT_OPEN_MULTI_FILE
};
// An interface implemented by a Listener object wishing to know about the
// the result of the Select File/Folder action. For any given call to
// SelectFile(), exactly one of these callbacks will be invoked once, possibly
// *but not necessarily* while SelectFile() is still on the stack.
class SHELL_DIALOGS_EXPORT Listener {
public:
// Notifies the Listener that a file/folder selection has been made. The
// file/folder path is in |file|. |index| specifies the index of the filter
// passed to the initial call to SelectFile.
virtual void FileSelected(const SelectedFileInfo& file, int index) {}
// Notifies the Listener that many files have been selected. The files are
// in |files|.
// Implementing this method is optional if no multi-file selection is ever
// made, as the default implementation will call NOTREACHED.
virtual void MultiFilesSelected(const std::vector<SelectedFileInfo>& files);
// Notifies the Listener that the file/folder selection was canceled (via
// the user canceling or closing the selection dialog box, for example).
virtual void FileSelectionCanceled() {}
protected:
virtual ~Listener() = default;
};
// Sets the factory that creates SelectFileDialog objects, overriding default
// behaviour.
//
// This is optional and should only be used by components that have to live
// elsewhere in the tree due to layering violations. (For example, because of
// a dependency on chrome's extension system.)
static void SetFactory(std::unique_ptr<SelectFileDialogFactory> factory);
// Creates a dialog box helper. This is an inexpensive wrapper around the
// platform-native file selection dialog. |policy| is an optional class that
// can prevent showing a dialog.
//
// Note that Listener's lifetime is tricky to get right: Listener must outlive
// the returned SelectFileDialog, but there may be hidden references to that
// object held by worker threads. In general it is only safe to destroy the
// listener when there are no calls to SelectFile() outstanding.
static scoped_refptr<SelectFileDialog> Create(
Listener* listener,
std::unique_ptr<SelectFilePolicy> policy);
SelectFileDialog(const SelectFileDialog&) = delete;
SelectFileDialog& operator=(const SelectFileDialog&) = delete;
// Holds information about allowed extensions on a file save dialog.
struct SHELL_DIALOGS_EXPORT FileTypeInfo {
using FileExtensionList = std::vector<base::FilePath::StringType>;
FileTypeInfo();
FileTypeInfo(const FileTypeInfo& other);
explicit FileTypeInfo(FileExtensionList extensions);
explicit FileTypeInfo(std::vector<FileExtensionList> extensions);
explicit FileTypeInfo(std::vector<FileExtensionList> extensions,
std::vector<std::u16string> descriptions);
~FileTypeInfo();
// A list of allowed extensions. For example, it might be
//
// { { "htm", "html" }, { "txt" } }
//
// Only pass more than one extension in the inner vector if the extensions
// are equivalent. Do NOT include leading periods.
std::vector<std::vector<base::FilePath::StringType>> extensions;
// Overrides the system descriptions of the specified extensions. Entries
// correspond to |extensions|. This must either be of length 0 or the same
// length as extensions.
// TODO(https://issues.chromium.org/issues/340178601): store a vector of
// FileTypeExtensions instead of this and the above vector?
std::vector<std::u16string> extension_description_overrides;
// Specifies whether there will be a filter added for all files (i.e. *.*).
bool include_all_files = false;
// Some implementations by default hide the extension of a file, in
// particular in a save file dialog. If this is set to true, where
// supported, the save file dialog will instead keep the file extension
// visible.
bool keep_extension_visible = false;
// Specifies which type of paths the caller can handle.
enum AllowedPaths {
// Any type of path, whether on a local/native volume or a remote/virtual
// volume. Excludes files that can only be opened by URL; for those use
// ANY_PATH_OR_URL below.
ANY_PATH,
// Set when the caller cannot handle virtual volumes (e.g. File System
// Provider [FSP] volumes like "File System for Dropbox"). When opening
// files, the dialog will create a native replica of the file and return
// its path. When saving files, the dialog will hide virtual volumes.
NATIVE_PATH,
// Set when the caller can open files via URL. For example, when opening a
// .gdoc file from Google Drive the file is opened by navigating to a
// docs.google.com URL.
ANY_PATH_OR_URL
};
AllowedPaths allowed_paths = NATIVE_PATH;
};
// Returns a file path with a base name at most 255 characters long. This
// is the limit on Windows and Linux, and on Windows the system file
// selection dialog will fail to open if the file name exceeds 255 characters.
static base::FilePath GetShortenedFilePath(const base::FilePath& path);
#if BUILDFLAG(IS_ANDROID)
// Set the list of acceptable MIME types for the file picker; this will apply
// to any subsequent SelectFile() calls.
virtual void SetAcceptTypes(std::vector<std::u16string> types);
// Set whether the media picker should try to use media capture, meaning
// offering whatever means the system has of recording media (audio, video,
// etc) as a "file" choice.
virtual void SetUseMediaCapture(bool use_media_capture);
// Set whether files should be opened as writable using the
// ACTION_OPEN_DOCUMENT Intent rather than ACTION_GET_CONTENT.
virtual void SetOpenWritable(bool open_writable);
#endif
// Selects a File.
// Before doing anything this function checks if FileBrowsing is forbidden
// by the SelectFilePolicy supplied at creation time. If so, it tries to show
// an InfoBar and behaves as though the dialog was cancelled, by posting a
// call back to the listener's FileSelectionCanceled method. Otherwise, it
// starts showing the dialog.
//
// On some platforms (Linux-kde), this method blocks the entire UI thread
// until the dialog is closed. On others (Mac) it may enter a nested message
// loop. It sometimes, but not always, tries to block input events from being
// delivered to its owning window (Windows, Linux-gtk). On some platforms it
// uses a background thread, although listener callbacks are always run on the
// UI thread. In general when using this method you must ensure that the
// Listener, and any data passed to SelectFile(), remain live until one of the
// callbacks has been run.
//
// |type| is the type of file dialog to be shown, see Type enumeration above.
// |title| is the title to be displayed in the dialog. If this string is
// empty, the default title is used.
// |default_path| is the default path and suggested file name to be shown in
// the dialog. This only works for SELECT_SAVEAS_FILE and SELECT_OPEN_FILE.
// Can be an empty string to indicate the platform default.
// |file_types| holds the information about the file types allowed. Pass NULL
// to get no special behavior
// |file_type_index| is the 1-based index into the file type list in
// |file_types|. Specify 0 if you don't need to specify extension behavior.
// |default_extension| is the default extension to add to the file if the
// user doesn't type one. This should NOT include the '.'. On Windows, if
// you specify this you must also specify |file_types|.
// |owning_window| is the window the dialog is modal to, or NULL for a
// modeless dialog.
// |caller| is the URL of the dialog caller which can be used to check further
// policy restrictions, when applicable. Can be NULL. Non-NULL values of
// |caller| are deprecated - store the state in the calling object directly.
// NOTE: only one instance of any shell dialog can be shown per owning_window
// at a time (for obvious reasons).
void SelectFile(Type type,
const std::u16string& title,
const base::FilePath& default_path,
const FileTypeInfo* file_types,
int file_type_index,
const base::FilePath::StringType& default_extension,
gfx::NativeWindow owning_window,
const GURL* caller = nullptr);
bool HasMultipleFileTypeChoices();
protected:
friend class base::RefCountedThreadSafe<SelectFileDialog>;
explicit SelectFileDialog(Listener* listener,
std::unique_ptr<SelectFilePolicy> policy);
~SelectFileDialog() override;
// Displays the actual file-selection dialog.
// This is overridden in the platform-specific descendants of FileSelectDialog
// and gets called from SelectFile after testing the
// AllowFileSelectionDialogs-Policy.
virtual void SelectFileImpl(
Type type,
const std::u16string& title,
const base::FilePath& default_path,
const FileTypeInfo* file_types,
int file_type_index,
const base::FilePath::StringType& default_extension,
gfx::NativeWindow owning_window,
const GURL* caller) = 0;
// The listener to be notified of selection completion.
raw_ptr<Listener> listener_;
private:
// Tests if the file selection dialog can be displayed by
// testing if the AllowFileSelectionDialogs-Policy is
// either unset or set to true.
bool CanOpenSelectFileDialog();
// Informs the |listener_| that the file selection dialog was canceled. Moved
// to a function for being able to post it to the message loop.
void CancelFileSelection();
// Returns true if the dialog has multiple file type choices.
virtual bool HasMultipleFileTypeChoicesImpl() = 0;
std::unique_ptr<SelectFilePolicy> select_file_policy_;
};
SelectFileDialog* CreateSelectFileDialog(
SelectFileDialog::Listener* listener,
std::unique_ptr<SelectFilePolicy> policy);
} // namespace ui
#endif // UI_SHELL_DIALOGS_SELECT_FILE_DIALOG_H_
|