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. 20static const int kTextfieldWidth = 200; 21 22class ContentView; 23 24// The Windows implementation of the cross platform input dialog interface. 25class 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. 58class 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 115bool 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 124bool ContentView::Accept() { 125 delegate_->delegate()->InputAccepted(text_field_->text()); 126 return true; 127} 128 129bool ContentView::Cancel() { 130 delegate_->delegate()->InputCanceled(); 131 return true; 132} 133 134void ContentView::DeleteDelegate() { 135 delete delegate_; 136} 137 138std::wstring ContentView::GetWindowTitle() const { 139 return delegate_->window_title(); 140} 141 142views::View* ContentView::GetContentsView() { 143 return this; 144} 145 146/////////////////////////////////////////////////////////////////////////////// 147// ContentView, views::TextfieldController implementation: 148 149void ContentView::ContentsChanged(views::Textfield* sender, 150 const std::wstring& new_contents) { 151 GetDialogClientView()->UpdateDialogButtons(); 152} 153 154/////////////////////////////////////////////////////////////////////////////// 155// ContentView, protected: 156 157void 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 167void 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 196void ContentView::FocusFirstFocusableControl() { 197 text_field_->SelectAll(); 198 text_field_->RequestFocus(); 199} 200 201WinInputWindowDialog::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 215WinInputWindowDialog::~WinInputWindowDialog() { 216} 217 218void WinInputWindowDialog::Show() { 219 window_->Show(); 220} 221 222void WinInputWindowDialog::Close() { 223 window_->CloseWindow(); 224} 225 226// static 227InputWindowDialog* 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