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