| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/autocomplete/keyword_provider.h" | 5 #include "chrome/browser/autocomplete/keyword_provider.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "app/l10n_util.h" | 10 #include "app/l10n_util.h" |
| 11 #include "base/string16.h" | 11 #include "base/string16.h" |
| 12 #include "base/utf_string_conversions.h" | 12 #include "base/utf_string_conversions.h" |
| 13 #include "chrome/browser/extensions/extension_omnibox_api.h" | 13 #include "chrome/browser/extensions/extension_omnibox_api.h" |
| 14 #include "chrome/browser/extensions/extensions_service.h" | 14 #include "chrome/browser/extensions/extensions_service.h" |
| 15 #include "chrome/browser/profile.h" | 15 #include "chrome/browser/profile.h" |
| 16 #include "chrome/browser/search_engines/template_url.h" | 16 #include "chrome/browser/search_engines/template_url.h" |
| 17 #include "chrome/browser/search_engines/template_url_model.h" | 17 #include "chrome/browser/search_engines/template_url_model.h" |
| 18 #include "chrome/common/notification_service.h" | 18 #include "chrome/common/notification_service.h" |
| 19 #include "grit/generated_resources.h" | 19 #include "grit/generated_resources.h" |
| 20 #include "net/base/escape.h" | 20 #include "net/base/escape.h" |
| 21 #include "net/base/net_util.h" | 21 #include "net/base/net_util.h" |
| 22 | 22 |
| 23 // Helper functor for Start(), for ending keyword mode unless explicitly told |
| 24 // otherwise. |
| 25 class KeywordProvider::ScopedEndExtensionKeywordMode { |
| 26 public: |
| 27 ScopedEndExtensionKeywordMode(KeywordProvider* provider) |
| 28 : provider_(provider) { } |
| 29 ~ScopedEndExtensionKeywordMode() { |
| 30 if (provider_) |
| 31 provider_->MaybeEndExtensionKeywordMode(); |
| 32 } |
| 33 |
| 34 void StayInKeywordMode() { |
| 35 provider_ = NULL; |
| 36 } |
| 37 private: |
| 38 KeywordProvider* provider_; |
| 39 }; |
| 40 |
| 23 // static | 41 // static |
| 24 std::wstring KeywordProvider::SplitReplacementStringFromInput( | 42 std::wstring KeywordProvider::SplitReplacementStringFromInput( |
| 25 const std::wstring& input) { | 43 const std::wstring& input) { |
| 26 // The input may contain leading whitespace, strip it. | 44 // The input may contain leading whitespace, strip it. |
| 27 std::wstring trimmed_input; | 45 std::wstring trimmed_input; |
| 28 TrimWhitespace(input, TRIM_LEADING, &trimmed_input); | 46 TrimWhitespace(input, TRIM_LEADING, &trimmed_input); |
| 29 | 47 |
| 30 // And extract the replacement string. | 48 // And extract the replacement string. |
| 31 std::wstring remaining_input; | 49 std::wstring remaining_input; |
| 32 SplitKeywordFromInput(trimmed_input, &remaining_input); | 50 SplitKeywordFromInput(trimmed_input, &remaining_input); |
| 33 return remaining_input; | 51 return remaining_input; |
| 34 } | 52 } |
| 35 | 53 |
| 36 KeywordProvider::KeywordProvider(ACProviderListener* listener, Profile* profile) | 54 KeywordProvider::KeywordProvider(ACProviderListener* listener, Profile* profile) |
| 37 : AutocompleteProvider(listener, profile, "Keyword"), | 55 : AutocompleteProvider(listener, profile, "Keyword"), |
| 38 model_(NULL), | 56 model_(NULL), |
| 39 current_input_id_(0) { | 57 current_input_id_(0) { |
| 40 // Extension suggestions always come from the original profile, since that's | 58 // Extension suggestions always come from the original profile, since that's |
| 41 // where extensions run. We use the input ID to distinguish whether the | 59 // where extensions run. We use the input ID to distinguish whether the |
| 42 // suggestions are meant for us. | 60 // suggestions are meant for us. |
| 43 registrar_.Add(this, NotificationType::EXTENSION_OMNIBOX_SUGGESTIONS_READY, | 61 registrar_.Add(this, NotificationType::EXTENSION_OMNIBOX_SUGGESTIONS_READY, |
| 44 Source<Profile>(profile->GetOriginalProfile())); | 62 Source<Profile>(profile->GetOriginalProfile())); |
| 63 registrar_.Add(this, NotificationType::EXTENSION_OMNIBOX_INPUT_ENTERED, |
| 64 Source<Profile>(profile)); |
| 45 } | 65 } |
| 46 | 66 |
| 47 KeywordProvider::KeywordProvider(ACProviderListener* listener, | 67 KeywordProvider::KeywordProvider(ACProviderListener* listener, |
| 48 TemplateURLModel* model) | 68 TemplateURLModel* model) |
| 49 : AutocompleteProvider(listener, NULL, "Keyword"), | 69 : AutocompleteProvider(listener, NULL, "Keyword"), |
| 50 model_(model), | 70 model_(model), |
| 51 current_input_id_(0) { | 71 current_input_id_(0) { |
| 52 } | 72 } |
| 53 | 73 |
| 54 | 74 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 90 TemplateURLModel* model = profile->GetTemplateURLModel(); | 110 TemplateURLModel* model = profile->GetTemplateURLModel(); |
| 91 DCHECK(model); | 111 DCHECK(model); |
| 92 model->Load(); | 112 model->Load(); |
| 93 | 113 |
| 94 const TemplateURL* template_url = model->GetTemplateURLForKeyword(keyword); | 114 const TemplateURL* template_url = model->GetTemplateURLForKeyword(keyword); |
| 95 return TemplateURL::SupportsReplacement(template_url) ? template_url : NULL; | 115 return TemplateURL::SupportsReplacement(template_url) ? template_url : NULL; |
| 96 } | 116 } |
| 97 | 117 |
| 98 void KeywordProvider::Start(const AutocompleteInput& input, | 118 void KeywordProvider::Start(const AutocompleteInput& input, |
| 99 bool minimal_changes) { | 119 bool minimal_changes) { |
| 120 // This object ensures we end keyword mode if we exit the function without |
| 121 // toggling keyword mode to on. |
| 122 ScopedEndExtensionKeywordMode keyword_mode_toggle(this); |
| 123 |
| 100 matches_.clear(); | 124 matches_.clear(); |
| 101 | 125 |
| 102 if (!minimal_changes) { | 126 if (!minimal_changes) { |
| 103 done_ = true; | 127 done_ = true; |
| 104 | 128 |
| 105 // Input has changed. Increment the input ID so that we can discard any | 129 // Input has changed. Increment the input ID so that we can discard any |
| 106 // stale extension suggestions that may be incoming. | 130 // stale extension suggestions that may be incoming. |
| 107 current_input_id_ = ++global_input_uid_; | 131 current_input_id_ = ++global_input_uid_; |
| 108 } | 132 } |
| 109 | 133 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 158 // If this extension keyword is disabled, make sure we don't add any | 182 // If this extension keyword is disabled, make sure we don't add any |
| 159 // matches (including the synchronous one below). | 183 // matches (including the synchronous one below). |
| 160 ExtensionsService* service = profile_->GetExtensionsService(); | 184 ExtensionsService* service = profile_->GetExtensionsService(); |
| 161 Extension* extension = service->GetExtensionById( | 185 Extension* extension = service->GetExtensionById( |
| 162 template_url->GetExtensionId(), false); | 186 template_url->GetExtensionId(), false); |
| 163 bool enabled = extension && (!profile_->IsOffTheRecord() || | 187 bool enabled = extension && (!profile_->IsOffTheRecord() || |
| 164 service->IsIncognitoEnabled(extension)); | 188 service->IsIncognitoEnabled(extension)); |
| 165 if (!enabled) | 189 if (!enabled) |
| 166 return; | 190 return; |
| 167 | 191 |
| 192 if (extension->id() != current_keyword_extension_id_) |
| 193 MaybeEndExtensionKeywordMode(); |
| 194 if (current_keyword_extension_id_.empty()) |
| 195 EnterExtensionKeywordMode(extension->id()); |
| 196 keyword_mode_toggle.StayInKeywordMode(); |
| 197 |
| 168 if (minimal_changes) { | 198 if (minimal_changes) { |
| 169 // If the input hasn't significantly changed, we can just use the | 199 // If the input hasn't significantly changed, we can just use the |
| 170 // suggestions from last time. We need to readjust the relevance to | 200 // suggestions from last time. We need to readjust the relevance to |
| 171 // ensure it is less than the main match's relevance. | 201 // ensure it is less than the main match's relevance. |
| 172 for (size_t i = 0; i < extension_suggest_matches_.size(); ++i) { | 202 for (size_t i = 0; i < extension_suggest_matches_.size(); ++i) { |
| 173 matches_.push_back(extension_suggest_matches_[i]); | 203 matches_.push_back(extension_suggest_matches_[i]); |
| 174 matches_.back().relevance = matches_[0].relevance - (i + 1); | 204 matches_.back().relevance = matches_[0].relevance - (i + 1); |
| 175 } | 205 } |
| 176 } else { | 206 } else { |
| 177 extension_suggest_last_input_ = input; | 207 extension_suggest_last_input_ = input; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 198 } | 228 } |
| 199 for (std::vector<std::wstring>::const_iterator i(keyword_matches.begin()); | 229 for (std::vector<std::wstring>::const_iterator i(keyword_matches.begin()); |
| 200 i != keyword_matches.end(); ++i) { | 230 i != keyword_matches.end(); ++i) { |
| 201 matches_.push_back(CreateAutocompleteMatch(model, *i, input, | 231 matches_.push_back(CreateAutocompleteMatch(model, *i, input, |
| 202 keyword.length(), | 232 keyword.length(), |
| 203 remaining_input, -1)); | 233 remaining_input, -1)); |
| 204 } | 234 } |
| 205 } | 235 } |
| 206 } | 236 } |
| 207 | 237 |
| 238 void KeywordProvider::Stop() { |
| 239 done_ = true; |
| 240 MaybeEndExtensionKeywordMode(); |
| 241 } |
| 242 |
| 208 // static | 243 // static |
| 209 bool KeywordProvider::ExtractKeywordFromInput(const AutocompleteInput& input, | 244 bool KeywordProvider::ExtractKeywordFromInput(const AutocompleteInput& input, |
| 210 std::wstring* keyword, | 245 std::wstring* keyword, |
| 211 std::wstring* remaining_input) { | 246 std::wstring* remaining_input) { |
| 212 if ((input.type() == AutocompleteInput::INVALID) || | 247 if ((input.type() == AutocompleteInput::INVALID) || |
| 213 (input.type() == AutocompleteInput::FORCED_QUERY)) | 248 (input.type() == AutocompleteInput::FORCED_QUERY)) |
| 214 return false; | 249 return false; |
| 215 | 250 |
| 216 *keyword = TemplateURLModel::CleanUserInputKeyword( | 251 *keyword = TemplateURLModel::CleanUserInputKeyword( |
| 217 SplitKeywordFromInput(input.text(), remaining_input)); | 252 SplitKeywordFromInput(input.text(), remaining_input)); |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 358 ACMatchClassification::DIM, | 393 ACMatchClassification::DIM, |
| 359 &result.description_class); | 394 &result.description_class); |
| 360 } | 395 } |
| 361 | 396 |
| 362 return result; | 397 return result; |
| 363 } | 398 } |
| 364 | 399 |
| 365 void KeywordProvider::Observe(NotificationType type, | 400 void KeywordProvider::Observe(NotificationType type, |
| 366 const NotificationSource& source, | 401 const NotificationSource& source, |
| 367 const NotificationDetails& details) { | 402 const NotificationDetails& details) { |
| 403 if (type == NotificationType::EXTENSION_OMNIBOX_INPUT_ENTERED) { |
| 404 // Input has been accepted, so we're done with this input session. Ensure |
| 405 // we don't send the OnInputCancelled event. |
| 406 current_keyword_extension_id_.clear(); |
| 407 return; |
| 408 } |
| 409 |
| 368 // TODO(mpcomplete): consider clamping the number of suggestions to | 410 // TODO(mpcomplete): consider clamping the number of suggestions to |
| 369 // AutocompleteProvider::kMaxMatches. | 411 // AutocompleteProvider::kMaxMatches. |
| 370 DCHECK(type == NotificationType::EXTENSION_OMNIBOX_SUGGESTIONS_READY); | 412 DCHECK(type == NotificationType::EXTENSION_OMNIBOX_SUGGESTIONS_READY); |
| 371 | 413 |
| 372 const ExtensionOmniboxSuggestions& suggestions = | 414 const ExtensionOmniboxSuggestions& suggestions = |
| 373 *Details<ExtensionOmniboxSuggestions>(details).ptr(); | 415 *Details<ExtensionOmniboxSuggestions>(details).ptr(); |
| 374 if (suggestions.request_id != current_input_id_) | 416 if (suggestions.request_id != current_input_id_) |
| 375 return; // This is an old result. Just ignore. | 417 return; // This is an old result. Just ignore. |
| 376 | 418 |
| 377 const AutocompleteInput& input = extension_suggest_last_input_; | 419 const AutocompleteInput& input = extension_suggest_last_input_; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 402 match->contents_class = suggestion.description_styles; | 444 match->contents_class = suggestion.description_styles; |
| 403 match->description.clear(); | 445 match->description.clear(); |
| 404 match->description_class.clear(); | 446 match->description_class.clear(); |
| 405 } | 447 } |
| 406 | 448 |
| 407 done_ = true; | 449 done_ = true; |
| 408 matches_.insert(matches_.end(), extension_suggest_matches_.begin(), | 450 matches_.insert(matches_.end(), extension_suggest_matches_.begin(), |
| 409 extension_suggest_matches_.end()); | 451 extension_suggest_matches_.end()); |
| 410 listener_->OnProviderUpdate(!extension_suggest_matches_.empty()); | 452 listener_->OnProviderUpdate(!extension_suggest_matches_.empty()); |
| 411 } | 453 } |
| 454 |
| 455 void KeywordProvider::EnterExtensionKeywordMode( |
| 456 const std::string& extension_id) { |
| 457 DCHECK(current_keyword_extension_id_.empty()); |
| 458 current_keyword_extension_id_ = extension_id; |
| 459 |
| 460 ExtensionOmniboxEventRouter::OnInputStarted( |
| 461 profile_, current_keyword_extension_id_); |
| 462 } |
| 463 |
| 464 void KeywordProvider::MaybeEndExtensionKeywordMode() { |
| 465 if (!current_keyword_extension_id_.empty()) { |
| 466 ExtensionOmniboxEventRouter::OnInputCancelled( |
| 467 profile_, current_keyword_extension_id_); |
| 468 |
| 469 current_keyword_extension_id_.clear(); |
| 470 } |
| 471 } |
| OLD | NEW |