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

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

Issue 135863002: Reland Merge NativeTextfieldViews into views::Textfield. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Handle Ctrl-Shift-Delete and Backspace on Linux, like on ChromeOS. Created 6 years, 11 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) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 288 matching lines...) Expand 10 before | Expand all | Expand 10 after
299 : delegate_(delegate), 299 : delegate_(delegate),
300 render_text_(gfx::RenderText::CreateInstance()), 300 render_text_(gfx::RenderText::CreateInstance()),
301 current_edit_(edit_history_.end()) { 301 current_edit_(edit_history_.end()) {
302 } 302 }
303 303
304 TextfieldViewsModel::~TextfieldViewsModel() { 304 TextfieldViewsModel::~TextfieldViewsModel() {
305 ClearEditHistory(); 305 ClearEditHistory();
306 ClearComposition(); 306 ClearComposition();
307 } 307 }
308 308
309 const base::string16& TextfieldViewsModel::GetText() const { 309 bool TextfieldViewsModel::SetText(const base::string16& new_text) {
310 return render_text_->text();
311 }
312
313 bool TextfieldViewsModel::SetText(const base::string16& text) {
314 bool changed = false; 310 bool changed = false;
315 if (HasCompositionText()) { 311 if (HasCompositionText()) {
316 ConfirmCompositionText(); 312 ConfirmCompositionText();
317 changed = true; 313 changed = true;
318 } 314 }
319 if (GetText() != text) { 315 if (text() != new_text) {
320 if (changed) // No need to remember composition. 316 if (changed) // No need to remember composition.
321 Undo(); 317 Undo();
322 size_t old_cursor = GetCursorPosition(); 318 size_t old_cursor = GetCursorPosition();
323 // SetText moves the cursor to the end. 319 // SetText moves the cursor to the end.
324 size_t new_cursor = text.length(); 320 size_t new_cursor = new_text.length();
325 SelectAll(false); 321 SelectAll(false);
326 // If there is a composition text, don't merge with previous edit. 322 // If there is a composition text, don't merge with previous edit.
327 // Otherwise, force merge the edits. 323 // Otherwise, force merge the edits.
328 ExecuteAndRecordReplace( 324 ExecuteAndRecordReplace(
329 changed ? DO_NOT_MERGE : MERGE_WITH_PREVIOUS, 325 changed ? DO_NOT_MERGE : MERGE_WITH_PREVIOUS,
330 old_cursor, 326 old_cursor,
331 new_cursor, 327 new_cursor,
332 text, 328 new_text,
333 0U); 329 0U);
334 render_text_->SetCursorPosition(new_cursor); 330 render_text_->SetCursorPosition(new_cursor);
335 } 331 }
336 ClearSelection(); 332 ClearSelection();
337 return changed; 333 return changed;
338 } 334 }
339 335
340 void TextfieldViewsModel::Append(const base::string16& text) { 336 void TextfieldViewsModel::Append(const base::string16& new_text) {
341 if (HasCompositionText()) 337 if (HasCompositionText())
342 ConfirmCompositionText(); 338 ConfirmCompositionText();
343 size_t save = GetCursorPosition(); 339 size_t save = GetCursorPosition();
344 MoveCursor(gfx::LINE_BREAK, 340 MoveCursor(gfx::LINE_BREAK,
345 render_text_->GetVisualDirectionOfLogicalEnd(), 341 render_text_->GetVisualDirectionOfLogicalEnd(),
346 false); 342 false);
347 InsertText(text); 343 InsertText(new_text);
348 render_text_->SetCursorPosition(save); 344 render_text_->SetCursorPosition(save);
349 ClearSelection(); 345 ClearSelection();
350 } 346 }
351 347
352 bool TextfieldViewsModel::Delete() { 348 bool TextfieldViewsModel::Delete() {
353 if (HasCompositionText()) { 349 if (HasCompositionText()) {
354 // No undo/redo for composition text. 350 // No undo/redo for composition text.
355 CancelCompositionText(); 351 CancelCompositionText();
356 return true; 352 return true;
357 } 353 }
358 if (HasSelection()) { 354 if (HasSelection()) {
359 DeleteSelection(); 355 DeleteSelection();
360 return true; 356 return true;
361 } 357 }
362 if (GetText().length() > GetCursorPosition()) { 358 if (text().length() > GetCursorPosition()) {
363 size_t cursor_position = GetCursorPosition(); 359 size_t cursor_position = GetCursorPosition();
364 size_t next_grapheme_index = render_text_->IndexOfAdjacentGrapheme( 360 size_t next_grapheme_index = render_text_->IndexOfAdjacentGrapheme(
365 cursor_position, gfx::CURSOR_FORWARD); 361 cursor_position, gfx::CURSOR_FORWARD);
366 ExecuteAndRecordDelete(gfx::Range(cursor_position, next_grapheme_index), 362 ExecuteAndRecordDelete(gfx::Range(cursor_position, next_grapheme_index),
367 true); 363 true);
368 return true; 364 return true;
369 } 365 }
370 return false; 366 return false;
371 } 367 }
372 368
373 bool TextfieldViewsModel::Backspace() { 369 bool TextfieldViewsModel::Backspace() {
374 if (HasCompositionText()) { 370 if (HasCompositionText()) {
375 // No undo/redo for composition text. 371 // No undo/redo for composition text.
376 CancelCompositionText(); 372 CancelCompositionText();
377 return true; 373 return true;
378 } 374 }
379 if (HasSelection()) { 375 if (HasSelection()) {
380 DeleteSelection(); 376 DeleteSelection();
381 return true; 377 return true;
382 } 378 }
383 size_t cursor_position = GetCursorPosition(); 379 size_t cursor_position = GetCursorPosition();
384 if (cursor_position > 0) { 380 if (cursor_position > 0) {
385 // Delete one code point, which may be two UTF-16 words. 381 // Delete one code point, which may be two UTF-16 words.
386 size_t previous_char = 382 size_t previous_char = gfx::UTF16OffsetToIndex(text(), cursor_position, -1);
387 gfx::UTF16OffsetToIndex(GetText(), cursor_position, -1);
388 ExecuteAndRecordDelete(gfx::Range(cursor_position, previous_char), true); 383 ExecuteAndRecordDelete(gfx::Range(cursor_position, previous_char), true);
389 return true; 384 return true;
390 } 385 }
391 return false; 386 return false;
392 } 387 }
393 388
394 size_t TextfieldViewsModel::GetCursorPosition() const { 389 size_t TextfieldViewsModel::GetCursorPosition() const {
395 return render_text_->cursor_position(); 390 return render_text_->cursor_position();
396 } 391 }
397 392
(...skipping 19 matching lines...) Expand all
417 return render_text_->MoveCursorTo(model); 412 return render_text_->MoveCursorTo(model);
418 } 413 }
419 414
420 bool TextfieldViewsModel::MoveCursorTo(const gfx::Point& point, bool select) { 415 bool TextfieldViewsModel::MoveCursorTo(const gfx::Point& point, bool select) {
421 if (HasCompositionText()) 416 if (HasCompositionText())
422 ConfirmCompositionText(); 417 ConfirmCompositionText();
423 return render_text_->MoveCursorTo(point, select); 418 return render_text_->MoveCursorTo(point, select);
424 } 419 }
425 420
426 base::string16 TextfieldViewsModel::GetSelectedText() const { 421 base::string16 TextfieldViewsModel::GetSelectedText() const {
427 return GetText().substr(render_text_->selection().GetMin(), 422 return text().substr(render_text_->selection().GetMin(),
428 render_text_->selection().length()); 423 render_text_->selection().length());
429 } 424 }
430 425
431 void TextfieldViewsModel::SelectRange(const gfx::Range& range) { 426 void TextfieldViewsModel::SelectRange(const gfx::Range& range) {
432 if (HasCompositionText()) 427 if (HasCompositionText())
433 ConfirmCompositionText(); 428 ConfirmCompositionText();
434 render_text_->SelectRange(range); 429 render_text_->SelectRange(range);
435 } 430 }
436 431
437 void TextfieldViewsModel::SelectSelectionModel(const gfx::SelectionModel& sel) { 432 void TextfieldViewsModel::SelectSelectionModel(const gfx::SelectionModel& sel) {
438 if (HasCompositionText()) 433 if (HasCompositionText())
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
472 ++iter != edit_history_.end(); 467 ++iter != edit_history_.end();
473 } 468 }
474 469
475 bool TextfieldViewsModel::Undo() { 470 bool TextfieldViewsModel::Undo() {
476 if (!CanUndo()) 471 if (!CanUndo())
477 return false; 472 return false;
478 DCHECK(!HasCompositionText()); 473 DCHECK(!HasCompositionText());
479 if (HasCompositionText()) // safe guard for release build. 474 if (HasCompositionText()) // safe guard for release build.
480 CancelCompositionText(); 475 CancelCompositionText();
481 476
482 base::string16 old = GetText(); 477 base::string16 old = text();
483 size_t old_cursor = GetCursorPosition(); 478 size_t old_cursor = GetCursorPosition();
484 (*current_edit_)->Commit(); 479 (*current_edit_)->Commit();
485 (*current_edit_)->Undo(this); 480 (*current_edit_)->Undo(this);
486 481
487 if (current_edit_ == edit_history_.begin()) 482 if (current_edit_ == edit_history_.begin())
488 current_edit_ = edit_history_.end(); 483 current_edit_ = edit_history_.end();
489 else 484 else
490 current_edit_--; 485 current_edit_--;
491 return old != GetText() || old_cursor != GetCursorPosition(); 486 return old != text() || old_cursor != GetCursorPosition();
492 } 487 }
493 488
494 bool TextfieldViewsModel::Redo() { 489 bool TextfieldViewsModel::Redo() {
495 if (!CanRedo()) 490 if (!CanRedo())
496 return false; 491 return false;
497 DCHECK(!HasCompositionText()); 492 DCHECK(!HasCompositionText());
498 if (HasCompositionText()) // safe guard for release build. 493 if (HasCompositionText()) // safe guard for release build.
499 CancelCompositionText(); 494 CancelCompositionText();
500 495
501 if (current_edit_ == edit_history_.end()) 496 if (current_edit_ == edit_history_.end())
502 current_edit_ = edit_history_.begin(); 497 current_edit_ = edit_history_.begin();
503 else 498 else
504 current_edit_ ++; 499 current_edit_ ++;
505 base::string16 old = GetText(); 500 base::string16 old = text();
506 size_t old_cursor = GetCursorPosition(); 501 size_t old_cursor = GetCursorPosition();
507 (*current_edit_)->Redo(this); 502 (*current_edit_)->Redo(this);
508 return old != GetText() || old_cursor != GetCursorPosition(); 503 return old != text() || old_cursor != GetCursorPosition();
509 } 504 }
510 505
511 bool TextfieldViewsModel::Cut() { 506 bool TextfieldViewsModel::Cut() {
512 if (!HasCompositionText() && HasSelection() && !render_text_->obscured()) { 507 if (!HasCompositionText() && HasSelection() && !render_text_->obscured()) {
513 ui::ScopedClipboardWriter( 508 ui::ScopedClipboardWriter(
514 ui::Clipboard::GetForCurrentThread(), 509 ui::Clipboard::GetForCurrentThread(),
515 ui::CLIPBOARD_TYPE_COPY_PASTE).WriteText(GetSelectedText()); 510 ui::CLIPBOARD_TYPE_COPY_PASTE).WriteText(GetSelectedText());
516 // A trick to let undo/redo handle cursor correctly. 511 // A trick to let undo/redo handle cursor correctly.
517 // Undoing CUT moves the cursor to the end of the change rather 512 // Undoing CUT moves the cursor to the end of the change rather
518 // than beginning, unlike Delete/Backspace. 513 // than beginning, unlike Delete/Backspace.
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
551 return !render_text_->selection().is_empty(); 546 return !render_text_->selection().is_empty();
552 } 547 }
553 548
554 void TextfieldViewsModel::DeleteSelection() { 549 void TextfieldViewsModel::DeleteSelection() {
555 DCHECK(!HasCompositionText()); 550 DCHECK(!HasCompositionText());
556 DCHECK(HasSelection()); 551 DCHECK(HasSelection());
557 ExecuteAndRecordDelete(render_text_->selection(), false); 552 ExecuteAndRecordDelete(render_text_->selection(), false);
558 } 553 }
559 554
560 void TextfieldViewsModel::DeleteSelectionAndInsertTextAt( 555 void TextfieldViewsModel::DeleteSelectionAndInsertTextAt(
561 const base::string16& text, size_t position) { 556 const base::string16& new_text,
557 size_t position) {
562 if (HasCompositionText()) 558 if (HasCompositionText())
563 CancelCompositionText(); 559 CancelCompositionText();
564 ExecuteAndRecordReplace(DO_NOT_MERGE, 560 ExecuteAndRecordReplace(DO_NOT_MERGE,
565 GetCursorPosition(), 561 GetCursorPosition(),
566 position + text.length(), 562 position + new_text.length(),
567 text, 563 new_text,
568 position); 564 position);
569 } 565 }
570 566
571 base::string16 TextfieldViewsModel::GetTextFromRange( 567 base::string16 TextfieldViewsModel::GetTextFromRange(
572 const gfx::Range& range) const { 568 const gfx::Range& range) const {
573 if (range.IsValid() && range.GetMin() < GetText().length()) 569 if (range.IsValid() && range.GetMin() < text().length())
574 return GetText().substr(range.GetMin(), range.length()); 570 return text().substr(range.GetMin(), range.length());
575 return base::string16(); 571 return base::string16();
576 } 572 }
577 573
578 void TextfieldViewsModel::GetTextRange(gfx::Range* range) const { 574 void TextfieldViewsModel::GetTextRange(gfx::Range* range) const {
579 *range = gfx::Range(0, GetText().length()); 575 *range = gfx::Range(0, text().length());
580 } 576 }
581 577
582 void TextfieldViewsModel::SetCompositionText( 578 void TextfieldViewsModel::SetCompositionText(
583 const ui::CompositionText& composition) { 579 const ui::CompositionText& composition) {
584 if (HasCompositionText()) 580 if (HasCompositionText())
585 CancelCompositionText(); 581 CancelCompositionText();
586 else if (HasSelection()) 582 else if (HasSelection())
587 DeleteSelection(); 583 DeleteSelection();
588 584
589 if (composition.text.empty()) 585 if (composition.text.empty())
590 return; 586 return;
591 587
592 size_t cursor = GetCursorPosition(); 588 size_t cursor = GetCursorPosition();
593 base::string16 new_text = GetText(); 589 base::string16 new_text = text();
594 render_text_->SetText(new_text.insert(cursor, composition.text)); 590 render_text_->SetText(new_text.insert(cursor, composition.text));
595 gfx::Range range(cursor, cursor + composition.text.length()); 591 gfx::Range range(cursor, cursor + composition.text.length());
596 render_text_->SetCompositionRange(range); 592 render_text_->SetCompositionRange(range);
597 gfx::Range emphasized_range = GetFirstEmphasizedRange(composition); 593 gfx::Range emphasized_range = GetFirstEmphasizedRange(composition);
598 if (emphasized_range.IsValid()) { 594 if (emphasized_range.IsValid()) {
599 // This is a workaround due to the lack of support in RenderText to draw 595 // This is a workaround due to the lack of support in RenderText to draw
600 // a thick underline. In a composition returned from an IME, the segment 596 // a thick underline. In a composition returned from an IME, the segment
601 // emphasized by a thick underline usually represents the target clause. 597 // emphasized by a thick underline usually represents the target clause.
602 // Because the target clause is more important than the actual selection 598 // Because the target clause is more important than the actual selection
603 // range (or caret position) in the composition here we use a selection-like 599 // range (or caret position) in the composition here we use a selection-like
604 // marker instead to show this range. 600 // marker instead to show this range.
605 // TODO(yukawa, msw): Support thick underline in RenderText and remove 601 // TODO(yukawa, msw): Support thick underline in RenderText and remove
606 // this workaround. 602 // this workaround.
607 render_text_->SelectRange(gfx::Range( 603 render_text_->SelectRange(gfx::Range(
608 cursor + emphasized_range.GetMin(), 604 cursor + emphasized_range.GetMin(),
609 cursor + emphasized_range.GetMax())); 605 cursor + emphasized_range.GetMax()));
610 } else if (!composition.selection.is_empty()) { 606 } else if (!composition.selection.is_empty()) {
611 render_text_->SelectRange(gfx::Range( 607 render_text_->SelectRange(gfx::Range(
612 cursor + composition.selection.GetMin(), 608 cursor + composition.selection.GetMin(),
613 cursor + composition.selection.GetMax())); 609 cursor + composition.selection.GetMax()));
614 } else { 610 } else {
615 render_text_->SetCursorPosition(cursor + composition.selection.end()); 611 render_text_->SetCursorPosition(cursor + composition.selection.end());
616 } 612 }
617 } 613 }
618 614
619 void TextfieldViewsModel::ConfirmCompositionText() { 615 void TextfieldViewsModel::ConfirmCompositionText() {
620 DCHECK(HasCompositionText()); 616 DCHECK(HasCompositionText());
621 gfx::Range range = render_text_->GetCompositionRange(); 617 gfx::Range range = render_text_->GetCompositionRange();
622 base::string16 text = GetText().substr(range.start(), range.length()); 618 base::string16 composition = text().substr(range.start(), range.length());
623 // TODO(oshima): current behavior on ChromeOS is a bit weird and not 619 // TODO(oshima): current behavior on ChromeOS is a bit weird and not
624 // sure exactly how this should work. Find out and fix if necessary. 620 // sure exactly how this should work. Find out and fix if necessary.
625 AddOrMergeEditHistory(new InsertEdit(false, text, range.start())); 621 AddOrMergeEditHistory(new InsertEdit(false, composition, range.start()));
626 render_text_->SetCursorPosition(range.end()); 622 render_text_->SetCursorPosition(range.end());
627 ClearComposition(); 623 ClearComposition();
628 if (delegate_) 624 if (delegate_)
629 delegate_->OnCompositionTextConfirmedOrCleared(); 625 delegate_->OnCompositionTextConfirmedOrCleared();
630 } 626 }
631 627
632 void TextfieldViewsModel::CancelCompositionText() { 628 void TextfieldViewsModel::CancelCompositionText() {
633 DCHECK(HasCompositionText()); 629 DCHECK(HasCompositionText());
634 gfx::Range range = render_text_->GetCompositionRange(); 630 gfx::Range range = render_text_->GetCompositionRange();
635 ClearComposition(); 631 ClearComposition();
636 base::string16 new_text = GetText(); 632 base::string16 new_text = text();
637 render_text_->SetText(new_text.erase(range.start(), range.length())); 633 render_text_->SetText(new_text.erase(range.start(), range.length()));
638 render_text_->SetCursorPosition(range.start()); 634 render_text_->SetCursorPosition(range.start());
639 if (delegate_) 635 if (delegate_)
640 delegate_->OnCompositionTextConfirmedOrCleared(); 636 delegate_->OnCompositionTextConfirmedOrCleared();
641 } 637 }
642 638
643 void TextfieldViewsModel::ClearComposition() { 639 void TextfieldViewsModel::ClearComposition() {
644 render_text_->SetCompositionRange(gfx::Range::InvalidRange()); 640 render_text_->SetCompositionRange(gfx::Range::InvalidRange());
645 } 641 }
646 642
647 void TextfieldViewsModel::GetCompositionTextRange(gfx::Range* range) const { 643 void TextfieldViewsModel::GetCompositionTextRange(gfx::Range* range) const {
648 *range = gfx::Range(render_text_->GetCompositionRange()); 644 *range = gfx::Range(render_text_->GetCompositionRange());
649 } 645 }
650 646
651 bool TextfieldViewsModel::HasCompositionText() const { 647 bool TextfieldViewsModel::HasCompositionText() const {
652 return !render_text_->GetCompositionRange().is_empty(); 648 return !render_text_->GetCompositionRange().is_empty();
653 } 649 }
654 650
651 void TextfieldViewsModel::ClearEditHistory() {
652 STLDeleteElements(&edit_history_);
653 current_edit_ = edit_history_.end();
654 }
655
655 ///////////////////////////////////////////////////////////////// 656 /////////////////////////////////////////////////////////////////
656 // TextfieldViewsModel: private 657 // TextfieldViewsModel: private
657 658
658 void TextfieldViewsModel::InsertTextInternal(const base::string16& text, 659 void TextfieldViewsModel::InsertTextInternal(const base::string16& new_text,
659 bool mergeable) { 660 bool mergeable) {
660 if (HasCompositionText()) { 661 if (HasCompositionText()) {
661 CancelCompositionText(); 662 CancelCompositionText();
662 ExecuteAndRecordInsert(text, mergeable); 663 ExecuteAndRecordInsert(new_text, mergeable);
663 } else if (HasSelection()) { 664 } else if (HasSelection()) {
664 ExecuteAndRecordReplaceSelection(mergeable ? MERGEABLE : DO_NOT_MERGE, 665 ExecuteAndRecordReplaceSelection(mergeable ? MERGEABLE : DO_NOT_MERGE,
665 text); 666 new_text);
666 } else { 667 } else {
667 ExecuteAndRecordInsert(text, mergeable); 668 ExecuteAndRecordInsert(new_text, mergeable);
668 } 669 }
669 } 670 }
670 671
671 void TextfieldViewsModel::ReplaceTextInternal(const base::string16& text, 672 void TextfieldViewsModel::ReplaceTextInternal(const base::string16& new_text,
672 bool mergeable) { 673 bool mergeable) {
673 if (HasCompositionText()) { 674 if (HasCompositionText()) {
674 CancelCompositionText(); 675 CancelCompositionText();
675 } else if (!HasSelection()) { 676 } else if (!HasSelection()) {
676 size_t cursor = GetCursorPosition(); 677 size_t cursor = GetCursorPosition();
677 const gfx::SelectionModel& model = render_text_->selection_model(); 678 const gfx::SelectionModel& model = render_text_->selection_model();
678 // When there is no selection, the default is to replace the next grapheme 679 // When there is no selection, the default is to replace the next grapheme
679 // with |text|. So, need to find the index of next grapheme first. 680 // with |new_text|. So, need to find the index of next grapheme first.
680 size_t next = 681 size_t next =
681 render_text_->IndexOfAdjacentGrapheme(cursor, gfx::CURSOR_FORWARD); 682 render_text_->IndexOfAdjacentGrapheme(cursor, gfx::CURSOR_FORWARD);
682 if (next == model.caret_pos()) 683 if (next == model.caret_pos())
683 render_text_->MoveCursorTo(model); 684 render_text_->MoveCursorTo(model);
684 else 685 else
685 render_text_->SelectRange(gfx::Range(next, model.caret_pos())); 686 render_text_->SelectRange(gfx::Range(next, model.caret_pos()));
686 } 687 }
687 // Edit history is recorded in InsertText. 688 // Edit history is recorded in InsertText.
688 InsertTextInternal(text, mergeable); 689 InsertTextInternal(new_text, mergeable);
689 }
690
691 void TextfieldViewsModel::ClearEditHistory() {
692 STLDeleteElements(&edit_history_);
693 current_edit_ = edit_history_.end();
694 } 690 }
695 691
696 void TextfieldViewsModel::ClearRedoHistory() { 692 void TextfieldViewsModel::ClearRedoHistory() {
697 if (edit_history_.begin() == edit_history_.end()) 693 if (edit_history_.begin() == edit_history_.end())
698 return; 694 return;
699 if (current_edit_ == edit_history_.end()) { 695 if (current_edit_ == edit_history_.end()) {
700 ClearEditHistory(); 696 ClearEditHistory();
701 return; 697 return;
702 } 698 }
703 EditHistory::iterator delete_start = current_edit_; 699 EditHistory::iterator delete_start = current_edit_;
704 delete_start++; 700 delete_start++;
705 STLDeleteContainerPointers(delete_start, edit_history_.end()); 701 STLDeleteContainerPointers(delete_start, edit_history_.end());
706 edit_history_.erase(delete_start, edit_history_.end()); 702 edit_history_.erase(delete_start, edit_history_.end());
707 } 703 }
708 704
709 void TextfieldViewsModel::ExecuteAndRecordDelete(gfx::Range range, 705 void TextfieldViewsModel::ExecuteAndRecordDelete(gfx::Range range,
710 bool mergeable) { 706 bool mergeable) {
711 size_t old_text_start = range.GetMin(); 707 size_t old_text_start = range.GetMin();
712 const base::string16 text = GetText().substr(old_text_start, range.length()); 708 const base::string16 old_text = text().substr(old_text_start, range.length());
713 bool backward = range.is_reversed(); 709 bool backward = range.is_reversed();
714 Edit* edit = new DeleteEdit(mergeable, text, old_text_start, backward); 710 Edit* edit = new DeleteEdit(mergeable, old_text, old_text_start, backward);
715 bool delete_edit = AddOrMergeEditHistory(edit); 711 bool delete_edit = AddOrMergeEditHistory(edit);
716 edit->Redo(this); 712 edit->Redo(this);
717 if (delete_edit) 713 if (delete_edit)
718 delete edit; 714 delete edit;
719 } 715 }
720 716
721 void TextfieldViewsModel::ExecuteAndRecordReplaceSelection( 717 void TextfieldViewsModel::ExecuteAndRecordReplaceSelection(
722 MergeType merge_type, const base::string16& new_text) { 718 MergeType merge_type,
719 const base::string16& new_text) {
723 size_t new_text_start = render_text_->selection().GetMin(); 720 size_t new_text_start = render_text_->selection().GetMin();
724 size_t new_cursor_pos = new_text_start + new_text.length(); 721 size_t new_cursor_pos = new_text_start + new_text.length();
725 ExecuteAndRecordReplace(merge_type, 722 ExecuteAndRecordReplace(merge_type,
726 GetCursorPosition(), 723 GetCursorPosition(),
727 new_cursor_pos, 724 new_cursor_pos,
728 new_text, 725 new_text,
729 new_text_start); 726 new_text_start);
730 } 727 }
731 728
732 void TextfieldViewsModel::ExecuteAndRecordReplace( 729 void TextfieldViewsModel::ExecuteAndRecordReplace(
(...skipping 11 matching lines...) Expand all
744 backward, 741 backward,
745 new_cursor_pos, 742 new_cursor_pos,
746 new_text, 743 new_text,
747 new_text_start); 744 new_text_start);
748 bool delete_edit = AddOrMergeEditHistory(edit); 745 bool delete_edit = AddOrMergeEditHistory(edit);
749 edit->Redo(this); 746 edit->Redo(this);
750 if (delete_edit) 747 if (delete_edit)
751 delete edit; 748 delete edit;
752 } 749 }
753 750
754 void TextfieldViewsModel::ExecuteAndRecordInsert(const base::string16& text, 751 void TextfieldViewsModel::ExecuteAndRecordInsert(const base::string16& new_text,
755 bool mergeable) { 752 bool mergeable) {
756 Edit* edit = new InsertEdit(mergeable, text, GetCursorPosition()); 753 Edit* edit = new InsertEdit(mergeable, new_text, GetCursorPosition());
757 bool delete_edit = AddOrMergeEditHistory(edit); 754 bool delete_edit = AddOrMergeEditHistory(edit);
758 edit->Redo(this); 755 edit->Redo(this);
759 if (delete_edit) 756 if (delete_edit)
760 delete edit; 757 delete edit;
761 } 758 }
762 759
763 bool TextfieldViewsModel::AddOrMergeEditHistory(Edit* edit) { 760 bool TextfieldViewsModel::AddOrMergeEditHistory(Edit* edit) {
764 ClearRedoHistory(); 761 ClearRedoHistory();
765 762
766 if (current_edit_ != edit_history_.end() && (*current_edit_)->Merge(edit)) { 763 if (current_edit_ != edit_history_.end() && (*current_edit_)->Merge(edit)) {
(...skipping 13 matching lines...) Expand all
780 } 777 }
781 return false; 778 return false;
782 } 779 }
783 780
784 void TextfieldViewsModel::ModifyText(size_t delete_from, 781 void TextfieldViewsModel::ModifyText(size_t delete_from,
785 size_t delete_to, 782 size_t delete_to,
786 const base::string16& new_text, 783 const base::string16& new_text,
787 size_t new_text_insert_at, 784 size_t new_text_insert_at,
788 size_t new_cursor_pos) { 785 size_t new_cursor_pos) {
789 DCHECK_LE(delete_from, delete_to); 786 DCHECK_LE(delete_from, delete_to);
790 base::string16 text = GetText(); 787 base::string16 old_text = text();
791 ClearComposition(); 788 ClearComposition();
792 if (delete_from != delete_to) 789 if (delete_from != delete_to)
793 render_text_->SetText(text.erase(delete_from, delete_to - delete_from)); 790 render_text_->SetText(old_text.erase(delete_from, delete_to - delete_from));
794 if (!new_text.empty()) 791 if (!new_text.empty())
795 render_text_->SetText(text.insert(new_text_insert_at, new_text)); 792 render_text_->SetText(old_text.insert(new_text_insert_at, new_text));
796 render_text_->SetCursorPosition(new_cursor_pos); 793 render_text_->SetCursorPosition(new_cursor_pos);
797 // TODO(oshima): mac selects the text that is just undone (but gtk doesn't). 794 // TODO(oshima): mac selects the text that is just undone (but gtk doesn't).
798 // This looks fine feature and we may want to do the same. 795 // This looks fine feature and we may want to do the same.
799 } 796 }
800 797
801 } // namespace views 798 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/controls/textfield/textfield_views_model.h ('k') | ui/views/controls/textfield/textfield_views_model_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698