diff --git a/shell/browser/api/electron_api_dialog.cc b/shell/browser/api/electron_api_dialog.cc index 66c7bf293753..b5feef3eed00 100644 --- a/shell/browser/api/electron_api_dialog.cc +++ b/shell/browser/api/electron_api_dialog.cc @@ -71,9 +71,8 @@ v8::Local 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 ShowSaveDialog( diff --git a/shell/browser/api/electron_api_web_contents.cc b/shell/browser/api/electron_api_web_contents.cc index ccfc5852fc64..5f87c4c8d49e 100644 --- a/shell/browser/api/electron_api_web_contents.cc +++ b/shell/browser/api/electron_api_web_contents.cc @@ -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" @@ -4008,30 +4009,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, diff --git a/shell/browser/ui/file_dialog.h b/shell/browser/ui/file_dialog.h index b8858c06ecb3..f7757da491c6 100644 --- a/shell/browser/ui/file_dialog.h +++ b/shell/browser/ui/file_dialog.h @@ -5,6 +5,7 @@ #ifndef ELECTRON_SHELL_BROWSER_UI_FILE_DIALOG_H_ #define ELECTRON_SHELL_BROWSER_UI_FILE_DIALOG_H_ +#include #include #include #include @@ -72,7 +73,8 @@ bool ShowOpenDialogSync(const DialogSettings& settings, void ShowOpenDialog(const DialogSettings& settings, gin_helper::Promise promise); -bool ShowSaveDialogSync(const DialogSettings& settings, base::FilePath* path); +std::optional ShowSaveDialogSync( + const DialogSettings& settings); void ShowSaveDialog(const DialogSettings& settings, gin_helper::Promise promise); diff --git a/shell/browser/ui/file_dialog_linux.cc b/shell/browser/ui/file_dialog_linux.cc index 732820aa193a..56251d971762 100644 --- a/shell/browser/ui/file_dialog_linux.cc +++ b/shell/browser/ui/file_dialog_linux.cc @@ -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 ShowSaveDialogSync( + const DialogSettings& settings) { + std::optional 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* 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, diff --git a/shell/browser/ui/file_dialog_mac.mm b/shell/browser/ui/file_dialog_mac.mm index c3967ef0d3c8..98896b6dfac4 100644 --- a/shell/browser/ui/file_dialog_mac.mm +++ b/shell/browser/ui/file_dialog_mac.mm @@ -436,19 +436,18 @@ void ShowOpenDialog(const DialogSettings& settings, } } -bool ShowSaveDialogSync(const DialogSettings& settings, base::FilePath* path) { - DCHECK(path); +std::optional 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, diff --git a/shell/browser/ui/file_dialog_win.cc b/shell/browser/ui/file_dialog_win.cc index 7e48879c4130..5ded77f64661 100644 --- a/shell/browser/ui/file_dialog_win.cc +++ b/shell/browser/ui/file_dialog_win.cc @@ -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 ShowSaveDialogSync( + const DialogSettings& settings) { ATL::CComPtr 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 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 promise) { auto done = [](gin_helper::Promise promise, - bool success, base::FilePath result) { + std::optional 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),