| OLD | NEW |
| 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" |
| 11 #include "base/stl_util.h" | 11 #include "base/stl_util.h" |
| 12 #include "base/utf_string_conversions.h" | 12 #include "base/utf_string_conversions.h" |
| 13 #include "ui/base/clipboard/clipboard.h" | 13 #include "ui/base/clipboard/clipboard.h" |
| 14 #include "ui/base/clipboard/scoped_clipboard_writer.h" | 14 #include "ui/base/clipboard/scoped_clipboard_writer.h" |
| 15 #include "ui/base/range/range.h" | 15 #include "ui/base/range/range.h" |
| 16 #include "ui/base/text/utf16_indexing.h" |
| 16 #include "ui/gfx/canvas.h" | 17 #include "ui/gfx/canvas.h" |
| 17 #include "ui/gfx/font.h" | 18 #include "ui/gfx/font.h" |
| 18 #include "ui/gfx/render_text.h" | 19 #include "ui/gfx/render_text.h" |
| 19 #include "ui/views/controls/textfield/textfield.h" | 20 #include "ui/views/controls/textfield/textfield.h" |
| 20 #include "ui/views/views_delegate.h" | 21 #include "ui/views/views_delegate.h" |
| 21 | 22 |
| 22 namespace views { | 23 namespace views { |
| 23 | 24 |
| 24 namespace internal { | 25 namespace internal { |
| 25 | 26 |
| (...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 354 bool TextfieldViewsModel::Backspace() { | 355 bool TextfieldViewsModel::Backspace() { |
| 355 if (HasCompositionText()) { | 356 if (HasCompositionText()) { |
| 356 // No undo/redo for composition text. | 357 // No undo/redo for composition text. |
| 357 CancelCompositionText(); | 358 CancelCompositionText(); |
| 358 return true; | 359 return true; |
| 359 } | 360 } |
| 360 if (HasSelection()) { | 361 if (HasSelection()) { |
| 361 DeleteSelection(); | 362 DeleteSelection(); |
| 362 return true; | 363 return true; |
| 363 } | 364 } |
| 364 if (GetCursorPosition() > 0) { | 365 size_t cursor_position = GetCursorPosition(); |
| 365 size_t cursor_position = GetCursorPosition(); | 366 if (cursor_position > 0) { |
| 366 ExecuteAndRecordDelete(cursor_position, cursor_position - 1, true); | 367 // Delete one code point, which may be two UTF-16 words. |
| 368 size_t previous_char = |
| 369 ui::UTF16OffsetToIndex(GetText(), cursor_position, -1); |
| 370 ExecuteAndRecordDelete(cursor_position, previous_char, true); |
| 367 return true; | 371 return true; |
| 368 } | 372 } |
| 369 return false; | 373 return false; |
| 370 } | 374 } |
| 371 | 375 |
| 372 size_t TextfieldViewsModel::GetCursorPosition() const { | 376 size_t TextfieldViewsModel::GetCursorPosition() const { |
| 373 return render_text_->GetCursorPosition(); | 377 return render_text_->GetCursorPosition(); |
| 374 } | 378 } |
| 375 | 379 |
| 376 void TextfieldViewsModel::MoveCursor(gfx::BreakType break_type, | 380 void TextfieldViewsModel::MoveCursor(gfx::BreakType break_type, |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 491 current_edit_ = edit_history_.begin(); | 495 current_edit_ = edit_history_.begin(); |
| 492 else | 496 else |
| 493 current_edit_ ++; | 497 current_edit_ ++; |
| 494 string16 old = GetText(); | 498 string16 old = GetText(); |
| 495 size_t old_cursor = GetCursorPosition(); | 499 size_t old_cursor = GetCursorPosition(); |
| 496 (*current_edit_)->Redo(this); | 500 (*current_edit_)->Redo(this); |
| 497 return old != GetText() || old_cursor != GetCursorPosition(); | 501 return old != GetText() || old_cursor != GetCursorPosition(); |
| 498 } | 502 } |
| 499 | 503 |
| 500 bool TextfieldViewsModel::Cut() { | 504 bool TextfieldViewsModel::Cut() { |
| 501 if (!HasCompositionText() && HasSelection()) { | 505 if (!HasCompositionText() && HasSelection() && !render_text_->is_obscured()) { |
| 502 ui::ScopedClipboardWriter( | 506 ui::ScopedClipboardWriter( |
| 503 views::ViewsDelegate::views_delegate->GetClipboard(), | 507 views::ViewsDelegate::views_delegate->GetClipboard(), |
| 504 ui::Clipboard::BUFFER_STANDARD).WriteText(GetSelectedText()); | 508 ui::Clipboard::BUFFER_STANDARD).WriteText(GetSelectedText()); |
| 505 // A trick to let undo/redo handle cursor correctly. | 509 // A trick to let undo/redo handle cursor correctly. |
| 506 // Undoing CUT moves the cursor to the end of the change rather | 510 // Undoing CUT moves the cursor to the end of the change rather |
| 507 // than beginning, unlike Delete/Backspace. | 511 // than beginning, unlike Delete/Backspace. |
| 508 // TODO(oshima): Change Delete/Backspace to use DeleteSelection, | 512 // TODO(oshima): Change Delete/Backspace to use DeleteSelection, |
| 509 // update DeleteEdit and remove this trick. | 513 // update DeleteEdit and remove this trick. |
| 510 render_text_->SelectRange(ui::Range(render_text_->GetCursorPosition(), | 514 render_text_->SelectRange(ui::Range(render_text_->GetCursorPosition(), |
| 511 render_text_->GetSelectionStart())); | 515 render_text_->GetSelectionStart())); |
| 512 DeleteSelection(); | 516 DeleteSelection(); |
| 513 return true; | 517 return true; |
| 514 } | 518 } |
| 515 return false; | 519 return false; |
| 516 } | 520 } |
| 517 | 521 |
| 518 bool TextfieldViewsModel::Copy() { | 522 bool TextfieldViewsModel::Copy() { |
| 519 if (!HasCompositionText() && HasSelection()) { | 523 if (!HasCompositionText() && HasSelection() && !render_text_->is_obscured()) { |
| 520 ui::ScopedClipboardWriter( | 524 ui::ScopedClipboardWriter( |
| 521 views::ViewsDelegate::views_delegate->GetClipboard(), | 525 views::ViewsDelegate::views_delegate->GetClipboard(), |
| 522 ui::Clipboard::BUFFER_STANDARD).WriteText(GetSelectedText()); | 526 ui::Clipboard::BUFFER_STANDARD).WriteText(GetSelectedText()); |
| 523 return true; | 527 return true; |
| 524 } | 528 } |
| 525 return false; | 529 return false; |
| 526 } | 530 } |
| 527 | 531 |
| 528 bool TextfieldViewsModel::Paste() { | 532 bool TextfieldViewsModel::Paste() { |
| 529 string16 result; | 533 string16 result; |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 776 if (delete_from != delete_to) | 780 if (delete_from != delete_to) |
| 777 render_text_->SetText(text.erase(delete_from, delete_to - delete_from)); | 781 render_text_->SetText(text.erase(delete_from, delete_to - delete_from)); |
| 778 if (!new_text.empty()) | 782 if (!new_text.empty()) |
| 779 render_text_->SetText(text.insert(new_text_insert_at, new_text)); | 783 render_text_->SetText(text.insert(new_text_insert_at, new_text)); |
| 780 render_text_->SetCursorPosition(new_cursor_pos); | 784 render_text_->SetCursorPosition(new_cursor_pos); |
| 781 // TODO(oshima): mac selects the text that is just undone (but gtk doesn't). | 785 // TODO(oshima): mac selects the text that is just undone (but gtk doesn't). |
| 782 // This looks fine feature and we may want to do the same. | 786 // This looks fine feature and we may want to do the same. |
| 783 } | 787 } |
| 784 | 788 |
| 785 } // namespace views | 789 } // namespace views |
| OLD | NEW |