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.
5 #ifndef CHROME_BROWSER_UI_COCOA_HISTORY_MENU_BRIDGE_H_
6 #define CHROME_BROWSER_UI_COCOA_HISTORY_MENU_BRIDGE_H_
8 #import <Cocoa/Cocoa.h>
12 #include "base/mac/scoped_nsobject.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/scoped_observer.h"
15 #include "base/task/cancelable_task_tracker.h"
16 #include "chrome/browser/sessions/tab_restore_service.h"
17 #include "chrome/browser/sessions/tab_restore_service_observer.h"
18 #import "chrome/browser/ui/cocoa/main_menu_item.h"
19 #import "components/favicon/core/favicon_service.h"
20 #include "components/history/core/browser/history_service.h"
21 #include "components/history/core/browser/history_service_observer.h"
22 #include "components/sessions/session_id.h"
25 class TabRestoreService
;
26 @
class HistoryMenuCocoaController
;
29 class HistoryMenuBridgeTest
;
32 namespace favicon_base
{
33 struct FaviconImageResult
;
36 // C++ bridge for the history menu; one per AppController (means there
37 // is only one). This class observes various data sources, namely the
38 // HistoryService and the TabRestoreService, and then updates the NSMenu when
41 // The history menu is broken up into sections: most visisted and recently
42 // closed. The overall menu has a tag of IDC_HISTORY_MENU, with the user content
43 // items having the local tags defined in the enum below. Items within a section
44 // all share the same tag. The structure of the menu is laid out in MainMenu.xib
45 // and the generated content is inserted after the Title elements. The recently
46 // closed section is special in that those menu items can have submenus to list
47 // all the tabs within that closed window. By convention, these submenu items
48 // have a tag that's equal to the parent + 1. Tags within the history menu have
49 // a range of [400,500) and do not go through CommandDispatch for their target-
52 // These menu items do not use firstResponder as their target. Rather, they are
53 // hooked directly up to the HistoryMenuCocoaController that then bridges back
54 // to this class. These items are created via the AddItemToMenu() helper. Also,
55 // unlike the typical ownership model, this bridge owns its controller. The
56 // controller is very thin and only exists to interact with Cocoa, but this
57 // class does the bulk of the work.
58 class HistoryMenuBridge
: public TabRestoreServiceObserver
,
60 public history::HistoryServiceObserver
{
62 // This is a generalization of the data we store in the history menu because
63 // we pull things from different sources with different data types.
67 // Copy constructor allowed.
68 HistoryItem(const HistoryItem
& copy
);
71 // The title for the menu item.
73 // The URL that will be navigated to if the user selects this item.
75 // Favicon for the URL.
76 base::scoped_nsobject
<NSImage
> icon
;
78 // If the icon is being requested from the FaviconService, |icon_requested|
79 // will be true and |icon_task_id| will be valid. If this is false, then
80 // |icon_task_id| will be
81 // base::CancelableTaskTracker::kBadTaskId.
83 // The Handle given to us by the FaviconService for the icon fetch request.
84 base::CancelableTaskTracker::TaskId icon_task_id
;
86 // The pointer to the item after it has been created. Strong; NSMenu also
87 // retains this. During a rebuild flood (if the user closes a lot of tabs
88 // quickly), the NSMenu can release the item before the HistoryItem has
89 // been fully deleted. If this were a weak pointer, it would result in a
91 base::scoped_nsobject
<NSMenuItem
> menu_item
;
93 // This ID is unique for a browser session and can be passed to the
94 // TabRestoreService to re-open the closed window or tab that this
95 // references. A non-0 session ID indicates that this is an entry can be
96 // restored that way. Otherwise, the URL will be used to open the item and
98 SessionID::id_type session_id
;
100 // If the HistoryItem is a window, this will be the vector of tabs. Note
101 // that this is a list of weak references. The |menu_item_map_| is the owner
102 // of all items. If it is not a window, then the entry is a single page and
103 // the vector will be empty.
104 std::vector
<HistoryItem
*> tabs
;
107 // Copying is explicitly allowed, but assignment is not.
108 void operator=(const HistoryItem
&);
111 // These tags are not global view tags and are local to the history menu. The
112 // normal procedure for menu items is to go through CommandDispatch, but since
113 // history menu items are hooked directly up to their target, they do not need
114 // to have the global IDC view tags.
116 kRecentlyClosedSeparator
= 400, // Item before recently closed section.
117 kRecentlyClosedTitle
= 401, // Title of recently closed section.
118 kRecentlyClosed
= 420, // Used for items in the recently closed section.
119 kVisitedSeparator
= 440, // Separator before visited section.
120 kVisitedTitle
= 441, // Title of the visited section.
121 kVisited
= 460, // Used for all entries in the visited section.
122 kShowFullSeparator
= 480 // Separator after the visited section.
125 explicit HistoryMenuBridge(Profile
* profile
);
126 ~HistoryMenuBridge() override
;
128 // TabRestoreServiceObserver:
129 void TabRestoreServiceChanged(TabRestoreService
* service
) override
;
130 void TabRestoreServiceDestroyed(TabRestoreService
* service
) override
;
133 void ResetMenu() override
;
134 void BuildMenu() override
;
136 // Looks up an NSMenuItem in the |menu_item_map_| and returns the
137 // corresponding HistoryItem.
138 HistoryItem
* HistoryItemForMenuItem(NSMenuItem
* item
);
140 // I wish I has a "friend @class" construct. These are used by the HMCC
141 // to access model information when responding to actions.
142 history::HistoryService
* service();
146 // Return the History menu.
147 virtual NSMenu
* HistoryMenu();
149 // Clear items in the given |menu|. Menu items in the same section are given
150 // the same tag. This will go through the entire history menu, removing all
151 // items with a given tag. Note that this will recurse to submenus, removing
152 // child items from the menu item map. This will only remove items that have
153 // a target hooked up to the |controller_|.
154 void ClearMenuSection(NSMenu
* menu
, NSInteger tag
);
156 // Adds a given title and URL to the passed-in menu with a certain tag and
157 // index. This will add |item| and the newly created menu item to the
158 // |menu_item_map_|, which takes ownership. Items are deleted in
159 // ClearMenuSection(). This returns the new menu item that was just added.
160 NSMenuItem
* AddItemToMenu(HistoryItem
* item
,
165 // Called by the ctor if |service_| is ready at the time, or by a
166 // notification receiver. Finishes initialization tasks by subscribing for
167 // change notifications and calling CreateMenu().
170 // Does the query for the history information to create the menu.
173 // Invoked when the History information has changed.
174 void OnHistoryChanged();
176 // Callback method for when HistoryService query results are ready with the
177 // most recently-visited sites.
178 void OnVisitedHistoryResults(history::QueryResults
* results
);
180 // Creates a HistoryItem* for the given tab entry. Caller takes ownership of
181 // the result and must delete it when finished.
182 HistoryItem
* HistoryItemForTab(const TabRestoreService::Tab
& entry
);
184 // Helper function that sends an async request to the FaviconService to get
185 // an icon. The callback will update the NSMenuItem directly.
186 void GetFaviconForHistoryItem(HistoryItem
* item
);
188 // Callback for the FaviconService to return favicon image data when we
189 // request it. This decodes the raw data, updates the HistoryItem, and then
190 // sets the image on the menu. Called on the same same thread that
191 // GetFaviconForHistoryItem() was called on (UI thread).
192 void GotFaviconData(HistoryItem
* item
,
193 const favicon_base::FaviconImageResult
& image_result
);
195 // Cancels a favicon load request for a given HistoryItem, if one is in
197 void CancelFaviconRequest(HistoryItem
* item
);
200 friend class ::HistoryMenuBridgeTest
;
201 friend class HistoryMenuCocoaControllerTest
;
203 // history::HistoryServiceObserver:
204 void OnURLVisited(history::HistoryService
* history_service
,
205 ui::PageTransition transition
,
206 const history::URLRow
& row
,
207 const history::RedirectList
& redirects
,
208 base::Time visit_time
) override
;
209 void OnURLsModified(history::HistoryService
* history_service
,
210 const history::URLRows
& changed_urls
) override
;
211 void OnURLsDeleted(history::HistoryService
* history_service
,
214 const history::URLRows
& deleted_rows
,
215 const std::set
<GURL
>& favicon_urls
) override
;
216 void OnHistoryServiceLoaded(history::HistoryService
* service
) override
;
218 base::scoped_nsobject
<HistoryMenuCocoaController
> controller_
; // strong
220 Profile
* profile_
; // weak
221 history::HistoryService
* history_service_
; // weak
222 TabRestoreService
* tab_restore_service_
; // weak
224 base::CancelableTaskTracker cancelable_task_tracker_
;
226 // Mapping of NSMenuItems to HistoryItems. This owns the HistoryItems until
227 // they are removed and deleted via ClearMenuSection().
228 std::map
<NSMenuItem
*, HistoryItem
*> menu_item_map_
;
230 // Requests to re-create the menu are coalesced. |create_in_progress_| is true
231 // when either waiting for the history service to return query results, or
232 // when the menu is rebuilding. |need_recreate_| is true whenever a rebuild
233 // has been scheduled but is waiting for the current one to finish.
234 bool create_in_progress_
;
237 // The default favicon if a HistoryItem does not have one.
238 base::scoped_nsobject
<NSImage
> default_favicon_
;
240 ScopedObserver
<history::HistoryService
, history::HistoryServiceObserver
>
241 history_service_observer_
;
243 DISALLOW_COPY_AND_ASSIGN(HistoryMenuBridge
);
246 #endif // CHROME_BROWSER_UI_COCOA_HISTORY_MENU_BRIDGE_H_