Chromium Code Reviews| Index: chrome/browser/ui/autofill/generated_credit_card_bubble_controller.cc |
| diff --git a/chrome/browser/ui/autofill/generated_credit_card_bubble_controller.cc b/chrome/browser/ui/autofill/generated_credit_card_bubble_controller.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..50bca85b11a8175a00ed24ae021ba7ebdf31b417 |
| --- /dev/null |
| +++ b/chrome/browser/ui/autofill/generated_credit_card_bubble_controller.cc |
| @@ -0,0 +1,263 @@ |
| +// Copyright 2013 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 "chrome/browser/ui/autofill/generated_credit_card_bubble_controller.h" |
| + |
| +#include <climits> |
| + |
| +#include "base/logging.h" |
| +#include "base/prefs/pref_service.h" |
| +#include "base/strings/string_split.h" |
| +#include "base/strings/utf_string_conversions.h" |
| +#include "chrome/browser/profiles/profile.h" |
| +#include "chrome/browser/ui/autofill/generated_credit_card_bubble.h" |
| +#include "chrome/browser/ui/autofill/tab_autofill_manager_delegate.h" |
| +#include "chrome/browser/ui/browser_finder.h" |
| +#include "chrome/browser/ui/browser_navigator.h" |
| +#include "chrome/browser/ui/browser_window.h" |
| +#include "chrome/browser/ui/omnibox/location_bar.h" |
| +#include "chrome/browser/ui/tabs/tab_strip_model.h" |
| +#include "chrome/common/pref_names.h" |
| +#include "components/user_prefs/pref_registry_syncable.h" |
| +#include "content/public/browser/navigation_details.h" |
| +#include "content/public/browser/navigation_entry.h" |
| +#include "content/public/browser/web_contents.h" |
| +#include "grit/generated_resources.h" |
| +#include "grit/theme_resources.h" |
| +#include "ui/base/l10n/l10n_util.h" |
| +#include "ui/base/resource/resource_bundle.h" |
| + |
| +DEFINE_WEB_CONTENTS_USER_DATA_KEY( |
| + autofill::GeneratedCreditCardBubbleController); |
| + |
| +namespace autofill { |
| + |
| +namespace { |
| + |
| +static const int kMaxGeneratedCardTimesToShow = INT_MAX; |
| +static const base::char16 kRangeSeparator = '|'; |
| +static const char kWalletGeneratedCardLearnMoreLink[] = |
| + "http://support.google.com/wallet/bin/answer.py?hl=en&answer=2740044"; |
| + |
| +GeneratedCreditCardBubbleController* GetOrCreate(content::WebContents* wc) { |
| + GeneratedCreditCardBubbleController::CreateForWebContents(wc); |
| + return GeneratedCreditCardBubbleController::FromWebContents(wc); |
| +} |
| + |
| +} // namespace |
| + |
| +bool TextRange::operator==(const TextRange& other) const { |
| + return other.range == range && other.is_link == is_link; |
| +} |
| + |
| +GeneratedCreditCardBubbleController::GeneratedCreditCardBubbleController( |
| + content::WebContents* web_contents) |
| + : WebContentsObserver(web_contents), |
| + web_contents_(web_contents), |
| + title_text_(l10n_util::GetStringUTF16( |
| + IDS_AUTOFILL_GENERATED_CREDIT_CARD_BUBBLE_TITLE)), |
| + should_show_anchor_(true), |
| + weak_ptr_factory_(this) {} |
| + |
| +GeneratedCreditCardBubbleController::~GeneratedCreditCardBubbleController() { |
| + // In the case that the tab is closed, the controller can be deleted while |
| + // bubble is showing. Always calling |Hide()| ensures that the bubble closes. |
| + Hide(); |
| +} |
| + |
| +// static |
| +void GeneratedCreditCardBubbleController::RegisterUserPrefs( |
| + user_prefs::PrefRegistrySyncable* registry) { |
| + registry->RegisterIntegerPref( |
| + ::prefs::kAutofillGeneratedCardBubbleTimesShown, |
| + 0, |
| + user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| +} |
| + |
| +// static |
| +void GeneratedCreditCardBubbleController::Show( |
| + content::WebContents* contents, |
| + const base::string16& fronting_card_name, |
| + const base::string16& backing_card_name) { |
| + GetOrCreate(contents)->SetupAndShow(fronting_card_name, backing_card_name); |
| +} |
| + |
| +void GeneratedCreditCardBubbleController::DidNavigateMainFrame( |
| + const content::LoadCommittedDetails& details, |
| + const content::FrameNavigateParams& params) { |
| + if (details.entry && |
| + !content::PageTransitionIsRedirect(details.entry->GetTransitionType())) { |
| + should_show_anchor_ = false; |
| + UpdateAnchor(); |
| + web_contents()->RemoveUserData(UserDataKey()); |
| + // |this| is now deleted. |
| + } |
| +} |
| + |
| +bool GeneratedCreditCardBubbleController::IsHiding() const { |
| + return bubble_ && bubble_->IsHiding(); |
| +} |
| + |
| +gfx::Image GeneratedCreditCardBubbleController::AnchorIcon() const { |
| + if (!should_show_anchor_) |
| + return gfx::Image(); |
| + return ui::ResourceBundle::GetSharedInstance().GetImageNamed(IDR_WALLET_ICON); |
| +} |
| + |
| +const base::string16& GeneratedCreditCardBubbleController::TitleText() const { |
| + return title_text_; |
| +} |
| + |
| +const base::string16& GeneratedCreditCardBubbleController::ContentsText() |
| + const { |
| + return contents_text_; |
| +} |
| + |
| +const std::vector<TextRange>& GeneratedCreditCardBubbleController:: |
| + ContentsTextRanges() const { |
| + return contents_text_ranges_; |
| +} |
| + |
| +void GeneratedCreditCardBubbleController::OnAnchorClicked() { |
| + Show(true); |
| +} |
| + |
| +void GeneratedCreditCardBubbleController::OnLinkClicked() { |
| + // Open a new tab to the Online Wallet help link. |
| + chrome::NavigateParams params( |
| + chrome::FindBrowserWithWebContents(web_contents()), |
| + GURL(kWalletGeneratedCardLearnMoreLink), |
| + content::PAGE_TRANSITION_AUTO_BOOKMARK); |
| + params.disposition = NEW_FOREGROUND_TAB; |
| + chrome::Navigate(¶ms); |
| + |
| + Hide(); |
| +} |
| + |
| +base::WeakPtr<GeneratedCreditCardBubbleController> |
| + GeneratedCreditCardBubbleController::GetWeakPtr() { |
| + return weak_ptr_factory_.GetWeakPtr(); |
| +} |
| + |
| +base::WeakPtr<GeneratedCreditCardBubble> GeneratedCreditCardBubbleController:: |
| + CreateBubble() { |
| + return GeneratedCreditCardBubble::Create(GetWeakPtr()); |
| +} |
| + |
| +base::WeakPtr<GeneratedCreditCardBubble> GeneratedCreditCardBubbleController:: |
| + bubble() { |
| + return bubble_; |
| +} |
| + |
| +bool GeneratedCreditCardBubbleController::CanShow() const { |
| + Browser* browser = chrome::FindBrowserWithWebContents(web_contents()); |
| + return web_contents() == browser->tab_strip_model()->GetActiveWebContents(); |
| +} |
| + |
| +bool GeneratedCreditCardBubbleController::ShouldDisplayBubbleInitially() const { |
| + Profile* profile = Profile::FromBrowserContext( |
| + web_contents_->GetBrowserContext()); |
| + int times_shown = profile->GetPrefs()->GetInteger( |
| + ::prefs::kAutofillGeneratedCardBubbleTimesShown); |
| + return times_shown < kMaxGeneratedCardTimesToShow; |
| +} |
| + |
| +void GeneratedCreditCardBubbleController::SetupAndShow( |
| + const base::string16& fronting_card_name, |
| + const base::string16& backing_card_name) { |
| + DCHECK(!fronting_card_name.empty()); |
| + DCHECK(!backing_card_name.empty()); |
| + |
| + fronting_card_name_ = fronting_card_name; |
| + backing_card_name_ = backing_card_name; |
| + |
| + // Clear any generated state or from the last |SetupAndShow()| call. |
| + contents_text_.clear(); |
| + contents_text_ranges_.clear(); |
| + |
| + base::string16 to_split = l10n_util::GetStringFUTF16( |
| + IDS_AUTOFILL_GENERATED_CREDIT_CARD_BUBBLE_CONTENTS, |
| + fronting_card_name_, |
| + backing_card_name_); |
| + |
| + // Split the full text on '|' to highlight certain parts. For example, "sly" |
| + // and "jumped" would be bolded in "The |sly| fox |jumped| over the lazy dog". |
| + std::vector<base::string16> pieces; |
| + base::SplitStringDontTrim(to_split, kRangeSeparator, &pieces); |
| + |
| + while (!pieces.empty()) { |
| + base::string16 piece = pieces.front(); |
| + |
| + // Every second piece should be bolded. Because |base::SplitString*()| |
| + // leaves an empty "" even if '|' is the first character, this is guaranteed |
| + // to work for "|highlighting| starts here". Ignore empty pieces because |
| + // there's nothing to highlight. |
| + if (!piece.empty() && pieces.size() % 2 == 0) { |
| + const size_t start = contents_text_.size(); |
| + TextRange bold_text; |
| + bold_text.range = ui::Range(start, start + piece.size()); |
| + bold_text.is_link = false; |
| + contents_text_ranges_.push_back(bold_text); |
| + } |
| + |
| + // Append the piece whether it's bolded or not and move on to the next one. |
| + contents_text_.append(piece); |
| + pieces.erase(pieces.begin(), pieces.begin() + 1); |
| + } |
| + |
| + // Add a "Learn more" link at the end of the header text if it's a generated |
| + // card bubble. |
| + base::string16 learn_more = l10n_util::GetStringUTF16(IDS_LEARN_MORE); |
| + contents_text_.append(ASCIIToUTF16(" ") + learn_more); |
|
Evan Stade
2013/08/08 22:43:20
does this not work: string16(" ")
Dan Beam
2013/08/09 01:47:58
Nope.
|
| + const size_t header_size = contents_text_.size(); |
| + TextRange end_link; |
| + end_link.range = ui::Range(header_size - learn_more.size(), header_size); |
| + end_link.is_link = true; |
| + contents_text_ranges_.push_back(end_link); |
| + |
| + UpdateAnchor(); |
| + |
| + if (ShouldDisplayBubbleInitially()) |
| + Show(false); |
| +} |
| + |
| +void GeneratedCreditCardBubbleController::Show(bool was_anchor_click) { |
| + if (!CanShow()) |
| + return; |
| + |
| + bubble_ = CreateBubble(); |
| + if (!bubble_) { |
| + // TODO(dbeam): Make a bubble on all applicable platforms. |
| + return; |
| + } |
| + |
| + bubble_->Show(); |
| + |
| + if (!was_anchor_click) { |
| + // If the bubble was an automatically created "you generated a card" bubble, |
| + // count it as a show. If the user clicked the omnibox icon, don't count it. |
| + PrefService* prefs = Profile::FromBrowserContext( |
| + web_contents()->GetBrowserContext())->GetPrefs(); |
| + prefs->SetInteger(::prefs::kAutofillGeneratedCardBubbleTimesShown, |
| + prefs->GetInteger(::prefs::kAutofillGeneratedCardBubbleTimesShown) + 1); |
| + } |
| +} |
| + |
| +void GeneratedCreditCardBubbleController::UpdateAnchor() { |
| + Browser* browser = chrome::FindBrowserWithWebContents(web_contents()); |
| + if (browser && browser->window() && browser->window()->GetLocationBar()) |
| + browser->window()->GetLocationBar()->UpdateGeneratedCreditCardView(); |
| +} |
| + |
| +void GeneratedCreditCardBubbleController::Hide() { |
| + // Sever |bubble_|'s reference to the controller and hide (if it exists). |
| + weak_ptr_factory_.InvalidateWeakPtrs(); |
|
Evan Stade
2013/08/08 22:43:20
I don't see why this is necessary. Calling Hide()
Dan Beam
2013/08/09 01:47:58
Done.
|
| + |
| + if (bubble_ && !bubble_->IsHiding()) |
| + bubble_->Hide(); |
| + |
| + DCHECK(!bubble_ || bubble_->IsHiding()); |
| +} |
| + |
| +} // namespace autofill |