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