Chromium Code Reviews| Index: chrome/browser/ui/autofill/autofill_dialog_i18n_input.cc |
| diff --git a/chrome/browser/ui/autofill/autofill_dialog_i18n_input.cc b/chrome/browser/ui/autofill/autofill_dialog_i18n_input.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..d7b30b11735e2336ae9e412e3513d97d2d61fc6e |
| --- /dev/null |
| +++ b/chrome/browser/ui/autofill/autofill_dialog_i18n_input.cc |
| @@ -0,0 +1,259 @@ |
| +// Copyright 2013 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. |
| +// |
| +// A stub implementation of internationalized address input fields for |
| +// interactive autofill dialog. The implementation always returns the same |
| +// address fields until libaddressinput library is integrated. |
| +// |
| +// Also, GetI18nFields() will call libaddressinput library to determine the |
| +// address fields instead of always returning US address fields. |
| +// |
| +// GuessCountry() uses only the application locale and should be improved to use |
| +// the timezone and possibly geolocation. |
| + |
| +#include "chrome/browser/ui/autofill/autofill_dialog_i18n_input.h" |
| + |
| +#include <algorithm> |
| + |
| +#include "base/command_line.h" |
| +#include "chrome/browser/browser_process.h" |
| +#include "chrome/common/chrome_switches.h" |
| +#include "components/autofill/core/browser/autofill_country.h" |
| +#include "grit/component_strings.h" |
| +#include "grit/generated_resources.h" |
| +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_field.h" |
| +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_ui.h" |
| +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_ui_component.h" |
| +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/localization.h" |
| +#include "ui/base/l10n/l10n_util.h" |
| + |
| +namespace autofill { |
| +namespace i18ninput { |
| + |
| +namespace { |
| + |
| +using i18n::addressinput::AddressField; |
| +using i18n::addressinput::AddressUiComponent; |
| + |
| +// Indexes into arrays of address field data. |
| +enum AddressFieldIndex { |
| + COUNTRY_INDEX, |
| + ADMIN_AREA_INDEX, |
| + LOCALITY_INDEX, |
| + DEPENDENT_LOCALITY_INDEX, |
| + POSTAL_CODE_INDEX, |
| + SORTING_CODE_INDEX, |
| + STREET_ADDRESS_1_INDEX, |
| + STREET_ADDRESS_2_INDEX, |
| + RECIPIENT_INDEX, |
| + ORGANIZATION_INDEX, |
| + ADDRESS_FIELD_INVALID_INDEX, |
| +}; |
| + |
| +// Indexes into arrays of street address line data. |
| +enum StreetAddressLine { |
| + STREET_ADDRESS_LINE_1, |
| + STREET_ADDRESS_LINE_2, |
| +}; |
| + |
| +// The number of address types. |
| +const int kNumberOfAddressTypes = ADDRESS_TYPE_BILLING + 1; |
| + |
| +// The maximum number of input fields. |
| +const int kMaxNumberOfInputFields = ADDRESS_FIELD_INVALID_INDEX; |
| + |
| +// The maximum number of street address lines. |
| +const int kMaxNumberOfStreetAddressLines = STREET_ADDRESS_LINE_2 + 1; |
| + |
| +// A mapping of StreetAddressLine to corresponding values in AddressFieldIndex. |
| +// Used to lookup address field data for street address lines. |
| +const AddressFieldIndex kStreetAddressLineIndex |
| + [kMaxNumberOfStreetAddressLines] = { |
| + STREET_ADDRESS_1_INDEX, |
| + STREET_ADDRESS_2_INDEX, |
| +}; |
| + |
| +// A mapping of AddressFieldIndex and AddressType to autofill field types. |
| +const ServerFieldType kServerFields[kMaxNumberOfInputFields] |
| + [kNumberOfAddressTypes] = { |
| + {ADDRESS_HOME_COUNTRY, ADDRESS_BILLING_COUNTRY}, |
|
Evan Stade
2013/11/25 20:35:45
there should be spaces inside the {} throughout th
Dan Beam
2013/11/28 02:52:45
Done.
|
| + {ADDRESS_HOME_STATE, ADDRESS_BILLING_STATE}, |
| + {ADDRESS_HOME_CITY, ADDRESS_BILLING_CITY}, |
| + {ADDRESS_HOME_DEPENDENT_LOCALITY, ADDRESS_BILLING_DEPENDENT_LOCALITY}, |
| + {ADDRESS_HOME_ZIP, ADDRESS_BILLING_ZIP}, |
| + {ADDRESS_HOME_SORTING_CODE, ADDRESS_BILLING_SORTING_CODE}, |
| + {ADDRESS_HOME_LINE1, ADDRESS_BILLING_LINE1}, |
| + {ADDRESS_HOME_LINE2, ADDRESS_BILLING_LINE2}, |
| + {NAME_FULL, NAME_BILLING_FULL}, |
| + {COMPANY_NAME, COMPANY_NAME}, |
| +}; |
| + |
| +// A mapping of AddressFieldIndex and AddressType to string identifiers for |
| +// placeholder text. |
| +const int kPlaceHolderStringIds[kMaxNumberOfInputFields] |
| + [kNumberOfAddressTypes] = { |
| + {IDS_AUTOFILL_FIELD_LABEL_COUNTRY, IDS_AUTOFILL_FIELD_LABEL_COUNTRY}, |
| + {IDS_AUTOFILL_FIELD_LABEL_STATE, IDS_AUTOFILL_FIELD_LABEL_STATE}, |
| + {IDS_AUTOFILL_DIALOG_PLACEHOLDER_LOCALITY, |
| + IDS_AUTOFILL_DIALOG_PLACEHOLDER_LOCALITY}, |
| + {IDS_AUTOFILL_DIALOG_PLACEHOLDER_DEPENDENT_LOCALITY, |
| + IDS_AUTOFILL_DIALOG_PLACEHOLDER_DEPENDENT_LOCALITY}, |
| + {IDS_AUTOFILL_DIALOG_PLACEHOLDER_POSTAL_CODE, |
| + IDS_AUTOFILL_DIALOG_PLACEHOLDER_POSTAL_CODE}, |
| + {IDS_AUTOFILL_DIALOG_PLACEHOLDER_SORTING_CODE, |
| + IDS_AUTOFILL_DIALOG_PLACEHOLDER_SORTING_CODE}, |
| + {IDS_AUTOFILL_DIALOG_PLACEHOLDER_ADDRESS_LINE_1, |
| + IDS_AUTOFILL_DIALOG_PLACEHOLDER_ADDRESS_LINE_1}, |
| + {IDS_AUTOFILL_DIALOG_PLACEHOLDER_ADDRESS_LINE_2, |
| + IDS_AUTOFILL_DIALOG_PLACEHOLDER_ADDRESS_LINE_2}, |
| + {IDS_AUTOFILL_DIALOG_PLACEHOLDER_ADDRESSEE_NAME, |
| + IDS_AUTOFILL_DIALOG_PLACEHOLDER_CARDHOLDER_NAME}, |
| + {IDS_AUTOFILL_DIALOG_PLACEHOLDER_ORGANIZATION, |
| + IDS_AUTOFILL_DIALOG_PLACEHOLDER_ORGANIZATION}, |
| +}; |
| + |
| +// Returns the AddressFieldIndex for the given i18n::addressinput::AddressField. |
| +// If the address field is STREET_ADDRESS, then uses the given StreetAddressLine |
| +// to determine whether to return STREET_ADDRESS_1_INDEX or |
| +// STREET_ADDRESS_2_INDEX. |
| +AddressFieldIndex AddressFieldToIndex(AddressField field_type, |
| + StreetAddressLine street_address_line) { |
| + switch (field_type) { |
| + case i18n::addressinput::COUNTRY: |
| + return COUNTRY_INDEX; |
| + case i18n::addressinput::ADMIN_AREA: |
| + return ADMIN_AREA_INDEX; |
| + case i18n::addressinput::LOCALITY: |
| + return LOCALITY_INDEX; |
| + case i18n::addressinput::DEPENDENT_LOCALITY: |
| + return DEPENDENT_LOCALITY_INDEX; |
| + case i18n::addressinput::POSTAL_CODE: |
| + return POSTAL_CODE_INDEX; |
| + case i18n::addressinput::SORTING_CODE: |
| + return SORTING_CODE_INDEX; |
| + case i18n::addressinput::STREET_ADDRESS: |
| + return kStreetAddressLineIndex[street_address_line]; |
| + case i18n::addressinput::RECIPIENT: |
| + return RECIPIENT_INDEX; |
| + case i18n::addressinput::ORGANIZATION: |
| + return ORGANIZATION_INDEX; |
| + } |
| + NOTREACHED(); |
| + return ADDRESS_FIELD_INVALID_INDEX; |
| +} |
| + |
| +// Sets the address field types and length hints for the given |country_region| |
| +// and |language|. |
| +void GetI18nFields(const std::string country_region, |
|
Evan Stade
2013/11/25 20:35:45
const ref
Dan Beam
2013/11/28 02:52:45
Done.
|
| + const std::string& language, |
| + std::vector<AddressField>* field_types, |
| + std::vector<AddressUiComponent::LengthHint>* length_hints) { |
| + i18n::addressinput::Localization localization; |
| + // TODO(dbeam): do we need to call |localization.SetGetter()| here? |
| + std::vector<AddressUiComponent> components( |
| + i18n::addressinput::BuildComponents(country_region, localization)); |
| + for (size_t i = 0; i < components.size(); ++i) { |
| + if (components[i].field == i18n::addressinput::ORGANIZATION) |
| + continue; |
| + field_types->push_back(components[i].field); |
| + length_hints->push_back(components[i].length_hint); |
| + } |
| + |
| + // If |field_types| does not contain a country field, add one at the end so |
| + // the user can still switch countries. |
| + if (std::find(field_types->begin(), field_types->end(), |
| + i18n::addressinput::COUNTRY) == field_types->end()) { |
| + field_types->push_back(i18n::addressinput::COUNTRY); |
| + length_hints->push_back(AddressUiComponent::HINT_LONG); |
| + } |
| +} |
| + |
| +// Returns an incremented |row_index| if |length_hint| and |prev_length_hint| |
| +// indicate that the current input should start on a new line. |
| +int IncrementRowIndexBasedOnLengthHint( |
| + AddressUiComponent::LengthHint prev_length_hint, |
| + AddressUiComponent::LengthHint length_hint, |
| + int row_index) { |
| + if (length_hint == AddressUiComponent::HINT_LONG || |
| + prev_length_hint != length_hint) { |
| + return row_index + 1; |
| + } |
| + return row_index; |
| +} |
| + |
| +// Appends the |field_type| input to |inputs|. Appends |
| +// kMaxNumberOfStreetAddressLines inputs if |field_type| is STREET_ADDRESS. |
| +int BuildI18nInput(int row_index, |
|
Evan Stade
2013/11/25 20:35:45
this doesn't seem like something that should be a
Dan Beam
2013/11/28 02:52:45
Done.
|
| + AddressField field_type, |
| + AddressUiComponent::LengthHint prev_length_hint, |
| + AddressUiComponent::LengthHint length_hint, |
| + AddressType address_type, |
| + DetailInputs* inputs) { |
| + int field_index = AddressFieldToIndex(field_type, STREET_ADDRESS_LINE_1); |
| + if (field_index == ADDRESS_FIELD_INVALID_INDEX) |
| + return row_index; |
| + |
| + row_index = IncrementRowIndexBasedOnLengthHint( |
| + prev_length_hint, length_hint, row_index); |
| + DetailInput input = {row_index, kServerFields[field_index][address_type], |
| + kPlaceHolderStringIds[field_index][address_type]}; |
| + inputs->push_back(input); |
| + |
| + if (field_type == i18n::addressinput::STREET_ADDRESS) { |
| + field_index = AddressFieldToIndex(field_type, STREET_ADDRESS_LINE_2); |
| + row_index = IncrementRowIndexBasedOnLengthHint( |
| + prev_length_hint, length_hint, row_index); |
| + DetailInput input = {row_index, kServerFields[field_index][address_type], |
| + kPlaceHolderStringIds[field_index][address_type]}; |
| + inputs->push_back(input); |
| + } |
| + |
| + return row_index; |
| +} |
| + |
| +// Returns the language of the current application locale. |
| +std::string GetLocaleLanguage() { |
| + return AutofillCountry::CountryCodeForLocale( |
| + g_browser_process->GetApplicationLocale()); |
| +} |
| + |
| +} // namespace |
| + |
| +bool IsI18nAddressInputEnabled() { |
| + return CommandLine::ForCurrentProcess()->HasSwitch( |
| + ::switches::kEnableAutofillAddressInternationalization); |
| +} |
| + |
| +std::string GuessCountry() { |
| + if (!IsI18nAddressInputEnabled()) |
| + return "US"; |
| + |
| + // TODO(rouslan): Improve on this rudimentary implementation of guessing the |
| + // current country code. |
| + return GetLocaleLanguage(); |
| +} |
| + |
| +void BuildI18nInputs(AddressType address_type, |
| + const std::string& country_region, |
| + int row_index, |
| + DetailInputs* inputs) { |
| + std::vector<AddressField> field_types; |
| + std::vector<AddressUiComponent::LengthHint> length_hints; |
| + GetI18nFields( |
| + country_region, GetLocaleLanguage(), &field_types, &length_hints); |
| + AddressUiComponent::LengthHint prev_length_hint = |
| + AddressUiComponent::HINT_LONG; |
| + for (size_t i = 0; i < field_types.size() && i < length_hints.size(); ++i) { |
| + row_index = BuildI18nInput(row_index, |
| + field_types[i], |
| + prev_length_hint, |
| + length_hints[i], |
| + address_type, |
| + inputs); |
| + prev_length_hint = length_hints[i]; |
| + } |
| +} |
| + |
| +} // namespace i18ninput |
| +} // namespace autofill |