Merge remote-tracking branch 'origin/master' into macos-open-save-panel

This commit is contained in:
Kevin Sawicki 2017-02-09 11:25:05 -08:00
commit f7f4de36af
17 changed files with 317 additions and 353 deletions

View file

@ -35,6 +35,27 @@ struct Converter<file_dialog::Filter> {
} }
}; };
template<>
struct Converter<file_dialog::DialogSettings> {
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
file_dialog::DialogSettings* out) {
mate::Dictionary dict;
if (!ConvertFromV8(isolate, val, &dict))
return false;
dict.Get("window", &(out->parent_window));
dict.Get("title", &(out->title));
dict.Get("message", &(out->message));
dict.Get("buttonLabel", &(out->button_label));
dict.Get("nameFieldLabel", &(out->name_field_label));
dict.Get("defaultPath", &(out->default_path));
dict.Get("filters", &(out->filters));
dict.Get("properties", &(out->properties));
dict.Get("showsTagField", &(out->shows_tag_field));
return true;
}
};
} // namespace mate } // namespace mate
namespace { namespace {
@ -47,6 +68,8 @@ void ShowMessageBox(int type,
const std::string& title, const std::string& title,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,
const std::string& checkbox_label,
bool checkbox_checked,
const gfx::ImageSkia& icon, const gfx::ImageSkia& icon,
atom::NativeWindow* window, atom::NativeWindow* window,
mate::Arguments* args) { mate::Arguments* args) {
@ -56,8 +79,8 @@ void ShowMessageBox(int type,
peek, peek,
&callback)) { &callback)) {
atom::ShowMessageBox(window, (atom::MessageBoxType)type, buttons, atom::ShowMessageBox(window, (atom::MessageBoxType)type, buttons,
default_id, cancel_id, options, title, default_id, cancel_id, options, title, message, detail,
message, detail, icon, callback); checkbox_label, checkbox_checked, icon, callback);
} else { } else {
int chosen = atom::ShowMessageBox(window, (atom::MessageBoxType)type, int chosen = atom::ShowMessageBox(window, (atom::MessageBoxType)type,
buttons, default_id, cancel_id, buttons, default_id, cancel_id,
@ -66,51 +89,32 @@ void ShowMessageBox(int type,
} }
} }
void ShowOpenDialog(const std::string& title, void ShowOpenDialog(const file_dialog::DialogSettings& settings,
const std::string& button_label,
const base::FilePath& default_path,
const file_dialog::Filters& filters,
int properties,
const std::string& message,
atom::NativeWindow* window,
mate::Arguments* args) { mate::Arguments* args) {
v8::Local<v8::Value> peek = args->PeekNext(); v8::Local<v8::Value> peek = args->PeekNext();
file_dialog::OpenDialogCallback callback; file_dialog::OpenDialogCallback callback;
if (mate::Converter<file_dialog::OpenDialogCallback>::FromV8(args->isolate(), if (mate::Converter<file_dialog::OpenDialogCallback>::FromV8(args->isolate(),
peek, peek,
&callback)) { &callback)) {
file_dialog::ShowOpenDialog(window, title, button_label, default_path, file_dialog::ShowOpenDialog(settings, callback);
filters, properties, message, callback);
} else { } else {
std::vector<base::FilePath> paths; std::vector<base::FilePath> paths;
if (file_dialog::ShowOpenDialog(window, title, button_label, default_path, if (file_dialog::ShowOpenDialog(settings, &paths))
filters, properties, message, &paths))
args->Return(paths); args->Return(paths);
} }
} }
void ShowSaveDialog(const std::string& title, void ShowSaveDialog(const file_dialog::DialogSettings& settings,
const std::string& button_label,
const base::FilePath& default_path,
const file_dialog::Filters& filters,
const std::string& message,
const std::string& name_field_label,
bool shows_tag_field,
atom::NativeWindow* window,
mate::Arguments* args) { mate::Arguments* args) {
v8::Local<v8::Value> peek = args->PeekNext(); v8::Local<v8::Value> peek = args->PeekNext();
file_dialog::SaveDialogCallback callback; file_dialog::SaveDialogCallback callback;
if (mate::Converter<file_dialog::SaveDialogCallback>::FromV8(args->isolate(), if (mate::Converter<file_dialog::SaveDialogCallback>::FromV8(args->isolate(),
peek, peek,
&callback)) { &callback)) {
file_dialog::ShowSaveDialog(window, title, button_label, default_path, file_dialog::ShowSaveDialog(settings, callback);
filters, message, name_field_label,
shows_tag_field, callback);
} else { } else {
base::FilePath path; base::FilePath path;
if (file_dialog::ShowSaveDialog(window, title, button_label, default_path, if (file_dialog::ShowSaveDialog(settings, &path))
filters, message, name_field_label,
shows_tag_field, &path))
args->Return(path); args->Return(path);
} }
} }

View file

@ -90,11 +90,11 @@ void AtomDownloadManagerDelegate::OnDownloadPathGenerated(
base::FilePath path; base::FilePath path;
GetItemSavePath(item, &path); GetItemSavePath(item, &path);
// Show save dialog if save path was not set already on item // Show save dialog if save path was not set already on item
if (path.empty() && file_dialog::ShowSaveDialog(window, item->GetURL().spec(), file_dialog::DialogSettings settings;
"", default_path, settings.parent_window = window;
file_dialog::Filters(), settings.title = item->GetURL().spec();
"", "", false, settings.default_path = default_path;
&path)) { if (path.empty() && file_dialog::ShowSaveDialog(settings, &path)) {
// Remember the last selected download directory. // Remember the last selected download directory.
AtomBrowserContext* browser_context = static_cast<AtomBrowserContext*>( AtomBrowserContext* browser_context = static_cast<AtomBrowserContext*>(
download_manager_->GetBrowserContext()); download_manager_->GetBrowserContext());

View file

@ -38,14 +38,9 @@ void AtomJavaScriptDialogManager::RunJavaScriptDialog(
} }
atom::ShowMessageBox(NativeWindow::FromWebContents(web_contents), atom::ShowMessageBox(NativeWindow::FromWebContents(web_contents),
atom::MessageBoxType::MESSAGE_BOX_TYPE_NONE, atom::MessageBoxType::MESSAGE_BOX_TYPE_NONE, buttons, -1,
buttons, 0, atom::MessageBoxOptions::MESSAGE_BOX_NONE, "",
-1, base::UTF16ToUTF8(message_text), "", "", false,
0,
atom::MessageBoxOptions::MESSAGE_BOX_NONE,
"",
base::UTF16ToUTF8(message_text),
"",
gfx::ImageSkia(), gfx::ImageSkia(),
base::Bind(&OnMessageBoxCallback, callback)); base::Bind(&OnMessageBoxCallback, callback));
} }
@ -66,7 +61,9 @@ void AtomJavaScriptDialogManager::CancelDialogs(
// static // static
void AtomJavaScriptDialogManager::OnMessageBoxCallback( void AtomJavaScriptDialogManager::OnMessageBoxCallback(
const DialogClosedCallback& callback, int code) { const DialogClosedCallback& callback,
int code,
bool checkbox_checked) {
callback.Run(code == 0, base::string16()); callback.Run(code == 0, base::string16());
} }

View file

@ -32,7 +32,8 @@ class AtomJavaScriptDialogManager : public content::JavaScriptDialogManager {
private: private:
static void OnMessageBoxCallback(const DialogClosedCallback& callback, static void OnMessageBoxCallback(const DialogClosedCallback& callback,
int code); int code,
bool checkbox_checked);
}; };
} // namespace atom } // namespace atom

