1 // Copyright 2014 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/views/autofill/expanding_textfield.h" 6 7 #include "base/bind.h" 8 #include "base/strings/string_split.h" 9 #include "base/strings/string_util.h" 10 #include "base/strings/utf_string_conversions.h" 11 #include "chrome/browser/ui/views/autofill/decorated_textfield.h" 12 #include "ui/views/layout/box_layout.h" 13 14 namespace autofill { 15 16 namespace { 17 18 // The vertical padding between textfields. 19 const int kManualInputRowPadding = 10; 20 21 } // namespace 22 23 // static 24 const char ExpandingTextfield::kViewClassName[] = "autofill/ExpandingTextfield"; 25 26 ExpandingTextfield::ExpandingTextfield( 27 const base::string16& default_value, 28 const base::string16& placeholder, 29 bool multiline, 30 views::TextfieldController* controller) 31 : controller_(controller) { 32 textfields_.push_back( 33 new DecoratedTextfield(base::string16(), placeholder, this)); 34 if (multiline) { 35 textfields_.push_back( 36 new DecoratedTextfield(base::string16(), placeholder, this)); 37 } 38 SetText(default_value); 39 40 for (std::list<DecoratedTextfield*>::iterator iter = textfields_.begin(); 41 iter != textfields_.end(); ++iter) { 42 AddChildView(*iter); 43 } 44 45 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 46 kManualInputRowPadding)); 47 } 48 49 ExpandingTextfield::~ExpandingTextfield() {} 50 51 void ExpandingTextfield::SetText(const base::string16& text) { 52 textfields_.front()->SetText(text); 53 std::vector<base::string16> strings; 54 base::SplitStringDontTrim(text, '\n', &strings); 55 56 size_t i = 0; 57 for (std::list<DecoratedTextfield*>::iterator iter = textfields_.begin(); 58 iter != textfields_.end(); ++iter) { 59 (*iter)->SetText(i < strings.size() ? strings[i++] : base::string16()); 60 } 61 62 for (; i < strings.size(); ++i) { 63 textfields_.push_back(new DecoratedTextfield( 64 strings[i], 65 textfields_.front()->GetPlaceholderText(), 66 this)); 67 AddChildView(textfields_.back()); 68 PreferredSizeChanged(); 69 } 70 } 71 72 base::string16 ExpandingTextfield::GetText() { 73 base::string16 text = textfields_.front()->text(); 74 std::list<DecoratedTextfield*>::const_iterator iter = ++textfields_.begin(); 75 while (iter != textfields_.end()) { 76 text += base::ASCIIToUTF16("\n") + (*iter++)->text(); 77 } 78 base::TrimWhitespace(text, base::TRIM_ALL, &text); 79 return text; 80 } 81 82 void ExpandingTextfield::SetInvalid(bool invalid) { 83 textfields_.front()->SetInvalid(invalid); 84 } 85 86 void ExpandingTextfield::SetDefaultWidthInCharacters(int chars) { 87 ForEachTextfield(&DecoratedTextfield::set_default_width_in_chars, chars); 88 } 89 90 void ExpandingTextfield::SetPlaceholderText(const base::string16& placeholder) { 91 ForEachTextfield<views::Textfield, const base::string16&>( 92 &DecoratedTextfield::set_placeholder_text, placeholder); 93 } 94 95 void ExpandingTextfield::SetIcon(const gfx::Image& icon) { 96 textfields_.front()->SetIcon(icon); 97 } 98 99 void ExpandingTextfield::SetTooltipIcon(const base::string16& text) { 100 textfields_.front()->SetTooltipIcon(text); 101 } 102 103 void ExpandingTextfield::SetEditable(bool editable) { 104 ForEachTextfield(&DecoratedTextfield::SetEditable, editable); 105 } 106 107 const char* ExpandingTextfield::GetClassName() const { 108 return kViewClassName; 109 } 110 111 void ExpandingTextfield::ContentsChanged(views::Textfield* sender, 112 const base::string16& new_contents) { 113 if (textfields_.size() > 1 && sender == textfields_.back() && 114 !new_contents.empty()) { 115 textfields_.push_back( 116 new DecoratedTextfield(base::string16(), 117 sender->GetPlaceholderText(), 118 this)); 119 AddChildView(textfields_.back()); 120 PreferredSizeChanged(); 121 } 122 123 controller_->ContentsChanged(sender, new_contents); 124 } 125 126 bool ExpandingTextfield::HandleKeyEvent(views::Textfield* sender, 127 const ui::KeyEvent& key_event) { 128 return controller_->HandleKeyEvent(sender, key_event); 129 } 130 131 bool ExpandingTextfield::HandleMouseEvent(views::Textfield* sender, 132 const ui::MouseEvent& mouse_event) { 133 return controller_->HandleMouseEvent(sender, mouse_event); 134 } 135 136 template <typename BaseType, typename Param> 137 void ExpandingTextfield::ForEachTextfield( 138 void (BaseType::* f)(Param), Param p) const { 139 for (std::list<DecoratedTextfield*>::const_iterator iter = 140 textfields_.begin(); 141 iter != textfields_.end(); ++iter) { 142 base::Bind(f, base::Unretained(*iter), p).Run(); 143 } 144 } 145 146 } // namespace autofill 147