simple_message_box_views.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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/message_loop/message_pump_dispatcher.h" 12#include "base/run_loop.h" 13#include "chrome/browser/browser_process.h" 14#include "chrome/browser/ui/views/constrained_window_views.h" 15#include "grit/generated_resources.h" 16#include "ui/aura/client/dispatcher_client.h" 17#include "ui/aura/env.h" 18#include "ui/aura/root_window.h" 19#include "ui/base/l10n/l10n_util.h" 20#include "ui/gfx/native_widget_types.h" 21#include "ui/views/controls/message_box_view.h" 22#include "ui/views/widget/widget.h" 23#include "ui/views/window/dialog_delegate.h" 24 25#if defined(OS_WIN) 26#include "chrome/browser/ui/views/simple_message_box_win.h" 27#endif 28 29namespace chrome { 30 31namespace { 32 33// Multiple SimpleMessageBoxViews can show up at the same time. Each of these 34// start a nested message-loop. However, these SimpleMessageBoxViews can be 35// deleted in any order. This creates problems if a box in an inner-loop gets 36// destroyed before a box in an outer-loop. So to avoid this, ref-counting is 37// used so that the SimpleMessageBoxViews gets deleted at the right time. 38class SimpleMessageBoxViews : public views::DialogDelegate, 39 public base::MessagePumpDispatcher, 40 public base::RefCounted<SimpleMessageBoxViews> { 41 public: 42 SimpleMessageBoxViews(const base::string16& title, 43 const base::string16& message, 44 MessageBoxType type, 45 const base::string16& yes_text, 46 const base::string16& no_text); 47 48 MessageBoxResult result() const { return result_; } 49 50 // Overridden from views::DialogDelegate: 51 virtual int GetDialogButtons() const OVERRIDE; 52 virtual base::string16 GetDialogButtonLabel( 53 ui::DialogButton button) const OVERRIDE; 54 virtual bool Cancel() OVERRIDE; 55 virtual bool Accept() OVERRIDE; 56 57 // Overridden from views::WidgetDelegate: 58 virtual base::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 MessagePumpDispatcher: 66 virtual uint32_t Dispatch(const base::NativeEvent& event) OVERRIDE; 67 68 private: 69 friend class base::RefCounted<SimpleMessageBoxViews>; 70 virtual ~SimpleMessageBoxViews(); 71 72 const base::string16 window_title_; 73 const MessageBoxType type_; 74 base::string16 yes_text_; 75 base::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 base::string16& title, 90 const base::string16& message, 91 MessageBoxType type, 92 const base::string16& yes_text, 93 const base::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 132base::string16 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 151base::string16 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 175uint32_t SimpleMessageBoxViews::Dispatch(const base::NativeEvent& event) { 176 uint32_t action = POST_DISPATCH_PERFORM_DEFAULT; 177 if (!should_show_dialog_) 178 action |= POST_DISPATCH_QUIT_LOOP; 179 return action; 180} 181 182//////////////////////////////////////////////////////////////////////////////// 183// SimpleMessageBoxViews, private: 184 185SimpleMessageBoxViews::~SimpleMessageBoxViews() { 186} 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 195#if defined(OS_WIN) 196 // If we're very early, we can't show a GPU-based dialog, so fallback to 197 // plain Windows MessageBox. 198 if (!ui::ContextFactory::GetInstance()) 199 return NativeShowMessageBox(NULL, title, message, type); 200#endif 201 202 scoped_refptr<SimpleMessageBoxViews> dialog( 203 new SimpleMessageBoxViews(title, message, type, yes_text, no_text)); 204 CreateBrowserModalDialogViews(dialog.get(), parent)->Show(); 205 206 aura::Window* anchor = parent; 207 aura::client::DispatcherClient* client = anchor ? 208 aura::client::GetDispatcherClient(anchor->GetRootWindow()) : NULL; 209 if (!client) { 210 // Use the widget's window itself so that the message loop 211 // exists when the dialog is closed by some other means than 212 // |Cancel| or |Accept|. 213 anchor = dialog->GetWidget()->GetNativeWindow(); 214 client = aura::client::GetDispatcherClient(anchor->GetRootWindow()); 215 } 216 client->RunWithDispatcher(dialog.get(), anchor); 217 return dialog->result(); 218} 219 220} // namespace 221 222MessageBoxResult ShowMessageBox(gfx::NativeWindow parent, 223 const base::string16& title, 224 const base::string16& message, 225 MessageBoxType type) { 226 return ShowMessageBoxImpl( 227 parent, title, message, type, base::string16(), base::string16()); 228} 229 230MessageBoxResult ShowMessageBoxWithButtonText(gfx::NativeWindow parent, 231 const base::string16& title, 232 const base::string16& message, 233 const base::string16& yes_text, 234 const base::string16& no_text) { 235 return ShowMessageBoxImpl( 236 parent, title, message, MESSAGE_BOX_TYPE_QUESTION, yes_text, no_text); 237} 238 239} // namespace chrome 240