autocomplete_popup_model.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_popup_model.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 73345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "unicode/ubidi.h" 83345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h" 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/autocomplete/autocomplete_edit.h" 11513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "chrome/browser/autocomplete/autocomplete_match.h" 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/autocomplete/autocomplete_popup_view.h" 13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/profile.h" 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extensions_service.h" 15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/search_engines/template_url.h" 16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/search_engines/template_url_model.h" 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/notification_service.h" 183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "gfx/rect.h" 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch/////////////////////////////////////////////////////////////////////////////// 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// AutocompletePopupModel 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompletePopupModel::AutocompletePopupModel( 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutocompletePopupView* popup_view, 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutocompleteEditModel* edit_model, 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Profile* profile) 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : view_(popup_view), 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch edit_model_(edit_model), 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch controller_(new AutocompleteController(profile)), 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile_(profile), 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch hovered_line_(kNoMatch), 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch selected_line_(kNoMatch) { 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch registrar_.Add(this, NotificationType::AUTOCOMPLETE_CONTROLLER_RESULT_UPDATED, 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Source<AutocompleteController>(controller_.get())); 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompletePopupModel::~AutocompletePopupModel() { 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompletePopupModel::SetProfile(Profile* profile) { 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(profile); 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile_ = profile; 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch controller_->SetProfile(profile); 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompletePopupModel::StartAutocomplete( 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::wstring& text, 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::wstring& desired_tld, 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool prevent_inline_autocomplete, 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool prefer_keyword) { 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The user is interacting with the edit, so stop tracking hover. 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetHoveredLine(kNoMatch); 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch manually_selected_match_.Clear(); 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch controller_->Start(text, desired_tld, prevent_inline_autocomplete, 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prefer_keyword, false); 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompletePopupModel::StopAutocomplete() { 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch controller_->Stop(true); 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool AutocompletePopupModel::IsOpen() const { 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return view_->IsOpen(); 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompletePopupModel::SetHoveredLine(size_t line) { 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const bool is_disabling = (line == kNoMatch); 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(is_disabling || (line < controller_->result().size())); 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (line == hovered_line_) 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; // Nothing to do 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Make sure the old hovered line is redrawn. No need to redraw the selected 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // line since selection overrides hover so the appearance won't change. 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if ((hovered_line_ != kNoMatch) && (hovered_line_ != selected_line_)) 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->InvalidateLine(hovered_line_); 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Change the hover to the new line. 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch hovered_line_ = line; 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!is_disabling && (hovered_line_ != selected_line_)) 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->InvalidateLine(hovered_line_); 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompletePopupModel::SetSelectedLine(size_t line, 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool reset_to_default) { 883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // We should at least be dealing with the results of the current query. Note 893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // that even if |line| was valid on entry, this may make it invalid. We clamp 903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // it below. 913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick controller_->CommitIfQueryHasNeverBeenCommitted(); 923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const AutocompleteResult& result = controller_->result(); 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (result.empty()) 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Cancel the query so the matches don't change on the user. 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch controller_->Stop(false); 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick line = std::min(line, result.size() - 1); 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const AutocompleteMatch& match = result.match_at(line); 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (reset_to_default) { 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch manually_selected_match_.Clear(); 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Track the user's selection until they cancel it. 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch manually_selected_match_.destination_url = match.destination_url; 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch manually_selected_match_.provider_affinity = match.provider; 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch manually_selected_match_.is_history_what_you_typed_match = 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch match.is_history_what_you_typed_match; 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (line == selected_line_) 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; // Nothing else to do. 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We need to update |selected_line_| before calling OnPopupDataChanged(), so 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // that when the edit notifies its controller that something has changed, the 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // controller can get the correct updated data. 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // NOTE: We should never reach here with no selected line; the same code that 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // opened the popup and made it possible to get here should have also set a 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // selected line. 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CHECK(selected_line_ != kNoMatch); 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GURL current_destination(result.match_at(selected_line_).destination_url); 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->InvalidateLine(selected_line_); 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch selected_line_ = line; 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->InvalidateLine(selected_line_); 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Update the edit with the new data for this match. 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(pkasting): If |selected_line_| moves to the controller, this can be 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // eliminated and just become a call to the observer on the edit. 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::wstring keyword; 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const bool is_keyword_hint = GetKeywordForMatch(match, &keyword); 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (reset_to_default) { 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::wstring inline_autocomplete_text; 135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if ((match.inline_autocomplete_offset != std::wstring::npos) && 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (match.inline_autocomplete_offset < match.fill_into_edit.length())) { 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch inline_autocomplete_text = 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch match.fill_into_edit.substr(match.inline_autocomplete_offset); 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch edit_model_->OnPopupDataChanged(inline_autocomplete_text, NULL, 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch keyword, is_keyword_hint); 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch edit_model_->OnPopupDataChanged(match.fill_into_edit, ¤t_destination, 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch keyword, is_keyword_hint); 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Repaint old and new selected lines immediately, so that the edit doesn't 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // appear to update [much] faster than the popup. 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->PaintUpdatesNow(); 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompletePopupModel::ResetToDefaultMatch() { 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const AutocompleteResult& result = controller_->result(); 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CHECK(!result.empty()); 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetSelectedLine(result.default_match() - result.begin(), true); 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->OnDragCanceled(); 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompletePopupModel::InfoForCurrentSelection( 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutocompleteMatch* match, 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GURL* alternate_nav_url) const { 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(match != NULL); 163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const AutocompleteResult* result; 164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!controller_->done()) { 1653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // NOTE: Using latest_result() is important here since not only could it 1663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // contain newer results than result() for the current query, it could even 1673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // refer to an entirely different query (e.g. if the user is typing rapidly 1683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // and the controller is purposefully delaying updates to avoid flicker). 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch result = &controller_->latest_result(); 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // It's technically possible for |result| to be empty if no provider returns 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // a synchronous result but the query has not completed synchronously; 172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // pratically, however, that should never actually happen. 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (result->empty()) 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The user cannot have manually selected a match, or the query would have 176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // stopped. So the default match must be the desired selection. 177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *match = *result->default_match(); 178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CHECK(IsOpen()); 180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The query isn't running, so the standard result set can't possibly be out 181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // of date. 182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // NOTE: In practice, it should actually be safe to use 184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // controller_->latest_result() here too, since the controller keeps that 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // up-to-date. However we generally try to avoid referring to that. 186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch result = &controller_->result(); 187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If there are no results, the popup should be closed (so we should have 188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // failed the CHECK above), and URLsForDefaultMatch() should have been 189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // called instead. 190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CHECK(!result->empty()); 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CHECK(selected_line_ < result->size()); 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *match = result->match_at(selected_line_); 193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (alternate_nav_url && manually_selected_match_.empty()) 195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *alternate_nav_url = result->alternate_nav_url(); 196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool AutocompletePopupModel::GetKeywordForMatch(const AutocompleteMatch& match, 199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::wstring* keyword) const { 200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Assume we have no keyword until we find otherwise. 201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch keyword->clear(); 202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the current match is a keyword, return that as the selected keyword. 204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (TemplateURL::SupportsReplacement(match.template_url)) { 205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch keyword->assign(match.template_url->keyword()); 206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // See if the current match's fill_into_edit corresponds to a keyword. 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!profile_->GetTemplateURLModel()) 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile_->GetTemplateURLModel()->Load(); 213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::wstring keyword_hint( 214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TemplateURLModel::CleanUserInputKeyword(match.fill_into_edit)); 215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (keyword_hint.empty()) 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Don't provide a hint if this keyword doesn't support replacement. 219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const TemplateURL* const template_url = 220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile_->GetTemplateURLModel()->GetTemplateURLForKeyword(keyword_hint); 221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!TemplateURL::SupportsReplacement(template_url)) 222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 224513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // Don't provide a hint if this is an extension keyword not enabled for 225513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // incognito mode (and if this is an incognito profile). 226513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (template_url->IsExtensionKeyword() && profile_->IsOffTheRecord()) { 227513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch const Extension* extension = profile_->GetExtensionsService()-> 228513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch GetExtensionById(template_url->GetExtensionId(), false); 229513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (!profile_->GetExtensionsService()->IsIncognitoEnabled(extension)) 230513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch return false; 231513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch } 232513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch keyword->assign(keyword_hint); 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 237c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAutocompleteLog* AutocompletePopupModel::GetAutocompleteLog() { 238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return new AutocompleteLog(controller_->input().text(), 239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch controller_->input().type(), selected_line_, 0, controller_->result()); 240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompletePopupModel::Move(int count) { 243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const AutocompleteResult& result = controller_->result(); 244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (result.empty()) 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The user is using the keyboard to change the selection, so stop tracking 248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // hover. 249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetHoveredLine(kNoMatch); 250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Clamp the new line to [0, result_.count() - 1]. 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const size_t new_line = selected_line_ + count; 2533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SetSelectedLine(((count < 0) && (new_line >= selected_line_)) ? 0 : new_line, 2543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick false); 255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompletePopupModel::TryDeletingCurrentItem() { 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We could use InfoForCurrentSelection() here, but it seems better to try 259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // and shift-delete the actual selection, rather than any "in progress, not 260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // yet visible" one. 261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (selected_line_ == kNoMatch) 262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Cancel the query so the matches don't change on the user. 265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch controller_->Stop(false); 266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const AutocompleteMatch& match = 268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch controller_->result().match_at(selected_line_); 269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (match.deletable) { 270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const size_t selected_line = selected_line_; 271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch controller_->DeleteMatch(match); // This may synchronously notify us that 272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the results have changed. 273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const AutocompleteResult& result = controller_->result(); 274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!result.empty()) { 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Move the selection to the next choice after the deleted one. 2763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // SetSelectedLine() will clamp to take care of the case where we deleted 2773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // the last item. 278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(pkasting): Eventually the controller should take care of this 279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // before notifying us, reducing flicker. At that point the check for 280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // deletability can move there too. 2813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SetSelectedLine(selected_line, false); 282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AutocompletePopupModel::Observe(NotificationType type, 287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const NotificationSource& source, 288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const NotificationDetails& details) { 289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK_EQ(NotificationType::AUTOCOMPLETE_CONTROLLER_RESULT_UPDATED, 290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch type.value); 291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const AutocompleteResult* result = 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Details<const AutocompleteResult>(details).ptr(); 2943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick selected_line_ = result->default_match() == result->end() ? 2953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick kNoMatch : static_cast<size_t>(result->default_match() - result->begin()); 296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // There had better not be a nonempty result set with no default match. 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CHECK((selected_line_ != kNoMatch) || result->empty()); 298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If we're going to trim the window size to no longer include the hovered 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // line, turn hover off. Practically, this shouldn't happen, but it 300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // doesn't hurt to be defensive. 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if ((hovered_line_ != kNoMatch) && (result->size() <= hovered_line_)) 302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetHoveredLine(kNoMatch); 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->UpdatePopupAppearance(); 305513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch edit_model_->ResultsUpdated(); 3063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick edit_model_->PopupBoundsChangedTo(view_->GetTargetBounds()); 307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst SkBitmap* AutocompletePopupModel::GetSpecialIconForMatch( 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const AutocompleteMatch& match) const { 311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!match.template_url || !match.template_url->IsExtensionKeyword()) 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return NULL; 313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 3143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return &profile_->GetExtensionsService()->GetOmniboxPopupIcon( 315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch match.template_url->GetExtensionId()); 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 317