autofill_dialog_views.h revision 868fa2fe829687343ffae624259930155e16dbd8
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.
4
5#ifndef CHROME_BROWSER_UI_VIEWS_AUTOFILL_AUTOFILL_DIALOG_VIEWS_H_
6#define CHROME_BROWSER_UI_VIEWS_AUTOFILL_AUTOFILL_DIALOG_VIEWS_H_
7
8#include <map>
9
10#include "base/memory/weak_ptr.h"
11#include "base/scoped_observer.h"
12#include "chrome/browser/ui/autofill/autofill_dialog_controller.h"
13#include "chrome/browser/ui/autofill/autofill_dialog_view.h"
14#include "chrome/browser/ui/autofill/testable_autofill_dialog_view.h"
15#include "ui/base/accelerators/accelerator.h"
16#include "ui/views/controls/button/button.h"
17#include "ui/views/controls/button/menu_button_listener.h"
18#include "ui/views/controls/combobox/combobox_listener.h"
19#include "ui/views/controls/link_listener.h"
20#include "ui/views/controls/progress_bar.h"
21#include "ui/views/controls/scroll_view.h"
22#include "ui/views/controls/styled_label_listener.h"
23#include "ui/views/controls/textfield/textfield_controller.h"
24#include "ui/views/focus/focus_manager.h"
25#include "ui/views/widget/widget_observer.h"
26#include "ui/views/window/dialog_delegate.h"
27
28namespace content {
29class KeyboardListener;
30}
31
32namespace gfx {
33class Image;
34}
35
36namespace views {
37class Checkbox;
38class Combobox;
39class FocusManager;
40class ImageButton;
41class ImageView;
42class Label;
43class Link;
44class MenuRunner;
45class StyledLabel;
46class Textfield;
47class WebView;
48class Widget;
49}
50
51namespace ui {
52class ComboboxModel;
53class KeyEvent;
54}
55
56namespace autofill {
57
58class AutofillDialogSignInDelegate;
59struct DetailInput;
60
61// Views toolkit implementation of the Autofill dialog that handles the
62// imperative autocomplete API call.
63class AutofillDialogViews : public AutofillDialogView,
64                            public TestableAutofillDialogView,
65                            public views::DialogDelegate,
66                            public views::WidgetObserver,
67                            public views::ButtonListener,
68                            public views::TextfieldController,
69                            public views::FocusChangeListener,
70                            public views::LinkListener,
71                            public views::ComboboxListener,
72                            public views::StyledLabelListener,
73                            public ui::AcceleratorTarget {
74 public:
75  explicit AutofillDialogViews(AutofillDialogController* controller);
76  virtual ~AutofillDialogViews();
77
78  // AutofillDialogView implementation:
79  virtual void Show() OVERRIDE;
80  virtual void Hide() OVERRIDE;
81  virtual void UpdateAccountChooser() OVERRIDE;
82  virtual void UpdateButtonStrip() OVERRIDE;
83  virtual void UpdateDetailArea() OVERRIDE;
84  virtual void UpdateNotificationArea() OVERRIDE;
85  virtual void UpdateSection(DialogSection section) OVERRIDE;
86  virtual void FillSection(DialogSection section,
87                           const DetailInput& originating_input) OVERRIDE;
88  virtual void GetUserInput(DialogSection section,
89                            DetailOutputMap* output) OVERRIDE;
90  virtual string16 GetCvc() OVERRIDE;
91  virtual bool SaveDetailsLocally() OVERRIDE;
92  virtual const content::NavigationController* ShowSignIn() OVERRIDE;
93  virtual void HideSignIn() OVERRIDE;
94  virtual void UpdateProgressBar(double value) OVERRIDE;
95  virtual void ModelChanged() OVERRIDE;
96  virtual TestableAutofillDialogView* GetTestableView() OVERRIDE;
97  virtual void OnSignInResize(const gfx::Size& pref_size) OVERRIDE;
98
99  // TestableAutofillDialogView implementation:
100  virtual void SubmitForTesting() OVERRIDE;
101  virtual void CancelForTesting() OVERRIDE;
102  virtual string16 GetTextContentsOfInput(const DetailInput& input) OVERRIDE;
103  virtual void SetTextContentsOfInput(const DetailInput& input,
104                                      const string16& contents) OVERRIDE;
105  virtual void ActivateInput(const DetailInput& input) OVERRIDE;
106  virtual gfx::Size GetSize() const OVERRIDE;
107
108  // ui::AcceleratorTarget implementation:
109  virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE;
110  virtual bool CanHandleAccelerators() const OVERRIDE;
111
112  // views::DialogDelegate implementation:
113  virtual string16 GetWindowTitle() const OVERRIDE;
114  virtual void WindowClosing() OVERRIDE;
115  virtual void DeleteDelegate() OVERRIDE;
116  virtual views::Widget* GetWidget() OVERRIDE;
117  virtual const views::Widget* GetWidget() const OVERRIDE;
118  virtual views::View* GetContentsView() OVERRIDE;
119  virtual int GetDialogButtons() const OVERRIDE;
120  virtual string16 GetDialogButtonLabel(ui::DialogButton button) const OVERRIDE;
121  virtual bool IsDialogButtonEnabled(ui::DialogButton button) const OVERRIDE;
122  virtual views::View* CreateExtraView() OVERRIDE;
123  virtual views::View* CreateTitlebarExtraView() OVERRIDE;
124  virtual views::View* CreateFootnoteView() OVERRIDE;
125  virtual bool Cancel() OVERRIDE;
126  virtual bool Accept() OVERRIDE;
127  virtual views::NonClientFrameView* CreateNonClientFrameView(
128      views::Widget* widget) OVERRIDE;
129
130  // views::WidgetObserver implementation:
131  virtual void OnWidgetClosing(views::Widget* widget) OVERRIDE;
132  virtual void OnWidgetBoundsChanged(views::Widget* widget,
133                                     const gfx::Rect& new_bounds) OVERRIDE;
134
135  // views::ButtonListener implementation:
136  virtual void ButtonPressed(views::Button* sender,
137                             const ui::Event& event) OVERRIDE;
138
139  // views::TextfieldController implementation:
140  virtual void ContentsChanged(views::Textfield* sender,
141                               const string16& new_contents) OVERRIDE;
142  virtual bool HandleKeyEvent(views::Textfield* sender,
143                              const ui::KeyEvent& key_event) OVERRIDE;
144  virtual bool HandleMouseEvent(views::Textfield* sender,
145                                const ui::MouseEvent& key_event) OVERRIDE;
146
147  // views::FocusChangeListener implementation.
148  virtual void OnWillChangeFocus(views::View* focused_before,
149                                 views::View* focused_now) OVERRIDE;
150  virtual void OnDidChangeFocus(views::View* focused_before,
151                                views::View* focused_now) OVERRIDE;
152
153  // views::LinkListener implementation:
154  virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE;
155
156  // views::ComboboxListener implementation:
157  virtual void OnSelectedIndexChanged(views::Combobox* combobox) OVERRIDE;
158
159  // views::StyledLabelListener implementation:
160  virtual void StyledLabelLinkClicked(const ui::Range& range, int event_flags)
161      OVERRIDE;
162
163 private:
164  // A view that contains a single child view, and adds a vertical scrollbar
165  // after a certain maximum height is reached.
166  class SizeLimitedScrollView : public views::ScrollView {
167   public:
168    explicit SizeLimitedScrollView(views::View* scroll_contents);
169    virtual ~SizeLimitedScrollView();
170
171    // views::View implementation.
172    virtual void Layout() OVERRIDE;
173    virtual gfx::Size GetPreferredSize() OVERRIDE;
174
175    // Sets the maximum height for the viewport.
176    void SetMaximumHeight(int max_height);
177
178   private:
179    int max_height_;
180
181    DISALLOW_COPY_AND_ASSIGN(SizeLimitedScrollView);
182  };
183
184  // A class that creates and manages a widget for error messages.
185  class ErrorBubble : public views::WidgetObserver {
186   public:
187    ErrorBubble(views::View* anchor, const string16& message);
188    virtual ~ErrorBubble();
189
190    bool IsShowing();
191
192    // Re-positions the bubble over |anchor_|. If |anchor_| is not visible,
193    // the bubble will hide.
194    void UpdatePosition();
195
196    virtual void OnWidgetClosing(views::Widget* widget) OVERRIDE;
197
198    views::View* anchor() { return anchor_; }
199
200   private:
201    // Calculates and returns the bounds of |widget_|, depending on |anchor_|
202    // and |contents_|.
203    gfx::Rect GetBoundsForWidget();
204
205    views::Widget* widget_;  // Weak, may be NULL.
206    views::View* anchor_;  // Weak.
207    // The contents view of |widget_|.
208    views::View* contents_;  // Weak.
209    ScopedObserver<views::Widget, ErrorBubble> observer_;
210
211    DISALLOW_COPY_AND_ASSIGN(ErrorBubble);
212  };
213
214  // A class which holds a textfield and draws extra stuff on top, like
215  // invalid content indications.
216  class DecoratedTextfield : public views::View {
217   public:
218    DecoratedTextfield(const string16& default_value,
219                       const string16& placeholder,
220                       views::TextfieldController* controller);
221    virtual ~DecoratedTextfield();
222
223    // The wrapped text field.
224    views::Textfield* textfield() { return textfield_; }
225
226    // Sets whether to indicate the textfield has invalid content.
227    void SetInvalid(bool invalid);
228    bool invalid() const { return invalid_; }
229
230    // views::View implementation.
231    virtual const char* GetClassName() const OVERRIDE;
232    virtual void PaintChildren(gfx::Canvas* canvas) OVERRIDE;
233    virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
234    virtual void RequestFocus() OVERRIDE;
235
236   private:
237    views::Textfield* textfield_;
238    bool invalid_;
239
240    DISALLOW_COPY_AND_ASSIGN(DecoratedTextfield);
241  };
242
243  // A View which displays the currently selected account and lets the user
244  // switch accounts.
245  class AccountChooser : public views::View,
246                         public views::LinkListener,
247                         public base::SupportsWeakPtr<AccountChooser> {
248   public:
249    explicit AccountChooser(AutofillDialogController* controller);
250    virtual ~AccountChooser();
251
252    // Updates the view based on the state that |controller_| reports.
253    void Update();
254
255    // views::View implementation.
256    virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
257    virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE;
258
259    // views::LinkListener implementation.
260    virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE;
261
262   private:
263    // The icon for the currently in-use account.
264    views::ImageView* image_;
265
266    // The label for the currently in-use account.
267    views::Label* label_;
268
269    // The drop arrow.
270    views::ImageView* arrow_;
271
272    // The sign in link.
273    views::Link* link_;
274
275    // The controller |this| queries for logic and state.
276    AutofillDialogController* controller_;
277
278    // Runs the suggestion menu (triggered by each section's |suggested_button|.
279    scoped_ptr<views::MenuRunner> menu_runner_;
280
281    DISALLOW_COPY_AND_ASSIGN(AccountChooser);
282  };
283
284  // An area for notifications. Some notifications point at the account chooser.
285  class NotificationArea : public views::View,
286                           public views::ButtonListener {
287   public:
288    explicit NotificationArea(AutofillDialogController* controller);
289    virtual ~NotificationArea();
290
291    // Displays the given notifications.
292    void SetNotifications(const std::vector<DialogNotification>& notifications);
293
294    // views::View implementation.
295    virtual gfx::Size GetPreferredSize() OVERRIDE;
296    virtual const char* GetClassName() const OVERRIDE;
297    virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
298
299    // views::ButtonListener implementation:
300    virtual void ButtonPressed(views::Button* sender,
301                               const ui::Event& event) OVERRIDE;
302
303    void set_arrow_centering_anchor(
304        const base::WeakPtr<views::View>& arrow_centering_anchor) {
305      arrow_centering_anchor_ = arrow_centering_anchor;
306    }
307
308   private:
309    // Utility function for determining whether an arrow should be drawn
310    // pointing at |arrow_centering_anchor_|.
311    bool HasArrow();
312
313    // A reference to the controller than owns this view. Used to report when
314    // checkboxes change their values.
315    AutofillDialogController* controller_;  // weak
316
317    // The currently showing checkbox, or NULL if none exists.
318    views::Checkbox* checkbox_;  // weak
319
320    // If HasArrow() is true, the arrow should point at this.
321    base::WeakPtr<views::View> arrow_centering_anchor_;
322
323    std::vector<DialogNotification> notifications_;
324
325    DISALLOW_COPY_AND_ASSIGN(NotificationArea);
326  };
327
328  typedef std::map<const DetailInput*, DecoratedTextfield*> TextfieldMap;
329  typedef std::map<const DetailInput*, views::Combobox*> ComboboxMap;
330
331  // A view that packs a label on the left and some related controls
332  // on the right.
333  class SectionContainer : public views::View {
334   public:
335    SectionContainer(const string16& label,
336                     views::View* controls,
337                     views::Button* proxy_button);
338    virtual ~SectionContainer();
339
340    // Sets the visual appearance of the section to active (considered active
341    // when showing the menu or hovered by the mouse cursor).
342    void SetActive(bool active);
343
344    // Sets whether mouse events should be forwarded to |proxy_button_|.
345    void SetForwardMouseEvents(bool forward);
346
347    // views::View implementation.
348    virtual void OnMouseMoved(const ui::MouseEvent& event) OVERRIDE;
349    virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE;
350    virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE;
351    virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
352    virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE;
353
354   private:
355    // Converts |event| to one suitable for |proxy_button_|.
356    static ui::MouseEvent ProxyEvent(const ui::MouseEvent& event);
357
358    // Mouse events on |this| are sent to this button.
359    views::Button* proxy_button_;  // Weak reference.
360
361    // When true, mouse events will be forwarded to |proxy_button_|.
362    bool forward_mouse_events_;
363
364    DISALLOW_COPY_AND_ASSIGN(SectionContainer);
365  };
366
367  // A view that contains a suggestion (such as a known address) and a link to
368  // edit the suggestion.
369  class SuggestionView : public views::View {
370   public:
371    SuggestionView(const string16& edit_label,
372                   AutofillDialogViews* autofill_dialog);
373    virtual ~SuggestionView();
374
375    // Whether this section is editable or not.
376    void SetEditable(bool editable);
377
378    // Sets the display text of the suggestion.
379    void SetSuggestionText(const string16& text, gfx::Font::FontStyle style);
380
381    // Sets the icon which should be displayed ahead of the text.
382    void SetSuggestionIcon(const gfx::Image& image);
383
384    // Shows an auxiliary textfield to the right of the suggestion icon and
385    // text. This is currently only used to show a CVC field for the CC section.
386    void ShowTextfield(const string16& placeholder_text,
387                       const gfx::ImageSkia& icon);
388
389    DecoratedTextfield* decorated_textfield() { return decorated_; }
390
391   private:
392    // The label that holds the suggestion description text.
393    views::Label* label_;
394    // The second (and greater) line of text that describes the suggestion.
395    views::Label* label_line_2_;
396    // The icon that comes just before |label_|.
397    views::ImageView* icon_;
398    // A view to contain |label_| and |icon_|.
399    views::View* label_container_;
400    // The input set by ShowTextfield.
401    DecoratedTextfield* decorated_;
402    // An "Edit" link that flips to editable inputs rather than suggestion text.
403    views::Link* edit_link_;
404
405    DISALLOW_COPY_AND_ASSIGN(SuggestionView);
406  };
407
408  // A convenience struct for holding pointers to views within each detail
409  // section. None of the member pointers are owned.
410  struct DetailsGroup {
411    explicit DetailsGroup(DialogSection section);
412    ~DetailsGroup();
413
414    // The section this group is associated with.
415    const DialogSection section;
416    // The view that contains the entire section (label + input).
417    SectionContainer* container;
418    // The view that allows manual input.
419    views::View* manual_input;
420    // The textfields in |manual_input|, tracked by their DetailInput.
421    TextfieldMap textfields;
422    // The comboboxes in |manual_input|, tracked by their DetailInput.
423    ComboboxMap comboboxes;
424    // The view that holds the text of the suggested data. This will be
425    // visible IFF |manual_input| is not visible.
426    SuggestionView* suggested_info;
427    // The view that allows selecting other data suggestions.
428    views::ImageButton* suggested_button;
429  };
430
431  class AutocheckoutProgressBar : public views::ProgressBar {
432   public:
433    AutocheckoutProgressBar();
434    virtual ~AutocheckoutProgressBar();
435
436   private:
437    // Overidden from View:
438    virtual gfx::Size GetPreferredSize() OVERRIDE;
439
440    DISALLOW_COPY_AND_ASSIGN(AutocheckoutProgressBar);
441  };
442
443  typedef std::map<DialogSection, DetailsGroup> DetailGroupMap;
444
445  void InitChildViews();
446
447  // Creates and returns a view that holds all detail sections.
448  views::View* CreateDetailsContainer();
449
450  // Creates and returns a view that holds the requesting host and intro text.
451  views::View* CreateNotificationArea();
452
453  // Creates and returns a view that holds the main controls of this dialog.
454  views::View* CreateMainContainer();
455
456  // Creates a detail section (Shipping, Email, etc.) with the given label,
457  // inputs View, and suggestion model. Relevant pointers are stored in |group|.
458  void CreateDetailsSection(DialogSection section);
459
460  // Like CreateDetailsSection, but creates the combined billing/cc section,
461  // which is somewhat more complicated than the others.
462  void CreateBillingSection();
463
464  // Creates the view that holds controls for inputing or selecting data for
465  // a given section.
466  views::View* CreateInputsContainer(DialogSection section);
467
468  // Creates a grid of textfield views for the given section, and stores them
469  // in the appropriate DetailsGroup. The top level View in the hierarchy is
470  // returned.
471  views::View* InitInputsView(DialogSection section);
472
473  // Updates the given section to match the state provided by |controller_|. If
474  // |clobber_inputs| is true, the current state of the textfields will be
475  // ignored, otherwise their contents will be preserved.
476  void UpdateSectionImpl(DialogSection section, bool clobber_inputs);
477
478  // Updates the visual state of the given group as per the model.
479  void UpdateDetailsGroupState(const DetailsGroup& group);
480
481  // Gets a pointer to the DetailsGroup that's associated with the given section
482  // of the dialog.
483  DetailsGroup* GroupForSection(DialogSection section);
484
485  // Gets a pointer to the DetailsGroup that's associated with a given |view|.
486  // Returns NULL if no DetailsGroup was found.
487  DetailsGroup* GroupForView(views::View* view);
488
489  // Sets the visual state for an input to be either valid or invalid. This
490  // should work on Comboboxes or DecoratedTextfields. If |message| is empty,
491  // the input is valid.
492  template<class T>
493  void SetValidityForInput(T* input, const string16& message);
494
495  // Shows an error bubble pointing at |view| if |view| has a message in
496  // |validity_map_|.
497  void ShowErrorBubbleForViewIfNecessary(views::View* view);
498
499  // Checks all manual inputs in |group| for validity. Decorates the invalid
500  // ones and returns true if all were valid.
501  bool ValidateGroup(const DetailsGroup& group, ValidationType type);
502
503  // Checks all manual inputs in the form for validity. Decorates the invalid
504  // ones and returns true if all were valid.
505  bool ValidateForm();
506
507  // When an input textfield is edited (its contents change) or activated
508  // (clicked while focused), this function will inform the controller that it's
509  // time to show a suggestion popup and possibly reset the validity state of
510  // the input.
511  void TextfieldEditedOrActivated(views::Textfield* textfield, bool was_edit);
512
513  // Updates the [X] Save in Chrome checkbox in the button strip.
514  void UpdateSaveInChromeCheckbox();
515
516  // Call this when the size of anything in |contents_| might've changed.
517  void ContentsPreferredSizeChanged();
518
519  // Gets the textfield view that is shown for the given DetailInput model, or
520  // NULL.
521  views::Textfield* TextfieldForInput(const DetailInput& input);
522
523  // Gets the combobox view that is shown for the given DetailInput model, or
524  // NULL.
525  views::Combobox* ComboboxForInput(const DetailInput& input);
526
527  // Called when the details container changes in size or position.
528  void DetailsContainerBoundsChanged();
529
530  // The controller that drives this view. Weak pointer, always non-NULL.
531  AutofillDialogController* const controller_;
532
533  // The window that displays |contents_|. Weak pointer; may be NULL when the
534  // dialog is closing.
535  views::Widget* window_;
536
537  // The top-level View for the dialog. Owned by the constrained window.
538  views::View* contents_;
539
540  // A DialogSection-keyed map of the DetailGroup structs.
541  DetailGroupMap detail_groups_;
542
543  // Somewhere to show notification messages about errors, warnings, or promos.
544  NotificationArea* notification_area_;
545
546  // Runs the suggestion menu (triggered by each section's |suggested_button|.
547  scoped_ptr<views::MenuRunner> menu_runner_;
548
549  // The view that allows the user to toggle the data source.
550  AccountChooser* account_chooser_;
551
552  // A WebView to that navigates to a Google sign-in page to allow the user to
553  // sign-in.
554  views::WebView* sign_in_webview_;
555
556  // View to host everything that isn't related to sign-in.
557  views::View* main_container_;
558
559  // View that wraps |details_container_| and makes it scroll vertically.
560  SizeLimitedScrollView* scrollable_area_;
561
562  // View to host details sections.
563  views::View* details_container_;
564
565  // The "Extra view" is on the same row as the dialog buttons.
566  views::View* button_strip_extra_view_;
567
568  // This checkbox controls whether new details are saved to the Autofill
569  // database. It lives in |extra_view_|.
570  views::Checkbox* save_in_chrome_checkbox_;
571
572  // View to host |autocheckout_progress_bar_| and its label.
573  views::View* autocheckout_progress_bar_view_;
574
575  // Progress bar for displaying Autocheckout progress.
576  AutocheckoutProgressBar* autocheckout_progress_bar_;
577
578  // The view that is appended to the bottom of the dialog, below the button
579  // strip. Used to display legal document links.
580  views::View* footnote_view_;
581
582  // The legal document text and links.
583  views::StyledLabel* legal_document_view_;
584
585  // The focus manager for |window_|.
586  views::FocusManager* focus_manager_;
587
588  // The object that manages the error bubble widget.
589  scoped_ptr<ErrorBubble> error_bubble_;
590
591  // Map from input view (textfield or combobox) to error string.
592  std::map<views::View*, string16> validity_map_;
593
594  ScopedObserver<views::Widget, AutofillDialogViews> observer_;
595
596  // Delegate for the sign-in dialog's webview.
597  scoped_ptr<AutofillDialogSignInDelegate> sign_in_delegate_;
598
599  DISALLOW_COPY_AND_ASSIGN(AutofillDialogViews);
600};
601
602}  // namespace autofill
603
604#endif  // CHROME_BROWSER_UI_VIEWS_AUTOFILL_AUTOFILL_DIALOG_VIEWS_H_
605