• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ExpandingTextfield(const base::string16 & default_value,const base::string16 & placeholder,bool multiline,views::TextfieldController * controller)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 
~ExpandingTextfield()49 ExpandingTextfield::~ExpandingTextfield() {}
50 
SetText(const base::string16 & text)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 
GetText()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 
SetInvalid(bool invalid)82 void ExpandingTextfield::SetInvalid(bool invalid) {
83   textfields_.front()->SetInvalid(invalid);
84 }
85 
SetDefaultWidthInCharacters(int chars)86 void ExpandingTextfield::SetDefaultWidthInCharacters(int chars) {
87   ForEachTextfield(&DecoratedTextfield::set_default_width_in_chars, chars);
88 }
89 
SetPlaceholderText(const base::string16 & placeholder)90 void ExpandingTextfield::SetPlaceholderText(const base::string16& placeholder) {
91   ForEachTextfield<views::Textfield, const base::string16&>(
92       &DecoratedTextfield::set_placeholder_text, placeholder);
93 }
94 
SetIcon(const gfx::Image & icon)95 void ExpandingTextfield::SetIcon(const gfx::Image& icon) {
96   textfields_.front()->SetIcon(icon);
97 }
98 
SetTooltipIcon(const base::string16 & text)99 void ExpandingTextfield::SetTooltipIcon(const base::string16& text) {
100   textfields_.front()->SetTooltipIcon(text);
101 }
102 
SetEditable(bool editable)103 void ExpandingTextfield::SetEditable(bool editable) {
104   ForEachTextfield(&DecoratedTextfield::SetEditable, editable);
105 }
106 
GetClassName() const107 const char* ExpandingTextfield::GetClassName() const {
108   return kViewClassName;
109 }
110 
ContentsChanged(views::Textfield * sender,const base::string16 & new_contents)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 
HandleKeyEvent(views::Textfield * sender,const ui::KeyEvent & key_event)126 bool ExpandingTextfield::HandleKeyEvent(views::Textfield* sender,
127                                         const ui::KeyEvent& key_event) {
128   return controller_->HandleKeyEvent(sender, key_event);
129 }
130 
HandleMouseEvent(views::Textfield * sender,const ui::MouseEvent & mouse_event)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>
ForEachTextfield(void (BaseType::* f)(Param),Param p) const137 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