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/autocomplete/autocomplete_match.h"
     14 #include "ui/base/clipboard/clipboard.h"
     15 
     16 // static
     17 string16 OmniboxView::StripJavascriptSchemas(const string16& text) {
     18   const string16 kJsPrefix(ASCIIToUTF16(chrome::kJavaScriptScheme) +
     19                            ASCIIToUTF16(":"));
     20   string16 out(text);
     21   while (StartsWith(out, kJsPrefix, false))
     22     TrimWhitespace(out.substr(kJsPrefix.length()), TRIM_LEADING, &out);
     23   return out;
     24 }
     25 
     26 // static
     27 string16 OmniboxView::SanitizeTextForPaste(const string16& text) {
     28   // Check for non-newline whitespace; if found, collapse whitespace runs down
     29   // to single spaces.
     30   // TODO(shess): It may also make sense to ignore leading or
     31   // trailing whitespace when making this determination.
     32   for (size_t i = 0; i < text.size(); ++i) {
     33     if (IsWhitespace(text[i]) && text[i] != '\n' && text[i] != '\r') {
     34       const string16 collapsed = CollapseWhitespace(text, false);
     35       // If the user is pasting all-whitespace, paste a single space
     36       // rather than nothing, since pasting nothing feels broken.
     37       return collapsed.empty() ?
     38           ASCIIToUTF16(" ") : StripJavascriptSchemas(collapsed);
     39     }
     40   }
     41 
     42   // Otherwise, all whitespace is newlines; remove it entirely.
     43   return StripJavascriptSchemas(CollapseWhitespace(text, true));
     44 }
     45 
     46 // static
     47 string16 OmniboxView::GetClipboardText() {
     48   // Try text format.
     49   ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
     50   if (clipboard->IsFormatAvailable(ui::Clipboard::GetPlainTextWFormatType(),
     51                                    ui::Clipboard::BUFFER_STANDARD)) {
     52     string16 text;
     53     clipboard->ReadText(ui::Clipboard::BUFFER_STANDARD, &text);
     54     return SanitizeTextForPaste(text);
     55   }
     56 
     57   // Try bookmark format.
     58   //
     59   // It is tempting to try bookmark format first, but the URL we get out of a
     60   // bookmark has been cannonicalized via GURL.  This means if a user copies
     61   // and pastes from the URL bar to itself, the text will get fixed up and
     62   // cannonicalized, which is not what the user expects.  By pasting in this
     63   // order, we are sure to paste what the user copied.
     64   if (clipboard->IsFormatAvailable(ui::Clipboard::GetUrlWFormatType(),
     65                                    ui::Clipboard::BUFFER_STANDARD)) {
     66     std::string url_str;
     67     clipboard->ReadBookmark(NULL, &url_str);
     68     // pass resulting url string through GURL to normalize
     69     GURL url(url_str);
     70     if (url.is_valid())
     71       return StripJavascriptSchemas(UTF8ToUTF16(url.spec()));
     72   }
     73 
     74   return string16();
     75 }
     76 
     77 OmniboxView::~OmniboxView() {
     78 }
     79 
     80 void OmniboxView::OpenMatch(const AutocompleteMatch& match,
     81                             WindowOpenDisposition disposition,
     82                             const GURL& alternate_nav_url,
     83                             size_t selected_line) {
     84   // Invalid URLs such as chrome://history can end up here.
     85   if (!match.destination_url.is_valid())
     86     return;
     87   if (model_.get())
     88     model_->OpenMatch(match, disposition, alternate_nav_url, selected_line);
     89 }
     90 
     91 bool OmniboxView::IsEditingOrEmpty() const {
     92   return (model_.get() && model_->user_input_in_progress()) ||
     93       (GetOmniboxTextLength() == 0);
     94 }
     95 
     96 int OmniboxView::GetIcon() const {
     97   if (IsEditingOrEmpty()) {
     98     return AutocompleteMatch::TypeToLocationBarIcon(model_.get() ?
     99           model_->CurrentTextType() :
    100               AutocompleteMatchType::URL_WHAT_YOU_TYPED);
    101   } else {
    102     return toolbar_model_->GetIcon();
    103   }
    104 }
    105 
    106 void OmniboxView::SetUserText(const string16& text) {
    107   SetUserText(text, text, true);
    108 }
    109 
    110 void OmniboxView::SetUserText(const string16& text,
    111                               const string16& display_text,
    112                               bool update_popup) {
    113   if (model_.get())
    114     model_->SetUserText(text);
    115   SetWindowTextAndCaretPos(display_text, display_text.length(), update_popup,
    116                            true);
    117 }
    118 
    119 void OmniboxView::RevertAll() {
    120   CloseOmniboxPopup();
    121   if (model_.get())
    122     model_->Revert();
    123   TextChanged();
    124 }
    125 
    126 void OmniboxView::CloseOmniboxPopup() {
    127   if (model_.get())
    128     model_->StopAutocomplete();
    129 }
    130 
    131 bool OmniboxView::IsImeShowingPopup() const {
    132   // Default to claiming that the IME is not showing a popup, since hiding the
    133   // omnibox dropdown is a bad user experience when we don't know for sure that
    134   // we have to.
    135   return false;
    136 }
    137 
    138 bool OmniboxView::IsIndicatingQueryRefinement() const {
    139   // The default implementation always returns false.  Mobile ports can override
    140   // this method and implement as needed.
    141   return false;
    142 }
    143 
    144 OmniboxView::OmniboxView(Profile* profile,
    145                          OmniboxEditController* controller,
    146                          ToolbarModel* toolbar_model,
    147                          CommandUpdater* command_updater)
    148     : controller_(controller),
    149       toolbar_model_(toolbar_model),
    150       command_updater_(command_updater) {
    151   // |profile| can be NULL in tests.
    152   if (profile)
    153     model_.reset(new OmniboxEditModel(this, controller, profile));
    154 }
    155 
    156 void OmniboxView::TextChanged() {
    157   EmphasizeURLComponents();
    158   if (model_.get())
    159     model_->OnChanged();
    160 }
    161