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(&params);
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