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/memory/ref_counted.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/message_loop/message_pump_dispatcher.h"
12 #include "base/run_loop.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/ui/views/constrained_window_views.h"
15 #include "grit/generated_resources.h"
16 #include "ui/base/l10n/l10n_util.h"
17 #include "ui/gfx/native_widget_types.h"
18 #include "ui/views/controls/message_box_view.h"
19 #include "ui/views/widget/widget.h"
20 #include "ui/views/window/dialog_delegate.h"
23 #include "ui/aura/client/dispatcher_client.h"
24 #include "ui/aura/env.h"
25 #include "ui/aura/root_window.h"
27 #include "chrome/browser/ui/views/simple_message_box_win.h"
35 // Multiple SimpleMessageBoxViews can show up at the same time. Each of these
36 // start a nested message-loop. However, these SimpleMessageBoxViews can be
37 // deleted in any order. This creates problems if a box in an inner-loop gets
38 // destroyed before a box in an outer-loop. So to avoid this, ref-counting is
39 // used so that the SimpleMessageBoxViews gets deleted at the right time.
40 class SimpleMessageBoxViews
: public views::DialogDelegate
,
41 public base::MessagePumpDispatcher
,
42 public base::RefCounted
<SimpleMessageBoxViews
> {
44 SimpleMessageBoxViews(const base::string16
& title
,
45 const base::string16
& message
,
47 const base::string16
& yes_text
,
48 const base::string16
& no_text
);
50 MessageBoxResult
result() const { return result_
; }
52 // Overridden from views::DialogDelegate:
53 virtual int GetDialogButtons() const OVERRIDE
;
54 virtual base::string16
GetDialogButtonLabel(
55 ui::DialogButton button
) const OVERRIDE
;
56 virtual bool Cancel() OVERRIDE
;
57 virtual bool Accept() OVERRIDE
;
59 // Overridden from views::WidgetDelegate:
60 virtual base::string16
GetWindowTitle() const OVERRIDE
;
61 virtual void DeleteDelegate() OVERRIDE
;
62 virtual ui::ModalType
GetModalType() const OVERRIDE
;
63 virtual views::View
* GetContentsView() OVERRIDE
;
64 virtual views::Widget
* GetWidget() OVERRIDE
;
65 virtual const views::Widget
* GetWidget() const OVERRIDE
;
67 // Overridden from MessagePumpDispatcher:
68 virtual bool Dispatch(const base::NativeEvent
& event
) OVERRIDE
;
71 friend class base::RefCounted
<SimpleMessageBoxViews
>;
72 virtual ~SimpleMessageBoxViews();
74 const base::string16 window_title_
;
75 const MessageBoxType type_
;
76 base::string16 yes_text_
;
77 base::string16 no_text_
;
78 MessageBoxResult result_
;
79 views::MessageBoxView
* message_box_view_
;
81 // Set to false as soon as the user clicks a dialog button; this tells the
82 // dispatcher we're done.
83 bool should_show_dialog_
;
85 DISALLOW_COPY_AND_ASSIGN(SimpleMessageBoxViews
);
88 ////////////////////////////////////////////////////////////////////////////////
89 // SimpleMessageBoxViews, public:
91 SimpleMessageBoxViews::SimpleMessageBoxViews(const base::string16
& title
,
92 const base::string16
& message
,
94 const base::string16
& yes_text
,
95 const base::string16
& no_text
)
96 : window_title_(title
),
100 result_(MESSAGE_BOX_RESULT_NO
),
101 message_box_view_(new views::MessageBoxView(
102 views::MessageBoxView::InitParams(message
))),
103 should_show_dialog_(true) {
106 if (yes_text_
.empty()) {
107 if (type_
== MESSAGE_BOX_TYPE_QUESTION
)
109 l10n_util::GetStringUTF16(IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL
);
110 else if (type_
== MESSAGE_BOX_TYPE_OK_CANCEL
)
111 yes_text_
= l10n_util::GetStringUTF16(IDS_OK
);
113 yes_text_
= l10n_util::GetStringUTF16(IDS_OK
);
116 if (no_text_
.empty()) {
117 if (type_
== MESSAGE_BOX_TYPE_QUESTION
)
119 l10n_util::GetStringUTF16(IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL
);
120 else if (type_
== MESSAGE_BOX_TYPE_OK_CANCEL
)
121 no_text_
= l10n_util::GetStringUTF16(IDS_CANCEL
);
125 int SimpleMessageBoxViews::GetDialogButtons() const {
126 if (type_
== MESSAGE_BOX_TYPE_QUESTION
||
127 type_
== MESSAGE_BOX_TYPE_OK_CANCEL
) {
128 return ui::DIALOG_BUTTON_OK
| ui::DIALOG_BUTTON_CANCEL
;
131 return ui::DIALOG_BUTTON_OK
;
134 base::string16
SimpleMessageBoxViews::GetDialogButtonLabel(
135 ui::DialogButton button
) const {
136 if (button
== ui::DIALOG_BUTTON_CANCEL
)
141 bool SimpleMessageBoxViews::Cancel() {
142 should_show_dialog_
= false;
143 result_
= MESSAGE_BOX_RESULT_NO
;
147 bool SimpleMessageBoxViews::Accept() {
148 should_show_dialog_
= false;
149 result_
= MESSAGE_BOX_RESULT_YES
;
153 base::string16
SimpleMessageBoxViews::GetWindowTitle() const {
154 return window_title_
;
157 void SimpleMessageBoxViews::DeleteDelegate() {
161 ui::ModalType
SimpleMessageBoxViews::GetModalType() const {
162 return ui::MODAL_TYPE_WINDOW
;
165 views::View
* SimpleMessageBoxViews::GetContentsView() {
166 return message_box_view_
;
169 views::Widget
* SimpleMessageBoxViews::GetWidget() {
170 return message_box_view_
->GetWidget();
173 const views::Widget
* SimpleMessageBoxViews::GetWidget() const {
174 return message_box_view_
->GetWidget();
177 bool SimpleMessageBoxViews::Dispatch(const base::NativeEvent
& event
) {
179 TranslateMessage(&event
);
180 DispatchMessage(&event
);
181 #elif defined(USE_AURA)
182 aura::Env::GetInstance()->GetDispatcher()->Dispatch(event
);
184 return should_show_dialog_
;
187 ////////////////////////////////////////////////////////////////////////////////
188 // SimpleMessageBoxViews, private:
190 SimpleMessageBoxViews::~SimpleMessageBoxViews() {
193 MessageBoxResult
ShowMessageBoxImpl(gfx::NativeWindow parent
,
194 const base::string16
& title
,
195 const base::string16
& message
,
197 const base::string16
& yes_text
,
198 const base::string16
& no_text
) {
200 #if defined(USE_AURA) && defined(OS_WIN)
201 // If we're very early, we can't show a GPU-based dialog, so fallback to
202 // plain Windows MessageBox.
203 if (!ui::ContextFactory::GetInstance())
204 return NativeShowMessageBox(NULL
, title
, message
, type
);
207 scoped_refptr
<SimpleMessageBoxViews
> dialog(
208 new SimpleMessageBoxViews(title
, message
, type
, yes_text
, no_text
));
209 CreateBrowserModalDialogViews(dialog
.get(), parent
)->Show();
211 #if defined(USE_AURA)
212 aura::Window
* anchor
= parent
;
213 aura::client::DispatcherClient
* client
= anchor
?
214 aura::client::GetDispatcherClient(anchor
->GetRootWindow()) : NULL
;
216 // Use the widget's window itself so that the message loop
217 // exists when the dialog is closed by some other means than
218 // |Cancel| or |Accept|.
219 anchor
= dialog
->GetWidget()->GetNativeWindow();
220 client
= aura::client::GetDispatcherClient(anchor
->GetRootWindow());
222 client
->RunWithDispatcher(dialog
.get(), anchor
, true);
225 base::MessageLoop::ScopedNestableTaskAllower
allow(
226 base::MessageLoopForUI::current());
227 base::RunLoop
run_loop(dialog
);
231 return dialog
->result();
236 MessageBoxResult
ShowMessageBox(gfx::NativeWindow parent
,
237 const base::string16
& title
,
238 const base::string16
& message
,
239 MessageBoxType type
) {
240 return ShowMessageBoxImpl(
241 parent
, title
, message
, type
, base::string16(), base::string16());
244 #if defined(USE_AURA)
245 MessageBoxResult
ShowMessageBoxWithButtonText(gfx::NativeWindow parent
,
246 const base::string16
& title
,
247 const base::string16
& message
,
248 const base::string16
& yes_text
,
249 const base::string16
& no_text
) {
250 return ShowMessageBoxImpl(
251 parent
, title
, message
, MESSAGE_BOX_TYPE_QUESTION
, yes_text
, no_text
);
255 } // namespace chrome