refactor: pass MessageBox params as a struct (#18732)
Historically, we've been passing in all MessageBox parameters individually, which makes augmenting or improving MessageBox functionality challenging because to change or add even one argument requires a huge cascade of argument changes that leaves room for errors. For other file dialog related APIs, we use a struct (DialogSettings), and so this PR takes a similar approach and refactors MessageBox parameters into a struct (MessageBoxSettings) which we then use to simplify argument passing and which will enable us to more quickly iterate and improve upon functionality in the future.
This commit is contained in:
parent
ffb53405fb
commit
bfcce8aa27
11 changed files with 207 additions and 247 deletions
|
@ -15,6 +15,7 @@
|
||||||
#include "atom/common/native_mate_converters/file_dialog_converter.h"
|
#include "atom/common/native_mate_converters/file_dialog_converter.h"
|
||||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||||
#include "atom/common/native_mate_converters/image_converter.h"
|
#include "atom/common/native_mate_converters/image_converter.h"
|
||||||
|
#include "atom/common/native_mate_converters/message_box_converter.h"
|
||||||
#include "atom/common/native_mate_converters/net_converter.h"
|
#include "atom/common/native_mate_converters/net_converter.h"
|
||||||
#include "atom/common/node_includes.h"
|
#include "atom/common/node_includes.h"
|
||||||
#include "atom/common/promise_util.h"
|
#include "atom/common/promise_util.h"
|
||||||
|
@ -22,21 +23,8 @@
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
int ShowMessageBoxSync(int type,
|
int ShowMessageBoxSync(const atom::MessageBoxSettings& settings) {
|
||||||
const std::vector<std::string>& buttons,
|
return atom::ShowMessageBoxSync(settings);
|
||||||
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,
|
|
||||||
atom::NativeWindow* window) {
|
|
||||||
return atom::ShowMessageBoxSync(
|
|
||||||
window, static_cast<atom::MessageBoxType>(type), buttons, default_id,
|
|
||||||
cancel_id, options, title, message, detail, icon);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResolvePromiseObject(atom::util::Promise promise,
|
void ResolvePromiseObject(atom::util::Promise promise,
|
||||||
|
@ -50,28 +38,14 @@ void ResolvePromiseObject(atom::util::Promise promise,
|
||||||
promise.Resolve(dict.GetHandle());
|
promise.Resolve(dict.GetHandle());
|
||||||
}
|
}
|
||||||
|
|
||||||
v8::Local<v8::Promise> ShowMessageBox(int type,
|
v8::Local<v8::Promise> ShowMessageBox(const atom::MessageBoxSettings& settings,
|
||||||
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,
|
|
||||||
atom::NativeWindow* window,
|
|
||||||
mate::Arguments* args) {
|
mate::Arguments* args) {
|
||||||
v8::Isolate* isolate = args->isolate();
|
v8::Isolate* isolate = args->isolate();
|
||||||
atom::util::Promise promise(isolate);
|
atom::util::Promise promise(isolate);
|
||||||
v8::Local<v8::Promise> handle = promise.GetHandle();
|
v8::Local<v8::Promise> handle = promise.GetHandle();
|
||||||
|
|
||||||
atom::ShowMessageBox(
|
atom::ShowMessageBox(
|
||||||
window, static_cast<atom::MessageBoxType>(type), buttons, default_id,
|
settings, base::BindOnce(&ResolvePromiseObject, std::move(promise)));
|
||||||
cancel_id, options, title, message, detail, checkbox_label,
|
|
||||||
checkbox_checked, icon,
|
|
||||||
base::BindOnce(&ResolvePromiseObject, std::move(promise)));
|
|
||||||
|
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,10 +91,15 @@ void AtomJavaScriptDialogManager::RunJavaScriptDialog(
|
||||||
window = relay->GetNativeWindow();
|
window = relay->GetNativeWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
atom::MessageBoxSettings settings;
|
||||||
|
settings.parent_window = window;
|
||||||
|
settings.buttons = buttons;
|
||||||
|
settings.default_id = default_id;
|
||||||
|
settings.cancel_id = cancel_id;
|
||||||
|
settings.message = base::UTF16ToUTF8(message_text);
|
||||||
|
|
||||||
atom::ShowMessageBox(
|
atom::ShowMessageBox(
|
||||||
window, atom::MessageBoxType::kNone, buttons, default_id, cancel_id,
|
settings,
|
||||||
atom::MessageBoxOptions::MESSAGE_BOX_NONE, "",
|
|
||||||
base::UTF16ToUTF8(message_text), "", checkbox, false, gfx::ImageSkia(),
|
|
||||||
base::BindOnce(&AtomJavaScriptDialogManager::OnMessageBoxCallback,
|
base::BindOnce(&AtomJavaScriptDialogManager::OnMessageBoxCallback,
|
||||||
base::Unretained(this), base::Passed(std::move(callback)),
|
base::Unretained(this), base::Passed(std::move(callback)),
|
||||||
origin));
|
origin));
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
|
|
||||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||||
#include "atom/common/promise_util.h"
|
#include "atom/common/promise_util.h"
|
||||||
#include "base/callback_forward.h"
|
|
||||||
#include "base/files/file_path.h"
|
#include "base/files/file_path.h"
|
||||||
#include "native_mate/dictionary.h"
|
#include "native_mate/dictionary.h"
|
||||||
|
|
||||||
|
|
|
@ -10,10 +10,7 @@
|
||||||
|
|
||||||
#include "base/callback_forward.h"
|
#include "base/callback_forward.h"
|
||||||
#include "base/strings/string16.h"
|
#include "base/strings/string16.h"
|
||||||
|
#include "ui/gfx/image/image_skia.h"
|
||||||
namespace gfx {
|
|
||||||
class ImageSkia;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace atom {
|
namespace atom {
|
||||||
|
|
||||||
|
@ -32,32 +29,31 @@ enum MessageBoxOptions {
|
||||||
MESSAGE_BOX_NO_LINK = 1 << 0,
|
MESSAGE_BOX_NO_LINK = 1 << 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
int ShowMessageBoxSync(NativeWindow* parent_window,
|
struct MessageBoxSettings {
|
||||||
MessageBoxType type,
|
atom::NativeWindow* parent_window = nullptr;
|
||||||
const std::vector<std::string>& buttons,
|
MessageBoxType type = atom::MessageBoxType::kNone;
|
||||||
int default_id,
|
std::vector<std::string> buttons;
|
||||||
int cancel_id,
|
int default_id;
|
||||||
int options,
|
int cancel_id;
|
||||||
const std::string& title,
|
int options = atom::MessageBoxOptions::MESSAGE_BOX_NONE;
|
||||||
const std::string& message,
|
std::string title;
|
||||||
const std::string& detail,
|
std::string message;
|
||||||
const gfx::ImageSkia& icon);
|
std::string detail;
|
||||||
|
std::string checkbox_label;
|
||||||
|
bool checkbox_checked = false;
|
||||||
|
gfx::ImageSkia icon;
|
||||||
|
|
||||||
|
MessageBoxSettings();
|
||||||
|
MessageBoxSettings(const MessageBoxSettings&);
|
||||||
|
~MessageBoxSettings();
|
||||||
|
};
|
||||||
|
|
||||||
|
int ShowMessageBoxSync(const MessageBoxSettings& settings);
|
||||||
|
|
||||||
typedef base::OnceCallback<void(int code, bool checkbox_checked)>
|
typedef base::OnceCallback<void(int code, bool checkbox_checked)>
|
||||||
MessageBoxCallback;
|
MessageBoxCallback;
|
||||||
|
|
||||||
void ShowMessageBox(NativeWindow* parent_window,
|
void ShowMessageBox(const MessageBoxSettings& settings,
|
||||||
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,
|
|
||||||
MessageBoxCallback callback);
|
MessageBoxCallback callback);
|
||||||
|
|
||||||
// Like ShowMessageBox with simplest settings, but safe to call at very early
|
// Like ShowMessageBox with simplest settings, but safe to call at very early
|
||||||
|
|
|
@ -27,42 +27,37 @@
|
||||||
|
|
||||||
namespace atom {
|
namespace atom {
|
||||||
|
|
||||||
|
MessageBoxSettings::MessageBoxSettings() = default;
|
||||||
|
MessageBoxSettings::MessageBoxSettings(const MessageBoxSettings&) = default;
|
||||||
|
MessageBoxSettings::~MessageBoxSettings() = default;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
class GtkMessageBox : public NativeWindowObserver {
|
class GtkMessageBox : public NativeWindowObserver {
|
||||||
public:
|
public:
|
||||||
GtkMessageBox(NativeWindow* parent_window,
|
explicit GtkMessageBox(const MessageBoxSettings& settings)
|
||||||
MessageBoxType type,
|
: cancel_id_(settings.cancel_id),
|
||||||
const std::vector<std::string>& buttons,
|
parent_(static_cast<NativeWindow*>(settings.parent_window)) {
|
||||||
int default_id,
|
|
||||||
int cancel_id,
|
|
||||||
const std::string& title,
|
|
||||||
const std::string& message,
|
|
||||||
const std::string& detail,
|
|
||||||
const std::string& checkbox_label,
|
|
||||||
bool checkbox_checked,
|
|
||||||
const gfx::ImageSkia& icon)
|
|
||||||
: cancel_id_(cancel_id),
|
|
||||||
parent_(static_cast<NativeWindow*>(parent_window)) {
|
|
||||||
// Create dialog.
|
// Create dialog.
|
||||||
dialog_ =
|
dialog_ =
|
||||||
gtk_message_dialog_new(nullptr, // parent
|
gtk_message_dialog_new(nullptr, // parent
|
||||||
static_cast<GtkDialogFlags>(0), // no flags
|
static_cast<GtkDialogFlags>(0), // no flags
|
||||||
GetMessageType(type), // type
|
GetMessageType(settings.type), // type
|
||||||
GTK_BUTTONS_NONE, // no buttons
|
GTK_BUTTONS_NONE, // no buttons
|
||||||
"%s", message.c_str());
|
"%s", settings.message.c_str());
|
||||||
if (!detail.empty())
|
if (!settings.detail.empty())
|
||||||
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog_),
|
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog_),
|
||||||
"%s", detail.c_str());
|
"%s", settings.detail.c_str());
|
||||||
if (!title.empty())
|
if (!settings.title.empty())
|
||||||
gtk_window_set_title(GTK_WINDOW(dialog_), title.c_str());
|
gtk_window_set_title(GTK_WINDOW(dialog_), settings.title.c_str());
|
||||||
|
|
||||||
if (!icon.isNull()) {
|
if (!settings.icon.isNull()) {
|
||||||
// No easy way to obtain this programmatically, but GTK+'s docs
|
// No easy way to obtain this programmatically, but GTK+'s docs
|
||||||
// define GTK_ICON_SIZE_DIALOG to be 48 pixels
|
// define GTK_ICON_SIZE_DIALOG to be 48 pixels
|
||||||
static constexpr int pixel_width = 48;
|
static constexpr int pixel_width = 48;
|
||||||
static constexpr int pixel_height = 48;
|
static constexpr int pixel_height = 48;
|
||||||
GdkPixbuf* pixbuf = libgtkui::GdkPixbufFromSkBitmap(*icon.bitmap());
|
GdkPixbuf* pixbuf =
|
||||||
|
libgtkui::GdkPixbufFromSkBitmap(*settings.icon.bitmap());
|
||||||
GdkPixbuf* scaled_pixbuf = gdk_pixbuf_scale_simple(
|
GdkPixbuf* scaled_pixbuf = gdk_pixbuf_scale_simple(
|
||||||
pixbuf, pixel_width, pixel_height, GDK_INTERP_BILINEAR);
|
pixbuf, pixel_width, pixel_height, GDK_INTERP_BILINEAR);
|
||||||
GtkWidget* w = gtk_image_new_from_pixbuf(scaled_pixbuf);
|
GtkWidget* w = gtk_image_new_from_pixbuf(scaled_pixbuf);
|
||||||
|
@ -72,25 +67,26 @@ class GtkMessageBox : public NativeWindowObserver {
|
||||||
g_clear_pointer(&pixbuf, g_object_unref);
|
g_clear_pointer(&pixbuf, g_object_unref);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!checkbox_label.empty()) {
|
if (!settings.checkbox_label.empty()) {
|
||||||
GtkWidget* message_area =
|
GtkWidget* message_area =
|
||||||
gtk_message_dialog_get_message_area(GTK_MESSAGE_DIALOG(dialog_));
|
gtk_message_dialog_get_message_area(GTK_MESSAGE_DIALOG(dialog_));
|
||||||
GtkWidget* check_button =
|
GtkWidget* check_button =
|
||||||
gtk_check_button_new_with_label(checkbox_label.c_str());
|
gtk_check_button_new_with_label(settings.checkbox_label.c_str());
|
||||||
g_signal_connect(check_button, "toggled",
|
g_signal_connect(check_button, "toggled",
|
||||||
G_CALLBACK(OnCheckboxToggledThunk), this);
|
G_CALLBACK(OnCheckboxToggledThunk), this);
|
||||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button),
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button),
|
||||||
checkbox_checked);
|
settings.checkbox_checked);
|
||||||
gtk_container_add(GTK_CONTAINER(message_area), check_button);
|
gtk_container_add(GTK_CONTAINER(message_area), check_button);
|
||||||
gtk_widget_show(check_button);
|
gtk_widget_show(check_button);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add buttons.
|
// Add buttons.
|
||||||
GtkDialog* dialog = GTK_DIALOG(dialog_);
|
GtkDialog* dialog = GTK_DIALOG(dialog_);
|
||||||
for (size_t i = 0; i < buttons.size(); ++i) {
|
for (size_t i = 0; i < settings.buttons.size(); ++i) {
|
||||||
gtk_dialog_add_button(dialog, TranslateToStock(i, buttons[i]), i);
|
gtk_dialog_add_button(dialog, TranslateToStock(i, settings.buttons[i]),
|
||||||
|
i);
|
||||||
}
|
}
|
||||||
gtk_dialog_set_default_response(dialog, default_id);
|
gtk_dialog_set_default_response(dialog, settings.default_id);
|
||||||
|
|
||||||
// Parent window.
|
// Parent window.
|
||||||
if (parent_) {
|
if (parent_) {
|
||||||
|
@ -200,46 +196,25 @@ void GtkMessageBox::OnCheckboxToggled(GtkWidget* widget) {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
int ShowMessageBoxSync(NativeWindow* parent,
|
int ShowMessageBoxSync(const MessageBoxSettings& settings) {
|
||||||
MessageBoxType type,
|
return GtkMessageBox(settings).RunSynchronous();
|
||||||
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 gfx::ImageSkia& icon) {
|
|
||||||
return GtkMessageBox(parent, type, buttons, default_id, cancel_id, title,
|
|
||||||
message, detail, "", false, icon)
|
|
||||||
.RunSynchronous();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShowMessageBox(NativeWindow* parent,
|
void ShowMessageBox(const MessageBoxSettings& settings,
|
||||||
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,
|
|
||||||
MessageBoxCallback callback) {
|
MessageBoxCallback callback) {
|
||||||
(new GtkMessageBox(parent, type, buttons, default_id, cancel_id, title,
|
(new GtkMessageBox(settings))->RunAsynchronous(std::move(callback));
|
||||||
message, detail, checkbox_label, checkbox_checked, icon))
|
|
||||||
->RunAsynchronous(std::move(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, MessageBoxType::kError, {"OK"}, -1, 0, "Error",
|
atom::MessageBoxSettings settings;
|
||||||
base::UTF16ToUTF8(title).c_str(),
|
settings.type = atom::MessageBoxType::kError;
|
||||||
base::UTF16ToUTF8(content).c_str(), "", false,
|
settings.buttons = {"OK"};
|
||||||
gfx::ImageSkia())
|
settings.title = "Error";
|
||||||
.RunSynchronous();
|
settings.message = base::UTF16ToUTF8(title);
|
||||||
|
settings.detail = base::UTF16ToUTF8(content);
|
||||||
|
|
||||||
|
GtkMessageBox(settings).RunSynchronous();
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
ANSI_TEXT_BOLD ANSI_BACKGROUND_GRAY ANSI_FOREGROUND_RED
|
ANSI_TEXT_BOLD ANSI_BACKGROUND_GRAY ANSI_FOREGROUND_RED
|
||||||
|
|
|
@ -19,25 +19,19 @@
|
||||||
|
|
||||||
namespace atom {
|
namespace atom {
|
||||||
|
|
||||||
|
MessageBoxSettings::MessageBoxSettings() = default;
|
||||||
|
MessageBoxSettings::MessageBoxSettings(const MessageBoxSettings&) = default;
|
||||||
|
MessageBoxSettings::~MessageBoxSettings() = default;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
NSAlert* CreateNSAlert(NativeWindow* parent_window,
|
NSAlert* CreateNSAlert(const MessageBoxSettings& settings) {
|
||||||
MessageBoxType type,
|
|
||||||
const std::vector<std::string>& buttons,
|
|
||||||
int default_id,
|
|
||||||
int cancel_id,
|
|
||||||
const std::string& title,
|
|
||||||
const std::string& message,
|
|
||||||
const std::string& detail,
|
|
||||||
const std::string& checkbox_label,
|
|
||||||
bool checkbox_checked,
|
|
||||||
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];
|
||||||
[alert setMessageText:base::SysUTF8ToNSString(message)];
|
[alert setMessageText:base::SysUTF8ToNSString(settings.message)];
|
||||||
[alert setInformativeText:base::SysUTF8ToNSString(detail)];
|
[alert setInformativeText:base::SysUTF8ToNSString(settings.detail)];
|
||||||
|
|
||||||
switch (type) {
|
switch (settings.type) {
|
||||||
case MessageBoxType::kInformation:
|
case MessageBoxType::kInformation:
|
||||||
alert.alertStyle = NSInformationalAlertStyle;
|
alert.alertStyle = NSInformationalAlertStyle;
|
||||||
break;
|
break;
|
||||||
|
@ -52,10 +46,10 @@ NSAlert* CreateNSAlert(NativeWindow* parent_window,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < buttons.size(); ++i) {
|
for (size_t i = 0; i < settings.buttons.size(); ++i) {
|
||||||
NSString* title = base::SysUTF8ToNSString(buttons[i]);
|
NSString* title = base::SysUTF8ToNSString(settings.buttons[i]);
|
||||||
// An empty title causes crash on macOS.
|
// An empty title causes crash on macOS.
|
||||||
if (buttons[i].empty())
|
if (settings.buttons[i].empty())
|
||||||
title = @"(empty)";
|
title = @"(empty)";
|
||||||
NSButton* button = [alert addButtonWithTitle:title];
|
NSButton* button = [alert addButtonWithTitle:title];
|
||||||
[button setTag:i];
|
[button setTag:i];
|
||||||
|
@ -64,28 +58,31 @@ NSAlert* CreateNSAlert(NativeWindow* parent_window,
|
||||||
NSArray* ns_buttons = [alert buttons];
|
NSArray* ns_buttons = [alert buttons];
|
||||||
int button_count = static_cast<int>([ns_buttons count]);
|
int button_count = static_cast<int>([ns_buttons count]);
|
||||||
|
|
||||||
if (default_id >= 0 && default_id < button_count) {
|
if (settings.default_id >= 0 && settings.default_id < button_count) {
|
||||||
// Focus the button at default_id if the user opted to do so.
|
// Focus the button at default_id if the user opted to do so.
|
||||||
// The first button added gets set as the default selected.
|
// The first button added gets set as the default selected.
|
||||||
// So remove that default, and make the requested button the default.
|
// So remove that default, and make the requested button the default.
|
||||||
[[ns_buttons objectAtIndex:0] setKeyEquivalent:@""];
|
[[ns_buttons objectAtIndex:0] setKeyEquivalent:@""];
|
||||||
[[ns_buttons objectAtIndex:default_id] setKeyEquivalent:@"\r"];
|
[[ns_buttons objectAtIndex:settings.default_id] setKeyEquivalent:@"\r"];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bind cancel id button to escape key if there is more than one button
|
// Bind cancel id button to escape key if there is more than one button
|
||||||
if (button_count > 1 && cancel_id >= 0 && cancel_id < button_count) {
|
if (button_count > 1 && settings.cancel_id >= 0 &&
|
||||||
[[ns_buttons objectAtIndex:cancel_id] setKeyEquivalent:@"\e"];
|
settings.cancel_id < button_count) {
|
||||||
|
[[ns_buttons objectAtIndex:settings.cancel_id] setKeyEquivalent:@"\e"];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!checkbox_label.empty()) {
|
if (!settings.checkbox_label.empty()) {
|
||||||
alert.showsSuppressionButton = YES;
|
alert.showsSuppressionButton = YES;
|
||||||
alert.suppressionButton.title = base::SysUTF8ToNSString(checkbox_label);
|
alert.suppressionButton.title =
|
||||||
alert.suppressionButton.state = checkbox_checked ? NSOnState : NSOffState;
|
base::SysUTF8ToNSString(settings.checkbox_label);
|
||||||
|
alert.suppressionButton.state =
|
||||||
|
settings.checkbox_checked ? NSOnState : NSOffState;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!icon.isNull()) {
|
if (!settings.icon.isNull()) {
|
||||||
NSImage* image = skia::SkBitmapToNSImageWithColorSpace(
|
NSImage* image = skia::SkBitmapToNSImageWithColorSpace(
|
||||||
*icon.bitmap(), base::mac::GetGenericRGBColorSpace());
|
*settings.icon.bitmap(), base::mac::GetGenericRGBColorSpace());
|
||||||
[alert setIcon:image];
|
[alert setIcon:image];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,28 +91,18 @@ NSAlert* CreateNSAlert(NativeWindow* parent_window,
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
int ShowMessageBoxSync(NativeWindow* parent_window,
|
int ShowMessageBoxSync(const MessageBoxSettings& settings) {
|
||||||
MessageBoxType type,
|
NSAlert* alert = CreateNSAlert(settings);
|
||||||
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 gfx::ImageSkia& icon) {
|
|
||||||
NSAlert* alert =
|
|
||||||
CreateNSAlert(parent_window, type, buttons, default_id, cancel_id, title,
|
|
||||||
message, detail, "", false, 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.
|
||||||
if (!parent_window)
|
if (!settings.parent_window)
|
||||||
return [[alert autorelease] runModal];
|
return [[alert autorelease] runModal];
|
||||||
|
|
||||||
__block int ret_code = -1;
|
__block int ret_code = -1;
|
||||||
|
|
||||||
NSWindow* window = parent_window->GetNativeWindow().GetNativeNSWindow();
|
NSWindow* window =
|
||||||
|
settings.parent_window->GetNativeWindow().GetNativeNSWindow();
|
||||||
[alert beginSheetModalForWindow:window
|
[alert beginSheetModalForWindow:window
|
||||||
completionHandler:^(NSModalResponse response) {
|
completionHandler:^(NSModalResponse response) {
|
||||||
ret_code = response;
|
ret_code = response;
|
||||||
|
@ -126,32 +113,20 @@ int ShowMessageBoxSync(NativeWindow* parent_window,
|
||||||
return ret_code;
|
return ret_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShowMessageBox(NativeWindow* parent_window,
|
void ShowMessageBox(const MessageBoxSettings& settings,
|
||||||
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,
|
|
||||||
MessageBoxCallback callback) {
|
MessageBoxCallback callback) {
|
||||||
NSAlert* alert =
|
NSAlert* alert = CreateNSAlert(settings);
|
||||||
CreateNSAlert(parent_window, type, buttons, default_id, cancel_id, title,
|
|
||||||
message, detail, checkbox_label, checkbox_checked, 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.
|
||||||
if (!parent_window) {
|
if (!settings.parent_window) {
|
||||||
int ret = [[alert autorelease] runModal];
|
int ret = [[alert autorelease] runModal];
|
||||||
std::move(callback).Run(ret, alert.suppressionButton.state == NSOnState);
|
std::move(callback).Run(ret, alert.suppressionButton.state == NSOnState);
|
||||||
} else {
|
} else {
|
||||||
NSWindow* window =
|
NSWindow* window =
|
||||||
parent_window ? parent_window->GetNativeWindow().GetNativeNSWindow()
|
settings.parent_window
|
||||||
: nil;
|
? settings.parent_window->GetNativeWindow().GetNativeNSWindow()
|
||||||
|
: nil;
|
||||||
|
|
||||||
// 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.
|
||||||
|
|
|
@ -26,6 +26,10 @@
|
||||||
|
|
||||||
namespace atom {
|
namespace atom {
|
||||||
|
|
||||||
|
MessageBoxSettings::MessageBoxSettings() = default;
|
||||||
|
MessageBoxSettings::MessageBoxSettings(const MessageBoxSettings&) = default;
|
||||||
|
MessageBoxSettings::~MessageBoxSettings() = default;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// Small command ID values are already taken by Windows, we have to start from
|
// Small command ID values are already taken by Windows, we have to start from
|
||||||
|
@ -183,88 +187,49 @@ int ShowTaskDialogUTF16(NativeWindow* parent,
|
||||||
return cancel_id;
|
return cancel_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ShowTaskDialogUTF8(NativeWindow* parent,
|
int ShowTaskDialogUTF8(const MessageBoxSettings& settings) {
|
||||||
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;
|
std::vector<base::string16> utf16_buttons;
|
||||||
for (const auto& button : buttons)
|
for (const auto& button : settings.buttons)
|
||||||
utf16_buttons.push_back(base::UTF8ToUTF16(button));
|
utf16_buttons.push_back(base::UTF8ToUTF16(button));
|
||||||
|
|
||||||
|
const base::string16 title_16 = base::UTF8ToUTF16(settings.title);
|
||||||
|
const base::string16 message_16 = base::UTF8ToUTF16(settings.message);
|
||||||
|
const base::string16 detail_16 = base::UTF8ToUTF16(settings.detail);
|
||||||
|
const base::string16 checkbox_label_16 =
|
||||||
|
base::UTF8ToUTF16(settings.checkbox_label);
|
||||||
|
bool cb_checked = settings.checkbox_checked;
|
||||||
|
|
||||||
return ShowTaskDialogUTF16(
|
return ShowTaskDialogUTF16(
|
||||||
parent, type, utf16_buttons, default_id, cancel_id, options,
|
settings.parent_window, settings.type, utf16_buttons, settings.default_id,
|
||||||
base::UTF8ToUTF16(title), base::UTF8ToUTF16(message),
|
settings.cancel_id, settings.options, title_16, message_16, detail_16,
|
||||||
base::UTF8ToUTF16(detail), base::UTF8ToUTF16(checkbox_label),
|
checkbox_label_16, &cb_checked, settings.icon);
|
||||||
checkbox_checked, icon);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RunMessageBoxInNewThread(base::Thread* thread,
|
void RunMessageBoxInNewThread(base::Thread* thread,
|
||||||
NativeWindow* parent,
|
const MessageBoxSettings& settings,
|
||||||
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,
|
|
||||||
MessageBoxCallback callback) {
|
MessageBoxCallback callback) {
|
||||||
int result = ShowTaskDialogUTF8(parent, type, buttons, default_id, cancel_id,
|
int result = ShowTaskDialogUTF8(settings);
|
||||||
options, title, message, detail,
|
|
||||||
checkbox_label, &checkbox_checked, icon);
|
|
||||||
base::PostTaskWithTraits(
|
base::PostTaskWithTraits(
|
||||||
FROM_HERE, {content::BrowserThread::UI},
|
FROM_HERE, {content::BrowserThread::UI},
|
||||||
base::BindOnce(std::move(callback), result, checkbox_checked));
|
base::BindOnce(std::move(callback), result, settings.checkbox_checked));
|
||||||
content::BrowserThread::DeleteSoon(content::BrowserThread::UI, FROM_HERE,
|
content::BrowserThread::DeleteSoon(content::BrowserThread::UI, FROM_HERE,
|
||||||
thread);
|
thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
int ShowMessageBoxSync(NativeWindow* parent,
|
int ShowMessageBoxSync(const MessageBoxSettings& settings) {
|
||||||
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 gfx::ImageSkia& icon) {
|
|
||||||
atom::UnresponsiveSuppressor suppressor;
|
atom::UnresponsiveSuppressor suppressor;
|
||||||
return ShowTaskDialogUTF8(parent, type, buttons, default_id, cancel_id,
|
return ShowTaskDialogUTF8(settings);
|
||||||
options, title, message, detail, "", nullptr, icon);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShowMessageBox(NativeWindow* parent,
|
void ShowMessageBox(const MessageBoxSettings& settings,
|
||||||
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,
|
|
||||||
MessageBoxCallback callback) {
|
MessageBoxCallback callback) {
|
||||||
auto thread =
|
auto thread =
|
||||||
std::make_unique<base::Thread>(ATOM_PRODUCT_NAME "MessageBoxThread");
|
std::make_unique<base::Thread>(ATOM_PRODUCT_NAME "MessageBoxThread");
|
||||||
thread->init_com_with_mta(false);
|
thread->init_com_with_mta(false);
|
||||||
if (!thread->Start()) {
|
if (!thread->Start()) {
|
||||||
std::move(callback).Run(cancel_id, checkbox_checked);
|
std::move(callback).Run(settings.cancel_id, settings.checkbox_checked);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,9 +237,7 @@ void ShowMessageBox(NativeWindow* parent,
|
||||||
unretained->task_runner()->PostTask(
|
unretained->task_runner()->PostTask(
|
||||||
FROM_HERE,
|
FROM_HERE,
|
||||||
base::BindOnce(&RunMessageBoxInNewThread, base::Unretained(unretained),
|
base::BindOnce(&RunMessageBoxInNewThread, base::Unretained(unretained),
|
||||||
parent, type, buttons, default_id, cancel_id, options,
|
settings, std::move(callback)));
|
||||||
title, message, detail, checkbox_label, checkbox_checked,
|
|
||||||
icon, std::move(callback)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShowErrorBox(const base::string16& title, const base::string16& content) {
|
void ShowErrorBox(const base::string16& title, const base::string16& content) {
|
||||||
|
|
38
atom/common/native_mate_converters/message_box_converter.cc
Normal file
38
atom/common/native_mate_converters/message_box_converter.cc
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
// Copyright (c) 2015 GitHub, Inc.
|
||||||
|
// Use of this source code is governed by the MIT license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#include "atom/common/native_mate_converters/message_box_converter.h"
|
||||||
|
|
||||||
|
#include "atom/browser/api/atom_api_browser_window.h"
|
||||||
|
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||||
|
#include "atom/common/native_mate_converters/image_converter.h"
|
||||||
|
#include "native_mate/dictionary.h"
|
||||||
|
|
||||||
|
namespace mate {
|
||||||
|
|
||||||
|
bool Converter<atom::MessageBoxSettings>::FromV8(
|
||||||
|
v8::Isolate* isolate,
|
||||||
|
v8::Local<v8::Value> val,
|
||||||
|
atom::MessageBoxSettings* out) {
|
||||||
|
mate::Dictionary dict;
|
||||||
|
int type = 0;
|
||||||
|
if (!ConvertFromV8(isolate, val, &dict))
|
||||||
|
return false;
|
||||||
|
dict.Get("window", &out->parent_window);
|
||||||
|
dict.Get("type", &type);
|
||||||
|
out->type = static_cast<atom::MessageBoxType>(type);
|
||||||
|
dict.Get("buttons", &out->buttons);
|
||||||
|
dict.Get("defaultId", &out->default_id);
|
||||||
|
dict.Get("cancelId", &out->cancel_id);
|
||||||
|
dict.Get("options", &out->options);
|
||||||
|
dict.Get("title", &out->title);
|
||||||
|
dict.Get("message", &out->message);
|
||||||
|
dict.Get("detail", &out->detail);
|
||||||
|
dict.Get("checkboxLabel", &out->checkbox_label);
|
||||||
|
dict.Get("checkboxChecked", &out->checkbox_checked);
|
||||||
|
dict.Get("icon", &out->icon);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace mate
|
22
atom/common/native_mate_converters/message_box_converter.h
Normal file
22
atom/common/native_mate_converters/message_box_converter.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
// Copyright (c) 2019 GitHub, Inc.
|
||||||
|
// Use of this source code is governed by the MIT license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_MESSAGE_BOX_CONVERTER_H_
|
||||||
|
#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_MESSAGE_BOX_CONVERTER_H_
|
||||||
|
|
||||||
|
#include "atom/browser/ui/message_box.h"
|
||||||
|
#include "native_mate/converter.h"
|
||||||
|
|
||||||
|
namespace mate {
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct Converter<atom::MessageBoxSettings> {
|
||||||
|
static bool FromV8(v8::Isolate* isolate,
|
||||||
|
v8::Local<v8::Value> val,
|
||||||
|
atom::MessageBoxSettings* out);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mate
|
||||||
|
|
||||||
|
#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_MESSAGE_BOX_CONVERTER_H_
|
|
@ -523,6 +523,8 @@ filenames = {
|
||||||
"atom/common/native_mate_converters/content_converter.h",
|
"atom/common/native_mate_converters/content_converter.h",
|
||||||
"atom/common/native_mate_converters/file_dialog_converter.cc",
|
"atom/common/native_mate_converters/file_dialog_converter.cc",
|
||||||
"atom/common/native_mate_converters/file_dialog_converter.h",
|
"atom/common/native_mate_converters/file_dialog_converter.h",
|
||||||
|
"atom/common/native_mate_converters/message_box_converter.cc",
|
||||||
|
"atom/common/native_mate_converters/message_box_converter.h",
|
||||||
"atom/common/native_mate_converters/file_path_converter.h",
|
"atom/common/native_mate_converters/file_path_converter.h",
|
||||||
"atom/common/native_mate_converters/gfx_converter.cc",
|
"atom/common/native_mate_converters/gfx_converter.cc",
|
||||||
"atom/common/native_mate_converters/gfx_converter.h",
|
"atom/common/native_mate_converters/gfx_converter.h",
|
||||||
|
|
|
@ -172,14 +172,25 @@ const messageBox = (sync, window, options) => {
|
||||||
|
|
||||||
const flags = options.noLink ? messageBoxOptions.noLink : 0
|
const flags = options.noLink ? messageBoxOptions.noLink : 0
|
||||||
|
|
||||||
|
const settings = {
|
||||||
|
window,
|
||||||
|
messageBoxType,
|
||||||
|
buttons,
|
||||||
|
defaultId,
|
||||||
|
cancelId,
|
||||||
|
flags,
|
||||||
|
title,
|
||||||
|
message,
|
||||||
|
detail,
|
||||||
|
checkboxLabel,
|
||||||
|
checkboxChecked,
|
||||||
|
icon
|
||||||
|
}
|
||||||
|
|
||||||
if (sync) {
|
if (sync) {
|
||||||
return binding.showMessageBoxSync(messageBoxType, buttons,
|
return binding.showMessageBoxSync(settings)
|
||||||
defaultId, cancelId, flags, title, message, detail,
|
|
||||||
checkboxLabel, checkboxChecked, icon, window)
|
|
||||||
} else {
|
} else {
|
||||||
return binding.showMessageBox(messageBoxType, buttons,
|
return binding.showMessageBox(settings)
|
||||||
defaultId, cancelId, flags, title, message, detail,
|
|
||||||
checkboxLabel, checkboxChecked, icon, window)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue