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