Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / cocoa / history_menu_bridge.h
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 #ifndef CHROME_BROWSER_UI_COCOA_HISTORY_MENU_BRIDGE_H_
6 #define CHROME_BROWSER_UI_COCOA_HISTORY_MENU_BRIDGE_H_
7
8 #import <Cocoa/Cocoa.h>
9 #include <map>
10 #include <vector>
11
12 #include "base/mac/scoped_nsobject.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/task/cancelable_task_tracker.h"
15 #include "chrome/browser/common/cancelable_request.h"
16 #import "chrome/browser/favicon/favicon_service.h"
17 #include "chrome/browser/history/history_service.h"
18 #include "chrome/browser/sessions/session_id.h"
19 #include "chrome/browser/sessions/tab_restore_service.h"
20 #include "chrome/browser/sessions/tab_restore_service_observer.h"
21 #import "chrome/browser/ui/cocoa/main_menu_item.h"
22 #include "content/public/browser/notification_observer.h"
23
24 class NotificationRegistrar;
25 class PageUsageData;
26 class Profile;
27 class TabRestoreService;
28 @class HistoryMenuCocoaController;
29
30 namespace {
31 class HistoryMenuBridgeTest;
32 }
33
34 namespace chrome {
35 struct FaviconImageResult;
36 }
37
38 // C++ bridge for the history menu; one per AppController (means there
39 // is only one). This class observes various data sources, namely the
40 // HistoryService and the TabRestoreService, and then updates the NSMenu when
41 // there is new data.
42 //
43 // The history menu is broken up into sections: most visisted and recently
44 // closed. The overall menu has a tag of IDC_HISTORY_MENU, with the user content
45 // items having the local tags defined in the enum below. Items within a section
46 // all share the same tag. The structure of the menu is laid out in MainMenu.xib
47 // and the generated content is inserted after the Title elements. The recently
48 // closed section is special in that those menu items can have submenus to list
49 // all the tabs within that closed window. By convention, these submenu items
50 // have a tag that's equal to the parent + 1. Tags within the history menu have
51 // a range of [400,500) and do not go through CommandDispatch for their target-
52 // action mechanism.
53 //
54 // These menu items do not use firstResponder as their target. Rather, they are
55 // hooked directly up to the HistoryMenuCocoaController that then bridges back
56 // to this class. These items are created via the AddItemToMenu() helper. Also,
57 // unlike the typical ownership model, this bridge owns its controller. The
58 // controller is very thin and only exists to interact with Cocoa, but this
59 // class does the bulk of the work.
60 class HistoryMenuBridge : public content::NotificationObserver,
61                           public TabRestoreServiceObserver,
62                           public MainMenuItem {
63  public:
64   // This is a generalization of the data we store in the history menu because
65   // we pull things from different sources with different data types.
66   struct HistoryItem {
67    public:
68     HistoryItem();
69     // Copy constructor allowed.
70     HistoryItem(const HistoryItem& copy);
71     ~HistoryItem();
72
73     // The title for the menu item.
74     base::string16 title;
75     // The URL that will be navigated to if the user selects this item.
76     GURL url;
77     // Favicon for the URL.
78     base::scoped_nsobject<NSImage> icon;
79
80     // If the icon is being requested from the FaviconService, |icon_requested|
81     // will be true and |icon_task_id| will be valid. If this is false, then
82     // |icon_task_id| will be
83     // base::CancelableTaskTracker::kBadTaskId.
84     bool icon_requested;
85     // The Handle given to us by the FaviconService for the icon fetch request.
86     base::CancelableTaskTracker::TaskId icon_task_id;
87
88     // The pointer to the item after it has been created. Strong; NSMenu also
89     // retains this. During a rebuild flood (if the user closes a lot of tabs
90     // quickly), the NSMenu can release the item before the HistoryItem has
91     // been fully deleted. If this were a weak pointer, it would result in a
92     // zombie.
93     base::scoped_nsobject<NSMenuItem> menu_item;
94
95     // This ID is unique for a browser session and can be passed to the
96     // TabRestoreService to re-open the closed window or tab that this
97     // references. A non-0 session ID indicates that this is an entry can be
98     // restored that way. Otherwise, the URL will be used to open the item and
99     // this ID will be 0.
100     SessionID::id_type session_id;
101
102     // If the HistoryItem is a window, this will be the vector of tabs. Note
103     // that this is a list of weak references. The |menu_item_map_| is the owner
104     // of all items. If it is not a window, then the entry is a single page and
105     // the vector will be empty.
106     std::vector<HistoryItem*> tabs;
107
108    private:
109     // Copying is explicitly allowed, but assignment is not.
110     void operator=(const HistoryItem&);
111   };
112
113   // These tags are not global view tags and are local to the history menu. The
114   // normal procedure for menu items is to go through CommandDispatch, but since
115   // history menu items are hooked directly up to their target, they do not need
116   // to have the global IDC view tags.
117   enum Tags {
118     kRecentlyClosedSeparator = 400,  // Item before recently closed section.
119     kRecentlyClosedTitle = 401,  // Title of recently closed section.
120     kRecentlyClosed = 420,  // Used for items in the recently closed section.
121     kVisitedSeparator = 440,  // Separator before visited section.
122     kVisitedTitle = 441,  // Title of the visited section.
123     kVisited = 460,  // Used for all entries in the visited section.
124     kShowFullSeparator = 480  // Separator after the visited section.
125   };
126
127   explicit HistoryMenuBridge(Profile* profile);
128   virtual ~HistoryMenuBridge();
129
130   // content::NotificationObserver:
131   virtual void Observe(int type,
132                        const content::NotificationSource& source,
133                        const content::NotificationDetails& details) OVERRIDE;
134
135   // TabRestoreServiceObserver:
136   virtual void TabRestoreServiceChanged(TabRestoreService* service) OVERRIDE;
137   virtual void TabRestoreServiceDestroyed(TabRestoreService* service) OVERRIDE;
138
139   // MainMenuItem:
140   virtual void ResetMenu() OVERRIDE;
141   virtual void BuildMenu() OVERRIDE;
142
143   // Looks up an NSMenuItem in the |menu_item_map_| and returns the
144   // corresponding HistoryItem.
145   HistoryItem* HistoryItemForMenuItem(NSMenuItem* item);
146
147   // I wish I has a "friend @class" construct. These are used by the HMCC
148   // to access model information when responding to actions.
149   HistoryService* service();
150   Profile* profile();
151
152  protected:
153   // Return the History menu.
154   virtual NSMenu* HistoryMenu();
155
156   // Clear items in the given |menu|. Menu items in the same section are given
157   // the same tag. This will go through the entire history menu, removing all
158   // items with a given tag. Note that this will recurse to submenus, removing
159   // child items from the menu item map. This will only remove items that have
160   // a target hooked up to the |controller_|.
161   void ClearMenuSection(NSMenu* menu, NSInteger tag);
162
163   // Adds a given title and URL to the passed-in menu with a certain tag and
164   // index. This will add |item| and the newly created menu item to the
165   // |menu_item_map_|, which takes ownership. Items are deleted in
166   // ClearMenuSection(). This returns the new menu item that was just added.
167   NSMenuItem* AddItemToMenu(HistoryItem* item,
168                             NSMenu* menu,
169                             NSInteger tag,
170                             NSInteger index);
171
172   // Called by the ctor if |service_| is ready at the time, or by a
173   // notification receiver. Finishes initialization tasks by subscribing for
174   // change notifications and calling CreateMenu().
175   void Init();
176
177   // Does the query for the history information to create the menu.
178   void CreateMenu();
179
180   // Callback method for when HistoryService query results are ready with the
181   // most recently-visited sites.
182   void OnVisitedHistoryResults(CancelableRequestProvider::Handle handle,
183                                history::QueryResults* results);
184
185   // Creates a HistoryItem* for the given tab entry. Caller takes ownership of
186   // the result and must delete it when finished.
187   HistoryItem* HistoryItemForTab(const TabRestoreService::Tab& entry);
188
189   // Helper function that sends an async request to the FaviconService to get
190   // an icon. The callback will update the NSMenuItem directly.
191   void GetFaviconForHistoryItem(HistoryItem* item);
192
193   // Callback for the FaviconService to return favicon image data when we
194   // request it. This decodes the raw data, updates the HistoryItem, and then
195   // sets the image on the menu. Called on the same same thread that
196   // GetFaviconForHistoryItem() was called on (UI thread).
197   void GotFaviconData(HistoryItem* item,
198                       const chrome::FaviconImageResult& image_result);
199
200   // Cancels a favicon load request for a given HistoryItem, if one is in
201   // progress.
202   void CancelFaviconRequest(HistoryItem* item);
203
204  private:
205   friend class ::HistoryMenuBridgeTest;
206   friend class HistoryMenuCocoaControllerTest;
207
208   base::scoped_nsobject<HistoryMenuCocoaController> controller_;  // strong
209
210   Profile* profile_;  // weak
211   HistoryService* history_service_;  // weak
212   TabRestoreService* tab_restore_service_;  // weak
213
214   content::NotificationRegistrar registrar_;
215   CancelableRequestConsumer cancelable_request_consumer_;
216   base::CancelableTaskTracker cancelable_task_tracker_;
217
218   // Mapping of NSMenuItems to HistoryItems. This owns the HistoryItems until
219   // they are removed and deleted via ClearMenuSection().
220   std::map<NSMenuItem*, HistoryItem*> menu_item_map_;
221
222   // Maps HistoryItems to favicon request Handles.
223   CancelableRequestConsumerTSimple<HistoryItem*> favicon_consumer_;
224
225   // Requests to re-create the menu are coalesced. |create_in_progress_| is true
226   // when either waiting for the history service to return query results, or
227   // when the menu is rebuilding. |need_recreate_| is true whenever a rebuild
228   // has been scheduled but is waiting for the current one to finish.
229   bool create_in_progress_;
230   bool need_recreate_;
231
232   // The default favicon if a HistoryItem does not have one.
233   base::scoped_nsobject<NSImage> default_favicon_;
234
235   DISALLOW_COPY_AND_ASSIGN(HistoryMenuBridge);
236 };
237
238 #endif  // CHROME_BROWSER_UI_COCOA_HISTORY_MENU_BRIDGE_H_