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