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

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_ = DONT_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_text_cursor,
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_text_cursor,
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_text_cursor),
msw 2011/06/02 10:16:42 nit: Rename the parameter |old_text_cursor| to |ol
oshima 2011/06/02 19:11:42 Done.
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_text_cursor),
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 10:16:42 nit: comment phrasing; perhaps eliminate this func
oshima 2011/06/02 19:11:42 I tried it but somehow didn't like it (probably du
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 old_text_ = old_text;
msw 2011/06/02 10:16:42 I thought I had this figured out before, but now I
oshima 2011/06/02 19:11:42 comment added. Will explain in person too.
126 old_text_start_ = edit->old_text_start_;
127 delete_backward_ = false;
128
129 new_text_ = edit->new_text_;
130 new_text_start_ = edit->new_text_start_;
131 merge_type_ = DONT_MERGE;
132 }
102 133
103 Type type_; 134 Type type_;
104 135
105 // True if the edit can be marged. 136 // True if the edit can be marged.
106 bool mergeable_; 137 MergeType merge_type_;
138 // Old cursor position.
139 size_t old_cursor_pos_;
107 // Deleted text by this edit. 140 // Deleted text by this edit.
108 string16 old_text_; 141 string16 old_text_;
109 // The index of |old_text_|. 142 // The index of |old_text_|.
110 size_t old_text_start_; 143 size_t old_text_start_;
111 // True if the deletion is made backward. 144 // True if the deletion is made backward.
112 bool delete_backward_; 145 bool delete_backward_;
146 // New cursor position.
147 size_t new_cursor_pos_;
113 // Added text. 148 // Added text.
114 string16 new_text_; 149 string16 new_text_;
115 // The index of |new_text_| 150 // The index of |new_text_|
116 size_t new_text_start_; 151 size_t new_text_start_;
117 152
118 DISALLOW_COPY_AND_ASSIGN(Edit); 153 DISALLOW_COPY_AND_ASSIGN(Edit);
119 }; 154 };
120 155
121 class InsertEdit : public Edit { 156 class InsertEdit : public Edit {
122 public: 157 public:
123 InsertEdit(bool mergeable, const string16& new_text, size_t at) 158 InsertEdit(bool mergeable, const string16& new_text, size_t at)
124 : Edit(INSERT_EDIT, mergeable, string16(), at, false, new_text, at) { 159 : Edit(INSERT_EDIT,
160 mergeable ? MERGEABLE : DONT_MERGE,
161 at /* old cursor */,
162 string16(),
163 at,
164 false /* N/A */,
msw 2011/06/02 10:16:42 nit: the other comments are preceded by two spaces
oshima 2011/06/02 19:11:42 Done.
165 at + new_text.length() /* new cursor */,
166 new_text,
167 at) {
125 } 168 }
126 169
127 // Edit implementation. 170 // Edit implementation.
128 virtual bool DoMerge(Edit* edit) OVERRIDE { 171 virtual bool DoMerge(const Edit* edit) OVERRIDE {
129 if (edit->type() != INSERT_EDIT || new_text_end() != edit->new_text_start_) 172 if (edit->type() != INSERT_EDIT || new_text_end() != edit->new_text_start_)
130 return false; 173 return false;
131 // If continuous edit, merge it. 174 // If continuous edit, merge it.
132 // TODO(oshima): gtk splits edits between whitespace. Find out what 175 // TODO(oshima): gtk splits edits between whitespace. Find out what
133 // we want to here and implement if necessary. 176 // we want to here and implement if necessary.
134 new_text_ += edit->new_text_; 177 new_text_ += edit->new_text_;
178 new_cursor_pos_ = edit->new_cursor_pos_;
135 return true; 179 return true;
136 } 180 }
137 }; 181 };
138 182
139 class ReplaceEdit : public Edit { 183 class ReplaceEdit : public Edit {
140 public: 184 public:
141 ReplaceEdit(bool mergeable, 185 ReplaceEdit(MergeType merge_type,
142 const string16& old_text, 186 const string16& old_text,
187 size_t old_text_cursor,
msw 2011/06/02 10:16:42 nit: rename to |old_cursor_pos| to match base clas
oshima 2011/06/02 19:11:42 Done.
143 size_t old_text_start, 188 size_t old_text_start,
144 bool backward, 189 bool backward,
190 size_t new_text_cursor,
145 const string16& new_text, 191 const string16& new_text,
146 size_t new_text_start) 192 size_t new_text_start)
147 : Edit(REPLACE_EDIT, mergeable, 193 : Edit(REPLACE_EDIT, merge_type,
194 old_text_cursor,
148 old_text, 195 old_text,
149 old_text_start, 196 old_text_start,
150 backward, 197 backward,
198 new_text_cursor,
151 new_text, 199 new_text,
152 new_text_start) { 200 new_text_start) {
153 } 201 }
154 202
155 // Edit implementation. 203 // Edit implementation.
156 virtual bool DoMerge(Edit* edit) OVERRIDE { 204 virtual bool DoMerge(const Edit* edit) OVERRIDE {
157 if (edit->type() == DELETE_EDIT || 205 if (edit->type() == DELETE_EDIT ||
158 new_text_end() != edit->old_text_start_ || 206 new_text_end() != edit->old_text_start_ ||
159 edit->old_text_start_ != edit->new_text_start_) 207 edit->old_text_start_ != edit->new_text_start_)
160 return false; 208 return false;
161 old_text_ += edit->old_text_; 209 old_text_ += edit->old_text_;
162 new_text_ += edit->new_text_; 210 new_text_ += edit->new_text_;
211 new_cursor_pos_ = edit->new_cursor_pos_;
163 return true; 212 return true;
164 } 213 }
165 }; 214 };
166 215
167 class DeleteEdit : public Edit { 216 class DeleteEdit : public Edit {
168 public: 217 public:
169 DeleteEdit(bool mergeable, 218 DeleteEdit(bool mergeable,
170 const string16& text, 219 const string16& text,
171 size_t text_start, 220 size_t text_start,
172 bool backward) 221 bool backward)
173 : Edit(DELETE_EDIT, mergeable, 222 : Edit(DELETE_EDIT,
223 mergeable ? MERGEABLE : DONT_MERGE,
224 (backward ? text_start + text.length() : text_start),
174 text, 225 text,
175 text_start, 226 text_start,
176 backward, 227 backward,
228 text_start,
177 string16(), 229 string16(),
178 text_start) { 230 text_start) {
179 } 231 }
180 232
181 // Edit implementation. 233 // Edit implementation.
182 virtual bool DoMerge(Edit* edit) OVERRIDE { 234 virtual bool DoMerge(const Edit* edit) OVERRIDE {
183 if (edit->type() != DELETE_EDIT) 235 if (edit->type() != DELETE_EDIT)
184 return false; 236 return false;
185 237
186 if (delete_backward_) { 238 if (delete_backward_) {
187 // backspace can be merged only with backspace at the 239 // backspace can be merged only with backspace at the
188 // same position. 240 // same position.
189 if (!edit->delete_backward_ || old_text_start_ != edit->old_text_end()) 241 if (!edit->delete_backward_ || old_text_start_ != edit->old_text_end())
190 return false; 242 return false;
191 old_text_start_ = edit->old_text_start_; 243 old_text_start_ = edit->old_text_start_;
192 old_text_ = edit->old_text_ + old_text_; 244 old_text_ = edit->old_text_ + old_text_;
245 new_cursor_pos_ = edit->new_cursor_pos_;
193 } else { 246 } else {
194 // delete can be merged only with delete at the same 247 // delete can be merged only with delete at the same
195 // position. 248 // position.
196 if (edit->delete_backward_ || old_text_start_ != edit->old_text_start_) 249 if (edit->delete_backward_ || old_text_start_ != edit->old_text_start_)
197 return false; 250 return false;
198 old_text_ += edit->old_text_; 251 old_text_ += edit->old_text_;
199 } 252 }
200 return true; 253 return true;
201 } 254 }
202 }; 255 };
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
306 DCHECK(CheckInvariant(style_ranges)); 359 DCHECK(CheckInvariant(style_ranges));
307 #endif 360 #endif
308 } 361 }
309 362
310 } // namespace 363 } // namespace
311 364
312 using internal::Edit; 365 using internal::Edit;
313 using internal::DeleteEdit; 366 using internal::DeleteEdit;
314 using internal::InsertEdit; 367 using internal::InsertEdit;
315 using internal::ReplaceEdit; 368 using internal::ReplaceEdit;
369 using internal::MergeType;
370 using internal::DONT_MERGE;
371 using internal::MERGE_WITH_PREVIOUS;
372 using internal::MERGEABLE;
316 373
317 ///////////////////////////////////////////////////////////////// 374 /////////////////////////////////////////////////////////////////
318 // TextfieldViewsModel: public 375 // TextfieldViewsModel: public
319 376
320 TextfieldViewsModel::Delegate::~Delegate() { 377 TextfieldViewsModel::Delegate::~Delegate() {
321 } 378 }
322 379
323 TextfieldViewsModel::TextfieldViewsModel(Delegate* delegate) 380 TextfieldViewsModel::TextfieldViewsModel(Delegate* delegate)
324 : delegate_(delegate), 381 : delegate_(delegate),
325 cursor_pos_(0), 382 cursor_pos_(0),
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
388 fragments->push_back(TextFragment(current, end, kNormalStyle)); 445 fragments->push_back(TextFragment(current, end, kNormalStyle));
389 } 446 }
390 447
391 bool TextfieldViewsModel::SetText(const string16& text) { 448 bool TextfieldViewsModel::SetText(const string16& text) {
392 bool changed = false; 449 bool changed = false;
393 if (HasCompositionText()) { 450 if (HasCompositionText()) {
394 ConfirmCompositionText(); 451 ConfirmCompositionText();
395 changed = true; 452 changed = true;
396 } 453 }
397 if (text_ != text) { 454 if (text_ != text) {
398 if (changed) // no need to remember composition. 455 if (changed) // No need to remember composition.
399 Undo(); 456 Undo();
457 size_t old_cursor = cursor_pos_;
458 size_t new_cursor = old_cursor > text.length() ? text.length() : old_cursor;
400 SelectAll(); 459 SelectAll();
401 InsertTextInternal(text, false); 460 // If there is a composition text, don't merge with previous edit.
402 cursor_pos_ = 0; 461 // Otherwise, force merge the edits.
462 ExecuteAndRecordReplace(
463 changed ? DONT_MERGE : MERGE_WITH_PREVIOUS,
464 old_cursor,
465 new_cursor,
466 text,
467 0U);
468 cursor_pos_ = new_cursor;
403 } 469 }
404 ClearSelection(); 470 ClearSelection();
405 return changed; 471 return changed;
406 } 472 }
407 473
408 void TextfieldViewsModel::Append(const string16& text) { 474 void TextfieldViewsModel::Append(const string16& text) {
409 if (HasCompositionText()) 475 if (HasCompositionText())
410 ConfirmCompositionText(); 476 ConfirmCompositionText();
411 size_t save = cursor_pos_; 477 size_t save = cursor_pos_;
412 MoveCursorToEnd(false); 478 MoveCursorToEnd(false);
(...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after
660 } 726 }
661 727
662 bool TextfieldViewsModel::Undo() { 728 bool TextfieldViewsModel::Undo() {
663 if (!CanUndo()) 729 if (!CanUndo())
664 return false; 730 return false;
665 DCHECK(!HasCompositionText()); 731 DCHECK(!HasCompositionText());
666 if (HasCompositionText()) // safe guard for release build. 732 if (HasCompositionText()) // safe guard for release build.
667 CancelCompositionText(); 733 CancelCompositionText();
668 734
669 string16 old = text_; 735 string16 old = text_;
736 size_t old_cursor = cursor_pos_;
670 (*current_edit_)->Commit(); 737 (*current_edit_)->Commit();
671 (*current_edit_)->Undo(this); 738 (*current_edit_)->Undo(this);
672 739
673 if (current_edit_ == edit_history_.begin()) 740 if (current_edit_ == edit_history_.begin())
674 current_edit_ = edit_history_.end(); 741 current_edit_ = edit_history_.end();
675 else 742 else
676 current_edit_--; 743 current_edit_--;
677 return old != text_; 744 return old != text_ || old_cursor != cursor_pos_;
678 } 745 }
679 746
680 bool TextfieldViewsModel::Redo() { 747 bool TextfieldViewsModel::Redo() {
681 if (!CanRedo()) 748 if (!CanRedo())
682 return false; 749 return false;
683 DCHECK(!HasCompositionText()); 750 DCHECK(!HasCompositionText());
684 if (HasCompositionText()) // safe guard for release build. 751 if (HasCompositionText()) // safe guard for release build.
685 CancelCompositionText(); 752 CancelCompositionText();
686 753
687 if (current_edit_ == edit_history_.end()) 754 if (current_edit_ == edit_history_.end())
688 current_edit_ = edit_history_.begin(); 755 current_edit_ = edit_history_.begin();
689 else 756 else
690 current_edit_ ++; 757 current_edit_ ++;
691 string16 old = text_; 758 string16 old = text_;
759 size_t old_cursor = cursor_pos_;
692 (*current_edit_)->Redo(this); 760 (*current_edit_)->Redo(this);
693 return old != text_; 761 return old != text_ || old_cursor != cursor_pos_;
694 } 762 }
695 763
696 bool TextfieldViewsModel::Cut() { 764 bool TextfieldViewsModel::Cut() {
697 if (!HasCompositionText() && HasSelection()) { 765 if (!HasCompositionText() && HasSelection()) {
698 ui::ScopedClipboardWriter(views::ViewsDelegate::views_delegate 766 ui::ScopedClipboardWriter(views::ViewsDelegate::views_delegate
699 ->GetClipboard()).WriteText(GetSelectedText()); 767 ->GetClipboard()).WriteText(GetSelectedText());
768 // A trick to let undo/redo handle cursor correctly.
769 // Undoing CUT moves the cursor to the end of the change rather
770 // than beginning, unlike Delete/Backspace.
771 // TODO(oshima): Change Delete/Backspace to use DeleteSelection,
772 // update DeleteEdit and remove this trick.
773 std::swap(cursor_pos_, selection_start_);
700 DeleteSelection(); 774 DeleteSelection();
701 return true; 775 return true;
702 } 776 }
703 return false; 777 return false;
704 } 778 }
705 779
706 void TextfieldViewsModel::Copy() { 780 void TextfieldViewsModel::Copy() {
707 if (!HasCompositionText() && HasSelection()) { 781 if (!HasCompositionText() && HasSelection()) {
708 ui::ScopedClipboardWriter(views::ViewsDelegate::views_delegate 782 ui::ScopedClipboardWriter(views::ViewsDelegate::views_delegate
709 ->GetClipboard()).WriteText(GetSelectedText()); 783 ->GetClipboard()).WriteText(GetSelectedText());
(...skipping 18 matching lines...) Expand all
728 void TextfieldViewsModel::DeleteSelection() { 802 void TextfieldViewsModel::DeleteSelection() {
729 DCHECK(!HasCompositionText()); 803 DCHECK(!HasCompositionText());
730 DCHECK(HasSelection()); 804 DCHECK(HasSelection());
731 ExecuteAndRecordDelete(selection_start_, cursor_pos_, false); 805 ExecuteAndRecordDelete(selection_start_, cursor_pos_, false);
732 } 806 }
733 807
734 void TextfieldViewsModel::DeleteSelectionAndInsertTextAt( 808 void TextfieldViewsModel::DeleteSelectionAndInsertTextAt(
735 const string16& text, size_t position) { 809 const string16& text, size_t position) {
736 if (HasCompositionText()) 810 if (HasCompositionText())
737 CancelCompositionText(); 811 CancelCompositionText();
738 ExecuteAndRecordReplaceAt(text, position, false); 812 ExecuteAndRecordReplace(DONT_MERGE,
813 cursor_pos_,
814 position + text.length(),
815 text,
816 position);
739 } 817 }
740 818
741 string16 TextfieldViewsModel::GetTextFromRange(const ui::Range& range) const { 819 string16 TextfieldViewsModel::GetTextFromRange(const ui::Range& range) const {
742 if (range.IsValid() && range.GetMin() < text_.length()) 820 if (range.IsValid() && range.GetMin() < text_.length())
743 return text_.substr(range.GetMin(), range.length()); 821 return text_.substr(range.GetMin(), range.length());
744 return string16(); 822 return string16();
745 } 823 }
746 824
747 void TextfieldViewsModel::GetTextRange(ui::Range* range) const { 825 void TextfieldViewsModel::GetTextRange(ui::Range* range) const {
748 *range = ui::Range(0, text_.length()); 826 *range = ui::Range(0, text_.length());
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
872 } 950 }
873 return position; 951 return position;
874 } 952 }
875 953
876 void TextfieldViewsModel::InsertTextInternal(const string16& text, 954 void TextfieldViewsModel::InsertTextInternal(const string16& text,
877 bool mergeable) { 955 bool mergeable) {
878 if (HasCompositionText()) { 956 if (HasCompositionText()) {
879 CancelCompositionText(); 957 CancelCompositionText();
880 ExecuteAndRecordInsert(text, mergeable); 958 ExecuteAndRecordInsert(text, mergeable);
881 } else if (HasSelection()) { 959 } else if (HasSelection()) {
882 ExecuteAndRecordReplace(text, mergeable); 960 ExecuteAndRecordReplaceSelection(mergeable ? MERGEABLE : DONT_MERGE,
961 text);
883 } else { 962 } else {
884 ExecuteAndRecordInsert(text, mergeable); 963 ExecuteAndRecordInsert(text, mergeable);
885 } 964 }
886 } 965 }
887 966
888 void TextfieldViewsModel::ReplaceTextInternal(const string16& text, 967 void TextfieldViewsModel::ReplaceTextInternal(const string16& text,
889 bool mergeable) { 968 bool mergeable) {
890 if (HasCompositionText()) 969 if (HasCompositionText())
891 CancelCompositionText(); 970 CancelCompositionText();
892 else if (!HasSelection()) 971 else if (!HasSelection())
(...skipping 11 matching lines...) Expand all
904 983
905 void TextfieldViewsModel::ClearRedoHistory() { 984 void TextfieldViewsModel::ClearRedoHistory() {
906 if (edit_history_.begin() == edit_history_.end()) 985 if (edit_history_.begin() == edit_history_.end())
907 return; 986 return;
908 if (current_edit_ == edit_history_.end()) { 987 if (current_edit_ == edit_history_.end()) {
909 ClearEditHistory(); 988 ClearEditHistory();
910 return; 989 return;
911 } 990 }
912 EditHistory::iterator delete_start = current_edit_; 991 EditHistory::iterator delete_start = current_edit_;
913 delete_start++; 992 delete_start++;
914 STLDeleteContainerPointers(delete_start, 993 STLDeleteContainerPointers(delete_start, edit_history_.end());
915 edit_history_.end());
916 edit_history_.erase(delete_start, edit_history_.end()); 994 edit_history_.erase(delete_start, edit_history_.end());
917 } 995 }
918 996
919 void TextfieldViewsModel::ExecuteAndRecordDelete(size_t from, 997 void TextfieldViewsModel::ExecuteAndRecordDelete(size_t from,
920 size_t to, 998 size_t to,
921 bool mergeable) { 999 bool mergeable) {
922 size_t old_text_start = std::min(from, to); 1000 size_t old_text_start = std::min(from, to);
923 const string16 text = text_.substr(old_text_start, 1001 const string16 text = text_.substr(old_text_start,
924 std::abs(static_cast<long>(from - to))); 1002 std::abs(static_cast<long>(from - to)));
925 Edit* edit = new DeleteEdit(mergeable, 1003 bool backward = from > to;
926 text, 1004 Edit* edit = new DeleteEdit(mergeable, text, old_text_start, backward);
927 old_text_start,
928 (from > to));
929 bool delete_edit = AddOrMergeEditHistory(edit); 1005 bool delete_edit = AddOrMergeEditHistory(edit);
930 edit->Redo(this); 1006 edit->Redo(this);
931 if (delete_edit) 1007 if (delete_edit)
932 delete edit; 1008 delete edit;
933 } 1009 }
934 1010
935 void TextfieldViewsModel::ExecuteAndRecordReplace(const string16& text, 1011 void TextfieldViewsModel::ExecuteAndRecordReplaceSelection(
936 bool mergeable) { 1012 MergeType merge_type, const string16& new_text) {
msw 2011/06/02 10:16:42 nit: I think these parameters are supposed to go o
oshima 2011/06/02 19:11:42 This is allowed if all arguments fit to single lin
937 size_t at = std::min(cursor_pos_, selection_start_); 1013 size_t new_text_start = std::min(cursor_pos_, selection_start_);
938 ExecuteAndRecordReplaceAt(text, at, mergeable); 1014 size_t new_cursor_pos = at + text.length();
msw 2011/06/02 10:16:42 It looks like you need to update the |at| referenc
oshima 2011/06/02 19:11:42 Yes. sorry for typos.
1015 ExecuteAndRecordReplace(merge_type,
1016 cursor_pos_,
1017 new_cursor_pos,
1018 new_text,
1019 new_text_start);
939 } 1020 }
940 1021
941 void TextfieldViewsModel::ExecuteAndRecordReplaceAt(const string16& text, 1022 void TextfieldViewsModel::ExecuteAndRecordReplace(MergeType merge_type,
942 size_t at, 1023 size_t old_cursor_pos,
943 bool mergeable) { 1024 size_t new_cursor_pos,
944 size_t text_start = std::min(cursor_pos_, selection_start_); 1025 const string16& new_text,
945 Edit* edit = new ReplaceEdit(mergeable, 1026 size_t new_text_start) {
1027 size_t old_text_start = std::min(cursor_pos_, selection_start_);
1028 bool backward = selection_start_ > cursor_pos_;
1029 Edit* edit = new ReplaceEdit(merge_type,
946 GetSelectedText(), 1030 GetSelectedText(),
947 text_start, 1031 old_cursor_pos,
948 selection_start_ > cursor_pos_, 1032 old_text_start,
949 text, 1033 backward,
950 at); 1034 new_cursor_pos,
1035 new_text,
1036 new_text_start);
951 bool delete_edit = AddOrMergeEditHistory(edit); 1037 bool delete_edit = AddOrMergeEditHistory(edit);
952 edit->Redo(this); 1038 edit->Redo(this);
953 if (delete_edit) 1039 if (delete_edit)
954 delete edit; 1040 delete edit;
955 } 1041 }
956 1042
957 void TextfieldViewsModel::ExecuteAndRecordInsert(const string16& text, 1043 void TextfieldViewsModel::ExecuteAndRecordInsert(const string16& text,
958 bool mergeable) { 1044 bool mergeable) {
959 Edit* edit = new InsertEdit(mergeable, text, cursor_pos_); 1045 Edit* edit = new InsertEdit(mergeable, text, cursor_pos_);
960 bool delete_edit = AddOrMergeEditHistory(edit); 1046 bool delete_edit = AddOrMergeEditHistory(edit);
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
1001 } 1087 }
1002 1088
1003 // static 1089 // static
1004 TextStyle* TextfieldViewsModel::CreateUnderlineStyle() { 1090 TextStyle* TextfieldViewsModel::CreateUnderlineStyle() {
1005 TextStyle* style = new TextStyle(); 1091 TextStyle* style = new TextStyle();
1006 style->set_underline(true); 1092 style->set_underline(true);
1007 return style; 1093 return style;
1008 } 1094 }
1009 1095
1010 } // namespace views 1096 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698