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 327 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
338 return true; | 338 return true; |
339 } | 339 } |
340 if (HasSelection()) { | 340 if (HasSelection()) { |
341 DeleteSelection(); | 341 DeleteSelection(); |
342 return true; | 342 return true; |
343 } | 343 } |
344 if (GetText().length() > GetCursorPosition()) { | 344 if (GetText().length() > GetCursorPosition()) { |
345 size_t cursor_position = GetCursorPosition(); | 345 size_t cursor_position = GetCursorPosition(); |
346 size_t next_grapheme_index = render_text_->IndexOfAdjacentGrapheme( | 346 size_t next_grapheme_index = render_text_->IndexOfAdjacentGrapheme( |
347 cursor_position, gfx::CURSOR_FORWARD); | 347 cursor_position, gfx::CURSOR_FORWARD); |
348 ExecuteAndRecordDelete(cursor_position, next_grapheme_index, true); | 348 ExecuteAndRecordDelete(ui::Range(cursor_position, next_grapheme_index), |
| 349 true); |
349 return true; | 350 return true; |
350 } | 351 } |
351 return false; | 352 return false; |
352 } | 353 } |
353 | 354 |
354 bool TextfieldViewsModel::Backspace() { | 355 bool TextfieldViewsModel::Backspace() { |
355 if (HasCompositionText()) { | 356 if (HasCompositionText()) { |
356 // No undo/redo for composition text. | 357 // No undo/redo for composition text. |
357 CancelCompositionText(); | 358 CancelCompositionText(); |
358 return true; | 359 return true; |
359 } | 360 } |
360 if (HasSelection()) { | 361 if (HasSelection()) { |
361 DeleteSelection(); | 362 DeleteSelection(); |
362 return true; | 363 return true; |
363 } | 364 } |
364 if (GetCursorPosition() > 0) { | 365 if (GetCursorPosition() > 0) { |
365 size_t cursor_position = GetCursorPosition(); | 366 size_t cursor_position = GetCursorPosition(); |
366 ExecuteAndRecordDelete(cursor_position, cursor_position - 1, true); | 367 ExecuteAndRecordDelete(ui::Range(cursor_position, cursor_position - 1), |
| 368 true); |
367 return true; | 369 return true; |
368 } | 370 } |
369 return false; | 371 return false; |
370 } | 372 } |
371 | 373 |
372 size_t TextfieldViewsModel::GetCursorPosition() const { | 374 size_t TextfieldViewsModel::GetCursorPosition() const { |
373 return render_text_->GetCursorPosition(); | 375 return render_text_->cursor_position(); |
374 } | 376 } |
375 | 377 |
376 void TextfieldViewsModel::MoveCursor(gfx::BreakType break_type, | 378 void TextfieldViewsModel::MoveCursor(gfx::BreakType break_type, |
377 gfx::VisualCursorDirection direction, | 379 gfx::VisualCursorDirection direction, |
378 bool select) { | 380 bool select) { |
379 if (HasCompositionText()) | 381 if (HasCompositionText()) |
380 ConfirmCompositionText(); | 382 ConfirmCompositionText(); |
381 render_text_->MoveCursor(break_type, direction, select); | 383 render_text_->MoveCursor(break_type, direction, select); |
382 } | 384 } |
383 | 385 |
384 bool TextfieldViewsModel::MoveCursorTo(const gfx::SelectionModel& selection) { | 386 bool TextfieldViewsModel::MoveCursorTo(const gfx::SelectionModel& model) { |
385 if (HasCompositionText()) { | 387 if (HasCompositionText()) { |
386 ConfirmCompositionText(); | 388 ConfirmCompositionText(); |
387 // ConfirmCompositionText() updates cursor position. Need to reflect it in | 389 // ConfirmCompositionText() updates cursor position. Need to reflect it in |
388 // the SelectionModel parameter of MoveCursorTo(). | 390 // the SelectionModel parameter of MoveCursorTo(). |
389 if (render_text_->GetSelectionStart() != selection.selection_end()) | 391 ui::Range range(render_text_->selection().start(), model.caret_pos()); |
390 return render_text_->SelectRange(ui::Range( | 392 if (!range.is_empty()) |
391 render_text_->GetSelectionStart(), selection.selection_end())); | 393 return render_text_->SelectRange(range); |
392 gfx::SelectionModel sel(selection.selection_end(), | 394 return render_text_->MoveCursorTo( |
393 selection.caret_pos(), | 395 gfx::SelectionModel(model.caret_pos(), model.caret_affinity())); |
394 selection.caret_placement()); | |
395 return render_text_->MoveCursorTo(sel); | |
396 } | 396 } |
397 return render_text_->MoveCursorTo(selection); | 397 return render_text_->MoveCursorTo(model); |
398 } | 398 } |
399 | 399 |
400 bool TextfieldViewsModel::MoveCursorTo(const gfx::Point& point, bool select) { | 400 bool TextfieldViewsModel::MoveCursorTo(const gfx::Point& point, bool select) { |
401 if (HasCompositionText()) | 401 if (HasCompositionText()) |
402 ConfirmCompositionText(); | 402 ConfirmCompositionText(); |
403 return render_text_->MoveCursorTo(point, select); | 403 return render_text_->MoveCursorTo(point, select); |
404 } | 404 } |
405 | 405 |
406 string16 TextfieldViewsModel::GetSelectedText() const { | 406 string16 TextfieldViewsModel::GetSelectedText() const { |
407 return GetText().substr(render_text_->MinOfSelection(), | 407 return GetText().substr(render_text_->selection().GetMin(), |
408 (render_text_->MaxOfSelection() - render_text_->MinOfSelection())); | 408 render_text_->selection().length()); |
409 } | |
410 | |
411 void TextfieldViewsModel::GetSelectedRange(ui::Range* range) const { | |
412 range->set_start(render_text_->GetSelectionStart()); | |
413 range->set_end(render_text_->GetCursorPosition()); | |
414 } | 409 } |
415 | 410 |
416 void TextfieldViewsModel::SelectRange(const ui::Range& range) { | 411 void TextfieldViewsModel::SelectRange(const ui::Range& range) { |
417 if (HasCompositionText()) | 412 if (HasCompositionText()) |
418 ConfirmCompositionText(); | 413 ConfirmCompositionText(); |
419 render_text_->SelectRange(range); | 414 render_text_->SelectRange(range); |
420 } | 415 } |
421 | 416 |
422 void TextfieldViewsModel::GetSelectionModel(gfx::SelectionModel* sel) const { | 417 void TextfieldViewsModel::GetSelectionModel(gfx::SelectionModel* sel) const { |
423 *sel = render_text_->selection_model(); | 418 *sel = render_text_->selection_model(); |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
499 | 494 |
500 bool TextfieldViewsModel::Cut() { | 495 bool TextfieldViewsModel::Cut() { |
501 if (!HasCompositionText() && HasSelection()) { | 496 if (!HasCompositionText() && HasSelection()) { |
502 ui::ScopedClipboardWriter(views::ViewsDelegate::views_delegate | 497 ui::ScopedClipboardWriter(views::ViewsDelegate::views_delegate |
503 ->GetClipboard()).WriteText(GetSelectedText()); | 498 ->GetClipboard()).WriteText(GetSelectedText()); |
504 // A trick to let undo/redo handle cursor correctly. | 499 // A trick to let undo/redo handle cursor correctly. |
505 // Undoing CUT moves the cursor to the end of the change rather | 500 // Undoing CUT moves the cursor to the end of the change rather |
506 // than beginning, unlike Delete/Backspace. | 501 // than beginning, unlike Delete/Backspace. |
507 // TODO(oshima): Change Delete/Backspace to use DeleteSelection, | 502 // TODO(oshima): Change Delete/Backspace to use DeleteSelection, |
508 // update DeleteEdit and remove this trick. | 503 // update DeleteEdit and remove this trick. |
509 render_text_->SelectRange(ui::Range(render_text_->GetCursorPosition(), | 504 const ui::Range& selection = render_text_->selection(); |
510 render_text_->GetSelectionStart())); | 505 render_text_->SelectRange(ui::Range(selection.end(), selection.start())); |
511 DeleteSelection(); | 506 DeleteSelection(); |
512 return true; | 507 return true; |
513 } | 508 } |
514 return false; | 509 return false; |
515 } | 510 } |
516 | 511 |
517 bool TextfieldViewsModel::Copy() { | 512 bool TextfieldViewsModel::Copy() { |
518 if (!HasCompositionText() && HasSelection()) { | 513 if (!HasCompositionText() && HasSelection()) { |
519 ui::ScopedClipboardWriter(views::ViewsDelegate::views_delegate | 514 ui::ScopedClipboardWriter(views::ViewsDelegate::views_delegate |
520 ->GetClipboard()).WriteText(GetSelectedText()); | 515 ->GetClipboard()).WriteText(GetSelectedText()); |
521 return true; | 516 return true; |
522 } | 517 } |
523 return false; | 518 return false; |
524 } | 519 } |
525 | 520 |
526 bool TextfieldViewsModel::Paste() { | 521 bool TextfieldViewsModel::Paste() { |
527 string16 result; | 522 string16 result; |
528 views::ViewsDelegate::views_delegate->GetClipboard() | 523 views::ViewsDelegate::views_delegate->GetClipboard() |
529 ->ReadText(ui::Clipboard::BUFFER_STANDARD, &result); | 524 ->ReadText(ui::Clipboard::BUFFER_STANDARD, &result); |
530 if (!result.empty()) { | 525 if (!result.empty()) { |
531 InsertTextInternal(result, false); | 526 InsertTextInternal(result, false); |
532 return true; | 527 return true; |
533 } | 528 } |
534 return false; | 529 return false; |
535 } | 530 } |
536 | 531 |
537 bool TextfieldViewsModel::HasSelection() const { | 532 bool TextfieldViewsModel::HasSelection() const { |
538 return !render_text_->EmptySelection(); | 533 return !render_text_->selection().is_empty(); |
539 } | 534 } |
540 | 535 |
541 void TextfieldViewsModel::DeleteSelection() { | 536 void TextfieldViewsModel::DeleteSelection() { |
542 DCHECK(!HasCompositionText()); | 537 DCHECK(!HasCompositionText()); |
543 DCHECK(HasSelection()); | 538 DCHECK(HasSelection()); |
544 ExecuteAndRecordDelete(render_text_->GetSelectionStart(), | 539 ExecuteAndRecordDelete(render_text_->selection(), false); |
545 render_text_->GetCursorPosition(), false); | |
546 } | 540 } |
547 | 541 |
548 void TextfieldViewsModel::DeleteSelectionAndInsertTextAt( | 542 void TextfieldViewsModel::DeleteSelectionAndInsertTextAt( |
549 const string16& text, size_t position) { | 543 const string16& text, size_t position) { |
550 if (HasCompositionText()) | 544 if (HasCompositionText()) |
551 CancelCompositionText(); | 545 CancelCompositionText(); |
552 ExecuteAndRecordReplace(DO_NOT_MERGE, | 546 ExecuteAndRecordReplace(DO_NOT_MERGE, |
553 GetCursorPosition(), | 547 GetCursorPosition(), |
554 position + text.length(), | 548 position + text.length(), |
555 text, | 549 text, |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
650 bool mergeable) { | 644 bool mergeable) { |
651 if (HasCompositionText()) { | 645 if (HasCompositionText()) { |
652 CancelCompositionText(); | 646 CancelCompositionText(); |
653 } else if (!HasSelection()) { | 647 } else if (!HasSelection()) { |
654 size_t cursor = GetCursorPosition(); | 648 size_t cursor = GetCursorPosition(); |
655 const gfx::SelectionModel& model = render_text_->selection_model(); | 649 const gfx::SelectionModel& model = render_text_->selection_model(); |
656 // When there is no selection, the default is to replace the next grapheme | 650 // When there is no selection, the default is to replace the next grapheme |
657 // with |text|. So, need to find the index of next grapheme first. | 651 // with |text|. So, need to find the index of next grapheme first. |
658 size_t next = | 652 size_t next = |
659 render_text_->IndexOfAdjacentGrapheme(cursor, gfx::CURSOR_FORWARD); | 653 render_text_->IndexOfAdjacentGrapheme(cursor, gfx::CURSOR_FORWARD); |
660 if (next == model.selection_end()) | 654 if (next == model.caret_pos()) |
661 render_text_->MoveCursorTo(model); | 655 render_text_->MoveCursorTo(model); |
662 else | 656 else |
663 render_text_->SelectRange(ui::Range(next, model.selection_end())); | 657 render_text_->SelectRange(ui::Range(next, model.caret_pos())); |
664 } | 658 } |
665 // Edit history is recorded in InsertText. | 659 // Edit history is recorded in InsertText. |
666 InsertTextInternal(text, mergeable); | 660 InsertTextInternal(text, mergeable); |
667 } | 661 } |
668 | 662 |
669 void TextfieldViewsModel::ClearEditHistory() { | 663 void TextfieldViewsModel::ClearEditHistory() { |
670 STLDeleteContainerPointers(edit_history_.begin(), | 664 STLDeleteContainerPointers(edit_history_.begin(), |
671 edit_history_.end()); | 665 edit_history_.end()); |
672 edit_history_.clear(); | 666 edit_history_.clear(); |
673 current_edit_ = edit_history_.end(); | 667 current_edit_ = edit_history_.end(); |
674 } | 668 } |
675 | 669 |
676 void TextfieldViewsModel::ClearRedoHistory() { | 670 void TextfieldViewsModel::ClearRedoHistory() { |
677 if (edit_history_.begin() == edit_history_.end()) | 671 if (edit_history_.begin() == edit_history_.end()) |
678 return; | 672 return; |
679 if (current_edit_ == edit_history_.end()) { | 673 if (current_edit_ == edit_history_.end()) { |
680 ClearEditHistory(); | 674 ClearEditHistory(); |
681 return; | 675 return; |
682 } | 676 } |
683 EditHistory::iterator delete_start = current_edit_; | 677 EditHistory::iterator delete_start = current_edit_; |
684 delete_start++; | 678 delete_start++; |
685 STLDeleteContainerPointers(delete_start, edit_history_.end()); | 679 STLDeleteContainerPointers(delete_start, edit_history_.end()); |
686 edit_history_.erase(delete_start, edit_history_.end()); | 680 edit_history_.erase(delete_start, edit_history_.end()); |
687 } | 681 } |
688 | 682 |
689 void TextfieldViewsModel::ExecuteAndRecordDelete(size_t from, | 683 void TextfieldViewsModel::ExecuteAndRecordDelete(ui::Range range, |
690 size_t to, | |
691 bool mergeable) { | 684 bool mergeable) { |
692 size_t old_text_start = std::min(from, to); | 685 size_t old_text_start = range.GetMin(); |
693 const string16 text = GetText().substr(old_text_start, | 686 const string16 text = GetText().substr(old_text_start, range.length()); |
694 std::abs(static_cast<long>(from - to))); | 687 bool backward = range.is_reversed(); |
695 bool backward = from > to; | |
696 Edit* edit = new DeleteEdit(mergeable, text, old_text_start, backward); | 688 Edit* edit = new DeleteEdit(mergeable, text, old_text_start, backward); |
697 bool delete_edit = AddOrMergeEditHistory(edit); | 689 bool delete_edit = AddOrMergeEditHistory(edit); |
698 edit->Redo(this); | 690 edit->Redo(this); |
699 if (delete_edit) | 691 if (delete_edit) |
700 delete edit; | 692 delete edit; |
701 } | 693 } |
702 | 694 |
703 void TextfieldViewsModel::ExecuteAndRecordReplaceSelection( | 695 void TextfieldViewsModel::ExecuteAndRecordReplaceSelection( |
704 MergeType merge_type, const string16& new_text) { | 696 MergeType merge_type, const string16& new_text) { |
705 size_t new_text_start = render_text_->MinOfSelection(); | 697 size_t new_text_start = render_text_->selection().GetMin(); |
706 size_t new_cursor_pos = new_text_start + new_text.length(); | 698 size_t new_cursor_pos = new_text_start + new_text.length(); |
707 ExecuteAndRecordReplace(merge_type, | 699 ExecuteAndRecordReplace(merge_type, |
708 GetCursorPosition(), | 700 GetCursorPosition(), |
709 new_cursor_pos, | 701 new_cursor_pos, |
710 new_text, | 702 new_text, |
711 new_text_start); | 703 new_text_start); |
712 } | 704 } |
713 | 705 |
714 void TextfieldViewsModel::ExecuteAndRecordReplace(MergeType merge_type, | 706 void TextfieldViewsModel::ExecuteAndRecordReplace(MergeType merge_type, |
715 size_t old_cursor_pos, | 707 size_t old_cursor_pos, |
716 size_t new_cursor_pos, | 708 size_t new_cursor_pos, |
717 const string16& new_text, | 709 const string16& new_text, |
718 size_t new_text_start) { | 710 size_t new_text_start) { |
719 size_t old_text_start = render_text_->MinOfSelection(); | 711 size_t old_text_start = render_text_->selection().GetMin(); |
720 bool backward = | 712 bool backward = render_text_->selection().is_reversed(); |
721 render_text_->GetSelectionStart() > render_text_->GetCursorPosition(); | |
722 Edit* edit = new ReplaceEdit(merge_type, | 713 Edit* edit = new ReplaceEdit(merge_type, |
723 GetSelectedText(), | 714 GetSelectedText(), |
724 old_cursor_pos, | 715 old_cursor_pos, |
725 old_text_start, | 716 old_text_start, |
726 backward, | 717 backward, |
727 new_cursor_pos, | 718 new_cursor_pos, |
728 new_text, | 719 new_text, |
729 new_text_start); | 720 new_text_start); |
730 bool delete_edit = AddOrMergeEditHistory(edit); | 721 bool delete_edit = AddOrMergeEditHistory(edit); |
731 edit->Redo(this); | 722 edit->Redo(this); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
774 if (delete_from != delete_to) | 765 if (delete_from != delete_to) |
775 render_text_->SetText(text.erase(delete_from, delete_to - delete_from)); | 766 render_text_->SetText(text.erase(delete_from, delete_to - delete_from)); |
776 if (!new_text.empty()) | 767 if (!new_text.empty()) |
777 render_text_->SetText(text.insert(new_text_insert_at, new_text)); | 768 render_text_->SetText(text.insert(new_text_insert_at, new_text)); |
778 render_text_->SetCursorPosition(new_cursor_pos); | 769 render_text_->SetCursorPosition(new_cursor_pos); |
779 // TODO(oshima): mac selects the text that is just undone (but gtk doesn't). | 770 // TODO(oshima): mac selects the text that is just undone (but gtk doesn't). |
780 // This looks fine feature and we may want to do the same. | 771 // This looks fine feature and we may want to do the same. |
781 } | 772 } |
782 | 773 |
783 } // namespace views | 774 } // namespace views |
OLD | NEW |