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 |