Skip to content

Commit 56a0b45

Browse files
trop[bot]mlaurencinckerr
authored
fix: modify file extension generation on Windows (#35171)
fix: modify file extension generation on Windows (#34723) * fix: modify file extension generation on Windows * modify includes * include vector in header * add win build flags * remove hardcoded strings * Update shell/browser/electron_download_manager_delegate.h Co-authored-by: Charles Kerr <charles@charleskerr.com> * fix string manipulation and function definitions * Update electron_download_manager_delegate.h * convert to std::string and modify for electron * Update shell/browser/electron_download_manager_delegate.cc Co-authored-by: Charles Kerr <charles@charleskerr.com> * remove vector include and update conversion * add vectr include for lint Co-authored-by: Charles Kerr <charles@charleskerr.com> Co-authored-by: Michaela Laurencin <35157522+mlaurencin@users.noreply.github.com> Co-authored-by: Charles Kerr <charles@charleskerr.com>
1 parent 5871f81 commit 56a0b45

File tree

1 file changed

+126
-0
lines changed

1 file changed

+126
-0
lines changed

shell/browser/electron_download_manager_delegate.cc

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@
3131
#include "shell/common/gin_converters/file_path_converter.h"
3232
#include "shell/common/options_switches.h"
3333

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+
3444
namespace electron {
3545

3646
namespace {
@@ -63,6 +73,112 @@ base::FilePath CreateDownloadPath(const GURL& url,
6373
return download_path.Append(generated_name);
6474
}
6575

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, &reg_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+
66182
} // namespace
67183

68184
ElectronDownloadManagerDelegate::ElectronDownloadManagerDelegate(
@@ -131,6 +247,16 @@ void ElectronDownloadManagerDelegate::OnDownloadPathGenerated(
131247
const bool offscreen = !web_preferences || web_preferences->IsOffscreen();
132248
settings.force_detached = offscreen;
133249

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+
134260
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
135261
v8::HandleScope scope(isolate);
136262
gin_helper::Promise<gin_helper::Dictionary> dialog_promise(isolate);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy