Chromium Code Reviews| Index: chrome/browser/autofill/phone_number.cc |
| =================================================================== |
| --- chrome/browser/autofill/phone_number.cc (revision 85791) |
| +++ chrome/browser/autofill/phone_number.cc (working copy) |
| @@ -5,10 +5,13 @@ |
| #include "chrome/browser/autofill/phone_number.h" |
| #include "base/basictypes.h" |
| +#include "base/string_number_conversions.h" |
| #include "base/string_util.h" |
| +#include "base/utf_string_conversions.h" |
| #include "chrome/browser/autofill/autofill_profile.h" |
| #include "chrome/browser/autofill/autofill_type.h" |
| #include "chrome/browser/autofill/field_types.h" |
| +#include "chrome/browser/autofill/phone_number_i18n.h" |
| namespace { |
| @@ -32,8 +35,14 @@ |
| } // namespace |
| -PhoneNumber::PhoneNumber() {} |
| +PhoneNumber::PhoneNumber() |
| + : phone_group_(AutofillType::NO_GROUP) { |
| +} |
| +PhoneNumber::PhoneNumber(AutofillType::FieldTypeGroup phone_group) |
| + : phone_group_(phone_group) { |
| +} |
| + |
| PhoneNumber::PhoneNumber(const PhoneNumber& number) : FormGroup() { |
| *this = number; |
| } |
| @@ -43,10 +52,9 @@ |
| PhoneNumber& PhoneNumber::operator=(const PhoneNumber& number) { |
| if (this == &number) |
| return *this; |
| - country_code_ = number.country_code_; |
| - city_code_ = number.city_code_; |
| number_ = number.number_; |
| extension_ = number.extension_; |
| + phone_group_ = number.phone_group_; |
| return *this; |
| } |
| @@ -54,59 +62,86 @@ |
| FieldTypeSet* matching_types) const { |
| string16 stripped_text(text); |
| StripPunctuation(&stripped_text); |
| - if (!Validate(stripped_text)) |
| + |
| + string16 number; |
| + string16 city_code; |
| + string16 country_code; |
| + // Full number - parse it, split it and re-combine into canonical form. |
| + if (!autofill_i18n::ParsePhoneNumber( |
| + number_, locale_, &country_code, &city_code, &number)) |
| return; |
| - if (IsNumber(stripped_text)) |
| + if (IsNumber(stripped_text, number)) |
| matching_types->insert(GetNumberType()); |
| - if (IsCityCode(stripped_text)) |
| + if (stripped_text == city_code) |
| matching_types->insert(GetCityCodeType()); |
| - if (IsCountryCode(stripped_text)) |
| + if (stripped_text == country_code) |
| matching_types->insert(GetCountryCodeType()); |
| - if (IsCityAndNumber(stripped_text)) |
| + city_code.append(number); |
| + if (stripped_text == city_code) |
| matching_types->insert(GetCityAndNumberType()); |
| - if (IsWholeNumber(stripped_text)) |
| + // Whole number is compared to unfiltered text - it would be parsed for phone |
| + // comparision (e.g. 1-800-FLOWERS and 18003569377 are the same) |
| + if (IsWholeNumber(text)) |
| matching_types->insert(GetWholeNumberType()); |
| } |
| -void PhoneNumber::GetNonEmptyTypes(FieldTypeSet* non_empty_typess) const { |
| - DCHECK(non_empty_typess); |
| +void PhoneNumber::GetNonEmptyTypes(FieldTypeSet* non_empty_types) const { |
| + DCHECK(non_empty_types); |
| - if (!number().empty()) |
| - non_empty_typess->insert(GetNumberType()); |
| + if (number().empty()) |
|
dhollowa
2011/05/19 23:35:02
Let's get rid of |number()|, |set_number()|, |exte
GeorgeY
2011/05/20 00:41:49
Yep, never used. Removed
|
| + return; |
| - if (!city_code().empty()) |
| - non_empty_typess->insert(GetCityCodeType()); |
| + non_empty_types->insert(GetWholeNumberType()); |
| - if (!country_code().empty()) |
| - non_empty_typess->insert(GetCountryCodeType()); |
| + string16 number; |
| + string16 city_code; |
| + string16 country_code; |
| + // Full number - parse it, split it and re-combine into canonical form. |
| + if (!autofill_i18n::ParsePhoneNumber( |
| + number_, locale_, &country_code, &city_code, &number)) |
| + return; |
| - if (!CityAndNumber().empty()) |
| - non_empty_typess->insert(GetCityAndNumberType()); |
| + non_empty_types->insert(GetNumberType()); |
| - if (!WholeNumber().empty()) |
| - non_empty_typess->insert(GetWholeNumberType()); |
| + if (!city_code.empty()) { |
| + non_empty_types->insert(GetCityCodeType()); |
| + non_empty_types->insert(GetCityAndNumberType()); |
| + } |
| + |
| + if (!country_code.empty()) |
| + non_empty_types->insert(GetCountryCodeType()); |
| } |
| string16 PhoneNumber::GetInfo(AutofillFieldType type) const { |
| - if (type == GetNumberType()) |
| + if (type == GetWholeNumberType()) |
| return number(); |
| + string16 number; |
| + string16 city_code; |
| + string16 country_code; |
| + // Full number - parse it, split it and re-combine into canonical form. |
| + if (!autofill_i18n::ParsePhoneNumber( |
| + number_, locale_, &country_code, &city_code, &number)) |
| + return string16(); |
| + |
| + if (type == GetNumberType()) |
| + return number; |
| + |
| if (type == GetCityCodeType()) |
| - return city_code(); |
| + return city_code; |
| if (type == GetCountryCodeType()) |
| - return country_code(); |
| + return country_code; |
| + city_code.append(number); |
| if (type == GetCityAndNumberType()) |
| - return CityAndNumber(); |
| + return city_code; |
| - if (type == GetWholeNumberType()) |
| - return WholeNumber(); |
|
dhollowa
2011/05/19 23:35:02
nit: remove extra line.
GeorgeY
2011/05/20 00:41:49
Done.
|
| return string16(); |
| } |
| @@ -114,134 +149,167 @@ |
| void PhoneNumber::SetInfo(AutofillFieldType type, const string16& value) { |
| string16 number(value); |
| StripPunctuation(&number); |
| - if (!Validate(number)) |
| - return; |
| FieldTypeSubGroup subgroup = AutofillType(type).subgroup(); |
| - if (subgroup == AutofillType::PHONE_NUMBER) |
| + FieldTypeGroup group = AutofillType(type).group(); |
| + if (phone_group_ == AutofillType::NO_GROUP) |
| + phone_group_ = group; // First call on empty phone - set the group. |
| + if (subgroup == AutofillType::PHONE_NUMBER) { |
| + // Should not be set directly. |
| + NOTREACHED(); |
| + } else if (subgroup == AutofillType::PHONE_CITY_CODE) { |
| + // Should not be set directly. |
| + NOTREACHED(); |
| + } else if (subgroup == AutofillType::PHONE_COUNTRY_CODE) { |
| + // Should not be set directly. |
| + NOTREACHED(); |
| + } else if (subgroup == AutofillType::PHONE_CITY_AND_NUMBER || |
| + subgroup == AutofillType::PHONE_WHOLE_NUMBER) { |
| set_number(number); |
| - else if (subgroup == AutofillType::PHONE_CITY_CODE) |
| - set_city_code(number); |
| - else if (subgroup == AutofillType::PHONE_COUNTRY_CODE) |
| - set_country_code(number); |
| - else if (subgroup == AutofillType::PHONE_CITY_AND_NUMBER || |
| - subgroup == AutofillType::PHONE_WHOLE_NUMBER) |
| - set_whole_number(number); |
| - else |
| + } else { |
| NOTREACHED(); |
| + } |
| } |
| -// Static. |
| -bool PhoneNumber::ParsePhoneNumber(const string16& value, |
| - string16* number, |
| - string16* city_code, |
| - string16* country_code) { |
| - DCHECK(number); |
| - DCHECK(city_code); |
| - DCHECK(country_code); |
| +bool PhoneNumber::NormalizePhone() { |
| + bool success = true; |
| + // Empty number does not need normalization. |
| + if (number_.empty()) |
| + return true; |
| - // Make a working copy of value. |
| - string16 working = value; |
| + string16 number; |
| + string16 city_code; |
| + string16 country_code; |
| + // Full number - parse it, split it and re-combine into canonical form. |
| + if (!autofill_i18n::ParsePhoneNumber( |
| + number_, locale_, &country_code, &city_code, &number) || |
| + !autofill_i18n::ConstructPhoneNumber( |
| + country_code, city_code, number, |
| + locale_, |
| + (country_code.empty() ? |
| + autofill_i18n::NATIONAL : autofill_i18n::INTERNATIONAL), |
| + &number_)) { |
| + // Parsing failed - do not store phone. |
| + number_.clear(); |
| + success = false; |
| + } |
| + number_ = autofill_i18n::NormalizePhoneNumber(number_); |
| + return success; |
| +} |
| - *number = string16(); |
| - *city_code = string16(); |
| - *country_code = string16(); |
| +void PhoneNumber::set_locale(const std::string& locale) { |
| + locale_ = locale; |
| +} |
| - // First remove any punctuation. |
| - StripPunctuation(&working); |
| +AutofillFieldType PhoneNumber::GetNumberType() const { |
| + if (phone_group_ == AutofillType::PHONE_HOME) |
| + return PHONE_HOME_NUMBER; |
| + else if (phone_group_ == AutofillType::PHONE_FAX) |
| + return PHONE_FAX_NUMBER; |
| + else |
| + NOTREACHED(); |
| + return UNKNOWN_TYPE; |
| +} |
| - if (working.size() < kPhoneNumberLength) |
| - return false; |
| +AutofillFieldType PhoneNumber::GetCityCodeType() const { |
| + if (phone_group_ == AutofillType::PHONE_HOME) |
| + return PHONE_HOME_CITY_CODE; |
| + else if (phone_group_ == AutofillType::PHONE_FAX) |
| + return PHONE_FAX_CITY_CODE; |
| + else |
| + NOTREACHED(); |
| + return UNKNOWN_TYPE; |
| +} |
| - // Treat the last 7 digits as the number. |
| - *number = working.substr(working.size() - kPhoneNumberLength, |
| - kPhoneNumberLength); |
| - working.resize(working.size() - kPhoneNumberLength); |
| - if (working.size() < kPhoneCityCodeLength) |
| - return true; |
| +AutofillFieldType PhoneNumber::GetCountryCodeType() const { |
| + if (phone_group_ == AutofillType::PHONE_HOME) |
| + return PHONE_HOME_COUNTRY_CODE; |
| + else if (phone_group_ == AutofillType::PHONE_FAX) |
| + return PHONE_FAX_COUNTRY_CODE; |
| + else |
| + NOTREACHED(); |
| + return UNKNOWN_TYPE; |
| +} |
| - // Treat the next three digits as the city code. |
| - *city_code = working.substr(working.size() - kPhoneCityCodeLength, |
| - kPhoneCityCodeLength); |
| - working.resize(working.size() - kPhoneCityCodeLength); |
| - if (working.empty()) |
| - return true; |
| +AutofillFieldType PhoneNumber::GetCityAndNumberType() const { |
| + if (phone_group_ == AutofillType::PHONE_HOME) |
| + return PHONE_HOME_CITY_AND_NUMBER; |
| + else if (phone_group_ == AutofillType::PHONE_FAX) |
| + return PHONE_FAX_CITY_AND_NUMBER; |
| + else |
| + NOTREACHED(); |
| + return UNKNOWN_TYPE; |
| +} |
| - // Treat any remaining digits as the country code. |
| - *country_code = working; |
| - return true; |
| +AutofillFieldType PhoneNumber::GetWholeNumberType() const { |
| + if (phone_group_ == AutofillType::PHONE_HOME) |
| + return PHONE_HOME_WHOLE_NUMBER; |
| + else if (phone_group_ == AutofillType::PHONE_FAX) |
| + return PHONE_FAX_WHOLE_NUMBER; |
| + else |
| + NOTREACHED(); |
| + return UNKNOWN_TYPE; |
| } |
| -string16 PhoneNumber::WholeNumber() const { |
| - string16 whole_number; |
| - if (!country_code_.empty()) |
| - whole_number.append(country_code_); |
| +bool PhoneNumber::PhoneCombineHelper::SetInfo(AutofillFieldType field_type, |
| + const string16& value) { |
| + PhoneNumber temp(phone_group_); |
| - if (!city_code_.empty()) |
| - whole_number.append(city_code_); |
| + if (field_type == temp.GetCountryCodeType()) { |
| + country_ = value; |
| + return true; |
| + } else if (field_type == temp.GetCityCodeType()) { |
| + city_ = value; |
| + return true; |
| + } else if (field_type == temp.GetCityAndNumberType()) { |
| + phone_ = value; |
| + return true; |
| + } else if (field_type == temp.GetNumberType()) { |
| + phone_.append(value); |
| + return true; |
| + } else { |
| + return false; |
| + } |
| +} |
| - if (!number_.empty()) |
| - whole_number.append(number_); |
| - |
| - return whole_number; |
| +bool PhoneNumber::PhoneCombineHelper::ParseNumber(const std::string& locale, |
| + string16* value) { |
| + DCHECK(value); |
| + return autofill_i18n::ConstructPhoneNumber( |
| + country_, city_, phone_, |
| + locale, |
| + (country_.empty() ? |
| + autofill_i18n::NATIONAL : autofill_i18n::INTERNATIONAL), |
| + value); |
| } |
| void PhoneNumber::set_number(const string16& number) { |
| - string16 digits(number); |
| - StripPunctuation(&digits); |
| - number_ = digits; |
| + number_ = number; |
| } |
| -void PhoneNumber::set_whole_number(const string16& whole_number) { |
| - string16 number, city_code, country_code; |
| - ParsePhoneNumber(whole_number, &number, &city_code, &country_code); |
| - set_number(number); |
| - set_city_code(city_code); |
| - set_country_code(country_code); |
| -} |
| - |
| -bool PhoneNumber::IsNumber(const string16& text) const { |
| - // TODO(isherman): This will need to be updated once we add support for |
| +bool PhoneNumber::IsNumber(const string16& text, const string16& number) const { |
| + // TODO(georgey): This will need to be updated once we add support for |
|
dhollowa
2011/05/19 23:35:02
I'm confused by this comment. What further work i
GeorgeY
2011/05/20 00:41:49
Not only, some other countries support the splitti
|
| // international phone numbers. |
| const size_t kPrefixLength = 3; |
| const size_t kSuffixLength = 4; |
| - if (text == number_) |
| + if (text == number) |
| return true; |
| - if (text.length() == kPrefixLength && StartsWith(number_, text, true)) |
| + if (text.length() == kPrefixLength && StartsWith(number, text, true)) |
| return true; |
| - if (text.length() == kSuffixLength && EndsWith(number_, text, true)) |
| + if (text.length() == kSuffixLength && EndsWith(number, text, true)) |
| return true; |
| return false; |
| } |
| -bool PhoneNumber::IsCityCode(const string16& text) const { |
| - return text == city_code_; |
| -} |
| - |
| -bool PhoneNumber::IsCountryCode(const string16& text) const { |
| - return text == country_code_; |
| -} |
| - |
| -bool PhoneNumber::IsCityAndNumber(const string16& text) const { |
| - return text == CityAndNumber(); |
| -} |
| - |
| bool PhoneNumber::IsWholeNumber(const string16& text) const { |
| - return text == WholeNumber(); |
| + return autofill_i18n::ComparePhones(text, number_, locale_) == |
| + autofill_i18n::PHONES_EQUAL; |
| } |
| -bool PhoneNumber::Validate(const string16& number) const { |
| - for (size_t i = 0; i < number.length(); ++i) { |
| - if (!IsAsciiDigit(number[i])) |
| - return false; |
| - } |
| - |
| - return true; |
| -} |
| - |
| // Static. |
| void PhoneNumber::StripPunctuation(string16* number) { |
| RemoveChars(*number, kPhoneNumberSeparators, number); |
| } |
| + |