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