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