Chromium Code Reviews
|
| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2011 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 #include "chrome/browser/autocomplete/extension_app_provider.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 | |
| 9 #include "base/string16.h" | |
| 10 #include "base/utf_string_conversions.h" | |
| 11 #include "chrome/browser/autocomplete/autocomplete_match.h" | |
| 12 #include "chrome/browser/extensions/extension_service.h" | |
| 13 #include "chrome/browser/profiles/profile.h" | |
| 14 #include "content/common/notification_service.h" | |
| 15 #include "ui/base/l10n/l10n_util.h" | |
| 16 | |
| 17 ExtensionAppProvider::ExtensionAppProvider(ACProviderListener* listener, | |
| 18 Profile* profile) | |
| 19 : AutocompleteProvider(listener, profile, "ExtensionApps") { | |
| 20 RegisterForNotifications(); | |
| 21 RefreshAppList(); | |
| 22 } | |
| 23 | |
| 24 void ExtensionAppProvider::Start(const AutocompleteInput& input, | |
| 25 bool minimal_changes) { | |
| 26 matches_.clear(); | |
| 27 | |
| 28 if (input.type() == AutocompleteInput::INVALID || | |
| 29 input.type() == AutocompleteInput::FORCED_QUERY) | |
|
Peter Kasting
2011/04/04 19:35:32
You should probably handle FORCED_QUERY but maybe
Finnur
2011/04/05 15:50:24
Sound good. Done.
On 2011/04/04 19:35:32, Peter K
| |
| 30 return; | |
| 31 | |
| 32 if (!input.text().empty()) { | |
| 33 std::string input_utf8 = UTF16ToUTF8(input.text()); | |
| 34 for (ExtensionApps::const_iterator app = extension_apps_.begin(); | |
| 35 app != extension_apps_.end(); ++app) { | |
| 36 // See if the input matches this extension application. | |
| 37 const std::string& name = app->first; | |
| 38 const std::string& url = app->second; | |
| 39 std::string::const_iterator name_iter = | |
| 40 std::search(name.begin(), | |
| 41 name.end(), | |
| 42 input_utf8.begin(), | |
| 43 input_utf8.end(), | |
| 44 base::CaseInsensitiveCompare<char>()); | |
| 45 std::string::const_iterator url_iter = | |
| 46 std::search(url.begin(), | |
| 47 url.end(), | |
| 48 input_utf8.begin(), | |
| 49 input_utf8.end(), | |
| 50 base::CaseInsensitiveCompare<char>()); | |
| 51 | |
| 52 bool matches_name = name_iter != name.end(); | |
| 53 bool matches_url = url_iter != url.end(); | |
| 54 if (matches_name || matches_url) { | |
| 55 // We have a match, might be a partial match. | |
| 56 // TODO(finnur): Figure out what type to return here, might want to have | |
| 57 // the extension icon/a generic icon show up in the Omnibox. | |
| 58 AutocompleteMatch match(this, 0, false, AutocompleteMatch::HISTORY_URL); | |
| 59 match.fill_into_edit = UTF8ToUTF16(url); | |
| 60 match.destination_url = GURL(url); | |
| 61 match.inline_autocomplete_offset = string16::npos; | |
| 62 match.contents = UTF8ToUTF16(name); | |
| 63 | |
| 64 size_t pos = name_iter - name.begin(); | |
|
Peter Kasting
2011/04/04 19:35:32
Nit: This block of code is basically repeated verb
Finnur
2011/04/05 15:50:24
Good idea. Done.
On 2011/04/04 19:35:32, Peter Ka
| |
| 65 if (!matches_name || pos > 0) { | |
| 66 match.contents_class.push_back( | |
| 67 ACMatchClassification(0, ACMatchClassification::DIM)); | |
| 68 } | |
| 69 if (matches_name) { | |
| 70 match.contents_class.push_back( | |
| 71 ACMatchClassification(pos, ACMatchClassification::MATCH)); | |
| 72 if (pos + input.text().length() < name.length()) { | |
| 73 match.contents_class.push_back( | |
| 74 ACMatchClassification(pos + input.text().length(), | |
| 75 ACMatchClassification::DIM)); | |
| 76 } | |
| 77 } | |
| 78 | |
| 79 match.description = UTF8ToUTF16(url); | |
| 80 pos = url_iter - url.begin(); | |
| 81 if (!matches_url || pos > 0) { | |
| 82 match.description_class.push_back( | |
| 83 ACMatchClassification(0, ACMatchClassification::DIM)); | |
| 84 } | |
| 85 if (matches_url) { | |
| 86 match.description_class.push_back( | |
| 87 ACMatchClassification(pos, ACMatchClassification::MATCH)); | |
| 88 if (pos + input.text().length() < url.length()) { | |
| 89 match.description_class.push_back( | |
| 90 ACMatchClassification(pos + input.text().length(), | |
| 91 ACMatchClassification::DIM)); | |
| 92 } | |
| 93 } | |
| 94 | |
| 95 match.relevance = CalculateRelevance(input.type(), | |
| 96 input.text().length(), | |
| 97 matches_name ? | |
| 98 name.length() : url.length()); | |
| 99 matches_.push_back(match); | |
| 100 } | |
| 101 } | |
| 102 } | |
| 103 } | |
| 104 | |
| 105 ExtensionAppProvider::~ExtensionAppProvider() { | |
| 106 } | |
| 107 | |
| 108 void ExtensionAppProvider::RefreshAppList() { | |
| 109 ExtensionService* extension_service = profile_->GetExtensionService(); | |
| 110 if (!extension_service) | |
| 111 return; // During testing, there is no extension service. | |
| 112 const ExtensionList* extensions = extension_service->extensions(); | |
| 113 extension_apps_.clear(); | |
| 114 for (ExtensionList::const_iterator app = extensions->begin(); | |
| 115 app != extensions->end(); ++app) { | |
| 116 if ((*app)->is_app() && !(*app)->launch_web_url().empty()) { | |
| 117 extension_apps_.push_back(std::make_pair((*app)->name(), | |
| 118 (*app)->launch_web_url())); | |
| 119 } | |
| 120 } | |
| 121 } | |
| 122 | |
| 123 void ExtensionAppProvider::RegisterForNotifications() { | |
| 124 registrar_.Add(this, NotificationType::EXTENSION_LOADED, | |
| 125 NotificationService::AllSources()); | |
| 126 registrar_.Add(this, NotificationType::EXTENSION_UNINSTALLED, | |
| 127 NotificationService::AllSources()); | |
| 128 } | |
| 129 | |
| 130 void ExtensionAppProvider::Observe(NotificationType type, | |
| 131 const NotificationSource& source, | |
| 132 const NotificationDetails& details) { | |
| 133 switch (type.value) { | |
|
Peter Kasting
2011/04/04 19:35:32
Nit: I don't think all this is useful. Just make
Finnur
2011/04/05 15:50:24
Done.
| |
| 134 case NotificationType::EXTENSION_LOADED: | |
| 135 case NotificationType::EXTENSION_UNINSTALLED: | |
| 136 RefreshAppList(); | |
| 137 break; | |
| 138 default: | |
| 139 NOTREACHED() << "Unhandled notification: " << type.value; | |
| 140 break; | |
| 141 } | |
| 142 } | |
| 143 | |
| 144 int ExtensionAppProvider::CalculateRelevance(AutocompleteInput::Type type, | |
| 145 int input_length, | |
| 146 int target_length) { | |
| 147 // If you update the algorithm here, please remember to update the tables in | |
| 148 // autocomplete.h also. | |
| 149 if (input_length == target_length) | |
| 150 return 1425; | |
| 151 | |
| 152 // Sliding scale from 700+100 to 1175 based on how many characters you typed. | |
|
Peter Kasting
2011/04/04 19:35:32
I suggest scaling from 400 up instead of 800, and
Finnur
2011/04/05 15:50:24
See? I knew there was a guideline hidden in there
| |
| 153 return std::min(1175, 700 + (input_length * 75)); | |
| 154 } | |
| OLD | NEW |