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" |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
54 | 54 |
55 KeywordProvider::KeywordProvider(ACProviderListener* listener, Profile* profile) | 55 KeywordProvider::KeywordProvider(ACProviderListener* listener, Profile* profile) |
56 : AutocompleteProvider(listener, profile, "Keyword"), | 56 : AutocompleteProvider(listener, profile, "Keyword"), |
57 model_(NULL), | 57 model_(NULL), |
58 current_input_id_(0) { | 58 current_input_id_(0) { |
59 // Extension suggestions always come from the original profile, since that's | 59 // Extension suggestions always come from the original profile, since that's |
60 // where extensions run. We use the input ID to distinguish whether the | 60 // where extensions run. We use the input ID to distinguish whether the |
61 // suggestions are meant for us. | 61 // suggestions are meant for us. |
62 registrar_.Add(this, NotificationType::EXTENSION_OMNIBOX_SUGGESTIONS_READY, | 62 registrar_.Add(this, NotificationType::EXTENSION_OMNIBOX_SUGGESTIONS_READY, |
63 Source<Profile>(profile->GetOriginalProfile())); | 63 Source<Profile>(profile->GetOriginalProfile())); |
| 64 registrar_.Add(this, |
| 65 NotificationType::EXTENSION_OMNIBOX_DEFAULT_SUGGESTION_CHANGED, |
| 66 Source<Profile>(profile->GetOriginalProfile())); |
64 registrar_.Add(this, NotificationType::EXTENSION_OMNIBOX_INPUT_ENTERED, | 67 registrar_.Add(this, NotificationType::EXTENSION_OMNIBOX_INPUT_ENTERED, |
65 Source<Profile>(profile)); | 68 Source<Profile>(profile)); |
66 } | 69 } |
67 | 70 |
68 KeywordProvider::KeywordProvider(ACProviderListener* listener, | 71 KeywordProvider::KeywordProvider(ACProviderListener* listener, |
69 TemplateURLModel* model) | 72 TemplateURLModel* model) |
70 : AutocompleteProvider(listener, NULL, "Keyword"), | 73 : AutocompleteProvider(listener, NULL, "Keyword"), |
71 model_(model), | 74 model_(model), |
72 current_input_id_(0) { | 75 current_input_id_(0) { |
73 } | 76 } |
(...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
426 ACMatchClassification::DIM, | 429 ACMatchClassification::DIM, |
427 &result.description_class); | 430 &result.description_class); |
428 } | 431 } |
429 | 432 |
430 return result; | 433 return result; |
431 } | 434 } |
432 | 435 |
433 void KeywordProvider::Observe(NotificationType type, | 436 void KeywordProvider::Observe(NotificationType type, |
434 const NotificationSource& source, | 437 const NotificationSource& source, |
435 const NotificationDetails& details) { | 438 const NotificationDetails& details) { |
436 if (type == NotificationType::EXTENSION_OMNIBOX_INPUT_ENTERED) { | 439 TemplateURLModel* model = profile_ ? profile_->GetTemplateURLModel() : model_; |
437 // Input has been accepted, so we're done with this input session. Ensure | 440 const AutocompleteInput& input = extension_suggest_last_input_; |
438 // we don't send the OnInputCancelled event. | 441 |
439 current_keyword_extension_id_.clear(); | 442 switch (type.value) { |
440 return; | 443 case NotificationType::EXTENSION_OMNIBOX_INPUT_ENTERED: |
| 444 // Input has been accepted, so we're done with this input session. Ensure |
| 445 // we don't send the OnInputCancelled event. |
| 446 current_keyword_extension_id_.clear(); |
| 447 return; |
| 448 |
| 449 case NotificationType::EXTENSION_OMNIBOX_DEFAULT_SUGGESTION_CHANGED: { |
| 450 // It's possible to change the default suggestion while not in an editing |
| 451 // session. |
| 452 std::wstring keyword, remaining_input; |
| 453 if (matches_.empty() || current_keyword_extension_id_.empty() || |
| 454 !ExtractKeywordFromInput(input, &keyword, &remaining_input)) |
| 455 return; |
| 456 |
| 457 const TemplateURL* template_url(model->GetTemplateURLForKeyword(keyword)); |
| 458 ApplyDefaultSuggestionForExtensionKeyword(profile_, template_url, |
| 459 WideToUTF16(remaining_input), |
| 460 &matches_[0]); |
| 461 listener_->OnProviderUpdate(true); |
| 462 return; |
| 463 } |
| 464 |
| 465 case NotificationType::EXTENSION_OMNIBOX_SUGGESTIONS_READY: { |
| 466 const ExtensionOmniboxSuggestions& suggestions = |
| 467 *Details<ExtensionOmniboxSuggestions>(details).ptr(); |
| 468 if (suggestions.request_id != current_input_id_) |
| 469 return; // This is an old result. Just ignore. |
| 470 |
| 471 std::wstring keyword, remaining_input; |
| 472 if (!ExtractKeywordFromInput(input, &keyword, &remaining_input)) { |
| 473 NOTREACHED(); |
| 474 return; |
| 475 } |
| 476 |
| 477 // TODO(mpcomplete): consider clamping the number of suggestions to |
| 478 // AutocompleteProvider::kMaxMatches. |
| 479 for (size_t i = 0; i < suggestions.suggestions.size(); ++i) { |
| 480 const ExtensionOmniboxSuggestion& suggestion = |
| 481 suggestions.suggestions[i]; |
| 482 // We want to order these suggestions in descending order, so start with |
| 483 // the relevance of the first result (added synchronously in Start()), |
| 484 // and subtract 1 for each subsequent suggestion from the extension. |
| 485 // We know that |complete| is true, because we wouldn't get results from |
| 486 // the extension unless the full keyword had been typed. |
| 487 int first_relevance = CalculateRelevance(input.type(), true, |
| 488 input.prefer_keyword(), input.allow_exact_keyword_match()); |
| 489 extension_suggest_matches_.push_back(CreateAutocompleteMatch( |
| 490 model, keyword, input, keyword.length(), |
| 491 UTF16ToWide(suggestion.content), first_relevance - (i + 1))); |
| 492 |
| 493 AutocompleteMatch* match = &extension_suggest_matches_.back(); |
| 494 match->contents.assign(UTF16ToWide(suggestion.description)); |
| 495 match->contents_class = suggestion.description_styles; |
| 496 match->description.clear(); |
| 497 match->description_class.clear(); |
| 498 } |
| 499 |
| 500 done_ = true; |
| 501 matches_.insert(matches_.end(), extension_suggest_matches_.begin(), |
| 502 extension_suggest_matches_.end()); |
| 503 listener_->OnProviderUpdate(!extension_suggest_matches_.empty()); |
| 504 return; |
| 505 } |
| 506 |
| 507 default: |
| 508 NOTREACHED(); |
| 509 return; |
441 } | 510 } |
442 | |
443 // TODO(mpcomplete): consider clamping the number of suggestions to | |
444 // AutocompleteProvider::kMaxMatches. | |
445 DCHECK(type == NotificationType::EXTENSION_OMNIBOX_SUGGESTIONS_READY); | |
446 | |
447 const ExtensionOmniboxSuggestions& suggestions = | |
448 *Details<ExtensionOmniboxSuggestions>(details).ptr(); | |
449 if (suggestions.request_id != current_input_id_) | |
450 return; // This is an old result. Just ignore. | |
451 | |
452 const AutocompleteInput& input = extension_suggest_last_input_; | |
453 std::wstring keyword, remaining_input; | |
454 if (!ExtractKeywordFromInput(input, &keyword, &remaining_input)) { | |
455 NOTREACHED(); | |
456 return; | |
457 } | |
458 | |
459 TemplateURLModel* model = | |
460 profile_ ? profile_->GetTemplateURLModel() : model_; | |
461 | |
462 for (size_t i = 0; i < suggestions.suggestions.size(); ++i) { | |
463 const ExtensionOmniboxSuggestion& suggestion = suggestions.suggestions[i]; | |
464 // We want to order these suggestions in descending order, so start with | |
465 // the relevance of the first result (added synchronously in Start()), | |
466 // and subtract 1 for each subsequent suggestion from the extension. | |
467 // We know that |complete| is true, because we wouldn't get results from | |
468 // the extension unless the full keyword had been typed. | |
469 int first_relevance = CalculateRelevance(input.type(), true, | |
470 input.prefer_keyword(), input.allow_exact_keyword_match()); | |
471 extension_suggest_matches_.push_back(CreateAutocompleteMatch( | |
472 model, keyword, input, keyword.length(), | |
473 UTF16ToWide(suggestion.content), first_relevance - (i + 1))); | |
474 | |
475 AutocompleteMatch* match = &extension_suggest_matches_.back(); | |
476 match->contents.assign(UTF16ToWide(suggestion.description)); | |
477 match->contents_class = suggestion.description_styles; | |
478 match->description.clear(); | |
479 match->description_class.clear(); | |
480 } | |
481 | |
482 done_ = true; | |
483 matches_.insert(matches_.end(), extension_suggest_matches_.begin(), | |
484 extension_suggest_matches_.end()); | |
485 listener_->OnProviderUpdate(!extension_suggest_matches_.empty()); | |
486 } | 511 } |
487 | 512 |
488 void KeywordProvider::EnterExtensionKeywordMode( | 513 void KeywordProvider::EnterExtensionKeywordMode( |
489 const std::string& extension_id) { | 514 const std::string& extension_id) { |
490 DCHECK(current_keyword_extension_id_.empty()); | 515 DCHECK(current_keyword_extension_id_.empty()); |
491 current_keyword_extension_id_ = extension_id; | 516 current_keyword_extension_id_ = extension_id; |
492 | 517 |
493 ExtensionOmniboxEventRouter::OnInputStarted( | 518 ExtensionOmniboxEventRouter::OnInputStarted( |
494 profile_, current_keyword_extension_id_); | 519 profile_, current_keyword_extension_id_); |
495 } | 520 } |
496 | 521 |
497 void KeywordProvider::MaybeEndExtensionKeywordMode() { | 522 void KeywordProvider::MaybeEndExtensionKeywordMode() { |
498 if (!current_keyword_extension_id_.empty()) { | 523 if (!current_keyword_extension_id_.empty()) { |
499 ExtensionOmniboxEventRouter::OnInputCancelled( | 524 ExtensionOmniboxEventRouter::OnInputCancelled( |
500 profile_, current_keyword_extension_id_); | 525 profile_, current_keyword_extension_id_); |
501 | 526 |
502 current_keyword_extension_id_.clear(); | 527 current_keyword_extension_id_.clear(); |
503 } | 528 } |
504 } | 529 } |
OLD | NEW |