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