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 "base/run_loop.h" 11#include "chrome/browser/ui/views/constrained_window_views.h" 12#include "chrome/grit/generated_resources.h" 13#include "ui/aura/window.h" 14#include "ui/base/l10n/l10n_util.h" 15#include "ui/base/resource/resource_bundle.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(OS_WIN) 22#include "ui/base/win/message_box_win.h" 23#include "ui/views/win/hwnd_util.h" 24#endif 25 26namespace chrome { 27 28namespace { 29 30class SimpleMessageBoxViews : public views::DialogDelegate { 31 public: 32 SimpleMessageBoxViews(const base::string16& title, 33 const base::string16& message, 34 MessageBoxType type, 35 const base::string16& yes_text, 36 const base::string16& no_text, 37 bool is_system_modal); 38 virtual ~SimpleMessageBoxViews(); 39 40 MessageBoxResult RunDialogAndGetResult(); 41 42 // Overridden from views::DialogDelegate: 43 virtual int GetDialogButtons() const OVERRIDE; 44 virtual base::string16 GetDialogButtonLabel( 45 ui::DialogButton button) const OVERRIDE; 46 virtual bool Cancel() OVERRIDE; 47 virtual bool Accept() OVERRIDE; 48 49 // Overridden from views::WidgetDelegate: 50 virtual base::string16 GetWindowTitle() const OVERRIDE; 51 virtual void DeleteDelegate() OVERRIDE; 52 virtual ui::ModalType GetModalType() const OVERRIDE; 53 virtual views::View* GetContentsView() OVERRIDE; 54 virtual views::Widget* GetWidget() OVERRIDE; 55 virtual const views::Widget* GetWidget() const OVERRIDE; 56 57 private: 58 59 // This terminates the nested message-loop. 60 void Done(); 61 62 const base::string16 window_title_; 63 const MessageBoxType type_; 64 base::string16 yes_text_; 65 base::string16 no_text_; 66 MessageBoxResult* result_; 67 bool is_system_modal_; 68 views::MessageBoxView* message_box_view_; 69 base::Closure quit_runloop_; 70 71 DISALLOW_COPY_AND_ASSIGN(SimpleMessageBoxViews); 72}; 73 74//////////////////////////////////////////////////////////////////////////////// 75// SimpleMessageBoxViews, public: 76 77SimpleMessageBoxViews::SimpleMessageBoxViews(const base::string16& title, 78 const base::string16& message, 79 MessageBoxType type, 80 const base::string16& yes_text, 81 const base::string16& no_text, 82 bool is_system_modal) 83 : window_title_(title), 84 type_(type), 85 yes_text_(yes_text), 86 no_text_(no_text), 87 result_(NULL), 88 is_system_modal_(is_system_modal), 89 message_box_view_(new views::MessageBoxView( 90 views::MessageBoxView::InitParams(message))) { 91 if (yes_text_.empty()) { 92 if (type_ == MESSAGE_BOX_TYPE_QUESTION) 93 yes_text_ = 94 l10n_util::GetStringUTF16(IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL); 95 else if (type_ == MESSAGE_BOX_TYPE_OK_CANCEL) 96 yes_text_ = l10n_util::GetStringUTF16(IDS_OK); 97 else 98 yes_text_ = l10n_util::GetStringUTF16(IDS_OK); 99 } 100 101 if (no_text_.empty()) { 102 if (type_ == MESSAGE_BOX_TYPE_QUESTION) 103 no_text_ = 104 l10n_util::GetStringUTF16(IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL); 105 else if (type_ == MESSAGE_BOX_TYPE_OK_CANCEL) 106 no_text_ = l10n_util::GetStringUTF16(IDS_CANCEL); 107 } 108} 109 110SimpleMessageBoxViews::~SimpleMessageBoxViews() { 111} 112 113MessageBoxResult SimpleMessageBoxViews::RunDialogAndGetResult() { 114 MessageBoxResult result = MESSAGE_BOX_RESULT_NO; 115 result_ = &result; 116 // TODO(pkotwicz): Exit message loop when the dialog is closed by some other 117 // means than |Cancel| or |Accept|. crbug.com/404385 118 base::MessageLoopForUI* loop = base::MessageLoopForUI::current(); 119 base::MessageLoopForUI::ScopedNestableTaskAllower allow_nested(loop); 120 base::RunLoop run_loop; 121 quit_runloop_ = run_loop.QuitClosure(); 122 run_loop.Run(); 123 return result; 124} 125 126int SimpleMessageBoxViews::GetDialogButtons() const { 127 if (type_ == MESSAGE_BOX_TYPE_QUESTION || 128 type_ == MESSAGE_BOX_TYPE_OK_CANCEL) { 129 return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL; 130 } 131 132 return ui::DIALOG_BUTTON_OK; 133} 134 135base::string16 SimpleMessageBoxViews::GetDialogButtonLabel( 136 ui::DialogButton button) const { 137 if (button == ui::DIALOG_BUTTON_CANCEL) 138 return no_text_; 139 return yes_text_; 140} 141 142bool SimpleMessageBoxViews::Cancel() { 143 *result_ = MESSAGE_BOX_RESULT_NO; 144 Done(); 145 return true; 146} 147 148bool SimpleMessageBoxViews::Accept() { 149 *result_ = MESSAGE_BOX_RESULT_YES; 150 Done(); 151 return true; 152} 153 154base::string16 SimpleMessageBoxViews::GetWindowTitle() const { 155 return window_title_; 156} 157 158void SimpleMessageBoxViews::DeleteDelegate() { 159 delete this; 160} 161 162ui::ModalType SimpleMessageBoxViews::GetModalType() const { 163 return is_system_modal_ ? ui::MODAL_TYPE_SYSTEM : ui::MODAL_TYPE_WINDOW; 164} 165 166views::View* SimpleMessageBoxViews::GetContentsView() { 167 return message_box_view_; 168} 169 170views::Widget* SimpleMessageBoxViews::GetWidget() { 171 return message_box_view_->GetWidget(); 172} 173 174const views::Widget* SimpleMessageBoxViews::GetWidget() const { 175 return message_box_view_->GetWidget(); 176} 177 178//////////////////////////////////////////////////////////////////////////////// 179// SimpleMessageBoxViews, private: 180 181void SimpleMessageBoxViews::Done() { 182 CHECK(!quit_runloop_.is_null()); 183 quit_runloop_.Run(); 184} 185 186#if defined(OS_WIN) 187UINT GetMessageBoxFlagsFromType(MessageBoxType type) { 188 UINT flags = MB_SETFOREGROUND; 189 switch (type) { 190 case MESSAGE_BOX_TYPE_INFORMATION: 191 return flags | MB_OK | MB_ICONINFORMATION; 192 case MESSAGE_BOX_TYPE_WARNING: 193 return flags | MB_OK | MB_ICONWARNING; 194 case MESSAGE_BOX_TYPE_QUESTION: 195 return flags | MB_YESNO | MB_ICONQUESTION; 196 case MESSAGE_BOX_TYPE_OK_CANCEL: 197 return flags | MB_OKCANCEL | MB_ICONWARNING; 198 } 199 NOTREACHED(); 200 return flags | MB_OK | MB_ICONWARNING; 201} 202#endif 203 204MessageBoxResult ShowMessageBoxImpl(gfx::NativeWindow parent, 205 const base::string16& title, 206 const base::string16& message, 207 MessageBoxType type, 208 const base::string16& yes_text, 209 const base::string16& no_text) { 210 // Views dialogs cannot be shown outside the UI thread message loop or if the 211 // ResourceBundle is not initialized yet. 212 // Fallback to logging with a default response or a Windows MessageBox. 213#if defined(OS_WIN) 214 if (!base::MessageLoopForUI::IsCurrent() || 215 !base::MessageLoopForUI::current()->is_running() || 216 !ResourceBundle::HasSharedInstance()) { 217 int result = ui::MessageBox(views::HWNDForNativeWindow(parent), message, 218 title, GetMessageBoxFlagsFromType(type)); 219 return (result == IDYES || result == IDOK) ? 220 MESSAGE_BOX_RESULT_YES : MESSAGE_BOX_RESULT_NO; 221 } 222#else 223 if (!base::MessageLoopForUI::IsCurrent() || 224 !ResourceBundle::HasSharedInstance()) { 225 LOG(ERROR) << "Unable to show a dialog outside the UI thread message loop: " 226 << title << " - " << message; 227 return MESSAGE_BOX_RESULT_NO; 228 } 229#endif 230 231 SimpleMessageBoxViews* dialog = 232 new SimpleMessageBoxViews(title, 233 message, 234 type, 235 yes_text, 236 no_text, 237 parent == NULL // is_system_modal 238 ); 239 CreateBrowserModalDialogViews(dialog, parent)->Show(); 240 241 // NOTE: |dialog| may have been deleted by the time |RunDialogAndGetResult()| 242 // returns. 243 return dialog->RunDialogAndGetResult(); 244} 245 246} // namespace 247 248MessageBoxResult ShowMessageBox(gfx::NativeWindow parent, 249 const base::string16& title, 250 const base::string16& message, 251 MessageBoxType type) { 252 return ShowMessageBoxImpl( 253 parent, title, message, type, base::string16(), base::string16()); 254} 255 256MessageBoxResult ShowMessageBoxWithButtonText(gfx::NativeWindow parent, 257 const base::string16& title, 258 const base::string16& message, 259 const base::string16& yes_text, 260 const base::string16& no_text) { 261 return ShowMessageBoxImpl( 262 parent, title, message, MESSAGE_BOX_TYPE_QUESTION, yes_text, no_text); 263} 264 265} // namespace chrome 266