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 |