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