Skip to content

Commit

Permalink
feat: promisify dialog.showSaveDialog()
Browse files Browse the repository at this point in the history
  • Loading branch information
codebytere committed Feb 27, 2019
1 parent 0806658 commit 8c9d837
Show file tree
Hide file tree
Showing 10 changed files with 182 additions and 146 deletions.
29 changes: 17 additions & 12 deletions atom/browser/api/atom_api_dialog.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#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/net_converter.h"
#include "atom/common/promise_util.h"
#include "native_mate/dictionary.h"

#include "atom/common/node_includes.h"
Expand Down Expand Up @@ -65,18 +66,21 @@ void ShowOpenDialog(const file_dialog::DialogSettings& settings,
}
}

void ShowSaveDialog(const file_dialog::DialogSettings& settings,
mate::Arguments* args) {
v8::Local<v8::Value> peek = args->PeekNext();
file_dialog::SaveDialogCallback callback;
if (mate::Converter<file_dialog::SaveDialogCallback>::FromV8(
args->isolate(), peek, &callback)) {
file_dialog::ShowSaveDialog(settings, callback);
} else {
base::FilePath path;
if (file_dialog::ShowSaveDialog(settings, &path))
args->Return(path);
}
void ShowSaveDialogSync(const file_dialog::DialogSettings& settings,
mate::Arguments* args) {
base::FilePath path;
if (file_dialog::ShowSaveDialogSync(settings, &path))
args->Return(path);
}

v8::Local<v8::Promise> ShowSaveDialog(
const file_dialog::DialogSettings& settings,
mate::Arguments* args) {
atom::util::Promise promise(args->isolate());
v8::Local<v8::Promise> handle = promise.GetHandle();

file_dialog::ShowSaveDialog(settings, std::move(promise));
return handle;
}

void Initialize(v8::Local<v8::Object> exports,
Expand All @@ -87,6 +91,7 @@ void Initialize(v8::Local<v8::Object> exports,
dict.SetMethod("showMessageBox", &ShowMessageBox);
dict.SetMethod("showErrorBox", &atom::ShowErrorBox);
dict.SetMethod("showOpenDialog", &ShowOpenDialog);
dict.SetMethod("showSaveDialogSync", &ShowSaveDialogSync);
dict.SetMethod("showSaveDialog", &ShowSaveDialog);
#if defined(OS_MACOSX) || defined(OS_WIN)
dict.SetMethod("showCertificateTrustDialog",
Expand Down
7 changes: 6 additions & 1 deletion atom/browser/atom_download_manager_delegate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "atom/browser/native_window.h"
#include "atom/browser/ui/file_dialog.h"
#include "atom/browser/web_contents_preferences.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/options_switches.h"
#include "base/bind.h"
#include "base/files/file_util.h"
Expand Down Expand Up @@ -119,10 +120,14 @@ void AtomDownloadManagerDelegate::OnDownloadPathGenerated(
!web_preferences || web_preferences->IsEnabled(options::kOffscreen);
settings.force_detached = offscreen;

v8::Isolate* isolate = v8::Isolate::GetCurrent();
atom::util::Promise dialog_promise(isolate);
auto dialog_callback =
base::Bind(&AtomDownloadManagerDelegate::OnDownloadSaveDialogDone,
base::Unretained(this), download_id, callback);
file_dialog::ShowSaveDialog(settings, dialog_callback);

file_dialog::ShowSaveDialog(settings, std::move(dialog_promise));
ignore_result(dialog_promise.Then(dialog_callback));
} else {
callback.Run(path, download::DownloadItem::TARGET_DISPOSITION_PROMPT,
download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, path,
Expand Down
2 changes: 1 addition & 1 deletion atom/browser/common_web_contents_delegate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ void CommonWebContentsDelegate::DevToolsSaveToFile(const std::string& url,
settings.force_detached = offscreen_;
settings.title = url;
settings.default_path = base::FilePath::FromUTF8Unsafe(url);
if (!file_dialog::ShowSaveDialog(settings, &path)) {
if (!file_dialog::ShowSaveDialogSync(settings, &path)) {
base::Value url_value(url);
web_contents_->CallClientFunction("DevToolsAPI.canceledSaveURL",
&url_value, nullptr, nullptr);
Expand Down
15 changes: 5 additions & 10 deletions atom/browser/ui/file_dialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@
#include <utility>
#include <vector>

#include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/promise_util.h"
#include "base/callback_forward.h"
#include "base/files/file_path.h"
#include "native_mate/dictionary.h"

namespace atom {
class NativeWindow;
Expand Down Expand Up @@ -38,18 +41,10 @@ typedef base::Callback<void(bool result,
const std::vector<base::FilePath>& paths,
const std::vector<std::string>& bookmarkData)>
OpenDialogCallback;

typedef base::Callback<void(bool result,
const base::FilePath& path,
const std::string& bookmarkData)>
SaveDialogCallback;
#else
typedef base::Callback<void(bool result,
const std::vector<base::FilePath>& paths)>
OpenDialogCallback;

typedef base::Callback<void(bool result, const base::FilePath& path)>
SaveDialogCallback;
#endif

struct DialogSettings {
Expand All @@ -76,10 +71,10 @@ bool ShowOpenDialog(const DialogSettings& settings,
void ShowOpenDialog(const DialogSettings& settings,
const OpenDialogCallback& callback);

bool ShowSaveDialog(const DialogSettings& settings, base::FilePath* path);
bool ShowSaveDialogSync(const DialogSettings& settings, base::FilePath* path);

void ShowSaveDialog(const DialogSettings& settings,
const SaveDialogCallback& callback);
atom::util::Promise promise);

} // namespace file_dialog

Expand Down
32 changes: 18 additions & 14 deletions atom/browser/ui/file_dialog_gtk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ class FileChooserDialog {
gtk_window_present_with_time(GTK_WINDOW(dialog_), time);
}

void RunSaveAsynchronous(const SaveDialogCallback& callback) {
save_callback_ = callback;
void RunSaveAsynchronous(atom::util::Promise promise) {
save_promise_->reset(std::move(promise));
RunAsynchronous();
}

Expand Down Expand Up @@ -173,7 +173,7 @@ class FileChooserDialog {
GtkWidget* preview_;

Filters filters_;
SaveDialogCallback save_callback_;
std::unique_ptr<atom::util::Promise> open_promise_;
OpenDialogCallback open_callback_;

// Callback for when we update the preview for the selection.
Expand All @@ -184,12 +184,17 @@ class FileChooserDialog {

void FileChooserDialog::OnFileDialogResponse(GtkWidget* widget, int response) {
gtk_widget_hide(dialog_);

if (!save_callback_.is_null()) {
if (response == GTK_RESPONSE_ACCEPT)
save_callback_.Run(true, GetFileName());
else
save_callback_.Run(false, base::FilePath());
if (!save_promise_->is_null()) {
mate::Dictionary dict =
mate::Dictionary::CreateEmpty(save_promise_->isolate());
if (response == GTK_RESPONSE_ACCEPT) {
dict.Set("canceled", false);
dict.Set("filename", GetFileName());
} else {
dict.Set("canceled", true);
dict.Set("filename", base::FilePath();
}
save_promise_->Resolve(dict.GetHandle());
} else if (!open_callback_.is_null()) {
if (response == GTK_RESPONSE_ACCEPT)
open_callback_.Run(true, GetFileNames());
Expand Down Expand Up @@ -280,23 +285,22 @@ void ShowOpenDialog(const DialogSettings& settings,
open_dialog->RunOpenAsynchronous(callback);
}

bool ShowSaveDialog(const DialogSettings& settings, base::FilePath* path) {
bool ShowSaveDialogSync(const DialogSettings& settings, base::FilePath* path) {
FileChooserDialog save_dialog(GTK_FILE_CHOOSER_ACTION_SAVE, settings);
gtk_widget_show_all(save_dialog.dialog());
int response = gtk_dialog_run(GTK_DIALOG(save_dialog.dialog()));
if (response == GTK_RESPONSE_ACCEPT) {
*path = save_dialog.GetFileName();
return true;
} else {
return false;
}
return false;
}

void ShowSaveDialog(const DialogSettings& settings,
const SaveDialogCallback& callback) {
atom::util::Promise promise) {
FileChooserDialog* save_dialog =
new FileChooserDialog(GTK_FILE_CHOOSER_ACTION_SAVE, settings);
save_dialog->RunSaveAsynchronous(callback);
save_dialog->RunSaveAsynchronous(promise);
}

} // namespace file_dialog
67 changes: 37 additions & 30 deletions atom/browser/ui/file_dialog_mac.mm
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ void ShowOpenDialog(const DialogSettings& settings,
}
}

bool ShowSaveDialog(const DialogSettings& settings, base::FilePath* path) {
bool ShowSaveDialogSync(const DialogSettings& settings, base::FilePath* path) {
DCHECK(path);
NSSavePanel* dialog = [NSSavePanel savePanel];

Expand All @@ -359,51 +359,58 @@ bool ShowSaveDialog(const DialogSettings& settings, base::FilePath* path) {
void SaveDialogCompletion(int chosen,
NSSavePanel* dialog,
bool security_scoped_bookmarks,
const SaveDialogCallback& callback) {
atom::util::Promise promise) {
if (chosen == NSFileHandlingPanelCancelButton) {
dict.Set("canceled", true);
#if defined(MAS_BUILD)
callback.Run(false, base::FilePath(), "");
dict.Set("filename", std::vector<base::FilePath>());
dict.Set("bookmark", "");
#else
callback.Run(false, base::FilePath());
dict.Set("filename", base::FilePath());
#endif
} else {
std::string path = base::SysNSStringToUTF8([[dialog URL] path]);
dict.Set("filename", base::FilePath(path));
dict.Set("canceled", false);
#if defined(MAS_BUILD)
std::string bookmark;
if (security_scoped_bookmarks) {
bookmark = GetBookmarkDataFromNSURL([dialog URL]);
}
callback.Run(true, base::FilePath(path), bookmark);
#else
callback.Run(true, base::FilePath(path));
dict.Set("bookmark", bookmark);
#endif
}
promise.Resolve(dict.GetHandle());
}
}

void ShowSaveDialog(const DialogSettings& settings,
const SaveDialogCallback& c) {
NSSavePanel* dialog = [NSSavePanel savePanel];
void ShowSaveDialog(const DialogSettings& settings,
atom::util::Promise promise) {
NSSavePanel* dialog = [NSSavePanel savePanel];

SetupDialog(dialog, settings);
[dialog setCanSelectHiddenExtension:YES];
SetupDialog(dialog, settings);
[dialog setCanSelectHiddenExtension:YES];

__block SaveDialogCallback callback = c;
bool security_scoped_bookmarks = settings.security_scoped_bookmarks;
// Capture the value of the security_scoped_bookmarks settings flag
// and pass it to the completion handler.
bool security_scoped_bookmarks = settings.security_scoped_bookmarks;

if (!settings.parent_window || !settings.parent_window->GetNativeWindow() ||
settings.force_detached) {
[dialog beginWithCompletionHandler:^(NSInteger chosen) {
SaveDialogCompletion(chosen, dialog, security_scoped_bookmarks, callback);
}];
} else {
NSWindow* window =
settings.parent_window->GetNativeWindow().GetNativeNSWindow();
[dialog beginSheetModalForWindow:window
completionHandler:^(NSInteger chosen) {
SaveDialogCompletion(chosen, dialog,
security_scoped_bookmarks, callback);
}];
__block atom::util::Promise p = std::move(promise);

if (!settings.parent_window || !settings.parent_window->GetNativeWindow() ||
settings.force_detached) {
[dialog beginWithCompletionHandler:^(NSInteger chosen) {
SaveDialogCompletion(chosen, dialog, security_scoped_bookmarks,
std::move(p));
}];
} else {
NSWindow* window =
settings.parent_window->GetNativeWindow().GetNativeNSWindow();
[dialog
beginSheetModalForWindow:window
completionHandler:^(NSInteger chosen) {
SaveDialogCompletion(
chosen, dialog, security_scoped_bookmarks, std::move(p));
}];
}
}
}

} // namespace file_dialog
36 changes: 24 additions & 12 deletions atom/browser/ui/file_dialog_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,23 @@ void RunOpenDialogInNewThread(const RunState& run_state,
run_state.ui_task_runner->DeleteSoon(FROM_HERE, run_state.dialog_thread);
}

void OnSaveDialogDone(atom::util::Promise promise,
bool canceled,
const base::FilePath path) {
mate::Dictionary dict = mate::Dictionary::CreateEmpty(promise.isolate());
dict.Set("canceled", canceled);
dict.Set("filename", path);
promise.Resolve(dict.GetHandle());
}

void RunSaveDialogInNewThread(const RunState& run_state,
const DialogSettings& settings,
const SaveDialogCallback& callback) {
atom::util::Promise promise) {
base::FilePath path;
bool result = ShowSaveDialog(settings, &path);
run_state.ui_task_runner->PostTask(FROM_HERE,
base::Bind(callback, result, path));
bool result = ShowSaveDialogSync(settings, &path);
run_state.ui_task_runner->PostTask(
FROM_HERE,
base::Bind(&OnSaveDialogDone, std::move(promise), result, path));
run_state.ui_task_runner->DeleteSoon(FROM_HERE, run_state.dialog_thread);
}

Expand Down Expand Up @@ -263,7 +273,7 @@ void ShowOpenDialog(const DialogSettings& settings,
base::Bind(&RunOpenDialogInNewThread, run_state, settings, callback));
}

bool ShowSaveDialog(const DialogSettings& settings, base::FilePath* path) {
bool ShowSaveDialogSync(const DialogSettings& settings, base::FilePath* path) {
ATL::CComPtr<IFileSaveDialog> file_save_dialog;
HRESULT hr = file_save_dialog.CoCreateInstance(CLSID_FileSaveDialog);
if (FAILED(hr))
Expand Down Expand Up @@ -294,16 +304,18 @@ bool ShowSaveDialog(const DialogSettings& settings, base::FilePath* path) {
}

void ShowSaveDialog(const DialogSettings& settings,
const SaveDialogCallback& callback) {
atom::util::Promise promise) {
RunState run_state;
if (!CreateDialogThread(&run_state)) {
callback.Run(false, base::FilePath());
return;
mate::Dictionary dict = mate::Dictionary::CreateEmpty(promise.isolate());
dict.Set("canceled", false);
dict.Set("filename", base::FilePath());
promise.Resolve(dict.GetHandle());
} else {
run_state.dialog_thread->task_runner()->PostTask(
FROM_HERE, base::Bind(&RunSaveDialogInNewThread, run_state, settings,
std::move(promise)));
}

run_state.dialog_thread->task_runner()->PostTask(
FROM_HERE,
base::Bind(&RunSaveDialogInNewThread, run_state, settings, callback));
}

} // namespace file_dialog
13 changes: 11 additions & 2 deletions atom/browser/web_dialog_helper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/native_window.h"
#include "atom/browser/ui/file_dialog.h"
#include "atom/common/native_mate_converters/callback.h"
#include "base/bind.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
Expand Down Expand Up @@ -51,8 +52,16 @@ class FileSelectHelper : public base::RefCounted<FileSelectHelper>,
}

void ShowSaveDialog(const file_dialog::DialogSettings& settings) {
auto callback = base::Bind(&FileSelectHelper::OnSaveDialogDone, this);
file_dialog::ShowSaveDialog(settings, callback);
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Local<v8::Context> context = isolate->GetCurrentContext();
atom::util::Promise promise(isolate);
v8::Local<v8::Promise> handle = promise.GetHandle();

file_dialog::ShowSaveDialog(settings, std::move(promise));
ignore_result(handle->Then(
context,
v8::Local<v8::Function>::Cast(mate::ConvertToV8(
isolate, base::Bind(&FileSelectHelper::OnSaveDialogDone, this)))));
}

private:
Expand Down
Loading

0 comments on commit 8c9d837

Please sign in to comment.