Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(242)

Side by Side Diff: views/controls/textfield/textfield_views_model.cc

Issue 7067015: An edit for SetText needs to be merged with previous edit for omnibox. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: " Created 9 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 "views/controls/textfield/textfield_views_model.h" 5 #include "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 23 matching lines...) Expand all
34 INSERT_EDIT, 34 INSERT_EDIT,
35 DELETE_EDIT, 35 DELETE_EDIT,
36 REPLACE_EDIT 36 REPLACE_EDIT
37 }; 37 };
38 38
39 virtual ~Edit() { 39 virtual ~Edit() {
40 } 40 }
41 41
42 // Revert the change made by this edit in |model|. 42 // Revert the change made by this edit in |model|.
43 void Undo(TextfieldViewsModel* model) { 43 void Undo(TextfieldViewsModel* model) {
44 size_t old_cursor = delete_backward_ ? old_text_end() : old_text_start_;
45 model->ModifyText(new_text_start_, new_text_end(), 44 model->ModifyText(new_text_start_, new_text_end(),
46 old_text_, old_text_start_, 45 old_text_, old_text_start_,
47 old_cursor); 46 old_cursor_pos_);
48 } 47 }
49 48
50 // Apply the change of this edit to the |model|. 49 // Apply the change of this edit to the |model|.
51 void Redo(TextfieldViewsModel* model) { 50 void Redo(TextfieldViewsModel* model) {
52 model->ModifyText(old_text_start_, old_text_end(), 51 model->ModifyText(old_text_start_, old_text_end(),
53 new_text_, new_text_start_, 52 new_text_, new_text_start_,
54 new_text_end()); 53 new_cursor_pos_);
55 } 54 }
56 55
57 // Try to merge the edit into this edit. Returns true if merge was 56 // Try to merge the |edit| into this edit. Returns true if merge was
58 // successful, or false otherwise. Merged edit will be deleted after 57 // successful, or false otherwise. Merged edit will be deleted after
59 // redo and should not be reused. 58 // redo and should not be reused.
60 bool Merge(Edit* edit) { 59 bool Merge(const Edit* edit) {
61 return mergeable_ && edit->mergeable() && DoMerge(edit); 60 if (edit->merge_with_previous()) {
61 MergeSet(edit);
62 return true;
63 }
64 return mergeable() && edit->mergeable() && DoMerge(edit);
62 } 65 }
63 66
64 // Commits the edit and marks as un-mergeable. 67 // Commits the edit and marks as un-mergeable.
65 void Commit() { mergeable_ = false; } 68 void Commit() { merge_type_ = DO_NOT_MERGE; }
66 69
67 private: 70 private:
68 friend class InsertEdit; 71 friend class InsertEdit;
69 friend class ReplaceEdit; 72 friend class ReplaceEdit;
70 friend class DeleteEdit; 73 friend class DeleteEdit;
71 74
72 Edit(Type type, 75 Edit(Type type,
73 bool mergeable, 76 MergeType merge_type,
77 size_t old_cursor_pos,
74 string16 old_text, 78 string16 old_text,
75 size_t old_text_start, 79 size_t old_text_start,
76 bool delete_backward, 80 bool delete_backward,
81 size_t new_cursor_pos,
77 string16 new_text, 82 string16 new_text,
78 size_t new_text_start) 83 size_t new_text_start)
79 : type_(type), 84 : type_(type),
80 mergeable_(mergeable), 85 merge_type_(merge_type),
86 old_cursor_pos_(old_cursor_pos),
81 old_text_(old_text), 87 old_text_(old_text),
82 old_text_start_(old_text_start), 88 old_text_start_(old_text_start),
83 delete_backward_(delete_backward), 89 delete_backward_(delete_backward),
90 new_cursor_pos_(new_cursor_pos),
84 new_text_(new_text), 91 new_text_(new_text),
85 new_text_start_(new_text_start) { 92 new_text_start_(new_text_start) {
86 } 93 }
87 94
88 // A template method pattern that provides specific merge 95 // A template method pattern that provides specific merge
89 // implementation for each type of edit. 96 // implementation for each type of edit.
90 virtual bool DoMerge(Edit* edit) = 0; 97 virtual bool DoMerge(const Edit* edit) = 0;
91 98
92 Type type() { return type_; } 99 Type type() const { return type_; }
93 100
94 // Can this edit be merged? 101 // Can this edit be merged?
95 bool mergeable() { return mergeable_; } 102 bool mergeable() const { return merge_type_ == MERGEABLE; }
103
104 // Does this edit should be merged with previous edit?
msw 2011/06/02 21:02:57 okay, the function is fine, but the comment needs
oshima 2011/06/03 00:39:24 Done.
105 bool merge_with_previous() const {
106 return merge_type_ == MERGE_WITH_PREVIOUS;
107 }
96 108
97 // Returns the end index of the |old_text_|. 109 // Returns the end index of the |old_text_|.
98 size_t old_text_end() { return old_text_start_ + old_text_.length(); } 110 size_t old_text_end() const { return old_text_start_ + old_text_.length(); }
99 111
100 // Returns the end index of the |new_text_|. 112 // Returns the end index of the |new_text_|.
101 size_t new_text_end() { return new_text_start_ + new_text_.length(); } 113 size_t new_text_end() const { return new_text_start_ + new_text_.length(); }
114
115 // Merge the Set edit into the current edit. This is a special case to
116 // handle an omnibox setting autocomplete string after new character is
117 // typed in.
118 void MergeSet(const Edit* edit) {
119 CHECK_EQ(REPLACE_EDIT, edit->type_);
120 CHECK_EQ(0U, edit->old_text_start_);
121 CHECK_EQ(0U, edit->new_text_start_);
122 string16 old_text = edit->old_text_;
123 old_text.erase(new_text_start_, new_text_.length());
124 old_text.insert(old_text_start_, old_text_);
125 // Set edit replaces entire text, so remember that.
msw 2011/06/02 21:02:57 I ran through an example just now and it makes sen
oshima 2011/06/03 00:39:24 Done.
126 old_text_ = old_text;
127 old_text_start_ = edit->old_text_start_;
128 delete_backward_ = false;
129
130 new_text_ = edit->new_text_;
131 new_text_start_ = edit->new_text_start_;
132 merge_type_ = DO_NOT_MERGE;
133 }
102 134
103 Type type_; 135 Type type_;
104 136
105 // True if the edit can be marged. 137 // True if the edit can be marged.
106 bool mergeable_; 138 MergeType merge_type_;
139 // Old cursor position.
140 size_t old_cursor_pos_;
107 // Deleted text by this edit. 141 // Deleted text by this edit.
108 string16 old_text_; 142 string16 old_text_;
109 // The index of |old_text_|. 143 // The index of |old_text_|.
110 size_t old_text_start_; 144 size_t old_text_start_;
111 // True if the deletion is made backward. 145 // True if the deletion is made backward.
112 bool delete_backward_; 146 bool delete_backward_;
147 // New cursor position.
148 size_t new_cursor_pos_;
113 // Added text. 149 // Added text.
114 string16 new_text_; 150 string16 new_text_;
115 // The index of |new_text_| 151 // The index of |new_text_|
116 size_t new_text_start_; 152 size_t new_text_start_;
117 153
118 DISALLOW_COPY_AND_ASSIGN(Edit); 154 DISALLOW_COPY_AND_ASSIGN(Edit);
119 }; 155 };
120 156
121 class InsertEdit : public Edit { 157 class InsertEdit : public Edit {
122 public: 158 public:
123 InsertEdit(bool mergeable, const string16& new_text, size_t at) 159 InsertEdit(bool mergeable, const string16& new_text, size_t at)
124 : Edit(INSERT_EDIT, mergeable, string16(), at, false, new_text, at) { 160 : Edit(INSERT_EDIT,
161 mergeable ? MERGEABLE : DO_NOT_MERGE,
162 at /* old cursor */,
163 string16(),
164 at,
165 false /* N/A */,
166 at + new_text.length() /* new cursor */,
167 new_text,
168 at) {
125 } 169 }
126 170
127 // Edit implementation. 171 // Edit implementation.
128 virtual bool DoMerge(Edit* edit) OVERRIDE { 172 virtual bool DoMerge(const Edit* edit) OVERRIDE {
129 if (edit->type() != INSERT_EDIT || new_text_end() != edit->new_text_start_) 173 if (edit->type() != INSERT_EDIT || new_text_end() != edit->new_text_start_)
130 return false; 174 return false;
131 // If continuous edit, merge it. 175 // If continuous edit, merge it.
132 // TODO(oshima): gtk splits edits between whitespace. Find out what 176 // TODO(oshima): gtk splits edits between whitespace. Find out what
133 // we want to here and implement if necessary. 177 // we want to here and implement if necessary.
134 new_text_ += edit->new_text_; 178 new_text_ += edit->new_text_;
179 new_cursor_pos_ = edit->new_cursor_pos_;
135 return true; 180 return true;
136 } 181 }
137 }; 182 };
138 183
139 class ReplaceEdit : public Edit { 184 class ReplaceEdit : public Edit {
140 public: 185 public:
141 ReplaceEdit(bool mergeable, 186 ReplaceEdit(MergeType merge_type,
142 const string16& old_text, 187 const string16& old_text,
188 size_t old_cursor_pos,
143 size_t old_text_start, 189 size_t old_text_start,
144 bool backward, 190 bool backward,
191 size_t new_cursor_pos,
145 const string16& new_text, 192 const string16& new_text,
146 size_t new_text_start) 193 size_t new_text_start)
147 : Edit(REPLACE_EDIT, mergeable, 194 : Edit(REPLACE_EDIT, merge_type,
195 old_cursor_pos,
148 old_text, 196 old_text,
149 old_text_start, 197 old_text_start,
150 backward, 198 backward,
199 new_cursor_pos,
151 new_text, 200 new_text,
152 new_text_start) { 201 new_text_start) {
153 } 202 }
154 203
155 // Edit implementation. 204 // Edit implementation.
156 virtual bool DoMerge(Edit* edit) OVERRIDE { 205 virtual bool DoMerge(const Edit* edit) OVERRIDE {
157 if (edit->type() == DELETE_EDIT || 206 if (edit->type() == DELETE_EDIT ||
158 new_text_end() != edit->old_text_start_ || 207 new_text_end() != edit->old_text_start_ ||
159 edit->old_text_start_ != edit->new_text_start_) 208 edit->old_text_start_ != edit->new_text_start_)
160 return false; 209 return false;
161 old_text_ += edit->old_text_; 210 old_text_ += edit->old_text_;
162 new_text_ += edit->new_text_; 211 new_text_ += edit->new_text_;
212 new_cursor_pos_ = edit->new_cursor_pos_;
163 return true; 213 return true;
164 } 214 }
165 }; 215 };
166 216
167 class DeleteEdit : public Edit { 217 class DeleteEdit : public Edit {
168 public: 218 public:
169 DeleteEdit(bool mergeable, 219 DeleteEdit(bool mergeable,
170 const string16& text, 220 const string16& text,
171 size_t text_start, 221 size_t text_start,
172 bool backward) 222 bool backward)
173 : Edit(DELETE_EDIT, mergeable, 223 : Edit(DELETE_EDIT,
224 mergeable ? MERGEABLE : DO_NOT_MERGE,
225 (backward ? text_start + text.length() : text_start),
174 text, 226 text,
175 text_start, 227 text_start,
176 backward, 228 backward,
229 text_start,
177 string16(), 230 string16(),
178 text_start) { 231 text_start) {
179 } 232 }
180 233
181 // Edit implementation. 234 // Edit implementation.
182 virtual bool DoMerge(Edit* edit) OVERRIDE { 235 virtual bool DoMerge(const Edit* edit) OVERRIDE {
183 if (edit->type() != DELETE_EDIT) 236 if (edit->type() != DELETE_EDIT)
184 return false; 237 return false;
185 238
186 if (delete_backward_) { 239 if (delete_backward_) {
187 // backspace can be merged only with backspace at the 240 // backspace can be merged only with backspace at the
188 // same position. 241 // same position.
189 if (!edit->delete_backward_ || old_text_start_ != edit->old_text_end()) 242 if (!edit->delete_backward_ || old_text_start_ != edit->old_text_end())
190 return false; 243 return false;
191 old_text_start_ = edit->old_text_start_; 244 old_text_start_ = edit->old_text_start_;
192 old_text_ = edit->old_text_ + old_text_; 245 old_text_ = edit->old_text_ + old_text_;
246 new_cursor_pos_ = edit->new_cursor_pos_;
193 } else { 247 } else {
194 // delete can be merged only with delete at the same 248 // delete can be merged only with delete at the same
195 // position. 249 // position.
196 if (edit->delete_backward_ || old_text_start_ != edit->old_text_start_) 250 if (edit->delete_backward_ || old_text_start_ != edit->old_text_start_)
197 return false; 251 return false;
198 old_text_ += edit->old_text_; 252 old_text_ += edit->old_text_;
199 } 253 }
200 return true; 254 return true;
201 } 255 }
202 }; 256 };
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
306 DCHECK(CheckInvariant(style_ranges)); 360 DCHECK(CheckInvariant(style_ranges));
307 #endif 361 #endif
308 } 362 }
309 363
310 } // namespace 364 } // namespace
311 365
312 using internal::Edit; 366 using internal::Edit;
313 using internal::DeleteEdit; 367 using internal::DeleteEdit;
314 using internal::InsertEdit; 368 using internal::InsertEdit;
315 using internal::ReplaceEdit; 369 using internal::ReplaceEdit;
370 using internal::MergeType;
371 using internal::DO_NOT_MERGE;
372 using internal::MERGE_WITH_PREVIOUS;
373 using internal::MERGEABLE;
316 374
317 ///////////////////////////////////////////////////////////////// 375 /////////////////////////////////////////////////////////////////
318 // TextfieldViewsModel: public 376 // TextfieldViewsModel: public
319 377
320 TextfieldViewsModel::Delegate::~Delegate() { 378 TextfieldViewsModel::Delegate::~Delegate() {
321 } 379 }
322 380
323 TextfieldViewsModel::TextfieldViewsModel(Delegate* delegate) 381 TextfieldViewsModel::TextfieldViewsModel(Delegate* delegate)
324 : delegate_(delegate), 382 : delegate_(delegate),
325 cursor_pos_(0), 383 cursor_pos_(0),
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
388 fragments->push_back(TextFragment(current, end, kNormalStyle)); 446 fragments->push_back(TextFragment(current, end, kNormalStyle));
389 } 447 }
390 448
391 bool TextfieldViewsModel::SetText(const string16& text) { 449 bool TextfieldViewsModel::SetText(const string16& text) {
392 bool changed = false; 450 bool changed = false;
393 if (HasCompositionText()) { 451 if (HasCompositionText()) {
394 ConfirmCompositionText(); 452 ConfirmCompositionText();
395 changed = true; 453 changed = true;
396 } 454 }
397 if (text_ != text) { 455 if (text_ != text) {
398 if (changed) // no need to remember composition. 456 if (changed) // No need to remember composition.
399 Undo(); 457 Undo();
458 size_t old_cursor = cursor_pos_;
459 size_t new_cursor = old_cursor > text.length() ? text.length() : old_cursor;
400 SelectAll(); 460 SelectAll();
401 InsertTextInternal(text, false); 461 // If there is a composition text, don't merge with previous edit.
402 cursor_pos_ = 0; 462 // Otherwise, force merge the edits.
463 ExecuteAndRecordReplace(
464 changed ? DO_NOT_MERGE : MERGE_WITH_PREVIOUS,
465 old_cursor,
466 new_cursor,
467 text,
468 0U);
469 cursor_pos_ = new_cursor;
403 } 470 }
404 ClearSelection(); 471 ClearSelection();
405 return changed; 472 return changed;
406 } 473 }
407 474
408 void TextfieldViewsModel::Append(const string16& text) { 475 void TextfieldViewsModel::Append(const string16& text) {
409 if (HasCompositionText()) 476 if (HasCompositionText())
410 ConfirmCompositionText(); 477 ConfirmCompositionText();
411 size_t save = cursor_pos_; 478 size_t save = cursor_pos_;
412 MoveCursorToEnd(false); 479 MoveCursorToEnd(false);
(...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after
660 } 727 }
661 728
662 bool TextfieldViewsModel::Undo() { 729 bool TextfieldViewsModel::Undo() {
663 if (!CanUndo()) 730 if (!CanUndo())
664 return false; 731 return false;
665 DCHECK(!HasCompositionText()); 732 DCHECK(!HasCompositionText());
666 if (HasCompositionText()) // safe guard for release build. 733 if (HasCompositionText()) // safe guard for release build.
667 CancelCompositionText(); 734 CancelCompositionText();
668 735
669 string16 old = text_; 736 string16 old = text_;
737 size_t old_cursor = cursor_pos_;
670 (*current_edit_)->Commit(); 738 (*current_edit_)->Commit();
671 (*current_edit_)->Undo(this); 739 (*current_edit_)->Undo(this);
672 740
673 if (current_edit_ == edit_history_.begin()) 741 if (current_edit_ == edit_history_.begin())
674 current_edit_ = edit_history_.end(); 742 current_edit_ = edit_history_.end();
675 else 743 else
676 current_edit_--; 744 current_edit_--;
677 return old != text_; 745 return old != text_ || old_cursor != cursor_pos_;
678 } 746 }
679 747
680 bool TextfieldViewsModel::Redo() { 748 bool TextfieldViewsModel::Redo() {
681 if (!CanRedo()) 749 if (!CanRedo())
682 return false; 750 return false;
683 DCHECK(!HasCompositionText()); 751 DCHECK(!HasCompositionText());
684 if (HasCompositionText()) // safe guard for release build. 752 if (HasCompositionText()) // safe guard for release build.
685 CancelCompositionText(); 753 CancelCompositionText();
686 754
687 if (current_edit_ == edit_history_.end()) 755 if (current_edit_ == edit_history_.end())
688 current_edit_ = edit_history_.begin(); 756 current_edit_ = edit_history_.begin();
689 else 757 else
690 current_edit_ ++; 758 current_edit_ ++;
691 string16 old = text_; 759 string16 old = text_;
760 size_t old_cursor = cursor_pos_;
692 (*current_edit_)->Redo(this); 761 (*current_edit_)->Redo(this);
693 return old != text_; 762 return old != text_ || old_cursor != cursor_pos_;
694 } 763 }
695 764
696 bool TextfieldViewsModel::Cut() { 765 bool TextfieldViewsModel::Cut() {
697 if (!HasCompositionText() && HasSelection()) { 766 if (!HasCompositionText() && HasSelection()) {
698 ui::ScopedClipboardWriter(views::ViewsDelegate::views_delegate 767 ui::ScopedClipboardWriter(views::ViewsDelegate::views_delegate
699 ->GetClipboard()).WriteText(GetSelectedText()); 768 ->GetClipboard()).WriteText(GetSelectedText());
769 // A trick to let undo/redo handle cursor correctly.
770 // Undoing CUT moves the cursor to the end of the change rather
771 // than beginning, unlike Delete/Backspace.
772 // TODO(oshima): Change Delete/Backspace to use DeleteSelection,
773 // update DeleteEdit and remove this trick.
774 std::swap(cursor_pos_, selection_start_);
700 DeleteSelection(); 775 DeleteSelection();
701 return true; 776 return true;
702 } 777 }
703 return false; 778 return false;
704 } 779 }
705 780
706 void TextfieldViewsModel::Copy() { 781 void TextfieldViewsModel::Copy() {
707 if (!HasCompositionText() && HasSelection()) { 782 if (!HasCompositionText() && HasSelection()) {
708 ui::ScopedClipboardWriter(views::ViewsDelegate::views_delegate 783 ui::ScopedClipboardWriter(views::ViewsDelegate::views_delegate
709 ->GetClipboard()).WriteText(GetSelectedText()); 784 ->GetClipboard()).WriteText(GetSelectedText());
(...skipping 18 matching lines...) Expand all
728 void TextfieldViewsModel::DeleteSelection() { 803 void TextfieldViewsModel::DeleteSelection() {
729 DCHECK(!HasCompositionText()); 804 DCHECK(!HasCompositionText());
730 DCHECK(HasSelection()); 805 DCHECK(HasSelection());
731 ExecuteAndRecordDelete(selection_start_, cursor_pos_, false); 806 ExecuteAndRecordDelete(selection_start_, cursor_pos_, false);
732 } 807 }
733 808
734 void TextfieldViewsModel::DeleteSelectionAndInsertTextAt( 809 void TextfieldViewsModel::DeleteSelectionAndInsertTextAt(
735 const string16& text, size_t position) { 810 const string16& text, size_t position) {
736 if (HasCompositionText()) 811 if (HasCompositionText())
737 CancelCompositionText(); 812 CancelCompositionText();
738 ExecuteAndRecordReplaceAt(text, position, false); 813 ExecuteAndRecordReplace(DO_NOT_MERGE,
814 cursor_pos_,
815 position + text.length(),
816 text,
817 position);
739 } 818 }
740 819
741 string16 TextfieldViewsModel::GetTextFromRange(const ui::Range& range) const { 820 string16 TextfieldViewsModel::GetTextFromRange(const ui::Range& range) const {
742 if (range.IsValid() && range.GetMin() < text_.length()) 821 if (range.IsValid() && range.GetMin() < text_.length())
743 return text_.substr(range.GetMin(), range.length()); 822 return text_.substr(range.GetMin(), range.length());
744 return string16(); 823 return string16();
745 } 824 }
746 825
747 void TextfieldViewsModel::GetTextRange(ui::Range* range) const { 826 void TextfieldViewsModel::GetTextRange(ui::Range* range) const {
748 *range = ui::Range(0, text_.length()); 827 *range = ui::Range(0, text_.length());
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
872 } 951 }
873 return position; 952 return position;
874 } 953 }
875 954
876 void TextfieldViewsModel::InsertTextInternal(const string16& text, 955 void TextfieldViewsModel::InsertTextInternal(const string16& text,
877 bool mergeable) { 956 bool mergeable) {
878 if (HasCompositionText()) { 957 if (HasCompositionText()) {
879 CancelCompositionText(); 958 CancelCompositionText();
880 ExecuteAndRecordInsert(text, mergeable); 959 ExecuteAndRecordInsert(text, mergeable);
881 } else if (HasSelection()) { 960 } else if (HasSelection()) {
882 ExecuteAndRecordReplace(text, mergeable); 961 ExecuteAndRecordReplaceSelection(mergeable ? MERGEABLE : DO_NOT_MERGE,
962 text);
883 } else { 963 } else {
884 ExecuteAndRecordInsert(text, mergeable); 964 ExecuteAndRecordInsert(text, mergeable);
885 } 965 }
886 } 966 }
887 967
888 void TextfieldViewsModel::ReplaceTextInternal(const string16& text, 968 void TextfieldViewsModel::ReplaceTextInternal(const string16& text,
889 bool mergeable) { 969 bool mergeable) {
890 if (HasCompositionText()) 970 if (HasCompositionText())
891 CancelCompositionText(); 971 CancelCompositionText();
892 else if (!HasSelection()) 972 else if (!HasSelection())
(...skipping 11 matching lines...) Expand all
904 984
905 void TextfieldViewsModel::ClearRedoHistory() { 985 void TextfieldViewsModel::ClearRedoHistory() {
906 if (edit_history_.begin() == edit_history_.end()) 986 if (edit_history_.begin() == edit_history_.end())
907 return; 987 return;
908 if (current_edit_ == edit_history_.end()) { 988 if (current_edit_ == edit_history_.end()) {
909 ClearEditHistory(); 989 ClearEditHistory();
910 return; 990 return;
911 } 991 }
912 EditHistory::iterator delete_start = current_edit_; 992 EditHistory::iterator delete_start = current_edit_;
913 delete_start++; 993 delete_start++;
914 STLDeleteContainerPointers(delete_start, 994 STLDeleteContainerPointers(delete_start, edit_history_.end());
915 edit_history_.end());
916 edit_history_.erase(delete_start, edit_history_.end()); 995 edit_history_.erase(delete_start, edit_history_.end());
917 } 996 }
918 997
919 void TextfieldViewsModel::ExecuteAndRecordDelete(size_t from, 998 void TextfieldViewsModel::ExecuteAndRecordDelete(size_t from,
920 size_t to, 999 size_t to,
921 bool mergeable) { 1000 bool mergeable) {
922 size_t old_text_start = std::min(from, to); 1001 size_t old_text_start = std::min(from, to);
923 const string16 text = text_.substr(old_text_start, 1002 const string16 text = text_.substr(old_text_start,
924 std::abs(static_cast<long>(from - to))); 1003 std::abs(static_cast<long>(from - to)));
925 Edit* edit = new DeleteEdit(mergeable, 1004 bool backward = from > to;
926 text, 1005 Edit* edit = new DeleteEdit(mergeable, text, old_text_start, backward);
927 old_text_start,
928 (from > to));
929 bool delete_edit = AddOrMergeEditHistory(edit); 1006 bool delete_edit = AddOrMergeEditHistory(edit);
930 edit->Redo(this); 1007 edit->Redo(this);
931 if (delete_edit) 1008 if (delete_edit)
932 delete edit; 1009 delete edit;
933 } 1010 }
934 1011
935 void TextfieldViewsModel::ExecuteAndRecordReplace(const string16& text, 1012 void TextfieldViewsModel::ExecuteAndRecordReplaceSelection(
936 bool mergeable) { 1013 MergeType merge_type, const string16& new_text) {
937 size_t at = std::min(cursor_pos_, selection_start_); 1014 size_t new_text_start = std::min(cursor_pos_, selection_start_);
938 ExecuteAndRecordReplaceAt(text, at, mergeable); 1015 size_t new_cursor_pos = new_text_start + new_text.length();
1016 ExecuteAndRecordReplace(merge_type,
1017 cursor_pos_,
1018 new_cursor_pos,
1019 new_text,
1020 new_text_start);
939 } 1021 }
940 1022
941 void TextfieldViewsModel::ExecuteAndRecordReplaceAt(const string16& text, 1023 void TextfieldViewsModel::ExecuteAndRecordReplace(MergeType merge_type,
942 size_t at, 1024 size_t old_cursor_pos,
943 bool mergeable) { 1025 size_t new_cursor_pos,
944 size_t text_start = std::min(cursor_pos_, selection_start_); 1026 const string16& new_text,
945 Edit* edit = new ReplaceEdit(mergeable, 1027 size_t new_text_start) {
1028 size_t old_text_start = std::min(cursor_pos_, selection_start_);
1029 bool backward = selection_start_ > cursor_pos_;
1030 Edit* edit = new ReplaceEdit(merge_type,
946 GetSelectedText(), 1031 GetSelectedText(),
947 text_start, 1032 old_cursor_pos,
948 selection_start_ > cursor_pos_, 1033 old_text_start,
949 text, 1034 backward,
950 at); 1035 new_cursor_pos,
1036 new_text,
1037 new_text_start);
951 bool delete_edit = AddOrMergeEditHistory(edit); 1038 bool delete_edit = AddOrMergeEditHistory(edit);
952 edit->Redo(this); 1039 edit->Redo(this);
953 if (delete_edit) 1040 if (delete_edit)
954 delete edit; 1041 delete edit;
955 } 1042 }
956 1043
957 void TextfieldViewsModel::ExecuteAndRecordInsert(const string16& text, 1044 void TextfieldViewsModel::ExecuteAndRecordInsert(const string16& text,
958 bool mergeable) { 1045 bool mergeable) {
959 Edit* edit = new InsertEdit(mergeable, text, cursor_pos_); 1046 Edit* edit = new InsertEdit(mergeable, text, cursor_pos_);
960 bool delete_edit = AddOrMergeEditHistory(edit); 1047 bool delete_edit = AddOrMergeEditHistory(edit);
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
1001 } 1088 }
1002 1089
1003 // static 1090 // static
1004 TextStyle* TextfieldViewsModel::CreateUnderlineStyle() { 1091 TextStyle* TextfieldViewsModel::CreateUnderlineStyle() {
1005 TextStyle* style = new TextStyle(); 1092 TextStyle* style = new TextStyle();
1006 style->set_underline(true); 1093 style->set_underline(true);
1007 return style; 1094 return style;
1008 } 1095 }
1009 1096
1010 } // namespace views 1097 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698