OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
51 void Redo(TextfieldViewsModel* model) { | 51 void Redo(TextfieldViewsModel* model) { |
52 model->ModifyText(old_text_start_, old_text_end(), | 52 model->ModifyText(old_text_start_, old_text_end(), |
53 new_text_, new_text_start_, | 53 new_text_, new_text_start_, |
54 new_cursor_pos_); | 54 new_cursor_pos_); |
55 } | 55 } |
56 | 56 |
57 // Try to merge the |edit| into this edit. Returns true if merge was | 57 // Try to merge the |edit| into this edit. Returns true if merge was |
58 // successful, or false otherwise. Merged edit will be deleted after | 58 // successful, or false otherwise. Merged edit will be deleted after |
59 // redo and should not be reused. | 59 // redo and should not be reused. |
60 bool Merge(const Edit* edit) { | 60 bool Merge(const Edit* edit) { |
61 if (edit->merge_with_previous()) { | 61 // Don't merge if previous edit is DELETE. This happens when a |
62 MergeSet(edit); | 62 // user deletes characters then hits return. In this case, the |
| 63 // delete should be treated as separate edit that can be undone |
| 64 // and should not be merged with the replace edit. |
| 65 if (type_ != DELETE_EDIT && edit->merge_with_previous()) { |
| 66 MergeReplace(edit); |
63 return true; | 67 return true; |
64 } | 68 } |
65 return mergeable() && edit->mergeable() && DoMerge(edit); | 69 return mergeable() && edit->mergeable() && DoMerge(edit); |
66 } | 70 } |
67 | 71 |
68 // Commits the edit and marks as un-mergeable. | 72 // Commits the edit and marks as un-mergeable. |
69 void Commit() { merge_type_ = DO_NOT_MERGE; } | 73 void Commit() { merge_type_ = DO_NOT_MERGE; } |
70 | 74 |
71 private: | 75 private: |
72 friend class InsertEdit; | 76 friend class InsertEdit; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
106 bool merge_with_previous() const { | 110 bool merge_with_previous() const { |
107 return merge_type_ == MERGE_WITH_PREVIOUS; | 111 return merge_type_ == MERGE_WITH_PREVIOUS; |
108 } | 112 } |
109 | 113 |
110 // Returns the end index of the |old_text_|. | 114 // Returns the end index of the |old_text_|. |
111 size_t old_text_end() const { return old_text_start_ + old_text_.length(); } | 115 size_t old_text_end() const { return old_text_start_ + old_text_.length(); } |
112 | 116 |
113 // Returns the end index of the |new_text_|. | 117 // Returns the end index of the |new_text_|. |
114 size_t new_text_end() const { return new_text_start_ + new_text_.length(); } | 118 size_t new_text_end() const { return new_text_start_ + new_text_.length(); } |
115 | 119 |
116 // Merge the Set edit into the current edit. This is a special case to | 120 // Merge the replace edit into the current edit. This is a special case to |
117 // handle an omnibox setting autocomplete string after new character is | 121 // handle an omnibox setting autocomplete string after new character is |
118 // typed in. | 122 // typed in. |
119 void MergeSet(const Edit* edit) { | 123 void MergeReplace(const Edit* edit) { |
120 CHECK_EQ(REPLACE_EDIT, edit->type_); | 124 CHECK_EQ(REPLACE_EDIT, edit->type_); |
121 CHECK_EQ(0U, edit->old_text_start_); | 125 CHECK_EQ(0U, edit->old_text_start_); |
122 CHECK_EQ(0U, edit->new_text_start_); | 126 CHECK_EQ(0U, edit->new_text_start_); |
123 string16 old_text = edit->old_text_; | 127 string16 old_text = edit->old_text_; |
124 old_text.erase(new_text_start_, new_text_.length()); | 128 old_text.erase(new_text_start_, new_text_.length()); |
125 old_text.insert(old_text_start_, old_text_); | 129 old_text.insert(old_text_start_, old_text_); |
126 // SetText() replaces entire text. Set |old_text_| to the entire | 130 // SetText() replaces entire text. Set |old_text_| to the entire |
127 // replaced text with |this| edit undone. | 131 // replaced text with |this| edit undone. |
128 old_text_ = old_text; | 132 old_text_ = old_text; |
129 old_text_start_ = edit->old_text_start_; | 133 old_text_start_ = edit->old_text_start_; |
(...skipping 656 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
786 if (delete_from != delete_to) | 790 if (delete_from != delete_to) |
787 render_text_->SetText(text.erase(delete_from, delete_to - delete_from)); | 791 render_text_->SetText(text.erase(delete_from, delete_to - delete_from)); |
788 if (!new_text.empty()) | 792 if (!new_text.empty()) |
789 render_text_->SetText(text.insert(new_text_insert_at, new_text)); | 793 render_text_->SetText(text.insert(new_text_insert_at, new_text)); |
790 render_text_->SetCursorPosition(new_cursor_pos); | 794 render_text_->SetCursorPosition(new_cursor_pos); |
791 // TODO(oshima): mac selects the text that is just undone (but gtk doesn't). | 795 // TODO(oshima): mac selects the text that is just undone (but gtk doesn't). |
792 // This looks fine feature and we may want to do the same. | 796 // This looks fine feature and we may want to do the same. |
793 } | 797 } |
794 | 798 |
795 } // namespace views | 799 } // namespace views |
OLD | NEW |