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

Side by Side Diff: ui/views/controls/textfield/textfield_model.cc

Issue 1989893005: Undo selection. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 7 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
OLDNEW
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"
(...skipping 17 matching lines...) Expand all
28 enum Type { 28 enum Type {
29 INSERT_EDIT, 29 INSERT_EDIT,
30 DELETE_EDIT, 30 DELETE_EDIT,
31 REPLACE_EDIT, 31 REPLACE_EDIT,
32 }; 32 };
33 33
34 virtual ~Edit() {} 34 virtual ~Edit() {}
35 35
36 // Revert the change made by this edit in |model|. 36 // Revert the change made by this edit in |model|.
37 void Undo(TextfieldModel* model) { 37 void Undo(TextfieldModel* model) {
38
39 size_t selection_end = old_text_start_ + old_text_.length();
40 gfx::Range selection_range = delete_backward_ ? gfx::Range(selection_end, ol d_text_start_) : gfx::Range(old_text_start_, selection_end);
38 model->ModifyText(new_text_start_, new_text_end(), 41 model->ModifyText(new_text_start_, new_text_end(),
39 old_text_, old_text_start_, 42 old_text_, old_text_start_,
40 old_cursor_pos_); 43 selection_range);
41 } 44 }
42 45
43 // Apply the change of this edit to the |model|. 46 // Apply the change of this edit to the |model|.
44 void Redo(TextfieldModel* model) { 47 void Redo(TextfieldModel* model) {
45 model->ModifyText(old_text_start_, old_text_end(), 48 model->ModifyText(old_text_start_, old_text_end(),
46 new_text_, new_text_start_, 49 new_text_, new_text_start_,
47 new_cursor_pos_); 50 gfx::Range(new_cursor_pos_));
48 } 51 }
49 52
50 // Try to merge the |edit| into this edit and returns true on success. The 53 // Try to merge the |edit| into this edit and returns true on success. The
51 // merged edit will be deleted after redo and should not be reused. 54 // merged edit will be deleted after redo and should not be reused.
52 bool Merge(const Edit* edit) { 55 bool Merge(const Edit* edit) {
53 // Don't merge if previous edit is DELETE. This happens when a 56 // Don't merge if previous edit is DELETE. This happens when a
54 // user deletes characters then hits return. In this case, the 57 // user deletes characters then hits return. In this case, the
55 // delete should be treated as separate edit that can be undone 58 // delete should be treated as separate edit that can be undone
56 // and should not be merged with the replace edit. 59 // and should not be merged with the replace edit.
57 if (type_ != DELETE_EDIT && edit->force_merge()) { 60 if (type_ != DELETE_EDIT && edit->force_merge()) {
(...skipping 424 matching lines...) Expand 10 before | Expand all | Expand 10 after
482 base::string16 old = text(); 485 base::string16 old = text();
483 size_t old_cursor = GetCursorPosition(); 486 size_t old_cursor = GetCursorPosition();
484 (*current_edit_)->Redo(this); 487 (*current_edit_)->Redo(this);
485 return old != text() || old_cursor != GetCursorPosition(); 488 return old != text() || old_cursor != GetCursorPosition();
486 } 489 }
487 490
488 bool TextfieldModel::Cut() { 491 bool TextfieldModel::Cut() {
489 if (!HasCompositionText() && HasSelection() && !render_text_->obscured()) { 492 if (!HasCompositionText() && HasSelection() && !render_text_->obscured()) {
490 ui::ScopedClipboardWriter( 493 ui::ScopedClipboardWriter(
491 ui::CLIPBOARD_TYPE_COPY_PASTE).WriteText(GetSelectedText()); 494 ui::CLIPBOARD_TYPE_COPY_PASTE).WriteText(GetSelectedText());
492 // A trick to let undo/redo handle cursor correctly.
493 // Undoing CUT moves the cursor to the end of the change rather
494 // than beginning, unlike Delete/Backspace.
495 // TODO(oshima): Change Delete/Backspace to use DeleteSelection,
496 // update DeleteEdit and remove this trick.
497 const gfx::Range& selection = render_text_->selection();
498 render_text_->SelectRange(gfx::Range(selection.end(), selection.start()));
499 DeleteSelection(); 495 DeleteSelection();
500 return true; 496 return true;
501 } 497 }
502 return false; 498 return false;
503 } 499 }
504 500
505 bool TextfieldModel::Copy() { 501 bool TextfieldModel::Copy() {
506 if (!HasCompositionText() && HasSelection() && !render_text_->obscured()) { 502 if (!HasCompositionText() && HasSelection() && !render_text_->obscured()) {
507 ui::ScopedClipboardWriter( 503 ui::ScopedClipboardWriter(
508 ui::CLIPBOARD_TYPE_COPY_PASTE).WriteText(GetSelectedText()); 504 ui::CLIPBOARD_TYPE_COPY_PASTE).WriteText(GetSelectedText());
(...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after
761 } else { 757 } else {
762 current_edit_++; 758 current_edit_++;
763 } 759 }
764 return false; 760 return false;
765 } 761 }
766 762
767 void TextfieldModel::ModifyText(size_t delete_from, 763 void TextfieldModel::ModifyText(size_t delete_from,
768 size_t delete_to, 764 size_t delete_to,
769 const base::string16& new_text, 765 const base::string16& new_text,
770 size_t new_text_insert_at, 766 size_t new_text_insert_at,
771 size_t new_cursor_pos) { 767 gfx::Range selection_range) {
772 DCHECK_LE(delete_from, delete_to); 768 DCHECK_LE(delete_from, delete_to);
773 base::string16 old_text = text(); 769 base::string16 old_text = text();
774 ClearComposition(); 770 ClearComposition();
775 if (delete_from != delete_to) 771 if (delete_from != delete_to)
776 render_text_->SetText(old_text.erase(delete_from, delete_to - delete_from)); 772 render_text_->SetText(old_text.erase(delete_from, delete_to - delete_from));
777 if (!new_text.empty()) 773 if (!new_text.empty())
778 render_text_->SetText(old_text.insert(new_text_insert_at, new_text)); 774 render_text_->SetText(old_text.insert(new_text_insert_at, new_text));
779 render_text_->SetCursorPosition(new_cursor_pos); 775
780 // TODO(oshima): Select text that was just undone, like Mac (but not GTK). 776 // Both result in different caret affinities for an empty range with non 0
777 // position.
778 if(selection_range.is_empty())
779 render_text_->SetCursorPosition(selection_range.start());
780 else
781 render_text_->SelectRange(selection_range);
781 } 782 }
782 783
783 } // namespace views 784 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/controls/textfield/textfield_model.h ('k') | ui/views/controls/textfield/textfield_model_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698