Infobar material design refresh: layout
[chromium-blink-merge.git] / chrome / browser / ui / views / autofill / autofill_dialog_views.h
blob16e306b6261494adc337a26fa5c7b8fc3e71057d
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_
8 #include <map>
9 #include <set>
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"
31 namespace gfx {
32 class Image;
35 namespace views {
36 class BubbleBorder;
37 class Checkbox;
38 class Combobox;
39 class FocusManager;
40 class ImageView;
41 class Label;
42 class LabelButton;
43 class Link;
44 class MenuRunner;
45 class StyledLabel;
46 class WebView;
47 class Widget;
48 } // namespace views
50 namespace ui {
51 class ComboboxModel;
52 class EventHandler;
53 class KeyEvent;
56 namespace autofill {
58 class AutofillDialogSignInDelegate;
59 class ExpandingTextfield;
60 class InfoBubble;
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::MenuButtonListener {
71 public:
72 explicit AutofillDialogViews(AutofillDialogViewDelegate* delegate);
73 ~AutofillDialogViews() override;
75 // AutofillDialogView implementation:
76 void Show() override;
77 void Hide() override;
78 void UpdatesStarted() override;
79 void UpdatesFinished() override;
80 void UpdateButtonStrip() override;
81 void UpdateDetailArea() override;
82 void UpdateForErrors() override;
83 void UpdateNotificationArea() override;
84 void UpdateSection(DialogSection section) override;
85 void UpdateErrorBubble() override;
86 void FillSection(DialogSection section,
87 ServerFieldType originating_type) override;
88 void GetUserInput(DialogSection section, FieldValueMap* output) override;
89 base::string16 GetCvc() override;
90 bool SaveDetailsLocally() override;
91 void ModelChanged() override;
92 void ValidateSection(DialogSection section) override;
94 // views::View implementation.
95 gfx::Size GetPreferredSize() const override;
96 gfx::Size GetMinimumSize() const override;
97 void Layout() override;
99 // views::DialogDelegate implementation:
100 ui::ModalType GetModalType() const override;
101 base::string16 GetWindowTitle() const override;
102 void WindowClosing() override;
103 void DeleteDelegate() override;
104 int GetDialogButtons() const override;
105 int GetDefaultDialogButton() const override;
106 base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
107 bool ShouldDefaultButtonBeBlue() const override;
108 bool IsDialogButtonEnabled(ui::DialogButton button) const override;
109 views::View* GetInitiallyFocusedView() override;
110 views::View* CreateExtraView() override;
111 bool Cancel() override;
112 bool Accept() override;
114 // views::WidgetObserver implementation:
115 void OnWidgetClosing(views::Widget* widget) override;
116 void OnWidgetDestroying(views::Widget* widget) override;
117 void OnWidgetBoundsChanged(views::Widget* widget,
118 const gfx::Rect& new_bounds) override;
120 // views::TextfieldController implementation:
121 void ContentsChanged(views::Textfield* sender,
122 const base::string16& new_contents) override;
123 bool HandleKeyEvent(views::Textfield* sender,
124 const ui::KeyEvent& key_event) override;
125 bool HandleMouseEvent(views::Textfield* sender,
126 const ui::MouseEvent& key_event) override;
128 // views::FocusChangeListener implementation.
129 void OnWillChangeFocus(views::View* focused_before,
130 views::View* focused_now) override;
131 void OnDidChangeFocus(views::View* focused_before,
132 views::View* focused_now) override;
134 // views::ComboboxListener implementation:
135 void OnPerformAction(views::Combobox* combobox) override;
137 // views::MenuButtonListener implementation.
138 void OnMenuButtonClicked(views::View* source,
139 const gfx::Point& point) override;
141 protected:
142 // Exposed for testing.
143 views::View* GetNotificationAreaForTesting();
144 views::View* GetScrollableAreaForTesting();
146 private:
147 friend class AutofillDialogViewTesterViews;
149 // An area for notifications. Some notifications point at the account chooser.
150 class NotificationArea : public views::View {
151 public:
152 explicit NotificationArea(AutofillDialogViewDelegate* delegate);
153 ~NotificationArea() override;
155 // Displays the given notifications.
156 void SetNotifications(const std::vector<DialogNotification>& notifications);
158 // views::View implementation.
159 gfx::Size GetPreferredSize() const override;
160 const char* GetClassName() const override;
161 void PaintChildren(const ui::PaintContext& context) override;
163 void set_arrow_centering_anchor(
164 const base::WeakPtr<views::View>& arrow_centering_anchor) {
165 arrow_centering_anchor_ = arrow_centering_anchor;
168 private:
169 // Utility function for determining whether an arrow should be drawn
170 // pointing at |arrow_centering_anchor_|.
171 bool HasArrow();
173 // A reference to the delegate/controller than owns this view.
174 // Used to report when checkboxes change their values.
175 AutofillDialogViewDelegate* delegate_; // weak
177 // If HasArrow() is true, the arrow should point at this.
178 base::WeakPtr<views::View> arrow_centering_anchor_;
180 std::vector<DialogNotification> notifications_;
182 DISALLOW_COPY_AND_ASSIGN(NotificationArea);
185 typedef std::map<ServerFieldType, ExpandingTextfield*> TextfieldMap;
186 typedef std::map<ServerFieldType, views::Combobox*> ComboboxMap;
188 // A view that packs a label on the left and some related controls
189 // on the right.
190 class SectionContainer : public views::View,
191 public views::ViewTargeterDelegate {
192 public:
193 SectionContainer(const base::string16& label,
194 views::View* controls,
195 views::Button* proxy_button);
196 ~SectionContainer() override;
198 // Sets the visual appearance of the section to active (considered active
199 // when showing the menu or hovered by the mouse cursor).
200 void SetActive(bool active);
202 // Sets whether mouse events should be forwarded to |proxy_button_|.
203 void SetForwardMouseEvents(bool forward);
205 // views::View implementation.
206 const char* GetClassName() const override;
207 void OnMouseMoved(const ui::MouseEvent& event) override;
208 void OnMouseEntered(const ui::MouseEvent& event) override;
209 void OnMouseExited(const ui::MouseEvent& event) override;
210 bool OnMousePressed(const ui::MouseEvent& event) override;
211 void OnMouseReleased(const ui::MouseEvent& event) override;
212 void OnGestureEvent(ui::GestureEvent* event) override;
214 private:
215 // views::ViewTargeterDelegate:
216 views::View* TargetForRect(views::View* root,
217 const gfx::Rect& rect) override;
219 // Converts |event| to one suitable for |proxy_button_|.
220 static ui::MouseEvent ProxyEvent(const ui::MouseEvent& event);
222 // Returns true if the given event should be forwarded to |proxy_button_|.
223 bool ShouldForwardEvent(const ui::LocatedEvent& event);
225 // Mouse events on |this| are sent to this button.
226 views::Button* proxy_button_; // Weak reference.
228 // When true, all mouse events will be forwarded to |proxy_button_|.
229 bool forward_mouse_events_;
231 DISALLOW_COPY_AND_ASSIGN(SectionContainer);
234 // A button to show address or billing suggestions.
235 class SuggestedButton : public views::MenuButton {
236 public:
237 explicit SuggestedButton(views::MenuButtonListener* listener);
238 ~SuggestedButton() override;
240 // views::MenuButton implementation.
241 gfx::Size GetPreferredSize() const override;
242 const char* GetClassName() const override;
243 void OnPaint(gfx::Canvas* canvas) override;
245 private:
246 // Returns the corred resource ID (i.e. IDR_*) for the current |state()|.
247 int ResourceIDForState() const;
249 DISALLOW_COPY_AND_ASSIGN(SuggestedButton);
252 // A view that runs a callback whenever its bounds change, and which can
253 // optionally suppress layout.
254 class DetailsContainerView : public views::View {
255 public:
256 explicit DetailsContainerView(const base::Closure& callback);
257 ~DetailsContainerView() override;
259 void set_ignore_layouts(bool ignore_layouts) {
260 ignore_layouts_ = ignore_layouts;
263 // views::View implementation.
264 void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
265 void Layout() override;
267 private:
268 base::Closure bounds_changed_callback_;
270 // The view ignores Layout() calls when this is true.
271 bool ignore_layouts_;
273 DISALLOW_COPY_AND_ASSIGN(DetailsContainerView);
276 // A view that contains a suggestion (such as a known address).
277 class SuggestionView : public views::View {
278 public:
279 explicit SuggestionView(AutofillDialogViews* autofill_dialog);
280 ~SuggestionView() override;
282 void SetState(const SuggestionState& state);
284 // views::View implementation.
285 gfx::Size GetPreferredSize() const override;
286 int GetHeightForWidth(int width) const override;
287 void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
289 ExpandingTextfield* textfield() { return textfield_; }
291 private:
292 // Returns whether there's room to display |state_.vertically_compact_text|
293 // without resorting to an ellipsis for a pixel width of |available_width|.
294 // Fills in |resulting_height| with the amount of space required to display
295 // |vertically_compact_text| or |horizontally_compact_text| as the case may
296 // be.
297 bool CanUseVerticallyCompactText(int available_width,
298 int* resulting_height) const;
300 // Sets the display text of the suggestion.
301 void SetLabelText(const base::string16& text);
303 // Sets the icon which should be displayed ahead of the text.
304 void SetIcon(const gfx::Image& image);
306 // Shows an auxiliary textfield to the right of the suggestion icon and
307 // text. This is currently only used to show a CVC field for the CC section.
308 void SetTextfield(const base::string16& placeholder_text,
309 const gfx::Image& icon);
311 // Calls SetLabelText() with the appropriate text based on current bounds.
312 void UpdateLabelText();
314 // The state of |this|.
315 SuggestionState state_;
317 // This caches preferred heights for given widths. The key is a preferred
318 // width, the value is a cached result of CanUseVerticallyCompactText.
319 mutable std::map<int, std::pair<bool, int> > calculated_heights_;
321 // The label that holds the suggestion description text.
322 views::Label* label_;
323 // The second (and greater) line of text that describes the suggestion.
324 views::Label* label_line_2_;
325 // The icon that comes just before |label_|.
326 views::ImageView* icon_;
327 // The input set by ShowTextfield.
328 ExpandingTextfield* textfield_;
330 DISALLOW_COPY_AND_ASSIGN(SuggestionView);
333 // A convenience struct for holding pointers to views within each detail
334 // section. None of the member pointers are owned.
335 struct DetailsGroup {
336 explicit DetailsGroup(DialogSection section);
337 ~DetailsGroup();
339 // The section this group is associated with.
340 const DialogSection section;
341 // The view that contains the entire section (label + input).
342 SectionContainer* container;
343 // The view that allows manual input.
344 views::View* manual_input;
345 // The textfields in |manual_input|, tracked by their ServerFieldType.
346 TextfieldMap textfields;
347 // The comboboxes in |manual_input|, tracked by their ServerFieldType.
348 ComboboxMap comboboxes;
349 // The view that holds the text of the suggested data. This will be
350 // visible IFF |manual_input| is not visible.
351 SuggestionView* suggested_info;
352 // The view that allows selecting other data suggestions.
353 SuggestedButton* suggested_button;
356 typedef std::map<DialogSection, DetailsGroup> DetailGroupMap;
358 // Returns the preferred size or minimum size (if |get_minimum_size| is true).
359 gfx::Size CalculatePreferredSize(bool get_minimum_size) const;
361 // Returns the minimum size of the sign in view for this dialog.
362 gfx::Size GetMinimumSignInViewSize() const;
364 // Returns the maximum size of the sign in view for this dialog.
365 gfx::Size GetMaximumSignInViewSize() const;
367 // Returns which section should currently be used for credit card info.
368 DialogSection GetCreditCardSection() const;
370 void InitChildViews();
372 // Creates and returns a view that holds all detail sections.
373 views::View* CreateDetailsContainer();
375 // Creates and returns a view that holds the requesting host and intro text.
376 views::View* CreateNotificationArea();
378 // Creates and returns a view that holds the main controls of this dialog.
379 views::View* CreateMainContainer();
381 // Creates a detail section (Shipping, Email, etc.) with the given label,
382 // inputs View, and suggestion model. Relevant pointers are stored in |group|.
383 void CreateDetailsSection(DialogSection section);
385 // Creates the view that holds controls for inputing or selecting data for
386 // a given section.
387 views::View* CreateInputsContainer(DialogSection section);
389 // Creates a grid of inputs for the given section.
390 void InitInputsView(DialogSection section);
392 // Updates the given section to match the state provided by |delegate_|. If
393 // |clobber_inputs| is true, the current state of the textfields will be
394 // ignored, otherwise their contents will be preserved.
395 void UpdateSectionImpl(DialogSection section, bool clobber_inputs);
397 // Updates the visual state of the given group as per the model.
398 void UpdateDetailsGroupState(const DetailsGroup& group);
400 // Gets a pointer to the DetailsGroup that's associated with the given section
401 // of the dialog.
402 DetailsGroup* GroupForSection(DialogSection section);
404 // Gets a pointer to the DetailsGroup that's associated with a given |view|.
405 // Returns NULL if no DetailsGroup was found.
406 DetailsGroup* GroupForView(views::View* view);
408 // Erases all views in |group| from |validity_map_|.
409 void EraseInvalidViewsInGroup(const DetailsGroup* group);
411 // Explicitly focuses the initially focusable view.
412 void FocusInitialView();
414 // Sets the visual state for an input to be either valid or invalid. This
415 // should work on Comboboxes or ExpandingTextfields. If |message| is empty,
416 // the input is valid.
417 template<class T>
418 void SetValidityForInput(T* input, const base::string16& message);
420 // Shows an error bubble pointing at |view| if |view| has a message in
421 // |validity_map_|.
422 void ShowErrorBubbleForViewIfNecessary(views::View* view);
424 // Hides |error_bubble_| (if it exists).
425 void HideErrorBubble();
427 // Updates validity of the inputs in |section| with new |validity_messages|.
428 // Fields are only updated with unsure messages if |overwrite_valid| is true.
429 void MarkInputsInvalid(DialogSection section,
430 const ValidityMessages& validity_messages,
431 bool overwrite_invalid);
433 // Checks all manual inputs in |group| for validity. Decorates the invalid
434 // ones and returns true if all were valid.
435 bool ValidateGroup(const DetailsGroup& group, ValidationType type);
437 // Checks all manual inputs in the form for validity. Decorates the invalid
438 // ones and returns true if all were valid.
439 bool ValidateForm();
441 // When an input is edited (its contents change) or activated (clicked while
442 // focused), this function will inform the delegate to take the appropriate
443 // action (textfields may show a suggestion popup, comboboxes may rebuild the
444 // section inputs). May also reset the validity state of the input.
445 void InputEditedOrActivated(ServerFieldType type,
446 const gfx::Rect& bounds,
447 bool was_edit);
449 // Updates the views in the button strip.
450 void UpdateButtonStripExtraView();
452 // Call this when the size of anything in the contents might have changed.
453 void ContentsPreferredSizeChanged();
454 void DoContentsPreferredSizeChanged();
456 // Gets the textfield view that is shown for the given |type| or NULL.
457 ExpandingTextfield* TextfieldForType(ServerFieldType type);
459 // Returns the associated ServerFieldType for |textfield|.
460 ServerFieldType TypeForTextfield(const views::View* textfield);
462 // Gets the combobox view that is shown for the given |type|, or NULL.
463 views::Combobox* ComboboxForType(ServerFieldType type);
465 // Returns the associated ServerFieldType for |combobox|.
466 ServerFieldType TypeForCombobox(const views::Combobox* combobox) const;
468 // Called when the details container changes in size or position.
469 void DetailsContainerBoundsChanged();
471 // Sets the icons in |section| according to the field values. For example,
472 // sets the credit card and CVC icons according to the credit card number.
473 void SetIconsForSection(DialogSection section);
475 // Handles mouse presses on the non-client view.
476 void NonClientMousePressed();
478 // The delegate that drives this view. Weak pointer, always non-NULL.
479 AutofillDialogViewDelegate* const delegate_;
481 // The preferred size of the view, cached to avoid needless recomputation.
482 mutable gfx::Size preferred_size_;
484 // The current number of unmatched calls to UpdatesStarted.
485 int updates_scope_;
487 // True when there's been a call to ContentsPreferredSizeChanged() suppressed
488 // due to an unmatched UpdatesStarted.
489 bool needs_update_;
491 // The window that displays the dialog contents. Weak pointer; may be NULL
492 // when the dialog is closing.
493 views::Widget* window_;
495 // A DialogSection-keyed map of the DetailGroup structs.
496 DetailGroupMap detail_groups_;
498 // Somewhere to show notification messages about errors, warnings, or promos.
499 NotificationArea* notification_area_;
501 // Runs the suggestion menu (triggered by each section's |suggested_button|).
502 scoped_ptr<views::MenuRunner> menu_runner_;
504 // View that wraps |details_container_| and makes it scroll vertically.
505 views::ScrollView* scrollable_area_;
507 // View to host details sections.
508 DetailsContainerView* details_container_;
510 // The "Extra view" is on the same row as the dialog buttons.
511 views::View* button_strip_extra_view_;
513 // This checkbox controls whether new details are saved to the Autofill
514 // database. It lives in |extra_view_|.
515 views::Checkbox* save_in_chrome_checkbox_;
517 // Holds the above checkbox and an associated tooltip icon.
518 views::View* save_in_chrome_checkbox_container_;
520 // View that aren't in the hierarchy but are owned by |this|. Currently
521 // just holds the (hidden) country comboboxes.
522 ScopedVector<views::View> other_owned_views_;
524 // The focus manager for |window_|.
525 views::FocusManager* focus_manager_;
527 // The object that manages the error bubble widget.
528 InfoBubble* error_bubble_; // Weak; owns itself.
530 // Map from input view (textfield or combobox) to error string.
531 std::map<views::View*, base::string16> validity_map_;
533 ScopedObserver<views::Widget, AutofillDialogViews> observer_;
535 // Used to tell the delegate when focus moves to hide the Autofill popup.
536 scoped_ptr<ui::EventHandler> event_handler_;
538 DISALLOW_COPY_AND_ASSIGN(AutofillDialogViews);
541 } // namespace autofill
543 #endif // CHROME_BROWSER_UI_VIEWS_AUTOFILL_AUTOFILL_DIALOG_VIEWS_H_