simple_message_box_views.cc revision f2477e01787aa58f445919b809d89e252beef54f
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#if defined(OS_WIN) 26#include "chrome/browser/ui/views/simple_message_box_win.h" 27#endif 28#endif 29 30namespace chrome { 31 32namespace { 33 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. 39class SimpleMessageBoxViews : public views::DialogDelegate, 40 public base::MessageLoop::Dispatcher, 41 public base::RefCounted<SimpleMessageBoxViews> { 42 public: 43 SimpleMessageBoxViews(const string16& title, 44 const string16& message, 45 MessageBoxType type, 46 const string16& yes_text, 47 const string16& no_text); 48 49 MessageBoxResult result() const { return result_; } 50 51 // Overridden from views::DialogDelegate: 52 virtual int GetDialogButtons() const OVERRIDE; 53 virtual string16 GetDialogButtonLabel(ui::DialogButton button) const OVERRIDE; 54 virtual bool Cancel() OVERRIDE; 55 virtual bool Accept() OVERRIDE; 56 57 // Overridden from views::WidgetDelegate: 58 virtual 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 MessageLoop::Dispatcher: 66 virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE; 67 68 private: 69 friend class base::RefCounted<SimpleMessageBoxViews>; 70 virtual ~SimpleMessageBoxViews(); 71 72 const string16 window_title_; 73 const MessageBoxType type_; 74 string16 yes_text_; 75 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 string16& title, 90 const string16& message, 91 MessageBoxType type, 92 const string16& yes_text, 93 const 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 132string16 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 151string16 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 175bool SimpleMessageBoxViews::Dispatch(const base::NativeEvent& event) { 176#if defined(OS_WIN) 177 TranslateMessage(&event); 178 DispatchMessage(&event); 179#elif defined(USE_AURA) 180 aura::Env::GetInstance()->GetDispatcher()->Dispatch(event); 181#endif 182 return should_show_dialog_; 183} 184 185//////////////////////////////////////////////////////////////////////////////// 186// SimpleMessageBoxViews, private: 187 188SimpleMessageBoxViews::~SimpleMessageBoxViews() { 189} 190 191MessageBoxResult ShowMessageBoxImpl(gfx::NativeWindow parent, 192 const string16& title, 193 const string16& message, 194 MessageBoxType type, 195 const string16& yes_text, 196 const string16& no_text) { 197 198#if defined(USE_AURA) && defined(OS_WIN) 199 // If we're very early, we can't show a GPU-based dialog, so fallback to 200 // plain Windows MessageBox. 201 if (!ui::ContextFactory::GetInstance()) 202 return NativeShowMessageBox(NULL, title, message, type); 203#endif 204 205 scoped_refptr<SimpleMessageBoxViews> dialog( 206 new SimpleMessageBoxViews(title, message, type, yes_text, no_text)); 207 CreateBrowserModalDialogViews(dialog.get(), parent)->Show(); 208 209#if defined(USE_AURA) 210 aura::Window* anchor = parent; 211 aura::client::DispatcherClient* client = anchor ? 212 aura::client::GetDispatcherClient(anchor->GetRootWindow()) : NULL; 213 if (!client) { 214 // Use the widget's window itself so that the message loop 215 // exists when the dialog is closed by some other means than 216 // |Cancel| or |Accept|. 217 anchor = dialog->GetWidget()->GetNativeWindow(); 218 client = aura::client::GetDispatcherClient(anchor->GetRootWindow()); 219 } 220 client->RunWithDispatcher(dialog.get(), anchor, true); 221#else 222 { 223 base::MessageLoop::ScopedNestableTaskAllower allow( 224 base::MessageLoopForUI::current()); 225 base::RunLoop run_loop(dialog); 226 run_loop.Run(); 227 } 228#endif 229 return dialog->result(); 230} 231 232} // namespace 233 234MessageBoxResult ShowMessageBox(gfx::NativeWindow parent, 235 const string16& title, 236 const string16& message, 237 MessageBoxType type) { 238 return ShowMessageBoxImpl( 239 parent, title, message, type, string16(), string16()); 240} 241 242#if defined(USE_AURA) 243MessageBoxResult ShowMessageBoxWithButtonText(gfx::NativeWindow parent, 244 const string16& title, 245 const string16& message, 246 const string16& yes_text, 247 const string16& no_text) { 248 return ShowMessageBoxImpl( 249 parent, title, message, MESSAGE_BOX_TYPE_QUESTION, yes_text, no_text); 250} 251#endif 252 253} // namespace chrome 254