File: bookmark_menu_bridge.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (186 lines) | stat: -rw-r--r-- 7,484 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_MENU_BRIDGE_H_
#define CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_MENU_BRIDGE_H_

#include <map>

#include "base/files/file_path.h"
#include "base/memory/raw_ptr.h"
#include "base/scoped_observation.h"
#include "chrome/browser/bookmarks/bookmark_merged_surface_service_observer.h"
#include "components/bookmarks/browser/bookmark_model.h"

class BookmarkMergedSurfaceService;
struct BookmarkParentFolder;
class Profile;
@class NSImage;
@class NSMenu;
@class NSMenuItem;
@class BookmarkMenuCocoaController;

namespace bookmarks {
class BookmarkNode;
}

// C++ controller for the bookmark menu; one per AppController (which
// means there is only one).  When bookmarks are changed, this class
// takes care of updating Cocoa bookmark menus.  This is not named
// BookmarkMenuController to help avoid confusion between languages.
// This class needs to be C++, not ObjC, since it derives from
// BookmarkMergedSurfaceServiceObserver.
//
// Most Chromium Cocoa menu items are static from a nib (e.g. New
// Tab), but may be enabled/disabled under certain circumstances
// (e.g. Cut and Paste).  In addition, most Cocoa menu items have
// firstResponder: as a target.  Unusually, bookmark menu items are
// created dynamically.  They also have a target of
// BookmarkMenuCocoaController instead of firstResponder.
// See BookmarkMenuBridge::AddNodeToMenu()).
class BookmarkMenuBridge : public BookmarkMergedSurfaceServiceObserver {
 public:
  BookmarkMenuBridge(Profile* profile, NSMenu* menu_root);

  BookmarkMenuBridge(const BookmarkMenuBridge&) = delete;
  BookmarkMenuBridge& operator=(const BookmarkMenuBridge&) = delete;

  ~BookmarkMenuBridge() override;

  // BookmarkMergedSurfaceServiceObserver:
  void BookmarkMergedSurfaceServiceLoaded() override;
  void BookmarkMergedSurfaceServiceBeingDeleted() override;
  void BookmarkNodeAdded(const BookmarkParentFolder& parent,
                         size_t index) override;
  void BookmarkNodesRemoved(
      const BookmarkParentFolder& parent,
      const base::flat_set<const bookmarks::BookmarkNode*>& nodes) override;
  void BookmarkNodeMoved(const BookmarkParentFolder& old_parent,
                         size_t old_index,
                         const BookmarkParentFolder& new_parent,
                         size_t new_index) override;
  void BookmarkNodeChanged(const bookmarks::BookmarkNode* node) override;
  void BookmarkNodeFaviconChanged(const bookmarks::BookmarkNode* node) override;
  void BookmarkParentFolderChildrenReordered(
      const BookmarkParentFolder& folder) override;
  void BookmarkAllUserNodesRemoved() override;

  bool IsMenuRoot(NSMenu* menu);

  // Builds the main bookmark menu if it has been marked invalid. Its submenus
  // will NOT be built recursively.
  void UpdateRootMenuIfInvalid();

  // Builds a bookmark folder submenu on demand. Submenus of `menu` will NOT be
  // built recursively.
  void UpdateNonRootMenu(NSMenu* menu, const BookmarkParentFolder& folder);

  // I wish I had a "friend @class" construct.
  bookmarks::BookmarkModel* GetBookmarkModelForTesting();
  Profile* GetProfile();
  const base::FilePath& GetProfileDir() const;

  // Return the Bookmark menu.
  NSMenu* BookmarkMenu();

  // Clear all bookmarks from |menu_root_|.
  void ClearBookmarkMenu();

  // Resets |profile_| to nullptr. Called before the Profile is destroyed, if
  // this bridge is still needed. Rebuilds the entire menu recursively, so it
  // remains functional after the Profile is destroyed.
  //
  // Also performs some internal cleanup, like resetting observers and pointers
  // to the Profile and KeyedServices.
  void OnProfileWillBeDestroyed();

