| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "views/controls/textfield/native_textfield_views.h" | 5 #include "views/controls/textfield/native_textfield_views.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 79 SetContextMenuController(this); | 79 SetContextMenuController(this); |
| 80 } | 80 } |
| 81 | 81 |
| 82 NativeTextfieldViews::~NativeTextfieldViews() { | 82 NativeTextfieldViews::~NativeTextfieldViews() { |
| 83 } | 83 } |
| 84 | 84 |
| 85 //////////////////////////////////////////////////////////////////////////////// | 85 //////////////////////////////////////////////////////////////////////////////// |
| 86 // NativeTextfieldViews, View overrides: | 86 // NativeTextfieldViews, View overrides: |
| 87 | 87 |
| 88 bool NativeTextfieldViews::OnMousePressed(const views::MouseEvent& e) { | 88 bool NativeTextfieldViews::OnMousePressed(const views::MouseEvent& e) { |
| 89 OnBeforeUserAction(); |
| 89 if (HandleMousePressed(e)) | 90 if (HandleMousePressed(e)) |
| 90 SchedulePaint(); | 91 SchedulePaint(); |
| 92 OnAfterUserAction(); |
| 91 return true; | 93 return true; |
| 92 } | 94 } |
| 93 | 95 |
| 94 bool NativeTextfieldViews::OnMouseDragged(const views::MouseEvent& e) { | 96 bool NativeTextfieldViews::OnMouseDragged(const views::MouseEvent& e) { |
| 97 OnBeforeUserAction(); |
| 95 size_t pos = FindCursorPosition(e.location()); | 98 size_t pos = FindCursorPosition(e.location()); |
| 96 if (model_->MoveCursorTo(pos, true)) { | 99 if (model_->MoveCursorTo(pos, true)) { |
| 97 UpdateCursorBoundsAndTextOffset(); | 100 UpdateCursorBoundsAndTextOffset(); |
| 98 SchedulePaint(); | 101 SchedulePaint(); |
| 99 } | 102 } |
| 103 OnAfterUserAction(); |
| 100 return true; | 104 return true; |
| 101 } | 105 } |
| 102 | 106 |
| 103 void NativeTextfieldViews::OnMouseReleased(const views::MouseEvent& e, | 107 void NativeTextfieldViews::OnMouseReleased(const views::MouseEvent& e, |
| 104 bool canceled) { | 108 bool canceled) { |
| 105 } | 109 } |
| 106 | 110 |
| 107 bool NativeTextfieldViews::OnKeyPressed(const views::KeyEvent& e) { | 111 bool NativeTextfieldViews::OnKeyPressed(const views::KeyEvent& e) { |
| 108 // OnKeyPressed/OnKeyReleased/OnFocus/OnBlur will never be invoked on | 112 // OnKeyPressed/OnKeyReleased/OnFocus/OnBlur will never be invoked on |
| 109 // NativeTextfieldViews as it will never gain focus. | 113 // NativeTextfieldViews as it will never gain focus. |
| (...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 353 } | 357 } |
| 354 | 358 |
| 355 bool NativeTextfieldViews::GetAcceleratorForCommandId(int command_id, | 359 bool NativeTextfieldViews::GetAcceleratorForCommandId(int command_id, |
| 356 ui::Accelerator* accelerator) { | 360 ui::Accelerator* accelerator) { |
| 357 return false; | 361 return false; |
| 358 } | 362 } |
| 359 | 363 |
| 360 void NativeTextfieldViews::ExecuteCommand(int command_id) { | 364 void NativeTextfieldViews::ExecuteCommand(int command_id) { |
| 361 bool text_changed = false; | 365 bool text_changed = false; |
| 362 bool editable = !textfield_->read_only(); | 366 bool editable = !textfield_->read_only(); |
| 367 OnBeforeUserAction(); |
| 363 switch (command_id) { | 368 switch (command_id) { |
| 364 case IDS_APP_CUT: | 369 case IDS_APP_CUT: |
| 365 if (editable) | 370 if (editable) |
| 366 text_changed = model_->Cut(); | 371 text_changed = model_->Cut(); |
| 367 break; | 372 break; |
| 368 case IDS_APP_COPY: | 373 case IDS_APP_COPY: |
| 369 model_->Copy(); | 374 model_->Copy(); |
| 370 break; | 375 break; |
| 371 case IDS_APP_PASTE: | 376 case IDS_APP_PASTE: |
| 372 if (editable) | 377 if (editable) |
| 373 text_changed = model_->Paste(); | 378 text_changed = model_->Paste(); |
| 374 break; | 379 break; |
| 375 case IDS_APP_DELETE: | 380 case IDS_APP_DELETE: |
| 376 if (editable) | 381 if (editable) |
| 377 text_changed = model_->Delete(); | 382 text_changed = model_->Delete(); |
| 378 break; | 383 break; |
| 379 case IDS_APP_SELECT_ALL: | 384 case IDS_APP_SELECT_ALL: |
| 380 SelectAll(); | 385 SelectAll(); |
| 381 break; | 386 break; |
| 382 default: | 387 default: |
| 383 NOTREACHED() << "unknown command: " << command_id; | 388 NOTREACHED() << "unknown command: " << command_id; |
| 384 break; | 389 break; |
| 385 } | 390 } |
| 386 | 391 |
| 387 // The cursor must have changed if text changed during cut/paste/delete. | 392 // The cursor must have changed if text changed during cut/paste/delete. |
| 388 UpdateAfterChange(text_changed, text_changed); | 393 UpdateAfterChange(text_changed, text_changed); |
| 394 OnAfterUserAction(); |
| 389 } | 395 } |
| 390 | 396 |
| 391 // static | 397 // static |
| 392 bool NativeTextfieldViews::IsTextfieldViewsEnabled() { | 398 bool NativeTextfieldViews::IsTextfieldViewsEnabled() { |
| 393 #if defined(TOUCH_UI) | 399 #if defined(TOUCH_UI) |
| 394 return true; | 400 return true; |
| 395 #else | 401 #else |
| 396 return textfield_view_enabled || | 402 return textfield_view_enabled || |
| 397 CommandLine::ForCurrentProcess()->HasSwitch( | 403 CommandLine::ForCurrentProcess()->HasSwitch( |
| 398 kEnableViewsBasedTextfieldSwitch); | 404 kEnableViewsBasedTextfieldSwitch); |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 524 } | 530 } |
| 525 } | 531 } |
| 526 | 532 |
| 527 bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) { | 533 bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) { |
| 528 // TODO(oshima): handle IME. | 534 // TODO(oshima): handle IME. |
| 529 if (key_event.type() == ui::ET_KEY_PRESSED) { | 535 if (key_event.type() == ui::ET_KEY_PRESSED) { |
| 530 ui::KeyboardCode key_code = key_event.key_code(); | 536 ui::KeyboardCode key_code = key_event.key_code(); |
| 531 // TODO(oshima): shift-tab does not work. Figure out why and fix. | 537 // TODO(oshima): shift-tab does not work. Figure out why and fix. |
| 532 if (key_code == ui::VKEY_TAB) | 538 if (key_code == ui::VKEY_TAB) |
| 533 return false; | 539 return false; |
| 540 |
| 541 OnBeforeUserAction(); |
| 534 bool editable = !textfield_->read_only(); | 542 bool editable = !textfield_->read_only(); |
| 535 bool selection = key_event.IsShiftDown(); | 543 bool selection = key_event.IsShiftDown(); |
| 536 bool control = key_event.IsControlDown(); | 544 bool control = key_event.IsControlDown(); |
| 537 bool text_changed = false; | 545 bool text_changed = false; |
| 538 bool cursor_changed = false; | 546 bool cursor_changed = false; |
| 539 switch (key_code) { | 547 switch (key_code) { |
| 540 case ui::VKEY_A: | 548 case ui::VKEY_A: |
| 541 if (control) { | 549 if (control) { |
| 542 model_->SelectAll(); | 550 model_->SelectAll(); |
| 543 cursor_changed = true; | 551 cursor_changed = true; |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 612 } | 620 } |
| 613 cursor_changed = text_changed = model_->Delete(); | 621 cursor_changed = text_changed = model_->Delete(); |
| 614 break; | 622 break; |
| 615 case ui::VKEY_INSERT: | 623 case ui::VKEY_INSERT: |
| 616 insert_ = !insert_; | 624 insert_ = !insert_; |
| 617 cursor_changed = true; | 625 cursor_changed = true; |
| 618 break; | 626 break; |
| 619 default: | 627 default: |
| 620 break; | 628 break; |
| 621 } | 629 } |
| 622 char16 print_char = GetPrintableChar(key_event); | 630 char16 ch = key_event.GetCharacter(); |
| 623 if (!control && print_char && editable) { | 631 if (!control && editable && ShouldInsertChar(ch, key_event.flags())) { |
| 624 if (insert_) | 632 if (insert_) |
| 625 model_->Insert(print_char); | 633 model_->Insert(ch); |
| 626 else | 634 else |
| 627 model_->Replace(print_char); | 635 model_->Replace(ch); |
| 628 text_changed = true; | 636 text_changed = true; |
| 629 } | 637 } |
| 630 | 638 |
| 631 UpdateAfterChange(text_changed, cursor_changed); | 639 UpdateAfterChange(text_changed, cursor_changed); |
| 640 OnAfterUserAction(); |
| 632 return (text_changed || cursor_changed); | 641 return (text_changed || cursor_changed); |
| 633 } | 642 } |
| 634 return false; | 643 return false; |
| 635 } | 644 } |
| 636 | 645 |
| 637 char16 NativeTextfieldViews::GetPrintableChar(const KeyEvent& key_event) { | |
| 638 // TODO(oshima): IME, i18n support. | |
| 639 // This only works for UCS-2 characters. | |
| 640 ui::KeyboardCode key_code = key_event.key_code(); | |
| 641 bool shift = key_event.IsShiftDown(); | |
| 642 bool upper = shift ^ key_event.IsCapsLockDown(); | |
| 643 // TODO(oshima): We should have a utility function | |
| 644 // under app to convert a KeyboardCode to a printable character, | |
| 645 // probably in keyboard_code_conversion{.h, _x | |
| 646 switch (key_code) { | |
| 647 case ui::VKEY_NUMPAD0: | |
| 648 return '0'; | |
| 649 case ui::VKEY_NUMPAD1: | |
| 650 return '1'; | |
| 651 case ui::VKEY_NUMPAD2: | |
| 652 return '2'; | |
| 653 case ui::VKEY_NUMPAD3: | |
| 654 return '3'; | |
| 655 case ui::VKEY_NUMPAD4: | |
| 656 return '4'; | |
| 657 case ui::VKEY_NUMPAD5: | |
| 658 return '5'; | |
| 659 case ui::VKEY_NUMPAD6: | |
| 660 return '6'; | |
| 661 case ui::VKEY_NUMPAD7: | |
| 662 return '7'; | |
| 663 case ui::VKEY_NUMPAD8: | |
| 664 return '8'; | |
| 665 case ui::VKEY_NUMPAD9: | |
| 666 return '9'; | |
| 667 case ui::VKEY_MULTIPLY: | |
| 668 return '*'; | |
| 669 case ui::VKEY_ADD: | |
| 670 return '+'; | |
| 671 case ui::VKEY_SUBTRACT: | |
| 672 return '-'; | |
| 673 case ui::VKEY_DECIMAL: | |
| 674 return '.'; | |
| 675 case ui::VKEY_DIVIDE: | |
| 676 return '/'; | |
| 677 case ui::VKEY_SPACE: | |
| 678 return ' '; | |
| 679 case ui::VKEY_0: | |
| 680 return shift ? ')' : '0'; | |
| 681 case ui::VKEY_1: | |
| 682 return shift ? '!' : '1'; | |
| 683 case ui::VKEY_2: | |
| 684 return shift ? '@' : '2'; | |
| 685 case ui::VKEY_3: | |
| 686 return shift ? '#' : '3'; | |
| 687 case ui::VKEY_4: | |
| 688 return shift ? '$' : '4'; | |
| 689 case ui::VKEY_5: | |
| 690 return shift ? '%' : '5'; | |
| 691 case ui::VKEY_6: | |
| 692 return shift ? '^' : '6'; | |
| 693 case ui::VKEY_7: | |
| 694 return shift ? '&' : '7'; | |
| 695 case ui::VKEY_8: | |
| 696 return shift ? '*' : '8'; | |
| 697 case ui::VKEY_9: | |
| 698 return shift ? '(' : '9'; | |
| 699 | |
| 700 case ui::VKEY_A: | |
| 701 case ui::VKEY_B: | |
| 702 case ui::VKEY_C: | |
| 703 case ui::VKEY_D: | |
| 704 case ui::VKEY_E: | |
| 705 case ui::VKEY_F: | |
| 706 case ui::VKEY_G: | |
| 707 case ui::VKEY_H: | |
| 708 case ui::VKEY_I: | |
| 709 case ui::VKEY_J: | |
| 710 case ui::VKEY_K: | |
| 711 case ui::VKEY_L: | |
| 712 case ui::VKEY_M: | |
| 713 case ui::VKEY_N: | |
| 714 case ui::VKEY_O: | |
| 715 case ui::VKEY_P: | |
| 716 case ui::VKEY_Q: | |
| 717 case ui::VKEY_R: | |
| 718 case ui::VKEY_S: | |
| 719 case ui::VKEY_T: | |
| 720 case ui::VKEY_U: | |
| 721 case ui::VKEY_V: | |
| 722 case ui::VKEY_W: | |
| 723 case ui::VKEY_X: | |
| 724 case ui::VKEY_Y: | |
| 725 case ui::VKEY_Z: | |
| 726 return (upper ? 'A' : 'a') + (key_code - ui::VKEY_A); | |
| 727 case ui::VKEY_OEM_1: | |
| 728 return shift ? ':' : ';'; | |
| 729 case ui::VKEY_OEM_PLUS: | |
| 730 return shift ? '+' : '='; | |
| 731 case ui::VKEY_OEM_COMMA: | |
| 732 return shift ? '<' : ','; | |
| 733 case ui::VKEY_OEM_MINUS: | |
| 734 return shift ? '_' : '-'; | |
| 735 case ui::VKEY_OEM_PERIOD: | |
| 736 return shift ? '>' : '.'; | |
| 737 case ui::VKEY_OEM_2: | |
| 738 return shift ? '?' : '/'; | |
| 739 case ui::VKEY_OEM_3: | |
| 740 return shift ? '~' : '`'; | |
| 741 case ui::VKEY_OEM_4: | |
| 742 return shift ? '}' : ']'; | |
| 743 case ui::VKEY_OEM_5: | |
| 744 return shift ? '|' : '\\'; | |
| 745 case ui::VKEY_OEM_6: | |
| 746 return shift ? '{' : '['; | |
| 747 case ui::VKEY_OEM_7: | |
| 748 return shift ? '"' : '\''; | |
| 749 default: | |
| 750 return 0; | |
| 751 } | |
| 752 } | |
| 753 | |
| 754 size_t NativeTextfieldViews::FindCursorPosition(const gfx::Point& point) const { | 646 size_t NativeTextfieldViews::FindCursorPosition(const gfx::Point& point) const { |
| 755 // TODO(oshima): BIDI/i18n support. | 647 // TODO(oshima): BIDI/i18n support. |
| 756 gfx::Font font = GetFont(); | 648 gfx::Font font = GetFont(); |
| 757 gfx::Insets insets = GetInsets(); | 649 gfx::Insets insets = GetInsets(); |
| 758 string16 text = model_->GetVisibleText(); | 650 string16 text = model_->GetVisibleText(); |
| 759 int left = 0; | 651 int left = 0; |
| 760 int left_pos = 0; | 652 int left_pos = 0; |
| 761 int right = font.GetStringWidth(text); | 653 int right = font.GetStringWidth(text); |
| 762 int right_pos = text.length(); | 654 int right_pos = text.length(); |
| 763 | 655 |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 852 context_menu_contents_->AddItemWithStringId(IDS_APP_CUT, IDS_APP_CUT); | 744 context_menu_contents_->AddItemWithStringId(IDS_APP_CUT, IDS_APP_CUT); |
| 853 context_menu_contents_->AddItemWithStringId(IDS_APP_COPY, IDS_APP_COPY); | 745 context_menu_contents_->AddItemWithStringId(IDS_APP_COPY, IDS_APP_COPY); |
| 854 context_menu_contents_->AddItemWithStringId(IDS_APP_PASTE, IDS_APP_PASTE); | 746 context_menu_contents_->AddItemWithStringId(IDS_APP_PASTE, IDS_APP_PASTE); |
| 855 context_menu_contents_->AddItemWithStringId(IDS_APP_DELETE, IDS_APP_DELETE); | 747 context_menu_contents_->AddItemWithStringId(IDS_APP_DELETE, IDS_APP_DELETE); |
| 856 context_menu_contents_->AddSeparator(); | 748 context_menu_contents_->AddSeparator(); |
| 857 context_menu_contents_->AddItemWithStringId(IDS_APP_SELECT_ALL, | 749 context_menu_contents_->AddItemWithStringId(IDS_APP_SELECT_ALL, |
| 858 IDS_APP_SELECT_ALL); | 750 IDS_APP_SELECT_ALL); |
| 859 context_menu_menu_.reset(new Menu2(context_menu_contents_.get())); | 751 context_menu_menu_.reset(new Menu2(context_menu_contents_.get())); |
| 860 } | 752 } |
| 861 | 753 |
| 754 void NativeTextfieldViews::OnBeforeUserAction() { |
| 755 TextfieldController* controller = textfield_->GetController(); |
| 756 if (controller) |
| 757 controller->OnBeforeUserAction(textfield_); |
| 758 } |
| 759 |
| 760 void NativeTextfieldViews::OnAfterUserAction() { |
| 761 TextfieldController* controller = textfield_->GetController(); |
| 762 if (controller) |
| 763 controller->OnAfterUserAction(textfield_); |
| 764 } |
| 765 |
| 766 // static |
| 767 bool NativeTextfieldViews::ShouldInsertChar(char16 ch, int flags) { |
| 768 // Filter out all control characters, including tab and new line characters, |
| 769 // and all characters with Alt modifier. But we need to allow characters with |
| 770 // AltGr modifier. |
| 771 // On Windows AltGr is represented by Alt+Ctrl, and on Linux it's a different |
| 772 // flag that we don't care about. |
| 773 return ((ch >= 0x20 && ch < 0x7F) || ch > 0x9F) && |
| 774 (flags & ~(ui::EF_SHIFT_DOWN | ui::EF_CAPS_LOCK_DOWN)) != ui::EF_ALT_DOWN; |
| 775 } |
| 776 |
| 862 /////////////////////////////////////////////////////////////////////////////// | 777 /////////////////////////////////////////////////////////////////////////////// |
| 863 // | 778 // |
| 864 // TextifieldBorder | 779 // TextifieldBorder |
| 865 // | 780 // |
| 866 /////////////////////////////////////////////////////////////////////////////// | 781 /////////////////////////////////////////////////////////////////////////////// |
| 867 | 782 |
| 868 NativeTextfieldViews::TextfieldBorder::TextfieldBorder() | 783 NativeTextfieldViews::TextfieldBorder::TextfieldBorder() |
| 869 : has_focus_(false), | 784 : has_focus_(false), |
| 870 insets_(4, 4, 4, 4) { | 785 insets_(4, 4, 4, 4) { |
| 871 } | 786 } |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 907 } | 822 } |
| 908 | 823 |
| 909 void NativeTextfieldViews::TextfieldBorder::SetInsets(int top, | 824 void NativeTextfieldViews::TextfieldBorder::SetInsets(int top, |
| 910 int left, | 825 int left, |
| 911 int bottom, | 826 int bottom, |
| 912 int right) { | 827 int right) { |
| 913 insets_.Set(top, left, bottom, right); | 828 insets_.Set(top, left, bottom, right); |
| 914 } | 829 } |
| 915 | 830 |
| 916 } // namespace views | 831 } // namespace views |
| OLD | NEW |