1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef CHROME_BROWSER_UI_VIEWS_AUTOFILL_AUTOFILL_DIALOG_VIEWS_H_
6 #define CHROME_BROWSER_UI_VIEWS_AUTOFILL_AUTOFILL_DIALOG_VIEWS_H_
11 #include "base/memory/scoped_vector.h"
12 #include "base/memory/weak_ptr.h"
13 #include "base/scoped_observer.h"
14 #include "chrome/browser/ui/autofill/autofill_dialog_types.h"
15 #include "chrome/browser/ui/autofill/autofill_dialog_view.h"
16 #include "chrome/browser/ui/autofill/autofill_dialog_view_delegate.h"
17 #include "ui/views/controls/button/button.h"
18 #include "ui/views/controls/button/menu_button.h"
19 #include "ui/views/controls/button/menu_button_listener.h"
20 #include "ui/views/controls/combobox/combobox_listener.h"
21 #include "ui/views/controls/link_listener.h"
22 #include "ui/views/controls/progress_bar.h"
23 #include "ui/views/controls/scroll_view.h"
24 #include "ui/views/controls/styled_label_listener.h"
25 #include "ui/views/controls/textfield/textfield_controller.h"
26 #include "ui/views/focus/focus_manager.h"
27 #include "ui/views/view_targeter_delegate.h"
28 #include "ui/views/widget/widget_observer.h"
29 #include "ui/views/window/dialog_delegate.h"
58 class AutofillDialogSignInDelegate;
59 class ExpandingTextfield;
62 // Views toolkit implementation of the Autofill dialog that handles the
63 // imperative autocomplete API call.
64 class AutofillDialogViews : public AutofillDialogView,
65 public views::DialogDelegateView,
66 public views::WidgetObserver,
67 public views::TextfieldController,
68 public views::FocusChangeListener,
69 public views::ComboboxListener,
70 public views::StyledLabelListener,
71 public views::MenuButtonListener {
73 explicit AutofillDialogViews(AutofillDialogViewDelegate* delegate);
74 ~AutofillDialogViews() override;
76 // AutofillDialogView implementation:
79 void UpdatesStarted() override;
80 void UpdatesFinished() override;
81 void UpdateAccountChooser() override;
82 void UpdateButtonStrip() override;
83 void UpdateOverlay() override;
84 void UpdateDetailArea() override;
85 void UpdateForErrors() override;
86 void UpdateNotificationArea() override;
87 void UpdateSection(DialogSection section) override;
88 void UpdateErrorBubble() override;
89 void FillSection(DialogSection section,
90 ServerFieldType originating_type) override;
91 void GetUserInput(DialogSection section, FieldValueMap* output) override;
92 base::string16 GetCvc() override;
93 bool SaveDetailsLocally() override;
94 const content::NavigationController* ShowSignIn(const GURL& url) override;
95 void HideSignIn() override;
96 void ModelChanged() override;
97 void OnSignInResize(const gfx::Size& pref_size) override;
98 void ValidateSection(DialogSection section) override;
100 // views::View implementation.
101 gfx::Size GetPreferredSize() const override;
102 gfx::Size GetMinimumSize() const override;
103 void Layout() override;
104 void OnNativeThemeChanged(const ui::NativeTheme* theme) override;
106 // views::DialogDelegate implementation:
107 ui::ModalType GetModalType() const override;
108 base::string16 GetWindowTitle() const override;
109 void WindowClosing() override;
110 void DeleteDelegate() override;
111 views::View* CreateOverlayView() override;
112 int GetDialogButtons() const override;
113 int GetDefaultDialogButton() const override;
114 base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
115 bool ShouldDefaultButtonBeBlue() const override;
116 bool IsDialogButtonEnabled(ui::DialogButton button) const override;
117 views::View* GetInitiallyFocusedView() override;
118 views::View* CreateExtraView() override;
119 views::View* CreateTitlebarExtraView() override;
120 views::View* CreateFootnoteView() override;
121 bool Cancel() override;
122 bool Accept() override;
124 // views::WidgetObserver implementation:
125 void OnWidgetClosing(views::Widget* widget) override;
126 void OnWidgetDestroying(views::Widget* widget) override;
127 void OnWidgetBoundsChanged(views::Widget* widget,
128 const gfx::Rect& new_bounds) override;
130 // views::TextfieldController implementation:
131 void ContentsChanged(views::Textfield* sender,
132 const base::string16& new_contents) override;
133 bool HandleKeyEvent(views::Textfield* sender,
134 const ui::KeyEvent& key_event) override;
135 bool HandleMouseEvent(views::Textfield* sender,
136 const ui::MouseEvent& key_event) override;
138 // views::FocusChangeListener implementation.
139 void OnWillChangeFocus(views::View* focused_before,
140 views::View* focused_now) override;
141 void OnDidChangeFocus(views::View* focused_before,
142 views::View* focused_now) override;
144 // views::ComboboxListener implementation:
145 void OnPerformAction(views::Combobox* combobox) override;
147 // views::StyledLabelListener implementation:
148 void StyledLabelLinkClicked(const gfx::Range& range,
149 int event_flags) override;
151 // views::MenuButtonListener implementation.
152 void OnMenuButtonClicked(views::View* source,
153 const gfx::Point& point) override;
156 // Exposed for testing.
157 views::View* GetLoadingShieldForTesting();
158 views::WebView* GetSignInWebViewForTesting();
159 views::View* GetNotificationAreaForTesting();
160 views::View* GetScrollableAreaForTesting();
163 friend class AutofillDialogViewTesterViews;
165 // What the entire dialog should be doing (e.g. gathering info from the user,
166 // asking the user to sign in, etc.).
173 // A View which displays the currently selected account and lets the user
175 class AccountChooser : public views::View,
176 public views::LinkListener,
177 public views::MenuButtonListener,
178 public base::SupportsWeakPtr<AccountChooser> {
180 explicit AccountChooser(AutofillDialogViewDelegate* delegate);
181 ~AccountChooser() override;
183 // Updates the view based on the state that |delegate_| reports.
186 // views::LinkListener implementation.
187 void LinkClicked(views::Link* source, int event_flags) override;
189 // views::MenuButtonListener implementation.
190 void OnMenuButtonClicked(views::View* source,
191 const gfx::Point& point) override;
194 // The icon for the currently in-use account.
195 views::ImageView* image_;
197 // The button for showing a menu to change the currently in-use account.
198 views::MenuButton* menu_button_;
203 // The delegate |this| queries for logic and state.
204 AutofillDialogViewDelegate* delegate_;
206 // Runs the suggestion menu (triggered by each section's |suggested_button|.
207 scoped_ptr<views::MenuRunner> menu_runner_;
209 DISALLOW_COPY_AND_ASSIGN(AccountChooser);
212 // A view which displays an image, optionally some messages and a button. Used
213 // for the Wallet interstitial.
214 class OverlayView : public views::View {
216 explicit OverlayView(AutofillDialogViewDelegate* delegate);
217 ~OverlayView() override;
219 // Returns a height which should be used when the contents view has width
220 // |w|. Note that the value returned should be used as the height of the
221 // dialog's contents.
222 int GetHeightForContentsForWidth(int width);
224 // Sets the state to whatever |delegate_| says it should be.
227 // views::View implementation:
228 gfx::Insets GetInsets() const override;
229 void Layout() override;
230 const char* GetClassName() const override;
231 void OnPaint(gfx::Canvas* canvas) override;
232 void OnNativeThemeChanged(const ui::NativeTheme* theme) override;
235 // Gets the border of the non-client frame view as a BubbleBorder.
236 views::BubbleBorder* GetBubbleBorder();
238 // Gets the bounds of this view without the frame view's bubble border.
239 gfx::Rect ContentBoundsSansBubbleBorder();
241 // The delegate that provides |state| when UpdateState is called.
242 AutofillDialogViewDelegate* delegate_;
244 // Child View. Front and center.
245 views::ImageView* image_view_;
246 // Child View. When visible, below |image_view_|.
247 views::Label* message_view_;
249 DISALLOW_COPY_AND_ASSIGN(OverlayView);
252 // An area for notifications. Some notifications point at the account chooser.
253 class NotificationArea : public views::View {
255 explicit NotificationArea(AutofillDialogViewDelegate* delegate);
256 ~NotificationArea() override;
258 // Displays the given notifications.
259 void SetNotifications(const std::vector<DialogNotification>& notifications);
261 // views::View implementation.
262 gfx::Size GetPreferredSize() const override;
263 const char* GetClassName() const override;
264 void PaintChildren(gfx::Canvas* canvas,
265 const views::CullSet& cull_set) override;
266 void OnPaint(gfx::Canvas* canvas) override;
268 void set_arrow_centering_anchor(
269 const base::WeakPtr<views::View>& arrow_centering_anchor) {
270 arrow_centering_anchor_ = arrow_centering_anchor;
274 // Utility function for determining whether an arrow should be drawn
275 // pointing at |arrow_centering_anchor_|.
278 // A reference to the delegate/controller than owns this view.
279 // Used to report when checkboxes change their values.
280 AutofillDialogViewDelegate* delegate_; // weak
282 // If HasArrow() is true, the arrow should point at this.
283 base::WeakPtr<views::View> arrow_centering_anchor_;
285 std::vector<DialogNotification> notifications_;
287 DISALLOW_COPY_AND_ASSIGN(NotificationArea);
290 typedef std::map<ServerFieldType, ExpandingTextfield*> TextfieldMap;
291 typedef std::map<ServerFieldType, views::Combobox*> ComboboxMap;
293 // A view that packs a label on the left and some related controls
295 class SectionContainer : public views::View,
296 public views::ViewTargeterDelegate {
298 SectionContainer(const base::string16& label,
299 views::View* controls,
300 views::Button* proxy_button);
301 ~SectionContainer() override;
303 // Sets the visual appearance of the section to active (considered active
304 // when showing the menu or hovered by the mouse cursor).
305 void SetActive(bool active);
307 // Sets whether mouse events should be forwarded to |proxy_button_|.
308 void SetForwardMouseEvents(bool forward);
310 // views::View implementation.
311 const char* GetClassName() const override;
312 void OnMouseMoved(const ui::MouseEvent& event) override;
313 void OnMouseEntered(const ui::MouseEvent& event) override;
314 void OnMouseExited(const ui::MouseEvent& event) override;
315 bool OnMousePressed(const ui::MouseEvent& event) override;
316 void OnMouseReleased(const ui::MouseEvent& event) override;
317 void OnGestureEvent(ui::GestureEvent* event) override;
320 // views::ViewTargeterDelegate:
321 views::View* TargetForRect(views::View* root,
322 const gfx::Rect& rect) override;
324 // Converts |event| to one suitable for |proxy_button_|.
325 static ui::MouseEvent ProxyEvent(const ui::MouseEvent& event);
327 // Returns true if the given event should be forwarded to |proxy_button_|.
328 bool ShouldForwardEvent(const ui::LocatedEvent& event);
330 // Mouse events on |this| are sent to this button.
331 views::Button* proxy_button_; // Weak reference.
333 // When true, all mouse events will be forwarded to |proxy_button_|.
334 bool forward_mouse_events_;
336 DISALLOW_COPY_AND_ASSIGN(SectionContainer);
339 // A button to show address or billing suggestions.
340 class SuggestedButton : public views::MenuButton {
342 explicit SuggestedButton(views::MenuButtonListener* listener);
343 ~SuggestedButton() override;
345 // views::MenuButton implementation.
346 gfx::Size GetPreferredSize() const override;
347 const char* GetClassName() const override;
348 void PaintChildren(gfx::Canvas* canvas,
349 const views::CullSet& cull_set) override;
350 void OnPaint(gfx::Canvas* canvas) override;
353 // Returns the corred resource ID (i.e. IDR_*) for the current |state()|.
354 int ResourceIDForState() const;
356 DISALLOW_COPY_AND_ASSIGN(SuggestedButton);
359 // A view that runs a callback whenever its bounds change, and which can
360 // optionally suppress layout.
361 class DetailsContainerView : public views::View {
363 explicit DetailsContainerView(const base::Closure& callback);
364 ~DetailsContainerView() override;
366 void set_ignore_layouts(bool ignore_layouts) {
367 ignore_layouts_ = ignore_layouts;
370 // views::View implementation.
371 void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
372 void Layout() override;
375 base::Closure bounds_changed_callback_;
377 // The view ignores Layout() calls when this is true.
378 bool ignore_layouts_;
380 DISALLOW_COPY_AND_ASSIGN(DetailsContainerView);
383 // A view that contains a suggestion (such as a known address).
384 class SuggestionView : public views::View {
386 explicit SuggestionView(AutofillDialogViews* autofill_dialog);
387 ~SuggestionView() override;
389 void SetState(const SuggestionState& state);
391 // views::View implementation.
392 gfx::Size GetPreferredSize() const override;
393 int GetHeightForWidth(int width) const override;
394 void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
396 ExpandingTextfield* textfield() { return textfield_; }
399 // Returns whether there's room to display |state_.vertically_compact_text|
400 // without resorting to an ellipsis for a pixel width of |available_width|.
401 // Fills in |resulting_height| with the amount of space required to display
402 // |vertically_compact_text| or |horizontally_compact_text| as the case may
404 bool CanUseVerticallyCompactText(int available_width,
405 int* resulting_height) const;
407 // Sets the display text of the suggestion.
408 void SetLabelText(const base::string16& text);
410 // Sets the icon which should be displayed ahead of the text.
411 void SetIcon(const gfx::Image& image);
413 // Shows an auxiliary textfield to the right of the suggestion icon and
414 // text. This is currently only used to show a CVC field for the CC section.
415 void SetTextfield(const base::string16& placeholder_text,
416 const gfx::Image& icon);
418 // Calls SetLabelText() with the appropriate text based on current bounds.
419 void UpdateLabelText();
421 // The state of |this|.
422 SuggestionState state_;
424 // This caches preferred heights for given widths. The key is a preferred
425 // width, the value is a cached result of CanUseVerticallyCompactText.
426 mutable std::map<int, std::pair<bool, int> > calculated_heights_;
428 // The label that holds the suggestion description text.
429 views::Label* label_;
430 // The second (and greater) line of text that describes the suggestion.
431 views::Label* label_line_2_;
432 // The icon that comes just before |label_|.
433 views::ImageView* icon_;
434 // The input set by ShowTextfield.
435 ExpandingTextfield* textfield_;
437 DISALLOW_COPY_AND_ASSIGN(SuggestionView);
440 // A convenience struct for holding pointers to views within each detail
441 // section. None of the member pointers are owned.
442 struct DetailsGroup {
443 explicit DetailsGroup(DialogSection section);
446 // The section this group is associated with.
447 const DialogSection section;
448 // The view that contains the entire section (label + input).
449 SectionContainer* container;
450 // The view that allows manual input.
451 views::View* manual_input;
452 // The textfields in |manual_input|, tracked by their ServerFieldType.
453 TextfieldMap textfields;
454 // The comboboxes in |manual_input|, tracked by their ServerFieldType.
455 ComboboxMap comboboxes;
456 // The view that holds the text of the suggested data. This will be
457 // visible IFF |manual_input| is not visible.
458 SuggestionView* suggested_info;
459 // The view that allows selecting other data suggestions.
460 SuggestedButton* suggested_button;
463 typedef std::map<DialogSection, DetailsGroup> DetailGroupMap;
465 // Returns the preferred size or minimum size (if |get_minimum_size| is true).
466 gfx::Size CalculatePreferredSize(bool get_minimum_size) const;
468 // Returns the minimum size of the sign in view for this dialog.
469 gfx::Size GetMinimumSignInViewSize() const;
471 // Returns the maximum size of the sign in view for this dialog.
472 gfx::Size GetMaximumSignInViewSize() const;
474 // Returns which section should currently be used for credit card info.
475 DialogSection GetCreditCardSection() const;
477 void InitChildViews();
479 // Creates and returns a view that holds all detail sections.
480 views::View* CreateDetailsContainer();
482 // Creates and returns a view that holds the requesting host and intro text.
483 views::View* CreateNotificationArea();
485 // Creates and returns a view that holds the main controls of this dialog.
486 views::View* CreateMainContainer();
488 // Creates a detail section (Shipping, Email, etc.) with the given label,
489 // inputs View, and suggestion model. Relevant pointers are stored in |group|.
490 void CreateDetailsSection(DialogSection section);
492 // Creates the view that holds controls for inputing or selecting data for
494 views::View* CreateInputsContainer(DialogSection section);
496 // Creates a grid of inputs for the given section.
497 void InitInputsView(DialogSection section);
499 // Changes the function of the whole dialog. Currently this can show a loading
500 // shield, an embedded sign in web view, or the more typical detail input mode
501 // (suggestions and form inputs).
502 void ShowDialogInMode(DialogMode dialog_mode);
504 // Updates the given section to match the state provided by |delegate_|. If
505 // |clobber_inputs| is true, the current state of the textfields will be
506 // ignored, otherwise their contents will be preserved.
507 void UpdateSectionImpl(DialogSection section, bool clobber_inputs);
509 // Updates the visual state of the given group as per the model.
510 void UpdateDetailsGroupState(const DetailsGroup& group);
512 // Gets a pointer to the DetailsGroup that's associated with the given section
514 DetailsGroup* GroupForSection(DialogSection section);
516 // Gets a pointer to the DetailsGroup that's associated with a given |view|.
517 // Returns NULL if no DetailsGroup was found.
518 DetailsGroup* GroupForView(views::View* view);
520 // Erases all views in |group| from |validity_map_|.
521 void EraseInvalidViewsInGroup(const DetailsGroup* group);
523 // Explicitly focuses the initially focusable view.
524 void FocusInitialView();
526 // Sets the visual state for an input to be either valid or invalid. This
527 // should work on Comboboxes or ExpandingTextfields. If |message| is empty,
528 // the input is valid.
530 void SetValidityForInput(T* input, const base::string16& message);
532 // Shows an error bubble pointing at |view| if |view| has a message in
534 void ShowErrorBubbleForViewIfNecessary(views::View* view);
536 // Hides |error_bubble_| (if it exists).
537 void HideErrorBubble();
539 // Updates validity of the inputs in |section| with new |validity_messages|.
540 // Fields are only updated with unsure messages if |overwrite_valid| is true.
541 void MarkInputsInvalid(DialogSection section,
542 const ValidityMessages& validity_messages,
543 bool overwrite_invalid);
545 // Checks all manual inputs in |group| for validity. Decorates the invalid
546 // ones and returns true if all were valid.
547 bool ValidateGroup(const DetailsGroup& group, ValidationType type);
549 // Checks all manual inputs in the form for validity. Decorates the invalid
550 // ones and returns true if all were valid.
553 // When an input is edited (its contents change) or activated (clicked while
554 // focused), this function will inform the delegate to take the appropriate
555 // action (textfields may show a suggestion popup, comboboxes may rebuild the
556 // section inputs). May also reset the validity state of the input.
557 void InputEditedOrActivated(ServerFieldType type,
558 const gfx::Rect& bounds,
561 // Updates the views in the button strip.
562 void UpdateButtonStripExtraView();
564 // Call this when the size of anything in the contents might have changed.
565 void ContentsPreferredSizeChanged();
566 void DoContentsPreferredSizeChanged();
568 // Gets the textfield view that is shown for the given |type| or NULL.
569 ExpandingTextfield* TextfieldForType(ServerFieldType type);
571 // Returns the associated ServerFieldType for |textfield|.
572 ServerFieldType TypeForTextfield(const views::View* textfield);
574 // Gets the combobox view that is shown for the given |type|, or NULL.
575 views::Combobox* ComboboxForType(ServerFieldType type);
577 // Returns the associated ServerFieldType for |combobox|.
578 ServerFieldType TypeForCombobox(const views::Combobox* combobox) const;
580 // Called when the details container changes in size or position.
581 void DetailsContainerBoundsChanged();
583 // Sets the icons in |section| according to the field values. For example,
584 // sets the credit card and CVC icons according to the credit card number.
585 void SetIconsForSection(DialogSection section);
587 // Iterates over all the inputs in |section| and sets their enabled/disabled
589 void SetEditabilityForSection(DialogSection section);
591 // Handles mouse presses on the non-client view.
592 void NonClientMousePressed();
594 // The delegate that drives this view. Weak pointer, always non-NULL.
595 AutofillDialogViewDelegate* const delegate_;
597 // The preferred size of the view, cached to avoid needless recomputation.
598 mutable gfx::Size preferred_size_;
600 // The current number of unmatched calls to UpdatesStarted.
603 // True when there's been a call to ContentsPreferredSizeChanged() suppressed
604 // due to an unmatched UpdatesStarted.
607 // The window that displays the dialog contents. Weak pointer; may be NULL
608 // when the dialog is closing.
609 views::Widget* window_;
611 // A DialogSection-keyed map of the DetailGroup structs.
612 DetailGroupMap detail_groups_;
614 // Somewhere to show notification messages about errors, warnings, or promos.
615 NotificationArea* notification_area_;
617 // Runs the suggestion menu (triggered by each section's |suggested_button|.
618 scoped_ptr<views::MenuRunner> menu_runner_;
620 // The view that allows the user to toggle the data source.
621 AccountChooser* account_chooser_;
623 // A WebView to that navigates to a Google sign-in page to allow the user to
625 views::WebView* sign_in_web_view_;
627 // View that wraps |details_container_| and makes it scroll vertically.
628 views::ScrollView* scrollable_area_;
630 // View to host details sections.
631 DetailsContainerView* details_container_;
633 // A view that overlays |this| (for "loading..." messages).
634 views::View* loading_shield_;
636 // The height for |loading_shield_|. This prevents the height of the dialog
637 // from changing while the loading shield is showing.
638 int loading_shield_height_;
640 // The view that completely overlays the dialog (used for the splash page).
641 OverlayView* overlay_view_;
643 // The "Extra view" is on the same row as the dialog buttons.
644 views::View* button_strip_extra_view_;
646 // This checkbox controls whether new details are saved to the Autofill
647 // database. It lives in |extra_view_|.
648 views::Checkbox* save_in_chrome_checkbox_;
650 // Holds the above checkbox and an associated tooltip icon.
651 views::View* save_in_chrome_checkbox_container_;
653 // Used to display an image in the button strip extra view.
654 views::ImageView* button_strip_image_;
656 // View that aren't in the hierarchy but are owned by |this|. Currently
657 // just holds the (hidden) country comboboxes.
658 ScopedVector<views::View> other_owned_views_;
660 // The view that is appended to the bottom of the dialog, below the button
661 // strip. Used to display legal document links.
662 views::View* footnote_view_;
664 // The legal document text and links.
665 views::StyledLabel* legal_document_view_;
667 // The focus manager for |window_|.
668 views::FocusManager* focus_manager_;
670 // The object that manages the error bubble widget.
671 InfoBubble* error_bubble_; // Weak; owns itself.
673 // Map from input view (textfield or combobox) to error string.
674 std::map<views::View*, base::string16> validity_map_;
676 ScopedObserver<views::Widget, AutofillDialogViews> observer_;
678 // Delegate for the sign-in dialog's webview.
679 scoped_ptr<AutofillDialogSignInDelegate> sign_in_delegate_;
681 // Used to tell the delegate when focus moves to hide the Autofill popup.
682 scoped_ptr<ui::EventHandler> event_handler_;
684 DISALLOW_COPY_AND_ASSIGN(AutofillDialogViews);
687 } // namespace autofill
689 #endif // CHROME_BROWSER_UI_VIEWS_AUTOFILL_AUTOFILL_DIALOG_VIEWS_H_