1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "build/build_config.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/toolbar/back_forward_menu_model.h"
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
93345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_number_conversions.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/metrics/user_metrics.h"
113f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "chrome/browser/prefs/pref_service.h"
123f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "chrome/browser/profiles/profile.h"
134a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/browser/ui/browser.h"
143f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "chrome/common/pref_names.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/url_constants.h"
16dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/navigation_controller.h"
17dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/navigation_entry.h"
18dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/tab_contents.h"
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/generated_resources.h"
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/theme_resources.h"
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/registry_controlled_domain.h"
2272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util.h"
2372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/resource/resource_bundle.h"
2472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/text/text_elider.h"
25ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "ui/gfx/codec/png_codec.h"
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int BackForwardMenuModel::kMaxHistoryItems = 12;
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int BackForwardMenuModel::kMaxChapterStops = 5;
29201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochstatic const int kMaxWidth = 700;
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBackForwardMenuModel::BackForwardMenuModel(Browser* browser,
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           ModelType model_type)
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : browser_(browser),
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      test_tab_contents_(NULL),
35ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      model_type_(model_type),
36ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      menu_model_delegate_(NULL) {
37ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
38ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
39ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenBackForwardMenuModel::~BackForwardMenuModel() {
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BackForwardMenuModel::HasIcons() const {
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BackForwardMenuModel::GetItemCount() const {
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int items = GetHistoryItemCount();
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (items > 0) {
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int chapter_stops = 0;
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Next, we count ChapterStops, if any.
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (items == kMaxHistoryItems)
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      chapter_stops = GetChapterStopCount(items);
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (chapter_stops)
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      items += chapter_stops + 1;  // Chapter stops also need a separator.
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If the menu is not empty, add two positions in the end
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // for a separator and a "Show Full History" item.
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    items += 2;
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return items;
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
6772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenui::MenuModel::ItemType BackForwardMenuModel::GetTypeAt(int index) const {
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return IsSeparator(index) ? TYPE_SEPARATOR : TYPE_COMMAND;
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BackForwardMenuModel::GetCommandIdAt(int index) const {
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return index;
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstring16 BackForwardMenuModel::GetLabelAt(int index) const {
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Return label "Show Full History" for the last item of the menu.
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (index == GetItemCount() - 1)
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return l10n_util::GetStringUTF16(IDS_SHOWFULLHISTORY_LINK);
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Return an empty string for a separator.
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (IsSeparator(index))
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return string16();
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
84201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // Return the entry title, escaping any '&' characters and eliding it if it's
85201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // super long.
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NavigationEntry* entry = GetNavigationEntry(index);
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  string16 menu_text(entry->GetTitleForDisplay(
883f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen      GetTabContents()->profile()->GetPrefs()->
893f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen          GetString(prefs::kAcceptLanguages)));
9072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  menu_text = ui::ElideText(menu_text, gfx::Font(), kMaxWidth, false);
91201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
92dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#if !defined(OS_MACOSX)
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = menu_text.find('&'); i != string16::npos;
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       i = menu_text.find('&', i + 2)) {
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    menu_text.insert(i, 1, '&');
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
97dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#endif
98dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return menu_text;
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
10221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool BackForwardMenuModel::IsItemDynamicAt(int index) const {
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This object is only used for a single showing of a menu.
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BackForwardMenuModel::GetAcceleratorAt(
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int index,
10972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    ui::Accelerator* accelerator) const {
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BackForwardMenuModel::IsItemCheckedAt(int index) const {
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BackForwardMenuModel::GetGroupIdAt(int index) const {
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
121ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool BackForwardMenuModel::GetIconAt(int index, SkBitmap* icon) {
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ItemHasIcon(index))
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (index == GetItemCount() - 1) {
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *icon = *ResourceBundle::GetSharedInstance().GetBitmapNamed(
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        IDR_HISTORY_FAVICON);
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NavigationEntry* entry = GetNavigationEntry(index);
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *icon = entry->favicon().bitmap();
131ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!entry->favicon().is_valid() && menu_model_delegate()) {
132ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      FetchFavicon(entry);
133ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
13972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenui::ButtonMenuItemModel* BackForwardMenuModel::GetButtonMenuItemAt(
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int index) const {
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return NULL;
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BackForwardMenuModel::IsEnabledAt(int index) const {
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return index < GetItemCount() && !IsSeparator(index);
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
14872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenui::MenuModel* BackForwardMenuModel::GetSubmenuModelAt(int index) const {
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return NULL;
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BackForwardMenuModel::HighlightChangedTo(int index) {
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BackForwardMenuModel::ActivatedAt(int index) {
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ActivatedAtWithDisposition(index, CURRENT_TAB);
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BackForwardMenuModel::ActivatedAtWithDisposition(
1604a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      int index, int disposition) {
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Profile* profile = browser_->profile();
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!IsSeparator(index));
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Execute the command for the last item: "Show Full History".
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (index == GetItemCount() - 1) {
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UserMetrics::RecordComputedAction(BuildActionName("ShowFullHistory", -1),
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      profile);
169dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    browser_->ShowSingletonTab(GURL(chrome::kChromeUIHistoryURL));
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Log whether it was a history or chapter click.
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (index < GetHistoryItemCount()) {
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UserMetrics::RecordComputedAction(
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        BuildActionName("HistoryClick", index), profile);
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UserMetrics::RecordComputedAction(
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        BuildActionName("ChapterClick", index - GetHistoryItemCount() - 1),
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        profile);
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int controller_index = MenuIndexToNavEntryIndex(index);
1844a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (!browser_->NavigateToIndexWithDisposition(
1854a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch          controller_index, static_cast<WindowOpenDisposition>(disposition))) {
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED();
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BackForwardMenuModel::MenuWillShow() {
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UserMetrics::RecordComputedAction(BuildActionName("Popup", -1),
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    browser_->profile());
193ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  requested_favicons_.clear();
194ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  load_consumer_.CancelAllRequests();
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BackForwardMenuModel::IsSeparator(int index) const {
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int history_items = GetHistoryItemCount();
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If the index is past the number of history items + separator,
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // we then consider if it is a chapter-stop entry.
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (index > history_items) {
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We either are in ChapterStop area, or at the end of the list (the "Show
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Full History" link).
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int chapter_stops = GetChapterStopCount(history_items);
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (chapter_stops == 0)
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;  // We must have reached the "Show Full History" link.
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Otherwise, look to see if we have reached the separator for the
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // chapter-stops. If not, this is a chapter stop.
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return (index == history_items + 1 + chapter_stops);
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Look to see if we have reached the separator for the history items.
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return index == history_items;
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
216ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BackForwardMenuModel::SetMenuModelDelegate(
217ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      ui::MenuModelDelegate* menu_model_delegate) {
218ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  menu_model_delegate_ = menu_model_delegate;
219ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
220ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
221ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BackForwardMenuModel::FetchFavicon(NavigationEntry* entry) {
222ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // If the favicon has already been requested for this menu, don't do
223ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // anything.
224ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (requested_favicons_.find(entry->unique_id()) !=
225ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      requested_favicons_.end()) {
226ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
227ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
228ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  requested_favicons_.insert(entry->unique_id());
229ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  FaviconService* favicon_service =
230ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      browser_->profile()->GetFaviconService(Profile::EXPLICIT_ACCESS);
231ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!favicon_service)
232ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
233ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  FaviconService::Handle handle = favicon_service->GetFaviconForURL(
234ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      entry->url(), history::FAVICON, &load_consumer_,
235ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      NewCallback(this, &BackForwardMenuModel::OnFavIconDataAvailable));
236ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  load_consumer_.SetClientData(favicon_service, handle, entry->unique_id());
237ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
238ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
239ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BackForwardMenuModel::OnFavIconDataAvailable(
240ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    FaviconService::Handle handle,
241ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    history::FaviconData favicon) {
242ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (favicon.is_valid()) {
243ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int unique_id = load_consumer_.GetClientDataForCurrentRequest();
244ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Find the current model_index for the unique_id.
245ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    NavigationEntry* entry = NULL;
246ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int model_index = -1;
247ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    for (int i = 0; i < GetItemCount() - 1; i++) {
248ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (IsSeparator(i))
249ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        continue;
250ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (GetNavigationEntry(i)->unique_id() == unique_id) {
251ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        model_index = i;
252ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        entry = GetNavigationEntry(i);
253ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        break;
254ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
255ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
256ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
257ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!entry)
258ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // The NavigationEntry wasn't found, this can happen if the user
259ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // navigates to another page and a NavigatationEntry falls out of the
260ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // range of kMaxHistoryItems.
261ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return;
262ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
263ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Now that we have a valid NavigationEntry, decode the favicon and assign
264ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // it to the NavigationEntry.
265ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    SkBitmap fav_icon;
266ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (gfx::PNGCodec::Decode(favicon.image_data->front(),
267ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                              favicon.image_data->size(),
268ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                              &fav_icon)) {
269ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      entry->favicon().set_is_valid(true);
270ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      entry->favicon().set_url(favicon.icon_url);
271ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (fav_icon.empty())
272ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        return;
273ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      entry->favicon().set_bitmap(fav_icon);
274ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (menu_model_delegate()) {
275ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        menu_model_delegate()->OnIconChanged(model_index);
276ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
277ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
278ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
279ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
280ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BackForwardMenuModel::GetHistoryItemCount() const {
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabContents* contents = GetTabContents();
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int items = 0;
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (model_type_ == FORWARD_MENU) {
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Only count items from n+1 to end (if n is current entry)
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    items = contents->controller().entry_count() -
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            contents->controller().GetCurrentEntryIndex() - 1;
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    items = contents->controller().GetCurrentEntryIndex();
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (items > kMaxHistoryItems)
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    items = kMaxHistoryItems;
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  else if (items < 0)
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    items = 0;
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return items;
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BackForwardMenuModel::GetChapterStopCount(int history_items) const {
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabContents* contents = GetTabContents();
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int chapter_stops = 0;
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int current_entry = contents->controller().GetCurrentEntryIndex();
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (history_items == kMaxHistoryItems) {
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int chapter_id = current_entry;
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (model_type_ == FORWARD_MENU) {
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      chapter_id += history_items;
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      chapter_id -= history_items;
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    do {
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      chapter_id = GetIndexOfNextChapterStop(chapter_id,
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          model_type_ == FORWARD_MENU);
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (chapter_id != -1)
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        ++chapter_stops;
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } while (chapter_id != -1 && chapter_stops < kMaxChapterStops);
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return chapter_stops;
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BackForwardMenuModel::GetIndexOfNextChapterStop(int start_from,
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                    bool forward) const {
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabContents* contents = GetTabContents();
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NavigationController& controller = contents->controller();
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int max_count = controller.entry_count();
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (start_from < 0 || start_from >= max_count)
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return -1;  // Out of bounds.
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (forward) {
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (start_from < max_count - 1) {
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // We want to advance over the current chapter stop, so we add one.
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // We don't need to do this when direction is backwards.
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      start_from++;
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return -1;
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NavigationEntry* start_entry = controller.GetEntryAtIndex(start_from);
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const GURL& url = start_entry->url();
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!forward) {
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // When going backwards we return the first entry we find that has a
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // different domain.
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (int i = start_from - 1; i >= 0; --i) {
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!net::RegistryControlledDomainService::SameDomainOrHost(url,
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              controller.GetEntryAtIndex(i)->url()))
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return i;
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We have reached the beginning without finding a chapter stop.
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return -1;
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // When going forwards we return the entry before the entry that has a
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // different domain.
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (int i = start_from + 1; i < max_count; ++i) {
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!net::RegistryControlledDomainService::SameDomainOrHost(url,
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              controller.GetEntryAtIndex(i)->url()))
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return i - 1;
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Last entry is always considered a chapter stop.
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return max_count - 1;
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BackForwardMenuModel::FindChapterStop(int offset,
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          bool forward,
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          int skip) const {
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (offset < 0 || skip < 0)
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return -1;
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!forward)
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    offset *= -1;
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabContents* contents = GetTabContents();
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int entry = contents->controller().GetCurrentEntryIndex() + offset;
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = 0; i < skip + 1; i++)
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    entry = GetIndexOfNextChapterStop(entry, forward);
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return entry;
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BackForwardMenuModel::ItemHasCommand(int index) const {
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return index < GetItemCount() && !IsSeparator(index);
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BackForwardMenuModel::ItemHasIcon(int index) const {
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return index < GetItemCount() && !IsSeparator(index);
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstring16 BackForwardMenuModel::GetShowFullHistoryLabel() const {
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return l10n_util::GetStringUTF16(IDS_SHOWFULLHISTORY_LINK);
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabContents* BackForwardMenuModel::GetTabContents() const {
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We use the test tab contents if the unit test has specified it.
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return test_tab_contents_ ? test_tab_contents_ :
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                              browser_->GetSelectedTabContents();
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BackForwardMenuModel::MenuIndexToNavEntryIndex(int index) const {
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabContents* contents = GetTabContents();
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int history_items = GetHistoryItemCount();
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_GE(index, 0);
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Convert anything above the History items separator.
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (index < history_items) {
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (model_type_ == FORWARD_MENU) {
415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      index += contents->controller().GetCurrentEntryIndex() + 1;
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Back menu is reverse.
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      index = contents->controller().GetCurrentEntryIndex() - (index + 1);
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return index;
421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (index == history_items)
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return -1;  // Don't translate the separator for history items.
424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (index >= history_items + 1 + GetChapterStopCount(history_items))
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return -1;  // This is beyond the last chapter stop so we abort.
427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This menu item is a chapter stop located between the two separators.
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  index = FindChapterStop(history_items,
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          model_type_ == FORWARD_MENU,
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          index - history_items - 1);
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return index;
434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochNavigationEntry* BackForwardMenuModel::GetNavigationEntry(int index) const {
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int controller_index = MenuIndexToNavEntryIndex(index);
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NavigationController& controller = GetTabContents()->controller();
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (controller_index >= 0 && controller_index < controller.entry_count())
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return controller.GetEntryAtIndex(controller_index);
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NOTREACHED();
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return NULL;
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::string BackForwardMenuModel::BuildActionName(
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& action, int index) const {
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!action.empty());
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(index >= -1);
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string metric_string;
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (model_type_ == FORWARD_MENU)
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    metric_string += "ForwardMenu_";
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  else
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    metric_string += "BackMenu_";
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  metric_string += action;
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (index != -1) {
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // +1 is for historical reasons (indices used to start at 1).
4583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    metric_string += base::IntToString(index + 1);
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return metric_string;
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
462