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

Side by Side Diff: chrome/browser/autofill/autofill_profile.cc

Issue 2835026: Added inferred labels implementation. Label inferred from the person name + d... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 5 months 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) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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/autofill/autofill_profile.h" 5 #include "chrome/browser/autofill/autofill_profile.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <list>
9 #include <map>
10 #include <set>
8 #include <vector> 11 #include <vector>
9 12
10 #include "app/l10n_util.h" 13 #include "app/l10n_util.h"
11 #include "base/stl_util-inl.h" 14 #include "base/stl_util-inl.h"
12 #include "base/utf_string_conversions.h" 15 #include "base/utf_string_conversions.h"
13 #include "chrome/browser/autofill/address.h" 16 #include "chrome/browser/autofill/address.h"
14 #include "chrome/browser/autofill/autofill_manager.h" 17 #include "chrome/browser/autofill/autofill_manager.h"
15 #include "chrome/browser/autofill/contact_info.h" 18 #include "chrome/browser/autofill/contact_info.h"
16 #include "chrome/browser/autofill/fax_number.h" 19 #include "chrome/browser/autofill/fax_number.h"
17 #include "chrome/browser/autofill/home_address.h" 20 #include "chrome/browser/autofill/home_address.h"
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
163 // may be an empty string. 166 // may be an empty string.
164 string16 first_name = GetFieldText(AutoFillType(NAME_FIRST)); 167 string16 first_name = GetFieldText(AutoFillType(NAME_FIRST));
165 string16 last_name = GetFieldText(AutoFillType(NAME_LAST)); 168 string16 last_name = GetFieldText(AutoFillType(NAME_LAST));
166 string16 address = GetFieldText(AutoFillType(ADDRESS_HOME_LINE1)); 169 string16 address = GetFieldText(AutoFillType(ADDRESS_HOME_LINE1));
167 170
168 // String separators depend (below) on the existence of the various fields. 171 // String separators depend (below) on the existence of the various fields.
169 bool have_first_name = first_name.length() > 0; 172 bool have_first_name = first_name.length() > 0;
170 bool have_last_name = last_name.length() > 0; 173 bool have_last_name = last_name.length() > 0;
171 bool have_address = address.length() > 0; 174 bool have_address = address.length() > 0;
172 175
173 // Name separator defaults to "". Space if we have first and last name. 176 // Name separator defaults to "". Space if we have first and last name.
174 string16 name_separator; 177 string16 name_separator;
178
175 if (have_first_name && have_last_name) { 179 if (have_first_name && have_last_name) {
176 name_separator = l10n_util::GetStringUTF16( 180 name_separator = l10n_util::GetStringUTF16(
177 IDS_AUTOFILL_DIALOG_ADDRESS_NAME_SEPARATOR); 181 IDS_AUTOFILL_DIALOG_ADDRESS_NAME_SEPARATOR);
178 } 182 }
179 183
180 // E.g. "John Smith", or "John", or "Smith", or "". 184 // E.g. "John Smith", or "John", or "Smith", or "".
181 string16 name_format = l10n_util::GetStringFUTF16( 185 string16 name_format = l10n_util::GetStringFUTF16(
182 IDS_AUTOFILL_DIALOG_ADDRESS_SUMMARY_NAME_FORMAT, 186 IDS_AUTOFILL_DIALOG_ADDRESS_SUMMARY_NAME_FORMAT,
183 first_name, 187 first_name,
184 name_separator, 188 name_separator,
185 last_name); 189 last_name);
186 190
187 // Summary separator defaults to "". ", " if we have name and address. 191 // Summary separator defaults to "". ", " if we have name and address.
188 string16 summary_separator; 192 string16 summary_separator;
189 if ((have_first_name || have_last_name) && have_address) { 193 if ((have_first_name || have_last_name) && have_address) {
190 summary_separator = l10n_util::GetStringUTF16( 194 summary_separator = l10n_util::GetStringUTF16(
191 IDS_AUTOFILL_DIALOG_ADDRESS_SUMMARY_SEPARATOR); 195 IDS_AUTOFILL_DIALOG_ADDRESS_SUMMARY_SEPARATOR);
192 } 196 }
193 197
194 // E.g. "John Smith, 123 Main Street". 198 // E.g. "John Smith, 123 Main Street".
195 string16 summary_format = l10n_util::GetStringFUTF16( 199 string16 summary_format = l10n_util::GetStringFUTF16(
196 IDS_AUTOFILL_DIALOG_ADDRESS_SUMMARY_FORMAT, 200 IDS_AUTOFILL_DIALOG_ADDRESS_SUMMARY_FORMAT,
197 name_format, 201 name_format,
198 summary_separator, 202 summary_separator,
199 address); 203 address);
200 204
201 return summary_format; 205 return summary_format;
202 } 206 }
203 207
208 bool AutoFillProfile::AdjustInferredLabels(
209 std::vector<AutoFillProfile*>* profiles) {
210 std::vector<string16> created_labels;
211 const size_t kMinimalFieldsShown = 2;
212 CreateInferredLabels(profiles, &created_labels, kMinimalFieldsShown,
213 UNKNOWN_TYPE);
214 DCHECK(profiles->size() == created_labels.size());
215 bool updated_labels = false;
216 for (size_t i = 0; i < profiles->size(); ++i) {
217 if (profiles->at(i)->Label() != created_labels[i]) {
218 updated_labels = true;
219 profiles->at(i)->set_label(created_labels[i]);
220 }
221 }
222 return updated_labels;
223 }
224
225 void AutoFillProfile::CreateInferredLabels(
226 const std::vector<AutoFillProfile*>* profiles,
227 std::vector<string16>* created_labels,
228 size_t minimal_fields_shown,
229 AutoFillFieldType exclude_field) {
230 // These fields are use to distinguish between two profiles in the order of
231 // importance, e. g. if both EMAIL_ADDRESS and COMPANY_NAME are different,
232 // EMAIL_ADDRESS will be used to distinguish them.
233 const AutoFillFieldType distinguishing_fields[] = {
234 // First non empty data are always present in the label, even if it matches.
235 NAME_FULL,
236 ADDRESS_HOME_LINE1,
237 ADDRESS_HOME_CITY,
238 ADDRESS_HOME_STATE,
239 ADDRESS_HOME_ZIP,
240 ADDRESS_HOME_COUNTRY,
241 EMAIL_ADDRESS,
242 PHONE_HOME_WHOLE_NUMBER,
243 PHONE_FAX_WHOLE_NUMBER,
244 COMPANY_NAME,
245 };
246 if (exclude_field == NAME_FIRST || exclude_field == NAME_LAST)
247 exclude_field = NAME_FULL;
248 DCHECK(profiles);
249 DCHECK(created_labels);
250 created_labels->resize(profiles->size());
251 std::map<string16, std::list<size_t> > labels;
252 for (size_t it = 0; it < profiles->size(); ++it) {
253 labels[
254 profiles->at(it)->GetFieldText(AutoFillType(NAME_FULL))].push_back(it);
255 }
256 std::map<string16, std::list<size_t> >::iterator label_iterator;
257 for (label_iterator = labels.begin(); label_iterator != labels.end();
258 ++label_iterator) {
259 if (label_iterator->second.size() > 1) {
260 // We have more than one item with the same preview, add differentiating
261 // data.
262 std::list<size_t>::iterator similar_profiles;
263 std::map<string16, int> tested_fields[arraysize(distinguishing_fields)];
264 for (similar_profiles = label_iterator->second.begin();
265 similar_profiles != label_iterator->second.end();
266 ++similar_profiles) {
267 for (size_t i = 0; i < arraysize(distinguishing_fields); ++i) {
268 string16 key = profiles->at(*similar_profiles)->GetFieldText(
269 AutoFillType(distinguishing_fields[i]));
270 std::map<string16, int>::iterator tested_field =
271 tested_fields[i].find(key);
272 if (tested_field == tested_fields[i].end())
273 (tested_fields[i])[key] = 1;
274 else
275 ++(tested_field->second);
276 }
277 }
278 std::vector<AutoFillFieldType> fields;
279 std::vector<AutoFillFieldType> first_non_empty_fields;
280 size_t added_fields = 0;
281 bool matched_necessary = false;
282 // Leave it as a candidate if it is not the same for everybody.
283 for (size_t i = 0; i < arraysize(distinguishing_fields); ++i) {
284 if (tested_fields[i].size() == label_iterator->second.size()) {
285 // This field is different for everybody.
286 if (!matched_necessary) {
287 matched_necessary = true;
288 fields.clear();
289 added_fields = 1;
290 if (first_non_empty_fields.size()) {
291 added_fields += first_non_empty_fields.size();
292 fields.resize(added_fields - 1);
293 std::copy(first_non_empty_fields.begin(),
294 first_non_empty_fields.end(),
295 fields.begin());
296 }
297 } else {
298 ++added_fields;
299 }
300 fields.push_back(distinguishing_fields[i]);
301 if (added_fields >= minimal_fields_shown)
302 break;
303 } else if (tested_fields[i].size() != 1) {
304 // this field is different for some.
305 if (added_fields < minimal_fields_shown) {
306 first_non_empty_fields.push_back(distinguishing_fields[i]);
307 ++added_fields;
308 if (added_fields == minimal_fields_shown && matched_necessary)
309 break;
310 }
311 fields.push_back(distinguishing_fields[i]);
312 } else if (added_fields < minimal_fields_shown &&
313 exclude_field != distinguishing_fields[i] &&
314 !label_iterator->first.empty()) {
315 fields.push_back(distinguishing_fields[i]);
316 first_non_empty_fields.push_back(distinguishing_fields[i]);
317 ++added_fields;
318 if (added_fields == minimal_fields_shown && matched_necessary)
319 break;
320 }
321 }
322 // Update labels if needed.
323 for (similar_profiles = label_iterator->second.begin();
324 similar_profiles != label_iterator->second.end();
325 ++similar_profiles) {
326 size_t field_it = 0;
327 for (size_t field_id = 0;
328 field_id < arraysize(distinguishing_fields) &&
329 field_it < fields.size(); ++field_id) {
330 if (fields[field_it] == distinguishing_fields[field_id]) {
331 if ((tested_fields[field_id])[
332 profiles->at(*similar_profiles)->GetFieldText(
333 AutoFillType(distinguishing_fields[field_id]))] == 1) {
334 // this field is unique among the subset.
335 break;
336 }
337 ++field_it;
338 }
339 }
340
341 string16 new_label;
342 if (field_it < fields.size() && fields.size() > minimal_fields_shown) {
343 std::vector<AutoFillFieldType> unique_fields;
344 unique_fields.resize(fields.size());
345 std::copy(fields.begin(), fields.end(), unique_fields.begin());
346 unique_fields.resize(std::max(field_it + 1, minimal_fields_shown));
347 new_label =
348 profiles->at(*similar_profiles)->ConstructInferredLabel(
349 &unique_fields);
350 } else {
351 new_label =
352 profiles->at(*similar_profiles)->ConstructInferredLabel(&fields);
353 }
354 (*created_labels)[*similar_profiles] = new_label;
355 }
356 } else {
357 std::vector<AutoFillFieldType> non_empty_fields;
358 size_t include_fields = minimal_fields_shown ? minimal_fields_shown : 1;
359 non_empty_fields.reserve(include_fields);
360 for (size_t i = 0; i < arraysize(distinguishing_fields); ++i) {
361 if (exclude_field == distinguishing_fields[i])
362 continue;
363 if (!profiles->at(label_iterator->second.front())->GetFieldText(
364 AutoFillType(distinguishing_fields[i])).empty()) {
365 non_empty_fields.push_back(distinguishing_fields[i]);
366 if (non_empty_fields.size() >= include_fields)
367 break;
368 }
369 }
370
371 (*created_labels)[label_iterator->second.front()] =
372 profiles->at(label_iterator->second.front())->ConstructInferredLabel(
373 &non_empty_fields);
374 }
375 }
376 }
377
204 void AutoFillProfile::operator=(const AutoFillProfile& source) { 378 void AutoFillProfile::operator=(const AutoFillProfile& source) {
205 label_ = source.label_; 379 label_ = source.label_;
206 unique_id_ = source.unique_id_; 380 unique_id_ = source.unique_id_;
207 381
208 STLDeleteContainerPairSecondPointers(personal_info_.begin(), 382 STLDeleteContainerPairSecondPointers(personal_info_.begin(),
209 personal_info_.end()); 383 personal_info_.end());
210 personal_info_.clear(); 384 personal_info_.clear();
211 385
212 FormGroupMap::const_iterator iter; 386 FormGroupMap::const_iterator iter;
213 for (iter = source.personal_info_.begin(); 387 for (iter = source.personal_info_.begin();
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
249 } 423 }
250 424
251 bool AutoFillProfile::operator!=(const AutoFillProfile& profile) const { 425 bool AutoFillProfile::operator!=(const AutoFillProfile& profile) const {
252 return !operator==(profile); 426 return !operator==(profile);
253 } 427 }
254 428
255 Address* AutoFillProfile::GetHomeAddress() { 429 Address* AutoFillProfile::GetHomeAddress() {
256 return static_cast<Address*>(personal_info_[AutoFillType::ADDRESS_HOME]); 430 return static_cast<Address*>(personal_info_[AutoFillType::ADDRESS_HOME]);
257 } 431 }
258 432
433 string16 AutoFillProfile::ConstructInferredLabel(
434 const std::vector<AutoFillFieldType>* included_fields) const {
435 DCHECK(included_fields);
436 string16 label;
437 string16 separator = l10n_util::GetStringUTF16(
438 IDS_AUTOFILL_DIALOG_ADDRESS_SUMMARY_SEPARATOR);
439 for (std::vector<AutoFillFieldType>::const_iterator it =
440 included_fields->begin(); it != included_fields->end(); ++it) {
441 string16 field = GetFieldText(AutoFillType(*it));
442 if (!field.empty()) {
443 if (!label.empty()) {
444 label.append(separator);
445 }
446 // Fax number has special format, to indicate that this is a fax number.
447 if (*it == PHONE_FAX_WHOLE_NUMBER) {
448 field = l10n_util::GetStringFUTF16(
449 IDS_AUTOFILL_DIALOG_ADDRESS_SUMMARY_FAX_FORMAT, field);
450 }
451 label.append(field);
452 }
453 }
454 return label;
455 }
456
457
259 // So we can compare AutoFillProfiles with EXPECT_EQ(). 458 // So we can compare AutoFillProfiles with EXPECT_EQ().
260 std::ostream& operator<<(std::ostream& os, const AutoFillProfile& profile) { 459 std::ostream& operator<<(std::ostream& os, const AutoFillProfile& profile) {
261 return os 460 return os
262 << UTF16ToUTF8(profile.Label()) 461 << UTF16ToUTF8(profile.Label())
263 << " " 462 << " "
264 << profile.unique_id() 463 << profile.unique_id()
265 << " " 464 << " "
266 << UTF16ToUTF8(profile.GetFieldText(AutoFillType(NAME_FIRST))) 465 << UTF16ToUTF8(profile.GetFieldText(AutoFillType(NAME_FIRST)))
267 << " " 466 << " "
268 << UTF16ToUTF8(profile.GetFieldText(AutoFillType(NAME_MIDDLE))) 467 << UTF16ToUTF8(profile.GetFieldText(AutoFillType(NAME_MIDDLE)))
(...skipping 15 matching lines...) Expand all
284 << UTF16ToUTF8(profile.GetFieldText(AutoFillType(ADDRESS_HOME_ZIP))) 483 << UTF16ToUTF8(profile.GetFieldText(AutoFillType(ADDRESS_HOME_ZIP)))
285 << " " 484 << " "
286 << UTF16ToUTF8(profile.GetFieldText(AutoFillType(ADDRESS_HOME_COUNTRY))) 485 << UTF16ToUTF8(profile.GetFieldText(AutoFillType(ADDRESS_HOME_COUNTRY)))
287 << " " 486 << " "
288 << UTF16ToUTF8(profile.GetFieldText(AutoFillType( 487 << UTF16ToUTF8(profile.GetFieldText(AutoFillType(
289 PHONE_HOME_WHOLE_NUMBER))) 488 PHONE_HOME_WHOLE_NUMBER)))
290 << " " 489 << " "
291 << UTF16ToUTF8(profile.GetFieldText(AutoFillType( 490 << UTF16ToUTF8(profile.GetFieldText(AutoFillType(
292 PHONE_FAX_WHOLE_NUMBER))); 491 PHONE_FAX_WHOLE_NUMBER)));
293 } 492 }
OLDNEW
« no previous file with comments | « chrome/browser/autofill/autofill_profile.h ('k') | chrome/browser/autofill/autofill_profile_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698