simple_message_box_views.cc revision f2477e01787aa58f445919b809d89e252beef54f
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/memory/ref_counted.h"
10#include "base/message_loop/message_loop.h"
11#include "base/run_loop.h"
12#include "chrome/browser/browser_process.h"
13#include "chrome/browser/ui/views/constrained_window_views.h"
14#include "grit/generated_resources.h"
15#include "ui/base/l10n/l10n_util.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(USE_AURA)
22#include "ui/aura/client/dispatcher_client.h"
23#include "ui/aura/env.h"
24#include "ui/aura/root_window.h"
25#if defined(OS_WIN)
26#include "chrome/browser/ui/views/simple_message_box_win.h"
27#endif
28#endif
29
30namespace chrome {
31
32namespace {
33
34// Multiple SimpleMessageBoxViews can show up at the same time. Each of these
35// start a nested message-loop. However, these SimpleMessageBoxViews can be
36// deleted in any order. This creates problems if a box in an inner-loop gets
37// destroyed before a box in an outer-loop. So to avoid this, ref-counting is
38// used so that the SimpleMessageBoxViews gets deleted at the right time.
39class SimpleMessageBoxViews : public views::DialogDelegate,
40                              public base::MessageLoop::Dispatcher,
41                              public base::RefCounted<SimpleMessageBoxViews> {
42 public:
43  SimpleMessageBoxViews(const string16& title,
44                        const string16& message,
45                        MessageBoxType type,
46                        const string16& yes_text,
47                        const string16& no_text);
48
49  MessageBoxResult result() const { return result_; }
50
51  // Overridden from views::DialogDelegate:
52  virtual int GetDialogButtons() const OVERRIDE;
53  virtual string16 GetDialogButtonLabel(ui::DialogButton button) const OVERRIDE;
54  virtual bool Cancel() OVERRIDE;
55  virtual bool Accept() OVERRIDE;
56
57  // Overridden from views::WidgetDelegate:
58  virtual 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;
64
65  // Overridden from MessageLoop::Dispatcher:
66  virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
67
68 private:
69  friend class base::RefCounted<SimpleMessageBoxViews>;
70  virtual ~SimpleMessageBoxViews();
71
72  const string16 window_title_;
73  const MessageBoxType type_;
74  string16 yes_text_;
75  string16 no_text_;
76  MessageBoxResult result_;
77  views::MessageBoxView* message_box_view_;
78
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_;
82
83  DISALLOW_COPY_AND_ASSIGN(SimpleMessageBoxViews);
84};
85
86////////////////////////////////////////////////////////////////////////////////
87// SimpleMessageBoxViews, public:
88
89SimpleMessageBoxViews::SimpleMessageBoxViews(const string16& title,
90                                             const string16& message,
91                                             MessageBoxType type,
92                                             const string16& yes_text,
93                                             const string16& no_text)
94    : window_title_(title),
95      type_(type),
96      yes_text_(yes_text),
97      no_text_(no_text),
98      result_(MESSAGE_BOX_RESULT_NO),
99      message_box_view_(new views::MessageBoxView(
100          views::MessageBoxView::InitParams(message))),
101      should_show_dialog_(true) {
102  AddRef();
103
104  if (yes_text_.empty()) {
105    if (type_ == MESSAGE_BOX_TYPE_QUESTION)
106      yes_text_ =
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);
110    else
111      yes_text_ = l10n_util::GetStringUTF16(IDS_OK);
112  }
113
114  if (no_text_.empty()) {
115    if (type_ == MESSAGE_BOX_TYPE_QUESTION)
116      no_text_ =
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);
120  }
121}
122
123int 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;
127  }
128
129  return ui::DIALOG_BUTTON_OK;
130}
131
132string16 SimpleMessageBoxViews::GetDialogButtonLabel(
133    ui::DialogButton button) const {
134  if (button == ui::DIALOG_BUTTON_CANCEL)
135    return no_text_;
136  return yes_text_;
137}
138
139bool SimpleMessageBoxViews::Cancel() {
140  should_show_dialog_= false;
141  result_ = MESSAGE_BOX_RESULT_NO;
142  return true;
143}
144
145bool SimpleMessageBoxViews::Accept() {
146  should_show_dialog_ = false;
147  result_ = MESSAGE_BOX_RESULT_YES;
148  return true;
149}
150
151string16 SimpleMessageBoxViews::GetWindowTitle() const {
152  return window_title_;
153}
154
155void SimpleMessageBoxViews::DeleteDelegate() {
156  Release();
157}
158
159ui::ModalType SimpleMessageBoxViews::GetModalType() const {
160  return ui::MODAL_TYPE_WINDOW;
161}
162
163views::View* SimpleMessageBoxViews::GetContentsView() {
164  return message_box_view_;
165}
166
167views::Widget* SimpleMessageBoxViews::GetWidget() {
168  return message_box_view_->GetWidget();
169}
170
171const views::Widget* SimpleMessageBoxViews::GetWidget() const {
172  return message_box_view_->GetWidget();
173}
174
175bool SimpleMessageBoxViews::Dispatch(const base::NativeEvent& event) {
176#if defined(OS_WIN)
177  TranslateMessage(&event);
178  DispatchMessage(&event);
179#elif defined(USE_AURA)
180  aura::Env::GetInstance()->GetDispatcher()->Dispatch(event);
181#endif
182  return should_show_dialog_;
183}
184
185////////////////////////////////////////////////////////////////////////////////
186// SimpleMessageBoxViews, private:
187
188SimpleMessageBoxViews::~SimpleMessageBoxViews() {
189}
190
191MessageBoxResult ShowMessageBoxImpl(gfx::NativeWindow parent,
192                                    const string16& title,
193                                    const string16& message,
194                                    MessageBoxType type,
195                                    const string16& yes_text,
196                                    const string16& no_text) {
197
198#if defined(USE_AURA) && defined(OS_WIN)
199  // If we're very early, we can't show a GPU-based dialog, so fallback to
200  // plain Windows MessageBox.
201  if (!ui::ContextFactory::GetInstance())
202    return NativeShowMessageBox(NULL, title, message, type);
203#endif
204
205  scoped_refptr<SimpleMessageBoxViews> dialog(
206      new SimpleMessageBoxViews(title, message, type, yes_text, no_text));
207  CreateBrowserModalDialogViews(dialog.get(), parent)->Show();
208
209#if defined(USE_AURA)
210  aura::Window* anchor = parent;
211  aura::client::DispatcherClient* client = anchor ?
212      aura::client::GetDispatcherClient(anchor->GetRootWindow()) : NULL;
213  if (!client) {
214    // Use the widget's window itself so that the message loop
215    // exists when the dialog is closed by some other means than
216    // |Cancel| or |Accept|.
217    anchor = dialog->GetWidget()->GetNativeWindow();
218    client = aura::client::GetDispatcherClient(anchor->GetRootWindow());
219  }
220  client->RunWithDispatcher(dialog.get(), anchor, true);
221#else
222  {
223    base::MessageLoop::ScopedNestableTaskAllower allow(
224        base::MessageLoopForUI::current());
225    base::RunLoop run_loop(dialog);
226    run_loop.Run();
227  }
228#endif
229  return dialog->result();
230}
231
232}  // namespace
233
234MessageBoxResult ShowMessageBox(gfx::NativeWindow parent,
235                                const string16& title,
236                                const string16& message,
237                                MessageBoxType type) {
238  return ShowMessageBoxImpl(
239      parent, title, message, type, string16(), string16());
240}
241
242#if defined(USE_AURA)
243MessageBoxResult ShowMessageBoxWithButtonText(gfx::NativeWindow parent,
244                                              const string16& title,
245                                              const string16& message,
246                                              const string16& yes_text,
247                                              const string16& no_text) {
248  return ShowMessageBoxImpl(
249      parent, title, message, MESSAGE_BOX_TYPE_QUESTION, yes_text, no_text);
250}
251#endif
252
253}  // namespace chrome
254