Home | History | Annotate | Download | only in ui
      1 // Copyright (c) 2011 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/input_window_dialog.h"
      6 
      7 #include "base/compiler_specific.h"
      8 #include "base/message_loop.h"
      9 #include "base/task.h"
     10 #include "grit/generated_resources.h"
     11 #include "views/controls/label.h"
     12 #include "views/controls/textfield/textfield.h"
     13 #include "views/controls/textfield/textfield_controller.h"
     14 #include "views/layout/grid_layout.h"
     15 #include "views/layout/layout_constants.h"
     16 #include "views/window/dialog_delegate.h"
     17 #include "views/window/window.h"
     18 
     19 // Width to make the text field, in pixels.
     20 static const int kTextfieldWidth = 200;
     21 
     22 class ContentView;
     23 
     24 // The Windows implementation of the cross platform input dialog interface.
     25 class WinInputWindowDialog : public InputWindowDialog {
     26  public:
     27   WinInputWindowDialog(HWND parent,
     28                        const std::wstring& window_title,
     29                        const std::wstring& label,
     30                        const std::wstring& contents,
     31                        Delegate* delegate);
     32   virtual ~WinInputWindowDialog();
     33 
     34   virtual void Show();
     35   virtual void Close();
     36 
     37   const std::wstring& window_title() const { return window_title_; }
     38   const std::wstring& label() const { return label_; }
     39   const std::wstring& contents() const { return contents_; }
     40 
     41   InputWindowDialog::Delegate* delegate() { return delegate_.get(); }
     42 
     43  private:
     44   // Our chrome views window.
     45   views::Window* window_;
     46 
     47   // Strings to feed to the on screen window.
     48   std::wstring window_title_;
     49   std::wstring label_;
     50   std::wstring contents_;
     51 
     52   // Our delegate. Consumes the window's output.
     53   scoped_ptr<InputWindowDialog::Delegate> delegate_;
     54 };
     55 
     56 // ContentView, as the name implies, is the content view for the InputWindow.
     57 // It registers accelerators that accept/cancel the input.
     58 class ContentView : public views::View,
     59                     public views::DialogDelegate,
     60                     public views::TextfieldController {
     61  public:
     62   explicit ContentView(WinInputWindowDialog* delegate)
     63       : delegate_(delegate),
     64         ALLOW_THIS_IN_INITIALIZER_LIST(focus_grabber_factory_(this)) {
     65     DCHECK(delegate_);
     66   }
     67 
     68   // views::DialogDelegate:
     69   virtual bool IsDialogButtonEnabled(
     70       MessageBoxFlags::DialogButton button) const;
     71   virtual bool Accept();
     72   virtual bool Cancel();
     73   virtual void DeleteDelegate();
     74   virtual std::wstring GetWindowTitle() const;
     75   virtual bool IsModal() const { return true; }
     76   virtual views::View* GetContentsView();
     77 
     78   // views::TextfieldController:
     79   virtual void ContentsChanged(views::Textfield* sender,
     80                                const std::wstring& new_contents);
     81   virtual bool HandleKeyEvent(views::Textfield*,
     82                               const views::KeyEvent&) {
     83     return false;
     84   }
     85 
     86  protected:
     87   // views::View:
     88   virtual void ViewHierarchyChanged(bool is_add,
     89                                     views::View* parent,
     90                                     views::View* child);
     91 
     92  private:
     93   // Set up dialog controls and layout.
     94   void InitControlLayout();
     95 
     96   // Sets focus to the first focusable element within the dialog.
     97   void FocusFirstFocusableControl();
     98 
     99   // The Textfield that the user can type into.
    100   views::Textfield* text_field_;
    101 
    102   // The delegate that the ContentView uses to communicate changes to the
    103   // caller.
    104   WinInputWindowDialog* delegate_;
    105 
    106   // Helps us set focus to the first Textfield in the window.
    107   ScopedRunnableMethodFactory<ContentView> focus_grabber_factory_;
    108 
    109   DISALLOW_COPY_AND_ASSIGN(ContentView);
    110 };
    111 
    112 ///////////////////////////////////////////////////////////////////////////////
    113 // ContentView, views::DialogDelegate implementation:
    114 
    115 bool ContentView::IsDialogButtonEnabled(
    116     MessageBoxFlags::DialogButton button) const {
    117   if (button == MessageBoxFlags::DIALOGBUTTON_OK &&
    118       !delegate_->delegate()->IsValid(text_field_->text())) {
    119     return false;
    120   }
    121   return true;
    122 }
    123 
    124 bool ContentView::Accept() {
    125   delegate_->delegate()->InputAccepted(text_field_->text());
    126   return true;
    127 }
    128 
    129 bool ContentView::Cancel() {
    130   delegate_->delegate()->InputCanceled();
    131   return true;
    132 }
    133 
    134 void ContentView::DeleteDelegate() {
    135   delete delegate_;
    136 }
    137 
    138 std::wstring ContentView::GetWindowTitle() const {
    139   return delegate_->window_title();
    140 }
    141 
    142 views::View* ContentView::GetContentsView() {
    143   return this;
    144 }
    145 
    146 ///////////////////////////////////////////////////////////////////////////////
    147 // ContentView, views::TextfieldController implementation:
    148 
    149 void ContentView::ContentsChanged(views::Textfield* sender,
    150                                   const std::wstring& new_contents) {
    151   GetDialogClientView()->UpdateDialogButtons();
    152 }
    153 
    154 ///////////////////////////////////////////////////////////////////////////////
    155 // ContentView, protected:
    156 
    157 void ContentView::ViewHierarchyChanged(bool is_add,
    158                                        views::View* parent,
    159                                        views::View* child) {
    160   if (is_add && child == this)
    161     InitControlLayout();
    162 }
    163 
    164 ///////////////////////////////////////////////////////////////////////////////
    165 // ContentView, private:
    166 
    167 void ContentView::InitControlLayout() {
    168   text_field_ = new views::Textfield;
    169   text_field_->SetText(delegate_->contents());
    170   text_field_->SetController(this);
    171 
    172   using views::ColumnSet;
    173   using views::GridLayout;
    174 
    175   // TODO(sky): Vertical alignment should be baseline.
    176   GridLayout* layout = GridLayout::CreatePanel(this);
    177   SetLayoutManager(layout);
    178 
    179   ColumnSet* c1 = layout->AddColumnSet(0);
    180   c1->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0,
    181                 GridLayout::USE_PREF, 0, 0);
    182   c1->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
    183   c1->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1,
    184                 GridLayout::USE_PREF, kTextfieldWidth, kTextfieldWidth);
    185 
    186   layout->StartRow(0, 0);
    187   views::Label* label = new views::Label(delegate_->label());
    188   layout->AddView(label);
    189   layout->AddView(text_field_);
    190 
    191   MessageLoop::current()->PostTask(FROM_HERE,
    192       focus_grabber_factory_.NewRunnableMethod(
    193           &ContentView::FocusFirstFocusableControl));
    194 }
    195 
    196 void ContentView::FocusFirstFocusableControl() {
    197   text_field_->SelectAll();
    198   text_field_->RequestFocus();
    199 }
    200 
    201 WinInputWindowDialog::WinInputWindowDialog(HWND parent,
    202                                            const std::wstring& window_title,
    203                                            const std::wstring& label,
    204                                            const std::wstring& contents,
    205                                            Delegate* delegate)
    206     : window_title_(window_title),
    207       label_(label),
    208       contents_(contents),
    209       delegate_(delegate) {
    210   window_ = views::Window::CreateChromeWindow(parent, gfx::Rect(),
    211                                               new ContentView(this));
    212   window_->client_view()->AsDialogClientView()->UpdateDialogButtons();
    213 }
    214 
    215 WinInputWindowDialog::~WinInputWindowDialog() {
    216 }
    217 
    218 void WinInputWindowDialog::Show() {
    219   window_->Show();
    220 }
    221 
    222 void WinInputWindowDialog::Close() {
    223   window_->CloseWindow();
    224 }
    225 
    226 // static
    227 InputWindowDialog* InputWindowDialog::Create(HWND parent,
    228                                              const std::wstring& window_title,
    229                                              const std::wstring& label,
    230                                              const std::wstring& contents,
    231                                              Delegate* delegate) {
    232   return new WinInputWindowDialog(parent,
    233                                   window_title,
    234                                   label,
    235                                   contents,
    236                                   delegate);
    237 }
    238