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.
5 #include "ui/views/controls/textfield/textfield.h"
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/views_delegate.h"
27 #include "ui/views/widget/widget.h"
30 #include "base/win/win_util.h"
31 // TODO(beng): this should be removed when the OS_WIN hack from
32 // ViewHierarchyChanged is removed.
33 #include "ui/views/controls/textfield/native_textfield_win.h"
38 // Default placeholder text color.
39 const SkColor kDefaultPlaceholderTextColor = SK_ColorLTGRAY;
41 gfx::FontList GetDefaultFontList() {
42 return ResourceBundle::GetSharedInstance().GetFontList(
43 ResourceBundle::BaseFont);
51 const char Textfield::kViewClassName[] = "Textfield";
54 bool Textfield::IsViewsTextfieldEnabled() {
55 #if defined(OS_WIN) && !defined(USE_AURA)
56 CommandLine* command_line = CommandLine::ForCurrentProcess();
57 if (command_line->HasSwitch(switches::kDisableViewsTextfield))
59 if (command_line->HasSwitch(switches::kEnableViewsTextfield))
61 // Avoid native Windows Textfields if the RichEdit library is not available.
62 static const HMODULE loaded_msftedit_dll = LoadLibrary(L"msftedit.dll");
63 if (!loaded_msftedit_dll)
70 size_t Textfield::GetCaretBlinkMs() {
71 static const size_t default_value = 500;
73 static const size_t system_value = ::GetCaretBlinkTime();
74 if (system_value != 0)
75 return (system_value == INFINITE) ? 0 : system_value;
80 Textfield::Textfield()
81 : native_wrapper_(NULL),
83 style_(STYLE_DEFAULT),
84 font_list_(GetDefaultFontList()),
86 default_width_in_chars_(0),
88 text_color_(SK_ColorBLACK),
89 use_default_text_color_(true),
90 background_color_(SK_ColorWHITE),
91 use_default_background_color_(true),
92 horizontal_margins_were_set_(false),
93 vertical_margins_were_set_(false),
94 placeholder_text_color_(kDefaultPlaceholderTextColor),
95 text_input_type_(ui::TEXT_INPUT_TYPE_TEXT),
96 weak_ptr_factory_(this) {
99 if (ViewsDelegate::views_delegate) {
100 obscured_reveal_duration_ = ViewsDelegate::views_delegate->
101 GetDefaultTextfieldObscuredRevealDuration();
105 Textfield::Textfield(StyleFlags style)
106 : native_wrapper_(NULL),
109 font_list_(GetDefaultFontList()),
111 default_width_in_chars_(0),
113 text_color_(SK_ColorBLACK),
114 use_default_text_color_(true),
115 background_color_(SK_ColorWHITE),
116 use_default_background_color_(true),
117 horizontal_margins_were_set_(false),
118 vertical_margins_were_set_(false),
119 placeholder_text_color_(kDefaultPlaceholderTextColor),
120 text_input_type_(ui::TEXT_INPUT_TYPE_TEXT),
121 weak_ptr_factory_(this) {
124 SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
126 if (ViewsDelegate::views_delegate) {
127 obscured_reveal_duration_ = ViewsDelegate::views_delegate->
128 GetDefaultTextfieldObscuredRevealDuration();
132 Textfield::~Textfield() {
135 void Textfield::SetController(TextfieldController* controller) {
136 controller_ = controller;
139 TextfieldController* Textfield::GetController() const {
143 void Textfield::SetReadOnly(bool read_only) {
144 // Update read-only without changing the focusable state (or active, etc.).
145 read_only_ = read_only;
146 if (native_wrapper_) {
147 native_wrapper_->UpdateReadOnly();
148 native_wrapper_->UpdateTextColor();
149 native_wrapper_->UpdateBackgroundColor();
153 bool Textfield::IsObscured() const {
154 return style_ & STYLE_OBSCURED;
157 void Textfield::SetObscured(bool obscured) {
159 style_ = static_cast<StyleFlags>(style_ | STYLE_OBSCURED);
160 SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
162 style_ = static_cast<StyleFlags>(style_ & ~STYLE_OBSCURED);
163 SetTextInputType(ui::TEXT_INPUT_TYPE_TEXT);
166 native_wrapper_->UpdateIsObscured();
169 ui::TextInputType Textfield::GetTextInputType() const {
170 if (read_only() || !enabled())
171 return ui::TEXT_INPUT_TYPE_NONE;
172 return text_input_type_;
175 void Textfield::SetTextInputType(ui::TextInputType type) {
176 text_input_type_ = type;
177 bool should_be_obscured = type == ui::TEXT_INPUT_TYPE_PASSWORD;
178 if (IsObscured() != should_be_obscured)
179 SetObscured(should_be_obscured);
182 void Textfield::SetText(const string16& text) {
185 native_wrapper_->UpdateText();
188 void Textfield::AppendText(const string16& text) {
191 native_wrapper_->AppendText(text);
194 void Textfield::InsertOrReplaceText(const string16& text) {
195 if (native_wrapper_) {
196 native_wrapper_->InsertOrReplaceText(text);
197 text_ = native_wrapper_->GetText();
201 base::i18n::TextDirection Textfield::GetTextDirection() const {
202 return native_wrapper_ ?
203 native_wrapper_->GetTextDirection() : base::i18n::UNKNOWN_DIRECTION;
206 void Textfield::SelectAll(bool reversed) {
208 native_wrapper_->SelectAll(reversed);
211 string16 Textfield::GetSelectedText() const {
212 return native_wrapper_ ? native_wrapper_->GetSelectedText() : string16();
215 void Textfield::ClearSelection() const {
217 native_wrapper_->ClearSelection();
220 bool Textfield::HasSelection() const {
221 return native_wrapper_ && !native_wrapper_->GetSelectedRange().is_empty();
224 SkColor Textfield::GetTextColor() const {
225 if (!use_default_text_color_)
228 return GetNativeTheme()->GetSystemColor(read_only() ?
229 ui::NativeTheme::kColorId_TextfieldReadOnlyColor :
230 ui::NativeTheme::kColorId_TextfieldDefaultColor);
233 void Textfield::SetTextColor(SkColor color) {
235 use_default_text_color_ = false;
237 native_wrapper_->UpdateTextColor();
240 void Textfield::UseDefaultTextColor() {
241 use_default_text_color_ = true;
243 native_wrapper_->UpdateTextColor();
246 SkColor Textfield::GetBackgroundColor() const {
247 if (!use_default_background_color_)
248 return background_color_;
250 return GetNativeTheme()->GetSystemColor(read_only() ?
251 ui::NativeTheme::kColorId_TextfieldReadOnlyBackground :
252 ui::NativeTheme::kColorId_TextfieldDefaultBackground);
255 void Textfield::SetBackgroundColor(SkColor color) {
256 background_color_ = color;
257 use_default_background_color_ = false;
259 native_wrapper_->UpdateBackgroundColor();
262 void Textfield::UseDefaultBackgroundColor() {
263 use_default_background_color_ = true;
265 native_wrapper_->UpdateBackgroundColor();
268 bool Textfield::GetCursorEnabled() const {
269 return native_wrapper_ && native_wrapper_->GetCursorEnabled();
272 void Textfield::SetCursorEnabled(bool enabled) {
274 native_wrapper_->SetCursorEnabled(enabled);
277 void Textfield::SetFontList(const gfx::FontList& font_list) {
278 font_list_ = font_list;
280 native_wrapper_->UpdateFont();
281 PreferredSizeChanged();
284 const gfx::Font& Textfield::GetPrimaryFont() const {
285 return font_list_.GetPrimaryFont();
288 void Textfield::SetFont(const gfx::Font& font) {
289 SetFontList(gfx::FontList(font));
292 void Textfield::SetHorizontalMargins(int left, int right) {
293 margins_.Set(margins_.top(), left, margins_.bottom(), right);
294 horizontal_margins_were_set_ = true;
296 native_wrapper_->UpdateHorizontalMargins();
297 PreferredSizeChanged();
300 void Textfield::SetVerticalMargins(int top, int bottom) {
301 margins_.Set(top, margins_.left(), bottom, margins_.right());
302 vertical_margins_were_set_ = true;
304 native_wrapper_->UpdateVerticalMargins();
305 PreferredSizeChanged();
308 void Textfield::RemoveBorder() {
312 draw_border_ = false;
314 native_wrapper_->UpdateBorder();
317 base::string16 Textfield::GetPlaceholderText() const {
318 return placeholder_text_;
321 bool Textfield::GetHorizontalMargins(int* left, int* right) {
322 if (!horizontal_margins_were_set_)
325 *left = margins_.left();
326 *right = margins_.right();
330 bool Textfield::GetVerticalMargins(int* top, int* bottom) {
331 if (!vertical_margins_were_set_)
334 *top = margins_.top();
335 *bottom = margins_.bottom();
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();
354 void Textfield::SyncText() {
355 if (native_wrapper_) {
356 string16 new_text = native_wrapper_->GetText();
357 if (new_text != text_) {
360 controller_->ContentsChanged(this, text_);
365 bool Textfield::IsIMEComposing() const {
366 return native_wrapper_ && native_wrapper_->IsIMEComposing();
369 gfx::Range Textfield::GetSelectedRange() const {
370 return native_wrapper_->GetSelectedRange();
373 void Textfield::SelectRange(const gfx::Range& range) {
374 native_wrapper_->SelectRange(range);
377 gfx::SelectionModel Textfield::GetSelectionModel() const {
378 return native_wrapper_->GetSelectionModel();
381 void Textfield::SelectSelectionModel(const gfx::SelectionModel& sel) {
382 native_wrapper_->SelectSelectionModel(sel);
385 size_t Textfield::GetCursorPosition() const {
386 return native_wrapper_->GetCursorPosition();
389 void Textfield::SetColor(SkColor value) {
390 return native_wrapper_->SetColor(value);
393 void Textfield::ApplyColor(SkColor value, const gfx::Range& range) {
394 return native_wrapper_->ApplyColor(value, range);
397 void Textfield::SetStyle(gfx::TextStyle style, bool value) {
398 return native_wrapper_->SetStyle(style, value);
401 void Textfield::ApplyStyle(gfx::TextStyle style,
403 const gfx::Range& range) {
404 return native_wrapper_->ApplyStyle(style, value, range);
407 void Textfield::ClearEditHistory() {
408 native_wrapper_->ClearEditHistory();
411 void Textfield::SetAccessibleName(const string16& name) {
412 accessible_name_ = name;
415 void Textfield::ExecuteCommand(int command_id) {
416 native_wrapper_->ExecuteTextCommand(command_id);
419 bool Textfield::HasTextBeingDragged() {
420 return native_wrapper_->HasTextBeingDragged();
423 ////////////////////////////////////////////////////////////////////////////////
424 // Textfield, View overrides:
426 void Textfield::Layout() {
427 if (native_wrapper_) {
428 native_wrapper_->GetView()->SetBoundsRect(GetContentsBounds());
429 native_wrapper_->GetView()->Layout();
433 int Textfield::GetBaseline() const {
434 gfx::Insets insets = GetTextInsets();
435 const int baseline = native_wrapper_ ?
436 native_wrapper_->GetTextfieldBaseline() : font_list_.GetBaseline();
437 return insets.top() + baseline;
440 gfx::Size Textfield::GetPreferredSize() {
441 gfx::Insets insets = GetTextInsets();
443 const int font_height = native_wrapper_ ? native_wrapper_->GetFontHeight() :
444 font_list_.GetHeight();
446 GetPrimaryFont().GetExpectedTextWidth(default_width_in_chars_)
448 font_height + insets.height());
451 void Textfield::AboutToRequestFocusFromTabTraversal(bool reverse) {
455 bool Textfield::SkipDefaultKeyEventProcessing(const ui::KeyEvent& e) {
456 // Skip any accelerator handling of backspace; textfields handle this key.
457 // Also skip processing of [Alt]+<num-pad digit> Unicode alt key codes.
458 return e.key_code() == ui::VKEY_BACK || e.IsUnicodeKeyCode();
461 void Textfield::OnPaintFocusBorder(gfx::Canvas* canvas) {
462 if (NativeViewHost::kRenderNativeControlFocus)
463 View::OnPaintFocusBorder(canvas);
466 bool Textfield::OnKeyPressed(const ui::KeyEvent& e) {
467 return native_wrapper_ && native_wrapper_->HandleKeyPressed(e);
470 bool Textfield::OnKeyReleased(const ui::KeyEvent& e) {
471 return native_wrapper_ && native_wrapper_->HandleKeyReleased(e);
474 bool Textfield::OnMouseDragged(const ui::MouseEvent& e) {
475 if (!e.IsOnlyRightMouseButton())
476 return View::OnMouseDragged(e);
480 void Textfield::OnFocus() {
482 native_wrapper_->HandleFocus();
484 // Forward the focus to the wrapper if it exists.
485 if (!native_wrapper_ || !native_wrapper_->SetFocus()) {
486 // If there is no wrapper or the wrapper didn't take focus, call
487 // View::Focus to clear the native focus so that we still get
488 // keyboard messages.
493 void Textfield::OnBlur() {
495 native_wrapper_->HandleBlur();
498 void Textfield::GetAccessibleState(ui::AccessibleViewState* state) {
499 state->role = ui::AccessibilityTypes::ROLE_TEXT;
500 state->name = accessible_name_;
502 state->state |= ui::AccessibilityTypes::STATE_READONLY;
504 state->state |= ui::AccessibilityTypes::STATE_PROTECTED;
505 state->value = text_;
507 const gfx::Range range = native_wrapper_->GetSelectedRange();
508 state->selection_start = range.start();
509 state->selection_end = range.end();
512 state->set_value_callback =
513 base::Bind(&Textfield::AccessibilitySetValue,
514 weak_ptr_factory_.GetWeakPtr());
518 ui::TextInputClient* Textfield::GetTextInputClient() {
519 return native_wrapper_ ? native_wrapper_->GetTextInputClient() : NULL;
522 gfx::Point Textfield::GetKeyboardContextMenuLocation() {
523 return native_wrapper_ ? native_wrapper_->GetContextMenuLocation() :
524 View::GetKeyboardContextMenuLocation();
527 void Textfield::OnEnabledChanged() {
528 View::OnEnabledChanged();
530 native_wrapper_->UpdateEnabled();
533 void Textfield::ViewHierarchyChanged(
534 const ViewHierarchyChangedDetails& details) {
535 if (details.is_add && !native_wrapper_ && GetWidget()) {
536 // The native wrapper's lifetime will be managed by the view hierarchy after
537 // we call AddChildView.
538 native_wrapper_ = NativeTextfieldWrapper::CreateWrapper(this);
539 AddChildViewAt(native_wrapper_->GetView(), 0);
542 // TODO(beng): Move this initialization to NativeTextfieldWin once it
543 // subclasses NativeControlWin.
544 UpdateAllProperties();
546 #if defined(OS_WIN) && !defined(USE_AURA)
547 // TODO(beng): Remove this once NativeTextfieldWin subclasses
548 // NativeControlWin. This is currently called to perform post-AddChildView
549 // initialization for the wrapper.
551 // Remove the include for native_textfield_win.h above when you fix this.
552 if (!IsViewsTextfieldEnabled())
553 static_cast<NativeTextfieldWin*>(native_wrapper_)->AttachHack();
558 const char* Textfield::GetClassName() const {
559 return kViewClassName;
562 ////////////////////////////////////////////////////////////////////////////////
563 // Textfield, private:
565 gfx::Insets Textfield::GetTextInsets() const {
566 gfx::Insets insets = GetInsets();
567 if (draw_border_ && native_wrapper_)
568 insets += native_wrapper_->CalculateInsets();
572 void Textfield::AccessibilitySetValue(const string16& new_value) {
579 ////////////////////////////////////////////////////////////////////////////////
580 // NativeTextfieldWrapper, public:
583 NativeTextfieldWrapper* NativeTextfieldWrapper::CreateWrapper(
585 #if defined(OS_WIN) && !defined(USE_AURA)
586 if (!Textfield::IsViewsTextfieldEnabled())
587 return new NativeTextfieldWin(field);
589 return new NativeTextfieldViews(field);