simple_message_box_views.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
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.
4
5#include "chrome/browser/ui/simple_message_box.h"
6
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"
20
21#if defined(OS_WIN)
22#include "ui/base/win/message_box_win.h"
23#include "ui/views/win/hwnd_util.h"
24#endif
25
26namespace chrome {
27
28namespace {
29
30class SimpleMessageBoxViews : public views::DialogDelegate {
31 public:
32  SimpleMessageBoxViews(const base::string16& title,
33                        const base::string16& message,
34                        MessageBoxType type,
35                        const base::string16& yes_text,
36                        const base::string16& no_text,
37                        bool is_system_modal);
38  virtual ~SimpleMessageBoxViews();
39
40  MessageBoxResult RunDialogAndGetResult();
41
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;
48
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;
56
57 private:
58
59  // This terminates the nested message-loop.
60  void Done();
61
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_;
70
71  DISALLOW_COPY_AND_ASSIGN(SimpleMessageBoxViews);
72};
73
74////////////////////////////////////////////////////////////////////////////////
75// SimpleMessageBoxViews, public:
76
77SimpleMessageBoxViews::SimpleMessageBoxViews(const base::string16& title,
78                                             const base::string16& message,
79                                             MessageBoxType type,
80                                             const base::string16& yes_text,
81                                             const base::string16& no_text,
82                                             bool is_system_modal)
83    : window_title_(title),
84      type_(type),
85      yes_text_(yes_text),
86      no_text_(no_text),
87      result_(NULL),
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)
93      yes_text_ =
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);
97    else
98      yes_text_ = l10n_util::GetStringUTF16(IDS_OK);
99  }
100
101  if (no_text_.empty()) {
102    if (type_ == MESSAGE_BOX_TYPE_QUESTION)
103      no_text_ =
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);
107  }
108}
109
110SimpleMessageBoxViews::~SimpleMessageBoxViews() {
111}
112
113MessageBoxResult SimpleMessageBoxViews::RunDialogAndGetResult() {
114  MessageBoxResult result = MESSAGE_BOX_RESULT_NO;
115  result_ = &result;
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();
122  run_loop.Run();
123  return result;
124}
125
126int 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;
130  }
131
132  return ui::DIALOG_BUTTON_OK;
133}
134
135base::string16 SimpleMessageBoxViews::GetDialogButtonLabel(
136    ui::DialogButton button) const {
137  if (button == ui::DIALOG_BUTTON_CANCEL)
138    return no_text_;
139  return yes_text_;
140}
141
142bool SimpleMessageBoxViews::Cancel() {
143  *result_ = MESSAGE_BOX_RESULT_NO;
144  Done();
145  return true;
146}
147
148bool SimpleMessageBoxViews::Accept() {
149  *result_ = MESSAGE_BOX_RESULT_YES;
150  Done();
151  return true;
152}
153
154base::string16 SimpleMessageBoxViews::GetWindowTitle() const {
155  return window_title_;
156}
157
158void SimpleMessageBoxViews::DeleteDelegate() {
159  delete this;
160}
161
162ui::ModalType SimpleMessageBoxViews::GetModalType() const {
163  return is_system_modal_ ? ui::MODAL_TYPE_SYSTEM : ui::MODAL_TYPE_WINDOW;
164}
165
166views::View* SimpleMessageBoxViews::GetContentsView() {
167  return message_box_view_;
168}
169
170views::Widget* SimpleMessageBoxViews::GetWidget() {
171  return message_box_view_->GetWidget();
172}
173
174const views::Widget* SimpleMessageBoxViews::GetWidget() const {
175  return message_box_view_->GetWidget();
176}
177
178////////////////////////////////////////////////////////////////////////////////
179// SimpleMessageBoxViews, private:
180
181void SimpleMessageBoxViews::Done() {
182  CHECK(!quit_runloop_.is_null());
183  quit_runloop_.Run();
184}
185
186#if defined(OS_WIN)
187UINT GetMessageBoxFlagsFromType(MessageBoxType type) {
188  UINT flags = MB_SETFOREGROUND;
189  switch (type) {
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;
198  }
199  NOTREACHED();
200  return flags | MB_OK | MB_ICONWARNING;
201}
202#endif
203
204MessageBoxResult ShowMessageBoxImpl(gfx::NativeWindow parent,
205                                    const base::string16& title,
206                                    const base::string16& message,
207                                    MessageBoxType type,
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.
213#if defined(OS_WIN)
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;
221  }
222#else
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;
228  }
229#endif
230
231  SimpleMessageBoxViews* dialog =
232      new SimpleMessageBoxViews(title,
233                                message,
234                                type,
235                                yes_text,
236                                no_text,
237                                parent == NULL  // is_system_modal
238                                );
239  CreateBrowserModalDialogViews(dialog, parent)->Show();
240
241  // NOTE: |dialog| may have been deleted by the time |RunDialogAndGetResult()|
242  // returns.
243  return dialog->RunDialogAndGetResult();
244}
245
246}  // namespace
247
248MessageBoxResult 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());
254}
255
256MessageBoxResult 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);
263}
264
265}  // namespace chrome
266