Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(189)

Side by Side Diff: chrome/browser/ui/views/simple_message_box_views.cc

Issue 2929953002: Make profile error dialog async (Closed)
Patch Set: rebase Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ui/simple_message_box.h" 5 #include "chrome/browser/ui/simple_message_box.h"
6 6
7 #include <utility>
8
7 #include "base/compiler_specific.h" 9 #include "base/compiler_specific.h"
8 #include "base/macros.h" 10 #include "base/macros.h"
9 #include "base/message_loop/message_loop.h" 11 #include "base/message_loop/message_loop.h"
10 #include "base/run_loop.h" 12 #include "base/run_loop.h"
11 #include "build/build_config.h" 13 #include "build/build_config.h"
12 #include "chrome/browser/ui/browser_dialogs.h" 14 #include "chrome/browser/ui/browser_dialogs.h"
13 #include "chrome/browser/ui/simple_message_box_internal.h" 15 #include "chrome/browser/ui/simple_message_box_internal.h"
14 #include "chrome/grit/generated_resources.h" 16 #include "chrome/grit/generated_resources.h"
15 #include "components/constrained_window/constrained_window_views.h" 17 #include "components/constrained_window/constrained_window_views.h"
16 #include "components/startup_metric_utils/browser/startup_metric_utils.h" 18 #include "components/startup_metric_utils/browser/startup_metric_utils.h"
17 #include "components/strings/grit/components_strings.h" 19 #include "components/strings/grit/components_strings.h"
18 #include "ui/base/l10n/l10n_util.h" 20 #include "ui/base/l10n/l10n_util.h"
19 #include "ui/base/resource/resource_bundle.h" 21 #include "ui/base/resource/resource_bundle.h"
20 #include "ui/gfx/native_widget_types.h" 22 #include "ui/gfx/native_widget_types.h"
21 #include "ui/views/controls/message_box_view.h" 23 #include "ui/views/controls/message_box_view.h"
22 #include "ui/views/widget/widget.h" 24 #include "ui/views/widget/widget.h"
23 #include "ui/views/window/dialog_delegate.h" 25 #include "ui/views/window/dialog_delegate.h"
24 26
25 #if defined(OS_WIN) 27 #if defined(OS_WIN)
26 #include "ui/base/win/message_box_win.h" 28 #include "ui/base/win/message_box_win.h"
27 #include "ui/views/win/hwnd_util.h" 29 #include "ui/views/win/hwnd_util.h"
28 #endif 30 #endif
29 31
30 namespace chrome { 32 namespace chrome {
31 33
32 namespace { 34 namespace {
33 35
34 class SimpleMessageBoxViews : public views::DialogDelegate { 36 class SimpleMessageBoxViews : public views::DialogDelegate {
35 public: 37 public:
38 using MessageBoxResultCallback =
39 base::OnceCallback<void(MessageBoxResult result)>;
40
36 SimpleMessageBoxViews(const base::string16& title, 41 SimpleMessageBoxViews(const base::string16& title,
37 const base::string16& message, 42 const base::string16& message,
38 MessageBoxType type, 43 MessageBoxType type,
39 const base::string16& yes_text, 44 const base::string16& yes_text,
40 const base::string16& no_text, 45 const base::string16& no_text,
41 const base::string16& checkbox_text, 46 const base::string16& checkbox_text,
42 bool is_system_modal); 47 bool is_system_modal);
43 ~SimpleMessageBoxViews() override; 48 ~SimpleMessageBoxViews() override;
44 49
45 MessageBoxResult RunDialogAndGetResult(); 50 void Run(MessageBoxResultCallback result_callback);
46 51
47 // Overridden from views::DialogDelegate: 52 // Overridden from views::DialogDelegate:
48 int GetDialogButtons() const override; 53 int GetDialogButtons() const override;
49 base::string16 GetDialogButtonLabel(ui::DialogButton button) const override; 54 base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
50 bool Cancel() override; 55 bool Cancel() override;
51 bool Accept() override; 56 bool Accept() override;
52 57
53 // Overridden from views::WidgetDelegate: 58 // Overridden from views::WidgetDelegate:
54 base::string16 GetWindowTitle() const override; 59 base::string16 GetWindowTitle() const override;
55 void DeleteDelegate() override; 60 void DeleteDelegate() override;
56 ui::ModalType GetModalType() const override; 61 ui::ModalType GetModalType() const override;
57 views::View* GetContentsView() override; 62 views::View* GetContentsView() override;
58 views::Widget* GetWidget() override; 63 views::Widget* GetWidget() override;
59 const views::Widget* GetWidget() const override; 64 const views::Widget* GetWidget() const override;
60 65
61 private: 66 private:
62 // This terminates the nested message-loop.
63 void Done(); 67 void Done();
64 68
65 const base::string16 window_title_; 69 const base::string16 window_title_;
66 const MessageBoxType type_; 70 const MessageBoxType type_;
67 base::string16 yes_text_; 71 base::string16 yes_text_;
68 base::string16 no_text_; 72 base::string16 no_text_;
69 MessageBoxResult* result_; 73 MessageBoxResult result_;
70 views::MessageBoxView* message_box_view_; 74 views::MessageBoxView* message_box_view_;
71 base::Closure quit_runloop_; 75 MessageBoxResultCallback result_callback_;
72 bool is_system_modal_; 76 bool is_system_modal_;
73 77
74 DISALLOW_COPY_AND_ASSIGN(SimpleMessageBoxViews); 78 DISALLOW_COPY_AND_ASSIGN(SimpleMessageBoxViews);
75 }; 79 };
76 80
77 // The currently showing message box, if there is one. Used for tests. 81 // The currently showing message box, if there is one. Used for tests.
78 SimpleMessageBoxViews* g_current_message_box = nullptr; 82 SimpleMessageBoxViews* g_current_message_box = nullptr;
79 83
80 //////////////////////////////////////////////////////////////////////////////// 84 ////////////////////////////////////////////////////////////////////////////////
81 // SimpleMessageBoxViews, public: 85 // SimpleMessageBoxViews, public:
82 86
83 SimpleMessageBoxViews::SimpleMessageBoxViews( 87 SimpleMessageBoxViews::SimpleMessageBoxViews(
84 const base::string16& title, 88 const base::string16& title,
85 const base::string16& message, 89 const base::string16& message,
86 MessageBoxType type, 90 MessageBoxType type,
87 const base::string16& yes_text, 91 const base::string16& yes_text,
88 const base::string16& no_text, 92 const base::string16& no_text,
89 const base::string16& checkbox_text, 93 const base::string16& checkbox_text,
90 bool is_system_modal) 94 bool is_system_modal)
91 : window_title_(title), 95 : window_title_(title),
92 type_(type), 96 type_(type),
93 yes_text_(yes_text), 97 yes_text_(yes_text),
94 no_text_(no_text), 98 no_text_(no_text),
95 result_(NULL), 99 result_(MESSAGE_BOX_RESULT_NO),
96 message_box_view_(new views::MessageBoxView( 100 message_box_view_(new views::MessageBoxView(
97 views::MessageBoxView::InitParams(message))), 101 views::MessageBoxView::InitParams(message))),
98 is_system_modal_(is_system_modal) { 102 is_system_modal_(is_system_modal) {
99 if (yes_text_.empty()) { 103 if (yes_text_.empty()) {
100 yes_text_ = 104 yes_text_ =
101 type_ == MESSAGE_BOX_TYPE_QUESTION 105 type_ == MESSAGE_BOX_TYPE_QUESTION
102 ? l10n_util::GetStringUTF16(IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL) 106 ? l10n_util::GetStringUTF16(IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL)
103 : l10n_util::GetStringUTF16(IDS_OK); 107 : l10n_util::GetStringUTF16(IDS_OK);
104 } 108 }
105 109
106 if (no_text_.empty() && type_ == MESSAGE_BOX_TYPE_QUESTION) 110 if (no_text_.empty() && type_ == MESSAGE_BOX_TYPE_QUESTION)
107 no_text_ = l10n_util::GetStringUTF16(IDS_CANCEL); 111 no_text_ = l10n_util::GetStringUTF16(IDS_CANCEL);
108 112
109 if (!checkbox_text.empty()) 113 if (!checkbox_text.empty())
110 message_box_view_->SetCheckBoxLabel(checkbox_text); 114 message_box_view_->SetCheckBoxLabel(checkbox_text);
111 chrome::RecordDialogCreation(chrome::DialogIdentifier::SIMPLE_MESSAGE_BOX); 115 chrome::RecordDialogCreation(chrome::DialogIdentifier::SIMPLE_MESSAGE_BOX);
112 } 116 }
113 117
114 SimpleMessageBoxViews::~SimpleMessageBoxViews() { 118 SimpleMessageBoxViews::~SimpleMessageBoxViews() {
115 } 119 }
116 120
117 MessageBoxResult SimpleMessageBoxViews::RunDialogAndGetResult() { 121 void SimpleMessageBoxViews::Run(MessageBoxResultCallback result_callback) {
118 g_current_message_box = this; 122 g_current_message_box = this;
119 MessageBoxResult result = MESSAGE_BOX_RESULT_NO; 123 result_callback_ = std::move(result_callback);
120 result_ = &result;
121 // TODO(pkotwicz): Exit message loop when the dialog is closed by some other
122 // means than |Cancel| or |Accept|. crbug.com/404385
123 base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
124 base::MessageLoopForUI::ScopedNestableTaskAllower allow_nested(loop);
125 base::RunLoop run_loop;
126 quit_runloop_ = run_loop.QuitClosure();
127 run_loop.Run();
128 g_current_message_box = nullptr;
129 return result;
130 } 124 }
131 125
132 int SimpleMessageBoxViews::GetDialogButtons() const { 126 int SimpleMessageBoxViews::GetDialogButtons() const {
133 if (type_ == MESSAGE_BOX_TYPE_QUESTION) 127 if (type_ == MESSAGE_BOX_TYPE_QUESTION)
134 return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL; 128 return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
135 129
136 return ui::DIALOG_BUTTON_OK; 130 return ui::DIALOG_BUTTON_OK;
137 } 131 }
138 132
139 base::string16 SimpleMessageBoxViews::GetDialogButtonLabel( 133 base::string16 SimpleMessageBoxViews::GetDialogButtonLabel(
140 ui::DialogButton button) const { 134 ui::DialogButton button) const {
141 if (button == ui::DIALOG_BUTTON_CANCEL) 135 if (button == ui::DIALOG_BUTTON_CANCEL)
142 return no_text_; 136 return no_text_;
143 return yes_text_; 137 return yes_text_;
144 } 138 }
145 139
146 bool SimpleMessageBoxViews::Cancel() { 140 bool SimpleMessageBoxViews::Cancel() {
147 *result_ = MESSAGE_BOX_RESULT_NO; 141 result_ = MESSAGE_BOX_RESULT_NO;
148 Done(); 142 Done();
149 return true; 143 return true;
150 } 144 }
151 145
152 bool SimpleMessageBoxViews::Accept() { 146 bool SimpleMessageBoxViews::Accept() {
153 if (!message_box_view_->HasCheckBox() || 147 if (!message_box_view_->HasCheckBox() ||
154 message_box_view_->IsCheckBoxSelected()) { 148 message_box_view_->IsCheckBoxSelected()) {
155 *result_ = MESSAGE_BOX_RESULT_YES; 149 result_ = MESSAGE_BOX_RESULT_YES;
156 } else { 150 } else {
157 *result_ = MESSAGE_BOX_RESULT_NO; 151 result_ = MESSAGE_BOX_RESULT_NO;
158 } 152 }
159 153
160 Done(); 154 Done();
161 return true; 155 return true;
162 } 156 }
163 157
164 base::string16 SimpleMessageBoxViews::GetWindowTitle() const { 158 base::string16 SimpleMessageBoxViews::GetWindowTitle() const {
165 return window_title_; 159 return window_title_;
166 } 160 }
167 161
(...skipping 14 matching lines...) Expand all
182 } 176 }
183 177
184 const views::Widget* SimpleMessageBoxViews::GetWidget() const { 178 const views::Widget* SimpleMessageBoxViews::GetWidget() const {
185 return message_box_view_->GetWidget(); 179 return message_box_view_->GetWidget();
186 } 180 }
187 181
188 //////////////////////////////////////////////////////////////////////////////// 182 ////////////////////////////////////////////////////////////////////////////////
189 // SimpleMessageBoxViews, private: 183 // SimpleMessageBoxViews, private:
190 184
191 void SimpleMessageBoxViews::Done() { 185 void SimpleMessageBoxViews::Done() {
192 CHECK(!quit_runloop_.is_null()); 186 CHECK(!result_callback_.is_null());
193 quit_runloop_.Run(); 187 std::move(result_callback_).Run(result_);
188 g_current_message_box = nullptr;
194 } 189 }
195 190
196 #if defined(OS_WIN) 191 #if defined(OS_WIN)
197 UINT GetMessageBoxFlagsFromType(MessageBoxType type) { 192 UINT GetMessageBoxFlagsFromType(MessageBoxType type) {
198 UINT flags = MB_SETFOREGROUND; 193 UINT flags = MB_SETFOREGROUND;
199 switch (type) { 194 switch (type) {
200 case MESSAGE_BOX_TYPE_WARNING: 195 case MESSAGE_BOX_TYPE_WARNING:
201 return flags | MB_OK | MB_ICONWARNING; 196 return flags | MB_OK | MB_ICONWARNING;
202 case MESSAGE_BOX_TYPE_QUESTION: 197 case MESSAGE_BOX_TYPE_QUESTION:
203 return flags | MB_YESNO | MB_ICONQUESTION; 198 return flags | MB_YESNO | MB_ICONQUESTION;
204 } 199 }
205 NOTREACHED(); 200 NOTREACHED();
206 return flags | MB_OK | MB_ICONWARNING; 201 return flags | MB_OK | MB_ICONWARNING;
207 } 202 }
208 #endif 203 #endif
209 204
210 MessageBoxResult ShowMessageBoxImpl(gfx::NativeWindow parent, 205 void ShowMessageBoxAsyncImpl(
211 const base::string16& title, 206 gfx::NativeWindow parent,
212 const base::string16& message, 207 const base::string16& title,
213 MessageBoxType type, 208 const base::string16& message,
214 const base::string16& yes_text, 209 MessageBoxType type,
215 const base::string16& no_text, 210 const base::string16& yes_text,
216 const base::string16& checkbox_text) { 211 const base::string16& no_text,
212 const base::string16& checkbox_text,
213 SimpleMessageBoxViews::MessageBoxResultCallback callback) {
217 startup_metric_utils::SetNonBrowserUIDisplayed(); 214 startup_metric_utils::SetNonBrowserUIDisplayed();
218 if (internal::g_should_skip_message_box_for_test) 215 if (internal::g_should_skip_message_box_for_test) {
219 return MESSAGE_BOX_RESULT_YES; 216 std::move(callback).Run(MESSAGE_BOX_RESULT_YES);
217 return;
218 }
220 219
221 // Views dialogs cannot be shown outside the UI thread message loop or if the 220 // Views dialogs cannot be shown outside the UI thread message loop or if the
222 // ResourceBundle is not initialized yet. 221 // ResourceBundle is not initialized yet.
223 // Fallback to logging with a default response or a Windows MessageBox. 222 // Fallback to logging with a default response or a Windows MessageBox.
224 #if defined(OS_WIN) 223 #if defined(OS_WIN)
225 if (!base::MessageLoopForUI::IsCurrent() || 224 if (!base::MessageLoopForUI::IsCurrent() ||
226 !base::RunLoop::IsRunningOnCurrentThread() || 225 !base::RunLoop::IsRunningOnCurrentThread() ||
227 !ResourceBundle::HasSharedInstance()) { 226 !ResourceBundle::HasSharedInstance()) {
228 LOG_IF(ERROR, !checkbox_text.empty()) << "Dialog checkbox won't be shown"; 227 LOG_IF(ERROR, !checkbox_text.empty()) << "Dialog checkbox won't be shown";
229 int result = ui::MessageBox(views::HWNDForNativeWindow(parent), message, 228 int result = ui::MessageBox(views::HWNDForNativeWindow(parent), message,
230 title, GetMessageBoxFlagsFromType(type)); 229 title, GetMessageBoxFlagsFromType(type));
231 return (result == IDYES || result == IDOK) ? 230 std::move(callback).Run((result == IDYES || result == IDOK)
232 MESSAGE_BOX_RESULT_YES : MESSAGE_BOX_RESULT_NO; 231 ? MESSAGE_BOX_RESULT_YES
232 : MESSAGE_BOX_RESULT_NO);
233 return;
233 } 234 }
234 #else 235 #else
235 if (!base::MessageLoopForUI::IsCurrent() || 236 if (!base::MessageLoopForUI::IsCurrent() ||
236 !ResourceBundle::HasSharedInstance()) { 237 !ResourceBundle::HasSharedInstance()) {
237 LOG(ERROR) << "Unable to show a dialog outside the UI thread message loop: " 238 LOG(ERROR) << "Unable to show a dialog outside the UI thread message loop: "
238 << title << " - " << message; 239 << title << " - " << message;
239 return MESSAGE_BOX_RESULT_NO; 240 std::move(callback).Run(MESSAGE_BOX_RESULT_NO);
241 return;
240 } 242 }
241 #endif 243 #endif
242 244
243 SimpleMessageBoxViews* dialog = 245 SimpleMessageBoxViews* dialog =
244 new SimpleMessageBoxViews(title, message, type, yes_text, no_text, 246 new SimpleMessageBoxViews(title, message, type, yes_text, no_text,
245 checkbox_text, !parent /* is_system_modal */); 247 checkbox_text, !parent /* is_system_modal */);
246 constrained_window::CreateBrowserModalDialogViews(dialog, parent)->Show(); 248 constrained_window::CreateBrowserModalDialogViews(dialog, parent)->Show();
247 249
248 // NOTE: |dialog| may have been deleted by the time |RunDialogAndGetResult()| 250 dialog->Run(std::move(callback));
249 // returns. 251 }
250 return dialog->RunDialogAndGetResult(); 252
253 MessageBoxResult ShowMessageBoxImpl(gfx::NativeWindow parent,
254 const base::string16& title,
255 const base::string16& message,
256 MessageBoxType type,
257 const base::string16& yes_text,
258 const base::string16& no_text,
259 const base::string16& checkbox_text) {
260 MessageBoxResult result = MESSAGE_BOX_RESULT_NO;
261
262 // TODO(pkotwicz): Exit message loop when the dialog is closed by some other
263 // means than |Cancel| or |Accept|. crbug.com/404385
264 base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
265 base::MessageLoopForUI::ScopedNestableTaskAllower allow_nested(loop);
266 base::RunLoop run_loop;
267
268 ShowMessageBoxAsyncImpl(
269 parent, title, message, type, yes_text, no_text, checkbox_text,
270 base::Bind(
271 [](base::RunLoop* run_loop, MessageBoxResult* out_result,
272 MessageBoxResult messagebox_result) {
273 *out_result = messagebox_result;
274 run_loop->Quit();
275 },
276 &run_loop, &result));
277
278 run_loop.Run();
279 return result;
251 } 280 }
252 281
253 } // namespace 282 } // namespace
254 283
255 bool CloseMessageBoxForTest(bool accept) { 284 bool CloseMessageBoxForTest(bool accept) {
256 if (!g_current_message_box) 285 if (!g_current_message_box)
257 return false; 286 return false;
258 287
259 if (accept) 288 if (accept)
260 g_current_message_box->Accept(); 289 g_current_message_box->Accept();
261 else 290 else
262 g_current_message_box->Cancel(); 291 g_current_message_box->Cancel();
263 return true; 292 return true;
264 } 293 }
265 294
266 void ShowWarningMessageBox(gfx::NativeWindow parent, 295 void ShowWarningMessageBox(gfx::NativeWindow parent,
267 const base::string16& title, 296 const base::string16& title,
268 const base::string16& message) { 297 const base::string16& message) {
269 ShowMessageBoxImpl(parent, title, message, MESSAGE_BOX_TYPE_WARNING, 298 ShowMessageBoxImpl(parent, title, message, MESSAGE_BOX_TYPE_WARNING,
270 base::string16(), base::string16(), base::string16()); 299 base::string16(), base::string16(), base::string16());
271 } 300 }
272 301
273 bool ShowWarningMessageBoxWithCheckbox(gfx::NativeWindow parent, 302 void ShowWarningMessageBoxWithCheckbox(
274 const base::string16& title, 303 gfx::NativeWindow parent,
275 const base::string16& message, 304 const base::string16& title,
276 const base::string16& checkbox_text) { 305 const base::string16& message,
277 return ShowMessageBoxImpl(parent, title, message, MESSAGE_BOX_TYPE_WARNING, 306 const base::string16& checkbox_text,
278 base::string16(), base::string16(), 307 base::OnceCallback<void(bool checked)> callback) {
279 checkbox_text) == MESSAGE_BOX_RESULT_YES; 308 ShowMessageBoxAsyncImpl(
309 parent, title, message, MESSAGE_BOX_TYPE_WARNING, base::string16(),
310 base::string16(), checkbox_text,
311 base::Bind(
312 [](base::OnceCallback<void(bool checked)> callback,
313 MessageBoxResult message_box_result) {
314 std::move(callback).Run(message_box_result ==
315 MESSAGE_BOX_RESULT_YES);
316 },
317 base::Passed(std::move(callback))));
280 } 318 }
281 319
282 MessageBoxResult ShowQuestionMessageBox(gfx::NativeWindow parent, 320 MessageBoxResult ShowQuestionMessageBox(gfx::NativeWindow parent,
283 const base::string16& title, 321 const base::string16& title,
284 const base::string16& message) { 322 const base::string16& message) {
285 return ShowMessageBoxImpl(parent, title, message, MESSAGE_BOX_TYPE_QUESTION, 323 return ShowMessageBoxImpl(parent, title, message, MESSAGE_BOX_TYPE_QUESTION,
286 base::string16(), base::string16(), 324 base::string16(), base::string16(),
287 base::string16()); 325 base::string16());
288 } 326 }
289 327
290 MessageBoxResult ShowMessageBoxWithButtonText(gfx::NativeWindow parent, 328 MessageBoxResult ShowMessageBoxWithButtonText(gfx::NativeWindow parent,
291 const base::string16& title, 329 const base::string16& title,
292 const base::string16& message, 330 const base::string16& message,
293 const base::string16& yes_text, 331 const base::string16& yes_text,
294 const base::string16& no_text) { 332 const base::string16& no_text) {
295 return ShowMessageBoxImpl(parent, title, message, MESSAGE_BOX_TYPE_QUESTION, 333 return ShowMessageBoxImpl(parent, title, message, MESSAGE_BOX_TYPE_QUESTION,
296 yes_text, no_text, base::string16()); 334 yes_text, no_text, base::string16());
297 } 335 }
298 336
299 } // namespace chrome 337 } // namespace chrome
OLDNEW
« chrome/browser/ui/simple_message_box.h ('K') | « chrome/browser/ui/simple_message_box.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698