Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1463)

Unified Diff: chrome/browser/ui/views/autofill/autofill_dialog_views.cc

Issue 1931043002: Remove requestAutocomplete (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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
deleted file mode 100644
index a2ee6460be0625fd94daf9e650644bccbdb92f4b..0000000000000000000000000000000000000000
--- a/chrome/browser/ui/views/autofill/autofill_dialog_views.cc
+++ /dev/null
@@ -1,1917 +0,0 @@
-// Copyright (c) 2012 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/views/autofill/autofill_dialog_views.h"
-
-#include <stddef.h>
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/macros.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/autofill/autofill_dialog_view_delegate.h"
-#include "chrome/browser/ui/autofill/loading_animation.h"
-#include "chrome/browser/ui/views/autofill/expanding_textfield.h"
-#include "chrome/browser/ui/views/autofill/info_bubble.h"
-#include "chrome/browser/ui/views/autofill/tooltip_icon.h"
-#include "components/autofill/core/browser/autofill_type.h"
-#include "components/constrained_window/constrained_window_views.h"
-#include "components/web_modal/web_contents_modal_dialog_host.h"
-#include "components/web_modal/web_contents_modal_dialog_manager.h"
-#include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
-#include "content/public/browser/native_web_keyboard_event.h"
-#include "content/public/browser/navigation_controller.h"
-#include "content/public/browser/web_contents.h"
-#include "grit/theme_resources.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/base/models/combobox_model.h"
-#include "ui/base/models/menu_model.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/compositor/paint_recorder.h"
-#include "ui/events/event_handler.h"
-#include "ui/gfx/animation/animation_delegate.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/color_utils.h"
-#include "ui/gfx/font_list.h"
-#include "ui/gfx/geometry/point.h"
-#include "ui/gfx/path.h"
-#include "ui/gfx/skia_util.h"
-#include "ui/views/background.h"
-#include "ui/views/border.h"
-#include "ui/views/bubble/bubble_border.h"
-#include "ui/views/bubble/bubble_frame_view.h"
-#include "ui/views/controls/button/blue_button.h"
-#include "ui/views/controls/button/checkbox.h"
-#include "ui/views/controls/button/label_button.h"
-#include "ui/views/controls/button/label_button_border.h"
-#include "ui/views/controls/button/menu_button.h"
-#include "ui/views/controls/combobox/combobox.h"
-#include "ui/views/controls/image_view.h"
-#include "ui/views/controls/label.h"
-#include "ui/views/controls/link.h"
-#include "ui/views/controls/menu/menu_runner.h"
-#include "ui/views/controls/separator.h"
-#include "ui/views/controls/styled_label.h"
-#include "ui/views/controls/textfield/textfield.h"
-#include "ui/views/controls/webview/webview.h"
-#include "ui/views/layout/box_layout.h"
-#include "ui/views/layout/fill_layout.h"
-#include "ui/views/layout/grid_layout.h"
-#include "ui/views/layout/layout_constants.h"
-#include "ui/views/painter.h"
-#include "ui/views/view_targeter.h"
-#include "ui/views/widget/widget.h"
-#include "ui/views/window/dialog_client_view.h"
-#include "ui/views/window/non_client_view.h"
-
-namespace autofill {
-
-namespace {
-
-// The width for the section container.
-const int kSectionContainerWidth = 440;
-
-// The minimum useful height of the contents area of the dialog.
-const int kMinimumContentsHeight = 101;
-
-// Horizontal padding between text and other elements (in pixels).
-const int kAroundTextPadding = 4;
-
-// The space between the edges of a notification bar and the text within (in
-// pixels).
-const int kNotificationPadding = 17;
-
-// Vertical padding above and below each detail section (in pixels).
-const int kDetailSectionVerticalPadding = 10;
-
-const int kArrowHeight = 7;
-const int kArrowWidth = 2 * kArrowHeight;
-
-// The padding inside the edges of the dialog, in pixels.
-const int kDialogEdgePadding = 20;
-
-// The vertical padding between rows of manual inputs (in pixels).
-const int kManualInputRowPadding = 10;
-
-// The top and bottom padding, in pixels, for the suggestions menu dropdown
-// arrows.
-const int kMenuButtonTopInset = 3;
-const int kMenuButtonBottomInset = 6;
-
-const char kNotificationAreaClassName[] = "autofill/NotificationArea";
-const char kSectionContainerClassName[] = "autofill/SectionContainer";
-const char kSuggestedButtonClassName[] = "autofill/SuggestedButton";
-
-// Draws an arrow at the top of |canvas| pointing to |tip_x|.
-void DrawArrow(gfx::Canvas* canvas,
- int tip_x,
- const SkColor& fill_color,
- const SkColor& stroke_color) {
- const int arrow_half_width = kArrowWidth / 2.0f;
-
- SkPath arrow;
- arrow.moveTo(tip_x - arrow_half_width, kArrowHeight);
- arrow.lineTo(tip_x, 0);
- arrow.lineTo(tip_x + arrow_half_width, kArrowHeight);
-
- SkPaint fill_paint;
- fill_paint.setColor(fill_color);
- canvas->DrawPath(arrow, fill_paint);
-
- if (stroke_color != SK_ColorTRANSPARENT) {
- SkPaint stroke_paint;
- stroke_paint.setColor(stroke_color);
- stroke_paint.setStyle(SkPaint::kStroke_Style);
- canvas->DrawPath(arrow, stroke_paint);
- }
-}
-
-void SelectComboboxValueOrSetToDefault(views::Combobox* combobox,
- const base::string16& value) {
- if (!combobox->SelectValue(value))
- combobox->SetSelectedIndex(combobox->model()->GetDefaultIndex());
-}
-
-// This class handles layout for the first row of a SuggestionView.
-// It exists to circumvent shortcomings of GridLayout and BoxLayout (namely that
-// the former doesn't fully respect child visibility, and that the latter won't
-// expand a single child).
-class SectionRowView : public views::View {
- public:
- SectionRowView() { SetBorder(views::Border::CreateEmptyBorder(10, 0, 0, 0)); }
-
- ~SectionRowView() override {}
-
- // views::View implementation:
- gfx::Size GetPreferredSize() const override {
- int height = 0;
- int width = 0;
- for (int i = 0; i < child_count(); ++i) {
- if (child_at(i)->visible()) {
- if (width > 0)
- width += kAroundTextPadding;
-
- gfx::Size size = child_at(i)->GetPreferredSize();
- height = std::max(height, size.height());
- width += size.width();
- }
- }
-
- gfx::Insets insets = GetInsets();
- return gfx::Size(width + insets.width(), height + insets.height());
- }
-
- void Layout() override {
- const gfx::Rect bounds = GetContentsBounds();
-
- // Icon is left aligned.
- int start_x = bounds.x();
- views::View* icon = child_at(0);
- if (icon->visible()) {
- icon->SizeToPreferredSize();
- icon->SetX(start_x);
- icon->SetY(bounds.y() +
- (bounds.height() - icon->bounds().height()) / 2);
- start_x += icon->bounds().width() + kAroundTextPadding;
- }
-
- // Textfield is right aligned.
- int end_x = bounds.width();
- views::View* textfield = child_at(2);
- if (textfield->visible()) {
- const int preferred_width = textfield->GetPreferredSize().width();
- textfield->SetBounds(bounds.width() - preferred_width, bounds.y(),
- preferred_width, bounds.height());
- end_x = textfield->bounds().x() - kAroundTextPadding;
- }
-
- // Label takes up all the space in between.
- views::View* label = child_at(1);
- if (label->visible())
- label->SetBounds(start_x, bounds.y(), end_x - start_x, bounds.height());
-
- views::View::Layout();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SectionRowView);
-};
-
-// A view that propagates visibility and preferred size changes.
-class LayoutPropagationView : public views::View {
- public:
- LayoutPropagationView() {}
- ~LayoutPropagationView() override {}
-
- protected:
- void ChildVisibilityChanged(views::View* child) override {
- PreferredSizeChanged();
- }
- void ChildPreferredSizeChanged(views::View* child) override {
- PreferredSizeChanged();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(LayoutPropagationView);
-};
-
-// A View for a single notification banner.
-class NotificationView : public views::View,
- public views::StyledLabelListener {
- public:
- NotificationView(const DialogNotification& data,
- AutofillDialogViewDelegate* delegate)
- : data_(data),
- delegate_(delegate),
- checkbox_(NULL) {
- std::unique_ptr<views::View> label_view;
- std::unique_ptr<views::StyledLabel> label(
- new views::StyledLabel(data.display_text(), this));
- label->set_auto_color_readability_enabled(false);
-
- views::StyledLabel::RangeStyleInfo text_style;
- text_style.color = data.GetTextColor();
-
- if (data.link_range().is_empty()) {
- label->AddStyleRange(gfx::Range(0, data.display_text().size()),
- text_style);
- } else {
- gfx::Range prefix_range(0, data.link_range().start());
- if (!prefix_range.is_empty())
- label->AddStyleRange(prefix_range, text_style);
-
- label->AddStyleRange(data.link_range(),
- views::StyledLabel::RangeStyleInfo::CreateForLink());
-
- gfx::Range suffix_range(data.link_range().end(),
- data.display_text().size());
- if (!suffix_range.is_empty())
- label->AddStyleRange(suffix_range, text_style);
- }
- label_view.reset(label.release());
-
- AddChildView(label_view.release());
-
- if (!data.tooltip_text().empty())
- AddChildView(new TooltipIcon(data.tooltip_text()));
-
- set_background(
- views::Background::CreateSolidBackground(data.GetBackgroundColor()));
- SetBorder(views::Border::CreateSolidSidedBorder(
- 1, 0, 1, 0, data.GetBorderColor()));
- }
-
- ~NotificationView() override {}
-
- views::Checkbox* checkbox() {
- return checkbox_;
- }
-
- // views::View implementation.
- gfx::Insets GetInsets() const override {
- int vertical_padding = kNotificationPadding;
- if (checkbox_)
- vertical_padding -= 3;
- return gfx::Insets(vertical_padding, kDialogEdgePadding,
- vertical_padding, kDialogEdgePadding);
- }
-
- int GetHeightForWidth(int width) const override {
- int label_width = width - GetInsets().width();
- if (child_count() > 1) {
- const views::View* tooltip_icon = child_at(1);
- label_width -= tooltip_icon->GetPreferredSize().width() +
- kDialogEdgePadding;
- }
-
- return child_at(0)->GetHeightForWidth(label_width) + GetInsets().height();
- }
-
- void Layout() override {
- // Surprisingly, GetContentsBounds() doesn't consult GetInsets().
- gfx::Rect bounds = GetLocalBounds();
- bounds.Inset(GetInsets());
- int right_bound = bounds.right();
-
- if (child_count() > 1) {
- // The icon takes up the entire vertical space and an extra 20px on
- // each side. This increases the hover target for the tooltip.
- views::View* tooltip_icon = child_at(1);
- gfx::Size icon_size = tooltip_icon->GetPreferredSize();
- int icon_width = icon_size.width() + kDialogEdgePadding;
- right_bound -= icon_width;
- tooltip_icon->SetBounds(
- right_bound, 0,
- icon_width + kDialogEdgePadding, GetLocalBounds().height());
- }
-
- child_at(0)->SetBounds(bounds.x(), bounds.y(),
- right_bound - bounds.x(), bounds.height());
- }
-
- // views::StyledLabelListener implementation.
- void StyledLabelLinkClicked(views::StyledLabel* label,
- const gfx::Range& range,
- int event_flags) override {
- delegate_->LinkClicked(data_.link_url());
- }
-
- private:
- // The model data for this notification.
- DialogNotification data_;
-
- // The delegate that handles interaction with |this|.
- AutofillDialogViewDelegate* delegate_;
-
- // The checkbox associated with this notification, or NULL if there is none.
- views::Checkbox* checkbox_;
-
- DISALLOW_COPY_AND_ASSIGN(NotificationView);
-};
-
-// Gets either the Combobox or ExpandingTextfield that is an ancestor (including
-// self) of |view|.
-views::View* GetAncestralInputView(views::View* view) {
- if (view->GetClassName() == views::Combobox::kViewClassName)
- return view;
-
- return view->GetAncestorWithClassName(ExpandingTextfield::kViewClassName);
-}
-
-// A class that informs |delegate_| when an unhandled mouse press occurs.
-class MousePressedHandler : public ui::EventHandler {
- public:
- explicit MousePressedHandler(AutofillDialogViewDelegate* delegate)
- : delegate_(delegate) {}
-
- // ui::EventHandler implementation.
- void OnMouseEvent(ui::MouseEvent* event) override {
- if (event->type() == ui::ET_MOUSE_PRESSED && !event->handled())
- delegate_->FocusMoved();
- }
-
- private:
- AutofillDialogViewDelegate* const delegate_;
-
- DISALLOW_COPY_AND_ASSIGN(MousePressedHandler);
-};
-
-} // namespace
-
-// AutofillDialogViews::NotificationArea ---------------------------------------
-
-AutofillDialogViews::NotificationArea::NotificationArea(
- AutofillDialogViewDelegate* delegate)
- : delegate_(delegate) {
- // Reserve vertical space for the arrow (regardless of whether one exists).
- // The -1 accounts for the border.
- SetBorder(views::Border::CreateEmptyBorder(kArrowHeight - 1, 0, 0, 0));
-
- views::BoxLayout* box_layout =
- new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0);
- SetLayoutManager(box_layout);
-}
-
-AutofillDialogViews::NotificationArea::~NotificationArea() {}
-
-void AutofillDialogViews::NotificationArea::SetNotifications(
- const std::vector<DialogNotification>& notifications) {
- notifications_ = notifications;
-
- RemoveAllChildViews(true);
-
- if (notifications_.empty())
- return;
-
- for (size_t i = 0; i < notifications_.size(); ++i) {
- const DialogNotification& notification = notifications_[i];
- std::unique_ptr<NotificationView> view(
- new NotificationView(notification, delegate_));
-
- AddChildView(view.release());
- }
-
- PreferredSizeChanged();
-}
-
-gfx::Size AutofillDialogViews::NotificationArea::GetPreferredSize() const {
- gfx::Size size = views::View::GetPreferredSize();
- // Ensure that long notifications wrap and don't enlarge the dialog.
- size.set_width(1);
- return size;
-}
-
-const char* AutofillDialogViews::NotificationArea::GetClassName() const {
- return kNotificationAreaClassName;
-}
-
-void AutofillDialogViews::NotificationArea::PaintChildren(
- const ui::PaintContext& context) {
- views::View::PaintChildren(context);
- if (HasArrow()) {
- ui::PaintRecorder recorder(context, size());
- DrawArrow(
- recorder.canvas(),
- GetMirroredXInView(width() - arrow_centering_anchor_->width() / 2.0f),
- notifications_[0].GetBackgroundColor(),
- notifications_[0].GetBorderColor());
- }
-}
-
-void AutofillDialogViews::OnWidgetDestroying(views::Widget* widget) {
- if (widget == window_)
- window_->GetRootView()->RemovePostTargetHandler(event_handler_.get());
-}
-
-void AutofillDialogViews::OnWidgetClosing(views::Widget* widget) {
- observer_.Remove(widget);
- if (error_bubble_ && error_bubble_->GetWidget() == widget)
- error_bubble_ = NULL;
-}
-
-void AutofillDialogViews::OnWidgetBoundsChanged(views::Widget* widget,
- const gfx::Rect& new_bounds) {
- if (error_bubble_ && error_bubble_->GetWidget() == widget)
- return;
- HideErrorBubble();
-}
-
-bool AutofillDialogViews::NotificationArea::HasArrow() {
- return !notifications_.empty() && notifications_[0].HasArrow() &&
- arrow_centering_anchor_.get();
-}
-
-// AutofillDialogViews::SectionContainer ---------------------------------------
-
-AutofillDialogViews::SectionContainer::SectionContainer(
- const base::string16& label,
- views::View* controls,
- views::Button* proxy_button)
- : proxy_button_(proxy_button),
- forward_mouse_events_(false) {
- set_notify_enter_exit_on_child(true);
-
- SetBorder(views::Border::CreateEmptyBorder(kDetailSectionVerticalPadding,
- kDialogEdgePadding,
- kDetailSectionVerticalPadding,
- kDialogEdgePadding));
-
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- views::Label* label_view = new views::Label(
- label, rb.GetFontList(ui::ResourceBundle::BoldFont));
- label_view->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-
- views::View* label_bar = new views::View();
- views::GridLayout* label_bar_layout = new views::GridLayout(label_bar);
- label_bar->SetLayoutManager(label_bar_layout);
- const int kColumnSetId = 0;
- views::ColumnSet* columns = label_bar_layout->AddColumnSet(kColumnSetId);
- columns->AddColumn(
- views::GridLayout::LEADING,
- views::GridLayout::LEADING,
- 0,
- views::GridLayout::FIXED,
- kSectionContainerWidth - proxy_button->GetPreferredSize().width(),
- 0);
- columns->AddColumn(views::GridLayout::LEADING,
- views::GridLayout::LEADING,
- 0,
- views::GridLayout::USE_PREF,
- 0,
- 0);
- label_bar_layout->StartRow(0, kColumnSetId);
- label_bar_layout->AddView(label_view);
- label_bar_layout->AddView(proxy_button);
-
- SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
- AddChildView(label_bar);
- AddChildView(controls);
-
- SetEventTargeter(
- std::unique_ptr<views::ViewTargeter>(new views::ViewTargeter(this)));
-}
-
-AutofillDialogViews::SectionContainer::~SectionContainer() {}
-
-void AutofillDialogViews::SectionContainer::SetActive(bool active) {
- bool is_active = active && proxy_button_->visible();
- if (is_active == !!background())
- return;
-
- set_background(
- is_active ? views::Background::CreateSolidBackground(kLightShadingColor)
- : NULL);
- SchedulePaint();
-}
-
-void AutofillDialogViews::SectionContainer::SetForwardMouseEvents(
- bool forward) {
- forward_mouse_events_ = forward;
- if (!forward)
- set_background(NULL);
-}
-
-const char* AutofillDialogViews::SectionContainer::GetClassName() const {
- return kSectionContainerClassName;
-}
-
-void AutofillDialogViews::SectionContainer::OnMouseMoved(
- const ui::MouseEvent& event) {
- SetActive(ShouldForwardEvent(event));
-}
-
-void AutofillDialogViews::SectionContainer::OnMouseEntered(
- const ui::MouseEvent& event) {
- if (!ShouldForwardEvent(event))
- return;
-
- SetActive(true);
- proxy_button_->OnMouseEntered(ProxyEvent(event));
- SchedulePaint();
-}
-
-void AutofillDialogViews::SectionContainer::OnMouseExited(
- const ui::MouseEvent& event) {
- SetActive(false);
- if (!ShouldForwardEvent(event))
- return;
-
- proxy_button_->OnMouseExited(ProxyEvent(event));
- SchedulePaint();
-}
-
-bool AutofillDialogViews::SectionContainer::OnMousePressed(
- const ui::MouseEvent& event) {
- if (!ShouldForwardEvent(event))
- return false;
-
- return proxy_button_->OnMousePressed(ProxyEvent(event));
-}
-
-void AutofillDialogViews::SectionContainer::OnMouseReleased(
- const ui::MouseEvent& event) {
- if (!ShouldForwardEvent(event))
- return;
-
- proxy_button_->OnMouseReleased(ProxyEvent(event));
-}
-
-void AutofillDialogViews::SectionContainer::OnGestureEvent(
- ui::GestureEvent* event) {
- if (!ShouldForwardEvent(*event))
- return;
-
- proxy_button_->OnGestureEvent(event);
-}
-
-views::View* AutofillDialogViews::SectionContainer::TargetForRect(
- views::View* root,
- const gfx::Rect& rect) {
- CHECK_EQ(root, this);
- views::View* handler = views::ViewTargeterDelegate::TargetForRect(root, rect);
-
- // If the event is not in the label bar and there's no background to be
- // cleared, let normal event handling take place.
- if (!background() &&
- rect.CenterPoint().y() > child_at(0)->bounds().bottom()) {
- return handler;
- }
-
- // Special case for (CVC) inputs in the suggestion view.
- if (forward_mouse_events_ &&
- handler->GetAncestorWithClassName(ExpandingTextfield::kViewClassName)) {
- return handler;
- }
-
- // Special case for the proxy button itself.
- if (handler == proxy_button_)
- return handler;
-
- return this;
-}
-
-// static
-ui::MouseEvent AutofillDialogViews::SectionContainer::ProxyEvent(
- const ui::MouseEvent& event) {
- ui::MouseEvent event_copy = event;
- event_copy.set_location(gfx::Point());
- return event_copy;
-}
-
-bool AutofillDialogViews::SectionContainer::ShouldForwardEvent(
- const ui::LocatedEvent& event) {
- // Always forward events on the label bar.
- return forward_mouse_events_ || event.y() <= child_at(0)->bounds().bottom();
-}
-
-// AutofillDialogViews::SuggestedButton ----------------------------------------
-
-AutofillDialogViews::SuggestedButton::SuggestedButton(
- views::MenuButtonListener* listener)
- : views::MenuButton(base::string16(), listener, false) {
- const int kFocusBorderWidth = 1;
- SetBorder(views::Border::CreateEmptyBorder(kMenuButtonTopInset,
- kFocusBorderWidth,
- kMenuButtonBottomInset,
- kFocusBorderWidth));
- gfx::Insets insets = GetInsets();
- insets += gfx::Insets(-kFocusBorderWidth, -kFocusBorderWidth,
- -kFocusBorderWidth, -kFocusBorderWidth);
- SetFocusPainter(
- views::Painter::CreateDashedFocusPainterWithInsets(insets));
- SetFocusBehavior(FocusBehavior::ALWAYS);
-}
-
-AutofillDialogViews::SuggestedButton::~SuggestedButton() {}
-
-gfx::Size AutofillDialogViews::SuggestedButton::GetPreferredSize() const {
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- gfx::Size size = rb.GetImageNamed(ResourceIDForState()).Size();
- const gfx::Insets insets = GetInsets();
- size.Enlarge(insets.width(), insets.height());
- return size;
-}
-
-const char* AutofillDialogViews::SuggestedButton::GetClassName() const {
- return kSuggestedButtonClassName;
-}
-
-void AutofillDialogViews::SuggestedButton::OnPaint(gfx::Canvas* canvas) {
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- const gfx::Insets insets = GetInsets();
- canvas->DrawImageInt(*rb.GetImageSkiaNamed(ResourceIDForState()),
- insets.left(), insets.top());
- views::Painter::PaintFocusPainter(this, canvas, focus_painter());
-}
-
-int AutofillDialogViews::SuggestedButton::ResourceIDForState() const {
- views::Button::ButtonState button_state = state();
- if (button_state == views::Button::STATE_PRESSED)
- return IDR_AUTOFILL_DIALOG_MENU_BUTTON_P;
- else if (button_state == views::Button::STATE_HOVERED)
- return IDR_AUTOFILL_DIALOG_MENU_BUTTON_H;
- else if (button_state == views::Button::STATE_DISABLED)
- return IDR_AUTOFILL_DIALOG_MENU_BUTTON_D;
- DCHECK_EQ(views::Button::STATE_NORMAL, button_state);
- return IDR_AUTOFILL_DIALOG_MENU_BUTTON;
-}
-
-// AutofillDialogViews::DetailsContainerView -----------------------------------
-
-AutofillDialogViews::DetailsContainerView::DetailsContainerView(
- const base::Closure& callback)
- : bounds_changed_callback_(callback),
- ignore_layouts_(false) {}
-
-AutofillDialogViews::DetailsContainerView::~DetailsContainerView() {}
-
-void AutofillDialogViews::DetailsContainerView::OnBoundsChanged(
- const gfx::Rect& previous_bounds) {
- bounds_changed_callback_.Run();
-}
-
-void AutofillDialogViews::DetailsContainerView::Layout() {
- if (!ignore_layouts_)
- views::View::Layout();
-}
-
-// AutofillDialogViews::SuggestionView -----------------------------------------
-
-AutofillDialogViews::SuggestionView::SuggestionView(
- AutofillDialogViews* autofill_dialog)
- : label_(new views::Label()),
- label_line_2_(new views::Label()),
- icon_(new views::ImageView()),
- textfield_(
- new ExpandingTextfield(base::string16(),
- base::string16(),
- false,
- autofill_dialog)) {
- // TODO(estade): Make this the correct color.
- SetBorder(views::Border::CreateSolidSidedBorder(1, 0, 0, 0, SK_ColorLTGRAY));
-
- SectionRowView* label_container = new SectionRowView();
- AddChildView(label_container);
-
- // Label and icon.
- label_container->AddChildView(icon_);
- label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
- label_container->AddChildView(label_);
-
- // TODO(estade): get the sizing and spacing right on this textfield.
- textfield_->SetVisible(false);
- textfield_->SetDefaultWidthInCharacters(15);
- label_container->AddChildView(textfield_);
-
- label_line_2_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
- label_line_2_->SetVisible(false);
- label_line_2_->SetLineHeight(22);
- label_line_2_->SetMultiLine(true);
- AddChildView(label_line_2_);
-
- SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 7));
-}
-
-AutofillDialogViews::SuggestionView::~SuggestionView() {}
-
-gfx::Size AutofillDialogViews::SuggestionView::GetPreferredSize() const {
- // There's no preferred width. The parent's layout should get the preferred
- // height from GetHeightForWidth().
- return gfx::Size();
-}
-
-int AutofillDialogViews::SuggestionView::GetHeightForWidth(int width) const {
- int height = 0;
- CanUseVerticallyCompactText(width, &height);
- return height;
-}
-
-bool AutofillDialogViews::SuggestionView::CanUseVerticallyCompactText(
- int available_width,
- int* resulting_height) const {
- // This calculation may be costly, avoid doing it more than once per width.
- if (!calculated_heights_.count(available_width)) {
- // Changing the state of |this| now will lead to extra layouts and
- // paints we don't want, so create another SuggestionView to calculate
- // which label we have room to show.
- SuggestionView sizing_view(NULL);
- sizing_view.SetLabelText(state_.vertically_compact_text);
- sizing_view.SetIcon(state_.icon);
- sizing_view.SetTextfield(state_.extra_text, state_.extra_icon);
- sizing_view.label_->SetSize(gfx::Size(available_width, 0));
- sizing_view.label_line_2_->SetSize(gfx::Size(available_width, 0));
-
- // Shortcut |sizing_view|'s GetHeightForWidth() to avoid an infinite loop.
- // Its BoxLayout must do these calculations for us.
- views::LayoutManager* layout = sizing_view.GetLayoutManager();
- if (layout->GetPreferredSize(&sizing_view).width() <= available_width) {
- calculated_heights_[available_width] = std::make_pair(
- true,
- layout->GetPreferredHeightForWidth(&sizing_view, available_width));
- } else {
- sizing_view.SetLabelText(state_.horizontally_compact_text);
- calculated_heights_[available_width] = std::make_pair(
- false,
- layout->GetPreferredHeightForWidth(&sizing_view, available_width));
- }
- }
-
- const std::pair<bool, int>& values = calculated_heights_[available_width];
- *resulting_height = values.second;
- return values.first;
-}
-
-void AutofillDialogViews::SuggestionView::OnBoundsChanged(
- const gfx::Rect& previous_bounds) {
- UpdateLabelText();
-}
-
-void AutofillDialogViews::SuggestionView::SetState(
- const SuggestionState& state) {
- calculated_heights_.clear();
- state_ = state;
- SetVisible(state_.visible);
- UpdateLabelText();
- SetIcon(state_.icon);
- SetTextfield(state_.extra_text, state_.extra_icon);
- PreferredSizeChanged();
-}
-
-void AutofillDialogViews::SuggestionView::SetLabelText(
- const base::string16& text) {
- // TODO(estade): does this localize well?
- base::string16 line_return(base::ASCIIToUTF16("\n"));
- size_t position = text.find(line_return);
- if (position == base::string16::npos) {
- label_->SetText(text);
- label_line_2_->SetVisible(false);
- } else {
- label_->SetText(text.substr(0, position));
- label_line_2_->SetText(text.substr(position + line_return.length()));
- label_line_2_->SetVisible(true);
- }
-}
-
-void AutofillDialogViews::SuggestionView::SetIcon(
- const gfx::Image& image) {
- icon_->SetVisible(!image.IsEmpty());
- icon_->SetImage(image.AsImageSkia());
-}
-
-void AutofillDialogViews::SuggestionView::SetTextfield(
- const base::string16& placeholder_text,
- const gfx::Image& icon) {
- textfield_->SetPlaceholderText(placeholder_text);
- textfield_->SetIcon(icon);
- textfield_->SetVisible(!placeholder_text.empty());
-}
-
-void AutofillDialogViews::SuggestionView::UpdateLabelText() {
- int unused;
- SetLabelText(CanUseVerticallyCompactText(width(), &unused) ?
- state_.vertically_compact_text :
- state_.horizontally_compact_text);
-}
-
-// AutofillDialogView ----------------------------------------------------------
-
-// static
-AutofillDialogView* AutofillDialogView::Create(
- AutofillDialogViewDelegate* delegate) {
- return new AutofillDialogViews(delegate);
-}
-
-// AutofillDialogViews ---------------------------------------------------------
-
-AutofillDialogViews::AutofillDialogViews(AutofillDialogViewDelegate* delegate)
- : delegate_(delegate),
- updates_scope_(0),
- needs_update_(false),
- window_(NULL),
- notification_area_(NULL),
- scrollable_area_(NULL),
- details_container_(NULL),
- button_strip_extra_view_(NULL),
- save_in_chrome_checkbox_(NULL),
- save_in_chrome_checkbox_container_(NULL),
- focus_manager_(NULL),
- error_bubble_(NULL),
- observer_(this) {
- DCHECK(delegate);
- detail_groups_.insert(std::make_pair(SECTION_CC,
- DetailsGroup(SECTION_CC)));
- detail_groups_.insert(std::make_pair(SECTION_BILLING,
- DetailsGroup(SECTION_BILLING)));
- detail_groups_.insert(std::make_pair(SECTION_SHIPPING,
- DetailsGroup(SECTION_SHIPPING)));
-}
-
-AutofillDialogViews::~AutofillDialogViews() {
- HideErrorBubble();
- DCHECK(!window_);
-}
-
-void AutofillDialogViews::Show() {
- InitChildViews();
- UpdateNotificationArea();
- UpdateButtonStripExtraView();
-
- window_ = constrained_window::ShowWebModalDialogViews(
- this, delegate_->GetWebContents());
- focus_manager_ = window_->GetFocusManager();
- focus_manager_->AddFocusChangeListener(this);
-
- FocusInitialView();
-
- // Listen for size changes on the browser.
- views::Widget* browser_widget =
- views::Widget::GetTopLevelWidgetForNativeView(
- delegate_->GetWebContents()->GetNativeView());
- observer_.Add(browser_widget);
-
- // Listen for unhandled mouse presses on the non-client view.
- event_handler_.reset(new MousePressedHandler(delegate_));
- window_->GetRootView()->AddPostTargetHandler(event_handler_.get());
- observer_.Add(window_);
-}
-
-void AutofillDialogViews::Hide() {
- if (window_)
- window_->Close();
-}
-
-void AutofillDialogViews::UpdatesStarted() {
- updates_scope_++;
-}
-
-void AutofillDialogViews::UpdatesFinished() {
- updates_scope_--;
- DCHECK_GE(updates_scope_, 0);
- if (updates_scope_ == 0 && needs_update_) {
- needs_update_ = false;
- ContentsPreferredSizeChanged();
- }
-}
-
-void AutofillDialogViews::UpdateButtonStrip() {
- button_strip_extra_view_->SetVisible(
- GetDialogButtons() != ui::DIALOG_BUTTON_NONE);
- UpdateButtonStripExtraView();
- GetDialogClientView()->UpdateDialogButtons();
-
- ContentsPreferredSizeChanged();
-}
-
-void AutofillDialogViews::UpdateDetailArea() {
- scrollable_area_->SetVisible(true);
- ContentsPreferredSizeChanged();
-}
-
-void AutofillDialogViews::UpdateForErrors() {
- ValidateForm();
-}
-
-void AutofillDialogViews::UpdateNotificationArea() {
- DCHECK(notification_area_);
- notification_area_->SetNotifications(delegate_->CurrentNotifications());
- ContentsPreferredSizeChanged();
-}
-
-void AutofillDialogViews::UpdateSection(DialogSection section) {
- UpdateSectionImpl(section, true);
-}
-
-void AutofillDialogViews::UpdateErrorBubble() {
- if (!delegate_->ShouldShowErrorBubble())
- HideErrorBubble();
-}
-
-void AutofillDialogViews::FillSection(DialogSection section,
- ServerFieldType originating_type) {
- DetailsGroup* group = GroupForSection(section);
- // Make sure to overwrite the originating input if it exists.
- TextfieldMap::iterator text_mapping =
- group->textfields.find(originating_type);
- if (text_mapping != group->textfields.end())
- text_mapping->second->SetText(base::string16());
-
- // If the Autofill data comes from a credit card, make sure to overwrite the
- // CC comboboxes (even if they already have something in them). If the
- // Autofill data comes from an AutofillProfile, leave the comboboxes alone.
- if (section == GetCreditCardSection() &&
- AutofillType(originating_type).group() == CREDIT_CARD) {
- for (ComboboxMap::const_iterator it = group->comboboxes.begin();
- it != group->comboboxes.end(); ++it) {
- if (AutofillType(it->first).group() == CREDIT_CARD)
- it->second->SetSelectedIndex(it->second->model()->GetDefaultIndex());
- }
- }
-
- UpdateSectionImpl(section, false);
-}
-
-void AutofillDialogViews::GetUserInput(DialogSection section,
- FieldValueMap* output) {
- DetailsGroup* group = GroupForSection(section);
- for (TextfieldMap::const_iterator it = group->textfields.begin();
- it != group->textfields.end(); ++it) {
- output->insert(std::make_pair(it->first, it->second->GetText()));
- }
- for (ComboboxMap::const_iterator it = group->comboboxes.begin();
- it != group->comboboxes.end(); ++it) {
- output->insert(std::make_pair(it->first,
- it->second->model()->GetItemAt(it->second->selected_index())));
- }
-}
-
-base::string16 AutofillDialogViews::GetCvc() {
- return GroupForSection(GetCreditCardSection())->suggested_info->
- textfield()->GetText();
-}
-
-bool AutofillDialogViews::SaveDetailsLocally() {
- DCHECK(save_in_chrome_checkbox_->visible());
- return save_in_chrome_checkbox_->checked();
-}
-
-void AutofillDialogViews::ModelChanged() {
- menu_runner_.reset();
-
- for (DetailGroupMap::const_iterator iter = detail_groups_.begin();
- iter != detail_groups_.end(); ++iter) {
- UpdateDetailsGroupState(iter->second);
- }
-}
-
-void AutofillDialogViews::ValidateSection(DialogSection section) {
- ValidateGroup(*GroupForSection(section), VALIDATE_EDIT);
-}
-
-gfx::Size AutofillDialogViews::GetPreferredSize() const {
- if (preferred_size_.IsEmpty())
- preferred_size_ = CalculatePreferredSize(false);
-
- return preferred_size_;
-}
-
-gfx::Size AutofillDialogViews::GetMinimumSize() const {
- return CalculatePreferredSize(true);
-}
-
-void AutofillDialogViews::Layout() {
- const gfx::Rect content_bounds = GetContentsBounds();
- const int x = content_bounds.x();
- const int y = content_bounds.y();
- const int width = content_bounds.width();
- // Layout notification area at top of dialog.
- int notification_height = notification_area_->GetHeightForWidth(width);
- notification_area_->SetBounds(x, y, width, notification_height);
-
- // The rest (the |scrollable_area_|) takes up whatever's left.
- if (scrollable_area_->visible()) {
- int scroll_y = y;
- if (notification_height > notification_area_->GetInsets().height())
- scroll_y += notification_height + views::kRelatedControlVerticalSpacing;
-
- int scroll_bottom = content_bounds.bottom();
- DCHECK_EQ(scrollable_area_->contents(), details_container_);
- details_container_->SizeToPreferredSize();
- details_container_->Layout();
- // TODO(estade): remove this hack. See crbug.com/285996
- details_container_->set_ignore_layouts(true);
- scrollable_area_->SetBounds(x, scroll_y, width, scroll_bottom - scroll_y);
- details_container_->set_ignore_layouts(false);
- }
-
- if (error_bubble_)
- error_bubble_->UpdatePosition();
-}
-
-ui::ModalType AutofillDialogViews::GetModalType() const {
- return ui::MODAL_TYPE_CHILD;
-}
-
-base::string16 AutofillDialogViews::GetWindowTitle() const {
- base::string16 title = delegate_->DialogTitle();
- // Hack alert: we don't want the dialog to jiggle when a title is added or
- // removed. Setting a non-empty string here keeps the dialog's title bar the
- // same size.
- return title.empty() ? base::ASCIIToUTF16(" ") : title;
-}
-
-void AutofillDialogViews::WindowClosing() {
- focus_manager_->RemoveFocusChangeListener(this);
-}
-
-void AutofillDialogViews::DeleteDelegate() {
- window_ = NULL;
- // |this| belongs to the controller (|delegate_|).
- delegate_->ViewClosed();
-}
-
-int AutofillDialogViews::GetDialogButtons() const {
- return delegate_->GetDialogButtons();
-}
-
-int AutofillDialogViews::GetDefaultDialogButton() const {
- if (GetDialogButtons() & ui::DIALOG_BUTTON_OK)
- return ui::DIALOG_BUTTON_OK;
-
- return ui::DIALOG_BUTTON_NONE;
-}
-
-base::string16 AutofillDialogViews::GetDialogButtonLabel(
- ui::DialogButton button) const {
- return button == ui::DIALOG_BUTTON_OK ?
- delegate_->ConfirmButtonText() : delegate_->CancelButtonText();
-}
-
-bool AutofillDialogViews::ShouldDefaultButtonBeBlue() const {
- return true;
-}
-
-bool AutofillDialogViews::IsDialogButtonEnabled(ui::DialogButton button) const {
- return delegate_->IsDialogButtonEnabled(button);
-}
-
-views::View* AutofillDialogViews::GetInitiallyFocusedView() {
- if (!window_ || !focus_manager_)
- return NULL;
-
- DCHECK(scrollable_area_->visible());
-
- views::FocusManager* manager = focus_manager_;
- for (views::View* next = scrollable_area_;
- next;
- next = manager->GetNextFocusableView(next, window_, false, true)) {
- views::View* input_view = GetAncestralInputView(next);
- if (!input_view)
- continue;
-
- // If there are no invalid inputs, return the first input found. Otherwise,
- // return the first invalid input found.
- if (validity_map_.empty() ||
- validity_map_.find(input_view) != validity_map_.end()) {
- return next;
- }
- }
-
- return views::DialogDelegateView::GetInitiallyFocusedView();
-}
-
-views::View* AutofillDialogViews::CreateExtraView() {
- return button_strip_extra_view_;
-}
-
-bool AutofillDialogViews::Cancel() {
- delegate_->OnCancel();
- return true;
-}
-
-bool AutofillDialogViews::Accept() {
- if (ValidateForm()) {
- delegate_->OnAccept();
- } else {
- // |ValidateForm()| failed; there should be invalid views in
- // |validity_map_|.
- DCHECK(!validity_map_.empty());
- FocusInitialView();
- }
-
- return false;
-}
-
-void AutofillDialogViews::ContentsChanged(views::Textfield* sender,
- const base::string16& new_contents) {
- InputEditedOrActivated(TypeForTextfield(sender),
- sender->GetBoundsInScreen(),
- true);
-
- const ExpandingTextfield* expanding = static_cast<ExpandingTextfield*>(
- sender->GetAncestorWithClassName(ExpandingTextfield::kViewClassName));
- if (expanding && expanding->needs_layout())
- ContentsPreferredSizeChanged();
-}
-
-bool AutofillDialogViews::HandleKeyEvent(views::Textfield* sender,
- const ui::KeyEvent& key_event) {
- content::NativeWebKeyboardEvent event(key_event);
- return delegate_->HandleKeyPressEventInInput(event);
-}
-
-bool AutofillDialogViews::HandleMouseEvent(views::Textfield* sender,
- const ui::MouseEvent& mouse_event) {
- if (mouse_event.IsLeftMouseButton() && sender->HasFocus()) {
- InputEditedOrActivated(TypeForTextfield(sender),
- sender->GetBoundsInScreen(),
- false);
- // Show an error bubble if a user clicks on an input that's already focused
- // (and invalid).
- ShowErrorBubbleForViewIfNecessary(sender);
- }
-
- return false;
-}
-
-void AutofillDialogViews::OnWillChangeFocus(
- views::View* focused_before,
- views::View* focused_now) {
- delegate_->FocusMoved();
- HideErrorBubble();
-}
-
-void AutofillDialogViews::OnDidChangeFocus(
- views::View* focused_before,
- views::View* focused_now) {
- // If user leaves an edit-field, revalidate the group it belongs to.
- if (focused_before) {
- DetailsGroup* group = GroupForView(focused_before);
- if (group && group->container->visible())
- ValidateGroup(*group, VALIDATE_EDIT);
- }
-
- // Show an error bubble when the user focuses the input.
- if (focused_now) {
- focused_now->ScrollRectToVisible(focused_now->GetLocalBounds());
- ShowErrorBubbleForViewIfNecessary(focused_now);
- }
-}
-
-void AutofillDialogViews::OnPerformAction(views::Combobox* combobox) {
- DialogSection section = GroupForView(combobox)->section;
- InputEditedOrActivated(TypeForCombobox(combobox), gfx::Rect(), true);
- // NOTE: |combobox| may have been deleted.
- ValidateGroup(*GroupForSection(section), VALIDATE_EDIT);
-}
-
-void AutofillDialogViews::OnMenuButtonClicked(views::MenuButton* source,
- const gfx::Point& point,
- const ui::Event* event) {
- DCHECK_EQ(kSuggestedButtonClassName, source->GetClassName());
-
- DetailsGroup* group = NULL;
- for (DetailGroupMap::iterator iter = detail_groups_.begin();
- iter != detail_groups_.end(); ++iter) {
- if (source == iter->second.suggested_button) {
- group = &iter->second;
- break;
- }
- }
- DCHECK(group);
-
- if (!group->suggested_button->visible())
- return;
-
- menu_runner_.reset(
- new views::MenuRunner(delegate_->MenuModelForSection(group->section), 0));
-
- group->container->SetActive(true);
-
- gfx::Rect screen_bounds = source->GetBoundsInScreen();
- screen_bounds.Inset(source->GetInsets());
- if (menu_runner_->RunMenuAt(source->GetWidget(),
- group->suggested_button,
- screen_bounds,
- views::MENU_ANCHOR_TOPRIGHT,
- ui::MENU_SOURCE_NONE) ==
- views::MenuRunner::MENU_DELETED) {
- return;
- }
-
- group->container->SetActive(false);
-}
-
-gfx::Size AutofillDialogViews::CalculatePreferredSize(
- bool get_minimum_size) const {
- gfx::Insets insets = GetInsets();
- gfx::Size scroll_size = scrollable_area_->contents()->GetPreferredSize();
- // The width is always set by the scroll area.
- const int width = scroll_size.width();
-
- int height = 0;
- const int notification_height = notification_area_->GetHeightForWidth(width);
- if (notification_height > notification_area_->GetInsets().height())
- height += notification_height + views::kRelatedControlVerticalSpacing;
-
- if (scrollable_area_->visible())
- height += get_minimum_size ? kMinimumContentsHeight : scroll_size.height();
-
- return gfx::Size(width + insets.width(), height + insets.height());
-}
-
-gfx::Size AutofillDialogViews::GetMinimumSignInViewSize() const {
- return gfx::Size(GetDialogClientView()->size().width() - GetInsets().width(),
- kMinimumContentsHeight);
-}
-
-gfx::Size AutofillDialogViews::GetMaximumSignInViewSize() const {
- web_modal::WebContentsModalDialogHost* dialog_host =
- web_modal::WebContentsModalDialogManager::FromWebContents(
- delegate_->GetWebContents())->delegate()->
- GetWebContentsModalDialogHost();
-
- // Inset the maximum dialog height to get the maximum content height.
- int height = dialog_host->GetMaximumDialogSize().height();
- const int non_client_height = GetWidget()->non_client_view()->height();
- const int client_height = GetWidget()->client_view()->height();
- // TODO(msw): Resolve the 12 pixel discrepancy; is that the bubble border?
- height -= non_client_height - client_height - 12;
- height = std::max(height, kMinimumContentsHeight);
-
- // The dialog's width never changes.
- const int width = GetDialogClientView()->size().width() - GetInsets().width();
- return gfx::Size(width, height);
-}
-
-// TODO(estade): remove.
-DialogSection AutofillDialogViews::GetCreditCardSection() const {
- return SECTION_CC;
-}
-
-void AutofillDialogViews::InitChildViews() {
- button_strip_extra_view_ = new LayoutPropagationView();
- button_strip_extra_view_->SetLayoutManager(
- new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0));
-
- save_in_chrome_checkbox_container_ = new views::View();
- save_in_chrome_checkbox_container_->SetLayoutManager(
- new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 7));
- button_strip_extra_view_->AddChildView(save_in_chrome_checkbox_container_);
-
- save_in_chrome_checkbox_ =
- new views::Checkbox(delegate_->SaveLocallyText());
- save_in_chrome_checkbox_->SetChecked(delegate_->ShouldSaveInChrome());
- save_in_chrome_checkbox_container_->AddChildView(save_in_chrome_checkbox_);
-
- save_in_chrome_checkbox_container_->AddChildView(
- new TooltipIcon(delegate_->SaveLocallyTooltip()));
-
- notification_area_ = new NotificationArea(delegate_);
- AddChildView(notification_area_);
-
- scrollable_area_ = new views::ScrollView();
- scrollable_area_->set_hide_horizontal_scrollbar(true);
- scrollable_area_->SetContents(CreateDetailsContainer());
- AddChildView(scrollable_area_);
-}
-
-views::View* AutofillDialogViews::CreateDetailsContainer() {
- details_container_ = new DetailsContainerView(
- base::Bind(&AutofillDialogViews::DetailsContainerBoundsChanged,
- base::Unretained(this)));
-
- // A box layout is used because it respects widget visibility.
- details_container_->SetLayoutManager(
- new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
- for (DetailGroupMap::iterator iter = detail_groups_.begin();
- iter != detail_groups_.end(); ++iter) {
- CreateDetailsSection(iter->second.section);
- details_container_->AddChildView(iter->second.container);
- }
-
- return details_container_;
-}
-
-void AutofillDialogViews::CreateDetailsSection(DialogSection section) {
- // Inputs container (manual inputs + combobox).
- views::View* inputs_container = CreateInputsContainer(section);
-
- DetailsGroup* group = GroupForSection(section);
- // Container (holds label + inputs).
- group->container = new SectionContainer(delegate_->LabelForSection(section),
- inputs_container,
- group->suggested_button);
- DCHECK(group->suggested_button->parent());
- UpdateDetailsGroupState(*group);
-}
-
-views::View* AutofillDialogViews::CreateInputsContainer(DialogSection section) {
- // The |info_view| holds |manual_inputs| and |suggested_info|, allowing the
- // dialog to toggle which is shown.
- views::View* info_view = new views::View();
- info_view->SetLayoutManager(
- new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
-
- DetailsGroup* group = GroupForSection(section);
- group->manual_input = new views::View();
- InitInputsView(section);
- info_view->AddChildView(group->manual_input);
-
- group->suggested_info = new SuggestionView(this);
- info_view->AddChildView(group->suggested_info);
-
- // TODO(estade): It might be slightly more OO if this button were created
- // and listened to by the section container.
- group->suggested_button = new SuggestedButton(this);
-
- return info_view;
-}
-
-// TODO(estade): we should be using Chrome-style constrained window padding
-// values.
-void AutofillDialogViews::InitInputsView(DialogSection section) {
- DetailsGroup* group = GroupForSection(section);
- EraseInvalidViewsInGroup(group);
-
- TextfieldMap* textfields = &group->textfields;
- textfields->clear();
-
- ComboboxMap* comboboxes = &group->comboboxes;
- comboboxes->clear();
-
- views::View* view = group->manual_input;
- view->RemoveAllChildViews(true);
-
- views::GridLayout* layout = new views::GridLayout(view);
- view->SetLayoutManager(layout);
-
- int column_set_id = 0;
- const DetailInputs& inputs = delegate_->RequestedFieldsForSection(section);
- for (DetailInputs::const_iterator it = inputs.begin();
- it != inputs.end(); ++it) {
- const DetailInput& input = *it;
-
- ui::ComboboxModel* input_model =
- delegate_->ComboboxModelForAutofillType(input.type);
- std::unique_ptr<views::View> view_to_add;
- if (input_model) {
- views::Combobox* combobox = new views::Combobox(input_model);
- combobox->set_listener(this);
- comboboxes->insert(std::make_pair(input.type, combobox));
- SelectComboboxValueOrSetToDefault(combobox, input.initial_value);
- view_to_add.reset(combobox);
- } else {
- ExpandingTextfield* field = new ExpandingTextfield(input.initial_value,
- input.placeholder_text,
- input.IsMultiline(),
- this);
- textfields->insert(std::make_pair(input.type, field));
- view_to_add.reset(field);
- }
-
- if (input.length == DetailInput::NONE) {
- other_owned_views_.push_back(view_to_add.release());
- continue;
- }
-
- if (input.length == DetailInput::LONG)
- ++column_set_id;
-
- views::ColumnSet* column_set = layout->GetColumnSet(column_set_id);
- if (!column_set) {
- // Create a new column set and row.
- column_set = layout->AddColumnSet(column_set_id);
- if (it != inputs.begin())
- layout->AddPaddingRow(0, kManualInputRowPadding);
- layout->StartRow(0, column_set_id);
- } else {
- // Add a new column to existing row.
- column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
- // Must explicitly skip the padding column since we've already started
- // adding views.
- layout->SkipColumns(1);
- }
-
- float expand = input.expand_weight;
- column_set->AddColumn(views::GridLayout::FILL,
- views::GridLayout::FILL,
- expand ? expand : 1.0,
- views::GridLayout::USE_PREF,
- 0,
- 0);
-
- // This is the same as AddView(view_to_add), except that 1 is used for the
- // view's preferred width. Thus the width of the column completely depends
- // on |expand|.
- layout->AddView(view_to_add.release(), 1, 1,
- views::GridLayout::FILL, views::GridLayout::FILL,
- 1, 0);
-
- if (input.length == DetailInput::LONG ||
- input.length == DetailInput::SHORT_EOL) {
- ++column_set_id;
- }
- }
-
- SetIconsForSection(section);
-}
-
-void AutofillDialogViews::UpdateSectionImpl(
- DialogSection section,
- bool clobber_inputs) {
- DetailsGroup* group = GroupForSection(section);
-
- if (clobber_inputs) {
- ServerFieldType type = UNKNOWN_TYPE;
- views::View* focused = GetFocusManager()->GetFocusedView();
- if (focused && group->container->Contains(focused)) {
- // Remember which view was focused before the inputs are clobbered.
- if (focused->GetClassName() == ExpandingTextfield::kViewClassName)
- type = TypeForTextfield(focused);
- else if (focused->GetClassName() == views::Combobox::kViewClassName)
- type = TypeForCombobox(static_cast<views::Combobox*>(focused));
- }
-
- InitInputsView(section);
-
- if (type != UNKNOWN_TYPE) {
- // Restore the focus to the input with the previous type (e.g. country).
- views::View* to_focus = TextfieldForType(type);
- if (!to_focus) to_focus = ComboboxForType(type);
- if (to_focus)
- to_focus->RequestFocus();
- }
- } else {
- const DetailInputs& updated_inputs =
- delegate_->RequestedFieldsForSection(section);
-
- for (DetailInputs::const_iterator iter = updated_inputs.begin();
- iter != updated_inputs.end(); ++iter) {
- const DetailInput& input = *iter;
-
- TextfieldMap::iterator text_mapping = group->textfields.find(input.type);
- if (text_mapping != group->textfields.end()) {
- ExpandingTextfield* textfield = text_mapping->second;
- if (textfield->GetText().empty())
- textfield->SetText(input.initial_value);
- }
-
- ComboboxMap::iterator combo_mapping = group->comboboxes.find(input.type);
- if (combo_mapping != group->comboboxes.end()) {
- views::Combobox* combobox = combo_mapping->second;
- if (combobox->selected_index() == combobox->model()->GetDefaultIndex())
- SelectComboboxValueOrSetToDefault(combobox, input.initial_value);
- }
- }
-
- SetIconsForSection(section);
- }
-
- UpdateDetailsGroupState(*group);
-}
-
-void AutofillDialogViews::UpdateDetailsGroupState(const DetailsGroup& group) {
- const SuggestionState& suggestion_state =
- delegate_->SuggestionStateForSection(group.section);
- group.suggested_info->SetState(suggestion_state);
- group.manual_input->SetVisible(!suggestion_state.visible);
-
- UpdateButtonStripExtraView();
-
- const bool has_menu = !!delegate_->MenuModelForSection(group.section);
-
- if (group.suggested_button)
- group.suggested_button->SetVisible(has_menu);
-
- if (group.container) {
- group.container->SetForwardMouseEvents(
- has_menu && suggestion_state.visible);
- group.container->SetVisible(delegate_->SectionIsActive(group.section));
- if (group.container->visible())
- ValidateGroup(group, VALIDATE_EDIT);
- }
-
- ContentsPreferredSizeChanged();
-}
-
-void AutofillDialogViews::FocusInitialView() {
- views::View* to_focus = GetInitiallyFocusedView();
- if (to_focus && !to_focus->HasFocus())
- to_focus->RequestFocus();
-}
-
-template<class T>
-void AutofillDialogViews::SetValidityForInput(
- T* input,
- const base::string16& message) {
- bool invalid = !message.empty();
- input->SetInvalid(invalid);
-
- if (invalid) {
- validity_map_[input] = message;
- } else {
- validity_map_.erase(input);
-
- if (error_bubble_ &&
- error_bubble_->anchor()->GetAncestorWithClassName(
- input->GetClassName()) == input) {
- validity_map_.erase(input);
- HideErrorBubble();
- }
- }
-}
-
-void AutofillDialogViews::ShowErrorBubbleForViewIfNecessary(views::View* view) {
- if (!view->GetWidget())
- return;
-
- if (!delegate_->ShouldShowErrorBubble()) {
- DCHECK(!error_bubble_);
- return;
- }
-
- if (view->GetClassName() == DecoratedTextfield::kViewClassName &&
- !static_cast<DecoratedTextfield*>(view)->invalid()) {
- return;
- }
-
- views::View* input_view = GetAncestralInputView(view);
- std::map<views::View*, base::string16>::iterator error_message =
- validity_map_.find(input_view);
- if (error_message != validity_map_.end()) {
- input_view->ScrollRectToVisible(input_view->GetLocalBounds());
-
- if (!error_bubble_ || error_bubble_->anchor() != view) {
- HideErrorBubble();
- error_bubble_ = new InfoBubble(view, error_message->second);
- error_bubble_->set_align_to_anchor_edge(true);
- error_bubble_->set_preferred_width(
- (kSectionContainerWidth - views::kRelatedControlVerticalSpacing) / 2);
- bool show_above = view->GetClassName() == views::Combobox::kViewClassName;
- error_bubble_->set_show_above_anchor(show_above);
- error_bubble_->Show();
- observer_.Add(error_bubble_->GetWidget());
- }
- }
-}
-
-void AutofillDialogViews::HideErrorBubble() {
- if (error_bubble_)
- error_bubble_->Hide();
-}
-
-void AutofillDialogViews::MarkInputsInvalid(
- DialogSection section,
- const ValidityMessages& messages,
- bool overwrite_unsure) {
- DetailsGroup* group = GroupForSection(section);
- DCHECK(group->container->visible());
-
- if (group->manual_input->visible()) {
- for (TextfieldMap::const_iterator iter = group->textfields.begin();
- iter != group->textfields.end(); ++iter) {
- const ValidityMessage& message =
- messages.GetMessageOrDefault(iter->first);
- if (overwrite_unsure || message.sure)
- SetValidityForInput(iter->second, message.text);
- }
- for (ComboboxMap::const_iterator iter = group->comboboxes.begin();
- iter != group->comboboxes.end(); ++iter) {
- const ValidityMessage& message =
- messages.GetMessageOrDefault(iter->first);
- if (overwrite_unsure || message.sure)
- SetValidityForInput(iter->second, message.text);
- }
- } else {
- EraseInvalidViewsInGroup(group);
-
- if (section == GetCreditCardSection()) {
- // Special case CVC as it's not part of |group->manual_input|.
- const ValidityMessage& message =
- messages.GetMessageOrDefault(CREDIT_CARD_VERIFICATION_CODE);
- if (overwrite_unsure || message.sure) {
- SetValidityForInput(group->suggested_info->textfield(), message.text);
- }
- }
- }
-}
-
-bool AutofillDialogViews::ValidateGroup(const DetailsGroup& group,
- ValidationType validation_type) {
- DCHECK(group.container->visible());
-
- FieldValueMap detail_outputs;
-
- if (group.manual_input->visible()) {
- for (TextfieldMap::const_iterator iter = group.textfields.begin();
- iter != group.textfields.end(); ++iter) {
- if (!iter->second->editable())
- continue;
-
- detail_outputs[iter->first] = iter->second->GetText();
- }
- for (ComboboxMap::const_iterator iter = group.comboboxes.begin();
- iter != group.comboboxes.end(); ++iter) {
- if (!iter->second->enabled())
- continue;
-
- views::Combobox* combobox = iter->second;
- base::string16 item =
- combobox->model()->GetItemAt(combobox->selected_index());
- detail_outputs[iter->first] = item;
- }
- } else if (group.section == GetCreditCardSection()) {
- ExpandingTextfield* cvc = group.suggested_info->textfield();
- if (cvc->visible())
- detail_outputs[CREDIT_CARD_VERIFICATION_CODE] = cvc->GetText();
- }
-
- ValidityMessages validity = delegate_->InputsAreValid(group.section,
- detail_outputs);
- MarkInputsInvalid(group.section, validity, validation_type == VALIDATE_FINAL);
-
- // If there are any validation errors, sure or unsure, the group is invalid.
- return !validity.HasErrors();
-}
-
-bool AutofillDialogViews::ValidateForm() {
- bool all_valid = true;
- validity_map_.clear();
-
- for (DetailGroupMap::iterator iter = detail_groups_.begin();
- iter != detail_groups_.end(); ++iter) {
- const DetailsGroup& group = iter->second;
- if (!group.container->visible())
- continue;
-
- if (!ValidateGroup(group, VALIDATE_FINAL))
- all_valid = false;
- }
-
- return all_valid;
-}
-
-void AutofillDialogViews::InputEditedOrActivated(ServerFieldType type,
- const gfx::Rect& bounds,
- bool was_edit) {
- DCHECK_NE(UNKNOWN_TYPE, type);
-
- ExpandingTextfield* textfield = TextfieldForType(type);
- views::Combobox* combobox = ComboboxForType(type);
-
- // Both views may be NULL if the event comes from an inactive section, which
- // may occur when using an IME.
- if (!combobox && !textfield)
- return;
-
- DCHECK_NE(!!combobox, !!textfield);
- DetailsGroup* group = textfield ? GroupForView(textfield) :
- GroupForView(combobox);
- base::string16 text = textfield ?
- textfield->GetText() :
- combobox->model()->GetItemAt(combobox->selected_index());
- DCHECK(group);
-
- delegate_->UserEditedOrActivatedInput(group->section,
- type,
- GetWidget()->GetNativeView(),
- bounds,
- text,
- was_edit);
-
- // If the field is a textfield and is invalid, check if the text is now valid.
- // Many fields (i.e. CC#) are invalid for most of the duration of editing,
- // so flagging them as invalid prematurely is not helpful. However,
- // correcting a minor mistake (i.e. a wrong CC digit) should immediately
- // result in validation - positive user feedback.
- if (textfield && textfield->invalid() && was_edit) {
- SetValidityForInput(
- textfield,
- delegate_->InputValidityMessage(
- group->section, type, textfield->GetText()));
-
- // If the field transitioned from invalid to valid, re-validate the group,
- // since inter-field checks become meaningful with valid fields.
- if (!textfield->invalid())
- ValidateGroup(*group, VALIDATE_EDIT);
- }
-
- if (delegate_->FieldControlsIcons(type))
- SetIconsForSection(group->section);
-}
-
-void AutofillDialogViews::UpdateButtonStripExtraView() {
- save_in_chrome_checkbox_container_->SetVisible(
- delegate_->ShouldOfferToSaveInChrome());
-}
-
-void AutofillDialogViews::ContentsPreferredSizeChanged() {
- if (updates_scope_ != 0) {
- needs_update_ = true;
- return;
- }
-
- preferred_size_ = gfx::Size();
-
- if (GetWidget() && delegate_ && delegate_->GetWebContents()) {
- constrained_window::UpdateWebContentsModalDialogPosition(
- GetWidget(),
- web_modal::WebContentsModalDialogManager::FromWebContents(
- delegate_->GetWebContents())->delegate()->
- GetWebContentsModalDialogHost());
- SetBoundsRect(bounds());
- }
-}
-
-AutofillDialogViews::DetailsGroup* AutofillDialogViews::GroupForSection(
- DialogSection section) {
- return &detail_groups_.find(section)->second;
-}
-
-AutofillDialogViews::DetailsGroup* AutofillDialogViews::GroupForView(
- views::View* view) {
- DCHECK(view);
-
- views::View* input_view = GetAncestralInputView(view);
- if (!input_view)
- return NULL;
-
- for (DetailGroupMap::iterator iter = detail_groups_.begin();
- iter != detail_groups_.end(); ++iter) {
- DetailsGroup* group = &iter->second;
- if (input_view->parent() == group->manual_input)
- return group;
-
- // Textfields need to check a second case, since they can be suggested
- // inputs instead of directly editable inputs. Those are accessed via
- // |suggested_info|.
- if (input_view == group->suggested_info->textfield()) {
- return group;
- }
- }
-
- return NULL;
-}
-
-void AutofillDialogViews::EraseInvalidViewsInGroup(const DetailsGroup* group) {
- std::map<views::View*, base::string16>::iterator it = validity_map_.begin();
- while (it != validity_map_.end()) {
- if (GroupForView(it->first) == group)
- validity_map_.erase(it++);
- else
- ++it;
- }
-}
-
-ExpandingTextfield* AutofillDialogViews::TextfieldForType(
- ServerFieldType type) {
- if (type == CREDIT_CARD_VERIFICATION_CODE) {
- DetailsGroup* group = GroupForSection(GetCreditCardSection());
- if (!group->manual_input->visible())
- return group->suggested_info->textfield();
- }
-
- for (DetailGroupMap::iterator iter = detail_groups_.begin();
- iter != detail_groups_.end(); ++iter) {
- const DetailsGroup& group = iter->second;
- if (!delegate_->SectionIsActive(group.section))
- continue;
-
- TextfieldMap::const_iterator text_mapping = group.textfields.find(type);
- if (text_mapping != group.textfields.end())
- return text_mapping->second;
- }
-
- return NULL;
-}
-
-ServerFieldType AutofillDialogViews::TypeForTextfield(
- const views::View* textfield) {
- const views::View* expanding =
- textfield->GetAncestorWithClassName(ExpandingTextfield::kViewClassName);
-
- DetailsGroup* cc_group = GroupForSection(GetCreditCardSection());
- if (expanding == cc_group->suggested_info->textfield())
- return CREDIT_CARD_VERIFICATION_CODE;
-
- for (DetailGroupMap::const_iterator it = detail_groups_.begin();
- it != detail_groups_.end(); ++it) {
- if (!delegate_->SectionIsActive(it->second.section))
- continue;
-
- for (TextfieldMap::const_iterator text_it = it->second.textfields.begin();
- text_it != it->second.textfields.end(); ++text_it) {
- if (expanding == text_it->second)
- return text_it->first;
- }
- }
-
- return UNKNOWN_TYPE;
-}
-
-views::Combobox* AutofillDialogViews::ComboboxForType(
- ServerFieldType type) {
- for (DetailGroupMap::iterator iter = detail_groups_.begin();
- iter != detail_groups_.end(); ++iter) {
- const DetailsGroup& group = iter->second;
- if (!delegate_->SectionIsActive(group.section))
- continue;
-
- ComboboxMap::const_iterator combo_mapping = group.comboboxes.find(type);
- if (combo_mapping != group.comboboxes.end())
- return combo_mapping->second;
- }
-
- return NULL;
-}
-
-ServerFieldType AutofillDialogViews::TypeForCombobox(
- const views::Combobox* combobox) const {
- for (DetailGroupMap::const_iterator it = detail_groups_.begin();
- it != detail_groups_.end(); ++it) {
- const DetailsGroup& group = it->second;
- if (!delegate_->SectionIsActive(group.section))
- continue;
-
- for (ComboboxMap::const_iterator combo_it = group.comboboxes.begin();
- combo_it != group.comboboxes.end(); ++combo_it) {
- if (combo_it->second == combobox)
- return combo_it->first;
- }
- }
-
- return UNKNOWN_TYPE;
-}
-
-void AutofillDialogViews::DetailsContainerBoundsChanged() {
- if (error_bubble_)
- error_bubble_->UpdatePosition();
-}
-
-void AutofillDialogViews::SetIconsForSection(DialogSection section) {
- FieldValueMap user_input;
- GetUserInput(section, &user_input);
- FieldIconMap field_icons = delegate_->IconsForFields(user_input);
- TextfieldMap* textfields = &GroupForSection(section)->textfields;
- for (TextfieldMap::const_iterator textfield_it = textfields->begin();
- textfield_it != textfields->end();
- ++textfield_it) {
- ServerFieldType field_type = textfield_it->first;
- FieldIconMap::const_iterator field_icon_it = field_icons.find(field_type);
- ExpandingTextfield* textfield = textfield_it->second;
- if (field_icon_it != field_icons.end())
- textfield->SetIcon(field_icon_it->second);
- else
- textfield->SetTooltipIcon(delegate_->TooltipForField(field_type));
- }
-}
-
-void AutofillDialogViews::NonClientMousePressed() {
- delegate_->FocusMoved();
-}
-
-views::View* AutofillDialogViews::GetNotificationAreaForTesting() {
- return notification_area_;
-}
-
-views::View* AutofillDialogViews::GetScrollableAreaForTesting() {
- return scrollable_area_;
-}
-
-AutofillDialogViews::DetailsGroup::DetailsGroup(DialogSection section)
- : section(section),
- container(NULL),
- manual_input(NULL),
- suggested_info(NULL),
- suggested_button(NULL) {}
-
-AutofillDialogViews::DetailsGroup::DetailsGroup(const DetailsGroup& other) =
- default;
-
-AutofillDialogViews::DetailsGroup::~DetailsGroup() {}
-
-} // namespace autofill

Powered by Google App Engine
This is Rietveld 408576698