| Index: components/omnibox/browser/omnibox_edit_model.cc
|
| diff --git a/components/omnibox/browser/omnibox_edit_model.cc b/components/omnibox/browser/omnibox_edit_model.cc
|
| index 14f7ae75945a0bec933f8fdf0b8d8d584a52d729..8d8d51d5463752ad785fc50cc166a2a3880056e4 100644
|
| --- a/components/omnibox/browser/omnibox_edit_model.cc
|
| +++ b/components/omnibox/browser/omnibox_edit_model.cc
|
| @@ -71,7 +71,7 @@ enum UserTextClearedType {
|
|
|
| // Histogram name which counts the number of times the user enters
|
| // keyword hint mode and via what method. The possible values are listed
|
| -// in the EnteredKeywordModeMethod enum which is defined in the .h file.
|
| +// in the KeywordModeEntryMethod enum which is defined in the .h file.
|
| const char kEnteredKeywordModeHistogram[] = "Omnibox.EnteredKeywordMode";
|
|
|
| // Histogram name which counts the number of milliseconds a user takes
|
| @@ -149,6 +149,7 @@ OmniboxEditModel::State::State(bool user_input_in_progress,
|
| const base::string16& gray_text,
|
| const base::string16& keyword,
|
| bool is_keyword_hint,
|
| + KeywordModeEntryMethod keyword_mode_entry_method,
|
| bool url_replacement_enabled,
|
| OmniboxFocusState focus_state,
|
| FocusSource focus_source,
|
| @@ -158,6 +159,7 @@ OmniboxEditModel::State::State(bool user_input_in_progress,
|
| gray_text(gray_text),
|
| keyword(keyword),
|
| is_keyword_hint(is_keyword_hint),
|
| + keyword_mode_entry_method(keyword_mode_entry_method),
|
| url_replacement_enabled(url_replacement_enabled),
|
| focus_state(focus_state),
|
| focus_source(focus_source),
|
| @@ -217,7 +219,7 @@ const OmniboxEditModel::State OmniboxEditModel::GetStateForTabSwitch() {
|
| user_input_in_progress_);
|
| return State(
|
| user_input_in_progress_, user_text_, view_->GetGrayTextAutocompletion(),
|
| - keyword_, is_keyword_hint_,
|
| + keyword_, is_keyword_hint_, keyword_mode_entry_method_,
|
| controller_->GetToolbarModel()->url_replacement_enabled(),
|
| focus_state_, focus_source_, input_);
|
| }
|
| @@ -242,11 +244,12 @@ void OmniboxEditModel::RestoreState(const State* state) {
|
| focus_source_ = state->focus_source;
|
| // Restore any user editing.
|
| if (state->user_input_in_progress) {
|
| - // NOTE: Be sure and set keyword-related state AFTER invoking
|
| + // NOTE: Be sure to set keyword-related state AFTER invoking
|
| // SetUserText(), as SetUserText() clears the keyword state.
|
| view_->SetUserText(state->user_text, false);
|
| keyword_ = state->keyword;
|
| is_keyword_hint_ = state->is_keyword_hint;
|
| + keyword_mode_entry_method_ = state->keyword_mode_entry_method;
|
| view_->SetGrayTextAutocompletion(state->gray_text);
|
| }
|
| }
|
| @@ -625,6 +628,23 @@ void OmniboxEditModel::AcceptInput(WindowOpenDisposition disposition,
|
| popup_model()->selected_line());
|
| }
|
|
|
| +void OmniboxEditModel::EnterKeywordModeForDefaultSearchProvider(
|
| + KeywordModeEntryMethod entry_method) {
|
| + autocomplete_controller()->Stop(false);
|
| +
|
| + user_input_in_progress_ = true;
|
| + keyword_ = client_->GetTemplateURLService()->
|
| + GetDefaultSearchProvider()->keyword();
|
| + is_keyword_hint_ = false;
|
| + keyword_mode_entry_method_ = entry_method;
|
| +
|
| + StartAutocomplete(false, false, true);
|
| +
|
| + UMA_HISTOGRAM_ENUMERATION(
|
| + kEnteredKeywordModeHistogram, static_cast<int>(entry_method),
|
| + static_cast<int>(KeywordModeEntryMethod::NUM_ITEMS));
|
| +}
|
| +
|
| void OmniboxEditModel::OpenMatch(AutocompleteMatch match,
|
| WindowOpenDisposition disposition,
|
| const GURL& alternate_nav_url,
|
| @@ -783,11 +803,15 @@ void OmniboxEditModel::OpenMatch(AutocompleteMatch match,
|
| client_->OnBookmarkLaunched();
|
| }
|
|
|
| -bool OmniboxEditModel::AcceptKeyword(EnteredKeywordModeMethod entered_method) {
|
| +bool OmniboxEditModel::AcceptKeyword(
|
| + KeywordModeEntryMethod entry_method) {
|
| DCHECK(is_keyword_hint_ && !keyword_.empty());
|
|
|
| autocomplete_controller()->Stop(false);
|
| +
|
| is_keyword_hint_ = false;
|
| + keyword_mode_entry_method_ = entry_method;
|
| + user_text_ = MaybeStripKeyword(user_text_);
|
|
|
| user_text_ = MaybeStripKeyword(user_text_);
|
|
|
| @@ -813,7 +837,7 @@ bool OmniboxEditModel::AcceptKeyword(EnteredKeywordModeMethod entered_method) {
|
| // here, may have generated a new match, which the user won't actually see and
|
| // which we don't want to switch back to when existing keyword mode; see
|
| // comments in ClearKeyword().
|
| - if (entered_method == ENTERED_KEYWORD_MODE_VIA_TAB) {
|
| + if (entry_method == KeywordModeEntryMethod::TAB) {
|
| // Ensure the current selection is saved before showing keyword mode
|
| // so that moving to another line and then reverting the text will restore
|
| // the current state properly.
|
| @@ -829,8 +853,9 @@ bool OmniboxEditModel::AcceptKeyword(EnteredKeywordModeMethod entered_method) {
|
| }
|
|
|
| base::RecordAction(base::UserMetricsAction("AcceptedKeywordHint"));
|
| - UMA_HISTOGRAM_ENUMERATION(kEnteredKeywordModeHistogram, entered_method,
|
| - ENTERED_KEYWORD_MODE_NUM_ITEMS);
|
| + UMA_HISTOGRAM_ENUMERATION(
|
| + kEnteredKeywordModeHistogram, static_cast<int>(entry_method),
|
| + static_cast<int>(KeywordModeEntryMethod::NUM_ITEMS));
|
|
|
| return true;
|
| }
|
| @@ -914,12 +939,24 @@ void OmniboxEditModel::ClearKeyword() {
|
| // user can easily delete it. On the other hand, if there is no space and
|
| // the user wants it, it's more work to add because typing the space will
|
| // enter keyword mode, which then the user would have to leave again.
|
| - const base::string16 window_text =
|
| - keyword_ + base::ASCIIToUTF16(" ") + view_->GetText();
|
| - view_->SetWindowTextAndCaretPos(window_text.c_str(), keyword_.length() + 1,
|
| - false, false);
|
| +
|
| + // If we entered keyword mode in a special way like using a keyboard
|
| + // shortcut or typing a question mark in a blank omnibox, don't restore the
|
| + // keyword. Instead, restore the question mark iff the user originally
|
| + // typed one.
|
| + base::string16 prefix;
|
| + if (keyword_mode_entry_method_ == KeywordModeEntryMethod::QUESTION_MARK)
|
| + prefix = base::ASCIIToUTF16("?");
|
| + else if (keyword_mode_entry_method_ !=
|
| + KeywordModeEntryMethod::KEYBOARD_SHORTCUT)
|
| + prefix = keyword_ + base::ASCIIToUTF16(" ");
|
| +
|
| keyword_.clear();
|
| is_keyword_hint_ = false;
|
| +
|
| + view_->SetWindowTextAndCaretPos(prefix + view_->GetText(), prefix.length(),
|
| + false, false);
|
| +
|
| view_->OnAfterPossibleChange(false);
|
| }
|
| }
|
| @@ -1153,23 +1190,18 @@ void OmniboxEditModel::OnPopupDataChanged(
|
| OnChanged();
|
| }
|
|
|
| -bool OmniboxEditModel::OnAfterPossibleChange(const base::string16& old_text,
|
| - const base::string16& new_text,
|
| - size_t selection_start,
|
| - size_t selection_end,
|
| - bool selection_differs,
|
| - bool text_differs,
|
| - bool just_deleted_text,
|
| - bool allow_keyword_ui_change) {
|
| +bool OmniboxEditModel::OnAfterPossibleChange(
|
| + const OmniboxView::StateChanges& state_changes,
|
| + bool allow_keyword_ui_change) {
|
| // Update the paste state as appropriate: if we're just finishing a paste
|
| // that replaced all the text, preserve that information; otherwise, if we've
|
| // made some other edit, clear paste tracking.
|
| if (paste_state_ == PASTING)
|
| paste_state_ = PASTED;
|
| - else if (text_differs)
|
| + else if (state_changes.text_differs)
|
| paste_state_ = NONE;
|
|
|
| - if (text_differs || selection_differs) {
|
| + if (state_changes.text_differs || state_changes.selection_differs) {
|
| // Record current focus state for this input if we haven't already.
|
| if (focus_source_ == INVALID) {
|
| // We should generally expect the omnibox to have focus at this point, but
|
| @@ -1178,8 +1210,8 @@ bool OmniboxEditModel::OnAfterPossibleChange(const base::string16& old_text,
|
| // right-click can change the contents without focusing the omnibox.
|
| // TODO(samarth): fix Linux focus behavior and add a DCHECK here to
|
| // check that the omnibox does have focus.
|
| - focus_source_ = (focus_state_ == OMNIBOX_FOCUS_INVISIBLE) ?
|
| - FAKEBOX : OMNIBOX;
|
| + focus_source_ =
|
| + (focus_state_ == OMNIBOX_FOCUS_INVISIBLE) ? FAKEBOX : OMNIBOX;
|
| }
|
|
|
| // Restore caret visibility whenever the user changes text or selection in
|
| @@ -1188,27 +1220,38 @@ bool OmniboxEditModel::OnAfterPossibleChange(const base::string16& old_text,
|
| }
|
|
|
| // Modifying the selection counts as accepting the autocompleted text.
|
| - const bool user_text_changed =
|
| - text_differs || (selection_differs && !inline_autocomplete_text_.empty());
|
| + const bool user_state_changesd =
|
| + state_changes.text_differs ||
|
| + (state_changes.selection_differs && !inline_autocomplete_text_.empty());
|
|
|
| // If something has changed while the control key is down, prevent
|
| // "ctrl-enter" until the control key is released.
|
| - if ((text_differs || selection_differs) &&
|
| + if ((state_changes.text_differs || state_changes.selection_differs) &&
|
| (control_key_state_ == DOWN_WITHOUT_CHANGE))
|
| control_key_state_ = DOWN_WITH_CHANGE;
|
|
|
| - if (!user_text_changed)
|
| - return false;
|
| + if (!user_state_changesd) {
|
| + if (state_changes.keyword_differs) {
|
| + // We won't need the below logic for creating a keyword by a space at the
|
| + // end or in the middle, or by typing a '?', but we do need to update the
|
| + // popup view because the keyword can change without the text changing,
|
| + // for example when the keyword is "youtube.com" and the user presses
|
| + // ctrl-k to change it to "google.com", or if the user text is empty and
|
| + // the user presses backspace.
|
| + view_->UpdatePopup();
|
| + }
|
| + return state_changes.keyword_differs;
|
| + }
|
|
|
| // If the user text has not changed, we do not want to change the model's
|
| // state associated with the text. Otherwise, we can get surprising behavior
|
| // where the autocompleted text unexpectedly reappears, e.g. crbug.com/55983
|
| - InternalSetUserText(new_text);
|
| + InternalSetUserText(*state_changes.new_text);
|
| has_temporary_text_ = false;
|
|
|
| // Track when the user has deleted text so we won't allow inline
|
| // autocomplete.
|
| - just_deleted_text_ = just_deleted_text;
|
| + just_deleted_text_ = state_changes.just_deleted_text;
|
|
|
| if (user_input_in_progress_ && user_text_.empty()) {
|
| // Log cases where the user started editing and then subsequently cleared
|
| @@ -1220,39 +1263,58 @@ bool OmniboxEditModel::OnAfterPossibleChange(const base::string16& old_text,
|
| OMNIBOX_USER_TEXT_CLEARED_NUM_OF_ITEMS);
|
| }
|
|
|
| - const bool no_selection = selection_start == selection_end;
|
| + const bool no_selection =
|
| + state_changes.new_sel_start == state_changes.new_sel_end;
|
|
|
| // Update the popup for the change, in the process changing to keyword mode
|
| // if the user hit space in mid-string after a keyword.
|
| // |allow_exact_keyword_match_| will be used by StartAutocomplete() method,
|
| // which will be called by |view_->UpdatePopup()|; so after that returns we
|
| // can safely reset this flag.
|
| - allow_exact_keyword_match_ = text_differs && allow_keyword_ui_change &&
|
| - !just_deleted_text && no_selection &&
|
| - CreatedKeywordSearchByInsertingSpaceInMiddle(old_text, user_text_,
|
| - selection_start);
|
| + allow_exact_keyword_match_ =
|
| + state_changes.text_differs && allow_keyword_ui_change &&
|
| + !state_changes.just_deleted_text && no_selection &&
|
| + CreatedKeywordSearchByInsertingSpaceInMiddle(
|
| + *state_changes.old_text, user_text_, state_changes.new_sel_start);
|
| view_->UpdatePopup();
|
| if (allow_exact_keyword_match_) {
|
| - UMA_HISTOGRAM_ENUMERATION(kEnteredKeywordModeHistogram,
|
| - ENTERED_KEYWORD_MODE_VIA_SPACE_IN_MIDDLE,
|
| - ENTERED_KEYWORD_MODE_NUM_ITEMS);
|
| + keyword_mode_entry_method_ = KeywordModeEntryMethod::SPACE_IN_MIDDLE;
|
| + UMA_HISTOGRAM_ENUMERATION(
|
| + kEnteredKeywordModeHistogram,
|
| + static_cast<int>(KeywordModeEntryMethod::SPACE_IN_MIDDLE),
|
| + static_cast<int>(KeywordModeEntryMethod::NUM_ITEMS));
|
| allow_exact_keyword_match_ = false;
|
| }
|
|
|
| + if (!state_changes.text_differs || !allow_keyword_ui_change ||
|
| + (state_changes.just_deleted_text && no_selection) ||
|
| + is_keyword_selected() || (paste_state_ != NONE))
|
| + return true;
|
| +
|
| + // If the user input a "?" at the beginning of the text, put them into
|
| + // keyword mode for their default search provider.
|
| + if ((state_changes.new_sel_start == 1) && (user_text_[0] == '?')) {
|
| + view_->SetUserText(user_text_.substr(1));
|
| + EnterKeywordModeForDefaultSearchProvider(
|
| + KeywordModeEntryMethod::QUESTION_MARK);
|
| + // Set the caret position to 0 without changing the user text.
|
| + view_->SetWindowTextAndCaretPos(view_->GetText(), 0, false, false);
|
| + return false;
|
| + }
|
| +
|
| // Change to keyword mode if the user is now pressing space after a keyword
|
| // name. Note that if this is the case, then even if there was no keyword
|
| // hint when we entered this function (e.g. if the user has used space to
|
| // replace some selected text that was adjoined to this keyword), there will
|
| // be one now because of the call to UpdatePopup() above; so it's safe for
|
| - // MaybeAcceptKeywordBySpace() to look at |keyword_| and |is_keyword_hint_| to
|
| - // determine what keyword, if any, is applicable.
|
| + // MaybeAcceptKeywordBySpace() to look at |keyword_| and |is_keyword_hint_|
|
| + // to determine what keyword, if any, is applicable.
|
| //
|
| // If MaybeAcceptKeywordBySpace() accepts the keyword and returns true, that
|
| // will have updated our state already, so in that case we don't also return
|
| // true from this function.
|
| - return !(text_differs && allow_keyword_ui_change && !just_deleted_text &&
|
| - no_selection && (selection_start == user_text_.length()) &&
|
| - MaybeAcceptKeywordBySpace(user_text_));
|
| + return (state_changes.new_sel_start != user_text_.length()) ||
|
| + !MaybeAcceptKeywordBySpace(user_text_);
|
| }
|
|
|
| // TODO(beaudoin): Merge OnPopupDataChanged with this method once the popup
|
| @@ -1376,11 +1438,10 @@ void OmniboxEditModel::RevertTemporaryText(bool revert_popup) {
|
| bool OmniboxEditModel::MaybeAcceptKeywordBySpace(
|
| const base::string16& new_text) {
|
| size_t keyword_length = new_text.length() - 1;
|
| - return (paste_state_ == NONE) && is_keyword_hint_ &&
|
| - (keyword_.length() == keyword_length) &&
|
| - IsSpaceCharForAcceptingKeyword(new_text[keyword_length]) &&
|
| - !new_text.compare(0, keyword_length, keyword_, 0, keyword_length) &&
|
| - AcceptKeyword(ENTERED_KEYWORD_MODE_VIA_SPACE_AT_END);
|
| + return is_keyword_hint_ && (keyword_.length() == keyword_length) &&
|
| + IsSpaceCharForAcceptingKeyword(new_text[keyword_length]) &&
|
| + !new_text.compare(0, keyword_length, keyword_, 0, keyword_length) &&
|
| + AcceptKeyword(KeywordModeEntryMethod::SPACE_AT_END);
|
| }
|
|
|
| bool OmniboxEditModel::CreatedKeywordSearchByInsertingSpaceInMiddle(
|
|
|