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