Chromium Code Reviews| 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 |