diff --git a/libcef/browser_webview_delegate.cc b/libcef/browser_webview_delegate.cc index 3e2d97972..9c8a13468 100644 --- a/libcef/browser_webview_delegate.cc +++ b/libcef/browser_webview_delegate.cc @@ -42,6 +42,7 @@ #include "third_party/WebKit/WebKit/chromium/public/WebURLError.h" #include "third_party/WebKit/WebKit/chromium/public/WebURLRequest.h" #include "third_party/WebKit/WebKit/chromium/public/WebURLResponse.h" +#include "third_party/WebKit/WebKit/chromium/public/WebVector.h" #include "third_party/WebKit/WebKit/chromium/public/WebView.h" #include "webkit/appcache/appcache_interfaces.h" #include "webkit/glue/glue_serialize.h" @@ -96,6 +97,7 @@ using WebKit::WebURL; using WebKit::WebURLError; using WebKit::WebURLRequest; using WebKit::WebURLResponse; +using WebKit::WebVector; using WebKit::WebView; using WebKit::WebWidget; using WebKit::WebWorker; @@ -236,7 +238,22 @@ bool BrowserWebViewDelegate::runFileChooser( bool multi_select, const WebKit::WebString& title, const WebKit::WebString& initial_value, WebKit::WebFileChooserCompletion* chooser_completion) { - return false; + // Support file open dialog. + std::vector file_names; + + if(!ShowFileChooser(file_names, multi_select, title, + webkit_glue::WebStringToFilePath(initial_value))) { + return false; + } + + WebVector ws_file_names(file_names.size()); + for (size_t i = 0; i < file_names.size(); ++i) { + ws_file_names[i] = webkit_glue::FilePathToWebString(file_names[i]); + } + + chooser_completion->didChooseFile(ws_file_names); + + return true; } void BrowserWebViewDelegate::runModalAlertDialog( diff --git a/libcef/browser_webview_delegate.h b/libcef/browser_webview_delegate.h index 9a56f6067..1d85a26ae 100644 --- a/libcef/browser_webview_delegate.h +++ b/libcef/browser_webview_delegate.h @@ -37,6 +37,7 @@ class CefBrowserImpl; struct WebPreferences; class GURL; class WebWidgetHost; +class FilePath; class BrowserWebViewDelegate : public WebKit::WebViewClient, public WebKit::WebFrameClient, @@ -237,6 +238,12 @@ class BrowserWebViewDelegate : public WebKit::WebViewClient, const std::wstring& default_value, std::wstring* result); + // Called to show the file chooser dialog. + bool ShowFileChooser(std::vector& file_names, + const bool multi_select, + const WebKit::WebString& title, + const FilePath& default_file); + // In the Mac code, this is called to trigger the end of a test after the // page has finished loading. From here, we can generate the dump for the // test. diff --git a/libcef/browser_webview_delegate_win.cc b/libcef/browser_webview_delegate_win.cc index 90bd6e99a..bce0e596c 100644 --- a/libcef/browser_webview_delegate_win.cc +++ b/libcef/browser_webview_delegate_win.cc @@ -415,3 +415,119 @@ bool BrowserWebViewDelegate::ShowJavaScriptPrompt(WebFrame* webframe, // TODO(cef): Implement a default prompt dialog return false; } + +namespace +{ + +// from chrome/browser/views/shell_dialogs_win.cc + +bool RunOpenFileDialog( + const std::wstring& filter, + HWND owner, + FilePath* path) +{ + OPENFILENAME ofn; + + // We must do this otherwise the ofn's FlagsEx may be initialized to random + // junk in release builds which can cause the Places Bar not to show up! + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = owner; + + wchar_t filename[MAX_PATH]; + base::wcslcpy(filename, path->value().c_str(), arraysize(filename)); + + ofn.lpstrFile = filename; + ofn.nMaxFile = MAX_PATH; + + // We use OFN_NOCHANGEDIR so that the user can rename or delete the directory + // without having to close Chrome first. + ofn.Flags = OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR; + + if (!filter.empty()) { + ofn.lpstrFilter = filter.c_str(); + } + bool success = !!GetOpenFileName(&ofn); + if (success) + *path = FilePath(filename); + return success; +} + +bool RunOpenMultiFileDialog( + const std::wstring& filter, + HWND owner, + std::vector* paths) +{ + OPENFILENAME ofn; + + // We must do this otherwise the ofn's FlagsEx may be initialized to random + // junk in release builds which can cause the Places Bar not to show up! + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = owner; + + wchar_t filename[MAX_PATH] = L""; + + ofn.lpstrFile = filename; + ofn.nMaxFile = MAX_PATH; + + // 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; + + if (!filter.empty()) { + ofn.lpstrFilter = filter.c_str(); + } + bool success = !!GetOpenFileName(&ofn); + + if (success) { + std::vector files; + const wchar_t* selection = ofn.lpstrFile; + while (*selection) { // Empty string indicates end of list. + files.push_back(FilePath(selection)); + // Skip over filename and null-terminator. + selection += files.back().value().length() + 1; + } + if (files.empty()) { + success = false; + } else if (files.size() == 1) { + // When there is one file, it contains the path and filename. + paths->swap(files); + } else { + // Otherwise, the first string is the path, and the remainder are + // filenames. + std::vector::iterator path = files.begin(); + for (std::vector::iterator file = path + 1; + file != files.end(); ++file) { + paths->push_back(path->Append(*file)); + } + } + } + return success; +} + +} + +bool BrowserWebViewDelegate::ShowFileChooser(std::vector& file_names, + const bool multi_select, + const WebKit::WebString& title, + const FilePath& default_file) +{ + bool result = false; + + if (multi_select) + { + result = RunOpenMultiFileDialog(L"", browser_->GetMainWndHandle(), &file_names); + } + else + { + FilePath file_name; + result = RunOpenFileDialog(L"", browser_->GetMainWndHandle(), &file_name); + if (result) + file_names.push_back(file_name); + } + + return result; +} +