Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(369)

Side by Side Diff: chrome/browser/ui/autofill/autofill_dialog_controller.cc

Issue 11636040: AutofillPopupController clarifications + simplifications. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: ilya review Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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_dialog_controller.h" 5 #include "chrome/browser/ui/autofill/autofill_dialog_controller.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/string_split.h" 8 #include "base/string_split.h"
9 #include "base/string_util.h" 9 #include "base/string_util.h"
10 #include "base/utf_string_conversions.h" 10 #include "base/utf_string_conversions.h"
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
78 const DetailInput* input = &input_template[i]; 78 const DetailInput* input = &input_template[i];
79 for (size_t j = 0; j < form_structure.field_count(); ++j) { 79 for (size_t j = 0; j < form_structure.field_count(); ++j) {
80 if (DetailInputMatchesField(*input, *form_structure.field(j))) { 80 if (DetailInputMatchesField(*input, *form_structure.field(j))) {
81 inputs->push_back(*input); 81 inputs->push_back(*input);
82 break; 82 break;
83 } 83 }
84 } 84 }
85 } 85 }
86 } 86 }
87 87
88 // Finds the instance of T which has the most data for filling in the inputs in 88 // Uses |group| to fill in the |autofilled_value| for all inputs in |all_inputs|
89 // |all_inputs|. T should be a FormGroup type. 89 // (an out-param).
90 template<class T> FormGroup* GetBestDataSource( 90 void FillInputFromFormGroup(FormGroup* group, DetailInputs* inputs) {
91 const std::vector<T*>& sources,
92 const DetailInputs* const* all_inputs,
93 size_t all_inputs_length) {
94 const std::string app_locale = AutofillCountry::ApplicationLocale(); 91 const std::string app_locale = AutofillCountry::ApplicationLocale();
95 92 for (size_t j = 0; j < inputs->size(); ++j) {
96 int best_field_fill_count = 0; 93 (*inputs)[j].autofilled_value =
97 FormGroup* best_source = NULL; 94 group->GetInfo((*inputs)[j].type, app_locale);
98
99 for (size_t i = 0; i < sources.size(); ++i) {
100 int field_fill_count = 0;
101
102 for (size_t j = 0; j < all_inputs_length; ++j) {
103 const DetailInputs& inputs = *all_inputs[j];
104 for (size_t k = 0; k < inputs.size(); ++k) {
105 if (!sources[i]->GetInfo(inputs[k].type, app_locale).empty())
106 field_fill_count++;
107 }
108 }
109
110 // TODO(estade): should there be a better tiebreaker?
111 if (field_fill_count > best_field_fill_count) {
112 best_field_fill_count = field_fill_count;
113 best_source = sources[i];
114 }
115 }
116
117 return best_source;
118 }
119
120 // Uses |group| to fill in the |starting_value| for all inputs in |all_inputs|
121 // (an out-param).
122 void FillInputsFromFormGroup(FormGroup* group,
123 DetailInputs** all_inputs,
124 size_t all_inputs_length) {
125 const std::string app_locale = AutofillCountry::ApplicationLocale();
126 for (size_t i = 0; i < all_inputs_length; ++i) {
127 DetailInputs& inputs = *all_inputs[i];
128 for (size_t j = 0; j < inputs.size(); ++j) {
129 inputs[j].starting_value = group->GetInfo(inputs[j].type, app_locale);
130 }
131 } 95 }
132 } 96 }
133 97
134 // Initializes |form_group| from user-entered data. 98 // Initializes |form_group| from user-entered data.
135 void FillFormGroupFromOutputs(const DetailOutputMap& detail_outputs, 99 void FillFormGroupFromOutputs(const DetailOutputMap& detail_outputs,
136 FormGroup* form_group) { 100 FormGroup* form_group) {
137 for (DetailOutputMap::const_iterator iter = detail_outputs.begin(); 101 for (DetailOutputMap::const_iterator iter = detail_outputs.begin();
138 iter != detail_outputs.end(); ++iter) { 102 iter != detail_outputs.end(); ++iter) {
139 if (!iter->second.empty()) 103 if (!iter->second.empty())
140 form_group->SetRawInfo(iter->first->type, iter->second); 104 form_group->SetRawInfo(iter->first->type, iter->second);
141 } 105 }
142 } 106 }
143 107
144 } // namespace 108 } // namespace
145 109
146 AutofillDialogController::AutofillDialogController( 110 AutofillDialogController::AutofillDialogController(
147 content::WebContents* contents, 111 content::WebContents* contents,
148 const FormData& form, 112 const FormData& form,
149 const GURL& source_url, 113 const GURL& source_url,
150 const content::SSLStatus& ssl_status, 114 const content::SSLStatus& ssl_status,
151 const base::Callback<void(const FormStructure*)>& callback) 115 const base::Callback<void(const FormStructure*)>& callback)
152 : profile_(Profile::FromBrowserContext(contents->GetBrowserContext())), 116 : profile_(Profile::FromBrowserContext(contents->GetBrowserContext())),
153 contents_(contents), 117 contents_(contents),
154 form_structure_(form), 118 form_structure_(form),
155 source_url_(source_url), 119 source_url_(source_url),
156 ssl_status_(ssl_status), 120 ssl_status_(ssl_status),
157 callback_(callback) { 121 callback_(callback),
122 popup_controller_(NULL) {
158 // TODO(estade): |this| should observe PersonalDataManager. 123 // TODO(estade): |this| should observe PersonalDataManager.
159 // TODO(estade): remove duplicates from |form|? 124 // TODO(estade): remove duplicates from |form|?
160 } 125 }
161 126
162 AutofillDialogController::~AutofillDialogController() {} 127 AutofillDialogController::~AutofillDialogController() {
128 if (popup_controller_)
129 popup_controller_->Hide();
130 }
163 131
164 void AutofillDialogController::Show() { 132 void AutofillDialogController::Show() {
165 bool has_types = false; 133 bool has_types = false;
166 bool has_sections = false; 134 bool has_sections = false;
167 form_structure_.ParseFieldTypesFromAutocompleteAttributes(&has_types, 135 form_structure_.ParseFieldTypesFromAutocompleteAttributes(&has_types,
168 &has_sections); 136 &has_sections);
169 // Fail if the author didn't specify autocomplete types. 137 // Fail if the author didn't specify autocomplete types.
170 if (!has_types) { 138 if (!has_types) {
171 callback_.Run(NULL); 139 callback_.Run(NULL);
172 delete this; 140 delete this;
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
219 arraysize(kBillingInputs), 187 arraysize(kBillingInputs),
220 &requested_billing_fields_); 188 &requested_billing_fields_);
221 189
222 FilterInputs(form_structure_, 190 FilterInputs(form_structure_,
223 kShippingInputs, 191 kShippingInputs,
224 arraysize(kShippingInputs), 192 arraysize(kShippingInputs),
225 &requested_shipping_fields_); 193 &requested_shipping_fields_);
226 194
227 // TODO(estade): make this actually check if it's a first run. 195 // TODO(estade): make this actually check if it's a first run.
228 bool first_run = true; 196 bool first_run = true;
229 if (first_run) 197 if (!first_run)
230 PopulateInputsWithGuesses();
231 else
232 GenerateComboboxModels(); 198 GenerateComboboxModels();
233 199
234 // TODO(estade): don't show the dialog if the site didn't specify the right 200 // TODO(estade): don't show the dialog if the site didn't specify the right
235 // fields. First we must figure out what the "right" fields are. 201 // fields. First we must figure out what the "right" fields are.
236 view_.reset(AutofillDialogView::Create(this)); 202 view_.reset(AutofillDialogView::Create(this));
237 view_->Show(); 203 view_->Show();
238 } 204 }
239 205
240 string16 AutofillDialogController::DialogTitle() const { 206 string16 AutofillDialogController::DialogTitle() const {
241 return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_TITLE); 207 return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_TITLE);
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
378 FillOutputForSection(SECTION_SHIPPING); 344 FillOutputForSection(SECTION_SHIPPING);
379 } 345 }
380 callback_.Run(&form_structure_); 346 callback_.Run(&form_structure_);
381 } else { 347 } else {
382 callback_.Run(NULL); 348 callback_.Run(NULL);
383 } 349 }
384 350
385 delete this; 351 delete this;
386 } 352 }
387 353
354 void AutofillDialogController::UserEditedInput(
355 const DetailInput* input,
356 gfx::NativeView view,
357 const gfx::Rect& content_bounds,
358 const string16& field_contents) {
359 // TODO(estade): support all sections, not just billing.
360 std::vector<string16> popup_values, popup_labels, popup_icons;
361 std::vector<AutofillFieldType> field_types;
362 const DetailInputs& inputs = RequestedFieldsForSection(SECTION_BILLING);
363 field_types.reserve(inputs.size());
364 for (DetailInputs::const_iterator iter = inputs.begin();
365 iter != inputs.end(); ++iter) {
366 field_types.push_back(iter->type);
367 }
368 GetManager()->GetProfileSuggestions(input->type,
369 field_contents,
370 false,
371 field_types,
372 &popup_values,
373 &popup_labels,
374 &popup_icons,
375 &popup_guids_);
376
377 // TODO(estade): do we need separators and control rows like 'Clear
378 // Form'?
379 std::vector<int> popup_ids;
380 for (size_t i = 0; i < popup_guids_.size(); ++i) {
381 popup_ids.push_back(i);
382 }
383
384 popup_controller_ = AutofillPopupControllerImpl::GetOrCreate(
385 popup_controller_, this, view, content_bounds);
386 popup_controller_->Show(popup_values,
387 popup_labels,
388 popup_icons,
389 popup_ids);
390 }
391
392 void AutofillDialogController::FocusMoved() {
393 if (popup_controller_) {
394 popup_controller_->Hide();
395 ControllerDestroyed();
396 }
397 }
398
399 void AutofillDialogController::DidSelectSuggestion(int identifier) {
400 // TODO(estade): implement.
401 }
402
403 void AutofillDialogController::DidAcceptSuggestion(const string16& value,
404 int identifier) {
405 const PersonalDataManager::GUIDPair& pair = popup_guids_[identifier];
406 // TODO(estade): need to use the variant, |pair.second|.
407 AutofillProfile* profile = GetManager()->GetProfileByGUID(pair.first);
408 // TODO(estade): we shouldn't let this happen.
409 if (!profile)
410 return;
411
412 // TODO(estade): implement for all sections.
413 FillInputFromFormGroup(profile, &requested_billing_fields_);
414 view_->UpdateSection(SECTION_BILLING);
415
416 // TODO(estade): not sure why it's necessary to do this explicitly.
417 popup_controller_->Hide();
418 ControllerDestroyed();
419 }
420
421 void AutofillDialogController::RemoveSuggestion(int identifier) {
422 // TODO(estade): implement.
423 }
424
425 void AutofillDialogController::RemoveAutocompleteEntry(const string16& value) {
426 // TODO(estade): implement.
427 }
428
429 void AutofillDialogController::ClearPreviewedForm() {
430 // TODO(estade): implement.
431 }
432
433 void AutofillDialogController::ControllerDestroyed() {
434 popup_controller_ = NULL;
435 }
436
388 void AutofillDialogController::GenerateComboboxModels() { 437 void AutofillDialogController::GenerateComboboxModels() {
389 PersonalDataManager* manager = 438 PersonalDataManager* manager = GetManager();
390 PersonalDataManagerFactory::GetForProfile(profile_);
391 const std::vector<CreditCard*>& cards = manager->credit_cards(); 439 const std::vector<CreditCard*>& cards = manager->credit_cards();
392 for (size_t i = 0; i < cards.size(); ++i) { 440 for (size_t i = 0; i < cards.size(); ++i) {
393 suggested_cc_.AddItem(cards[i]->guid(), cards[i]->Label()); 441 suggested_cc_.AddItem(cards[i]->guid(), cards[i]->Label());
394 } 442 }
395 suggested_cc_.AddItem("", ASCIIToUTF16("Enter new card")); 443 suggested_cc_.AddItem("", ASCIIToUTF16("Enter new card"));
396 444
397 const std::vector<AutofillProfile*>& profiles = manager->GetProfiles(); 445 const std::vector<AutofillProfile*>& profiles = manager->GetProfiles();
398 const std::string app_locale = AutofillCountry::ApplicationLocale(); 446 const std::string app_locale = AutofillCountry::ApplicationLocale();
399 for (size_t i = 0; i < profiles.size(); ++i) { 447 for (size_t i = 0; i < profiles.size(); ++i) {
400 string16 email = profiles[i]->GetInfo(EMAIL_ADDRESS, app_locale); 448 string16 email = profiles[i]->GetInfo(EMAIL_ADDRESS, app_locale);
401 if (!email.empty()) 449 if (!email.empty())
402 suggested_email_.AddItem(profiles[i]->guid(), email); 450 suggested_email_.AddItem(profiles[i]->guid(), email);
403 suggested_billing_.AddItem(profiles[i]->guid(), profiles[i]->Label()); 451 suggested_billing_.AddItem(profiles[i]->guid(), profiles[i]->Label());
404 suggested_shipping_.AddItem(profiles[i]->guid(), profiles[i]->Label()); 452 suggested_shipping_.AddItem(profiles[i]->guid(), profiles[i]->Label());
405 } 453 }
406 suggested_billing_.AddItem("", ASCIIToUTF16("Enter new billing")); 454 suggested_billing_.AddItem("", ASCIIToUTF16("Enter new billing"));
407 suggested_email_.AddItem("", ASCIIToUTF16("Enter new email")); 455 suggested_email_.AddItem("", ASCIIToUTF16("Enter new email"));
408 suggested_shipping_.AddItem("", ASCIIToUTF16("Enter new shipping")); 456 suggested_shipping_.AddItem("", ASCIIToUTF16("Enter new shipping"));
409 } 457 }
410 458
411 void AutofillDialogController::PopulateInputsWithGuesses() {
412 PersonalDataManager* manager =
413 PersonalDataManagerFactory::GetForProfile(profile_);
414
415 DetailInputs* profile_inputs[] = { &requested_email_fields_,
416 &requested_billing_fields_ };
417 const std::vector<AutofillProfile*>& profiles = manager->GetProfiles();
418 FormGroup* best_profile =
419 GetBestDataSource(profiles, profile_inputs, arraysize(profile_inputs));
420 if (best_profile) {
421 FillInputsFromFormGroup(best_profile,
422 profile_inputs,
423 arraysize(profile_inputs));
424 }
425
426 DetailInputs* cc_inputs[] = { &requested_cc_fields_ };
427 const std::vector<CreditCard*>& credit_cards = manager->credit_cards();
428 FormGroup* best_cc =
429 GetBestDataSource(credit_cards, cc_inputs, arraysize(cc_inputs));
430 if (best_cc) {
431 FillInputsFromFormGroup(best_cc,
432 cc_inputs,
433 arraysize(cc_inputs));
434 }
435 }
436
437 void AutofillDialogController::FillOutputForSectionWithComparator( 459 void AutofillDialogController::FillOutputForSectionWithComparator(
438 DialogSection section, const InputFieldComparator& compare) { 460 DialogSection section, const InputFieldComparator& compare) {
439 int suggestion_selection = view_->GetSuggestionSelection(section); 461 int suggestion_selection = view_->GetSuggestionSelection(section);
440 SuggestionsComboboxModel* model = SuggestionsModelForSection(section); 462 SuggestionsComboboxModel* model = SuggestionsModelForSection(section);
463 PersonalDataManager* manager = GetManager();
441 if (suggestion_selection < model->GetItemCount() - 1) { 464 if (suggestion_selection < model->GetItemCount() - 1) {
442 std::string guid = model->GetItemKeyAt(suggestion_selection); 465 std::string guid = model->GetItemKeyAt(suggestion_selection);
443 PersonalDataManager* manager =
444 PersonalDataManagerFactory::GetForProfile(profile_);
445 FormGroup* form_group = section == SECTION_CC ? 466 FormGroup* form_group = section == SECTION_CC ?
446 static_cast<FormGroup*>(manager->GetCreditCardByGUID(guid)) : 467 static_cast<FormGroup*>(manager->GetCreditCardByGUID(guid)) :
447 static_cast<FormGroup*>(manager->GetProfileByGUID(guid)); 468 static_cast<FormGroup*>(manager->GetProfileByGUID(guid));
448 // TODO(estade): we shouldn't let this happen. 469 // TODO(estade): we shouldn't let this happen.
449 if (!form_group) 470 if (!form_group)
450 return; 471 return;
451 472
452 FillFormStructureForSection(*form_group, section, compare); 473 FillFormStructureForSection(*form_group, section, compare);
453 } else { 474 } else {
454 // The user manually input data. 475 // The user manually input data.
455 DetailOutputMap output; 476 DetailOutputMap output;
456 view_->GetUserInput(section, &output); 477 view_->GetUserInput(section, &output);
457 478
458 // Save the info as new or edited data, then fill it into |form_structure_|. 479 // Save the info as new or edited data, then fill it into |form_structure_|.
459 PersonalDataManager* manager =
460 PersonalDataManagerFactory::GetForProfile(profile_);
461 if (section == SECTION_CC) { 480 if (section == SECTION_CC) {
462 CreditCard card; 481 CreditCard card;
463 FillFormGroupFromOutputs(output, &card); 482 FillFormGroupFromOutputs(output, &card);
464 manager->SaveImportedCreditCard(card); 483 manager->SaveImportedCreditCard(card);
465 FillFormStructureForSection(card, section, compare); 484 FillFormStructureForSection(card, section, compare);
466 485
467 // CVC needs special-casing because the CreditCard class doesn't store 486 // CVC needs special-casing because the CreditCard class doesn't store
468 // or handle them. Fill it in directly from |output|. 487 // or handle them. Fill it in directly from |output|.
469 for (size_t i = 0; i < form_structure_.field_count(); ++i) { 488 for (size_t i = 0; i < form_structure_.field_count(); ++i) {
470 AutofillField* field = form_structure_.field(i); 489 AutofillField* field = form_structure_.field(i);
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
520 case SECTION_BILLING: 539 case SECTION_BILLING:
521 return &suggested_billing_; 540 return &suggested_billing_;
522 case SECTION_SHIPPING: 541 case SECTION_SHIPPING:
523 return &suggested_shipping_; 542 return &suggested_shipping_;
524 } 543 }
525 544
526 NOTREACHED(); 545 NOTREACHED();
527 return NULL; 546 return NULL;
528 } 547 }
529 548
549 PersonalDataManager* AutofillDialogController::GetManager() {
550 return PersonalDataManagerFactory::GetForProfile(profile_);
551 }
552
530 } // namespace autofill 553 } // namespace autofill
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698