OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/views/controls/textfield/textfield_views_model.h" | 5 #include "ui/views/controls/textfield/textfield_views_model.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/i18n/break_iterator.h" | 9 #include "base/i18n/break_iterator.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
74 void Commit() { merge_type_ = DO_NOT_MERGE; } | 74 void Commit() { merge_type_ = DO_NOT_MERGE; } |
75 | 75 |
76 private: | 76 private: |
77 friend class InsertEdit; | 77 friend class InsertEdit; |
78 friend class ReplaceEdit; | 78 friend class ReplaceEdit; |
79 friend class DeleteEdit; | 79 friend class DeleteEdit; |
80 | 80 |
81 Edit(Type type, | 81 Edit(Type type, |
82 MergeType merge_type, | 82 MergeType merge_type, |
83 size_t old_cursor_pos, | 83 size_t old_cursor_pos, |
84 const string16& old_text, | 84 const base::string16& old_text, |
85 size_t old_text_start, | 85 size_t old_text_start, |
86 bool delete_backward, | 86 bool delete_backward, |
87 size_t new_cursor_pos, | 87 size_t new_cursor_pos, |
88 const string16& new_text, | 88 const base::string16& new_text, |
89 size_t new_text_start) | 89 size_t new_text_start) |
90 : type_(type), | 90 : type_(type), |
91 merge_type_(merge_type), | 91 merge_type_(merge_type), |
92 old_cursor_pos_(old_cursor_pos), | 92 old_cursor_pos_(old_cursor_pos), |
93 old_text_(old_text), | 93 old_text_(old_text), |
94 old_text_start_(old_text_start), | 94 old_text_start_(old_text_start), |
95 delete_backward_(delete_backward), | 95 delete_backward_(delete_backward), |
96 new_cursor_pos_(new_cursor_pos), | 96 new_cursor_pos_(new_cursor_pos), |
97 new_text_(new_text), | 97 new_text_(new_text), |
98 new_text_start_(new_text_start) { | 98 new_text_start_(new_text_start) { |
(...skipping 19 matching lines...) Expand all Loading... |
118 // Returns the end index of the |new_text_|. | 118 // Returns the end index of the |new_text_|. |
119 size_t new_text_end() const { return new_text_start_ + new_text_.length(); } | 119 size_t new_text_end() const { return new_text_start_ + new_text_.length(); } |
120 | 120 |
121 // Merge the replace edit into the current edit. This is a special case to | 121 // Merge the replace edit into the current edit. This is a special case to |
122 // handle an omnibox setting autocomplete string after new character is | 122 // handle an omnibox setting autocomplete string after new character is |
123 // typed in. | 123 // typed in. |
124 void MergeReplace(const Edit* edit) { | 124 void MergeReplace(const Edit* edit) { |
125 CHECK_EQ(REPLACE_EDIT, edit->type_); | 125 CHECK_EQ(REPLACE_EDIT, edit->type_); |
126 CHECK_EQ(0U, edit->old_text_start_); | 126 CHECK_EQ(0U, edit->old_text_start_); |
127 CHECK_EQ(0U, edit->new_text_start_); | 127 CHECK_EQ(0U, edit->new_text_start_); |
128 string16 old_text = edit->old_text_; | 128 base::string16 old_text = edit->old_text_; |
129 old_text.erase(new_text_start_, new_text_.length()); | 129 old_text.erase(new_text_start_, new_text_.length()); |
130 old_text.insert(old_text_start_, old_text_); | 130 old_text.insert(old_text_start_, old_text_); |
131 // SetText() replaces entire text. Set |old_text_| to the entire | 131 // SetText() replaces entire text. Set |old_text_| to the entire |
132 // replaced text with |this| edit undone. | 132 // replaced text with |this| edit undone. |
133 old_text_ = old_text; | 133 old_text_ = old_text; |
134 old_text_start_ = edit->old_text_start_; | 134 old_text_start_ = edit->old_text_start_; |
135 delete_backward_ = false; | 135 delete_backward_ = false; |
136 | 136 |
137 new_text_ = edit->new_text_; | 137 new_text_ = edit->new_text_; |
138 new_text_start_ = edit->new_text_start_; | 138 new_text_start_ = edit->new_text_start_; |
139 merge_type_ = DO_NOT_MERGE; | 139 merge_type_ = DO_NOT_MERGE; |
140 } | 140 } |
141 | 141 |
142 Type type_; | 142 Type type_; |
143 | 143 |
144 // True if the edit can be marged. | 144 // True if the edit can be marged. |
145 MergeType merge_type_; | 145 MergeType merge_type_; |
146 // Old cursor position. | 146 // Old cursor position. |
147 size_t old_cursor_pos_; | 147 size_t old_cursor_pos_; |
148 // Deleted text by this edit. | 148 // Deleted text by this edit. |
149 string16 old_text_; | 149 base::string16 old_text_; |
150 // The index of |old_text_|. | 150 // The index of |old_text_|. |
151 size_t old_text_start_; | 151 size_t old_text_start_; |
152 // True if the deletion is made backward. | 152 // True if the deletion is made backward. |
153 bool delete_backward_; | 153 bool delete_backward_; |
154 // New cursor position. | 154 // New cursor position. |
155 size_t new_cursor_pos_; | 155 size_t new_cursor_pos_; |
156 // Added text. | 156 // Added text. |
157 string16 new_text_; | 157 base::string16 new_text_; |
158 // The index of |new_text_| | 158 // The index of |new_text_| |
159 size_t new_text_start_; | 159 size_t new_text_start_; |
160 | 160 |
161 DISALLOW_COPY_AND_ASSIGN(Edit); | 161 DISALLOW_COPY_AND_ASSIGN(Edit); |
162 }; | 162 }; |
163 | 163 |
164 class InsertEdit : public Edit { | 164 class InsertEdit : public Edit { |
165 public: | 165 public: |
166 InsertEdit(bool mergeable, const string16& new_text, size_t at) | 166 InsertEdit(bool mergeable, const base::string16& new_text, size_t at) |
167 : Edit(INSERT_EDIT, | 167 : Edit(INSERT_EDIT, |
168 mergeable ? MERGEABLE : DO_NOT_MERGE, | 168 mergeable ? MERGEABLE : DO_NOT_MERGE, |
169 at /* old cursor */, | 169 at /* old cursor */, |
170 string16(), | 170 base::string16(), |
171 at, | 171 at, |
172 false /* N/A */, | 172 false /* N/A */, |
173 at + new_text.length() /* new cursor */, | 173 at + new_text.length() /* new cursor */, |
174 new_text, | 174 new_text, |
175 at) { | 175 at) { |
176 } | 176 } |
177 | 177 |
178 // Edit implementation. | 178 // Edit implementation. |
179 virtual bool DoMerge(const Edit* edit) OVERRIDE { | 179 virtual bool DoMerge(const Edit* edit) OVERRIDE { |
180 if (edit->type() != INSERT_EDIT || new_text_end() != edit->new_text_start_) | 180 if (edit->type() != INSERT_EDIT || new_text_end() != edit->new_text_start_) |
181 return false; | 181 return false; |
182 // If continuous edit, merge it. | 182 // If continuous edit, merge it. |
183 // TODO(oshima): gtk splits edits between whitespace. Find out what | 183 // TODO(oshima): gtk splits edits between whitespace. Find out what |
184 // we want to here and implement if necessary. | 184 // we want to here and implement if necessary. |
185 new_text_ += edit->new_text_; | 185 new_text_ += edit->new_text_; |
186 new_cursor_pos_ = edit->new_cursor_pos_; | 186 new_cursor_pos_ = edit->new_cursor_pos_; |
187 return true; | 187 return true; |
188 } | 188 } |
189 }; | 189 }; |
190 | 190 |
191 class ReplaceEdit : public Edit { | 191 class ReplaceEdit : public Edit { |
192 public: | 192 public: |
193 ReplaceEdit(MergeType merge_type, | 193 ReplaceEdit(MergeType merge_type, |
194 const string16& old_text, | 194 const base::string16& old_text, |
195 size_t old_cursor_pos, | 195 size_t old_cursor_pos, |
196 size_t old_text_start, | 196 size_t old_text_start, |
197 bool backward, | 197 bool backward, |
198 size_t new_cursor_pos, | 198 size_t new_cursor_pos, |
199 const string16& new_text, | 199 const base::string16& new_text, |
200 size_t new_text_start) | 200 size_t new_text_start) |
201 : Edit(REPLACE_EDIT, merge_type, | 201 : Edit(REPLACE_EDIT, merge_type, |
202 old_cursor_pos, | 202 old_cursor_pos, |
203 old_text, | 203 old_text, |
204 old_text_start, | 204 old_text_start, |
205 backward, | 205 backward, |
206 new_cursor_pos, | 206 new_cursor_pos, |
207 new_text, | 207 new_text, |
208 new_text_start) { | 208 new_text_start) { |
209 } | 209 } |
210 | 210 |
211 // Edit implementation. | 211 // Edit implementation. |
212 virtual bool DoMerge(const Edit* edit) OVERRIDE { | 212 virtual bool DoMerge(const Edit* edit) OVERRIDE { |
213 if (edit->type() == DELETE_EDIT || | 213 if (edit->type() == DELETE_EDIT || |
214 new_text_end() != edit->old_text_start_ || | 214 new_text_end() != edit->old_text_start_ || |
215 edit->old_text_start_ != edit->new_text_start_) | 215 edit->old_text_start_ != edit->new_text_start_) |
216 return false; | 216 return false; |
217 old_text_ += edit->old_text_; | 217 old_text_ += edit->old_text_; |
218 new_text_ += edit->new_text_; | 218 new_text_ += edit->new_text_; |
219 new_cursor_pos_ = edit->new_cursor_pos_; | 219 new_cursor_pos_ = edit->new_cursor_pos_; |
220 return true; | 220 return true; |
221 } | 221 } |
222 }; | 222 }; |
223 | 223 |
224 class DeleteEdit : public Edit { | 224 class DeleteEdit : public Edit { |
225 public: | 225 public: |
226 DeleteEdit(bool mergeable, | 226 DeleteEdit(bool mergeable, |
227 const string16& text, | 227 const base::string16& text, |
228 size_t text_start, | 228 size_t text_start, |
229 bool backward) | 229 bool backward) |
230 : Edit(DELETE_EDIT, | 230 : Edit(DELETE_EDIT, |
231 mergeable ? MERGEABLE : DO_NOT_MERGE, | 231 mergeable ? MERGEABLE : DO_NOT_MERGE, |
232 (backward ? text_start + text.length() : text_start), | 232 (backward ? text_start + text.length() : text_start), |
233 text, | 233 text, |
234 text_start, | 234 text_start, |
235 backward, | 235 backward, |
236 text_start, | 236 text_start, |
237 string16(), | 237 base::string16(), |
238 text_start) { | 238 text_start) { |
239 } | 239 } |
240 | 240 |
241 // Edit implementation. | 241 // Edit implementation. |
242 virtual bool DoMerge(const Edit* edit) OVERRIDE { | 242 virtual bool DoMerge(const Edit* edit) OVERRIDE { |
243 if (edit->type() != DELETE_EDIT) | 243 if (edit->type() != DELETE_EDIT) |
244 return false; | 244 return false; |
245 | 245 |
246 if (delete_backward_) { | 246 if (delete_backward_) { |
247 // backspace can be merged only with backspace at the | 247 // backspace can be merged only with backspace at the |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
299 : delegate_(delegate), | 299 : delegate_(delegate), |
300 render_text_(gfx::RenderText::CreateInstance()), | 300 render_text_(gfx::RenderText::CreateInstance()), |
301 current_edit_(edit_history_.end()) { | 301 current_edit_(edit_history_.end()) { |
302 } | 302 } |
303 | 303 |
304 TextfieldViewsModel::~TextfieldViewsModel() { | 304 TextfieldViewsModel::~TextfieldViewsModel() { |
305 ClearEditHistory(); | 305 ClearEditHistory(); |
306 ClearComposition(); | 306 ClearComposition(); |
307 } | 307 } |
308 | 308 |
309 const string16& TextfieldViewsModel::GetText() const { | 309 const base::string16& TextfieldViewsModel::GetText() const { |
310 return render_text_->text(); | 310 return render_text_->text(); |
311 } | 311 } |
312 | 312 |
313 bool TextfieldViewsModel::SetText(const string16& text) { | 313 bool TextfieldViewsModel::SetText(const base::string16& text) { |
314 bool changed = false; | 314 bool changed = false; |
315 if (HasCompositionText()) { | 315 if (HasCompositionText()) { |
316 ConfirmCompositionText(); | 316 ConfirmCompositionText(); |
317 changed = true; | 317 changed = true; |
318 } | 318 } |
319 if (GetText() != text) { | 319 if (GetText() != text) { |
320 if (changed) // No need to remember composition. | 320 if (changed) // No need to remember composition. |
321 Undo(); | 321 Undo(); |
322 size_t old_cursor = GetCursorPosition(); | 322 size_t old_cursor = GetCursorPosition(); |
323 // SetText moves the cursor to the end. | 323 // SetText moves the cursor to the end. |
324 size_t new_cursor = text.length(); | 324 size_t new_cursor = text.length(); |
325 SelectAll(false); | 325 SelectAll(false); |
326 // If there is a composition text, don't merge with previous edit. | 326 // If there is a composition text, don't merge with previous edit. |
327 // Otherwise, force merge the edits. | 327 // Otherwise, force merge the edits. |
328 ExecuteAndRecordReplace( | 328 ExecuteAndRecordReplace( |
329 changed ? DO_NOT_MERGE : MERGE_WITH_PREVIOUS, | 329 changed ? DO_NOT_MERGE : MERGE_WITH_PREVIOUS, |
330 old_cursor, | 330 old_cursor, |
331 new_cursor, | 331 new_cursor, |
332 text, | 332 text, |
333 0U); | 333 0U); |
334 render_text_->SetCursorPosition(new_cursor); | 334 render_text_->SetCursorPosition(new_cursor); |
335 } | 335 } |
336 ClearSelection(); | 336 ClearSelection(); |
337 return changed; | 337 return changed; |
338 } | 338 } |
339 | 339 |
340 void TextfieldViewsModel::Append(const string16& text) { | 340 void TextfieldViewsModel::Append(const base::string16& text) { |
341 if (HasCompositionText()) | 341 if (HasCompositionText()) |
342 ConfirmCompositionText(); | 342 ConfirmCompositionText(); |
343 size_t save = GetCursorPosition(); | 343 size_t save = GetCursorPosition(); |
344 MoveCursor(gfx::LINE_BREAK, | 344 MoveCursor(gfx::LINE_BREAK, |
345 render_text_->GetVisualDirectionOfLogicalEnd(), | 345 render_text_->GetVisualDirectionOfLogicalEnd(), |
346 false); | 346 false); |
347 InsertText(text); | 347 InsertText(text); |
348 render_text_->SetCursorPosition(save); | 348 render_text_->SetCursorPosition(save); |
349 ClearSelection(); | 349 ClearSelection(); |
350 } | 350 } |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
416 } | 416 } |
417 return render_text_->MoveCursorTo(model); | 417 return render_text_->MoveCursorTo(model); |
418 } | 418 } |
419 | 419 |
420 bool TextfieldViewsModel::MoveCursorTo(const gfx::Point& point, bool select) { | 420 bool TextfieldViewsModel::MoveCursorTo(const gfx::Point& point, bool select) { |
421 if (HasCompositionText()) | 421 if (HasCompositionText()) |
422 ConfirmCompositionText(); | 422 ConfirmCompositionText(); |
423 return render_text_->MoveCursorTo(point, select); | 423 return render_text_->MoveCursorTo(point, select); |
424 } | 424 } |
425 | 425 |
426 string16 TextfieldViewsModel::GetSelectedText() const { | 426 base::string16 TextfieldViewsModel::GetSelectedText() const { |
427 return GetText().substr(render_text_->selection().GetMin(), | 427 return GetText().substr(render_text_->selection().GetMin(), |
428 render_text_->selection().length()); | 428 render_text_->selection().length()); |
429 } | 429 } |
430 | 430 |
431 void TextfieldViewsModel::SelectRange(const gfx::Range& range) { | 431 void TextfieldViewsModel::SelectRange(const gfx::Range& range) { |
432 if (HasCompositionText()) | 432 if (HasCompositionText()) |
433 ConfirmCompositionText(); | 433 ConfirmCompositionText(); |
434 render_text_->SelectRange(range); | 434 render_text_->SelectRange(range); |
435 } | 435 } |
436 | 436 |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
472 ++iter != edit_history_.end(); | 472 ++iter != edit_history_.end(); |
473 } | 473 } |
474 | 474 |
475 bool TextfieldViewsModel::Undo() { | 475 bool TextfieldViewsModel::Undo() { |
476 if (!CanUndo()) | 476 if (!CanUndo()) |
477 return false; | 477 return false; |
478 DCHECK(!HasCompositionText()); | 478 DCHECK(!HasCompositionText()); |
479 if (HasCompositionText()) // safe guard for release build. | 479 if (HasCompositionText()) // safe guard for release build. |
480 CancelCompositionText(); | 480 CancelCompositionText(); |
481 | 481 |
482 string16 old = GetText(); | 482 base::string16 old = GetText(); |
483 size_t old_cursor = GetCursorPosition(); | 483 size_t old_cursor = GetCursorPosition(); |
484 (*current_edit_)->Commit(); | 484 (*current_edit_)->Commit(); |
485 (*current_edit_)->Undo(this); | 485 (*current_edit_)->Undo(this); |
486 | 486 |
487 if (current_edit_ == edit_history_.begin()) | 487 if (current_edit_ == edit_history_.begin()) |
488 current_edit_ = edit_history_.end(); | 488 current_edit_ = edit_history_.end(); |
489 else | 489 else |
490 current_edit_--; | 490 current_edit_--; |
491 return old != GetText() || old_cursor != GetCursorPosition(); | 491 return old != GetText() || old_cursor != GetCursorPosition(); |
492 } | 492 } |
493 | 493 |
494 bool TextfieldViewsModel::Redo() { | 494 bool TextfieldViewsModel::Redo() { |
495 if (!CanRedo()) | 495 if (!CanRedo()) |
496 return false; | 496 return false; |
497 DCHECK(!HasCompositionText()); | 497 DCHECK(!HasCompositionText()); |
498 if (HasCompositionText()) // safe guard for release build. | 498 if (HasCompositionText()) // safe guard for release build. |
499 CancelCompositionText(); | 499 CancelCompositionText(); |
500 | 500 |
501 if (current_edit_ == edit_history_.end()) | 501 if (current_edit_ == edit_history_.end()) |
502 current_edit_ = edit_history_.begin(); | 502 current_edit_ = edit_history_.begin(); |
503 else | 503 else |
504 current_edit_ ++; | 504 current_edit_ ++; |
505 string16 old = GetText(); | 505 base::string16 old = GetText(); |
506 size_t old_cursor = GetCursorPosition(); | 506 size_t old_cursor = GetCursorPosition(); |
507 (*current_edit_)->Redo(this); | 507 (*current_edit_)->Redo(this); |
508 return old != GetText() || old_cursor != GetCursorPosition(); | 508 return old != GetText() || old_cursor != GetCursorPosition(); |
509 } | 509 } |
510 | 510 |
511 bool TextfieldViewsModel::Cut() { | 511 bool TextfieldViewsModel::Cut() { |
512 if (!HasCompositionText() && HasSelection() && !render_text_->obscured()) { | 512 if (!HasCompositionText() && HasSelection() && !render_text_->obscured()) { |
513 ui::ScopedClipboardWriter( | 513 ui::ScopedClipboardWriter( |
514 ui::Clipboard::GetForCurrentThread(), | 514 ui::Clipboard::GetForCurrentThread(), |
515 ui::CLIPBOARD_TYPE_COPY_PASTE).WriteText(GetSelectedText()); | 515 ui::CLIPBOARD_TYPE_COPY_PASTE).WriteText(GetSelectedText()); |
(...skipping 14 matching lines...) Expand all Loading... |
530 if (!HasCompositionText() && HasSelection() && !render_text_->obscured()) { | 530 if (!HasCompositionText() && HasSelection() && !render_text_->obscured()) { |
531 ui::ScopedClipboardWriter( | 531 ui::ScopedClipboardWriter( |
532 ui::Clipboard::GetForCurrentThread(), | 532 ui::Clipboard::GetForCurrentThread(), |
533 ui::CLIPBOARD_TYPE_COPY_PASTE).WriteText(GetSelectedText()); | 533 ui::CLIPBOARD_TYPE_COPY_PASTE).WriteText(GetSelectedText()); |
534 return true; | 534 return true; |
535 } | 535 } |
536 return false; | 536 return false; |
537 } | 537 } |
538 | 538 |
539 bool TextfieldViewsModel::Paste() { | 539 bool TextfieldViewsModel::Paste() { |
540 string16 result; | 540 base::string16 result; |
541 ui::Clipboard::GetForCurrentThread()->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, | 541 ui::Clipboard::GetForCurrentThread()->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, |
542 &result); | 542 &result); |
543 if (!result.empty()) { | 543 if (!result.empty()) { |
544 InsertTextInternal(result, false); | 544 InsertTextInternal(result, false); |
545 return true; | 545 return true; |
546 } | 546 } |
547 return false; | 547 return false; |
548 } | 548 } |
549 | 549 |
550 bool TextfieldViewsModel::HasSelection() const { | 550 bool TextfieldViewsModel::HasSelection() const { |
551 return !render_text_->selection().is_empty(); | 551 return !render_text_->selection().is_empty(); |
552 } | 552 } |
553 | 553 |
554 void TextfieldViewsModel::DeleteSelection() { | 554 void TextfieldViewsModel::DeleteSelection() { |
555 DCHECK(!HasCompositionText()); | 555 DCHECK(!HasCompositionText()); |
556 DCHECK(HasSelection()); | 556 DCHECK(HasSelection()); |
557 ExecuteAndRecordDelete(render_text_->selection(), false); | 557 ExecuteAndRecordDelete(render_text_->selection(), false); |
558 } | 558 } |
559 | 559 |
560 void TextfieldViewsModel::DeleteSelectionAndInsertTextAt( | 560 void TextfieldViewsModel::DeleteSelectionAndInsertTextAt( |
561 const string16& text, size_t position) { | 561 const base::string16& text, size_t position) { |
562 if (HasCompositionText()) | 562 if (HasCompositionText()) |
563 CancelCompositionText(); | 563 CancelCompositionText(); |
564 ExecuteAndRecordReplace(DO_NOT_MERGE, | 564 ExecuteAndRecordReplace(DO_NOT_MERGE, |
565 GetCursorPosition(), | 565 GetCursorPosition(), |
566 position + text.length(), | 566 position + text.length(), |
567 text, | 567 text, |
568 position); | 568 position); |
569 } | 569 } |
570 | 570 |
571 string16 TextfieldViewsModel::GetTextFromRange(const gfx::Range& range) const { | 571 base::string16 TextfieldViewsModel::GetTextFromRange( |
| 572 const gfx::Range& range) const { |
572 if (range.IsValid() && range.GetMin() < GetText().length()) | 573 if (range.IsValid() && range.GetMin() < GetText().length()) |
573 return GetText().substr(range.GetMin(), range.length()); | 574 return GetText().substr(range.GetMin(), range.length()); |
574 return string16(); | 575 return base::string16(); |
575 } | 576 } |
576 | 577 |
577 void TextfieldViewsModel::GetTextRange(gfx::Range* range) const { | 578 void TextfieldViewsModel::GetTextRange(gfx::Range* range) const { |
578 *range = gfx::Range(0, GetText().length()); | 579 *range = gfx::Range(0, GetText().length()); |
579 } | 580 } |
580 | 581 |
581 void TextfieldViewsModel::SetCompositionText( | 582 void TextfieldViewsModel::SetCompositionText( |
582 const ui::CompositionText& composition) { | 583 const ui::CompositionText& composition) { |
583 if (HasCompositionText()) | 584 if (HasCompositionText()) |
584 CancelCompositionText(); | 585 CancelCompositionText(); |
585 else if (HasSelection()) | 586 else if (HasSelection()) |
586 DeleteSelection(); | 587 DeleteSelection(); |
587 | 588 |
588 if (composition.text.empty()) | 589 if (composition.text.empty()) |
589 return; | 590 return; |
590 | 591 |
591 size_t cursor = GetCursorPosition(); | 592 size_t cursor = GetCursorPosition(); |
592 string16 new_text = GetText(); | 593 base::string16 new_text = GetText(); |
593 render_text_->SetText(new_text.insert(cursor, composition.text)); | 594 render_text_->SetText(new_text.insert(cursor, composition.text)); |
594 gfx::Range range(cursor, cursor + composition.text.length()); | 595 gfx::Range range(cursor, cursor + composition.text.length()); |
595 render_text_->SetCompositionRange(range); | 596 render_text_->SetCompositionRange(range); |
596 gfx::Range emphasized_range = GetFirstEmphasizedRange(composition); | 597 gfx::Range emphasized_range = GetFirstEmphasizedRange(composition); |
597 if (emphasized_range.IsValid()) { | 598 if (emphasized_range.IsValid()) { |
598 // This is a workaround due to the lack of support in RenderText to draw | 599 // This is a workaround due to the lack of support in RenderText to draw |
599 // a thick underline. In a composition returned from an IME, the segment | 600 // a thick underline. In a composition returned from an IME, the segment |
600 // emphasized by a thick underline usually represents the target clause. | 601 // emphasized by a thick underline usually represents the target clause. |
601 // Because the target clause is more important than the actual selection | 602 // Because the target clause is more important than the actual selection |
602 // range (or caret position) in the composition here we use a selection-like | 603 // range (or caret position) in the composition here we use a selection-like |
603 // marker instead to show this range. | 604 // marker instead to show this range. |
604 // TODO(yukawa, msw): Support thick underline in RenderText and remove | 605 // TODO(yukawa, msw): Support thick underline in RenderText and remove |
605 // this workaround. | 606 // this workaround. |
606 render_text_->SelectRange(gfx::Range( | 607 render_text_->SelectRange(gfx::Range( |
607 cursor + emphasized_range.GetMin(), | 608 cursor + emphasized_range.GetMin(), |
608 cursor + emphasized_range.GetMax())); | 609 cursor + emphasized_range.GetMax())); |
609 } else if (!composition.selection.is_empty()) { | 610 } else if (!composition.selection.is_empty()) { |
610 render_text_->SelectRange(gfx::Range( | 611 render_text_->SelectRange(gfx::Range( |
611 cursor + composition.selection.GetMin(), | 612 cursor + composition.selection.GetMin(), |
612 cursor + composition.selection.GetMax())); | 613 cursor + composition.selection.GetMax())); |
613 } else { | 614 } else { |
614 render_text_->SetCursorPosition(cursor + composition.selection.end()); | 615 render_text_->SetCursorPosition(cursor + composition.selection.end()); |
615 } | 616 } |
616 } | 617 } |
617 | 618 |
618 void TextfieldViewsModel::ConfirmCompositionText() { | 619 void TextfieldViewsModel::ConfirmCompositionText() { |
619 DCHECK(HasCompositionText()); | 620 DCHECK(HasCompositionText()); |
620 gfx::Range range = render_text_->GetCompositionRange(); | 621 gfx::Range range = render_text_->GetCompositionRange(); |
621 string16 text = GetText().substr(range.start(), range.length()); | 622 base::string16 text = GetText().substr(range.start(), range.length()); |
622 // TODO(oshima): current behavior on ChromeOS is a bit weird and not | 623 // TODO(oshima): current behavior on ChromeOS is a bit weird and not |
623 // sure exactly how this should work. Find out and fix if necessary. | 624 // sure exactly how this should work. Find out and fix if necessary. |
624 AddOrMergeEditHistory(new InsertEdit(false, text, range.start())); | 625 AddOrMergeEditHistory(new InsertEdit(false, text, range.start())); |
625 render_text_->SetCursorPosition(range.end()); | 626 render_text_->SetCursorPosition(range.end()); |
626 ClearComposition(); | 627 ClearComposition(); |
627 if (delegate_) | 628 if (delegate_) |
628 delegate_->OnCompositionTextConfirmedOrCleared(); | 629 delegate_->OnCompositionTextConfirmedOrCleared(); |
629 } | 630 } |
630 | 631 |
631 void TextfieldViewsModel::CancelCompositionText() { | 632 void TextfieldViewsModel::CancelCompositionText() { |
632 DCHECK(HasCompositionText()); | 633 DCHECK(HasCompositionText()); |
633 gfx::Range range = render_text_->GetCompositionRange(); | 634 gfx::Range range = render_text_->GetCompositionRange(); |
634 ClearComposition(); | 635 ClearComposition(); |
635 string16 new_text = GetText(); | 636 base::string16 new_text = GetText(); |
636 render_text_->SetText(new_text.erase(range.start(), range.length())); | 637 render_text_->SetText(new_text.erase(range.start(), range.length())); |
637 render_text_->SetCursorPosition(range.start()); | 638 render_text_->SetCursorPosition(range.start()); |
638 if (delegate_) | 639 if (delegate_) |
639 delegate_->OnCompositionTextConfirmedOrCleared(); | 640 delegate_->OnCompositionTextConfirmedOrCleared(); |
640 } | 641 } |
641 | 642 |
642 void TextfieldViewsModel::ClearComposition() { | 643 void TextfieldViewsModel::ClearComposition() { |
643 render_text_->SetCompositionRange(gfx::Range::InvalidRange()); | 644 render_text_->SetCompositionRange(gfx::Range::InvalidRange()); |
644 } | 645 } |
645 | 646 |
646 void TextfieldViewsModel::GetCompositionTextRange(gfx::Range* range) const { | 647 void TextfieldViewsModel::GetCompositionTextRange(gfx::Range* range) const { |
647 *range = gfx::Range(render_text_->GetCompositionRange()); | 648 *range = gfx::Range(render_text_->GetCompositionRange()); |
648 } | 649 } |
649 | 650 |
650 bool TextfieldViewsModel::HasCompositionText() const { | 651 bool TextfieldViewsModel::HasCompositionText() const { |
651 return !render_text_->GetCompositionRange().is_empty(); | 652 return !render_text_->GetCompositionRange().is_empty(); |
652 } | 653 } |
653 | 654 |
654 ///////////////////////////////////////////////////////////////// | 655 ///////////////////////////////////////////////////////////////// |
655 // TextfieldViewsModel: private | 656 // TextfieldViewsModel: private |
656 | 657 |
657 void TextfieldViewsModel::InsertTextInternal(const string16& text, | 658 void TextfieldViewsModel::InsertTextInternal(const base::string16& text, |
658 bool mergeable) { | 659 bool mergeable) { |
659 if (HasCompositionText()) { | 660 if (HasCompositionText()) { |
660 CancelCompositionText(); | 661 CancelCompositionText(); |
661 ExecuteAndRecordInsert(text, mergeable); | 662 ExecuteAndRecordInsert(text, mergeable); |
662 } else if (HasSelection()) { | 663 } else if (HasSelection()) { |
663 ExecuteAndRecordReplaceSelection(mergeable ? MERGEABLE : DO_NOT_MERGE, | 664 ExecuteAndRecordReplaceSelection(mergeable ? MERGEABLE : DO_NOT_MERGE, |
664 text); | 665 text); |
665 } else { | 666 } else { |
666 ExecuteAndRecordInsert(text, mergeable); | 667 ExecuteAndRecordInsert(text, mergeable); |
667 } | 668 } |
668 } | 669 } |
669 | 670 |
670 void TextfieldViewsModel::ReplaceTextInternal(const string16& text, | 671 void TextfieldViewsModel::ReplaceTextInternal(const base::string16& text, |
671 bool mergeable) { | 672 bool mergeable) { |
672 if (HasCompositionText()) { | 673 if (HasCompositionText()) { |
673 CancelCompositionText(); | 674 CancelCompositionText(); |
674 } else if (!HasSelection()) { | 675 } else if (!HasSelection()) { |
675 size_t cursor = GetCursorPosition(); | 676 size_t cursor = GetCursorPosition(); |
676 const gfx::SelectionModel& model = render_text_->selection_model(); | 677 const gfx::SelectionModel& model = render_text_->selection_model(); |
677 // When there is no selection, the default is to replace the next grapheme | 678 // When there is no selection, the default is to replace the next grapheme |
678 // with |text|. So, need to find the index of next grapheme first. | 679 // with |text|. So, need to find the index of next grapheme first. |
679 size_t next = | 680 size_t next = |
680 render_text_->IndexOfAdjacentGrapheme(cursor, gfx::CURSOR_FORWARD); | 681 render_text_->IndexOfAdjacentGrapheme(cursor, gfx::CURSOR_FORWARD); |
(...skipping 20 matching lines...) Expand all Loading... |
701 } | 702 } |
702 EditHistory::iterator delete_start = current_edit_; | 703 EditHistory::iterator delete_start = current_edit_; |
703 delete_start++; | 704 delete_start++; |
704 STLDeleteContainerPointers(delete_start, edit_history_.end()); | 705 STLDeleteContainerPointers(delete_start, edit_history_.end()); |
705 edit_history_.erase(delete_start, edit_history_.end()); | 706 edit_history_.erase(delete_start, edit_history_.end()); |
706 } | 707 } |
707 | 708 |
708 void TextfieldViewsModel::ExecuteAndRecordDelete(gfx::Range range, | 709 void TextfieldViewsModel::ExecuteAndRecordDelete(gfx::Range range, |
709 bool mergeable) { | 710 bool mergeable) { |
710 size_t old_text_start = range.GetMin(); | 711 size_t old_text_start = range.GetMin(); |
711 const string16 text = GetText().substr(old_text_start, range.length()); | 712 const base::string16 text = GetText().substr(old_text_start, range.length()); |
712 bool backward = range.is_reversed(); | 713 bool backward = range.is_reversed(); |
713 Edit* edit = new DeleteEdit(mergeable, text, old_text_start, backward); | 714 Edit* edit = new DeleteEdit(mergeable, text, old_text_start, backward); |
714 bool delete_edit = AddOrMergeEditHistory(edit); | 715 bool delete_edit = AddOrMergeEditHistory(edit); |
715 edit->Redo(this); | 716 edit->Redo(this); |
716 if (delete_edit) | 717 if (delete_edit) |
717 delete edit; | 718 delete edit; |
718 } | 719 } |
719 | 720 |
720 void TextfieldViewsModel::ExecuteAndRecordReplaceSelection( | 721 void TextfieldViewsModel::ExecuteAndRecordReplaceSelection( |
721 MergeType merge_type, const string16& new_text) { | 722 MergeType merge_type, const base::string16& new_text) { |
722 size_t new_text_start = render_text_->selection().GetMin(); | 723 size_t new_text_start = render_text_->selection().GetMin(); |
723 size_t new_cursor_pos = new_text_start + new_text.length(); | 724 size_t new_cursor_pos = new_text_start + new_text.length(); |
724 ExecuteAndRecordReplace(merge_type, | 725 ExecuteAndRecordReplace(merge_type, |
725 GetCursorPosition(), | 726 GetCursorPosition(), |
726 new_cursor_pos, | 727 new_cursor_pos, |
727 new_text, | 728 new_text, |
728 new_text_start); | 729 new_text_start); |
729 } | 730 } |
730 | 731 |
731 void TextfieldViewsModel::ExecuteAndRecordReplace(MergeType merge_type, | 732 void TextfieldViewsModel::ExecuteAndRecordReplace( |
732 size_t old_cursor_pos, | 733 MergeType merge_type, |
733 size_t new_cursor_pos, | 734 size_t old_cursor_pos, |
734 const string16& new_text, | 735 size_t new_cursor_pos, |
735 size_t new_text_start) { | 736 const base::string16& new_text, |
| 737 size_t new_text_start) { |
736 size_t old_text_start = render_text_->selection().GetMin(); | 738 size_t old_text_start = render_text_->selection().GetMin(); |
737 bool backward = render_text_->selection().is_reversed(); | 739 bool backward = render_text_->selection().is_reversed(); |
738 Edit* edit = new ReplaceEdit(merge_type, | 740 Edit* edit = new ReplaceEdit(merge_type, |
739 GetSelectedText(), | 741 GetSelectedText(), |
740 old_cursor_pos, | 742 old_cursor_pos, |
741 old_text_start, | 743 old_text_start, |
742 backward, | 744 backward, |
743 new_cursor_pos, | 745 new_cursor_pos, |
744 new_text, | 746 new_text, |
745 new_text_start); | 747 new_text_start); |
746 bool delete_edit = AddOrMergeEditHistory(edit); | 748 bool delete_edit = AddOrMergeEditHistory(edit); |
747 edit->Redo(this); | 749 edit->Redo(this); |
748 if (delete_edit) | 750 if (delete_edit) |
749 delete edit; | 751 delete edit; |
750 } | 752 } |
751 | 753 |
752 void TextfieldViewsModel::ExecuteAndRecordInsert(const string16& text, | 754 void TextfieldViewsModel::ExecuteAndRecordInsert(const base::string16& text, |
753 bool mergeable) { | 755 bool mergeable) { |
754 Edit* edit = new InsertEdit(mergeable, text, GetCursorPosition()); | 756 Edit* edit = new InsertEdit(mergeable, text, GetCursorPosition()); |
755 bool delete_edit = AddOrMergeEditHistory(edit); | 757 bool delete_edit = AddOrMergeEditHistory(edit); |
756 edit->Redo(this); | 758 edit->Redo(this); |
757 if (delete_edit) | 759 if (delete_edit) |
758 delete edit; | 760 delete edit; |
759 } | 761 } |
760 | 762 |
761 bool TextfieldViewsModel::AddOrMergeEditHistory(Edit* edit) { | 763 bool TextfieldViewsModel::AddOrMergeEditHistory(Edit* edit) { |
762 ClearRedoHistory(); | 764 ClearRedoHistory(); |
(...skipping 11 matching lines...) Expand all Loading... |
774 DCHECK_EQ(1u, edit_history_.size()); | 776 DCHECK_EQ(1u, edit_history_.size()); |
775 current_edit_ = edit_history_.begin(); | 777 current_edit_ = edit_history_.begin(); |
776 } else { | 778 } else { |
777 current_edit_++; | 779 current_edit_++; |
778 } | 780 } |
779 return false; | 781 return false; |
780 } | 782 } |
781 | 783 |
782 void TextfieldViewsModel::ModifyText(size_t delete_from, | 784 void TextfieldViewsModel::ModifyText(size_t delete_from, |
783 size_t delete_to, | 785 size_t delete_to, |
784 const string16& new_text, | 786 const base::string16& new_text, |
785 size_t new_text_insert_at, | 787 size_t new_text_insert_at, |
786 size_t new_cursor_pos) { | 788 size_t new_cursor_pos) { |
787 DCHECK_LE(delete_from, delete_to); | 789 DCHECK_LE(delete_from, delete_to); |
788 string16 text = GetText(); | 790 base::string16 text = GetText(); |
789 ClearComposition(); | 791 ClearComposition(); |
790 if (delete_from != delete_to) | 792 if (delete_from != delete_to) |
791 render_text_->SetText(text.erase(delete_from, delete_to - delete_from)); | 793 render_text_->SetText(text.erase(delete_from, delete_to - delete_from)); |
792 if (!new_text.empty()) | 794 if (!new_text.empty()) |
793 render_text_->SetText(text.insert(new_text_insert_at, new_text)); | 795 render_text_->SetText(text.insert(new_text_insert_at, new_text)); |
794 render_text_->SetCursorPosition(new_cursor_pos); | 796 render_text_->SetCursorPosition(new_cursor_pos); |
795 // TODO(oshima): mac selects the text that is just undone (but gtk doesn't). | 797 // TODO(oshima): mac selects the text that is just undone (but gtk doesn't). |
796 // This looks fine feature and we may want to do the same. | 798 // This looks fine feature and we may want to do the same. |
797 } | 799 } |
798 | 800 |
799 } // namespace views | 801 } // namespace views |
OLD | NEW |