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 30namespace { 31 32// Default placeholder text color. 33const SkColor kDefaultPlaceholderTextColor = SK_ColorLTGRAY; 34 35gfx::FontList GetDefaultFontList() { 36 return ResourceBundle::GetSharedInstance().GetFontList( 37 ResourceBundle::BaseFont); 38} 39 40} // namespace 41 42namespace views { 43 44// static 45const char Textfield::kViewClassName[] = "Textfield"; 46 47// static 48size_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 58Textfield::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 86Textfield::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 116Textfield::~Textfield() { 117} 118 119void Textfield::SetController(TextfieldController* controller) { 120 controller_ = controller; 121} 122 123TextfieldController* Textfield::GetController() const { 124 return controller_; 125} 126 127void 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 137bool Textfield::IsObscured() const { 138 return style_ & STYLE_OBSCURED; 139} 140 141void 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 153ui::TextInputType Textfield::GetTextInputType() const { 154 if (read_only() || !enabled()) 155 return ui::TEXT_INPUT_TYPE_NONE; 156 return text_input_type_; 157} 158 159void 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 166void Textfield::SetText(const string16& text) { 167 text_ = text; 168 if (native_wrapper_) 169 native_wrapper_->UpdateText(); 170} 171 172void Textfield::AppendText(const string16& text) { 173 text_ += text; 174 if (native_wrapper_) 175 native_wrapper_->AppendText(text); 176} 177 178void Textfield::InsertOrReplaceText(const string16& text) { 179 if (native_wrapper_) { 180 native_wrapper_->InsertOrReplaceText(text); 181 text_ = native_wrapper_->GetText(); 182 } 183} 184 185base::i18n::TextDirection Textfield::GetTextDirection() const { 186 return native_wrapper_ ? 187 native_wrapper_->GetTextDirection() : base::i18n::UNKNOWN_DIRECTION; 188} 189 190void Textfield::SelectAll(bool reversed) { 191 if (native_wrapper_) 192 native_wrapper_->SelectAll(reversed); 193} 194 195string16 Textfield::GetSelectedText() const { 196 return native_wrapper_ ? native_wrapper_->GetSelectedText() : string16(); 197} 198 199void Textfield::ClearSelection() const { 200 if (native_wrapper_) 201 native_wrapper_->ClearSelection(); 202} 203 204bool Textfield::HasSelection() const { 205 return native_wrapper_ && !native_wrapper_->GetSelectedRange().is_empty(); 206} 207 208SkColor 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 217void Textfield::SetTextColor(SkColor color) { 218 text_color_ = color; 219 use_default_text_color_ = false; 220 if (native_wrapper_) 221 native_wrapper_->UpdateTextColor(); 222} 223 224void Textfield::UseDefaultTextColor() { 225 use_default_text_color_ = true; 226 if (native_wrapper_) 227 native_wrapper_->UpdateTextColor(); 228} 229 230SkColor 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 239void Textfield::SetBackgroundColor(SkColor color) { 240 background_color_ = color; 241 use_default_background_color_ = false; 242 if (native_wrapper_) 243 native_wrapper_->UpdateBackgroundColor(); 244} 245 246void Textfield::UseDefaultBackgroundColor() { 247 use_default_background_color_ = true; 248 if (native_wrapper_) 249 native_wrapper_->UpdateBackgroundColor(); 250} 251 252bool Textfield::GetCursorEnabled() const { 253 return native_wrapper_ && native_wrapper_->GetCursorEnabled(); 254} 255 256void Textfield::SetCursorEnabled(bool enabled) { 257 if (native_wrapper_) 258 native_wrapper_->SetCursorEnabled(enabled); 259} 260 261void Textfield::SetFontList(const gfx::FontList& font_list) { 262 font_list_ = font_list; 263 if (native_wrapper_) 264 native_wrapper_->UpdateFont(); 265 PreferredSizeChanged(); 266} 267 268const gfx::Font& Textfield::GetPrimaryFont() const { 269 return font_list_.GetPrimaryFont(); 270} 271 272void Textfield::SetFont(const gfx::Font& font) { 273 SetFontList(gfx::FontList(font)); 274} 275 276void 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 288void 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 300void Textfield::RemoveBorder() { 301 if (!draw_border_) 302 return; 303 304 draw_border_ = false; 305 if (native_wrapper_) 306 native_wrapper_->UpdateBorder(); 307} 308 309base::string16 Textfield::GetPlaceholderText() const { 310 return placeholder_text_; 311} 312 313bool 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 322bool 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 331void 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 346void 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 357bool Textfield::IsIMEComposing() const { 358 return native_wrapper_ && native_wrapper_->IsIMEComposing(); 359} 360 361gfx::Range Textfield::GetSelectedRange() const { 362 return native_wrapper_->GetSelectedRange(); 363} 364 365void Textfield::SelectRange(const gfx::Range& range) { 366 native_wrapper_->SelectRange(range); 367} 368 369gfx::SelectionModel Textfield::GetSelectionModel() const { 370 return native_wrapper_->GetSelectionModel(); 371} 372 373void Textfield::SelectSelectionModel(const gfx::SelectionModel& sel) { 374 native_wrapper_->SelectSelectionModel(sel); 375} 376 377size_t Textfield::GetCursorPosition() const { 378 return native_wrapper_->GetCursorPosition(); 379} 380 381void Textfield::SetColor(SkColor value) { 382 return native_wrapper_->SetColor(value); 383} 384 385void Textfield::ApplyColor(SkColor value, const gfx::Range& range) { 386 return native_wrapper_->ApplyColor(value, range); 387} 388 389void Textfield::SetStyle(gfx::TextStyle style, bool value) { 390 return native_wrapper_->SetStyle(style, value); 391} 392 393void Textfield::ApplyStyle(gfx::TextStyle style, 394 bool value, 395 const gfx::Range& range) { 396 return native_wrapper_->ApplyStyle(style, value, range); 397} 398 399void Textfield::ClearEditHistory() { 400 native_wrapper_->ClearEditHistory(); 401} 402 403void Textfield::SetAccessibleName(const string16& name) { 404 accessible_name_ = name; 405} 406 407void Textfield::ExecuteCommand(int command_id) { 408 native_wrapper_->ExecuteTextCommand(command_id); 409} 410 411void Textfield::SetFocusPainter(scoped_ptr<Painter> focus_painter) { 412 focus_painter_ = focus_painter.Pass(); 413} 414 415bool Textfield::HasTextBeingDragged() { 416 return native_wrapper_->HasTextBeingDragged(); 417} 418 419//////////////////////////////////////////////////////////////////////////////// 420// Textfield, View overrides: 421 422void Textfield::Layout() { 423 if (native_wrapper_) { 424 native_wrapper_->GetView()->SetBoundsRect(GetContentsBounds()); 425 native_wrapper_->GetView()->Layout(); 426 } 427} 428 429int 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 436gfx::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 447void Textfield::AboutToRequestFocusFromTabTraversal(bool reverse) { 448 SelectAll(false); 449} 450 451bool 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 457void Textfield::OnPaint(gfx::Canvas* canvas) { 458 View::OnPaint(canvas); 459 if (NativeViewHost::kRenderNativeControlFocus) 460 Painter::PaintFocusPainter(this, canvas, focus_painter_.get()); 461} 462 463bool Textfield::OnKeyPressed(const ui::KeyEvent& e) { 464 return native_wrapper_ && native_wrapper_->HandleKeyPressed(e); 465} 466 467bool Textfield::OnKeyReleased(const ui::KeyEvent& e) { 468 return native_wrapper_ && native_wrapper_->HandleKeyReleased(e); 469} 470 471bool Textfield::OnMouseDragged(const ui::MouseEvent& e) { 472 if (!e.IsOnlyRightMouseButton()) 473 return View::OnMouseDragged(e); 474 return true; 475} 476 477void 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 493void Textfield::OnBlur() { 494 if (native_wrapper_) 495 native_wrapper_->HandleBlur(); 496 497 // Border typically draws focus indicator. 498 SchedulePaint(); 499} 500 501void 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 521ui::TextInputClient* Textfield::GetTextInputClient() { 522 return native_wrapper_ ? native_wrapper_->GetTextInputClient() : NULL; 523} 524 525gfx::Point Textfield::GetKeyboardContextMenuLocation() { 526 return native_wrapper_ ? native_wrapper_->GetContextMenuLocation() : 527 View::GetKeyboardContextMenuLocation(); 528} 529 530void Textfield::OnEnabledChanged() { 531 View::OnEnabledChanged(); 532 if (native_wrapper_) 533 native_wrapper_->UpdateEnabled(); 534} 535 536void 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 548const char* Textfield::GetClassName() const { 549 return kViewClassName; 550} 551 552//////////////////////////////////////////////////////////////////////////////// 553// Textfield, private: 554 555gfx::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 562void 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 573NativeTextfieldWrapper* NativeTextfieldWrapper::CreateWrapper( 574 Textfield* field) { 575 return new NativeTextfieldViews(field); 576} 577 578} // namespace views 579