blob: 5fab6a85870257a9fb776fc4fd295ec35f34dc85 [file] [log] [blame]
[email protected]a26dc362010-04-23 01:48:581// Copyright (c) 2010 The Chromium Authors. All rights reserved.
[email protected]c8865482009-07-23 20:40:102// 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/omnibox_search_hint.h"
6
[email protected]c8865482009-07-23 20:40:107#include "app/l10n_util.h"
8#include "app/resource_bundle.h"
9#include "base/command_line.h"
[email protected]835d7c82010-10-14 04:38:3810#include "base/metrics/histogram.h"
[email protected]c8865482009-07-23 20:40:1011#include "base/task.h"
[email protected]9ac40092010-10-27 23:05:2612#include "chrome/browser/autocomplete/autocomplete.h"
[email protected]12802702010-07-09 19:43:0913#include "chrome/browser/autocomplete/autocomplete_edit.h"
[email protected]052313b2010-02-19 09:43:0814#include "chrome/browser/autocomplete/autocomplete_edit_view.h"
[email protected]9ac40092010-10-27 23:05:2615#include "chrome/browser/autocomplete/autocomplete_match.h"
[email protected]c8865482009-07-23 20:40:1016#include "chrome/browser/browser_list.h"
17#include "chrome/browser/browser_window.h"
[email protected]37858e52010-08-26 00:22:0218#include "chrome/browser/prefs/pref_service.h"
[email protected]c8865482009-07-23 20:40:1019#include "chrome/browser/profile.h"
[email protected]8b62334b2010-08-31 22:37:1120#include "chrome/browser/search_engines/template_url.h"
[email protected]c8865482009-07-23 20:40:1021#include "chrome/browser/search_engines/template_url_model.h"
22#include "chrome/browser/tab_contents/infobar_delegate.h"
23#include "chrome/browser/tab_contents/tab_contents.h"
[email protected]6a3ec2312010-12-02 19:30:1924#include "chrome/browser/ui/omnibox/location_bar.h"
[email protected]c8865482009-07-23 20:40:1025#include "chrome/common/chrome_switches.h"
26#include "chrome/common/notification_service.h"
27#include "chrome/common/notification_type.h"
28#include "chrome/common/pref_names.h"
29#include "grit/generated_resources.h"
[email protected]1db6ff152009-10-12 15:32:0730#include "grit/theme_resources.h"
[email protected]c8865482009-07-23 20:40:1031
32// The URLs of search engines for which we want to trigger the infobar.
33const char* kSearchEngineURLs[] = {
34 "http://www.google.com/",
35 "http://www.yahoo.com/",
36 "http://www.bing.com/",
37 "http://www.altavista.com/",
38 "http://www.ask.com/",
39 "http://www.wolframalpha.com/",
40};
41
42class HintInfoBar : public ConfirmInfoBarDelegate {
43 public:
44 explicit HintInfoBar(OmniboxSearchHint* omnibox_hint)
45 : ConfirmInfoBarDelegate(omnibox_hint->tab()),
46 omnibox_hint_(omnibox_hint),
47 action_taken_(false),
48 should_expire_(false),
49 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
50 // We want the info-bar to stick-around for few seconds and then be hidden
51 // on the next navigation after that.
52 MessageLoop::current()->PostDelayedTask(FROM_HERE,
53 method_factory_.NewRunnableMethod(&HintInfoBar::Expire),
54 8000); // 8 seconds.
55 }
56
57 virtual bool ShouldExpire(
58 const NavigationController::LoadCommittedDetails& details) const {
59 return should_expire_;
60 }
61
62 // Overridden from ConfirmInfoBarDelegate:
63 virtual void InfoBarClosed() {
64 if (!action_taken_)
65 UMA_HISTOGRAM_COUNTS("OmniboxSearchHint.Ignored", 1);
66 delete this;
67 }
68
69 virtual void InfoBarDismissed() {
70 action_taken_ = true;
71 UMA_HISTOGRAM_COUNTS("OmniboxSearchHint.Closed", 1);
72 // User closed the infobar, let's not bug him again with this in the future.
73 omnibox_hint_->DisableHint();
74 }
75
[email protected]e23d3a32010-08-13 19:39:5876 virtual string16 GetMessageText() const {
77 return l10n_util::GetStringUTF16(IDS_OMNIBOX_SEARCH_HINT_INFOBAR_TEXT);
[email protected]c8865482009-07-23 20:40:1078 }
79
80 virtual SkBitmap* GetIcon() const {
81 return ResourceBundle::GetSharedInstance().GetBitmapNamed(
82 IDR_INFOBAR_QUESTION_MARK);
83 }
84
85 virtual int GetButtons() const {
86 return BUTTON_OK;
87 }
88
[email protected]e23d3a32010-08-13 19:39:5889 virtual string16 GetButtonLabel(InfoBarButton button) const {
90 return l10n_util::GetStringUTF16(
91 IDS_OMNIBOX_SEARCH_HINT_INFOBAR_BUTTON_LABEL);
[email protected]c8865482009-07-23 20:40:1092 }
93
[email protected]8db2b842010-07-30 02:22:3594 virtual Type GetInfoBarType() { return PAGE_ACTION_TYPE; }
[email protected]c8865482009-07-23 20:40:1095
96 virtual bool Accept() {
97 action_taken_ = true;
98 UMA_HISTOGRAM_COUNTS("OmniboxSearchHint.ShowMe", 1);
99 omnibox_hint_->DisableHint();
100 omnibox_hint_->ShowEnteringQuery();
101 return true;
102 }
103
104 void Expire() {
105 should_expire_ = true;
106 }
107
108 private:
109 // The omnibox hint that shows us.
110 OmniboxSearchHint* omnibox_hint_;
111
112 // Whether the user clicked one of the buttons.
113 bool action_taken_;
114
115 // Whether the info-bar should be dismissed on the next navigation.
116 bool should_expire_;
117
118 // Used to delay the expiration of the info-bar.
119 ScopedRunnableMethodFactory<HintInfoBar> method_factory_;
120
121 DISALLOW_COPY_AND_ASSIGN(HintInfoBar);
122};
123
124OmniboxSearchHint::OmniboxSearchHint(TabContents* tab) : tab_(tab) {
125 NavigationController* controller = &(tab->controller());
126 notification_registrar_.Add(this,
127 NotificationType::NAV_ENTRY_COMMITTED,
128 Source<NavigationController>(controller));
129 // Fill the search_engine_urls_ map, used for faster look-up (overkill?).
130 for (size_t i = 0;
131 i < sizeof(kSearchEngineURLs) / sizeof(kSearchEngineURLs[0]); ++i) {
132 search_engine_urls_[kSearchEngineURLs[i]] = 1;
133 }
134
135 // Listen for omnibox to figure-out when the user searches from the omnibox.
136 notification_registrar_.Add(this,
137 NotificationType::OMNIBOX_OPENED_URL,
138 Source<Profile>(tab->profile()));
139}
140
141OmniboxSearchHint::~OmniboxSearchHint() {
142}
143
144void OmniboxSearchHint::Observe(NotificationType type,
145 const NotificationSource& source,
146 const NotificationDetails& details) {
147 if (type == NotificationType::NAV_ENTRY_COMMITTED) {
148 NavigationEntry* entry = tab_->controller().GetActiveEntry();
149 if (search_engine_urls_.find(entry->url().spec()) ==
150 search_engine_urls_.end()) {
151 // The search engine is not in our white-list, bail.
152 return;
153 }
154 const TemplateURL* const default_provider =
155 tab_->profile()->GetTemplateURLModel()->GetDefaultSearchProvider();
156 if (!default_provider)
157 return;
158
159 const TemplateURLRef* const search_url = default_provider->url();
160 if (search_url->GetHost() == entry->url().host())
161 ShowInfoBar();
162 } else if (type == NotificationType::OMNIBOX_OPENED_URL) {
163 AutocompleteLog* log = Details<AutocompleteLog>(details).ptr();
164 AutocompleteMatch::Type type =
165 log->result.match_at(log->selected_index).type;
166 if (type == AutocompleteMatch::SEARCH_WHAT_YOU_TYPED ||
167 type == AutocompleteMatch::SEARCH_HISTORY ||
168 type == AutocompleteMatch::SEARCH_SUGGEST) {
169 // The user performed a search from the omnibox, don't show the infobar
170 // again.
171 DisableHint();
172 }
173 }
174}
175
176void OmniboxSearchHint::ShowInfoBar() {
177 tab_->AddInfoBar(new HintInfoBar(this));
178}
179
180void OmniboxSearchHint::ShowEnteringQuery() {
181 LocationBar* location_bar = BrowserList::GetLastActive()->window()->
182 GetLocationBar();
183 AutocompleteEditView* edit_view = location_bar->location_entry();
[email protected]a26dc362010-04-23 01:48:58184 location_bar->FocusLocation(true);
[email protected]c8865482009-07-23 20:40:10185 edit_view->SetUserText(
186 l10n_util::GetString(IDS_OMNIBOX_SEARCH_HINT_OMNIBOX_TEXT));
187 edit_view->SelectAll(false);
188 // Entering text in the autocomplete edit view triggers the suggestion popup
189 // that we don't want to show in this case.
190 edit_view->ClosePopup();
191}
192
193void OmniboxSearchHint::DisableHint() {
194 // The NAV_ENTRY_COMMITTED notification was needed to show the infobar, the
195 // OMNIBOX_OPENED_URL notification was there to set the kShowOmniboxSearchHint
196 // prefs to false, none of them are needed anymore.
197 notification_registrar_.RemoveAll();
198 tab_->profile()->GetPrefs()->SetBoolean(prefs::kShowOmniboxSearchHint,
199 false);
200}
201
202// static
203bool OmniboxSearchHint::IsEnabled(Profile* profile) {
204 // The infobar can only be shown if the correct switch has been provided and
205 // the user did not dismiss the infobar before.
206 return profile->GetPrefs()->GetBoolean(prefs::kShowOmniboxSearchHint) &&
207 CommandLine::ForCurrentProcess()->HasSwitch(
208 switches::kSearchInOmniboxHint);
209}