summaryrefslogtreecommitdiffstats
path: root/chrome/browser/cocoa/history_menu_bridge.h
blob: bfa7959b21d8bc51b3216a551f93b648cc7b390a (plain)
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
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_COCOA_HISTORY_MENU_BRIDGE_H_
#define CHROME_BROWSER_COCOA_HISTORY_MENU_BRIDGE_H_

#import <Cocoa/Cocoa.h>
#include "base/scoped_nsobject.h"
#include "base/scoped_ptr.h"
#include "base/scoped_vector.h"
#include "chrome/browser/cancelable_request.h"
#import "chrome/browser/favicon_service.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/sessions/tab_restore_service.h"
#include "chrome/common/notification_observer.h"

class NavigationEntry;
class NotificationRegistrar;
class PageUsageData;
class Profile;
class TabNavigationEntry;
@class HistoryMenuCocoaController;

// C++ controller for the history menu; one per AppController (means there
// is only one). This class observes various data sources, namely the
// HistoryService and the TabRestoreService, and then updates the NSMenu when
// there is new data.
//
// The history menu is broken up into sections: most visisted and recently
// closed. The overall menu has a tag of IDC_HISTORY_MENU, with two sections
// IDC_HISTORY_MENU_VISITED and IDC_HISTORY_MENU_CLOSED, which are used to
// delineate the two sections. Items within these sections are assigned tags
// within IDC_HISTORY_MENU_* + 1..99. 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, history menu items are created
// dynamically. They also have a target of HistoryMenuCocoaController, not
// firstResponder. See HistoryMenuBridge::AddItemToMenu(). Unlike most of our
// Cocoa-Bridge classes, the HMCC is not at the root of the ownership model
// because its only function is to respond to menu item actions; everything
// else is done in this bridge.
class HistoryMenuBridge : public NotificationObserver,
                          public TabRestoreService::Observer {
 public:
  // This is a generalization of the data we store in the history menu because
  // we pull things from different sources with different data types.
  struct HistoryItem {
   public:
    HistoryItem() : icon_requested(false) {}
    ~HistoryItem() {}

    // The title for the menu item.
    string16 title;
    // The URL that will be navigated to if the user selects this item.
    GURL url;
    // Favicon for the URL.
    scoped_nsobject<NSImage> icon;

    // If the icon is being requested from the FaviconService, |icon_requested|
    // will be true and |icon_handle| will be non-NULL. If this is false, then
    // |icon_handle| will be NULL.
    bool icon_requested;
    // The Handle given to us by the FaviconService for the icon fetch request.
    FaviconService::Handle icon_handle;

    // The pointer to the item after it has been created. Weak.
    NSMenuItem* menu_item;

   private:
    DISALLOW_COPY_AND_ASSIGN(HistoryItem);
  };

  explicit HistoryMenuBridge(Profile* profile);
  virtual ~HistoryMenuBridge();

  // Overriden from NotificationObserver.
  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details);

  // For TabRestoreService::Observer
  virtual void TabRestoreServiceChanged(TabRestoreService* service);
  virtual void TabRestoreServiceDestroyed(TabRestoreService* service);

  // I wish I has a "friend @class" construct. These are used by the HMCC
  // to access model information when responding to actions.
  HistoryService* service();
  Profile* profile();
  const ScopedVector<HistoryItem>* const visited_results();
  const ScopedVector<HistoryItem>* const closed_results();

 protected:
  // Return the History menu.
  NSMenu* HistoryMenu();

  // Clear items in the given |menu|. The menu is broken into sections, defined
  // by IDC_HISTORY_MENU_* constants. This function will clear |count| menu
  // items, starting from |tag|.
  void ClearMenuSection(NSMenu* menu, NSInteger tag, unsigned int count);

  // Adds a given title and URL to HistoryMenu() with a certain tag and index.
  void AddItemToMenu(HistoryItem* item,
                     NSMenu* menu,
                     NSInteger tag,
                     NSInteger index);

  // Called by the ctor if |service_| is ready at the time, or by a
  // notification receiver. Finishes initialization tasks by subscribing for
  // change notifications and calling CreateMenu().
  void Init();

  // Does the query for the history information to create the menu.
  void CreateMenu();

  // Callback method for when HistoryService query results are ready with the
  // most recently-visited sites.
  void OnVisitedHistoryResults(CancelableRequestProvider::Handle handle,
                               std::vector<PageUsageData*>* results);

  // Tries to add the current Tab's TabNavigationEntry's NavigationEntry object
  // to |closed_results_|. Return TRUE if the operation completed successfully.
  bool AddNavigationForTab(const TabRestoreService::Tab& entry);

  // Helper function that sends an async request to the FaviconService to get
  // an icon. The callback will update the NSMenuItem directly.
  void GetFaviconForHistoryItem(HistoryItem* item);

  // Callback for the FaviconService to return favicon image data when we
  // request it. This decodes the raw data, updates the HistoryItem, and then
  // sets the image on the menu. Called on the same same thread that
  // GetFaviconForHistoryItem() was called on (UI thread).
  void GotFaviconData(FaviconService::Handle handle,
                      bool know_favicon,
                      scoped_refptr<RefCountedMemory> data,
                      bool expired,
                      GURL url);

  // Cancels a favicon load request for a given HistoryItem, if one is in
  // progress.
  void CancelFaviconRequest(HistoryItem* item);

 private:
  friend class HistoryMenuBridgeTest;

  scoped_nsobject<HistoryMenuCocoaController> controller_;  // strong

  Profile* profile_; // weak
  HistoryService* history_service_; // weak
  TabRestoreService* tab_restore_service_; // weak

  NotificationRegistrar registrar_;
  CancelableRequestConsumer cancelable_request_consumer_;

  // The most recent results we've received.
  ScopedVector<HistoryItem> visited_results_;
  ScopedVector<HistoryItem> closed_results_;

  // Maps HistoryItems to favicon request Handles.
  CancelableRequestConsumerTSimple<HistoryItem*> favicon_consumer_;

  // We coalesce requests to re-create the menu. |create_in_progress_| is true
  // whenever we are either waiting for the history service to return query
  // results, or when we are rebuilding. |need_recreate_| is true whenever a
  // rebuild has been scheduled but is waiting for the current one to finish.
  bool create_in_progress_;
  bool need_recreate_;

  // The default favicon if a HistoryItem does not have one.
  scoped_nsobject<NSImage> default_favicon_;

  DISALLOW_COPY_AND_ASSIGN(HistoryMenuBridge);
};

#endif  // CHROME_BROWSER_COCOA_HISTORY_MENU_BRIDGE_H_