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.
5 #include "chrome/browser/ui/simple_message_box.h"
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"
22 #include "ui/aura/client/dispatcher_client.h"
23 #include "ui/aura/env.h"
24 #include "ui/aura/root_window.h"
26 #include "chrome/browser/ui/views/simple_message_box_win.h"
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.
39 class SimpleMessageBoxViews : public views::DialogDelegate,
40 public base::MessageLoop::Dispatcher,
41 public base::RefCounted<SimpleMessageBoxViews> {
43 SimpleMessageBoxViews(const string16& title,
44 const string16& message,
47 MessageBoxResult result() const { return result_; }
49 // Overridden from views::DialogDelegate:
50 virtual int GetDialogButtons() const OVERRIDE;
51 virtual string16 GetDialogButtonLabel(ui::DialogButton button) const OVERRIDE;
52 virtual bool Cancel() OVERRIDE;
53 virtual bool Accept() OVERRIDE;
55 // Overridden from views::WidgetDelegate:
56 virtual string16 GetWindowTitle() const OVERRIDE;
57 virtual void DeleteDelegate() OVERRIDE;
58 virtual ui::ModalType GetModalType() const OVERRIDE;
59 virtual views::View* GetContentsView() OVERRIDE;
60 virtual views::Widget* GetWidget() OVERRIDE;
61 virtual const views::Widget* GetWidget() const OVERRIDE;
63 // Overridden from MessageLoop::Dispatcher:
64 virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
67 friend class base::RefCounted<SimpleMessageBoxViews>;
68 virtual ~SimpleMessageBoxViews();
70 const string16 window_title_;
71 const MessageBoxType type_;
72 MessageBoxResult result_;
73 views::MessageBoxView* message_box_view_;
75 // Set to false as soon as the user clicks a dialog button; this tells the
76 // dispatcher we're done.
77 bool should_show_dialog_;
79 DISALLOW_COPY_AND_ASSIGN(SimpleMessageBoxViews);
82 ////////////////////////////////////////////////////////////////////////////////
83 // SimpleMessageBoxViews, public:
85 SimpleMessageBoxViews::SimpleMessageBoxViews(const string16& title,
86 const string16& message,
88 : window_title_(title),
90 result_(MESSAGE_BOX_RESULT_NO),
91 message_box_view_(new views::MessageBoxView(
92 views::MessageBoxView::InitParams(message))),
93 should_show_dialog_(true) {
97 int SimpleMessageBoxViews::GetDialogButtons() const {
98 if (type_ == MESSAGE_BOX_TYPE_QUESTION ||
99 type_ == MESSAGE_BOX_TYPE_OK_CANCEL) {
100 return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
103 return ui::DIALOG_BUTTON_OK;
106 string16 SimpleMessageBoxViews::GetDialogButtonLabel(
107 ui::DialogButton button) const {
108 if (type_ == MESSAGE_BOX_TYPE_QUESTION) {
109 return l10n_util::GetStringUTF16((button == ui::DIALOG_BUTTON_OK) ?
110 IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL :
111 IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL);
114 if (type_ == MESSAGE_BOX_TYPE_OK_CANCEL) {
115 return l10n_util::GetStringUTF16((button == ui::DIALOG_BUTTON_OK) ?
116 IDS_OK : IDS_CANCEL);
119 return l10n_util::GetStringUTF16(IDS_OK);
122 bool SimpleMessageBoxViews::Cancel() {
123 should_show_dialog_= false;
124 result_ = MESSAGE_BOX_RESULT_NO;
128 bool SimpleMessageBoxViews::Accept() {
129 should_show_dialog_ = false;
130 result_ = MESSAGE_BOX_RESULT_YES;
134 string16 SimpleMessageBoxViews::GetWindowTitle() const {
135 return window_title_;
138 void SimpleMessageBoxViews::DeleteDelegate() {
142 ui::ModalType SimpleMessageBoxViews::GetModalType() const {
143 return ui::MODAL_TYPE_WINDOW;
146 views::View* SimpleMessageBoxViews::GetContentsView() {
147 return message_box_view_;
150 views::Widget* SimpleMessageBoxViews::GetWidget() {
151 return message_box_view_->GetWidget();
154 const views::Widget* SimpleMessageBoxViews::GetWidget() const {
155 return message_box_view_->GetWidget();
158 bool SimpleMessageBoxViews::Dispatch(const base::NativeEvent& event) {
160 TranslateMessage(&event);
161 DispatchMessage(&event);
162 #elif defined(USE_AURA)
163 aura::Env::GetInstance()->GetDispatcher()->Dispatch(event);
165 return should_show_dialog_;
168 ////////////////////////////////////////////////////////////////////////////////
169 // SimpleMessageBoxViews, private:
171 SimpleMessageBoxViews::~SimpleMessageBoxViews() {
176 MessageBoxResult ShowMessageBox(gfx::NativeWindow parent,
177 const string16& title,
178 const string16& message,
179 MessageBoxType type) {
180 #if defined(USE_AURA) && defined(OS_WIN)
181 // If we're very early, we can't show a GPU-based dialog, so fallback to
182 // plain Windows MessageBox.
183 if (!ui::ContextFactory::GetInstance())
184 return NativeShowMessageBox(NULL, title, message, type);
187 scoped_refptr<SimpleMessageBoxViews> dialog(
188 new SimpleMessageBoxViews(title, message, type));
189 CreateBrowserModalDialogViews(dialog.get(), parent)->Show();
191 #if defined(USE_AURA)
192 aura::Window* anchor = parent;
193 aura::client::DispatcherClient* client = anchor ?
194 aura::client::GetDispatcherClient(anchor->GetRootWindow()) : NULL;
196 // Use the widget's window itself so that the message loop
197 // exists when the dialog is closed by some other means than
198 // |Cancel| or |Accept|.
199 anchor = dialog->GetWidget()->GetNativeWindow();
200 client = aura::client::GetDispatcherClient(anchor->GetRootWindow());
202 client->RunWithDispatcher(dialog.get(), anchor, true);
205 base::MessageLoop::ScopedNestableTaskAllower allow(
206 base::MessageLoopForUI::current());
207 base::RunLoop run_loop(dialog);
211 return dialog->result();
214 } // namespace chrome