| Index: chrome/browser/ui/views/autofill/autofill_dialog_views.cc
|
| diff --git a/chrome/browser/ui/views/autofill/autofill_dialog_views.cc b/chrome/browser/ui/views/autofill/autofill_dialog_views.cc
|
| index cee04ad7a45ba4cba4a6e2282f9507dba92c9e09..d8ddaf7de68617bce676f825b8dc3f95d0e8118b 100644
|
| --- a/chrome/browser/ui/views/autofill/autofill_dialog_views.cc
|
| +++ b/chrome/browser/ui/views/autofill/autofill_dialog_views.cc
|
| @@ -6,6 +6,8 @@
|
|
|
| #include <utility>
|
|
|
| +#include "base/i18n/break_iterator.h"
|
| +#include "base/string_util.h"
|
| #include "base/utf_string_conversions.h"
|
| #include "chrome/browser/autofill/wallet/wallet_service_url.h"
|
| #include "chrome/browser/profiles/profile.h"
|
| @@ -52,6 +54,7 @@ const size_t kArrowWidth = 2 * kArrowHeight;
|
|
|
| const char kDecoratedTextfieldClassName[] = "autofill/DecoratedTextfield";
|
| const char kNotificationAreaClassName[] = "autofill/NotificationArea";
|
| +const char kFootnoteViewClassName[] = "autofill/FootnoteView";
|
|
|
| // Returns a label that describes a details section.
|
| views::Label* CreateDetailsSectionLabel(const string16& text) {
|
| @@ -332,6 +335,7 @@ void AutofillDialogViews::SuggestionView::ShowTextfield(
|
| }
|
|
|
| // AutofilDialogViews::AutocheckoutProgressBar ---------------------------------
|
| +
|
| AutofillDialogViews::AutocheckoutProgressBar::AutocheckoutProgressBar() {}
|
|
|
| gfx::Size AutofillDialogViews::AutocheckoutProgressBar::GetPreferredSize() {
|
| @@ -339,6 +343,209 @@ gfx::Size AutofillDialogViews::AutocheckoutProgressBar::GetPreferredSize() {
|
| kAutocheckoutProgressBarHeight);
|
| }
|
|
|
| +// AutofillDialogViews::FootnoteView -------------------------------------------
|
| +
|
| +AutofillDialogViews::FootnoteView::FootnoteView()
|
| + : current_width_(0),
|
| + layout_(NULL),
|
| + previous_parent_width_(-1),
|
| + single_column_set_(0) {
|
| + set_border(views::Border::CreateEmptyBorder(
|
| + views::kUnrelatedControlVerticalSpacing, 0,
|
| + views::kUnrelatedControlVerticalSpacing, 0));
|
| +}
|
| +
|
| +AutofillDialogViews::FootnoteView::~FootnoteView() {}
|
| +
|
| +std::string AutofillDialogViews::FootnoteView::GetClassName() const {
|
| + return kFootnoteViewClassName;
|
| +}
|
| +
|
| +void AutofillDialogViews::FootnoteView::AddLabel(views::Label* label,
|
| + bool is_link) {
|
| + FootnoteLabel* footnote_label = new FootnoteLabel();
|
| + footnote_label->label.reset(label);
|
| + footnote_label->is_link = is_link;
|
| + footnote_labels_.push_back(footnote_label);
|
| + previous_parent_width_ = -1;
|
| +}
|
| +
|
| +int AutofillDialogViews::FootnoteView::IndexOfLink(views::Label* link) {
|
| + size_t distance = std::distance(
|
| + links_.begin(), std::find(links_.begin(), links_.end(), link));
|
| + return distance < links_.size() ? distance : -1;
|
| +}
|
| +
|
| +void AutofillDialogViews::FootnoteView::StartRow() {
|
| + layout_->StartRow(0, single_column_set_);
|
| + views::View* row = new views::View();
|
| + row->SetLayoutManager(
|
| + new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0));
|
| + layout_->AddView(row);
|
| +}
|
| +
|
| +views::View* AutofillDialogViews::FootnoteView::CurrentRow() {
|
| + return child_at(child_count() - 1);
|
| +}
|
| +
|
| +void AutofillDialogViews::FootnoteView::ResetRows() {
|
| + ResetLayoutManager();
|
| + RemoveAllChildViews(true);
|
| +}
|
| +
|
| +void AutofillDialogViews::FootnoteView::ResetLayoutManager() {
|
| + views::GridLayout* layout = new views::GridLayout(this);
|
| + SetLayoutManager(layout);
|
| +
|
| + layout_ = layout;
|
| + layout_->AddColumnSet(single_column_set_)->AddColumn(
|
| + views::GridLayout::FILL,
|
| + views::GridLayout::FILL,
|
| + 1,
|
| + views::GridLayout::USE_PREF,
|
| + 0,
|
| + 0);
|
| +}
|
| +
|
| +void AutofillDialogViews::FootnoteView::Reset() {
|
| + ResetRows();
|
| + ResetText();
|
| + ResetWidth();
|
| + StartRow();
|
| +}
|
| +
|
| +void AutofillDialogViews::FootnoteView::AppendText(const string16& text_part) {
|
| + current_text_.append(text_part);
|
| +}
|
| +
|
| +const string16& AutofillDialogViews::FootnoteView::CurrentText() const {
|
| + return current_text_;
|
| +}
|
| +
|
| +void AutofillDialogViews::FootnoteView::ResetWidth() {
|
| + current_width_ = 0;
|
| +}
|
| +
|
| +size_t AutofillDialogViews::FootnoteView::CurrentWidth() const {
|
| + return current_width_;
|
| +}
|
| +
|
| +void AutofillDialogViews::FootnoteView::AddWidth(size_t width) {
|
| + current_width_ += width;
|
| +}
|
| +
|
| +void AutofillDialogViews::FootnoteView::ResetText() {
|
| + current_text_.clear();
|
| +}
|
| +
|
| +int AutofillDialogViews::FootnoteView::ParentWidth() {
|
| + DCHECK(parent());
|
| + return parent()->GetPreferredSize().width();
|
| +}
|
| +
|
| +int AutofillDialogViews::FootnoteView::WidthRemaining() {
|
| + return ParentWidth() - CurrentWidth();
|
| +}
|
| +
|
| +void AutofillDialogViews::FootnoteView::AddCloneWithWidth(views::Label* label,
|
| + size_t width) {
|
| + AddWidth(width);
|
| + CurrentRow()->AddChildView(label);
|
| +}
|
| +
|
| +views::Label* AutofillDialogViews::FootnoteView::CloneLabel(
|
| + const string16& text, const gfx::Font& font, bool is_link) {
|
| + views::Label* label = is_link ? new views::Link(text) :
|
| + new views::Label(text);
|
| + label->SetFont(font);
|
| + return label;
|
| +}
|
| +
|
| +void AutofillDialogViews::FootnoteView::TransferListener(
|
| + views::Label* from_label, views::Label* to_label) {
|
| + views::Link* from = static_cast<views::Link*>(from_label);
|
| + views::Link* to = static_cast<views::Link*>(to_label);
|
| + to->set_listener(const_cast<views::LinkListener*>(from->listener()));
|
| +}
|
| +
|
| +void AutofillDialogViews::FootnoteView::Layout() {
|
| + views::View::Layout();
|
| +
|
| + if (!parent() || previous_parent_width_ == ParentWidth())
|
| + return;
|
| +
|
| + Reset();
|
| +
|
| + for (size_t i = 0; i < footnote_labels_.size(); ++i) {
|
| + views::Label* label = footnote_labels_[i]->label.get();
|
| + if (!label->visible())
|
| + continue;
|
| +
|
| + // The label is smaller than the available space. Add it wholesale.
|
| + int tw = gfx::Canvas::GetStringWidth(label->text(), label->font());
|
| + if (tw < WidthRemaining()) {
|
| + views::Label* clone = CloneLabel(label->text(),
|
| + label->font(),
|
| + footnote_labels_[i]->is_link);
|
| + if (footnote_labels_[i]->is_link) {
|
| + TransferListener(label, clone);
|
| + links_.push_back(clone);
|
| + }
|
| + AddCloneWithWidth(clone, tw);
|
| + continue;
|
| + }
|
| +
|
| + // Don't wrap links mid-line. This one's too big, so make a new row.
|
| + if (footnote_labels_[i]->is_link) {
|
| + StartRow();
|
| + ResetWidth();
|
| + links_.push_back(CloneLabel(label->text(), label->font(), true));
|
| + TransferListener(label, links_.back());
|
| + AddCloneWithWidth(links_.back(), tw);
|
| + if (tw > ParentWidth()) {
|
| + StartRow();
|
| + ResetWidth();
|
| + }
|
| + continue;
|
| + }
|
| +
|
| + // Go through the text word by word, seeing if each one fits.
|
| + DCHECK(CurrentText().empty());
|
| + base::i18n::BreakIterator iter(label->text(),
|
| + base::i18n::BreakIterator::BREAK_SPACE);
|
| + for (bool first_word = true, more_words = iter.Init() && iter.Advance();
|
| + more_words; ) {
|
| + int width = 0;
|
| + // Iterate until no more words or space left.
|
| + do {
|
| + string16 text = iter.GetString();
|
| + if (first_word) {
|
| + TrimWhitespace(text, TRIM_LEADING, &text);
|
| + first_word = false;
|
| + }
|
| +
|
| + const int w = gfx::Canvas::GetStringWidth(text, label->font());
|
| + if (width + w > WidthRemaining())
|
| + break;
|
| +
|
| + width += w;
|
| + AppendText(text);
|
| + } while ((more_words = iter.Advance()));
|
| +
|
| + // If we didn't run out of words, the space is full. Start a new row.
|
| + if (more_words) {
|
| + StartRow();
|
| + ResetWidth();
|
| + }
|
| +
|
| + AddCloneWithWidth(CloneLabel(CurrentText(), label->font(), false), width);
|
| + ResetText();
|
| + }
|
| + }
|
| +
|
| + previous_parent_width_ = ParentWidth();
|
| +}
|
| +
|
| // AutofillDialogView ----------------------------------------------------------
|
|
|
| // static
|
| @@ -365,6 +572,7 @@ AutofillDialogViews::AutofillDialogViews(AutofillDialogController* controller)
|
| save_in_chrome_checkbox_(NULL),
|
| autocheckout_progress_bar_view_(NULL),
|
| autocheckout_progress_bar_(NULL),
|
| + footnote_view_(NULL),
|
| focus_manager_(NULL) {
|
| DCHECK(controller);
|
| detail_groups_.insert(std::make_pair(SECTION_EMAIL,
|
| @@ -389,6 +597,7 @@ void AutofillDialogViews::Show() {
|
| InitChildViews();
|
| UpdateAccountChooser();
|
| UpdateNotificationArea();
|
| + UpdateFootnote();
|
|
|
| // Ownership of |contents_| is handed off by this call. The
|
| // WebContentsModalDialog will take care of deleting itself after calling
|
| @@ -413,11 +622,7 @@ void AutofillDialogViews::UpdateAccountChooser() {
|
| void AutofillDialogViews::UpdateNotificationArea() {
|
| DCHECK(notification_area_);
|
| notification_area_->SetNotification(controller_->CurrentNotification());
|
| -
|
| - if (GetWidget())
|
| - GetWidget()->SetSize(GetWidget()->non_client_view()->GetPreferredSize());
|
| -
|
| - contents_->Layout();
|
| + ContentsResized();
|
| }
|
|
|
| void AutofillDialogViews::UpdateSection(DialogSection section) {
|
| @@ -484,6 +689,11 @@ void AutofillDialogViews::UpdateProgressBar(double value) {
|
| autocheckout_progress_bar_->SetValue(value);
|
| }
|
|
|
| +void AutofillDialogViews::UpdateFootnote() {
|
| + PopulateFootnoteLinks();
|
| + ContentsResized();
|
| +}
|
| +
|
| string16 AutofillDialogViews::GetWindowTitle() const {
|
| return controller_->DialogTitle();
|
| }
|
| @@ -525,8 +735,7 @@ views::View* AutofillDialogViews::GetExtraView() {
|
| }
|
|
|
| views::View* AutofillDialogViews::GetFootnoteView() {
|
| - // TODO(estade): add a view to contain the terms of service.
|
| - return NULL;
|
| + return footnote_view_;
|
| }
|
|
|
| bool AutofillDialogViews::Cancel() {
|
| @@ -607,22 +816,22 @@ void AutofillDialogViews::OnDidChangeFocus(
|
| views::View* focused_now) {}
|
|
|
| void AutofillDialogViews::LinkClicked(views::Link* source, int event_flags) {
|
| - // Sign in link.
|
| if (source == account_chooser_link_) {
|
| if (controller_->SignedInState() != SIGNED_IN) {
|
| DCHECK(controller_->CanPayWithWallet());
|
| controller_->StartSignInFlow();
|
| }
|
| // TODO(dbeam): handle other clicks on the account chooser (i.e. combobox).
|
| - return;
|
| - }
|
| -
|
| - // Edit links.
|
| - for (DetailGroupMap::iterator iter = detail_groups_.begin();
|
| - iter != detail_groups_.end(); ++iter) {
|
| - if (iter->second.suggested_info->Contains(source)) {
|
| - controller_->EditClickedForSection(iter->first);
|
| - return;
|
| + } else if (footnote_view_->Contains(source)) {
|
| + controller_->LegalDocumentLinkClicked(footnote_view_->IndexOfLink(source));
|
| + } else {
|
| + // Edit links.
|
| + for (DetailGroupMap::iterator iter = detail_groups_.begin();
|
| + iter != detail_groups_.end(); ++iter) {
|
| + if (iter->second.suggested_info->Contains(source)) {
|
| + controller_->EditClickedForSection(iter->first);
|
| + return;
|
| + }
|
| }
|
| }
|
| }
|
| @@ -656,19 +865,9 @@ void AutofillDialogViews::InitChildViews() {
|
| new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0));
|
| contents_->AddChildView(CreateMainContainer());
|
| contents_->AddChildView(CreateSignInContainer());
|
| -}
|
|
|
| -views::View* AutofillDialogViews::CreateSignInContainer() {
|
| - sign_in_container_ = new views::View();
|
| - sign_in_container_->SetLayoutManager(
|
| - new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
|
| - sign_in_container_->SetVisible(false);
|
| - sign_in_webview_ = new views::WebView(controller_->profile());
|
| - cancel_sign_in_ = new views::TextButton(this,
|
| - controller_->CancelSignInText());
|
| - sign_in_container_->AddChildView(cancel_sign_in_);
|
| - sign_in_container_->AddChildView(sign_in_webview_);
|
| - return sign_in_container_;
|
| + // |footnote_view_| is added to View hierarchy by |GetFootnoteView()|.
|
| + footnote_view_ = new FootnoteView();
|
| }
|
|
|
| views::View* AutofillDialogViews::CreateMainContainer() {
|
| @@ -705,6 +904,37 @@ views::View* AutofillDialogViews::CreateMainContainer() {
|
| return main_container_;
|
| }
|
|
|
| +views::View* AutofillDialogViews::CreateSignInContainer() {
|
| + sign_in_container_ = new views::View();
|
| + sign_in_container_->SetLayoutManager(
|
| + new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
|
| + sign_in_container_->SetVisible(false);
|
| + sign_in_webview_ = new views::WebView(controller_->profile());
|
| + cancel_sign_in_ = new views::TextButton(this,
|
| + controller_->CancelSignInText());
|
| + sign_in_container_->AddChildView(cancel_sign_in_);
|
| + sign_in_container_->AddChildView(sign_in_webview_);
|
| + return sign_in_container_;
|
| +}
|
| +
|
| +void AutofillDialogViews::PopulateFootnoteLinks() {
|
| + const std::vector<string16>& link_parts = controller_->FootnoteLinkParts();
|
| + for (size_t i = 0; i < link_parts.size(); ++i) {
|
| + if (i % 2 == 0) {
|
| + // Text between links.
|
| + footnote_view_->AddLabel(new views::Label(link_parts[i]), false);
|
| + } else {
|
| + // Link to a legal document (i.e. Terms Of Service, Privacy Policy).
|
| + views::Link* link = new views::Link(link_parts[i]);
|
| + link->SetEnabledColor(SkColorSetRGB(0x64, 0x64, 0x64));
|
| + link->set_listener(this);
|
| + footnote_view_->AddLabel(link, true);
|
| + }
|
| + }
|
| + footnote_view_->Layout();
|
| + ContentsResized();
|
| +}
|
| +
|
| views::View* AutofillDialogViews::CreateDetailsContainer() {
|
| views::View* view = new views::View();
|
| // A box layout is used because it respects widget visibility.
|
| @@ -738,7 +968,7 @@ views::View* AutofillDialogViews::CreateInputsContainer(DialogSection section) {
|
| views::GridLayout* layout = new views::GridLayout(inputs_container);
|
| inputs_container->SetLayoutManager(layout);
|
|
|
| - int kColumnSetId = 0;
|
| + const int kColumnSetId = 0;
|
| views::ColumnSet* column_set = layout->AddColumnSet(kColumnSetId);
|
| column_set->AddColumn(views::GridLayout::FILL,
|
| views::GridLayout::LEADING,
|
| @@ -892,8 +1122,7 @@ void AutofillDialogViews::UpdateDetailsGroupState(const DetailsGroup& group) {
|
| if (group.container)
|
| group.container->SetForwardMouseEvents(show_suggestions);
|
|
|
| - if (GetWidget())
|
| - GetWidget()->SetSize(GetWidget()->non_client_view()->GetPreferredSize());
|
| + ContentsResized();
|
| }
|
|
|
| bool AutofillDialogViews::AtLeastOneSectionIsEditing() {
|
| @@ -981,6 +1210,11 @@ void AutofillDialogViews::TextfieldEditedOrActivated(
|
| decorated->SetInvalid(!controller_->InputIsValid(type, textfield->text()));
|
| }
|
|
|
| +void AutofillDialogViews::ContentsResized() {
|
| + if (GetWidget())
|
| + GetWidget()->SetSize(GetWidget()->non_client_view()->GetPreferredSize());
|
| +}
|
| +
|
| AutofillDialogViews::DetailsGroup* AutofillDialogViews::GroupForSection(
|
| DialogSection section) {
|
| return &detail_groups_.find(section)->second;
|
|
|