simple_message_box_views.cc revision effb81e5f8246d0db0270817048dc992db66e9fb
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/gfx/native_widget_types.h"
15#include "ui/views/controls/message_box_view.h"
16#include "ui/views/widget/widget.h"
17#include "ui/views/window/dialog_delegate.h"
18#include "ui/wm/public/dispatcher_client.h"
19
20#if defined(OS_WIN)
21#include "ui/base/win/message_box_win.h"
22#include "ui/views/win/hwnd_util.h"
23#endif
24
25namespace chrome {
26
27namespace {
28
29class SimpleMessageBoxViews : public views::DialogDelegate {
30 public:
31  SimpleMessageBoxViews(const base::string16& title,
32                        const base::string16& message,
33                        MessageBoxType type,
34                        const base::string16& yes_text,
35                        const base::string16& no_text,
36                        MessageBoxResult* result);
37  virtual ~SimpleMessageBoxViews();
38
39  // Overridden from views::DialogDelegate:
40  virtual int GetDialogButtons() const OVERRIDE;
41  virtual base::string16 GetDialogButtonLabel(
42      ui::DialogButton button) const OVERRIDE;
43  virtual bool Cancel() OVERRIDE;
44  virtual bool Accept() OVERRIDE;
45
46  // Overridden from views::WidgetDelegate:
47  virtual base::string16 GetWindowTitle() const OVERRIDE;
48  virtual void DeleteDelegate() OVERRIDE;
49  virtual ui::ModalType GetModalType() const OVERRIDE;
50  virtual views::View* GetContentsView() OVERRIDE;
51  virtual views::Widget* GetWidget() OVERRIDE;
52  virtual const views::Widget* GetWidget() const OVERRIDE;
53
54 private:
55
56  // This terminates the nested message-loop.
57  void Done();
58
59  const base::string16 window_title_;
60  const MessageBoxType type_;
61  base::string16 yes_text_;
62  base::string16 no_text_;
63  MessageBoxResult* result_;
64  views::MessageBoxView* message_box_view_;
65
66  DISALLOW_COPY_AND_ASSIGN(SimpleMessageBoxViews);
67};
68
69////////////////////////////////////////////////////////////////////////////////
70// SimpleMessageBoxViews, public:
71
72SimpleMessageBoxViews::SimpleMessageBoxViews(const base::string16& title,
73                                             const base::string16& message,
74                                             MessageBoxType type,
75                                             const base::string16& yes_text,
76                                             const base::string16& no_text,
77                                             MessageBoxResult* result)
78    : window_title_(title),
79      type_(type),
80      yes_text_(yes_text),
81      no_text_(no_text),
82      result_(result),
83      message_box_view_(new views::MessageBoxView(
84          views::MessageBoxView::InitParams(message))) {
85  CHECK(result_);
86  if (yes_text_.empty()) {
87    if (type_ == MESSAGE_BOX_TYPE_QUESTION)
88      yes_text_ =
89          l10n_util::GetStringUTF16(IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL);
90    else if (type_ == MESSAGE_BOX_TYPE_OK_CANCEL)
91      yes_text_ = l10n_util::GetStringUTF16(IDS_OK);
92    else
93      yes_text_ = l10n_util::GetStringUTF16(IDS_OK);
94  }
95
96  if (no_text_.empty()) {
97    if (type_ == MESSAGE_BOX_TYPE_QUESTION)
98      no_text_ =
99          l10n_util::GetStringUTF16(IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL);
100    else if (type_ == MESSAGE_BOX_TYPE_OK_CANCEL)
101      no_text_ = l10n_util::GetStringUTF16(IDS_CANCEL);
102  }
103}
104
105SimpleMessageBoxViews::~SimpleMessageBoxViews() {
106}
107
108int SimpleMessageBoxViews::GetDialogButtons() const {
109  if (type_ == MESSAGE_BOX_TYPE_QUESTION ||
110      type_ == MESSAGE_BOX_TYPE_OK_CANCEL) {
111    return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
112  }
113
114  return ui::DIALOG_BUTTON_OK;
115}
116
117base::string16 SimpleMessageBoxViews::GetDialogButtonLabel(
118    ui::DialogButton button) const {
119  if (button == ui::DIALOG_BUTTON_CANCEL)
120    return no_text_;
121  return yes_text_;
122}
123
124bool SimpleMessageBoxViews::Cancel() {
125  *result_ = MESSAGE_BOX_RESULT_NO;
126  Done();
127  return true;
128}
129
130bool SimpleMessageBoxViews::Accept() {
131  *result_ = MESSAGE_BOX_RESULT_YES;
132  Done();
133  return true;
134}
135
136base::string16 SimpleMessageBoxViews::GetWindowTitle() const {
137  return window_title_;
138}
139
140void SimpleMessageBoxViews::DeleteDelegate() {
141  delete this;
142}
143
144ui::ModalType SimpleMessageBoxViews::GetModalType() const {
145  return ui::MODAL_TYPE_WINDOW;
146}
147
148views::View* SimpleMessageBoxViews::GetContentsView() {
149  return message_box_view_;
150}
151
152views::Widget* SimpleMessageBoxViews::GetWidget() {
153  return message_box_view_->GetWidget();
154}
155
156const views::Widget* SimpleMessageBoxViews::GetWidget() const {
157  return message_box_view_->GetWidget();
158}
159
160////////////////////////////////////////////////////////////////////////////////
161// SimpleMessageBoxViews, private:
162
163void SimpleMessageBoxViews::Done() {
164  aura::Window* window = GetWidget()->GetNativeView();
165  aura::client::DispatcherClient* client =
166      aura::client::GetDispatcherClient(window->GetRootWindow());
167  client->QuitNestedMessageLoop();
168}
169
170#if defined(OS_WIN)
171UINT GetMessageBoxFlagsFromType(MessageBoxType type) {
172  UINT flags = MB_SETFOREGROUND;
173  switch (type) {
174    case MESSAGE_BOX_TYPE_INFORMATION:
175      return flags | MB_OK | MB_ICONINFORMATION;
176    case MESSAGE_BOX_TYPE_WARNING:
177      return flags | MB_OK | MB_ICONWARNING;
178    case MESSAGE_BOX_TYPE_QUESTION:
179      return flags | MB_YESNO | MB_ICONQUESTION;
180    case MESSAGE_BOX_TYPE_OK_CANCEL:
181      return flags | MB_OKCANCEL | MB_ICONWARNING;
182  }
183  NOTREACHED();
184  return flags | MB_OK | MB_ICONWARNING;
185}
186#endif
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#if defined(OS_WIN)
195  // GPU-based dialogs can't be used early on; fallback to a Windows MessageBox.
196  if (!base::MessageLoop::current()->is_running()) {
197    int result = ui::MessageBox(views::HWNDForNativeWindow(parent), message,
198                                title, GetMessageBoxFlagsFromType(type));
199    return (result == IDYES || result == IDOK) ?
200        MESSAGE_BOX_RESULT_YES : MESSAGE_BOX_RESULT_NO;
201  }
202#endif
203
204  MessageBoxResult result = MESSAGE_BOX_RESULT_NO;
205  SimpleMessageBoxViews* dialog = new SimpleMessageBoxViews(
206      title, message, type, yes_text, no_text, &result);
207  CreateBrowserModalDialogViews(dialog, parent)->Show();
208
209  // Use the widget's window itself so that the message loop
210  // exists when the dialog is closed by some other means than
211  // |Cancel| or |Accept|.
212  aura::Window* anchor = dialog->GetWidget()->GetNativeWindow();
213  aura::client::DispatcherClient* client =
214      aura::client::GetDispatcherClient(anchor->GetRootWindow());
215  client->RunWithDispatcher(NULL);
216  // NOTE: |dialog| will have been deleted by the time control returns here.
217
218  return result;
219}
220
221}  // namespace
222
223MessageBoxResult ShowMessageBox(gfx::NativeWindow parent,
224                                const base::string16& title,
225                                const base::string16& message,
226                                MessageBoxType type) {
227  return ShowMessageBoxImpl(
228      parent, title, message, type, base::string16(), base::string16());
229}
230
231MessageBoxResult ShowMessageBoxWithButtonText(gfx::NativeWindow parent,
232                                              const base::string16& title,
233                                              const base::string16& message,
234                                              const base::string16& yes_text,
235                                              const base::string16& no_text) {
236  return ShowMessageBoxImpl(
237      parent, title, message, MESSAGE_BOX_TYPE_QUESTION, yes_text, no_text);
238}
239
240}  // namespace chrome
241