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