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

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

Issue 9467017: Password support for NativeTextfieldViews, in the model (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 10 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
« no previous file with comments | « ui/views/controls/textfield/textfield_views_model.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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"
11 #include "base/stl_util.h" 11 #include "base/stl_util.h"
12 #include "base/utf_offset_string_conversions.h"
12 #include "base/utf_string_conversions.h" 13 #include "base/utf_string_conversions.h"
13 #include "ui/base/clipboard/clipboard.h" 14 #include "ui/base/clipboard/clipboard.h"
14 #include "ui/base/clipboard/scoped_clipboard_writer.h" 15 #include "ui/base/clipboard/scoped_clipboard_writer.h"
15 #include "ui/base/range/range.h" 16 #include "ui/base/range/range.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
27 // All chars are replaced by this char when the password style is set.
28 // TODO(benrg): GTK uses the first of U+25CF, U+2022, U+2731, U+273A, '*'
29 // that's available in the font (find_invisible_char() in gtkentry.c).
30 const char16 kPasswordReplacementChar = '*';
31
26 // An edit object holds enough information/state to undo/redo the 32 // An edit object holds enough information/state to undo/redo the
27 // change. Two edits are merged when possible, for example, when 33 // change. Two edits are merged when possible, for example, when
28 // you type new characters in sequence. |Commit()| can be used to 34 // you type new characters in sequence. |Commit()| can be used to
29 // mark an edit as an independent edit and it shouldn't be merged. 35 // mark an edit as an independent edit and it shouldn't be merged.
30 // (For example, when you did undo/redo, or a text is appended via 36 // (For example, when you did undo/redo, or a text is appended via
31 // API) 37 // API)
32 class Edit { 38 class Edit {
33 public: 39 public:
34 enum Type { 40 enum Type {
35 INSERT_EDIT, 41 INSERT_EDIT,
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after
282 : delegate_(delegate), 288 : delegate_(delegate),
283 render_text_(gfx::RenderText::CreateRenderText()), 289 render_text_(gfx::RenderText::CreateRenderText()),
284 current_edit_(edit_history_.end()) { 290 current_edit_(edit_history_.end()) {
285 } 291 }
286 292
287 TextfieldViewsModel::~TextfieldViewsModel() { 293 TextfieldViewsModel::~TextfieldViewsModel() {
288 ClearEditHistory(); 294 ClearEditHistory();
289 ClearComposition(); 295 ClearComposition();
290 } 296 }
291 297
292 const string16& TextfieldViewsModel::GetText() const {
293 return render_text_->text();
294 }
295
296 bool TextfieldViewsModel::SetText(const string16& text) { 298 bool TextfieldViewsModel::SetText(const string16& text) {
297 bool changed = false; 299 bool changed = false;
298 if (HasCompositionText()) { 300 if (HasCompositionText()) {
299 ConfirmCompositionText(); 301 ConfirmCompositionText();
300 changed = true; 302 changed = true;
301 } 303 }
302 if (GetText() != text) { 304 if (GetText() != text) {
303 if (changed) // No need to remember composition. 305 if (changed) // No need to remember composition.
304 Undo(); 306 Undo();
305 size_t old_cursor = GetCursorPosition(); 307 size_t old_cursor = GetCursorPosition();
306 size_t new_cursor = old_cursor > text.length() ? text.length() : old_cursor; 308 size_t new_cursor = old_cursor > text.length() ? text.length() : old_cursor;
307 SelectAll(); 309 SelectAll();
308 // If there is a composition text, don't merge with previous edit. 310 // If there is a composition text, don't merge with previous edit.
309 // Otherwise, force merge the edits. 311 // Otherwise, force merge the edits.
310 ExecuteAndRecordReplace( 312 ExecuteAndRecordReplace(
311 changed ? DO_NOT_MERGE : MERGE_WITH_PREVIOUS, 313 changed ? DO_NOT_MERGE : MERGE_WITH_PREVIOUS,
312 old_cursor, 314 old_cursor,
313 new_cursor, 315 new_cursor,
314 text, 316 text,
315 0U); 317 0U);
316 render_text_->SetCursorPosition(new_cursor); 318 render_text_->SetCursorPosition(ToDisplayIndex(new_cursor));
317 } 319 }
318 ClearSelection(); 320 ClearSelection();
319 return changed; 321 return changed;
320 } 322 }
321 323
324 void TextfieldViewsModel::SetObscured(bool obscured) {
325 if (obscured != obscured_) {
326 obscured_ = obscured;
327 render_text_->SetText(GetDisplayText());
328 }
329 }
330
322 void TextfieldViewsModel::Append(const string16& text) { 331 void TextfieldViewsModel::Append(const string16& text) {
323 if (HasCompositionText()) 332 if (HasCompositionText())
324 ConfirmCompositionText(); 333 ConfirmCompositionText();
325 size_t save = GetCursorPosition(); 334 size_t save = render_text_->GetCursorPosition();
326 MoveCursor(gfx::LINE_BREAK, 335 MoveCursor(gfx::LINE_BREAK,
327 render_text_->GetVisualDirectionOfLogicalEnd(), 336 render_text_->GetVisualDirectionOfLogicalEnd(),
328 false); 337 false);
329 InsertText(text); 338 InsertText(text);
330 render_text_->SetCursorPosition(save); 339 render_text_->SetCursorPosition(save);
331 ClearSelection(); 340 ClearSelection();
332 } 341 }
333 342
334 bool TextfieldViewsModel::Delete() { 343 bool TextfieldViewsModel::Delete() {
335 if (HasCompositionText()) { 344 if (HasCompositionText()) {
336 // No undo/redo for composition text. 345 // No undo/redo for composition text.
337 CancelCompositionText(); 346 CancelCompositionText();
338 return true; 347 return true;
339 } 348 }
340 if (HasSelection()) { 349 if (HasSelection()) {
341 DeleteSelection(); 350 DeleteSelection();
342 return true; 351 return true;
343 } 352 }
344 if (GetText().length() > GetCursorPosition()) { 353 if (GetText().length() > GetCursorPosition()) {
345 size_t cursor_position = GetCursorPosition(); 354 size_t cursor_position = GetCursorPosition();
346 size_t next_grapheme_index = render_text_->IndexOfAdjacentGrapheme( 355 size_t next_grapheme_index =
347 cursor_position, gfx::CURSOR_FORWARD); 356 FromDisplayIndex(render_text_->IndexOfAdjacentGrapheme(
357 ToDisplayIndex(cursor_position), gfx::CURSOR_FORWARD));
348 ExecuteAndRecordDelete(cursor_position, next_grapheme_index, true); 358 ExecuteAndRecordDelete(cursor_position, next_grapheme_index, true);
349 return true; 359 return true;
350 } 360 }
351 return false; 361 return false;
352 } 362 }
353 363
354 bool TextfieldViewsModel::Backspace() { 364 bool TextfieldViewsModel::Backspace() {
355 if (HasCompositionText()) { 365 if (HasCompositionText()) {
356 // No undo/redo for composition text. 366 // No undo/redo for composition text.
357 CancelCompositionText(); 367 CancelCompositionText();
358 return true; 368 return true;
359 } 369 }
360 if (HasSelection()) { 370 if (HasSelection()) {
361 DeleteSelection(); 371 DeleteSelection();
362 return true; 372 return true;
363 } 373 }
364 if (GetCursorPosition() > 0) { 374 size_t cursor_position = GetCursorPosition();
365 size_t cursor_position = GetCursorPosition(); 375 if (cursor_position > 0) {
366 ExecuteAndRecordDelete(cursor_position, cursor_position - 1, true); 376 size_t previous_char = Utf16OffsetToIndex(GetText(), cursor_position, -1);
377 ExecuteAndRecordDelete(cursor_position, previous_char, true);
367 return true; 378 return true;
368 } 379 }
369 return false; 380 return false;
370 } 381 }
371 382
372 size_t TextfieldViewsModel::GetCursorPosition() const { 383 size_t TextfieldViewsModel::GetCursorPosition() const {
373 return render_text_->GetCursorPosition(); 384 return FromDisplayIndex(render_text_->GetCursorPosition());
374 } 385 }
375 386
376 void TextfieldViewsModel::MoveCursor(gfx::BreakType break_type, 387 void TextfieldViewsModel::MoveCursor(gfx::BreakType break_type,
377 gfx::VisualCursorDirection direction, 388 gfx::VisualCursorDirection direction,
378 bool select) { 389 bool select) {
379 if (HasCompositionText()) 390 if (HasCompositionText())
380 ConfirmCompositionText(); 391 ConfirmCompositionText();
381 render_text_->MoveCursor(break_type, direction, select); 392 render_text_->MoveCursor(break_type, direction, select);
382 } 393 }
383 394
384 bool TextfieldViewsModel::MoveCursorTo(const gfx::SelectionModel& selection) { 395 bool TextfieldViewsModel::MoveCursorTo(const gfx::SelectionModel& sel) {
396 gfx::SelectionModel selection = ToDisplaySelection(sel);
385 if (HasCompositionText()) { 397 if (HasCompositionText()) {
386 ConfirmCompositionText(); 398 ConfirmCompositionText();
387 // ConfirmCompositionText() updates cursor position. Need to reflect it in 399 // ConfirmCompositionText() updates cursor position. Need to reflect it in
388 // the SelectionModel parameter of MoveCursorTo(). 400 // the SelectionModel parameter of MoveCursorTo().
389 if (render_text_->GetSelectionStart() != selection.selection_end()) 401 if (render_text_->GetSelectionStart() != selection.selection_end())
390 return render_text_->SelectRange(ui::Range( 402 return render_text_->SelectRange(ui::Range(
391 render_text_->GetSelectionStart(), selection.selection_end())); 403 render_text_->GetSelectionStart(), selection.selection_end()));
392 gfx::SelectionModel sel(selection.selection_end(), 404 gfx::SelectionModel sel(selection.selection_end(),
393 selection.caret_pos(), 405 selection.caret_pos(),
394 selection.caret_placement()); 406 selection.caret_placement());
395 return render_text_->MoveCursorTo(sel); 407 return render_text_->MoveCursorTo(sel);
396 } 408 }
397 return render_text_->MoveCursorTo(selection); 409 return render_text_->MoveCursorTo(selection);
398 } 410 }
399 411
400 bool TextfieldViewsModel::MoveCursorTo(const gfx::Point& point, bool select) { 412 bool TextfieldViewsModel::MoveCursorTo(const gfx::Point& point, bool select) {
401 if (HasCompositionText()) 413 if (HasCompositionText())
402 ConfirmCompositionText(); 414 ConfirmCompositionText();
403 return render_text_->MoveCursorTo(point, select); 415 return render_text_->MoveCursorTo(point, select);
404 } 416 }
405 417
406 string16 TextfieldViewsModel::GetSelectedText() const { 418 string16 TextfieldViewsModel::GetSelectedText() const {
407 return GetText().substr(render_text_->MinOfSelection(), 419 size_t lo = FromDisplayIndex(render_text_->MinOfSelection());
408 (render_text_->MaxOfSelection() - render_text_->MinOfSelection())); 420 size_t hi = FromDisplayIndex(render_text_->MaxOfSelection());
421 return GetText().substr(lo, hi - lo);
409 } 422 }
410 423
411 void TextfieldViewsModel::GetSelectedRange(ui::Range* range) const { 424 void TextfieldViewsModel::GetSelectedRange(ui::Range* range) const {
412 range->set_start(render_text_->GetSelectionStart()); 425 *range = FromDisplayRange(ui::Range(
413 range->set_end(render_text_->GetCursorPosition()); 426 render_text_->GetSelectionStart(), render_text_->GetCursorPosition()));
414 } 427 }
415 428
416 void TextfieldViewsModel::SelectRange(const ui::Range& range) { 429 void TextfieldViewsModel::SelectRange(const ui::Range& range) {
417 if (HasCompositionText()) 430 if (HasCompositionText())
418 ConfirmCompositionText(); 431 ConfirmCompositionText();
419 render_text_->SelectRange(range); 432 render_text_->SelectRange(ToDisplayRange(range));
420 } 433 }
421 434
422 void TextfieldViewsModel::GetSelectionModel(gfx::SelectionModel* sel) const { 435 void TextfieldViewsModel::GetSelectionModel(gfx::SelectionModel* sel) const {
423 *sel = render_text_->selection_model(); 436 *sel = FromDisplaySelection(render_text_->selection_model());
424 } 437 }
425 438
426 void TextfieldViewsModel::SelectSelectionModel(const gfx::SelectionModel& sel) { 439 void TextfieldViewsModel::SelectSelectionModel(const gfx::SelectionModel& sel) {
427 if (HasCompositionText()) 440 if (HasCompositionText())
428 ConfirmCompositionText(); 441 ConfirmCompositionText();
429 render_text_->MoveCursorTo(sel); 442 render_text_->MoveCursorTo(ToDisplaySelection(sel));
430 } 443 }
431 444
432 void TextfieldViewsModel::SelectAll() { 445 void TextfieldViewsModel::SelectAll() {
433 if (HasCompositionText()) 446 if (HasCompositionText())
434 ConfirmCompositionText(); 447 ConfirmCompositionText();
435 render_text_->SelectAll(); 448 render_text_->SelectAll();
436 } 449 }
437 450
438 void TextfieldViewsModel::SelectWord() { 451 void TextfieldViewsModel::SelectWord() {
439 if (HasCompositionText()) 452 if (HasCompositionText())
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
491 current_edit_ = edit_history_.begin(); 504 current_edit_ = edit_history_.begin();
492 else 505 else
493 current_edit_ ++; 506 current_edit_ ++;
494 string16 old = GetText(); 507 string16 old = GetText();
495 size_t old_cursor = GetCursorPosition(); 508 size_t old_cursor = GetCursorPosition();
496 (*current_edit_)->Redo(this); 509 (*current_edit_)->Redo(this);
497 return old != GetText() || old_cursor != GetCursorPosition(); 510 return old != GetText() || old_cursor != GetCursorPosition();
498 } 511 }
499 512
500 bool TextfieldViewsModel::Cut() { 513 bool TextfieldViewsModel::Cut() {
501 if (!HasCompositionText() && HasSelection()) { 514 if (!HasCompositionText() && HasSelection() && !is_obscured()) {
502 ui::ScopedClipboardWriter(views::ViewsDelegate::views_delegate 515 ui::ScopedClipboardWriter(views::ViewsDelegate::views_delegate
503 ->GetClipboard()).WriteText(GetSelectedText()); 516 ->GetClipboard()).WriteText(GetSelectedText());
504 // A trick to let undo/redo handle cursor correctly. 517 // A trick to let undo/redo handle cursor correctly.
505 // Undoing CUT moves the cursor to the end of the change rather 518 // Undoing CUT moves the cursor to the end of the change rather
506 // than beginning, unlike Delete/Backspace. 519 // than beginning, unlike Delete/Backspace.
507 // TODO(oshima): Change Delete/Backspace to use DeleteSelection, 520 // TODO(oshima): Change Delete/Backspace to use DeleteSelection,
508 // update DeleteEdit and remove this trick. 521 // update DeleteEdit and remove this trick.
509 render_text_->SelectRange(ui::Range(render_text_->GetCursorPosition(), 522 render_text_->SelectRange(ui::Range(render_text_->GetCursorPosition(),
510 render_text_->GetSelectionStart())); 523 render_text_->GetSelectionStart()));
511 DeleteSelection(); 524 DeleteSelection();
512 return true; 525 return true;
513 } 526 }
514 return false; 527 return false;
515 } 528 }
516 529
517 bool TextfieldViewsModel::Copy() { 530 bool TextfieldViewsModel::Copy() {
518 if (!HasCompositionText() && HasSelection()) { 531 if (!HasCompositionText() && HasSelection() && !is_obscured()) {
519 ui::ScopedClipboardWriter(views::ViewsDelegate::views_delegate 532 ui::ScopedClipboardWriter(views::ViewsDelegate::views_delegate
520 ->GetClipboard()).WriteText(GetSelectedText()); 533 ->GetClipboard()).WriteText(GetSelectedText());
521 return true; 534 return true;
522 } 535 }
523 return false; 536 return false;
524 } 537 }
525 538
526 bool TextfieldViewsModel::Paste() { 539 bool TextfieldViewsModel::Paste() {
527 string16 result; 540 string16 result;
528 views::ViewsDelegate::views_delegate->GetClipboard() 541 views::ViewsDelegate::views_delegate->GetClipboard()
529 ->ReadText(ui::Clipboard::BUFFER_STANDARD, &result); 542 ->ReadText(ui::Clipboard::BUFFER_STANDARD, &result);
530 if (!result.empty()) { 543 if (!result.empty()) {
531 InsertTextInternal(result, false); 544 InsertTextInternal(result, false);
532 return true; 545 return true;
533 } 546 }
534 return false; 547 return false;
535 } 548 }
536 549
537 bool TextfieldViewsModel::HasSelection() const { 550 bool TextfieldViewsModel::HasSelection() const {
538 return !render_text_->EmptySelection(); 551 return !render_text_->EmptySelection();
539 } 552 }
540 553
541 void TextfieldViewsModel::DeleteSelection() { 554 void TextfieldViewsModel::DeleteSelection() {
542 DCHECK(!HasCompositionText()); 555 DCHECK(!HasCompositionText());
543 DCHECK(HasSelection()); 556 DCHECK(HasSelection());
544 ExecuteAndRecordDelete(render_text_->GetSelectionStart(), 557 ExecuteAndRecordDelete(FromDisplayIndex(render_text_->GetSelectionStart()),
545 render_text_->GetCursorPosition(), false); 558 FromDisplayIndex(render_text_->GetCursorPosition()),
559 false);
546 } 560 }
547 561
548 void TextfieldViewsModel::DeleteSelectionAndInsertTextAt( 562 void TextfieldViewsModel::DeleteSelectionAndInsertTextAt(
549 const string16& text, size_t position) { 563 const string16& text, size_t position) {
550 if (HasCompositionText()) 564 if (HasCompositionText())
551 CancelCompositionText(); 565 CancelCompositionText();
552 ExecuteAndRecordReplace(DO_NOT_MERGE, 566 ExecuteAndRecordReplace(DO_NOT_MERGE,
553 GetCursorPosition(), 567 GetCursorPosition(),
554 position + text.length(), 568 position + text.length(),
555 text, 569 text,
(...skipping 15 matching lines...) Expand all
571 if (HasCompositionText()) 585 if (HasCompositionText())
572 CancelCompositionText(); 586 CancelCompositionText();
573 else if (HasSelection()) 587 else if (HasSelection())
574 DeleteSelection(); 588 DeleteSelection();
575 589
576 if (composition.text.empty()) 590 if (composition.text.empty())
577 return; 591 return;
578 592
579 size_t cursor = GetCursorPosition(); 593 size_t cursor = GetCursorPosition();
580 string16 new_text = GetText(); 594 string16 new_text = GetText();
581 render_text_->SetText(new_text.insert(cursor, composition.text)); 595 SetTextInternal(new_text.insert(cursor, composition.text));
582 ui::Range range(cursor, cursor + composition.text.length()); 596 ui::Range range(cursor, cursor + composition.text.length());
583 render_text_->SetCompositionRange(range); 597 render_text_->SetCompositionRange(ToDisplayRange(range));
584 // TODO(msw): Support multiple composition underline ranges. 598 // TODO(msw): Support multiple composition underline ranges.
585 599
586 if (composition.selection.IsValid()) { 600 if (composition.selection.IsValid()) {
587 size_t start = 601 size_t start =
588 std::min(range.start() + composition.selection.start(), range.end()); 602 std::min(range.start() + composition.selection.start(), range.end());
589 size_t end = 603 size_t end =
590 std::min(range.start() + composition.selection.end(), range.end()); 604 std::min(range.start() + composition.selection.end(), range.end());
591 render_text_->SelectRange(ui::Range(start, end)); 605 render_text_->SelectRange(ToDisplayRange(ui::Range(start, end)));
592 } else { 606 } else {
593 render_text_->SetCursorPosition(range.end()); 607 render_text_->SetCursorPosition(ToDisplayIndex(range.end()));
594 } 608 }
595 } 609 }
596 610
597 void TextfieldViewsModel::ConfirmCompositionText() { 611 void TextfieldViewsModel::ConfirmCompositionText() {
598 DCHECK(HasCompositionText()); 612 DCHECK(HasCompositionText());
599 ui::Range range = render_text_->GetCompositionRange(); 613 ui::Range range = FromDisplayRange(render_text_->GetCompositionRange());
600 string16 text = GetText().substr(range.start(), range.length()); 614 string16 text = GetText().substr(range.start(), range.length());
601 // TODO(oshima): current behavior on ChromeOS is a bit weird and not 615 // TODO(oshima): current behavior on ChromeOS is a bit weird and not
602 // sure exactly how this should work. Find out and fix if necessary. 616 // sure exactly how this should work. Find out and fix if necessary.
603 AddOrMergeEditHistory(new InsertEdit(false, text, range.start())); 617 AddOrMergeEditHistory(new InsertEdit(false, text, range.start()));
604 render_text_->SetCursorPosition(range.end()); 618 render_text_->SetCursorPosition(ToDisplayIndex(range.end()));
605 ClearComposition(); 619 ClearComposition();
606 if (delegate_) 620 if (delegate_)
607 delegate_->OnCompositionTextConfirmedOrCleared(); 621 delegate_->OnCompositionTextConfirmedOrCleared();
608 } 622 }
609 623
610 void TextfieldViewsModel::CancelCompositionText() { 624 void TextfieldViewsModel::CancelCompositionText() {
611 DCHECK(HasCompositionText()); 625 DCHECK(HasCompositionText());
612 ui::Range range = render_text_->GetCompositionRange(); 626 ui::Range range = FromDisplayRange(render_text_->GetCompositionRange());
613 ClearComposition(); 627 ClearComposition();
614 string16 new_text = GetText(); 628 string16 new_text = GetText();
615 render_text_->SetText(new_text.erase(range.start(), range.length())); 629 SetTextInternal(new_text.erase(range.start(), range.length()));
616 render_text_->SetCursorPosition(range.start()); 630 render_text_->SetCursorPosition(ToDisplayIndex(range.start()));
617 if (delegate_) 631 if (delegate_)
618 delegate_->OnCompositionTextConfirmedOrCleared(); 632 delegate_->OnCompositionTextConfirmedOrCleared();
619 } 633 }
620 634
621 void TextfieldViewsModel::ClearComposition() { 635 void TextfieldViewsModel::ClearComposition() {
622 render_text_->SetCompositionRange(ui::Range::InvalidRange()); 636 render_text_->SetCompositionRange(ui::Range::InvalidRange());
623 } 637 }
624 638
625 void TextfieldViewsModel::GetCompositionTextRange(ui::Range* range) const { 639 void TextfieldViewsModel::GetCompositionTextRange(ui::Range* range) const {
626 *range = ui::Range(render_text_->GetCompositionRange()); 640 *range = ui::Range(FromDisplayRange(render_text_->GetCompositionRange()));
627 } 641 }
628 642
629 bool TextfieldViewsModel::HasCompositionText() const { 643 bool TextfieldViewsModel::HasCompositionText() const {
630 return !render_text_->GetCompositionRange().is_empty(); 644 return !render_text_->GetCompositionRange().is_empty();
631 } 645 }
632 646
633 ///////////////////////////////////////////////////////////////// 647 /////////////////////////////////////////////////////////////////
634 // TextfieldViewsModel: private 648 // TextfieldViewsModel: private
635 649
636 void TextfieldViewsModel::InsertTextInternal(const string16& text, 650 void TextfieldViewsModel::InsertTextInternal(const string16& text,
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
695 bool backward = from > to; 709 bool backward = from > to;
696 Edit* edit = new DeleteEdit(mergeable, text, old_text_start, backward); 710 Edit* edit = new DeleteEdit(mergeable, text, old_text_start, backward);
697 bool delete_edit = AddOrMergeEditHistory(edit); 711 bool delete_edit = AddOrMergeEditHistory(edit);
698 edit->Redo(this); 712 edit->Redo(this);
699 if (delete_edit) 713 if (delete_edit)
700 delete edit; 714 delete edit;
701 } 715 }
702 716
703 void TextfieldViewsModel::ExecuteAndRecordReplaceSelection( 717 void TextfieldViewsModel::ExecuteAndRecordReplaceSelection(
704 MergeType merge_type, const string16& new_text) { 718 MergeType merge_type, const string16& new_text) {
705 size_t new_text_start = render_text_->MinOfSelection(); 719 size_t new_text_start = FromDisplayIndex(render_text_->MinOfSelection());
706 size_t new_cursor_pos = new_text_start + new_text.length(); 720 size_t new_cursor_pos = new_text_start + new_text.length();
707 ExecuteAndRecordReplace(merge_type, 721 ExecuteAndRecordReplace(merge_type,
708 GetCursorPosition(), 722 GetCursorPosition(),
709 new_cursor_pos, 723 new_cursor_pos,
710 new_text, 724 new_text,
711 new_text_start); 725 new_text_start);
712 } 726 }
713 727
714 void TextfieldViewsModel::ExecuteAndRecordReplace(MergeType merge_type, 728 void TextfieldViewsModel::ExecuteAndRecordReplace(MergeType merge_type,
715 size_t old_cursor_pos, 729 size_t old_cursor_pos,
716 size_t new_cursor_pos, 730 size_t new_cursor_pos,
717 const string16& new_text, 731 const string16& new_text,
718 size_t new_text_start) { 732 size_t new_text_start) {
719 size_t old_text_start = render_text_->MinOfSelection(); 733 size_t old_text_start = FromDisplayIndex(render_text_->MinOfSelection());
720 bool backward = 734 bool backward =
721 render_text_->GetSelectionStart() > render_text_->GetCursorPosition(); 735 render_text_->GetSelectionStart() > render_text_->GetCursorPosition();
722 Edit* edit = new ReplaceEdit(merge_type, 736 Edit* edit = new ReplaceEdit(merge_type,
723 GetSelectedText(), 737 GetSelectedText(),
724 old_cursor_pos, 738 old_cursor_pos,
725 old_text_start, 739 old_text_start,
726 backward, 740 backward,
727 new_cursor_pos, 741 new_cursor_pos,
728 new_text, 742 new_text,
729 new_text_start); 743 new_text_start);
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
765 779
766 void TextfieldViewsModel::ModifyText(size_t delete_from, 780 void TextfieldViewsModel::ModifyText(size_t delete_from,
767 size_t delete_to, 781 size_t delete_to,
768 const string16& new_text, 782 const string16& new_text,
769 size_t new_text_insert_at, 783 size_t new_text_insert_at,
770 size_t new_cursor_pos) { 784 size_t new_cursor_pos) {
771 DCHECK_LE(delete_from, delete_to); 785 DCHECK_LE(delete_from, delete_to);
772 string16 text = GetText(); 786 string16 text = GetText();
773 ClearComposition(); 787 ClearComposition();
774 if (delete_from != delete_to) 788 if (delete_from != delete_to)
775 render_text_->SetText(text.erase(delete_from, delete_to - delete_from)); 789 SetTextInternal(text.erase(delete_from, delete_to - delete_from));
776 if (!new_text.empty()) 790 if (!new_text.empty())
777 render_text_->SetText(text.insert(new_text_insert_at, new_text)); 791 SetTextInternal(text.insert(new_text_insert_at, new_text));
778 render_text_->SetCursorPosition(new_cursor_pos); 792 render_text_->SetCursorPosition(ToDisplayIndex(new_cursor_pos));
779 // TODO(oshima): mac selects the text that is just undone (but gtk doesn't). 793 // TODO(oshima): mac selects the text that is just undone (but gtk doesn't).
780 // This looks fine feature and we may want to do the same. 794 // This looks fine feature and we may want to do the same.
781 } 795 }
782 796
797 void TextfieldViewsModel::SetTextInternal(const string16& new_text) {
798 text_ = new_text;
799 render_text_->SetText(GetDisplayText());
800 }
801
802 string16 TextfieldViewsModel::GetDisplayText() const {
803 if (!obscured_)
804 return text_;
805 size_t obscured_text_length =
806 static_cast<size_t>(Utf16IndexToOffset(text_, 0, text_.length()));
807 return string16(obscured_text_length, internal::kPasswordReplacementChar);
808 }
809
810 size_t TextfieldViewsModel::FromDisplayIndex(size_t index) const {
811 if (!is_obscured())
812 return index;
813 return Utf16OffsetToIndex(GetText(), 0, index);
814 }
815 size_t TextfieldViewsModel::ToDisplayIndex(size_t index) const {
816 if (!is_obscured())
817 return index;
818 return Utf16IndexToOffset(GetText(), 0, index);
819 }
820 ui::Range TextfieldViewsModel::FromDisplayRange(ui::Range range) const {
821 if (!is_obscured() || !range.IsValid())
822 return range;
823 return ui::Range(FromDisplayIndex(range.start()),
824 FromDisplayIndex(range.end()));
825 }
826 ui::Range TextfieldViewsModel::ToDisplayRange(ui::Range range) const {
827 if (!is_obscured() || !range.IsValid())
828 return range;
829 return ui::Range(ToDisplayIndex(range.start()),
830 ToDisplayIndex(range.end()));
831 }
832 gfx::SelectionModel TextfieldViewsModel::FromDisplaySelection(
833 const gfx::SelectionModel& model) const {
834 return gfx::SelectionModel(FromDisplayIndex(model.selection_start()),
835 FromDisplayIndex(model.selection_end()),
836 FromDisplayIndex(model.caret_pos()),
837 model.caret_placement());
838 }
839 gfx::SelectionModel TextfieldViewsModel::ToDisplaySelection(
840 const gfx::SelectionModel& model) const {
841 return gfx::SelectionModel(ToDisplayIndex(model.selection_start()),
842 ToDisplayIndex(model.selection_end()),
843 ToDisplayIndex(model.caret_pos()),
844 model.caret_placement());
845 }
846
783 } // namespace views 847 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/controls/textfield/textfield_views_model.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698