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

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

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