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 |