Home | History | Annotate | Download | only in omnibox
      1 // Copyright (c) 2012 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 // This file defines helper functions shared by the various implementations
      6 // of OmniboxView.
      7 
      8 #include "chrome/browser/ui/omnibox/omnibox_view.h"
      9 
     10 #include "base/strings/string16.h"
     11 #include "base/strings/string_util.h"
     12 #include "base/strings/utf_string_conversions.h"
     13 #include "chrome/browser/search/search.h"
     14 #include "chrome/browser/search_engines/template_url_service_factory.h"
     15 #include "chrome/browser/ui/omnibox/omnibox_edit_controller.h"
     16 #include "chrome/browser/ui/toolbar/toolbar_model.h"
     17 #include "chrome/grit/generated_resources.h"
     18 #include "components/omnibox/autocomplete_match.h"
     19 #include "components/search_engines/template_url.h"
     20 #include "components/search_engines/template_url_service.h"
     21 #include "grit/components_scaled_resources.h"
     22 #include "grit/theme_resources.h"
     23 #include "ui/base/clipboard/clipboard.h"
     24 #include "ui/base/l10n/l10n_util.h"
     25 
     26 // static
     27 base::string16 OmniboxView::StripJavascriptSchemas(const base::string16& text) {
     28   const base::string16 kJsPrefix(
     29       base::ASCIIToUTF16(url::kJavaScriptScheme) + base::ASCIIToUTF16(":"));
     30   base::string16 out(text);
     31   while (StartsWith(out, kJsPrefix, false)) {
     32     base::TrimWhitespace(out.substr(kJsPrefix.length()), base::TRIM_LEADING,
     33                          &out);
     34   }
     35   return out;
     36 }
     37 
     38 // static
     39 base::string16 OmniboxView::SanitizeTextForPaste(const base::string16& text) {
     40   // Check for non-newline whitespace; if found, collapse whitespace runs down
     41   // to single spaces.
     42   // TODO(shess): It may also make sense to ignore leading or
     43   // trailing whitespace when making this determination.
     44   for (size_t i = 0; i < text.size(); ++i) {
     45     if (IsWhitespace(text[i]) && text[i] != '\n' && text[i] != '\r') {
     46       const base::string16 collapsed = base::CollapseWhitespace(text, false);
     47       // If the user is pasting all-whitespace, paste a single space
     48       // rather than nothing, since pasting nothing feels broken.
     49       return collapsed.empty() ?
     50           base::ASCIIToUTF16(" ") : StripJavascriptSchemas(collapsed);
     51     }
     52   }
     53 
     54   // Otherwise, all whitespace is newlines; remove it entirely.
     55   return StripJavascriptSchemas(base::CollapseWhitespace(text, true));
     56 }
     57 
     58 // static
     59 base::string16 OmniboxView::GetClipboardText() {
     60   // Try text format.
     61   ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
     62   if (clipboard->IsFormatAvailable(ui::Clipboard::GetPlainTextWFormatType(),
     63                                    ui::CLIPBOARD_TYPE_COPY_PASTE)) {
     64     base::string16 text;
     65     clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &text);
     66     return SanitizeTextForPaste(text);
     67   }
     68 
     69   // Try bookmark format.
     70   //
     71   // It is tempting to try bookmark format first, but the URL we get out of a
     72   // bookmark has been cannonicalized via GURL.  This means if a user copies
     73   // and pastes from the URL bar to itself, the text will get fixed up and
     74   // cannonicalized, which is not what the user expects.  By pasting in this
     75   // order, we are sure to paste what the user copied.
     76   if (clipboard->IsFormatAvailable(ui::Clipboard::GetUrlWFormatType(),
     77                                    ui::CLIPBOARD_TYPE_COPY_PASTE)) {
     78     std::string url_str;
     79     clipboard->ReadBookmark(NULL, &url_str);
     80     // pass resulting url string through GURL to normalize
     81     GURL url(url_str);
     82     if (url.is_valid())
     83       return StripJavascriptSchemas(base::UTF8ToUTF16(url.spec()));
     84   }
     85 
     86   return base::string16();
     87 }
     88 
     89 OmniboxView::~OmniboxView() {
     90 }
     91 
     92 void OmniboxView::HandleOriginChipMouseRelease() {
     93   // Only hide if there isn't any current text in the Omnibox (e.g. search
     94   // terms).
     95   if (controller()->GetToolbarModel()->GetText().empty())
     96     controller()->HideOriginChip();
     97 }
     98 
     99 void OmniboxView::OnDidKillFocus() {
    100   if (chrome::ShouldDisplayOriginChip() && !model()->user_input_in_progress())
    101     controller()->ShowOriginChip();
    102 }
    103 
    104 void OmniboxView::OpenMatch(const AutocompleteMatch& match,
    105                             WindowOpenDisposition disposition,
    106                             const GURL& alternate_nav_url,
    107                             const base::string16& pasted_text,
    108                             size_t selected_line) {
    109   // Invalid URLs such as chrome://history can end up here.
    110   if (!match.destination_url.is_valid() || !model_)
    111     return;
    112   model_->OpenMatch(
    113       match, disposition, alternate_nav_url, pasted_text, selected_line);
    114   OnMatchOpened(match, controller_->GetWebContents());
    115 }
    116 
    117 bool OmniboxView::IsEditingOrEmpty() const {
    118   return (model_.get() && model_->user_input_in_progress()) ||
    119       (GetOmniboxTextLength() == 0);
    120 }
    121 
    122 int OmniboxView::GetIcon() const {
    123   if (!IsEditingOrEmpty())
    124     return controller_->GetToolbarModel()->GetIcon();
    125   int id = AutocompleteMatch::TypeToIcon(model_.get() ?
    126       model_->CurrentTextType() : AutocompleteMatchType::URL_WHAT_YOU_TYPED);
    127   return (id == IDR_OMNIBOX_HTTP) ? IDR_LOCATION_BAR_HTTP : id;
    128 }
    129 
    130 base::string16 OmniboxView::GetHintText() const {
    131   // If the user is in keyword mode (the "Search <some site>:" chip is showing)
    132   // then it doesn't make sense to show the "Search <default search engine>"
    133   // hint text.
    134   if (model_->is_keyword_selected())
    135     return base::string16();
    136 
    137   // Attempt to determine the default search provider and use that in the hint
    138   // text.
    139   TemplateURLService* template_url_service =
    140       TemplateURLServiceFactory::GetForProfile(model_->profile());
    141   if (template_url_service) {
    142     TemplateURL* template_url =
    143         template_url_service->GetDefaultSearchProvider();
    144     if (template_url)
    145       return l10n_util::GetStringFUTF16(
    146           IDS_OMNIBOX_EMPTY_HINT_WITH_DEFAULT_SEARCH_PROVIDER,
    147           template_url->AdjustedShortNameForLocaleDirection());
    148   }
    149 
    150   // Otherwise return a hint based on there being no default search provider.
    151   return l10n_util::GetStringUTF16(
    152       IDS_OMNIBOX_EMPTY_HINT_NO_DEFAULT_SEARCH_PROVIDER);
    153 }
    154 
    155 void OmniboxView::SetUserText(const base::string16& text) {
    156   SetUserText(text, text, true);
    157 }
    158 
    159 void OmniboxView::SetUserText(const base::string16& text,
    160                               const base::string16& display_text,
    161                               bool update_popup) {
    162   if (model_.get())
    163     model_->SetUserText(text);
    164   SetWindowTextAndCaretPos(display_text, display_text.length(), update_popup,
    165                            true);
    166 }
    167 
    168 void OmniboxView::ShowURL() {
    169   SetFocus();
    170   controller_->GetToolbarModel()->set_origin_chip_enabled(false);
    171   controller_->GetToolbarModel()->set_url_replacement_enabled(false);
    172   model_->UpdatePermanentText();
    173   RevertWithoutResettingSearchTermReplacement();
    174   SelectAll(true);
    175 }
    176 
    177 void OmniboxView::HideURL() {
    178   controller_->GetToolbarModel()->set_origin_chip_enabled(true);
    179   controller_->GetToolbarModel()->set_url_replacement_enabled(true);
    180   model_->UpdatePermanentText();
    181   RevertWithoutResettingSearchTermReplacement();
    182 }
    183 
    184 void OmniboxView::RevertAll() {
    185   controller_->GetToolbarModel()->set_origin_chip_enabled(true);
    186   controller_->GetToolbarModel()->set_url_replacement_enabled(true);
    187   RevertWithoutResettingSearchTermReplacement();
    188 }
    189 
    190 void OmniboxView::RevertWithoutResettingSearchTermReplacement() {
    191   CloseOmniboxPopup();
    192   if (model_.get())
    193     model_->Revert();
    194   TextChanged();
    195 }
    196 
    197 void OmniboxView::CloseOmniboxPopup() {
    198   if (model_.get())
    199     model_->StopAutocomplete();
    200 }
    201 
    202 bool OmniboxView::IsImeShowingPopup() const {
    203   // Default to claiming that the IME is not showing a popup, since hiding the
    204   // omnibox dropdown is a bad user experience when we don't know for sure that
    205   // we have to.
    206   return false;
    207 }
    208 
    209 void OmniboxView::ShowImeIfNeeded() {
    210 }
    211 
    212 bool OmniboxView::IsIndicatingQueryRefinement() const {
    213   // The default implementation always returns false.  Mobile ports can override
    214   // this method and implement as needed.
    215   return false;
    216 }
    217 
    218 void OmniboxView::OnMatchOpened(const AutocompleteMatch& match,
    219                                 content::WebContents* web_contents) {
    220 }
    221 
    222 OmniboxView::OmniboxView(Profile* profile,
    223                          OmniboxEditController* controller,
    224                          CommandUpdater* command_updater)
    225     : controller_(controller),
    226       command_updater_(command_updater) {
    227   // |profile| can be NULL in tests.
    228   if (profile)
    229     model_.reset(new OmniboxEditModel(this, controller, profile));
    230 }
    231 
    232 void OmniboxView::TextChanged() {
    233   EmphasizeURLComponents();
    234   if (model_.get())
    235     model_->OnChanged();
    236 }
    237