// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/ui/webui/options/autofill_options_handler.h" #include <vector> #include "base/logging.h" #include "base/string16.h" #include "base/string_number_conversions.h" #include "base/utf_string_conversions.h" #include "base/values.h" #include "chrome/browser/autofill/autofill_country.h" #include "chrome/browser/autofill/autofill_profile.h" #include "chrome/browser/autofill/credit_card.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/webui/web_ui_util.h" #include "chrome/common/guid.h" #include "grit/generated_resources.h" #include "grit/webkit_resources.h" #include "ui/base/l10n/l10n_util.h" namespace { // Converts a credit card type to the appropriate resource ID of the CC icon. int CreditCardTypeToResourceID(const std::string& type) { if (type == kAmericanExpressCard) return IDR_AUTOFILL_CC_AMEX; else if (type == kDinersCard) return IDR_AUTOFILL_CC_DINERS; else if (type == kDiscoverCard) return IDR_AUTOFILL_CC_DISCOVER; else if (type == kGenericCard) return IDR_AUTOFILL_CC_GENERIC; else if (type == kJCBCard) return IDR_AUTOFILL_CC_JCB; else if (type == kMasterCard) return IDR_AUTOFILL_CC_MASTERCARD; else if (type == kSoloCard) return IDR_AUTOFILL_CC_SOLO; else if (type == kVisaCard) return IDR_AUTOFILL_CC_VISA; NOTREACHED(); return 0; } // Converts a credit card type to the appropriate localized card type. string16 LocalizedCreditCardType(const std::string& type) { if (type == kAmericanExpressCard) return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_AMEX); else if (type == kDinersCard) return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_DINERS); else if (type == kDiscoverCard) return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_DISCOVER); else if (type == kGenericCard) return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_GENERIC); else if (type == kJCBCard) return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_JCB); else if (type == kMasterCard) return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_MASTERCARD); else if (type == kSoloCard) return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_SOLO); else if (type == kVisaCard) return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_VISA); NOTREACHED(); return string16(); } // Returns a dictionary that maps country codes to data for the country. DictionaryValue* GetCountryData() { std::string app_locale = AutofillCountry::ApplicationLocale(); std::vector<std::string> country_codes; AutofillCountry::GetAvailableCountries(&country_codes); DictionaryValue* country_data = new DictionaryValue(); for (size_t i = 0; i < country_codes.size(); ++i) { const AutofillCountry country(country_codes[i], app_locale); DictionaryValue* details = new DictionaryValue(); details->SetString("name", country.name()); details->SetString("postalCodeLabel", country.postal_code_label()); details->SetString("stateLabel", country.state_label()); country_data->Set(country.country_code(), details); } return country_data; } // Get the multi-valued element for |type| and return it in |ListValue| form. void GetValueList(const AutofillProfile& profile, AutofillFieldType type, scoped_ptr<ListValue>* list) { std::vector<string16> values; profile.GetMultiInfo(type, &values); list->reset(new ListValue); for (size_t i = 0; i < values.size(); ++i) { (*list)->Set(i, Value::CreateStringValue(values[i])); } } // Set the multi-valued element for |type| from input |list| values. void SetValueList(const ListValue* list, AutofillFieldType type, AutofillProfile* profile) { std::vector<string16> values(list->GetSize()); for (size_t i = 0; i < list->GetSize(); ++i) { string16 value; if (list->GetString(i, &value)) values[i] = value; } profile->SetMultiInfo(type, values); } } // namespace AutofillOptionsHandler::AutofillOptionsHandler() : personal_data_(NULL) { } AutofillOptionsHandler::~AutofillOptionsHandler() { if (personal_data_) personal_data_->RemoveObserver(this); } ///////////////////////////////////////////////////////////////////////////// // OptionsPageUIHandler implementation: void AutofillOptionsHandler::GetLocalizedValues( DictionaryValue* localized_strings) { DCHECK(localized_strings); static OptionsStringResource resources[] = { { "autofillAddresses", IDS_AUTOFILL_ADDRESSES_GROUP_NAME }, { "autofillCreditCards", IDS_AUTOFILL_CREDITCARDS_GROUP_NAME }, { "autofillAddAddress", IDS_AUTOFILL_ADD_ADDRESS_BUTTON }, { "autofillAddCreditCard", IDS_AUTOFILL_ADD_CREDITCARD_BUTTON }, { "helpButton", IDS_AUTOFILL_HELP_LABEL }, { "addAddressTitle", IDS_AUTOFILL_ADD_ADDRESS_CAPTION }, { "editAddressTitle", IDS_AUTOFILL_EDIT_ADDRESS_CAPTION }, { "addCreditCardTitle", IDS_AUTOFILL_ADD_CREDITCARD_CAPTION }, { "editCreditCardTitle", IDS_AUTOFILL_EDIT_CREDITCARD_CAPTION }, #if defined(OS_MACOSX) { "auxiliaryProfilesEnabled", IDS_AUTOFILL_USE_MAC_ADDRESS_BOOK }, #endif // defined(OS_MACOSX) }; RegisterStrings(localized_strings, resources, arraysize(resources)); RegisterTitle(localized_strings, "autofillOptionsPage", IDS_AUTOFILL_OPTIONS_TITLE); SetAddressOverlayStrings(localized_strings); SetCreditCardOverlayStrings(localized_strings); } void AutofillOptionsHandler::Initialize() { personal_data_ = web_ui_->GetProfile()->GetPersonalDataManager(); personal_data_->SetObserver(this); LoadAutofillData(); } void AutofillOptionsHandler::RegisterMessages() { web_ui_->RegisterMessageCallback( "removeAddress", NewCallback(this, &AutofillOptionsHandler::RemoveAddress)); web_ui_->RegisterMessageCallback( "removeCreditCard", NewCallback(this, &AutofillOptionsHandler::RemoveCreditCard)); web_ui_->RegisterMessageCallback( "loadAddressEditor", NewCallback(this, &AutofillOptionsHandler::LoadAddressEditor)); web_ui_->RegisterMessageCallback( "loadCreditCardEditor", NewCallback(this, &AutofillOptionsHandler::LoadCreditCardEditor)); web_ui_->RegisterMessageCallback( "setAddress", NewCallback(this, &AutofillOptionsHandler::SetAddress)); web_ui_->RegisterMessageCallback( "setCreditCard", NewCallback(this, &AutofillOptionsHandler::SetCreditCard)); } ///////////////////////////////////////////////////////////////////////////// // PersonalDataManager::Observer implementation: void AutofillOptionsHandler::OnPersonalDataLoaded() { LoadAutofillData(); } void AutofillOptionsHandler::OnPersonalDataChanged() { LoadAutofillData(); } void AutofillOptionsHandler::SetAddressOverlayStrings( DictionaryValue* localized_strings) { localized_strings->SetString("autofillEditAddressTitle", l10n_util::GetStringUTF16(IDS_AUTOFILL_EDIT_ADDRESS_CAPTION)); localized_strings->SetString("fullNameLabel", l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_FULL_NAME)); localized_strings->SetString("companyNameLabel", l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_COMPANY_NAME)); localized_strings->SetString("addrLine1Label", l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADDRESS_LINE_1)); localized_strings->SetString("addrLine2Label", l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADDRESS_LINE_2)); localized_strings->SetString("cityLabel", l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_CITY)); localized_strings->SetString("countryLabel", l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_COUNTRY)); localized_strings->SetString("phoneLabel", l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_PHONE)); localized_strings->SetString("faxLabel", l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_FAX)); localized_strings->SetString("emailLabel", l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_EMAIL)); localized_strings->SetString("addNewNamePlaceholder", l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADD_NEW_NAME)); localized_strings->SetString("addNewPhonePlaceholder", l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADD_NEW_PHONE)); localized_strings->SetString("addNewFaxPlaceholder", l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADD_NEW_FAX)); localized_strings->SetString("addNewEmailPlaceholder", l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADD_NEW_EMAIL)); std::string app_locale = AutofillCountry::ApplicationLocale(); std::string default_country_code = AutofillCountry::CountryCodeForLocale(app_locale); localized_strings->SetString("defaultCountryCode", default_country_code); localized_strings->Set("autofillCountryData", GetCountryData()); } void AutofillOptionsHandler::SetCreditCardOverlayStrings( DictionaryValue* localized_strings) { localized_strings->SetString("autofillEditCreditCardTitle", l10n_util::GetStringUTF16(IDS_AUTOFILL_EDIT_CREDITCARD_CAPTION)); localized_strings->SetString("nameOnCardLabel", l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_NAME_ON_CARD)); localized_strings->SetString("creditCardNumberLabel", l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_CREDIT_CARD_NUMBER)); localized_strings->SetString("creditCardExpirationDateLabel", l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_EXPIRATION_DATE)); } void AutofillOptionsHandler::LoadAutofillData() { if (!personal_data_->IsDataLoaded()) return; ListValue addresses; for (std::vector<AutofillProfile*>::const_iterator i = personal_data_->web_profiles().begin(); i != personal_data_->web_profiles().end(); ++i) { ListValue* entry = new ListValue(); entry->Append(new StringValue((*i)->guid())); entry->Append(new StringValue((*i)->Label())); addresses.Append(entry); } web_ui_->CallJavascriptFunction("AutofillOptions.setAddressList", addresses); ListValue credit_cards; for (std::vector<CreditCard*>::const_iterator i = personal_data_->credit_cards().begin(); i != personal_data_->credit_cards().end(); ++i) { ListValue* entry = new ListValue(); entry->Append(new StringValue((*i)->guid())); entry->Append(new StringValue((*i)->Label())); int res = CreditCardTypeToResourceID((*i)->type()); entry->Append( new StringValue(web_ui_util::GetImageDataUrlFromResource(res))); entry->Append(new StringValue(LocalizedCreditCardType((*i)->type()))); credit_cards.Append(entry); } web_ui_->CallJavascriptFunction("AutofillOptions.setCreditCardList", credit_cards); } void AutofillOptionsHandler::RemoveAddress(const ListValue* args) { DCHECK(personal_data_->IsDataLoaded()); std::string guid; if (!args->GetString(0, &guid)) { NOTREACHED(); return; } personal_data_->RemoveProfile(guid); } void AutofillOptionsHandler::RemoveCreditCard(const ListValue* args) { DCHECK(personal_data_->IsDataLoaded()); std::string guid; if (!args->GetString(0, &guid)) { NOTREACHED(); return; } personal_data_->RemoveCreditCard(guid); } void AutofillOptionsHandler::LoadAddressEditor(const ListValue* args) { DCHECK(personal_data_->IsDataLoaded()); std::string guid; if (!args->GetString(0, &guid)) { NOTREACHED(); return; } AutofillProfile* profile = personal_data_->GetProfileByGUID(guid); if (!profile) { // There is a race where a user can click once on the close button and // quickly click again on the list item before the item is removed (since // the list is not updated until the model tells the list an item has been // removed). This will activate the editor for a profile that has been // removed. Do nothing in that case. return; } DictionaryValue address; address.SetString("guid", profile->guid()); scoped_ptr<ListValue> list; GetValueList(*profile, NAME_FULL, &list); address.Set("fullName", list.release()); address.SetString("companyName", profile->GetInfo(COMPANY_NAME)); address.SetString("addrLine1", profile->GetInfo(ADDRESS_HOME_LINE1)); address.SetString("addrLine2", profile->GetInfo(ADDRESS_HOME_LINE2)); address.SetString("city", profile->GetInfo(ADDRESS_HOME_CITY)); address.SetString("state", profile->GetInfo(ADDRESS_HOME_STATE)); address.SetString("postalCode", profile->GetInfo(ADDRESS_HOME_ZIP)); address.SetString("country", profile->CountryCode()); GetValueList(*profile, PHONE_HOME_WHOLE_NUMBER, &list); address.Set("phone", list.release()); GetValueList(*profile, PHONE_FAX_WHOLE_NUMBER, &list); address.Set("fax", list.release()); GetValueList(*profile, EMAIL_ADDRESS, &list); address.Set("email", list.release()); web_ui_->CallJavascriptFunction("AutofillOptions.editAddress", address); } void AutofillOptionsHandler::LoadCreditCardEditor(const ListValue* args) { DCHECK(personal_data_->IsDataLoaded()); std::string guid; if (!args->GetString(0, &guid)) { NOTREACHED(); return; } CreditCard* credit_card = personal_data_->GetCreditCardByGUID(guid); if (!credit_card) { // There is a race where a user can click once on the close button and // quickly click again on the list item before the item is removed (since // the list is not updated until the model tells the list an item has been // removed). This will activate the editor for a profile that has been // removed. Do nothing in that case. return; } DictionaryValue credit_card_data; credit_card_data.SetString("guid", credit_card->guid()); credit_card_data.SetString("nameOnCard", credit_card->GetInfo(CREDIT_CARD_NAME)); credit_card_data.SetString("creditCardNumber", credit_card->GetInfo(CREDIT_CARD_NUMBER)); credit_card_data.SetString("expirationMonth", credit_card->GetInfo(CREDIT_CARD_EXP_MONTH)); credit_card_data.SetString( "expirationYear", credit_card->GetInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR)); web_ui_->CallJavascriptFunction("AutofillOptions.editCreditCard", credit_card_data); } void AutofillOptionsHandler::SetAddress(const ListValue* args) { if (!personal_data_->IsDataLoaded()) return; std::string guid; if (!args->GetString(0, &guid)) { NOTREACHED(); return; } AutofillProfile profile(guid); std::string country_code; string16 value; ListValue* list_value; if (args->GetList(1, &list_value)) SetValueList(list_value, NAME_FULL, &profile); if (args->GetString(2, &value)) profile.SetInfo(COMPANY_NAME, value); if (args->GetString(3, &value)) profile.SetInfo(ADDRESS_HOME_LINE1, value); if (args->GetString(4, &value)) profile.SetInfo(ADDRESS_HOME_LINE2, value); if (args->GetString(5, &value)) profile.SetInfo(ADDRESS_HOME_CITY, value); if (args->GetString(6, &value)) profile.SetInfo(ADDRESS_HOME_STATE, value); if (args->GetString(7, &value)) profile.SetInfo(ADDRESS_HOME_ZIP, value); if (args->GetString(8, &country_code)) profile.SetCountryCode(country_code); if (args->GetList(9, &list_value)) SetValueList(list_value, PHONE_HOME_WHOLE_NUMBER, &profile); if (args->GetList(10, &list_value)) SetValueList(list_value, PHONE_FAX_WHOLE_NUMBER, &profile); if (args->GetList(11, &list_value)) SetValueList(list_value, EMAIL_ADDRESS, &profile); if (!guid::IsValidGUID(profile.guid())) { profile.set_guid(guid::GenerateGUID()); personal_data_->AddProfile(profile); } else { personal_data_->UpdateProfile(profile); } } void AutofillOptionsHandler::SetCreditCard(const ListValue* args) { if (!personal_data_->IsDataLoaded()) return; std::string guid; if (!args->GetString(0, &guid)) { NOTREACHED(); return; } CreditCard credit_card(guid); string16 value; if (args->GetString(1, &value)) credit_card.SetInfo(CREDIT_CARD_NAME, value); if (args->GetString(2, &value)) credit_card.SetInfo(CREDIT_CARD_NUMBER, value); if (args->GetString(3, &value)) credit_card.SetInfo(CREDIT_CARD_EXP_MONTH, value); if (args->GetString(4, &value)) credit_card.SetInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, value); if (!guid::IsValidGUID(credit_card.guid())) { credit_card.set_guid(guid::GenerateGUID()); personal_data_->AddCreditCard(credit_card); } else { personal_data_->UpdateCreditCard(credit_card); } }