• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 MenuRunnerImpl;
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 
87   enum RunResult {
88     // Indicates RunMenuAt is returning because the MenuRunner was deleted.
89     MENU_DELETED,
90 
91     // Indicates RunMenuAt returned and MenuRunner was not deleted.
92     NORMAL_EXIT
93   };
94 
95   // Creates a new MenuRunner.
96   explicit MenuRunner(ui::MenuModel* menu_model);
97   explicit MenuRunner(MenuItemView* menu);
98   ~MenuRunner();
99 
100   // Returns the menu.
101   MenuItemView* GetMenu();
102 
103   // Takes ownership of |menu|, deleting it when MenuRunner is deleted. You
104   // only need call this if you create additional menus from
105   // MenuDelegate::GetSiblingMenu.
106   void OwnMenu(MenuItemView* menu);
107 
108   // Runs the menu. |types| is a bitmask of RunTypes. If this returns
109   // MENU_DELETED the method is returning because the MenuRunner was deleted.
110   // Typically callers should NOT do any processing if this returns
111   // MENU_DELETED.
112   // If |anchor| uses a |BUBBLE_..| type, the bounds will get determined by
113   // using |bounds| as the thing to point at in screen coordinates.
114   RunResult RunMenuAt(Widget* parent,
115                       MenuButton* button,
116                       const gfx::Rect& bounds,
117                       MenuAnchorPosition anchor,
118                       ui::MenuSourceType source_type,
119                       int32 types) WARN_UNUSED_RESULT;
120 
121   // Returns true if we're in a nested message loop running the menu.
122   bool IsRunning() const;
123 
124   // Hides and cancels the menu. This does nothing if the menu is not open.
125   void Cancel();
126 
127   // Returns the time from the event which closed the menu - or 0.
128   base::TimeDelta closing_event_time() const;
129 
130  private:
131   friend class test::MenuRunnerTestAPI;
132 
133   // Sets an implementation of RunMenuAt. This is intended to be used at test.
134   void SetRunnerHandler(scoped_ptr<MenuRunnerHandler> runner_handler);
135 
136   scoped_ptr<MenuModelAdapter> menu_model_adapter_;
137 
138   internal::MenuRunnerImpl* holder_;
139 
140   // An implementation of RunMenuAt. This is usually NULL and ignored. If this
141   // is not NULL, this implementation will be used.
142   scoped_ptr<MenuRunnerHandler> runner_handler_;
143 
144   scoped_ptr<internal::DisplayChangeListener> display_change_listener_;
145 
146   DISALLOW_COPY_AND_ASSIGN(MenuRunner);
147 };
148 
149 namespace internal {
150 
151 // DisplayChangeListener is intended to listen for changes in the display size
152 // and cancel the menu. DisplayChangeListener is created when the menu is
153 // shown.
154 class DisplayChangeListener {
155  public:
~DisplayChangeListener()156   virtual ~DisplayChangeListener() {}
157 
158   // Creates the platform specified DisplayChangeListener, or NULL if there
159   // isn't one. Caller owns the returned value.
160   static DisplayChangeListener* Create(Widget* parent,
161                                        MenuRunner* runner);
162 
163  protected:
DisplayChangeListener()164   DisplayChangeListener() {}
165 };
166 
167 }
168 
169 }  // namespace views
170 
171 #endif  // UI_VIEWS_CONTROLS_MENU_MENU_RUNNER_H_
172