OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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_model.h" | 5 #include "ui/views/controls/textfield/textfield_model.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/macros.h" | 10 #include "base/macros.h" |
11 #include "base/memory/ptr_util.h" | |
11 #include "base/message_loop/message_loop.h" | 12 #include "base/message_loop/message_loop.h" |
12 #include "base/stl_util.h" | 13 #include "base/stl_util.h" |
13 #include "base/strings/string_util.h" | 14 #include "base/strings/string_util.h" |
14 #include "base/strings/utf_string_conversions.h" | 15 #include "base/strings/utf_string_conversions.h" |
15 #include "ui/base/clipboard/clipboard.h" | 16 #include "ui/base/clipboard/clipboard.h" |
16 #include "ui/base/clipboard/scoped_clipboard_writer.h" | 17 #include "ui/base/clipboard/scoped_clipboard_writer.h" |
17 #include "ui/gfx/range/range.h" | 18 #include "ui/gfx/range/range.h" |
18 #include "ui/gfx/utf16_indexing.h" | 19 #include "ui/gfx/utf16_indexing.h" |
19 | 20 |
20 namespace views { | 21 namespace views { |
(...skipping 644 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
665 render_text_->SetCursorPosition(cursor + composition.selection.end()); | 666 render_text_->SetCursorPosition(cursor + composition.selection.end()); |
666 } | 667 } |
667 } | 668 } |
668 | 669 |
669 void TextfieldModel::ConfirmCompositionText() { | 670 void TextfieldModel::ConfirmCompositionText() { |
670 DCHECK(HasCompositionText()); | 671 DCHECK(HasCompositionText()); |
671 base::string16 composition = text().substr( | 672 base::string16 composition = text().substr( |
672 composition_range_.start(), composition_range_.length()); | 673 composition_range_.start(), composition_range_.length()); |
673 // TODO(oshima): current behavior on ChromeOS is a bit weird and not | 674 // TODO(oshima): current behavior on ChromeOS is a bit weird and not |
674 // sure exactly how this should work. Find out and fix if necessary. | 675 // sure exactly how this should work. Find out and fix if necessary. |
675 AddOrMergeEditHistory( | 676 AddOrMergeEditHistory(base::MakeUnique<InsertEdit>( |
676 new InsertEdit(false, composition, composition_range_.start())); | 677 false, composition, composition_range_.start())); |
677 render_text_->SetCursorPosition(composition_range_.end()); | 678 render_text_->SetCursorPosition(composition_range_.end()); |
678 ClearComposition(); | 679 ClearComposition(); |
679 if (delegate_) | 680 if (delegate_) |
680 delegate_->OnCompositionTextConfirmedOrCleared(); | 681 delegate_->OnCompositionTextConfirmedOrCleared(); |
681 } | 682 } |
682 | 683 |
683 void TextfieldModel::CancelCompositionText() { | 684 void TextfieldModel::CancelCompositionText() { |
684 DCHECK(HasCompositionText()); | 685 DCHECK(HasCompositionText()); |
685 gfx::Range range = composition_range_; | 686 gfx::Range range = composition_range_; |
686 ClearComposition(); | 687 ClearComposition(); |
(...skipping 11 matching lines...) Expand all Loading... | |
698 | 699 |
699 void TextfieldModel::GetCompositionTextRange(gfx::Range* range) const { | 700 void TextfieldModel::GetCompositionTextRange(gfx::Range* range) const { |
700 *range = composition_range_; | 701 *range = composition_range_; |
701 } | 702 } |
702 | 703 |
703 bool TextfieldModel::HasCompositionText() const { | 704 bool TextfieldModel::HasCompositionText() const { |
704 return !composition_range_.is_empty(); | 705 return !composition_range_.is_empty(); |
705 } | 706 } |
706 | 707 |
707 void TextfieldModel::ClearEditHistory() { | 708 void TextfieldModel::ClearEditHistory() { |
708 base::STLDeleteElements(&edit_history_); | 709 edit_history_.clear(); |
709 current_edit_ = edit_history_.end(); | 710 current_edit_ = edit_history_.end(); |
710 } | 711 } |
711 | 712 |
712 ///////////////////////////////////////////////////////////////// | 713 ///////////////////////////////////////////////////////////////// |
713 // TextfieldModel: private | 714 // TextfieldModel: private |
714 | 715 |
715 void TextfieldModel::InsertTextInternal(const base::string16& new_text, | 716 void TextfieldModel::InsertTextInternal(const base::string16& new_text, |
716 bool mergeable) { | 717 bool mergeable) { |
717 if (HasCompositionText()) { | 718 if (HasCompositionText()) { |
718 CancelCompositionText(); | 719 CancelCompositionText(); |
(...skipping 28 matching lines...) Expand all Loading... | |
747 | 748 |
748 void TextfieldModel::ClearRedoHistory() { | 749 void TextfieldModel::ClearRedoHistory() { |
749 if (edit_history_.begin() == edit_history_.end()) | 750 if (edit_history_.begin() == edit_history_.end()) |
750 return; | 751 return; |
751 if (current_edit_ == edit_history_.end()) { | 752 if (current_edit_ == edit_history_.end()) { |
752 ClearEditHistory(); | 753 ClearEditHistory(); |
753 return; | 754 return; |
754 } | 755 } |
755 EditHistory::iterator delete_start = current_edit_; | 756 EditHistory::iterator delete_start = current_edit_; |
756 ++delete_start; | 757 ++delete_start; |
757 base::STLDeleteContainerPointers(delete_start, edit_history_.end()); | |
758 edit_history_.erase(delete_start, edit_history_.end()); | 758 edit_history_.erase(delete_start, edit_history_.end()); |
759 } | 759 } |
760 | 760 |
761 void TextfieldModel::ExecuteAndRecordDelete(gfx::Range range, bool mergeable) { | 761 void TextfieldModel::ExecuteAndRecordDelete(gfx::Range range, bool mergeable) { |
762 size_t old_text_start = range.GetMin(); | 762 size_t old_text_start = range.GetMin(); |
763 const base::string16 old_text = text().substr(old_text_start, range.length()); | 763 const base::string16 old_text = text().substr(old_text_start, range.length()); |
764 bool backward = range.is_reversed(); | 764 bool backward = range.is_reversed(); |
765 Edit* edit = new DeleteEdit(mergeable, old_text, old_text_start, backward); | 765 std::unique_ptr<Edit> edit_ptr = base::MakeUnique<DeleteEdit>( |
766 bool delete_edit = AddOrMergeEditHistory(edit); | 766 mergeable, old_text, old_text_start, backward); |
767 Edit* edit = edit_ptr.get(); | |
768 std::unique_ptr<Edit> returned_edit = | |
769 AddOrMergeEditHistory(std::move(edit_ptr)); | |
767 edit->Redo(this); | 770 edit->Redo(this); |
Nico
2016/09/08 17:32:00
Getting a raw ptr to a unique_ptr that's moved fro
Avi (use Gerrit)
2016/09/13 14:36:13
This entire code is insane re ownership. I would d
| |
768 if (delete_edit) | |
769 delete edit; | |
770 } | 771 } |
771 | 772 |
772 void TextfieldModel::ExecuteAndRecordReplaceSelection( | 773 void TextfieldModel::ExecuteAndRecordReplaceSelection( |
773 MergeType merge_type, | 774 MergeType merge_type, |
774 const base::string16& new_text) { | 775 const base::string16& new_text) { |
775 size_t new_text_start = render_text_->selection().GetMin(); | 776 size_t new_text_start = render_text_->selection().GetMin(); |
776 size_t new_cursor_pos = new_text_start + new_text.length(); | 777 size_t new_cursor_pos = new_text_start + new_text.length(); |
777 ExecuteAndRecordReplace(merge_type, | 778 ExecuteAndRecordReplace(merge_type, |
778 GetCursorPosition(), | 779 GetCursorPosition(), |
779 new_cursor_pos, | 780 new_cursor_pos, |
780 new_text, | 781 new_text, |
781 new_text_start); | 782 new_text_start); |
782 } | 783 } |
783 | 784 |
784 void TextfieldModel::ExecuteAndRecordReplace(MergeType merge_type, | 785 void TextfieldModel::ExecuteAndRecordReplace(MergeType merge_type, |
785 size_t old_cursor_pos, | 786 size_t old_cursor_pos, |
786 size_t new_cursor_pos, | 787 size_t new_cursor_pos, |
787 const base::string16& new_text, | 788 const base::string16& new_text, |
788 size_t new_text_start) { | 789 size_t new_text_start) { |
789 size_t old_text_start = render_text_->selection().GetMin(); | 790 size_t old_text_start = render_text_->selection().GetMin(); |
790 bool backward = render_text_->selection().is_reversed(); | 791 bool backward = render_text_->selection().is_reversed(); |
791 Edit* edit = new ReplaceEdit(merge_type, | 792 std::unique_ptr<Edit> edit_ptr = base::MakeUnique<ReplaceEdit>( |
792 GetSelectedText(), | 793 merge_type, GetSelectedText(), old_cursor_pos, old_text_start, backward, |
793 old_cursor_pos, | 794 new_cursor_pos, new_text, new_text_start); |
794 old_text_start, | 795 Edit* edit = edit_ptr.get(); |
795 backward, | 796 std::unique_ptr<Edit> returned_edit = |
796 new_cursor_pos, | 797 AddOrMergeEditHistory(std::move(edit_ptr)); |
797 new_text, | |
798 new_text_start); | |
799 bool delete_edit = AddOrMergeEditHistory(edit); | |
800 edit->Redo(this); | 798 edit->Redo(this); |
Nico
2016/09/08 17:32:00
ditto
| |
801 if (delete_edit) | |
802 delete edit; | |
803 } | 799 } |
804 | 800 |
805 void TextfieldModel::ExecuteAndRecordInsert(const base::string16& new_text, | 801 void TextfieldModel::ExecuteAndRecordInsert(const base::string16& new_text, |
806 bool mergeable) { | 802 bool mergeable) { |
807 Edit* edit = new InsertEdit(mergeable, new_text, GetCursorPosition()); | 803 std::unique_ptr<Edit> edit_ptr = |
808 bool delete_edit = AddOrMergeEditHistory(edit); | 804 base::MakeUnique<InsertEdit>(mergeable, new_text, GetCursorPosition()); |
805 Edit* edit = edit_ptr.get(); | |
806 std::unique_ptr<Edit> returned_edit = | |
807 AddOrMergeEditHistory(std::move(edit_ptr)); | |
809 edit->Redo(this); | 808 edit->Redo(this); |
810 if (delete_edit) | |
811 delete edit; | |
812 } | 809 } |
813 | 810 |
814 bool TextfieldModel::AddOrMergeEditHistory(Edit* edit) { | 811 std::unique_ptr<internal::Edit> TextfieldModel::AddOrMergeEditHistory( |
812 std::unique_ptr<Edit> edit) { | |
815 ClearRedoHistory(); | 813 ClearRedoHistory(); |
816 | 814 |
817 if (current_edit_ != edit_history_.end() && (*current_edit_)->Merge(edit)) { | 815 if (current_edit_ != edit_history_.end() && |
816 (*current_edit_)->Merge(edit.get())) { | |
818 // If a current edit exists and has been merged with a new edit, don't add | 817 // If a current edit exists and has been merged with a new edit, don't add |
819 // to the history, and return true to delete |edit| after redo. | 818 // to the history, and return the edit so that it is deleted after redo. |
820 return true; | 819 return edit; |
821 } | 820 } |
822 edit_history_.push_back(edit); | 821 edit_history_.push_back(std::move(edit)); |
823 if (current_edit_ == edit_history_.end()) { | 822 if (current_edit_ == edit_history_.end()) { |
824 // If there is no redoable edit, this is the 1st edit because RedoHistory | 823 // If there is no redoable edit, this is the 1st edit because RedoHistory |
825 // has been already deleted. | 824 // has been already deleted. |
826 DCHECK_EQ(1u, edit_history_.size()); | 825 DCHECK_EQ(1u, edit_history_.size()); |
827 current_edit_ = edit_history_.begin(); | 826 current_edit_ = edit_history_.begin(); |
828 } else { | 827 } else { |
829 ++current_edit_; | 828 ++current_edit_; |
830 } | 829 } |
831 return false; | 830 return nullptr; |
832 } | 831 } |
833 | 832 |
834 void TextfieldModel::ModifyText(size_t delete_from, | 833 void TextfieldModel::ModifyText(size_t delete_from, |
835 size_t delete_to, | 834 size_t delete_to, |
836 const base::string16& new_text, | 835 const base::string16& new_text, |
837 size_t new_text_insert_at, | 836 size_t new_text_insert_at, |
838 size_t new_cursor_pos) { | 837 size_t new_cursor_pos) { |
839 DCHECK_LE(delete_from, delete_to); | 838 DCHECK_LE(delete_from, delete_to); |
840 base::string16 old_text = text(); | 839 base::string16 old_text = text(); |
841 ClearComposition(); | 840 ClearComposition(); |
842 if (delete_from != delete_to) | 841 if (delete_from != delete_to) |
843 render_text_->SetText(old_text.erase(delete_from, delete_to - delete_from)); | 842 render_text_->SetText(old_text.erase(delete_from, delete_to - delete_from)); |
844 if (!new_text.empty()) | 843 if (!new_text.empty()) |
845 render_text_->SetText(old_text.insert(new_text_insert_at, new_text)); | 844 render_text_->SetText(old_text.insert(new_text_insert_at, new_text)); |
846 render_text_->SetCursorPosition(new_cursor_pos); | 845 render_text_->SetCursorPosition(new_cursor_pos); |
847 // TODO(oshima): Select text that was just undone, like Mac (but not GTK). | 846 // TODO(oshima): Select text that was just undone, like Mac (but not GTK). |
848 } | 847 } |
849 | 848 |
850 // static | 849 // static |
851 void TextfieldModel::ClearKillBuffer() { | 850 void TextfieldModel::ClearKillBuffer() { |
852 SetKillBuffer(base::string16()); | 851 SetKillBuffer(base::string16()); |
853 } | 852 } |
854 | 853 |
855 } // namespace views | 854 } // namespace views |
OLD | NEW |