1// Copyright (c) 2011 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// C++ controller for the bookmark menu; one per AppController (which
6// means there is only one).  When bookmarks are changed, this class
7// takes care of updating Cocoa bookmark menus.  This is not named
8// BookmarkMenuController to help avoid confusion between languages.
9// This class needs to be C++, not ObjC, since it derives from
10// BookmarkModelObserver.
11//
12// Most Chromium Cocoa menu items are static from a nib (e.g. New
13// Tab), but may be enabled/disabled under certain circumstances
14// (e.g. Cut and Paste).  In addition, most Cocoa menu items have
15// firstResponder: as a target.  Unusually, bookmark menu items are
16// created dynamically.  They also have a target of
17// BookmarkMenuCocoaController instead of firstResponder.
18// See BookmarkMenuBridge::AddNodeToMenu()).
19
20#ifndef CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_MENU_BRIDGE_H_
21#define CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_MENU_BRIDGE_H_
22#pragma once
23
24#include <map>
25
26#include "base/memory/scoped_nsobject.h"
27#include "chrome/browser/bookmarks/bookmark_model_observer.h"
28
29class BookmarkNode;
30class Profile;
31@class NSImage;
32@class NSMenu;
33@class NSMenuItem;
34@class BookmarkMenuCocoaController;
35
36class BookmarkMenuBridge : public BookmarkModelObserver {
37 public:
38  BookmarkMenuBridge(Profile* profile);
39  virtual ~BookmarkMenuBridge();
40
41  // Overridden from BookmarkModelObserver
42  virtual void Loaded(BookmarkModel* model);
43  virtual void BookmarkModelBeingDeleted(BookmarkModel* model);
44  virtual void BookmarkNodeMoved(BookmarkModel* model,
45                                 const BookmarkNode* old_parent,
46                                 int old_index,
47                                 const BookmarkNode* new_parent,
48                                 int new_index);
49  virtual void BookmarkNodeAdded(BookmarkModel* model,
50                                 const BookmarkNode* parent,
51                                 int index);
52  virtual void BookmarkNodeRemoved(BookmarkModel* model,
53                                   const BookmarkNode* parent,
54                                   int old_index,
55                                   const BookmarkNode* node);
56  virtual void BookmarkNodeChanged(BookmarkModel* model,
57                                   const BookmarkNode* node);
58  virtual void BookmarkNodeFaviconLoaded(BookmarkModel* model,
59                                         const BookmarkNode* node);
60  virtual void BookmarkNodeChildrenReordered(BookmarkModel* model,
61                                             const BookmarkNode* node);
62
63  // Rebuilds the bookmark menu, if it has been marked invalid.
64  void UpdateMenu(NSMenu* bookmark_menu);
65
66  // I wish I had a "friend @class" construct.
67  BookmarkModel* GetBookmarkModel();
68  Profile* GetProfile();
69
70 protected:
71  // Clear all bookmarks from the given bookmark menu.
72  void ClearBookmarkMenu(NSMenu* menu);
73
74  // Mark the bookmark menu as being invalid.
75  void InvalidateMenu()  { menuIsValid_ = false; }
76
77  // Helper for adding the node as a submenu to the menu with the
78  // given title.
79  void AddNodeAsSubmenu(NSMenu* menu,
80                        const BookmarkNode* node,
81                        NSString* title);
82
83  // Helper for recursively adding items to our bookmark menu.
84  // All children of |node| will be added to |menu|.
85  // TODO(jrg): add a counter to enforce maximum nodes added
86  void AddNodeToMenu(const BookmarkNode* node, NSMenu* menu);
87
88  // Helper for adding an item to our bookmark menu. An item which has a
89  // localized title specified by |message_id| will be added to |menu|.
90  // The item is also bound to |node| by tag. |command_id| selects the action.
91  void AddItemToMenu(int command_id,
92                     int message_id,
93                     const BookmarkNode* node,
94                     NSMenu* menu,
95                     bool enabled);
96
97  // This configures an NSMenuItem with all the data from a BookmarkNode. This
98  // is used to update existing menu items, as well as to configure newly
99  // created ones, like in AddNodeToMenu().
100  // |set_title| is optional since it is only needed when we get a
101  // node changed notification.  On initial build of the menu we set
102  // the title as part of alloc/init.
103  void ConfigureMenuItem(const BookmarkNode* node, NSMenuItem* item,
104                         bool set_title);
105
106  // Returns the NSMenuItem for a given BookmarkNode.
107  NSMenuItem* MenuItemForNode(const BookmarkNode* node);
108
109  // Return the Bookmark menu.
110  virtual NSMenu* BookmarkMenu();
111
112  // Start watching the bookmarks for changes.
113  void ObserveBookmarkModel();
114
115 private:
116  friend class BookmarkMenuBridgeTest;
117
118  // True iff the menu is up-to-date with the actual BookmarkModel.
119  bool menuIsValid_;
120
121  Profile* profile_;  // weak
122  BookmarkMenuCocoaController* controller_;  // strong
123
124  // The folder image so we can use one copy for all.
125  scoped_nsobject<NSImage> folder_image_;
126
127  // In order to appropriately update items in the bookmark menu, without
128  // forcing a rebuild, map the model's nodes to menu items.
129  std::map<const BookmarkNode*, NSMenuItem*> bookmark_nodes_;
130};
131
132#endif  // CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_MENU_BRIDGE_H_
133