omnibox_provider.cc revision 6d86b77056ed63eb6871182f42a9fd5f07550f90
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 "components/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(&params);
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                                       metrics::OmniboxEventProto::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<SearchResult>(new OmniboxResult(profile_, *it)));
171  }
172}
173
174void OmniboxProvider::OnResultChanged(bool default_match_changed) {
175  const AutocompleteResult& result = controller_->result();
176  PopulateFromACResult(result);
177}
178
179}  // namespace app_list
180