diff options
-rw-r--r-- | chrome/app/generated_resources.grd | 10 | ||||
-rw-r--r-- | chrome/browser/browser.cc | 1 | ||||
-rw-r--r-- | chrome/browser/gtk/infobar_gtk.cc | 2 | ||||
-rw-r--r-- | chrome/browser/omnibox_search_hint.cc | 204 | ||||
-rw-r--r-- | chrome/browser/omnibox_search_hint.h | 61 | ||||
-rw-r--r-- | chrome/browser/tab_contents/infobar_delegate.h | 17 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents.cc | 5 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents.h | 5 | ||||
-rw-r--r-- | chrome/browser/views/infobars/infobars.cc | 44 | ||||
-rw-r--r-- | chrome/chrome.gyp | 2 | ||||
-rw-r--r-- | chrome/common/chrome_switches.cc | 4 | ||||
-rw-r--r-- | chrome/common/chrome_switches.h | 2 | ||||
-rw-r--r-- | chrome/common/pref_names.cc | 4 | ||||
-rw-r--r-- | chrome/common/pref_names.h | 1 |
14 files changed, 355 insertions, 7 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 84508d4..1a4ffa5 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -4058,6 +4058,16 @@ each locale. --> Created new window in existing browser session. </message> + <message name="IDS_OMNIBOX_SEARCH_HINT_INFOBAR_TEXT" desc="The text displayed in the info-bar to tell users they can type their search queries directly in the location bar."> + Did you know you can search directly from the box above? + </message> + <message name="IDS_OMNIBOX_SEARCH_HINT_INFOBAR_BUTTON_LABEL" desc="The label of the 'Show Me' button on the omnibox search hint infobar."> + Show Me + </message> + <message name="IDS_OMNIBOX_SEARCH_HINT_OMNIBOX_TEXT" desc="The text displayed selected in the omnibox once the user clicked the 'Show Me' button on the omnibox search hint infobar."> + Type your search query here + </message> + <!-- Mac Menubar Menus --> <if expr="os == 'darwin'"> <!-- Menubar Menu Titles --> diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc index 6df7a48..b373b4f 100644 --- a/chrome/browser/browser.cc +++ b/chrome/browser/browser.cc @@ -1207,6 +1207,7 @@ void Browser::RegisterUserPrefs(PrefService* prefs) { prefs->RegisterIntegerPref(prefs::kDeleteTimePeriod, 0); prefs->RegisterBooleanPref(prefs::kCheckDefaultBrowser, true); prefs->RegisterBooleanPref(prefs::kUseCustomChromeFrame, false); + prefs->RegisterBooleanPref(prefs::kShowOmniboxSearchHint, true); } // static diff --git a/chrome/browser/gtk/infobar_gtk.cc b/chrome/browser/gtk/infobar_gtk.cc index 06c549c..4acc96f 100644 --- a/chrome/browser/gtk/infobar_gtk.cc +++ b/chrome/browser/gtk/infobar_gtk.cc @@ -150,6 +150,8 @@ void InfoBar::Closed() { // static void InfoBar::OnCloseButton(GtkWidget* button, InfoBar* info_bar) { + if (info_bar->delegate_) + info_bar->delegate_->InfoBarDismissed(); info_bar->RemoveInfoBar(); } diff --git a/chrome/browser/omnibox_search_hint.cc b/chrome/browser/omnibox_search_hint.cc new file mode 100644 index 0000000..9d36690 --- /dev/null +++ b/chrome/browser/omnibox_search_hint.cc @@ -0,0 +1,204 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/omnibox_search_hint.h" + +#include "app/animation.h" +#include "app/l10n_util.h" +#include "app/resource_bundle.h" +#include "base/command_line.h" +#include "base/task.h" +#include "chrome/browser/browser_list.h" +#include "chrome/browser/browser_window.h" +#include "chrome/browser/location_bar.h" +#include "chrome/browser/autocomplete/autocomplete_edit_view.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/search_engines/template_url_model.h" +#include "chrome/browser/tab_contents/infobar_delegate.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/notification_service.h" +#include "chrome/common/notification_type.h" +#include "chrome/common/pref_names.h" +#include "grit/generated_resources.h" + +// The URLs of search engines for which we want to trigger the infobar. +const char* kSearchEngineURLs[] = { + "http://www.google.com/", + "http://www.yahoo.com/", + "http://www.bing.com/", + "http://www.altavista.com/", + "http://www.ask.com/", + "http://www.wolframalpha.com/", +}; + +class HintInfoBar : public ConfirmInfoBarDelegate { + public: + explicit HintInfoBar(OmniboxSearchHint* omnibox_hint) + : ConfirmInfoBarDelegate(omnibox_hint->tab()), + omnibox_hint_(omnibox_hint), + action_taken_(false), + should_expire_(false), + ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { + // We want the info-bar to stick-around for few seconds and then be hidden + // on the next navigation after that. + MessageLoop::current()->PostDelayedTask(FROM_HERE, + method_factory_.NewRunnableMethod(&HintInfoBar::Expire), + 8000); // 8 seconds. + } + + virtual bool ShouldExpire( + const NavigationController::LoadCommittedDetails& details) const { + return should_expire_; + } + + // Overridden from ConfirmInfoBarDelegate: + virtual void InfoBarClosed() { + if (!action_taken_) + UMA_HISTOGRAM_COUNTS("OmniboxSearchHint.Ignored", 1); + delete this; + } + + virtual void InfoBarDismissed() { + action_taken_ = true; + UMA_HISTOGRAM_COUNTS("OmniboxSearchHint.Closed", 1); + // User closed the infobar, let's not bug him again with this in the future. + omnibox_hint_->DisableHint(); + } + + virtual std::wstring GetMessageText() const { + return l10n_util::GetString(IDS_OMNIBOX_SEARCH_HINT_INFOBAR_TEXT); + } + + virtual SkBitmap* GetIcon() const { + return ResourceBundle::GetSharedInstance().GetBitmapNamed( + IDR_INFOBAR_QUESTION_MARK); + } + + virtual int GetButtons() const { + return BUTTON_OK; + } + + virtual std::wstring GetButtonLabel(InfoBarButton button) const { + return l10n_util::GetString(IDS_OMNIBOX_SEARCH_HINT_INFOBAR_BUTTON_LABEL); + } + + virtual Type GetInfoBarType() { + return INFO_TYPE; + } + + virtual bool Accept() { + action_taken_ = true; + UMA_HISTOGRAM_COUNTS("OmniboxSearchHint.ShowMe", 1); + omnibox_hint_->DisableHint(); + omnibox_hint_->ShowEnteringQuery(); + return true; + } + + void Expire() { + should_expire_ = true; + } + + private: + // The omnibox hint that shows us. + OmniboxSearchHint* omnibox_hint_; + + // Whether the user clicked one of the buttons. + bool action_taken_; + + // Whether the info-bar should be dismissed on the next navigation. + bool should_expire_; + + // Used to delay the expiration of the info-bar. + ScopedRunnableMethodFactory<HintInfoBar> method_factory_; + + DISALLOW_COPY_AND_ASSIGN(HintInfoBar); +}; + +OmniboxSearchHint::OmniboxSearchHint(TabContents* tab) : tab_(tab) { + NavigationController* controller = &(tab->controller()); + notification_registrar_.Add(this, + NotificationType::NAV_ENTRY_COMMITTED, + Source<NavigationController>(controller)); + // Fill the search_engine_urls_ map, used for faster look-up (overkill?). + for (size_t i = 0; + i < sizeof(kSearchEngineURLs) / sizeof(kSearchEngineURLs[0]); ++i) { + search_engine_urls_[kSearchEngineURLs[i]] = 1; + } + + // Listen for omnibox to figure-out when the user searches from the omnibox. + notification_registrar_.Add(this, + NotificationType::OMNIBOX_OPENED_URL, + Source<Profile>(tab->profile())); +} + +OmniboxSearchHint::~OmniboxSearchHint() { +} + +void OmniboxSearchHint::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + if (type == NotificationType::NAV_ENTRY_COMMITTED) { + NavigationEntry* entry = tab_->controller().GetActiveEntry(); + if (search_engine_urls_.find(entry->url().spec()) == + search_engine_urls_.end()) { + // The search engine is not in our white-list, bail. + return; + } + const TemplateURL* const default_provider = + tab_->profile()->GetTemplateURLModel()->GetDefaultSearchProvider(); + if (!default_provider) + return; + + const TemplateURLRef* const search_url = default_provider->url(); + if (search_url->GetHost() == entry->url().host()) + ShowInfoBar(); + } else if (type == NotificationType::OMNIBOX_OPENED_URL) { + AutocompleteLog* log = Details<AutocompleteLog>(details).ptr(); + AutocompleteMatch::Type type = + log->result.match_at(log->selected_index).type; + if (type == AutocompleteMatch::SEARCH_WHAT_YOU_TYPED || + type == AutocompleteMatch::SEARCH_HISTORY || + type == AutocompleteMatch::SEARCH_SUGGEST) { + // The user performed a search from the omnibox, don't show the infobar + // again. + DisableHint(); + } + } +} + +void OmniboxSearchHint::ShowInfoBar() { + tab_->AddInfoBar(new HintInfoBar(this)); +} + +void OmniboxSearchHint::ShowEnteringQuery() { + LocationBar* location_bar = BrowserList::GetLastActive()->window()-> + GetLocationBar(); + AutocompleteEditView* edit_view = location_bar->location_entry(); + location_bar->FocusLocation(); + edit_view->SetUserText( + l10n_util::GetString(IDS_OMNIBOX_SEARCH_HINT_OMNIBOX_TEXT)); + edit_view->SelectAll(false); + // Entering text in the autocomplete edit view triggers the suggestion popup + // that we don't want to show in this case. + edit_view->ClosePopup(); +} + +void OmniboxSearchHint::DisableHint() { + // The NAV_ENTRY_COMMITTED notification was needed to show the infobar, the + // OMNIBOX_OPENED_URL notification was there to set the kShowOmniboxSearchHint + // prefs to false, none of them are needed anymore. + notification_registrar_.RemoveAll(); + tab_->profile()->GetPrefs()->SetBoolean(prefs::kShowOmniboxSearchHint, + false); +} + +// static +bool OmniboxSearchHint::IsEnabled(Profile* profile) { + // The infobar can only be shown if the correct switch has been provided and + // the user did not dismiss the infobar before. + return profile->GetPrefs()->GetBoolean(prefs::kShowOmniboxSearchHint) && + CommandLine::ForCurrentProcess()->HasSwitch( + switches::kSearchInOmniboxHint); +} diff --git a/chrome/browser/omnibox_search_hint.h b/chrome/browser/omnibox_search_hint.h new file mode 100644 index 0000000..3d92011 --- /dev/null +++ b/chrome/browser/omnibox_search_hint.h @@ -0,0 +1,61 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_OMNIBOX_SEARCH_HINT_ +#define CHROME_BROWSER_OMNIBOX_SEARCH_HINT_ + +#include <map> +#include <string> + +#include "base/scoped_ptr.h" +#include "chrome/common/notification_observer.h" +#include "chrome/common/notification_registrar.h" + +class Profile; +class TabContents; + +// This class is responsible for showing an info-bar that tells the user she +// can type her search query directly in the omnibox. +// It is displayed when the user visits a known search engine URL and has not +// searched from the omnibox before, or has not previously dismissed a similar +// info-bar. +class OmniboxSearchHint : public NotificationObserver { + public: + explicit OmniboxSearchHint(TabContents* tab); + ~OmniboxSearchHint(); + + // NotificationObserver method: + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + // Focus the location bar and displays a message instructing that search + // queries can be typed directly in there. + void ShowEnteringQuery(); + + TabContents* tab() { return tab_; } + + // Disables the hint infobar permanently, so that it does not show ever again. + void DisableHint(); + + // Returns true if the profile and current environment make the showing of the + // hint infobar possible. + static bool IsEnabled(Profile* profile); + + private: + void ShowInfoBar(); + + NotificationRegistrar notification_registrar_; + + // The tab we are associated with. + TabContents* tab_; + + // A map containing the URLs of the search engine for which we want to + // trigger the hint. + std::map<std::string, int> search_engine_urls_; + + DISALLOW_COPY_AND_ASSIGN(OmniboxSearchHint); +}; + +#endif // CHROME_BROWSER_OMNIBOX_SEARCH_HINT_ diff --git a/chrome/browser/tab_contents/infobar_delegate.h b/chrome/browser/tab_contents/infobar_delegate.h index 6f44dd2..f8ce253 100644 --- a/chrome/browser/tab_contents/infobar_delegate.h +++ b/chrome/browser/tab_contents/infobar_delegate.h @@ -41,6 +41,14 @@ class LinkInfoBarDelegate; // AddInfoBar! class InfoBarDelegate { public: + // The type of the infobar. It controls its appearence, such as its background + // color. + enum Type { + INFO_TYPE, + WARNING_TYPE, + ERROR_TYPE + }; + // Returns true if the supplied |delegate| is equal to this one. Equality is // left to the implementation to define. This function is called by the // TabContents when determining whether or not a delegate should be added @@ -57,6 +65,9 @@ class InfoBarDelegate { virtual bool ShouldExpire( const NavigationController::LoadCommittedDetails& details) const; + // Called when the user clicks on the close button to dismiss the infobar. + virtual void InfoBarDismissed() {} + // Called after the InfoBar is closed. The delegate is free to delete itself // at this point. virtual void InfoBarClosed() {} @@ -84,6 +95,12 @@ class InfoBarDelegate { return NULL; } + // Returns the type of the infobar. The type determines the appearance (such + // as background color) of the infobar. + virtual Type GetInfoBarType() { + return WARNING_TYPE; + } + protected: // Provided to subclasses as a convenience to initialize the state of this // object. If |contents| is non-NULL, its active entry's unique ID will be diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc index e91f188..3678335 100644 --- a/chrome/browser/tab_contents/tab_contents.cc +++ b/chrome/browser/tab_contents/tab_contents.cc @@ -28,6 +28,7 @@ #include "chrome/browser/jsmessage_box_handler.h" #include "chrome/browser/load_from_memory_cache_details.h" #include "chrome/browser/load_notification_details.h" +#include "chrome/browser/omnibox_search_hint.h" #include "chrome/browser/password_manager/password_manager.h" #include "chrome/browser/plugin_installer.h" #include "chrome/browser/profile.h" @@ -285,6 +286,10 @@ TabContents::TabContents(Profile* profile, static string16 global_last_search = string16(); last_search_prepopulate_text_ = &global_last_search; + // Set-up the showing of the omnibox search infobar if applicable. + if (OmniboxSearchHint::IsEnabled(profile)) + omnibox_search_hint_.reset(new OmniboxSearchHint(this)); + view_->InitRendererPrefs(&renderer_preferences_); } diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h index e0bb482..fc6f76f 100644 --- a/chrome/browser/tab_contents/tab_contents.h +++ b/chrome/browser/tab_contents/tab_contents.h @@ -74,6 +74,7 @@ class DOMUI; class DOMUIContents; class DownloadItem; class LoadNotificationDetails; +class OmniboxSearchHint; class PageAction; class PasswordManager; class PluginInstaller; @@ -1089,6 +1090,10 @@ class TabContents : public PageNavigator, // reset on navigations to false on navigations. bool suppress_javascript_messages_; + // Shows an info-bar to users when they search from a known search engine and + // have never used the monibox for search before. + scoped_ptr<OmniboxSearchHint> omnibox_search_hint_; + // Settings that get passed to the renderer process. RendererPreferences renderer_preferences_; diff --git a/chrome/browser/views/infobars/infobars.cc b/chrome/browser/views/infobars/infobars.cc index 8c67150..c404d0e 100644 --- a/chrome/browser/views/infobars/infobars.cc +++ b/chrome/browser/views/infobars/infobars.cc @@ -30,8 +30,16 @@ static const int kIconLabelSpacing = 5; static const int kButtonSpacing = 5; static const int kWordSpacing = 2; -static const SkColor kBackgroundColorTop = SkColorSetRGB(255, 242, 183); -static const SkColor kBackgroundColorBottom = SkColorSetRGB(250, 230, 145); +static const SkColor kInfoBackgroundColorTop = SkColorSetRGB(170, 214, 112); +static const SkColor kInfoBackgroundColorBottom = SkColorSetRGB(146, 205, 114); + +static const SkColor kWarningBackgroundColorTop = SkColorSetRGB(255, 242, 183); +static const SkColor kWarningBackgroundColorBottom = + SkColorSetRGB(250, 230, 145); + +static const SkColor kErrorBackgroundColorTop = kWarningBackgroundColorTop; +static const SkColor kErrorBackgroundColorBottom = + kWarningBackgroundColorBottom; static const int kSeparatorLineHeight = 1; @@ -57,10 +65,29 @@ int OffsetY(views::View* parent, const gfx::Size prefsize) { class InfoBarBackground : public views::Background { public: - InfoBarBackground() { + InfoBarBackground(InfoBarDelegate::Type infobar_type) { + SkColor top_color; + SkColor bottom_color; + switch (infobar_type) { + case InfoBarDelegate::INFO_TYPE: + top_color = kInfoBackgroundColorTop; + bottom_color = kInfoBackgroundColorBottom; + break; + case InfoBarDelegate::WARNING_TYPE: + top_color = kWarningBackgroundColorTop; + bottom_color = kWarningBackgroundColorBottom; + break; + case InfoBarDelegate::ERROR_TYPE: + top_color = kErrorBackgroundColorTop; + bottom_color = kErrorBackgroundColorBottom; + break; + default: + NOTREACHED(); + break; + } gradient_background_.reset( - views::Background::CreateVerticalGradientBackground( - kBackgroundColorTop, kBackgroundColorBottom)); + views::Background::CreateVerticalGradientBackground(top_color, + bottom_color)); } // Overridden from views::View: @@ -90,7 +117,7 @@ InfoBar::InfoBar(InfoBarDelegate* delegate) // We delete ourselves when we're removed from the view hierarchy. SetParentOwned(false); - set_background(new InfoBarBackground); + set_background(new InfoBarBackground(delegate->GetInfoBarType())); ResourceBundle& rb = ResourceBundle::GetSharedInstance(); close_button_->SetImage(views::CustomButton::BS_NORMAL, @@ -172,8 +199,11 @@ void InfoBar::RemoveInfoBar() const { // InfoBar, views::ButtonListener implementation: ------------------ void InfoBar::ButtonPressed(views::Button* sender) { - if (sender == close_button_) + if (sender == close_button_) { + if (delegate_) + delegate_->InfoBarDismissed(); RemoveInfoBar(); + } } // InfoBar, AnimationDelegate implementation: ---------------------------------- diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index ae71889..ca3b3c3 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -1294,6 +1294,8 @@ 'browser/net/url_fetcher_protect.h', 'browser/net/url_fixer_upper.cc', 'browser/net/url_fixer_upper.h', + 'browser/omnibox_search_hint.cc', + 'browser/omnibox_search_hint.h', 'browser/options_page_base.cc', 'browser/options_page_base.h', 'browser/options_util.cc', diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 99bcd33..ee617fd 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -538,6 +538,10 @@ const wchar_t kEnableTabtastic2[] = L"enable-tabtastic2"; // enabled. const wchar_t kPinnedTabCount[] = L"pinned-tab-count"; +// Enables the showing of an info-bar instructing user they can search directly +// from the omnibox. +const wchar_t kSearchInOmniboxHint[] = L"search-in-omnibox-hint"; + // Enable local storage. Still buggy. const wchar_t kEnableLocalStorage[] = L"enable-local-storage"; diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index 038a630..ea089e8 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -207,6 +207,8 @@ extern const wchar_t kEnableTabtastic2[]; extern const wchar_t kPinnedTabCount[]; +extern const wchar_t kSearchInOmniboxHint[]; + extern const wchar_t kEnableLocalStorage[]; extern const wchar_t kEnableSessionStorage[]; diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index 14176e4..ed4c086 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc @@ -268,6 +268,10 @@ const wchar_t kCheckDefaultBrowser[] = L"browser.check_default_browser"; // true, we draw a custom chrome frame (thicker title bar and blue border). const wchar_t kUseCustomChromeFrame[] = L"browser.custom_chrome_frame"; +// Boolean that indicates whether the infobar explaining that search can be done +// directly from the omnibox should be shown. +const wchar_t kShowOmniboxSearchHint[] = L"browser.show_omnibox_search_hint"; + // *************** LOCAL STATE *************** // These are attached to the machine/installation diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 96b2caf..a33ca22 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h @@ -101,6 +101,7 @@ extern const wchar_t kCurrentThemeTints[]; extern const wchar_t kCurrentThemeDisplayProperties[]; extern const wchar_t kCheckDefaultBrowser[]; extern const wchar_t kUseCustomChromeFrame[]; +extern const wchar_t kShowOmniboxSearchHint[]; // Local state extern const wchar_t kAvailableProfiles[]; |