electron/shell/browser/ui/file_dialog_linux.cc
Charles Kerr aa23198ad8
chore: remove more unused #include calls (#43000)
* chore: in shell/renderer/renderer_client_base.h, remove include media/base/key_systems_support_registration.h

last use removed in c670e38b (##41610)

* chore: iwyu electron/fuses.h

* chore: iwyu media/base/video_frame.h

* chore: iwyu base/functional/callback.h

* chore: iwyu base/task/cancelable_task_tracker.h

* chore: iwyu shell/browser/draggable_region_provider.h

* chore: iwyu shell/browser/ui/inspectable_web_contents_view.h

* chore: iwyu ui/aura/window.h

* chore: iwyu ui/base/win/shell.h

* chore: iwyu ui/display/win/screen_win.h

* chore: iwyu ui/gfx/geometry/insets.h

* chore: iwyu ui/display/display.h

* chore: iwyu ui/gfx/geometry/skia_conversions.h

* chore: iwyu ui/gfx/geometry/rect_conversions.h

* chore: iwyu ui/gfx/geometry/point.h

* chore: iwyu ui/gfx/scoped_canvas.h

* chore: iwyu ui/gfx/image/image.h

* chore: iwyu ui/accessibility/ax_node_data.h

* chore: iwyu ui/views/animation/ink_drop_highlight.h

* chore: iwyu ui/gfx/font_list.h

* chore: iwyu ui/linux/nav_button_provider.h

* chore: iwyu shell/browser/ui/views/frameless_view.h

* chore: iwyu services/metrics/public/cpp/ukm_source_id.h

* chore: iwyu net/http/http_util.h

* chore: iwyu net/base/mime_util.h

* chore: iwyu content/public/common/content_client.h

* chore: iwyu <list>

* chore: iwyu <optional>

* chore: iwyu <memory>

* chore: iwyu base/files/file_path.h

* chore: iwyu ui/base/cursor/cursor.h

* chore: iwyu build/build_config.h

* chore: iwyu content/public/browser/web_contents.h

* chore: iwyu shell/browser/hid/hid_chooser_context.h

* chore: iwyu shell/common/platform_util.h

* chore: iwyu base/task/single_thread_task_runner.h

* chore: iwyu content/browser/renderer_host/render_widget_host_impl.h

* chore: iwyu content/public/browser/render_widget_host.h

* chore: iwyu shell/browser/electron_browser_context.h

* chore: iwyu content/public/browser/web_contents_observer.h

* chore: iwyu content/public/browser/render_frame_host.h

* chore: iwyu content/public/browser/media_stream_request.h

* chore: iwyu chrome/common/chrome_paths.h

* chore: iwyu chrome/browser/icon_manager.h

* chore: iwyu printing/print_settings.h

* chore: iwyu renderer/pepper_helper.h

* chore: iwyu shell/browser/api/process_metric.h

* chore: iwyu shell/browser/electron_browser_client.h

* chore: iwyu shell/browser/electron_browser_context.h

* chore: iwyu shell/browser/api/electron_api_session.h

* chore: iwyu shell/browser/api/electron_api_app.h

* chore: iwyu shell/browser/ui/views/client_frame_view_linux.h

* chore: iwyu shell/browser/native_window_views.h

* chore: iwyu base/win/windows_version.h

* chore: iwyu shell/common/electron_paths.h

* chore: iwyu content/public/common/content_switches.h

* chore: iwyu third_party/skia/include/core/SkRRect.h

* chore: iwyu third_party/skia/include/core/SkBitmap.h

* chore: iwyu third_party/skia

* chore: iwyu shell/browser/osr/osr_host_display_client.h

* chore: iwyu shell/browser/login_handler.h

* chore: iwyu shell/browser/javascript_environment.h

* chore: iwyu shell/browser/event_emitter_mixin.h

* fix: mac

* fix: mac

* chore: iwyu base/nix/xdg_util.h

* fix: win

* fix: win

* fix: win

* fix: win
2024-07-25 11:25:45 +02:00

243 lines
8.1 KiB
C++

// Copyright (c) 2024 Microsoft, GmbH.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include <vector>
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "shell/browser/javascript_environment.h"
#include "shell/browser/native_window_views.h"
#include "shell/browser/ui/file_dialog.h"
#include "shell/common/gin_converters/callback_converter.h"
#include "shell/common/gin_converters/file_path_converter.h"
#include "ui/gtk/select_file_dialog_linux_gtk.h" // nogncheck
#include "ui/shell_dialogs/select_file_dialog.h"
#include "ui/shell_dialogs/selected_file_info.h"
namespace file_dialog {
DialogSettings::DialogSettings() = default;
DialogSettings::DialogSettings(const DialogSettings&) = default;
DialogSettings::~DialogSettings() = default;
namespace {
ui::SelectFileDialog::Type GetDialogType(int properties) {
if (properties & OPEN_DIALOG_OPEN_DIRECTORY)
return ui::SelectFileDialog::SELECT_FOLDER;
if (properties & OPEN_DIALOG_MULTI_SELECTIONS)
return ui::SelectFileDialog::SELECT_OPEN_MULTI_FILE;
return ui::SelectFileDialog::SELECT_OPEN_FILE;
}
ui::SelectFileDialog::FileTypeInfo GetFilterInfo(const Filters& filters) {
ui::SelectFileDialog::FileTypeInfo file_type_info;
for (const auto& [name, extension_group] : filters) {
file_type_info.extension_description_overrides.push_back(
base::UTF8ToUTF16(name));
const bool has_all_files_wildcard = base::ranges::any_of(
extension_group, [](const auto& ext) { return ext == "*"; });
if (has_all_files_wildcard) {
file_type_info.include_all_files = true;
} else {
file_type_info.extensions.emplace_back(extension_group);
}
}
return file_type_info;
}
class FileChooserDialog : public ui::SelectFileDialog::Listener {
public:
enum class DialogType { OPEN, SAVE };
FileChooserDialog() { dialog_ = ui::SelectFileDialog::Create(this, nullptr); }
~FileChooserDialog() override = default;
void RunSaveDialogImpl(const DialogSettings& settings) {
type_ = DialogType::SAVE;
ui::SelectFileDialog::FileTypeInfo file_info =
GetFilterInfo(settings.filters);
ApplySettings(settings);
dialog_->SelectFile(
ui::SelectFileDialog::SELECT_SAVEAS_FILE,
base::UTF8ToUTF16(settings.title), settings.default_path,
&file_info /* file_types */, 0 /* file_type_index */,
base::FilePath::StringType() /* default_extension */,
settings.parent_window ? settings.parent_window->GetNativeWindow()
: nullptr,
nullptr);
}
void RunSaveDialog(gin_helper::Promise<gin_helper::Dictionary> promise,
const DialogSettings& settings) {
promise_ = std::move(promise);
RunSaveDialogImpl(settings);
}
void RunSaveDialog(base::OnceCallback<void(gin_helper::Dictionary)> callback,
const DialogSettings& settings) {
callback_ = std::move(callback);
RunSaveDialogImpl(settings);
}
void RunOpenDialogImpl(const DialogSettings& settings) {
type_ = DialogType::OPEN;
ui::SelectFileDialog::FileTypeInfo file_info =
GetFilterInfo(settings.filters);
ApplySettings(settings);
dialog_->SelectFile(
GetDialogType(settings.properties), base::UTF8ToUTF16(settings.title),
settings.default_path, &file_info, 0 /* file_type_index */,
base::FilePath::StringType() /* default_extension */,
settings.parent_window ? settings.parent_window->GetNativeWindow()
: nullptr,
nullptr);
}
void RunOpenDialog(gin_helper::Promise<gin_helper::Dictionary> promise,
const DialogSettings& settings) {
promise_ = std::move(promise);
RunOpenDialogImpl(settings);
}
void RunOpenDialog(base::OnceCallback<void(gin_helper::Dictionary)> callback,
const DialogSettings& settings) {
callback_ = std::move(callback);
RunOpenDialogImpl(settings);
}
// ui::SelectFileDialog::Listener
void FileSelected(const ui::SelectedFileInfo& file, int index) override {
v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
v8::HandleScope scope(isolate);
auto dict = gin_helper::Dictionary::CreateEmpty(isolate);
dict.Set("canceled", false);
if (type_ == DialogType::SAVE) {
dict.Set("filePath", file.file_path);
} else {
dict.Set("filePaths", std::vector<base::FilePath>{file.file_path});
}
if (callback_) {
std::move(callback_).Run(dict);
} else {
promise_.Resolve(dict);
}
delete this;
}
void MultiFilesSelected(
const std::vector<ui::SelectedFileInfo>& files) override {
v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
v8::HandleScope scope(isolate);
auto dict = gin_helper::Dictionary::CreateEmpty(isolate);
dict.Set("canceled", false);
dict.Set("filePaths", ui::SelectedFileInfoListToFilePathList(files));
if (callback_) {
std::move(callback_).Run(dict);
} else {
promise_.Resolve(dict);
}
delete this;
}
void FileSelectionCanceled() override {
v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
v8::HandleScope scope(isolate);
auto dict = gin_helper::Dictionary::CreateEmpty(isolate);
dict.Set("canceled", true);
if (type_ == DialogType::SAVE) {
dict.Set("filePath", base::FilePath());
} else {
dict.Set("filePaths", std::vector<base::FilePath>());
}
if (callback_) {
std::move(callback_).Run(dict);
} else {
promise_.Resolve(dict);
}
delete this;
}
private:
void ApplySettings(const DialogSettings& settings) {
dialog_->SetButtonLabel(settings.button_label);
dialog_->SetOverwriteConfirmationShown(
settings.properties & SAVE_DIALOG_SHOW_OVERWRITE_CONFIRMATION);
dialog_->SetMultipleSelectionsAllowed(settings.properties &
OPEN_DIALOG_MULTI_SELECTIONS);
int hidden_flag = type_ == DialogType::SAVE
? static_cast<int>(SAVE_DIALOG_SHOW_HIDDEN_FILES)
: static_cast<int>(OPEN_DIALOG_SHOW_HIDDEN_FILES);
dialog_->SetHiddenShown(settings.properties & hidden_flag);
}
DialogType type_;
scoped_refptr<ui::SelectFileDialog> dialog_;
base::OnceCallback<void(gin_helper::Dictionary)> callback_;
gin_helper::Promise<gin_helper::Dictionary> promise_;
};
} // namespace
bool ShowOpenDialogSync(const DialogSettings& settings,
std::vector<base::FilePath>* paths) {
base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
auto cb = base::BindOnce(
[](base::RepeatingClosure cb, std::vector<base::FilePath>* file_paths,
gin_helper::Dictionary result) {
result.Get("filePaths", file_paths);
std::move(cb).Run();
},
run_loop.QuitClosure(), paths);
FileChooserDialog* dialog = new FileChooserDialog();
dialog->RunOpenDialog(std::move(cb), settings);
run_loop.Run();
return !paths->empty();
}
void ShowOpenDialog(const DialogSettings& settings,
gin_helper::Promise<gin_helper::Dictionary> promise) {
FileChooserDialog* dialog = new FileChooserDialog();
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);
FileChooserDialog* dialog = new FileChooserDialog();
dialog->RunSaveDialog(std::move(cb), settings);
run_loop.Run();
return !path->empty();
}
void ShowSaveDialog(const DialogSettings& settings,
gin_helper::Promise<gin_helper::Dictionary> promise) {
FileChooserDialog* dialog = new FileChooserDialog();
dialog->RunSaveDialog(std::move(promise), settings);
}
} // namespace file_dialog