|
31 | 31 | #include "shell/common/gin_converters/file_path_converter.h"
|
32 | 32 | #include "shell/common/options_switches.h"
|
33 | 33 |
|
| 34 | +#if BUILDFLAG(IS_WIN) |
| 35 | +#include <vector> |
| 36 | + |
| 37 | +#include "base/i18n/case_conversion.h" |
| 38 | +#include "base/win/registry.h" |
| 39 | +#include "ui/base/l10n/l10n_util.h" |
| 40 | +#include "ui/shell_dialogs/execute_select_file_win.h" |
| 41 | +#include "ui/strings/grit/ui_strings.h" |
| 42 | +#endif // BUILDFLAG(IS_WIN) |
| 43 | + |
34 | 44 | namespace electron {
|
35 | 45 |
|
36 | 46 | namespace {
|
@@ -63,6 +73,112 @@ base::FilePath CreateDownloadPath(const GURL& url,
|
63 | 73 | return download_path.Append(generated_name);
|
64 | 74 | }
|
65 | 75 |
|
| 76 | +#if BUILDFLAG(IS_WIN) |
| 77 | +// Get the file type description from the registry. This will be "Text Document" |
| 78 | +// for .txt files, "JPEG Image" for .jpg files, etc. If the registry doesn't |
| 79 | +// have an entry for the file type, we return false, true if the description was |
| 80 | +// found. 'file_ext' must be in form ".txt". |
| 81 | +// Modified from ui/shell_dialogs/select_file_dialog_win.cc |
| 82 | +bool GetRegistryDescriptionFromExtension(const std::string& file_ext, |
| 83 | + std::string* reg_description) { |
| 84 | + DCHECK(reg_description); |
| 85 | + base::win::RegKey reg_ext(HKEY_CLASSES_ROOT, |
| 86 | + base::UTF8ToWide(file_ext).c_str(), KEY_READ); |
| 87 | + std::wstring reg_app; |
| 88 | + if (reg_ext.ReadValue(nullptr, ®_app) == ERROR_SUCCESS && |
| 89 | + !reg_app.empty()) { |
| 90 | + base::win::RegKey reg_link(HKEY_CLASSES_ROOT, reg_app.c_str(), KEY_READ); |
| 91 | + std::wstring description; |
| 92 | + if (reg_link.ReadValue(nullptr, &description) == ERROR_SUCCESS) { |
| 93 | + *reg_description = base::WideToUTF8(description); |
| 94 | + return true; |
| 95 | + } |
| 96 | + } |
| 97 | + return false; |
| 98 | +} |
| 99 | + |
| 100 | +// Set up a filter for a Save/Open dialog, |ext_desc| as the text descriptions |
| 101 | +// of the |file_ext| types (optional), and (optionally) the default 'All Files' |
| 102 | +// view. The purpose of the filter is to show only files of a particular type in |
| 103 | +// a Windows Save/Open dialog box. The resulting filter is returned. The filter |
| 104 | +// created here are: |
| 105 | +// 1. only files that have 'file_ext' as their extension |
| 106 | +// 2. all files (only added if 'include_all_files' is true) |
| 107 | +// If a description is not provided for a file extension, it will be retrieved |
| 108 | +// from the registry. If the file extension does not exist in the registry, a |
| 109 | +// default description will be created (e.g. "qqq" yields "QQQ File"). |
| 110 | +// Copied from ui/shell_dialogs/select_file_dialog_win.cc |
| 111 | +file_dialog::Filters FormatFilterForExtensions( |
| 112 | + const std::vector<std::string>& file_ext, |
| 113 | + const std::vector<std::string>& ext_desc, |
| 114 | + bool include_all_files, |
| 115 | + bool keep_extension_visible) { |
| 116 | + const std::string all_ext = "*"; |
| 117 | + const std::string all_desc = |
| 118 | + l10n_util::GetStringUTF8(IDS_APP_SAVEAS_ALL_FILES); |
| 119 | + |
| 120 | + DCHECK(file_ext.size() >= ext_desc.size()); |
| 121 | + |
| 122 | + if (file_ext.empty()) |
| 123 | + include_all_files = true; |
| 124 | + |
| 125 | + file_dialog::Filters result; |
| 126 | + result.reserve(file_ext.size() + 1); |
| 127 | + |
| 128 | + for (size_t i = 0; i < file_ext.size(); ++i) { |
| 129 | + std::string ext = file_ext[i]; |
| 130 | + std::string desc; |
| 131 | + if (i < ext_desc.size()) |
| 132 | + desc = ext_desc[i]; |
| 133 | + |
| 134 | + if (ext.empty()) { |
| 135 | + // Force something reasonable to appear in the dialog box if there is no |
| 136 | + // extension provided. |
| 137 | + include_all_files = true; |
| 138 | + continue; |
| 139 | + } |
| 140 | + |
| 141 | + if (desc.empty()) { |
| 142 | + DCHECK(ext.find('.') != std::string::npos); |
| 143 | + std::string first_extension = ext.substr(ext.find('.')); |
| 144 | + size_t first_separator_index = first_extension.find(';'); |
| 145 | + if (first_separator_index != std::string::npos) |
| 146 | + first_extension = first_extension.substr(0, first_separator_index); |
| 147 | + |
| 148 | + // Find the extension name without the preceeding '.' character. |
| 149 | + std::string ext_name = first_extension; |
| 150 | + size_t ext_index = ext_name.find_first_not_of('.'); |
| 151 | + if (ext_index != std::string::npos) |
| 152 | + ext_name = ext_name.substr(ext_index); |
| 153 | + |
| 154 | + if (!GetRegistryDescriptionFromExtension(first_extension, &desc)) { |
| 155 | + // The extension doesn't exist in the registry. Create a description |
| 156 | + // based on the unknown extension type (i.e. if the extension is .qqq, |
| 157 | + // then we create a description "QQQ File"). |
| 158 | + desc = l10n_util::GetStringFUTF8( |
| 159 | + IDS_APP_SAVEAS_EXTENSION_FORMAT, |
| 160 | + base::i18n::ToUpper(base::UTF8ToUTF16(ext_name))); |
| 161 | + include_all_files = true; |
| 162 | + } |
| 163 | + if (desc.empty()) |
| 164 | + desc = "*." + ext_name; |
| 165 | + } else if (keep_extension_visible) { |
| 166 | + // Having '*' in the description could cause the windows file dialog to |
| 167 | + // not include the file extension in the file dialog. So strip out any '*' |
| 168 | + // characters if `keep_extension_visible` is set. |
| 169 | + base::ReplaceChars(desc, "*", base::StringPiece(), &desc); |
| 170 | + } |
| 171 | + |
| 172 | + result.push_back({desc, {ext}}); |
| 173 | + } |
| 174 | + |
| 175 | + if (include_all_files) |
| 176 | + result.push_back({all_desc, {all_ext}}); |
| 177 | + |
| 178 | + return result; |
| 179 | +} |
| 180 | +#endif // BUILDFLAG(IS_WIN) |
| 181 | + |
66 | 182 | } // namespace
|
67 | 183 |
|
68 | 184 | ElectronDownloadManagerDelegate::ElectronDownloadManagerDelegate(
|
@@ -131,6 +247,16 @@ void ElectronDownloadManagerDelegate::OnDownloadPathGenerated(
|
131 | 247 | const bool offscreen = !web_preferences || web_preferences->IsOffscreen();
|
132 | 248 | settings.force_detached = offscreen;
|
133 | 249 |
|
| 250 | +#if BUILDFLAG(IS_WIN) |
| 251 | + if (settings.filters.empty()) { |
| 252 | + const std::wstring extension = settings.default_path.FinalExtension(); |
| 253 | + if (!extension.empty()) { |
| 254 | + settings.filters = FormatFilterForExtensions( |
| 255 | + {base::WideToUTF8(extension)}, {""}, true, true); |
| 256 | + } |
| 257 | + } |
| 258 | +#endif // BUILDFLAG(IS_WIN) |
| 259 | + |
134 | 260 | v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
135 | 261 | v8::HandleScope scope(isolate);
|
136 | 262 | gin_helper::Promise<gin_helper::Dictionary> dialog_promise(isolate);
|
|
0 commit comments