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 (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 |