diff options
author | suzhe@google.com <suzhe@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-28 02:36:49 +0000 |
---|---|---|
committer | suzhe@google.com <suzhe@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-28 02:36:49 +0000 |
commit | 911696b92b1b5a666e59433b8b64303a2f4eae62 (patch) | |
tree | a47bab7021b5a34a532b1dae4140b8651558efd5 /chrome/browser | |
parent | b7d6c22f8092a652d6b4572d4800e8a6aac6ccbe (diff) | |
download | chromium_src-911696b92b1b5a666e59433b8b64303a2f4eae62.zip chromium_src-911696b92b1b5a666e59433b8b64303a2f4eae62.tar.gz chromium_src-911696b92b1b5a666e59433b8b64303a2f4eae62.tar.bz2 |
Hitting Tab should always move cursor to end of omnibox text.
BUG=66850
TEST=AutocompleteEditViewTest.TabMoveCursorToEnd and InstantTest.TabKey
Review URL: http://codereview.chromium.org/5966006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@72920 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
22 files changed, 321 insertions, 170 deletions
diff --git a/chrome/browser/autocomplete/autocomplete_edit.cc b/chrome/browser/autocomplete/autocomplete_edit.cc index 54bf5ed..4e88607 100644 --- a/chrome/browser/autocomplete/autocomplete_edit.cc +++ b/chrome/browser/autocomplete/autocomplete_edit.cc @@ -154,8 +154,16 @@ void AutocompleteEditModel::SetUserText(const string16& text) { void AutocompleteEditModel::FinalizeInstantQuery( const string16& input_text, - const string16& suggest_text) { - popup_->FinalizeInstantQuery(input_text, suggest_text); + const string16& suggest_text, + bool skip_inline_autocomplete) { + if (skip_inline_autocomplete) { + const string16 final_text = input_text + suggest_text; + view_->OnBeforePossibleChange(); + view_->SetWindowTextAndCaretPos(final_text, final_text.length()); + view_->OnAfterPossibleChange(); + } else { + popup_->FinalizeInstantQuery(input_text, suggest_text); + } } void AutocompleteEditModel::GetDataForURLExport(GURL* url, diff --git a/chrome/browser/autocomplete/autocomplete_edit.h b/chrome/browser/autocomplete/autocomplete_edit.h index 7b00fc6..3b8c287 100644 --- a/chrome/browser/autocomplete/autocomplete_edit.h +++ b/chrome/browser/autocomplete/autocomplete_edit.h @@ -48,9 +48,11 @@ class AutocompleteEditController { // OnAutoCompleteAccept. virtual void OnAutocompleteWillAccept() = 0; - // Commits the suggested text. |typed_text| is the current text showing in the - // autocomplete. Returns true if the text was committed. - virtual bool OnCommitSuggestedText(const string16& typed_text) = 0; + // Commits the suggested text. If |skip_inline_autocomplete| is true then the + // suggested text will be committed as final text as if it's inputted by the + // user, rather than as inline autocomplete suggest. + // Returns true if the text was committed. + virtual bool OnCommitSuggestedText(bool skip_inline_autocomplete) = 0; // Accepts the currently showing instant preview, if any, and returns true. // Returns false if there is no instant preview showing. @@ -191,8 +193,11 @@ class AutocompleteEditModel : public NotificationObserver { void SetUserText(const string16& text); // Calls through to SearchProvider::FinalizeInstantQuery. + // If |skip_inline_autocomplete| is true then the |suggest_text| will be + // turned into final text instead of inline autocomplete suggest. void FinalizeInstantQuery(const string16& input_text, - const string16& suggest_text); + const string16& suggest_text, + bool skip_inline_autocomplete); // Reverts the edit model back to its unedited state (permanent text showing, // no user input in progress). diff --git a/chrome/browser/autocomplete/autocomplete_edit_unittest.cc b/chrome/browser/autocomplete/autocomplete_edit_unittest.cc index 7643936..9d54555 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_unittest.cc +++ b/chrome/browser/autocomplete/autocomplete_edit_unittest.cc @@ -56,14 +56,12 @@ class TestingAutocompleteEditView : public AutocompleteEditView { virtual gfx::NativeView GetNativeView() const { return 0; } virtual CommandUpdater* GetCommandUpdater() { return NULL; } virtual void SetInstantSuggestion(const string16& input) {} + virtual string16 GetInstantSuggestion() const { return string16(); } virtual int TextWidth() const { return 0; } virtual bool IsImeComposing() const { return false; } #if defined(TOOLKIT_VIEWS) virtual views::View* AddToView(views::View* parent) { return NULL; } - virtual bool CommitInstantSuggestion( - const string16& typed_text, - const string16& suggested_text) { return false; } #endif private: @@ -76,7 +74,7 @@ class TestingAutocompleteEditController : public AutocompleteEditController { virtual void OnAutocompleteWillClosePopup() {} virtual void OnAutocompleteLosingFocus(gfx::NativeView view_gaining_focus) {} virtual void OnAutocompleteWillAccept() {} - virtual bool OnCommitSuggestedText(const string16& typed_text) { + virtual bool OnCommitSuggestedText(bool skip_inline_autocomplete) { return false; } virtual bool AcceptCurrentInstantPreview() { diff --git a/chrome/browser/autocomplete/autocomplete_edit_view.h b/chrome/browser/autocomplete/autocomplete_edit_view.h index 73ccb46..408c848 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view.h +++ b/chrome/browser/autocomplete/autocomplete_edit_view.h @@ -161,6 +161,9 @@ class AutocompleteEditView { // Shows the instant suggestion text. virtual void SetInstantSuggestion(const string16& input) = 0; + // Returns the current instant suggestion text. + virtual string16 GetInstantSuggestion() const = 0; + // Returns the width in pixels needed to display the current text. The // returned value includes margins. virtual int TextWidth() const = 0; @@ -172,10 +175,6 @@ class AutocompleteEditView { // Adds the autocomplete edit view to view hierarchy and // returns the views::View of the edit view. virtual views::View* AddToView(views::View* parent) = 0; - - // Commits the suggested text. - virtual bool CommitInstantSuggestion(const string16& typed_text, - const string16& suggested_text) = 0; #endif virtual ~AutocompleteEditView() {} diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_browsertest.cc b/chrome/browser/autocomplete/autocomplete_edit_view_browsertest.cc index 1e79685..f452757 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_browsertest.cc +++ b/chrome/browser/autocomplete/autocomplete_edit_view_browsertest.cc @@ -944,6 +944,52 @@ class AutocompleteEditViewTest : public InProcessBrowserTest, ASSERT_TRUE(edit_view->IsSelectAll()); } + void TabMoveCursorToEndTest() { + AutocompleteEditView* edit_view = NULL; + ASSERT_NO_FATAL_FAILURE(GetAutocompleteEditView(&edit_view)); + + edit_view->SetUserText(ASCIIToUTF16("Hello world")); + + // Move cursor to the beginning. + ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_HOME, false, false, false)); + + string16::size_type start, end; + edit_view->GetSelectionBounds(&start, &end); + EXPECT_EQ(0U, start); + EXPECT_EQ(0U, end); + + // Pressing tab should move cursor to the end. + ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_TAB, false, false, false)); + + edit_view->GetSelectionBounds(&start, &end); + EXPECT_EQ(edit_view->GetText().size(), start); + EXPECT_EQ(edit_view->GetText().size(), end); + + // The location bar should still have focus. + ASSERT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_LOCATION_BAR)); + + // Select all text. + edit_view->SelectAll(true); + EXPECT_TRUE(edit_view->IsSelectAll()); + edit_view->GetSelectionBounds(&start, &end); + EXPECT_EQ(0U, start); + EXPECT_EQ(edit_view->GetText().size(), end); + + // Pressing tab should move cursor to the end. + ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_TAB, false, false, false)); + + edit_view->GetSelectionBounds(&start, &end); + EXPECT_EQ(edit_view->GetText().size(), start); + EXPECT_EQ(edit_view->GetText().size(), end); + + // The location bar should still have focus. + ASSERT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_LOCATION_BAR)); + + // Pressing tab when cursor is at the end should change focus. + ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_TAB, false, false, false)); + + ASSERT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_LOCATION_BAR)); + } }; // Test if ctrl-* accelerators are workable in omnibox. @@ -1005,6 +1051,10 @@ IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, DeleteItem) { DeleteItemTest(); } +IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, TabMoveCursorToEnd) { + TabMoveCursorToEndTest(); +} + #if defined(OS_LINUX) // TODO(oshima): enable these tests for views-implmentation when // these featuers are supported. @@ -1190,4 +1240,11 @@ IN_PROC_BROWSER_TEST_F(AutocompleteEditViewViewsTest, DeleteItem) { DeleteItemTest(); } +// TODO(suzhe): This test is broken because of broken ViewID support when +// enabling AutocompleteEditViewViews. +IN_PROC_BROWSER_TEST_F(AutocompleteEditViewViewsTest, + DISABLED_TabMoveCursorToEnd) { + TabMoveCursorToEndTest(); +} + #endif diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc index 46ddb70..30db56a 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc +++ b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc @@ -779,6 +779,11 @@ void AutocompleteEditViewGtk::SetInstantSuggestion(const string16& suggestion) { UpdateInstantViewColors(); } +string16 AutocompleteEditViewGtk::GetInstantSuggestion() const { + const gchar* suggestion = gtk_label_get_text(GTK_LABEL(instant_view_)); + return suggestion ? UTF8ToUTF16(suggestion) : string16(); +} + int AutocompleteEditViewGtk::TextWidth() const { int horizontal_border_size = gtk_text_view_get_border_window_size(GTK_TEXT_VIEW(text_view_), @@ -834,12 +839,6 @@ views::View* AutocompleteEditViewGtk::AddToView(views::View* parent) { return host; } -bool AutocompleteEditViewGtk::CommitInstantSuggestion( - const string16& typed_text, - const string16& suggestion) { - return CommitInstantSuggestion(); -} - void AutocompleteEditViewGtk::EnableAccessibility() { accessible_widget_helper_.reset( new AccessibleWidgetHelper(text_view(), model_->profile())); @@ -898,7 +897,7 @@ void AutocompleteEditViewGtk::Observe(NotificationType type, } void AutocompleteEditViewGtk::AnimationEnded(const ui::Animation* animation) { - controller_->OnCommitSuggestedText(GetText()); + controller_->OnCommitSuggestedText(false); } void AutocompleteEditViewGtk::AnimationProgressed( @@ -1344,9 +1343,6 @@ void AutocompleteEditViewGtk::HandleViewMoveCursor( if (step == GTK_MOVEMENT_VISUAL_POSITIONS && !extend_selection && (count == 1 || count == -1)) { - gint cursor_pos; - g_object_get(G_OBJECT(text_buffer_), "cursor-position", &cursor_pos, NULL); - // We need to take the content direction into account when handling cursor // movement, because the behavior of Left and Right key will be inverted if // the direction is RTL. Although we should check the direction around the @@ -1369,8 +1365,8 @@ void AutocompleteEditViewGtk::HandleViewMoveCursor( text_buffer_, count == count_towards_end ? &sel_end : &sel_start); OnAfterPossibleChange(); handled = true; - } else if (count == count_towards_end && cursor_pos == GetTextLength()) { - handled = controller_->OnCommitSuggestedText(GetText()); + } else if (count == count_towards_end && !IsCaretAtEnd()) { + handled = controller_->OnCommitSuggestedText(true); } } else if (step == GTK_MOVEMENT_PAGES) { // Page up and down. // Multiply by count for the direction (if we move too much that's ok). @@ -1638,15 +1634,29 @@ void AutocompleteEditViewGtk::HandleViewMoveFocus(GtkWidget* widget, bool handled = false; // Trigger Tab to search behavior only when Tab key is pressed. - if (model_->is_keyword_hint()) { + if (model_->is_keyword_hint()) handled = model_->AcceptKeyword(); - } else if (GTK_WIDGET_VISIBLE(instant_view_)) { - controller_->OnCommitSuggestedText(GetText()); + +#if GTK_CHECK_VERSION(2, 20, 0) + if (!handled && !preedit_.empty()) handled = true; - } else { - handled = controller_->AcceptCurrentInstantPreview(); +#endif + + if (!handled && GTK_WIDGET_VISIBLE(instant_view_)) + handled = controller_->OnCommitSuggestedText(true); + + if (!handled) { + if (!IsCaretAtEnd()) { + OnBeforePossibleChange(); + PlaceCaretAt(GetTextLength()); + OnAfterPossibleChange(); + handled = true; + } } + if (!handled) + handled = controller_->AcceptCurrentInstantPreview(); + if (handled) { static guint signal_id = g_signal_lookup("move-focus", GTK_TYPE_WIDGET); g_signal_stop_emission(widget, signal_id, 0); @@ -1822,7 +1832,8 @@ void AutocompleteEditViewGtk::FinishUpdatingHighlightedText() { g_signal_handler_unblock(text_buffer_, mark_set_handler_id2_); } -AutocompleteEditViewGtk::CharRange AutocompleteEditViewGtk::GetSelection() { +AutocompleteEditViewGtk::CharRange + AutocompleteEditViewGtk::GetSelection() const { // You can not just use get_selection_bounds here, since the order will be // ascending, and you don't know where the user's start and end of the // selection was (if the selection was forwards or backwards). Get the @@ -1871,6 +1882,18 @@ int AutocompleteEditViewGtk::GetTextLength() const { #endif } +void AutocompleteEditViewGtk::PlaceCaretAt(int pos) { + GtkTextIter cursor; + gtk_text_buffer_get_iter_at_offset(text_buffer_, &cursor, pos); + gtk_text_buffer_place_cursor(text_buffer_, &cursor); +} + +bool AutocompleteEditViewGtk::IsCaretAtEnd() const { + const CharRange selection = GetSelection(); + return selection.cp_min == selection.cp_max && + selection.cp_min == GetTextLength(); +} + void AutocompleteEditViewGtk::EmphasizeURLComponents() { #if GTK_CHECK_VERSION(2, 20, 0) // We can't change the text style easily, if the preedit string (the text @@ -1946,16 +1969,6 @@ void AutocompleteEditViewGtk::StopAnimation() { UpdateInstantViewColors(); } -bool AutocompleteEditViewGtk::CommitInstantSuggestion() { - const gchar* suggestion = gtk_label_get_text(GTK_LABEL(instant_view_)); - if (!suggestion || !*suggestion) - return false; - - model()->FinalizeInstantQuery(GetText(), - UTF8ToUTF16(suggestion)); - return true; -} - void AutocompleteEditViewGtk::TextChanged() { EmphasizeURLComponents(); controller_->OnChanged(); diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h index 4508ffa..27a3aaa 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h +++ b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h @@ -144,13 +144,12 @@ class AutocompleteEditViewGtk : public AutocompleteEditView, virtual gfx::NativeView GetNativeView() const; virtual CommandUpdater* GetCommandUpdater(); virtual void SetInstantSuggestion(const string16& suggestion); + virtual string16 GetInstantSuggestion() const; virtual int TextWidth() const; virtual bool IsImeComposing() const; #if defined(TOOLKIT_VIEWS) virtual views::View* AddToView(views::View* parent); - virtual bool CommitInstantSuggestion(const string16& typed_text, - const string16& suggested_text); // Enables accessibility on AutocompleteEditView. void EnableAccessibility(); @@ -183,8 +182,6 @@ class AutocompleteEditViewGtk : public AutocompleteEditView, // the animation state. void UpdateInstantViewColors(); - bool CommitInstantSuggestion(); - GtkWidget* text_view() { return text_view_; } @@ -302,7 +299,7 @@ class AutocompleteEditViewGtk : public AutocompleteEditView, // Get the character indices of the current selection. This honors // direction, cp_max is the insertion point, and cp_min is the bound. - CharRange GetSelection(); + CharRange GetSelection() const; // Translate from character positions to iterators for the current buffer. void ItersFromCharRange(const CharRange& range, @@ -312,6 +309,12 @@ class AutocompleteEditViewGtk : public AutocompleteEditView, // Return the number of characers in the current buffer. int GetTextLength() const; + // Places the caret at the given position. This clears any selection. + void PlaceCaretAt(int pos); + + // Returns true if the caret is at the end of the content. + bool IsCaretAtEnd() const; + // Try to parse the current text as a URL and colorize the components. void EmphasizeURLComponents(); diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_mac.h b/chrome/browser/autocomplete/autocomplete_edit_view_mac.h index a671393..3ba5963 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_mac.h +++ b/chrome/browser/autocomplete/autocomplete_edit_view_mac.h @@ -84,6 +84,7 @@ class AutocompleteEditViewMac : public AutocompleteEditView, virtual gfx::NativeView GetNativeView() const; virtual CommandUpdater* GetCommandUpdater(); virtual void SetInstantSuggestion(const string16& input); + virtual string16 GetInstantSuggestion() const; virtual int TextWidth() const; virtual bool IsImeComposing() const; @@ -104,8 +105,6 @@ class AutocompleteEditViewMac : public AutocompleteEditView, virtual void OnSetFocus(bool control_down); virtual void OnKillFocus(); - bool CommitSuggestText(); - // Helper for LocationBarViewMac. Optionally selects all in |field_|. void FocusLocation(bool select_all); @@ -160,6 +159,9 @@ class AutocompleteEditViewMac : public AutocompleteEditView, // Returns the non-suggest portion of |field_|'s string value. NSString* GetNonSuggestTextSubstring() const; + // Returns the suggest portion of |field_|'s string value. + NSString* GetSuggestTextSubstring() const; + // Pass the current content of |field_| to SetText(), maintaining // any selection. Named to be consistent with GTK and Windows, // though here we cannot really do the in-place operation they do. @@ -170,6 +172,16 @@ class AutocompleteEditViewMac : public AutocompleteEditView, void ApplyTextAttributes(const string16& display_text, NSMutableAttributedString* as); + // Return the number of UTF-16 units in the current buffer, excluding the + // suggested text. + NSUInteger GetTextLength() const; + + // Places the caret at the given position. This clears any selection. + void PlaceCaretAt(NSUInteger pos); + + // Returns true if the caret is at the end of the content. + bool IsCaretAtEnd() const; + scoped_ptr<AutocompleteEditModel> model_; scoped_ptr<AutocompletePopupViewMac> popup_view_; diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm b/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm index a003166..c2841f4 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm +++ b/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm @@ -216,7 +216,7 @@ void AutocompleteEditViewMac::SaveStateToTab(TabContents* tab) { } else { // If we are not focussed, there is no selection. Manufacture // something reasonable in case it starts to matter in the future. - range = NSMakeRange(0, [[field_ stringValue] length]); + range = NSMakeRange(0, GetTextLength()); } AutocompleteEditViewMacState state(model_->GetStateForTabSwitch(), @@ -296,8 +296,7 @@ string16 AutocompleteEditViewMac::GetText() const { } bool AutocompleteEditViewMac::IsEditingOrEmpty() const { - return model_->user_input_in_progress() || - ([[field_ stringValue] length] == 0); + return model_->user_input_in_progress() || !GetTextLength(); } int AutocompleteEditViewMac::GetIcon() const { @@ -324,7 +323,6 @@ void AutocompleteEditViewMac::SetUserText(const string16& text, } NSRange AutocompleteEditViewMac::GetSelectedRange() const { - DCHECK([field_ currentEditor]); return [[field_ currentEditor] selectedRange]; } @@ -374,7 +372,7 @@ void AutocompleteEditViewMac::SetForcedQuery() { bool AutocompleteEditViewMac::IsSelectAll() { if (![field_ currentEditor]) return true; - const NSRange all_range = NSMakeRange(0, GetText().length()); + const NSRange all_range = NSMakeRange(0, GetTextLength()); return NSEqualRanges(all_range, GetSelectedRange()); } @@ -401,7 +399,7 @@ void AutocompleteEditViewMac::SelectAll(bool reversed) { // TODO(shess): Verify that we should be stealing focus at this // point. - SetSelectedRange(NSMakeRange(0, GetText().length())); + SetSelectedRange(NSMakeRange(0, GetTextLength())); } void AutocompleteEditViewMac::RevertAll() { @@ -422,16 +420,8 @@ void AutocompleteEditViewMac::UpdatePopup() { // * The caret/selection isn't at the end of the text // * The user has just pasted in something that replaced all the text // * The user is trying to compose something in an IME - bool prevent_inline_autocomplete = IsImeComposing(); - NSTextView* editor = (NSTextView*)[field_ currentEditor]; - if (editor) { - if (NSMaxRange([editor selectedRange]) < - [[editor textStorage] length] - suggest_text_length_) - prevent_inline_autocomplete = true; - } - - model_->StartAutocomplete([editor selectedRange].length != 0, - prevent_inline_autocomplete); + model_->StartAutocomplete(GetSelectedRange().length != 0, + IsImeComposing() || !IsCaretAtEnd()); } void AutocompleteEditViewMac::ClosePopup() { @@ -444,19 +434,6 @@ void AutocompleteEditViewMac::ClosePopup() { void AutocompleteEditViewMac::SetFocus() { } -bool AutocompleteEditViewMac::CommitSuggestText() { - if (suggest_text_length_ == 0) - return false; - - string16 input_text(GetText()); - suggest_text_length_ = 0; - string16 text(GetText()); - // Call SetText() to force a redraw and move the cursor to the end. - SetText(text); - model()->FinalizeInstantQuery(input_text, text.substr(input_text.size())); - return true; -} - void AutocompleteEditViewMac::SetText(const string16& display_text) { // If we are setting the text directly, there cannot be any suggest text. suggest_text_length_ = 0; @@ -507,6 +484,16 @@ NSString* AutocompleteEditViewMac::GetNonSuggestTextSubstring() const { return text; } +NSString* AutocompleteEditViewMac::GetSuggestTextSubstring() const { + if (suggest_text_length_ == 0) + return nil; + + NSString* text = [field_ stringValue]; + NSUInteger length = [text length]; + DCHECK_LE(suggest_text_length_, length); + return [text substringFromIndex:(length - suggest_text_length_)]; +} + void AutocompleteEditViewMac::EmphasizeURLComponents() { NSTextView* editor = (NSTextView*)[field_ currentEditor]; // If the autocomplete text field is in editing mode, then we can just change @@ -723,6 +710,11 @@ void AutocompleteEditViewMac::SetInstantSuggestion( } } +string16 AutocompleteEditViewMac::GetInstantSuggestion() const { + return suggest_text_length_ ? + base::SysNSStringToUTF16(GetSuggestTextSubstring()) : string16(); +} + int AutocompleteEditViewMac::TextWidth() const { // Not used on mac. NOTREACHED(); @@ -785,12 +777,8 @@ bool AutocompleteEditViewMac::OnDoCommandBySelector(SEL cmd) { if (cmd == @selector(moveRight:)) { // Only commit suggested text if the cursor is all the way to the right and // there is no selection. - NSRange range = GetSelectedRange(); - if (range.length == 0 && - suggest_text_length_ > 0 && - (range.location + suggest_text_length_ == - [[field_ stringValue] length])) { - controller_->OnCommitSuggestedText(GetText()); + if (suggest_text_length_ > 0 && IsCaretAtEnd()) { + controller_->OnCommitSuggestedText(true); return true; } } @@ -815,7 +803,15 @@ bool AutocompleteEditViewMac::OnDoCommandBySelector(SEL cmd) { return model_->AcceptKeyword(); if (suggest_text_length_ > 0) { - controller_->OnCommitSuggestedText(GetText()); + controller_->OnCommitSuggestedText(true); + return true; + } + + if (!IsCaretAtEnd()) { + PlaceCaretAt(GetTextLength()); + // OnDidChange() will not be triggered when setting selected range in this + // method, so we need to call it explicitly. + OnDidChange(); return true; } @@ -1094,3 +1090,19 @@ NSFont* AutocompleteEditViewMac::GetFieldFont() { ResourceBundle& rb = ResourceBundle::GetSharedInstance(); return rb.GetFont(ResourceBundle::BaseFont).GetNativeFont(); } + +NSUInteger AutocompleteEditViewMac::GetTextLength() const { + return ([field_ currentEditor] ? + [[[field_ currentEditor] string] length] : + [[field_ stringValue] length]) - suggest_text_length_; +} + +void AutocompleteEditViewMac::PlaceCaretAt(NSUInteger pos) { + DCHECK(pos <= GetTextLength()); + SetSelectedRange(NSMakeRange(pos, pos)); +} + +bool AutocompleteEditViewMac::IsCaretAtEnd() const { + const NSRange selection = GetSelectedRange(); + return selection.length == 0 && selection.location == GetTextLength(); +} diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_views.cc b/chrome/browser/autocomplete/autocomplete_edit_view_views.cc index 2b77099..5093873 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_views.cc +++ b/chrome/browser/autocomplete/autocomplete_edit_view_views.cc @@ -197,10 +197,20 @@ bool AutocompleteEditViewViews::HandleAfterKeyEvent( event.GetKeyCode() == ui::VKEY_TAB && !event.IsShiftDown() && !event.IsControlDown()) { - if (model_->is_keyword_hint() && !model_->keyword().empty()) { - model_->AcceptKeyword(); - handled = true; + if (model_->is_keyword_hint()) { + handled = model_->AcceptKeyword(); } else { + string16::size_type start = 0; + string16::size_type end = 0; + size_t length = GetTextLength(); + GetSelectionBounds(&start, &end); + if (start != end || start < length) { + OnBeforePossibleChange(); + SelectRange(length, length); + OnAfterPossibleChange(); + handled = true; + } + // TODO(Oshima): handle instant } } @@ -527,10 +537,13 @@ CommandUpdater* AutocompleteEditViewViews::GetCommandUpdater() { return command_updater_; } -views::View* AutocompleteEditViewViews::AddToView(views::View* parent) { - parent->AddChildView(this); - AddChildView(textfield_); - return this; +void AutocompleteEditViewViews::SetInstantSuggestion(const string16& input) { + NOTIMPLEMENTED(); +} + +string16 AutocompleteEditViewViews::GetInstantSuggestion() const { + NOTIMPLEMENTED(); + return string16(); } int AutocompleteEditViewViews::TextWidth() const { @@ -542,15 +555,10 @@ bool AutocompleteEditViewViews::IsImeComposing() const { return false; } -bool AutocompleteEditViewViews::CommitInstantSuggestion( - const string16& typed_text, - const string16& suggested_text) { - model_->FinalizeInstantQuery(typed_text, suggested_text); - return true; -} - -void AutocompleteEditViewViews::SetInstantSuggestion(const string16& input) { - NOTIMPLEMENTED(); +views::View* AutocompleteEditViewViews::AddToView(views::View* parent) { + parent->AddChildView(this); + AddChildView(textfield_); + return this; } //////////////////////////////////////////////////////////////////////////////// diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_views.h b/chrome/browser/autocomplete/autocomplete_edit_view_views.h index a6ca9db..e347aa2 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_views.h +++ b/chrome/browser/autocomplete/autocomplete_edit_view_views.h @@ -111,12 +111,11 @@ class AutocompleteEditViewViews : public views::View, virtual bool OnAfterPossibleChange(); virtual gfx::NativeView GetNativeView() const; virtual CommandUpdater* GetCommandUpdater(); - virtual views::View* AddToView(views::View* parent); + virtual void SetInstantSuggestion(const string16& input); + virtual string16 GetInstantSuggestion() const; virtual int TextWidth() const; virtual bool IsImeComposing() const; - virtual bool CommitInstantSuggestion(const string16& typed_text, - const string16& suggested_text); - virtual void SetInstantSuggestion(const string16& input); + virtual views::View* AddToView(views::View* parent); // Overridden from NotificationObserver: virtual void Observe(NotificationType type, diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_win.cc b/chrome/browser/autocomplete/autocomplete_edit_view_win.cc index 89d8f55..cca0d08 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_win.cc +++ b/chrome/browser/autocomplete/autocomplete_edit_view_win.cc @@ -924,6 +924,12 @@ void AutocompleteEditViewWin::SetInstantSuggestion(const string16& suggestion) { NOTREACHED(); } +string16 AutocompleteEditViewWin::GetInstantSuggestion() const { + // On Windows, we shows the suggestion in LocationBarView. + NOTREACHED(); + return string16(); +} + int AutocompleteEditViewWin::TextWidth() const { return WidthNeededToDisplay(GetText()); } @@ -946,13 +952,6 @@ views::View* AutocompleteEditViewWin::AddToView(views::View* parent) { return host; } -bool AutocompleteEditViewWin::CommitInstantSuggestion( - const string16& typed_text, - const string16& suggested_text) { - model_->FinalizeInstantQuery(typed_text, suggested_text); - return true; -} - void AutocompleteEditViewWin::PasteAndGo(const string16& text) { if (CanPasteAndGo(text)) model_->PasteAndGo(); @@ -1848,7 +1847,7 @@ bool AutocompleteEditViewWin::OnKeyDownOnlyWritable(TCHAR key, GetSel(selection); return (selection.cpMin == selection.cpMax) && (selection.cpMin == GetTextLength()) && - controller_->OnCommitSuggestedText(GetText()); + controller_->OnCommitSuggestedText(true); } case VK_RETURN: @@ -1977,8 +1976,13 @@ bool AutocompleteEditViewWin::OnKeyDownOnlyWritable(TCHAR key, // Accept the keyword. ScopedFreeze freeze(this, GetTextObjectModel()); model_->AcceptKeyword(); + } else if (!IsCaretAtEnd()) { + ScopedFreeze freeze(this, GetTextObjectModel()); + OnBeforePossibleChange(); + PlaceCaretAt(GetTextLength()); + OnAfterPossibleChange(); } else { - controller_->OnCommitSuggestedText(GetText()); + controller_->OnCommitSuggestedText(true); } return true; } @@ -2568,3 +2572,10 @@ int AutocompleteEditViewWin::WidthNeededToDisplay( // PosFromChar(i) might return 0 when i is greater than 1. return font_.GetStringWidth(text) + GetHorizontalMargin(); } + +bool AutocompleteEditViewWin::IsCaretAtEnd() const { + long length = GetTextLength(); + CHARRANGE sel; + GetSelection(sel); + return sel.cpMin == sel.cpMax && sel.cpMin == length; +} diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_win.h b/chrome/browser/autocomplete/autocomplete_edit_view_win.h index 1b81787..5e4efdb 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_win.h +++ b/chrome/browser/autocomplete/autocomplete_edit_view_win.h @@ -134,12 +134,11 @@ class AutocompleteEditViewWin virtual gfx::NativeView GetNativeView() const; virtual CommandUpdater* GetCommandUpdater(); virtual void SetInstantSuggestion(const string16& suggestion); + virtual string16 GetInstantSuggestion() const; virtual int TextWidth() const; virtual bool IsImeComposing() const; virtual views::View* AddToView(views::View* parent); - virtual bool CommitInstantSuggestion(const string16& typed_text, - const string16& suggested_text); int GetPopupMaxYCoordinate(); @@ -216,6 +215,9 @@ class AutocompleteEditViewWin virtual string16 GetLabelForCommandId(int command_id) const; virtual void ExecuteCommand(int command_id); + // Returns true if the caret is at the end of the content. + bool IsCaretAtEnd() const; + private: enum MouseButton { kLeft = 0, diff --git a/chrome/browser/browser_focus_uitest.cc b/chrome/browser/browser_focus_uitest.cc index 9bd27da..75a6304 100644 --- a/chrome/browser/browser_focus_uitest.cc +++ b/chrome/browser/browser_focus_uitest.cc @@ -469,6 +469,10 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusTraversal) { // Location bar should be focused. ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); + // Move the caret to the end, otherwise the next Tab key may not move focus. + ASSERT_TRUE(ui_test_utils::SendKeyPressSync( + browser(), ui::VKEY_END, false, false, false, false)); + // Now let's press tab to move the focus. for (size_t j = 0; j < arraysize(kExpElementIDs); ++j) { SCOPED_TRACE(StringPrintf("inner loop %" PRIuS, j)); @@ -515,6 +519,10 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusTraversal) { // Location bar should be focused. ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); + // Move the caret to the end, otherwise the next Tab key may not move focus. + ASSERT_TRUE(ui_test_utils::SendKeyPressSync( + browser(), ui::VKEY_END, false, false, false, false)); + // Now let's press shift-tab to move the focus in reverse. for (size_t j = 0; j < arraysize(kExpElementIDs); ++j) { SCOPED_TRACE(StringPrintf("inner loop: %" PRIuS, j)); @@ -595,6 +603,10 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusTraversalOnInterstitial) { // Location bar should be focused. ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); + // Move the caret to the end, otherwise the next Tab key may not move focus. + ASSERT_TRUE(ui_test_utils::SendKeyPressSync( + browser(), ui::VKEY_END, false, false, false, false)); + // Now let's press tab to move the focus. for (size_t j = 0; j < 7; ++j) { // Let's make sure the focus is on the expected element in the page. @@ -634,6 +646,10 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusTraversalOnInterstitial) { // Location bar should be focused. ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); + // Move the caret to the end, otherwise the next Tab key may not move focus. + ASSERT_TRUE(ui_test_utils::SendKeyPressSync( + browser(), ui::VKEY_END, false, false, false, false)); + // Now let's press shift-tab to move the focus in reverse. for (size_t j = 0; j < 7; ++j) { NotificationType::Type notification_type; diff --git a/chrome/browser/instant/instant_browsertest.cc b/chrome/browser/instant/instant_browsertest.cc index 258b4f4..231109e 100644 --- a/chrome/browser/instant/instant_browsertest.cc +++ b/chrome/browser/instant/instant_browsertest.cc @@ -663,13 +663,7 @@ IN_PROC_BROWSER_TEST_F(InstantTest, OnCancelEvent) { GetSearchStateAsString(preview_)); } -#if !defined(OS_MACOSX) -// Only passes on Mac. http://crbug.com/66850 -#define MAYBE_TabKey FAILS_TabKey -#else -#define MAYBE_TabKey TabKey -#endif -IN_PROC_BROWSER_TEST_F(InstantTest, MAYBE_TabKey) { +IN_PROC_BROWSER_TEST_F(InstantTest, TabKey) { ASSERT_TRUE(test_server()->Start()); EnableInstant(); ASSERT_NO_FATAL_FAILURE(SetupInstantProvider("search.html")); @@ -685,7 +679,7 @@ IN_PROC_BROWSER_TEST_F(InstantTest, MAYBE_TabKey) { ASSERT_EQ(ASCIIToUTF16("abcdef"), location_bar_->location_entry()->GetText()); - EXPECT_EQ("true 0 0 2 2 a false abcdef false 6 6", + EXPECT_EQ("true 0 0 2 1 a false abcdef false 6 6", GetSearchStateAsString(preview_)); // Pressing tab again to accept the current instant preview. @@ -698,6 +692,6 @@ IN_PROC_BROWSER_TEST_F(InstantTest, MAYBE_TabKey) { ASSERT_TRUE(contents); // Check that the value is reflected and onsubmit is called. - EXPECT_EQ("true 1 0 2 2 a false abcdef true 6 6", + EXPECT_EQ("true 1 0 2 1 a false abcdef true 6 6", GetSearchStateAsString(preview_)); } diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h index 0f87f44..7b06b91 100644 --- a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h +++ b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h @@ -132,7 +132,7 @@ class LocationBarViewMac : public AutocompleteEditController, virtual void OnAutocompleteWillClosePopup(); virtual void OnAutocompleteLosingFocus(gfx::NativeView unused); virtual void OnAutocompleteWillAccept(); - virtual bool OnCommitSuggestedText(const string16& typed_text); + virtual bool OnCommitSuggestedText(bool skip_inline_autocomplete); virtual bool AcceptCurrentInstantPreview(); virtual void OnPopupBoundsChanged(const gfx::Rect& bounds); virtual void OnAutocompleteAccept(const GURL& url, diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm index 213cc53..ba43a7c 100644 --- a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm +++ b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm @@ -248,8 +248,17 @@ void LocationBarViewMac::OnAutocompleteWillAccept() { update_instant_ = false; } -bool LocationBarViewMac::OnCommitSuggestedText(const string16& typed_text) { - return edit_view_->CommitSuggestText(); +bool LocationBarViewMac::OnCommitSuggestedText(bool skip_inline_autocomplete) { + if (!browser_->instant()) + return false; + + const string16 suggestion = edit_view_->GetInstantSuggestion(); + if (suggestion.empty()) + return false; + + edit_view_->model()->FinalizeInstantQuery( + edit_view_->GetText(), suggestion, skip_inline_autocomplete); + return true; } bool LocationBarViewMac::AcceptCurrentInstantPreview() { @@ -321,13 +330,13 @@ void LocationBarViewMac::OnChanged() { edit_view_->model()->UseVerbatimInstant(), &suggested_text); if (!instant->MightSupportInstant()) { - edit_view_->model()->FinalizeInstantQuery(string16(), - string16()); + edit_view_->model()->FinalizeInstantQuery( + string16(), string16(), false); } } else { instant->DestroyPreviewContents(); - edit_view_->model()->FinalizeInstantQuery(string16(), - string16()); + edit_view_->model()->FinalizeInstantQuery( + string16(), string16(), false); } } diff --git a/chrome/browser/ui/gtk/location_bar_view_gtk.cc b/chrome/browser/ui/gtk/location_bar_view_gtk.cc index 6b600d4..b7a5c72 100644 --- a/chrome/browser/ui/gtk/location_bar_view_gtk.cc +++ b/chrome/browser/ui/gtk/location_bar_view_gtk.cc @@ -458,9 +458,17 @@ void LocationBarViewGtk::OnAutocompleteWillAccept() { update_instant_ = false; } -bool LocationBarViewGtk::OnCommitSuggestedText( - const string16& typed_text) { - return browser_->instant() && location_entry_->CommitInstantSuggestion(); +bool LocationBarViewGtk::OnCommitSuggestedText(bool skip_inline_autocomplete) { + if (!browser_->instant()) + return false; + + const string16 suggestion = location_entry_->GetInstantSuggestion(); + if (suggestion.empty()) + return false; + + location_entry_->model()->FinalizeInstantQuery( + location_entry_->GetText(), suggestion, skip_inline_autocomplete); + return true; } bool LocationBarViewGtk::AcceptCurrentInstantPreview() { @@ -538,13 +546,13 @@ void LocationBarViewGtk::OnChanged() { location_entry_->model()->UseVerbatimInstant(), &suggested_text); if (!instant->MightSupportInstant()) { - location_entry_->model()->FinalizeInstantQuery(string16(), - string16()); + location_entry_->model()->FinalizeInstantQuery( + string16(), string16(), false); } } else { instant->DestroyPreviewContents(); - location_entry_->model()->FinalizeInstantQuery(string16(), - string16()); + location_entry_->model()->FinalizeInstantQuery( + string16(), string16(), false); } } @@ -627,7 +635,7 @@ void LocationBarViewGtk::SetSuggestedText(const string16& text) { // text. if (!text.empty()) { location_entry_->model()->FinalizeInstantQuery( - location_entry_->GetText(), text); + location_entry_->GetText(), text, false); } } else { location_entry_->SetInstantSuggestion(text); diff --git a/chrome/browser/ui/gtk/location_bar_view_gtk.h b/chrome/browser/ui/gtk/location_bar_view_gtk.h index 374d8fc..2bc9ba5 100644 --- a/chrome/browser/ui/gtk/location_bar_view_gtk.h +++ b/chrome/browser/ui/gtk/location_bar_view_gtk.h @@ -95,7 +95,7 @@ class LocationBarViewGtk : public AutocompleteEditController, virtual void OnAutocompleteLosingFocus(gfx::NativeView view_gaining_focus); virtual void OnAutocompleteWillAccept(); // For this implementation, the parameter is ignored. - virtual bool OnCommitSuggestedText(const string16& typed_text); + virtual bool OnCommitSuggestedText(bool skip_inline_autocomplete); virtual bool AcceptCurrentInstantPreview(); virtual void OnPopupBoundsChanged(const gfx::Rect& bounds); virtual void OnAutocompleteAccept(const GURL& url, diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc index d66b51a..8dc3a25 100644 --- a/chrome/browser/ui/views/location_bar/location_bar_view.cc +++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc @@ -399,15 +399,6 @@ gfx::Point LocationBarView::GetLocationEntryOrigin() const { return origin; } -#if defined(OS_WIN) -void LocationBarView::OnCommitSuggestedText() { - InstantController* instant = delegate_->GetInstant(); - DCHECK(instant); - DCHECK(suggested_text_view_); - OnCommitSuggestedText(location_entry_->GetText()); -} -#endif - gfx::Size LocationBarView::GetPreferredSize() { return gfx::Size(0, GetThemeProvider()->GetBitmapNamed(mode_ == POPUP ? IDR_LOCATIONBG_POPUPMODE_CENTER : IDR_LOCATIONBG_C)->height()); @@ -768,17 +759,24 @@ void LocationBarView::OnAutocompleteWillAccept() { update_instant_ = false; } -bool LocationBarView::OnCommitSuggestedText(const string16& typed_text) { - InstantController* instant = delegate_->GetInstant(); - if (!instant) +bool LocationBarView::OnCommitSuggestedText(bool skip_inline_autocomplete) { + if (!delegate_->GetInstant()) return false; + string16 suggestion; #if defined(OS_WIN) - if (!HasValidSuggestText()) - return false; - suggestion = suggested_text_view_->GetText(); + if (HasValidSuggestText()) + suggestion = suggested_text_view_->GetText(); +#else + suggestion = location_entry_->GetInstantSuggestion(); #endif - return location_entry_->CommitInstantSuggestion(typed_text, suggestion); + + if (suggestion.empty()) + return false; + + location_entry_->model()->FinalizeInstantQuery( + location_entry_->GetText(), suggestion, skip_inline_autocomplete); + return true; } bool LocationBarView::AcceptCurrentInstantPreview() { @@ -852,13 +850,13 @@ void LocationBarView::OnChanged() { location_entry_->model()->UseVerbatimInstant(), &suggested_text); if (!instant->MightSupportInstant()) { - location_entry_->model()->FinalizeInstantQuery(string16(), - string16()); + location_entry_->model()->FinalizeInstantQuery( + string16(), string16(), false); } } else { instant->DestroyPreviewContents(); - location_entry_->model()->FinalizeInstantQuery(string16(), - string16()); + location_entry_->model()->FinalizeInstantQuery( + string16(), string16(), false); } } @@ -1058,6 +1056,10 @@ bool LocationBarView::SkipDefaultKeyEventProcessing(const views::KeyEvent& e) { return true; } + // If the caret is not at the end, then tab moves the caret to the end. + if (!location_entry_->IsCaretAtEnd()) + return true; + // Tab while showing instant commits instant immediately. // Return true so that focus traversal isn't attempted. The edit ends // up doing nothing in this case. @@ -1128,8 +1130,8 @@ void LocationBarView::SetSuggestedText(const string16& input) { // TODO: if we keep autocomplete, make it so this isn't invoked with empty // text. if (!input.empty()) { - location_entry_->model()->FinalizeInstantQuery(location_entry_->GetText(), - input); + location_entry_->model()->FinalizeInstantQuery( + location_entry_->GetText(), input, false); } return; } diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.h b/chrome/browser/ui/views/location_bar/location_bar_view.h index 90273e9..d149aba 100644 --- a/chrome/browser/ui/views/location_bar/location_bar_view.h +++ b/chrome/browser/ui/views/location_bar/location_bar_view.h @@ -155,11 +155,6 @@ class LocationBarView : public LocationBar, // appears, not where the icons are shown). gfx::Point GetLocationEntryOrigin() const; -#if defined(OS_WIN) - // Invoked from SuggestedTextView when the suggested text should be committed. - void OnCommitSuggestedText(); -#endif - // Sizing functions virtual gfx::Size GetPreferredSize(); @@ -194,7 +189,7 @@ class LocationBarView : public LocationBar, virtual void OnAutocompleteWillClosePopup(); virtual void OnAutocompleteLosingFocus(gfx::NativeView view_gaining_focus); virtual void OnAutocompleteWillAccept(); - virtual bool OnCommitSuggestedText(const string16& typed_text); + virtual bool OnCommitSuggestedText(bool skip_inline_autocomplete); virtual bool AcceptCurrentInstantPreview(); virtual void OnPopupBoundsChanged(const gfx::Rect& bounds); virtual void OnAutocompleteAccept(const GURL& url, diff --git a/chrome/browser/ui/views/location_bar/suggested_text_view.cc b/chrome/browser/ui/views/location_bar/suggested_text_view.cc index 22b9e9f..6fa19c0 100644 --- a/chrome/browser/ui/views/location_bar/suggested_text_view.cc +++ b/chrome/browser/ui/views/location_bar/suggested_text_view.cc @@ -46,7 +46,7 @@ void SuggestedTextView::PaintBackground(gfx::Canvas* canvas) { } void SuggestedTextView::AnimationEnded(const ui::Animation* animation) { - location_bar_->OnCommitSuggestedText(); + location_bar_->OnCommitSuggestedText(false); } void SuggestedTextView::AnimationProgressed(const ui::Animation* animation) { |