  // Returns the GUID of the BookmarkNode for |tag|. If |tag| is not the tag of
  // an NSMenuItem in this menu, returns the invalid GUID.
  base::Uuid TagToGUID(int64_t tag) const;

  // Returns the NSMenuItem for a given BookmarkNode, exposed publicly for
  // testing.
  NSMenuItem* MenuItemForNodeForTest(const bookmarks::BookmarkNode* node);

 private:
  friend class BookmarkMenuBridgeTest;

  // Returns true if the parent folder has at least one child.
  bool HasContent(const BookmarkParentFolder& folder);

  void BuildRootMenu(bool recurse);

  // Marks the bookmark menu as being invalid.
  void InvalidateMenu() { is_menu_valid_ = false; }
  bool IsMenuValid() const { return is_menu_valid_; }

  // Adds a submenu representing |folder| to |menu|. Uses the title of
  // |folder|'s underlying nodes as the submenu's title and the provided |image|
  // as its icon. If |recurse| is true, recursively adds all child nodes of
  // |node|.
  void AddSubmenu(NSMenu* menu,
                  const BookmarkParentFolder& folder,
                  NSImage* image,
                  bool recurse);

  // Adds all child nodes of |folder| to |menu|. If |recurse| is true,
  // recursively adds children of the child nodes.
  void AddChildrenToMenu(const BookmarkParentFolder& folder,
                         NSMenu* menu,
                         bool recurse);

  // Adds |node| as an item or a submenu to the bookmark menu. If |recurse| is
  // true and |node| has children, recursively adds them.
  //
  // TODO(jrg): add a counter to enforce maximum nodes added
  void AddNodeToMenu(const bookmarks::BookmarkNode* node,
                     NSMenu* menu,
                     bool recurse);

  // Helper for adding an item to our bookmark menu. An item which has a
  // localized title specified by |message_id| will be added to |menu|.
  // The item is also bound to |node| by tag. |command_id| selects the action.
  void AddItemToMenu(int command_id,
                     int message_id,
                     const bookmarks::BookmarkNode* node,
                     NSMenu* menu,
                     bool enabled);

  // This configures an NSMenuItem with all the data from a BookmarkNode. This
  // is used to update existing menu items, as well as to configure newly
  // created ones, like in AddNodeToMenu().
  void ConfigureMenuItem(const bookmarks::BookmarkNode* node, NSMenuItem* item);

  // Returns the NSMenuItem for a given BookmarkNode.
  NSMenuItem* MenuItemForNode(const bookmarks::BookmarkNode* node);

  // True iff the menu is up to date with the BookmarkMergedSurfaceService.
  bool is_menu_valid_;

  raw_ptr<Profile> profile_;  // weak
  raw_ptr<BookmarkMergedSurfaceService>
      bookmark_service_;  // owned by |profile_|.

  BookmarkMenuCocoaController* __strong controller_;
  NSMenu* __strong menu_root_;

  base::FilePath profile_dir_;  // Remembered after OnProfileWillBeDestroyed().

  // The folder image so we can use one copy for all.
  NSImage* __strong folder_image_;

  // In order to appropriately update items in the bookmark menu, without
  // forcing a rebuild, map the model's nodes to menu items.
  std::map<const bookmarks::BookmarkNode*, NSMenuItem*> bookmark_nodes_;

  // Tags are NSIntegers, so they're not necessarily large enough to hold a
  // GUID. Instead, map the tags to the corresponding GUIDs.
  std::map<int64_t, base::Uuid> tag_to_guid_;

  base::ScopedObservation<BookmarkMergedSurfaceService,
                          BookmarkMergedSurfaceServiceObserver>
      bookmark_service_observation_{this};
};

#endif  // CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_MENU_BRIDGE_H_