- Add open folder dialog support (FILE_DIALOG_OPEN_FOLDER mode) for CefBrowserHost::RunFileDialog (issue #1030).
- Standardize file dialog behavior across all platforms (issue #1492). -- Show a file type filter list on OS X. -- Show the file extensions as part of the filter list description on all platforms (e.g. "Image Types (*.png;*.gif;*.jpg)"). -- Rename the CefBrowserHost::RunFileDialog |accept_types| argument to |accept_filters| and expand support for filters that will be displayed as-is in addition to the currently supported mime-type and extension-based filters. For example, a filter value of "Supported Image Types|.png;.gif;.jpg" will display "Supported Image Types (*.png;*.gif;*.jpg)" in the filter drop-down list and accept *.png, *.gif and *.jpg files. -- Persist the selected filter item index by passing a new |selected_accept_filter| argument to CefBrowserHost::RunFileDialog and returning the newly selected index via the CefRunFileDialogCallback and CefFileDialogCallback callbacks. -- Rename the CefBrowserHost::RunFileDialog |default_file_name| argument to |default_file_path| and use the directory component, if any, to set the default directory location. If |default_file_path| ends in a trailing path separator it will be treated as a directory without a file name component. -- Add FILE_DIALOG_OVERWRITEPROMPT_FLAG and FILE_DIALOG_HIDEREADONLY_FLAG values to cef_file_dialog_mode_t for controlling those behaviors where possible. git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@1973 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
parent
3eabbb2e7d
commit
e50ea8c29f
|
@ -195,13 +195,15 @@ typedef struct _cef_run_file_dialog_callback_t {
|
|||
cef_base_t base;
|
||||
|
||||
///
|
||||
// Called asynchronously after the file dialog is dismissed. If the selection
|
||||
// was successful |file_paths| will be a single value or a list of values
|
||||
// depending on the dialog mode. If the selection was cancelled |file_paths|
|
||||
// will be NULL.
|
||||
// Called asynchronously after the file dialog is dismissed.
|
||||
// |selected_accept_filter| is the 0-based index of the value selected from
|
||||
// the accept filters array passed to cef_browser_host_t::RunFileDialog.
|
||||
// |file_paths| will be a single value or a list of values depending on the
|
||||
// dialog mode. If the selection was cancelled |file_paths| will be NULL.
|
||||
///
|
||||
void (CEF_CALLBACK *cont)(struct _cef_run_file_dialog_callback_t* self,
|
||||
struct _cef_browser_host_t* browser_host, cef_string_list_t file_paths);
|
||||
void (CEF_CALLBACK *on_file_dialog_dismissed)(
|
||||
struct _cef_run_file_dialog_callback_t* self, int selected_accept_filter,
|
||||
cef_string_list_t file_paths);
|
||||
} cef_run_file_dialog_callback_t;
|
||||
|
||||
|
||||
|
@ -315,17 +317,22 @@ typedef struct _cef_browser_host_t {
|
|||
// Call to run a file chooser dialog. Only a single file chooser dialog may be
|
||||
// pending at any given time. |mode| represents the type of dialog to display.
|
||||
// |title| to the title to be used for the dialog and may be NULL to show the
|
||||
// default title ("Open" or "Save" depending on the mode). |default_file_name|
|
||||
// is the default file name to select in the dialog. |accept_types| is a list
|
||||
// of valid lower-cased MIME types or file extensions specified in an input
|
||||
// element and is used to restrict selectable files to such types. |callback|
|
||||
// will be executed after the dialog is dismissed or immediately if another
|
||||
// dialog is already pending. The dialog will be initiated asynchronously on
|
||||
// the UI thread.
|
||||
// default title ("Open" or "Save" depending on the mode). |default_file_path|
|
||||
// is the path with optional directory and/or file name component that will be
|
||||
// initially selected in the dialog. |accept_filters| are used to restrict the
|
||||
// selectable file types and may any combination of (a) valid lower-cased MIME
|
||||
// types (e.g. "text/*" or "image/*"), (b) individual file extensions (e.g.
|
||||
// ".txt" or ".png"), or (c) combined description and file extension delimited
|
||||
// using "|" and ";" (e.g. "Image Types|.png;.gif;.jpg").
|
||||
// |selected_accept_filter| is the 0-based index of the filter that will be
|
||||
// selected by default. |callback| will be executed after the dialog is
|
||||
// dismissed or immediately if another dialog is already pending. The dialog
|
||||
// will be initiated asynchronously on the UI thread.
|
||||
///
|
||||
void (CEF_CALLBACK *run_file_dialog)(struct _cef_browser_host_t* self,
|
||||
cef_file_dialog_mode_t mode, const cef_string_t* title,
|
||||
const cef_string_t* default_file_name, cef_string_list_t accept_types,
|
||||
const cef_string_t* default_file_path, cef_string_list_t accept_filters,
|
||||
int selected_accept_filter,
|
||||
struct _cef_run_file_dialog_callback_t* callback);
|
||||
|
||||
///
|
||||
|
|
|
@ -56,12 +56,14 @@ typedef struct _cef_file_dialog_callback_t {
|
|||
cef_base_t base;
|
||||
|
||||
///
|
||||
// Continue the file selection with the specified |file_paths|. This may be a
|
||||
// single value or a list of values depending on the dialog mode. An NULL
|
||||
// Continue the file selection. |selected_accept_filter| should be the 0-based
|
||||
// index of the value selected from the accept filters array passed to
|
||||
// cef_dialog_handler_t::OnFileDialog. |file_paths| should be a single value
|
||||
// or a list of values depending on the dialog mode. An NULL |file_paths|
|
||||
// value is treated the same as calling cancel().
|
||||
///
|
||||
void (CEF_CALLBACK *cont)(struct _cef_file_dialog_callback_t* self,
|
||||
cef_string_list_t file_paths);
|
||||
int selected_accept_filter, cef_string_list_t file_paths);
|
||||
|
||||
///
|
||||
// Cancel the file selection.
|
||||
|
@ -84,17 +86,21 @@ typedef struct _cef_dialog_handler_t {
|
|||
// Called to run a file chooser dialog. |mode| represents the type of dialog
|
||||
// to display. |title| to the title to be used for the dialog and may be NULL
|
||||
// to show the default title ("Open" or "Save" depending on the mode).
|
||||
// |default_file_name| is the default file name to select in the dialog.
|
||||
// |accept_types| is a list of valid lower-cased MIME types or file extensions
|
||||
// specified in an input element and is used to restrict selectable files to
|
||||
// such types. To display a custom dialog return true (1) and execute
|
||||
// |callback| either inline or at a later time. To display the default dialog
|
||||
// return false (0).
|
||||
// |default_file_path| is the path with optional directory and/or file name
|
||||
// component that should be initially selected in the dialog. |accept_filters|
|
||||
// are used to restrict the selectable file types and may any combination of
|
||||
// (a) valid lower-cased MIME types (e.g. "text/*" or "image/*"), (b)
|
||||
// individual file extensions (e.g. ".txt" or ".png"), or (c) combined
|
||||
// description and file extension delimited using "|" and ";" (e.g. "Image
|
||||
// Types|.png;.gif;.jpg"). |selected_accept_filter| is the 0-based index of
|
||||
// the filter that should be selected by default. To display a custom dialog
|
||||
// return true (1) and execute |callback| either inline or at a later time. To
|
||||
// display the default dialog return false (0).
|
||||
///
|
||||
int (CEF_CALLBACK *on_file_dialog)(struct _cef_dialog_handler_t* self,
|
||||
struct _cef_browser_t* browser, cef_file_dialog_mode_t mode,
|
||||
const cef_string_t* title, const cef_string_t* default_file_name,
|
||||
cef_string_list_t accept_types,
|
||||
const cef_string_t* title, const cef_string_t* default_file_path,
|
||||
cef_string_list_t accept_filters, int selected_accept_filter,
|
||||
struct _cef_file_dialog_callback_t* callback);
|
||||
} cef_dialog_handler_t;
|
||||
|
||||
|
|
|
@ -199,14 +199,15 @@ class CefBrowser : public virtual CefBase {
|
|||
class CefRunFileDialogCallback : public virtual CefBase {
|
||||
public:
|
||||
///
|
||||
// Called asynchronously after the file dialog is dismissed. If the selection
|
||||
// was successful |file_paths| will be a single value or a list of values
|
||||
// depending on the dialog mode. If the selection was cancelled |file_paths|
|
||||
// will be empty.
|
||||
// Called asynchronously after the file dialog is dismissed.
|
||||
// |selected_accept_filter| is the 0-based index of the value selected from
|
||||
// the accept filters array passed to CefBrowserHost::RunFileDialog.
|
||||
// |file_paths| will be a single value or a list of values depending on the
|
||||
// dialog mode. If the selection was cancelled |file_paths| will be empty.
|
||||
///
|
||||
/*--cef(capi_name=cont)--*/
|
||||
/*--cef(index_param=selected_accept_filter,optional_param=file_paths)--*/
|
||||
virtual void OnFileDialogDismissed(
|
||||
CefRefPtr<CefBrowserHost> browser_host,
|
||||
int selected_accept_filter,
|
||||
const std::vector<CefString>& file_paths) =0;
|
||||
};
|
||||
|
||||
|
@ -355,20 +356,25 @@ class CefBrowserHost : public virtual CefBase {
|
|||
// Call to run a file chooser dialog. Only a single file chooser dialog may be
|
||||
// pending at any given time. |mode| represents the type of dialog to display.
|
||||
// |title| to the title to be used for the dialog and may be empty to show the
|
||||
// default title ("Open" or "Save" depending on the mode). |default_file_name|
|
||||
// is the default file name to select in the dialog. |accept_types| is a list
|
||||
// of valid lower-cased MIME types or file extensions specified in an input
|
||||
// element and is used to restrict selectable files to such types. |callback|
|
||||
// will be executed after the dialog is dismissed or immediately if another
|
||||
// dialog is already pending. The dialog will be initiated asynchronously on
|
||||
// the UI thread.
|
||||
// default title ("Open" or "Save" depending on the mode). |default_file_path|
|
||||
// is the path with optional directory and/or file name component that will be
|
||||
// initially selected in the dialog. |accept_filters| are used to restrict the
|
||||
// selectable file types and may any combination of (a) valid lower-cased MIME
|
||||
// types (e.g. "text/*" or "image/*"), (b) individual file extensions (e.g.
|
||||
// ".txt" or ".png"), or (c) combined description and file extension delimited
|
||||
// using "|" and ";" (e.g. "Image Types|.png;.gif;.jpg").
|
||||
// |selected_accept_filter| is the 0-based index of the filter that will be
|
||||
// selected by default. |callback| will be executed after the dialog is
|
||||
// dismissed or immediately if another dialog is already pending. The dialog
|
||||
// will be initiated asynchronously on the UI thread.
|
||||
///
|
||||
/*--cef(optional_param=title,optional_param=default_file_name,
|
||||
optional_param=accept_types)--*/
|
||||
/*--cef(optional_param=title,optional_param=default_file_path,
|
||||
optional_param=accept_filters,index_param=selected_accept_filter)--*/
|
||||
virtual void RunFileDialog(FileDialogMode mode,
|
||||
const CefString& title,
|
||||
const CefString& default_file_name,
|
||||
const std::vector<CefString>& accept_types,
|
||||
const CefString& default_file_path,
|
||||
const std::vector<CefString>& accept_filters,
|
||||
int selected_accept_filter,
|
||||
CefRefPtr<CefRunFileDialogCallback> callback) =0;
|
||||
|
||||
///
|
||||
|
|
|
@ -48,13 +48,17 @@
|
|||
class CefFileDialogCallback : public virtual CefBase {
|
||||
public:
|
||||
///
|
||||
// Continue the file selection with the specified |file_paths|. This may be
|
||||
// a single value or a list of values depending on the dialog mode. An empty
|
||||
// value is treated the same as calling Cancel().
|
||||
// Continue the file selection. |selected_accept_filter| should be the 0-based
|
||||
// index of the value selected from the accept filters array passed to
|
||||
// CefDialogHandler::OnFileDialog. |file_paths| should be a single value or a
|
||||
// list of values depending on the dialog mode. An empty |file_paths| value is
|
||||
// treated the same as calling Cancel().
|
||||
///
|
||||
/*--cef(capi_name=cont)--*/
|
||||
virtual void Continue(const std::vector<CefString>& file_paths) =0;
|
||||
|
||||
/*--cef(capi_name=cont,index_param=selected_accept_filter,
|
||||
optional_param=file_paths)--*/
|
||||
virtual void Continue(int selected_accept_filter,
|
||||
const std::vector<CefString>& file_paths) =0;
|
||||
|
||||
///
|
||||
// Cancel the file selection.
|
||||
///
|
||||
|
@ -76,20 +80,25 @@ class CefDialogHandler : public virtual CefBase {
|
|||
// Called to run a file chooser dialog. |mode| represents the type of dialog
|
||||
// to display. |title| to the title to be used for the dialog and may be empty
|
||||
// to show the default title ("Open" or "Save" depending on the mode).
|
||||
// |default_file_name| is the default file name to select in the dialog.
|
||||
// |accept_types| is a list of valid lower-cased MIME types or file extensions
|
||||
// specified in an input element and is used to restrict selectable files to
|
||||
// such types. To display a custom dialog return true and execute |callback|
|
||||
// either inline or at a later time. To display the default dialog return
|
||||
// false.
|
||||
// |default_file_path| is the path with optional directory and/or file name
|
||||
// component that should be initially selected in the dialog. |accept_filters|
|
||||
// are used to restrict the selectable file types and may any combination of
|
||||
// (a) valid lower-cased MIME types (e.g. "text/*" or "image/*"),
|
||||
// (b) individual file extensions (e.g. ".txt" or ".png"), or (c) combined
|
||||
// description and file extension delimited using "|" and ";" (e.g.
|
||||
// "Image Types|.png;.gif;.jpg"). |selected_accept_filter| is the 0-based
|
||||
// index of the filter that should be selected by default. To display a custom
|
||||
// dialog return true and execute |callback| either inline or at a later time.
|
||||
// To display the default dialog return false.
|
||||
///
|
||||
/*--cef(optional_param=title,optional_param=default_file_name,
|
||||
optional_param=accept_types)--*/
|
||||
/*--cef(optional_param=title,optional_param=default_file_path,
|
||||
optional_param=accept_filters,index_param=selected_accept_filter)--*/
|
||||
virtual bool OnFileDialog(CefRefPtr<CefBrowser> browser,
|
||||
FileDialogMode mode,
|
||||
const CefString& title,
|
||||
const CefString& default_file_name,
|
||||
const std::vector<CefString>& accept_types,
|
||||
const CefString& default_file_path,
|
||||
const std::vector<CefString>& accept_filters,
|
||||
int selected_accept_filter,
|
||||
CefRefPtr<CefFileDialogCallback> callback) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1720,11 +1720,36 @@ typedef enum {
|
|||
///
|
||||
FILE_DIALOG_OPEN_MULTIPLE,
|
||||
|
||||
///
|
||||
// Like Open, but selects a folder to open.
|
||||
///
|
||||
FILE_DIALOG_OPEN_FOLDER,
|
||||
|
||||
///
|
||||
// Allows picking a nonexistent file, and prompts to overwrite if the file
|
||||
// already exists.
|
||||
///
|
||||
FILE_DIALOG_SAVE,
|
||||
|
||||
///
|
||||
// General mask defining the bits used for the type values.
|
||||
///
|
||||
FILE_DIALOG_TYPE_MASK = 0xFF,
|
||||
|
||||
// Qualifiers.
|
||||
// Any of the type values above can be augmented by one or more qualifiers.
|
||||
// These qualifiers further define the dialog behavior.
|
||||
|
||||
///
|
||||
// Prompt to overwrite if the user selects an existing file with the Save
|
||||
// dialog.
|
||||
///
|
||||
FILE_DIALOG_OVERWRITEPROMPT_FLAG = 0x01000000,
|
||||
|
||||
///
|
||||
// Do not display read-only files.
|
||||
///
|
||||
FILE_DIALOG_HIDEREADONLY_FLAG = 0x02000000,
|
||||
} cef_file_dialog_mode_t;
|
||||
|
||||
///
|
||||
|
|
|
@ -200,7 +200,8 @@ class CefFileDialogCallbackImpl : public CefFileDialogCallback {
|
|||
}
|
||||
}
|
||||
|
||||
void Continue(const std::vector<CefString>& file_paths) override {
|
||||
void Continue(int selected_accept_filter,
|
||||
const std::vector<CefString>& file_paths) override {
|
||||
if (CEF_CURRENTLY_ON_UIT()) {
|
||||
if (!callback_.is_null()) {
|
||||
std::vector<base::FilePath> vec;
|
||||
|
@ -209,12 +210,13 @@ class CefFileDialogCallbackImpl : public CefFileDialogCallback {
|
|||
for (; it != file_paths.end(); ++it)
|
||||
vec.push_back(base::FilePath(*it));
|
||||
}
|
||||
callback_.Run(vec);
|
||||
callback_.Run(selected_accept_filter, vec);
|
||||
callback_.Reset();
|
||||
}
|
||||
} else {
|
||||
CEF_POST_TASK(CEF_UIT,
|
||||
base::Bind(&CefFileDialogCallbackImpl::Continue, this, file_paths));
|
||||
base::Bind(&CefFileDialogCallbackImpl::Continue, this,
|
||||
selected_accept_filter, file_paths));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -243,7 +245,7 @@ class CefFileDialogCallbackImpl : public CefFileDialogCallback {
|
|||
const CefBrowserHostImpl::RunFileChooserCallback& callback) {
|
||||
CEF_REQUIRE_UIT();
|
||||
std::vector<base::FilePath> file_paths;
|
||||
callback.Run(file_paths);
|
||||
callback.Run(0, file_paths);
|
||||
}
|
||||
|
||||
CefBrowserHostImpl::RunFileChooserCallback callback_;
|
||||
|
@ -251,32 +253,17 @@ class CefFileDialogCallbackImpl : public CefFileDialogCallback {
|
|||
IMPLEMENT_REFCOUNTING(CefFileDialogCallbackImpl);
|
||||
};
|
||||
|
||||
class CefRunFileDialogCallbackWrapper
|
||||
: public base::RefCountedThreadSafe<CefRunFileDialogCallbackWrapper> {
|
||||
public:
|
||||
CefRunFileDialogCallbackWrapper(CefRefPtr<CefBrowserHost> host,
|
||||
CefRefPtr<CefRunFileDialogCallback> callback)
|
||||
: host_(host),
|
||||
callback_(callback) {
|
||||
void RunFileDialogDismissed(
|
||||
CefRefPtr<CefRunFileDialogCallback> callback,
|
||||
int selected_accept_filter,
|
||||
const std::vector<base::FilePath>& file_paths) {
|
||||
std::vector<CefString> paths;
|
||||
if (file_paths.size() > 0) {
|
||||
for (size_t i = 0; i < file_paths.size(); ++i)
|
||||
paths.push_back(file_paths[i].value());
|
||||
}
|
||||
|
||||
void Callback(const std::vector<base::FilePath>& file_paths) {
|
||||
std::vector<CefString> paths;
|
||||
if (file_paths.size() > 0) {
|
||||
for (size_t i = 0; i < file_paths.size(); ++i)
|
||||
paths.push_back(file_paths[i].value());
|
||||
}
|
||||
callback_->OnFileDialogDismissed(host_, paths);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class base::RefCountedThreadSafe<CefRunFileDialogCallbackWrapper>;
|
||||
|
||||
~CefRunFileDialogCallbackWrapper() {}
|
||||
|
||||
CefRefPtr<CefBrowserHost> host_;
|
||||
CefRefPtr<CefRunFileDialogCallback> callback_;
|
||||
};
|
||||
callback->OnFileDialogDismissed(selected_accept_filter, paths);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
@ -712,38 +699,47 @@ void CefBrowserHostImpl::SetZoomLevel(double zoomLevel) {
|
|||
void CefBrowserHostImpl::RunFileDialog(
|
||||
FileDialogMode mode,
|
||||
const CefString& title,
|
||||
const CefString& default_file_name,
|
||||
const std::vector<CefString>& accept_types,
|
||||
const CefString& default_file_path,
|
||||
const std::vector<CefString>& accept_filters,
|
||||
int selected_accept_filter,
|
||||
CefRefPtr<CefRunFileDialogCallback> callback) {
|
||||
DCHECK(callback.get());
|
||||
if (!callback.get())
|
||||
return;
|
||||
|
||||
content::FileChooserParams params;
|
||||
switch (mode) {
|
||||
FileChooserParams params;
|
||||
switch (mode & FILE_DIALOG_TYPE_MASK) {
|
||||
case FILE_DIALOG_OPEN:
|
||||
params.mode = content::FileChooserParams::Open;
|
||||
break;
|
||||
case FILE_DIALOG_OPEN_MULTIPLE:
|
||||
params.mode = content::FileChooserParams::OpenMultiple;
|
||||
break;
|
||||
case FILE_DIALOG_OPEN_FOLDER:
|
||||
params.mode = content::FileChooserParams::UploadFolder;
|
||||
break;
|
||||
case FILE_DIALOG_SAVE:
|
||||
params.mode = content::FileChooserParams::Save;
|
||||
break;
|
||||
}
|
||||
|
||||
DCHECK_GE(selected_accept_filter, 0);
|
||||
params.selected_accept_filter = selected_accept_filter;
|
||||
|
||||
params.overwriteprompt = !!(mode & FILE_DIALOG_OVERWRITEPROMPT_FLAG);
|
||||
params.hidereadonly = !!(mode & FILE_DIALOG_HIDEREADONLY_FLAG);
|
||||
|
||||
params.title = title;
|
||||
if (!default_file_name.empty())
|
||||
params.default_file_name = base::FilePath(default_file_name);
|
||||
if (!accept_types.empty()) {
|
||||
std::vector<CefString>::const_iterator it = accept_types.begin();
|
||||
for (; it != accept_types.end(); ++it)
|
||||
if (!default_file_path.empty())
|
||||
params.default_file_name = base::FilePath(default_file_path);
|
||||
|
||||
if (!accept_filters.empty()) {
|
||||
std::vector<CefString>::const_iterator it = accept_filters.begin();
|
||||
for (; it != accept_filters.end(); ++it)
|
||||
params.accept_types.push_back(*it);
|
||||
}
|
||||
|
||||
scoped_refptr<CefRunFileDialogCallbackWrapper> wrapper =
|
||||
new CefRunFileDialogCallbackWrapper(this, callback);
|
||||
RunFileChooser(params,
|
||||
base::Bind(&CefRunFileDialogCallbackWrapper::Callback, wrapper));
|
||||
RunFileChooser(params, base::Bind(RunFileDialogDismissed, callback));
|
||||
}
|
||||
|
||||
void CefBrowserHostImpl::StartDownload(const CefString& url) {
|
||||
|
@ -1773,7 +1769,7 @@ void CefBrowserHostImpl::OnSetFocus(cef_focus_source_t source) {
|
|||
}
|
||||
|
||||
void CefBrowserHostImpl::RunFileChooser(
|
||||
const content::FileChooserParams& params,
|
||||
const FileChooserParams& params,
|
||||
const RunFileChooserCallback& callback) {
|
||||
CEF_POST_TASK(CEF_UIT,
|
||||
base::Bind(&CefBrowserHostImpl::RunFileChooserOnUIThread, this, params,
|
||||
|
@ -2269,7 +2265,7 @@ void CefBrowserHostImpl::WebContentsCreated(
|
|||
}
|
||||
|
||||
void CefBrowserHostImpl::DidNavigateMainFramePostCommit(
|
||||
content::WebContents* tab) {
|
||||
content::WebContents* web_contents) {
|
||||
base::AutoLock lock_scope(state_lock_);
|
||||
has_document_ = false;
|
||||
}
|
||||
|
@ -2283,15 +2279,25 @@ content::JavaScriptDialogManager*
|
|||
}
|
||||
|
||||
void CefBrowserHostImpl::RunFileChooser(
|
||||
content::WebContents* tab,
|
||||
content::WebContents* web_contents,
|
||||
const content::FileChooserParams& params) {
|
||||
content::RenderViewHost* render_view_host = tab->GetRenderViewHost();
|
||||
content::RenderViewHost* render_view_host = web_contents->GetRenderViewHost();
|
||||
if (!render_view_host)
|
||||
return;
|
||||
|
||||
RunFileChooserOnUIThread(params,
|
||||
if (params.mode == content::FileChooserParams::UploadFolder) {
|
||||
// TODO(cef): Implement the logic necessary for the 'webkitdirectory'
|
||||
// attribute. See CEF issue #958.
|
||||
OnRunFileChooserDelegateCallback(
|
||||
web_contents, params.mode, 0, std::vector<base::FilePath>());
|
||||
return;
|
||||
}
|
||||
|
||||
FileChooserParams cef_params;
|
||||
static_cast<content::FileChooserParams&>(cef_params) = params;
|
||||
RunFileChooserOnUIThread(cef_params,
|
||||
base::Bind(&CefBrowserHostImpl::OnRunFileChooserDelegateCallback, this,
|
||||
tab, params.mode));
|
||||
web_contents, params.mode));
|
||||
}
|
||||
|
||||
bool CefBrowserHostImpl::SetPendingPopupInfo(
|
||||
|
@ -2931,19 +2937,13 @@ void CefBrowserHostImpl::OnLoadEnd(CefRefPtr<CefFrame> frame,
|
|||
}
|
||||
|
||||
void CefBrowserHostImpl::RunFileChooserOnUIThread(
|
||||
const content::FileChooserParams& params,
|
||||
const FileChooserParams& params,
|
||||
const RunFileChooserCallback& callback) {
|
||||
CEF_REQUIRE_UIT();
|
||||
|
||||
if (file_chooser_pending_) {
|
||||
// Dismiss the new dialog immediately.
|
||||
callback.Run(std::vector<base::FilePath>());
|
||||
return;
|
||||
}
|
||||
|
||||
if (params.mode == content::FileChooserParams::UploadFolder) {
|
||||
NOTIMPLEMENTED();
|
||||
callback.Run(std::vector<base::FilePath>());
|
||||
callback.Run(0, std::vector<base::FilePath>());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2958,7 +2958,7 @@ void CefBrowserHostImpl::RunFileChooserOnUIThread(
|
|||
if (client_.get()) {
|
||||
CefRefPtr<CefDialogHandler> handler = client_->GetDialogHandler();
|
||||
if (handler.get()) {
|
||||
cef_file_dialog_mode_t mode = FILE_DIALOG_OPEN;
|
||||
int mode = FILE_DIALOG_OPEN;
|
||||
switch (params.mode) {
|
||||
case content::FileChooserParams::Open:
|
||||
mode = FILE_DIALOG_OPEN;
|
||||
|
@ -2966,6 +2966,9 @@ void CefBrowserHostImpl::RunFileChooserOnUIThread(
|
|||
case content::FileChooserParams::OpenMultiple:
|
||||
mode = FILE_DIALOG_OPEN_MULTIPLE;
|
||||
break;
|
||||
case content::FileChooserParams::UploadFolder:
|
||||
mode = FILE_DIALOG_OPEN_FOLDER;
|
||||
break;
|
||||
case content::FileChooserParams::Save:
|
||||
mode = FILE_DIALOG_SAVE;
|
||||
break;
|
||||
|
@ -2974,17 +2977,28 @@ void CefBrowserHostImpl::RunFileChooserOnUIThread(
|
|||
break;
|
||||
}
|
||||
|
||||
std::vector<CefString> accept_types;
|
||||
std::vector<base::string16>::const_iterator it =
|
||||
params.accept_types.begin();
|
||||
if (params.overwriteprompt)
|
||||
mode |= FILE_DIALOG_OVERWRITEPROMPT_FLAG;
|
||||
if (params.hidereadonly)
|
||||
mode |= FILE_DIALOG_HIDEREADONLY_FLAG;
|
||||
|
||||
std::vector<base::string16>::const_iterator it;
|
||||
|
||||
std::vector<CefString> accept_filters;
|
||||
it = params.accept_types.begin();
|
||||
for (; it != params.accept_types.end(); ++it)
|
||||
accept_types.push_back(*it);
|
||||
accept_filters.push_back(*it);
|
||||
|
||||
CefRefPtr<CefFileDialogCallbackImpl> callbackImpl(
|
||||
new CefFileDialogCallbackImpl(host_callback));
|
||||
handled = handler->OnFileDialog(this, mode, params.title,
|
||||
params.default_file_name.value(),
|
||||
accept_types, callbackImpl.get());
|
||||
handled = handler->OnFileDialog(
|
||||
this,
|
||||
static_cast<cef_file_dialog_mode_t>(mode),
|
||||
params.title,
|
||||
params.default_file_name.value(),
|
||||
accept_filters,
|
||||
params.selected_accept_filter,
|
||||
callbackImpl.get());
|
||||
if (!handled) {
|
||||
if (callbackImpl->IsConnected()) {
|
||||
callbackImpl->Disconnect();
|
||||
|
@ -3003,22 +3017,25 @@ void CefBrowserHostImpl::RunFileChooserOnUIThread(
|
|||
|
||||
void CefBrowserHostImpl::OnRunFileChooserCallback(
|
||||
const RunFileChooserCallback& callback,
|
||||
int selected_accept_filter,
|
||||
const std::vector<base::FilePath>& file_paths) {
|
||||
CEF_REQUIRE_UIT();
|
||||
|
||||
file_chooser_pending_ = false;
|
||||
|
||||
// Execute the callback asynchronously.
|
||||
CEF_POST_TASK(CEF_UIT, base::Bind(callback, file_paths));
|
||||
CEF_POST_TASK(CEF_UIT,
|
||||
base::Bind(callback, selected_accept_filter, file_paths));
|
||||
}
|
||||
|
||||
void CefBrowserHostImpl::OnRunFileChooserDelegateCallback(
|
||||
content::WebContents* tab,
|
||||
content::WebContents* web_contents,
|
||||
content::FileChooserParams::Mode mode,
|
||||
int selected_accept_filter,
|
||||
const std::vector<base::FilePath>& file_paths) {
|
||||
CEF_REQUIRE_UIT();
|
||||
|
||||
content::RenderViewHost* render_view_host = tab->GetRenderViewHost();
|
||||
content::RenderViewHost* render_view_host = web_contents->GetRenderViewHost();
|
||||
if (!render_view_host)
|
||||
return;
|
||||
|
||||
|
|
|
@ -97,6 +97,18 @@ class CefBrowserHostImpl : public CefBrowserHost,
|
|||
virtual void OnResponse(const std::string& response) =0;
|
||||
};
|
||||
|
||||
// Extend content::FileChooserParams with some options unique to CEF.
|
||||
struct FileChooserParams : public content::FileChooserParams {
|
||||
// 0-based index of the selected value in |accept_types|.
|
||||
int selected_accept_filter = 0;
|
||||
|
||||
// True if the Save dialog should prompt before overwriting files.
|
||||
bool overwriteprompt = true;
|
||||
|
||||
// True if read-only files should be hidden.
|
||||
bool hidereadonly = true;
|
||||
};
|
||||
|
||||
~CefBrowserHostImpl() override;
|
||||
|
||||
// Create a new CefBrowserHostImpl instance.
|
||||
|
@ -142,8 +154,9 @@ class CefBrowserHostImpl : public CefBrowserHost,
|
|||
void RunFileDialog(
|
||||
FileDialogMode mode,
|
||||
const CefString& title,
|
||||
const CefString& default_file_name,
|
||||
const std::vector<CefString>& accept_types,
|
||||
const CefString& default_file_path,
|
||||
const std::vector<CefString>& accept_filters,
|
||||
int selected_accept_filter,
|
||||
CefRefPtr<CefRunFileDialogCallback> callback) override;
|
||||
void StartDownload(const CefString& url) override;
|
||||
void Print() override;
|
||||
|
@ -307,13 +320,13 @@ class CefBrowserHostImpl : public CefBrowserHost,
|
|||
void OnSetFocus(cef_focus_source_t source);
|
||||
|
||||
// The argument vector will be empty if the dialog was cancelled.
|
||||
typedef base::Callback<void(const std::vector<base::FilePath>&)>
|
||||
typedef base::Callback<void(int, const std::vector<base::FilePath>&)>
|
||||
RunFileChooserCallback;
|
||||
|
||||
// Run the file chooser dialog specified by |params|. Only a single dialog may
|
||||
// be pending at any given time. |callback| will be executed asynchronously
|
||||
// after the dialog is dismissed or if another dialog is already pending.
|
||||
void RunFileChooser(const content::FileChooserParams& params,
|
||||
void RunFileChooser(const FileChooserParams& params,
|
||||
const RunFileChooserCallback& callback);
|
||||
|
||||
// Used when creating a new popup window.
|
||||
|
@ -383,11 +396,11 @@ class CefBrowserHostImpl : public CefBrowserHost,
|
|||
const GURL& target_url,
|
||||
content::WebContents* new_contents) override;
|
||||
void DidNavigateMainFramePostCommit(
|
||||
content::WebContents* tab) override;
|
||||
content::WebContents* web_contents) override;
|
||||
content::JavaScriptDialogManager* GetJavaScriptDialogManager(
|
||||
content::WebContents* source) override;
|
||||
void RunFileChooser(
|
||||
content::WebContents* tab,
|
||||
content::WebContents* web_contents,
|
||||
const content::FileChooserParams& params) override;
|
||||
void FindReply(
|
||||
content::WebContents* web_contents,
|
||||
|
@ -528,7 +541,7 @@ class CefBrowserHostImpl : public CefBrowserHost,
|
|||
// Invoke platform specific handling for the external protocol.
|
||||
void PlatformHandleExternalProtocol(const GURL& url);
|
||||
// Invoke platform specific file chooser dialog.
|
||||
void PlatformRunFileChooser(const content::FileChooserParams& params,
|
||||
void PlatformRunFileChooser(const FileChooserParams& params,
|
||||
RunFileChooserCallback callback);
|
||||
|
||||
void PlatformTranslateKeyEvent(content::NativeWebKeyboardEvent& native_event,
|
||||
|
@ -565,17 +578,19 @@ class CefBrowserHostImpl : public CefBrowserHost,
|
|||
int http_status_code);
|
||||
|
||||
// Continuation from RunFileChooser.
|
||||
void RunFileChooserOnUIThread(const content::FileChooserParams& params,
|
||||
void RunFileChooserOnUIThread(const FileChooserParams& params,
|
||||
const RunFileChooserCallback& callback);
|
||||
|
||||
// Used with RunFileChooser to clear the |file_chooser_pending_| flag.
|
||||
void OnRunFileChooserCallback(const RunFileChooserCallback& callback,
|
||||
int selected_accept_filter,
|
||||
const std::vector<base::FilePath>& file_paths);
|
||||
|
||||
// Used with WebContentsDelegate::RunFileChooser to notify the WebContents.
|
||||
void OnRunFileChooserDelegateCallback(
|
||||
content::WebContents* tab,
|
||||
content::WebContents* web_contents,
|
||||
content::FileChooserParams::Mode mode,
|
||||
int selected_accept_filter,
|
||||
const std::vector<base::FilePath>& file_paths);
|
||||
|
||||
void OnDevToolsWebContentsDestroyed();
|
||||
|
|
|
@ -282,11 +282,10 @@ void CefBrowserHostImpl::PlatformHandleKeyboardEvent(
|
|||
}
|
||||
|
||||
void CefBrowserHostImpl::PlatformRunFileChooser(
|
||||
const content::FileChooserParams& params,
|
||||
const FileChooserParams& params,
|
||||
RunFileChooserCallback callback) {
|
||||
NOTIMPLEMENTED();
|
||||
std::vector<base::FilePath> files;
|
||||
callback.Run(files);
|
||||
callback.Run(0, std::vector<base::FilePath>());
|
||||
}
|
||||
|
||||
void CefBrowserHostImpl::PlatformHandleExternalProtocol(const GURL& url) {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "base/files/file_util.h"
|
||||
#include "base/mac/mac_util.h"
|
||||
#include "base/mac/scoped_nsautorelease_pool.h"
|
||||
#include "base/strings/string_split.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
|
@ -23,6 +24,7 @@
|
|||
#include "content/public/browser/render_widget_host_view.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/common/file_chooser_params.h"
|
||||
#include "grit/cef_strings.h"
|
||||
#include "grit/ui_strings.h"
|
||||
#include "net/base/mime_util.h"
|
||||
#include "third_party/WebKit/public/web/WebInputEvent.h"
|
||||
|
@ -170,33 +172,216 @@
|
|||
|
||||
@end
|
||||
|
||||
namespace {
|
||||
|
||||
base::string16 GetDescriptionFromMimeType(const std::string& mime_type) {
|
||||
// Check for wild card mime types and return an appropriate description.
|
||||
static const struct {
|
||||
const char* mime_type;
|
||||
int string_id;
|
||||
} kWildCardMimeTypes[] = {
|
||||
{ "audio", IDS_APP_AUDIO_FILES },
|
||||
{ "image", IDS_APP_IMAGE_FILES },
|
||||
{ "text", IDS_APP_TEXT_FILES },
|
||||
{ "video", IDS_APP_VIDEO_FILES },
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < arraysize(kWildCardMimeTypes); ++i) {
|
||||
if (mime_type == std::string(kWildCardMimeTypes[i].mime_type) + "/*")
|
||||
return l10n_util::GetStringUTF16(kWildCardMimeTypes[i].string_id);
|
||||
}
|
||||
|
||||
return base::string16();
|
||||
}
|
||||
|
||||
void AddFilters(NSPopUpButton *button,
|
||||
const std::vector<base::string16>& accept_filters,
|
||||
bool include_all_files,
|
||||
std::vector<std::vector<base::string16> >* all_extensions) {
|
||||
for (size_t i = 0; i < accept_filters.size(); ++i) {
|
||||
const base::string16& filter = accept_filters[i];
|
||||
if (filter.empty())
|
||||
continue;
|
||||
|
||||
std::vector<base::string16> extensions;
|
||||
base::string16 description;
|
||||
|
||||
size_t sep_index = filter.find('|');
|
||||
if (sep_index != std::string::npos) {
|
||||
// Treat as a filter of the form "Filter Name|.ext1;.ext2;.ext3".
|
||||
description = filter.substr(0, sep_index);
|
||||
|
||||
std::vector<base::string16> ext;
|
||||
base::SplitString(filter.substr(sep_index + 1), ';', &ext);
|
||||
for (size_t x = 0; x < ext.size(); ++x) {
|
||||
const base::string16& file_ext = ext[x];
|
||||
if (!file_ext.empty() && file_ext[0] == '.')
|
||||
extensions.push_back(file_ext);
|
||||
}
|
||||
} else if (filter[0] == '.') {
|
||||
// Treat as an extension beginning with the '.' character.
|
||||
extensions.push_back(filter);
|
||||
} else {
|
||||
// Otherwise convert mime type to one or more extensions.
|
||||
const std::string& ascii = base::UTF16ToASCII(filter);
|
||||
std::vector<base::FilePath::StringType> ext;
|
||||
net::GetExtensionsForMimeType(ascii, &ext);
|
||||
if (!ext.empty()) {
|
||||
for (size_t x = 0; x < ext.size(); ++x)
|
||||
extensions.push_back(base::ASCIIToUTF16("." + ext[x]));
|
||||
description = GetDescriptionFromMimeType(ascii);
|
||||
}
|
||||
}
|
||||
|
||||
if (extensions.empty())
|
||||
continue;
|
||||
|
||||
// Don't display a crazy number of extensions since the NSPopUpButton width
|
||||
// will keep growing.
|
||||
const size_t kMaxExtensions = 10;
|
||||
|
||||
base::string16 ext_str;
|
||||
for (size_t x = 0; x < std::min(kMaxExtensions, extensions.size()); ++x) {
|
||||
const base::string16& pattern = base::ASCIIToUTF16("*") + extensions[x];
|
||||
if (x != 0)
|
||||
ext_str += base::ASCIIToUTF16(";");
|
||||
ext_str += pattern;
|
||||
}
|
||||
|
||||
if (extensions.size() > kMaxExtensions)
|
||||
ext_str += base::ASCIIToUTF16(";...");
|
||||
|
||||
if (description.empty()) {
|
||||
description = ext_str;
|
||||
} else {
|
||||
description +=
|
||||
base::ASCIIToUTF16(" (") + ext_str + base::ASCIIToUTF16(")");
|
||||
}
|
||||
|
||||
[button addItemWithTitle:base::SysUTF16ToNSString(description)];
|
||||
|
||||
all_extensions->push_back(extensions);
|
||||
}
|
||||
|
||||
// Add the *.* filter, but only if we have added other filters (otherwise it
|
||||
// is implied).
|
||||
if (include_all_files && !all_extensions->empty()) {
|
||||
[button addItemWithTitle:base::SysUTF8ToNSString("All Files (*)")];
|
||||
all_extensions->push_back(std::vector<base::string16>());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Used to manage the file type filter in the NSSavePanel/NSOpenPanel.
|
||||
@interface CefFilterDelegate : NSObject {
|
||||
@private
|
||||
NSSavePanel* panel_;
|
||||
std::vector<std::vector<base::string16> > extensions_;
|
||||
int selected_index_;
|
||||
}
|
||||
- (id)initWithPanel:(NSSavePanel*)panel
|
||||
andAcceptFilters:(const std::vector<base::string16>&)accept_filters
|
||||
andFilterIndex:(int)index;
|
||||
- (void)setFilter:(int)index;
|
||||
- (int)filter;
|
||||
- (void)filterSelectionChanged:(id)sender;
|
||||
- (void)setFileExtension;
|
||||
@end
|
||||
|
||||
@implementation CefFilterDelegate
|
||||
|
||||
- (id)initWithPanel:(NSSavePanel*)panel
|
||||
andAcceptFilters:(const std::vector<base::string16>&)accept_filters
|
||||
andFilterIndex:(int)index {
|
||||
if (self = [super init]) {
|
||||
DCHECK(panel);
|
||||
panel_ = panel;
|
||||
selected_index_ = 0;
|
||||
|
||||
NSPopUpButton *button = [[NSPopUpButton alloc] init];
|
||||
AddFilters(button, accept_filters, true, &extensions_);
|
||||
[button sizeToFit];
|
||||
[button setTarget:self];
|
||||
[button setAction:@selector(filterSelectionChanged:)];
|
||||
|
||||
if (index < static_cast<int>(extensions_.size())) {
|
||||
[button selectItemAtIndex:index];
|
||||
[self setFilter:index];
|
||||
}
|
||||
|
||||
[panel_ setAccessoryView:button];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
// Set the current filter index.
|
||||
- (void)setFilter:(int)index {
|
||||
DCHECK(index >= 0 && index < static_cast<int>(extensions_.size()));
|
||||
selected_index_ = index;
|
||||
|
||||
// Set the selectable file types. For open panels this limits the files that
|
||||
// can be selected. For save panels this applies a default file extenion when
|
||||
// the dialog is dismissed if none is already provided.
|
||||
NSMutableArray* acceptArray = nil;
|
||||
if (!extensions_[index].empty()) {
|
||||
acceptArray = [[NSMutableArray alloc] init];
|
||||
for (size_t i = 0; i < extensions_[index].size(); ++i) {
|
||||
[acceptArray addObject:
|
||||
base::SysUTF16ToNSString(extensions_[index][i].substr(1))];
|
||||
}
|
||||
}
|
||||
[panel_ setAllowedFileTypes:acceptArray];
|
||||
|
||||
if (![panel_ isKindOfClass:[NSOpenPanel class]]) {
|
||||
// For save panels set the file extension.
|
||||
[self setFileExtension];
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the current filter index.
|
||||
- (int)filter {
|
||||
return selected_index_;
|
||||
}
|
||||
|
||||
// Called when the selected filter is changed via the NSPopUpButton.
|
||||
- (void)filterSelectionChanged:(id)sender {
|
||||
NSPopUpButton *button = (NSPopUpButton*)sender;
|
||||
[self setFilter:[button indexOfSelectedItem]];
|
||||
}
|
||||
|
||||
// Set the extension on the currently selected file name.
|
||||
- (void)setFileExtension {
|
||||
const std::vector<base::string16>& filter = extensions_[selected_index_];
|
||||
if (filter.empty()) {
|
||||
// All extensions are allowed so don't change anything.
|
||||
return;
|
||||
}
|
||||
|
||||
base::FilePath path(base::SysNSStringToUTF8([panel_ nameFieldStringValue]));
|
||||
|
||||
// If the file name currently includes an extension from |filter| then don't
|
||||
// change anything.
|
||||
base::string16 extension = base::UTF8ToUTF16(path.Extension());
|
||||
if (!extension.empty()) {
|
||||
for (size_t i = 0; i < filter.size(); ++i) {
|
||||
if (filter[i] == extension)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Change the extension to the first value in |filter|.
|
||||
path = path.ReplaceExtension(base::UTF16ToUTF8(filter[0]));
|
||||
[panel_ setNameFieldStringValue:base::SysUTF8ToNSString(path.value())];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
namespace {
|
||||
|
||||
// Accept-types to file-types helper.
|
||||
NSMutableArray* GetFileTypesFromAcceptTypes(
|
||||
const std::vector<base::string16>& accept_types) {
|
||||
NSMutableArray* acceptArray = [[NSMutableArray alloc] init];
|
||||
for (size_t i=0; i<accept_types.size(); i++) {
|
||||
std::string ascii_type = base::UTF16ToASCII(accept_types[i]);
|
||||
if (ascii_type.length()) {
|
||||
// Just treat as extension if contains '.' as the first character.
|
||||
if (ascii_type[0] == '.') {
|
||||
[acceptArray addObject:base::SysUTF8ToNSString(ascii_type.substr(1))];
|
||||
} else {
|
||||
// Otherwise convert mime type to one or more extensions.
|
||||
std::vector<base::FilePath::StringType> ext;
|
||||
net::GetExtensionsForMimeType(ascii_type, &ext);
|
||||
for (size_t x = 0; x < ext.size(); ++x)
|
||||
[acceptArray addObject:base::SysUTF8ToNSString(ext[x])];
|
||||
}
|
||||
}
|
||||
}
|
||||
return acceptArray;
|
||||
}
|
||||
|
||||
void RunOpenFileDialog(const content::FileChooserParams& params,
|
||||
void RunOpenFileDialog(const CefBrowserHostImpl::FileChooserParams& params,
|
||||
NSView* view,
|
||||
int* filter_index,
|
||||
std::vector<base::FilePath>* files) {
|
||||
NSOpenPanel* openPanel = [NSOpenPanel openPanel];
|
||||
|
||||
|
@ -206,39 +391,51 @@ void RunOpenFileDialog(const content::FileChooserParams& params,
|
|||
} else {
|
||||
title = l10n_util::GetStringUTF16(
|
||||
params.mode == content::FileChooserParams::Open ?
|
||||
IDS_OPEN_FILE_DIALOG_TITLE : IDS_OPEN_FILES_DIALOG_TITLE);
|
||||
IDS_OPEN_FILE_DIALOG_TITLE :
|
||||
(params.mode == content::FileChooserParams::OpenMultiple ?
|
||||
IDS_OPEN_FILES_DIALOG_TITLE : IDS_SELECT_FOLDER_DIALOG_TITLE));
|
||||
}
|
||||
[openPanel setTitle:base::SysUTF16ToNSString(title)];
|
||||
|
||||
// Consider default file name if any.
|
||||
base::FilePath default_file_name(params.default_file_name);
|
||||
|
||||
if (!default_file_name.empty()) {
|
||||
if (!default_file_name.BaseName().empty()) {
|
||||
NSString* defaultName = base::SysUTF8ToNSString(
|
||||
default_file_name.BaseName().value());
|
||||
[openPanel setNameFieldStringValue:defaultName];
|
||||
}
|
||||
|
||||
if (!default_file_name.DirName().empty()) {
|
||||
NSString* defaultDir = base::SysUTF8ToNSString(
|
||||
default_file_name.DirName().value());
|
||||
[openPanel setDirectoryURL:[NSURL fileURLWithPath:defaultDir]];
|
||||
std::string filename, directory;
|
||||
if (!params.default_file_name.empty()) {
|
||||
if (params.mode == content::FileChooserParams::UploadFolder ||
|
||||
params.default_file_name.EndsWithSeparator()) {
|
||||
// The value is only a directory.
|
||||
directory = params.default_file_name.value();
|
||||
} else {
|
||||
// The value is a file name and possibly a directory.
|
||||
filename = params.default_file_name.BaseName().value();
|
||||
directory = params.default_file_name.DirName().value();
|
||||
}
|
||||
}
|
||||
if (!filename.empty()) {
|
||||
[openPanel setNameFieldStringValue:base::SysUTF8ToNSString(filename)];
|
||||
}
|
||||
if (!directory.empty()) {
|
||||
[openPanel setDirectoryURL:
|
||||
[NSURL fileURLWithPath:base::SysUTF8ToNSString(directory)]];
|
||||
}
|
||||
|
||||
// Consider supported file types
|
||||
if (!params.accept_types.empty()) {
|
||||
[openPanel setAllowedFileTypes:GetFileTypesFromAcceptTypes(
|
||||
params.accept_types)];
|
||||
CefFilterDelegate* filter_delegate = nil;
|
||||
if (params.mode != content::FileChooserParams::UploadFolder &&
|
||||
!params.accept_types.empty()) {
|
||||
// Add the file filter control.
|
||||
filter_delegate =
|
||||
[[CefFilterDelegate alloc] initWithPanel:openPanel
|
||||
andAcceptFilters:params.accept_types
|
||||
andFilterIndex:*filter_index];
|
||||
}
|
||||
|
||||
// Further panel configuration.
|
||||
[openPanel setAllowsOtherFileTypes:YES];
|
||||
[openPanel setAllowsMultipleSelection:
|
||||
(params.mode == content::FileChooserParams::OpenMultiple)];
|
||||
[openPanel setCanChooseFiles:YES];
|
||||
[openPanel setCanChooseDirectories:NO];
|
||||
[openPanel setCanChooseFiles:
|
||||
(params.mode != content::FileChooserParams::UploadFolder)];
|
||||
[openPanel setCanChooseDirectories:
|
||||
(params.mode == content::FileChooserParams::UploadFolder)];
|
||||
[openPanel setShowsHiddenFiles:!params.hidereadonly];
|
||||
|
||||
// Show panel.
|
||||
[openPanel beginSheetModalForWindow:[view window] completionHandler:nil];
|
||||
|
@ -251,11 +448,16 @@ void RunOpenFileDialog(const content::FileChooserParams& params,
|
|||
files->push_back(base::FilePath(base::SysNSStringToUTF8([url path])));
|
||||
}
|
||||
}
|
||||
|
||||
if (filter_delegate != nil)
|
||||
*filter_index = [filter_delegate filter];
|
||||
|
||||
[NSApp endSheet:openPanel];
|
||||
}
|
||||
|
||||
bool RunSaveFileDialog(const content::FileChooserParams& params,
|
||||
bool RunSaveFileDialog(const CefBrowserHostImpl::FileChooserParams& params,
|
||||
NSView* view,
|
||||
int* filter_index,
|
||||
base::FilePath* file) {
|
||||
NSSavePanel* savePanel = [NSSavePanel savePanel];
|
||||
|
||||
|
@ -266,30 +468,36 @@ bool RunSaveFileDialog(const content::FileChooserParams& params,
|
|||
title = l10n_util::GetStringUTF16(IDS_SAVE_AS_DIALOG_TITLE);
|
||||
[savePanel setTitle:base::SysUTF16ToNSString(title)];
|
||||
|
||||
// Consider default file name if any.
|
||||
base::FilePath default_file_name(params.default_file_name);
|
||||
|
||||
if (!default_file_name.empty()) {
|
||||
if (!default_file_name.BaseName().empty()) {
|
||||
NSString* defaultName = base::SysUTF8ToNSString(
|
||||
default_file_name.BaseName().value());
|
||||
[savePanel setNameFieldStringValue:defaultName];
|
||||
}
|
||||
|
||||
if (!default_file_name.DirName().empty()) {
|
||||
NSString* defaultDir = base::SysUTF8ToNSString(
|
||||
default_file_name.DirName().value());
|
||||
[savePanel setDirectoryURL:[NSURL fileURLWithPath:defaultDir]];
|
||||
std::string filename, directory;
|
||||
if (!params.default_file_name.empty()) {
|
||||
if (params.default_file_name.EndsWithSeparator()) {
|
||||
// The value is only a directory.
|
||||
directory = params.default_file_name.value();
|
||||
} else {
|
||||
// The value is a file name and possibly a directory.
|
||||
filename = params.default_file_name.BaseName().value();
|
||||
directory = params.default_file_name.DirName().value();
|
||||
}
|
||||
}
|
||||
if (!filename.empty()) {
|
||||
[savePanel setNameFieldStringValue:base::SysUTF8ToNSString(filename)];
|
||||
}
|
||||
if (!directory.empty()) {
|
||||
[savePanel setDirectoryURL:
|
||||
[NSURL fileURLWithPath:base::SysUTF8ToNSString(directory)]];
|
||||
}
|
||||
|
||||
// Consider supported file types
|
||||
CefFilterDelegate* filter_delegate = nil;
|
||||
if (!params.accept_types.empty()) {
|
||||
[savePanel setAllowedFileTypes:GetFileTypesFromAcceptTypes(
|
||||
params.accept_types)];
|
||||
// Add the file filter control.
|
||||
filter_delegate =
|
||||
[[CefFilterDelegate alloc] initWithPanel:savePanel
|
||||
andAcceptFilters:params.accept_types
|
||||
andFilterIndex:*filter_index];
|
||||
}
|
||||
|
||||
[savePanel setAllowsOtherFileTypes:YES];
|
||||
[savePanel setShowsHiddenFiles:!params.hidereadonly];
|
||||
|
||||
bool success = false;
|
||||
|
||||
|
@ -300,6 +508,10 @@ bool RunSaveFileDialog(const content::FileChooserParams& params,
|
|||
*file = base::FilePath([path UTF8String]);
|
||||
success = true;
|
||||
}
|
||||
|
||||
if (filter_delegate != nil)
|
||||
*filter_index = [filter_delegate filter];
|
||||
|
||||
[NSApp endSheet:savePanel];
|
||||
|
||||
return success;
|
||||
|
@ -491,22 +703,26 @@ void CefBrowserHostImpl::PlatformHandleKeyboardEvent(
|
|||
}
|
||||
|
||||
void CefBrowserHostImpl::PlatformRunFileChooser(
|
||||
const content::FileChooserParams& params,
|
||||
const FileChooserParams& params,
|
||||
RunFileChooserCallback callback) {
|
||||
std::vector<base::FilePath> files;
|
||||
int filter_index = params.selected_accept_filter;
|
||||
NSView* owner = PlatformGetWindowHandle();
|
||||
|
||||
if (params.mode == content::FileChooserParams::Open ||
|
||||
params.mode == content::FileChooserParams::OpenMultiple) {
|
||||
RunOpenFileDialog(params, PlatformGetWindowHandle(), &files);
|
||||
params.mode == content::FileChooserParams::OpenMultiple ||
|
||||
params.mode == content::FileChooserParams::UploadFolder) {
|
||||
RunOpenFileDialog(params, owner, &filter_index, &files);
|
||||
} else if (params.mode == content::FileChooserParams::Save) {
|
||||
base::FilePath file;
|
||||
if (RunSaveFileDialog(params, PlatformGetWindowHandle(), &file))
|
||||
if (RunSaveFileDialog(params, owner, &filter_index, &file)) {
|
||||
files.push_back(file);
|
||||
}
|
||||
} else {
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
|
||||
callback.Run(files);
|
||||
callback.Run(filter_index, files);
|
||||
}
|
||||
|
||||
void CefBrowserHostImpl::PlatformHandleExternalProtocol(const GURL& url) {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <commdlg.h>
|
||||
#include <dwmapi.h>
|
||||
#include <shellapi.h>
|
||||
#include <shlobj.h>
|
||||
#include <wininet.h>
|
||||
#include <winspool.h>
|
||||
|
||||
|
@ -19,9 +20,11 @@
|
|||
#include "base/files/file_util.h"
|
||||
#include "base/i18n/case_conversion.h"
|
||||
#include "base/memory/ref_counted_memory.h"
|
||||
#include "base/strings/string_split.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/win/registry.h"
|
||||
#include "base/win/scoped_comptr.h"
|
||||
#include "base/win/windows_version.h"
|
||||
#include "content/common/cursors/webcursor.h"
|
||||
#include "content/public/browser/native_web_keyboard_event.h"
|
||||
|
@ -140,14 +143,8 @@ std::wstring FormatFilterForExtensions(
|
|||
ext_name = ext_name.substr(ext_index);
|
||||
|
||||
if (!GetRegistryDescriptionFromExtension(first_extension, &desc)) {
|
||||
// The extension doesn't exist in the registry. Create a description
|
||||
// based on the unknown extension type (i.e. if the extension is .qqq,
|
||||
// the we create a description "QQQ File (.qqq)").
|
||||
// The extension doesn't exist in the registry.
|
||||
include_all_files = true;
|
||||
desc = l10n_util::GetStringFUTF16(
|
||||
IDS_APP_SAVEAS_EXTENSION_FORMAT,
|
||||
base::i18n::ToUpper(base::WideToUTF16(ext_name)),
|
||||
ext_name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -189,33 +186,54 @@ std::wstring GetDescriptionFromMimeType(const std::string& mime_type) {
|
|||
return std::wstring();
|
||||
}
|
||||
|
||||
std::wstring GetFilterStringFromAcceptTypes(
|
||||
const std::vector<base::string16>& accept_types) {
|
||||
std::wstring GetFilterString(
|
||||
const std::vector<base::string16>& accept_filters) {
|
||||
std::vector<std::wstring> extensions;
|
||||
std::vector<std::wstring> descriptions;
|
||||
|
||||
for (size_t i = 0; i < accept_types.size(); ++i) {
|
||||
std::string ascii_type = base::UTF16ToASCII(accept_types[i]);
|
||||
if (ascii_type.length()) {
|
||||
// Just treat as extension if contains '.' as the first character.
|
||||
if (ascii_type[0] == '.') {
|
||||
extensions.push_back(L"*" + base::ASCIIToUTF16(ascii_type));
|
||||
descriptions.push_back(std::wstring());
|
||||
} else {
|
||||
// Otherwise convert mime type to one or more extensions.
|
||||
std::vector<base::FilePath::StringType> ext;
|
||||
std::wstring ext_str;
|
||||
net::GetExtensionsForMimeType(ascii_type, &ext);
|
||||
if (ext.size() > 0) {
|
||||
for (size_t x = 0; x < ext.size(); ++x) {
|
||||
if (x != 0)
|
||||
ext_str += L";";
|
||||
ext_str += L"*." + ext[x];
|
||||
}
|
||||
extensions.push_back(ext_str);
|
||||
descriptions.push_back(GetDescriptionFromMimeType(ascii_type));
|
||||
for (size_t i = 0; i < accept_filters.size(); ++i) {
|
||||
const base::string16& filter = accept_filters[i];
|
||||
if (filter.empty())
|
||||
continue;
|
||||
|
||||
size_t sep_index = filter.find('|');
|
||||
if (sep_index != base::string16::npos) {
|
||||
// Treat as a filter of the form "Filter Name|.ext1;.ext2;.ext3".
|
||||
const base::string16& desc = filter.substr(0, sep_index);
|
||||
std::vector<base::string16> ext;
|
||||
base::SplitString(filter.substr(sep_index + 1), ';', &ext);
|
||||
std::wstring ext_str;
|
||||
for (size_t x = 0; x < ext.size(); ++x) {
|
||||
const base::string16& file_ext = ext[x];
|
||||
if (!file_ext.empty() && file_ext[0] == '.') {
|
||||
if (!ext_str.empty())
|
||||
ext_str += L";";
|
||||
ext_str += L"*" + file_ext;
|
||||
}
|
||||
}
|
||||
if (!ext_str.empty()) {
|
||||
extensions.push_back(ext_str);
|
||||
descriptions.push_back(desc);
|
||||
}
|
||||
} else if (filter[0] == L'.') {
|
||||
// Treat as an extension beginning with the '.' character.
|
||||
extensions.push_back(L"*" + filter);
|
||||
descriptions.push_back(std::wstring());
|
||||
} else {
|
||||
// Otherwise convert mime type to one or more extensions.
|
||||
const std::string& ascii = base::UTF16ToASCII(filter);
|
||||
std::vector<base::FilePath::StringType> ext;
|
||||
std::wstring ext_str;
|
||||
net::GetExtensionsForMimeType(ascii, &ext);
|
||||
if (!ext.empty()) {
|
||||
for (size_t x = 0; x < ext.size(); ++x) {
|
||||
if (x != 0)
|
||||
ext_str += L";";
|
||||
ext_str += L"*." + ext[x];
|
||||
}
|
||||
extensions.push_back(ext_str);
|
||||
descriptions.push_back(GetDescriptionFromMimeType(ascii));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -224,8 +242,9 @@ std::wstring GetFilterStringFromAcceptTypes(
|
|||
|
||||
// from chrome/browser/views/shell_dialogs_win.cc
|
||||
|
||||
bool RunOpenFileDialog(const content::FileChooserParams& params,
|
||||
bool RunOpenFileDialog(const CefBrowserHostImpl::FileChooserParams& params,
|
||||
HWND owner,
|
||||
int* filter_index,
|
||||
base::FilePath* path) {
|
||||
OPENFILENAME ofn;
|
||||
|
||||
|
@ -235,22 +254,25 @@ bool RunOpenFileDialog(const content::FileChooserParams& params,
|
|||
ofn.lStructSize = sizeof(ofn);
|
||||
ofn.hwndOwner = owner;
|
||||
|
||||
// Consider default file name if any.
|
||||
base::FilePath default_file_name(params.default_file_name);
|
||||
|
||||
wchar_t filename[MAX_PATH] = {0};
|
||||
|
||||
ofn.lpstrFile = filename;
|
||||
ofn.nMaxFile = MAX_PATH;
|
||||
|
||||
std::wstring directory;
|
||||
if (!default_file_name.empty()) {
|
||||
base::wcslcpy(filename, default_file_name.value().c_str(),
|
||||
arraysize(filename));
|
||||
|
||||
directory = default_file_name.DirName().value();
|
||||
ofn.lpstrInitialDir = directory.c_str();
|
||||
if (!params.default_file_name.empty()) {
|
||||
if (params.default_file_name.EndsWithSeparator()) {
|
||||
// The value is only a directory.
|
||||
directory = params.default_file_name.value();
|
||||
} else {
|
||||
// The value is a file name and possibly a directory.
|
||||
base::wcslcpy(filename, params.default_file_name.value().c_str(),
|
||||
arraysize(filename));
|
||||
directory = params.default_file_name.DirName().value();
|
||||
}
|
||||
}
|
||||
if (!directory.empty())
|
||||
ofn.lpstrInitialDir = directory.c_str();
|
||||
|
||||
std::wstring title;
|
||||
if (!params.title.empty())
|
||||
|
@ -264,19 +286,27 @@ bool RunOpenFileDialog(const content::FileChooserParams& params,
|
|||
// without having to close Chrome first.
|
||||
ofn.Flags = OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR | OFN_EXPLORER |
|
||||
OFN_ENABLESIZING;
|
||||
if (params.hidereadonly)
|
||||
ofn.Flags |= OFN_HIDEREADONLY;
|
||||
|
||||
std::wstring filter = GetFilterStringFromAcceptTypes(params.accept_types);
|
||||
if (!filter.empty())
|
||||
const std::wstring& filter = GetFilterString(params.accept_types);
|
||||
if (!filter.empty()) {
|
||||
ofn.lpstrFilter = filter.c_str();
|
||||
// Indices into |lpstrFilter| start at 1.
|
||||
ofn.nFilterIndex = *filter_index + 1;
|
||||
}
|
||||
|
||||
bool success = !!GetOpenFileName(&ofn);
|
||||
if (success)
|
||||
if (success) {
|
||||
*filter_index = ofn.nFilterIndex == 0 ? 0 : ofn.nFilterIndex - 1;
|
||||
*path = base::FilePath(filename);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool RunOpenMultiFileDialog(const content::FileChooserParams& params,
|
||||
bool RunOpenMultiFileDialog(const CefBrowserHostImpl::FileChooserParams& params,
|
||||
HWND owner,
|
||||
int* filter_index,
|
||||
std::vector<base::FilePath>* paths) {
|
||||
OPENFILENAME ofn;
|
||||
|
||||
|
@ -292,6 +322,19 @@ bool RunOpenMultiFileDialog(const content::FileChooserParams& params,
|
|||
ofn.lpstrFile = filename.get();
|
||||
ofn.nMaxFile = UNICODE_STRING_MAX_CHARS;
|
||||
|
||||
std::wstring directory;
|
||||
if (!params.default_file_name.empty()) {
|
||||
if (params.default_file_name.EndsWithSeparator()) {
|
||||
// The value is only a directory.
|
||||
directory = params.default_file_name.value();
|
||||
} else {
|
||||
// The value is a file name and possibly a directory.
|
||||
directory = params.default_file_name.DirName().value();
|
||||
}
|
||||
}
|
||||
if (!directory.empty())
|
||||
ofn.lpstrInitialDir = directory.c_str();
|
||||
|
||||
std::wstring title;
|
||||
if (!params.title.empty())
|
||||
title = params.title;
|
||||
|
@ -303,11 +346,16 @@ bool RunOpenMultiFileDialog(const content::FileChooserParams& params,
|
|||
// We use OFN_NOCHANGEDIR so that the user can rename or delete the directory
|
||||
// without having to close Chrome first.
|
||||
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER |
|
||||
OFN_HIDEREADONLY | OFN_ALLOWMULTISELECT | OFN_ENABLESIZING;
|
||||
OFN_ALLOWMULTISELECT | OFN_ENABLESIZING;
|
||||
if (params.hidereadonly)
|
||||
ofn.Flags |= OFN_HIDEREADONLY;
|
||||
|
||||
std::wstring filter = GetFilterStringFromAcceptTypes(params.accept_types);
|
||||
if (!filter.empty())
|
||||
const std::wstring& filter = GetFilterString(params.accept_types);
|
||||
if (!filter.empty()) {
|
||||
ofn.lpstrFilter = filter.c_str();
|
||||
// Indices into |lpstrFilter| start at 1.
|
||||
ofn.nFilterIndex = *filter_index + 1;
|
||||
}
|
||||
|
||||
bool success = !!GetOpenFileName(&ofn);
|
||||
|
||||
|
@ -334,11 +382,84 @@ bool RunOpenMultiFileDialog(const content::FileChooserParams& params,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (success)
|
||||
*filter_index = ofn.nFilterIndex == 0 ? 0 : ofn.nFilterIndex - 1;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool RunSaveFileDialog(const content::FileChooserParams& params,
|
||||
// The callback function for when the select folder dialog is opened.
|
||||
int CALLBACK BrowseCallbackProc(HWND window,
|
||||
UINT message,
|
||||
LPARAM parameter,
|
||||
LPARAM data)
|
||||
{
|
||||
if (message == BFFM_INITIALIZED) {
|
||||
// WParam is TRUE since passing a path.
|
||||
// data lParam member of the BROWSEINFO structure.
|
||||
SendMessage(window, BFFM_SETSELECTION, TRUE, (LPARAM)data);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool RunOpenFolderDialog(const CefBrowserHostImpl::FileChooserParams& params,
|
||||
HWND owner,
|
||||
base::FilePath* path) {
|
||||
wchar_t dir_buffer[MAX_PATH + 1] = {0};
|
||||
|
||||
bool result = false;
|
||||
BROWSEINFO browse_info = {0};
|
||||
browse_info.hwndOwner = owner;
|
||||
browse_info.pszDisplayName = dir_buffer;
|
||||
browse_info.ulFlags = BIF_USENEWUI | BIF_RETURNONLYFSDIRS;
|
||||
|
||||
std::wstring title;
|
||||
if (!params.title.empty())
|
||||
title = params.title;
|
||||
else
|
||||
title = l10n_util::GetStringUTF16(IDS_SELECT_FOLDER_DIALOG_TITLE);
|
||||
if (!title.empty())
|
||||
browse_info.lpszTitle = title.c_str();
|
||||
|
||||
const std::wstring& file_path = params.default_file_name.value();
|
||||
if (!file_path.empty()) {
|
||||
// Highlight the current value.
|
||||
browse_info.lParam = (LPARAM)file_path.c_str();
|
||||
browse_info.lpfn = &BrowseCallbackProc;
|
||||
}
|
||||
|
||||
LPITEMIDLIST list = SHBrowseForFolder(&browse_info);
|
||||
if (list) {
|
||||
STRRET out_dir_buffer;
|
||||
ZeroMemory(&out_dir_buffer, sizeof(out_dir_buffer));
|
||||
out_dir_buffer.uType = STRRET_WSTR;
|
||||
base::win::ScopedComPtr<IShellFolder> shell_folder;
|
||||
if (SHGetDesktopFolder(shell_folder.Receive()) == NOERROR) {
|
||||
HRESULT hr = shell_folder->GetDisplayNameOf(list, SHGDN_FORPARSING,
|
||||
&out_dir_buffer);
|
||||
if (SUCCEEDED(hr) && out_dir_buffer.uType == STRRET_WSTR) {
|
||||
*path = base::FilePath(out_dir_buffer.pOleStr);
|
||||
CoTaskMemFree(out_dir_buffer.pOleStr);
|
||||
result = true;
|
||||
} else {
|
||||
// Use old way if we don't get what we want.
|
||||
wchar_t old_out_dir_buffer[MAX_PATH + 1];
|
||||
if (SHGetPathFromIDList(list, old_out_dir_buffer)) {
|
||||
*path = base::FilePath(old_out_dir_buffer);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
CoTaskMemFree(list);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool RunSaveFileDialog(const CefBrowserHostImpl::FileChooserParams& params,
|
||||
HWND owner,
|
||||
int* filter_index,
|
||||
base::FilePath* path) {
|
||||
OPENFILENAME ofn;
|
||||
|
||||
|
@ -348,22 +469,25 @@ bool RunSaveFileDialog(const content::FileChooserParams& params,
|
|||
ofn.lStructSize = sizeof(ofn);
|
||||
ofn.hwndOwner = owner;
|
||||
|
||||
// Consider default file name if any.
|
||||
base::FilePath default_file_name(params.default_file_name);
|
||||
|
||||
wchar_t filename[MAX_PATH] = {0};
|
||||
|
||||
ofn.lpstrFile = filename;
|
||||
ofn.nMaxFile = MAX_PATH;
|
||||
|
||||
std::wstring directory;
|
||||
if (!default_file_name.empty()) {
|
||||
base::wcslcpy(filename, default_file_name.value().c_str(),
|
||||
arraysize(filename));
|
||||
|
||||
directory = default_file_name.DirName().value();
|
||||
ofn.lpstrInitialDir = directory.c_str();
|
||||
if (!params.default_file_name.empty()) {
|
||||
if (params.default_file_name.EndsWithSeparator()) {
|
||||
// The value is only a directory.
|
||||
directory = params.default_file_name.value();
|
||||
} else {
|
||||
// The value is a file name and possibly a directory.
|
||||
base::wcslcpy(filename, params.default_file_name.value().c_str(),
|
||||
arraysize(filename));
|
||||
directory = params.default_file_name.DirName().value();
|
||||
}
|
||||
}
|
||||
if (!directory.empty())
|
||||
ofn.lpstrInitialDir = directory.c_str();
|
||||
|
||||
std::wstring title;
|
||||
if (!params.title.empty())
|
||||
|
@ -375,16 +499,25 @@ bool RunSaveFileDialog(const content::FileChooserParams& params,
|
|||
|
||||
// We use OFN_NOCHANGEDIR so that the user can rename or delete the directory
|
||||
// without having to close Chrome first.
|
||||
ofn.Flags = OFN_OVERWRITEPROMPT | OFN_EXPLORER | OFN_ENABLESIZING |
|
||||
OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST;
|
||||
ofn.Flags = OFN_EXPLORER | OFN_ENABLESIZING | OFN_NOCHANGEDIR |
|
||||
OFN_PATHMUSTEXIST;
|
||||
if (params.hidereadonly)
|
||||
ofn.Flags |= OFN_HIDEREADONLY;
|
||||
if (params.overwriteprompt)
|
||||
ofn.Flags |= OFN_OVERWRITEPROMPT;
|
||||
|
||||
std::wstring filter = GetFilterStringFromAcceptTypes(params.accept_types);
|
||||
if (!filter.empty())
|
||||
const std::wstring& filter = GetFilterString(params.accept_types);
|
||||
if (!filter.empty()) {
|
||||
ofn.lpstrFilter = filter.c_str();
|
||||
// Indices into |lpstrFilter| start at 1.
|
||||
ofn.nFilterIndex = *filter_index + 1;
|
||||
}
|
||||
|
||||
bool success = !!GetSaveFileName(&ofn);
|
||||
if (success)
|
||||
if (success) {
|
||||
*filter_index = ofn.nFilterIndex == 0 ? 0 : ofn.nFilterIndex - 1;
|
||||
*path = base::FilePath(filename);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
@ -782,25 +915,32 @@ void CefBrowserHostImpl::PlatformHandleKeyboardEvent(
|
|||
}
|
||||
|
||||
void CefBrowserHostImpl::PlatformRunFileChooser(
|
||||
const content::FileChooserParams& params,
|
||||
const FileChooserParams& params,
|
||||
RunFileChooserCallback callback) {
|
||||
int filter_index = params.selected_accept_filter;
|
||||
std::vector<base::FilePath> files;
|
||||
|
||||
HWND owner = PlatformGetWindowHandle();
|
||||
|
||||
if (params.mode == content::FileChooserParams::Open) {
|
||||
base::FilePath file;
|
||||
if (RunOpenFileDialog(params, PlatformGetWindowHandle(), &file))
|
||||
if (RunOpenFileDialog(params, owner, &filter_index, &file))
|
||||
files.push_back(file);
|
||||
} else if (params.mode == content::FileChooserParams::OpenMultiple) {
|
||||
RunOpenMultiFileDialog(params, PlatformGetWindowHandle(), &files);
|
||||
RunOpenMultiFileDialog(params, owner, &filter_index, &files);
|
||||
} else if (params.mode == content::FileChooserParams::UploadFolder) {
|
||||
base::FilePath file;
|
||||
if (RunOpenFolderDialog(params, owner, &file))
|
||||
files.push_back(file);
|
||||
} else if (params.mode == content::FileChooserParams::Save) {
|
||||
base::FilePath file;
|
||||
if (RunSaveFileDialog(params, PlatformGetWindowHandle(), &file))
|
||||
if (RunSaveFileDialog(params, owner, &filter_index, &file))
|
||||
files.push_back(file);
|
||||
} else {
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
|
||||
callback.Run(files);
|
||||
callback.Run(filter_index, files);
|
||||
}
|
||||
|
||||
void CefBrowserHostImpl::PlatformHandleExternalProtocol(const GURL& url) {
|
||||
|
|
|
@ -142,7 +142,7 @@ class CefBeforeDownloadCallbackImpl : public CefBeforeDownloadCallback {
|
|||
if (browser.get()) {
|
||||
handled = true;
|
||||
|
||||
content::FileChooserParams params;
|
||||
CefBrowserHostImpl::FileChooserParams params;
|
||||
params.mode = content::FileChooserParams::Save;
|
||||
if (!suggested_path.empty()) {
|
||||
params.default_file_name = suggested_path;
|
||||
|
@ -169,6 +169,7 @@ class CefBeforeDownloadCallbackImpl : public CefBeforeDownloadCallback {
|
|||
|
||||
static void ChooseDownloadPathCallback(
|
||||
const content::DownloadTargetCallback& callback,
|
||||
int selected_accept_filter,
|
||||
const std::vector<base::FilePath>& file_paths) {
|
||||
DCHECK_LE(file_paths.size(), (size_t) 1);
|
||||
|
||||
|
|
|
@ -246,29 +246,34 @@ void CEF_CALLBACK browser_host_set_zoom_level(struct _cef_browser_host_t* self,
|
|||
|
||||
void CEF_CALLBACK browser_host_run_file_dialog(struct _cef_browser_host_t* self,
|
||||
cef_file_dialog_mode_t mode, const cef_string_t* title,
|
||||
const cef_string_t* default_file_name, cef_string_list_t accept_types,
|
||||
cef_run_file_dialog_callback_t* callback) {
|
||||
const cef_string_t* default_file_path, cef_string_list_t accept_filters,
|
||||
int selected_accept_filter, cef_run_file_dialog_callback_t* callback) {
|
||||
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||
|
||||
DCHECK(self);
|
||||
if (!self)
|
||||
return;
|
||||
// Verify param: selected_accept_filter; type: simple_byval
|
||||
DCHECK_GE(selected_accept_filter, 0);
|
||||
if (selected_accept_filter < 0)
|
||||
return;
|
||||
// Verify param: callback; type: refptr_diff
|
||||
DCHECK(callback);
|
||||
if (!callback)
|
||||
return;
|
||||
// Unverified params: title, default_file_name, accept_types
|
||||
// Unverified params: title, default_file_path, accept_filters
|
||||
|
||||
// Translate param: accept_types; type: string_vec_byref_const
|
||||
std::vector<CefString> accept_typesList;
|
||||
transfer_string_list_contents(accept_types, accept_typesList);
|
||||
// Translate param: accept_filters; type: string_vec_byref_const
|
||||
std::vector<CefString> accept_filtersList;
|
||||
transfer_string_list_contents(accept_filters, accept_filtersList);
|
||||
|
||||
// Execute
|
||||
CefBrowserHostCppToC::Get(self)->RunFileDialog(
|
||||
mode,
|
||||
CefString(title),
|
||||
CefString(default_file_name),
|
||||
accept_typesList,
|
||||
CefString(default_file_path),
|
||||
accept_filtersList,
|
||||
selected_accept_filter,
|
||||
CefRunFileDialogCallbackCToCpp::Wrap(callback));
|
||||
}
|
||||
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
int CEF_CALLBACK dialog_handler_on_file_dialog(
|
||||
struct _cef_dialog_handler_t* self, cef_browser_t* browser,
|
||||
cef_file_dialog_mode_t mode, const cef_string_t* title,
|
||||
const cef_string_t* default_file_name, cef_string_list_t accept_types,
|
||||
cef_file_dialog_callback_t* callback) {
|
||||
const cef_string_t* default_file_path, cef_string_list_t accept_filters,
|
||||
int selected_accept_filter, cef_file_dialog_callback_t* callback) {
|
||||
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||
|
||||
DCHECK(self);
|
||||
|
@ -32,23 +32,28 @@ int CEF_CALLBACK dialog_handler_on_file_dialog(
|
|||
DCHECK(browser);
|
||||
if (!browser)
|
||||
return 0;
|
||||
// Verify param: selected_accept_filter; type: simple_byval
|
||||
DCHECK_GE(selected_accept_filter, 0);
|
||||
if (selected_accept_filter < 0)
|
||||
return 0;
|
||||
// Verify param: callback; type: refptr_diff
|
||||
DCHECK(callback);
|
||||
if (!callback)
|
||||
return 0;
|
||||
// Unverified params: title, default_file_name, accept_types
|
||||
// Unverified params: title, default_file_path, accept_filters
|
||||
|
||||
// Translate param: accept_types; type: string_vec_byref_const
|
||||
std::vector<CefString> accept_typesList;
|
||||
transfer_string_list_contents(accept_types, accept_typesList);
|
||||
// Translate param: accept_filters; type: string_vec_byref_const
|
||||
std::vector<CefString> accept_filtersList;
|
||||
transfer_string_list_contents(accept_filters, accept_filtersList);
|
||||
|
||||
// Execute
|
||||
bool _retval = CefDialogHandlerCppToC::Get(self)->OnFileDialog(
|
||||
CefBrowserCToCpp::Wrap(browser),
|
||||
mode,
|
||||
CefString(title),
|
||||
CefString(default_file_name),
|
||||
accept_typesList,
|
||||
CefString(default_file_path),
|
||||
accept_filtersList,
|
||||
selected_accept_filter,
|
||||
CefFileDialogCallbackCToCpp::Wrap(callback));
|
||||
|
||||
// Return type: bool
|
||||
|
|
|
@ -17,16 +17,18 @@
|
|||
// MEMBER FUNCTIONS - Body may be edited by hand.
|
||||
|
||||
void CEF_CALLBACK file_dialog_callback_cont(
|
||||
struct _cef_file_dialog_callback_t* self, cef_string_list_t file_paths) {
|
||||
struct _cef_file_dialog_callback_t* self, int selected_accept_filter,
|
||||
cef_string_list_t file_paths) {
|
||||
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||
|
||||
DCHECK(self);
|
||||
if (!self)
|
||||
return;
|
||||
// Verify param: file_paths; type: string_vec_byref_const
|
||||
DCHECK(file_paths);
|
||||
if (!file_paths)
|
||||
// Verify param: selected_accept_filter; type: simple_byval
|
||||
DCHECK_GE(selected_accept_filter, 0);
|
||||
if (selected_accept_filter < 0)
|
||||
return;
|
||||
// Unverified params: file_paths
|
||||
|
||||
// Translate param: file_paths; type: string_vec_byref_const
|
||||
std::vector<CefString> file_pathsList;
|
||||
|
@ -34,6 +36,7 @@ void CEF_CALLBACK file_dialog_callback_cont(
|
|||
|
||||
// Execute
|
||||
CefFileDialogCallbackCppToC::Get(self)->Continue(
|
||||
selected_accept_filter,
|
||||
file_pathsList);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,28 +11,24 @@
|
|||
//
|
||||
|
||||
#include "libcef_dll/cpptoc/run_file_dialog_callback_cpptoc.h"
|
||||
#include "libcef_dll/ctocpp/browser_host_ctocpp.h"
|
||||
#include "libcef_dll/transfer_util.h"
|
||||
|
||||
|
||||
// MEMBER FUNCTIONS - Body may be edited by hand.
|
||||
|
||||
void CEF_CALLBACK run_file_dialog_callback_cont(
|
||||
struct _cef_run_file_dialog_callback_t* self,
|
||||
struct _cef_browser_host_t* browser_host, cef_string_list_t file_paths) {
|
||||
void CEF_CALLBACK run_file_dialog_callback_on_file_dialog_dismissed(
|
||||
struct _cef_run_file_dialog_callback_t* self, int selected_accept_filter,
|
||||
cef_string_list_t file_paths) {
|
||||
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||
|
||||
DCHECK(self);
|
||||
if (!self)
|
||||
return;
|
||||
// Verify param: browser_host; type: refptr_diff
|
||||
DCHECK(browser_host);
|
||||
if (!browser_host)
|
||||
return;
|
||||
// Verify param: file_paths; type: string_vec_byref_const
|
||||
DCHECK(file_paths);
|
||||
if (!file_paths)
|
||||
// Verify param: selected_accept_filter; type: simple_byval
|
||||
DCHECK_GE(selected_accept_filter, 0);
|
||||
if (selected_accept_filter < 0)
|
||||
return;
|
||||
// Unverified params: file_paths
|
||||
|
||||
// Translate param: file_paths; type: string_vec_byref_const
|
||||
std::vector<CefString> file_pathsList;
|
||||
|
@ -40,7 +36,7 @@ void CEF_CALLBACK run_file_dialog_callback_cont(
|
|||
|
||||
// Execute
|
||||
CefRunFileDialogCallbackCppToC::Get(self)->OnFileDialogDismissed(
|
||||
CefBrowserHostCToCpp::Wrap(browser_host),
|
||||
selected_accept_filter,
|
||||
file_pathsList);
|
||||
}
|
||||
|
||||
|
@ -51,7 +47,8 @@ CefRunFileDialogCallbackCppToC::CefRunFileDialogCallbackCppToC(
|
|||
CefRunFileDialogCallback* cls)
|
||||
: CefCppToC<CefRunFileDialogCallbackCppToC, CefRunFileDialogCallback,
|
||||
cef_run_file_dialog_callback_t>(cls) {
|
||||
struct_.struct_.cont = run_file_dialog_callback_cont;
|
||||
struct_.struct_.on_file_dialog_dismissed =
|
||||
run_file_dialog_callback_on_file_dialog_dismissed;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
|
|
@ -188,37 +188,42 @@ void CefBrowserHostCToCpp::SetZoomLevel(double zoomLevel) {
|
|||
}
|
||||
|
||||
void CefBrowserHostCToCpp::RunFileDialog(FileDialogMode mode,
|
||||
const CefString& title, const CefString& default_file_name,
|
||||
const std::vector<CefString>& accept_types,
|
||||
const CefString& title, const CefString& default_file_path,
|
||||
const std::vector<CefString>& accept_filters, int selected_accept_filter,
|
||||
CefRefPtr<CefRunFileDialogCallback> callback) {
|
||||
if (CEF_MEMBER_MISSING(struct_, run_file_dialog))
|
||||
return;
|
||||
|
||||
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||
|
||||
// Verify param: selected_accept_filter; type: simple_byval
|
||||
DCHECK_GE(selected_accept_filter, 0);
|
||||
if (selected_accept_filter < 0)
|
||||
return;
|
||||
// Verify param: callback; type: refptr_diff
|
||||
DCHECK(callback.get());
|
||||
if (!callback.get())
|
||||
return;
|
||||
// Unverified params: title, default_file_name, accept_types
|
||||
// Unverified params: title, default_file_path, accept_filters
|
||||
|
||||
// Translate param: accept_types; type: string_vec_byref_const
|
||||
cef_string_list_t accept_typesList = cef_string_list_alloc();
|
||||
DCHECK(accept_typesList);
|
||||
if (accept_typesList)
|
||||
transfer_string_list_contents(accept_types, accept_typesList);
|
||||
// Translate param: accept_filters; type: string_vec_byref_const
|
||||
cef_string_list_t accept_filtersList = cef_string_list_alloc();
|
||||
DCHECK(accept_filtersList);
|
||||
if (accept_filtersList)
|
||||
transfer_string_list_contents(accept_filters, accept_filtersList);
|
||||
|
||||
// Execute
|
||||
struct_->run_file_dialog(struct_,
|
||||
mode,
|
||||
title.GetStruct(),
|
||||
default_file_name.GetStruct(),
|
||||
accept_typesList,
|
||||
default_file_path.GetStruct(),
|
||||
accept_filtersList,
|
||||
selected_accept_filter,
|
||||
CefRunFileDialogCallbackCppToC::Wrap(callback));
|
||||
|
||||
// Restore param:accept_types; type: string_vec_byref_const
|
||||
if (accept_typesList)
|
||||
cef_string_list_free(accept_typesList);
|
||||
// Restore param:accept_filters; type: string_vec_byref_const
|
||||
if (accept_filtersList)
|
||||
cef_string_list_free(accept_filtersList);
|
||||
}
|
||||
|
||||
void CefBrowserHostCToCpp::StartDownload(const CefString& url) {
|
||||
|
|
|
@ -47,8 +47,8 @@ class CefBrowserHostCToCpp
|
|||
virtual double GetZoomLevel() OVERRIDE;
|
||||
virtual void SetZoomLevel(double zoomLevel) OVERRIDE;
|
||||
virtual void RunFileDialog(FileDialogMode mode, const CefString& title,
|
||||
const CefString& default_file_name,
|
||||
const std::vector<CefString>& accept_types,
|
||||
const CefString& default_file_path,
|
||||
const std::vector<CefString>& accept_filters, int selected_accept_filter,
|
||||
CefRefPtr<CefRunFileDialogCallback> callback) OVERRIDE;
|
||||
virtual void StartDownload(const CefString& url) OVERRIDE;
|
||||
virtual void Print() OVERRIDE;
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
|
||||
bool CefDialogHandlerCToCpp::OnFileDialog(CefRefPtr<CefBrowser> browser,
|
||||
FileDialogMode mode, const CefString& title,
|
||||
const CefString& default_file_name,
|
||||
const std::vector<CefString>& accept_types,
|
||||
const CefString& default_file_path,
|
||||
const std::vector<CefString>& accept_filters, int selected_accept_filter,
|
||||
CefRefPtr<CefFileDialogCallback> callback) {
|
||||
if (CEF_MEMBER_MISSING(struct_, on_file_dialog))
|
||||
return false;
|
||||
|
@ -32,30 +32,35 @@ bool CefDialogHandlerCToCpp::OnFileDialog(CefRefPtr<CefBrowser> browser,
|
|||
DCHECK(browser.get());
|
||||
if (!browser.get())
|
||||
return false;
|
||||
// Verify param: selected_accept_filter; type: simple_byval
|
||||
DCHECK_GE(selected_accept_filter, 0);
|
||||
if (selected_accept_filter < 0)
|
||||
return false;
|
||||
// Verify param: callback; type: refptr_diff
|
||||
DCHECK(callback.get());
|
||||
if (!callback.get())
|
||||
return false;
|
||||
// Unverified params: title, default_file_name, accept_types
|
||||
// Unverified params: title, default_file_path, accept_filters
|
||||
|
||||
// Translate param: accept_types; type: string_vec_byref_const
|
||||
cef_string_list_t accept_typesList = cef_string_list_alloc();
|
||||
DCHECK(accept_typesList);
|
||||
if (accept_typesList)
|
||||
transfer_string_list_contents(accept_types, accept_typesList);
|
||||
// Translate param: accept_filters; type: string_vec_byref_const
|
||||
cef_string_list_t accept_filtersList = cef_string_list_alloc();
|
||||
DCHECK(accept_filtersList);
|
||||
if (accept_filtersList)
|
||||
transfer_string_list_contents(accept_filters, accept_filtersList);
|
||||
|
||||
// Execute
|
||||
int _retval = struct_->on_file_dialog(struct_,
|
||||
CefBrowserCppToC::Wrap(browser),
|
||||
mode,
|
||||
title.GetStruct(),
|
||||
default_file_name.GetStruct(),
|
||||
accept_typesList,
|
||||
default_file_path.GetStruct(),
|
||||
accept_filtersList,
|
||||
selected_accept_filter,
|
||||
CefFileDialogCallbackCppToC::Wrap(callback));
|
||||
|
||||
// Restore param:accept_types; type: string_vec_byref_const
|
||||
if (accept_typesList)
|
||||
cef_string_list_free(accept_typesList);
|
||||
// Restore param:accept_filters; type: string_vec_byref_const
|
||||
if (accept_filtersList)
|
||||
cef_string_list_free(accept_filtersList);
|
||||
|
||||
// Return type: bool
|
||||
return _retval?true:false;
|
||||
|
|
|
@ -35,8 +35,8 @@ class CefDialogHandlerCToCpp
|
|||
|
||||
// CefDialogHandler methods
|
||||
bool OnFileDialog(CefRefPtr<CefBrowser> browser, FileDialogMode mode,
|
||||
const CefString& title, const CefString& default_file_name,
|
||||
const std::vector<CefString>& accept_types,
|
||||
const CefString& title, const CefString& default_file_path,
|
||||
const std::vector<CefString>& accept_filters, int selected_accept_filter,
|
||||
CefRefPtr<CefFileDialogCallback> callback) override;
|
||||
};
|
||||
|
||||
|
|
|
@ -16,13 +16,19 @@
|
|||
|
||||
// VIRTUAL METHODS - Body may be edited by hand.
|
||||
|
||||
void CefFileDialogCallbackCToCpp::Continue(
|
||||
void CefFileDialogCallbackCToCpp::Continue(int selected_accept_filter,
|
||||
const std::vector<CefString>& file_paths) {
|
||||
if (CEF_MEMBER_MISSING(struct_, cont))
|
||||
return;
|
||||
|
||||
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||
|
||||
// Verify param: selected_accept_filter; type: simple_byval
|
||||
DCHECK_GE(selected_accept_filter, 0);
|
||||
if (selected_accept_filter < 0)
|
||||
return;
|
||||
// Unverified params: file_paths
|
||||
|
||||
// Translate param: file_paths; type: string_vec_byref_const
|
||||
cef_string_list_t file_pathsList = cef_string_list_alloc();
|
||||
DCHECK(file_pathsList);
|
||||
|
@ -31,6 +37,7 @@ void CefFileDialogCallbackCToCpp::Continue(
|
|||
|
||||
// Execute
|
||||
struct_->cont(struct_,
|
||||
selected_accept_filter,
|
||||
file_pathsList);
|
||||
|
||||
// Restore param:file_paths; type: string_vec_byref_const
|
||||
|
|
|
@ -34,7 +34,8 @@ class CefFileDialogCallbackCToCpp
|
|||
cef_file_dialog_callback_t>(str) {}
|
||||
|
||||
// CefFileDialogCallback methods
|
||||
virtual void Continue(const std::vector<CefString>& file_paths) OVERRIDE;
|
||||
virtual void Continue(int selected_accept_filter,
|
||||
const std::vector<CefString>& file_paths) OVERRIDE;
|
||||
virtual void Cancel() OVERRIDE;
|
||||
};
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
// for more information.
|
||||
//
|
||||
|
||||
#include "libcef_dll/cpptoc/browser_host_cpptoc.h"
|
||||
#include "libcef_dll/ctocpp/run_file_dialog_callback_ctocpp.h"
|
||||
#include "libcef_dll/transfer_util.h"
|
||||
|
||||
|
@ -18,17 +17,17 @@
|
|||
// VIRTUAL METHODS - Body may be edited by hand.
|
||||
|
||||
void CefRunFileDialogCallbackCToCpp::OnFileDialogDismissed(
|
||||
CefRefPtr<CefBrowserHost> browser_host,
|
||||
const std::vector<CefString>& file_paths) {
|
||||
if (CEF_MEMBER_MISSING(struct_, cont))
|
||||
int selected_accept_filter, const std::vector<CefString>& file_paths) {
|
||||
if (CEF_MEMBER_MISSING(struct_, on_file_dialog_dismissed))
|
||||
return;
|
||||
|
||||
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||
|
||||
// Verify param: browser_host; type: refptr_diff
|
||||
DCHECK(browser_host.get());
|
||||
if (!browser_host.get())
|
||||
// Verify param: selected_accept_filter; type: simple_byval
|
||||
DCHECK_GE(selected_accept_filter, 0);
|
||||
if (selected_accept_filter < 0)
|
||||
return;
|
||||
// Unverified params: file_paths
|
||||
|
||||
// Translate param: file_paths; type: string_vec_byref_const
|
||||
cef_string_list_t file_pathsList = cef_string_list_alloc();
|
||||
|
@ -37,8 +36,8 @@ void CefRunFileDialogCallbackCToCpp::OnFileDialogDismissed(
|
|||
transfer_string_list_contents(file_paths, file_pathsList);
|
||||
|
||||
// Execute
|
||||
struct_->cont(struct_,
|
||||
CefBrowserHostCppToC::Wrap(browser_host),
|
||||
struct_->on_file_dialog_dismissed(struct_,
|
||||
selected_accept_filter,
|
||||
file_pathsList);
|
||||
|
||||
// Restore param:file_paths; type: string_vec_byref_const
|
||||
|
|
|
@ -36,7 +36,7 @@ class CefRunFileDialogCallbackCToCpp
|
|||
cef_run_file_dialog_callback_t>(str) {}
|
||||
|
||||
// CefRunFileDialogCallback methods
|
||||
void OnFileDialogDismissed(CefRefPtr<CefBrowserHost> browser_host,
|
||||
void OnFileDialogDismissed(int selected_accept_filter,
|
||||
const std::vector<CefString>& file_paths) override;
|
||||
};
|
||||
|
||||
|
|
|
@ -195,8 +195,9 @@ bool ClientHandler::OnContextMenuCommand(
|
|||
bool ClientHandler::OnFileDialog(CefRefPtr<CefBrowser> browser,
|
||||
FileDialogMode mode,
|
||||
const CefString& title,
|
||||
const CefString& default_file_name,
|
||||
const std::vector<CefString>& accept_types,
|
||||
const CefString& default_file_path,
|
||||
const std::vector<CefString>& accept_filters,
|
||||
int selected_accept_filter,
|
||||
CefRefPtr<CefFileDialogCallback> callback) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
|
@ -841,12 +842,16 @@ void ClientHandler::EndTracing() {
|
|||
|
||||
// Results in a call to OnFileDialogDismissed.
|
||||
handler_->GetBrowser()->GetHost()->RunFileDialog(
|
||||
FILE_DIALOG_SAVE, CefString(), path, std::vector<CefString>(),
|
||||
FILE_DIALOG_SAVE,
|
||||
CefString(), // title
|
||||
path,
|
||||
std::vector<CefString>(), // accept_filters
|
||||
0, // selected_accept_filter
|
||||
this);
|
||||
}
|
||||
|
||||
virtual void OnFileDialogDismissed(
|
||||
CefRefPtr<CefBrowserHost> browser_host,
|
||||
int selected_accept_filter,
|
||||
const std::vector<CefString>& file_paths) OVERRIDE {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
if (!file_paths.empty()) {
|
||||
|
|
|
@ -111,8 +111,9 @@ class ClientHandler : public CefClient,
|
|||
virtual bool OnFileDialog(CefRefPtr<CefBrowser> browser,
|
||||
FileDialogMode mode,
|
||||
const CefString& title,
|
||||
const CefString& default_file_name,
|
||||
const std::vector<CefString>& accept_types,
|
||||
const CefString& default_file_path,
|
||||
const std::vector<CefString>& accept_filters,
|
||||
int selected_accept_filter,
|
||||
CefRefPtr<CefFileDialogCallback> callback) OVERRIDE;
|
||||
|
||||
// CefDisplayHandler methods
|
||||
|
|
|
@ -50,52 +50,74 @@ std::string GetDescriptionFromMimeType(const std::string& mime_type) {
|
|||
return std::string();
|
||||
}
|
||||
|
||||
void AddFiltersForAcceptTypes(GtkFileChooser* chooser,
|
||||
const std::vector<CefString>& accept_types,
|
||||
bool include_all_files) {
|
||||
void AddFilters(GtkFileChooser* chooser,
|
||||
const std::vector<CefString>& accept_filters,
|
||||
bool include_all_files,
|
||||
std::vector<GtkFileFilter*>* filters) {
|
||||
bool has_filter = false;
|
||||
|
||||
for (size_t i = 0; i < accept_types.size(); ++i) {
|
||||
std::string ascii_type = accept_types[i];
|
||||
if (ascii_type.length()) {
|
||||
// Just treat as extension if contains '.' as the first character.
|
||||
if (ascii_type[0] == '.') {
|
||||
GtkFileFilter* filter = gtk_file_filter_new();
|
||||
std::string pattern = "*" + ascii_type;
|
||||
gtk_file_filter_add_pattern(filter, pattern.c_str());
|
||||
gtk_file_filter_set_name(filter, pattern.c_str());
|
||||
gtk_file_chooser_add_filter(chooser, filter);
|
||||
if (!has_filter)
|
||||
has_filter = true;
|
||||
} else {
|
||||
// Otherwise convert mime type to one or more extensions.
|
||||
GtkFileFilter* filter = NULL;
|
||||
std::string description = GetDescriptionFromMimeType(ascii_type);
|
||||
bool description_from_ext = description.empty();
|
||||
for (size_t i = 0; i < accept_filters.size(); ++i) {
|
||||
const std::string& filter = accept_filters[i];
|
||||
if (filter.empty())
|
||||
continue;
|
||||
|
||||
std::vector<CefString> ext;
|
||||
CefGetExtensionsForMimeType(ascii_type, ext);
|
||||
for (size_t x = 0; x < ext.size(); ++x) {
|
||||
if (!filter)
|
||||
filter = gtk_file_filter_new();
|
||||
std::string pattern = "*." + ext[x].ToString();
|
||||
gtk_file_filter_add_pattern(filter, pattern.c_str());
|
||||
std::vector<std::string> extensions;
|
||||
std::string description;
|
||||
|
||||
if (description_from_ext) {
|
||||
if (x != 0)
|
||||
description += ";";
|
||||
description += pattern;
|
||||
}
|
||||
}
|
||||
size_t sep_index = filter.find('|');
|
||||
if (sep_index != std::string::npos) {
|
||||
// Treat as a filter of the form "Filter Name|.ext1;.ext2;.ext3".
|
||||
description = filter.substr(0, sep_index);
|
||||
|
||||
if (filter) {
|
||||
gtk_file_filter_set_name(filter, description.c_str());
|
||||
gtk_file_chooser_add_filter(chooser, filter);
|
||||
if (!has_filter)
|
||||
has_filter = true;
|
||||
const std::string& exts = filter.substr(sep_index + 1);
|
||||
size_t last = 0;
|
||||
size_t size = exts.size();
|
||||
for (size_t i = 0; i <= size; ++i) {
|
||||
if (i == size || exts[i] == ';') {
|
||||
std::string ext(exts, last, i - last);
|
||||
if (!ext.empty() && ext[0] == '.')
|
||||
extensions.push_back(ext);
|
||||
last = i + 1;
|
||||
}
|
||||
}
|
||||
} else if (filter[0] == '.') {
|
||||
// Treat as an extension beginning with the '.' character.
|
||||
extensions.push_back(filter);
|
||||
} else {
|
||||
// Otherwise convert mime type to one or more extensions.
|
||||
description = GetDescriptionFromMimeType(filter);
|
||||
|
||||
std::vector<CefString> ext;
|
||||
CefGetExtensionsForMimeType(filter, ext);
|
||||
for (size_t x = 0; x < ext.size(); ++x)
|
||||
extensions.push_back("." + ext[x].ToString());
|
||||
}
|
||||
|
||||
if (extensions.empty())
|
||||
continue;
|
||||
|
||||
GtkFileFilter* gtk_filter = gtk_file_filter_new();
|
||||
|
||||
std::string ext_str;
|
||||
for (size_t x = 0; x < extensions.size(); ++x) {
|
||||
const std::string& pattern = "*" + extensions[x];
|
||||
if (x != 0)
|
||||
ext_str += ";";
|
||||
ext_str += pattern;
|
||||
gtk_file_filter_add_pattern(gtk_filter, pattern.c_str());
|
||||
}
|
||||
|
||||
if (description.empty())
|
||||
description = ext_str;
|
||||
else
|
||||
description += " (" + ext_str + ")";
|
||||
|
||||
gtk_file_filter_set_name(gtk_filter, description.c_str());
|
||||
gtk_file_chooser_add_filter(chooser, gtk_filter);
|
||||
if (!has_filter)
|
||||
has_filter = true;
|
||||
|
||||
filters->push_back(gtk_filter);
|
||||
}
|
||||
|
||||
// Add the *.* filter, but only if we have added other filters (otherwise it
|
||||
|
@ -103,7 +125,7 @@ void AddFiltersForAcceptTypes(GtkFileChooser* chooser,
|
|||
if (include_all_files && has_filter) {
|
||||
GtkFileFilter* filter = gtk_file_filter_new();
|
||||
gtk_file_filter_add_pattern(filter, "*");
|
||||
gtk_file_filter_set_name(filter, "All Files");
|
||||
gtk_file_filter_set_name(filter, "All Files (*)");
|
||||
gtk_file_chooser_add_filter(chooser, filter);
|
||||
}
|
||||
}
|
||||
|
@ -113,17 +135,26 @@ void AddFiltersForAcceptTypes(GtkFileChooser* chooser,
|
|||
bool ClientHandler::OnFileDialog(CefRefPtr<CefBrowser> browser,
|
||||
FileDialogMode mode,
|
||||
const CefString& title,
|
||||
const CefString& default_file_name,
|
||||
const std::vector<CefString>& accept_types,
|
||||
const CefString& default_file_path,
|
||||
const std::vector<CefString>& accept_filters,
|
||||
int selected_accept_filter,
|
||||
CefRefPtr<CefFileDialogCallback> callback) {
|
||||
std::vector<CefString> files;
|
||||
|
||||
GtkFileChooserAction action;
|
||||
const gchar* accept_button;
|
||||
if (mode == FILE_DIALOG_OPEN || mode == FILE_DIALOG_OPEN_MULTIPLE) {
|
||||
|
||||
// Remove any modifier flags.
|
||||
FileDialogMode mode_type =
|
||||
static_cast<FileDialogMode>(mode & FILE_DIALOG_TYPE_MASK);
|
||||
|
||||
if (mode_type == FILE_DIALOG_OPEN || mode_type == FILE_DIALOG_OPEN_MULTIPLE) {
|
||||
action = GTK_FILE_CHOOSER_ACTION_OPEN;
|
||||
accept_button = GTK_STOCK_OPEN;
|
||||
} else if (mode == FILE_DIALOG_SAVE) {
|
||||
} else if (mode_type == FILE_DIALOG_OPEN_FOLDER) {
|
||||
action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
|
||||
accept_button = GTK_STOCK_OPEN;
|
||||
} else if (mode_type == FILE_DIALOG_SAVE) {
|
||||
action = GTK_FILE_CHOOSER_ACTION_SAVE;
|
||||
accept_button = GTK_STOCK_SAVE;
|
||||
} else {
|
||||
|
@ -131,12 +162,6 @@ bool ClientHandler::OnFileDialog(CefRefPtr<CefBrowser> browser,
|
|||
return false;
|
||||
}
|
||||
|
||||
std::string base_name;
|
||||
if (!default_file_name.empty()) {
|
||||
base_name =
|
||||
basename(const_cast<char*>(default_file_name.ToString().c_str()));
|
||||
}
|
||||
|
||||
std::string title_str;
|
||||
if (!title.empty()) {
|
||||
title_str = title;
|
||||
|
@ -148,6 +173,9 @@ bool ClientHandler::OnFileDialog(CefRefPtr<CefBrowser> browser,
|
|||
case FILE_DIALOG_OPEN_MULTIPLE:
|
||||
title_str = "Open Files";
|
||||
break;
|
||||
case FILE_DIALOG_OPEN_FOLDER:
|
||||
title_str = "Open Folder";
|
||||
break;
|
||||
case FILE_DIALOG_SAVE:
|
||||
title_str = "Save File";
|
||||
break;
|
||||
|
@ -166,28 +194,39 @@ bool ClientHandler::OnFileDialog(CefRefPtr<CefBrowser> browser,
|
|||
accept_button, GTK_RESPONSE_ACCEPT,
|
||||
NULL);
|
||||
|
||||
if (mode == FILE_DIALOG_OPEN_MULTIPLE) {
|
||||
if (mode_type == FILE_DIALOG_OPEN_MULTIPLE)
|
||||
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
|
||||
} else if (mode == FILE_DIALOG_SAVE) {
|
||||
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog),
|
||||
TRUE);
|
||||
|
||||
if (mode_type == FILE_DIALOG_SAVE) {
|
||||
gtk_file_chooser_set_do_overwrite_confirmation(
|
||||
GTK_FILE_CHOOSER(dialog),
|
||||
!!(mode & FILE_DIALOG_OVERWRITEPROMPT_FLAG));
|
||||
}
|
||||
|
||||
if (mode == FILE_DIALOG_SAVE && !base_name.empty()) {
|
||||
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog),
|
||||
base_name.c_str());
|
||||
gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dialog),
|
||||
!(mode & FILE_DIALOG_HIDEREADONLY_FLAG));
|
||||
|
||||
if (!default_file_path.empty()) {
|
||||
gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog),
|
||||
default_file_path.ToString().c_str());
|
||||
}
|
||||
|
||||
AddFiltersForAcceptTypes(GTK_FILE_CHOOSER(dialog), accept_types, true);
|
||||
std::vector<GtkFileFilter*> filters;
|
||||
AddFilters(GTK_FILE_CHOOSER(dialog), accept_filters, true, &filters);
|
||||
if (selected_accept_filter < static_cast<int>(filters.size())) {
|
||||
gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog),
|
||||
filters[selected_accept_filter]);
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
|
||||
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
|
||||
if (mode == FILE_DIALOG_OPEN || mode == FILE_DIALOG_SAVE) {
|
||||
if (mode_type == FILE_DIALOG_OPEN || mode_type == FILE_DIALOG_OPEN_FOLDER ||
|
||||
mode_type == FILE_DIALOG_SAVE) {
|
||||
char* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
||||
files.push_back(std::string(filename));
|
||||
success = true;
|
||||
} else if (mode == FILE_DIALOG_OPEN_MULTIPLE) {
|
||||
} else if (mode_type == FILE_DIALOG_OPEN_MULTIPLE) {
|
||||
GSList* filenames =
|
||||
gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
|
||||
if (filenames) {
|
||||
|
@ -203,10 +242,24 @@ bool ClientHandler::OnFileDialog(CefRefPtr<CefBrowser> browser,
|
|||
}
|
||||
}
|
||||
|
||||
int filter_index = selected_accept_filter;
|
||||
if (success) {
|
||||
GtkFileFilter* selected_filter =
|
||||
gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(dialog));
|
||||
if (selected_filter != NULL) {
|
||||
for (size_t x = 0; x < filters.size(); ++x) {
|
||||
if (filters[x] == selected_filter) {
|
||||
filter_index = x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gtk_widget_destroy(dialog);
|
||||
|
||||
if (success)
|
||||
callback->Continue(files);
|
||||
callback->Continue(filter_index, files);
|
||||
else
|
||||
callback->Cancel();
|
||||
|
||||
|
|
|
@ -14,19 +14,63 @@ namespace {
|
|||
const char kTestUrl[] = "http://tests/dialogs";
|
||||
const char kFileOpenMessageName[] = "DialogTest.FileOpen";
|
||||
const char kFileOpenMultipleMessageName[] = "DialogTest.FileOpenMultiple";
|
||||
const char kFileOpenFolderMessageName[] = "DialogTest.FileOpenFolder";
|
||||
const char kFileSaveMessageName[] = "DialogTest.FileSave";
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#define PATH_SEP '\\'
|
||||
#else
|
||||
#define PATH_SEP '/'
|
||||
#endif
|
||||
|
||||
// Store persistent dialog state information.
|
||||
class DialogState : public base::RefCountedThreadSafe<DialogState> {
|
||||
public:
|
||||
DialogState()
|
||||
: mode_(FILE_DIALOG_OPEN),
|
||||
last_selected_filter_(0),
|
||||
pending_(false) {}
|
||||
|
||||
cef_file_dialog_mode_t mode_;
|
||||
int last_selected_filter_;
|
||||
CefString last_file_;
|
||||
bool pending_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(DialogState);
|
||||
};
|
||||
|
||||
// Callback executed when the file dialog is dismissed.
|
||||
class DialogCallback : public CefRunFileDialogCallback {
|
||||
public:
|
||||
explicit DialogCallback(
|
||||
CefRefPtr<CefMessageRouterBrowserSide::Callback> router_callback)
|
||||
: router_callback_(router_callback) {
|
||||
DialogCallback(
|
||||
CefRefPtr<CefMessageRouterBrowserSide::Callback> router_callback,
|
||||
scoped_refptr<DialogState> dialog_state)
|
||||
: router_callback_(router_callback),
|
||||
dialog_state_(dialog_state) {
|
||||
}
|
||||
|
||||
virtual void OnFileDialogDismissed(
|
||||
CefRefPtr<CefBrowserHost> browser_host,
|
||||
int last_selected_filter,
|
||||
const std::vector<CefString>& file_paths) OVERRIDE {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
DCHECK(dialog_state_->pending_);
|
||||
|
||||
if (!file_paths.empty()) {
|
||||
if (dialog_state_->mode_ != FILE_DIALOG_OPEN_FOLDER)
|
||||
dialog_state_->last_selected_filter_ = last_selected_filter;
|
||||
|
||||
dialog_state_->last_file_ = file_paths[0];
|
||||
if (dialog_state_->mode_ == FILE_DIALOG_OPEN_FOLDER) {
|
||||
std::string last_file = dialog_state_->last_file_;
|
||||
if (last_file[last_file.length() - 1] != PATH_SEP) {
|
||||
// Add a trailing slash so we know it's a directory. Otherwise, file
|
||||
// dialogs will think the last path component is a file name.
|
||||
last_file += PATH_SEP;
|
||||
dialog_state_->last_file_ = last_file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Send a message back to the render process with the list of file paths.
|
||||
std::string response;
|
||||
for (int i = 0; i < static_cast<int>(file_paths.size()); ++i) {
|
||||
|
@ -37,12 +81,17 @@ class DialogCallback : public CefRunFileDialogCallback {
|
|||
|
||||
router_callback_->Success(response);
|
||||
router_callback_ = NULL;
|
||||
|
||||
dialog_state_->pending_ = false;
|
||||
dialog_state_ = NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
CefRefPtr<CefMessageRouterBrowserSide::Callback> router_callback_;
|
||||
scoped_refptr<DialogState> dialog_state_;
|
||||
|
||||
IMPLEMENT_REFCOUNTING(DialogCallback);
|
||||
DISALLOW_COPY_AND_ASSIGN(DialogCallback);
|
||||
};
|
||||
|
||||
// Handle messages in the browser process.
|
||||
|
@ -57,36 +106,72 @@ class Handler : public CefMessageRouterBrowserSide::Handler {
|
|||
const CefString& request,
|
||||
bool persistent,
|
||||
CefRefPtr<Callback> callback) OVERRIDE {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
// Only handle messages from the test URL.
|
||||
const std::string& url = frame->GetURL();
|
||||
if (url.find(kTestUrl) != 0)
|
||||
return false;
|
||||
|
||||
// Sample file type filter.
|
||||
std::vector<CefString> file_types;
|
||||
file_types.push_back("text/*");
|
||||
file_types.push_back(".log");
|
||||
file_types.push_back(".patch");
|
||||
if (!dialog_state_.get())
|
||||
dialog_state_ = new DialogState;
|
||||
|
||||
CefRefPtr<DialogCallback> dialog_callback(new DialogCallback(callback));
|
||||
// Make sure we're only running one dialog at a time.
|
||||
DCHECK(!dialog_state_->pending_);
|
||||
|
||||
std::vector<CefString> accept_filters;
|
||||
std::string title;
|
||||
|
||||
const std::string& message_name = request;
|
||||
if (message_name == kFileOpenMessageName) {
|
||||
browser->GetHost()->RunFileDialog(FILE_DIALOG_OPEN, "My Open Dialog",
|
||||
"test.txt", file_types, dialog_callback.get());
|
||||
dialog_state_->mode_ = FILE_DIALOG_OPEN;
|
||||
title = "My Open Dialog";
|
||||
} else if (message_name == kFileOpenMultipleMessageName) {
|
||||
browser->GetHost()->RunFileDialog(FILE_DIALOG_OPEN_MULTIPLE,
|
||||
"My Open Multiple Dialog", CefString(), file_types,
|
||||
dialog_callback.get());
|
||||
dialog_state_->mode_ = FILE_DIALOG_OPEN_MULTIPLE;
|
||||
title = "My Open Multiple Dialog";
|
||||
} else if (message_name == kFileOpenFolderMessageName) {
|
||||
dialog_state_->mode_ = FILE_DIALOG_OPEN_FOLDER;
|
||||
title = "My Open Folder Dialog";
|
||||
} else if (message_name == kFileSaveMessageName) {
|
||||
browser->GetHost()->RunFileDialog(FILE_DIALOG_SAVE, "My Save Dialog",
|
||||
"test.txt", file_types, dialog_callback.get());
|
||||
dialog_state_->mode_ = static_cast<cef_file_dialog_mode_t>(
|
||||
FILE_DIALOG_SAVE | FILE_DIALOG_OVERWRITEPROMPT_FLAG);
|
||||
title = "My Save Dialog";
|
||||
} else {
|
||||
NOTREACHED();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (dialog_state_->mode_ != FILE_DIALOG_OPEN_FOLDER) {
|
||||
// Build filters based on mime time.
|
||||
accept_filters.push_back("text/*");
|
||||
|
||||
// Build filters based on file extension.
|
||||
accept_filters.push_back(".log");
|
||||
accept_filters.push_back(".patch");
|
||||
|
||||
// Add specific filters as-is.
|
||||
accept_filters.push_back("Document Files|.doc;.odt");
|
||||
accept_filters.push_back("Image Files|.png;.jpg;.gif");
|
||||
accept_filters.push_back("PDF Files|.pdf");
|
||||
}
|
||||
|
||||
dialog_state_->pending_ = true;
|
||||
|
||||
browser->GetHost()->RunFileDialog(
|
||||
dialog_state_->mode_,
|
||||
title,
|
||||
dialog_state_->last_file_,
|
||||
accept_filters,
|
||||
dialog_state_->last_selected_filter_,
|
||||
new DialogCallback(callback, dialog_state_));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
scoped_refptr<DialogState> dialog_state_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Handler);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -57,6 +57,7 @@ Click a button to show the associated dialog type.
|
|||
<br/>input type="file": <input type="file" name="pic" accept="text/*,.js,.css,image/*">
|
||||
<br/><input type="button" onclick="show_file_dialog('fo', 'FileOpen');" value="Show File Open"> <span id="fo"></span>
|
||||
<br/><input type="button" onclick="show_file_dialog('fom', 'FileOpenMultiple');" value="Show File Open Multiple"> <span id="fom"></span>
|
||||
<br/><input type="button" onclick="show_file_dialog('fof', 'FileOpenFolder');" value="Show File Open Folder"> <span id="fof"></span>
|
||||
<br/><input type="button" onclick="show_file_dialog('fs', 'FileSave');" value="Show File Save"> <span id="fs"></span>
|
||||
<p id="time"></p>
|
||||
</form>
|
||||
|
|
|
@ -22,6 +22,7 @@ class DialogTestHandler : public TestHandler {
|
|||
: mode(dialog_mode),
|
||||
title("Test Title"),
|
||||
default_file_name("Test File Name"),
|
||||
selected_accept_filter(1), // Something other than 0 for testing.
|
||||
callback_async(false),
|
||||
callback_cancel(false) {
|
||||
accept_types.push_back("text/*");
|
||||
|
@ -33,6 +34,7 @@ class DialogTestHandler : public TestHandler {
|
|||
CefString title;
|
||||
CefString default_file_name;
|
||||
std::vector<CefString> accept_types;
|
||||
int selected_accept_filter;
|
||||
|
||||
bool callback_async; // True if the callback should execute asynchronously.
|
||||
bool callback_cancel; // True if the callback should cancel.
|
||||
|
@ -46,17 +48,18 @@ class DialogTestHandler : public TestHandler {
|
|||
}
|
||||
|
||||
void OnFileDialogDismissed(
|
||||
CefRefPtr<CefBrowserHost> browser_host,
|
||||
int selected_accept_filter,
|
||||
const std::vector<CefString>& file_paths) override {
|
||||
handler_->got_onfiledialogdismissed_.yes();
|
||||
|
||||
std::string url = browser_host->GetBrowser()->GetMainFrame()->GetURL();
|
||||
EXPECT_STREQ(kTestUrl, url.c_str());
|
||||
|
||||
if (handler_->config_.callback_cancel)
|
||||
if (handler_->config_.callback_cancel) {
|
||||
EXPECT_EQ(0, selected_accept_filter);
|
||||
EXPECT_TRUE(file_paths.empty());
|
||||
else
|
||||
} else {
|
||||
EXPECT_EQ(handler_->config_.selected_accept_filter,
|
||||
selected_accept_filter);
|
||||
TestStringVectorEqual(handler_->config_.callback_paths, file_paths);
|
||||
}
|
||||
|
||||
handler_->DestroyTest();
|
||||
handler_ = NULL;
|
||||
|
@ -89,6 +92,7 @@ class DialogTestHandler : public TestHandler {
|
|||
config_.title,
|
||||
config_.default_file_name,
|
||||
config_.accept_types,
|
||||
config_.selected_accept_filter,
|
||||
new Callback(this));
|
||||
}
|
||||
|
||||
|
@ -96,7 +100,8 @@ class DialogTestHandler : public TestHandler {
|
|||
if (config_.callback_cancel)
|
||||
callback->Cancel();
|
||||
else
|
||||
callback->Continue(config_.callback_paths);
|
||||
callback->Continue(config_.selected_accept_filter,
|
||||
config_.callback_paths);
|
||||
}
|
||||
|
||||
// CefDialogHandler
|
||||
|
@ -106,6 +111,7 @@ class DialogTestHandler : public TestHandler {
|
|||
const CefString& title,
|
||||
const CefString& default_file_name,
|
||||
const std::vector<CefString>& accept_types,
|
||||
int selected_accept_filter,
|
||||
CefRefPtr<CefFileDialogCallback> callback) override {
|
||||
got_onfiledialog_.yes();
|
||||
|
||||
|
@ -157,6 +163,22 @@ TEST(DialogTest, FileEmptyParams) {
|
|||
ReleaseAndWaitForDestructor(handler);
|
||||
}
|
||||
|
||||
TEST(DialogTest, FileAdditionalFlags) {
|
||||
DialogTestHandler::TestConfig config(
|
||||
static_cast<cef_file_dialog_mode_t>(FILE_DIALOG_OPEN |
|
||||
FILE_DIALOG_HIDEREADONLY_FLAG |
|
||||
FILE_DIALOG_OVERWRITEPROMPT_FLAG));
|
||||
config.title.clear();
|
||||
config.default_file_name.clear();
|
||||
config.accept_types.clear();
|
||||
config.callback_async = false;
|
||||
config.callback_cancel = false;
|
||||
|
||||
CefRefPtr<DialogTestHandler> handler = new DialogTestHandler(config);
|
||||
handler->ExecuteTest();
|
||||
ReleaseAndWaitForDestructor(handler);
|
||||
}
|
||||
|
||||
TEST(DialogTest, FileOpen) {
|
||||
DialogTestHandler::TestConfig config(FILE_DIALOG_OPEN);
|
||||
config.callback_async = false;
|
||||
|
@ -243,6 +265,48 @@ TEST(DialogTest, FileOpenMultipleAsyncCancel) {
|
|||
ReleaseAndWaitForDestructor(handler);
|
||||
}
|
||||
|
||||
TEST(DialogTest, FileOpenFolder) {
|
||||
DialogTestHandler::TestConfig config(FILE_DIALOG_OPEN_FOLDER);
|
||||
config.callback_async = false;
|
||||
config.callback_cancel = false;
|
||||
config.callback_paths.push_back("/path/to/folder");
|
||||
|
||||
CefRefPtr<DialogTestHandler> handler = new DialogTestHandler(config);
|
||||
handler->ExecuteTest();
|
||||
ReleaseAndWaitForDestructor(handler);
|
||||
}
|
||||
|
||||
TEST(DialogTest, FileOpenFolderCancel) {
|
||||
DialogTestHandler::TestConfig config(FILE_DIALOG_OPEN_FOLDER);
|
||||
config.callback_async = false;
|
||||
config.callback_cancel = true;
|
||||
|
||||
CefRefPtr<DialogTestHandler> handler = new DialogTestHandler(config);
|
||||
handler->ExecuteTest();
|
||||
ReleaseAndWaitForDestructor(handler);
|
||||
}
|
||||
|
||||
TEST(DialogTest, FileOpenFolderAsync) {
|
||||
DialogTestHandler::TestConfig config(FILE_DIALOG_OPEN_FOLDER);
|
||||
config.callback_async = true;
|
||||
config.callback_cancel = false;
|
||||
config.callback_paths.push_back("/path/to/folder");
|
||||
|
||||
CefRefPtr<DialogTestHandler> handler = new DialogTestHandler(config);
|
||||
handler->ExecuteTest();
|
||||
ReleaseAndWaitForDestructor(handler);
|
||||
}
|
||||
|
||||
TEST(DialogTest, FileOpenFolderAsyncCancel) {
|
||||
DialogTestHandler::TestConfig config(FILE_DIALOG_OPEN_FOLDER);
|
||||
config.callback_async = false;
|
||||
config.callback_cancel = true;
|
||||
|
||||
CefRefPtr<DialogTestHandler> handler = new DialogTestHandler(config);
|
||||
handler->ExecuteTest();
|
||||
ReleaseAndWaitForDestructor(handler);
|
||||
}
|
||||
|
||||
TEST(DialogTest, FileSave) {
|
||||
DialogTestHandler::TestConfig config(FILE_DIALOG_SAVE);
|
||||
config.callback_async = false;
|
||||
|
|
Loading…
Reference in New Issue