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