Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / ui / views / controls / menu / menu_controller.h
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 UI_VIEWS_CONTROLS_MENU_MENU_CONTROLLER_H_
6 #define UI_VIEWS_CONTROLS_MENU_MENU_CONTROLLER_H_
7
8 #include "build/build_config.h"
9
10 #include <list>
11 #include <set>
12 #include <vector>
13
14 #include "base/compiler_specific.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/timer/timer.h"
17 #include "ui/events/event.h"
18 #include "ui/events/event_constants.h"
19 #include "ui/events/platform/platform_event_dispatcher.h"
20 #include "ui/views/controls/menu/menu_config.h"
21 #include "ui/views/controls/menu/menu_delegate.h"
22 #include "ui/views/widget/widget_observer.h"
23
24 namespace base {
25 class MessagePumpDispatcher;
26 }
27 namespace gfx {
28 class Screen;
29 }
30 namespace ui {
31 class NativeTheme;
32 class OSExchangeData;
33 class ScopedEventDispatcher;
34 }
35 namespace views {
36
37 class MenuButton;
38 class MenuHostRootView;
39 class MenuItemView;
40 class MenuMessageLoop;
41 class MouseEvent;
42 class SubmenuView;
43 class View;
44
45 namespace internal {
46 class MenuControllerDelegate;
47 class MenuEventDispatcher;
48 class MenuMessagePumpDispatcher;
49 class MenuRunnerImpl;
50 }
51
52 // MenuController -------------------------------------------------------------
53
54 // MenuController is used internally by the various menu classes to manage
55 // showing, selecting and drag/drop for menus. All relevant events are
56 // forwarded to the MenuController from SubmenuView and MenuHost.
57 class VIEWS_EXPORT MenuController : public WidgetObserver {
58  public:
59   // Enumeration of how the menu should exit.
60   enum ExitType {
61     // Don't exit.
62     EXIT_NONE,
63
64     // All menus, including nested, should be exited.
65     EXIT_ALL,
66
67     // Only the outermost menu should be exited.
68     EXIT_OUTERMOST,
69
70     // This is set if the menu is being closed as the result of one of the menus
71     // being destroyed.
72     EXIT_DESTROYED
73   };
74
75   // If a menu is currently active, this returns the controller for it.
76   static MenuController* GetActiveInstance();
77
78   // Runs the menu at the specified location. If the menu was configured to
79   // block, the selected item is returned. If the menu does not block this
80   // returns NULL immediately.
81   MenuItemView* Run(Widget* parent,
82                     MenuButton* button,
83                     MenuItemView* root,
84                     const gfx::Rect& bounds,
85                     MenuAnchorPosition position,
86                     bool context_menu,
87                     bool is_nested_drag,
88                     int* event_flags);
89
90   // Whether or not Run blocks.
91   bool IsBlockingRun() const { return blocking_run_; }
92
93   bool in_nested_run() const { return !menu_stack_.empty(); }
94
95   // Whether or not drag operation is in progress.
96   bool drag_in_progress() const { return drag_in_progress_; }
97
98   // Whether the MenuController initiated the drag in progress. False if there
99   // is no drag in progress.
100   bool did_initiate_drag() const { return did_initiate_drag_; }
101
102   // Returns the owner of child windows.
103   // WARNING: this may be NULL.
104   Widget* owner() { return owner_; }
105
106   // Get the anchor position wich is used to show this menu.
107   MenuAnchorPosition GetAnchorPosition() { return state_.anchor; }
108
109   // Cancels the current Run. See ExitType for a description of what happens
110   // with the various parameters.
111   void Cancel(ExitType type);
112
113   // An alternative to Cancel(EXIT_ALL) that can be used with a OneShotTimer.
114   void CancelAll() { Cancel(EXIT_ALL); }
115
116   // Returns the current exit type. This returns a value other than EXIT_NONE if
117   // the menu is being canceled.
118   ExitType exit_type() const { return exit_type_; }
119
120   // Returns the time from the event which closed the menu - or 0.
121   base::TimeDelta closing_event_time() const { return closing_event_time_; }
122
123   void set_is_combobox(bool is_combobox) { is_combobox_ = is_combobox; }
124
125   // Various events, forwarded from the submenu.
126   //
127   // NOTE: the coordinates of the events are in that of the
128   // MenuScrollViewContainer.
129   void OnMousePressed(SubmenuView* source, const ui::MouseEvent& event);
130   void OnMouseDragged(SubmenuView* source, const ui::MouseEvent& event);
131   void OnMouseReleased(SubmenuView* source, const ui::MouseEvent& event);
132   void OnMouseMoved(SubmenuView* source, const ui::MouseEvent& event);
133   void OnMouseEntered(SubmenuView* source, const ui::MouseEvent& event);
134   bool OnMouseWheel(SubmenuView* source, const ui::MouseWheelEvent& event);
135   void OnGestureEvent(SubmenuView* source, ui::GestureEvent* event);
136
137   bool GetDropFormats(
138       SubmenuView* source,
139       int* formats,
140       std::set<ui::OSExchangeData::CustomFormat>* custom_formats);
141   bool AreDropTypesRequired(SubmenuView* source);
142   bool CanDrop(SubmenuView* source, const ui::OSExchangeData& data);
143   void OnDragEntered(SubmenuView* source, const ui::DropTargetEvent& event);
144   int OnDragUpdated(SubmenuView* source, const ui::DropTargetEvent& event);
145   void OnDragExited(SubmenuView* source);
146   int OnPerformDrop(SubmenuView* source, const ui::DropTargetEvent& event);
147
148   // Invoked from the scroll buttons of the MenuScrollViewContainer.
149   void OnDragEnteredScrollButton(SubmenuView* source, bool is_up);
150   void OnDragExitedScrollButton(SubmenuView* source);
151
152   // Called by the Widget when a drag is about to start on a child view. This
153   // could be initiated by one of our MenuItemViews, or could be through another
154   // child View.
155   void OnDragWillStart();
156
157   // Called by the Widget when the drag has completed. |should_close|
158   // corresponds to whether or not the menu should close.
159   void OnDragComplete(bool should_close);
160
161   // Update the submenu's selection based on the current mouse location
162   void UpdateSubmenuSelection(SubmenuView* source);
163
164   // WidgetObserver overrides:
165   virtual void OnWidgetDestroying(Widget* widget) OVERRIDE;
166
167   // Only used for testing.
168   bool IsCancelAllTimerRunningForTest();
169
170   // Only used for testing.
171   static void TurnOffMenuSelectionHoldForTest();
172
173  private:
174   friend class internal::MenuEventDispatcher;
175   friend class internal::MenuMessagePumpDispatcher;
176   friend class internal::MenuRunnerImpl;
177   friend class MenuControllerTest;
178   friend class MenuHostRootView;
179   friend class MenuItemView;
180   friend class SubmenuView;
181
182   class MenuScrollTask;
183
184   struct SelectByCharDetails;
185
186   // Values supplied to SetSelection.
187   enum SetSelectionTypes {
188     SELECTION_DEFAULT               = 0,
189
190     // If set submenus are opened immediately, otherwise submenus are only
191     // openned after a timer fires.
192     SELECTION_UPDATE_IMMEDIATELY    = 1 << 0,
193
194     // If set and the menu_item has a submenu, the submenu is shown.
195     SELECTION_OPEN_SUBMENU          = 1 << 1,
196
197     // SetSelection is being invoked as the result exiting or cancelling the
198     // menu. This is used for debugging.
199     SELECTION_EXIT                  = 1 << 2,
200   };
201
202   // Result type for SendAcceleratorToHotTrackedView
203   enum SendAcceleratorResultType {
204     // Accelerator is not sent because of no hot tracked views.
205     ACCELERATOR_NOT_PROCESSED,
206
207     // Accelerator is sent to the hot tracked views.
208     ACCELERATOR_PROCESSED,
209
210     // Same as above and the accelerator causes the exit of the menu.
211     ACCELERATOR_PROCESSED_EXIT
212   };
213
214   // Tracks selection information.
215   struct State {
216     State();
217     ~State();
218
219     // The selected menu item.
220     MenuItemView* item;
221
222     // If item has a submenu this indicates if the submenu is showing.
223     bool submenu_open;
224
225     // Bounds passed to the run menu. Used for positioning the first menu.
226     gfx::Rect initial_bounds;
227
228     // Position of the initial menu.
229     MenuAnchorPosition anchor;
230
231     // The direction child menus have opened in.
232     std::list<bool> open_leading;
233
234     // Bounds for the monitor we're showing on.
235     gfx::Rect monitor_bounds;
236
237     // Is the current menu a context menu.
238     bool context_menu;
239   };
240
241   // Used by GetMenuPart to indicate the menu part at a particular location.
242   struct MenuPart {
243     // Type of part.
244     enum Type {
245       NONE,
246       MENU_ITEM,
247       SCROLL_UP,
248       SCROLL_DOWN
249     };
250
251     MenuPart() : type(NONE), menu(NULL), parent(NULL), submenu(NULL) {}
252
253     // Convenience for testing type == SCROLL_DOWN or type == SCROLL_UP.
254     bool is_scroll() const { return type == SCROLL_DOWN || type == SCROLL_UP; }
255
256     // Type of part.
257     Type type;
258
259     // If type is MENU_ITEM, this is the menu item the mouse is over, otherwise
260     // this is NULL.
261     // NOTE: if type is MENU_ITEM and the mouse is not over a valid menu item
262     //       but is over a menu (for example, the mouse is over a separator or
263     //       empty menu), this is NULL and parent is the menu the mouse was
264     //       clicked on.
265     MenuItemView* menu;
266
267     // If type is MENU_ITEM but the mouse is not over a menu item this is the
268     // parent of the menu item the user clicked on. Otherwise this is NULL.
269     MenuItemView* parent;
270
271     // This is the submenu the mouse is over.
272     SubmenuView* submenu;
273   };
274
275   // Sets the selection to |menu_item|. A value of NULL unselects
276   // everything. |types| is a bitmask of |SetSelectionTypes|.
277   //
278   // Internally this updates pending_state_ immediatley. state_ is only updated
279   // immediately if SELECTION_UPDATE_IMMEDIATELY is set. If
280   // SELECTION_UPDATE_IMMEDIATELY is not set CommitPendingSelection is invoked
281   // to show/hide submenus and update state_.
282   void SetSelection(MenuItemView* menu_item, int types);
283
284   void SetSelectionOnPointerDown(SubmenuView* source,
285                                  const ui::LocatedEvent& event);
286   void StartDrag(SubmenuView* source, const gfx::Point& location);
287
288   // Key processing. The return value of this is returned from Dispatch.
289   // In other words, if this returns false (which happens if escape was
290   // pressed, or a matching mnemonic was found) the message loop returns.
291   bool OnKeyDown(ui::KeyboardCode key_code);
292
293   // Creates a MenuController. If |blocking| is true a nested message loop is
294   // started in |Run|.
295   MenuController(ui::NativeTheme* theme,
296                  bool blocking,
297                  internal::MenuControllerDelegate* delegate);
298
299   virtual ~MenuController();
300
301   // Runs the platform specific bits of the message loop. If |nested_menu| is
302   // true we're being asked to run a menu from within a menu (eg a context
303   // menu).
304   void RunMessageLoop(bool nested_menu);
305
306   // AcceleratorPressed is invoked on the hot tracked view if it exists.
307   SendAcceleratorResultType SendAcceleratorToHotTrackedView();
308
309   void UpdateInitialLocation(const gfx::Rect& bounds,
310                              MenuAnchorPosition position,
311                              bool context_menu);
312
313   // Invoked when the user accepts the selected item. This is only used
314   // when blocking. This schedules the loop to quit.
315   void Accept(MenuItemView* item, int event_flags);
316
317   bool ShowSiblingMenu(SubmenuView* source, const gfx::Point& mouse_location);
318
319   // Shows a context menu for |menu_item| as a result of a located event if
320   // appropriate. This is invoked on long press and releasing the right mouse
321   // button. Returns whether a context menu was shown.
322   bool ShowContextMenu(MenuItemView* menu_item,
323                        SubmenuView* source,
324                        const ui::LocatedEvent& event,
325                        ui::MenuSourceType source_type);
326
327   // Closes all menus, including any menus of nested invocations of Run.
328   void CloseAllNestedMenus();
329
330   // Gets the enabled menu item at the specified location.
331   // If over_any_menu is non-null it is set to indicate whether the location
332   // is over any menu. It is possible for this to return NULL, but
333   // over_any_menu to be true. For example, the user clicked on a separator.
334   MenuItemView* GetMenuItemAt(View* menu, int x, int y);
335
336   // If there is an empty menu item at the specified location, it is returned.
337   MenuItemView* GetEmptyMenuItemAt(View* source, int x, int y);
338
339   // Returns true if the coordinate is over the scroll buttons of the
340   // SubmenuView's MenuScrollViewContainer. If true is returned, part is set to
341   // indicate which scroll button the coordinate is.
342   bool IsScrollButtonAt(SubmenuView* source,
343                         int x,
344                         int y,
345                         MenuPart::Type* part);
346
347   // Returns the target for the mouse event. The coordinates are in terms of
348   // source's scroll view container.
349   MenuPart GetMenuPart(SubmenuView* source, const gfx::Point& source_loc);
350
351   // Returns the target for mouse events. The search is done through |item| and
352   // all its parents.
353   MenuPart GetMenuPartByScreenCoordinateUsingMenu(MenuItemView* item,
354                                                   const gfx::Point& screen_loc);
355
356   // Implementation of GetMenuPartByScreenCoordinate for a single menu. Returns
357   // true if the supplied SubmenuView contains the location in terms of the
358   // screen. If it does, part is set appropriately and true is returned.
359   bool GetMenuPartByScreenCoordinateImpl(SubmenuView* menu,
360                                          const gfx::Point& screen_loc,
361                                          MenuPart* part);
362
363   // Returns true if the SubmenuView contains the specified location. This does
364   // NOT included the scroll buttons, only the submenu view.
365   bool DoesSubmenuContainLocation(SubmenuView* submenu,
366                                   const gfx::Point& screen_loc);
367
368   // Opens/Closes the necessary menus such that state_ matches that of
369   // pending_state_. This is invoked if submenus are not opened immediately,
370   // but after a delay.
371   void CommitPendingSelection();
372
373   // If item has a submenu, it is closed. This does NOT update the selection
374   // in anyway.
375   void CloseMenu(MenuItemView* item);
376
377   // If item has a submenu, it is opened. This does NOT update the selection
378   // in anyway.
379   void OpenMenu(MenuItemView* item);
380
381   // Implementation of OpenMenu. If |show| is true, this invokes show on the
382   // menu, otherwise Reposition is invoked.
383   void OpenMenuImpl(MenuItemView* item, bool show);
384
385   // Invoked when the children of a menu change and the menu is showing.
386   // This closes any submenus and resizes the submenu.
387   void MenuChildrenChanged(MenuItemView* item);
388
389   // Builds the paths of the two menu items into the two paths, and
390   // sets first_diff_at to the location of the first difference between the
391   // two paths.
392   void BuildPathsAndCalculateDiff(MenuItemView* old_item,
393                                   MenuItemView* new_item,
394                                   std::vector<MenuItemView*>* old_path,
395                                   std::vector<MenuItemView*>* new_path,
396                                   size_t* first_diff_at);
397
398   // Builds the path for the specified item.
399   void BuildMenuItemPath(MenuItemView* item, std::vector<MenuItemView*>* path);
400
401   // Starts/stops the timer that commits the pending state to state
402   // (opens/closes submenus).
403   void StartShowTimer();
404   void StopShowTimer();
405
406   // Starts/stops the timer cancel the menu. This is used during drag and
407   // drop when the drop enters/exits the menu.
408   void StartCancelAllTimer();
409   void StopCancelAllTimer();
410
411   // Calculates the bounds of the menu to show. is_leading is set to match the
412   // direction the menu opened in.
413   gfx::Rect CalculateMenuBounds(MenuItemView* item,
414                                 bool prefer_leading,
415                                 bool* is_leading);
416
417   // Calculates the bubble bounds of the menu to show. is_leading is set to
418   // match the direction the menu opened in.
419   gfx::Rect CalculateBubbleMenuBounds(MenuItemView* item,
420                                       bool prefer_leading,
421                                       bool* is_leading);
422
423   // Returns the depth of the menu.
424   static int MenuDepth(MenuItemView* item);
425
426   // Selects the next/previous menu item.
427   void IncrementSelection(int delta);
428
429   // Returns the next selectable child menu item of |parent| starting at |index|
430   // and incrementing index by |delta|. If there are no more selected menu items
431   // NULL is returned.
432   MenuItemView* FindNextSelectableMenuItem(MenuItemView* parent,
433                                            int index,
434                                            int delta);
435
436   // If the selected item has a submenu and it isn't currently open, the
437   // the selection is changed such that the menu opens immediately.
438   void OpenSubmenuChangeSelectionIfCan();
439
440   // If possible, closes the submenu.
441   void CloseSubmenu();
442
443   // Returns details about which menu items match the mnemonic |key|.
444   // |match_function| is used to determine which menus match.
445   SelectByCharDetails FindChildForMnemonic(
446       MenuItemView* parent,
447       base::char16 key,
448       bool (*match_function)(MenuItemView* menu, base::char16 mnemonic));
449
450   // Selects or accepts the appropriate menu item based on |details|. Returns
451   // true if |Accept| was invoked (which happens if there aren't multiple item
452   // with the same mnemonic and the item to select does not have a submenu).
453   bool AcceptOrSelect(MenuItemView* parent, const SelectByCharDetails& details);
454
455   // Selects by mnemonic, and if that doesn't work tries the first character of
456   // the title. Returns true if a match was selected and the menu should exit.
457   bool SelectByChar(base::char16 key);
458
459   // For Windows and Aura we repost an event for some events that dismiss
460   // the context menu. The event is then reprocessed to cause its result
461   // if the context menu had not been present.
462   // On non-aura Windows, a new mouse event is generated and posted to
463   // the window (if there is one) at the location of the event. On
464   // aura, the event is reposted on the RootWindow.
465   void RepostEvent(SubmenuView* source, const ui::LocatedEvent& event);
466
467   // Sets the drop target to new_item.
468   void SetDropMenuItem(MenuItemView* new_item,
469                        MenuDelegate::DropPosition position);
470
471   // Starts/stops scrolling as appropriate. part gives the part the mouse is
472   // over.
473   void UpdateScrolling(const MenuPart& part);
474
475   // Stops scrolling.
476   void StopScrolling();
477
478   // Updates active mouse view from the location of the event and sends it
479   // the appropriate events. This is used to send mouse events to child views so
480   // that they react to click-drag-release as if the user clicked on the view
481   // itself.
482   void UpdateActiveMouseView(SubmenuView* event_source,
483                              const ui::MouseEvent& event,
484                              View* target_menu);
485
486   // Sends a mouse release event to the current active mouse view and sets
487   // it to null.
488   void SendMouseReleaseToActiveView(SubmenuView* event_source,
489                                     const ui::MouseEvent& event);
490
491   // Sends a mouse capture lost event to the current active mouse view and sets
492   // it to null.
493   void SendMouseCaptureLostToActiveView();
494
495   // Sets/gets the active mouse view. See UpdateActiveMouseView() for details.
496   void SetActiveMouseView(View* view);
497   View* GetActiveMouseView();
498
499   // Sets exit type. Calling this can terminate the active nested message-loop.
500   void SetExitType(ExitType type);
501
502   // Terminates the current nested message-loop.
503   void TerminateNestedMessageLoop();
504
505   // Returns true if SetExitType() should quit the message loop.
506   bool ShouldQuitNow() const;
507
508   // Handles the mouse location event on the submenu |source|.
509   void HandleMouseLocation(SubmenuView* source,
510                            const gfx::Point& mouse_location);
511
512   // Retrieve an appropriate Screen.
513   gfx::Screen* GetScreen();
514
515   // The active instance.
516   static MenuController* active_instance_;
517
518   // If true, Run blocks. If false, Run doesn't block and this is used for
519   // drag and drop. Note that the semantics for drag and drop are slightly
520   // different: cancel timer is kicked off any time the drag moves outside the
521   // menu, mouse events do nothing...
522   bool blocking_run_;
523
524   // If true, we're showing.
525   bool showing_;
526
527   // Indicates what to exit.
528   ExitType exit_type_;
529
530   // Whether we did a capture. We do a capture only if we're blocking and
531   // the mouse was down when Run.
532   bool did_capture_;
533
534   // As the user drags the mouse around pending_state_ changes immediately.
535   // When the user stops moving/dragging the mouse (or clicks the mouse)
536   // pending_state_ is committed to state_, potentially resulting in
537   // opening or closing submenus. This gives a slight delayed effect to
538   // submenus as the user moves the mouse around. This is done so that as the
539   // user moves the mouse all submenus don't immediately pop.
540   State pending_state_;
541   State state_;
542
543   // If the user accepted the selection, this is the result.
544   MenuItemView* result_;
545
546   // The event flags when the user selected the menu.
547   int accept_event_flags_;
548
549   // If not empty, it means we're nested. When Run is invoked from within
550   // Run, the current state (state_) is pushed onto menu_stack_. This allows
551   // MenuController to restore the state when the nested run returns.
552   std::list<State> menu_stack_;
553
554   // As the mouse moves around submenus are not opened immediately. Instead
555   // they open after this timer fires.
556   base::OneShotTimer<MenuController> show_timer_;
557
558   // Used to invoke CancelAll(). This is used during drag and drop to hide the
559   // menu after the mouse moves out of the of the menu. This is necessitated by
560   // the lack of an ability to detect when the drag has completed from the drop
561   // side.
562   base::OneShotTimer<MenuController> cancel_all_timer_;
563
564   // Drop target.
565   MenuItemView* drop_target_;
566   MenuDelegate::DropPosition drop_position_;
567
568   // Owner of child windows.
569   // WARNING: this may be NULL.
570   Widget* owner_;
571
572   // Indicates a possible drag operation.
573   bool possible_drag_;
574
575   // True when drag operation is in progress.
576   bool drag_in_progress_;
577
578   // True when the drag operation in progress was initiated by the
579   // MenuController for a child MenuItemView (as opposed to initiated separately
580   // by a child View).
581   bool did_initiate_drag_;
582
583   // Location the mouse was pressed at. Used to detect d&d.
584   gfx::Point press_pt_;
585
586   // We get a slew of drag updated messages as the mouse is over us. To avoid
587   // continually processing whether we can drop, we cache the coordinates.
588   bool valid_drop_coordinates_;
589   gfx::Point drop_pt_;
590   int last_drop_operation_;
591
592   // If true, we're in the middle of invoking ShowAt on a submenu.
593   bool showing_submenu_;
594
595   // Task for scrolling the menu. If non-null indicates a scroll is currently
596   // underway.
597   scoped_ptr<MenuScrollTask> scroll_task_;
598
599   MenuButton* menu_button_;
600
601   // ViewStorage id used to store the view mouse drag events are forwarded to.
602   // See UpdateActiveMouseView() for details.
603   const int active_mouse_view_id_;
604
605   internal::MenuControllerDelegate* delegate_;
606
607   // How deep we are in nested message loops. This should be at most 2 (when
608   // showing a context menu from a menu).
609   int message_loop_depth_;
610
611   views::MenuConfig menu_config_;
612
613   // The timestamp of the event which closed the menu - or 0 otherwise.
614   base::TimeDelta closing_event_time_;
615
616   // Time when the menu is first shown.
617   base::TimeTicks menu_start_time_;
618
619   // If a mouse press triggered this menu, this will have its location (in
620   // screen coordinates). Otherwise this will be (0, 0).
621   gfx::Point menu_start_mouse_press_loc_;
622
623   // Controls behavior differences between a combobox and other types of menu
624   // (like a context menu).
625   bool is_combobox_;
626
627   // Set to true if the menu item was selected by touch.
628   bool item_selected_by_touch_;
629
630   scoped_ptr<MenuMessageLoop> message_loop_;
631
632   DISALLOW_COPY_AND_ASSIGN(MenuController);
633 };
634
635 }  // namespace views
636
637 #endif  // UI_VIEWS_CONTROLS_MENU_MENU_CONTROLLER_H_