autocomplete_edit.cc revision 513209b27ff55e2841eac0e4120199c23acce758
1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 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" 18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/autocomplete/keyword_provider.h" 193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/browser_list.h" 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/command_updater.h" 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_omnibox_api.h" 223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/google/google_url_tracker.h" 23513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "chrome/browser/instant/instant_controller.h" 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/metrics/user_metrics.h" 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/net/predictor_api.h" 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/net/url_fixer_upper.h" 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/profile.h" 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/search_engines/template_url.h" 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/search_engines/template_url_model.h" 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/notification_service.h" 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/url_constants.h" 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "googleurl/src/gurl.h" 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "googleurl/src/url_util.h" 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "third_party/skia/include/core/SkBitmap.h" 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch/////////////////////////////////////////////////////////////////////////////// 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// AutocompleteEditController 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteEditController::~AutocompleteEditController() { 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch/////////////////////////////////////////////////////////////////////////////// 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// AutocompleteEditModel::State 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteEditModel::State::State(bool user_input_in_progress, 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::wstring& user_text, 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::wstring& keyword, 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool is_keyword_hint, 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch KeywordUIState keyword_ui_state) 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : user_input_in_progress(user_input_in_progress), 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch user_text(user_text), 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch keyword(keyword), 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch is_keyword_hint(is_keyword_hint), 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch keyword_ui_state(keyword_ui_state) { 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteEditModel::State::~State() { 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch/////////////////////////////////////////////////////////////////////////////// 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// AutocompleteEditModel 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteEditModel::AutocompleteEditModel( 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutocompleteEditView* view, 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutocompleteEditController* controller, 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Profile* profile) 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : view_(view), 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch popup_(NULL), 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch controller_(controller), 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch has_focus_(false), 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch user_input_in_progress_(false), 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch just_deleted_text_(false), 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch has_temporary_text_(false), 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch original_keyword_ui_state_(NORMAL), 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch paste_state_(NONE), 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch control_key_state_(UP), 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch is_keyword_hint_(false), 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch keyword_ui_state_(NORMAL), 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch paste_and_go_transition_(PageTransition::TYPED), 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile_(profile) { 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteEditModel::~AutocompleteEditModel() { 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::SetPopupModel(AutocompletePopupModel* popup_model) { 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch popup_ = popup_model; 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch registrar_.Add(this, 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationType::AUTOCOMPLETE_CONTROLLER_DEFAULT_MATCH_UPDATED, 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Source<AutocompleteController>(popup_->autocomplete_controller())); 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::SetProfile(Profile* profile) { 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(profile); 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile_ = profile; 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch popup_->SetProfile(profile); 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst AutocompleteEditModel::State 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutocompleteEditModel::GetStateForTabSwitch() { 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Like typing, switching tabs "accepts" the temporary text as the user 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // text, because it makes little sense to have temporary text when the 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // popup is closed. 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (user_input_in_progress_) { 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Weird edge case to match other browsers: if the edit is empty, revert to 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the permanent text (so the user can get it back easily) but select it (so 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // on switching back, typing will "just work"). 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::wstring user_text(UserTextFromDisplayText(view_->GetText())); 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (user_text.empty()) { 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->RevertAll(); 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->SelectAll(true); 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch InternalSetUserText(user_text); 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return State(user_input_in_progress_, user_text_, keyword_, is_keyword_hint_, 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch keyword_ui_state_); 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::RestoreState(const State& state) { 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Restore any user editing. 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (state.user_input_in_progress) { 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // NOTE: Be sure and set keyword-related state BEFORE invoking 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // DisplayTextFromUserText(), as its result depends upon this state. 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch keyword_ = state.keyword; 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch is_keyword_hint_ = state.is_keyword_hint; 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch keyword_ui_state_ = state.keyword_ui_state; 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->SetUserText(state.user_text, 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DisplayTextFromUserText(state.user_text), false); 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1343345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickAutocompleteMatch AutocompleteEditModel::CurrentMatch() { 1353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick AutocompleteMatch match; 1363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick GetInfoForCurrentText(&match, NULL); 1373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return match; 1383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 1393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool AutocompleteEditModel::UpdatePermanentText( 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::wstring& new_permanent_text) { 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // When there's a new URL, and the user is not editing anything or the edit 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // doesn't have focus, we want to revert the edit to show the new URL. (The 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // common case where the edit doesn't have focus is when the user has started 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // an edit and then abandoned it and clicked a link on the page.) 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const bool visibly_changed_permanent_text = 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (permanent_text_ != new_permanent_text) && 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (!user_input_in_progress_ || !has_focus_); 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch permanent_text_ = new_permanent_text; 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return visibly_changed_permanent_text; 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::SetUserText(const std::wstring& text) { 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetInputInProgress(true); 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch InternalSetUserText(text); 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch paste_state_ = NONE; 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch has_temporary_text_ = false; 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::GetDataForURLExport(GURL* url, 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::wstring* title, 163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SkBitmap* favicon) { 164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutocompleteMatch match; 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetInfoForCurrentText(&match, NULL); 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *url = match.destination_url; 1673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (*url == URLFixerUpper::FixupURL(WideToUTF8(permanent_text_), 1683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick std::string())) { 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *title = controller_->GetTitle(); 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *favicon = controller_->GetFavIcon(); 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::wstring AutocompleteEditModel::GetDesiredTLD() const { 1753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Tricky corner case: The user has typed "foo" and currently sees an inline 1763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // autocomplete suggestion of "foo.net". He now presses ctrl-a (e.g. to 1773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // select all, on Windows). If we treat the ctrl press as potentially for the 1783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // sake of ctrl-enter, then we risk "www.foo.com" being promoted as the best 1793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // match. This would make the autocompleted text disappear, leaving our user 1803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // feeling very confused when the wrong text gets highlighted. 1813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // 1823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Thus, we only treat the user as pressing ctrl-enter when the user presses 1833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // ctrl without any fragile state built up in the omnibox: 1843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // * the contents of the omnibox have not changed since the keypress, 1853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // * there is no autocompleted text visible, and 1863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // * the user is not typing a keyword query. 1873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return (control_key_state_ == DOWN_WITHOUT_CHANGE && 1883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick inline_autocomplete_text_.empty() && !KeywordIsSelected())? 189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::wstring(L"com") : std::wstring(); 190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool AutocompleteEditModel::CurrentTextIsURL() const { 193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If !user_input_in_progress_, the permanent text is showing, which should 194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // always be a URL, so no further checking is needed. By avoiding checking in 195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // this case, we avoid calling into the autocomplete providers, and thus 196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // initializing the history system, as long as possible, which speeds startup. 197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!user_input_in_progress_) 198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutocompleteMatch match; 201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetInfoForCurrentText(&match, NULL); 202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return match.transition == PageTransition::TYPED; 203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 205c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteMatch::Type AutocompleteEditModel::CurrentTextType() const { 206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutocompleteMatch match; 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetInfoForCurrentText(&match, NULL); 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return match.type; 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool AutocompleteEditModel::GetURLForText(const std::wstring& text, 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GURL* url) const { 213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const AutocompleteInput::Type type = AutocompleteInput::Parse( 214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UserTextFromDisplayText(text), std::wstring(), NULL, NULL); 215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (type != AutocompleteInput::URL) 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *url = URLFixerUpper::FixupURL(WideToUTF8(text), std::string()); 219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::AdjustTextForCopy(int sel_min, 223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool is_all_selected, 224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::wstring* text, 225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GURL* url, 226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool* write_url) { 227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *write_url = false; 228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (sel_min != 0) 230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We can't use CurrentTextIsURL() or GetDataForURLExport() because right now 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the user is probably holding down control to cause the copy, which will 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // screw up our calculation of the desired_tld. 235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!GetURLForText(*text, url)) 236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; // Can't be parsed as a url, no need to adjust text. 237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!user_input_in_progress() && is_all_selected) { 239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The user selected all the text and has not edited it. Use the url as the 240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // text so that if the scheme was stripped it's added back, and the url 241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // is unescaped (we escape parts of the url for display). 242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *text = UTF8ToWide(url->spec()); 243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *write_url = true; 244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Prefix the text with 'http://' if the text doesn't start with 'http://', 248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the text parses as a url with a scheme of http, the user selected the 249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // entire host, and the user hasn't edited the host or manually removed the 250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // scheme. 251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GURL perm_url; 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (GetURLForText(permanent_text_, &perm_url) && 253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch perm_url.SchemeIs(chrome::kHttpScheme) && 254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch url->SchemeIs(chrome::kHttpScheme) && 255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch perm_url.host() == url->host()) { 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *write_url = true; 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::wstring http = ASCIIToWide(chrome::kHttpScheme) + 259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ASCIIToWide(chrome::kStandardSchemeSeparator); 260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (text->compare(0, http.length(), http) != 0) 261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *text = http + *text; 262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::SetInputInProgress(bool in_progress) { 266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (user_input_in_progress_ == in_progress) 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch user_input_in_progress_ = in_progress; 270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch controller_->OnInputInProgress(in_progress); 271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::Revert() { 274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetInputInProgress(false); 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch paste_state_ = NONE; 276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch InternalSetUserText(std::wstring()); 277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch keyword_.clear(); 278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch is_keyword_hint_ = false; 279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch keyword_ui_state_ = NORMAL; 280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch has_temporary_text_ = false; 281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->SetWindowTextAndCaretPos(permanent_text_, 282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch has_focus_ ? permanent_text_.length() : 0); 283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::StartAutocomplete( 2863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick bool has_selected_text, 287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool prevent_inline_autocomplete) const { 288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch popup_->StartAutocomplete(user_text_, GetDesiredTLD(), 289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prevent_inline_autocomplete || just_deleted_text_ || 2903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick (has_selected_text && inline_autocomplete_text_.empty()) || 291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (paste_state_ != NONE), keyword_ui_state_ == KEYWORD); 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool AutocompleteEditModel::CanPasteAndGo(const std::wstring& text) const { 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!view_->GetCommandUpdater()->IsCommandEnabled(IDC_OPEN_CURRENT_URL)) 296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutocompleteMatch match; 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile_->GetAutocompleteClassifier()->Classify(text, std::wstring(), 300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &match, &paste_and_go_alternate_nav_url_); 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch paste_and_go_url_ = match.destination_url; 302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch paste_and_go_transition_ = match.transition; 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return paste_and_go_url_.is_valid(); 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::PasteAndGo() { 307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The final parameter to OpenURL, keyword, is not quite correct here: it's 308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // possible to "paste and go" a string that contains a keyword. This is 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // enough of an edge case that we ignore this possibility. 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->RevertAll(); 311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->OpenURL(paste_and_go_url_, CURRENT_TAB, paste_and_go_transition_, 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch paste_and_go_alternate_nav_url_, AutocompletePopupModel::kNoMatch, 313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::wstring()); 314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::AcceptInput(WindowOpenDisposition disposition, 317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool for_drop) { 318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Get the URL and transition type for the selected entry. 319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutocompleteMatch match; 320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GURL alternate_nav_url; 321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetInfoForCurrentText(&match, &alternate_nav_url); 322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!match.destination_url.is_valid()) 324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 326513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if ((match.transition == PageTransition::TYPED) && (match.destination_url == 327513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch URLFixerUpper::FixupURL(WideToUTF8(permanent_text_), std::string()))) { 328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // When the user hit enter on the existing permanent URL, treat it like a 329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // reload for scoring purposes. We could detect this by just checking 330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // user_input_in_progress_, but it seems better to treat "edits" that end 331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // up leaving the URL unchanged (e.g. deleting the last character and then 332513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // retyping it) as reloads too. We exclude non-TYPED transitions because if 333513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // the transition is GENERATED, the user input something that looked 334513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // different from the current URL, even if it wound up at the same place 335513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // (e.g. manually retyping the same search query), and it seems wrong to 336513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // treat this as a reload. 337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch match.transition = PageTransition::RELOAD; 338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (for_drop || ((paste_state_ != NONE) && 339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch match.is_history_what_you_typed_match)) { 340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // When the user pasted in a URL and hit enter, score it like a link click 341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // rather than a normal typed URL, so it doesn't get inline autocompleted 342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // as aggressively later. 343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch match.transition = PageTransition::LINK; 344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 3463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (match.type == AutocompleteMatch::SEARCH_WHAT_YOU_TYPED || 3473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick match.type == AutocompleteMatch::SEARCH_HISTORY || 3483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick match.type == AutocompleteMatch::SEARCH_SUGGEST) { 3493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const TemplateURL* default_provider = 3503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick profile_->GetTemplateURLModel()->GetDefaultSearchProvider(); 3513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (default_provider && default_provider->url() && 3523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick default_provider->url()->HasGoogleBaseURLs()) 3533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick GoogleURLTracker::GoogleURLSearchCommitted(); 3543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->OpenURL(match.destination_url, disposition, match.transition, 356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch alternate_nav_url, AutocompletePopupModel::kNoMatch, 357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch is_keyword_hint_ ? std::wstring() : keyword_); 358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::OpenURL(const GURL& url, 361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WindowOpenDisposition disposition, 362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PageTransition::Type transition, 363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const GURL& alternate_nav_url, 364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t index, 365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::wstring& keyword) { 366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We only care about cases where there is a selection (i.e. the popup is 367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // open). 368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (popup_->IsOpen()) { 369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<AutocompleteLog> log(popup_->GetAutocompleteLog()); 370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (index != AutocompletePopupModel::kNoMatch) 371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch log->selected_index = index; 372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else if (!has_temporary_text_) 373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch log->inline_autocompleted_length = inline_autocomplete_text_.length(); 374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationService::current()->Notify( 375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationType::OMNIBOX_OPENED_URL, Source<Profile>(profile_), 376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Details<AutocompleteLog>(log.get())); 377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TemplateURLModel* template_url_model = profile_->GetTemplateURLModel(); 380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (template_url_model && !keyword.empty()) { 381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const TemplateURL* const template_url = 382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch template_url_model->GetTemplateURLForKeyword(keyword); 383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Special case for extension keywords. Don't increment usage count for 385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // these. 386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (template_url && template_url->IsExtensionKeyword()) { 387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutocompleteMatch current_match; 388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetInfoForCurrentText(¤t_match, NULL); 389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const AutocompleteMatch& match = 391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch index == AutocompletePopupModel::kNoMatch ? 392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_match : result().match_at(index); 393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Strip the keyword + leading space off the input. 395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t prefix_length = match.template_url->keyword().size() + 1; 396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ExtensionOmniboxEventRouter::OnInputEntered( 397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile_, match.template_url->GetExtensionId(), 398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WideToUTF8(match.fill_into_edit.substr(prefix_length))); 399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->RevertAll(); 400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (template_url) { 404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UserMetrics::RecordAction(UserMetricsAction("AcceptedKeyword"), profile_); 405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch template_url_model->IncrementUsageCount(template_url); 406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // NOTE: We purposefully don't increment the usage count of the default 409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // search engine, if applicable; see comments in template_url.h. 410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 4123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick controller_->OnAutocompleteWillAccept(); 413731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (disposition != NEW_BACKGROUND_TAB) 415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->RevertAll(); // Revert the box to its unedited state 416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch controller_->OnAutocompleteAccept(url, disposition, transition, 417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch alternate_nav_url); 418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::AcceptKeyword() { 421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->OnBeforePossibleChange(); 422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->SetWindowTextAndCaretPos(std::wstring(), 0); 423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch is_keyword_hint_ = false; 424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch keyword_ui_state_ = KEYWORD; 425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->OnAfterPossibleChange(); 426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch just_deleted_text_ = false; // OnAfterPossibleChange() erroneously sets this 427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // since the edit contents have disappeared. It 428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // doesn't really matter, but we clear it to be 429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // consistent. 430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UserMetrics::RecordAction(UserMetricsAction("AcceptedKeywordHint"), profile_); 431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::ClearKeyword(const std::wstring& visible_text) { 434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->OnBeforePossibleChange(); 435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::wstring window_text(keyword_ + visible_text); 436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->SetWindowTextAndCaretPos(window_text.c_str(), keyword_.length()); 437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch keyword_.clear(); 438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch keyword_ui_state_ = NORMAL; 439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->OnAfterPossibleChange(); 440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch just_deleted_text_ = true; // OnAfterPossibleChange() fails to clear this 441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // since the edit contents have actually grown 442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // longer. 443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool AutocompleteEditModel::query_in_progress() const { 446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return !popup_->autocomplete_controller()->done(); 447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst AutocompleteResult& AutocompleteEditModel::result() const { 450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return popup_->autocomplete_controller()->result(); 451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::OnSetFocus(bool control_down) { 454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch has_focus_ = true; 455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch control_key_state_ = control_down ? DOWN_WITHOUT_CHANGE : UP; 4563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick NotificationService::current()->Notify( 4573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick NotificationType::AUTOCOMPLETE_EDIT_FOCUSED, 4583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick Source<AutocompleteEditModel>(this), 4593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick NotificationService::NoDetails()); 460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::OnKillFocus() { 463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch has_focus_ = false; 464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch control_key_state_ = UP; 465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch paste_state_ = NONE; 466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Like typing, killing focus "accepts" the temporary text as the user 468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // text, because it makes little sense to have temporary text when the 469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // popup is closed. 470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch InternalSetUserText(UserTextFromDisplayText(view_->GetText())); 471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch has_temporary_text_ = false; 472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool AutocompleteEditModel::OnEscapeKeyPressed() { 475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (has_temporary_text_) { 476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutocompleteMatch match; 477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch popup_->InfoForCurrentSelection(&match, NULL); 478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (match.destination_url != original_url_) { 479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The user typed something, then selected a different item. Restore the 480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // text they typed and change back to the default item. 481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // NOTE: This purposefully does not reset paste_state_. 482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch just_deleted_text_ = false; 483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch has_temporary_text_ = false; 484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch keyword_ui_state_ = original_keyword_ui_state_; 485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch popup_->ResetToDefaultMatch(); 486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->OnRevertTemporaryText(); 487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the user wasn't editing, but merely had focus in the edit, allow <esc> 492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // to be processed as an accelerator, so it can still be used to stop a load. 493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // When the permanent text isn't all selected we still fall through to the 494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // SelectAll() call below so users can arrow around in the text and then hit 495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // <esc> to quickly replace all the text; this matches IE. 496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!user_input_in_progress_ && view_->IsSelectAll()) 497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->RevertAll(); 500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->SelectAll(true); 501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::OnControlKeyChanged(bool pressed) { 505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Don't change anything unless the key state is actually toggling. 506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (pressed == (control_key_state_ == UP)) { 507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ControlKeyState old_state = control_key_state_; 508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch control_key_state_ = pressed ? DOWN_WITHOUT_CHANGE : UP; 509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if ((control_key_state_ == DOWN_WITHOUT_CHANGE) && has_temporary_text_) { 510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Arrowing down and then hitting control accepts the temporary text as 511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the input text. 512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch InternalSetUserText(UserTextFromDisplayText(view_->GetText())); 513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch has_temporary_text_ = false; 5143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (KeywordIsSelected()) 5153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick AcceptKeyword(); 516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if ((old_state != DOWN_WITH_CHANGE) && popup_->IsOpen()) { 518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Autocomplete history provider results may change, so refresh the 519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // popup. This will force user_input_in_progress_ to true, but if the 520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // popup is open, that should have already been the case. 521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->UpdatePopup(); 522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::OnUpOrDownKeyPressed(int count) { 527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // NOTE: This purposefully don't trigger any code that resets paste_state_. 528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!popup_->IsOpen()) { 530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!query_in_progress()) { 531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The popup is neither open nor working on a query already. So, start an 532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // autocomplete query for the current text. This also sets 533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // user_input_in_progress_ to true, which we want: if the user has started 534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // to interact with the popup, changing the permanent_text_ shouldn't 535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // change the displayed text. 536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Note: This does not force the popup to open immediately. 537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(pkasting): We should, in fact, force this particular query to open 538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the popup immediately. 539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!user_input_in_progress_) 540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch InternalSetUserText(permanent_text_); 541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->UpdatePopup(); 542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(pkasting): The popup is working on a query but is not open. We 544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // should force it to open immediately. 545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The popup is open, so the user should be able to interact with it 548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // normally. 549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch popup_->Move(count); 550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // NOTE: We need to reset the keyword_ui_state_ after the popup updates, since 553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Move() will eventually call back to OnPopupDataChanged(), which needs to 554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // save off the current keyword_ui_state_. 555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch keyword_ui_state_ = NORMAL; 556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::OnPopupDataChanged( 559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::wstring& text, 560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GURL* destination_for_temporary_text_change, 561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::wstring& keyword, 562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool is_keyword_hint) { 563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Update keyword/hint-related local state. 564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool keyword_state_changed = (keyword_ != keyword) || 565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ((is_keyword_hint_ != is_keyword_hint) && !keyword.empty()); 566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (keyword_state_changed) { 567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch keyword_ = keyword; 568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch is_keyword_hint_ = is_keyword_hint; 569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Handle changes to temporary text. 572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (destination_for_temporary_text_change != NULL) { 573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const bool save_original_selection = !has_temporary_text_; 574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (save_original_selection) { 575c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Save the original selection and URL so it can be reverted later. 576c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch has_temporary_text_ = true; 577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch original_url_ = *destination_for_temporary_text_change; 578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch original_keyword_ui_state_ = keyword_ui_state_; 579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (control_key_state_ == DOWN_WITHOUT_CHANGE) { 581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Arrowing around the popup cancels control-enter. 582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch control_key_state_ = DOWN_WITH_CHANGE; 583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Now things are a bit screwy: the desired_tld has changed, but if we 584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // update the popup, the new order of entries won't match the old, so the 585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // user's selection gets screwy; and if we don't update the popup, and the 586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // user reverts, then the selected item will be as if control is still 587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // pressed, even though maybe it isn't any more. There is no obvious 588c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // right answer here :( 589c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->OnTemporaryTextMaybeChanged(DisplayTextFromUserText(text), 591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch save_original_selection); 592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(suzhe): Instead of messing with |inline_autocomplete_text_| here, 596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // we should probably do it inside Observe(), and save/restore it around 597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // changes to the temporary text. This will let us remove knowledge of 598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // inline autocompletions from the popup code. 599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Handle changes to inline autocomplete text. Don't make changes if the user 601c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // is showing temporary text. Making display changes would be obviously 602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // wrong; making changes to the inline_autocomplete_text_ itself turns out to 603c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // be more subtlely wrong, because it means hitting esc will no longer revert 604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // to the original state before arrowing. 605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!has_temporary_text_) { 606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch inline_autocomplete_text_ = text; 607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (view_->OnInlineAutocompleteTextMaybeChanged( 608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DisplayTextFromUserText(user_text_ + inline_autocomplete_text_), 609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DisplayTextFromUserText(user_text_).length())) 610c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the above changes didn't warrant a text update but we did change keyword 614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // state, we have yet to notify the controller about it. 615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (keyword_state_changed) 616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch controller_->OnChanged(); 617c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 619c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool AutocompleteEditModel::OnAfterPossibleChange(const std::wstring& new_text, 620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool selection_differs, 621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool text_differs, 622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool just_deleted_text, 623c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool at_end_of_edit) { 624c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Update the paste state as appropriate: if we're just finishing a paste 625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // that replaced all the text, preserve that information; otherwise, if we've 626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // made some other edit, clear paste tracking. 627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (paste_state_ == REPLACING_ALL) 628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch paste_state_ = REPLACED_ALL; 629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else if (text_differs) 630c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch paste_state_ = NONE; 631c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 6323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Modifying the selection counts as accepting the autocompleted text. 6333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const bool user_text_changed = 6343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick text_differs || (selection_differs && !inline_autocomplete_text_.empty()); 6353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 636c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If something has changed while the control key is down, prevent 637c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // "ctrl-enter" until the control key is released. When we do this, we need 638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // to update the popup if it's open, since the desired_tld will have changed. 639c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if ((text_differs || selection_differs) && 640c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (control_key_state_ == DOWN_WITHOUT_CHANGE)) { 641c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch control_key_state_ = DOWN_WITH_CHANGE; 642c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!text_differs && !popup_->IsOpen()) 643c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; // Don't open the popup for no reason. 6443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } else if (!user_text_changed) { 645c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 647c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 6483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const bool had_keyword = KeywordIsSelected(); 649c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 6503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // If the user text has not changed, we do not want to change the model's 6513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // state associated with the text. Otherwise, we can get surprising behavior 6523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // where the autocompleted text unexpectedly reappears, e.g. crbug.com/55983 6533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (user_text_changed) { 6543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick InternalSetUserText(UserTextFromDisplayText(new_text)); 6553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick has_temporary_text_ = false; 656c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 6573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Track when the user has deleted text so we won't allow inline 6583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // autocomplete. 6593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick just_deleted_text_ = just_deleted_text; 6603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 661c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 662c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Disable the fancy keyword UI if the user didn't already have a visible 663c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // keyword and is not at the end of the edit. This prevents us from showing 664c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the fancy UI (and interrupting the user's editing) if the user happens to 665c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // have a keyword for 'a', types 'ab' then puts a space between the 'a' and 666c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the 'b'. 667c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!had_keyword) 668c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch keyword_ui_state_ = at_end_of_edit ? NORMAL : NO_KEYWORD; 669c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 670c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->UpdatePopup(); 671c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 672c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (had_keyword) { 673c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (is_keyword_hint_ || keyword_.empty()) 674c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch keyword_ui_state_ = NORMAL; 675c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if ((keyword_ui_state_ != NO_KEYWORD) && !is_keyword_hint_ && 676c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch !keyword_.empty()) { 677c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Went from no selected keyword to a selected keyword. 678c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch keyword_ui_state_ = KEYWORD; 679c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 680c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 681c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 682c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 683c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 6843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid AutocompleteEditModel::PopupBoundsChangedTo(const gfx::Rect& bounds) { 6853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick controller_->OnPopupBoundsChanged(bounds); 6863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 6873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 688513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid AutocompleteEditModel::ResultsUpdated() { 689513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch UpdateSuggestedSearchText(); 690513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch} 691513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 692c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Return true if the suggestion type warrants a TCP/IP preconnection. 693c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// i.e., it is now highly likely that the user will select the related domain. 694c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic bool IsPreconnectable(AutocompleteMatch::Type type) { 695c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UMA_HISTOGRAM_ENUMERATION("Autocomplete.MatchType", type, 696c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutocompleteMatch::NUM_TYPES); 697c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch switch (type) { 698c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Matches using the user's default search engine. 699c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case AutocompleteMatch::SEARCH_WHAT_YOU_TYPED: 700c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case AutocompleteMatch::SEARCH_HISTORY: 701c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case AutocompleteMatch::SEARCH_SUGGEST: 702c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // A match that uses a non-default search engine (e.g. for tab-to-search). 703c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case AutocompleteMatch::SEARCH_OTHER_ENGINE: 704c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 705c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 706c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default: 707c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 708c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 709c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 710c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 711c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::Observe(NotificationType type, 712c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const NotificationSource& source, 713c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const NotificationDetails& details) { 714c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK_EQ(NotificationType::AUTOCOMPLETE_CONTROLLER_DEFAULT_MATCH_UPDATED, 715c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch type.value); 716c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 717c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::wstring inline_autocomplete_text; 718c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::wstring keyword; 719c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool is_keyword_hint = false; 720c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const AutocompleteResult* result = 721c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Details<const AutocompleteResult>(details).ptr(); 722c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const AutocompleteResult::const_iterator match(result->default_match()); 723c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (match != result->end()) { 724c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if ((match->inline_autocomplete_offset != std::wstring::npos) && 725c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (match->inline_autocomplete_offset < match->fill_into_edit.length())) { 726c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch inline_autocomplete_text = 727c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch match->fill_into_edit.substr(match->inline_autocomplete_offset); 728c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 729c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 730c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!match->destination_url.SchemeIs(chrome::kExtensionScheme)) { 731c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Warm up DNS Prefetch cache, or preconnect to a search service. 7323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick chrome_browser_net::AnticipateOmniboxUrl(match->destination_url, 7333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick IsPreconnectable(match->type)); 734c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 735c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 736c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We could prefetch the alternate nav URL, if any, but because there 737c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // can be many of these as a user types an initial series of characters, 738c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the OS DNS cache could suffer eviction problems for minimal gain. 739c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 740c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch is_keyword_hint = popup_->GetKeywordForMatch(*match, &keyword); 741c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 742c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 743c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch OnPopupDataChanged(inline_autocomplete_text, NULL, keyword, is_keyword_hint); 744c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 745c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 746c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::InternalSetUserText(const std::wstring& text) { 747c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch user_text_ = text; 748c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch just_deleted_text_ = false; 749c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch inline_autocomplete_text_.clear(); 750c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 751c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool AutocompleteEditModel::KeywordIsSelected() const { 7533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return ((keyword_ui_state_ != NO_KEYWORD) && !is_keyword_hint_ && 7543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick !keyword_.empty()); 7553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 7563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 757c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::wstring AutocompleteEditModel::DisplayTextFromUserText( 758c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::wstring& text) const { 7593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return KeywordIsSelected() ? 7603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick KeywordProvider::SplitReplacementStringFromInput(text) : text; 761c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 762c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 763c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::wstring AutocompleteEditModel::UserTextFromDisplayText( 764c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::wstring& text) const { 7653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return KeywordIsSelected() ? (keyword_ + L" " + text) : text; 766c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 767c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 768c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompleteEditModel::GetInfoForCurrentText( 769c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutocompleteMatch* match, 770c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GURL* alternate_nav_url) const { 771c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (popup_->IsOpen() || query_in_progress()) { 772c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch popup_->InfoForCurrentSelection(match, alternate_nav_url); 773c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 774c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile_->GetAutocompleteClassifier()->Classify( 775c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UserTextFromDisplayText(view_->GetText()), GetDesiredTLD(), match, 776c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch alternate_nav_url); 777c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 778c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 779513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 780513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// Returns true if suggested search text should be shown for the specified match 781513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// type. 782513209b27ff55e2841eac0e4120199c23acce758Ben Murdochstatic bool ShouldShowSuggestSearchTextFor(AutocompleteMatch::Type type) { 783513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // TODO: add support for other engines when in keyword mode. 784513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch return ((type == AutocompleteMatch::SEARCH_HISTORY) || 785513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch (type == AutocompleteMatch::SEARCH_SUGGEST)); 786513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch} 787513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 788513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid AutocompleteEditModel::UpdateSuggestedSearchText() { 789513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (!InstantController::IsEnabled(profile_, InstantController::VERBATIM_TYPE)) 790513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch return; 791513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 792513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch string16 suggested_text; 793513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // The suggested text comes from the first search result. 794513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (popup_->IsOpen()) { 795513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch const AutocompleteResult& result = popup_->result(); 796513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if ((result.size() > 1) && (popup_->selected_line() == 0) && 797513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch ((result.begin()->inline_autocomplete_offset == std::wstring::npos) || 798513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch (result.begin()->inline_autocomplete_offset == 799513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch result.begin()->fill_into_edit.size()))) { 800513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch for (AutocompleteResult::const_iterator i = result.begin() + 1; 801513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch i != result.end(); ++i) { 802513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // TODO: add support for other engines when in keyword mode. 803513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (ShouldShowSuggestSearchTextFor(i->type) && 804513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch i->inline_autocomplete_offset != std::wstring::npos) { 805513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch suggested_text = WideToUTF16(i->fill_into_edit.substr( 806513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch i->inline_autocomplete_offset)); 807513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch break; 808513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch } 809513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch } 810513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch } 811513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch } 812513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch controller_->OnSetSuggestedSearchText(suggested_text); 813513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch} 814