190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// found in the LICENSE file.
490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/ui/app_list/search/omnibox_provider.h"
690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/autocomplete/autocomplete_classifier.h"
890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/autocomplete/autocomplete_controller.h"
9116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h"
105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/bookmarks/bookmark_model_factory.h"
11116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "chrome/browser/search_engines/template_url_service_factory.h"
1290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/ui/app_list/search/chrome_search_result.h"
1390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/ui/browser_navigator.h"
145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "components/bookmarks/browser/bookmark_model.h"
156d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "components/metrics/proto/omnibox_event.pb.h"
165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "components/omnibox/autocomplete_input.h"
175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "components/omnibox/autocomplete_match.h"
1890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "grit/theme_resources.h"
1990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
2090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace app_list {
2290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace {
2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)int ACMatchStyleToTagStyle(int styles) {
2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int tag_styles = 0;
2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (styles & ACMatchClassification::URL)
2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    tag_styles |= SearchResult::Tag::URL;
2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (styles & ACMatchClassification::MATCH)
3090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    tag_styles |= SearchResult::Tag::MATCH;
3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (styles & ACMatchClassification::DIM)
3290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    tag_styles |= SearchResult::Tag::DIM;
3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return tag_styles;
3590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
3690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Translates ACMatchClassifications into SearchResult tags.
3890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void ACMatchClassificationsToTags(
39a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::string16& text,
4090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const ACMatchClassifications& text_classes,
4190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    SearchResult::Tags* tags) {
4290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int tag_styles = SearchResult::Tag::NONE;
4390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  size_t tag_start = 0;
4490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for (size_t i = 0; i < text_classes.size(); ++i) {
4690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const ACMatchClassification& text_class = text_classes[i];
4790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Closes current tag.
4990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (tag_styles != SearchResult::Tag::NONE) {
5090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      tags->push_back(SearchResult::Tag(
5190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          tag_styles, tag_start, text_class.offset));
5290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      tag_styles = SearchResult::Tag::NONE;
5390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
5490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (text_class.style == ACMatchClassification::NONE)
5690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      continue;
5790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    tag_start = text_class.offset;
5990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    tag_styles = ACMatchStyleToTagStyle(text_class.style);
6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
6290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (tag_styles != SearchResult::Tag::NONE) {
6390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    tags->push_back(SearchResult::Tag(
6490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        tag_styles, tag_start, text.length()));
6590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
6690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
6790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
6890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)class OmniboxResult : public ChromeSearchResult {
6990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) public:
705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  OmniboxResult(Profile* profile,
715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                AutocompleteController* autocomplete_controller,
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                const AutocompleteMatch& match)
7390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      : profile_(profile),
745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        autocomplete_controller_(autocomplete_controller),
7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        match_(match) {
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (match_.search_terms_args) {
775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      match_.search_terms_args->from_app_list = true;
785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      autocomplete_controller_->UpdateMatchDestinationURL(
795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          *match_.search_terms_args, &match_);
805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    set_id(match_.destination_url.spec());
8290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
8390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Derive relevance from omnibox relevance and normalize it to [0, 1].
8490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // The magic number 1500 is the highest score of an omnibox result.
8590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // See comments in autocomplete_provider.h.
865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    set_relevance(match_.relevance / 1500.0);
8790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
8890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    UpdateIcon();
8990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    UpdateTitleAndDetails();
9090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual ~OmniboxResult() {}
9290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // ChromeSearchResult overides:
9490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual void Open(int event_flags) OVERRIDE {
9590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    chrome::NavigateParams params(profile_,
9690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                  match_.destination_url,
9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                  match_.transition);
9890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    params.disposition = ui::DispositionFromEventFlags(event_flags);
9990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    chrome::Navigate(&params);
10090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
10190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
10290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual void InvokeAction(int action_index, int event_flags) OVERRIDE {}
10390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
10490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual scoped_ptr<ChromeSearchResult> Duplicate() OVERRIDE {
10590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return scoped_ptr<ChromeSearchResult>(
1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        new OmniboxResult(profile_, autocomplete_controller_, match_)).Pass();
10790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
10890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  virtual ChromeSearchResultType GetType() OVERRIDE {
110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return OMNIBOX_SEARCH_RESULT;
111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
11390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) private:
11490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void UpdateIcon() {
1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    BookmarkModel* bookmark_model =
1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        BookmarkModelFactory::GetForProfile(profile_);
1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    bool is_bookmarked =
1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        bookmark_model && bookmark_model->IsBookmarked(match_.destination_url);
1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    int resource_id = is_bookmarked ?
12090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        IDR_OMNIBOX_STAR : AutocompleteMatch::TypeToIcon(match_.type);
12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    SetIcon(*ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
12290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        resource_id));
12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
12490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
12590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void UpdateTitleAndDetails() {
12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    set_title(match_.contents);
12790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    SearchResult::Tags title_tags;
12890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ACMatchClassificationsToTags(match_.contents,
12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                 match_.contents_class,
13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                 &title_tags);
13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    set_title_tags(title_tags);
13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    set_details(match_.description);
13490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    SearchResult::Tags details_tags;
13590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ACMatchClassificationsToTags(match_.description,
13690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                 match_.description_class,
13790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                 &details_tags);
13890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    set_details_tags(details_tags);
13990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
14090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  Profile* profile_;
1425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  AutocompleteController* autocomplete_controller_;
14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  AutocompleteMatch match_;
14490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(OmniboxResult);
14690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)};
14790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}  // namespace
14990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
15090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)OmniboxProvider::OmniboxProvider(Profile* profile)
15190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    : profile_(profile),
15290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      controller_(new AutocompleteController(
15390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          profile,
154116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          TemplateURLServiceFactory::GetForProfile(profile),
15590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          this,
156c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          AutocompleteClassifier::kDefaultOmniboxProviders &
157c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch              ~AutocompleteProvider::TYPE_ZERO_SUGGEST)) {
15890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
15990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
16090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)OmniboxProvider::~OmniboxProvider() {}
16190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
16290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void OmniboxProvider::Start(const base::string16& query) {
163116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  controller_->Start(AutocompleteInput(
164116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      query, base::string16::npos, base::string16(), GURL(),
165116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      metrics::OmniboxEventProto::INVALID_SPEC, false, false, true, true,
166116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      ChromeAutocompleteSchemeClassifier(profile_)));
16790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
16890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
16990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void OmniboxProvider::Stop() {
17090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  controller_->Stop(false);
17190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
17290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void OmniboxProvider::PopulateFromACResult(const AutocompleteResult& result) {
17490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ClearResults();
17590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for (ACMatches::const_iterator it = result.begin();
17690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)       it != result.end();
17790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)       ++it) {
17890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (!it->destination_url.is_valid())
17990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      continue;
18090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    Add(scoped_ptr<SearchResult>(
1825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        new OmniboxResult(profile_, controller_.get(), *it)));
18390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
18490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
18590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
18690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void OmniboxProvider::OnResultChanged(bool default_match_changed) {
18790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const AutocompleteResult& result = controller_->result();
18890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  PopulateFromACResult(result);
18990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
19090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
19190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}  // namespace app_list
192