simple_message_box_views.cc revision 010d83a9304c5a91596085d917d248abff47903a
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 "chrome/browser/ui/views/constrained_window_views.h"
11#include "grit/generated_resources.h"
12#include "ui/aura/window.h"
13#include "ui/base/l10n/l10n_util.h"
14#include "ui/base/resource/resource_bundle.h"
15#include "ui/gfx/native_widget_types.h"
16#include "ui/views/controls/message_box_view.h"
17#include "ui/views/widget/widget.h"
18#include "ui/views/window/dialog_delegate.h"
19#include "ui/wm/public/dispatcher_client.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                        MessageBoxResult* result);
39  virtual ~SimpleMessageBoxViews();
40
41  // Overridden from views::DialogDelegate:
42  virtual int GetDialogButtons() const OVERRIDE;
43  virtual base::string16 GetDialogButtonLabel(
44      ui::DialogButton button) const OVERRIDE;
45  virtual bool Cancel() OVERRIDE;
46  virtual bool Accept() OVERRIDE;
47
48  // Overridden from views::WidgetDelegate:
49  virtual base::string16 GetWindowTitle() const OVERRIDE;
50  virtual void DeleteDelegate() OVERRIDE;
51  virtual ui::ModalType GetModalType() const OVERRIDE;
52  virtual views::View* GetContentsView() OVERRIDE;
53  virtual views::Widget* GetWidget() OVERRIDE;
54  virtual const views::Widget* GetWidget() const OVERRIDE;
55
56 private:
57
58  // This terminates the nested message-loop.
59  void Done();
60
61  const base::string16 window_title_;
62  const MessageBoxType type_;
63  base::string16 yes_text_;
64  base::string16 no_text_;
65  MessageBoxResult* result_;
66  bool is_system_modal_;
67  views::MessageBoxView* message_box_view_;
68
69  DISALLOW_COPY_AND_ASSIGN(SimpleMessageBoxViews);
70};
71
72////////////////////////////////////////////////////////////////////////////////
73// SimpleMessageBoxViews, public:
74
75SimpleMessageBoxViews::SimpleMessageBoxViews(const base::string16& title,
76                                             const base::string16& message,
77                                             MessageBoxType type,
78                                             const base::string16& yes_text,
79                                             const base::string16& no_text,
80                                             bool is_system_modal,
81                                             MessageBoxResult* result)
82    : window_title_(title),
83      type_(type),
84      yes_text_(yes_text),
85      no_text_(no_text),
86      result_(result),
87      is_system_modal_(is_system_modal),
88      message_box_view_(new views::MessageBoxView(
89          views::MessageBoxView::InitParams(message))) {
90  CHECK(result_);
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
113int SimpleMessageBoxViews::GetDialogButtons() const {
114  if (type_ == MESSAGE_BOX_TYPE_QUESTION ||
115      type_ == MESSAGE_BOX_TYPE_OK_CANCEL) {
116    return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
117  }
118
119  return ui::DIALOG_BUTTON_OK;
120}
121
122base::string16 SimpleMessageBoxViews::GetDialogButtonLabel(
123    ui::DialogButton button) const {
124  if (button == ui::DIALOG_BUTTON_CANCEL)
125    return no_text_;
126  return yes_text_;
127}
128
129bool SimpleMessageBoxViews::Cancel() {
130  *result_ = MESSAGE_BOX_RESULT_NO;
131  Done();
132  return true;
133}
134
135bool SimpleMessageBoxViews::Accept() {
136  *result_ = MESSAGE_BOX_RESULT_YES;
137  Done();
138  return true;
139}
140
141base::string16 SimpleMessageBoxViews::GetWindowTitle() const {
142  return window_title_;
143}
144
145void SimpleMessageBoxViews::DeleteDelegate() {
146  delete this;
147}
148
149ui::ModalType SimpleMessageBoxViews::GetModalType() const {
150  return is_system_modal_ ? ui::MODAL_TYPE_SYSTEM : ui::MODAL_TYPE_WINDOW;
151}
152
153views::View* SimpleMessageBoxViews::GetContentsView() {
154  return message_box_view_;
155}
156
157views::Widget* SimpleMessageBoxViews::GetWidget() {
158  return message_box_view_->GetWidget();
159}
160
161const views::Widget* SimpleMessageBoxViews::GetWidget() const {
162  return message_box_view_->GetWidget();
163}
164
165////////////////////////////////////////////////////////////////////////////////
166// SimpleMessageBoxViews, private:
167
168void SimpleMessageBoxViews::Done() {
169  aura::Window* window = GetWidget()->GetNativeView();
170  aura::client::DispatcherClient* client =
171      aura::client::GetDispatcherClient(window->GetRootWindow());
172  client->QuitNestedMessageLoop();
173}
174
175#if defined(OS_WIN)
176UINT GetMessageBoxFlagsFromType(MessageBoxType type) {
177  UINT flags = MB_SETFOREGROUND;
178  switch (type) {
179    case MESSAGE_BOX_TYPE_INFORMATION:
180      return flags | MB_OK | MB_ICONINFORMATION;
181    case MESSAGE_BOX_TYPE_WARNING:
182      return flags | MB_OK | MB_ICONWARNING;
183    case MESSAGE_BOX_TYPE_QUESTION:
184      return flags | MB_YESNO | MB_ICONQUESTION;
185    case MESSAGE_BOX_TYPE_OK_CANCEL:
186      return flags | MB_OKCANCEL | MB_ICONWARNING;
187  }
188  NOTREACHED();
189  return flags | MB_OK | MB_ICONWARNING;
190}
191#endif
192
193MessageBoxResult ShowMessageBoxImpl(gfx::NativeWindow parent,
194                                    const base::string16& title,
195                                    const base::string16& message,
196                                    MessageBoxType type,
197                                    const base::string16& yes_text,
198                                    const base::string16& no_text) {
199  // Views dialogs cannot be shown outside the UI thread message loop or if the
200  // ResourceBundle is not initialized yet.
201  // Fallback to logging with a default response or a Windows MessageBox.
202#if defined(OS_WIN)
203  if (!base::MessageLoopForUI::IsCurrent() ||
204      !base::MessageLoopForUI::current()->is_running() ||
205      !ResourceBundle::HasSharedInstance()) {
206    int result = ui::MessageBox(views::HWNDForNativeWindow(parent), message,
207                                title, GetMessageBoxFlagsFromType(type));
208    return (result == IDYES || result == IDOK) ?
209        MESSAGE_BOX_RESULT_YES : MESSAGE_BOX_RESULT_NO;
210  }
211#else
212  if (!base::MessageLoopForUI::IsCurrent() ||
213      !ResourceBundle::HasSharedInstance()) {
214    LOG(ERROR) << "Unable to show a dialog outside the UI thread message loop: "
215               << title << " - " << message;
216    return MESSAGE_BOX_RESULT_NO;
217  }
218#endif
219
220  MessageBoxResult result = MESSAGE_BOX_RESULT_NO;
221  SimpleMessageBoxViews* dialog = new SimpleMessageBoxViews(
222      title,
223      message,
224      type,
225      yes_text,
226      no_text,
227      parent == NULL,  // is_system_modal
228      &result);
229  CreateBrowserModalDialogViews(dialog, parent)->Show();
230
231  // Use the widget's window itself so that the message loop exists when the
232  // dialog is closed by some other means than |Cancel| or |Accept|.
233  aura::Window* anchor = dialog->GetWidget()->GetNativeWindow();
234  aura::client::DispatcherClient* client =
235      aura::client::GetDispatcherClient(anchor->GetRootWindow());
236  client->RunWithDispatcher(NULL);
237  // NOTE: |dialog| will have been deleted by the time control returns here.
238
239  return result;
240}
241
242}  // namespace
243
244MessageBoxResult ShowMessageBox(gfx::NativeWindow parent,
245                                const base::string16& title,
246                                const base::string16& message,
247                                MessageBoxType type) {
248  return ShowMessageBoxImpl(
249      parent, title, message, type, base::string16(), base::string16());
250}
251
252MessageBoxResult ShowMessageBoxWithButtonText(gfx::NativeWindow parent,
253                                              const base::string16& title,
254                                              const base::string16& message,
255                                              const base::string16& yes_text,
256                                              const base::string16& no_text) {
257  return ShowMessageBoxImpl(
258      parent, title, message, MESSAGE_BOX_TYPE_QUESTION, yes_text, no_text);
259}
260
261}  // namespace chrome
262