Chromium Code Reviews| 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 "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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |