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/aura/client/dispatcher_client.h"
17 #include "ui/aura/env.h"
18 #include "ui/aura/root_window.h"
19 #include "ui/base/l10n/l10n_util.h"
20 #include "ui/gfx/native_widget_types.h"
21 #include "ui/views/controls/message_box_view.h"
22 #include "ui/views/widget/widget.h"
23 #include "ui/views/window/dialog_delegate.h"
26 #include "chrome/browser/ui/views/simple_message_box_win.h"
33 // Multiple SimpleMessageBoxViews can show up at the same time. Each of these
34 // start a nested message-loop. However, these SimpleMessageBoxViews can be
35 // deleted in any order. This creates problems if a box in an inner-loop gets
36 // destroyed before a box in an outer-loop. So to avoid this, ref-counting is
37 // used so that the SimpleMessageBoxViews gets deleted at the right time.
38 class SimpleMessageBoxViews
: public views::DialogDelegate
,
39 public base::MessagePumpDispatcher
,
40 public base::RefCounted
<SimpleMessageBoxViews
> {
42 SimpleMessageBoxViews(const base::string16
& title
,
43 const base::string16
& message
,
45 const base::string16
& yes_text
,
46 const base::string16
& no_text
);
48 MessageBoxResult
result() const { return result_
; }
50 // Overridden from views::DialogDelegate:
51 virtual int GetDialogButtons() const OVERRIDE
;
52 virtual base::string16
GetDialogButtonLabel(
53 ui::DialogButton button
) const OVERRIDE
;
54 virtual bool Cancel() OVERRIDE
;
55 virtual bool Accept() OVERRIDE
;
57 // Overridden from views::WidgetDelegate:
58 virtual base::string16
GetWindowTitle() const OVERRIDE
;
59 virtual void DeleteDelegate() OVERRIDE
;
60 virtual ui::ModalType
GetModalType() const OVERRIDE
;
61 virtual views::View
* GetContentsView() OVERRIDE
;
62 virtual views::Widget
* GetWidget() OVERRIDE
;
63 virtual const views::Widget
* GetWidget() const OVERRIDE
;
65 // Overridden from MessagePumpDispatcher:
66 virtual uint32_t Dispatch(const base::NativeEvent
& event
) OVERRIDE
;
69 friend class base::RefCounted
<SimpleMessageBoxViews
>;
70 virtual ~SimpleMessageBoxViews();
72 const base::string16 window_title_
;
73 const MessageBoxType type_
;
74 base::string16 yes_text_
;
75 base::string16 no_text_
;
76 MessageBoxResult result_
;
77 views::MessageBoxView
* message_box_view_
;
79 // Set to false as soon as the user clicks a dialog button; this tells the
80 // dispatcher we're done.
81 bool should_show_dialog_
;
83 DISALLOW_COPY_AND_ASSIGN(SimpleMessageBoxViews
);
86 ////////////////////////////////////////////////////////////////////////////////
87 // SimpleMessageBoxViews, public:
89 SimpleMessageBoxViews::SimpleMessageBoxViews(const base::string16
& title
,
90 const base::string16
& message
,
92 const base::string16
& yes_text
,
93 const base::string16
& no_text
)
94 : window_title_(title
),
98 result_(MESSAGE_BOX_RESULT_NO
),
99 message_box_view_(new views::MessageBoxView(
100 views::MessageBoxView::InitParams(message
))),
101 should_show_dialog_(true) {
104 if (yes_text_
.empty()) {
105 if (type_
== MESSAGE_BOX_TYPE_QUESTION
)
107 l10n_util::GetStringUTF16(IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL
);
108 else if (type_
== MESSAGE_BOX_TYPE_OK_CANCEL
)
109 yes_text_
= l10n_util::GetStringUTF16(IDS_OK
);
111 yes_text_
= l10n_util::GetStringUTF16(IDS_OK
);
114 if (no_text_
.empty()) {
115 if (type_
== MESSAGE_BOX_TYPE_QUESTION
)
117 l10n_util::GetStringUTF16(IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL
);
118 else if (type_
== MESSAGE_BOX_TYPE_OK_CANCEL
)
119 no_text_
= l10n_util::GetStringUTF16(IDS_CANCEL
);
123 int SimpleMessageBoxViews::GetDialogButtons() const {
124 if (type_
== MESSAGE_BOX_TYPE_QUESTION
||
125 type_
== MESSAGE_BOX_TYPE_OK_CANCEL
) {
126 return ui::DIALOG_BUTTON_OK
| ui::DIALOG_BUTTON_CANCEL
;
129 return ui::DIALOG_BUTTON_OK
;
132 base::string16
SimpleMessageBoxViews::GetDialogButtonLabel(
133 ui::DialogButton button
) const {
134 if (button
== ui::DIALOG_BUTTON_CANCEL
)
139 bool SimpleMessageBoxViews::Cancel() {
140 should_show_dialog_
= false;
141 result_
= MESSAGE_BOX_RESULT_NO
;
145 bool SimpleMessageBoxViews::Accept() {
146 should_show_dialog_
= false;
147 result_
= MESSAGE_BOX_RESULT_YES
;
151 base::string16
SimpleMessageBoxViews::GetWindowTitle() const {
152 return window_title_
;
155 void SimpleMessageBoxViews::DeleteDelegate() {
159 ui::ModalType
SimpleMessageBoxViews::GetModalType() const {
160 return ui::MODAL_TYPE_WINDOW
;
163 views::View
* SimpleMessageBoxViews::GetContentsView() {
164 return message_box_view_
;
167 views::Widget
* SimpleMessageBoxViews::GetWidget() {
168 return message_box_view_
->GetWidget();
171 const views::Widget
* SimpleMessageBoxViews::GetWidget() const {
172 return message_box_view_
->GetWidget();
175 uint32_t SimpleMessageBoxViews::Dispatch(const base::NativeEvent
& event
) {
176 uint32_t action
= POST_DISPATCH_PERFORM_DEFAULT
;
177 if (!should_show_dialog_
)
178 action
|= POST_DISPATCH_QUIT_LOOP
;
182 ////////////////////////////////////////////////////////////////////////////////
183 // SimpleMessageBoxViews, private:
185 SimpleMessageBoxViews::~SimpleMessageBoxViews() {
188 MessageBoxResult
ShowMessageBoxImpl(gfx::NativeWindow parent
,
189 const base::string16
& title
,
190 const base::string16
& message
,
192 const base::string16
& yes_text
,
193 const base::string16
& no_text
) {
196 // If we're very early, we can't show a GPU-based dialog, so fallback to
197 // plain Windows MessageBox.
198 if (!ui::ContextFactory::GetInstance())
199 return NativeShowMessageBox(NULL
, title
, message
, type
);
202 scoped_refptr
<SimpleMessageBoxViews
> dialog(
203 new SimpleMessageBoxViews(title
, message
, type
, yes_text
, no_text
));
204 CreateBrowserModalDialogViews(dialog
.get(), parent
)->Show();
206 aura::Window
* anchor
= parent
;
207 aura::client::DispatcherClient
* client
= anchor
?
208 aura::client::GetDispatcherClient(anchor
->GetRootWindow()) : NULL
;
210 // Use the widget's window itself so that the message loop
211 // exists when the dialog is closed by some other means than
212 // |Cancel| or |Accept|.
213 anchor
= dialog
->GetWidget()->GetNativeWindow();
214 client
= aura::client::GetDispatcherClient(anchor
->GetRootWindow());
216 client
->RunWithDispatcher(dialog
.get(), anchor
);
217 return dialog
->result();
222 MessageBoxResult
ShowMessageBox(gfx::NativeWindow parent
,
223 const base::string16
& title
,
224 const base::string16
& message
,
225 MessageBoxType type
) {
226 return ShowMessageBoxImpl(
227 parent
, title
, message
, type
, base::string16(), base::string16());
230 MessageBoxResult
ShowMessageBoxWithButtonText(gfx::NativeWindow parent
,
231 const base::string16
& title
,
232 const base::string16
& message
,
233 const base::string16
& yes_text
,
234 const base::string16
& no_text
) {
235 return ShowMessageBoxImpl(
236 parent
, title
, message
, MESSAGE_BOX_TYPE_QUESTION
, yes_text
, no_text
);
239 } // namespace chrome