Home | History | Annotate | Download | only in textfield
      1 // Copyright (c) 2012 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 "ui/views/controls/textfield/textfield.h"
      6 
      7 #include <string>
      8 
      9 #include "base/command_line.h"
     10 #include "base/strings/string_util.h"
     11 #include "base/strings/utf_string_conversions.h"
     12 #include "ui/base/accessibility/accessible_view_state.h"
     13 #include "ui/base/ime/text_input_type.h"
     14 #include "ui/base/resource/resource_bundle.h"
     15 #include "ui/base/ui_base_switches.h"
     16 #include "ui/events/event.h"
     17 #include "ui/events/keycodes/keyboard_codes.h"
     18 #include "ui/gfx/insets.h"
     19 #include "ui/gfx/range/range.h"
     20 #include "ui/gfx/selection_model.h"
     21 #include "ui/native_theme/native_theme.h"
     22 #include "ui/views/controls/native/native_view_host.h"
     23 #include "ui/views/controls/textfield/native_textfield_views.h"
     24 #include "ui/views/controls/textfield/native_textfield_wrapper.h"
     25 #include "ui/views/controls/textfield/textfield_controller.h"
     26 #include "ui/views/painter.h"
     27 #include "ui/views/views_delegate.h"
     28 #include "ui/views/widget/widget.h"
     29 
     30 namespace {
     31 
     32 // Default placeholder text color.
     33 const SkColor kDefaultPlaceholderTextColor = SK_ColorLTGRAY;
     34 
     35 gfx::FontList GetDefaultFontList() {
     36   return ResourceBundle::GetSharedInstance().GetFontList(
     37       ResourceBundle::BaseFont);
     38 }
     39 
     40 }  // namespace
     41 
     42 namespace views {
     43 
     44 // static
     45 const char Textfield::kViewClassName[] = "Textfield";
     46 
     47 // static
     48 size_t Textfield::GetCaretBlinkMs() {
     49   static const size_t default_value = 500;
     50 #if defined(OS_WIN)
     51   static const size_t system_value = ::GetCaretBlinkTime();
     52   if (system_value != 0)
     53     return (system_value == INFINITE) ? 0 : system_value;
     54 #endif
     55   return default_value;
     56 }
     57 
     58 Textfield::Textfield()
     59     : native_wrapper_(NULL),
     60       controller_(NULL),
     61       style_(STYLE_DEFAULT),
     62       font_list_(GetDefaultFontList()),
     63       read_only_(false),
     64       default_width_in_chars_(0),
     65       draw_border_(true),
     66       text_color_(SK_ColorBLACK),
     67       use_default_text_color_(true),
     68       background_color_(SK_ColorWHITE),
     69       use_default_background_color_(true),
     70       horizontal_margins_were_set_(false),
     71       vertical_margins_were_set_(false),
     72       placeholder_text_color_(kDefaultPlaceholderTextColor),
     73       text_input_type_(ui::TEXT_INPUT_TYPE_TEXT),
     74       weak_ptr_factory_(this) {
     75   SetFocusable(true);
     76 
     77   if (ViewsDelegate::views_delegate) {
     78     obscured_reveal_duration_ = ViewsDelegate::views_delegate->
     79         GetDefaultTextfieldObscuredRevealDuration();
     80   }
     81 
     82   if (NativeViewHost::kRenderNativeControlFocus)
     83     focus_painter_ = Painter::CreateDashedFocusPainter();
     84 }
     85 
     86 Textfield::Textfield(StyleFlags style)
     87     : native_wrapper_(NULL),
     88       controller_(NULL),
     89       style_(style),
     90       font_list_(GetDefaultFontList()),
     91       read_only_(false),
     92       default_width_in_chars_(0),
     93       draw_border_(true),
     94       text_color_(SK_ColorBLACK),
     95       use_default_text_color_(true),
     96       background_color_(SK_ColorWHITE),
     97       use_default_background_color_(true),
     98       horizontal_margins_were_set_(false),
     99       vertical_margins_were_set_(false),
    100       placeholder_text_color_(kDefaultPlaceholderTextColor),
    101       text_input_type_(ui::TEXT_INPUT_TYPE_TEXT),
    102       weak_ptr_factory_(this) {
    103   SetFocusable(true);
    104   if (IsObscured())
    105     SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
    106 
    107   if (ViewsDelegate::views_delegate) {
    108     obscured_reveal_duration_ = ViewsDelegate::views_delegate->
    109         GetDefaultTextfieldObscuredRevealDuration();
    110   }
    111 
    112   if (NativeViewHost::kRenderNativeControlFocus)
    113     focus_painter_ = Painter::CreateDashedFocusPainter();
    114 }
    115 
    116 Textfield::~Textfield() {
    117 }
    118 
    119 void Textfield::SetController(TextfieldController* controller) {
    120   controller_ = controller;
    121 }
    122 
    123 TextfieldController* Textfield::GetController() const {
    124   return controller_;
    125 }
    126 
    127 void Textfield::SetReadOnly(bool read_only) {
    128   // Update read-only without changing the focusable state (or active, etc.).
    129   read_only_ = read_only;
    130   if (native_wrapper_) {
    131     native_wrapper_->UpdateReadOnly();
    132     native_wrapper_->UpdateTextColor();
    133     native_wrapper_->UpdateBackgroundColor();
    134   }
    135 }
    136 
    137 bool Textfield::IsObscured() const {
    138   return style_ & STYLE_OBSCURED;
    139 }
    140 
    141 void Textfield::SetObscured(bool obscured) {
    142   if (obscured) {
    143     style_ = static_cast<StyleFlags>(style_ | STYLE_OBSCURED);
    144     SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
    145   } else {
    146     style_ = static_cast<StyleFlags>(style_ & ~STYLE_OBSCURED);
    147     SetTextInputType(ui::TEXT_INPUT_TYPE_TEXT);
    148   }
    149   if (native_wrapper_)
    150     native_wrapper_->UpdateIsObscured();
    151 }
    152 
    153 ui::TextInputType Textfield::GetTextInputType() const {
    154   if (read_only() || !enabled())
    155     return ui::TEXT_INPUT_TYPE_NONE;
    156   return text_input_type_;
    157 }
    158 
    159 void Textfield::SetTextInputType(ui::TextInputType type) {
    160   text_input_type_ = type;
    161   bool should_be_obscured = type == ui::TEXT_INPUT_TYPE_PASSWORD;
    162   if (IsObscured() != should_be_obscured)
    163     SetObscured(should_be_obscured);
    164 }
    165 
    166 void Textfield::SetText(const string16& text) {
    167   text_ = text;
    168   if (native_wrapper_)
    169     native_wrapper_->UpdateText();
    170 }
    171 
    172 void Textfield::AppendText(const string16& text) {
    173   text_ += text;
    174   if (native_wrapper_)
    175     native_wrapper_->AppendText(text);
    176 }
    177 
    178 void Textfield::InsertOrReplaceText(const string16& text) {
    179   if (native_wrapper_) {
    180     native_wrapper_->InsertOrReplaceText(text);
    181     text_ = native_wrapper_->GetText();
    182   }
    183 }
    184 
    185 base::i18n::TextDirection Textfield::GetTextDirection() const {
    186   return native_wrapper_ ?
    187       native_wrapper_->GetTextDirection() : base::i18n::UNKNOWN_DIRECTION;
    188 }
    189 
    190 void Textfield::SelectAll(bool reversed) {
    191   if (native_wrapper_)
    192     native_wrapper_->SelectAll(reversed);
    193 }
    194 
    195 string16 Textfield::GetSelectedText() const {
    196   return native_wrapper_ ? native_wrapper_->GetSelectedText() : string16();
    197 }
    198 
    199 void Textfield::ClearSelection() const {
    200   if (native_wrapper_)
    201     native_wrapper_->ClearSelection();
    202 }
    203 
    204 bool Textfield::HasSelection() const {
    205   return native_wrapper_ && !native_wrapper_->GetSelectedRange().is_empty();
    206 }
    207 
    208 SkColor Textfield::GetTextColor() const {
    209   if (!use_default_text_color_)
    210     return text_color_;
    211 
    212   return GetNativeTheme()->GetSystemColor(read_only() ?
    213       ui::NativeTheme::kColorId_TextfieldReadOnlyColor :
    214       ui::NativeTheme::kColorId_TextfieldDefaultColor);
    215 }
    216 
    217 void Textfield::SetTextColor(SkColor color) {
    218   text_color_ = color;
    219   use_default_text_color_ = false;
    220   if (native_wrapper_)
    221     native_wrapper_->UpdateTextColor();
    222 }
    223 
    224 void Textfield::UseDefaultTextColor() {
    225   use_default_text_color_ = true;
    226   if (native_wrapper_)
    227     native_wrapper_->UpdateTextColor();
    228 }
    229 
    230 SkColor Textfield::GetBackgroundColor() const {
    231   if (!use_default_background_color_)
    232     return background_color_;
    233 
    234   return GetNativeTheme()->GetSystemColor(read_only() ?
    235       ui::NativeTheme::kColorId_TextfieldReadOnlyBackground :
    236       ui::NativeTheme::kColorId_TextfieldDefaultBackground);
    237 }
    238 
    239 void Textfield::SetBackgroundColor(SkColor color) {
    240   background_color_ = color;
    241   use_default_background_color_ = false;
    242   if (native_wrapper_)
    243     native_wrapper_->UpdateBackgroundColor();
    244 }
    245 
    246 void Textfield::UseDefaultBackgroundColor() {
    247   use_default_background_color_ = true;
    248   if (native_wrapper_)
    249     native_wrapper_->UpdateBackgroundColor();
    250 }
    251 
    252 bool Textfield::GetCursorEnabled() const {
    253   return native_wrapper_ && native_wrapper_->GetCursorEnabled();
    254 }
    255 
    256 void Textfield::SetCursorEnabled(bool enabled) {
    257   if (native_wrapper_)
    258     native_wrapper_->SetCursorEnabled(enabled);
    259 }
    260 
    261 void Textfield::SetFontList(const gfx::FontList& font_list) {
    262   font_list_ = font_list;
    263   if (native_wrapper_)
    264     native_wrapper_->UpdateFont();
    265   PreferredSizeChanged();
    266 }
    267 
    268 const gfx::Font& Textfield::GetPrimaryFont() const {
    269   return font_list_.GetPrimaryFont();
    270 }
    271 
    272 void Textfield::SetFont(const gfx::Font& font) {
    273   SetFontList(gfx::FontList(font));
    274 }
    275 
    276 void Textfield::SetHorizontalMargins(int left, int right) {
    277   if (horizontal_margins_were_set_ &&
    278       left == margins_.left() && right == margins_.right()) {
    279     return;
    280   }
    281   margins_.Set(margins_.top(), left, margins_.bottom(), right);
    282   horizontal_margins_were_set_ = true;
    283   if (native_wrapper_)
    284     native_wrapper_->UpdateHorizontalMargins();
    285   PreferredSizeChanged();
    286 }
    287 
    288 void Textfield::SetVerticalMargins(int top, int bottom) {
    289   if (vertical_margins_were_set_ &&
    290       top == margins_.top() && bottom == margins_.bottom()) {
    291     return;
    292   }
    293   margins_.Set(top, margins_.left(), bottom, margins_.right());
    294   vertical_margins_were_set_ = true;
    295   if (native_wrapper_)
    296     native_wrapper_->UpdateVerticalMargins();
    297   PreferredSizeChanged();
    298 }
    299 
    300 void Textfield::RemoveBorder() {
    301   if (!draw_border_)
    302     return;
    303 
    304   draw_border_ = false;
    305   if (native_wrapper_)
    306     native_wrapper_->UpdateBorder();
    307 }
    308 
    309 base::string16 Textfield::GetPlaceholderText() const {
    310   return placeholder_text_;
    311 }
    312 
    313 bool Textfield::GetHorizontalMargins(int* left, int* right) {
    314   if (!horizontal_margins_were_set_)
    315     return false;
    316 
    317   *left = margins_.left();
    318   *right = margins_.right();
    319   return true;
    320 }
    321 
    322 bool Textfield::GetVerticalMargins(int* top, int* bottom) {
    323   if (!vertical_margins_were_set_)
    324     return false;
    325 
    326   *top = margins_.top();
    327   *bottom = margins_.bottom();
    328   return true;
    329 }
    330 
    331 void Textfield::UpdateAllProperties() {
    332   if (native_wrapper_) {
    333     native_wrapper_->UpdateText();
    334     native_wrapper_->UpdateTextColor();
    335     native_wrapper_->UpdateBackgroundColor();
    336     native_wrapper_->UpdateReadOnly();
    337     native_wrapper_->UpdateFont();
    338     native_wrapper_->UpdateEnabled();
    339     native_wrapper_->UpdateBorder();
    340     native_wrapper_->UpdateIsObscured();
    341     native_wrapper_->UpdateHorizontalMargins();
    342     native_wrapper_->UpdateVerticalMargins();
    343   }
    344 }
    345 
    346 void Textfield::SyncText() {
    347   if (native_wrapper_) {
    348     string16 new_text = native_wrapper_->GetText();
    349     if (new_text != text_) {
    350       text_ = new_text;
    351       if (controller_)
    352         controller_->ContentsChanged(this, text_);
    353     }
    354   }
    355 }
    356 
    357 bool Textfield::IsIMEComposing() const {
    358   return native_wrapper_ && native_wrapper_->IsIMEComposing();
    359 }
    360 
    361 gfx::Range Textfield::GetSelectedRange() const {
    362   return native_wrapper_->GetSelectedRange();
    363 }
    364 
    365 void Textfield::SelectRange(const gfx::Range& range) {
    366   native_wrapper_->SelectRange(range);
    367 }
    368 
    369 gfx::SelectionModel Textfield::GetSelectionModel() const {
    370   return native_wrapper_->GetSelectionModel();
    371 }
    372 
    373 void Textfield::SelectSelectionModel(const gfx::SelectionModel& sel) {
    374   native_wrapper_->SelectSelectionModel(sel);
    375 }
    376 
    377 size_t Textfield::GetCursorPosition() const {
    378   return native_wrapper_->GetCursorPosition();
    379 }
    380 
    381 void Textfield::SetColor(SkColor value) {
    382   return native_wrapper_->SetColor(value);
    383 }
    384 
    385 void Textfield::ApplyColor(SkColor value, const gfx::Range& range) {
    386   return native_wrapper_->ApplyColor(value, range);
    387 }
    388 
    389 void Textfield::SetStyle(gfx::TextStyle style, bool value) {
    390   return native_wrapper_->SetStyle(style, value);
    391 }
    392 
    393 void Textfield::ApplyStyle(gfx::TextStyle style,
    394                            bool value,
    395                            const gfx::Range& range) {
    396   return native_wrapper_->ApplyStyle(style, value, range);
    397 }
    398 
    399 void Textfield::ClearEditHistory() {
    400   native_wrapper_->ClearEditHistory();
    401 }
    402 
    403 void Textfield::SetAccessibleName(const string16& name) {
    404   accessible_name_ = name;
    405 }
    406 
    407 void Textfield::ExecuteCommand(int command_id) {
    408   native_wrapper_->ExecuteTextCommand(command_id);
    409 }
    410 
    411 void Textfield::SetFocusPainter(scoped_ptr<Painter> focus_painter) {
    412   focus_painter_ = focus_painter.Pass();
    413 }
    414 
    415 bool Textfield::HasTextBeingDragged() {
    416   return native_wrapper_->HasTextBeingDragged();
    417 }
    418 
    419 ////////////////////////////////////////////////////////////////////////////////
    420 // Textfield, View overrides:
    421 
    422 void Textfield::Layout() {
    423   if (native_wrapper_) {
    424     native_wrapper_->GetView()->SetBoundsRect(GetContentsBounds());
    425     native_wrapper_->GetView()->Layout();
    426   }
    427 }
    428 
    429 int Textfield::GetBaseline() const {
    430   gfx::Insets insets = GetTextInsets();
    431   const int baseline = native_wrapper_ ?
    432       native_wrapper_->GetTextfieldBaseline() : font_list_.GetBaseline();
    433   return insets.top() + baseline;
    434 }
    435 
    436 gfx::Size Textfield::GetPreferredSize() {
    437   gfx::Insets insets = GetTextInsets();
    438 
    439   const int font_height = native_wrapper_ ? native_wrapper_->GetFontHeight() :
    440                                             font_list_.GetHeight();
    441   return gfx::Size(
    442       GetPrimaryFont().GetExpectedTextWidth(default_width_in_chars_)
    443       + insets.width(),
    444       font_height + insets.height());
    445 }
    446 
    447 void Textfield::AboutToRequestFocusFromTabTraversal(bool reverse) {
    448   SelectAll(false);
    449 }
    450 
    451 bool Textfield::SkipDefaultKeyEventProcessing(const ui::KeyEvent& e) {
    452   // Skip any accelerator handling of backspace; textfields handle this key.
    453   // Also skip processing of [Alt]+<num-pad digit> Unicode alt key codes.
    454   return e.key_code() == ui::VKEY_BACK || e.IsUnicodeKeyCode();
    455 }
    456 
    457 void Textfield::OnPaint(gfx::Canvas* canvas) {
    458   View::OnPaint(canvas);
    459   if (NativeViewHost::kRenderNativeControlFocus)
    460     Painter::PaintFocusPainter(this, canvas, focus_painter_.get());
    461 }
    462 
    463 bool Textfield::OnKeyPressed(const ui::KeyEvent& e) {
    464   return native_wrapper_ && native_wrapper_->HandleKeyPressed(e);
    465 }
    466 
    467 bool Textfield::OnKeyReleased(const ui::KeyEvent& e) {
    468   return native_wrapper_ && native_wrapper_->HandleKeyReleased(e);
    469 }
    470 
    471 bool Textfield::OnMouseDragged(const ui::MouseEvent& e) {
    472   if (!e.IsOnlyRightMouseButton())
    473     return View::OnMouseDragged(e);
    474   return true;
    475 }
    476 
    477 void Textfield::OnFocus() {
    478   if (native_wrapper_)
    479     native_wrapper_->HandleFocus();
    480 
    481   // Forward the focus to the wrapper if it exists.
    482   if (!native_wrapper_ || !native_wrapper_->SetFocus()) {
    483     // If there is no wrapper or the wrapper didn't take focus, call
    484     // View::Focus to clear the native focus so that we still get
    485     // keyboard messages.
    486     View::OnFocus();
    487   }
    488 
    489   // Border typically draws focus indicator.
    490   SchedulePaint();
    491 }
    492 
    493 void Textfield::OnBlur() {
    494   if (native_wrapper_)
    495     native_wrapper_->HandleBlur();
    496 
    497   // Border typically draws focus indicator.
    498   SchedulePaint();
    499 }
    500 
    501 void Textfield::GetAccessibleState(ui::AccessibleViewState* state) {
    502   state->role = ui::AccessibilityTypes::ROLE_TEXT;
    503   state->name = accessible_name_;
    504   if (read_only())
    505     state->state |= ui::AccessibilityTypes::STATE_READONLY;
    506   if (IsObscured())
    507     state->state |= ui::AccessibilityTypes::STATE_PROTECTED;
    508   state->value = text_;
    509 
    510   const gfx::Range range = native_wrapper_->GetSelectedRange();
    511   state->selection_start = range.start();
    512   state->selection_end = range.end();
    513 
    514   if (!read_only()) {
    515     state->set_value_callback =
    516         base::Bind(&Textfield::AccessibilitySetValue,
    517                    weak_ptr_factory_.GetWeakPtr());
    518   }
    519 }
    520 
    521 ui::TextInputClient* Textfield::GetTextInputClient() {
    522   return native_wrapper_ ? native_wrapper_->GetTextInputClient() : NULL;
    523 }
    524 
    525 gfx::Point Textfield::GetKeyboardContextMenuLocation() {
    526   return native_wrapper_ ? native_wrapper_->GetContextMenuLocation() :
    527                            View::GetKeyboardContextMenuLocation();
    528 }
    529 
    530 void Textfield::OnEnabledChanged() {
    531   View::OnEnabledChanged();
    532   if (native_wrapper_)
    533     native_wrapper_->UpdateEnabled();
    534 }
    535 
    536 void Textfield::ViewHierarchyChanged(
    537     const ViewHierarchyChangedDetails& details) {
    538   if (details.is_add && !native_wrapper_ && GetWidget()) {
    539     // The native wrapper's lifetime will be managed by the view hierarchy after
    540     // we call AddChildView.
    541     native_wrapper_ = NativeTextfieldWrapper::CreateWrapper(this);
    542     AddChildViewAt(native_wrapper_->GetView(), 0);
    543     Layout();
    544     UpdateAllProperties();
    545   }
    546 }
    547 
    548 const char* Textfield::GetClassName() const {
    549   return kViewClassName;
    550 }
    551 
    552 ////////////////////////////////////////////////////////////////////////////////
    553 // Textfield, private:
    554 
    555 gfx::Insets Textfield::GetTextInsets() const {
    556   gfx::Insets insets = GetInsets();
    557   if (draw_border_ && native_wrapper_)
    558     insets += native_wrapper_->CalculateInsets();
    559   return insets;
    560 }
    561 
    562 void Textfield::AccessibilitySetValue(const string16& new_value) {
    563   if (!read_only()) {
    564     SetText(new_value);
    565     ClearSelection();
    566   }
    567 }
    568 
    569 ////////////////////////////////////////////////////////////////////////////////
    570 // NativeTextfieldWrapper, public:
    571 
    572 // static
    573 NativeTextfieldWrapper* NativeTextfieldWrapper::CreateWrapper(
    574     Textfield* field) {
    575   return new NativeTextfieldViews(field);
    576 }
    577 
    578 }  // namespace views
    579