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

Unified 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 side-by-side diff with in-line comments
Download patch
« 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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/autofill/autofill_profile.cc
===================================================================
--- chrome/browser/autofill/autofill_profile.cc (revision 52727)
+++ chrome/browser/autofill/autofill_profile.cc (working copy)
@@ -5,6 +5,9 @@
#include "chrome/browser/autofill/autofill_profile.h"
#include <algorithm>
+#include <list>
+#include <map>
+#include <set>
#include <vector>
#include "app/l10n_util.h"
@@ -170,8 +173,9 @@
bool have_last_name = last_name.length() > 0;
bool have_address = address.length() > 0;
- // Name separator defaults to "". Space if we have first and last name.
+ // Name separator defaults to "". Space if we have first and last name.
string16 name_separator;
+
if (have_first_name && have_last_name) {
name_separator = l10n_util::GetStringUTF16(
IDS_AUTOFILL_DIALOG_ADDRESS_NAME_SEPARATOR);
@@ -201,6 +205,176 @@
return summary_format;
}
+bool AutoFillProfile::AdjustInferredLabels(
+ std::vector<AutoFillProfile*>* profiles) {
+ std::vector<string16> created_labels;
+ const size_t kMinimalFieldsShown = 2;
+ CreateInferredLabels(profiles, &created_labels, kMinimalFieldsShown,
+ UNKNOWN_TYPE);
+ DCHECK(profiles->size() == created_labels.size());
+ bool updated_labels = false;
+ for (size_t i = 0; i < profiles->size(); ++i) {
+ if (profiles->at(i)->Label() != created_labels[i]) {
+ updated_labels = true;
+ profiles->at(i)->set_label(created_labels[i]);
+ }
+ }
+ return updated_labels;
+}
+
+void AutoFillProfile::CreateInferredLabels(
+ const std::vector<AutoFillProfile*>* profiles,
+ std::vector<string16>* created_labels,
+ size_t minimal_fields_shown,
+ AutoFillFieldType exclude_field) {
+ // These fields are use to distinguish between two profiles in the order of
+ // importance, e. g. if both EMAIL_ADDRESS and COMPANY_NAME are different,
+ // EMAIL_ADDRESS will be used to distinguish them.
+ const AutoFillFieldType distinguishing_fields[] = {
+ // First non empty data are always present in the label, even if it matches.
+ NAME_FULL,
+ ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY,
+ ADDRESS_HOME_STATE,
+ ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY,
+ EMAIL_ADDRESS,
+ PHONE_HOME_WHOLE_NUMBER,
+ PHONE_FAX_WHOLE_NUMBER,
+ COMPANY_NAME,
+ };
+ if (exclude_field == NAME_FIRST || exclude_field == NAME_LAST)
+ exclude_field = NAME_FULL;
+ DCHECK(profiles);
+ DCHECK(created_labels);
+ created_labels->resize(profiles->size());
+ std::map<string16, std::list<size_t> > labels;
+ for (size_t it = 0; it < profiles->size(); ++it) {
+ labels[
+ profiles->at(it)->GetFieldText(AutoFillType(NAME_FULL))].push_back(it);
+ }
+ std::map<string16, std::list<size_t> >::iterator label_iterator;
+ for (label_iterator = labels.begin(); label_iterator != labels.end();
+ ++label_iterator) {
+ if (label_iterator->second.size() > 1) {
+ // We have more than one item with the same preview, add differentiating
+ // data.
+ std::list<size_t>::iterator similar_profiles;
+ std::map<string16, int> tested_fields[arraysize(distinguishing_fields)];
+ for (similar_profiles = label_iterator->second.begin();
+ similar_profiles != label_iterator->second.end();
+ ++similar_profiles) {
+ for (size_t i = 0; i < arraysize(distinguishing_fields); ++i) {
+ string16 key = profiles->at(*similar_profiles)->GetFieldText(
+ AutoFillType(distinguishing_fields[i]));
+ std::map<string16, int>::iterator tested_field =
+ tested_fields[i].find(key);
+ if (tested_field == tested_fields[i].end())
+ (tested_fields[i])[key] = 1;
+ else
+ ++(tested_field->second);
+ }
+ }
+ std::vector<AutoFillFieldType> fields;
+ std::vector<AutoFillFieldType> first_non_empty_fields;
+ size_t added_fields = 0;
+ bool matched_necessary = false;
+ // Leave it as a candidate if it is not the same for everybody.
+ for (size_t i = 0; i < arraysize(distinguishing_fields); ++i) {
+ if (tested_fields[i].size() == label_iterator->second.size()) {
+ // This field is different for everybody.
+ if (!matched_necessary) {
+ matched_necessary = true;
+ fields.clear();
+ added_fields = 1;
+ if (first_non_empty_fields.size()) {
+ added_fields += first_non_empty_fields.size();
+ fields.resize(added_fields - 1);
+ std::copy(first_non_empty_fields.begin(),
+ first_non_empty_fields.end(),
+ fields.begin());
+ }
+ } else {
+ ++added_fields;
+ }
+ fields.push_back(distinguishing_fields[i]);
+ if (added_fields >= minimal_fields_shown)
+ break;
+ } else if (tested_fields[i].size() != 1) {
+ // this field is different for some.
+ if (added_fields < minimal_fields_shown) {
+ first_non_empty_fields.push_back(distinguishing_fields[i]);
+ ++added_fields;
+ if (added_fields == minimal_fields_shown && matched_necessary)
+ break;
+ }
+ fields.push_back(distinguishing_fields[i]);
+ } else if (added_fields < minimal_fields_shown &&
+ exclude_field != distinguishing_fields[i] &&
+ !label_iterator->first.empty()) {
+ fields.push_back(distinguishing_fields[i]);
+ first_non_empty_fields.push_back(distinguishing_fields[i]);
+ ++added_fields;
+ if (added_fields == minimal_fields_shown && matched_necessary)
+ break;
+ }
+ }
+ // Update labels if needed.
+ for (similar_profiles = label_iterator->second.begin();
+ similar_profiles != label_iterator->second.end();
+ ++similar_profiles) {
+ size_t field_it = 0;
+ for (size_t field_id = 0;
+ field_id < arraysize(distinguishing_fields) &&
+ field_it < fields.size(); ++field_id) {
+ if (fields[field_it] == distinguishing_fields[field_id]) {
+ if ((tested_fields[field_id])[
+ profiles->at(*similar_profiles)->GetFieldText(
+ AutoFillType(distinguishing_fields[field_id]))] == 1) {
+ // this field is unique among the subset.
+ break;
+ }
+ ++field_it;
+ }
+ }
+
+ string16 new_label;
+ if (field_it < fields.size() && fields.size() > minimal_fields_shown) {
+ std::vector<AutoFillFieldType> unique_fields;
+ unique_fields.resize(fields.size());
+ std::copy(fields.begin(), fields.end(), unique_fields.begin());
+ unique_fields.resize(std::max(field_it + 1, minimal_fields_shown));
+ new_label =
+ profiles->at(*similar_profiles)->ConstructInferredLabel(
+ &unique_fields);
+ } else {
+ new_label =
+ profiles->at(*similar_profiles)->ConstructInferredLabel(&fields);
+ }
+ (*created_labels)[*similar_profiles] = new_label;
+ }
+ } else {
+ std::vector<AutoFillFieldType> non_empty_fields;
+ size_t include_fields = minimal_fields_shown ? minimal_fields_shown : 1;
+ non_empty_fields.reserve(include_fields);
+ for (size_t i = 0; i < arraysize(distinguishing_fields); ++i) {
+ if (exclude_field == distinguishing_fields[i])
+ continue;
+ if (!profiles->at(label_iterator->second.front())->GetFieldText(
+ AutoFillType(distinguishing_fields[i])).empty()) {
+ non_empty_fields.push_back(distinguishing_fields[i]);
+ if (non_empty_fields.size() >= include_fields)
+ break;
+ }
+ }
+
+ (*created_labels)[label_iterator->second.front()] =
+ profiles->at(label_iterator->second.front())->ConstructInferredLabel(
+ &non_empty_fields);
+ }
+ }
+}
+
void AutoFillProfile::operator=(const AutoFillProfile& source) {
label_ = source.label_;
unique_id_ = source.unique_id_;
@@ -256,6 +430,31 @@
return static_cast<Address*>(personal_info_[AutoFillType::ADDRESS_HOME]);
}
+string16 AutoFillProfile::ConstructInferredLabel(
+ const std::vector<AutoFillFieldType>* included_fields) const {
+ DCHECK(included_fields);
+ string16 label;
+ string16 separator = l10n_util::GetStringUTF16(
+ IDS_AUTOFILL_DIALOG_ADDRESS_SUMMARY_SEPARATOR);
+ for (std::vector<AutoFillFieldType>::const_iterator it =
+ included_fields->begin(); it != included_fields->end(); ++it) {
+ string16 field = GetFieldText(AutoFillType(*it));
+ if (!field.empty()) {
+ if (!label.empty()) {
+ label.append(separator);
+ }
+ // Fax number has special format, to indicate that this is a fax number.
+ if (*it == PHONE_FAX_WHOLE_NUMBER) {
+ field = l10n_util::GetStringFUTF16(
+ IDS_AUTOFILL_DIALOG_ADDRESS_SUMMARY_FAX_FORMAT, field);
+ }
+ label.append(field);
+ }
+ }
+ return label;
+}
+
+
// So we can compare AutoFillProfiles with EXPECT_EQ().
std::ostream& operator<<(std::ostream& os, const AutoFillProfile& profile) {
return os
« 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