| OLD | NEW |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 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/ui/views/payments/shipping_address_editor_view_controll
er.h" | 5 #include "chrome/browser/ui/views/payments/shipping_address_editor_view_controll
er.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 #include <string> | 8 #include <string> |
| 9 #include <utility> | 9 #include <utility> |
| 10 #include <vector> | 10 #include <vector> |
| 11 | 11 |
| 12 #include "base/bind.h" | 12 #include "base/bind.h" |
| 13 #include "base/bind_helpers.h" | 13 #include "base/bind_helpers.h" |
| 14 #include "base/location.h" | 14 #include "base/location.h" |
| 15 #include "base/memory/ptr_util.h" | 15 #include "base/memory/ptr_util.h" |
| 16 #include "base/single_thread_task_runner.h" | 16 #include "base/single_thread_task_runner.h" |
| 17 #include "base/strings/string16.h" | 17 #include "base/strings/string16.h" |
| 18 #include "base/strings/utf_string_conversions.h" | 18 #include "base/strings/utf_string_conversions.h" |
| 19 #include "base/threading/thread_task_runner_handle.h" | 19 #include "base/threading/thread_task_runner_handle.h" |
| 20 #include "chrome/browser/autofill/validation_rules_storage_factory.h" | |
| 21 #include "chrome/browser/profiles/profile.h" | 20 #include "chrome/browser/profiles/profile.h" |
| 22 #include "chrome/browser/ui/views/payments/payment_request_dialog_view.h" | 21 #include "chrome/browser/ui/views/payments/payment_request_dialog_view.h" |
| 23 #include "chrome/browser/ui/views/payments/validating_combobox.h" | 22 #include "chrome/browser/ui/views/payments/validating_combobox.h" |
| 24 #include "chrome/browser/ui/views/payments/validating_textfield.h" | 23 #include "chrome/browser/ui/views/payments/validating_textfield.h" |
| 25 #include "chrome/grit/generated_resources.h" | 24 #include "chrome/grit/generated_resources.h" |
| 26 #include "components/autofill/core/browser/autofill_address_util.h" | 25 #include "components/autofill/core/browser/autofill_address_util.h" |
| 27 #include "components/autofill/core/browser/autofill_country.h" | 26 #include "components/autofill/core/browser/autofill_country.h" |
| 28 #include "components/autofill/core/browser/autofill_type.h" | 27 #include "components/autofill/core/browser/autofill_type.h" |
| 29 #include "components/autofill/core/browser/country_combobox_model.h" | 28 #include "components/autofill/core/browser/country_combobox_model.h" |
| 30 #include "components/autofill/core/browser/field_types.h" | 29 #include "components/autofill/core/browser/field_types.h" |
| 31 #include "components/autofill/core/browser/personal_data_manager.h" | 30 #include "components/autofill/core/browser/personal_data_manager.h" |
| 32 #include "components/autofill/core/browser/region_combobox_model.h" | 31 #include "components/autofill/core/browser/region_combobox_model.h" |
| 33 #include "components/autofill/core/browser/validation.h" | 32 #include "components/autofill/core/browser/validation.h" |
| 34 #include "components/autofill/core/common/autofill_constants.h" | 33 #include "components/autofill/core/common/autofill_constants.h" |
| 35 #include "components/payments/content/payment_request_state.h" | 34 #include "components/payments/content/payment_request_state.h" |
| 36 #include "components/strings/grit/components_strings.h" | 35 #include "components/strings/grit/components_strings.h" |
| 37 #include "content/public/browser/web_contents.h" | 36 #include "content/public/browser/web_contents.h" |
| 38 #include "third_party/libaddressinput/chromium/chrome_metadata_source.h" | |
| 39 #include "third_party/libaddressinput/chromium/chrome_storage_impl.h" | |
| 40 #include "third_party/libaddressinput/messages.h" | 37 #include "third_party/libaddressinput/messages.h" |
| 41 #include "ui/base/l10n/l10n_util.h" | 38 #include "ui/base/l10n/l10n_util.h" |
| 42 #include "ui/views/controls/textfield/textfield.h" | 39 #include "ui/views/controls/textfield/textfield.h" |
| 43 | 40 |
| 44 namespace payments { | 41 namespace payments { |
| 45 | 42 |
| 46 namespace { | 43 namespace { |
| 47 | 44 |
| 48 // Converts a field type in string format as returned by | 45 // Converts a field type in string format as returned by |
| 49 // autofill::GetAddressComponents into the appropriate autofill::ServerFieldType | 46 // autofill::GetAddressComponents into the appropriate autofill::ServerFieldType |
| (...skipping 21 matching lines...) Expand all Loading... |
| 71 return autofill::UNKNOWN_TYPE; | 68 return autofill::UNKNOWN_TYPE; |
| 72 } | 69 } |
| 73 | 70 |
| 74 } // namespace | 71 } // namespace |
| 75 | 72 |
| 76 ShippingAddressEditorViewController::ShippingAddressEditorViewController( | 73 ShippingAddressEditorViewController::ShippingAddressEditorViewController( |
| 77 PaymentRequestSpec* spec, | 74 PaymentRequestSpec* spec, |
| 78 PaymentRequestState* state, | 75 PaymentRequestState* state, |
| 79 PaymentRequestDialogView* dialog, | 76 PaymentRequestDialogView* dialog, |
| 80 autofill::AutofillProfile* profile) | 77 autofill::AutofillProfile* profile) |
| 81 : EditorViewController(spec, state, dialog), profile_to_edit_(profile) { | 78 : EditorViewController(spec, state, dialog), |
| 79 profile_to_edit_(profile), |
| 80 chosen_country_index_(0), |
| 81 failed_to_load_region_data_(false) { |
| 82 UpdateEditorFields(); | 82 UpdateEditorFields(); |
| 83 } | 83 } |
| 84 | 84 |
| 85 ShippingAddressEditorViewController::~ShippingAddressEditorViewController() {} | 85 ShippingAddressEditorViewController::~ShippingAddressEditorViewController() {} |
| 86 | 86 |
| 87 std::unique_ptr<views::View> | 87 std::unique_ptr<views::View> |
| 88 ShippingAddressEditorViewController::CreateHeaderView() { | 88 ShippingAddressEditorViewController::CreateHeaderView() { |
| 89 return base::MakeUnique<views::View>(); | 89 return base::MakeUnique<views::View>(); |
| 90 } | 90 } |
| 91 | 91 |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 181 model->SetCountries(*state()->GetPersonalDataManager(), | 181 model->SetCountries(*state()->GetPersonalDataManager(), |
| 182 base::Callback<bool(const std::string&)>(), | 182 base::Callback<bool(const std::string&)>(), |
| 183 state()->GetApplicationLocale()); | 183 state()->GetApplicationLocale()); |
| 184 country_codes_.clear(); | 184 country_codes_.clear(); |
| 185 for (size_t i = 0; i < model->countries().size(); ++i) { | 185 for (size_t i = 0; i < model->countries().size(); ++i) { |
| 186 if (model->countries()[i].get()) | 186 if (model->countries()[i].get()) |
| 187 country_codes_.push_back(model->countries()[i]->country_code()); | 187 country_codes_.push_back(model->countries()[i]->country_code()); |
| 188 else | 188 else |
| 189 country_codes_.push_back(""); // Separator. | 189 country_codes_.push_back(""); // Separator. |
| 190 } | 190 } |
| 191 return std::unique_ptr<ui::ComboboxModel>(model.release()); | 191 return std::move(model); |
| 192 } | 192 } |
| 193 case autofill::ADDRESS_HOME_STATE: { | 193 case autofill::ADDRESS_HOME_STATE: { |
| 194 return std::unique_ptr< | 194 std::unique_ptr<autofill::RegionComboboxModel> model = |
| 195 ui::ComboboxModel>(new autofill::RegionComboboxModel( | 195 base::MakeUnique<autofill::RegionComboboxModel>( |
| 196 base::WrapUnique(new autofill::ChromeMetadataSource( | 196 state()->GetAddressInputSource(), |
| 197 I18N_ADDRESS_VALIDATION_DATA_URL, | 197 state()->GetAddressInputStorage(), |
| 198 state()->GetPersonalDataManager()->GetURLRequestContextGetter())), | 198 state()->GetApplicationLocale(), |
| 199 autofill::ValidationRulesStorageFactory::CreateStorage(), | 199 country_codes_[chosen_country_index_]); |
| 200 state()->GetApplicationLocale(), | 200 // If the data was already pre-loaded, the observer won't get notified so |
| 201 country_codes_[chosen_country_index_])); | 201 // we have to check for failure here. |
| 202 if (!model->pending_region_data_load()) { |
| 203 failed_to_load_region_data_ = model->failed_to_load_data(); |
| 204 if (failed_to_load_region_data_) |
| 205 OnDataChanged(); |
| 206 } |
| 207 return std::move(model); |
| 202 } | 208 } |
| 203 default: | 209 default: |
| 204 NOTREACHED(); | 210 NOTREACHED(); |
| 205 break; | 211 break; |
| 206 } | 212 } |
| 207 return std::unique_ptr<ui::ComboboxModel>(); | 213 return std::unique_ptr<ui::ComboboxModel>(); |
| 208 } | 214 } |
| 209 | 215 |
| 210 void ShippingAddressEditorViewController::OnPerformAction( | 216 void ShippingAddressEditorViewController::OnPerformAction( |
| 211 views::Combobox* sender) { | 217 views::Combobox* sender) { |
| 212 EditorViewController::OnPerformAction(sender); | 218 EditorViewController::OnPerformAction(sender); |
| 213 if (sender->id() != autofill::ADDRESS_HOME_COUNTRY) | 219 if (sender->id() != autofill::ADDRESS_HOME_COUNTRY) |
| 214 return; | 220 return; |
| 215 DCHECK_GE(sender->selected_index(), 0); | 221 DCHECK_GE(sender->selected_index(), 0); |
| 216 if (chosen_country_index_ != static_cast<size_t>(sender->selected_index())) { | 222 if (chosen_country_index_ != static_cast<size_t>(sender->selected_index())) { |
| 217 chosen_country_index_ = sender->selected_index(); | 223 chosen_country_index_ = sender->selected_index(); |
| 218 OnCountryChanged(sender); | 224 failed_to_load_region_data_ = false; |
| 225 OnDataChanged(); |
| 219 } | 226 } |
| 220 } | 227 } |
| 221 | 228 |
| 222 void ShippingAddressEditorViewController::UpdateEditorView() { | 229 void ShippingAddressEditorViewController::UpdateEditorView() { |
| 223 EditorViewController::UpdateEditorView(); | 230 EditorViewController::UpdateEditorView(); |
| 224 if (chosen_country_index_ > 0UL) { | 231 if (chosen_country_index_ > 0UL) { |
| 225 views::Combobox* country_combo_box = static_cast<views::Combobox*>( | 232 views::Combobox* country_combo_box = static_cast<views::Combobox*>( |
| 226 dialog()->GetViewByID(autofill::ADDRESS_HOME_COUNTRY)); | 233 dialog()->GetViewByID(autofill::ADDRESS_HOME_COUNTRY)); |
| 227 DCHECK(country_combo_box); | 234 DCHECK(country_combo_box); |
| 228 country_combo_box->SetSelectedIndex(chosen_country_index_); | 235 country_combo_box->SetSelectedIndex(chosen_country_index_); |
| 229 } | 236 } |
| 230 } | 237 } |
| 231 | 238 |
| 232 base::string16 ShippingAddressEditorViewController::GetSheetTitle() { | 239 base::string16 ShippingAddressEditorViewController::GetSheetTitle() { |
| 233 return l10n_util::GetStringUTF16( | 240 return l10n_util::GetStringUTF16( |
| 234 IDS_PAYMENT_REQUEST_ADDRESS_EDITOR_ADD_TITLE); | 241 IDS_PAYMENT_REQUEST_ADDRESS_EDITOR_ADD_TITLE); |
| 235 } | 242 } |
| 236 | 243 |
| 237 void ShippingAddressEditorViewController::UpdateEditorFields() { | 244 void ShippingAddressEditorViewController::UpdateEditorFields() { |
| 238 editor_fields_.clear(); | 245 editor_fields_.clear(); |
| 239 std::string chosen_country_code; | 246 std::string chosen_country_code; |
| 240 if (chosen_country_index_ < country_codes_.size()) | 247 if (chosen_country_index_ < country_codes_.size()) |
| 241 chosen_country_code = country_codes_[chosen_country_index_]; | 248 chosen_country_code = country_codes_[chosen_country_index_]; |
| 242 | 249 |
| 243 std::unique_ptr<base::ListValue> components(new base::ListValue); | 250 std::unique_ptr<base::ListValue> components(new base::ListValue); |
| 244 std::string unused; | 251 std::string unused; |
| 245 autofill::GetAddressComponents(chosen_country_code, | 252 autofill::GetAddressComponents(chosen_country_code, |
| 246 state()->GetApplicationLocale(), | 253 state()->GetApplicationLocale(), |
| 247 components.get(), &unused); | 254 components.get(), &unused); |
| 248 | |
| 249 for (size_t line_index = 0; line_index < components->GetSize(); | 255 for (size_t line_index = 0; line_index < components->GetSize(); |
| 250 ++line_index) { | 256 ++line_index) { |
| 251 const base::ListValue* line = nullptr; | 257 const base::ListValue* line = nullptr; |
| 252 if (!components->GetList(line_index, &line)) { | 258 if (!components->GetList(line_index, &line)) { |
| 253 NOTREACHED(); | 259 NOTREACHED(); |
| 254 return; | 260 return; |
| 255 } | 261 } |
| 256 DCHECK_NE(nullptr, line); | 262 DCHECK_NE(nullptr, line); |
| 257 for (size_t component_index = 0; component_index < line->GetSize(); | 263 for (size_t component_index = 0; component_index < line->GetSize(); |
| 258 ++component_index) { | 264 ++component_index) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 279 EditorField::LengthHint length_hint = EditorField::LengthHint::HINT_LONG; | 285 EditorField::LengthHint length_hint = EditorField::LengthHint::HINT_LONG; |
| 280 if (field_length == autofill::kShortField) | 286 if (field_length == autofill::kShortField) |
| 281 length_hint = EditorField::LengthHint::HINT_SHORT; | 287 length_hint = EditorField::LengthHint::HINT_SHORT; |
| 282 else | 288 else |
| 283 DCHECK_EQ(autofill::kLongField, field_length); | 289 DCHECK_EQ(autofill::kLongField, field_length); |
| 284 autofill::ServerFieldType server_field_type = | 290 autofill::ServerFieldType server_field_type = |
| 285 GetFieldTypeFromString(field_type); | 291 GetFieldTypeFromString(field_type); |
| 286 EditorField::ControlType control_type = | 292 EditorField::ControlType control_type = |
| 287 EditorField::ControlType::TEXTFIELD; | 293 EditorField::ControlType::TEXTFIELD; |
| 288 if (server_field_type == autofill::ADDRESS_HOME_COUNTRY || | 294 if (server_field_type == autofill::ADDRESS_HOME_COUNTRY || |
| 289 server_field_type == autofill::ADDRESS_HOME_STATE) { | 295 (server_field_type == autofill::ADDRESS_HOME_STATE && |
| 296 !failed_to_load_region_data_)) { |
| 290 control_type = EditorField::ControlType::COMBOBOX; | 297 control_type = EditorField::ControlType::COMBOBOX; |
| 291 } | 298 } |
| 292 editor_fields_.emplace_back( | 299 editor_fields_.emplace_back( |
| 293 server_field_type, base::UTF8ToUTF16(field_name), length_hint, | 300 server_field_type, base::UTF8ToUTF16(field_name), length_hint, |
| 294 /*required=*/server_field_type != autofill::COMPANY_NAME, | 301 /*required=*/server_field_type != autofill::COMPANY_NAME, |
| 295 control_type); | 302 control_type); |
| 296 // Insert the Country combobox right after NAME_FULL. | 303 // Insert the Country combobox right after NAME_FULL. |
| 297 if (server_field_type == autofill::NAME_FULL) { | 304 if (server_field_type == autofill::NAME_FULL) { |
| 298 editor_fields_.emplace_back( | 305 editor_fields_.emplace_back( |
| 299 autofill::ADDRESS_HOME_COUNTRY, | 306 autofill::ADDRESS_HOME_COUNTRY, |
| 300 l10n_util::GetStringUTF16( | 307 l10n_util::GetStringUTF16( |
| 301 IDS_LIBADDRESSINPUT_COUNTRY_OR_REGION_LABEL), | 308 IDS_LIBADDRESSINPUT_COUNTRY_OR_REGION_LABEL), |
| 302 EditorField::LengthHint::HINT_LONG, /*required=*/true, | 309 EditorField::LengthHint::HINT_LONG, /*required=*/true, |
| 303 EditorField::ControlType::COMBOBOX); | 310 EditorField::ControlType::COMBOBOX); |
| 304 } | 311 } |
| 305 } | 312 } |
| 306 } | 313 } |
| 307 // Always add phone number at the end. | 314 // Always add phone number at the end. |
| 308 editor_fields_.emplace_back( | 315 editor_fields_.emplace_back( |
| 309 autofill::PHONE_HOME_NUMBER, | 316 autofill::PHONE_HOME_NUMBER, |
| 310 l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_PHONE), | 317 l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_PHONE), |
| 311 EditorField::LengthHint::HINT_LONG, /*required=*/false, | 318 EditorField::LengthHint::HINT_LONG, /*required=*/false, |
| 312 EditorField::ControlType::TEXTFIELD); | 319 EditorField::ControlType::TEXTFIELD); |
| 313 } | 320 } |
| 314 | 321 |
| 315 void ShippingAddressEditorViewController::OnCountryChanged( | 322 void ShippingAddressEditorViewController::OnDataChanged() { |
| 316 views::Combobox* combobox) { | |
| 317 // TODO(crbug.com/703764): save the current state so we can map it to the new | 323 // TODO(crbug.com/703764): save the current state so we can map it to the new |
| 318 // country fields as best we can. | 324 // country fields as best we can. |
| 319 UpdateEditorFields(); | 325 UpdateEditorFields(); |
| 320 | 326 |
| 321 // The editor can't be updated while in the middle of a combobox event. | 327 // The editor can't be updated while in the middle of a combobox event. |
| 322 base::ThreadTaskRunnerHandle::Get()->PostTask( | 328 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 323 FROM_HERE, | 329 FROM_HERE, |
| 324 base::Bind(&ShippingAddressEditorViewController::UpdateEditorView, | 330 base::Bind(&ShippingAddressEditorViewController::UpdateEditorView, |
| 325 base::Unretained(this))); | 331 base::Unretained(this))); |
| 326 } | 332 } |
| 327 | 333 |
| 334 void ShippingAddressEditorViewController::OnComboboxModelChanged( |
| 335 views::Combobox* combobox) { |
| 336 if (combobox->id() != autofill::ADDRESS_HOME_STATE) |
| 337 return; |
| 338 autofill::RegionComboboxModel* model = |
| 339 static_cast<autofill::RegionComboboxModel*>(combobox->model()); |
| 340 if (model->pending_region_data_load()) |
| 341 return; |
| 342 if (model->failed_to_load_data()) { |
| 343 failed_to_load_region_data_ = true; |
| 344 OnDataChanged(); |
| 345 } |
| 346 } |
| 347 |
| 328 ShippingAddressEditorViewController::ShippingAddressValidationDelegate:: | 348 ShippingAddressEditorViewController::ShippingAddressValidationDelegate:: |
| 329 ShippingAddressValidationDelegate( | 349 ShippingAddressValidationDelegate( |
| 330 ShippingAddressEditorViewController* controller, | 350 ShippingAddressEditorViewController* controller, |
| 331 const EditorField& field) | 351 const EditorField& field) |
| 332 : field_(field), controller_(controller) {} | 352 : field_(field), controller_(controller) {} |
| 333 | 353 |
| 334 ShippingAddressEditorViewController::ShippingAddressValidationDelegate:: | 354 ShippingAddressEditorViewController::ShippingAddressValidationDelegate:: |
| 335 ~ShippingAddressValidationDelegate() {} | 355 ~ShippingAddressValidationDelegate() {} |
| 336 | 356 |
| 337 bool ShippingAddressEditorViewController::ShippingAddressValidationDelegate:: | 357 bool ShippingAddressEditorViewController::ShippingAddressValidationDelegate:: |
| 338 ValidateTextfield(views::Textfield* textfield) { | 358 ValidateTextfield(views::Textfield* textfield) { |
| 339 return ValidateValue(textfield->text()); | 359 return ValidateValue(textfield->text()); |
| 340 } | 360 } |
| 341 | 361 |
| 342 bool ShippingAddressEditorViewController::ShippingAddressValidationDelegate:: | 362 bool ShippingAddressEditorViewController::ShippingAddressValidationDelegate:: |
| 343 ValidateCombobox(views::Combobox* combobox) { | 363 ValidateCombobox(views::Combobox* combobox) { |
| 344 return ValidateValue(combobox->GetTextForRow(combobox->selected_index())); | 364 return ValidateValue(combobox->GetTextForRow(combobox->selected_index())); |
| 345 } | 365 } |
| 346 | 366 |
| 367 void ShippingAddressEditorViewController::ShippingAddressValidationDelegate:: |
| 368 ComboboxModelChanged(views::Combobox* combobox) { |
| 369 controller_->OnComboboxModelChanged(combobox); |
| 370 } |
| 371 |
| 347 bool ShippingAddressEditorViewController::ShippingAddressValidationDelegate:: | 372 bool ShippingAddressEditorViewController::ShippingAddressValidationDelegate:: |
| 348 ValidateValue(const base::string16& value) { | 373 ValidateValue(const base::string16& value) { |
| 349 if (!value.empty()) { | 374 if (!value.empty()) { |
| 350 if (field_.type == autofill::PHONE_HOME_NUMBER && | 375 if (field_.type == autofill::PHONE_HOME_NUMBER && |
| 351 !autofill::IsValidPhoneNumber( | 376 !autofill::IsValidPhoneNumber( |
| 352 value, | 377 value, |
| 353 controller_->country_codes_[controller_->chosen_country_index_])) { | 378 controller_->country_codes_[controller_->chosen_country_index_])) { |
| 354 controller_->DisplayErrorMessageForField( | 379 controller_->DisplayErrorMessageForField( |
| 355 field_, l10n_util::GetStringUTF16( | 380 field_, l10n_util::GetStringUTF16( |
| 356 IDS_PAYMENTS_PHONE_INVALID_VALIDATION_MESSAGE)); | 381 IDS_PAYMENTS_PHONE_INVALID_VALIDATION_MESSAGE)); |
| 357 return false; | 382 return false; |
| 358 } | 383 } |
| 359 // As long as other field types are non-empty, they are valid. | 384 // As long as other field types are non-empty, they are valid. |
| 360 controller_->DisplayErrorMessageForField(field_, base::ASCIIToUTF16("")); | 385 controller_->DisplayErrorMessageForField(field_, base::ASCIIToUTF16("")); |
| 361 return true; | 386 return true; |
| 362 } | 387 } |
| 363 | 388 |
| 364 bool is_required_valid = !field_.required; | 389 bool is_required_valid = !field_.required; |
| 365 const base::string16 displayed_message = | 390 const base::string16 displayed_message = |
| 366 is_required_valid ? base::ASCIIToUTF16("") | 391 is_required_valid ? base::ASCIIToUTF16("") |
| 367 : l10n_util::GetStringUTF16( | 392 : l10n_util::GetStringUTF16( |
| 368 IDS_PAYMENTS_FIELD_REQUIRED_VALIDATION_MESSAGE); | 393 IDS_PAYMENTS_FIELD_REQUIRED_VALIDATION_MESSAGE); |
| 369 controller_->DisplayErrorMessageForField(field_, displayed_message); | 394 controller_->DisplayErrorMessageForField(field_, displayed_message); |
| 370 return is_required_valid; | 395 return is_required_valid; |
| 371 } | 396 } |
| 372 | 397 |
| 373 } // namespace payments | 398 } // namespace payments |
| OLD | NEW |