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/browser/ui/views/constrained_window_views.h"
12 #include "chrome/grit/generated_resources.h"
13 #include "ui/aura/window.h"
14 #include "ui/base/l10n/l10n_util.h"
15 #include "ui/base/resource/resource_bundle.h"
16 #include "ui/gfx/native_widget_types.h"
17 #include "ui/views/controls/message_box_view.h"
18 #include "ui/views/widget/widget.h"
19 #include "ui/views/window/dialog_delegate.h"
22 #include "ui/base/win/message_box_win.h"
23 #include "ui/views/win/hwnd_util.h"
30 class SimpleMessageBoxViews : public views::DialogDelegate {
32 SimpleMessageBoxViews(const base::string16& title,
33 const base::string16& message,
35 const base::string16& yes_text,
36 const base::string16& no_text,
37 bool is_system_modal);
38 virtual ~SimpleMessageBoxViews();
40 MessageBoxResult RunDialogAndGetResult();
42 // Overridden from views::DialogDelegate:
43 virtual int GetDialogButtons() const OVERRIDE;
44 virtual base::string16 GetDialogButtonLabel(
45 ui::DialogButton button) const OVERRIDE;
46 virtual bool Cancel() OVERRIDE;
47 virtual bool Accept() OVERRIDE;
49 // Overridden from views::WidgetDelegate:
50 virtual base::string16 GetWindowTitle() const OVERRIDE;
51 virtual void DeleteDelegate() OVERRIDE;
52 virtual ui::ModalType GetModalType() const OVERRIDE;
53 virtual views::View* GetContentsView() OVERRIDE;
54 virtual views::Widget* GetWidget() OVERRIDE;
55 virtual const views::Widget* GetWidget() const OVERRIDE;
59 // This terminates the nested message-loop.
62 const base::string16 window_title_;
63 const MessageBoxType type_;
64 base::string16 yes_text_;
65 base::string16 no_text_;
66 MessageBoxResult* result_;
67 bool is_system_modal_;
68 views::MessageBoxView* message_box_view_;
69 base::Closure quit_runloop_;
71 DISALLOW_COPY_AND_ASSIGN(SimpleMessageBoxViews);
74 ////////////////////////////////////////////////////////////////////////////////
75 // SimpleMessageBoxViews, public:
77 SimpleMessageBoxViews::SimpleMessageBoxViews(const base::string16& title,
78 const base::string16& message,
80 const base::string16& yes_text,
81 const base::string16& no_text,
83 : window_title_(title),
88 is_system_modal_(is_system_modal),
89 message_box_view_(new views::MessageBoxView(
90 views::MessageBoxView::InitParams(message))) {
91 if (yes_text_.empty()) {
92 if (type_ == MESSAGE_BOX_TYPE_QUESTION)
94 l10n_util::GetStringUTF16(IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL);
95 else if (type_ == MESSAGE_BOX_TYPE_OK_CANCEL)
96 yes_text_ = l10n_util::GetStringUTF16(IDS_OK);
98 yes_text_ = l10n_util::GetStringUTF16(IDS_OK);
101 if (no_text_.empty()) {
102 if (type_ == MESSAGE_BOX_TYPE_QUESTION)
104 l10n_util::GetStringUTF16(IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL);
105 else if (type_ == MESSAGE_BOX_TYPE_OK_CANCEL)
106 no_text_ = l10n_util::GetStringUTF16(IDS_CANCEL);
110 SimpleMessageBoxViews::~SimpleMessageBoxViews() {
113 MessageBoxResult SimpleMessageBoxViews::RunDialogAndGetResult() {
114 MessageBoxResult result = MESSAGE_BOX_RESULT_NO;
116 // TODO(pkotwicz): Exit message loop when the dialog is closed by some other
117 // means than |Cancel| or |Accept|. crbug.com/404385
118 base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
119 base::MessageLoopForUI::ScopedNestableTaskAllower allow_nested(loop);
120 base::RunLoop run_loop;
121 quit_runloop_ = run_loop.QuitClosure();
126 int SimpleMessageBoxViews::GetDialogButtons() const {
127 if (type_ == MESSAGE_BOX_TYPE_QUESTION ||
128 type_ == MESSAGE_BOX_TYPE_OK_CANCEL) {
129 return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
132 return ui::DIALOG_BUTTON_OK;
135 base::string16 SimpleMessageBoxViews::GetDialogButtonLabel(
136 ui::DialogButton button) const {
137 if (button == ui::DIALOG_BUTTON_CANCEL)
142 bool SimpleMessageBoxViews::Cancel() {
143 *result_ = MESSAGE_BOX_RESULT_NO;
148 bool SimpleMessageBoxViews::Accept() {
149 *result_ = MESSAGE_BOX_RESULT_YES;
154 base::string16 SimpleMessageBoxViews::GetWindowTitle() const {
155 return window_title_;
158 void SimpleMessageBoxViews::DeleteDelegate() {
162 ui::ModalType SimpleMessageBoxViews::GetModalType() const {
163 return is_system_modal_ ? ui::MODAL_TYPE_SYSTEM : ui::MODAL_TYPE_WINDOW;
166 views::View* SimpleMessageBoxViews::GetContentsView() {
167 return message_box_view_;
170 views::Widget* SimpleMessageBoxViews::GetWidget() {
171 return message_box_view_->GetWidget();
174 const views::Widget* SimpleMessageBoxViews::GetWidget() const {
175 return message_box_view_->GetWidget();
178 ////////////////////////////////////////////////////////////////////////////////
179 // SimpleMessageBoxViews, private:
181 void SimpleMessageBoxViews::Done() {
182 CHECK(!quit_runloop_.is_null());
187 UINT GetMessageBoxFlagsFromType(MessageBoxType type) {
188 UINT flags = MB_SETFOREGROUND;
190 case MESSAGE_BOX_TYPE_INFORMATION:
191 return flags | MB_OK | MB_ICONINFORMATION;
192 case MESSAGE_BOX_TYPE_WARNING:
193 return flags | MB_OK | MB_ICONWARNING;
194 case MESSAGE_BOX_TYPE_QUESTION:
195 return flags | MB_YESNO | MB_ICONQUESTION;
196 case MESSAGE_BOX_TYPE_OK_CANCEL:
197 return flags | MB_OKCANCEL | MB_ICONWARNING;
200 return flags | MB_OK | MB_ICONWARNING;
204 MessageBoxResult ShowMessageBoxImpl(gfx::NativeWindow parent,
205 const base::string16& title,
206 const base::string16& message,
208 const base::string16& yes_text,
209 const base::string16& no_text) {
210 // Views dialogs cannot be shown outside the UI thread message loop or if the
211 // ResourceBundle is not initialized yet.
212 // Fallback to logging with a default response or a Windows MessageBox.
214 if (!base::MessageLoopForUI::IsCurrent() ||
215 !base::MessageLoopForUI::current()->is_running() ||
216 !ResourceBundle::HasSharedInstance()) {
217 int result = ui::MessageBox(views::HWNDForNativeWindow(parent), message,
218 title, GetMessageBoxFlagsFromType(type));
219 return (result == IDYES || result == IDOK) ?
220 MESSAGE_BOX_RESULT_YES : MESSAGE_BOX_RESULT_NO;
223 if (!base::MessageLoopForUI::IsCurrent() ||
224 !ResourceBundle::HasSharedInstance()) {
225 LOG(ERROR) << "Unable to show a dialog outside the UI thread message loop: "
226 << title << " - " << message;
227 return MESSAGE_BOX_RESULT_NO;
231 SimpleMessageBoxViews* dialog =
232 new SimpleMessageBoxViews(title,
237 parent == NULL // is_system_modal
239 CreateBrowserModalDialogViews(dialog, parent)->Show();
241 // NOTE: |dialog| may have been deleted by the time |RunDialogAndGetResult()|
243 return dialog->RunDialogAndGetResult();
248 MessageBoxResult ShowMessageBox(gfx::NativeWindow parent,
249 const base::string16& title,
250 const base::string16& message,
251 MessageBoxType type) {
252 return ShowMessageBoxImpl(
253 parent, title, message, type, base::string16(), base::string16());
256 MessageBoxResult ShowMessageBoxWithButtonText(gfx::NativeWindow parent,
257 const base::string16& title,
258 const base::string16& message,
259 const base::string16& yes_text,
260 const base::string16& no_text) {
261 return ShowMessageBoxImpl(
262 parent, title, message, MESSAGE_BOX_TYPE_QUESTION, yes_text, no_text);
265 } // namespace chrome