1 // Copyright (c) 2012 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_TOOLBAR_BACK_FORWARD_MENU_MODEL_H_
6 #define CHROME_BROWSER_UI_TOOLBAR_BACK_FORWARD_MENU_MODEL_H_
11 #include "base/basictypes.h"
12 #include "base/gtest_prod_util.h"
13 #include "base/strings/string16.h"
14 #include "base/task/cancelable_task_tracker.h"
15 #include "chrome/browser/favicon/favicon_service.h"
16 #include "ui/base/models/menu_model.h"
17 #include "ui/base/window_open_disposition.h"
21 namespace favicon_base
{
22 struct FaviconImageResult
;
26 class NavigationEntry
;
34 ///////////////////////////////////////////////////////////////////////////////
36 // BackForwardMenuModel
38 // Interface for the showing of the dropdown menu for the Back/Forward buttons.
39 // Actual implementations are platform-specific.
40 ///////////////////////////////////////////////////////////////////////////////
41 class BackForwardMenuModel
: public ui::MenuModel
{
43 // These are IDs used to identify individual UI elements within the
44 // browser window using View::GetViewByID.
50 BackForwardMenuModel(Browser
* browser
, ModelType model_type
);
51 virtual ~BackForwardMenuModel();
53 // MenuModel implementation.
54 virtual bool HasIcons() const OVERRIDE
;
55 // Returns how many items the menu should show, including history items,
56 // chapter-stops, separators and the Show Full History link. This function
57 // uses GetHistoryItemCount() and GetChapterStopCount() internally to figure
58 // out the total number of items to show.
59 virtual int GetItemCount() const OVERRIDE
;
60 virtual ItemType
GetTypeAt(int index
) const OVERRIDE
;
61 virtual ui::MenuSeparatorType
GetSeparatorTypeAt(int index
) const OVERRIDE
;
62 virtual int GetCommandIdAt(int index
) const OVERRIDE
;
63 virtual base::string16
GetLabelAt(int index
) const OVERRIDE
;
64 virtual bool IsItemDynamicAt(int index
) const OVERRIDE
;
65 virtual bool GetAcceleratorAt(int index
,
66 ui::Accelerator
* accelerator
) const OVERRIDE
;
67 virtual bool IsItemCheckedAt(int index
) const OVERRIDE
;
68 virtual int GetGroupIdAt(int index
) const OVERRIDE
;
69 virtual bool GetIconAt(int index
, gfx::Image
* icon
) OVERRIDE
;
70 virtual ui::ButtonMenuItemModel
* GetButtonMenuItemAt(
71 int index
) const OVERRIDE
;
72 virtual bool IsEnabledAt(int index
) const OVERRIDE
;
73 virtual MenuModel
* GetSubmenuModelAt(int index
) const OVERRIDE
;
74 virtual void HighlightChangedTo(int index
) OVERRIDE
;
75 virtual void ActivatedAt(int index
) OVERRIDE
;
76 virtual void ActivatedAt(int index
, int event_flags
) OVERRIDE
;
77 virtual void MenuWillShow() OVERRIDE
;
79 // Is the item at |index| a separator?
80 bool IsSeparator(int index
) const;
82 // Set the delegate for triggering OnIconChanged.
83 virtual void SetMenuModelDelegate(
84 ui::MenuModelDelegate
* menu_model_delegate
) OVERRIDE
;
85 virtual ui::MenuModelDelegate
* GetMenuModelDelegate() const OVERRIDE
;
88 ui::MenuModelDelegate
* menu_model_delegate() { return menu_model_delegate_
; }
91 friend class BackFwdMenuModelTest
;
92 FRIEND_TEST_ALL_PREFIXES(BackFwdMenuModelTest
, BasicCase
);
93 FRIEND_TEST_ALL_PREFIXES(BackFwdMenuModelTest
, MaxItemsTest
);
94 FRIEND_TEST_ALL_PREFIXES(BackFwdMenuModelTest
, ChapterStops
);
95 FRIEND_TEST_ALL_PREFIXES(BackFwdMenuModelTest
, EscapeLabel
);
96 FRIEND_TEST_ALL_PREFIXES(BackFwdMenuModelTest
, FaviconLoadTest
);
98 // Requests a favicon from the FaviconService. Called by GetIconAt if the
99 // NavigationEntry has an invalid favicon.
100 void FetchFavicon(content::NavigationEntry
* entry
);
102 // Callback from the favicon service.
103 void OnFavIconDataAvailable(
104 int navigation_entry_unique_id
,
105 const favicon_base::FaviconImageResult
& image_result
);
107 // Allows the unit test to use its own dummy tab contents.
108 void set_test_web_contents(content::WebContents
* test_web_contents
) {
109 test_web_contents_
= test_web_contents
;
112 // Returns how many history items the menu should show. For example, if the
113 // navigation controller of the current tab has a current entry index of 5 and
114 // forward_direction_ is false (we are the back button delegate) then this
115 // function will return 5 (representing 0-4). If forward_direction_ is
116 // true (we are the forward button delegate), then this function will return
117 // the number of entries after 5. Note, though, that in either case it will
118 // not report more than kMaxHistoryItems. The number returned also does not
119 // include the separator line after the history items (nor the separator for
120 // the "Show Full History" link).
121 int GetHistoryItemCount() const;
123 // Returns how many chapter-stop items the menu should show. For the
124 // definition of a chapter-stop, see GetIndexOfNextChapterStop(). The number
125 // returned does not include the separator lines before and after the
127 int GetChapterStopCount(int history_items
) const;
129 // Finds the next chapter-stop in the NavigationEntryList starting from
130 // the index specified in |start_from| and continuing in the direction
131 // specified (|forward|) until either a chapter-stop is found or we reach the
132 // end, in which case -1 is returned. If |start_from| is out of bounds, -1
133 // will also be returned. A chapter-stop is defined as the last page the user
134 // browsed to within the same domain. For example, if the user's homepage is
135 // Google and she navigates to Google pages G1, G2 and G3 before heading over
136 // to WikiPedia for pages W1 and W2 and then back to Google for pages G4 and
137 // G5 then G3, W2 and G5 are considered chapter-stops. The return value from
138 // this function is an index into the NavigationEntryList vector.
139 int GetIndexOfNextChapterStop(int start_from
, bool forward
) const;
141 // Finds a given chapter-stop starting at the currently active entry in the
142 // NavigationEntryList vector advancing first forward or backward by |offset|
143 // (depending on the direction specified in parameter |forward|). It also
144 // allows you to skip chapter-stops by specifying a positive value for |skip|.
145 // Example: FindChapterStop(5, false, 3) starts with the currently active
146 // index, subtracts 5 from it and then finds the fourth chapter-stop before
147 // that index (skipping the first 3 it finds).
148 // Example: FindChapterStop(0, true, 0) is functionally equivalent to
149 // calling GetIndexOfNextChapterStop(GetCurrentEntryIndex(), true).
151 // NOTE: Both |offset| and |skip| must be non-negative. The return value from
152 // this function is an index into the NavigationEntryList vector. If |offset|
153 // is out of bounds or if we skip too far (run out of chapter-stops) this
154 // function returns -1.
155 int FindChapterStop(int offset
, bool forward
, int skip
) const;
157 // How many items (max) to show in the back/forward history menu dropdown.
158 static const int kMaxHistoryItems
;
160 // How many chapter-stops (max) to show in the back/forward dropdown list.
161 static const int kMaxChapterStops
;
163 // Takes a menu item index as passed in through one of the menu delegate
164 // functions and converts it into an index into the NavigationEntryList
165 // vector. |index| can point to a separator, or the
166 // "Show Full History" link in which case this function returns -1.
167 int MenuIndexToNavEntryIndex(int index
) const;
169 // Does the item have a command associated with it?
170 bool ItemHasCommand(int index
) const;
172 // Returns true if there is an icon for this menu item.
173 bool ItemHasIcon(int index
) const;
175 // Allow the unit test to use the "Show Full History" label.
176 base::string16
GetShowFullHistoryLabel() const;
178 // Looks up a NavigationEntry by menu id.
179 content::NavigationEntry
* GetNavigationEntry(int index
) const;
181 // Retrieves the WebContents pointer to use, which is either the one that
182 // the unit test sets (using set_test_web_contents) or the one from
183 // the browser window.
184 content::WebContents
* GetWebContents() const;
186 // Build a string version of a user action on this menu, used as an
187 // identifier for logging user behavior.
188 // E.g. BuildActionName("Click", 2) returns "BackMenu_Click2".
189 // An index of -1 means no index.
190 std::string
BuildActionName(const std::string
& name
, int index
) const;
194 // The unit tests will provide their own WebContents to use.
195 content::WebContents
* test_web_contents_
;
197 // Represents whether this is the delegate for the forward button or the
199 ModelType model_type_
;
201 // Keeps track of which favicons have already been requested from the history
202 // to prevent duplicate requests, identified by
203 // NavigationEntry->GetUniqueID().
204 std::set
<int> requested_favicons_
;
206 // Used for loading favicons.
207 base::CancelableTaskTracker cancelable_task_tracker_
;
209 // Used for receiving notifications when an icon is changed.
210 ui::MenuModelDelegate
* menu_model_delegate_
;
212 DISALLOW_COPY_AND_ASSIGN(BackForwardMenuModel
);
215 #endif // CHROME_BROWSER_UI_TOOLBAR_BACK_FORWARD_MENU_MODEL_H_