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