expanding_textfield.cc revision effb81e5f8246d0db0270817048dc992db66e9fb
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
14namespace autofill {
15
16namespace {
17
18// The vertical padding between textfields.
19const int kManualInputRowPadding = 10;
20
21}  // namespace
22
23// static
24const char ExpandingTextfield::kViewClassName[] = "autofill/ExpandingTextfield";
25
26ExpandingTextfield::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
49ExpandingTextfield::~ExpandingTextfield() {}
50
51void 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
72base::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
82void ExpandingTextfield::SetInvalid(bool invalid) {
83  textfields_.front()->SetInvalid(invalid);
84}
85
86void ExpandingTextfield::SetDefaultWidthInCharacters(int chars) {
87  ForEachTextfield(&DecoratedTextfield::set_default_width_in_chars, chars);
88}
89
90void ExpandingTextfield::SetPlaceholderText(const base::string16& placeholder) {
91  ForEachTextfield<views::Textfield, const base::string16&>(
92      &DecoratedTextfield::set_placeholder_text, placeholder);
93}
94
95void ExpandingTextfield::SetIcon(const gfx::Image& icon) {
96  textfields_.front()->SetIcon(icon);
97}
98
99void ExpandingTextfield::SetTooltipIcon(const base::string16& text) {
100  textfields_.front()->SetTooltipIcon(text);
101}
102
103void ExpandingTextfield::SetEditable(bool editable) {
104  ForEachTextfield(&DecoratedTextfield::SetEditable, editable);
105}
106
107const char* ExpandingTextfield::GetClassName() const {
108  return kViewClassName;
109}
110
111void 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
126bool ExpandingTextfield::HandleKeyEvent(views::Textfield* sender,
127                                        const ui::KeyEvent& key_event) {
128  return controller_->HandleKeyEvent(sender, key_event);
129}
130
131bool ExpandingTextfield::HandleMouseEvent(views::Textfield* sender,
132                                          const ui::MouseEvent& mouse_event) {
133  return controller_->HandleMouseEvent(sender, mouse_event);
134}
135
136template <typename BaseType, typename Param>
137void 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