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.
5 // This file defines helper functions shared by the various implementations
8 #include "chrome/browser/ui/omnibox/omnibox_view.h"
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"
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
,
39 base::string16
OmniboxView::SanitizeTextForPaste(const base::string16
& text
) {
40 // Check for non-newline whitespace; if found, collapse whitespace runs down
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
);
54 // Otherwise, all whitespace is newlines; remove it entirely.
55 return StripJavascriptSchemas(base::CollapseWhitespace(text
, true));
59 base::string16
OmniboxView::GetClipboardText() {
61 ui::Clipboard
* clipboard
= ui::Clipboard::GetForCurrentThread();
62 if (clipboard
->IsFormatAvailable(ui::Clipboard::GetPlainTextWFormatType(),
63 ui::CLIPBOARD_TYPE_COPY_PASTE
)) {
65 clipboard
->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE
, &text
);
66 return SanitizeTextForPaste(text
);
69 // Try bookmark format.
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
)) {
79 clipboard
->ReadBookmark(NULL
, &url_str
);
80 // pass resulting url string through GURL to normalize
83 return StripJavascriptSchemas(base::UTF8ToUTF16(url
.spec()));
86 return base::string16();
89 OmniboxView::~OmniboxView() {
92 void OmniboxView::HandleOriginChipMouseRelease() {
93 // Only hide if there isn't any current text in the Omnibox (e.g. search
95 if (controller()->GetToolbarModel()->GetText().empty())
96 controller()->HideOriginChip();
99 void OmniboxView::OnDidKillFocus() {
100 if (chrome::ShouldDisplayOriginChip() && !model()->user_input_in_progress())
101 controller()->ShowOriginChip();
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_
)
113 match
, disposition
, alternate_nav_url
, pasted_text
, selected_line
);
114 OnMatchOpened(match
, controller_
->GetWebContents());
117 bool OmniboxView::IsEditingOrEmpty() const {
118 return (model_
.get() && model_
->user_input_in_progress()) ||
119 (GetOmniboxTextLength() == 0);
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
;
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>"
134 if (model_
->is_keyword_selected())
135 return base::string16();
137 // Attempt to determine the default search provider and use that in the hint
139 TemplateURLService
* template_url_service
=
140 TemplateURLServiceFactory::GetForProfile(model_
->profile());
141 if (template_url_service
) {
142 TemplateURL
* template_url
=
143 template_url_service
->GetDefaultSearchProvider();
145 return l10n_util::GetStringFUTF16(
146 IDS_OMNIBOX_EMPTY_HINT_WITH_DEFAULT_SEARCH_PROVIDER
,
147 template_url
->AdjustedShortNameForLocaleDirection());
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
);
155 void OmniboxView::SetUserText(const base::string16
& text
) {
156 SetUserText(text
, text
, true);
159 void OmniboxView::SetUserText(const base::string16
& text
,
160 const base::string16
& display_text
,
163 model_
->SetUserText(text
);
164 SetWindowTextAndCaretPos(display_text
, display_text
.length(), update_popup
,
168 void OmniboxView::ShowURL() {
170 controller_
->GetToolbarModel()->set_origin_chip_enabled(false);
171 controller_
->GetToolbarModel()->set_url_replacement_enabled(false);
172 model_
->UpdatePermanentText();
173 RevertWithoutResettingSearchTermReplacement();
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();
184 void OmniboxView::RevertAll() {
185 controller_
->GetToolbarModel()->set_origin_chip_enabled(true);
186 controller_
->GetToolbarModel()->set_url_replacement_enabled(true);
187 RevertWithoutResettingSearchTermReplacement();
190 void OmniboxView::RevertWithoutResettingSearchTermReplacement() {
197 void OmniboxView::CloseOmniboxPopup() {
199 model_
->StopAutocomplete();
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
209 void OmniboxView::ShowImeIfNeeded() {
212 bool OmniboxView::IsIndicatingQueryRefinement() const {
213 // The default implementation always returns false. Mobile ports can override
214 // this method and implement as needed.
218 void OmniboxView::OnMatchOpened(const AutocompleteMatch
& match
,
219 content::WebContents
* web_contents
) {
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.
229 model_
.reset(new OmniboxEditModel(this, controller
, profile
));
232 void OmniboxView::TextChanged() {
233 EmphasizeURLComponents();