Home | History | Annotate | Download | only in autofill
      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