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_RUNNER_H_
      6 #define UI_VIEWS_CONTROLS_MENU_MENU_RUNNER_H_
      7 
      8 #include "base/basictypes.h"
      9 #include "base/compiler_specific.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "ui/base/ui_base_types.h"
     12 #include "ui/views/controls/menu/menu_types.h"
     13 #include "ui/views/views_export.h"
     14 
     15 namespace base {
     16 class TimeDelta;
     17 }
     18 
     19 namespace gfx {
     20 class Rect;
     21 }
     22 
     23 namespace ui {
     24 class MenuModel;
     25 }
     26 
     27 namespace views {
     28 
     29 class MenuButton;
     30 class MenuItemView;
     31 class MenuModelAdapter;
     32 class MenuRunnerHandler;
     33 class Widget;
     34 
     35 namespace internal {
     36 class DisplayChangeListener;
     37 class MenuRunnerImplInterface;
     38 }
     39 
     40 namespace test {
     41 class MenuRunnerTestAPI;
     42 }
     43 
     44 // MenuRunner is responsible for showing (running) the menu and additionally
     45 // owning the MenuItemView. RunMenuAt() runs a nested message loop. It is safe
     46 // to delete MenuRunner at any point, but MenuRunner internally only deletes the
     47 // MenuItemView *after* the nested message loop completes. If MenuRunner is
     48 // deleted while the menu is showing the delegate of the menu is reset. This is
     49 // done to ensure delegates aren't notified after they may have been deleted.
     50 //
     51 // NOTE: while you can delete a MenuRunner at any point, the nested message loop
     52 // won't return immediately. This means if you delete the object that owns
     53 // the MenuRunner while the menu is running, your object is effectively still
     54 // on the stack. A return value of MENU_DELETED indicated this. In most cases
     55 // if RunMenuAt() returns MENU_DELETED, you should return immediately.
     56 //
     57 // Similarly you should avoid creating MenuRunner on the stack. Doing so means
     58 // MenuRunner may not be immediately destroyed if your object is destroyed,
     59 // resulting in possible callbacks to your now deleted object. Instead you
     60 // should define MenuRunner as a scoped_ptr in your class so that when your
     61 // object is destroyed MenuRunner initiates the proper cleanup and ensures your
     62 // object isn't accessed again.
     63 class VIEWS_EXPORT MenuRunner {
     64  public:
     65   enum RunTypes {
     66     // The menu has mnemonics.
     67     HAS_MNEMONICS = 1 << 0,
     68 
     69     // The menu is a nested context menu. For example, click a folder on the
     70     // bookmark bar, then right click an entry to get its context menu.
     71     IS_NESTED     = 1 << 1,
     72 
     73     // Used for showing a menu during a drop operation. This does NOT block the
     74     // caller, instead the delegate is notified when the menu closes via the
     75     // DropMenuClosed method.
     76     FOR_DROP      = 1 << 2,
     77 
     78     // The menu is a context menu (not necessarily nested), for example right
     79     // click on a link on a website in the browser.
     80     CONTEXT_MENU  = 1 << 3,
     81 
     82     // The menu should behave like a Windows native Combobox dropdow menu.
     83     // This behavior includes accepting the pending item and closing on F4.
     84     COMBOBOX  = 1 << 4,
     85 
     86     // A child view is performing a drag-and-drop operation, so the menu should
     87     // stay open (even if it doesn't receive drag updated events). In this case,
     88     // the caller is responsible for closing the menu upon completion of the
     89     // drag-and-drop.
     90     NESTED_DRAG = 1 << 5,
     91   };
     92 
     93   enum RunResult {
     94     // Indicates RunMenuAt is returning because the MenuRunner was deleted.
     95     MENU_DELETED,
     96 
     97     // Indicates RunMenuAt returned and MenuRunner was not deleted.
     98     NORMAL_EXIT
     99   };
    100 
    101   // Creates a new MenuRunner.
    102   // |run_types| is a bitmask of RunTypes.
    103   MenuRunner(ui::MenuModel* menu_model, int32 run_types);
    104   MenuRunner(MenuItemView* menu, int32 run_types);
    105   ~MenuRunner();
    106 
    107   // Runs the menu. If this returns MENU_DELETED the method is returning
    108   // because the MenuRunner was deleted.
    109   // Typically callers should NOT do any processing if this returns
    110   // MENU_DELETED.
    111   // If |anchor| uses a |BUBBLE_..| type, the bounds will get determined by
    112   // using |bounds| as the thing to point at in screen coordinates.
    113   RunResult RunMenuAt(Widget* parent,
    114                       MenuButton* button,
    115                       const gfx::Rect& bounds,
    116                       MenuAnchorPosition anchor,
    117                       ui::MenuSourceType source_type) WARN_UNUSED_RESULT;
    118 
    119   // Returns true if we're in a nested message loop running the menu.
    120   bool IsRunning() const;
    121 
    122   // Hides and cancels the menu. This does nothing if the menu is not open.
    123   void Cancel();
    124 
    125   // Returns the time from the event which closed the menu - or 0.
    126   base::TimeDelta closing_event_time() const;
    127 
    128  private:
    129   friend class test::MenuRunnerTestAPI;
    130 
    131   // Sets an implementation of RunMenuAt. This is intended to be used at test.
    132   void SetRunnerHandler(scoped_ptr<MenuRunnerHandler> runner_handler);
    133 
    134   const int32 run_types_;
    135 
    136   // We own this. No scoped_ptr because it is destroyed by calling Release().
    137   internal::MenuRunnerImplInterface* impl_;
    138 
    139   // An implementation of RunMenuAt. This is usually NULL and ignored. If this
    140   // is not NULL, this implementation will be used.
    141   scoped_ptr<MenuRunnerHandler> runner_handler_;
    142 
    143   scoped_ptr<internal::DisplayChangeListener> display_change_listener_;
    144 
    145   DISALLOW_COPY_AND_ASSIGN(MenuRunner);
    146 };
    147 
    148 namespace internal {
    149 
    150 // DisplayChangeListener is intended to listen for changes in the display size
    151 // and cancel the menu. DisplayChangeListener is created when the menu is
    152 // shown.
    153 class DisplayChangeListener {
    154  public:
    155   virtual ~DisplayChangeListener() {}
    156 
    157   // Creates the platform specified DisplayChangeListener, or NULL if there
    158   // isn't one. Caller owns the returned value.
    159   static DisplayChangeListener* Create(Widget* parent,
    160                                        MenuRunner* runner);
    161 
    162  protected:
    163   DisplayChangeListener() {}
    164 };
    165 
    166 }  // namespace internal
    167 
    168 }  // namespace views
    169 
    170 #endif  // UI_VIEWS_CONTROLS_MENU_MENU_RUNNER_H_
    171