simple_message_box_views.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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/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"
24
25#if defined(OS_WIN)
26#include "chrome/browser/ui/views/simple_message_box_win.h"
27#endif
28
29namespace chrome {
30
31namespace {
32
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.
38class SimpleMessageBoxViews : public views::DialogDelegate,
39                              public base::MessagePumpDispatcher,
40                              public base::RefCounted<SimpleMessageBoxViews> {
41 public:
42  SimpleMessageBoxViews(const base::string16& title,
43                        const base::string16& message,
44                        MessageBoxType type,
45                        const base::string16& yes_text,
46                        const base::string16& no_text);
47
48  MessageBoxResult result() const { return result_; }
49
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;
56
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;
64
65  // Overridden from MessagePumpDispatcher:
66  virtual uint32_t Dispatch(const base::NativeEvent& event) OVERRIDE;
67
68 private:
69  friend class base::RefCounted<SimpleMessageBoxViews>;
70  virtual ~SimpleMessageBoxViews();
71
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_;
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 base::string16& title,
90                                             const base::string16& message,
91                                             MessageBoxType type,
92                                             const base::string16& yes_text,
93                                             const base::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
132base::string16 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
151base::string16 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
175uint32_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;
179  return action;
180}
181
182////////////////////////////////////////////////////////////////////////////////
183// SimpleMessageBoxViews, private:
184
185SimpleMessageBoxViews::~SimpleMessageBoxViews() {
186}
187
188MessageBoxResult ShowMessageBoxImpl(gfx::NativeWindow parent,
189                                    const base::string16& title,
190                                    const base::string16& message,
191                                    MessageBoxType type,
192                                    const base::string16& yes_text,
193                                    const base::string16& no_text) {
194
195#if defined(OS_WIN)
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);
200#endif
201
202  scoped_refptr<SimpleMessageBoxViews> dialog(
203      new SimpleMessageBoxViews(title, message, type, yes_text, no_text));
204  CreateBrowserModalDialogViews(dialog.get(), parent)->Show();
205
206  aura::Window* anchor = parent;
207  aura::client::DispatcherClient* client = anchor ?
208      aura::client::GetDispatcherClient(anchor->GetRootWindow()) : NULL;
209  if (!client) {
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());
215  }
216  client->RunWithDispatcher(dialog.get(), anchor);
217  return dialog->result();
218}
219
220}  // namespace
221
222MessageBoxResult 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());
228}
229
230MessageBoxResult 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);
237}
238
239}  // namespace chrome
240