Home | History | Annotate | Download | only in views
      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