| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 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/autocomplete_popup_model.h" | 5 #include "chrome/browser/autocomplete/autocomplete_popup_model.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "unicode/ubidi.h" | 9 #include "unicode/ubidi.h" |
| 10 | 10 |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 93 // selected line. | 93 // selected line. |
| 94 CHECK(selected_line_ != kNoMatch); | 94 CHECK(selected_line_ != kNoMatch); |
| 95 GURL current_destination(result.match_at(selected_line_).destination_url); | 95 GURL current_destination(result.match_at(selected_line_).destination_url); |
| 96 view_->InvalidateLine(selected_line_); | 96 view_->InvalidateLine(selected_line_); |
| 97 selected_line_ = line; | 97 selected_line_ = line; |
| 98 view_->InvalidateLine(selected_line_); | 98 view_->InvalidateLine(selected_line_); |
| 99 | 99 |
| 100 // Update the edit with the new data for this match. | 100 // Update the edit with the new data for this match. |
| 101 // TODO(pkasting): If |selected_line_| moves to the controller, this can be | 101 // TODO(pkasting): If |selected_line_| moves to the controller, this can be |
| 102 // eliminated and just become a call to the observer on the edit. | 102 // eliminated and just become a call to the observer on the edit. |
| 103 string16 keyword; | |
| 104 const bool is_keyword_hint = GetKeywordForMatch(match, &keyword); | |
| 105 if (reset_to_default) { | 103 if (reset_to_default) { |
| 106 string16 inline_autocomplete_text; | 104 string16 inline_autocomplete_text; |
| 107 if ((match.inline_autocomplete_offset != string16::npos) && | 105 if ((match.inline_autocomplete_offset != string16::npos) && |
| 108 (match.inline_autocomplete_offset < match.fill_into_edit.length())) { | 106 (match.inline_autocomplete_offset < match.fill_into_edit.length())) { |
| 109 inline_autocomplete_text = | 107 inline_autocomplete_text = |
| 110 match.fill_into_edit.substr(match.inline_autocomplete_offset); | 108 match.fill_into_edit.substr(match.inline_autocomplete_offset); |
| 111 } | 109 } |
| 112 edit_model_->OnPopupDataChanged(inline_autocomplete_text, NULL, | 110 edit_model_->OnPopupDataChanged(inline_autocomplete_text, NULL, |
| 113 keyword, is_keyword_hint); | 111 match.keyword, match.has_keyword_hint()); |
| 114 } else { | 112 } else { |
| 115 edit_model_->OnPopupDataChanged(match.fill_into_edit, ¤t_destination, | 113 edit_model_->OnPopupDataChanged(match.fill_into_edit, ¤t_destination, |
| 116 keyword, is_keyword_hint); | 114 match.keyword, match.has_keyword_hint()); |
| 117 } | 115 } |
| 118 | 116 |
| 119 // Repaint old and new selected lines immediately, so that the edit doesn't | 117 // Repaint old and new selected lines immediately, so that the edit doesn't |
| 120 // appear to update [much] faster than the popup. | 118 // appear to update [much] faster than the popup. |
| 121 view_->PaintUpdatesNow(); | 119 view_->PaintUpdatesNow(); |
| 122 } | 120 } |
| 123 | 121 |
| 124 void AutocompletePopupModel::ResetToDefaultMatch() { | 122 void AutocompletePopupModel::ResetToDefaultMatch() { |
| 125 const AutocompleteResult& result = this->result(); | 123 const AutocompleteResult& result = this->result(); |
| 126 CHECK(!result.empty()); | 124 CHECK(!result.empty()); |
| 127 SetSelectedLine(result.default_match() - result.begin(), true, false); | 125 SetSelectedLine(result.default_match() - result.begin(), true, false); |
| 128 view_->OnDragCanceled(); | 126 view_->OnDragCanceled(); |
| 129 } | 127 } |
| 130 | 128 |
| 131 bool AutocompletePopupModel::GetKeywordForMatch(const AutocompleteMatch& match, | |
| 132 string16* keyword) const { | |
| 133 // If the current match is a keyword, return that as the selected keyword. | |
| 134 if (TemplateURL::SupportsReplacement(match.template_url)) { | |
| 135 keyword->assign(match.template_url->keyword()); | |
| 136 return false; | |
| 137 } | |
| 138 | |
| 139 // See if the current match's fill_into_edit corresponds to a keyword. | |
| 140 return GetKeywordForText(match.fill_into_edit, keyword); | |
| 141 } | |
| 142 | |
| 143 bool AutocompletePopupModel::GetKeywordForText(const string16& text, | |
| 144 string16* keyword) const { | |
| 145 // Creates keyword_hint first in case |keyword| is a pointer to |text|. | |
| 146 const string16 keyword_hint(TemplateURLModel::CleanUserInputKeyword(text)); | |
| 147 | |
| 148 // Assume we have no keyword until we find otherwise. | |
| 149 keyword->clear(); | |
| 150 | |
| 151 if (keyword_hint.empty()) | |
| 152 return false; | |
| 153 if (!profile_->GetTemplateURLModel()) | |
| 154 return false; | |
| 155 profile_->GetTemplateURLModel()->Load(); | |
| 156 | |
| 157 // Don't provide a hint if this keyword doesn't support replacement. | |
| 158 const TemplateURL* const template_url = | |
| 159 profile_->GetTemplateURLModel()->GetTemplateURLForKeyword(keyword_hint); | |
| 160 if (!TemplateURL::SupportsReplacement(template_url)) | |
| 161 return false; | |
| 162 | |
| 163 // Don't provide a hint for inactive/disabled extension keywords. | |
| 164 if (template_url->IsExtensionKeyword()) { | |
| 165 const Extension* extension = profile_->GetExtensionService()-> | |
| 166 GetExtensionById(template_url->GetExtensionId(), false); | |
| 167 if (!extension || | |
| 168 (profile_->IsOffTheRecord() && | |
| 169 !profile_->GetExtensionService()-> | |
| 170 IsIncognitoEnabled(extension->id()))) | |
| 171 return false; | |
| 172 } | |
| 173 | |
| 174 keyword->assign(keyword_hint); | |
| 175 return true; | |
| 176 } | |
| 177 | |
| 178 void AutocompletePopupModel::Move(int count) { | 129 void AutocompletePopupModel::Move(int count) { |
| 179 const AutocompleteResult& result = this->result(); | 130 const AutocompleteResult& result = this->result(); |
| 180 if (result.empty()) | 131 if (result.empty()) |
| 181 return; | 132 return; |
| 182 | 133 |
| 183 // The user is using the keyboard to change the selection, so stop tracking | 134 // The user is using the keyboard to change the selection, so stop tracking |
| 184 // hover. | 135 // hover. |
| 185 SetHoveredLine(kNoMatch); | 136 SetHoveredLine(kNoMatch); |
| 186 | 137 |
| 187 // Clamp the new line to [0, result_.count() - 1]. | 138 // Clamp the new line to [0, result_.count() - 1]. |
| (...skipping 29 matching lines...) Expand all Loading... |
| 217 // TODO(pkasting): Eventually the controller should take care of this | 168 // TODO(pkasting): Eventually the controller should take care of this |
| 218 // before notifying us, reducing flicker. At that point the check for | 169 // before notifying us, reducing flicker. At that point the check for |
| 219 // deletability can move there too. | 170 // deletability can move there too. |
| 220 SetSelectedLine(selected_line, false, true); | 171 SetSelectedLine(selected_line, false, true); |
| 221 } | 172 } |
| 222 } | 173 } |
| 223 } | 174 } |
| 224 | 175 |
| 225 const SkBitmap* AutocompletePopupModel::GetSpecialIconForMatch( | 176 const SkBitmap* AutocompletePopupModel::GetSpecialIconForMatch( |
| 226 const AutocompleteMatch& match) const { | 177 const AutocompleteMatch& match) const { |
| 227 if (!match.template_url || !match.template_url->IsExtensionKeyword()) | 178 if (!match.keyword_url || |
| 179 (match.keyword_state == AutocompleteMatch::KEYWORD && |
| 180 !match.keyword_url->IsExtensionKeyword())) |
| 228 return NULL; | 181 return NULL; |
| 229 | 182 |
| 230 return &profile_->GetExtensionService()->GetOmniboxPopupIcon( | 183 return &profile_->GetExtensionService()->GetOmniboxPopupIcon( |
| 231 match.template_url->GetExtensionId()); | 184 match.keyword_url->GetExtensionId()); |
| 232 } | 185 } |
| 233 | 186 |
| 234 void AutocompletePopupModel::OnResultChanged() { | 187 void AutocompletePopupModel::OnResultChanged() { |
| 235 const AutocompleteResult& result = this->result(); | 188 const AutocompleteResult& result = this->result(); |
| 236 selected_line_ = result.default_match() == result.end() ? | 189 selected_line_ = result.default_match() == result.end() ? |
| 237 kNoMatch : static_cast<size_t>(result.default_match() - result.begin()); | 190 kNoMatch : static_cast<size_t>(result.default_match() - result.begin()); |
| 238 // There had better not be a nonempty result set with no default match. | 191 // There had better not be a nonempty result set with no default match. |
| 239 CHECK((selected_line_ != kNoMatch) || result.empty()); | 192 CHECK((selected_line_ != kNoMatch) || result.empty()); |
| 240 manually_selected_match_.Clear(); | 193 manually_selected_match_.Clear(); |
| 241 // If we're going to trim the window size to no longer include the hovered | 194 // If we're going to trim the window size to no longer include the hovered |
| 242 // line, turn hover off. Practically, this shouldn't happen, but it | 195 // line, turn hover off. Practically, this shouldn't happen, but it |
| 243 // doesn't hurt to be defensive. | 196 // doesn't hurt to be defensive. |
| 244 if ((hovered_line_ != kNoMatch) && (result.size() <= hovered_line_)) | 197 if ((hovered_line_ != kNoMatch) && (result.size() <= hovered_line_)) |
| 245 SetHoveredLine(kNoMatch); | 198 SetHoveredLine(kNoMatch); |
| 246 | 199 |
| 247 view_->UpdatePopupAppearance(); | 200 view_->UpdatePopupAppearance(); |
| 248 } | 201 } |
| OLD | NEW |