Home | History | Annotate | Download | only in toolbar
      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