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