omnibox_provider.cc revision 116680a4aac90f2aa7413d9095a592090648e557
1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/ui/app_list/search/omnibox_provider.h" 6 7#include "chrome/browser/autocomplete/autocomplete_classifier.h" 8#include "chrome/browser/autocomplete/autocomplete_controller.h" 9#include "chrome/browser/autocomplete/autocomplete_match.h" 10#include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h" 11#include "chrome/browser/autocomplete/search_provider.h" 12#include "chrome/browser/search_engines/template_url_service_factory.h" 13#include "chrome/browser/ui/app_list/search/chrome_search_result.h" 14#include "chrome/browser/ui/browser_navigator.h" 15#include "components/autocomplete/autocomplete_input.h" 16#include "components/metrics/proto/omnibox_event.pb.h" 17#include "grit/theme_resources.h" 18#include "ui/base/resource/resource_bundle.h" 19 20namespace app_list { 21 22namespace { 23 24int ACMatchStyleToTagStyle(int styles) { 25 int tag_styles = 0; 26 if (styles & ACMatchClassification::URL) 27 tag_styles |= SearchResult::Tag::URL; 28 if (styles & ACMatchClassification::MATCH) 29 tag_styles |= SearchResult::Tag::MATCH; 30 if (styles & ACMatchClassification::DIM) 31 tag_styles |= SearchResult::Tag::DIM; 32 33 return tag_styles; 34} 35 36// Translates ACMatchClassifications into SearchResult tags. 37void ACMatchClassificationsToTags( 38 const base::string16& text, 39 const ACMatchClassifications& text_classes, 40 SearchResult::Tags* tags) { 41 int tag_styles = SearchResult::Tag::NONE; 42 size_t tag_start = 0; 43 44 for (size_t i = 0; i < text_classes.size(); ++i) { 45 const ACMatchClassification& text_class = text_classes[i]; 46 47 // Closes current tag. 48 if (tag_styles != SearchResult::Tag::NONE) { 49 tags->push_back(SearchResult::Tag( 50 tag_styles, tag_start, text_class.offset)); 51 tag_styles = SearchResult::Tag::NONE; 52 } 53 54 if (text_class.style == ACMatchClassification::NONE) 55 continue; 56 57 tag_start = text_class.offset; 58 tag_styles = ACMatchStyleToTagStyle(text_class.style); 59 } 60 61 if (tag_styles != SearchResult::Tag::NONE) { 62 tags->push_back(SearchResult::Tag( 63 tag_styles, tag_start, text.length())); 64 } 65} 66 67class OmniboxResult : public ChromeSearchResult { 68 public: 69 OmniboxResult(Profile* profile, const AutocompleteMatch& match) 70 : profile_(profile), 71 match_(match) { 72 set_id(match.destination_url.spec()); 73 74 // Derive relevance from omnibox relevance and normalize it to [0, 1]. 75 // The magic number 1500 is the highest score of an omnibox result. 76 // See comments in autocomplete_provider.h. 77 set_relevance(match.relevance / 1500.0); 78 79 UpdateIcon(); 80 UpdateTitleAndDetails(); 81 } 82 virtual ~OmniboxResult() {} 83 84 // ChromeSearchResult overides: 85 virtual void Open(int event_flags) OVERRIDE { 86 chrome::NavigateParams params(profile_, 87 match_.destination_url, 88 match_.transition); 89 params.disposition = ui::DispositionFromEventFlags(event_flags); 90 chrome::Navigate(¶ms); 91 } 92 93 virtual void InvokeAction(int action_index, int event_flags) OVERRIDE {} 94 95 virtual scoped_ptr<ChromeSearchResult> Duplicate() OVERRIDE { 96 return scoped_ptr<ChromeSearchResult>( 97 new OmniboxResult(profile_, match_)).Pass(); 98 } 99 100 virtual ChromeSearchResultType GetType() OVERRIDE { 101 return OMNIBOX_SEARCH_RESULT; 102 } 103 104 private: 105 void UpdateIcon() { 106 int resource_id = match_.starred ? 107 IDR_OMNIBOX_STAR : AutocompleteMatch::TypeToIcon(match_.type); 108 SetIcon(*ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( 109 resource_id)); 110 } 111 112 void UpdateTitleAndDetails() { 113 set_title(match_.contents); 114 SearchResult::Tags title_tags; 115 ACMatchClassificationsToTags(match_.contents, 116 match_.contents_class, 117 &title_tags); 118 set_title_tags(title_tags); 119 120 set_details(match_.description); 121 SearchResult::Tags details_tags; 122 ACMatchClassificationsToTags(match_.description, 123 match_.description_class, 124 &details_tags); 125 set_details_tags(details_tags); 126 } 127 128 Profile* profile_; 129 AutocompleteMatch match_; 130 131 DISALLOW_COPY_AND_ASSIGN(OmniboxResult); 132}; 133 134} // namespace 135 136OmniboxProvider::OmniboxProvider(Profile* profile) 137 : profile_(profile), 138 controller_(new AutocompleteController( 139 profile, 140 TemplateURLServiceFactory::GetForProfile(profile), 141 this, 142 AutocompleteClassifier::kDefaultOmniboxProviders & 143 ~AutocompleteProvider::TYPE_ZERO_SUGGEST)) { 144 controller_->search_provider()->set_in_app_list(); 145} 146 147OmniboxProvider::~OmniboxProvider() {} 148 149void OmniboxProvider::Start(const base::string16& query) { 150 controller_->Start(AutocompleteInput( 151 query, base::string16::npos, base::string16(), GURL(), 152 metrics::OmniboxEventProto::INVALID_SPEC, false, false, true, true, 153 ChromeAutocompleteSchemeClassifier(profile_))); 154} 155 156void OmniboxProvider::Stop() { 157 controller_->Stop(false); 158} 159 160void OmniboxProvider::PopulateFromACResult(const AutocompleteResult& result) { 161 ClearResults(); 162 for (ACMatches::const_iterator it = result.begin(); 163 it != result.end(); 164 ++it) { 165 if (!it->destination_url.is_valid()) 166 continue; 167 168 Add(scoped_ptr<SearchResult>(new OmniboxResult(profile_, *it))); 169 } 170} 171 172void OmniboxProvider::OnResultChanged(bool default_match_changed) { 173 const AutocompleteResult& result = controller_->result(); 174 PopulateFromACResult(result); 175} 176 177} // namespace app_list 178