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

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

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

Powered by Google App Engine
This is Rietveld 408576698