15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef UI_VIEWS_CONTROLS_MENU_MENU_RUNNER_H_
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define UI_VIEWS_CONTROLS_MENU_MENU_RUNNER_H_
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h"
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/memory/scoped_ptr.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/menu/menu_item_view.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace ui {
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class MenuModel;
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace views {
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MenuButton;
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class MenuModelAdapter;
21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class MenuRunnerHandler;
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Widget;
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace internal {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class DisplayChangeListener;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MenuRunnerImpl;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace test {
30a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class MenuRunnerTestAPI;
31a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
32a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MenuRunner is responsible for showing (running) the menu and additionally
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// owning the MenuItemView. RunMenuAt() runs a nested message loop. It is safe
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to delete MenuRunner at any point, but MenuRunner internally only deletes the
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MenuItemView *after* the nested message loop completes. If MenuRunner is
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// deleted while the menu is showing the delegate of the menu is reset. This is
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// done to ensure delegates aren't notified after they may have been deleted.
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// NOTE: while you can delete a MenuRunner at any point, the nested message loop
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// won't return immediately. This means if you delete the object that owns
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the MenuRunner while the menu is running, your object is effectively still
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// on the stack. A return value of MENU_DELETED indicated this. In most cases
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// if RunMenuAt() returns MENU_DELETED, you should return immediately.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Similarly you should avoid creating MenuRunner on the stack. Doing so means
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MenuRunner may not be immediately destroyed if your object is destroyed,
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// resulting in possible callbacks to your now deleted object. Instead you
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// should define MenuRunner as a scoped_ptr in your class so that when your
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// object is destroyed MenuRunner initiates the proper cleanup and ensures your
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// object isn't accessed again.
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class VIEWS_EXPORT MenuRunner {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enum RunTypes {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The menu has mnemonics.
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HAS_MNEMONICS = 1 << 0,
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The menu is a nested context menu. For example, click a folder on the
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // bookmark bar, then right click an entry to get its context menu.
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IS_NESTED     = 1 << 1,
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Used for showing a menu during a drop operation. This does NOT block the
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // caller, instead the delegate is notified when the menu closes via the
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // DropMenuClosed method.
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FOR_DROP      = 1 << 2,
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The menu is a context menu (not necessarily nested), for example right
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // click on a link on a website in the browser.
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CONTEXT_MENU  = 1 << 3,
704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // The menu should behave like a Windows native Combobox dropdow menu.
724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // This behavior includes accepting the pending item and closing on F4.
734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    COMBOBOX  = 1 << 4,
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enum RunResult {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Indicates RunMenuAt is returning because the MenuRunner was deleted.
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MENU_DELETED,
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Indicates RunMenuAt returned and MenuRunner was not deleted.
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NORMAL_EXIT
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Creates a new MenuRunner.
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  explicit MenuRunner(ui::MenuModel* menu_model);
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit MenuRunner(MenuItemView* menu);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~MenuRunner();
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns the menu.
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MenuItemView* GetMenu();
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Takes ownership of |menu|, deleting it when MenuRunner is deleted. You
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // only need call this if you create additional menus from
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // MenuDelegate::GetSiblingMenu.
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void OwnMenu(MenuItemView* menu);
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Runs the menu. |types| is a bitmask of RunTypes. If this returns
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // MENU_DELETED the method is returning because the MenuRunner was deleted.
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Typically callers should NOT do any processing if this returns
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // MENU_DELETED.
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If |anchor| uses a |BUBBLE_..| type, the bounds will get determined by
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // using |bounds| as the thing to point at in screen coordinates.
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RunResult RunMenuAt(Widget* parent,
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      MenuButton* button,
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      const gfx::Rect& bounds,
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      MenuItemView::AnchorPosition anchor,
1077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                      ui::MenuSourceType source_type,
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      int32 types) WARN_UNUSED_RESULT;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns true if we're in a nested message loop running the menu.
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool IsRunning() const;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Hides and cancels the menu. This does nothing if the menu is not open.
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Cancel();
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Returns the time from the event which closed the menu - or 0.
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeDelta closing_event_time() const;
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
120a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  friend class test::MenuRunnerTestAPI;
121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Sets an implementation of RunMenuAt. This is intended to be used at test.
123a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  void SetRunnerHandler(scoped_ptr<MenuRunnerHandler> runner_handler);
124a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<MenuModelAdapter> menu_model_adapter_;
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  internal::MenuRunnerImpl* holder_;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
129a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // An implementation of RunMenuAt. This is usually NULL and ignored. If this
130a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // is not NULL, this implementation will be used.
131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_ptr<MenuRunnerHandler> runner_handler_;
132a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<internal::DisplayChangeListener> display_change_listener_;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(MenuRunner);
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace internal {
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DisplayChangeListener is intended to listen for changes in the display size
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and cancel the menu. DisplayChangeListener is created when the menu is
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// shown.
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class DisplayChangeListener {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~DisplayChangeListener() {}
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Creates the platform specified DisplayChangeListener, or NULL if there
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // isn't one. Caller owns the returned value.
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static DisplayChangeListener* Create(Widget* parent,
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       MenuRunner* runner);
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DisplayChangeListener() {}
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace views
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // UI_VIEWS_CONTROLS_MENU_MENU_RUNNER_H_
161