Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(769)

Side by Side Diff: ui/views/controls/textfield/textfield.cc

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

Powered by Google App Engine
This is Rietveld 408576698