simple_message_box_views.cc revision 010d83a9304c5a91596085d917d248abff47903a
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 "chrome/browser/ui/views/constrained_window_views.h" 11#include "grit/generated_resources.h" 12#include "ui/aura/window.h" 13#include "ui/base/l10n/l10n_util.h" 14#include "ui/base/resource/resource_bundle.h" 15#include "ui/gfx/native_widget_types.h" 16#include "ui/views/controls/message_box_view.h" 17#include "ui/views/widget/widget.h" 18#include "ui/views/window/dialog_delegate.h" 19#include "ui/wm/public/dispatcher_client.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 MessageBoxResult* result); 39 virtual ~SimpleMessageBoxViews(); 40 41 // Overridden from views::DialogDelegate: 42 virtual int GetDialogButtons() const OVERRIDE; 43 virtual base::string16 GetDialogButtonLabel( 44 ui::DialogButton button) const OVERRIDE; 45 virtual bool Cancel() OVERRIDE; 46 virtual bool Accept() OVERRIDE; 47 48 // Overridden from views::WidgetDelegate: 49 virtual base::string16 GetWindowTitle() const OVERRIDE; 50 virtual void DeleteDelegate() OVERRIDE; 51 virtual ui::ModalType GetModalType() const OVERRIDE; 52 virtual views::View* GetContentsView() OVERRIDE; 53 virtual views::Widget* GetWidget() OVERRIDE; 54 virtual const views::Widget* GetWidget() const OVERRIDE; 55 56 private: 57 58 // This terminates the nested message-loop. 59 void Done(); 60 61 const base::string16 window_title_; 62 const MessageBoxType type_; 63 base::string16 yes_text_; 64 base::string16 no_text_; 65 MessageBoxResult* result_; 66 bool is_system_modal_; 67 views::MessageBoxView* message_box_view_; 68 69 DISALLOW_COPY_AND_ASSIGN(SimpleMessageBoxViews); 70}; 71 72//////////////////////////////////////////////////////////////////////////////// 73// SimpleMessageBoxViews, public: 74 75SimpleMessageBoxViews::SimpleMessageBoxViews(const base::string16& title, 76 const base::string16& message, 77 MessageBoxType type, 78 const base::string16& yes_text, 79 const base::string16& no_text, 80 bool is_system_modal, 81 MessageBoxResult* result) 82 : window_title_(title), 83 type_(type), 84 yes_text_(yes_text), 85 no_text_(no_text), 86 result_(result), 87 is_system_modal_(is_system_modal), 88 message_box_view_(new views::MessageBoxView( 89 views::MessageBoxView::InitParams(message))) { 90 CHECK(result_); 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 113int SimpleMessageBoxViews::GetDialogButtons() const { 114 if (type_ == MESSAGE_BOX_TYPE_QUESTION || 115 type_ == MESSAGE_BOX_TYPE_OK_CANCEL) { 116 return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL; 117 } 118 119 return ui::DIALOG_BUTTON_OK; 120} 121 122base::string16 SimpleMessageBoxViews::GetDialogButtonLabel( 123 ui::DialogButton button) const { 124 if (button == ui::DIALOG_BUTTON_CANCEL) 125 return no_text_; 126 return yes_text_; 127} 128 129bool SimpleMessageBoxViews::Cancel() { 130 *result_ = MESSAGE_BOX_RESULT_NO; 131 Done(); 132 return true; 133} 134 135bool SimpleMessageBoxViews::Accept() { 136 *result_ = MESSAGE_BOX_RESULT_YES; 137 Done(); 138 return true; 139} 140 141base::string16 SimpleMessageBoxViews::GetWindowTitle() const { 142 return window_title_; 143} 144 145void SimpleMessageBoxViews::DeleteDelegate() { 146 delete this; 147} 148 149ui::ModalType SimpleMessageBoxViews::GetModalType() const { 150 return is_system_modal_ ? ui::MODAL_TYPE_SYSTEM : ui::MODAL_TYPE_WINDOW; 151} 152 153views::View* SimpleMessageBoxViews::GetContentsView() { 154 return message_box_view_; 155} 156 157views::Widget* SimpleMessageBoxViews::GetWidget() { 158 return message_box_view_->GetWidget(); 159} 160 161const views::Widget* SimpleMessageBoxViews::GetWidget() const { 162 return message_box_view_->GetWidget(); 163} 164 165//////////////////////////////////////////////////////////////////////////////// 166// SimpleMessageBoxViews, private: 167 168void SimpleMessageBoxViews::Done() { 169 aura::Window* window = GetWidget()->GetNativeView(); 170 aura::client::DispatcherClient* client = 171 aura::client::GetDispatcherClient(window->GetRootWindow()); 172 client->QuitNestedMessageLoop(); 173} 174 175#if defined(OS_WIN) 176UINT GetMessageBoxFlagsFromType(MessageBoxType type) { 177 UINT flags = MB_SETFOREGROUND; 178 switch (type) { 179 case MESSAGE_BOX_TYPE_INFORMATION: 180 return flags | MB_OK | MB_ICONINFORMATION; 181 case MESSAGE_BOX_TYPE_WARNING: 182 return flags | MB_OK | MB_ICONWARNING; 183 case MESSAGE_BOX_TYPE_QUESTION: 184 return flags | MB_YESNO | MB_ICONQUESTION; 185 case MESSAGE_BOX_TYPE_OK_CANCEL: 186 return flags | MB_OKCANCEL | MB_ICONWARNING; 187 } 188 NOTREACHED(); 189 return flags | MB_OK | MB_ICONWARNING; 190} 191#endif 192 193MessageBoxResult ShowMessageBoxImpl(gfx::NativeWindow parent, 194 const base::string16& title, 195 const base::string16& message, 196 MessageBoxType type, 197 const base::string16& yes_text, 198 const base::string16& no_text) { 199 // Views dialogs cannot be shown outside the UI thread message loop or if the 200 // ResourceBundle is not initialized yet. 201 // Fallback to logging with a default response or a Windows MessageBox. 202#if defined(OS_WIN) 203 if (!base::MessageLoopForUI::IsCurrent() || 204 !base::MessageLoopForUI::current()->is_running() || 205 !ResourceBundle::HasSharedInstance()) { 206 int result = ui::MessageBox(views::HWNDForNativeWindow(parent), message, 207 title, GetMessageBoxFlagsFromType(type)); 208 return (result == IDYES || result == IDOK) ? 209 MESSAGE_BOX_RESULT_YES : MESSAGE_BOX_RESULT_NO; 210 } 211#else 212 if (!base::MessageLoopForUI::IsCurrent() || 213 !ResourceBundle::HasSharedInstance()) { 214 LOG(ERROR) << "Unable to show a dialog outside the UI thread message loop: " 215 << title << " - " << message; 216 return MESSAGE_BOX_RESULT_NO; 217 } 218#endif 219 220 MessageBoxResult result = MESSAGE_BOX_RESULT_NO; 221 SimpleMessageBoxViews* dialog = new SimpleMessageBoxViews( 222 title, 223 message, 224 type, 225 yes_text, 226 no_text, 227 parent == NULL, // is_system_modal 228 &result); 229 CreateBrowserModalDialogViews(dialog, parent)->Show(); 230 231 // Use the widget's window itself so that the message loop exists when the 232 // dialog is closed by some other means than |Cancel| or |Accept|. 233 aura::Window* anchor = dialog->GetWidget()->GetNativeWindow(); 234 aura::client::DispatcherClient* client = 235 aura::client::GetDispatcherClient(anchor->GetRootWindow()); 236 client->RunWithDispatcher(NULL); 237 // NOTE: |dialog| will have been deleted by the time control returns here. 238 239 return result; 240} 241 242} // namespace 243 244MessageBoxResult ShowMessageBox(gfx::NativeWindow parent, 245 const base::string16& title, 246 const base::string16& message, 247 MessageBoxType type) { 248 return ShowMessageBoxImpl( 249 parent, title, message, type, base::string16(), base::string16()); 250} 251 252MessageBoxResult ShowMessageBoxWithButtonText(gfx::NativeWindow parent, 253 const base::string16& title, 254 const base::string16& message, 255 const base::string16& yes_text, 256 const base::string16& no_text) { 257 return ShowMessageBoxImpl( 258 parent, title, message, MESSAGE_BOX_TYPE_QUESTION, yes_text, no_text); 259} 260 261} // namespace chrome 262