OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/ui/autofill/autofill_popup_controller_impl.h" | 5 #include "chrome/browser/ui/autofill/autofill_popup_controller_impl.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/strings/utf_string_conversions.h" | 11 #include "base/strings/utf_string_conversions.h" |
12 #include "chrome/browser/ui/autofill/autofill_popup_view.h" | 12 #include "chrome/browser/ui/autofill/autofill_popup_view.h" |
13 #include "chrome/browser/ui/autofill/popup_constants.h" | 13 #include "chrome/browser/ui/autofill/popup_constants.h" |
14 #include "components/autofill/core/browser/autofill_popup_delegate.h" | 14 #include "components/autofill/core/browser/autofill_popup_delegate.h" |
15 #include "components/autofill/core/browser/popup_item_ids.h" | 15 #include "components/autofill/core/browser/popup_item_ids.h" |
| 16 #include "components/autofill/core/browser/suggestion.h" |
16 #include "content/public/browser/native_web_keyboard_event.h" | 17 #include "content/public/browser/native_web_keyboard_event.h" |
17 #include "grit/components_scaled_resources.h" | 18 #include "grit/components_scaled_resources.h" |
18 #include "ui/base/resource/resource_bundle.h" | 19 #include "ui/base/resource/resource_bundle.h" |
19 #include "ui/events/event.h" | 20 #include "ui/events/event.h" |
20 #include "ui/gfx/rect_conversions.h" | 21 #include "ui/gfx/rect_conversions.h" |
21 #include "ui/gfx/screen.h" | 22 #include "ui/gfx/screen.h" |
22 #include "ui/gfx/text_elider.h" | 23 #include "ui/gfx/text_elider.h" |
23 #include "ui/gfx/text_utils.h" | 24 #include "ui/gfx/text_utils.h" |
24 #include "ui/gfx/vector2d.h" | 25 #include "ui/gfx/vector2d.h" |
25 | 26 |
26 using base::WeakPtr; | 27 using base::WeakPtr; |
27 | 28 |
28 namespace autofill { | 29 namespace autofill { |
29 namespace { | 30 namespace { |
30 | 31 |
31 // Used to indicate that no line is currently selected by the user. | 32 // Used to indicate that no line is currently selected by the user. |
32 const int kNoSelection = -1; | 33 const int kNoSelection = -1; |
33 | 34 |
34 // The vertical height of each row in pixels. | 35 // The vertical height of each row in pixels. |
35 const size_t kRowHeight = 24; | 36 const size_t kRowHeight = 24; |
36 | 37 |
37 // The vertical height of a separator in pixels. | 38 // The vertical height of a separator in pixels. |
38 const size_t kSeparatorHeight = 1; | 39 const size_t kSeparatorHeight = 1; |
39 | 40 |
40 #if !defined(OS_ANDROID) | 41 #if !defined(OS_ANDROID) |
41 // Size difference between name and subtext in pixels. | 42 // Size difference between name and label in pixels. |
42 const int kLabelFontSizeDelta = -2; | 43 const int kLabelFontSizeDelta = -2; |
43 | 44 |
44 const size_t kNamePadding = AutofillPopupView::kNamePadding; | 45 const size_t kNamePadding = AutofillPopupView::kNamePadding; |
45 const size_t kIconPadding = AutofillPopupView::kIconPadding; | 46 const size_t kIconPadding = AutofillPopupView::kIconPadding; |
46 const size_t kEndPadding = AutofillPopupView::kEndPadding; | 47 const size_t kEndPadding = AutofillPopupView::kEndPadding; |
47 #endif | 48 #endif |
48 | 49 |
49 struct DataResource { | 50 struct DataResource { |
50 const char* name; | 51 const char* name; |
51 int id; | 52 int id; |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
103 web_contents)), | 104 web_contents)), |
104 view_(NULL), | 105 view_(NULL), |
105 delegate_(delegate), | 106 delegate_(delegate), |
106 text_direction_(text_direction), | 107 text_direction_(text_direction), |
107 weak_ptr_factory_(this) { | 108 weak_ptr_factory_(this) { |
108 ClearState(); | 109 ClearState(); |
109 controller_common_->SetKeyPressCallback( | 110 controller_common_->SetKeyPressCallback( |
110 base::Bind(&AutofillPopupControllerImpl::HandleKeyPressEvent, | 111 base::Bind(&AutofillPopupControllerImpl::HandleKeyPressEvent, |
111 base::Unretained(this))); | 112 base::Unretained(this))); |
112 #if !defined(OS_ANDROID) | 113 #if !defined(OS_ANDROID) |
113 subtext_font_list_ = name_font_list_.DeriveWithSizeDelta(kLabelFontSizeDelta); | 114 label_font_list_ = value_font_list_.DeriveWithSizeDelta(kLabelFontSizeDelta); |
114 title_font_list_ = name_font_list_.DeriveWithStyle(gfx::Font::BOLD); | 115 title_font_list_ = value_font_list_.DeriveWithStyle(gfx::Font::BOLD); |
115 #if defined(OS_MACOSX) | 116 #if defined(OS_MACOSX) |
116 // There is no italic version of the system font. | 117 // There is no italic version of the system font. |
117 warning_font_list_ = name_font_list_; | 118 warning_font_list_ = value_font_list_; |
118 #else | 119 #else |
119 warning_font_list_ = name_font_list_.DeriveWithStyle(gfx::Font::ITALIC); | 120 warning_font_list_ = value_font_list_.DeriveWithStyle(gfx::Font::ITALIC); |
120 #endif | 121 #endif |
121 #endif | 122 #endif |
122 } | 123 } |
123 | 124 |
124 AutofillPopupControllerImpl::~AutofillPopupControllerImpl() {} | 125 AutofillPopupControllerImpl::~AutofillPopupControllerImpl() {} |
125 | 126 |
126 void AutofillPopupControllerImpl::Show( | 127 void AutofillPopupControllerImpl::Show( |
127 const std::vector<base::string16>& names, | 128 const std::vector<autofill::Suggestion>& suggestions) { |
128 const std::vector<base::string16>& subtexts, | 129 SetValues(suggestions); |
129 const std::vector<base::string16>& icons, | 130 DCHECK_EQ(suggestions_.size(), elided_values_.size()); |
130 const std::vector<int>& identifiers) { | 131 DCHECK_EQ(suggestions_.size(), elided_labels_.size()); |
131 SetValues(names, subtexts, icons, identifiers); | |
132 | 132 |
133 #if !defined(OS_ANDROID) | 133 #if !defined(OS_ANDROID) |
134 // Android displays the long text with ellipsis using the view attributes. | 134 // Android displays the long text with ellipsis using the view attributes. |
135 | 135 |
136 UpdatePopupBounds(); | 136 UpdatePopupBounds(); |
137 int popup_width = popup_bounds().width(); | 137 int popup_width = popup_bounds().width(); |
138 | 138 |
139 // Elide the name and subtext strings so that the popup fits in the available | 139 // Elide the name and label strings so that the popup fits in the available |
140 // space. | 140 // space. |
141 for (size_t i = 0; i < names_.size(); ++i) { | 141 for (size_t i = 0; i < suggestions_.size(); ++i) { |
142 int name_width = gfx::GetStringWidth(names_[i], GetNameFontListForRow(i)); | 142 int value_width = |
143 int subtext_width = gfx::GetStringWidth(subtexts_[i], subtext_font_list()); | 143 gfx::GetStringWidth(suggestions_[i].value, GetValueFontListForRow(i)); |
144 int total_text_length = name_width + subtext_width; | 144 int label_width = |
| 145 gfx::GetStringWidth(suggestions_[i].label, GetLabelFontList()); |
| 146 int total_text_length = value_width + label_width; |
145 | 147 |
146 // The line can have no strings if it represents a UI element, such as | 148 // The line can have no strings if it represents a UI element, such as |
147 // a separator line. | 149 // a separator line. |
148 if (total_text_length == 0) | 150 if (total_text_length == 0) |
149 continue; | 151 continue; |
150 | 152 |
151 int available_width = popup_width - RowWidthWithoutText(i); | 153 int available_width = popup_width - RowWidthWithoutText(i); |
152 | 154 |
153 // Each field receives space in proportion to its length. | 155 // Each field receives space in proportion to its length. |
154 int name_size = available_width * name_width / total_text_length; | 156 int value_size = available_width * value_width / total_text_length; |
155 names_[i] = gfx::ElideText(names_[i], GetNameFontListForRow(i), | 157 elided_values_[i] = gfx::ElideText(suggestions_[i].value, |
156 name_size, gfx::ELIDE_TAIL); | 158 GetValueFontListForRow(i), |
| 159 value_size, gfx::ELIDE_TAIL); |
157 | 160 |
158 int subtext_size = available_width * subtext_width / total_text_length; | 161 int label_size = available_width * label_width / total_text_length; |
159 subtexts_[i] = gfx::ElideText(subtexts_[i], subtext_font_list(), | 162 elided_labels_[i] = gfx::ElideText(suggestions_[i].label, |
160 subtext_size, gfx::ELIDE_TAIL); | 163 GetLabelFontList(), |
| 164 label_size, gfx::ELIDE_TAIL); |
161 } | 165 } |
162 #endif | 166 #endif |
163 | 167 |
164 if (!view_) { | 168 if (!view_) { |
165 view_ = AutofillPopupView::Create(this); | 169 view_ = AutofillPopupView::Create(this); |
166 | 170 |
167 // It is possible to fail to create the popup, in this case | 171 // It is possible to fail to create the popup, in this case |
168 // treat the popup as hiding right away. | 172 // treat the popup as hiding right away. |
169 if (!view_) { | 173 if (!view_) { |
170 Hide(); | 174 Hide(); |
171 return; | 175 return; |
172 } | 176 } |
173 | 177 |
174 ShowView(); | 178 ShowView(); |
175 } else { | 179 } else { |
176 UpdateBoundsAndRedrawPopup(); | 180 UpdateBoundsAndRedrawPopup(); |
177 } | 181 } |
178 | 182 |
179 controller_common_->RegisterKeyPressCallback(); | 183 controller_common_->RegisterKeyPressCallback(); |
180 delegate_->OnPopupShown(); | 184 delegate_->OnPopupShown(); |
181 } | 185 } |
182 | 186 |
183 void AutofillPopupControllerImpl::UpdateDataListValues( | 187 void AutofillPopupControllerImpl::UpdateDataListValues( |
184 const std::vector<base::string16>& values, | 188 const std::vector<base::string16>& values, |
185 const std::vector<base::string16>& labels) { | 189 const std::vector<base::string16>& labels) { |
186 // Remove all the old data list values, which should always be at the top of | 190 // Remove all the old data list values, which should always be at the top of |
187 // the list if they are present. | 191 // the list if they are present. |
188 while (!identifiers_.empty() && | 192 while (!suggestions_.empty() && |
189 identifiers_[0] == POPUP_ITEM_ID_DATALIST_ENTRY) { | 193 suggestions_[0].frontend_id == POPUP_ITEM_ID_DATALIST_ENTRY) { |
190 names_.erase(names_.begin()); | 194 suggestions_.erase(suggestions_.begin()); |
191 subtexts_.erase(subtexts_.begin()); | 195 elided_values_.erase(elided_values_.begin()); |
192 icons_.erase(icons_.begin()); | 196 elided_labels_.erase(elided_labels_.begin()); |
193 identifiers_.erase(identifiers_.begin()); | |
194 } | 197 } |
195 | 198 |
196 // If there are no new data list values, exit (clearing the separator if there | 199 // If there are no new data list values, exit (clearing the separator if there |
197 // is one). | 200 // is one). |
198 if (values.empty()) { | 201 if (values.empty()) { |
199 if (!identifiers_.empty() && identifiers_[0] == POPUP_ITEM_ID_SEPARATOR) { | 202 if (!suggestions_.empty() && |
200 names_.erase(names_.begin()); | 203 suggestions_[0].frontend_id == POPUP_ITEM_ID_SEPARATOR) { |
201 subtexts_.erase(subtexts_.begin()); | 204 suggestions_.erase(suggestions_.begin()); |
202 icons_.erase(icons_.begin()); | 205 elided_values_.erase(elided_values_.begin()); |
203 identifiers_.erase(identifiers_.begin()); | 206 elided_labels_.erase(elided_labels_.begin()); |
204 } | 207 } |
205 | 208 |
206 // The popup contents have changed, so either update the bounds or hide it. | 209 // The popup contents have changed, so either update the bounds or hide it. |
207 if (HasSuggestions()) | 210 if (HasSuggestions()) |
208 UpdateBoundsAndRedrawPopup(); | 211 UpdateBoundsAndRedrawPopup(); |
209 else | 212 else |
210 Hide(); | 213 Hide(); |
211 | 214 |
212 return; | 215 return; |
213 } | 216 } |
214 | 217 |
215 // Add a separator if there are any other values. | 218 // Add a separator if there are any other values. |
216 if (!identifiers_.empty() && identifiers_[0] != POPUP_ITEM_ID_SEPARATOR) { | 219 if (!suggestions_.empty() && |
217 names_.insert(names_.begin(), base::string16()); | 220 suggestions_[0].frontend_id != POPUP_ITEM_ID_SEPARATOR) { |
218 subtexts_.insert(subtexts_.begin(), base::string16()); | 221 suggestions_.insert(suggestions_.begin(), autofill::Suggestion()); |
219 icons_.insert(icons_.begin(), base::string16()); | 222 suggestions_[0].frontend_id = POPUP_ITEM_ID_SEPARATOR; |
220 identifiers_.insert(identifiers_.begin(), POPUP_ITEM_ID_SEPARATOR); | 223 elided_values_.insert(elided_values_.begin(), base::string16()); |
| 224 elided_labels_.insert(elided_labels_.begin(), base::string16()); |
221 } | 225 } |
222 | 226 |
223 | 227 // Prepend the parameters to the suggestions we already have. |
224 names_.insert(names_.begin(), values.begin(), values.end()); | 228 suggestions_.insert(suggestions_.begin(), values.size(), Suggestion()); |
225 subtexts_.insert(subtexts_.begin(), labels.begin(), labels.end()); | 229 for (size_t i = 0; i < values.size(); i++) { |
226 | 230 suggestions_[i].value = values[i]; |
227 // Add the values that are the same for all data list elements. | 231 suggestions_[i].label = labels[i]; |
228 icons_.insert(icons_.begin(), values.size(), base::string16()); | 232 suggestions_[i].frontend_id = POPUP_ITEM_ID_DATALIST_ENTRY; |
229 identifiers_.insert( | 233 } |
230 identifiers_.begin(), values.size(), POPUP_ITEM_ID_DATALIST_ENTRY); | |
231 | 234 |
232 UpdateBoundsAndRedrawPopup(); | 235 UpdateBoundsAndRedrawPopup(); |
233 } | 236 } |
234 | 237 |
235 void AutofillPopupControllerImpl::Hide() { | 238 void AutofillPopupControllerImpl::Hide() { |
236 controller_common_->RemoveKeyPressCallback(); | 239 controller_common_->RemoveKeyPressCallback(); |
237 if (delegate_) | 240 if (delegate_) |
238 delegate_->OnPopupHidden(); | 241 delegate_->OnPopupHidden(); |
239 | 242 |
240 if (view_) | 243 if (view_) |
(...skipping 18 matching lines...) Expand all Loading... |
259 case ui::VKEY_DOWN: | 262 case ui::VKEY_DOWN: |
260 SelectNextLine(); | 263 SelectNextLine(); |
261 return true; | 264 return true; |
262 case ui::VKEY_PRIOR: // Page up. | 265 case ui::VKEY_PRIOR: // Page up. |
263 // Set no line and then select the next line in case the first line is not | 266 // Set no line and then select the next line in case the first line is not |
264 // selectable. | 267 // selectable. |
265 SetSelectedLine(kNoSelection); | 268 SetSelectedLine(kNoSelection); |
266 SelectNextLine(); | 269 SelectNextLine(); |
267 return true; | 270 return true; |
268 case ui::VKEY_NEXT: // Page down. | 271 case ui::VKEY_NEXT: // Page down. |
269 SetSelectedLine(names().size() - 1); | 272 SetSelectedLine(GetLineCount() - 1); |
270 return true; | 273 return true; |
271 case ui::VKEY_ESCAPE: | 274 case ui::VKEY_ESCAPE: |
272 Hide(); | 275 Hide(); |
273 return true; | 276 return true; |
274 case ui::VKEY_DELETE: | 277 case ui::VKEY_DELETE: |
275 return (event.modifiers & content::NativeWebKeyboardEvent::ShiftKey) && | 278 return (event.modifiers & content::NativeWebKeyboardEvent::ShiftKey) && |
276 RemoveSelectedLine(); | 279 RemoveSelectedLine(); |
277 case ui::VKEY_TAB: | 280 case ui::VKEY_TAB: |
278 // A tab press should cause the selected line to be accepted, but still | 281 // A tab press should cause the selected line to be accepted, but still |
279 // return false so the tab key press propagates and changes the cursor | 282 // return false so the tab key press propagates and changes the cursor |
(...skipping 21 matching lines...) Expand all Loading... |
301 | 304 |
302 void AutofillPopupControllerImpl::SetSelectionAtPoint(const gfx::Point& point) { | 305 void AutofillPopupControllerImpl::SetSelectionAtPoint(const gfx::Point& point) { |
303 SetSelectedLine(LineFromY(point.y())); | 306 SetSelectedLine(LineFromY(point.y())); |
304 } | 307 } |
305 | 308 |
306 bool AutofillPopupControllerImpl::AcceptSelectedLine() { | 309 bool AutofillPopupControllerImpl::AcceptSelectedLine() { |
307 if (selected_line_ == kNoSelection) | 310 if (selected_line_ == kNoSelection) |
308 return false; | 311 return false; |
309 | 312 |
310 DCHECK_GE(selected_line_, 0); | 313 DCHECK_GE(selected_line_, 0); |
311 DCHECK_LT(selected_line_, static_cast<int>(names_.size())); | 314 DCHECK_LT(selected_line_, static_cast<int>(GetLineCount())); |
312 | 315 |
313 if (!CanAccept(identifiers_[selected_line_])) | 316 if (!CanAccept(suggestions_[selected_line_].frontend_id)) |
314 return false; | 317 return false; |
315 | 318 |
316 AcceptSuggestion(selected_line_); | 319 AcceptSuggestion(selected_line_); |
317 return true; | 320 return true; |
318 } | 321 } |
319 | 322 |
320 void AutofillPopupControllerImpl::SelectionCleared() { | 323 void AutofillPopupControllerImpl::SelectionCleared() { |
321 SetSelectedLine(kNoSelection); | 324 SetSelectedLine(kNoSelection); |
322 } | 325 } |
323 | 326 |
324 void AutofillPopupControllerImpl::AcceptSuggestion(size_t index) { | 327 void AutofillPopupControllerImpl::AcceptSuggestion(size_t index) { |
325 delegate_->DidAcceptSuggestion(full_names_[index], identifiers_[index]); | 328 const autofill::Suggestion& suggestion = suggestions_[index]; |
| 329 delegate_->DidAcceptSuggestion(suggestion.value, suggestion.frontend_id); |
326 } | 330 } |
327 | 331 |
328 int AutofillPopupControllerImpl::GetIconResourceID( | 332 int AutofillPopupControllerImpl::GetIconResourceID( |
329 const base::string16& resource_name) const { | 333 const base::string16& resource_name) const { |
330 for (size_t i = 0; i < arraysize(kDataResources); ++i) { | 334 for (size_t i = 0; i < arraysize(kDataResources); ++i) { |
331 if (resource_name == base::ASCIIToUTF16(kDataResources[i].name)) | 335 if (resource_name == base::ASCIIToUTF16(kDataResources[i].name)) |
332 return kDataResources[i].id; | 336 return kDataResources[i].id; |
333 } | 337 } |
334 | 338 |
335 return -1; | 339 return -1; |
336 } | 340 } |
337 | 341 |
338 bool AutofillPopupControllerImpl::CanDelete(size_t index) const { | 342 bool AutofillPopupControllerImpl::CanDelete(size_t index) const { |
339 // TODO(isherman): Native AddressBook suggestions on Mac and Android should | 343 // TODO(isherman): Native AddressBook suggestions on Mac and Android should |
340 // not be considered to be deleteable. | 344 // not be considered to be deleteable. |
341 int id = identifiers_[index]; | 345 int id = suggestions_[index].frontend_id; |
342 return id > 0 || id == POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY || | 346 return id > 0 || id == POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY || |
343 id == POPUP_ITEM_ID_PASSWORD_ENTRY; | 347 id == POPUP_ITEM_ID_PASSWORD_ENTRY; |
344 } | 348 } |
345 | 349 |
346 bool AutofillPopupControllerImpl::IsWarning(size_t index) const { | 350 bool AutofillPopupControllerImpl::IsWarning(size_t index) const { |
347 return identifiers_[index] == POPUP_ITEM_ID_WARNING_MESSAGE; | 351 return suggestions_[index].frontend_id == POPUP_ITEM_ID_WARNING_MESSAGE; |
348 } | 352 } |
349 | 353 |
350 gfx::Rect AutofillPopupControllerImpl::GetRowBounds(size_t index) { | 354 gfx::Rect AutofillPopupControllerImpl::GetRowBounds(size_t index) { |
351 int top = kPopupBorderThickness; | 355 int top = kPopupBorderThickness; |
352 for (size_t i = 0; i < index; ++i) { | 356 for (size_t i = 0; i < index; ++i) { |
353 top += GetRowHeightFromId(identifiers()[i]); | 357 top += GetRowHeightFromId(suggestions_[i].frontend_id); |
354 } | 358 } |
355 | 359 |
356 return gfx::Rect( | 360 return gfx::Rect( |
357 kPopupBorderThickness, | 361 kPopupBorderThickness, |
358 top, | 362 top, |
359 popup_bounds_.width() - 2 * kPopupBorderThickness, | 363 popup_bounds_.width() - 2 * kPopupBorderThickness, |
360 GetRowHeightFromId(identifiers()[index])); | 364 GetRowHeightFromId(suggestions_[index].frontend_id)); |
361 } | 365 } |
362 | 366 |
363 void AutofillPopupControllerImpl::SetPopupBounds(const gfx::Rect& bounds) { | 367 void AutofillPopupControllerImpl::SetPopupBounds(const gfx::Rect& bounds) { |
364 popup_bounds_ = bounds; | 368 popup_bounds_ = bounds; |
365 UpdateBoundsAndRedrawPopup(); | 369 UpdateBoundsAndRedrawPopup(); |
366 } | 370 } |
367 | 371 |
368 const gfx::Rect& AutofillPopupControllerImpl::popup_bounds() const { | 372 const gfx::Rect& AutofillPopupControllerImpl::popup_bounds() const { |
369 return popup_bounds_; | 373 return popup_bounds_; |
370 } | 374 } |
371 | 375 |
372 content::WebContents* AutofillPopupControllerImpl::web_contents() { | 376 content::WebContents* AutofillPopupControllerImpl::web_contents() { |
373 return controller_common_->web_contents(); | 377 return controller_common_->web_contents(); |
374 } | 378 } |
375 | 379 |
376 gfx::NativeView AutofillPopupControllerImpl::container_view() { | 380 gfx::NativeView AutofillPopupControllerImpl::container_view() { |
377 return controller_common_->container_view(); | 381 return controller_common_->container_view(); |
378 } | 382 } |
379 | 383 |
380 const gfx::RectF& AutofillPopupControllerImpl::element_bounds() const { | 384 const gfx::RectF& AutofillPopupControllerImpl::element_bounds() const { |
381 return controller_common_->element_bounds(); | 385 return controller_common_->element_bounds(); |
382 } | 386 } |
383 | 387 |
384 bool AutofillPopupControllerImpl::IsRTL() const { | 388 bool AutofillPopupControllerImpl::IsRTL() const { |
385 return text_direction_ == base::i18n::RIGHT_TO_LEFT; | 389 return text_direction_ == base::i18n::RIGHT_TO_LEFT; |
386 } | 390 } |
387 | 391 |
388 const std::vector<base::string16>& AutofillPopupControllerImpl::names() const { | 392 size_t AutofillPopupControllerImpl::GetLineCount() const { |
389 return names_; | 393 return suggestions_.size(); |
390 } | 394 } |
391 | 395 |
392 const std::vector<base::string16>& AutofillPopupControllerImpl::subtexts() | 396 const autofill::Suggestion& AutofillPopupControllerImpl::GetSuggestionAt( |
393 const { | 397 size_t row) const { |
394 return subtexts_; | 398 return suggestions_[row]; |
395 } | 399 } |
396 | 400 |
397 const std::vector<base::string16>& AutofillPopupControllerImpl::icons() const { | 401 const base::string16& AutofillPopupControllerImpl::GetElidedValueAt( |
398 return icons_; | 402 size_t row) const { |
| 403 return elided_values_[row]; |
399 } | 404 } |
400 | 405 |
401 const std::vector<int>& AutofillPopupControllerImpl::identifiers() const { | 406 const base::string16& AutofillPopupControllerImpl::GetElidedLabelAt( |
402 return identifiers_; | 407 size_t row) const { |
| 408 return elided_labels_[row]; |
403 } | 409 } |
404 | 410 |
405 #if !defined(OS_ANDROID) | 411 #if !defined(OS_ANDROID) |
406 const gfx::FontList& AutofillPopupControllerImpl::GetNameFontListForRow( | 412 const gfx::FontList& AutofillPopupControllerImpl::GetValueFontListForRow( |
407 size_t index) const { | 413 size_t index) const { |
408 if (identifiers_[index] == POPUP_ITEM_ID_WARNING_MESSAGE) | 414 if (suggestions_[index].frontend_id == POPUP_ITEM_ID_WARNING_MESSAGE) |
409 return warning_font_list_; | 415 return warning_font_list_; |
410 | 416 |
411 if (identifiers_[index] == POPUP_ITEM_ID_TITLE) | 417 if (suggestions_[index].frontend_id == POPUP_ITEM_ID_TITLE) |
412 return title_font_list_; | 418 return title_font_list_; |
413 | 419 |
414 return name_font_list_; | 420 return value_font_list_; |
415 } | 421 } |
416 | 422 |
417 const gfx::FontList& AutofillPopupControllerImpl::subtext_font_list() const { | 423 const gfx::FontList& AutofillPopupControllerImpl::GetLabelFontList() const { |
418 return subtext_font_list_; | 424 return label_font_list_; |
419 } | 425 } |
420 #endif | 426 #endif |
421 | 427 |
422 int AutofillPopupControllerImpl::selected_line() const { | 428 int AutofillPopupControllerImpl::selected_line() const { |
423 return selected_line_; | 429 return selected_line_; |
424 } | 430 } |
425 | 431 |
426 void AutofillPopupControllerImpl::SetSelectedLine(int selected_line) { | 432 void AutofillPopupControllerImpl::SetSelectedLine(int selected_line) { |
427 if (selected_line_ == selected_line) | 433 if (selected_line_ == selected_line) |
428 return; | 434 return; |
429 | 435 |
430 if (selected_line_ != kNoSelection && | 436 if (selected_line_ != kNoSelection && |
431 static_cast<size_t>(selected_line_) < identifiers_.size()) | 437 static_cast<size_t>(selected_line_) < suggestions_.size()) |
432 InvalidateRow(selected_line_); | 438 InvalidateRow(selected_line_); |
433 | 439 |
434 if (selected_line != kNoSelection) { | 440 if (selected_line != kNoSelection) { |
435 InvalidateRow(selected_line); | 441 InvalidateRow(selected_line); |
436 | 442 |
437 if (!CanAccept(identifiers_[selected_line])) | 443 if (!CanAccept(suggestions_[selected_line].frontend_id)) |
438 selected_line = kNoSelection; | 444 selected_line = kNoSelection; |
439 } | 445 } |
440 | 446 |
441 selected_line_ = selected_line; | 447 selected_line_ = selected_line; |
442 | 448 |
443 if (selected_line_ != kNoSelection) { | 449 if (selected_line_ != kNoSelection) { |
444 delegate_->DidSelectSuggestion(names_[selected_line_], | 450 delegate_->DidSelectSuggestion(elided_values_[selected_line_], |
445 identifiers_[selected_line_]); | 451 suggestions_[selected_line_].frontend_id); |
446 } else { | 452 } else { |
447 delegate_->ClearPreviewedForm(); | 453 delegate_->ClearPreviewedForm(); |
448 } | 454 } |
449 } | 455 } |
450 | 456 |
451 void AutofillPopupControllerImpl::SelectNextLine() { | 457 void AutofillPopupControllerImpl::SelectNextLine() { |
452 int new_selected_line = selected_line_ + 1; | 458 int new_selected_line = selected_line_ + 1; |
453 | 459 |
454 // Skip over any lines that can't be selected. | 460 // Skip over any lines that can't be selected. |
455 while (static_cast<size_t>(new_selected_line) < names_.size() && | 461 while (static_cast<size_t>(new_selected_line) < GetLineCount() && |
456 !CanAccept(identifiers()[new_selected_line])) { | 462 !CanAccept(suggestions_[new_selected_line].frontend_id)) { |
457 ++new_selected_line; | 463 ++new_selected_line; |
458 } | 464 } |
459 | 465 |
460 if (new_selected_line >= static_cast<int>(names_.size())) | 466 if (new_selected_line >= static_cast<int>(GetLineCount())) |
461 new_selected_line = 0; | 467 new_selected_line = 0; |
462 | 468 |
463 SetSelectedLine(new_selected_line); | 469 SetSelectedLine(new_selected_line); |
464 } | 470 } |
465 | 471 |
466 void AutofillPopupControllerImpl::SelectPreviousLine() { | 472 void AutofillPopupControllerImpl::SelectPreviousLine() { |
467 int new_selected_line = selected_line_ - 1; | 473 int new_selected_line = selected_line_ - 1; |
468 | 474 |
469 // Skip over any lines that can't be selected. | 475 // Skip over any lines that can't be selected. |
470 while (new_selected_line > kNoSelection && | 476 while (new_selected_line > kNoSelection && |
471 !CanAccept(identifiers()[new_selected_line])) { | 477 !CanAccept(GetSuggestionAt(new_selected_line).frontend_id)) { |
472 --new_selected_line; | 478 --new_selected_line; |
473 } | 479 } |
474 | 480 |
475 if (new_selected_line <= kNoSelection) | 481 if (new_selected_line <= kNoSelection) |
476 new_selected_line = names_.size() - 1; | 482 new_selected_line = GetLineCount() - 1; |
477 | 483 |
478 SetSelectedLine(new_selected_line); | 484 SetSelectedLine(new_selected_line); |
479 } | 485 } |
480 | 486 |
481 bool AutofillPopupControllerImpl::RemoveSelectedLine() { | 487 bool AutofillPopupControllerImpl::RemoveSelectedLine() { |
482 if (selected_line_ == kNoSelection) | 488 if (selected_line_ == kNoSelection) |
483 return false; | 489 return false; |
484 | 490 |
485 DCHECK_GE(selected_line_, 0); | 491 DCHECK_GE(selected_line_, 0); |
486 DCHECK_LT(selected_line_, static_cast<int>(names_.size())); | 492 DCHECK_LT(selected_line_, static_cast<int>(GetLineCount())); |
487 | 493 |
488 if (!CanDelete(selected_line_)) | 494 if (!CanDelete(selected_line_)) |
489 return false; | 495 return false; |
490 | 496 |
491 delegate_->RemoveSuggestion(full_names_[selected_line_], | 497 delegate_->RemoveSuggestion(suggestions_[selected_line_].value, |
492 identifiers_[selected_line_]); | 498 suggestions_[selected_line_].frontend_id); |
493 | 499 |
494 // Remove the deleted element. | 500 // Remove the deleted element. |
495 names_.erase(names_.begin() + selected_line_); | 501 suggestions_.erase(suggestions_.begin() + selected_line_); |
496 full_names_.erase(full_names_.begin() + selected_line_); | 502 elided_values_.erase(elided_values_.begin() + selected_line_); |
497 subtexts_.erase(subtexts_.begin() + selected_line_); | 503 elided_labels_.erase(elided_labels_.begin() + selected_line_); |
498 icons_.erase(icons_.begin() + selected_line_); | |
499 identifiers_.erase(identifiers_.begin() + selected_line_); | |
500 | 504 |
501 SetSelectedLine(kNoSelection); | 505 SetSelectedLine(kNoSelection); |
502 | 506 |
503 if (HasSuggestions()) { | 507 if (HasSuggestions()) { |
504 delegate_->ClearPreviewedForm(); | 508 delegate_->ClearPreviewedForm(); |
505 UpdateBoundsAndRedrawPopup(); | 509 UpdateBoundsAndRedrawPopup(); |
506 } else { | 510 } else { |
507 Hide(); | 511 Hide(); |
508 } | 512 } |
509 | 513 |
510 return true; | 514 return true; |
511 } | 515 } |
512 | 516 |
513 int AutofillPopupControllerImpl::LineFromY(int y) { | 517 int AutofillPopupControllerImpl::LineFromY(int y) { |
514 int current_height = kPopupBorderThickness; | 518 int current_height = kPopupBorderThickness; |
515 | 519 |
516 for (size_t i = 0; i < identifiers().size(); ++i) { | 520 for (size_t i = 0; i < suggestions_.size(); ++i) { |
517 current_height += GetRowHeightFromId(identifiers()[i]); | 521 current_height += GetRowHeightFromId(suggestions_[i].frontend_id); |
518 | 522 |
519 if (y <= current_height) | 523 if (y <= current_height) |
520 return i; | 524 return i; |
521 } | 525 } |
522 | 526 |
523 // The y value goes beyond the popup so stop the selection at the last line. | 527 // The y value goes beyond the popup so stop the selection at the last line. |
524 return identifiers().size() - 1; | 528 return GetLineCount() - 1; |
525 } | 529 } |
526 | 530 |
527 int AutofillPopupControllerImpl::GetRowHeightFromId(int identifier) const { | 531 int AutofillPopupControllerImpl::GetRowHeightFromId(int identifier) const { |
528 if (identifier == POPUP_ITEM_ID_SEPARATOR) | 532 if (identifier == POPUP_ITEM_ID_SEPARATOR) |
529 return kSeparatorHeight; | 533 return kSeparatorHeight; |
530 | 534 |
531 return kRowHeight; | 535 return kRowHeight; |
532 } | 536 } |
533 | 537 |
534 bool AutofillPopupControllerImpl::CanAccept(int id) { | 538 bool AutofillPopupControllerImpl::CanAccept(int id) { |
535 return id != POPUP_ITEM_ID_SEPARATOR && id != POPUP_ITEM_ID_WARNING_MESSAGE && | 539 return id != POPUP_ITEM_ID_SEPARATOR && id != POPUP_ITEM_ID_WARNING_MESSAGE && |
536 id != POPUP_ITEM_ID_TITLE; | 540 id != POPUP_ITEM_ID_TITLE; |
537 } | 541 } |
538 | 542 |
539 bool AutofillPopupControllerImpl::HasSuggestions() { | 543 bool AutofillPopupControllerImpl::HasSuggestions() { |
540 return identifiers_.size() != 0 && | 544 if (suggestions_.empty()) |
541 (identifiers_[0] > 0 || | 545 return false; |
542 identifiers_[0] == POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY || | 546 int id = suggestions_[0].frontend_id; |
543 identifiers_[0] == POPUP_ITEM_ID_PASSWORD_ENTRY || | 547 return id > 0 || |
544 identifiers_[0] == POPUP_ITEM_ID_DATALIST_ENTRY || | 548 id == POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY || |
545 identifiers_[0] == POPUP_ITEM_ID_MAC_ACCESS_CONTACTS); | 549 id == POPUP_ITEM_ID_PASSWORD_ENTRY || |
| 550 id == POPUP_ITEM_ID_DATALIST_ENTRY || |
| 551 id == POPUP_ITEM_ID_MAC_ACCESS_CONTACTS; |
546 } | 552 } |
547 | 553 |
548 void AutofillPopupControllerImpl::SetValues( | 554 void AutofillPopupControllerImpl::SetValues( |
549 const std::vector<base::string16>& names, | 555 const std::vector<autofill::Suggestion>& suggestions) { |
550 const std::vector<base::string16>& subtexts, | 556 suggestions_ = suggestions; |
551 const std::vector<base::string16>& icons, | 557 elided_values_.resize(suggestions.size()); |
552 const std::vector<int>& identifiers) { | 558 elided_labels_.resize(suggestions.size()); |
553 names_ = names; | 559 for (size_t i = 0; i < suggestions.size(); i++) { |
554 full_names_ = names; | 560 elided_values_[i] = suggestions[i].value; |
555 subtexts_ = subtexts; | 561 elided_labels_[i] = suggestions[i].label; |
556 icons_ = icons; | 562 } |
557 identifiers_ = identifiers; | |
558 } | 563 } |
559 | 564 |
560 void AutofillPopupControllerImpl::ShowView() { | 565 void AutofillPopupControllerImpl::ShowView() { |
561 view_->Show(); | 566 view_->Show(); |
562 } | 567 } |
563 | 568 |
564 void AutofillPopupControllerImpl::InvalidateRow(size_t row) { | 569 void AutofillPopupControllerImpl::InvalidateRow(size_t row) { |
565 DCHECK(0 <= row); | 570 DCHECK(0 <= row); |
566 DCHECK(row < identifiers_.size()); | 571 DCHECK(row < suggestions_.size()); |
567 view_->InvalidateRow(row); | 572 view_->InvalidateRow(row); |
568 } | 573 } |
569 | 574 |
570 #if !defined(OS_ANDROID) | 575 #if !defined(OS_ANDROID) |
571 int AutofillPopupControllerImpl::GetDesiredPopupWidth() const { | 576 int AutofillPopupControllerImpl::GetDesiredPopupWidth() const { |
572 int popup_width = controller_common_->RoundedElementBounds().width(); | 577 int popup_width = controller_common_->RoundedElementBounds().width(); |
573 DCHECK_EQ(names().size(), subtexts().size()); | 578 for (size_t i = 0; i < GetLineCount(); ++i) { |
574 for (size_t i = 0; i < names().size(); ++i) { | |
575 int row_size = | 579 int row_size = |
576 gfx::GetStringWidth(names()[i], name_font_list_) + | 580 gfx::GetStringWidth(GetElidedValueAt(i), value_font_list_) + |
577 gfx::GetStringWidth(subtexts()[i], subtext_font_list_) + | 581 gfx::GetStringWidth(GetElidedLabelAt(i), label_font_list_) + |
578 RowWidthWithoutText(i); | 582 RowWidthWithoutText(i); |
579 | 583 |
580 popup_width = std::max(popup_width, row_size); | 584 popup_width = std::max(popup_width, row_size); |
581 } | 585 } |
582 | 586 |
583 return popup_width; | 587 return popup_width; |
584 } | 588 } |
585 | 589 |
586 int AutofillPopupControllerImpl::GetDesiredPopupHeight() const { | 590 int AutofillPopupControllerImpl::GetDesiredPopupHeight() const { |
587 int popup_height = 2 * kPopupBorderThickness; | 591 int popup_height = 2 * kPopupBorderThickness; |
588 | 592 |
589 for (size_t i = 0; i < identifiers().size(); ++i) { | 593 for (size_t i = 0; i < suggestions_.size(); ++i) { |
590 popup_height += GetRowHeightFromId(identifiers()[i]); | 594 popup_height += GetRowHeightFromId(suggestions_[i].frontend_id); |
591 } | 595 } |
592 | 596 |
593 return popup_height; | 597 return popup_height; |
594 } | 598 } |
595 | 599 |
596 int AutofillPopupControllerImpl::RowWidthWithoutText(int row) const { | 600 int AutofillPopupControllerImpl::RowWidthWithoutText(int row) const { |
597 int row_size = kEndPadding; | 601 int row_size = kEndPadding; |
598 | 602 |
599 if (!subtexts_[row].empty()) | 603 if (!elided_labels_[row].empty()) |
600 row_size += kNamePadding; | 604 row_size += kNamePadding; |
601 | 605 |
602 // Add the Autofill icon size, if required. | 606 // Add the Autofill icon size, if required. |
603 if (!icons_[row].empty()) { | 607 const base::string16& icon = suggestions_[row].icon; |
| 608 if (!icon.empty()) { |
604 int icon_width = ui::ResourceBundle::GetSharedInstance().GetImageNamed( | 609 int icon_width = ui::ResourceBundle::GetSharedInstance().GetImageNamed( |
605 GetIconResourceID(icons_[row])).Width(); | 610 GetIconResourceID(icon)).Width(); |
606 row_size += icon_width + kIconPadding; | 611 row_size += icon_width + kIconPadding; |
607 } | 612 } |
608 | 613 |
609 // Add the padding at the end. | 614 // Add the padding at the end. |
610 row_size += kEndPadding; | 615 row_size += kEndPadding; |
611 | 616 |
612 // Add room for the popup border. | 617 // Add room for the popup border. |
613 row_size += 2 * kPopupBorderThickness; | 618 row_size += 2 * kPopupBorderThickness; |
614 | 619 |
615 return row_size; | 620 return row_size; |
616 } | 621 } |
617 | 622 |
618 void AutofillPopupControllerImpl::UpdatePopupBounds() { | 623 void AutofillPopupControllerImpl::UpdatePopupBounds() { |
619 int popup_width = GetDesiredPopupWidth(); | 624 int popup_width = GetDesiredPopupWidth(); |
620 int popup_height = GetDesiredPopupHeight(); | 625 int popup_height = GetDesiredPopupHeight(); |
621 | 626 |
622 popup_bounds_ = controller_common_->GetPopupBounds(popup_width, | 627 popup_bounds_ = controller_common_->GetPopupBounds(popup_width, popup_height); |
623 popup_height); | |
624 } | 628 } |
625 #endif // !defined(OS_ANDROID) | 629 #endif // !defined(OS_ANDROID) |
626 | 630 |
627 WeakPtr<AutofillPopupControllerImpl> AutofillPopupControllerImpl::GetWeakPtr() { | 631 WeakPtr<AutofillPopupControllerImpl> AutofillPopupControllerImpl::GetWeakPtr() { |
628 return weak_ptr_factory_.GetWeakPtr(); | 632 return weak_ptr_factory_.GetWeakPtr(); |
629 } | 633 } |
630 | 634 |
631 void AutofillPopupControllerImpl::ClearState() { | 635 void AutofillPopupControllerImpl::ClearState() { |
632 // Don't clear view_, because otherwise the popup will have to get regenerated | 636 // Don't clear view_, because otherwise the popup will have to get regenerated |
633 // and this will cause flickering. | 637 // and this will cause flickering. |
634 | 638 |
635 popup_bounds_ = gfx::Rect(); | 639 popup_bounds_ = gfx::Rect(); |
636 | 640 |
637 names_.clear(); | 641 suggestions_.clear(); |
638 subtexts_.clear(); | 642 elided_values_.clear(); |
639 icons_.clear(); | 643 elided_labels_.clear(); |
640 identifiers_.clear(); | |
641 full_names_.clear(); | |
642 | 644 |
643 selected_line_ = kNoSelection; | 645 selected_line_ = kNoSelection; |
644 } | 646 } |
645 | 647 |
646 } // namespace autofill | 648 } // namespace autofill |
OLD | NEW |