menu_runner.h revision 5c02ac1a9c1b504631c0a3d2b6e737b5d738bae1
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 15namespace base { 16class TimeDelta; 17} 18 19namespace gfx { 20class Rect; 21} 22 23namespace ui { 24class MenuModel; 25} 26 27namespace views { 28 29class MenuButton; 30class MenuItemView; 31class MenuModelAdapter; 32class MenuRunnerHandler; 33class Widget; 34 35namespace internal { 36class DisplayChangeListener; 37class MenuRunnerImpl; 38} 39 40namespace test { 41class 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. 63class 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 149namespace 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. 154class DisplayChangeListener { 155 public: 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: 164 DisplayChangeListener() {} 165}; 166 167} 168 169} // namespace views 170 171#endif // UI_VIEWS_CONTROLS_MENU_MENU_RUNNER_H_ 172