Chromium Code Reviews| Index: components/autofill/core/browser/address_combobox_model.cc |
| diff --git a/components/autofill/core/browser/address_combobox_model.cc b/components/autofill/core/browser/address_combobox_model.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..0f2d5b13e89e73be47943a4b94b232a38ff49b54 |
| --- /dev/null |
| +++ b/components/autofill/core/browser/address_combobox_model.cc |
| @@ -0,0 +1,140 @@ |
| +// Copyright 2017 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "components/autofill/core/browser/address_combobox_model.h" |
| + |
| +#include "base/memory/ptr_util.h" |
| +#include "base/strings/utf_string_conversions.h" |
| +#include "components/autofill/core/browser/autofill_profile.h" |
| +#include "components/autofill/core/browser/personal_data_manager.h" |
| +#include "components/strings/grit/components_strings.h" |
| +#include "ui/base/l10n/l10n_util.h" |
| +#include "ui/base/models/combobox_model_observer.h" |
| +#include "ui/gfx/text_elider.h" |
| + |
| +namespace autofill { |
| + |
| +namespace { |
| +// There's one header entry to prompt the user to select an address, and a |
| +// separator. |
| +int kNbHeaderEntries = 2; |
| +} // namespace |
| + |
| +AddressComboboxModel::AddressComboboxModel( |
| + const PersonalDataManager& personal_data_manager, |
| + const std::string& app_locale) |
| + : app_locale_(app_locale) { |
| + for (const auto* profile : personal_data_manager.GetProfilesToSuggest()) { |
| + profiles_cache_.push_back(base::MakeUnique<AutofillProfile>(*profile)); |
| + } |
| + UpdateAddresses(); |
| +} |
| + |
| +AddressComboboxModel::~AddressComboboxModel() {} |
| + |
| +int AddressComboboxModel::GetItemCount() const { |
| + // When there are not addresses, a special entry is shown to prompt the user |
| + // to add addresses, but nothing else is shown, since there are no address to |
| + // select from, and no need for a separator. |
| + if (addresses_.size() == 0) |
| + return 1; |
| + // If there are addresses to choose from, but none is selected, add extra |
| + // items for the "Select" entry and a separator. |
| + return addresses_.size() + kNbHeaderEntries; |
| +} |
| + |
| +base::string16 AddressComboboxModel::GetItemAt(int index) { |
| + DCHECK_GE(index, 0); |
| + // A special entry is always added at index 0 and a separator at index 1. |
| + DCHECK_LT(static_cast<size_t>(index), addresses_.size() + kNbHeaderEntries); |
| + |
| + // Special entry when no profiles have been created yet. |
| + if (addresses_.empty()) |
| + return l10n_util::GetStringUTF16(IDS_AUTOFILL_ADD_BILLING_ADDRESS); |
| + |
| + // Always show the "Select" entry at the top, default selection position. |
| + if (index == 0) |
| + return l10n_util::GetStringUTF16(IDS_AUTOFILL_SELECT); |
| + |
| + // Always show the "Select" entry at the top, default selection position. |
| + if (index == 1) |
| + return base::ASCIIToUTF16("---"); |
| + |
| + return addresses_[index - kNbHeaderEntries].second; |
| +} |
| + |
| +bool AddressComboboxModel::IsItemSeparatorAt(int index) { |
| + // The only separator is between the "Select" entry at 0 and the first address |
| + // at index 2. So there must be at least one address for a separator to be |
| + // shown. |
| + DCHECK(index <= kNbHeaderEntries || !addresses_.empty()); |
| + return index == 1; |
| +} |
| + |
| +void AddressComboboxModel::AddObserver(ui::ComboboxModelObserver* observer) { |
| + observers_.AddObserver(observer); |
| +} |
| + |
| +void AddressComboboxModel::RemoveObserver(ui::ComboboxModelObserver* observer) { |
| + observers_.RemoveObserver(observer); |
| +} |
| + |
| +int AddressComboboxModel::AddNewProfile(const AutofillProfile& profile) { |
| + profiles_cache_.push_back(base::MakeUnique<AutofillProfile>(profile)); |
| + UpdateAddresses(); |
| + DCHECK_GT(addresses_.size(), 0UL); |
| + return addresses_.size() + kNbHeaderEntries - 1; |
| +} |
| + |
| +std::string AddressComboboxModel::GetItemIdentifierAt(int index) { |
| + // The first two indices are special entries, with no addresses. |
| + if (index < kNbHeaderEntries) |
| + return std::string(); |
| + DCHECK_LT(static_cast<size_t>(index), addresses_.size() + kNbHeaderEntries); |
| + return addresses_[index - kNbHeaderEntries].first; |
| +} |
| + |
| +int AddressComboboxModel::GetIndexOfIdentifier(const std::string& identifier) { |
| + for (size_t i = 0; i < addresses_.size(); ++i) { |
| + if (addresses_[i].first == identifier) |
| + return i + kNbHeaderEntries; |
| + } |
| + return -1; |
| +} |
| + |
| +void AddressComboboxModel::UpdateAddresses() { |
| + addresses_.clear(); |
| + std::vector<base::string16> labels; |
| + // CreateDifferentiatingLabels is expecting a pointer vector and we keep |
| + // profiles as unique_ptr. |
| + std::vector<AutofillProfile*> profiles; |
| + for (const auto& profile : profiles_cache_) { |
| + profiles.push_back(profile.get()); |
| + } |
| + AutofillProfile::CreateDifferentiatingLabels(profiles, app_locale_, &labels); |
| + DCHECK_EQ(labels.size(), profiles_cache_.size()); |
| + |
| + for (size_t i = 0; i < profiles_cache_.size(); ++i) { |
| + // Skip showing auxiliary profiles (e.g. Mac Contacts). |
| + if (profiles_cache_[i]->record_type() == AutofillProfile::AUXILIARY_PROFILE) |
| + continue; |
| + |
| + base::string16 label(labels[i]); |
| + if (label.size() > 20) { |
| + // gfx::StringSlicer keeps a references to the string16. |
| + base::string16 ellipsis(base::ASCIIToUTF16("...")); |
|
Mathieu
2017/05/04 20:29:19
There appears to be kEllipsisUTF16 already defined
MAD
2017/05/05 00:50:07
ElideText requires a font list which we don't have
Mathieu
2017/05/05 13:51:33
I find this "cutting to 20" a bit weird, I'm not s
Mathieu
2017/05/05 13:59:07
Also I've asked Anthony and gfx::ElideRectangleTex
MAD
2017/05/05 18:32:34
I talked to Anthony and we found this simpler solu
|
| + gfx::StringSlicer slicer(label, |
| + /*ellipsis=*/ellipsis, |
| + /*elide_in_middle=*/false, |
| + /*elide_at_beginning=*/false); |
| + label = slicer.CutString(20, /*insert_ellipsis=*/true); |
| + } |
| + addresses_.push_back(std::make_pair(profiles_cache_[i]->guid(), label)); |
| + } |
| + |
| + for (auto& observer : observers_) { |
| + observer.OnComboboxModelChanged(this); |
| + } |
| +} |
| +} // namespace autofill |