OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/views/controls/textfield/textfield.h" | 5 #include "ui/views/controls/textfield/textfield.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/debug/trace_event.h" | 9 #include "base/command_line.h" |
10 #include "base/i18n/case_conversion.h" | 10 #include "base/strings/string_util.h" |
11 #include "grit/ui_strings.h" | 11 #include "base/strings/utf_string_conversions.h" |
12 #include "ui/base/accessibility/accessible_view_state.h" | 12 #include "ui/base/accessibility/accessible_view_state.h" |
13 #include "ui/base/dragdrop/drag_drop_types.h" | 13 #include "ui/base/ime/text_input_type.h" |
14 #include "ui/base/dragdrop/drag_utils.h" | |
15 #include "ui/base/resource/resource_bundle.h" | 14 #include "ui/base/resource/resource_bundle.h" |
16 #include "ui/base/ui_base_switches_util.h" | 15 #include "ui/base/ui_base_switches.h" |
17 #include "ui/events/event.h" | 16 #include "ui/events/event.h" |
18 #include "ui/events/keycodes/keyboard_codes.h" | 17 #include "ui/events/keycodes/keyboard_codes.h" |
19 #include "ui/gfx/canvas.h" | |
20 #include "ui/gfx/insets.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" | 21 #include "ui/native_theme/native_theme.h" |
22 #include "ui/views/background.h" | |
23 #include "ui/views/controls/focusable_border.h" | |
24 #include "ui/views/controls/menu/menu_item_view.h" | |
25 #include "ui/views/controls/menu/menu_model_adapter.h" | |
26 #include "ui/views/controls/menu/menu_runner.h" | |
27 #include "ui/views/controls/native/native_view_host.h" | 22 #include "ui/views/controls/native/native_view_host.h" |
| 23 #include "ui/views/controls/textfield/native_textfield_views.h" |
28 #include "ui/views/controls/textfield/textfield_controller.h" | 24 #include "ui/views/controls/textfield/textfield_controller.h" |
29 #include "ui/views/drag_utils.h" | |
30 #include "ui/views/ime/input_method.h" | |
31 #include "ui/views/metrics.h" | |
32 #include "ui/views/painter.h" | 25 #include "ui/views/painter.h" |
33 #include "ui/views/views_delegate.h" | 26 #include "ui/views/views_delegate.h" |
34 #include "ui/views/widget/widget.h" | 27 #include "ui/views/widget/widget.h" |
35 | 28 |
36 #if defined(USE_AURA) | |
37 #include "ui/base/cursor/cursor.h" | |
38 #endif | |
39 | |
40 #if defined(OS_WIN) && defined(USE_AURA) | |
41 #include "base/win/win_util.h" | |
42 #endif | |
43 | |
44 namespace { | 29 namespace { |
45 | 30 |
46 // Default placeholder text color. | 31 // Default placeholder text color. |
47 const SkColor kDefaultPlaceholderTextColor = SK_ColorLTGRAY; | 32 const SkColor kDefaultPlaceholderTextColor = SK_ColorLTGRAY; |
48 | 33 |
49 void ConvertRectToScreen(const views::View* src, gfx::Rect* r) { | 34 gfx::FontList GetDefaultFontList() { |
50 DCHECK(src); | 35 return ResourceBundle::GetSharedInstance().GetFontList( |
51 | 36 ResourceBundle::BaseFont); |
52 gfx::Point new_origin = r->origin(); | |
53 views::View::ConvertPointToScreen(src, &new_origin); | |
54 r->set_origin(new_origin); | |
55 } | 37 } |
56 | 38 |
57 } // namespace | 39 } // namespace |
58 | 40 |
59 namespace views { | 41 namespace views { |
60 | 42 |
61 // static | 43 // static |
62 const char Textfield::kViewClassName[] = "Textfield"; | 44 const char Textfield::kViewClassName[] = "Textfield"; |
63 | 45 |
64 // static | 46 // static |
65 size_t Textfield::GetCaretBlinkMs() { | 47 size_t Textfield::GetCaretBlinkMs() { |
66 static const size_t default_value = 500; | 48 static const size_t default_value = 500; |
67 #if defined(OS_WIN) | 49 #if defined(OS_WIN) |
68 static const size_t system_value = ::GetCaretBlinkTime(); | 50 static const size_t system_value = ::GetCaretBlinkTime(); |
69 if (system_value != 0) | 51 if (system_value != 0) |
70 return (system_value == INFINITE) ? 0 : system_value; | 52 return (system_value == INFINITE) ? 0 : system_value; |
71 #endif | 53 #endif |
72 return default_value; | 54 return default_value; |
73 } | 55 } |
74 | 56 |
75 Textfield::Textfield() | 57 Textfield::Textfield() |
76 : model_(new TextfieldViewsModel(this)), | 58 : textfield_view_(NULL), |
77 controller_(NULL), | 59 controller_(NULL), |
78 style_(STYLE_DEFAULT), | 60 style_(STYLE_DEFAULT), |
| 61 font_list_(GetDefaultFontList()), |
79 read_only_(false), | 62 read_only_(false), |
80 default_width_in_chars_(0), | 63 default_width_in_chars_(0), |
| 64 draw_border_(true), |
81 text_color_(SK_ColorBLACK), | 65 text_color_(SK_ColorBLACK), |
82 use_default_text_color_(true), | 66 use_default_text_color_(true), |
83 background_color_(SK_ColorWHITE), | 67 background_color_(SK_ColorWHITE), |
84 use_default_background_color_(true), | 68 use_default_background_color_(true), |
| 69 horizontal_margins_were_set_(false), |
| 70 vertical_margins_were_set_(false), |
85 placeholder_text_color_(kDefaultPlaceholderTextColor), | 71 placeholder_text_color_(kDefaultPlaceholderTextColor), |
86 text_input_type_(ui::TEXT_INPUT_TYPE_TEXT), | 72 text_input_type_(ui::TEXT_INPUT_TYPE_TEXT), |
87 skip_input_method_cancel_composition_(false), | |
88 is_cursor_visible_(false), | |
89 is_drop_cursor_visible_(false), | |
90 initiating_drag_(false), | |
91 aggregated_clicks_(0), | |
92 weak_ptr_factory_(this) { | 73 weak_ptr_factory_(this) { |
93 set_context_menu_controller(this); | |
94 set_drag_controller(this); | |
95 set_border(new FocusableBorder()); | |
96 SetFocusable(true); | 74 SetFocusable(true); |
97 | 75 |
98 if (ViewsDelegate::views_delegate) { | 76 if (ViewsDelegate::views_delegate) { |
99 obscured_reveal_duration_ = ViewsDelegate::views_delegate-> | 77 obscured_reveal_duration_ = ViewsDelegate::views_delegate-> |
100 GetDefaultTextfieldObscuredRevealDuration(); | 78 GetDefaultTextfieldObscuredRevealDuration(); |
101 } | 79 } |
102 | 80 |
103 if (NativeViewHost::kRenderNativeControlFocus) | 81 if (NativeViewHost::kRenderNativeControlFocus) |
104 focus_painter_ = Painter::CreateDashedFocusPainter(); | 82 focus_painter_ = Painter::CreateDashedFocusPainter(); |
105 } | 83 } |
106 | 84 |
107 Textfield::Textfield(StyleFlags style) | 85 Textfield::Textfield(StyleFlags style) |
108 : model_(new TextfieldViewsModel(this)), | 86 : textfield_view_(NULL), |
109 controller_(NULL), | 87 controller_(NULL), |
110 style_(style), | 88 style_(style), |
| 89 font_list_(GetDefaultFontList()), |
111 read_only_(false), | 90 read_only_(false), |
112 default_width_in_chars_(0), | 91 default_width_in_chars_(0), |
| 92 draw_border_(true), |
113 text_color_(SK_ColorBLACK), | 93 text_color_(SK_ColorBLACK), |
114 use_default_text_color_(true), | 94 use_default_text_color_(true), |
115 background_color_(SK_ColorWHITE), | 95 background_color_(SK_ColorWHITE), |
116 use_default_background_color_(true), | 96 use_default_background_color_(true), |
| 97 horizontal_margins_were_set_(false), |
| 98 vertical_margins_were_set_(false), |
117 placeholder_text_color_(kDefaultPlaceholderTextColor), | 99 placeholder_text_color_(kDefaultPlaceholderTextColor), |
118 text_input_type_(ui::TEXT_INPUT_TYPE_TEXT), | 100 text_input_type_(ui::TEXT_INPUT_TYPE_TEXT), |
119 skip_input_method_cancel_composition_(false), | |
120 is_cursor_visible_(false), | |
121 is_drop_cursor_visible_(false), | |
122 initiating_drag_(false), | |
123 aggregated_clicks_(0), | |
124 weak_ptr_factory_(this) { | 101 weak_ptr_factory_(this) { |
125 set_context_menu_controller(this); | |
126 set_drag_controller(this); | |
127 set_border(new FocusableBorder()); | |
128 SetFocusable(true); | 102 SetFocusable(true); |
129 | |
130 if (IsObscured()) | 103 if (IsObscured()) |
131 SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD); | 104 SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD); |
132 | 105 |
133 if (ViewsDelegate::views_delegate) { | 106 if (ViewsDelegate::views_delegate) { |
134 obscured_reveal_duration_ = ViewsDelegate::views_delegate-> | 107 obscured_reveal_duration_ = ViewsDelegate::views_delegate-> |
135 GetDefaultTextfieldObscuredRevealDuration(); | 108 GetDefaultTextfieldObscuredRevealDuration(); |
136 } | 109 } |
137 | 110 |
138 if (NativeViewHost::kRenderNativeControlFocus) | 111 if (NativeViewHost::kRenderNativeControlFocus) |
139 focus_painter_ = Painter::CreateDashedFocusPainter(); | 112 focus_painter_ = Painter::CreateDashedFocusPainter(); |
140 } | 113 } |
141 | 114 |
142 Textfield::~Textfield() { | 115 Textfield::~Textfield() { |
143 } | 116 } |
144 | 117 |
145 void Textfield::SetController(TextfieldController* controller) { | 118 void Textfield::SetController(TextfieldController* controller) { |
146 controller_ = controller; | 119 controller_ = controller; |
147 } | 120 } |
148 | 121 |
149 TextfieldController* Textfield::GetController() const { | 122 TextfieldController* Textfield::GetController() const { |
150 return controller_; | 123 return controller_; |
151 } | 124 } |
152 | 125 |
153 void Textfield::SetReadOnly(bool read_only) { | 126 void Textfield::SetReadOnly(bool read_only) { |
154 // Update read-only without changing the focusable state (or active, etc.). | 127 // Update read-only without changing the focusable state (or active, etc.). |
155 read_only_ = read_only; | 128 read_only_ = read_only; |
156 if (GetInputMethod()) | 129 if (textfield_view_) { |
157 GetInputMethod()->OnTextInputTypeChanged(this); | 130 textfield_view_->UpdateReadOnly(); |
158 SetColor(GetTextColor()); | 131 textfield_view_->UpdateTextColor(); |
159 UpdateBackgroundColor(); | 132 textfield_view_->UpdateBackgroundColor(); |
| 133 } |
160 } | 134 } |
161 | 135 |
162 bool Textfield::IsObscured() const { | 136 bool Textfield::IsObscured() const { |
163 return style_ & STYLE_OBSCURED; | 137 return style_ & STYLE_OBSCURED; |
164 } | 138 } |
165 | 139 |
166 void Textfield::SetObscured(bool obscured) { | 140 void Textfield::SetObscured(bool obscured) { |
167 if (obscured) { | 141 if (obscured) { |
168 style_ = static_cast<StyleFlags>(style_ | STYLE_OBSCURED); | 142 style_ = static_cast<StyleFlags>(style_ | STYLE_OBSCURED); |
169 SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD); | 143 SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD); |
170 } else { | 144 } else { |
171 style_ = static_cast<StyleFlags>(style_ & ~STYLE_OBSCURED); | 145 style_ = static_cast<StyleFlags>(style_ & ~STYLE_OBSCURED); |
172 SetTextInputType(ui::TEXT_INPUT_TYPE_TEXT); | 146 SetTextInputType(ui::TEXT_INPUT_TYPE_TEXT); |
173 } | 147 } |
174 GetRenderText()->SetObscured(obscured); | 148 if (textfield_view_) |
175 OnCaretBoundsChanged(); | 149 textfield_view_->UpdateIsObscured(); |
176 if (GetInputMethod()) | 150 } |
177 GetInputMethod()->OnTextInputTypeChanged(this); | 151 |
178 SchedulePaint(); | 152 ui::TextInputType Textfield::GetTextInputType() const { |
| 153 if (read_only() || !enabled()) |
| 154 return ui::TEXT_INPUT_TYPE_NONE; |
| 155 return text_input_type_; |
179 } | 156 } |
180 | 157 |
181 void Textfield::SetTextInputType(ui::TextInputType type) { | 158 void Textfield::SetTextInputType(ui::TextInputType type) { |
182 text_input_type_ = type; | 159 text_input_type_ = type; |
183 bool should_be_obscured = type == ui::TEXT_INPUT_TYPE_PASSWORD; | 160 bool should_be_obscured = type == ui::TEXT_INPUT_TYPE_PASSWORD; |
184 if (IsObscured() != should_be_obscured) | 161 if (IsObscured() != should_be_obscured) |
185 SetObscured(should_be_obscured); | 162 SetObscured(should_be_obscured); |
186 } | 163 } |
187 | 164 |
188 void Textfield::SetText(const base::string16& new_text) { | 165 void Textfield::SetText(const base::string16& text) { |
189 model_->SetText(GetTextForDisplay(new_text)); | 166 text_ = text; |
190 OnCaretBoundsChanged(); | 167 if (textfield_view_) |
191 SchedulePaint(); | 168 textfield_view_->UpdateText(); |
192 NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_TEXT_CHANGED, true); | |
193 } | 169 } |
194 | 170 |
195 void Textfield::AppendText(const base::string16& new_text) { | 171 void Textfield::AppendText(const base::string16& text) { |
196 if (new_text.empty()) | 172 text_ += text; |
197 return; | 173 if (textfield_view_) |
198 model_->Append(GetTextForDisplay(new_text)); | 174 textfield_view_->AppendText(text); |
199 OnCaretBoundsChanged(); | |
200 SchedulePaint(); | |
201 } | 175 } |
202 | 176 |
203 void Textfield::InsertOrReplaceText(const base::string16& new_text) { | 177 void Textfield::InsertOrReplaceText(const base::string16& text) { |
204 if (new_text.empty()) | 178 if (textfield_view_) { |
205 return; | 179 textfield_view_->InsertOrReplaceText(text); |
206 model_->InsertText(new_text); | 180 text_ = textfield_view_->GetText(); |
207 OnCaretBoundsChanged(); | 181 } |
208 SchedulePaint(); | |
209 } | 182 } |
210 | 183 |
211 base::i18n::TextDirection Textfield::GetTextDirection() const { | 184 base::i18n::TextDirection Textfield::GetTextDirection() const { |
212 return GetRenderText()->GetTextDirection(); | 185 return textfield_view_ ? |
| 186 textfield_view_->GetTextDirection() : base::i18n::UNKNOWN_DIRECTION; |
213 } | 187 } |
214 | 188 |
215 void Textfield::SelectAll(bool reversed) { | 189 void Textfield::SelectAll(bool reversed) { |
216 model_->SelectAll(reversed); | 190 if (textfield_view_) |
217 OnCaretBoundsChanged(); | 191 textfield_view_->SelectAll(reversed); |
218 SchedulePaint(); | |
219 } | 192 } |
220 | 193 |
221 base::string16 Textfield::GetSelectedText() const { | 194 base::string16 Textfield::GetSelectedText() const { |
222 return model_->GetSelectedText(); | 195 return textfield_view_ ? textfield_view_->GetSelectedText() : |
| 196 base::string16(); |
223 } | 197 } |
224 | 198 |
225 void Textfield::ClearSelection() { | 199 void Textfield::ClearSelection() const { |
226 model_->ClearSelection(); | 200 if (textfield_view_) |
227 OnCaretBoundsChanged(); | 201 textfield_view_->ClearSelection(); |
228 SchedulePaint(); | |
229 } | 202 } |
230 | 203 |
231 bool Textfield::HasSelection() const { | 204 bool Textfield::HasSelection() const { |
232 return !GetSelectedRange().is_empty(); | 205 return textfield_view_ && !textfield_view_->GetSelectedRange().is_empty(); |
233 } | 206 } |
234 | 207 |
235 SkColor Textfield::GetTextColor() const { | 208 SkColor Textfield::GetTextColor() const { |
236 if (!use_default_text_color_) | 209 if (!use_default_text_color_) |
237 return text_color_; | 210 return text_color_; |
238 | 211 |
239 return GetNativeTheme()->GetSystemColor(read_only() ? | 212 return GetNativeTheme()->GetSystemColor(read_only() ? |
240 ui::NativeTheme::kColorId_TextfieldReadOnlyColor : | 213 ui::NativeTheme::kColorId_TextfieldReadOnlyColor : |
241 ui::NativeTheme::kColorId_TextfieldDefaultColor); | 214 ui::NativeTheme::kColorId_TextfieldDefaultColor); |
242 } | 215 } |
243 | 216 |
244 void Textfield::SetTextColor(SkColor color) { | 217 void Textfield::SetTextColor(SkColor color) { |
245 text_color_ = color; | 218 text_color_ = color; |
246 use_default_text_color_ = false; | 219 use_default_text_color_ = false; |
247 SetColor(color); | 220 if (textfield_view_) |
| 221 textfield_view_->UpdateTextColor(); |
248 } | 222 } |
249 | 223 |
250 void Textfield::UseDefaultTextColor() { | 224 void Textfield::UseDefaultTextColor() { |
251 use_default_text_color_ = true; | 225 use_default_text_color_ = true; |
252 SetColor(GetTextColor()); | 226 if (textfield_view_) |
| 227 textfield_view_->UpdateTextColor(); |
253 } | 228 } |
254 | 229 |
255 SkColor Textfield::GetBackgroundColor() const { | 230 SkColor Textfield::GetBackgroundColor() const { |
256 if (!use_default_background_color_) | 231 if (!use_default_background_color_) |
257 return background_color_; | 232 return background_color_; |
258 | 233 |
259 return GetNativeTheme()->GetSystemColor(read_only() ? | 234 return GetNativeTheme()->GetSystemColor(read_only() ? |
260 ui::NativeTheme::kColorId_TextfieldReadOnlyBackground : | 235 ui::NativeTheme::kColorId_TextfieldReadOnlyBackground : |
261 ui::NativeTheme::kColorId_TextfieldDefaultBackground); | 236 ui::NativeTheme::kColorId_TextfieldDefaultBackground); |
262 } | 237 } |
263 | 238 |
264 void Textfield::SetBackgroundColor(SkColor color) { | 239 void Textfield::SetBackgroundColor(SkColor color) { |
265 background_color_ = color; | 240 background_color_ = color; |
266 use_default_background_color_ = false; | 241 use_default_background_color_ = false; |
267 UpdateBackgroundColor(); | 242 if (textfield_view_) |
| 243 textfield_view_->UpdateBackgroundColor(); |
268 } | 244 } |
269 | 245 |
270 void Textfield::UseDefaultBackgroundColor() { | 246 void Textfield::UseDefaultBackgroundColor() { |
271 use_default_background_color_ = true; | 247 use_default_background_color_ = true; |
272 UpdateBackgroundColor(); | 248 if (textfield_view_) |
| 249 textfield_view_->UpdateBackgroundColor(); |
273 } | 250 } |
274 | 251 |
275 bool Textfield::GetCursorEnabled() const { | 252 bool Textfield::GetCursorEnabled() const { |
276 return GetRenderText()->cursor_enabled(); | 253 return textfield_view_ && textfield_view_->GetCursorEnabled(); |
277 } | 254 } |
278 | 255 |
279 void Textfield::SetCursorEnabled(bool enabled) { | 256 void Textfield::SetCursorEnabled(bool enabled) { |
280 GetRenderText()->SetCursorEnabled(enabled); | 257 if (textfield_view_) |
281 } | 258 textfield_view_->SetCursorEnabled(enabled); |
282 | |
283 const gfx::FontList& Textfield::GetFontList() const { | |
284 return GetRenderText()->font_list(); | |
285 } | 259 } |
286 | 260 |
287 void Textfield::SetFontList(const gfx::FontList& font_list) { | 261 void Textfield::SetFontList(const gfx::FontList& font_list) { |
288 GetRenderText()->SetFontList(font_list); | 262 font_list_ = font_list; |
289 OnCaretBoundsChanged(); | 263 if (textfield_view_) |
| 264 textfield_view_->UpdateFont(); |
290 PreferredSizeChanged(); | 265 PreferredSizeChanged(); |
291 } | 266 } |
292 | 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 (textfield_view_) |
| 284 textfield_view_->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 (textfield_view_) |
| 296 textfield_view_->UpdateVerticalMargins(); |
| 297 PreferredSizeChanged(); |
| 298 } |
| 299 |
| 300 void Textfield::RemoveBorder() { |
| 301 if (!draw_border_) |
| 302 return; |
| 303 |
| 304 draw_border_ = false; |
| 305 if (textfield_view_) |
| 306 textfield_view_->UpdateBorder(); |
| 307 } |
| 308 |
293 base::string16 Textfield::GetPlaceholderText() const { | 309 base::string16 Textfield::GetPlaceholderText() const { |
294 return placeholder_text_; | 310 return placeholder_text_; |
295 } | 311 } |
296 | 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 (textfield_view_) { |
| 333 textfield_view_->UpdateText(); |
| 334 textfield_view_->UpdateTextColor(); |
| 335 textfield_view_->UpdateBackgroundColor(); |
| 336 textfield_view_->UpdateReadOnly(); |
| 337 textfield_view_->UpdateFont(); |
| 338 textfield_view_->UpdateEnabled(); |
| 339 textfield_view_->UpdateBorder(); |
| 340 textfield_view_->UpdateIsObscured(); |
| 341 textfield_view_->UpdateHorizontalMargins(); |
| 342 textfield_view_->UpdateVerticalMargins(); |
| 343 } |
| 344 } |
| 345 |
| 346 void Textfield::SyncText() { |
| 347 if (textfield_view_) { |
| 348 base::string16 new_text = textfield_view_->GetText(); |
| 349 if (new_text != text_) { |
| 350 text_ = new_text; |
| 351 if (controller_) |
| 352 controller_->ContentsChanged(this, text_); |
| 353 } |
| 354 } |
| 355 } |
| 356 |
297 bool Textfield::IsIMEComposing() const { | 357 bool Textfield::IsIMEComposing() const { |
298 return model_->HasCompositionText(); | 358 return textfield_view_ && textfield_view_->IsIMEComposing(); |
299 } | 359 } |
300 | 360 |
301 const gfx::Range& Textfield::GetSelectedRange() const { | 361 const gfx::Range& Textfield::GetSelectedRange() const { |
302 return GetRenderText()->selection(); | 362 return textfield_view_->GetSelectedRange(); |
303 } | 363 } |
304 | 364 |
305 void Textfield::SelectRange(const gfx::Range& range) { | 365 void Textfield::SelectRange(const gfx::Range& range) { |
306 model_->SelectRange(range); | 366 textfield_view_->SelectRange(range); |
307 OnCaretBoundsChanged(); | |
308 SchedulePaint(); | |
309 NotifyAccessibilityEvent( | |
310 ui::AccessibilityTypes::EVENT_SELECTION_CHANGED, true); | |
311 } | 367 } |
312 | 368 |
313 const gfx::SelectionModel& Textfield::GetSelectionModel() const { | 369 const gfx::SelectionModel& Textfield::GetSelectionModel() const { |
314 return GetRenderText()->selection_model(); | 370 return textfield_view_->GetSelectionModel(); |
315 } | 371 } |
316 | 372 |
317 void Textfield::SelectSelectionModel(const gfx::SelectionModel& sel) { | 373 void Textfield::SelectSelectionModel(const gfx::SelectionModel& sel) { |
318 model_->SelectSelectionModel(sel); | 374 textfield_view_->SelectSelectionModel(sel); |
319 OnCaretBoundsChanged(); | |
320 SchedulePaint(); | |
321 } | 375 } |
322 | 376 |
323 size_t Textfield::GetCursorPosition() const { | 377 size_t Textfield::GetCursorPosition() const { |
324 return model_->GetCursorPosition(); | 378 return textfield_view_->GetCursorPosition(); |
325 } | 379 } |
326 | 380 |
327 void Textfield::SetColor(SkColor value) { | 381 void Textfield::SetColor(SkColor value) { |
328 GetRenderText()->SetColor(value); | 382 return textfield_view_->SetColor(value); |
329 SchedulePaint(); | |
330 } | 383 } |
331 | 384 |
332 void Textfield::ApplyColor(SkColor value, const gfx::Range& range) { | 385 void Textfield::ApplyColor(SkColor value, const gfx::Range& range) { |
333 GetRenderText()->ApplyColor(value, range); | 386 return textfield_view_->ApplyColor(value, range); |
334 SchedulePaint(); | |
335 } | 387 } |
336 | 388 |
337 void Textfield::SetStyle(gfx::TextStyle style, bool value) { | 389 void Textfield::SetStyle(gfx::TextStyle style, bool value) { |
338 GetRenderText()->SetStyle(style, value); | 390 return textfield_view_->SetStyle(style, value); |
339 SchedulePaint(); | |
340 } | 391 } |
341 | 392 |
342 void Textfield::ApplyStyle(gfx::TextStyle style, | 393 void Textfield::ApplyStyle(gfx::TextStyle style, |
343 bool value, | 394 bool value, |
344 const gfx::Range& range) { | 395 const gfx::Range& range) { |
345 GetRenderText()->ApplyStyle(style, value, range); | 396 return textfield_view_->ApplyStyle(style, value, range); |
346 SchedulePaint(); | |
347 } | 397 } |
348 | 398 |
349 void Textfield::ClearEditHistory() { | 399 void Textfield::ClearEditHistory() { |
350 model_->ClearEditHistory(); | 400 textfield_view_->ClearEditHistory(); |
351 } | 401 } |
352 | 402 |
353 void Textfield::SetAccessibleName(const base::string16& name) { | 403 void Textfield::SetAccessibleName(const base::string16& name) { |
354 accessible_name_ = name; | 404 accessible_name_ = name; |
355 } | 405 } |
356 | 406 |
357 void Textfield::ExecuteCommand(int command_id) { | 407 void Textfield::ExecuteCommand(int command_id) { |
358 ExecuteCommand(command_id, ui::EF_NONE); | 408 textfield_view_->ExecuteCommand(command_id, ui::EF_NONE); |
359 } | 409 } |
360 | 410 |
361 void Textfield::SetFocusPainter(scoped_ptr<Painter> focus_painter) { | 411 void Textfield::SetFocusPainter(scoped_ptr<Painter> focus_painter) { |
362 focus_painter_ = focus_painter.Pass(); | 412 focus_painter_ = focus_painter.Pass(); |
363 } | 413 } |
364 | 414 |
365 bool Textfield::HasTextBeingDragged() { | 415 bool Textfield::HasTextBeingDragged() { |
366 return initiating_drag_; | 416 return textfield_view_->HasTextBeingDragged(); |
367 } | 417 } |
368 | 418 |
369 //////////////////////////////////////////////////////////////////////////////// | 419 //////////////////////////////////////////////////////////////////////////////// |
370 // Textfield, View overrides: | 420 // Textfield, View overrides: |
371 | 421 |
| 422 void Textfield::Layout() { |
| 423 if (textfield_view_) { |
| 424 textfield_view_->SetBoundsRect(GetContentsBounds()); |
| 425 textfield_view_->Layout(); |
| 426 } |
| 427 } |
| 428 |
372 int Textfield::GetBaseline() const { | 429 int Textfield::GetBaseline() const { |
373 return GetInsets().top() + GetRenderText()->GetBaseline(); | 430 gfx::Insets insets = GetTextInsets(); |
| 431 const int baseline = textfield_view_ ? |
| 432 textfield_view_->GetTextfieldBaseline() : font_list_.GetBaseline(); |
| 433 return insets.top() + baseline; |
374 } | 434 } |
375 | 435 |
376 gfx::Size Textfield::GetPreferredSize() { | 436 gfx::Size Textfield::GetPreferredSize() { |
377 const gfx::Insets& insets = GetInsets(); | 437 gfx::Insets insets = GetTextInsets(); |
378 return gfx::Size(GetFontList().GetExpectedTextWidth(default_width_in_chars_) + | 438 |
379 insets.width(), GetFontList().GetHeight() + insets.height()); | 439 const int font_height = textfield_view_ ? textfield_view_->GetFontHeight() : |
| 440 font_list_.GetHeight(); |
| 441 return gfx::Size( |
| 442 GetPrimaryFont().GetExpectedTextWidth(default_width_in_chars_) |
| 443 + insets.width(), |
| 444 font_height + insets.height()); |
380 } | 445 } |
381 | 446 |
382 void Textfield::AboutToRequestFocusFromTabTraversal(bool reverse) { | 447 void Textfield::AboutToRequestFocusFromTabTraversal(bool reverse) { |
383 SelectAll(false); | 448 SelectAll(false); |
384 } | 449 } |
385 | 450 |
386 bool Textfield::SkipDefaultKeyEventProcessing(const ui::KeyEvent& e) { | 451 bool Textfield::SkipDefaultKeyEventProcessing(const ui::KeyEvent& e) { |
387 // Skip any accelerator handling of backspace; textfields handle this key. | 452 // Skip any accelerator handling of backspace; textfields handle this key. |
388 // Also skip processing of [Alt]+<num-pad digit> Unicode alt key codes. | 453 // Also skip processing of [Alt]+<num-pad digit> Unicode alt key codes. |
389 return e.key_code() == ui::VKEY_BACK || e.IsUnicodeKeyCode(); | 454 return e.key_code() == ui::VKEY_BACK || e.IsUnicodeKeyCode(); |
390 } | 455 } |
391 | 456 |
392 void Textfield::OnPaint(gfx::Canvas* canvas) { | 457 void Textfield::OnPaint(gfx::Canvas* canvas) { |
393 OnPaintBackground(canvas); | 458 View::OnPaint(canvas); |
394 PaintTextAndCursor(canvas); | |
395 OnPaintBorder(canvas); | |
396 if (NativeViewHost::kRenderNativeControlFocus) | 459 if (NativeViewHost::kRenderNativeControlFocus) |
397 Painter::PaintFocusPainter(this, canvas, focus_painter_.get()); | 460 Painter::PaintFocusPainter(this, canvas, focus_painter_.get()); |
398 } | 461 } |
399 | 462 |
400 bool Textfield::OnKeyPressed(const ui::KeyEvent& event) { | 463 bool Textfield::OnKeyPressed(const ui::KeyEvent& e) { |
401 bool handled = controller_ && controller_->HandleKeyEvent(this, event); | 464 return textfield_view_ && textfield_view_->HandleKeyPressed(e); |
402 touch_selection_controller_.reset(); | |
403 if (handled) | |
404 return true; | |
405 | |
406 // TODO(oshima): Refactor and consolidate with ExecuteCommand. | |
407 if (event.type() == ui::ET_KEY_PRESSED) { | |
408 ui::KeyboardCode key_code = event.key_code(); | |
409 if (key_code == ui::VKEY_TAB || event.IsUnicodeKeyCode()) | |
410 return false; | |
411 | |
412 gfx::RenderText* render_text = GetRenderText(); | |
413 const bool editable = !read_only(); | |
414 const bool readable = !IsObscured(); | |
415 const bool shift = event.IsShiftDown(); | |
416 const bool control = event.IsControlDown(); | |
417 const bool alt = event.IsAltDown() || event.IsAltGrDown(); | |
418 bool text_changed = false; | |
419 bool cursor_changed = false; | |
420 | |
421 OnBeforeUserAction(); | |
422 switch (key_code) { | |
423 case ui::VKEY_Z: | |
424 if (control && !shift && !alt && editable) | |
425 cursor_changed = text_changed = model_->Undo(); | |
426 else if (control && shift && !alt && editable) | |
427 cursor_changed = text_changed = model_->Redo(); | |
428 break; | |
429 case ui::VKEY_Y: | |
430 if (control && !alt && editable) | |
431 cursor_changed = text_changed = model_->Redo(); | |
432 break; | |
433 case ui::VKEY_A: | |
434 if (control && !alt) { | |
435 model_->SelectAll(false); | |
436 cursor_changed = true; | |
437 } | |
438 break; | |
439 case ui::VKEY_X: | |
440 if (control && !alt && editable && readable) | |
441 cursor_changed = text_changed = Cut(); | |
442 break; | |
443 case ui::VKEY_C: | |
444 if (control && !alt && readable) | |
445 Copy(); | |
446 break; | |
447 case ui::VKEY_V: | |
448 if (control && !alt && editable) | |
449 cursor_changed = text_changed = Paste(); | |
450 break; | |
451 case ui::VKEY_RIGHT: | |
452 case ui::VKEY_LEFT: { | |
453 // We should ignore the alt-left/right keys because alt key doesn't make | |
454 // any special effects for them and they can be shortcut keys such like | |
455 // forward/back of the browser history. | |
456 if (alt) | |
457 break; | |
458 const gfx::Range selection_range = render_text->selection(); | |
459 model_->MoveCursor( | |
460 control ? gfx::WORD_BREAK : gfx::CHARACTER_BREAK, | |
461 (key_code == ui::VKEY_RIGHT) ? gfx::CURSOR_RIGHT : gfx::CURSOR_LEFT, | |
462 shift); | |
463 cursor_changed = render_text->selection() != selection_range; | |
464 break; | |
465 } | |
466 case ui::VKEY_END: | |
467 case ui::VKEY_HOME: | |
468 if ((key_code == ui::VKEY_HOME) == | |
469 (render_text->GetTextDirection() == base::i18n::RIGHT_TO_LEFT)) | |
470 model_->MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, shift); | |
471 else | |
472 model_->MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, shift); | |
473 cursor_changed = true; | |
474 break; | |
475 case ui::VKEY_BACK: | |
476 case ui::VKEY_DELETE: | |
477 if (!editable) | |
478 break; | |
479 if (!model_->HasSelection()) { | |
480 gfx::VisualCursorDirection direction = (key_code == ui::VKEY_DELETE) ? | |
481 gfx::CURSOR_RIGHT : gfx::CURSOR_LEFT; | |
482 if (shift && control) { | |
483 // If both shift and control are pressed, then erase up to the | |
484 // beginning/end of the buffer in ChromeOS. Otherwise, do nothing. | |
485 model_->MoveCursor(gfx::LINE_BREAK, direction, true); | |
486 #if !defined(OS_CHROMEOS) | |
487 break; | |
488 #endif | |
489 } else if (control) { | |
490 // If only control is pressed, then erase the previous/next word. | |
491 model_->MoveCursor(gfx::WORD_BREAK, direction, true); | |
492 } | |
493 } | |
494 if (key_code == ui::VKEY_BACK) | |
495 model_->Backspace(); | |
496 else if (shift && model_->HasSelection() && readable) | |
497 Cut(); | |
498 else | |
499 model_->Delete(); | |
500 | |
501 // Consume backspace and delete keys even if the edit did nothing. This | |
502 // prevents potential unintended side-effects of further event handling. | |
503 text_changed = true; | |
504 break; | |
505 case ui::VKEY_INSERT: | |
506 if (control && !shift && readable) | |
507 Copy(); | |
508 else if (shift && !control && editable) | |
509 cursor_changed = text_changed = Paste(); | |
510 break; | |
511 default: | |
512 break; | |
513 } | |
514 | |
515 // We must have input method in order to support text input. | |
516 DCHECK(GetInputMethod()); | |
517 UpdateAfterChange(text_changed, cursor_changed); | |
518 OnAfterUserAction(); | |
519 return (text_changed || cursor_changed); | |
520 } | |
521 return false; | |
522 } | 465 } |
523 | 466 |
524 bool Textfield::OnMousePressed(const ui::MouseEvent& event) { | 467 bool Textfield::OnKeyReleased(const ui::KeyEvent& e) { |
525 OnBeforeUserAction(); | 468 return textfield_view_ && textfield_view_->HandleKeyReleased(e); |
526 TrackMouseClicks(event); | 469 } |
527 | 470 |
528 if (!controller_ || !controller_->HandleMouseEvent(this, event)) { | 471 bool Textfield::OnMouseDragged(const ui::MouseEvent& e) { |
529 if (event.IsOnlyLeftMouseButton() || event.IsOnlyRightMouseButton()) | 472 if (!e.IsOnlyRightMouseButton()) |
530 RequestFocus(); | 473 return View::OnMouseDragged(e); |
531 | |
532 if (event.IsOnlyLeftMouseButton()) { | |
533 initiating_drag_ = false; | |
534 bool can_drag = true; | |
535 | |
536 switch (aggregated_clicks_) { | |
537 case 0: | |
538 if (can_drag && | |
539 GetRenderText()->IsPointInSelection(event.location())) { | |
540 initiating_drag_ = true; | |
541 } else { | |
542 MoveCursorTo(event.location(), event.IsShiftDown()); | |
543 } | |
544 break; | |
545 case 1: | |
546 MoveCursorTo(event.location(), false); | |
547 model_->SelectWord(); | |
548 double_click_word_ = GetRenderText()->selection(); | |
549 OnCaretBoundsChanged(); | |
550 break; | |
551 case 2: | |
552 model_->SelectAll(false); | |
553 OnCaretBoundsChanged(); | |
554 break; | |
555 default: | |
556 NOTREACHED(); | |
557 } | |
558 } | |
559 SchedulePaint(); | |
560 } | |
561 | |
562 OnAfterUserAction(); | |
563 touch_selection_controller_.reset(); | |
564 return true; | 474 return true; |
565 } | 475 } |
566 | 476 |
567 bool Textfield::OnMouseDragged(const ui::MouseEvent& event) { | |
568 // Don't adjust the cursor on a potential drag and drop, or if the mouse | |
569 // movement from the last mouse click does not exceed the drag threshold. | |
570 if (initiating_drag_ || !event.IsOnlyLeftMouseButton() || | |
571 !ExceededDragThreshold(event.location() - last_click_location_)) { | |
572 return true; | |
573 } | |
574 | |
575 if (!event.IsOnlyRightMouseButton()) { | |
576 OnBeforeUserAction(); | |
577 MoveCursorTo(event.location(), true); | |
578 if (aggregated_clicks_ == 1) { | |
579 model_->SelectWord(); | |
580 // Expand the selection so the initially selected word remains selected. | |
581 gfx::Range selection = GetRenderText()->selection(); | |
582 const size_t min = std::min(selection.GetMin(), | |
583 double_click_word_.GetMin()); | |
584 const size_t max = std::max(selection.GetMax(), | |
585 double_click_word_.GetMax()); | |
586 const bool reversed = selection.is_reversed(); | |
587 selection.set_start(reversed ? max : min); | |
588 selection.set_end(reversed ? min : max); | |
589 model_->SelectRange(selection); | |
590 } | |
591 SchedulePaint(); | |
592 OnAfterUserAction(); | |
593 } | |
594 return true; | |
595 } | |
596 | |
597 void Textfield::OnMouseReleased(const ui::MouseEvent& event) { | |
598 OnBeforeUserAction(); | |
599 // Cancel suspected drag initiations, the user was clicking in the selection. | |
600 if (initiating_drag_ && MoveCursorTo(event.location(), false)) | |
601 SchedulePaint(); | |
602 initiating_drag_ = false; | |
603 OnAfterUserAction(); | |
604 } | |
605 | |
606 void Textfield::OnFocus() { | 477 void Textfield::OnFocus() { |
607 GetRenderText()->set_focused(true); | 478 if (textfield_view_) |
608 is_cursor_visible_ = true; | 479 textfield_view_->HandleFocus(); |
609 SchedulePaint(); | |
610 GetInputMethod()->OnFocus(); | |
611 OnCaretBoundsChanged(); | |
612 | |
613 const size_t caret_blink_ms = Textfield::GetCaretBlinkMs(); | |
614 if (caret_blink_ms != 0) { | |
615 cursor_repaint_timer_.Start(FROM_HERE, | |
616 base::TimeDelta::FromMilliseconds(caret_blink_ms), this, | |
617 &Textfield::UpdateCursor); | |
618 } | |
619 | |
620 View::OnFocus(); | 480 View::OnFocus(); |
621 SchedulePaint(); | 481 SchedulePaint(); |
622 } | 482 } |
623 | 483 |
624 void Textfield::OnBlur() { | 484 void Textfield::OnBlur() { |
625 GetRenderText()->set_focused(false); | 485 if (textfield_view_) |
626 GetInputMethod()->OnBlur(); | 486 textfield_view_->HandleBlur(); |
627 cursor_repaint_timer_.Stop(); | |
628 if (is_cursor_visible_) { | |
629 is_cursor_visible_ = false; | |
630 RepaintCursor(); | |
631 } | |
632 | |
633 touch_selection_controller_.reset(); | |
634 | 487 |
635 // Border typically draws focus indicator. | 488 // Border typically draws focus indicator. |
636 SchedulePaint(); | 489 SchedulePaint(); |
637 } | 490 } |
638 | 491 |
639 void Textfield::GetAccessibleState(ui::AccessibleViewState* state) { | 492 void Textfield::GetAccessibleState(ui::AccessibleViewState* state) { |
640 state->role = ui::AccessibilityTypes::ROLE_TEXT; | 493 state->role = ui::AccessibilityTypes::ROLE_TEXT; |
641 state->name = accessible_name_; | 494 state->name = accessible_name_; |
642 if (read_only()) | 495 if (read_only()) |
643 state->state |= ui::AccessibilityTypes::STATE_READONLY; | 496 state->state |= ui::AccessibilityTypes::STATE_READONLY; |
644 if (IsObscured()) | 497 if (IsObscured()) |
645 state->state |= ui::AccessibilityTypes::STATE_PROTECTED; | 498 state->state |= ui::AccessibilityTypes::STATE_PROTECTED; |
646 state->value = text(); | 499 state->value = text_; |
647 | 500 |
648 const gfx::Range range = GetSelectedRange(); | 501 const gfx::Range range = textfield_view_->GetSelectedRange(); |
649 state->selection_start = range.start(); | 502 state->selection_start = range.start(); |
650 state->selection_end = range.end(); | 503 state->selection_end = range.end(); |
651 | 504 |
652 if (!read_only()) { | 505 if (!read_only()) { |
653 state->set_value_callback = | 506 state->set_value_callback = |
654 base::Bind(&Textfield::AccessibilitySetValue, | 507 base::Bind(&Textfield::AccessibilitySetValue, |
655 weak_ptr_factory_.GetWeakPtr()); | 508 weak_ptr_factory_.GetWeakPtr()); |
656 } | 509 } |
657 } | 510 } |
658 | 511 |
659 ui::TextInputClient* Textfield::GetTextInputClient() { | 512 ui::TextInputClient* Textfield::GetTextInputClient() { |
660 return read_only_ ? NULL : this; | 513 return textfield_view_ ? textfield_view_->GetTextInputClient() : NULL; |
661 } | 514 } |
662 | 515 |
663 gfx::Point Textfield::GetKeyboardContextMenuLocation() { | 516 gfx::Point Textfield::GetKeyboardContextMenuLocation() { |
664 return GetCaretBounds().bottom_right(); | 517 return textfield_view_ ? textfield_view_->GetContextMenuLocation() : |
665 } | 518 View::GetKeyboardContextMenuLocation(); |
666 | |
667 void Textfield::OnNativeThemeChanged(const ui::NativeTheme* theme) { | |
668 UpdateColorsFromTheme(theme); | |
669 } | 519 } |
670 | 520 |
671 void Textfield::OnEnabledChanged() { | 521 void Textfield::OnEnabledChanged() { |
672 View::OnEnabledChanged(); | 522 View::OnEnabledChanged(); |
673 if (GetInputMethod()) | 523 if (textfield_view_) |
674 GetInputMethod()->OnTextInputTypeChanged(this); | 524 textfield_view_->UpdateEnabled(); |
675 SchedulePaint(); | 525 } |
| 526 |
| 527 void Textfield::ViewHierarchyChanged( |
| 528 const ViewHierarchyChangedDetails& details) { |
| 529 if (details.is_add && !textfield_view_ && GetWidget()) { |
| 530 // The textfield view's lifetime is managed by the view hierarchy. |
| 531 textfield_view_ = new NativeTextfieldViews(this); |
| 532 AddChildViewAt(textfield_view_, 0); |
| 533 Layout(); |
| 534 UpdateAllProperties(); |
| 535 } |
676 } | 536 } |
677 | 537 |
678 const char* Textfield::GetClassName() const { | 538 const char* Textfield::GetClassName() const { |
679 return kViewClassName; | 539 return kViewClassName; |
680 } | 540 } |
681 | 541 |
682 gfx::NativeCursor Textfield::GetCursor(const ui::MouseEvent& event) { | |
683 bool in_selection = GetRenderText()->IsPointInSelection(event.location()); | |
684 bool drag_event = event.type() == ui::ET_MOUSE_DRAGGED; | |
685 bool text_cursor = !initiating_drag_ && (drag_event || !in_selection); | |
686 #if defined(USE_AURA) | |
687 return text_cursor ? ui::kCursorIBeam : ui::kCursorNull; | |
688 #elif defined(OS_WIN) | |
689 static HCURSOR ibeam = LoadCursor(NULL, IDC_IBEAM); | |
690 static HCURSOR arrow = LoadCursor(NULL, IDC_ARROW); | |
691 return text_cursor ? ibeam : arrow; | |
692 #endif | |
693 } | |
694 | |
695 void Textfield::OnGestureEvent(ui::GestureEvent* event) { | |
696 switch (event->type()) { | |
697 case ui::ET_GESTURE_TAP_DOWN: | |
698 OnBeforeUserAction(); | |
699 RequestFocus(); | |
700 // We don't deselect if the point is in the selection | |
701 // because TAP_DOWN may turn into a LONG_PRESS. | |
702 if (!GetRenderText()->IsPointInSelection(event->location()) && | |
703 MoveCursorTo(event->location(), false)) | |
704 SchedulePaint(); | |
705 OnAfterUserAction(); | |
706 event->SetHandled(); | |
707 break; | |
708 case ui::ET_GESTURE_SCROLL_UPDATE: | |
709 OnBeforeUserAction(); | |
710 if (MoveCursorTo(event->location(), true)) | |
711 SchedulePaint(); | |
712 OnAfterUserAction(); | |
713 event->SetHandled(); | |
714 break; | |
715 case ui::ET_GESTURE_SCROLL_END: | |
716 case ui::ET_SCROLL_FLING_START: | |
717 CreateTouchSelectionControllerAndNotifyIt(); | |
718 event->SetHandled(); | |
719 break; | |
720 case ui::ET_GESTURE_TAP: | |
721 if (event->details().tap_count() == 1) { | |
722 CreateTouchSelectionControllerAndNotifyIt(); | |
723 } else { | |
724 OnBeforeUserAction(); | |
725 SelectAll(false); | |
726 OnAfterUserAction(); | |
727 event->SetHandled(); | |
728 } | |
729 #if defined(OS_WIN) && defined(USE_AURA) | |
730 if (!read_only()) | |
731 base::win::DisplayVirtualKeyboard(); | |
732 #endif | |
733 break; | |
734 case ui::ET_GESTURE_LONG_PRESS: | |
735 // If long press happens outside selection, select word and show context | |
736 // menu (If touch selection is enabled, context menu is shown by the | |
737 // |touch_selection_controller_|, hence we mark the event handled. | |
738 // Otherwise, the regular context menu will be shown by views). | |
739 // If long press happens in selected text and touch drag drop is enabled, | |
740 // we will turn off touch selection (if one exists) and let views do drag | |
741 // drop. | |
742 if (!GetRenderText()->IsPointInSelection(event->location())) { | |
743 OnBeforeUserAction(); | |
744 model_->SelectWord(); | |
745 touch_selection_controller_.reset( | |
746 ui::TouchSelectionController::create(this)); | |
747 OnCaretBoundsChanged(); | |
748 SchedulePaint(); | |
749 OnAfterUserAction(); | |
750 if (touch_selection_controller_) | |
751 event->SetHandled(); | |
752 } else if (switches::IsTouchDragDropEnabled()) { | |
753 initiating_drag_ = true; | |
754 touch_selection_controller_.reset(); | |
755 } else { | |
756 if (!touch_selection_controller_) | |
757 CreateTouchSelectionControllerAndNotifyIt(); | |
758 if (touch_selection_controller_) | |
759 event->SetHandled(); | |
760 } | |
761 return; | |
762 case ui::ET_GESTURE_LONG_TAP: | |
763 if (!touch_selection_controller_) | |
764 CreateTouchSelectionControllerAndNotifyIt(); | |
765 | |
766 // If touch selection is enabled, the context menu on long tap will be | |
767 // shown by the |touch_selection_controller_|, hence we mark the event | |
768 // handled so views does not try to show context menu on it. | |
769 if (touch_selection_controller_) | |
770 event->SetHandled(); | |
771 break; | |
772 default: | |
773 return; | |
774 } | |
775 } | |
776 | |
777 bool Textfield::GetDropFormats( | |
778 int* formats, | |
779 std::set<OSExchangeData::CustomFormat>* custom_formats) { | |
780 if (!enabled() || read_only()) | |
781 return false; | |
782 // TODO(msw): Can we support URL, FILENAME, etc.? | |
783 *formats = ui::OSExchangeData::STRING; | |
784 if (controller_) | |
785 controller_->AppendDropFormats(formats, custom_formats); | |
786 return true; | |
787 } | |
788 | |
789 bool Textfield::CanDrop(const OSExchangeData& data) { | |
790 int formats; | |
791 std::set<OSExchangeData::CustomFormat> custom_formats; | |
792 GetDropFormats(&formats, &custom_formats); | |
793 return enabled() && !read_only() && | |
794 data.HasAnyFormat(formats, custom_formats); | |
795 } | |
796 | |
797 int Textfield::OnDragUpdated(const ui::DropTargetEvent& event) { | |
798 DCHECK(CanDrop(event.data())); | |
799 gfx::RenderText* render_text = GetRenderText(); | |
800 const gfx::Range& selection = render_text->selection(); | |
801 drop_cursor_position_ = render_text->FindCursorPosition(event.location()); | |
802 bool in_selection = !selection.is_empty() && | |
803 selection.Contains(gfx::Range(drop_cursor_position_.caret_pos())); | |
804 is_drop_cursor_visible_ = !in_selection; | |
805 // TODO(msw): Pan over text when the user drags to the visible text edge. | |
806 OnCaretBoundsChanged(); | |
807 SchedulePaint(); | |
808 | |
809 if (initiating_drag_) { | |
810 if (in_selection) | |
811 return ui::DragDropTypes::DRAG_NONE; | |
812 return event.IsControlDown() ? ui::DragDropTypes::DRAG_COPY : | |
813 ui::DragDropTypes::DRAG_MOVE; | |
814 } | |
815 return ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE; | |
816 } | |
817 | |
818 void Textfield::OnDragExited() { | |
819 is_drop_cursor_visible_ = false; | |
820 SchedulePaint(); | |
821 } | |
822 | |
823 int Textfield::OnPerformDrop(const ui::DropTargetEvent& event) { | |
824 DCHECK(CanDrop(event.data())); | |
825 is_drop_cursor_visible_ = false; | |
826 | |
827 if (controller_) { | |
828 int drag_operation = controller_->OnDrop(event.data()); | |
829 if (drag_operation != ui::DragDropTypes::DRAG_NONE) | |
830 return drag_operation; | |
831 } | |
832 | |
833 gfx::RenderText* render_text = GetRenderText(); | |
834 DCHECK(!initiating_drag_ || | |
835 !render_text->IsPointInSelection(event.location())); | |
836 OnBeforeUserAction(); | |
837 skip_input_method_cancel_composition_ = true; | |
838 | |
839 gfx::SelectionModel drop_destination_model = | |
840 render_text->FindCursorPosition(event.location()); | |
841 base::string16 new_text; | |
842 event.data().GetString(&new_text); | |
843 new_text = GetTextForDisplay(new_text); | |
844 | |
845 // Delete the current selection for a drag and drop within this view. | |
846 const bool move = initiating_drag_ && !event.IsControlDown() && | |
847 event.source_operations() & ui::DragDropTypes::DRAG_MOVE; | |
848 if (move) { | |
849 // Adjust the drop destination if it is on or after the current selection. | |
850 size_t pos = drop_destination_model.caret_pos(); | |
851 pos -= render_text->selection().Intersect(gfx::Range(0, pos)).length(); | |
852 model_->DeleteSelectionAndInsertTextAt(new_text, pos); | |
853 } else { | |
854 model_->MoveCursorTo(drop_destination_model); | |
855 // Drop always inserts text even if the textfield is not in insert mode. | |
856 model_->InsertText(new_text); | |
857 } | |
858 skip_input_method_cancel_composition_ = false; | |
859 UpdateAfterChange(true, true); | |
860 OnAfterUserAction(); | |
861 return move ? ui::DragDropTypes::DRAG_MOVE : ui::DragDropTypes::DRAG_COPY; | |
862 } | |
863 | |
864 void Textfield::OnDragDone() { | |
865 initiating_drag_ = false; | |
866 is_drop_cursor_visible_ = false; | |
867 } | |
868 | |
869 void Textfield::OnBoundsChanged(const gfx::Rect& previous_bounds) { | |
870 GetRenderText()->SetDisplayRect(GetContentsBounds()); | |
871 OnCaretBoundsChanged(); | |
872 } | |
873 | |
874 //////////////////////////////////////////////////////////////////////////////// | |
875 // Textfield, TextfieldViewsModel::Delegate overrides: | |
876 | |
877 void Textfield::OnCompositionTextConfirmedOrCleared() { | |
878 if (!skip_input_method_cancel_composition_) | |
879 GetInputMethod()->CancelComposition(this); | |
880 } | |
881 | |
882 //////////////////////////////////////////////////////////////////////////////// | |
883 // Textfield, ContextMenuController overrides: | |
884 | |
885 void Textfield::ShowContextMenuForView( | |
886 View* source, | |
887 const gfx::Point& point, | |
888 ui::MenuSourceType source_type) { | |
889 UpdateContextMenu(); | |
890 if (context_menu_runner_->RunMenuAt(GetWidget(), NULL, | |
891 gfx::Rect(point, gfx::Size()), views::MenuItemView::TOPLEFT, | |
892 source_type, | |
893 MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU) == | |
894 MenuRunner::MENU_DELETED) | |
895 return; | |
896 } | |
897 | |
898 //////////////////////////////////////////////////////////////////////////////// | |
899 // Textfield, views::DragController overrides: | |
900 | |
901 void Textfield::WriteDragDataForView(views::View* sender, | |
902 const gfx::Point& press_pt, | |
903 OSExchangeData* data) { | |
904 DCHECK_NE(ui::DragDropTypes::DRAG_NONE, | |
905 GetDragOperationsForView(sender, press_pt)); | |
906 data->SetString(model_->GetSelectedText()); | |
907 scoped_ptr<gfx::Canvas> canvas( | |
908 views::GetCanvasForDragImage(GetWidget(), size())); | |
909 GetRenderText()->DrawSelectedTextForDrag(canvas.get()); | |
910 drag_utils::SetDragImageOnDataObject(*canvas, size(), | |
911 press_pt.OffsetFromOrigin(), | |
912 data); | |
913 if (controller_) | |
914 controller_->OnWriteDragData(data); | |
915 } | |
916 | |
917 int Textfield::GetDragOperationsForView(views::View* sender, | |
918 const gfx::Point& p) { | |
919 int drag_operations = ui::DragDropTypes::DRAG_COPY; | |
920 if (!enabled() || IsObscured() || !GetRenderText()->IsPointInSelection(p)) | |
921 drag_operations = ui::DragDropTypes::DRAG_NONE; | |
922 else if (sender == this && !read_only()) | |
923 drag_operations = | |
924 ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY; | |
925 if (controller_) | |
926 controller_->OnGetDragOperationsForTextfield(&drag_operations); | |
927 return drag_operations; | |
928 } | |
929 | |
930 bool Textfield::CanStartDragForView(View* sender, | |
931 const gfx::Point& press_pt, | |
932 const gfx::Point& p) { | |
933 return initiating_drag_ && GetRenderText()->IsPointInSelection(press_pt); | |
934 } | |
935 | |
936 //////////////////////////////////////////////////////////////////////////////// | |
937 // Textfield, ui::TouchEditable overrides: | |
938 | |
939 void Textfield::SelectRect(const gfx::Point& start, const gfx::Point& end) { | |
940 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE) | |
941 return; | |
942 | |
943 gfx::SelectionModel start_caret = GetRenderText()->FindCursorPosition(start); | |
944 gfx::SelectionModel end_caret = GetRenderText()->FindCursorPosition(end); | |
945 gfx::SelectionModel selection( | |
946 gfx::Range(start_caret.caret_pos(), end_caret.caret_pos()), | |
947 end_caret.caret_affinity()); | |
948 | |
949 OnBeforeUserAction(); | |
950 model_->SelectSelectionModel(selection); | |
951 OnCaretBoundsChanged(); | |
952 SchedulePaint(); | |
953 OnAfterUserAction(); | |
954 } | |
955 | |
956 void Textfield::MoveCaretTo(const gfx::Point& point) { | |
957 SelectRect(point, point); | |
958 } | |
959 | |
960 void Textfield::GetSelectionEndPoints(gfx::Rect* p1, gfx::Rect* p2) { | |
961 gfx::RenderText* render_text = GetRenderText(); | |
962 const gfx::SelectionModel& sel = render_text->selection_model(); | |
963 gfx::SelectionModel start_sel = | |
964 render_text->GetSelectionModelForSelectionStart(); | |
965 *p1 = render_text->GetCursorBounds(start_sel, true); | |
966 *p2 = render_text->GetCursorBounds(sel, true); | |
967 } | |
968 | |
969 gfx::Rect Textfield::GetBounds() { | |
970 return bounds(); | |
971 } | |
972 | |
973 gfx::NativeView Textfield::GetNativeView() const { | |
974 return GetWidget()->GetNativeView(); | |
975 } | |
976 | |
977 void Textfield::ConvertPointToScreen(gfx::Point* point) { | |
978 View::ConvertPointToScreen(this, point); | |
979 } | |
980 | |
981 void Textfield::ConvertPointFromScreen(gfx::Point* point) { | |
982 View::ConvertPointFromScreen(this, point); | |
983 } | |
984 | |
985 bool Textfield::DrawsHandles() { | |
986 return false; | |
987 } | |
988 | |
989 void Textfield::OpenContextMenu(const gfx::Point& anchor) { | |
990 touch_selection_controller_.reset(); | |
991 ShowContextMenu(anchor, ui::MENU_SOURCE_TOUCH_EDIT_MENU); | |
992 } | |
993 | |
994 //////////////////////////////////////////////////////////////////////////////// | |
995 // Textfield, ui::SimpleMenuModel::Delegate overrides: | |
996 | |
997 bool Textfield::IsCommandIdChecked(int command_id) const { | |
998 return true; | |
999 } | |
1000 | |
1001 bool Textfield::IsCommandIdEnabled(int command_id) const { | |
1002 base::string16 result; | |
1003 bool editable = !read_only(); | |
1004 switch (command_id) { | |
1005 case IDS_APP_UNDO: | |
1006 return editable && model_->CanUndo(); | |
1007 case IDS_APP_CUT: | |
1008 return editable && model_->HasSelection() && !IsObscured(); | |
1009 case IDS_APP_COPY: | |
1010 return model_->HasSelection() && !IsObscured(); | |
1011 case IDS_APP_PASTE: | |
1012 ui::Clipboard::GetForCurrentThread()->ReadText( | |
1013 ui::CLIPBOARD_TYPE_COPY_PASTE, &result); | |
1014 return editable && !result.empty(); | |
1015 case IDS_APP_DELETE: | |
1016 return editable && model_->HasSelection(); | |
1017 case IDS_APP_SELECT_ALL: | |
1018 return !text().empty(); | |
1019 default: | |
1020 return false; | |
1021 } | |
1022 } | |
1023 | |
1024 bool Textfield::GetAcceleratorForCommandId(int command_id, | |
1025 ui::Accelerator* accelerator) { | |
1026 return false; | |
1027 } | |
1028 | |
1029 void Textfield::ExecuteCommand(int command_id, int event_flags) { | |
1030 touch_selection_controller_.reset(); | |
1031 if (!IsCommandIdEnabled(command_id)) | |
1032 return; | |
1033 | |
1034 bool text_changed = false; | |
1035 switch (command_id) { | |
1036 case IDS_APP_UNDO: | |
1037 OnBeforeUserAction(); | |
1038 text_changed = model_->Undo(); | |
1039 UpdateAfterChange(text_changed, text_changed); | |
1040 OnAfterUserAction(); | |
1041 break; | |
1042 case IDS_APP_CUT: | |
1043 OnBeforeUserAction(); | |
1044 text_changed = Cut(); | |
1045 UpdateAfterChange(text_changed, text_changed); | |
1046 OnAfterUserAction(); | |
1047 break; | |
1048 case IDS_APP_COPY: | |
1049 OnBeforeUserAction(); | |
1050 Copy(); | |
1051 OnAfterUserAction(); | |
1052 break; | |
1053 case IDS_APP_PASTE: | |
1054 OnBeforeUserAction(); | |
1055 text_changed = Paste(); | |
1056 UpdateAfterChange(text_changed, text_changed); | |
1057 OnAfterUserAction(); | |
1058 break; | |
1059 case IDS_APP_DELETE: | |
1060 OnBeforeUserAction(); | |
1061 text_changed = model_->Delete(); | |
1062 UpdateAfterChange(text_changed, text_changed); | |
1063 OnAfterUserAction(); | |
1064 break; | |
1065 case IDS_APP_SELECT_ALL: | |
1066 OnBeforeUserAction(); | |
1067 SelectAll(false); | |
1068 UpdateAfterChange(false, true); | |
1069 OnAfterUserAction(); | |
1070 break; | |
1071 default: | |
1072 NOTREACHED(); | |
1073 break; | |
1074 } | |
1075 } | |
1076 | |
1077 //////////////////////////////////////////////////////////////////////////////// | |
1078 // Textfield, ui::TextInputClient overrides: | |
1079 | |
1080 void Textfield::SetCompositionText(const ui::CompositionText& composition) { | |
1081 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE) | |
1082 return; | |
1083 | |
1084 OnBeforeUserAction(); | |
1085 skip_input_method_cancel_composition_ = true; | |
1086 model_->SetCompositionText(composition); | |
1087 skip_input_method_cancel_composition_ = false; | |
1088 UpdateAfterChange(true, true); | |
1089 OnAfterUserAction(); | |
1090 } | |
1091 | |
1092 void Textfield::ConfirmCompositionText() { | |
1093 if (!model_->HasCompositionText()) | |
1094 return; | |
1095 | |
1096 OnBeforeUserAction(); | |
1097 skip_input_method_cancel_composition_ = true; | |
1098 model_->ConfirmCompositionText(); | |
1099 skip_input_method_cancel_composition_ = false; | |
1100 UpdateAfterChange(true, true); | |
1101 OnAfterUserAction(); | |
1102 } | |
1103 | |
1104 void Textfield::ClearCompositionText() { | |
1105 if (!model_->HasCompositionText()) | |
1106 return; | |
1107 | |
1108 OnBeforeUserAction(); | |
1109 skip_input_method_cancel_composition_ = true; | |
1110 model_->CancelCompositionText(); | |
1111 skip_input_method_cancel_composition_ = false; | |
1112 UpdateAfterChange(true, true); | |
1113 OnAfterUserAction(); | |
1114 } | |
1115 | |
1116 void Textfield::InsertText(const base::string16& new_text) { | |
1117 // TODO(suzhe): Filter invalid characters. | |
1118 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE || new_text.empty()) | |
1119 return; | |
1120 | |
1121 OnBeforeUserAction(); | |
1122 skip_input_method_cancel_composition_ = true; | |
1123 if (GetRenderText()->insert_mode()) | |
1124 model_->InsertText(GetTextForDisplay(new_text)); | |
1125 else | |
1126 model_->ReplaceText(GetTextForDisplay(new_text)); | |
1127 skip_input_method_cancel_composition_ = false; | |
1128 UpdateAfterChange(true, true); | |
1129 OnAfterUserAction(); | |
1130 } | |
1131 | |
1132 void Textfield::InsertChar(base::char16 ch, int flags) { | |
1133 // Filter out all control characters, including tab and new line characters, | |
1134 // and all characters with Alt modifier. But allow characters with the AltGr | |
1135 // modifier. On Windows AltGr is represented by Alt+Ctrl, and on Linux it's a | |
1136 // different flag that we don't care about. | |
1137 const bool should_insert_char = ((ch >= 0x20 && ch < 0x7F) || ch > 0x9F) && | |
1138 (flags & ~(ui::EF_SHIFT_DOWN | ui::EF_CAPS_LOCK_DOWN)) != ui::EF_ALT_DOWN; | |
1139 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE || !should_insert_char) | |
1140 return; | |
1141 | |
1142 OnBeforeUserAction(); | |
1143 skip_input_method_cancel_composition_ = true; | |
1144 if (GetRenderText()->insert_mode()) | |
1145 model_->InsertChar(ch); | |
1146 else | |
1147 model_->ReplaceChar(ch); | |
1148 skip_input_method_cancel_composition_ = false; | |
1149 | |
1150 model_->SetText(GetTextForDisplay(text())); | |
1151 | |
1152 UpdateAfterChange(true, true); | |
1153 OnAfterUserAction(); | |
1154 | |
1155 if (IsObscured() && obscured_reveal_duration_ != base::TimeDelta()) { | |
1156 const size_t change_offset = model_->GetCursorPosition(); | |
1157 DCHECK_GT(change_offset, 0u); | |
1158 RevealObscuredChar(change_offset - 1, obscured_reveal_duration_); | |
1159 } | |
1160 } | |
1161 | |
1162 gfx::NativeWindow Textfield::GetAttachedWindow() const { | |
1163 // Imagine the following hierarchy. | |
1164 // [NativeWidget A] - FocusManager | |
1165 // [View] | |
1166 // [NativeWidget B] | |
1167 // [View] | |
1168 // [View X] | |
1169 // An important thing is that [NativeWidget A] owns Win32 input focus even | |
1170 // when [View X] is logically focused by FocusManager. As a result, an Win32 | |
1171 // IME may want to interact with the native view of [NativeWidget A] rather | |
1172 // than that of [NativeWidget B]. This is why we need to call | |
1173 // GetTopLevelWidget() here. | |
1174 return GetWidget()->GetTopLevelWidget()->GetNativeView(); | |
1175 } | |
1176 | |
1177 ui::TextInputType Textfield::GetTextInputType() const { | |
1178 if (read_only() || !enabled()) | |
1179 return ui::TEXT_INPUT_TYPE_NONE; | |
1180 return text_input_type_; | |
1181 } | |
1182 | |
1183 ui::TextInputMode Textfield::GetTextInputMode() const { | |
1184 return ui::TEXT_INPUT_MODE_DEFAULT; | |
1185 } | |
1186 | |
1187 bool Textfield::CanComposeInline() const { | |
1188 return true; | |
1189 } | |
1190 | |
1191 gfx::Rect Textfield::GetCaretBounds() const { | |
1192 gfx::Rect rect = GetRenderText()->GetUpdatedCursorBounds(); | |
1193 ConvertRectToScreen(this, &rect); | |
1194 return rect; | |
1195 } | |
1196 | |
1197 bool Textfield::GetCompositionCharacterBounds(uint32 index, | |
1198 gfx::Rect* rect) const { | |
1199 DCHECK(rect); | |
1200 if (!HasCompositionText()) | |
1201 return false; | |
1202 gfx::RenderText* render_text = GetRenderText(); | |
1203 const gfx::Range& composition_range = render_text->GetCompositionRange(); | |
1204 DCHECK(!composition_range.is_empty()); | |
1205 | |
1206 size_t text_index = composition_range.start() + index; | |
1207 if (composition_range.end() <= text_index) | |
1208 return false; | |
1209 if (!render_text->IsCursorablePosition(text_index)) { | |
1210 text_index = render_text->IndexOfAdjacentGrapheme( | |
1211 text_index, gfx::CURSOR_BACKWARD); | |
1212 } | |
1213 if (text_index < composition_range.start()) | |
1214 return false; | |
1215 const gfx::SelectionModel caret(text_index, gfx::CURSOR_BACKWARD); | |
1216 *rect = render_text->GetCursorBounds(caret, false); | |
1217 ConvertRectToScreen(this, rect); | |
1218 return true; | |
1219 } | |
1220 | |
1221 bool Textfield::HasCompositionText() const { | |
1222 return model_->HasCompositionText(); | |
1223 } | |
1224 | |
1225 bool Textfield::GetTextRange(gfx::Range* range) const { | |
1226 if (!ImeEditingAllowed()) | |
1227 return false; | |
1228 | |
1229 model_->GetTextRange(range); | |
1230 return true; | |
1231 } | |
1232 | |
1233 bool Textfield::GetCompositionTextRange(gfx::Range* range) const { | |
1234 if (!ImeEditingAllowed()) | |
1235 return false; | |
1236 | |
1237 model_->GetCompositionTextRange(range); | |
1238 return true; | |
1239 } | |
1240 | |
1241 bool Textfield::GetSelectionRange(gfx::Range* range) const { | |
1242 if (!ImeEditingAllowed()) | |
1243 return false; | |
1244 *range = GetRenderText()->selection(); | |
1245 return true; | |
1246 } | |
1247 | |
1248 bool Textfield::SetSelectionRange(const gfx::Range& range) { | |
1249 if (!ImeEditingAllowed() || !range.IsValid()) | |
1250 return false; | |
1251 | |
1252 OnBeforeUserAction(); | |
1253 SelectRange(range); | |
1254 OnAfterUserAction(); | |
1255 return true; | |
1256 } | |
1257 | |
1258 bool Textfield::DeleteRange(const gfx::Range& range) { | |
1259 if (!ImeEditingAllowed() || range.is_empty()) | |
1260 return false; | |
1261 | |
1262 OnBeforeUserAction(); | |
1263 model_->SelectRange(range); | |
1264 if (model_->HasSelection()) { | |
1265 model_->DeleteSelection(); | |
1266 UpdateAfterChange(true, true); | |
1267 } | |
1268 OnAfterUserAction(); | |
1269 return true; | |
1270 } | |
1271 | |
1272 bool Textfield::GetTextFromRange(const gfx::Range& range, | |
1273 base::string16* range_text) const { | |
1274 if (!ImeEditingAllowed() || !range.IsValid()) | |
1275 return false; | |
1276 | |
1277 gfx::Range text_range; | |
1278 if (!GetTextRange(&text_range) || !text_range.Contains(range)) | |
1279 return false; | |
1280 | |
1281 *range_text = model_->GetTextFromRange(range); | |
1282 return true; | |
1283 } | |
1284 | |
1285 void Textfield::OnInputMethodChanged() {} | |
1286 | |
1287 bool Textfield::ChangeTextDirectionAndLayoutAlignment( | |
1288 base::i18n::TextDirection direction) { | |
1289 // Restore text directionality mode when the indicated direction matches the | |
1290 // current forced mode; otherwise, force the mode indicated. This helps users | |
1291 // manage BiDi text layout without getting stuck in forced LTR or RTL modes. | |
1292 const gfx::DirectionalityMode mode = direction == base::i18n::RIGHT_TO_LEFT ? | |
1293 gfx::DIRECTIONALITY_FORCE_RTL : gfx::DIRECTIONALITY_FORCE_LTR; | |
1294 if (mode == GetRenderText()->directionality_mode()) | |
1295 GetRenderText()->SetDirectionalityMode(gfx::DIRECTIONALITY_FROM_TEXT); | |
1296 else | |
1297 GetRenderText()->SetDirectionalityMode(mode); | |
1298 SchedulePaint(); | |
1299 return true; | |
1300 } | |
1301 | |
1302 void Textfield::ExtendSelectionAndDelete(size_t before, size_t after) { | |
1303 gfx::Range range = GetRenderText()->selection(); | |
1304 DCHECK_GE(range.start(), before); | |
1305 | |
1306 range.set_start(range.start() - before); | |
1307 range.set_end(range.end() + after); | |
1308 gfx::Range text_range; | |
1309 if (GetTextRange(&text_range) && text_range.Contains(range)) | |
1310 DeleteRange(range); | |
1311 } | |
1312 | |
1313 void Textfield::EnsureCaretInRect(const gfx::Rect& rect) {} | |
1314 | |
1315 void Textfield::OnCandidateWindowShown() {} | |
1316 | |
1317 void Textfield::OnCandidateWindowUpdated() {} | |
1318 | |
1319 void Textfield::OnCandidateWindowHidden() {} | |
1320 | |
1321 //////////////////////////////////////////////////////////////////////////////// | |
1322 // Textfield, protected: | |
1323 | |
1324 gfx::RenderText* Textfield::GetRenderText() const { | |
1325 return model_->render_text(); | |
1326 } | |
1327 | |
1328 //////////////////////////////////////////////////////////////////////////////// | 542 //////////////////////////////////////////////////////////////////////////////// |
1329 // Textfield, private: | 543 // Textfield, private: |
1330 | 544 |
1331 base::string16 Textfield::GetTextForDisplay(const base::string16& raw) { | 545 gfx::Insets Textfield::GetTextInsets() const { |
1332 return style_ & Textfield::STYLE_LOWERCASE ? base::i18n::ToLower(raw) : raw; | 546 gfx::Insets insets = GetInsets(); |
| 547 if (draw_border_ && textfield_view_) |
| 548 insets += textfield_view_->GetInsets(); |
| 549 return insets; |
1333 } | 550 } |
1334 | 551 |
1335 void Textfield::AccessibilitySetValue(const base::string16& new_value) { | 552 void Textfield::AccessibilitySetValue(const base::string16& new_value) { |
1336 if (!read_only()) { | 553 if (!read_only()) { |
1337 SetText(new_value); | 554 SetText(new_value); |
1338 ClearSelection(); | 555 ClearSelection(); |
1339 } | 556 } |
1340 } | 557 } |
1341 | 558 |
1342 void Textfield::UpdateBackgroundColor() { | |
1343 const SkColor color = GetBackgroundColor(); | |
1344 set_background(Background::CreateSolidBackground(color)); | |
1345 GetRenderText()->set_background_is_transparent(SkColorGetA(color) != 0xFF); | |
1346 SchedulePaint(); | |
1347 } | |
1348 | |
1349 void Textfield::UpdateColorsFromTheme(const ui::NativeTheme* theme) { | |
1350 gfx::RenderText* render_text = GetRenderText(); | |
1351 render_text->SetColor(GetTextColor()); | |
1352 UpdateBackgroundColor(); | |
1353 render_text->set_cursor_color(GetTextColor()); | |
1354 render_text->set_selection_color(theme->GetSystemColor( | |
1355 ui::NativeTheme::kColorId_TextfieldSelectionColor)); | |
1356 render_text->set_selection_background_focused_color(theme->GetSystemColor( | |
1357 ui::NativeTheme::kColorId_TextfieldSelectionBackgroundFocused)); | |
1358 } | |
1359 | |
1360 void Textfield::UpdateAfterChange(bool text_changed, bool cursor_changed) { | |
1361 if (text_changed) { | |
1362 if (controller_) | |
1363 controller_->ContentsChanged(this, text()); | |
1364 NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_TEXT_CHANGED, true); | |
1365 } | |
1366 if (cursor_changed) { | |
1367 is_cursor_visible_ = true; | |
1368 RepaintCursor(); | |
1369 if (cursor_repaint_timer_.IsRunning()) | |
1370 cursor_repaint_timer_.Reset(); | |
1371 if (!text_changed) { | |
1372 // TEXT_CHANGED implies SELECTION_CHANGED, so we only need to fire | |
1373 // this if only the selection changed. | |
1374 NotifyAccessibilityEvent( | |
1375 ui::AccessibilityTypes::EVENT_SELECTION_CHANGED, true); | |
1376 } | |
1377 } | |
1378 if (text_changed || cursor_changed) { | |
1379 OnCaretBoundsChanged(); | |
1380 SchedulePaint(); | |
1381 } | |
1382 } | |
1383 | |
1384 void Textfield::UpdateCursor() { | |
1385 const size_t caret_blink_ms = Textfield::GetCaretBlinkMs(); | |
1386 is_cursor_visible_ = !is_cursor_visible_ || (caret_blink_ms == 0); | |
1387 RepaintCursor(); | |
1388 } | |
1389 | |
1390 void Textfield::RepaintCursor() { | |
1391 gfx::Rect r(GetRenderText()->GetUpdatedCursorBounds()); | |
1392 r.Inset(-1, -1, -1, -1); | |
1393 SchedulePaintInRect(r); | |
1394 } | |
1395 | |
1396 void Textfield::PaintTextAndCursor(gfx::Canvas* canvas) { | |
1397 TRACE_EVENT0("views", "Textfield::PaintTextAndCursor"); | |
1398 canvas->Save(); | |
1399 gfx::RenderText* render_text = GetRenderText(); | |
1400 render_text->set_cursor_visible(!is_drop_cursor_visible_ && | |
1401 is_cursor_visible_ && !model_->HasSelection()); | |
1402 // Draw the text, cursor, and selection. | |
1403 render_text->Draw(canvas); | |
1404 | |
1405 // Draw the detached drop cursor that marks where the text will be dropped. | |
1406 if (is_drop_cursor_visible_) | |
1407 render_text->DrawCursor(canvas, drop_cursor_position_); | |
1408 | |
1409 // Draw placeholder text if needed. | |
1410 if (text().empty() && !GetPlaceholderText().empty()) { | |
1411 canvas->DrawStringRect(GetPlaceholderText(), GetFontList(), | |
1412 placeholder_text_color(), render_text->display_rect()); | |
1413 } | |
1414 canvas->Restore(); | |
1415 } | |
1416 | |
1417 bool Textfield::MoveCursorTo(const gfx::Point& point, bool select) { | |
1418 if (!model_->MoveCursorTo(point, select)) | |
1419 return false; | |
1420 OnCaretBoundsChanged(); | |
1421 return true; | |
1422 } | |
1423 | |
1424 void Textfield::OnCaretBoundsChanged() { | |
1425 if (GetInputMethod()) | |
1426 GetInputMethod()->OnCaretBoundsChanged(this); | |
1427 if (touch_selection_controller_) | |
1428 touch_selection_controller_->SelectionChanged(); | |
1429 } | |
1430 | |
1431 void Textfield::OnBeforeUserAction() { | |
1432 if (controller_) | |
1433 controller_->OnBeforeUserAction(this); | |
1434 } | |
1435 | |
1436 void Textfield::OnAfterUserAction() { | |
1437 if (controller_) | |
1438 controller_->OnAfterUserAction(this); | |
1439 } | |
1440 | |
1441 bool Textfield::Cut() { | |
1442 if (!read_only() && !IsObscured() && model_->Cut()) { | |
1443 if (controller_) | |
1444 controller_->OnAfterCutOrCopy(); | |
1445 return true; | |
1446 } | |
1447 return false; | |
1448 } | |
1449 | |
1450 bool Textfield::Copy() { | |
1451 if (!IsObscured() && model_->Copy()) { | |
1452 if (controller_) | |
1453 controller_->OnAfterCutOrCopy(); | |
1454 return true; | |
1455 } | |
1456 return false; | |
1457 } | |
1458 | |
1459 bool Textfield::Paste() { | |
1460 if (read_only()) | |
1461 return false; | |
1462 | |
1463 const base::string16 original_text = text(); | |
1464 if (model_->Paste()) { | |
1465 // As Paste is handled in model_->Paste(), the RenderText may contain | |
1466 // upper case characters. This is not consistent with other places | |
1467 // which keeps RenderText only containing lower case characters. | |
1468 base::string16 new_text = GetTextForDisplay(text()); | |
1469 model_->SetText(new_text); | |
1470 if (controller_) | |
1471 controller_->OnAfterPaste(); | |
1472 return true; | |
1473 } | |
1474 return false; | |
1475 } | |
1476 | |
1477 void Textfield::UpdateContextMenu() { | |
1478 if (!context_menu_contents_.get()) { | |
1479 context_menu_contents_.reset(new ui::SimpleMenuModel(this)); | |
1480 context_menu_contents_->AddItemWithStringId(IDS_APP_UNDO, IDS_APP_UNDO); | |
1481 context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR); | |
1482 context_menu_contents_->AddItemWithStringId(IDS_APP_CUT, IDS_APP_CUT); | |
1483 context_menu_contents_->AddItemWithStringId(IDS_APP_COPY, IDS_APP_COPY); | |
1484 context_menu_contents_->AddItemWithStringId(IDS_APP_PASTE, IDS_APP_PASTE); | |
1485 context_menu_contents_->AddItemWithStringId(IDS_APP_DELETE, IDS_APP_DELETE); | |
1486 context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR); | |
1487 context_menu_contents_->AddItemWithStringId(IDS_APP_SELECT_ALL, | |
1488 IDS_APP_SELECT_ALL); | |
1489 if (controller_) | |
1490 controller_->UpdateContextMenu(context_menu_contents_.get()); | |
1491 context_menu_runner_.reset(new MenuRunner(context_menu_contents_.get())); | |
1492 } | |
1493 } | |
1494 | |
1495 void Textfield::TrackMouseClicks(const ui::MouseEvent& event) { | |
1496 if (event.IsOnlyLeftMouseButton()) { | |
1497 base::TimeDelta time_delta = event.time_stamp() - last_click_time_; | |
1498 if (time_delta.InMilliseconds() <= GetDoubleClickInterval() && | |
1499 !ExceededDragThreshold(event.location() - last_click_location_)) { | |
1500 // Upon clicking after a triple click, the count should go back to double | |
1501 // click and alternate between double and triple. This assignment maps | |
1502 // 0 to 1, 1 to 2, 2 to 1. | |
1503 aggregated_clicks_ = (aggregated_clicks_ % 2) + 1; | |
1504 } else { | |
1505 aggregated_clicks_ = 0; | |
1506 } | |
1507 last_click_time_ = event.time_stamp(); | |
1508 last_click_location_ = event.location(); | |
1509 } | |
1510 } | |
1511 | |
1512 bool Textfield::ImeEditingAllowed() const { | |
1513 // Disallow input method editing of password fields. | |
1514 ui::TextInputType t = GetTextInputType(); | |
1515 return (t != ui::TEXT_INPUT_TYPE_NONE && t != ui::TEXT_INPUT_TYPE_PASSWORD); | |
1516 } | |
1517 | |
1518 void Textfield::RevealObscuredChar(int index, const base::TimeDelta& duration) { | |
1519 GetRenderText()->SetObscuredRevealIndex(index); | |
1520 SchedulePaint(); | |
1521 | |
1522 if (index != -1) { | |
1523 obscured_reveal_timer_.Start(FROM_HERE, duration, | |
1524 base::Bind(&Textfield::RevealObscuredChar, base::Unretained(this), | |
1525 -1, base::TimeDelta())); | |
1526 } | |
1527 } | |
1528 | |
1529 void Textfield::CreateTouchSelectionControllerAndNotifyIt() { | |
1530 if (!touch_selection_controller_) { | |
1531 touch_selection_controller_.reset( | |
1532 ui::TouchSelectionController::create(this)); | |
1533 } | |
1534 if (touch_selection_controller_) | |
1535 touch_selection_controller_->SelectionChanged(); | |
1536 } | |
1537 | |
1538 } // namespace views | 559 } // namespace views |
OLD | NEW |