Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 244 old_text_ += edit->old_text_; | 244 old_text_ += edit->old_text_; |
| 245 } | 245 } |
| 246 return true; | 246 return true; |
| 247 } | 247 } |
| 248 }; | 248 }; |
| 249 | 249 |
| 250 } // namespace internal | 250 } // namespace internal |
| 251 | 251 |
| 252 namespace { | 252 namespace { |
| 253 | 253 |
| 254 // Buffer containing the text to be inserted on executing yank command. This | |
| 255 // is a singleton since it needs to be persisted across multiple textfields. | |
| 256 // On Mac, the size of the kill ring (no. of buffers) is controlled by | |
| 257 // NSTextKillRingSize, a text system default. However to keep things simple, | |
| 258 // the default kill ring size of 1 (i.e. a single buffer) is assumed. | |
| 259 base::string16 g_kill_buffer_; | |
|
tapted
2016/07/06 01:46:37
This will add a static initializer, which isn't al
karandeepb
2016/07/19 07:04:40
Added as a member of ViewsDelegate.
| |
| 260 | |
| 254 // Returns the first segment that is visually emphasized. Usually it's used for | 261 // Returns the first segment that is visually emphasized. Usually it's used for |
| 255 // representing the target clause (on Windows). Returns an invalid range if | 262 // representing the target clause (on Windows). Returns an invalid range if |
| 256 // there is no such a range. | 263 // there is no such a range. |
| 257 gfx::Range GetFirstEmphasizedRange(const ui::CompositionText& composition) { | 264 gfx::Range GetFirstEmphasizedRange(const ui::CompositionText& composition) { |
| 258 for (size_t i = 0; i < composition.underlines.size(); ++i) { | 265 for (size_t i = 0; i < composition.underlines.size(); ++i) { |
| 259 const ui::CompositionUnderline& underline = composition.underlines[i]; | 266 const ui::CompositionUnderline& underline = composition.underlines[i]; |
| 260 if (underline.thick) | 267 if (underline.thick) |
| 261 return gfx::Range(underline.start_offset, underline.end_offset); | 268 return gfx::Range(underline.start_offset, underline.end_offset); |
| 262 } | 269 } |
| 263 return gfx::Range::InvalidRange(); | 270 return gfx::Range::InvalidRange(); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 318 ConfirmCompositionText(); | 325 ConfirmCompositionText(); |
| 319 size_t save = GetCursorPosition(); | 326 size_t save = GetCursorPosition(); |
| 320 MoveCursor(gfx::LINE_BREAK, | 327 MoveCursor(gfx::LINE_BREAK, |
| 321 render_text_->GetVisualDirectionOfLogicalEnd(), | 328 render_text_->GetVisualDirectionOfLogicalEnd(), |
| 322 false); | 329 false); |
| 323 InsertText(new_text); | 330 InsertText(new_text); |
| 324 render_text_->SetCursorPosition(save); | 331 render_text_->SetCursorPosition(save); |
| 325 ClearSelection(); | 332 ClearSelection(); |
| 326 } | 333 } |
| 327 | 334 |
| 328 bool TextfieldModel::Delete() { | 335 bool TextfieldModel::Delete(bool add_to_kill_buffer) { |
| 329 if (HasCompositionText()) { | 336 if (HasCompositionText()) { |
| 330 // No undo/redo for composition text. | 337 // No undo/redo for composition text. |
| 331 CancelCompositionText(); | 338 CancelCompositionText(); |
| 332 return true; | 339 return true; |
| 333 } | 340 } |
| 334 if (HasSelection()) { | 341 if (HasSelection()) { |
| 342 if (add_to_kill_buffer) | |
| 343 g_kill_buffer_ = GetSelectedText(); | |
| 335 DeleteSelection(); | 344 DeleteSelection(); |
| 336 return true; | 345 return true; |
| 337 } | 346 } |
| 338 if (text().length() > GetCursorPosition()) { | 347 if (text().length() > GetCursorPosition()) { |
| 339 size_t cursor_position = GetCursorPosition(); | 348 size_t cursor_position = GetCursorPosition(); |
| 340 size_t next_grapheme_index = render_text_->IndexOfAdjacentGrapheme( | 349 size_t next_grapheme_index = render_text_->IndexOfAdjacentGrapheme( |
| 341 cursor_position, gfx::CURSOR_FORWARD); | 350 cursor_position, gfx::CURSOR_FORWARD); |
| 342 ExecuteAndRecordDelete(gfx::Range(cursor_position, next_grapheme_index), | 351 gfx::Range range_to_delete(cursor_position, next_grapheme_index); |
| 343 true); | 352 if (add_to_kill_buffer) |
| 353 g_kill_buffer_ = GetTextFromRange(range_to_delete); | |
| 354 ExecuteAndRecordDelete(range_to_delete, true); | |
| 344 return true; | 355 return true; |
| 345 } | 356 } |
| 346 return false; | 357 return false; |
| 347 } | 358 } |
| 348 | 359 |
| 349 bool TextfieldModel::Backspace() { | 360 bool TextfieldModel::Backspace(bool add_to_kill_buffer) { |
| 350 if (HasCompositionText()) { | 361 if (HasCompositionText()) { |
| 351 // No undo/redo for composition text. | 362 // No undo/redo for composition text. |
| 352 CancelCompositionText(); | 363 CancelCompositionText(); |
| 353 return true; | 364 return true; |
| 354 } | 365 } |
| 355 if (HasSelection()) { | 366 if (HasSelection()) { |
| 367 if (add_to_kill_buffer) | |
| 368 g_kill_buffer_ = GetSelectedText(); | |
| 356 DeleteSelection(); | 369 DeleteSelection(); |
| 357 return true; | 370 return true; |
| 358 } | 371 } |
| 359 size_t cursor_position = GetCursorPosition(); | 372 size_t cursor_position = GetCursorPosition(); |
| 360 if (cursor_position > 0) { | 373 if (cursor_position > 0) { |
| 361 // Delete one code point, which may be two UTF-16 words. | 374 // Delete one code point, which may be two UTF-16 words. |
| 362 size_t previous_char = gfx::UTF16OffsetToIndex(text(), cursor_position, -1); | 375 size_t previous_char = gfx::UTF16OffsetToIndex(text(), cursor_position, -1); |
| 363 ExecuteAndRecordDelete(gfx::Range(cursor_position, previous_char), true); | 376 gfx::Range range_to_delete(cursor_position, previous_char); |
| 377 if (add_to_kill_buffer) | |
| 378 g_kill_buffer_ = GetTextFromRange(range_to_delete); | |
| 379 ExecuteAndRecordDelete(range_to_delete, true); | |
| 364 return true; | 380 return true; |
| 365 } | 381 } |
| 366 return false; | 382 return false; |
| 367 } | 383 } |
| 368 | 384 |
| 369 size_t TextfieldModel::GetCursorPosition() const { | 385 size_t TextfieldModel::GetCursorPosition() const { |
| 370 return render_text_->cursor_position(); | 386 return render_text_->cursor_position(); |
| 371 } | 387 } |
| 372 | 388 |
| 373 void TextfieldModel::MoveCursor(gfx::BreakType break_type, | 389 void TextfieldModel::MoveCursor(gfx::BreakType break_type, |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 550 | 566 |
| 551 SelectRange(gfx::Range(prev, next)); | 567 SelectRange(gfx::Range(prev, next)); |
| 552 base::string16 text = GetSelectedText(); | 568 base::string16 text = GetSelectedText(); |
| 553 base::string16 transposed_text = | 569 base::string16 transposed_text = |
| 554 text.substr(cur - prev) + text.substr(0, cur - prev); | 570 text.substr(cur - prev) + text.substr(0, cur - prev); |
| 555 | 571 |
| 556 InsertTextInternal(transposed_text, false); | 572 InsertTextInternal(transposed_text, false); |
| 557 return true; | 573 return true; |
| 558 } | 574 } |
| 559 | 575 |
| 576 bool TextfieldModel::Yank() { | |
| 577 if (!g_kill_buffer_.empty() || HasSelection()) { | |
| 578 InsertTextInternal(g_kill_buffer_, false); | |
| 579 return true; | |
| 580 } | |
| 581 return false; | |
| 582 } | |
| 583 | |
| 560 bool TextfieldModel::HasSelection() const { | 584 bool TextfieldModel::HasSelection() const { |
| 561 return !render_text_->selection().is_empty(); | 585 return !render_text_->selection().is_empty(); |
| 562 } | 586 } |
| 563 | 587 |
| 564 void TextfieldModel::DeleteSelection() { | 588 void TextfieldModel::DeleteSelection() { |
| 565 DCHECK(!HasCompositionText()); | 589 DCHECK(!HasCompositionText()); |
| 566 DCHECK(HasSelection()); | 590 DCHECK(HasSelection()); |
| 567 ExecuteAndRecordDelete(render_text_->selection(), false); | 591 ExecuteAndRecordDelete(render_text_->selection(), false); |
| 568 } | 592 } |
| 569 | 593 |
| (...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 804 ClearComposition(); | 828 ClearComposition(); |
| 805 if (delete_from != delete_to) | 829 if (delete_from != delete_to) |
| 806 render_text_->SetText(old_text.erase(delete_from, delete_to - delete_from)); | 830 render_text_->SetText(old_text.erase(delete_from, delete_to - delete_from)); |
| 807 if (!new_text.empty()) | 831 if (!new_text.empty()) |
| 808 render_text_->SetText(old_text.insert(new_text_insert_at, new_text)); | 832 render_text_->SetText(old_text.insert(new_text_insert_at, new_text)); |
| 809 render_text_->SetCursorPosition(new_cursor_pos); | 833 render_text_->SetCursorPosition(new_cursor_pos); |
| 810 // TODO(oshima): Select text that was just undone, like Mac (but not GTK). | 834 // TODO(oshima): Select text that was just undone, like Mac (but not GTK). |
| 811 } | 835 } |
| 812 | 836 |
| 813 } // namespace views | 837 } // namespace views |
| OLD | NEW |