simple_message_box_views.cc revision 9ab5563a3196760eb381d102cbb2bc0f7abc6a50
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#endif
26
27namespace chrome {
28
29namespace {
30
31// Multiple SimpleMessageBoxViews can show up at the same time. Each of these
32// start a nested message-loop. However, these SimpleMessageBoxViews can be
33// deleted in any order. This creates problems if a box in an inner-loop gets
34// destroyed before a box in an outer-loop. So to avoid this, ref-counting is
35// used so that the SimpleMessageBoxViews gets deleted at the right time.
36class SimpleMessageBoxViews : public views::DialogDelegate,
37                              public base::MessageLoop::Dispatcher,
38                              public base::RefCounted<SimpleMessageBoxViews> {
39 public:
40  SimpleMessageBoxViews(const string16& title,
41                        const string16& message,
42                        MessageBoxType type);
43
44  MessageBoxResult result() const { return result_; }
45
46  // Overridden from views::DialogDelegate:
47  virtual int GetDialogButtons() const OVERRIDE;
48  virtual string16 GetDialogButtonLabel(ui::DialogButton button) const OVERRIDE;
49  virtual bool Cancel() OVERRIDE;
50  virtual bool Accept() OVERRIDE;
51
52  // Overridden from views::WidgetDelegate:
53  virtual string16 GetWindowTitle() const OVERRIDE;
54  virtual void DeleteDelegate() OVERRIDE;
55  virtual ui::ModalType GetModalType() const OVERRIDE;
56  virtual views::View* GetContentsView() OVERRIDE;
57  virtual views::Widget* GetWidget() OVERRIDE;
58  virtual const views::Widget* GetWidget() const OVERRIDE;
59
60  // Overridden from MessageLoop::Dispatcher:
61  virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
62
63 private:
64  friend class base::RefCounted<SimpleMessageBoxViews>;
65  virtual ~SimpleMessageBoxViews();
66
67  const string16 window_title_;
68  const MessageBoxType type_;
69  MessageBoxResult result_;
70  views::MessageBoxView* message_box_view_;
71
72  // Set to false as soon as the user clicks a dialog button; this tells the
73  // dispatcher we're done.
74  bool should_show_dialog_;
75
76  DISALLOW_COPY_AND_ASSIGN(SimpleMessageBoxViews);
77};
78
79////////////////////////////////////////////////////////////////////////////////
80// SimpleMessageBoxViews, public:
81
82SimpleMessageBoxViews::SimpleMessageBoxViews(const string16& title,
83                                             const string16& message,
84                                             MessageBoxType type)
85    : window_title_(title),
86      type_(type),
87      result_(MESSAGE_BOX_RESULT_NO),
88      message_box_view_(new views::MessageBoxView(
89          views::MessageBoxView::InitParams(message))),
90      should_show_dialog_(true) {
91  AddRef();
92}
93
94int SimpleMessageBoxViews::GetDialogButtons() const {
95  if (type_ == MESSAGE_BOX_TYPE_QUESTION ||
96      type_ == MESSAGE_BOX_TYPE_OK_CANCEL) {
97    return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
98  }
99
100  return ui::DIALOG_BUTTON_OK;
101}
102
103string16 SimpleMessageBoxViews::GetDialogButtonLabel(
104    ui::DialogButton button) const {
105  if (type_ == MESSAGE_BOX_TYPE_QUESTION) {
106    return l10n_util::GetStringUTF16((button == ui::DIALOG_BUTTON_OK) ?
107        IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL :
108        IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL);
109  }
110
111  if (type_ == MESSAGE_BOX_TYPE_OK_CANCEL) {
112    return l10n_util::GetStringUTF16((button == ui::DIALOG_BUTTON_OK) ?
113        IDS_OK : IDS_CANCEL);
114  }
115
116  return l10n_util::GetStringUTF16(IDS_OK);
117}
118
119bool SimpleMessageBoxViews::Cancel() {
120  should_show_dialog_= false;
121  result_ = MESSAGE_BOX_RESULT_NO;
122  return true;
123}
124
125bool SimpleMessageBoxViews::Accept() {
126  should_show_dialog_ = false;
127  result_ = MESSAGE_BOX_RESULT_YES;
128  return true;
129}
130
131string16 SimpleMessageBoxViews::GetWindowTitle() const {
132  return window_title_;
133}
134
135void SimpleMessageBoxViews::DeleteDelegate() {
136  Release();
137}
138
139ui::ModalType SimpleMessageBoxViews::GetModalType() const {
140  return ui::MODAL_TYPE_WINDOW;
141}
142
143views::View* SimpleMessageBoxViews::GetContentsView() {
144  return message_box_view_;
145}
146
147views::Widget* SimpleMessageBoxViews::GetWidget() {
148  return message_box_view_->GetWidget();
149}
150
151const views::Widget* SimpleMessageBoxViews::GetWidget() const {
152  return message_box_view_->GetWidget();
153}
154
155bool SimpleMessageBoxViews::Dispatch(const base::NativeEvent& event) {
156#if defined(OS_WIN)
157  TranslateMessage(&event);
158  DispatchMessage(&event);
159#elif defined(USE_AURA)
160  aura::Env::GetInstance()->GetDispatcher()->Dispatch(event);
161#endif
162  return should_show_dialog_;
163}
164
165////////////////////////////////////////////////////////////////////////////////
166// SimpleMessageBoxViews, private:
167
168SimpleMessageBoxViews::~SimpleMessageBoxViews() {
169}
170
171}  // namespace
172
173MessageBoxResult ShowMessageBox(gfx::NativeWindow parent,
174                                const string16& title,
175                                const string16& message,
176                                MessageBoxType type) {
177  scoped_refptr<SimpleMessageBoxViews> dialog(
178      new SimpleMessageBoxViews(title, message, type));
179  CreateBrowserModalDialogViews(dialog.get(), parent)->Show();
180
181#if defined(USE_AURA)
182  // Use the widget's window itself so that the message loop
183  // exists when the dialog is closed by some other means than
184  // |Cancel| or |Accept|.
185  aura::Window* anchor = parent ?
186      parent : dialog->GetWidget()->GetNativeWindow();
187  aura::client::GetDispatcherClient(anchor->GetRootWindow())
188      ->RunWithDispatcher(dialog.get(), anchor, true);
189#else
190  {
191    base::MessageLoop::ScopedNestableTaskAllower allow(
192        base::MessageLoopForUI::current());
193    base::RunLoop run_loop(dialog);
194    run_loop.Run();
195  }
196#endif
197  return dialog->result();
198}
199
200}  // namespace chrome
201