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