| 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 "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h" | 5 #include "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h" |
| 6 | 6 |
| 7 #include <Carbon/Carbon.h> // kVK_Return | 7 #include <Carbon/Carbon.h> // kVK_Return |
| 8 | 8 |
| 9 #include "base/mac/foundation_util.h" | 9 #include "base/mac/foundation_util.h" |
| 10 #include "base/memory/ptr_util.h" | 10 #include "base/memory/ptr_util.h" |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 207 Profile* profile, | 207 Profile* profile, |
| 208 CommandUpdater* command_updater, | 208 CommandUpdater* command_updater, |
| 209 AutocompleteTextField* field) | 209 AutocompleteTextField* field) |
| 210 : OmniboxView( | 210 : OmniboxView( |
| 211 controller, | 211 controller, |
| 212 base::WrapUnique(new ChromeOmniboxClient(controller, profile))), | 212 base::WrapUnique(new ChromeOmniboxClient(controller, profile))), |
| 213 profile_(profile), | 213 profile_(profile), |
| 214 popup_view_(new OmniboxPopupViewMac(this, model(), field)), | 214 popup_view_(new OmniboxPopupViewMac(this, model(), field)), |
| 215 field_(field), | 215 field_(field), |
| 216 saved_temporary_selection_(NSMakeRange(0, 0)), | 216 saved_temporary_selection_(NSMakeRange(0, 0)), |
| 217 selection_before_change_(NSMakeRange(0, 0)), | |
| 218 marked_range_before_change_(NSMakeRange(0, 0)), | 217 marked_range_before_change_(NSMakeRange(0, 0)), |
| 219 delete_was_pressed_(false), | 218 delete_was_pressed_(false), |
| 220 delete_at_end_pressed_(false), | 219 delete_at_end_pressed_(false), |
| 221 in_coalesced_update_block_(false), | 220 in_coalesced_update_block_(false), |
| 222 do_coalesced_text_update_(false), | 221 do_coalesced_text_update_(false), |
| 223 do_coalesced_range_update_(false) { | 222 do_coalesced_range_update_(false) { |
| 224 [field_ setObserver:this]; | 223 [field_ setObserver:this]; |
| 225 | 224 |
| 226 // Needed so that editing doesn't lose the styling. | 225 // Needed so that editing doesn't lose the styling. |
| 227 [field_ setAllowsEditingTextAttributes:YES]; | 226 [field_ setAllowsEditingTextAttributes:YES]; |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 381 DCHECK_LE(caret_pos, text.size()); | 380 DCHECK_LE(caret_pos, text.size()); |
| 382 SetTextAndSelectedRange(text, NSMakeRange(caret_pos, 0)); | 381 SetTextAndSelectedRange(text, NSMakeRange(caret_pos, 0)); |
| 383 | 382 |
| 384 if (update_popup) | 383 if (update_popup) |
| 385 UpdatePopup(); | 384 UpdatePopup(); |
| 386 | 385 |
| 387 if (notify_text_changed) | 386 if (notify_text_changed) |
| 388 TextChanged(); | 387 TextChanged(); |
| 389 } | 388 } |
| 390 | 389 |
| 391 void OmniboxViewMac::SetForcedQuery() { | 390 void OmniboxViewMac::EnterKeywordModeForDefaultSearchProvider() { |
| 392 // We need to do this first, else |SetSelectedRange()| won't work. | 391 // We need to do this first, else |SetSelectedRange()| won't work. |
| 393 FocusLocation(true); | 392 FocusLocation(true); |
| 394 | 393 |
| 395 const base::string16 current_text(GetText()); | 394 // Transition the user into keyword mode using their default search provider. |
| 396 const size_t start = current_text.find_first_not_of(base::kWhitespaceUTF16); | 395 // Select their query if they typed one. |
| 397 if (start == base::string16::npos || (current_text[start] != '?')) { | 396 model()->EnterKeywordModeForDefaultSearchProvider( |
| 398 SetUserText(base::ASCIIToUTF16("?")); | 397 KeywordModeEntryMethod::KEYBOARD_SHORTCUT); |
| 399 } else { | 398 SelectAll(false); |
| 400 NSRange range = NSMakeRange(start + 1, current_text.size() - start - 1); | |
| 401 [[field_ currentEditor] setSelectedRange:range]; | |
| 402 } | |
| 403 } | 399 } |
| 404 | 400 |
| 405 bool OmniboxViewMac::IsSelectAll() const { | 401 bool OmniboxViewMac::IsSelectAll() const { |
| 406 if (![field_ currentEditor]) | 402 if (![field_ currentEditor]) |
| 407 return true; | 403 return true; |
| 408 const NSRange all_range = NSMakeRange(0, GetTextLength()); | 404 const NSRange all_range = NSMakeRange(0, GetTextLength()); |
| 409 return NSEqualRanges(all_range, GetSelectedRange()); | 405 return NSEqualRanges(all_range, GetSelectedRange()); |
| 410 } | 406 } |
| 411 | 407 |
| 412 bool OmniboxViewMac::DeleteAtEndPressed() { | 408 bool OmniboxViewMac::DeleteAtEndPressed() { |
| (...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 676 } | 672 } |
| 677 | 673 |
| 678 bool OmniboxViewMac::IsFirstResponder() const { | 674 bool OmniboxViewMac::IsFirstResponder() const { |
| 679 return [field_ currentEditor] != nil ? true : false; | 675 return [field_ currentEditor] != nil ? true : false; |
| 680 } | 676 } |
| 681 | 677 |
| 682 void OmniboxViewMac::OnBeforePossibleChange() { | 678 void OmniboxViewMac::OnBeforePossibleChange() { |
| 683 // We should only arrive here when the field is focused. | 679 // We should only arrive here when the field is focused. |
| 684 DCHECK(IsFirstResponder()); | 680 DCHECK(IsFirstResponder()); |
| 685 | 681 |
| 686 selection_before_change_ = GetSelectedRange(); | 682 GetState(&state_before_change_); |
| 687 text_before_change_ = GetText(); | |
| 688 marked_range_before_change_ = GetMarkedRange(); | 683 marked_range_before_change_ = GetMarkedRange(); |
| 689 } | 684 } |
| 690 | 685 |
| 691 bool OmniboxViewMac::OnAfterPossibleChange(bool allow_keyword_ui_change) { | 686 bool OmniboxViewMac::OnAfterPossibleChange(bool allow_keyword_ui_change) { |
| 692 // We should only arrive here when the field is focused. | 687 // We should only arrive here when the field is focused. |
| 693 DCHECK(IsFirstResponder()); | 688 DCHECK(IsFirstResponder()); |
| 694 | 689 |
| 695 const NSRange new_selection(GetSelectedRange()); | 690 State new_state; |
| 696 const base::string16 new_text(GetText()); | 691 GetState(&new_state); |
| 697 const size_t length = new_text.length(); | 692 OmniboxView::StateChanges state_changes = |
| 693 GetStateChanges(state_before_change_, new_state); |
| 698 | 694 |
| 699 const bool selection_differs = | 695 const bool at_end_of_edit = (new_state.text.length() == new_state.sel_end); |
| 700 (new_selection.length || selection_before_change_.length) && | |
| 701 !NSEqualRanges(new_selection, selection_before_change_); | |
| 702 const bool at_end_of_edit = (length == new_selection.location); | |
| 703 const bool text_differs = (new_text != text_before_change_) || | |
| 704 !NSEqualRanges(marked_range_before_change_, GetMarkedRange()); | |
| 705 | |
| 706 // When the user has deleted text, we don't allow inline | |
| 707 // autocomplete. This is assumed if the text has gotten shorter AND | |
| 708 // the selection has shifted towards the front of the text. During | |
| 709 // normal typing the text will almost always be shorter (as the new | |
| 710 // input replaces the autocomplete suggestion), but in that case the | |
| 711 // selection point will have moved towards the end of the text. | |
| 712 // TODO(shess): In our implementation, we can catch -deleteBackward: | |
| 713 // and other methods to provide positive knowledge that a delete | |
| 714 // occurred, rather than intuiting it from context. Consider whether | |
| 715 // that would be a stronger approach. | |
| 716 const bool just_deleted_text = | |
| 717 (length < text_before_change_.length() && | |
| 718 new_selection.location <= selection_before_change_.location); | |
| 719 | 696 |
| 720 delete_at_end_pressed_ = false; | 697 delete_at_end_pressed_ = false; |
| 721 | 698 |
| 722 const bool something_changed = model()->OnAfterPossibleChange( | 699 const bool something_changed = model()->OnAfterPossibleChange( |
| 723 text_before_change_, new_text, new_selection.location, | 700 state_changes, allow_keyword_ui_change && !IsImeComposing()); |
| 724 NSMaxRange(new_selection), selection_differs, text_differs, | |
| 725 just_deleted_text, allow_keyword_ui_change && !IsImeComposing()); | |
| 726 | 701 |
| 727 if (delete_was_pressed_ && at_end_of_edit) | 702 if (delete_was_pressed_ && at_end_of_edit) |
| 728 delete_at_end_pressed_ = true; | 703 delete_at_end_pressed_ = true; |
| 729 | 704 |
| 730 // Restyle in case the user changed something. | 705 // Restyle in case the user changed something. |
| 731 // TODO(shess): I believe there are multiple-redraw cases, here. | 706 // TODO(shess): I believe there are multiple-redraw cases, here. |
| 732 // Linux watches for something_changed && text_differs, but that | 707 // Linux watches for something_changed && text_differs, but that |
| 733 // fails for us in case you copy the URL and paste the identical URL | 708 // fails for us in case you copy the URL and paste the identical URL |
| 734 // back (we'll lose the styling). | 709 // back (we'll lose the styling). |
| 735 TextChanged(); | 710 TextChanged(); |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 863 return true; | 838 return true; |
| 864 } | 839 } |
| 865 | 840 |
| 866 if (cmd == @selector(cancelOperation:)) { | 841 if (cmd == @selector(cancelOperation:)) { |
| 867 return model()->OnEscapeKeyPressed(); | 842 return model()->OnEscapeKeyPressed(); |
| 868 } | 843 } |
| 869 | 844 |
| 870 if ((cmd == @selector(insertTab:) || | 845 if ((cmd == @selector(insertTab:) || |
| 871 cmd == @selector(insertTabIgnoringFieldEditor:)) && | 846 cmd == @selector(insertTabIgnoringFieldEditor:)) && |
| 872 model()->is_keyword_hint()) { | 847 model()->is_keyword_hint()) { |
| 873 return model()->AcceptKeyword(ENTERED_KEYWORD_MODE_VIA_TAB); | 848 return model()->AcceptKeyword(KeywordModeEntryMethod::TAB); |
| 874 } | 849 } |
| 875 | 850 |
| 876 // |-noop:| is sent when the user presses Cmd+Return. Override the no-op | 851 // |-noop:| is sent when the user presses Cmd+Return. Override the no-op |
| 877 // behavior with the proper WindowOpenDisposition. | 852 // behavior with the proper WindowOpenDisposition. |
| 878 NSEvent* event = [NSApp currentEvent]; | 853 NSEvent* event = [NSApp currentEvent]; |
| 879 if (cmd == @selector(insertNewline:) || | 854 if (cmd == @selector(insertNewline:) || |
| 880 (cmd == @selector(noop:) && | 855 (cmd == @selector(noop:) && |
| 881 ([event type] == NSKeyDown || [event type] == NSKeyUp) && | 856 ([event type] == NSKeyDown || [event type] == NSKeyUp) && |
| 882 [event keyCode] == kVK_Return)) { | 857 [event keyCode] == kVK_Return)) { |
| 883 WindowOpenDisposition disposition = | 858 WindowOpenDisposition disposition = |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1016 // from the Chrome-specific code. | 991 // from the Chrome-specific code. |
| 1017 NSTextView* editor = static_cast<NSTextView*>([field_ currentEditor]); | 992 NSTextView* editor = static_cast<NSTextView*>([field_ currentEditor]); |
| 1018 const NSRange selectedRange = GetSelectedRange(); | 993 const NSRange selectedRange = GetSelectedRange(); |
| 1019 if ([editor shouldChangeTextInRange:selectedRange replacementString:s]) { | 994 if ([editor shouldChangeTextInRange:selectedRange replacementString:s]) { |
| 1020 // Record this paste, so we can do different behavior. | 995 // Record this paste, so we can do different behavior. |
| 1021 model()->OnPaste(); | 996 model()->OnPaste(); |
| 1022 | 997 |
| 1023 // Force a Paste operation to trigger the text_changed code in | 998 // Force a Paste operation to trigger the text_changed code in |
| 1024 // OnAfterPossibleChange(), even if identical contents are pasted | 999 // OnAfterPossibleChange(), even if identical contents are pasted |
| 1025 // into the text box. | 1000 // into the text box. |
| 1026 text_before_change_.clear(); | 1001 state_before_change_.text.clear(); |
| 1027 | 1002 |
| 1028 [editor replaceCharactersInRange:selectedRange withString:s]; | 1003 [editor replaceCharactersInRange:selectedRange withString:s]; |
| 1029 [editor didChangeText]; | 1004 [editor didChangeText]; |
| 1030 } | 1005 } |
| 1031 } | 1006 } |
| 1032 | 1007 |
| 1033 // TODO(dominich): Move to OmniboxView base class? Currently this is defined on | 1008 // TODO(dominich): Move to OmniboxView base class? Currently this is defined on |
| 1034 // the AutocompleteTextFieldObserver but the logic is shared between all | 1009 // the AutocompleteTextFieldObserver but the logic is shared between all |
| 1035 // platforms. Some refactor might be necessary to simplify this. Or at least | 1010 // platforms. Some refactor might be necessary to simplify this. Or at least |
| 1036 // this method could call the OmniboxView version. | 1011 // this method could call the OmniboxView version. |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1169 display_text); | 1144 display_text); |
| 1170 NSDictionary* notification_info = @{ | 1145 NSDictionary* notification_info = @{ |
| 1171 NSAccessibilityAnnouncementKey : announcement, | 1146 NSAccessibilityAnnouncementKey : announcement, |
| 1172 NSAccessibilityPriorityKey : @(NSAccessibilityPriorityHigh) | 1147 NSAccessibilityPriorityKey : @(NSAccessibilityPriorityHigh) |
| 1173 }; | 1148 }; |
| 1174 NSAccessibilityPostNotificationWithUserInfo( | 1149 NSAccessibilityPostNotificationWithUserInfo( |
| 1175 [field_ window], | 1150 [field_ window], |
| 1176 NSAccessibilityAnnouncementRequestedNotification, | 1151 NSAccessibilityAnnouncementRequestedNotification, |
| 1177 notification_info); | 1152 notification_info); |
| 1178 } | 1153 } |
| OLD | NEW |