OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 // | |
5 // A stub implementation of internationalized address input fields for | |
6 // interactive autofill dialog. The implementation always returns the same | |
7 // address fields until libaddressinput library is integrated. | |
8 // | |
9 // Also, GetI18nFields() will call libaddressinput library to determine the | |
10 // address fields instead of always returning US address fields. | |
11 // | |
12 // GuessCountry() uses only the application locale and should be improved to use | |
13 // the timezone and possibly geolocation. | |
14 | |
15 #include "chrome/browser/ui/autofill/autofill_dialog_i18n_input.h" | |
16 | |
17 #include <algorithm> | |
18 | |
19 #include "base/command_line.h" | |
20 #include "chrome/browser/browser_process.h" | |
21 #include "chrome/common/chrome_switches.h" | |
22 #include "components/autofill/core/browser/autofill_country.h" | |
23 #include "grit/component_strings.h" | |
24 #include "grit/generated_resources.h" | |
25 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_fi eld.h" | |
26 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_ui .h" | |
27 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_ui _component.h" | |
28 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/localizati on.h" | |
29 #include "ui/base/l10n/l10n_util.h" | |
30 | |
31 namespace autofill { | |
32 namespace i18ninput { | |
33 | |
34 namespace { | |
35 | |
36 using i18n::addressinput::AddressField; | |
37 using i18n::addressinput::AddressUiComponent; | |
38 | |
39 // Indexes into arrays of address field data. | |
40 enum AddressFieldIndex { | |
41 COUNTRY_INDEX, | |
42 ADMIN_AREA_INDEX, | |
43 LOCALITY_INDEX, | |
44 DEPENDENT_LOCALITY_INDEX, | |
45 POSTAL_CODE_INDEX, | |
46 SORTING_CODE_INDEX, | |
47 STREET_ADDRESS_1_INDEX, | |
48 STREET_ADDRESS_2_INDEX, | |
49 RECIPIENT_INDEX, | |
50 ORGANIZATION_INDEX, | |
51 ADDRESS_FIELD_INVALID_INDEX, | |
52 }; | |
53 | |
54 // Indexes into arrays of street address line data. | |
55 enum StreetAddressLine { | |
56 STREET_ADDRESS_LINE_1, | |
57 STREET_ADDRESS_LINE_2, | |
58 }; | |
59 | |
60 // The number of address types. | |
61 const int kNumberOfAddressTypes = ADDRESS_TYPE_BILLING + 1; | |
62 | |
63 // The maximum number of input fields. | |
64 const int kMaxNumberOfInputFields = ADDRESS_FIELD_INVALID_INDEX; | |
65 | |
66 // The maximum number of street address lines. | |
67 const int kMaxNumberOfStreetAddressLines = STREET_ADDRESS_LINE_2 + 1; | |
68 | |
69 // A mapping of StreetAddressLine to corresponding values in AddressFieldIndex. | |
70 // Used to lookup address field data for street address lines. | |
71 const AddressFieldIndex kStreetAddressLineIndex | |
72 [kMaxNumberOfStreetAddressLines] = { | |
73 STREET_ADDRESS_1_INDEX, | |
74 STREET_ADDRESS_2_INDEX, | |
75 }; | |
76 | |
77 // A mapping of AddressFieldIndex and AddressType to autofill field types. | |
78 const ServerFieldType kServerFields[kMaxNumberOfInputFields] | |
79 [kNumberOfAddressTypes] = { | |
80 {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.
| |
81 {ADDRESS_HOME_STATE, ADDRESS_BILLING_STATE}, | |
82 {ADDRESS_HOME_CITY, ADDRESS_BILLING_CITY}, | |
83 {ADDRESS_HOME_DEPENDENT_LOCALITY, ADDRESS_BILLING_DEPENDENT_LOCALITY}, | |
84 {ADDRESS_HOME_ZIP, ADDRESS_BILLING_ZIP}, | |
85 {ADDRESS_HOME_SORTING_CODE, ADDRESS_BILLING_SORTING_CODE}, | |
86 {ADDRESS_HOME_LINE1, ADDRESS_BILLING_LINE1}, | |
87 {ADDRESS_HOME_LINE2, ADDRESS_BILLING_LINE2}, | |
88 {NAME_FULL, NAME_BILLING_FULL}, | |
89 {COMPANY_NAME, COMPANY_NAME}, | |
90 }; | |
91 | |
92 // A mapping of AddressFieldIndex and AddressType to string identifiers for | |
93 // placeholder text. | |
94 const int kPlaceHolderStringIds[kMaxNumberOfInputFields] | |
95 [kNumberOfAddressTypes] = { | |
96 {IDS_AUTOFILL_FIELD_LABEL_COUNTRY, IDS_AUTOFILL_FIELD_LABEL_COUNTRY}, | |
97 {IDS_AUTOFILL_FIELD_LABEL_STATE, IDS_AUTOFILL_FIELD_LABEL_STATE}, | |
98 {IDS_AUTOFILL_DIALOG_PLACEHOLDER_LOCALITY, | |
99 IDS_AUTOFILL_DIALOG_PLACEHOLDER_LOCALITY}, | |
100 {IDS_AUTOFILL_DIALOG_PLACEHOLDER_DEPENDENT_LOCALITY, | |
101 IDS_AUTOFILL_DIALOG_PLACEHOLDER_DEPENDENT_LOCALITY}, | |
102 {IDS_AUTOFILL_DIALOG_PLACEHOLDER_POSTAL_CODE, | |
103 IDS_AUTOFILL_DIALOG_PLACEHOLDER_POSTAL_CODE}, | |
104 {IDS_AUTOFILL_DIALOG_PLACEHOLDER_SORTING_CODE, | |
105 IDS_AUTOFILL_DIALOG_PLACEHOLDER_SORTING_CODE}, | |
106 {IDS_AUTOFILL_DIALOG_PLACEHOLDER_ADDRESS_LINE_1, | |
107 IDS_AUTOFILL_DIALOG_PLACEHOLDER_ADDRESS_LINE_1}, | |
108 {IDS_AUTOFILL_DIALOG_PLACEHOLDER_ADDRESS_LINE_2, | |
109 IDS_AUTOFILL_DIALOG_PLACEHOLDER_ADDRESS_LINE_2}, | |
110 {IDS_AUTOFILL_DIALOG_PLACEHOLDER_ADDRESSEE_NAME, | |
111 IDS_AUTOFILL_DIALOG_PLACEHOLDER_CARDHOLDER_NAME}, | |
112 {IDS_AUTOFILL_DIALOG_PLACEHOLDER_ORGANIZATION, | |
113 IDS_AUTOFILL_DIALOG_PLACEHOLDER_ORGANIZATION}, | |
114 }; | |
115 | |
116 // Returns the AddressFieldIndex for the given i18n::addressinput::AddressField. | |
117 // If the address field is STREET_ADDRESS, then uses the given StreetAddressLine | |
118 // to determine whether to return STREET_ADDRESS_1_INDEX or | |
119 // STREET_ADDRESS_2_INDEX. | |
120 AddressFieldIndex AddressFieldToIndex(AddressField field_type, | |
121 StreetAddressLine street_address_line) { | |
122 switch (field_type) { | |
123 case i18n::addressinput::COUNTRY: | |
124 return COUNTRY_INDEX; | |
125 case i18n::addressinput::ADMIN_AREA: | |
126 return ADMIN_AREA_INDEX; | |
127 case i18n::addressinput::LOCALITY: | |
128 return LOCALITY_INDEX; | |
129 case i18n::addressinput::DEPENDENT_LOCALITY: | |
130 return DEPENDENT_LOCALITY_INDEX; | |
131 case i18n::addressinput::POSTAL_CODE: | |
132 return POSTAL_CODE_INDEX; | |
133 case i18n::addressinput::SORTING_CODE: | |
134 return SORTING_CODE_INDEX; | |
135 case i18n::addressinput::STREET_ADDRESS: | |
136 return kStreetAddressLineIndex[street_address_line]; | |
137 case i18n::addressinput::RECIPIENT: | |
138 return RECIPIENT_INDEX; | |
139 case i18n::addressinput::ORGANIZATION: | |
140 return ORGANIZATION_INDEX; | |
141 } | |
142 NOTREACHED(); | |
143 return ADDRESS_FIELD_INVALID_INDEX; | |
144 } | |
145 | |
146 // Sets the address field types and length hints for the given |country_region| | |
147 // and |language|. | |
148 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.
| |
149 const std::string& language, | |
150 std::vector<AddressField>* field_types, | |
151 std::vector<AddressUiComponent::LengthHint>* length_hints) { | |
152 i18n::addressinput::Localization localization; | |
153 // TODO(dbeam): do we need to call |localization.SetGetter()| here? | |
154 std::vector<AddressUiComponent> components( | |
155 i18n::addressinput::BuildComponents(country_region, localization)); | |
156 for (size_t i = 0; i < components.size(); ++i) { | |
157 if (components[i].field == i18n::addressinput::ORGANIZATION) | |
158 continue; | |
159 field_types->push_back(components[i].field); | |
160 length_hints->push_back(components[i].length_hint); | |
161 } | |
162 | |
163 // If |field_types| does not contain a country field, add one at the end so | |
164 // the user can still switch countries. | |
165 if (std::find(field_types->begin(), field_types->end(), | |
166 i18n::addressinput::COUNTRY) == field_types->end()) { | |
167 field_types->push_back(i18n::addressinput::COUNTRY); | |
168 length_hints->push_back(AddressUiComponent::HINT_LONG); | |
169 } | |
170 } | |
171 | |
172 // Returns an incremented |row_index| if |length_hint| and |prev_length_hint| | |
173 // indicate that the current input should start on a new line. | |
174 int IncrementRowIndexBasedOnLengthHint( | |
175 AddressUiComponent::LengthHint prev_length_hint, | |
176 AddressUiComponent::LengthHint length_hint, | |
177 int row_index) { | |
178 if (length_hint == AddressUiComponent::HINT_LONG || | |
179 prev_length_hint != length_hint) { | |
180 return row_index + 1; | |
181 } | |
182 return row_index; | |
183 } | |
184 | |
185 // Appends the |field_type| input to |inputs|. Appends | |
186 // kMaxNumberOfStreetAddressLines inputs if |field_type| is STREET_ADDRESS. | |
187 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.
| |
188 AddressField field_type, | |
189 AddressUiComponent::LengthHint prev_length_hint, | |
190 AddressUiComponent::LengthHint length_hint, | |
191 AddressType address_type, | |
192 DetailInputs* inputs) { | |
193 int field_index = AddressFieldToIndex(field_type, STREET_ADDRESS_LINE_1); | |
194 if (field_index == ADDRESS_FIELD_INVALID_INDEX) | |
195 return row_index; | |
196 | |
197 row_index = IncrementRowIndexBasedOnLengthHint( | |
198 prev_length_hint, length_hint, row_index); | |
199 DetailInput input = {row_index, kServerFields[field_index][address_type], | |
200 kPlaceHolderStringIds[field_index][address_type]}; | |
201 inputs->push_back(input); | |
202 | |
203 if (field_type == i18n::addressinput::STREET_ADDRESS) { | |
204 field_index = AddressFieldToIndex(field_type, STREET_ADDRESS_LINE_2); | |
205 row_index = IncrementRowIndexBasedOnLengthHint( | |
206 prev_length_hint, length_hint, row_index); | |
207 DetailInput input = {row_index, kServerFields[field_index][address_type], | |
208 kPlaceHolderStringIds[field_index][address_type]}; | |
209 inputs->push_back(input); | |
210 } | |
211 | |
212 return row_index; | |
213 } | |
214 | |
215 // Returns the language of the current application locale. | |
216 std::string GetLocaleLanguage() { | |
217 return AutofillCountry::CountryCodeForLocale( | |
218 g_browser_process->GetApplicationLocale()); | |
219 } | |
220 | |
221 } // namespace | |
222 | |
223 bool IsI18nAddressInputEnabled() { | |
224 return CommandLine::ForCurrentProcess()->HasSwitch( | |
225 ::switches::kEnableAutofillAddressInternationalization); | |
226 } | |
227 | |
228 std::string GuessCountry() { | |
229 if (!IsI18nAddressInputEnabled()) | |
230 return "US"; | |
231 | |
232 // TODO(rouslan): Improve on this rudimentary implementation of guessing the | |
233 // current country code. | |
234 return GetLocaleLanguage(); | |
235 } | |
236 | |
237 void BuildI18nInputs(AddressType address_type, | |
238 const std::string& country_region, | |
239 int row_index, | |
240 DetailInputs* inputs) { | |
241 std::vector<AddressField> field_types; | |
242 std::vector<AddressUiComponent::LengthHint> length_hints; | |
243 GetI18nFields( | |
244 country_region, GetLocaleLanguage(), &field_types, &length_hints); | |
245 AddressUiComponent::LengthHint prev_length_hint = | |
246 AddressUiComponent::HINT_LONG; | |
247 for (size_t i = 0; i < field_types.size() && i < length_hints.size(); ++i) { | |
248 row_index = BuildI18nInput(row_index, | |
249 field_types[i], | |
250 prev_length_hint, | |
251 length_hints[i], | |
252 address_type, | |
253 inputs); | |
254 prev_length_hint = length_hints[i]; | |
255 } | |
256 } | |
257 | |
258 } // namespace i18ninput | |
259 } // namespace autofill | |
OLD | NEW |