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 #endif 26 27 namespace chrome { 28 29 namespace { 30 31 // Multiple SimpleMessageBoxViews can show up at the same time. Each of these 32 // start a nested message-loop. However, these SimpleMessageBoxViews can be 33 // deleted in any order. This creates problems if a box in an inner-loop gets 34 // destroyed before a box in an outer-loop. So to avoid this, ref-counting is 35 // used so that the SimpleMessageBoxViews gets deleted at the right time. 36 class SimpleMessageBoxViews : public views::DialogDelegate, 37 public base::MessageLoop::Dispatcher, 38 public base::RefCounted<SimpleMessageBoxViews> { 39 public: 40 SimpleMessageBoxViews(const string16& title, 41 const string16& message, 42 MessageBoxType type); 43 44 MessageBoxResult result() const { return result_; } 45 46 // Overridden from views::DialogDelegate: 47 virtual int GetDialogButtons() const OVERRIDE; 48 virtual string16 GetDialogButtonLabel(ui::DialogButton button) const OVERRIDE; 49 virtual bool Cancel() OVERRIDE; 50 virtual bool Accept() OVERRIDE; 51 52 // Overridden from views::WidgetDelegate: 53 virtual string16 GetWindowTitle() const OVERRIDE; 54 virtual void DeleteDelegate() OVERRIDE; 55 virtual ui::ModalType GetModalType() const OVERRIDE; 56 virtual views::View* GetContentsView() OVERRIDE; 57 virtual views::Widget* GetWidget() OVERRIDE; 58 virtual const views::Widget* GetWidget() const OVERRIDE; 59 60 // Overridden from MessageLoop::Dispatcher: 61 virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE; 62 63 private: 64 friend class base::RefCounted<SimpleMessageBoxViews>; 65 virtual ~SimpleMessageBoxViews(); 66 67 const string16 window_title_; 68 const MessageBoxType type_; 69 MessageBoxResult result_; 70 views::MessageBoxView* message_box_view_; 71 72 // Set to false as soon as the user clicks a dialog button; this tells the 73 // dispatcher we're done. 74 bool should_show_dialog_; 75 76 DISALLOW_COPY_AND_ASSIGN(SimpleMessageBoxViews); 77 }; 78 79 //////////////////////////////////////////////////////////////////////////////// 80 // SimpleMessageBoxViews, public: 81 82 SimpleMessageBoxViews::SimpleMessageBoxViews(const string16& title, 83 const string16& message, 84 MessageBoxType type) 85 : window_title_(title), 86 type_(type), 87 result_(MESSAGE_BOX_RESULT_NO), 88 message_box_view_(new views::MessageBoxView( 89 views::MessageBoxView::InitParams(message))), 90 should_show_dialog_(true) { 91 AddRef(); 92 } 93 94 int SimpleMessageBoxViews::GetDialogButtons() const { 95 if (type_ == MESSAGE_BOX_TYPE_QUESTION || 96 type_ == MESSAGE_BOX_TYPE_OK_CANCEL) { 97 return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL; 98 } 99 100 return ui::DIALOG_BUTTON_OK; 101 } 102 103 string16 SimpleMessageBoxViews::GetDialogButtonLabel( 104 ui::DialogButton button) const { 105 if (type_ == MESSAGE_BOX_TYPE_QUESTION) { 106 return l10n_util::GetStringUTF16((button == ui::DIALOG_BUTTON_OK) ? 107 IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL : 108 IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL); 109 } 110 111 if (type_ == MESSAGE_BOX_TYPE_OK_CANCEL) { 112 return l10n_util::GetStringUTF16((button == ui::DIALOG_BUTTON_OK) ? 113 IDS_OK : IDS_CANCEL); 114 } 115 116 return l10n_util::GetStringUTF16(IDS_OK); 117 } 118 119 bool SimpleMessageBoxViews::Cancel() { 120 should_show_dialog_= false; 121 result_ = MESSAGE_BOX_RESULT_NO; 122 return true; 123 } 124 125 bool SimpleMessageBoxViews::Accept() { 126 should_show_dialog_ = false; 127 result_ = MESSAGE_BOX_RESULT_YES; 128 return true; 129 } 130 131 string16 SimpleMessageBoxViews::GetWindowTitle() const { 132 return window_title_; 133 } 134 135 void SimpleMessageBoxViews::DeleteDelegate() { 136 Release(); 137 } 138 139 ui::ModalType SimpleMessageBoxViews::GetModalType() const { 140 return ui::MODAL_TYPE_WINDOW; 141 } 142 143 views::View* SimpleMessageBoxViews::GetContentsView() { 144 return message_box_view_; 145 } 146 147 views::Widget* SimpleMessageBoxViews::GetWidget() { 148 return message_box_view_->GetWidget(); 149 } 150 151 const views::Widget* SimpleMessageBoxViews::GetWidget() const { 152 return message_box_view_->GetWidget(); 153 } 154 155 bool SimpleMessageBoxViews::Dispatch(const base::NativeEvent& event) { 156 #if defined(OS_WIN) 157 TranslateMessage(&event); 158 DispatchMessage(&event); 159 #elif defined(USE_AURA) 160 aura::Env::GetInstance()->GetDispatcher()->Dispatch(event); 161 #endif 162 return should_show_dialog_; 163 } 164 165 //////////////////////////////////////////////////////////////////////////////// 166 // SimpleMessageBoxViews, private: 167 168 SimpleMessageBoxViews::~SimpleMessageBoxViews() { 169 } 170 171 } // namespace 172 173 MessageBoxResult ShowMessageBox(gfx::NativeWindow parent, 174 const string16& title, 175 const string16& message, 176 MessageBoxType type) { 177 scoped_refptr<SimpleMessageBoxViews> dialog( 178 new SimpleMessageBoxViews(title, message, type)); 179 CreateBrowserModalDialogViews(dialog.get(), parent)->Show(); 180 181 #if defined(USE_AURA) 182 // Use the widget's window itself so that the message loop 183 // exists when the dialog is closed by some other means than 184 // |Cancel| or |Accept|. 185 aura::Window* anchor = parent ? 186 parent : dialog->GetWidget()->GetNativeWindow(); 187 aura::client::GetDispatcherClient(anchor->GetRootWindow()) 188 ->RunWithDispatcher(dialog.get(), anchor, true); 189 #else 190 { 191 base::MessageLoop::ScopedNestableTaskAllower allow( 192 base::MessageLoopForUI::current()); 193 base::RunLoop run_loop(dialog); 194 run_loop.Run(); 195 } 196 #endif 197 return dialog->result(); 198 } 199 200 } // namespace chrome 201