View file

@ -294,10 +294,11 @@ void CommonWebContentsDelegate::DevToolsSaveToFile(
if (it != saved_files_.end() && !save_as) { if (it != saved_files_.end() && !save_as) {
path = it->second; path = it->second;
} else { } else {
file_dialog::Filters filters; file_dialog::DialogSettings settings;
base::FilePath default_path(base::FilePath::FromUTF8Unsafe(url)); settings.parent_window = owner_window();
if (!file_dialog::ShowSaveDialog(owner_window(), url, "", default_path, settings.title = url;
filters, "", "", false, &path)) { settings.default_path = base::FilePath::FromUTF8Unsafe(url);
if (!file_dialog::ShowSaveDialog(settings, &path)) {
base::StringValue url_value(url); base::StringValue url_value(url);
web_contents_->CallClientFunction( web_contents_->CallClientFunction(
"DevToolsAPI.canceledSaveURL", &url_value, nullptr, nullptr); "DevToolsAPI.canceledSaveURL", &url_value, nullptr, nullptr);
@ -358,12 +359,11 @@ void CommonWebContentsDelegate::DevToolsAddFileSystem(
const base::FilePath& file_system_path) { const base::FilePath& file_system_path) {
base::FilePath path = file_system_path; base::FilePath path = file_system_path;
if (path.empty()) { if (path.empty()) {
file_dialog::Filters filters;
base::FilePath default_path;
std::vector<base::FilePath> paths; std::vector<base::FilePath> paths;
int flag = file_dialog::FILE_DIALOG_OPEN_DIRECTORY; file_dialog::DialogSettings settings;
if (!file_dialog::ShowOpenDialog(owner_window(), "", "", default_path, settings.parent_window = owner_window();
filters, flag, "", &paths)) settings.properties = file_dialog::FILE_DIALOG_OPEN_DIRECTORY;
if (!file_dialog::ShowOpenDialog(settings, &paths))
return; return;
path = paths[0]; path = paths[0];

View file

@ -37,42 +37,28 @@ typedef base::Callback<void(
typedef base::Callback<void( typedef base::Callback<void(
bool result, const base::FilePath& path)> SaveDialogCallback; bool result, const base::FilePath& path)> SaveDialogCallback;
bool ShowOpenDialog(atom::NativeWindow* parent_window, struct DialogSettings {
const std::string& title, atom::NativeWindow* parent_window = nullptr;
const std::string& button_label, std::string title;
const base::FilePath& default_path, std::string message;
const Filters& filters, std::string button_label;
int properties, std::string name_field_label;
const std::string& message, base::FilePath default_path;
Filters filters;
int properties = 0;
bool shows_tag_field = true;
};
bool ShowOpenDialog(const DialogSettings& settings,
std::vector<base::FilePath>* paths); std::vector<base::FilePath>* paths);
void ShowOpenDialog(atom::NativeWindow* parent_window, void ShowOpenDialog(const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
int properties,
const std::string& message,
const OpenDialogCallback& callback); const OpenDialogCallback& callback);
bool ShowSaveDialog(atom::NativeWindow* parent_window, bool ShowSaveDialog(const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
const std::string& message,
const std::string& name_field_label,
bool shows_tag_field,
base::FilePath* path); base::FilePath* path);
void ShowSaveDialog(atom::NativeWindow* parent_window, void ShowSaveDialog(const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
const std::string& message,
const std::string& name_field_label,
bool shows_tag_field,
const SaveDialogCallback& callback); const SaveDialogCallback& callback);
} // namespace file_dialog } // namespace file_dialog

View file

@ -36,24 +36,20 @@ void OnFileFilterDataDestroyed(std::string* file_extension) {
class FileChooserDialog { class FileChooserDialog {
public: public:
FileChooserDialog(GtkFileChooserAction action, FileChooserDialog(GtkFileChooserAction action,
atom::NativeWindow* parent_window, const DialogSettings& settings)
const std::string& title, : parent_(static_cast<atom::NativeWindowViews*>(settings.parent_window)),
const std::string& button_label, filters_(settings.filters) {
const base::FilePath& default_path,
const Filters& filters)
: parent_(static_cast<atom::NativeWindowViews*>(parent_window)),
filters_(filters) {
const char* confirm_text = GTK_STOCK_OK; const char* confirm_text = GTK_STOCK_OK;
if (!button_label.empty()) if (!settings.button_label.empty())
confirm_text = button_label.c_str(); confirm_text = settings.button_label.c_str();
else if (action == GTK_FILE_CHOOSER_ACTION_SAVE) else if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
confirm_text = GTK_STOCK_SAVE; confirm_text = GTK_STOCK_SAVE;
else if (action == GTK_FILE_CHOOSER_ACTION_OPEN) else if (action == GTK_FILE_CHOOSER_ACTION_OPEN)
confirm_text = GTK_STOCK_OPEN; confirm_text = GTK_STOCK_OPEN;
dialog_ = gtk_file_chooser_dialog_new( dialog_ = gtk_file_chooser_dialog_new(
title.c_str(), settings.title.c_str(),
NULL, NULL,
action, action,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
@ -71,20 +67,20 @@ class FileChooserDialog {
if (action != GTK_FILE_CHOOSER_ACTION_OPEN) if (action != GTK_FILE_CHOOSER_ACTION_OPEN)
gtk_file_chooser_set_create_folders(GTK_FILE_CHOOSER(dialog_), TRUE); gtk_file_chooser_set_create_folders(GTK_FILE_CHOOSER(dialog_), TRUE);
if (!default_path.empty()) { if (!settings.default_path.empty()) {
if (base::DirectoryExists(default_path)) { if (base::DirectoryExists(settings.default_path)) {
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog_), gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog_),
default_path.value().c_str()); settings.default_path.value().c_str());
} else { } else {
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog_), gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog_),
default_path.DirName().value().c_str()); settings.default_path.DirName().value().c_str());
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog_), gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog_),
default_path.BaseName().value().c_str()); settings.default_path.BaseName().value().c_str());
} }
} }
if (!filters.empty()) if (!settings.filters.empty())
AddFilters(filters); AddFilters(settings.filters);
} }
~FileChooserDialog() { ~FileChooserDialog() {
@ -230,20 +226,13 @@ base::FilePath FileChooserDialog::AddExtensionForFilename(
} // namespace } // namespace
bool ShowOpenDialog(atom::NativeWindow* parent_window, bool ShowOpenDialog(const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
int properties,
const std::string& message,
std::vector<base::FilePath>* paths) { std::vector<base::FilePath>* paths) {
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN; GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
if (properties & FILE_DIALOG_OPEN_DIRECTORY) if (settings.properties & FILE_DIALOG_OPEN_DIRECTORY)
action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER; action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
FileChooserDialog open_dialog(action, parent_window, title, button_label, FileChooserDialog open_dialog(action, settings);
default_path, filters); open_dialog.SetupProperties(settings.properties);
open_dialog.SetupProperties(properties);
gtk_widget_show_all(open_dialog.dialog()); gtk_widget_show_all(open_dialog.dialog());
int response = gtk_dialog_run(GTK_DIALOG(open_dialog.dialog())); int response = gtk_dialog_run(GTK_DIALOG(open_dialog.dialog()));
@ -255,34 +244,19 @@ bool ShowOpenDialog(atom::NativeWindow* parent_window,
} }
} }
void ShowOpenDialog(atom::NativeWindow* parent_window, void ShowOpenDialog(const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
int properties,
const std::string& message,
const OpenDialogCallback& callback) { const OpenDialogCallback& callback) {
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN; GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
if (properties & FILE_DIALOG_OPEN_DIRECTORY) if (settings.properties & FILE_DIALOG_OPEN_DIRECTORY)
action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER; action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
FileChooserDialog* open_dialog = new FileChooserDialog( FileChooserDialog* open_dialog = new FileChooserDialog(action, settings);
action, parent_window, title, button_label, default_path, filters); open_dialog->SetupProperties(settings.properties);
open_dialog->SetupProperties(properties);
open_dialog->RunOpenAsynchronous(callback); open_dialog->RunOpenAsynchronous(callback);
} }
bool ShowSaveDialog(atom::NativeWindow* parent_window, bool ShowSaveDialog(const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
const std::string& message,
const std::string& name_field_label,
bool shows_tag_field,
base::FilePath* path) { base::FilePath* path) {
FileChooserDialog save_dialog(GTK_FILE_CHOOSER_ACTION_SAVE, parent_window, FileChooserDialog save_dialog(GTK_FILE_CHOOSER_ACTION_SAVE, settings);
title, button_label, default_path, filters);
gtk_widget_show_all(save_dialog.dialog()); gtk_widget_show_all(save_dialog.dialog());
int response = gtk_dialog_run(GTK_DIALOG(save_dialog.dialog())); int response = gtk_dialog_run(GTK_DIALOG(save_dialog.dialog()));
if (response == GTK_RESPONSE_ACCEPT) { if (response == GTK_RESPONSE_ACCEPT) {
@ -293,18 +267,10 @@ bool ShowSaveDialog(atom::NativeWindow* parent_window,
} }
} }
void ShowSaveDialog(atom::NativeWindow* parent_window, void ShowSaveDialog(const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
const std::string& message,
const std::string& name_field_label,
bool shows_tag_field,
const SaveDialogCallback& callback) { const SaveDialogCallback& callback) {
FileChooserDialog* save_dialog = new FileChooserDialog( FileChooserDialog* save_dialog = new FileChooserDialog(
GTK_FILE_CHOOSER_ACTION_SAVE, parent_window, title, button_label, GTK_FILE_CHOOSER_ACTION_SAVE, settings);
default_path, filters);
save_dialog->RunSaveAsynchronous(callback); save_dialog->RunSaveAsynchronous(callback);
} }

View file

@ -44,36 +44,31 @@ void SetAllowedFileTypes(NSSavePanel* dialog, const Filters& filters) {
} }
void SetupDialog(NSSavePanel* dialog, void SetupDialog(NSSavePanel* dialog,
const std::string& title, const DialogSettings& settings) {
const std::string& button_label, if (!settings.title.empty())
const base::FilePath& default_path, [dialog setTitle:base::SysUTF8ToNSString(settings.title)];
const Filters& filters,
const std::string& message,
const std::string& name_field_label,
const bool& shows_tag_field) {
if (!title.empty())
[dialog setTitle:base::SysUTF8ToNSString(title)];
if (!button_label.empty()) if (!settings.button_label.empty())
[dialog setPrompt:base::SysUTF8ToNSString(button_label)]; [dialog setPrompt:base::SysUTF8ToNSString(settings.button_label)];
if (!message.empty()) if (!settings.message.empty())
[dialog setMessage:base::SysUTF8ToNSString(message)]; [dialog setMessage:base::SysUTF8ToNSString(settings.message)];
if (!name_field_label.empty()) if (!settings.name_field_label.empty())
[dialog setNameFieldLabel:base::SysUTF8ToNSString(name_field_label)]; [dialog setNameFieldLabel:base::SysUTF8ToNSString(settings.name_field_label)];
[dialog setShowsTagField:shows_tag_field]; [dialog setShowsTagField:settings.shows_tag_field];
NSString* default_dir = nil; NSString* default_dir = nil;
NSString* default_filename = nil; NSString* default_filename = nil;
if (!default_path.empty()) { if (!settings.default_path.empty()) {
if (base::DirectoryExists(default_path)) { if (base::DirectoryExists(settings.default_path)) {
default_dir = base::SysUTF8ToNSString(default_path.value()); default_dir = base::SysUTF8ToNSString(settings.default_path.value());
} else { } else {
default_dir = base::SysUTF8ToNSString(default_path.DirName().value()); default_dir =
base::SysUTF8ToNSString(settings.default_path.DirName().value());
default_filename = default_filename =
base::SysUTF8ToNSString(default_path.BaseName().value()); base::SysUTF8ToNSString(settings.default_path.BaseName().value());
} }
} }
@ -82,10 +77,10 @@ void SetupDialog(NSSavePanel* dialog,
if (default_filename) if (default_filename)
[dialog setNameFieldStringValue:default_filename]; [dialog setNameFieldStringValue:default_filename];
if (filters.empty()) if (settings.filters.empty())
[dialog setAllowsOtherFileTypes:YES]; [dialog setAllowsOtherFileTypes:YES];
else else
SetAllowedFileTypes(dialog, filters); SetAllowedFileTypes(dialog, settings.filters);
} }
void SetupDialogForProperties(NSOpenPanel* dialog, int properties) { void SetupDialogForProperties(NSOpenPanel* dialog, int properties) {
@ -128,22 +123,15 @@ void ReadDialogPaths(NSOpenPanel* dialog, std::vector<base::FilePath>* paths) {
} // namespace } // namespace
bool ShowOpenDialog(atom::NativeWindow* parent_window, bool ShowOpenDialog(const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
int properties,
const std::string& message,
std::vector<base::FilePath>* paths) { std::vector<base::FilePath>* paths) {
DCHECK(paths); DCHECK(paths);
NSOpenPanel* dialog = [NSOpenPanel openPanel]; NSOpenPanel* dialog = [NSOpenPanel openPanel];
// NSOpenPanel does not support name_field_label and shows_tag_field SetupDialog(dialog, settings);
SetupDialog(dialog, title, button_label, default_path, filters, message, "", false); SetupDialogForProperties(dialog, settings.properties);
SetupDialogForProperties(dialog, properties);
int chosen = RunModalDialog(dialog, parent_window); int chosen = RunModalDialog(dialog, settings.parent_window);
if (chosen == NSFileHandlingPanelCancelButton) if (chosen == NSFileHandlingPanelCancelButton)
return false; return false;
@ -151,25 +139,20 @@ bool ShowOpenDialog(atom::NativeWindow* parent_window,
return true; return true;
} }
void ShowOpenDialog(atom::NativeWindow* parent_window, void ShowOpenDialog(const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
int properties,
const std::string& message,
const OpenDialogCallback& c) { const OpenDialogCallback& c) {
NSOpenPanel* dialog = [NSOpenPanel openPanel]; NSOpenPanel* dialog = [NSOpenPanel openPanel];
// NSOpenPanel does not support name_field_label and shows_tag_field SetupDialog(dialog, settings);
SetupDialog(dialog, title, button_label, default_path, filters, message, "", false); SetupDialogForProperties(dialog, settings.properties);
SetupDialogForProperties(dialog, properties);
// Duplicate the callback object here since c is a reference and gcd would // Duplicate the callback object here since c is a reference and gcd would
// only store the pointer, by duplication we can force gcd to store a copy. // only store the pointer, by duplication we can force gcd to store a copy.
__block OpenDialogCallback callback = c; __block OpenDialogCallback callback = c;
NSWindow* window = parent_window ? parent_window->GetNativeWindow() : NULL; NSWindow* window = settings.parent_window ?
settings.parent_window->GetNativeWindow() :
NULL;
[dialog beginSheetModalForWindow:window [dialog beginSheetModalForWindow:window
completionHandler:^(NSInteger chosen) { completionHandler:^(NSInteger chosen) {
if (chosen == NSFileHandlingPanelCancelButton) { if (chosen == NSFileHandlingPanelCancelButton) {
@ -182,22 +165,14 @@ void ShowOpenDialog(atom::NativeWindow* parent_window,
}]; }];
} }
bool ShowSaveDialog(atom::NativeWindow* parent_window, bool ShowSaveDialog(const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
const std::string& message,
const std::string& name_field_label,
bool shows_tag_field,
base::FilePath* path) { base::FilePath* path) {
DCHECK(path); DCHECK(path);
NSSavePanel* dialog = [NSSavePanel savePanel]; NSSavePanel* dialog = [NSSavePanel savePanel];
SetupDialog(dialog, title, button_label, default_path, filters, message, SetupDialog(dialog, settings);
name_field_label, shows_tag_field);
int chosen = RunModalDialog(dialog, parent_window); int chosen = RunModalDialog(dialog, settings.parent_window);
if (chosen == NSFileHandlingPanelCancelButton || ![[dialog URL] isFileURL]) if (chosen == NSFileHandlingPanelCancelButton || ![[dialog URL] isFileURL])
return false; return false;
@ -205,24 +180,18 @@ bool ShowSaveDialog(atom::NativeWindow* parent_window,
return true; return true;
} }
void ShowSaveDialog(atom::NativeWindow* parent_window, void ShowSaveDialog(const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
const std::string& message,
const std::string& name_field_label,
bool shows_tag_field,
const SaveDialogCallback& c) { const SaveDialogCallback& c) {
NSSavePanel* dialog = [NSSavePanel savePanel]; NSSavePanel* dialog = [NSSavePanel savePanel];
SetupDialog(dialog, title, button_label, default_path, filters, message, SetupDialog(dialog, settings);
name_field_label, shows_tag_field);
[dialog setCanSelectHiddenExtension:YES]; [dialog setCanSelectHiddenExtension:YES];
__block SaveDialogCallback callback = c; __block SaveDialogCallback callback = c;
NSWindow* window = parent_window ? parent_window->GetNativeWindow() : NULL; NSWindow* window = settings.parent_window ?
settings.parent_window->GetNativeWindow() :
NULL;
[dialog beginSheetModalForWindow:window [dialog beginSheetModalForWindow:window
completionHandler:^(NSInteger chosen) { completionHandler:^(NSInteger chosen) {
if (chosen == NSFileHandlingPanelCancelButton) { if (chosen == NSFileHandlingPanelCancelButton) {

View file

@ -66,26 +66,24 @@ void ConvertFilters(const Filters& filters,
template <typename T> template <typename T>
class FileDialog { class FileDialog {
public: public:
FileDialog(const base::FilePath& default_path, FileDialog(const DialogSettings& settings, int options) {
const std::string& title,
const std::string& button_label,
const Filters& filters, int options) {
std::wstring file_part; std::wstring file_part;
if (!IsDirectory(default_path)) if (!IsDirectory(settings.default_path))
file_part = default_path.BaseName().value(); file_part = settings.default_path.BaseName().value();
std::vector<std::wstring> buffer; std::vector<std::wstring> buffer;
std::vector<COMDLG_FILTERSPEC> filterspec; std::vector<COMDLG_FILTERSPEC> filterspec;
ConvertFilters(filters, &buffer, &filterspec); ConvertFilters(settings.filters, &buffer, &filterspec);
dialog_.reset(new T(file_part.c_str(), options, NULL, dialog_.reset(new T(file_part.c_str(), options, NULL,
filterspec.data(), filterspec.size())); filterspec.data(), filterspec.size()));
if (!title.empty()) if (!settings.title.empty())
GetPtr()->SetTitle(base::UTF8ToUTF16(title).c_str()); GetPtr()->SetTitle(base::UTF8ToUTF16(settings.title).c_str());
if (!button_label.empty()) if (!settings.button_label.empty())
GetPtr()->SetOkButtonLabel(base::UTF8ToUTF16(button_label).c_str()); GetPtr()->SetOkButtonLabel(
base::UTF8ToUTF16(settings.button_label).c_str());
// By default, *.* will be added to the file name if file type is "*.*". In // By default, *.* will be added to the file name if file type is "*.*". In
// Electron, we disable it to make a better experience. // Electron, we disable it to make a better experience.
@ -107,7 +105,7 @@ class FileDialog {
} }
} }
SetDefaultFolder(default_path); SetDefaultFolder(settings.default_path);
} }
bool Show(atom::NativeWindow* parent_window) { bool Show(atom::NativeWindow* parent_window) {
@ -160,31 +158,20 @@ bool CreateDialogThread(RunState* run_state) {
} }
void RunOpenDialogInNewThread(const RunState& run_state, void RunOpenDialogInNewThread(const RunState& run_state,
atom::NativeWindow* parent, const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
int properties,
const OpenDialogCallback& callback) { const OpenDialogCallback& callback) {
std::vector<base::FilePath> paths; std::vector<base::FilePath> paths;
bool result = ShowOpenDialog(parent, title, button_label, default_path, bool result = ShowOpenDialog(settings, &paths);
filters, properties, "", &paths);
run_state.ui_task_runner->PostTask(FROM_HERE, run_state.ui_task_runner->PostTask(FROM_HERE,
base::Bind(callback, result, paths)); base::Bind(callback, result, paths));
run_state.ui_task_runner->DeleteSoon(FROM_HERE, run_state.dialog_thread); run_state.ui_task_runner->DeleteSoon(FROM_HERE, run_state.dialog_thread);
} }
void RunSaveDialogInNewThread(const RunState& run_state, void RunSaveDialogInNewThread(const RunState& run_state,
atom::NativeWindow* parent, const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
const SaveDialogCallback& callback) { const SaveDialogCallback& callback) {
base::FilePath path; base::FilePath path;
bool result = ShowSaveDialog(parent, title, button_label, default_path, bool result = ShowSaveDialog(settings, &path);
filters, "", "", false, &path);
run_state.ui_task_runner->PostTask(FROM_HERE, run_state.ui_task_runner->PostTask(FROM_HERE,
base::Bind(callback, result, path)); base::Bind(callback, result, path));
run_state.ui_task_runner->DeleteSoon(FROM_HERE, run_state.dialog_thread); run_state.ui_task_runner->DeleteSoon(FROM_HERE, run_state.dialog_thread);
@ -192,27 +179,20 @@ void RunSaveDialogInNewThread(const RunState& run_state,
} // namespace } // namespace
bool ShowOpenDialog(atom::NativeWindow* parent_window, bool ShowOpenDialog(const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
int properties,
const std::string& message,
std::vector<base::FilePath>* paths) { std::vector<base::FilePath>* paths) {
int options = FOS_FORCEFILESYSTEM | FOS_FILEMUSTEXIST; int options = FOS_FORCEFILESYSTEM | FOS_FILEMUSTEXIST;
if (properties & FILE_DIALOG_OPEN_DIRECTORY) if (settings.properties & FILE_DIALOG_OPEN_DIRECTORY)
options |= FOS_PICKFOLDERS; options |= FOS_PICKFOLDERS;
if (properties & FILE_DIALOG_MULTI_SELECTIONS) if (settings.properties & FILE_DIALOG_MULTI_SELECTIONS)
options |= FOS_ALLOWMULTISELECT; options |= FOS_ALLOWMULTISELECT;
if (properties & FILE_DIALOG_SHOW_HIDDEN_FILES) if (settings.properties & FILE_DIALOG_SHOW_HIDDEN_FILES)
options |= FOS_FORCESHOWHIDDEN; options |= FOS_FORCESHOWHIDDEN;
if (properties & FILE_DIALOG_PROMPT_TO_CREATE) if (settings.properties & FILE_DIALOG_PROMPT_TO_CREATE)
options |= FOS_CREATEPROMPT; options |= FOS_CREATEPROMPT;
FileDialog<CShellFileOpenDialog> open_dialog( FileDialog<CShellFileOpenDialog> open_dialog(settings, options);
default_path, title, button_label, filters, options); if (!open_dialog.Show(settings.parent_window))
if (!open_dialog.Show(parent_window))
return false; return false;
ATL::CComPtr<IShellItemArray> items; ATL::CComPtr<IShellItemArray> items;
@ -245,13 +225,7 @@ bool ShowOpenDialog(atom::NativeWindow* parent_window,
return true; return true;
} }
void ShowOpenDialog(atom::NativeWindow* parent, void ShowOpenDialog(const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
int properties,
const std::string& message,
const OpenDialogCallback& callback) { const OpenDialogCallback& callback) {
RunState run_state; RunState run_state;
if (!CreateDialogThread(&run_state)) { if (!CreateDialogThread(&run_state)) {
@ -261,23 +235,14 @@ void ShowOpenDialog(atom::NativeWindow* parent,
run_state.dialog_thread->task_runner()->PostTask( run_state.dialog_thread->task_runner()->PostTask(
FROM_HERE, FROM_HERE,
base::Bind(&RunOpenDialogInNewThread, run_state, parent, title, base::Bind(&RunOpenDialogInNewThread, run_state, settings, callback));
button_label, default_path, filters, properties, callback));
} }
bool ShowSaveDialog(atom::NativeWindow* parent_window, bool ShowSaveDialog(const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
const std::string& message,
const std::string& name_field_label,
bool shows_tag_field,
base::FilePath* path) { base::FilePath* path) {
FileDialog<CShellFileSaveDialog> save_dialog( FileDialog<CShellFileSaveDialog> save_dialog(
default_path, title, button_label, filters, settings, FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_OVERWRITEPROMPT);
FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_OVERWRITEPROMPT); if (!save_dialog.Show(settings.parent_window))
if (!save_dialog.Show(parent_window))
return false; return false;
wchar_t buffer[MAX_PATH]; wchar_t buffer[MAX_PATH];
@ -289,14 +254,7 @@ bool ShowSaveDialog(atom::NativeWindow* parent_window,
return true; return true;
} }
void ShowSaveDialog(atom::NativeWindow* parent, void ShowSaveDialog(const DialogSettings& settings,
const std::string& title,
const std::string& button_label,
const base::FilePath& default_path,
const Filters& filters,
const std::string& message,
const std::string& name_field_label,
bool shows_tag_field,
const SaveDialogCallback& callback) { const SaveDialogCallback& callback) {
RunState run_state; RunState run_state;
if (!CreateDialogThread(&run_state)) { if (!CreateDialogThread(&run_state)) {
@ -306,8 +264,7 @@ void ShowSaveDialog(atom::NativeWindow* parent,
run_state.dialog_thread->task_runner()->PostTask( run_state.dialog_thread->task_runner()->PostTask(
FROM_HERE, FROM_HERE,
base::Bind(&RunSaveDialogInNewThread, run_state, parent, title, base::Bind(&RunSaveDialogInNewThread, run_state, settings, callback));
button_label, default_path, filters, callback));
} }
} // namespace file_dialog } // namespace file_dialog

View file

@ -32,7 +32,8 @@ enum MessageBoxOptions {
MESSAGE_BOX_NO_LINK = 1 << 0, MESSAGE_BOX_NO_LINK = 1 << 0,
}; };
typedef base::Callback<void(int code)> MessageBoxCallback; typedef base::Callback<void(int code, bool checkbox_checked)>
MessageBoxCallback;
int ShowMessageBox(NativeWindow* parent_window, int ShowMessageBox(NativeWindow* parent_window,
MessageBoxType type, MessageBoxType type,
@ -54,6 +55,8 @@ void ShowMessageBox(NativeWindow* parent_window,
const std::string& title, const std::string& title,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,
const std::string& checkbox_label,
bool checkbox_checked,
const gfx::ImageSkia& icon, const gfx::ImageSkia& icon,
const MessageBoxCallback& callback); const MessageBoxCallback& callback);

View file

@ -36,8 +36,11 @@ class GtkMessageBox : public NativeWindowObserver {
const std::string& title, const std::string& title,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,
const std::string& checkbox_label,
bool checkbox_checked,
const gfx::ImageSkia& icon) const gfx::ImageSkia& icon)
: cancel_id_(cancel_id), : cancel_id_(cancel_id),
checkbox_checked_(false),
parent_(static_cast<NativeWindowViews*>(parent_window)) { parent_(static_cast<NativeWindowViews*>(parent_window)) {
// Create dialog. // Create dialog.
dialog_ = gtk_message_dialog_new( dialog_ = gtk_message_dialog_new(
@ -68,6 +71,18 @@ class GtkMessageBox : public NativeWindowObserver {
g_object_unref(pixbuf); g_object_unref(pixbuf);
} }
if (!checkbox_label.empty()) {
GtkWidget* message_area =
gtk_message_dialog_get_message_area(GTK_MESSAGE_DIALOG(dialog_));
GtkWidget* check_button =
gtk_check_button_new_with_label(checkbox_label.c_str());
g_signal_connect(check_button, "toggled",
G_CALLBACK(OnCheckboxToggledThunk), this);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button),
checkbox_checked);
gtk_container_add(GTK_CONTAINER(message_area), check_button);
}
// Add buttons. // Add buttons.
for (size_t i = 0; i < buttons.size(); ++i) { for (size_t i = 0; i < buttons.size(); ++i) {
GtkWidget* button = gtk_dialog_add_button( GtkWidget* button = gtk_dialog_add_button(
@ -154,6 +169,7 @@ class GtkMessageBox : public NativeWindowObserver {
} }
CHROMEGTK_CALLBACK_1(GtkMessageBox, void, OnResponseDialog, int); CHROMEGTK_CALLBACK_1(GtkMessageBox, void, OnResponseDialog, int);
CHROMEGTK_CALLBACK_0(GtkMessageBox, void, OnCheckboxToggled);
private: private:
atom::UnresponsiveSuppressor unresponsive_suppressor_; atom::UnresponsiveSuppressor unresponsive_suppressor_;
@ -161,6 +177,8 @@ class GtkMessageBox : public NativeWindowObserver {
// The id to return when the dialog is closed without pressing buttons. // The id to return when the dialog is closed without pressing buttons.
int cancel_id_; int cancel_id_;
bool checkbox_checked_;
NativeWindowViews* parent_; NativeWindowViews* parent_;
GtkWidget* dialog_; GtkWidget* dialog_;
MessageBoxCallback callback_; MessageBoxCallback callback_;
@ -172,12 +190,16 @@ void GtkMessageBox::OnResponseDialog(GtkWidget* widget, int response) {
gtk_widget_hide(dialog_); gtk_widget_hide(dialog_);
if (response < 0) if (response < 0)
callback_.Run(cancel_id_); callback_.Run(cancel_id_, checkbox_checked_);
else else
callback_.Run(response); callback_.Run(response, checkbox_checked_);
delete this; delete this;
} }
void GtkMessageBox::OnCheckboxToggled(GtkWidget* widget) {
checkbox_checked_ = GTK_TOGGLE_BUTTON(widget)->active;
}
} // namespace } // namespace
int ShowMessageBox(NativeWindow* parent, int ShowMessageBox(NativeWindow* parent,
@ -190,8 +212,9 @@ int ShowMessageBox(NativeWindow* parent,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,
const gfx::ImageSkia& icon) { const gfx::ImageSkia& icon) {
return GtkMessageBox(parent, type, buttons, default_id, cancel_id, return GtkMessageBox(parent, type, buttons, default_id, cancel_id, title,
title, message, detail, icon).RunSynchronous(); message, detail, "", false, icon)
.RunSynchronous();
} }
void ShowMessageBox(NativeWindow* parent, void ShowMessageBox(NativeWindow* parent,
@ -203,18 +226,22 @@ void ShowMessageBox(NativeWindow* parent,
const std::string& title, const std::string& title,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,
const std::string& checkbox_label,
bool checkbox_checked,
const gfx::ImageSkia& icon, const gfx::ImageSkia& icon,
const MessageBoxCallback& callback) { const MessageBoxCallback& callback) {
(new GtkMessageBox(parent, type, buttons, default_id, cancel_id, (new GtkMessageBox(parent, type, buttons, default_id, cancel_id, title,
title, message, detail, icon))->RunAsynchronous(callback); message, detail, checkbox_label, checkbox_checked, icon))
->RunAsynchronous(callback);
} }
void ShowErrorBox(const base::string16& title, const base::string16& content) { void ShowErrorBox(const base::string16& title, const base::string16& content) {
if (Browser::Get()->is_ready()) { if (Browser::Get()->is_ready()) {
GtkMessageBox(nullptr, MESSAGE_BOX_TYPE_ERROR, {"OK"}, -1, 0, "Error", GtkMessageBox(nullptr, MESSAGE_BOX_TYPE_ERROR, {"OK"}, -1, 0, "Error",
base::UTF16ToUTF8(title).c_str(), base::UTF16ToUTF8(title).c_str(),
base::UTF16ToUTF8(content).c_str(), base::UTF16ToUTF8(content).c_str(), "", false,
gfx::ImageSkia()).RunSynchronous(); gfx::ImageSkia())
.RunSynchronous();
} else { } else {
fprintf(stderr, fprintf(stderr,
ANSI_TEXT_BOLD ANSI_BACKGROUND_GRAY ANSI_TEXT_BOLD ANSI_BACKGROUND_GRAY

View file

@ -39,7 +39,7 @@
- (void)alertDidEnd:(NSAlert*)alert - (void)alertDidEnd:(NSAlert*)alert
returnCode:(NSInteger)returnCode returnCode:(NSInteger)returnCode
contextInfo:(void*)contextInfo { contextInfo:(void*)contextInfo {
callback_.Run(returnCode); callback_.Run(returnCode, alert.suppressionButton.state == NSOnState);
[alert_ release]; [alert_ release];
[self release]; [self release];
@ -60,6 +60,8 @@ NSAlert* CreateNSAlert(NativeWindow* parent_window,
const std::string& title, const std::string& title,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,
const std::string& checkbox_label,
bool checkbox_checked,
const gfx::ImageSkia& icon) { const gfx::ImageSkia& icon) {
// Ignore the title; it's the window title on other platforms and ignorable. // Ignore the title; it's the window title on other platforms and ignorable.
NSAlert* alert = [[NSAlert alloc] init]; NSAlert* alert = [[NSAlert alloc] init];
@ -95,6 +97,12 @@ NSAlert* CreateNSAlert(NativeWindow* parent_window,
[[ns_buttons objectAtIndex:default_id] setKeyEquivalent:@"\r"]; [[ns_buttons objectAtIndex:default_id] setKeyEquivalent:@"\r"];
} }
if (!checkbox_label.empty()) {
alert.showsSuppressionButton = YES;
alert.suppressionButton.title = base::SysUTF8ToNSString(checkbox_label);
alert.suppressionButton.state = checkbox_checked ? NSOnState : NSOffState;
}
if (!icon.isNull()) { if (!icon.isNull()) {
NSImage* image = skia::SkBitmapToNSImageWithColorSpace( NSImage* image = skia::SkBitmapToNSImageWithColorSpace(
*icon.bitmap(), base::mac::GetGenericRGBColorSpace()); *icon.bitmap(), base::mac::GetGenericRGBColorSpace());
@ -104,7 +112,7 @@ NSAlert* CreateNSAlert(NativeWindow* parent_window,
return alert; return alert;
} }
void SetReturnCode(int* ret_code, int result) { void SetReturnCode(int* ret_code, int result, bool checkbox_checked) {
*ret_code = result; *ret_code = result;
} }
@ -120,9 +128,8 @@ int ShowMessageBox(NativeWindow* parent_window,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,
const gfx::ImageSkia& icon) { const gfx::ImageSkia& icon) {
NSAlert* alert = CreateNSAlert( NSAlert* alert = CreateNSAlert(parent_window, type, buttons, default_id,
parent_window, type, buttons, default_id, title, message, title, message, detail, "", false, icon);
detail, icon);
// Use runModal for synchronous alert without parent, since we don't have a // Use runModal for synchronous alert without parent, since we don't have a
// window to wait for. // window to wait for.
@ -154,11 +161,13 @@ void ShowMessageBox(NativeWindow* parent_window,
const std::string& title, const std::string& title,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,
const std::string& checkbox_label,
bool checkbox_checked,
const gfx::ImageSkia& icon, const gfx::ImageSkia& icon,
const MessageBoxCallback& callback) { const MessageBoxCallback& callback) {
NSAlert* alert = CreateNSAlert( NSAlert* alert =
parent_window, type, buttons, default_id, title, message, CreateNSAlert(parent_window, type, buttons, default_id, title, message,
detail, icon); detail, checkbox_label, checkbox_checked, icon);
ModalDelegate* delegate = [[ModalDelegate alloc] initWithCallback:callback ModalDelegate* delegate = [[ModalDelegate alloc] initWithCallback:callback
andAlert:alert andAlert:alert
callEndModal:false]; callEndModal:false];

View file

@ -72,7 +72,7 @@ void MapToCommonID(const std::vector<base::string16>& buttons,
} }
} }
int ShowMessageBoxUTF16(HWND parent, int ShowTaskDialogUTF16(NativeWindow* parent,
MessageBoxType type, MessageBoxType type,
const std::vector<base::string16>& buttons, const std::vector<base::string16>& buttons,
int default_id, int default_id,
@ -81,6 +81,8 @@ int ShowMessageBoxUTF16(HWND parent,
const base::string16& title, const base::string16& title,
const base::string16& message, const base::string16& message,
const base::string16& detail, const base::string16& detail,
const base::string16& checkbox_label,
bool* checkbox_checked,
const gfx::ImageSkia& icon) { const gfx::ImageSkia& icon) {
TASKDIALOG_FLAGS flags = TASKDIALOG_FLAGS flags =
TDF_SIZE_TO_CONTENT | // Show all content. TDF_SIZE_TO_CONTENT | // Show all content.
@ -88,10 +90,14 @@ int ShowMessageBoxUTF16(HWND parent,
TASKDIALOGCONFIG config = { 0 }; TASKDIALOGCONFIG config = { 0 };
config.cbSize = sizeof(config); config.cbSize = sizeof(config);
config.hwndParent = parent;
config.hInstance = GetModuleHandle(NULL); config.hInstance = GetModuleHandle(NULL);
config.dwFlags = flags; config.dwFlags = flags;
if (parent) {
config.hwndParent =
static_cast<atom::NativeWindowViews*>(parent)->GetAcceleratedWidget();
}
if (default_id > 0) if (default_id > 0)
config.nDefaultButton = kIDStart + default_id; config.nDefaultButton = kIDStart + default_id;
@ -132,6 +138,14 @@ int ShowMessageBoxUTF16(HWND parent,
config.pszContent = detail.c_str(); config.pszContent = detail.c_str();
} }
if (!checkbox_label.empty()) {
config.pszVerificationText = checkbox_label.c_str();
if (checkbox_checked && *checkbox_checked) {
config.dwFlags |= TDF_VERIFICATION_FLAG_CHECKED;
}
}
// Iterate through the buttons, put common buttons in dwCommonButtons // Iterate through the buttons, put common buttons in dwCommonButtons
// and custom buttons in pButtons. // and custom buttons in pButtons.
std::map<int, int> id_map; std::map<int, int> id_map;
@ -151,7 +165,12 @@ int ShowMessageBoxUTF16(HWND parent,
} }
int id = 0; int id = 0;
TaskDialogIndirect(&config, &id, NULL, NULL); BOOL verificationFlagChecked = FALSE;
TaskDialogIndirect(&config, &id, nullptr, &verificationFlagChecked);
if (checkbox_checked) {
*checkbox_checked = verificationFlagChecked;
}
if (id_map.find(id) != id_map.end()) // common button. if (id_map.find(id) != id_map.end()) // common button.
return id_map[id]; return id_map[id];
else if (id >= kIDStart) // custom button. else if (id >= kIDStart) // custom button.
@ -160,6 +179,29 @@ int ShowMessageBoxUTF16(HWND parent,
return cancel_id; return cancel_id;
} }
int ShowTaskDialogUTF8(NativeWindow* parent,
MessageBoxType type,
const std::vector<std::string>& buttons,
int default_id,
int cancel_id,
int options,
const std::string& title,
const std::string& message,
const std::string& detail,
const std::string& checkbox_label,
bool* checkbox_checked,
const gfx::ImageSkia& icon) {
std::vector<base::string16> utf16_buttons;
for (const auto& button : buttons)
utf16_buttons.push_back(base::UTF8ToUTF16(button));
return ShowTaskDialogUTF16(
parent, type, utf16_buttons, default_id, cancel_id, options,
base::UTF8ToUTF16(title), base::UTF8ToUTF16(message),
base::UTF8ToUTF16(detail), base::UTF8ToUTF16(checkbox_label),
checkbox_checked, icon);
}
void RunMessageBoxInNewThread(base::Thread* thread, void RunMessageBoxInNewThread(base::Thread* thread,
NativeWindow* parent, NativeWindow* parent,
MessageBoxType type, MessageBoxType type,
@ -170,12 +212,16 @@ void RunMessageBoxInNewThread(base::Thread* thread,
const std::string& title, const std::string& title,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,
const std::string& checkbox_label,
bool checkbox_checked,
const gfx::ImageSkia& icon, const gfx::ImageSkia& icon,
const MessageBoxCallback& callback) { const MessageBoxCallback& callback) {
int result = ShowMessageBox(parent, type, buttons, default_id, int result = ShowTaskDialogUTF8(parent, type, buttons, default_id, cancel_id,
cancel_id, options, title, message, detail, icon); options, title, message, detail,
checkbox_label, &checkbox_checked, icon);
content::BrowserThread::PostTask( content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE, base::Bind(callback, result)); content::BrowserThread::UI, FROM_HERE,
base::Bind(callback, result, checkbox_checked));
content::BrowserThread::DeleteSoon( content::BrowserThread::DeleteSoon(
content::BrowserThread::UI, FROM_HERE, thread); content::BrowserThread::UI, FROM_HERE, thread);
} }
@ -192,25 +238,9 @@ int ShowMessageBox(NativeWindow* parent,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,
const gfx::ImageSkia& icon) { const gfx::ImageSkia& icon) {
std::vector<base::string16> utf16_buttons;
for (const auto& button : buttons)
utf16_buttons.push_back(base::UTF8ToUTF16(button));
HWND hwnd_parent = parent ?
static_cast<atom::NativeWindowViews*>(parent)->GetAcceleratedWidget() :
NULL;
atom::UnresponsiveSuppressor suppressor; atom::UnresponsiveSuppressor suppressor;
return ShowMessageBoxUTF16(hwnd_parent, return ShowTaskDialogUTF8(parent, type, buttons, default_id, cancel_id,
type, options, title, message, detail, "", nullptr, icon);
utf16_buttons,
default_id,
cancel_id,
options,
base::UTF8ToUTF16(title),
base::UTF8ToUTF16(message),
base::UTF8ToUTF16(detail),
icon);
} }
void ShowMessageBox(NativeWindow* parent, void ShowMessageBox(NativeWindow* parent,
@ -222,13 +252,15 @@ void ShowMessageBox(NativeWindow* parent,
const std::string& title, const std::string& title,
const std::string& message, const std::string& message,
const std::string& detail, const std::string& detail,
const std::string& checkbox_label,
bool checkbox_checked,
const gfx::ImageSkia& icon, const gfx::ImageSkia& icon,
const MessageBoxCallback& callback) { const MessageBoxCallback& callback) {
std::unique_ptr<base::Thread> thread( std::unique_ptr<base::Thread> thread(
new base::Thread(ATOM_PRODUCT_NAME "MessageBoxThread")); new base::Thread(ATOM_PRODUCT_NAME "MessageBoxThread"));
thread->init_com_with_mta(false); thread->init_com_with_mta(false);
if (!thread->Start()) { if (!thread->Start()) {
callback.Run(cancel_id); callback.Run(cancel_id, checkbox_checked);
return; return;
} }
@ -237,13 +269,14 @@ void ShowMessageBox(NativeWindow* parent,
FROM_HERE, FROM_HERE,
base::Bind(&RunMessageBoxInNewThread, base::Unretained(unretained), base::Bind(&RunMessageBoxInNewThread, base::Unretained(unretained),
parent, type, buttons, default_id, cancel_id, options, title, parent, type, buttons, default_id, cancel_id, options, title,
message, detail, icon, callback)); message, detail, checkbox_label, checkbox_checked, icon,
callback));
} }
void ShowErrorBox(const base::string16& title, const base::string16& content) { void ShowErrorBox(const base::string16& title, const base::string16& content) {
atom::UnresponsiveSuppressor suppressor; atom::UnresponsiveSuppressor suppressor;
ShowMessageBoxUTF16(NULL, MESSAGE_BOX_TYPE_ERROR, {}, -1, 0, 0, L"Error", ShowTaskDialogUTF16(nullptr, MESSAGE_BOX_TYPE_ERROR, {}, -1, 0, 0, L"Error",
title, content, gfx::ImageSkia()); title, content, L"", nullptr, gfx::ImageSkia());
} }
} // namespace atom } // namespace atom

View file

@ -81,19 +81,16 @@ void WebDialogHelper::RunFileChooser(
content::RenderFrameHost* render_frame_host, content::RenderFrameHost* render_frame_host,
const content::FileChooserParams& params) { const content::FileChooserParams& params) {
std::vector<content::FileChooserFileInfo> result; std::vector<content::FileChooserFileInfo> result;
file_dialog::Filters filters = GetFileTypesFromAcceptType(
params.accept_types); file_dialog::DialogSettings settings;
settings.filters = GetFileTypesFromAcceptType(params.accept_types);
settings.parent_window = window_;
settings.title = base::UTF16ToUTF8(params.title);
if (params.mode == content::FileChooserParams::Save) { if (params.mode == content::FileChooserParams::Save) {
base::FilePath path; base::FilePath path;
if (file_dialog::ShowSaveDialog(window_, settings.default_path = params.default_file_name;
base::UTF16ToUTF8(params.title), if (file_dialog::ShowSaveDialog(settings, &path)) {
"",
params.default_file_name,
filters,
"",
"",
false,
&path)) {
content::FileChooserFileInfo info; content::FileChooserFileInfo info;
info.file_path = path; info.file_path = path;
info.display_name = path.BaseName().value(); info.display_name = path.BaseName().value();
@ -117,16 +114,10 @@ void WebDialogHelper::RunFileChooser(
std::vector<base::FilePath> paths; std::vector<base::FilePath> paths;
AtomBrowserContext* browser_context = static_cast<AtomBrowserContext*>( AtomBrowserContext* browser_context = static_cast<AtomBrowserContext*>(
window_->web_contents()->GetBrowserContext()); window_->web_contents()->GetBrowserContext());
base::FilePath default_file_path = browser_context->prefs()->GetFilePath( settings.default_path = browser_context->prefs()->GetFilePath(
prefs::kSelectFileLastDirectory).Append(params.default_file_name); prefs::kSelectFileLastDirectory).Append(params.default_file_name);
if (file_dialog::ShowOpenDialog(window_, settings.properties = flags;
base::UTF16ToUTF8(params.title), if (file_dialog::ShowOpenDialog(settings, &paths)) {
"",
default_file_path,
filters,
flags,
"",
&paths)) {
for (auto& path : paths) { for (auto& path : paths) {
content::FileChooserFileInfo info; content::FileChooserFileInfo info;
info.file_path = path; info.file_path = path;

View file

@ -127,6 +127,11 @@ will be passed via `callback(filename)`
* `title` String (optional) - Title of the message box, some platforms will not show it. * `title` String (optional) - Title of the message box, some platforms will not show it.
* `message` String - Content of the message box. * `message` String - Content of the message box.
* `detail` String (optional) - Extra information of the message. * `detail` String (optional) - Extra information of the message.
* `checkboxLabel` String (optional) - If provided, the message box will
include a checkbox with the given label. The checkbox state can be
inspected only when using `callback`.
* `checkboxChecked` Boolean (optional) - Initial checked state of the
checkbox. `false` by default.
* `icon` [NativeImage](native-image.md) (optional) * `icon` [NativeImage](native-image.md) (optional)
* `cancelId` Integer (optional) - The value will be returned when user cancels the dialog * `cancelId` Integer (optional) - The value will be returned when user cancels the dialog
instead of clicking the buttons of the dialog. By default it is the index instead of clicking the buttons of the dialog. By default it is the index
@ -140,6 +145,8 @@ will be passed via `callback(filename)`
set `noLink` to `true`. set `noLink` to `true`.
* `callback` Function (optional) * `callback` Function (optional)
* `response` Number - The index of the button that was clicked * `response` Number - The index of the button that was clicked
* `checkboxChecked` Boolean - The checked state of the checkbox if
`checkboxLabel` was set. Otherwise `false`.
Returns `Integer`, the index of the clicked button, if a callback is provided Returns `Integer`, the index of the clicked button, if a callback is provided
it returns undefined. it returns undefined.

View file

@ -127,9 +127,9 @@ module.exports = {
const wrappedCallback = typeof callback === 'function' ? function (success, result) { const wrappedCallback = typeof callback === 'function' ? function (success, result) {
return callback(success ? result : void 0) return callback(success ? result : void 0)
} : null } : null
return binding.showOpenDialog(title, buttonLabel, defaultPath, filters, const settings = {title, buttonLabel, defaultPath, filters, message, window}
dialogProperties, message, window, settings.properties = dialogProperties
wrappedCallback) return binding.showOpenDialog(settings, wrappedCallback)
}, },
showSaveDialog: function (...args) { showSaveDialog: function (...args) {
@ -187,9 +187,8 @@ module.exports = {
const wrappedCallback = typeof callback === 'function' ? function (success, result) { const wrappedCallback = typeof callback === 'function' ? function (success, result) {
return callback(success ? result : void 0) return callback(success ? result : void 0)
} : null } : null
return binding.showSaveDialog(title, buttonLabel, defaultPath, filters, const settings = {title, buttonLabel, defaultPath, filters, message, nameFieldLabel, showsTagField, window}
message, nameFieldLabel, showsTagField, return binding.showSaveDialog(settings, wrappedCallback)
window, wrappedCallback)
}, },
showMessageBox: function (...args) { showMessageBox: function (...args) {
@ -203,7 +202,10 @@ module.exports = {
} }
} }
let {buttons, cancelId, defaultId, detail, icon, message, title, type} = options let {
buttons, cancelId, checkboxLabel, checkboxChecked, defaultId, detail,
icon, message, title, type
} = options
if (type == null) { if (type == null) {
type = 'none' type = 'none'
@ -242,6 +244,14 @@ module.exports = {
throw new TypeError('Detail must be a string') throw new TypeError('Detail must be a string')
} }
checkboxChecked = !!checkboxChecked
if (checkboxLabel == null) {
checkboxLabel = ''
} else if (typeof checkboxLabel !== 'string') {
throw new TypeError('checkboxLabel must be a string')
}
if (icon == null) { if (icon == null) {
icon = null icon = null
} }
@ -264,8 +274,8 @@ module.exports = {
const flags = options.noLink ? messageBoxOptions.noLink : 0 const flags = options.noLink ? messageBoxOptions.noLink : 0
return binding.showMessageBox(messageBoxType, buttons, defaultId, cancelId, return binding.showMessageBox(messageBoxType, buttons, defaultId, cancelId,
flags, title, message, detail, icon, window, flags, title, message, detail, checkboxLabel,
callback) checkboxChecked, icon, window, callback)
}, },
showErrorBox: function (...args) { showErrorBox: function (...args) {

View file

@ -71,6 +71,10 @@ describe('dialog module', () => {
assert.throws(() => { assert.throws(() => {
dialog.showMessageBox({detail: 3.14}) dialog.showMessageBox({detail: 3.14})
}, /Detail must be a string/) }, /Detail must be a string/)
assert.throws(() => {
dialog.showMessageBox({checkboxLabel: false})
}, /checkboxLabel must be a string/)
}) })
}) })