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