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. 4 5 #ifndef CHROME_BROWSER_UI_TOOLBAR_BACK_FORWARD_MENU_MODEL_H_ 6 #define CHROME_BROWSER_UI_TOOLBAR_BACK_FORWARD_MENU_MODEL_H_ 7 8 #include <set> 9 #include <string> 10 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" 18 19 class Browser; 20 21 namespace favicon_base { 22 struct FaviconImageResult; 23 } 24 25 namespace content { 26 class NavigationEntry; 27 class WebContents; 28 } 29 30 namespace gfx { 31 class Image; 32 } 33 34 /////////////////////////////////////////////////////////////////////////////// 35 // 36 // BackForwardMenuModel 37 // 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 { 42 public: 43 // These are IDs used to identify individual UI elements within the 44 // browser window using View::GetViewByID. 45 enum ModelType { 46 FORWARD_MENU = 1, 47 BACKWARD_MENU = 2 48 }; 49 50 BackForwardMenuModel(Browser* browser, ModelType model_type); 51 virtual ~BackForwardMenuModel(); 52 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; 78 79 // Is the item at |index| a separator? 80 bool IsSeparator(int index) const; 81 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; 86 87 protected: 88 ui::MenuModelDelegate* menu_model_delegate() { return menu_model_delegate_; } 89 90 private: 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); 97 98 // Requests a favicon from the FaviconService. Called by GetIconAt if the 99 // NavigationEntry has an invalid favicon. 100 void FetchFavicon(content::NavigationEntry* entry); 101 102 // Callback from the favicon service. 103 void OnFavIconDataAvailable( 104 int navigation_entry_unique_id, 105 const favicon_base::FaviconImageResult& image_result); 106 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; 110 } 111 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; 122 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 126 // chapter-stops. 127 int GetChapterStopCount(int history_items) const; 128 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; 140 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). 150 // 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; 156 157 // How many items (max) to show in the back/forward history menu dropdown. 158 static const int kMaxHistoryItems; 159 160 // How many chapter-stops (max) to show in the back/forward dropdown list. 161 static const int kMaxChapterStops; 162 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; 168 169 // Does the item have a command associated with it? 170 bool ItemHasCommand(int index) const; 171 172 // Returns true if there is an icon for this menu item. 173 bool ItemHasIcon(int index) const; 174 175 // Allow the unit test to use the "Show Full History" label. 176 base::string16 GetShowFullHistoryLabel() const; 177 178 // Looks up a NavigationEntry by menu id. 179 content::NavigationEntry* GetNavigationEntry(int index) const; 180 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; 185 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; 191 192 Browser* browser_; 193 194 // The unit tests will provide their own WebContents to use. 195 content::WebContents* test_web_contents_; 196 197 // Represents whether this is the delegate for the forward button or the 198 // back button. 199 ModelType model_type_; 200 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_; 205 206 // Used for loading favicons. 207 base::CancelableTaskTracker cancelable_task_tracker_; 208 209 // Used for receiving notifications when an icon is changed. 210 ui::MenuModelDelegate* menu_model_delegate_; 211 212 DISALLOW_COPY_AND_ASSIGN(BackForwardMenuModel); 213 }; 214 215 #endif // CHROME_BROWSER_UI_TOOLBAR_BACK_FORWARD_MENU_MODEL_H_ 216