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
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/simple_message_box.h"
7 #include "base/basictypes.h"
8 #include "base/compiler_specific.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/run_loop.h"
11 #include "chrome/grit/generated_resources.h"
12 #include "components/constrained_window/constrained_window_views.h"
13 #include "ui/base/l10n/l10n_util.h"
14 #include "ui/base/resource/resource_bundle.h"
15 #include "ui/gfx/native_widget_types.h"
16 #include "ui/views/controls/message_box_view.h"
17 #include "ui/views/widget/widget.h"
18 #include "ui/views/window/dialog_delegate.h"
21 #include "ui/base/win/message_box_win.h"
22 #include "ui/views/win/hwnd_util.h"
29 class SimpleMessageBoxViews
: public views::DialogDelegate
{
31 SimpleMessageBoxViews(const base::string16
& title
,
32 const base::string16
& message
,
34 const base::string16
& yes_text
,
35 const base::string16
& no_text
,
36 bool is_system_modal
);
37 ~SimpleMessageBoxViews() override
;
39 MessageBoxResult
RunDialogAndGetResult();
41 // Overridden from views::DialogDelegate:
42 int GetDialogButtons() const override
;
43 base::string16
GetDialogButtonLabel(ui::DialogButton button
) const override
;
44 bool Cancel() override
;
45 bool Accept() override
;
47 // Overridden from views::WidgetDelegate:
48 base::string16
GetWindowTitle() const override
;
49 void DeleteDelegate() override
;
50 ui::ModalType
GetModalType() const override
;
51 views::View
* GetContentsView() override
;
52 views::Widget
* GetWidget() override
;
53 const views::Widget
* GetWidget() const override
;
57 // This terminates the nested message-loop.
60 const base::string16 window_title_
;
61 const MessageBoxType type_
;
62 base::string16 yes_text_
;
63 base::string16 no_text_
;
64 MessageBoxResult
* result_
;
65 bool is_system_modal_
;
66 views::MessageBoxView
* message_box_view_
;
67 base::Closure quit_runloop_
;
69 DISALLOW_COPY_AND_ASSIGN(SimpleMessageBoxViews
);
72 ////////////////////////////////////////////////////////////////////////////////
73 // SimpleMessageBoxViews, public:
75 SimpleMessageBoxViews::SimpleMessageBoxViews(const base::string16
& title
,
76 const base::string16
& message
,
78 const base::string16
& yes_text
,
79 const base::string16
& no_text
,
81 : window_title_(title
),
86 is_system_modal_(is_system_modal
),
87 message_box_view_(new views::MessageBoxView(
88 views::MessageBoxView::InitParams(message
))) {
89 if (yes_text_
.empty()) {
90 if (type_
== MESSAGE_BOX_TYPE_QUESTION
)
92 l10n_util::GetStringUTF16(IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL
);
93 else if (type_
== MESSAGE_BOX_TYPE_OK_CANCEL
)
94 yes_text_
= l10n_util::GetStringUTF16(IDS_OK
);
96 yes_text_
= l10n_util::GetStringUTF16(IDS_OK
);
99 if (no_text_
.empty()) {
100 if (type_
== MESSAGE_BOX_TYPE_QUESTION
)
102 l10n_util::GetStringUTF16(IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL
);
103 else if (type_
== MESSAGE_BOX_TYPE_OK_CANCEL
)
104 no_text_
= l10n_util::GetStringUTF16(IDS_CANCEL
);
108 SimpleMessageBoxViews::~SimpleMessageBoxViews() {
111 MessageBoxResult
SimpleMessageBoxViews::RunDialogAndGetResult() {
112 MessageBoxResult result
= MESSAGE_BOX_RESULT_NO
;
114 // TODO(pkotwicz): Exit message loop when the dialog is closed by some other
115 // means than |Cancel| or |Accept|. crbug.com/404385
116 base::MessageLoopForUI
* loop
= base::MessageLoopForUI::current();
117 base::MessageLoopForUI::ScopedNestableTaskAllower
allow_nested(loop
);
118 base::RunLoop run_loop
;
119 quit_runloop_
= run_loop
.QuitClosure();
124 int SimpleMessageBoxViews::GetDialogButtons() const {
125 if (type_
== MESSAGE_BOX_TYPE_QUESTION
||
126 type_
== MESSAGE_BOX_TYPE_OK_CANCEL
) {
127 return ui::DIALOG_BUTTON_OK
| ui::DIALOG_BUTTON_CANCEL
;
130 return ui::DIALOG_BUTTON_OK
;
133 base::string16
SimpleMessageBoxViews::GetDialogButtonLabel(
134 ui::DialogButton button
) const {
135 if (button
== ui::DIALOG_BUTTON_CANCEL
)
140 bool SimpleMessageBoxViews::Cancel() {
141 *result_
= MESSAGE_BOX_RESULT_NO
;
146 bool SimpleMessageBoxViews::Accept() {
147 *result_
= MESSAGE_BOX_RESULT_YES
;
152 base::string16
SimpleMessageBoxViews::GetWindowTitle() const {
153 return window_title_
;
156 void SimpleMessageBoxViews::DeleteDelegate() {
160 ui::ModalType
SimpleMessageBoxViews::GetModalType() const {
161 return is_system_modal_
? ui::MODAL_TYPE_SYSTEM
: ui::MODAL_TYPE_WINDOW
;
164 views::View
* SimpleMessageBoxViews::GetContentsView() {
165 return message_box_view_
;
168 views::Widget
* SimpleMessageBoxViews::GetWidget() {
169 return message_box_view_
->GetWidget();
172 const views::Widget
* SimpleMessageBoxViews::GetWidget() const {
173 return message_box_view_
->GetWidget();
176 ////////////////////////////////////////////////////////////////////////////////
177 // SimpleMessageBoxViews, private:
179 void SimpleMessageBoxViews::Done() {
180 CHECK(!quit_runloop_
.is_null());
185 UINT
GetMessageBoxFlagsFromType(MessageBoxType type
) {
186 UINT flags
= MB_SETFOREGROUND
;
188 case MESSAGE_BOX_TYPE_INFORMATION
:
189 return flags
| MB_OK
| MB_ICONINFORMATION
;
190 case MESSAGE_BOX_TYPE_WARNING
:
191 return flags
| MB_OK
| MB_ICONWARNING
;
192 case MESSAGE_BOX_TYPE_QUESTION
:
193 return flags
| MB_YESNO
| MB_ICONQUESTION
;
194 case MESSAGE_BOX_TYPE_OK_CANCEL
:
195 return flags
| MB_OKCANCEL
| MB_ICONWARNING
;
198 return flags
| MB_OK
| MB_ICONWARNING
;
202 MessageBoxResult
ShowMessageBoxImpl(gfx::NativeWindow parent
,
203 const base::string16
& title
,
204 const base::string16
& message
,
206 const base::string16
& yes_text
,
207 const base::string16
& no_text
) {
208 // Views dialogs cannot be shown outside the UI thread message loop or if the
209 // ResourceBundle is not initialized yet.
210 // Fallback to logging with a default response or a Windows MessageBox.
212 if (!base::MessageLoopForUI::IsCurrent() ||
213 !base::MessageLoopForUI::current()->is_running() ||
214 !ResourceBundle::HasSharedInstance()) {
215 int result
= ui::MessageBox(views::HWNDForNativeWindow(parent
), message
,
216 title
, GetMessageBoxFlagsFromType(type
));
217 return (result
== IDYES
|| result
== IDOK
) ?
218 MESSAGE_BOX_RESULT_YES
: MESSAGE_BOX_RESULT_NO
;
221 if (!base::MessageLoopForUI::IsCurrent() ||
222 !ResourceBundle::HasSharedInstance()) {
223 LOG(ERROR
) << "Unable to show a dialog outside the UI thread message loop: "
224 << title
<< " - " << message
;
225 return MESSAGE_BOX_RESULT_NO
;
229 SimpleMessageBoxViews
* dialog
=
230 new SimpleMessageBoxViews(title
,
235 parent
== NULL
// is_system_modal
237 constrained_window::CreateBrowserModalDialogViews(dialog
, parent
)->Show();
239 // NOTE: |dialog| may have been deleted by the time |RunDialogAndGetResult()|
241 return dialog
->RunDialogAndGetResult();
246 MessageBoxResult
ShowMessageBox(gfx::NativeWindow parent
,
247 const base::string16
& title
,
248 const base::string16
& message
,
249 MessageBoxType type
) {
250 return ShowMessageBoxImpl(
251 parent
, title
, message
, type
, base::string16(), base::string16());
254 MessageBoxResult
ShowMessageBoxWithButtonText(gfx::NativeWindow parent
,
255 const base::string16
& title
,
256 const base::string16
& message
,
257 const base::string16
& yes_text
,
258 const base::string16
& no_text
) {
259 return ShowMessageBoxImpl(
260 parent
, title
, message
, MESSAGE_BOX_TYPE_QUESTION
, yes_text
, no_text
);
263 } // namespace chrome