13f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/autocomplete/autocomplete_edit.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <string> 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/basictypes.h" 10731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/metrics/histogram.h" 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h" 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/utf_string_conversions.h" 13513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "chrome/app/chrome_command_ids.h" 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/autocomplete/autocomplete_classifier.h" 15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/autocomplete/autocomplete_edit_view.h" 16513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "chrome/browser/autocomplete/autocomplete_match.h" 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/autocomplete/autocomplete_popup_model.h" 1872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/autocomplete/autocomplete_popup_view.h" 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/autocomplete/keyword_provider.h" 20dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/autocomplete/search_provider.h" 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/command_updater.h" 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_omnibox_api.h" 233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/google/google_url_tracker.h" 24513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "chrome/browser/instant/instant_controller.h" 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/metrics/user_metrics.h" 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/net/predictor_api.h" 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/net/url_fixer_upper.h" 2821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h" 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/search_engines/template_url.h" 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/search_engines/template_url_model.h" 31ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/browser_list.h" 32dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/url_constants.h" 34ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_service.h" 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "googleurl/src/gurl.h" 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "googleurl/src/url_util.h" 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "third_party/skia/include/core/SkBitmap.h" 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch/////////////////////////////////////////////////////////////////////////////// 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// AutocompleteEditController 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteEditController::~AutocompleteEditController() { 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch/////////////////////////////////////////////////////////////////////////////// 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// AutocompleteEditModel::State 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteEditModel::State::State(bool user_input_in_progress, 4972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const string16& user_text, 5072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const string16& keyword, 5172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen bool is_keyword_hint) 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : user_input_in_progress(user_input_in_progress), 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch user_text(user_text), 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch keyword(keyword), 5572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen is_keyword_hint(is_keyword_hint) { 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteEditModel::State::~State() { 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch/////////////////////////////////////////////////////////////////////////////// 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// AutocompleteEditModel 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteEditModel::AutocompleteEditModel( 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutocompleteEditView* view, 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutocompleteEditController* controller, 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Profile* profile) 68dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen : ALLOW_THIS_IN_INITIALIZER_LIST( 69dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen autocomplete_controller_(new AutocompleteController(profile, this))), 70dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen view_(view), 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch popup_(NULL), 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch controller_(controller), 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch has_focus_(false), 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch user_input_in_progress_(false), 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch just_deleted_text_(false), 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch has_temporary_text_(false), 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch paste_state_(NONE), 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch control_key_state_(UP), 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch is_keyword_hint_(false), 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch paste_and_go_transition_(PageTransition::TYPED), 81dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen profile_(profile), 82ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen update_instant_(true), 83ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen allow_exact_keyword_match_(false), 84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen instant_complete_behavior_(INSTANT_COMPLETE_DELAYED) { 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteEditModel::~AutocompleteEditModel() { 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::SetProfile(Profile* profile) { 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(profile); 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile_ = profile; 93dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen autocomplete_controller_->SetProfile(profile); 94dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen popup_->set_profile(profile); 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst AutocompleteEditModel::State 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutocompleteEditModel::GetStateForTabSwitch() { 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Like typing, switching tabs "accepts" the temporary text as the user 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // text, because it makes little sense to have temporary text when the 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // popup is closed. 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (user_input_in_progress_) { 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Weird edge case to match other browsers: if the edit is empty, revert to 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the permanent text (so the user can get it back easily) but select it (so 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // on switching back, typing will "just work"). 10672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const string16 user_text(UserTextFromDisplayText(view_->GetText())); 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (user_text.empty()) { 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->RevertAll(); 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->SelectAll(true); 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch InternalSetUserText(user_text); 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 11572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return State(user_input_in_progress_, user_text_, keyword_, is_keyword_hint_); 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::RestoreState(const State& state) { 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Restore any user editing. 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (state.user_input_in_progress) { 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // NOTE: Be sure and set keyword-related state BEFORE invoking 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // DisplayTextFromUserText(), as its result depends upon this state. 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch keyword_ = state.keyword; 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch is_keyword_hint_ = state.is_keyword_hint; 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->SetUserText(state.user_text, 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DisplayTextFromUserText(state.user_text), false); 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1303345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickAutocompleteMatch AutocompleteEditModel::CurrentMatch() { 1313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick AutocompleteMatch match; 1323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick GetInfoForCurrentText(&match, NULL); 1333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return match; 1343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 1353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool AutocompleteEditModel::UpdatePermanentText( 13772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const string16& new_permanent_text) { 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // When there's a new URL, and the user is not editing anything or the edit 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // doesn't have focus, we want to revert the edit to show the new URL. (The 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // common case where the edit doesn't have focus is when the user has started 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // an edit and then abandoned it and clicked a link on the page.) 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const bool visibly_changed_permanent_text = 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (permanent_text_ != new_permanent_text) && 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (!user_input_in_progress_ || !has_focus_); 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch permanent_text_ = new_permanent_text; 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return visibly_changed_permanent_text; 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 150dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenGURL AutocompleteEditModel::PermanentURL() { 151dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return URLFixerUpper::FixupURL(UTF16ToUTF8(permanent_text_), std::string()); 152dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 153dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 15472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid AutocompleteEditModel::SetUserText(const string16& text) { 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetInputInProgress(true); 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch InternalSetUserText(text); 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch paste_state_ = NONE; 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch has_temporary_text_ = false; 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 161201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid AutocompleteEditModel::FinalizeInstantQuery( 16272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const string16& input_text, 16372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const string16& suggest_text, 16472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen bool skip_inline_autocomplete) { 16572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (skip_inline_autocomplete) { 16672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const string16 final_text = input_text + suggest_text; 16772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen view_->OnBeforePossibleChange(); 16872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen view_->SetWindowTextAndCaretPos(final_text, final_text.length()); 16972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen view_->OnAfterPossibleChange(); 170dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } else if (popup_->IsOpen()) { 171dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen SearchProvider* search_provider = 172dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen autocomplete_controller_->search_provider(); 173dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen search_provider->FinalizeInstantQuery(input_text, suggest_text); 17472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 175201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch} 176201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch 177ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid AutocompleteEditModel::SetSuggestedText( 178ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const string16& text, 179ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen InstantCompleteBehavior behavior) { 180ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen instant_complete_behavior_ = behavior; 181ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (instant_complete_behavior_ == INSTANT_COMPLETE_NOW) { 182ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!text.empty()) 183ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen FinalizeInstantQuery(view_->GetText(), text, false); 184ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen else 185ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen view_->SetInstantSuggestion(text, false); 186ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } else { 187ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK((behavior == INSTANT_COMPLETE_DELAYED) || 188ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen (behavior == INSTANT_COMPLETE_NEVER)); 189ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen view_->SetInstantSuggestion(text, behavior == INSTANT_COMPLETE_DELAYED); 190ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 191dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 192dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 193dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenbool AutocompleteEditModel::CommitSuggestedText(bool skip_inline_autocomplete) { 194dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (!controller_->GetInstant()) 195dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return false; 196dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 197dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const string16 suggestion = view_->GetInstantSuggestion(); 198dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (suggestion.empty()) 199dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return false; 200dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 201dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen FinalizeInstantQuery(view_->GetText(), suggestion, skip_inline_autocomplete); 202dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return true; 203dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 204dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 205dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenbool AutocompleteEditModel::AcceptCurrentInstantPreview() { 206dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return InstantController::CommitIfCurrent(controller_->GetInstant()); 207dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 208dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 209dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid AutocompleteEditModel::OnChanged() { 210dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen InstantController* instant = controller_->GetInstant(); 211dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen string16 suggested_text; 212dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen TabContentsWrapper* tab = controller_->GetTabContentsWrapper(); 213ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool might_support_instant = false; 214dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (update_instant_ && instant && tab) { 215dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (user_input_in_progress() && popup_->IsOpen()) { 216dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen AutocompleteMatch current_match = CurrentMatch(); 217dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (current_match.destination_url == PermanentURL()) { 218dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // The destination is the same as the current url. This typically 219dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // happens if the user presses the down error in the omnibox, in which 220dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // case we don't want to load a preview. 221dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen instant->DestroyPreviewContentsAndLeaveActive(); 222dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } else { 223dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen instant->Update(tab, CurrentMatch(), view_->GetText(), 224dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen UseVerbatimInstant(), &suggested_text); 225dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 226dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } else { 227dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen instant->DestroyPreviewContents(); 228dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 229ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen might_support_instant = instant->MightSupportInstant(); 230dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 231dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 232ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!might_support_instant) { 233ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Hide any suggestions we might be showing. 234ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen view_->SetInstantSuggestion(string16(), false); 235ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 236ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // No need to wait any longer for instant. 237ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen FinalizeInstantQuery(string16(), string16(), false); 238ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } else { 239ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen SetSuggestedText(suggested_text, instant_complete_behavior_); 240ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 241dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 242dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen controller_->OnChanged(); 243dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 244dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::GetDataForURLExport(GURL* url, 24672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen string16* title, 247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SkBitmap* favicon) { 248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutocompleteMatch match; 249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetInfoForCurrentText(&match, NULL); 250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *url = match.destination_url; 25172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (*url == URLFixerUpper::FixupURL(UTF16ToUTF8(permanent_text_), 2523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick std::string())) { 253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *title = controller_->GetTitle(); 254ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen *favicon = controller_->GetFavicon(); 255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 258201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochbool AutocompleteEditModel::UseVerbatimInstant() { 25921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#if defined(OS_MACOSX) 26021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // TODO(suzhe): Fix Mac port to display Instant suggest in a separated NSView, 26121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // so that we can display instant suggest along with composition text. 262dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const AutocompleteInput& input = autocomplete_controller_->input(); 26321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (input.initial_prevent_inline_autocomplete()) 26421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen return true; 26521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#endif 26621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 2673f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // The value of input.initial_prevent_inline_autocomplete() is determined by 2683f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // following conditions: 2693f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // 1. If the caret is at the end of the text (checked below). 2703f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // 2. If it's in IME composition mode. 2713f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // As we use a separated widget for displaying the instant suggest, it won't 2723f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // interfere with IME composition, so we don't need to care about the value of 2733f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // input.initial_prevent_inline_autocomplete() here. 27421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (view_->DeleteAtEndPressed() || (popup_->selected_line() != 0) || 27521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen just_deleted_text_) 276201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch return true; 277201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch 27872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen string16::size_type start, end; 279201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch view_->GetSelectionBounds(&start, &end); 280201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch return (start != end) || (start != view_->GetText().size()); 2814a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} 2824a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 28372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenstring16 AutocompleteEditModel::GetDesiredTLD() const { 2843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Tricky corner case: The user has typed "foo" and currently sees an inline 2853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // autocomplete suggestion of "foo.net". He now presses ctrl-a (e.g. to 2863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // select all, on Windows). If we treat the ctrl press as potentially for the 2873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // sake of ctrl-enter, then we risk "www.foo.com" being promoted as the best 2883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // match. This would make the autocompleted text disappear, leaving our user 2893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // feeling very confused when the wrong text gets highlighted. 2903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // 2913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Thus, we only treat the user as pressing ctrl-enter when the user presses 2923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // ctrl without any fragile state built up in the omnibox: 2933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // * the contents of the omnibox have not changed since the keypress, 2943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // * there is no autocompleted text visible, and 2953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // * the user is not typing a keyword query. 2963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return (control_key_state_ == DOWN_WITHOUT_CHANGE && 2973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick inline_autocomplete_text_.empty() && !KeywordIsSelected())? 29872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ASCIIToUTF16("com") : string16(); 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool AutocompleteEditModel::CurrentTextIsURL() const { 302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If !user_input_in_progress_, the permanent text is showing, which should 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // always be a URL, so no further checking is needed. By avoiding checking in 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // this case, we avoid calling into the autocomplete providers, and thus 305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // initializing the history system, as long as possible, which speeds startup. 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!user_input_in_progress_) 307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutocompleteMatch match; 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetInfoForCurrentText(&match, NULL); 311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return match.transition == PageTransition::TYPED; 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 314c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteMatch::Type AutocompleteEditModel::CurrentTextType() const { 315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutocompleteMatch match; 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetInfoForCurrentText(&match, NULL); 317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return match.type; 318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::AdjustTextForCopy(int sel_min, 321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool is_all_selected, 32272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen string16* text, 323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GURL* url, 324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool* write_url) { 325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *write_url = false; 326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (sel_min != 0) 328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We can't use CurrentTextIsURL() or GetDataForURLExport() because right now 331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the user is probably holding down control to cause the copy, which will 332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // screw up our calculation of the desired_tld. 333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!GetURLForText(*text, url)) 334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; // Can't be parsed as a url, no need to adjust text. 335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!user_input_in_progress() && is_all_selected) { 337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The user selected all the text and has not edited it. Use the url as the 338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // text so that if the scheme was stripped it's added back, and the url 339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // is unescaped (we escape parts of the url for display). 34072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen *text = UTF8ToUTF16(url->spec()); 341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *write_url = true; 342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Prefix the text with 'http://' if the text doesn't start with 'http://', 346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the text parses as a url with a scheme of http, the user selected the 347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // entire host, and the user hasn't edited the host or manually removed the 348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // scheme. 349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GURL perm_url; 350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (GetURLForText(permanent_text_, &perm_url) && 351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch perm_url.SchemeIs(chrome::kHttpScheme) && 352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch url->SchemeIs(chrome::kHttpScheme) && 353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch perm_url.host() == url->host()) { 354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *write_url = true; 355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 35672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen string16 http = ASCIIToUTF16(chrome::kHttpScheme) + 35772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ASCIIToUTF16(chrome::kStandardSchemeSeparator); 358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (text->compare(0, http.length(), http) != 0) 359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *text = http + *text; 360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::SetInputInProgress(bool in_progress) { 364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (user_input_in_progress_ == in_progress) 365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch user_input_in_progress_ = in_progress; 368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch controller_->OnInputInProgress(in_progress); 369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::Revert() { 372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetInputInProgress(false); 373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch paste_state_ = NONE; 37472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen InternalSetUserText(string16()); 375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch keyword_.clear(); 376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch is_keyword_hint_ = false; 377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch has_temporary_text_ = false; 378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->SetWindowTextAndCaretPos(permanent_text_, 379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch has_focus_ ? permanent_text_.length() : 0); 380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::StartAutocomplete( 3833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick bool has_selected_text, 384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool prevent_inline_autocomplete) const { 38572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen bool keyword_is_selected = KeywordIsSelected(); 386dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen popup_->SetHoveredLine(AutocompletePopupModel::kNoMatch); 387dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // We don't explicitly clear AutocompletePopupModel::manually_selected_match, 388dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // as Start ends up invoking AutocompletePopupModel::OnResultChanged which 389dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // clears it. 390dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen autocomplete_controller_->Start( 391dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen user_text_, GetDesiredTLD(), 392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prevent_inline_autocomplete || just_deleted_text_ || 3933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick (has_selected_text && inline_autocomplete_text_.empty()) || 394ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen (paste_state_ != NONE), keyword_is_selected, 395ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen keyword_is_selected || allow_exact_keyword_match_, 396ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen AutocompleteInput::ALL_MATCHES); 397dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 398dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 399dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid AutocompleteEditModel::StopAutocomplete() { 400dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (popup_->IsOpen() && update_instant_) { 401dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen InstantController* instant = controller_->GetInstant(); 402dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (instant && !instant->commit_on_mouse_up()) 403dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen instant->DestroyPreviewContents(); 404dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 405dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 406dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen autocomplete_controller_->Stop(true); 407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 40972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool AutocompleteEditModel::CanPasteAndGo(const string16& text) const { 410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!view_->GetCommandUpdater()->IsCommandEnabled(IDC_OPEN_CURRENT_URL)) 411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutocompleteMatch match; 41472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen profile_->GetAutocompleteClassifier()->Classify(text, string16(), false, 415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &match, &paste_and_go_alternate_nav_url_); 416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch paste_and_go_url_ = match.destination_url; 417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch paste_and_go_transition_ = match.transition; 418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return paste_and_go_url_.is_valid(); 419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::PasteAndGo() { 422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The final parameter to OpenURL, keyword, is not quite correct here: it's 423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // possible to "paste and go" a string that contains a keyword. This is 424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // enough of an edge case that we ignore this possibility. 425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->RevertAll(); 426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->OpenURL(paste_and_go_url_, CURRENT_TAB, paste_and_go_transition_, 427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch paste_and_go_alternate_nav_url_, AutocompletePopupModel::kNoMatch, 42872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen string16()); 429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::AcceptInput(WindowOpenDisposition disposition, 432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool for_drop) { 433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Get the URL and transition type for the selected entry. 434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutocompleteMatch match; 435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GURL alternate_nav_url; 436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetInfoForCurrentText(&match, &alternate_nav_url); 437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!match.destination_url.is_valid()) 439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 441513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if ((match.transition == PageTransition::TYPED) && (match.destination_url == 44272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen URLFixerUpper::FixupURL(UTF16ToUTF8(permanent_text_), std::string()))) { 443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // When the user hit enter on the existing permanent URL, treat it like a 444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // reload for scoring purposes. We could detect this by just checking 445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // user_input_in_progress_, but it seems better to treat "edits" that end 446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // up leaving the URL unchanged (e.g. deleting the last character and then 447513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // retyping it) as reloads too. We exclude non-TYPED transitions because if 448513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // the transition is GENERATED, the user input something that looked 449513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // different from the current URL, even if it wound up at the same place 450513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // (e.g. manually retyping the same search query), and it seems wrong to 451513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // treat this as a reload. 452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch match.transition = PageTransition::RELOAD; 453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (for_drop || ((paste_state_ != NONE) && 454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch match.is_history_what_you_typed_match)) { 455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // When the user pasted in a URL and hit enter, score it like a link click 456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // rather than a normal typed URL, so it doesn't get inline autocompleted 457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // as aggressively later. 458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch match.transition = PageTransition::LINK; 459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 4613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (match.type == AutocompleteMatch::SEARCH_WHAT_YOU_TYPED || 4623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick match.type == AutocompleteMatch::SEARCH_HISTORY || 4633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick match.type == AutocompleteMatch::SEARCH_SUGGEST) { 4643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const TemplateURL* default_provider = 4653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick profile_->GetTemplateURLModel()->GetDefaultSearchProvider(); 4663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (default_provider && default_provider->url() && 46772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen default_provider->url()->HasGoogleBaseURLs()) { 4683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick GoogleURLTracker::GoogleURLSearchCommitted(); 46972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD) 47072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // TODO(pastarmovj): Remove these metrics once we have proven that (close 47172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // to) none searches that should have RLZ are sent out without one. 47272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen default_provider->url()->CollectRLZMetrics(); 47372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#endif 47472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 4753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->OpenURL(match.destination_url, disposition, match.transition, 477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch alternate_nav_url, AutocompletePopupModel::kNoMatch, 47872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen is_keyword_hint_ ? string16() : keyword_); 479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::OpenURL(const GURL& url, 482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WindowOpenDisposition disposition, 483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PageTransition::Type transition, 484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const GURL& alternate_nav_url, 485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t index, 48672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const string16& keyword) { 487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We only care about cases where there is a selection (i.e. the popup is 488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // open). 489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (popup_->IsOpen()) { 490dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen AutocompleteLog log(autocomplete_controller_->input().text(), 491dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen autocomplete_controller_->input().type(), 492dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen popup_->selected_line(), 0, result()); 493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (index != AutocompletePopupModel::kNoMatch) 494dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen log.selected_index = index; 495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else if (!has_temporary_text_) 496dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen log.inline_autocompleted_length = inline_autocomplete_text_.length(); 497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationService::current()->Notify( 498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationType::OMNIBOX_OPENED_URL, Source<Profile>(profile_), 499dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen Details<AutocompleteLog>(&log)); 500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TemplateURLModel* template_url_model = profile_->GetTemplateURLModel(); 503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (template_url_model && !keyword.empty()) { 504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const TemplateURL* const template_url = 505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch template_url_model->GetTemplateURLForKeyword(keyword); 506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Special case for extension keywords. Don't increment usage count for 508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // these. 509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (template_url && template_url->IsExtensionKeyword()) { 510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutocompleteMatch current_match; 511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetInfoForCurrentText(¤t_match, NULL); 512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const AutocompleteMatch& match = 514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch index == AutocompletePopupModel::kNoMatch ? 515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_match : result().match_at(index); 516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Strip the keyword + leading space off the input. 518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t prefix_length = match.template_url->keyword().size() + 1; 519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ExtensionOmniboxEventRouter::OnInputEntered( 520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile_, match.template_url->GetExtensionId(), 52172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen UTF16ToUTF8(match.fill_into_edit.substr(prefix_length))); 522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->RevertAll(); 523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (template_url) { 527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UserMetrics::RecordAction(UserMetricsAction("AcceptedKeyword"), profile_); 528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch template_url_model->IncrementUsageCount(template_url); 529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // NOTE: We purposefully don't increment the usage count of the default 532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // search engine, if applicable; see comments in template_url.h. 533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5353f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen if (disposition != NEW_BACKGROUND_TAB) { 536dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen update_instant_ = false; 537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->RevertAll(); // Revert the box to its unedited state 5383f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen } 539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch controller_->OnAutocompleteAccept(url, disposition, transition, 540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch alternate_nav_url); 541dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 542dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen InstantController* instant = controller_->GetInstant(); 543dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (instant && !popup_->IsOpen()) 544dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen instant->DestroyPreviewContents(); 545dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen update_instant_ = true; 546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 54872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool AutocompleteEditModel::AcceptKeyword() { 54972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen DCHECK(is_keyword_hint_ && !keyword_.empty()); 55072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->OnBeforePossibleChange(); 55272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen view_->SetWindowTextAndCaretPos(string16(), 0); 553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch is_keyword_hint_ = false; 554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->OnAfterPossibleChange(); 555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch just_deleted_text_ = false; // OnAfterPossibleChange() erroneously sets this 556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // since the edit contents have disappeared. It 557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // doesn't really matter, but we clear it to be 558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // consistent. 559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UserMetrics::RecordAction(UserMetricsAction("AcceptedKeywordHint"), profile_); 56072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return true; 561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 56372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid AutocompleteEditModel::ClearKeyword(const string16& visible_text) { 564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->OnBeforePossibleChange(); 56572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const string16 window_text(keyword_ + visible_text); 566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->SetWindowTextAndCaretPos(window_text.c_str(), keyword_.length()); 567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch keyword_.clear(); 56872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen is_keyword_hint_ = false; 569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->OnAfterPossibleChange(); 570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch just_deleted_text_ = true; // OnAfterPossibleChange() fails to clear this 571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // since the edit contents have actually grown 572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // longer. 573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 575c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst AutocompleteResult& AutocompleteEditModel::result() const { 576dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return autocomplete_controller_->result(); 577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::OnSetFocus(bool control_down) { 580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch has_focus_ = true; 581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch control_key_state_ = control_down ? DOWN_WITHOUT_CHANGE : UP; 5823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick NotificationService::current()->Notify( 5833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick NotificationType::AUTOCOMPLETE_EDIT_FOCUSED, 5843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick Source<AutocompleteEditModel>(this), 5853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick NotificationService::NoDetails()); 586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 588dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid AutocompleteEditModel::OnWillKillFocus( 589dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen gfx::NativeView view_gaining_focus) { 590ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen SetSuggestedText(string16(), INSTANT_COMPLETE_NOW); 591dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 592dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen InstantController* instant = controller_->GetInstant(); 593dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (instant) 594dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen instant->OnAutocompleteLostFocus(view_gaining_focus); 595dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 596dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::OnKillFocus() { 598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch has_focus_ = false; 599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch control_key_state_ = UP; 600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch paste_state_ = NONE; 601c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 603c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool AutocompleteEditModel::OnEscapeKeyPressed() { 604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (has_temporary_text_) { 605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutocompleteMatch match; 606dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen InfoForCurrentSelection(&match, NULL); 607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (match.destination_url != original_url_) { 60872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen RevertTemporaryText(true); 609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 610c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the user wasn't editing, but merely had focus in the edit, allow <esc> 614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // to be processed as an accelerator, so it can still be used to stop a load. 615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // When the permanent text isn't all selected we still fall through to the 616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // SelectAll() call below so users can arrow around in the text and then hit 617c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // <esc> to quickly replace all the text; this matches IE. 618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!user_input_in_progress_ && view_->IsSelectAll()) 619c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->RevertAll(); 622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->SelectAll(true); 623c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 624c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::OnControlKeyChanged(bool pressed) { 627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Don't change anything unless the key state is actually toggling. 628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (pressed == (control_key_state_ == UP)) { 629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ControlKeyState old_state = control_key_state_; 630c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch control_key_state_ = pressed ? DOWN_WITHOUT_CHANGE : UP; 631c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if ((control_key_state_ == DOWN_WITHOUT_CHANGE) && has_temporary_text_) { 632c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Arrowing down and then hitting control accepts the temporary text as 633c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the input text. 634c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch InternalSetUserText(UserTextFromDisplayText(view_->GetText())); 635c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch has_temporary_text_ = false; 6363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (KeywordIsSelected()) 6373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick AcceptKeyword(); 638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 639c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if ((old_state != DOWN_WITH_CHANGE) && popup_->IsOpen()) { 640c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Autocomplete history provider results may change, so refresh the 641c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // popup. This will force user_input_in_progress_ to true, but if the 642c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // popup is open, that should have already been the case. 643c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->UpdatePopup(); 644c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 645c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 647c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 648c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::OnUpOrDownKeyPressed(int count) { 649c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // NOTE: This purposefully don't trigger any code that resets paste_state_. 650c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!popup_->IsOpen()) { 652c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!query_in_progress()) { 653c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The popup is neither open nor working on a query already. So, start an 654c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // autocomplete query for the current text. This also sets 655c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // user_input_in_progress_ to true, which we want: if the user has started 656c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // to interact with the popup, changing the permanent_text_ shouldn't 657c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // change the displayed text. 658c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Note: This does not force the popup to open immediately. 659c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(pkasting): We should, in fact, force this particular query to open 660c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the popup immediately. 661c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!user_input_in_progress_) 662c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch InternalSetUserText(permanent_text_); 663c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->UpdatePopup(); 664c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 665c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(pkasting): The popup is working on a query but is not open. We 666c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // should force it to open immediately. 667c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 668c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 669c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The popup is open, so the user should be able to interact with it 670c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // normally. 671c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch popup_->Move(count); 672c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 673c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 674c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 675c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::OnPopupDataChanged( 67672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const string16& text, 677c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GURL* destination_for_temporary_text_change, 67872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const string16& keyword, 679c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool is_keyword_hint) { 680c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Update keyword/hint-related local state. 681c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool keyword_state_changed = (keyword_ != keyword) || 682c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ((is_keyword_hint_ != is_keyword_hint) && !keyword.empty()); 683c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (keyword_state_changed) { 684c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch keyword_ = keyword; 685c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch is_keyword_hint_ = is_keyword_hint; 68672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 68772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // |is_keyword_hint_| should always be false if |keyword_| is empty. 68872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen DCHECK(!keyword_.empty() || !is_keyword_hint_); 689c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 690c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 691c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Handle changes to temporary text. 692c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (destination_for_temporary_text_change != NULL) { 693c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const bool save_original_selection = !has_temporary_text_; 694c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (save_original_selection) { 695c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Save the original selection and URL so it can be reverted later. 696c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch has_temporary_text_ = true; 697c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch original_url_ = *destination_for_temporary_text_change; 69872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen inline_autocomplete_text_.clear(); 699c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 700c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (control_key_state_ == DOWN_WITHOUT_CHANGE) { 701c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Arrowing around the popup cancels control-enter. 702c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch control_key_state_ = DOWN_WITH_CHANGE; 703c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Now things are a bit screwy: the desired_tld has changed, but if we 704c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // update the popup, the new order of entries won't match the old, so the 705c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // user's selection gets screwy; and if we don't update the popup, and the 706c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // user reverts, then the selected item will be as if control is still 707c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // pressed, even though maybe it isn't any more. There is no obvious 708c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // right answer here :( 709c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 710c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->OnTemporaryTextMaybeChanged(DisplayTextFromUserText(text), 711c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_original_selection); 712c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 713c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 714c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 71572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen bool call_controller_onchanged = true; 71672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen inline_autocomplete_text_ = text; 71772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (view_->OnInlineAutocompleteTextMaybeChanged( 71872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen DisplayTextFromUserText(user_text_ + inline_autocomplete_text_), 71972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen DisplayTextFromUserText(user_text_).length())) 72072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen call_controller_onchanged = false; 72172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 72272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // If |has_temporary_text_| is true, then we previously had a manual selection 72372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // but now don't (or |destination_for_temporary_text_change| would have been 72472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // non-NULL). This can happen when deleting the selected item in the popup. 72572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // In this case, we've already reverted the popup to the default match, so we 72672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // need to revert ourselves as well. 72772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (has_temporary_text_) { 72872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen RevertTemporaryText(false); 72972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen call_controller_onchanged = false; 730c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 731c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 73272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // We need to invoke OnChanged in case the destination url changed (as could 73372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // happen when control is toggled). 73472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (call_controller_onchanged) 735dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen OnChanged(); 736c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 737c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 73872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool AutocompleteEditModel::OnAfterPossibleChange( 73972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const string16& new_text, 740ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen size_t selection_start, 741ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen size_t selection_end, 74272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen bool selection_differs, 74372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen bool text_differs, 74472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen bool just_deleted_text, 74572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen bool allow_keyword_ui_change) { 746c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Update the paste state as appropriate: if we're just finishing a paste 747c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // that replaced all the text, preserve that information; otherwise, if we've 748c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // made some other edit, clear paste tracking. 74972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (paste_state_ == PASTING) 75072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen paste_state_ = PASTED; 751c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else if (text_differs) 752c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch paste_state_ = NONE; 753c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Modifying the selection counts as accepting the autocompleted text. 7553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const bool user_text_changed = 7563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick text_differs || (selection_differs && !inline_autocomplete_text_.empty()); 7573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 758c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If something has changed while the control key is down, prevent 759c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // "ctrl-enter" until the control key is released. When we do this, we need 760c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // to update the popup if it's open, since the desired_tld will have changed. 761c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if ((text_differs || selection_differs) && 762c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (control_key_state_ == DOWN_WITHOUT_CHANGE)) { 763c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch control_key_state_ = DOWN_WITH_CHANGE; 764c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!text_differs && !popup_->IsOpen()) 765c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; // Don't open the popup for no reason. 7663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } else if (!user_text_changed) { 767c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 768c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 769c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 77072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const string16 old_user_text = user_text_; 7713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // If the user text has not changed, we do not want to change the model's 7723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // state associated with the text. Otherwise, we can get surprising behavior 7733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // where the autocompleted text unexpectedly reappears, e.g. crbug.com/55983 7743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (user_text_changed) { 7753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick InternalSetUserText(UserTextFromDisplayText(new_text)); 7763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick has_temporary_text_ = false; 777c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Track when the user has deleted text so we won't allow inline 7793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // autocomplete. 7803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick just_deleted_text_ = just_deleted_text; 7813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 782c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 783ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const bool no_selection = selection_start == selection_end; 784ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 785ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Update the popup for the change, in the process changing to keyword mode 786ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // if the user hit space in mid-string after a keyword. 787ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // |allow_exact_keyword_match_| will be used by StartAutocomplete() method, 788ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // which will be called by |view_->UpdatePopup()|. So we can safely clear 789ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // this flag afterwards. 790ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen allow_exact_keyword_match_ = 791ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen text_differs && allow_keyword_ui_change && 792ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen !just_deleted_text && no_selection && 793ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ShouldAllowExactKeywordMatch(old_user_text, user_text_, selection_start); 794c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->UpdatePopup(); 795ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen allow_exact_keyword_match_ = false; 796c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 79772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Change to keyword mode if the user has typed a keyword name and is now 79872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // pressing space after the name. Accepting the keyword will update our 79972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // state, so in that case there's no need to also return true here. 80072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return !(text_differs && allow_keyword_ui_change && !just_deleted_text && 801ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen no_selection && selection_start == user_text_.length() && 80272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen MaybeAcceptKeywordBySpace(old_user_text, user_text_)); 803c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 804c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 8053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid AutocompleteEditModel::PopupBoundsChangedTo(const gfx::Rect& bounds) { 806dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen InstantController* instant = controller_->GetInstant(); 807dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (instant) 808dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen instant->SetOmniboxBounds(bounds); 8093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 8103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 811c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Return true if the suggestion type warrants a TCP/IP preconnection. 812c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// i.e., it is now highly likely that the user will select the related domain. 813c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic bool IsPreconnectable(AutocompleteMatch::Type type) { 814c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UMA_HISTOGRAM_ENUMERATION("Autocomplete.MatchType", type, 815c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutocompleteMatch::NUM_TYPES); 816c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch switch (type) { 817c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Matches using the user's default search engine. 818c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case AutocompleteMatch::SEARCH_WHAT_YOU_TYPED: 819c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case AutocompleteMatch::SEARCH_HISTORY: 820c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case AutocompleteMatch::SEARCH_SUGGEST: 821c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // A match that uses a non-default search engine (e.g. for tab-to-search). 822c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case AutocompleteMatch::SEARCH_OTHER_ENGINE: 823c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 824c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 825c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default: 826c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 827c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 828c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 829c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 830dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid AutocompleteEditModel::OnResultChanged(bool default_match_changed) { 831dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const bool was_open = popup_->IsOpen(); 832dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (default_match_changed) { 83372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen string16 inline_autocomplete_text; 83472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen string16 keyword; 83572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen bool is_keyword_hint = false; 836dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const AutocompleteResult& result = this->result(); 83772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const AutocompleteResult::const_iterator match(result.default_match()); 83872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (match != result.end()) { 83972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if ((match->inline_autocomplete_offset != string16::npos) && 84072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen (match->inline_autocomplete_offset < 84172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen match->fill_into_edit.length())) { 84272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen inline_autocomplete_text = 84372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen match->fill_into_edit.substr(match->inline_autocomplete_offset); 84472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 845c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 84672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!match->destination_url.SchemeIs(chrome::kExtensionScheme)) { 84772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Warm up DNS Prefetch cache, or preconnect to a search service. 84872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen chrome_browser_net::AnticipateOmniboxUrl(match->destination_url, 84972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen IsPreconnectable(match->type)); 85072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 851c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 85272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // We could prefetch the alternate nav URL, if any, but because there 85372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // can be many of these as a user types an initial series of characters, 85472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // the OS DNS cache could suffer eviction problems for minimal gain. 855c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 85672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen is_keyword_hint = popup_->GetKeywordForMatch(*match, &keyword); 85772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 85872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen popup_->OnResultChanged(); 85972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen OnPopupDataChanged(inline_autocomplete_text, NULL, keyword, 86072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen is_keyword_hint); 86172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } else { 86272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen popup_->OnResultChanged(); 863c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 864c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 865dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (popup_->IsOpen()) { 86672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen PopupBoundsChangedTo(popup_->view()->GetTargetBounds()); 86772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } else if (was_open) { 86872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Accepts the temporary text as the user text, because it makes little 86972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // sense to have temporary text when the popup is closed. 87072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen InternalSetUserText(UserTextFromDisplayText(view_->GetText())); 87172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen has_temporary_text_ = false; 87272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen PopupBoundsChangedTo(gfx::Rect()); 87372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 874c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 875c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 876dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenbool AutocompleteEditModel::query_in_progress() const { 877dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return !autocomplete_controller_->done(); 878dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 879dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 88072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid AutocompleteEditModel::InternalSetUserText(const string16& text) { 881c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch user_text_ = text; 882c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch just_deleted_text_ = false; 883c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch inline_autocomplete_text_.clear(); 884c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 885c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 8863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool AutocompleteEditModel::KeywordIsSelected() const { 88772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return !is_keyword_hint_ && !keyword_.empty(); 8883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 8893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 89072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenstring16 AutocompleteEditModel::DisplayTextFromUserText( 89172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const string16& text) const { 8923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return KeywordIsSelected() ? 89372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen KeywordProvider::SplitReplacementStringFromInput(text, false) : text; 894c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 895c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 89672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenstring16 AutocompleteEditModel::UserTextFromDisplayText( 89772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const string16& text) const { 89872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return KeywordIsSelected() ? (keyword_ + char16(' ') + text) : text; 899c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 900c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 901dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid AutocompleteEditModel::InfoForCurrentSelection( 902dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen AutocompleteMatch* match, 903dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen GURL* alternate_nav_url) const { 904dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen DCHECK(match != NULL); 905dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const AutocompleteResult& result = this->result(); 906dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (!autocomplete_controller_->done()) { 907dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // It's technically possible for |result| to be empty if no provider returns 908dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // a synchronous result but the query has not completed synchronously; 909dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // pratically, however, that should never actually happen. 910dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (result.empty()) 911dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return; 912dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // The user cannot have manually selected a match, or the query would have 913dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // stopped. So the default match must be the desired selection. 914dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen *match = *result.default_match(); 915dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } else { 916dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen CHECK(popup_->IsOpen()); 917dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // If there are no results, the popup should be closed (so we should have 918dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // failed the CHECK above), and URLsForDefaultMatch() should have been 919dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // called instead. 920dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen CHECK(!result.empty()); 921dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen CHECK(popup_->selected_line() < result.size()); 922dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen *match = result.match_at(popup_->selected_line()); 923dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 924dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (alternate_nav_url && popup_->manually_selected_match().empty()) 925dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen *alternate_nav_url = result.alternate_nav_url(); 926dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 927dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 928c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::GetInfoForCurrentText( 929c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutocompleteMatch* match, 930c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GURL* alternate_nav_url) const { 931c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (popup_->IsOpen() || query_in_progress()) { 932dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen InfoForCurrentSelection(match, alternate_nav_url); 933c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 934c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile_->GetAutocompleteClassifier()->Classify( 9354a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch UserTextFromDisplayText(view_->GetText()), GetDesiredTLD(), true, 9364a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch match, alternate_nav_url); 937c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 938c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 939513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 94072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool AutocompleteEditModel::GetURLForText(const string16& text, 94121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen GURL* url) const { 94221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen GURL parsed_url; 94321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen const AutocompleteInput::Type type = AutocompleteInput::Parse( 94472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen UserTextFromDisplayText(text), string16(), NULL, NULL, &parsed_url); 94521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (type != AutocompleteInput::URL) 94621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen return false; 94721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 94821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen *url = parsed_url; 94921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen return true; 95021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen} 95121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 95272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid AutocompleteEditModel::RevertTemporaryText(bool revert_popup) { 95372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // The user typed something, then selected a different item. Restore the 95472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // text they typed and change back to the default item. 95572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // NOTE: This purposefully does not reset paste_state_. 95672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen just_deleted_text_ = false; 95772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen has_temporary_text_ = false; 95872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (revert_popup) 95972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen popup_->ResetToDefaultMatch(); 96072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen view_->OnRevertTemporaryText(); 96172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 96272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 96372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool AutocompleteEditModel::MaybeAcceptKeywordBySpace( 96472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const string16& old_user_text, 96572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const string16& new_user_text) { 96672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return (paste_state_ == NONE) && is_keyword_hint_ && !keyword_.empty() && 96772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen inline_autocomplete_text_.empty() && new_user_text.length() >= 2 && 96872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen IsSpaceCharForAcceptingKeyword(*new_user_text.rbegin()) && 96972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen !IsWhitespace(*(new_user_text.rbegin() + 1)) && 97072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen (old_user_text.length() + 1 >= new_user_text.length()) && 97172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen !new_user_text.compare(0, new_user_text.length() - 1, old_user_text, 97272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 0, new_user_text.length() - 1) && 97372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen AcceptKeyword(); 97472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 97572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 976ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool AutocompleteEditModel::ShouldAllowExactKeywordMatch( 977ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const string16& old_user_text, 978ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const string16& new_user_text, 979ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen size_t caret_position) { 980ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Check simple conditions first. 981ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (paste_state_ != NONE || caret_position < 2 || 982ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen new_user_text.length() <= caret_position || 983ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen old_user_text.length() < caret_position || 984ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen !IsSpaceCharForAcceptingKeyword(new_user_text[caret_position - 1]) || 985ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen IsSpaceCharForAcceptingKeyword(new_user_text[caret_position - 2]) || 986ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen new_user_text.compare(0, caret_position - 1, old_user_text, 987ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 0, caret_position - 1) || 988ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen !new_user_text.compare(caret_position - 1, 989ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen new_user_text.length() - caret_position + 1, 990ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen old_user_text, caret_position - 1, 991ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen old_user_text.length() - caret_position + 1)) { 992ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return false; 993ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 994ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 995ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Then check if the text before the inserted space matches a keyword. 996ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen string16 keyword; 997ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen TrimWhitespace(new_user_text.substr(0, caret_position - 1), 998ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen TRIM_LEADING, &keyword); 999ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 1000ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Only allow exact keyword match if |keyword| represents a keyword hint. 1001ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return keyword.length() && popup_->GetKeywordForText(keyword, &keyword); 1002ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 1003ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 100472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// static 100572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool AutocompleteEditModel::IsSpaceCharForAcceptingKeyword(wchar_t c) { 100672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen switch (c) { 100772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen case 0x0020: // Space 100872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen case 0x3000: // Ideographic Space 100972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return true; 101072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen default: 101172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return false; 1012513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch } 1013513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch} 1014