refactor: have ShowSaveDialogSync() return a std::optional<base::FilePath> (#47453)

* refactor: have ShowSaveDialogSync() return a std::optional<base::FilePath>

Co-authored-by: Charles Kerr <charles@charleskerr.com>

* fixup! refactor: have ShowSaveDialogSync() return a std::optional<base::FilePath>

Co-authored-by: Charles Kerr <charles@charleskerr.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
This commit is contained in:
trop[bot] 2025-06-13 10:03:03 +02:00 committed by GitHub
commit f72ec2c45a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 57 additions and 46 deletions

View file

@ -71,9 +71,8 @@ v8::Local<v8::Promise> ShowOpenDialog(
void ShowSaveDialogSync(const file_dialog::DialogSettings& settings,
gin::Arguments* args) {
base::FilePath path;
if (file_dialog::ShowSaveDialogSync(settings, &path))
args->Return(path);
if (const auto path = file_dialog::ShowSaveDialogSync(settings))
args->Return(*path);
}
v8::Local<v8::Promise> ShowSaveDialog(

View file

@ -18,6 +18,7 @@
#include "base/containers/fixed_flat_map.h"
#include "base/containers/flat_set.h"
#include "base/containers/id_map.h"
#include "base/containers/map_util.h"
#include "base/files/file_util.h"
#include "base/json/json_reader.h"
#include "base/no_destructor.h"
@ -4013,30 +4014,35 @@ void WebContents::DevToolsSaveToFile(const std::string& url,
const std::string& content,
bool save_as,
bool is_base64) {
base::FilePath path;
auto it = saved_files_.find(url);
if (it != saved_files_.end() && !save_as) {
path = it->second;
} else {
const base::FilePath* path = nullptr;
if (!save_as)
base::FindOrNull(saved_files_, url);
if (path == nullptr) {
file_dialog::DialogSettings settings;
settings.parent_window = owner_window();
settings.force_detached = offscreen_;
settings.title = url;
settings.default_path = base::FilePath::FromUTF8Unsafe(url);
if (!file_dialog::ShowSaveDialogSync(settings, &path)) {
inspectable_web_contents_->CallClientFunction(
"DevToolsAPI", "canceledSaveURL", base::Value(url));
return;
if (auto new_path = file_dialog::ShowSaveDialogSync(settings)) {
auto [iter, _] = saved_files_.try_emplace(url, std::move(*new_path));
path = &iter->second;
}
}
saved_files_[url] = path;
if (path == nullptr) {
inspectable_web_contents_->CallClientFunction(
"DevToolsAPI", "canceledSaveURL", base::Value{url});
return;
}
// Notify DevTools.
inspectable_web_contents_->CallClientFunction(
"DevToolsAPI", "savedURL", base::Value(url),
base::Value(path.AsUTF8Unsafe()));
"DevToolsAPI", "savedURL", base::Value{url},
base::Value{path->AsUTF8Unsafe()});
file_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&WriteToFile, path, content, is_base64));
FROM_HERE, base::BindOnce(&WriteToFile, *path, content, is_base64));
}
void WebContents::DevToolsAppendToFile(const std::string& url,

View file

@ -5,6 +5,7 @@
#ifndef ELECTRON_SHELL_BROWSER_UI_FILE_DIALOG_H_
#define ELECTRON_SHELL_BROWSER_UI_FILE_DIALOG_H_
#include <optional>
#include <string>
#include <utility>
#include <vector>
@ -72,7 +73,8 @@ bool ShowOpenDialogSync(const DialogSettings& settings,
void ShowOpenDialog(const DialogSettings& settings,
gin_helper::Promise<gin_helper::Dictionary> promise);
bool ShowSaveDialogSync(const DialogSettings& settings, base::FilePath* path);
std::optional<base::FilePath> ShowSaveDialogSync(
const DialogSettings& settings);
void ShowSaveDialog(const DialogSettings& settings,
gin_helper::Promise<gin_helper::Dictionary> promise);

View file

@ -233,20 +233,25 @@ void ShowOpenDialog(const DialogSettings& settings,
dialog->RunOpenDialog(std::move(promise), settings);
}
bool ShowSaveDialogSync(const DialogSettings& settings, base::FilePath* path) {
base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
auto cb = base::BindOnce(
[](base::RepeatingClosure cb, base::FilePath* file_path,
gin_helper::Dictionary result) {
result.Get("filePath", file_path);
std::move(cb).Run();
},
run_loop.QuitClosure(), path);
std::optional<base::FilePath> ShowSaveDialogSync(
const DialogSettings& settings) {
std::optional<base::FilePath> path;
FileChooserDialog* dialog = new FileChooserDialog();
dialog->RunSaveDialog(std::move(cb), settings);
base::RunLoop run_loop{base::RunLoop::Type::kNestableTasksAllowed};
auto on_chooser_dialog_done = base::BindOnce(
[](base::RepeatingClosure run_loop_closure,
std::optional<base::FilePath>* path, gin_helper::Dictionary result) {
if (base::FilePath val; result.Get("filePath", &val))
*path = std::move(val);
std::move(run_loop_closure).Run();
},
run_loop.QuitClosure(), &path);
auto* const dialog = new FileChooserDialog{};
dialog->RunSaveDialog(std::move(on_chooser_dialog_done), settings);
run_loop.Run();
return !path->empty();
return path;
}
void ShowSaveDialog(const DialogSettings& settings,

View file

@ -436,19 +436,18 @@ void ShowOpenDialog(const DialogSettings& settings,
}
}
bool ShowSaveDialogSync(const DialogSettings& settings, base::FilePath* path) {
DCHECK(path);
std::optional<base::FilePath> ShowSaveDialogSync(
const DialogSettings& settings) {
NSSavePanel* dialog = [NSSavePanel savePanel];
SetupDialog(dialog, settings);
SetupSaveDialogForProperties(dialog, settings.properties);
int chosen = RunModalDialog(dialog, settings);
const int chosen = RunModalDialog(dialog, settings);
if (chosen == NSModalResponseCancel || ![[dialog URL] isFileURL])
return false;
return {};
*path = base::FilePath(base::SysNSStringToUTF8([[dialog URL] path]));
return true;
return base::FilePath{base::SysNSStringToUTF8([[dialog URL] path])};
}
void SaveDialogCompletion(int chosen,

View file

@ -219,11 +219,12 @@ void ShowOpenDialog(const DialogSettings& settings,
base::BindOnce(done, std::move(promise)));
}
bool ShowSaveDialogSync(const DialogSettings& settings, base::FilePath* path) {
std::optional<base::FilePath> ShowSaveDialogSync(
const DialogSettings& settings) {
ATL::CComPtr<IFileSaveDialog> file_save_dialog;
HRESULT hr = file_save_dialog.CoCreateInstance(CLSID_FileSaveDialog);
if (FAILED(hr))
return false;
return {};
DWORD options = FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_OVERWRITEPROMPT;
if (settings.properties & SAVE_DIALOG_SHOW_HIDDEN_FILES)
@ -236,32 +237,31 @@ bool ShowSaveDialogSync(const DialogSettings& settings, base::FilePath* path) {
hr = ShowFileDialog(file_save_dialog, settings);
if (FAILED(hr))
return false;
return {};
CComPtr<IShellItem> pItem;
hr = file_save_dialog->GetResult(&pItem);
if (FAILED(hr))
return false;
return {};
PWSTR result_path = nullptr;
hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &result_path);
if (!SUCCEEDED(hr))
return false;
return {};
*path = base::FilePath(result_path);
auto path = base::FilePath{result_path};
CoTaskMemFree(result_path);
return true;
return path;
}
void ShowSaveDialog(const DialogSettings& settings,
gin_helper::Promise<gin_helper::Dictionary> promise) {
auto done = [](gin_helper::Promise<gin_helper::Dictionary> promise,
bool success, base::FilePath result) {
std::optional<base::FilePath> result) {
v8::HandleScope handle_scope(promise.isolate());
auto dict = gin::Dictionary::CreateEmpty(promise.isolate());
dict.Set("canceled", !success);
dict.Set("filePath", result);
dict.Set("canceled", !result.has_value());
dict.Set("filePath", result.value_or(base::FilePath{}));
promise.Resolve(dict);
};
dialog_thread::Run(base::BindOnce(ShowSaveDialogSync, settings),