|
20 | 20 | #include "libcef/drag_data_impl.h" |
21 | 21 | #include "libcef/web_drop_target_win.h" |
22 | 22 |
|
| 23 | +#include "base/i18n/case_conversion.h" |
23 | 24 | #include "base/message_loop.h" |
24 | 25 | #include "base/string_util.h" |
| 26 | +#include "base/utf_string_conversions.h" |
| 27 | +#include "base/win/registry.h" |
| 28 | +#include "net/base/mime_util.h" |
25 | 29 | #include "net/base/net_errors.h" |
26 | 30 | #include "third_party/WebKit/Source/WebKit/chromium/public/WebContextMenuData.h" |
27 | 31 | #include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h" |
|
31 | 35 | #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebPoint.h" |
32 | 36 | #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h" |
33 | 37 | #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" |
| 38 | +#include "ui/base/l10n/l10n_util.h" |
34 | 39 | #include "ui/gfx/gdi_util.h" |
35 | 40 | #include "ui/gfx/native_widget_types.h" |
36 | 41 | #include "ui/gfx/point.h" |
@@ -61,6 +66,178 @@ namespace { |
61 | 66 |
|
62 | 67 | static const wchar_t kPluginWindowClassName[] = L"WebPluginHost"; |
63 | 68 |
|
| 69 | +// From ui/base/dialogs/select_file_dialog_win.cc. |
| 70 | + |
| 71 | +// Get the file type description from the registry. This will be "Text Document" |
| 72 | +// for .txt files, "JPEG Image" for .jpg files, etc. If the registry doesn't |
| 73 | +// have an entry for the file type, we return false, true if the description was |
| 74 | +// found. 'file_ext' must be in form ".txt". |
| 75 | +static bool GetRegistryDescriptionFromExtension(const std::wstring& file_ext, |
| 76 | + std::wstring* reg_description) { |
| 77 | + DCHECK(reg_description); |
| 78 | + base::win::RegKey reg_ext(HKEY_CLASSES_ROOT, file_ext.c_str(), KEY_READ); |
| 79 | + std::wstring reg_app; |
| 80 | + if (reg_ext.ReadValue(NULL, ®_app) == ERROR_SUCCESS && !reg_app.empty()) { |
| 81 | + base::win::RegKey reg_link(HKEY_CLASSES_ROOT, reg_app.c_str(), KEY_READ); |
| 82 | + if (reg_link.ReadValue(NULL, reg_description) == ERROR_SUCCESS) |
| 83 | + return true; |
| 84 | + } |
| 85 | + return false; |
| 86 | +} |
| 87 | + |
| 88 | +// Set up a filter for a Save/Open dialog, which will consist of |file_ext| file |
| 89 | +// extensions (internally separated by semicolons), |ext_desc| as the text |
| 90 | +// descriptions of the |file_ext| types (optional), and (optionally) the default |
| 91 | +// 'All Files' view. The purpose of the filter is to show only files of a |
| 92 | +// particular type in a Windows Save/Open dialog box. The resulting filter is |
| 93 | +// returned. The filters created here are: |
| 94 | +// 1. only files that have 'file_ext' as their extension |
| 95 | +// 2. all files (only added if 'include_all_files' is true) |
| 96 | +// Example: |
| 97 | +// file_ext: { "*.txt", "*.htm;*.html" } |
| 98 | +// ext_desc: { "Text Document" } |
| 99 | +// returned: "Text Document\0*.txt\0HTML Document\0*.htm;*.html\0" |
| 100 | +// "All Files\0*.*\0\0" (in one big string) |
| 101 | +// If a description is not provided for a file extension, it will be retrieved |
| 102 | +// from the registry. If the file extension does not exist in the registry, it |
| 103 | +// will be omitted from the filter, as it is likely a bogus extension. |
| 104 | +std::wstring FormatFilterForExtensions( |
| 105 | + const std::vector<std::wstring>& file_ext, |
| 106 | + const std::vector<std::wstring>& ext_desc, |
| 107 | + bool include_all_files) { |
| 108 | + const std::wstring all_ext = L"*.*"; |
| 109 | + const std::wstring all_desc = |
| 110 | + std::wstring(L"All Files") + |
| 111 | + L" (" + all_ext + L")"; |
| 112 | + |
| 113 | + DCHECK(file_ext.size() >= ext_desc.size()); |
| 114 | + |
| 115 | + if (file_ext.empty()) |
| 116 | + include_all_files = true; |
| 117 | + |
| 118 | + std::wstring result; |
| 119 | + |
| 120 | + if (file_ext.size() > 1) { |
| 121 | + std::wstring extensions = JoinString(file_ext, L';'); |
| 122 | + std::wstring all_supported_types = L"All Supported Types (" + |
| 123 | + extensions + L")"; |
| 124 | + |
| 125 | + result.append(all_supported_types.c_str(), all_supported_types.size() + 1); |
| 126 | + result.append(extensions.c_str(), extensions.size() + 1); |
| 127 | + } |
| 128 | + |
| 129 | + for (size_t i = 0; i < file_ext.size(); ++i) { |
| 130 | + std::wstring ext = file_ext[i]; |
| 131 | + std::wstring desc; |
| 132 | + if (i < ext_desc.size()) |
| 133 | + desc = ext_desc[i]; |
| 134 | + |
| 135 | + if (ext.empty()) { |
| 136 | + // Force something reasonable to appear in the dialog box if there is no |
| 137 | + // extension provided. |
| 138 | + include_all_files = true; |
| 139 | + continue; |
| 140 | + } |
| 141 | + |
| 142 | + if (desc.empty()) { |
| 143 | + DCHECK(ext.find(L'.') != std::wstring::npos); |
| 144 | + std::wstring first_extension = ext.substr(ext.find(L'.')); |
| 145 | + size_t first_separator_index = first_extension.find(L';'); |
| 146 | + if (first_separator_index != std::wstring::npos) |
| 147 | + first_extension = first_extension.substr(0, first_separator_index); |
| 148 | + |
| 149 | + // Find the extension name without the preceeding '.' character. |
| 150 | + std::wstring ext_name = first_extension; |
| 151 | + size_t ext_index = ext_name.find_first_not_of(L'.'); |
| 152 | + if (ext_index != std::wstring::npos) |
| 153 | + ext_name = ext_name.substr(ext_index); |
| 154 | + |
| 155 | + if (!GetRegistryDescriptionFromExtension(first_extension, &desc)) { |
| 156 | + // The extension doesn't exist in the registry. Create a description |
| 157 | + // based on the unknown extension type (i.e. if the extension is .qqq, |
| 158 | + // the we create a description "QQQ File (.qqq)"). |
| 159 | + include_all_files = true; |
| 160 | + std::vector<string16> replacements; |
| 161 | + replacements.push_back(base::i18n::ToUpper(WideToUTF16(ext_name))); |
| 162 | + replacements.push_back(ext_name); |
| 163 | + desc = ReplaceStringPlaceholders( |
| 164 | + L"$1 File (.$2)", |
| 165 | + replacements, |
| 166 | + NULL); |
| 167 | + } |
| 168 | + } |
| 169 | + |
| 170 | + if (!desc.empty()) |
| 171 | + desc += L" (" + ext + L")"; |
| 172 | + else |
| 173 | + desc = ext; |
| 174 | + |
| 175 | + result.append(desc.c_str(), desc.size() + 1); // Append NULL too. |
| 176 | + result.append(ext.c_str(), ext.size() + 1); |
| 177 | + } |
| 178 | + |
| 179 | + if (include_all_files) { |
| 180 | + result.append(all_desc.c_str(), all_desc.size() + 1); |
| 181 | + result.append(all_ext.c_str(), all_ext.size() + 1); |
| 182 | + } |
| 183 | + |
| 184 | + result.append(1, '\0'); // Double NULL required. |
| 185 | + return result; |
| 186 | +} |
| 187 | + |
| 188 | +std::wstring GetDescriptionFromMimeType(const std::string& mime_type) { |
| 189 | + // Check for wild card mime types and return an appropriate description. |
| 190 | + static const struct { |
| 191 | + const char* mime_type; |
| 192 | + std::wstring full_string; |
| 193 | + } kWildCardMimeTypes[] = { |
| 194 | + { "audio", L"Audio Files" }, |
| 195 | + { "image", L"Image Files" }, |
| 196 | + { "text", L"Text Files" }, |
| 197 | + { "video", L"Video Files" }, |
| 198 | + }; |
| 199 | + |
| 200 | + for (size_t i = 0; i < arraysize(kWildCardMimeTypes); ++i) { |
| 201 | + if (mime_type == std::string(kWildCardMimeTypes[i].mime_type) + "/*") |
| 202 | + return std::wstring(kWildCardMimeTypes[i].full_string); |
| 203 | + } |
| 204 | + |
| 205 | + return std::wstring(); |
| 206 | +} |
| 207 | + |
| 208 | +std::wstring GetFilterStringFromAcceptTypes( |
| 209 | + const std::vector<std::string>& accept_types) { |
| 210 | + std::vector<std::wstring> extensions; |
| 211 | + std::vector<std::wstring> descriptions; |
| 212 | + |
| 213 | + for (size_t i = 0; i < accept_types.size(); ++i) { |
| 214 | + std::string ascii_type = accept_types[i]; |
| 215 | + if (ascii_type.length()) { |
| 216 | + // Just treat as extension if contains '.' as the first character. |
| 217 | + if (ascii_type[0] == '.') { |
| 218 | + extensions.push_back(L"*" + ASCIIToWide(ascii_type)); |
| 219 | + descriptions.push_back(std::wstring()); |
| 220 | + } else { |
| 221 | + // Otherwise convert mime type to one or more extensions. |
| 222 | + std::vector<FilePath::StringType> ext; |
| 223 | + std::wstring ext_str; |
| 224 | + net::GetExtensionsForMimeType(ascii_type, &ext); |
| 225 | + if (ext.size() > 0) { |
| 226 | + for (size_t x = 0; x < ext.size(); ++x) { |
| 227 | + if (x != 0) |
| 228 | + ext_str += L";"; |
| 229 | + ext_str += L"*." + ext[x]; |
| 230 | + } |
| 231 | + extensions.push_back(ext_str); |
| 232 | + descriptions.push_back(GetDescriptionFromMimeType(ascii_type)); |
| 233 | + } |
| 234 | + } |
| 235 | + } |
| 236 | + } |
| 237 | + |
| 238 | + return FormatFilterForExtensions(extensions, descriptions, true); |
| 239 | +} |
| 240 | + |
64 | 241 | void AddMenuItem(CefRefPtr<CefBrowser> browser, |
65 | 242 | CefRefPtr<CefMenuHandler> handler, |
66 | 243 | HMENU menu, |
@@ -648,23 +825,26 @@ bool RunOpenMultiFileDialog(const std::wstring& filter, HWND owner, |
648 | 825 |
|
649 | 826 | } // namespace |
650 | 827 |
|
651 | | -bool BrowserWebViewDelegate::ShowFileChooser(std::vector<FilePath>& file_names, |
652 | | - const bool multi_select, |
653 | | - const WebKit::WebString& title, |
654 | | - const FilePath& default_file) { |
| 828 | +bool BrowserWebViewDelegate::ShowFileChooser( |
| 829 | + std::vector<FilePath>& file_names, |
| 830 | + bool multi_select, |
| 831 | + const WebKit::WebString& title, |
| 832 | + const FilePath& default_file, |
| 833 | + const std::vector<std::string>& accept_mime_types) { |
655 | 834 | bool result = false; |
| 835 | + const std::wstring& filter = |
| 836 | + GetFilterStringFromAcceptTypes(accept_mime_types); |
656 | 837 |
|
657 | 838 | if (multi_select) { |
658 | | - result = RunOpenMultiFileDialog(L"", browser_->UIT_GetMainWndHandle(), |
659 | | - &file_names); |
| 839 | + result = RunOpenMultiFileDialog(filter, browser_->UIT_GetMainWndHandle(), |
| 840 | + &file_names); |
660 | 841 | } else { |
661 | 842 | FilePath file_name; |
662 | | - result = RunOpenFileDialog(L"", browser_->UIT_GetMainWndHandle(), |
663 | | - &file_name); |
| 843 | + result = RunOpenFileDialog(filter, browser_->UIT_GetMainWndHandle(), |
| 844 | + &file_name); |
664 | 845 | if (result) |
665 | 846 | file_names.push_back(file_name); |
666 | 847 | } |
667 | 848 |
|
668 | 849 | return result; |
669 | 850 | } |
670 | | - |
|
0 commit comments