blob: a09b95436e3f1311519e50db03b7bdf84862e8d4 [file] [log] [blame]
[email protected]b1ce30692012-05-15 18:26:351// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]067095a2011-05-24 23:43:442// 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
blundell7dbd3792015-08-05 15:14:198#include "components/omnibox/browser/omnibox_view.h"
[email protected]067095a2011-05-24 23:43:449
dcheng51ace48a2015-12-26 22:45:1710#include <utility>
11
[email protected]11521182013-06-11 04:06:3612#include "base/strings/string16.h"
13#include "base/strings/string_util.h"
[email protected]5846d582013-06-08 16:02:1214#include "base/strings/utf_string_conversions.h"
avif57136c12015-12-25 23:27:4515#include "build/build_config.h"
blundell2102f7c2015-07-09 10:00:5316#include "components/omnibox/browser/autocomplete_match.h"
blundell26a618e2015-07-31 11:16:4517#include "components/omnibox/browser/omnibox_client.h"
blundell3f0c8bb42015-08-03 18:55:0518#include "components/omnibox/browser/omnibox_edit_controller.h"
thomasanderson00687d02016-06-08 16:06:3419#include "components/omnibox/browser/omnibox_edit_model.h"
blundell11d93bc2015-07-31 12:33:1220#include "components/toolbar/toolbar_model.h"
hashimotocfb460f2014-09-25 06:59:0021#include "grit/components_scaled_resources.h"
[email protected]cb39d672014-02-06 02:22:1122#include "ui/base/l10n/l10n_util.h"
estade3c7c6b12015-11-10 01:25:3723#include "ui/gfx/vector_icons_public.h"
[email protected]067095a2011-05-24 23:43:4424
[email protected]c51eed72012-08-07 22:01:5525// static
[email protected]6a72a632013-12-12 22:22:0026base::string16 OmniboxView::StripJavascriptSchemas(const base::string16& text) {
[email protected]d9dfe402013-12-24 23:30:2127 const base::string16 kJsPrefix(
[email protected]cca6f392014-05-28 21:32:2628 base::ASCIIToUTF16(url::kJavaScriptScheme) + base::ASCIIToUTF16(":"));
[email protected]e9273e192013-12-11 17:51:4929 base::string16 out(text);
brettw66d1b81b2015-07-06 19:29:4030 while (base::StartsWith(out, kJsPrefix,
31 base::CompareCase::INSENSITIVE_ASCII)) {
[email protected]8af69c6c2014-03-03 19:05:3132 base::TrimWhitespace(out.substr(kJsPrefix.length()), base::TRIM_LEADING,
33 &out);
34 }
[email protected]067095a2011-05-24 23:43:4435 return out;
36}
37
[email protected]b1ce30692012-05-15 18:26:3538// static
[email protected]6a72a632013-12-12 22:22:0039base::string16 OmniboxView::SanitizeTextForPaste(const base::string16& text) {
[email protected]6cf51b62013-08-10 13:49:2240 // 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) {
brettwb3413062015-06-24 00:39:0245 if (base::IsUnicodeWhitespace(text[i]) &&
46 text[i] != '\n' && text[i] != '\r') {
[email protected]1e1229a12014-03-11 23:16:2447 const base::string16 collapsed = base::CollapseWhitespace(text, false);
[email protected]6cf51b62013-08-10 13:49:2248 // If the user is pasting all-whitespace, paste a single space
49 // rather than nothing, since pasting nothing feels broken.
50 return collapsed.empty() ?
[email protected]d9dfe402013-12-24 23:30:2151 base::ASCIIToUTF16(" ") : StripJavascriptSchemas(collapsed);
[email protected]6cf51b62013-08-10 13:49:2252 }
53 }
54
55 // Otherwise, all whitespace is newlines; remove it entirely.
[email protected]1e1229a12014-03-11 23:16:2456 return StripJavascriptSchemas(base::CollapseWhitespace(text, true));
[email protected]6cf51b62013-08-10 13:49:2257}
58
[email protected]c51eed72012-08-07 22:01:5559OmniboxView::~OmniboxView() {
60}
61
62void OmniboxView::OpenMatch(const AutocompleteMatch& match,
63 WindowOpenDisposition disposition,
64 const GURL& alternate_nav_url,
[email protected]60b55e92014-02-12 03:14:1865 const base::string16& pasted_text,
[email protected]c51eed72012-08-07 22:01:5566 size_t selected_line) {
67 // Invalid URLs such as chrome://history can end up here.
[email protected]94b8a51a2014-03-26 20:57:5568 if (!match.destination_url.is_valid() || !model_)
69 return;
pkastingda6dd842016-02-24 15:26:5970 const AutocompleteMatch::Type match_type = match.type;
[email protected]94b8a51a2014-03-26 20:57:5571 model_->OpenMatch(
72 match, disposition, alternate_nav_url, pasted_text, selected_line);
pkastingda6dd842016-02-24 15:26:5973 // WARNING: |match| may refer to a deleted object at this point!
74 OnMatchOpened(match_type);
[email protected]c51eed72012-08-07 22:01:5575}
76
77bool OmniboxView::IsEditingOrEmpty() const {
78 return (model_.get() && model_->user_input_in_progress()) ||
79 (GetOmniboxTextLength() == 0);
80}
81
palmerc354e282016-05-24 00:55:5782gfx::VectorIconId OmniboxView::GetVectorIcon() const {
palmerc354e282016-05-24 00:55:5783 if (!IsEditingOrEmpty())
84 return controller_->GetToolbarModel()->GetVectorIcon();
85
palmer79f10e42016-07-22 03:45:5786 return AutocompleteMatch::TypeToVectorIcon(
estade3c7c6b12015-11-10 01:25:3787 model_ ? model_->CurrentTextType()
88 : AutocompleteMatchType::URL_WHAT_YOU_TYPED);
estade3c7c6b12015-11-10 01:25:3789}
90
[email protected]e9273e192013-12-11 17:51:4991void OmniboxView::SetUserText(const base::string16& text) {
thomasanderson2f005e52016-05-18 21:28:2892 SetUserText(text, true);
[email protected]c51eed72012-08-07 22:01:5593}
94
[email protected]e9273e192013-12-11 17:51:4995void OmniboxView::SetUserText(const base::string16& text,
[email protected]c51eed72012-08-07 22:01:5596 bool update_popup) {
97 if (model_.get())
98 model_->SetUserText(text);
thomasanderson2f005e52016-05-18 21:28:2899 SetWindowTextAndCaretPos(text, text.length(), update_popup, true);
[email protected]c51eed72012-08-07 22:01:55100}
101
[email protected]c51eed72012-08-07 22:01:55102void OmniboxView::RevertAll() {
[email protected]c51eed72012-08-07 22:01:55103 CloseOmniboxPopup();
104 if (model_.get())
105 model_->Revert();
106 TextChanged();
107}
108
109void OmniboxView::CloseOmniboxPopup() {
110 if (model_.get())
111 model_->StopAutocomplete();
112}
113
[email protected]13177832013-05-31 07:46:05114bool OmniboxView::IsImeShowingPopup() const {
[email protected]d4606b5d2013-06-20 22:38:59115 // Default to claiming that the IME is not showing a popup, since hiding the
116 // omnibox dropdown is a bad user experience when we don't know for sure that
117 // we have to.
118 return false;
[email protected]13177832013-05-31 07:46:05119}
120
[email protected]183e28d2014-01-20 18:18:02121void OmniboxView::ShowImeIfNeeded() {
122}
123
[email protected]40a01152013-06-20 03:52:00124bool OmniboxView::IsIndicatingQueryRefinement() const {
125 // The default implementation always returns false. Mobile ports can override
126 // this method and implement as needed.
127 return false;
128}
129
pkastingda6dd842016-02-24 15:26:59130void OmniboxView::OnMatchOpened(AutocompleteMatch::Type match_type) {
[email protected]5655ea32014-06-21 05:28:08131}
[email protected]94b8a51a2014-03-26 20:57:55132
thomasanderson00687d02016-06-08 16:06:34133void OmniboxView::GetState(State* state) {
134 state->text = GetText();
135 state->keyword = model()->keyword();
136 state->is_keyword_selected = model()->is_keyword_selected();
137 GetSelectionBounds(&state->sel_start, &state->sel_end);
138}
139
140OmniboxView::StateChanges OmniboxView::GetStateChanges(const State& before,
141 const State& after) {
142 OmniboxView::StateChanges state_changes;
143 state_changes.old_text = &before.text;
144 state_changes.new_text = &after.text;
145 state_changes.new_sel_start = after.sel_start;
146 state_changes.new_sel_end = after.sel_end;
147 const bool old_sel_empty = before.sel_start == before.sel_end;
148 const bool new_sel_empty = after.sel_start == after.sel_end;
149 const bool sel_same_ignoring_direction =
150 std::min(before.sel_start, before.sel_end) ==
151 std::min(after.sel_start, after.sel_end) &&
152 std::max(before.sel_start, before.sel_end) ==
153 std::max(after.sel_start, after.sel_end);
154 state_changes.selection_differs =
155 (!old_sel_empty || !new_sel_empty) && !sel_same_ignoring_direction;
156 state_changes.text_differs = before.text != after.text;
157 state_changes.keyword_differs =
158 (after.is_keyword_selected != before.is_keyword_selected) ||
159 (after.is_keyword_selected && before.is_keyword_selected &&
160 after.keyword != before.keyword);
161
162 // When the user has deleted text, we don't allow inline autocomplete. Make
163 // sure to not flag cases like selecting part of the text and then pasting
164 // (or typing) the prefix of that selection. (We detect these by making
165 // sure the caret, which should be after any insertion, hasn't moved
166 // forward of the old selection start.)
167 state_changes.just_deleted_text =
168 (before.text.length() > after.text.length()) &&
169 (after.sel_start <= std::min(before.sel_start, before.sel_end));
170
171 return state_changes;
172}
173
blundelld28fa852015-08-04 16:19:54174OmniboxView::OmniboxView(OmniboxEditController* controller,
dcheng259570c2016-04-22 00:45:57175 std::unique_ptr<OmniboxClient> client)
blundell18b35fd2015-07-28 13:16:06176 : controller_(controller) {
blundelld28fa852015-08-04 16:19:54177 // |client| can be null in tests.
178 if (client) {
dcheng51ace48a2015-12-26 22:45:17179 model_.reset(new OmniboxEditModel(this, controller, std::move(client)));
blundelld28fa852015-08-04 16:19:54180 }
[email protected]c51eed72012-08-07 22:01:55181}
182
183void OmniboxView::TextChanged() {
184 EmphasizeURLComponents();
185 if (model_.get())
186 model_->OnChanged();
187}