| OLD | NEW |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h" | 5 #include "chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/metrics/histogram.h" | 8 #include "base/metrics/histogram.h" |
| 9 #include "base/strings/string_number_conversions.h" | 9 #include "base/strings/string_number_conversions.h" |
| 10 #include "base/strings/utf_string_conversions.h" | 10 #include "base/strings/utf_string_conversions.h" |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 #include "ui/base/l10n/l10n_util.h" | 34 #include "ui/base/l10n/l10n_util.h" |
| 35 #include "ui/base/resource/resource_bundle.h" | 35 #include "ui/base/resource/resource_bundle.h" |
| 36 #include "ui/gfx/favicon_size.h" | 36 #include "ui/gfx/favicon_size.h" |
| 37 | 37 |
| 38 #if defined(USE_ASH) | 38 #if defined(USE_ASH) |
| 39 #include "ash/accelerators/accelerator_table.h" | 39 #include "ash/accelerators/accelerator_table.h" |
| 40 #endif // defined(USE_ASH) | 40 #endif // defined(USE_ASH) |
| 41 | 41 |
| 42 namespace { | 42 namespace { |
| 43 | 43 |
| 44 // First comamnd id for navigatable (and hence executable) tab menu item. | 44 // First comamnd id for navigatable (and hence executable) tab/window menu item. |
| 45 // The models and menu are not 1-1: | 45 // The models and menu are not 1-1: |
| 46 // - menu has "Reopen closed tab", "No tabs from other devices", device section | 46 // - menu has "Recently closed" header, "No tabs from other devices", device |
| 47 // headers, separators and executable tab items. | 47 // section headers, separators, executable local and foreign tab items, and |
| 48 // - |tab_navigation_items_| only has navigatabale/executable tab items. | 48 // executable local window items. |
| 49 // - |window_items_| only has executable open window items. | 49 // - |local_tab_navigation_items_| and |foreign_tab_navigation_items_| only have |
| 50 // Using an initial command ids for tab/window items makes it easier and less | 50 // navigatabale/executable tab items. |
| 51 // error-prone to manipulate the models and menu. | 51 // - |local_window_items_| only has executable open window items. |
| 52 // These values must be bigger than the maximum possible number of items in | 52 // Using initial command ids for local tab, local window and foreign tab items |
| 53 // menu, so that index of last menu item doesn't clash with this value when menu | 53 // makes it easier and less error-prone to manipulate the models, data vectors |
| 54 // items are retrieved via GetIndexOfCommandId. | 54 // and menu. These ids must be bigger than the maximum possible number of |
| 55 const int kFirstTabCommandId = 100; | 55 // items in menu, so that index of the last menu item doesn't clash with these |
| 56 const int kFirstWindowCommandId = 200; | 56 // values when menu items are retrieved via GetIndexOfCommandId. |
| 57 const int kFirstLocalTabCommandId = 100; |
| 58 const int kFirstLocalWindowCommandId = 200; |
| 59 const int kFirstForeignTabCommandId = 300; |
| 57 | 60 |
| 58 // The maximum number of recently closed entries to be shown in the menu. | 61 // The maximum number of local recently closed entries (tab or window) to be |
| 59 const int kMaxRecentlyClosedEntries = 8; | 62 // shown in the menu. |
| 63 const int kMaxLocalEntries = 8; |
| 60 | 64 |
| 61 // Comparator function for use with std::sort that will sort sessions by | 65 // Comparator function for use with std::sort that will sort sessions by |
| 62 // descending modified_time (i.e., most recent first). | 66 // descending modified_time (i.e., most recent first). |
| 63 bool SortSessionsByRecency(const browser_sync::SyncedSession* s1, | 67 bool SortSessionsByRecency(const browser_sync::SyncedSession* s1, |
| 64 const browser_sync::SyncedSession* s2) { | 68 const browser_sync::SyncedSession* s2) { |
| 65 return s1->modified_time > s2->modified_time; | 69 return s1->modified_time > s2->modified_time; |
| 66 } | 70 } |
| 67 | 71 |
| 68 // Comparator function for use with std::sort that will sort tabs by | 72 // Comparator function for use with std::sort that will sort tabs by |
| 69 // descending timestamp (i.e., most recent first). | 73 // descending timestamp (i.e., most recent first). |
| 70 bool SortTabsByRecency(const SessionTab* t1, const SessionTab* t2) { | 74 bool SortTabsByRecency(const SessionTab* t1, const SessionTab* t2) { |
| 71 return t1->timestamp > t2->timestamp; | 75 return t1->timestamp > t2->timestamp; |
| 72 } | 76 } |
| 73 | 77 |
| 74 // Returns true if the command id is related to a tab model index. | 78 // Returns true if the command id identifies a tab model index. |
| 75 bool IsTabModelCommandId(int command_id) { | 79 bool IsTabModelCommandId(int command_id) { |
| 76 return command_id >= kFirstTabCommandId && command_id < kFirstWindowCommandId; | 80 return command_id >= kFirstForeignTabCommandId || |
| 81 (command_id >= kFirstLocalTabCommandId && |
| 82 command_id < kFirstLocalWindowCommandId); |
| 77 } | 83 } |
| 78 | 84 |
| 79 // Returns true if the command id is related to a window model index. | 85 // Returns true if the command id identifies a window model index. |
| 80 bool IsWindowModelCommandId(int command_id) { | 86 bool IsWindowModelCommandId(int command_id) { |
| 81 return command_id >= kFirstWindowCommandId && | 87 return command_id >= kFirstLocalWindowCommandId && |
| 82 command_id < RecentTabsSubMenuModel::kRecentlyClosedHeaderCommandId; | 88 command_id < RecentTabsSubMenuModel::kRecentlyClosedHeaderCommandId; |
| 83 } | 89 } |
| 84 | 90 |
| 85 // Convert |tab_model_index| to command id of menu item. | 91 // Convert |tab_model_index| to command id of menu item, with |first_command_id| |
| 86 int TabModelIndexToCommandId(int tab_model_index) { | 92 // as the base command id. |
| 87 int command_id = tab_model_index + kFirstTabCommandId; | 93 int TabModelIndexToCommandId(int tab_model_index, int first_command_id) { |
| 88 DCHECK_LT(command_id, kFirstWindowCommandId); | 94 int command_id = tab_model_index + first_command_id; |
| 95 DCHECK(first_command_id == kFirstForeignTabCommandId || |
| 96 command_id < kFirstLocalWindowCommandId); |
| 89 return command_id; | 97 return command_id; |
| 90 } | 98 } |
| 91 | 99 |
| 92 // Convert |command_id| of menu item to index in tab model. | |
| 93 int CommandIdToTabModelIndex(int command_id) { | |
| 94 DCHECK_GE(command_id, kFirstTabCommandId); | |
| 95 DCHECK_LT(command_id, kFirstWindowCommandId); | |
| 96 return command_id - kFirstTabCommandId; | |
| 97 } | |
| 98 | |
| 99 // Convert |window_model_index| to command id of menu item. | 100 // Convert |window_model_index| to command id of menu item. |
| 100 int WindowModelIndexToCommandId(int window_model_index) { | 101 int WindowModelIndexToCommandId(int window_model_index) { |
| 101 int command_id = window_model_index + kFirstWindowCommandId; | 102 int command_id = window_model_index + kFirstLocalWindowCommandId; |
| 103 DCHECK_LT(command_id, kFirstForeignTabCommandId); |
| 102 DCHECK_LT(command_id, RecentTabsSubMenuModel::kRecentlyClosedHeaderCommandId); | 104 DCHECK_LT(command_id, RecentTabsSubMenuModel::kRecentlyClosedHeaderCommandId); |
| 103 return command_id; | 105 return command_id; |
| 104 } | 106 } |
| 105 | 107 |
| 106 // Convert |command_id| of menu item to index in window model. | 108 // Convert |command_id| of menu item to index in window model. |
| 107 int CommandIdToWindowModelIndex(int command_id) { | 109 int CommandIdToWindowModelIndex(int command_id) { |
| 108 DCHECK_GE(command_id, kFirstWindowCommandId); | 110 DCHECK_GE(command_id, kFirstLocalWindowCommandId); |
| 111 DCHECK_LT(command_id, kFirstForeignTabCommandId); |
| 109 DCHECK_LT(command_id, RecentTabsSubMenuModel::kRecentlyClosedHeaderCommandId); | 112 DCHECK_LT(command_id, RecentTabsSubMenuModel::kRecentlyClosedHeaderCommandId); |
| 110 return command_id - kFirstWindowCommandId; | 113 return command_id - kFirstLocalWindowCommandId; |
| 111 } | 114 } |
| 112 | 115 |
| 113 } // namespace | 116 } // namespace |
| 114 | 117 |
| 115 enum RecentTabAction { | 118 enum RecentTabAction { |
| 116 LOCAL_SESSION_TAB = 0, | 119 LOCAL_SESSION_TAB = 0, |
| 117 OTHER_DEVICE_TAB, | 120 OTHER_DEVICE_TAB, |
| 118 RESTORE_WINDOW, | 121 RESTORE_WINDOW, |
| 119 SHOW_MORE, | 122 SHOW_MORE, |
| 120 LIMIT_RECENT_TAB_ACTION | 123 LIMIT_RECENT_TAB_ACTION |
| 121 }; | 124 }; |
| 122 | 125 |
| 123 // An element in |RecentTabsSubMenuModel::tab_navigation_items_| that stores | 126 // An element in |RecentTabsSubMenuModel::local_tab_navigation_items_| or |
| 127 // |RecentTabsSubMenuModel::foreign_tab_navigation_items_| that stores |
| 124 // the navigation information of a local or foreign tab required to restore the | 128 // the navigation information of a local or foreign tab required to restore the |
| 125 // tab. | 129 // tab. |
| 126 struct RecentTabsSubMenuModel::TabNavigationItem { | 130 struct RecentTabsSubMenuModel::TabNavigationItem { |
| 127 TabNavigationItem() : tab_id(-1) {} | 131 TabNavigationItem() : tab_id(-1) {} |
| 128 | 132 |
| 129 TabNavigationItem(const std::string& session_tag, | 133 TabNavigationItem(const std::string& session_tag, |
| 130 const SessionID::id_type& tab_id, | 134 const SessionID::id_type& tab_id, |
| 131 const string16& title, | 135 const string16& title, |
| 132 const GURL& url) | 136 const GURL& url) |
| 133 : session_tag(session_tag), | 137 : session_tag(session_tag), |
| (...skipping 16 matching lines...) Expand all Loading... |
| 150 const int RecentTabsSubMenuModel::kDisabledRecentlyClosedHeaderCommandId = 501; | 154 const int RecentTabsSubMenuModel::kDisabledRecentlyClosedHeaderCommandId = 501; |
| 151 const int RecentTabsSubMenuModel::kDeviceNameCommandId = 1000; | 155 const int RecentTabsSubMenuModel::kDeviceNameCommandId = 1000; |
| 152 | 156 |
| 153 RecentTabsSubMenuModel::RecentTabsSubMenuModel( | 157 RecentTabsSubMenuModel::RecentTabsSubMenuModel( |
| 154 ui::AcceleratorProvider* accelerator_provider, | 158 ui::AcceleratorProvider* accelerator_provider, |
| 155 Browser* browser, | 159 Browser* browser, |
| 156 browser_sync::SessionModelAssociator* associator) | 160 browser_sync::SessionModelAssociator* associator) |
| 157 : ui::SimpleMenuModel(this), | 161 : ui::SimpleMenuModel(this), |
| 158 browser_(browser), | 162 browser_(browser), |
| 159 associator_(associator), | 163 associator_(associator), |
| 164 last_local_model_index_(-1), |
| 160 default_favicon_(ResourceBundle::GetSharedInstance(). | 165 default_favicon_(ResourceBundle::GetSharedInstance(). |
| 161 GetNativeImageNamed(IDR_DEFAULT_FAVICON)), | 166 GetNativeImageNamed(IDR_DEFAULT_FAVICON)), |
| 162 weak_ptr_factory_(this) { | 167 weak_ptr_factory_(this) { |
| 168 // Invoke asynchronous call to load tabs from local last session, which does |
| 169 // nothing if the tabs have already been loaded or they shouldn't be loaded. |
| 170 // TabRestoreServiceChanged() will be called after the tabs are loaded. |
| 171 TabRestoreService* service = |
| 172 TabRestoreServiceFactory::GetForProfile(browser_->profile()); |
| 173 if (service) { |
| 174 service->LoadTabsFromLastSession(); |
| 175 |
| 176 // TODO(sail): enable this when mac implements the dynamic menu, together with |
| 177 // MenuModelDelegate::PrepareChange, OnItemRemoved, OnItemAdded and ChangesDone. |
| 178 #if !defined(OS_MACOSX) |
| 179 service->AddObserver(this); |
| 180 #endif |
| 181 } |
| 182 |
| 183 // Build the menu. |
| 163 Build(); | 184 Build(); |
| 164 | 185 |
| 165 // Retrieve accelerator key for IDC_RESTORE_TAB now, because on ASH, it's not | 186 // Retrieve accelerator key for IDC_RESTORE_TAB now, because on ASH, it's not |
| 166 // defined in |accelerator_provider|, but in shell, so simply retrieve it now | 187 // defined in |accelerator_provider|, but in shell, so simply retrieve it now |
| 167 // for all ASH and non-ASH for use in |GetAcceleratorForCommandId|. | 188 // for all ASH and non-ASH for use in |GetAcceleratorForCommandId|. |
| 168 #if defined(USE_ASH) | 189 #if defined(USE_ASH) |
| 169 for (size_t i = 0; i < ash::kAcceleratorDataLength; ++i) { | 190 for (size_t i = 0; i < ash::kAcceleratorDataLength; ++i) { |
| 170 const ash::AcceleratorData& accel_data = ash::kAcceleratorData[i]; | 191 const ash::AcceleratorData& accel_data = ash::kAcceleratorData[i]; |
| 171 if (accel_data.action == ash::RESTORE_TAB) { | 192 if (accel_data.action == ash::RESTORE_TAB) { |
| 172 reopen_closed_tab_accelerator_ = ui::Accelerator(accel_data.keycode, | 193 reopen_closed_tab_accelerator_ = ui::Accelerator(accel_data.keycode, |
| 173 accel_data.modifiers); | 194 accel_data.modifiers); |
| 174 break; | 195 break; |
| 175 } | 196 } |
| 176 } | 197 } |
| 177 #else | 198 #else |
| 178 if (accelerator_provider) { | 199 if (accelerator_provider) { |
| 179 accelerator_provider->GetAcceleratorForCommandId( | 200 accelerator_provider->GetAcceleratorForCommandId( |
| 180 IDC_RESTORE_TAB, &reopen_closed_tab_accelerator_); | 201 IDC_RESTORE_TAB, &reopen_closed_tab_accelerator_); |
| 181 } | 202 } |
| 182 #endif // defined(USE_ASH) | 203 #endif // defined(USE_ASH) |
| 183 } | 204 } |
| 184 | 205 |
| 185 RecentTabsSubMenuModel::~RecentTabsSubMenuModel() { | 206 RecentTabsSubMenuModel::~RecentTabsSubMenuModel() { |
| 207 TabRestoreService* service = |
| 208 TabRestoreServiceFactory::GetForProfile(browser_->profile()); |
| 209 if (service) |
| 210 service->RemoveObserver(this); |
| 211 } |
| 212 |
| 213 int RecentTabsSubMenuModel::ModelIndexToIdInParentMenu(int model_index) const { |
| 214 // If |model_index| identifies a local tab/window menu item, return as is; |
| 215 // otherwise, reserve enough id's for maximum possible local entries. |
| 216 if (model_index <= last_local_model_index_) |
| 217 return model_index; |
| 218 return model_index + kMaxLocalEntries - last_local_model_index_; |
| 219 } |
| 220 |
| 221 int RecentTabsSubMenuModel::IdInParentMenuToModelIndex( |
| 222 int id_in_parent_menu) const { |
| 223 // If |id_in_parent_menu| identifies a local tab/window menu item, return as |
| 224 // is; otherwise, ModelIndexToIdInParentMenu() would have reserved enough Id's |
| 225 // for maximum possible local entries, so reverse that logic. |
| 226 int index = id_in_parent_menu <= last_local_model_index_ ? id_in_parent_menu : |
| 227 id_in_parent_menu - kMaxLocalEntries + last_local_model_index_; |
| 228 DCHECK(index >= 0 && index < GetItemCount()); |
| 229 return index; |
| 186 } | 230 } |
| 187 | 231 |
| 188 bool RecentTabsSubMenuModel::IsCommandIdChecked(int command_id) const { | 232 bool RecentTabsSubMenuModel::IsCommandIdChecked(int command_id) const { |
| 189 return false; | 233 return false; |
| 190 } | 234 } |
| 191 | 235 |
| 192 bool RecentTabsSubMenuModel::IsCommandIdEnabled(int command_id) const { | 236 bool RecentTabsSubMenuModel::IsCommandIdEnabled(int command_id) const { |
| 193 if (command_id == kRecentlyClosedHeaderCommandId || | 237 if (command_id == kRecentlyClosedHeaderCommandId || |
| 194 command_id == kDisabledRecentlyClosedHeaderCommandId || | 238 command_id == kDisabledRecentlyClosedHeaderCommandId || |
| 195 command_id == kDeviceNameCommandId || | 239 command_id == kDeviceNameCommandId || |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 231 ui::DispositionFromEventFlags(event_flags); | 275 ui::DispositionFromEventFlags(event_flags); |
| 232 if (disposition == CURRENT_TAB) // Force to open a new foreground tab. | 276 if (disposition == CURRENT_TAB) // Force to open a new foreground tab. |
| 233 disposition = NEW_FOREGROUND_TAB; | 277 disposition = NEW_FOREGROUND_TAB; |
| 234 | 278 |
| 235 TabRestoreService* service = | 279 TabRestoreService* service = |
| 236 TabRestoreServiceFactory::GetForProfile(browser_->profile()); | 280 TabRestoreServiceFactory::GetForProfile(browser_->profile()); |
| 237 TabRestoreServiceDelegate* delegate = | 281 TabRestoreServiceDelegate* delegate = |
| 238 TabRestoreServiceDelegate::FindDelegateForWebContents( | 282 TabRestoreServiceDelegate::FindDelegateForWebContents( |
| 239 browser_->tab_strip_model()->GetActiveWebContents()); | 283 browser_->tab_strip_model()->GetActiveWebContents()); |
| 240 if (IsTabModelCommandId(command_id)) { | 284 if (IsTabModelCommandId(command_id)) { |
| 241 int model_idx = CommandIdToTabModelIndex(command_id); | 285 TabNavigationItems* tab_items = NULL; |
| 242 DCHECK(model_idx >= 0 && | 286 int model_idx = CommandIdToTabModelIndex(command_id, &tab_items); |
| 243 model_idx < static_cast<int>(tab_navigation_items_.size())); | 287 const TabNavigationItem& item = tab_items->at(model_idx); |
| 244 const TabNavigationItem& item = tab_navigation_items_[model_idx]; | |
| 245 DCHECK(item.tab_id > -1 && item.url.is_valid()); | 288 DCHECK(item.tab_id > -1 && item.url.is_valid()); |
| 246 | 289 |
| 247 if (item.session_tag.empty()) { // Restore tab of local session. | 290 if (item.session_tag.empty()) { // Restore tab of local session. |
| 248 if (service && delegate) { | 291 if (service && delegate) { |
| 249 UMA_HISTOGRAM_ENUMERATION("WrenchMenu.RecentTabsSubMenu", | 292 UMA_HISTOGRAM_ENUMERATION("WrenchMenu.RecentTabsSubMenu", |
| 250 LOCAL_SESSION_TAB, LIMIT_RECENT_TAB_ACTION); | 293 LOCAL_SESSION_TAB, LIMIT_RECENT_TAB_ACTION); |
| 251 service->RestoreEntryById(delegate, item.tab_id, | 294 service->RestoreEntryById(delegate, item.tab_id, |
| 252 browser_->host_desktop_type(), disposition); | 295 browser_->host_desktop_type(), disposition); |
| 253 } | 296 } |
| 254 } else { // Restore tab of foreign session. | 297 } else { // Restore tab of foreign session. |
| 255 browser_sync::SessionModelAssociator* associator = GetModelAssociator(); | 298 browser_sync::SessionModelAssociator* associator = GetModelAssociator(); |
| 256 if (!associator) | 299 if (!associator) |
| 257 return; | 300 return; |
| 258 const SessionTab* tab; | 301 const SessionTab* tab; |
| 259 if (!associator->GetForeignTab(item.session_tag, item.tab_id, &tab)) | 302 if (!associator->GetForeignTab(item.session_tag, item.tab_id, &tab)) |
| 260 return; | 303 return; |
| 261 if (tab->navigations.empty()) | 304 if (tab->navigations.empty()) |
| 262 return; | 305 return; |
| 263 UMA_HISTOGRAM_ENUMERATION("WrenchMenu.RecentTabsSubMenu", | 306 UMA_HISTOGRAM_ENUMERATION("WrenchMenu.RecentTabsSubMenu", |
| 264 OTHER_DEVICE_TAB, LIMIT_RECENT_TAB_ACTION); | 307 OTHER_DEVICE_TAB, LIMIT_RECENT_TAB_ACTION); |
| 265 SessionRestore::RestoreForeignSessionTab( | 308 SessionRestore::RestoreForeignSessionTab( |
| 266 browser_->tab_strip_model()->GetActiveWebContents(), | 309 browser_->tab_strip_model()->GetActiveWebContents(), |
| 267 *tab, disposition); | 310 *tab, disposition); |
| 268 } | 311 } |
| 269 } else { | 312 } else { |
| 270 DCHECK(IsWindowModelCommandId(command_id)); | 313 DCHECK(IsWindowModelCommandId(command_id)); |
| 271 if (service && delegate) { | 314 if (service && delegate) { |
| 272 int model_idx = CommandIdToWindowModelIndex(command_id); | 315 int model_idx = CommandIdToWindowModelIndex(command_id); |
| 273 DCHECK(model_idx >= 0 && | 316 DCHECK(model_idx >= 0 && |
| 274 model_idx < static_cast<int>(window_items_.size())); | 317 model_idx < static_cast<int>(local_window_items_.size())); |
| 275 UMA_HISTOGRAM_ENUMERATION("WrenchMenu.RecentTabsSubMenu", RESTORE_WINDOW, | 318 UMA_HISTOGRAM_ENUMERATION("WrenchMenu.RecentTabsSubMenu", RESTORE_WINDOW, |
| 276 LIMIT_RECENT_TAB_ACTION); | 319 LIMIT_RECENT_TAB_ACTION); |
| 277 service->RestoreEntryById(delegate, window_items_[model_idx], | 320 service->RestoreEntryById(delegate, local_window_items_[model_idx], |
| 278 browser_->host_desktop_type(), disposition); | 321 browser_->host_desktop_type(), disposition); |
| 279 } | 322 } |
| 280 } | 323 } |
| 281 } | 324 } |
| 282 | 325 |
| 283 const gfx::Font* RecentTabsSubMenuModel::GetLabelFontAt(int index) const { | 326 const gfx::Font* RecentTabsSubMenuModel::GetLabelFontAt(int index) const { |
| 284 int command_id = GetCommandIdAt(index); | 327 int command_id = GetCommandIdAt(index); |
| 285 if (command_id == kDeviceNameCommandId || | 328 if (command_id == kDeviceNameCommandId || |
| 286 command_id == kRecentlyClosedHeaderCommandId) { | 329 command_id == kRecentlyClosedHeaderCommandId) { |
| 287 return &ResourceBundle::GetSharedInstance().GetFont( | 330 return &ResourceBundle::GetSharedInstance().GetFont( |
| 288 ResourceBundle::BoldFont); | 331 ResourceBundle::BoldFont); |
| 289 } | 332 } |
| 290 return NULL; | 333 return NULL; |
| 291 } | 334 } |
| 292 | 335 |
| 293 int RecentTabsSubMenuModel::GetMaxWidthForItemAtIndex(int item_index) const { | 336 int RecentTabsSubMenuModel::GetMaxWidthForItemAtIndex(int item_index) const { |
| 294 int command_id = GetCommandIdAt(item_index); | 337 int command_id = GetCommandIdAt(item_index); |
| 295 if (command_id == IDC_RECENT_TABS_NO_DEVICE_TABS || | 338 if (command_id == IDC_RECENT_TABS_NO_DEVICE_TABS || |
| 296 command_id == kRecentlyClosedHeaderCommandId || | 339 command_id == kRecentlyClosedHeaderCommandId || |
| 297 command_id == kDisabledRecentlyClosedHeaderCommandId) { | 340 command_id == kDisabledRecentlyClosedHeaderCommandId) { |
| 298 return -1; | 341 return -1; |
| 299 } | 342 } |
| 300 return 320; | 343 return 320; |
| 301 } | 344 } |
| 302 | 345 |
| 303 bool RecentTabsSubMenuModel::GetURLAndTitleForItemAtIndex( | 346 bool RecentTabsSubMenuModel::GetURLAndTitleForItemAtIndex(int index, |
| 304 int index, | 347 std::string* url, |
| 305 std::string* url, | 348 string16* title) { |
| 306 string16* title) const { | |
| 307 int command_id = GetCommandIdAt(index); | 349 int command_id = GetCommandIdAt(index); |
| 308 if (IsTabModelCommandId(command_id)) { | 350 if (IsTabModelCommandId(command_id)) { |
| 309 int model_idx = CommandIdToTabModelIndex(command_id); | 351 TabNavigationItems* tab_items = NULL; |
| 310 DCHECK(model_idx >= 0 && | 352 int model_idx = CommandIdToTabModelIndex(command_id, &tab_items); |
| 311 model_idx < static_cast<int>(tab_navigation_items_.size())); | 353 *url = tab_items->at(model_idx).url.possibly_invalid_spec(); |
| 312 *url = tab_navigation_items_[model_idx].url.possibly_invalid_spec(); | 354 *title = tab_items->at(model_idx).title; |
| 313 *title = tab_navigation_items_[model_idx].title; | |
| 314 return true; | 355 return true; |
| 315 } | 356 } |
| 316 return false; | 357 return false; |
| 317 } | 358 } |
| 318 | 359 |
| 319 void RecentTabsSubMenuModel::Build() { | 360 void RecentTabsSubMenuModel::Build() { |
| 320 // The menu contains: | 361 // The menu contains: |
| 321 // - Recently closed tabs header, then list of tabs, then separator | 362 // - Recently closed header, then list of local recently closed tabs/windows, |
| 363 // then separator |
| 322 // - device 1 section header, then list of tabs from device, then separator | 364 // - device 1 section header, then list of tabs from device, then separator |
| 323 // - device 2 section header, then list of tabs from device, then separator | 365 // - device 2 section header, then list of tabs from device, then separator |
| 324 // - device 3 section header, then list of tabs from device, then separator | 366 // - device 3 section header, then list of tabs from device, then separator |
| 325 // - More... to open the history tab to get more other devices. | 367 // - More... to open the history tab to get more other devices. |
| 326 // |tab_navigation_items_| only contains navigatable (and hence executable) | 368 // |local_tab_navigation_items_| and |foreign_tab_navigation_items_| only |
| 327 // tab items for other devices, and |window_items_| contains the recently | 369 // contain navigatable (and hence executable) tab items for local recently |
| 328 // closed windows. | 370 // closed tabs and tabs of other devices respectively. |
| 329 BuildRecentTabs(); | 371 // |local_window_items_| contains the local recently closed windows. |
| 330 BuildDevices(); | 372 BuildLocalEntries(); |
| 373 BuildForeignTabs(); |
| 331 } | 374 } |
| 332 | 375 |
| 333 void RecentTabsSubMenuModel::BuildRecentTabs() { | 376 void RecentTabsSubMenuModel::BuildLocalEntries() { |
| 334 ListValue recently_closed_list; | 377 // All local items use InsertItem*At() to append or insert a menu item. |
| 378 // We're appending if building the entries for the first time i.e. invoked |
| 379 // from Constructor(), inserting when local entries change subsequently i.e. |
| 380 // invoked from TabRestoreServiceChanged(). |
| 381 |
| 382 int curr_model_index = 0; |
| 383 |
| 335 TabRestoreService* service = | 384 TabRestoreService* service = |
| 336 TabRestoreServiceFactory::GetForProfile(browser_->profile()); | 385 TabRestoreServiceFactory::GetForProfile(browser_->profile()); |
| 337 if (service) { | |
| 338 // This does nothing if the tabs have already been loaded or they | |
| 339 // shouldn't be loaded. | |
| 340 service->LoadTabsFromLastSession(); | |
| 341 } | |
| 342 | |
| 343 if (!service || service->entries().size() == 0) { | 386 if (!service || service->entries().size() == 0) { |
| 344 // This is to show a disabled restore tab entry with the accelerator to | 387 // This is to show a disabled restore tab entry with the accelerator to |
| 345 // teach users about this command. | 388 // teach users about this command. |
| 346 AddItemWithStringId(kDisabledRecentlyClosedHeaderCommandId, | 389 InsertItemWithStringIdAt(curr_model_index++, |
| 347 IDS_NEW_TAB_RECENTLY_CLOSED); | 390 kDisabledRecentlyClosedHeaderCommandId, |
| 348 return; | 391 IDS_NEW_TAB_RECENTLY_CLOSED); |
| 392 } else { |
| 393 InsertItemWithStringIdAt(curr_model_index, |
| 394 kRecentlyClosedHeaderCommandId, |
| 395 IDS_NEW_TAB_RECENTLY_CLOSED); |
| 396 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| 397 SetIcon(curr_model_index, |
| 398 rb.GetNativeImageNamed(IDR_RECENTLY_CLOSED_WINDOW)); |
| 399 ++curr_model_index; |
| 400 |
| 401 int added_count = 0; |
| 402 TabRestoreService::Entries entries = service->entries(); |
| 403 for (TabRestoreService::Entries::const_iterator it = entries.begin(); |
| 404 it != entries.end() && added_count < kMaxLocalEntries; ++it) { |
| 405 TabRestoreService::Entry* entry = *it; |
| 406 if (entry->type == TabRestoreService::TAB) { |
| 407 TabRestoreService::Tab* tab = |
| 408 static_cast<TabRestoreService::Tab*>(entry); |
| 409 const sessions::SerializedNavigationEntry& current_navigation = |
| 410 tab->navigations.at(tab->current_navigation_index); |
| 411 BuildLocalTabItem( |
| 412 entry->id, |
| 413 current_navigation.title(), |
| 414 current_navigation.virtual_url(), |
| 415 curr_model_index); |
| 416 } else { |
| 417 DCHECK_EQ(entry->type, TabRestoreService::WINDOW); |
| 418 BuildLocalWindowItem( |
| 419 entry->id, |
| 420 static_cast<TabRestoreService::Window*>(entry)->tabs.size(), |
| 421 curr_model_index); |
| 422 } |
| 423 ++added_count; |
| 424 ++curr_model_index; |
| 425 } |
| 349 } | 426 } |
| 350 | 427 |
| 351 AddItemWithStringId(kRecentlyClosedHeaderCommandId, | 428 DCHECK_GT(curr_model_index, 0); |
| 352 IDS_NEW_TAB_RECENTLY_CLOSED); | 429 last_local_model_index_ = curr_model_index - 1; |
| 353 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
| 354 SetIcon(GetItemCount() - 1, | |
| 355 rb.GetNativeImageNamed(IDR_RECENTLY_CLOSED_WINDOW)); | |
| 356 | |
| 357 int added_count = 0; | |
| 358 TabRestoreService::Entries entries = service->entries(); | |
| 359 for (TabRestoreService::Entries::const_iterator it = entries.begin(); | |
| 360 it != entries.end() && added_count < kMaxRecentlyClosedEntries; ++it) { | |
| 361 TabRestoreService::Entry* entry = *it; | |
| 362 if (entry->type == TabRestoreService::TAB) { | |
| 363 TabRestoreService::Tab* tab = static_cast<TabRestoreService::Tab*>(entry); | |
| 364 const sessions::SerializedNavigationEntry& current_navigation = | |
| 365 tab->navigations.at(tab->current_navigation_index); | |
| 366 BuildLocalTabItem( | |
| 367 entry->id, | |
| 368 current_navigation.title(), | |
| 369 current_navigation.virtual_url()); | |
| 370 } else { | |
| 371 DCHECK_EQ(entry->type, TabRestoreService::WINDOW); | |
| 372 BuildWindowItem( | |
| 373 entry->id, | |
| 374 static_cast<TabRestoreService::Window*>(entry)->tabs.size()); | |
| 375 } | |
| 376 ++added_count; | |
| 377 } | |
| 378 } | 430 } |
| 379 | 431 |
| 380 void RecentTabsSubMenuModel::BuildDevices() { | 432 void RecentTabsSubMenuModel::BuildForeignTabs() { |
| 433 // All foreign items (device headers or tabs) use AddItem*() to append a menu |
| 434 // item, because they are always only built once (i.e. invoked from |
| 435 // Constructor()) and don't change after that. |
| 436 |
| 381 browser_sync::SessionModelAssociator* associator = GetModelAssociator(); | 437 browser_sync::SessionModelAssociator* associator = GetModelAssociator(); |
| 382 std::vector<const browser_sync::SyncedSession*> sessions; | 438 std::vector<const browser_sync::SyncedSession*> sessions; |
| 383 if (!associator || !associator->GetAllForeignSessions(&sessions)) { | 439 if (!associator || !associator->GetAllForeignSessions(&sessions)) { |
| 384 AddSeparator(ui::NORMAL_SEPARATOR); | 440 AddSeparator(ui::NORMAL_SEPARATOR); |
| 385 AddItemWithStringId(IDC_RECENT_TABS_NO_DEVICE_TABS, | 441 AddItemWithStringId(IDC_RECENT_TABS_NO_DEVICE_TABS, |
| 386 IDS_RECENT_TABS_NO_DEVICE_TABS); | 442 IDS_RECENT_TABS_NO_DEVICE_TABS); |
| 387 return; | 443 return; |
| 388 } | 444 } |
| 389 | 445 |
| 390 // Sort sessions from most recent to least recent. | 446 // Sort sessions from most recent to least recent. |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 444 | 500 |
| 445 ++num_sessions_added; | 501 ++num_sessions_added; |
| 446 } // for all sessions | 502 } // for all sessions |
| 447 | 503 |
| 448 // We are not supposed to get here unless at least some items were added. | 504 // We are not supposed to get here unless at least some items were added. |
| 449 DCHECK_GT(GetItemCount(), 0); | 505 DCHECK_GT(GetItemCount(), 0); |
| 450 AddSeparator(ui::NORMAL_SEPARATOR); | 506 AddSeparator(ui::NORMAL_SEPARATOR); |
| 451 AddItemWithStringId(IDC_SHOW_HISTORY, IDS_RECENT_TABS_MORE); | 507 AddItemWithStringId(IDC_SHOW_HISTORY, IDS_RECENT_TABS_MORE); |
| 452 } | 508 } |
| 453 | 509 |
| 454 void RecentTabsSubMenuModel::BuildLocalTabItem( | 510 void RecentTabsSubMenuModel::BuildLocalTabItem(int session_id, |
| 455 int session_id, | 511 const string16& title, |
| 456 const string16& title, | 512 const GURL& url, |
| 457 const GURL& url) { | 513 int curr_model_index) { |
| 458 TabNavigationItem item("", session_id, title, url); | 514 TabNavigationItem item("", session_id, title, url); |
| 459 int command_id = TabModelIndexToCommandId(tab_navigation_items_.size()); | 515 int command_id = TabModelIndexToCommandId( |
| 516 local_tab_navigation_items_.size(), kFirstLocalTabCommandId); |
| 517 // See comments in BuildLocalEntries() about usage of InsertItem*At(). |
| 460 // There may be no tab title, in which case, use the url as tab title. | 518 // There may be no tab title, in which case, use the url as tab title. |
| 461 AddItem(command_id, title.empty() ? UTF8ToUTF16(item.url.spec()) : title); | 519 InsertItemAt(curr_model_index, command_id, |
| 462 AddTabFavicon(tab_navigation_items_.size(), command_id, item.url); | 520 title.empty() ? UTF8ToUTF16(item.url.spec()) : title); |
| 463 tab_navigation_items_.push_back(item); | 521 AddTabFavicon(command_id, item.url); |
| 522 local_tab_navigation_items_.push_back(item); |
| 464 } | 523 } |
| 465 | 524 |
| 466 void RecentTabsSubMenuModel::BuildForeignTabItem( | 525 void RecentTabsSubMenuModel::BuildLocalWindowItem( |
| 467 const std::string& session_tag, | 526 const SessionID::id_type& window_id, |
| 468 const SessionTab& tab) { | 527 int num_tabs, |
| 528 int curr_model_index) { |
| 529 int command_id = WindowModelIndexToCommandId(local_window_items_.size()); |
| 530 // See comments in BuildLocalEntries() about usage of InsertItem*At(). |
| 531 if (num_tabs == 1) { |
| 532 InsertItemWithStringIdAt(curr_model_index, command_id, |
| 533 IDS_NEW_TAB_RECENTLY_CLOSED_WINDOW_SINGLE); |
| 534 } else { |
| 535 InsertItemAt(curr_model_index, command_id, l10n_util::GetStringFUTF16( |
| 536 IDS_NEW_TAB_RECENTLY_CLOSED_WINDOW_MULTIPLE, |
| 537 base::IntToString16(num_tabs))); |
| 538 } |
| 539 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| 540 SetIcon(curr_model_index, rb.GetNativeImageNamed(IDR_RECENTLY_CLOSED_WINDOW)); |
| 541 local_window_items_.push_back(window_id); |
| 542 } |
| 543 |
| 544 void RecentTabsSubMenuModel::BuildForeignTabItem(const std::string& session_tag, |
| 545 const SessionTab& tab) { |
| 469 const sessions::SerializedNavigationEntry& current_navigation = | 546 const sessions::SerializedNavigationEntry& current_navigation = |
| 470 tab.navigations.at(tab.normalized_navigation_index()); | 547 tab.navigations.at(tab.normalized_navigation_index()); |
| 471 TabNavigationItem item(session_tag, tab.tab_id.id(), | 548 TabNavigationItem item(session_tag, tab.tab_id.id(), |
| 472 current_navigation.title(), | 549 current_navigation.title(), |
| 473 current_navigation.virtual_url()); | 550 current_navigation.virtual_url()); |
| 474 int command_id = TabModelIndexToCommandId(tab_navigation_items_.size()); | 551 int command_id = TabModelIndexToCommandId( |
| 552 foreign_tab_navigation_items_.size(), kFirstForeignTabCommandId); |
| 553 // See comments in BuildForeignTabs() about usage of AddItem*(). |
| 475 // There may be no tab title, in which case, use the url as tab title. | 554 // There may be no tab title, in which case, use the url as tab title. |
| 476 AddItem(command_id, | 555 AddItem(command_id, |
| 477 current_navigation.title().empty() ? | 556 current_navigation.title().empty() ? |
| 478 UTF8ToUTF16(item.url.spec()) : current_navigation.title()); | 557 UTF8ToUTF16(item.url.spec()) : current_navigation.title()); |
| 479 AddTabFavicon(tab_navigation_items_.size(), command_id, item.url); | 558 AddTabFavicon(command_id, item.url); |
| 480 tab_navigation_items_.push_back(item); | 559 foreign_tab_navigation_items_.push_back(item); |
| 481 } | |
| 482 | |
| 483 void RecentTabsSubMenuModel::BuildWindowItem( | |
| 484 const SessionID::id_type& window_id, | |
| 485 int num_tabs) { | |
| 486 int command_id = WindowModelIndexToCommandId(window_items_.size()); | |
| 487 if (num_tabs == 1) { | |
| 488 AddItemWithStringId(command_id, IDS_NEW_TAB_RECENTLY_CLOSED_WINDOW_SINGLE); | |
| 489 } else { | |
| 490 AddItem(command_id, l10n_util::GetStringFUTF16( | |
| 491 IDS_NEW_TAB_RECENTLY_CLOSED_WINDOW_MULTIPLE, | |
| 492 base::IntToString16(num_tabs))); | |
| 493 } | |
| 494 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
| 495 SetIcon(GetItemCount() - 1, | |
| 496 rb.GetNativeImageNamed(IDR_RECENTLY_CLOSED_WINDOW)); | |
| 497 window_items_.push_back(window_id); | |
| 498 } | 560 } |
| 499 | 561 |
| 500 void RecentTabsSubMenuModel::AddDeviceFavicon( | 562 void RecentTabsSubMenuModel::AddDeviceFavicon( |
| 501 int index_in_menu, | 563 int index_in_menu, |
| 502 browser_sync::SyncedSession::DeviceType device_type) { | 564 browser_sync::SyncedSession::DeviceType device_type) { |
| 503 int favicon_id = -1; | 565 int favicon_id = -1; |
| 504 switch (device_type) { | 566 switch (device_type) { |
| 505 case browser_sync::SyncedSession::TYPE_PHONE: | 567 case browser_sync::SyncedSession::TYPE_PHONE: |
| 506 favicon_id = IDR_PHONE_FAVICON; | 568 favicon_id = IDR_PHONE_FAVICON; |
| 507 break; | 569 break; |
| 508 | 570 |
| 509 case browser_sync::SyncedSession::TYPE_TABLET: | 571 case browser_sync::SyncedSession::TYPE_TABLET: |
| 510 favicon_id = IDR_TABLET_FAVICON; | 572 favicon_id = IDR_TABLET_FAVICON; |
| 511 break; | 573 break; |
| 512 | 574 |
| 513 case browser_sync::SyncedSession::TYPE_CHROMEOS: | 575 case browser_sync::SyncedSession::TYPE_CHROMEOS: |
| 514 case browser_sync::SyncedSession::TYPE_WIN: | 576 case browser_sync::SyncedSession::TYPE_WIN: |
| 515 case browser_sync::SyncedSession::TYPE_MACOSX: | 577 case browser_sync::SyncedSession::TYPE_MACOSX: |
| 516 case browser_sync::SyncedSession::TYPE_LINUX: | 578 case browser_sync::SyncedSession::TYPE_LINUX: |
| 517 case browser_sync::SyncedSession::TYPE_OTHER: | 579 case browser_sync::SyncedSession::TYPE_OTHER: |
| 518 case browser_sync::SyncedSession::TYPE_UNSET: | 580 case browser_sync::SyncedSession::TYPE_UNSET: |
| 519 favicon_id = IDR_LAPTOP_FAVICON; | 581 favicon_id = IDR_LAPTOP_FAVICON; |
| 520 break; | 582 break; |
| 521 }; | 583 }; |
| 522 | 584 |
| 523 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | 585 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| 524 SetIcon(index_in_menu, rb.GetNativeImageNamed(favicon_id)); | 586 SetIcon(index_in_menu, rb.GetNativeImageNamed(favicon_id)); |
| 525 } | 587 } |
| 526 | 588 |
| 527 void RecentTabsSubMenuModel::AddTabFavicon(int model_index, | 589 void RecentTabsSubMenuModel::AddTabFavicon(int command_id, const GURL& url) { |
| 528 int command_id, | |
| 529 const GURL& url) { | |
| 530 int index_in_menu = GetIndexOfCommandId(command_id); | 590 int index_in_menu = GetIndexOfCommandId(command_id); |
| 531 | 591 |
| 532 // If tab has synced favicon, use it. | 592 // If tab has synced favicon, use it. |
| 533 // Note that currently, foreign tab only has favicon if --sync-tab-favicons | 593 // Note that currently, foreign tab only has favicon if --sync-tab-favicons |
| 534 // switch is on; according to zea@, this flag is now automatically enabled for | 594 // switch is on; according to zea@, this flag is now automatically enabled for |
| 535 // iOS and android, and they're looking into enabling it for other platforms. | 595 // iOS and android, and they're looking into enabling it for other platforms. |
| 536 browser_sync::SessionModelAssociator* associator = GetModelAssociator(); | 596 browser_sync::SessionModelAssociator* associator = GetModelAssociator(); |
| 537 scoped_refptr<base::RefCountedMemory> favicon_png; | 597 scoped_refptr<base::RefCountedMemory> favicon_png; |
| 538 if (associator && | 598 if (associator && |
| 539 associator->GetSyncedFaviconForPageURL(url.spec(), &favicon_png)) { | 599 associator->GetSyncedFaviconForPageURL(url.spec(), &favicon_png)) { |
| 540 gfx::Image image = gfx::Image::CreateFrom1xPNGBytes( | 600 gfx::Image image = gfx::Image::CreateFrom1xPNGBytes(favicon_png->front(), |
| 541 favicon_png->front(), | 601 favicon_png->size()); |
| 542 favicon_png->size()); | |
| 543 SetIcon(index_in_menu, image); | 602 SetIcon(index_in_menu, image); |
| 544 return; | 603 return; |
| 545 } | 604 } |
| 546 | 605 |
| 547 // Otherwise, start to fetch the favicon from local history asynchronously. | 606 // Otherwise, start to fetch the favicon from local history asynchronously. |
| 548 // Set default icon first. | 607 // Set default icon first. |
| 549 SetIcon(index_in_menu, default_favicon_); | 608 SetIcon(index_in_menu, default_favicon_); |
| 550 // Start request to fetch actual icon if possible. | 609 // Start request to fetch actual icon if possible. |
| 551 FaviconService* favicon_service = FaviconServiceFactory::GetForProfile( | 610 FaviconService* favicon_service = FaviconServiceFactory::GetForProfile( |
| 552 browser_->profile(), Profile::EXPLICIT_ACCESS); | 611 browser_->profile(), Profile::EXPLICIT_ACCESS); |
| 553 if (!favicon_service) | 612 if (!favicon_service) |
| 554 return; | 613 return; |
| 555 | 614 |
| 556 favicon_service->GetFaviconImageForURL( | 615 favicon_service->GetFaviconImageForURL( |
| 557 FaviconService::FaviconForURLParams(browser_->profile(), | 616 FaviconService::FaviconForURLParams(browser_->profile(), |
| 558 url, | 617 url, |
| 559 chrome::FAVICON, | 618 chrome::FAVICON, |
| 560 gfx::kFaviconSize), | 619 gfx::kFaviconSize), |
| 561 base::Bind(&RecentTabsSubMenuModel::OnFaviconDataAvailable, | 620 base::Bind(&RecentTabsSubMenuModel::OnFaviconDataAvailable, |
| 562 weak_ptr_factory_.GetWeakPtr(), | 621 weak_ptr_factory_.GetWeakPtr(), |
| 563 command_id), | 622 command_id), |
| 564 &cancelable_task_tracker_); | 623 command_id >= kFirstForeignTabCommandId ? |
| 624 &foreign_tab_cancelable_task_tracker_ : |
| 625 &local_tab_cancelable_task_tracker_); |
| 565 } | 626 } |
| 566 | 627 |
| 567 void RecentTabsSubMenuModel::OnFaviconDataAvailable( | 628 void RecentTabsSubMenuModel::OnFaviconDataAvailable( |
| 568 int command_id, | 629 int command_id, |
| 569 const chrome::FaviconImageResult& image_result) { | 630 const chrome::FaviconImageResult& image_result) { |
| 570 if (image_result.image.IsEmpty()) | 631 if (image_result.image.IsEmpty()) |
| 571 return; | 632 return; |
| 572 DCHECK(!tab_navigation_items_.empty()); | |
| 573 int index_in_menu = GetIndexOfCommandId(command_id); | 633 int index_in_menu = GetIndexOfCommandId(command_id); |
| 574 DCHECK(index_in_menu != -1); | 634 DCHECK_GT(index_in_menu, -1); |
| 575 SetIcon(index_in_menu, image_result.image); | 635 SetIcon(index_in_menu, image_result.image); |
| 576 if (GetMenuModelDelegate()) | 636 if (GetMenuModelDelegate()) |
| 577 GetMenuModelDelegate()->OnIconChanged(index_in_menu); | 637 GetMenuModelDelegate()->OnIconChanged(index_in_menu); |
| 578 } | 638 } |
| 579 | 639 |
| 640 int RecentTabsSubMenuModel::CommandIdToTabModelIndex( |
| 641 int command_id, TabNavigationItems** tab_items) { |
| 642 if (command_id >= kFirstForeignTabCommandId) { |
| 643 *tab_items = &foreign_tab_navigation_items_; |
| 644 return command_id - kFirstForeignTabCommandId; |
| 645 } |
| 646 DCHECK_GE(command_id, kFirstLocalTabCommandId); |
| 647 DCHECK_LT(command_id, kFirstLocalWindowCommandId); |
| 648 *tab_items = &local_tab_navigation_items_; |
| 649 return command_id - kFirstLocalTabCommandId; |
| 650 } |
| 651 |
| 652 void RecentTabsSubMenuModel::ClearLocalEntries() { |
| 653 // Remove local items (recent tabs and windows) from model. |
| 654 while (last_local_model_index_ >= 0) |
| 655 RemoveItemAt(last_local_model_index_--); |
| 656 |
| 657 // Cancel asynchronous FaviconService::GetFaviconImageForURL() tasks of all |
| 658 // local tabs. |
| 659 local_tab_cancelable_task_tracker_.TryCancelAll(); |
| 660 |
| 661 // Remove all local tab navigation items. |
| 662 local_tab_navigation_items_.clear(); |
| 663 |
| 664 // Remove all local window items. |
| 665 local_window_items_.clear(); |
| 666 } |
| 667 |
| 580 browser_sync::SessionModelAssociator* | 668 browser_sync::SessionModelAssociator* |
| 581 RecentTabsSubMenuModel::GetModelAssociator() { | 669 RecentTabsSubMenuModel::GetModelAssociator() { |
| 582 if (!associator_) { | 670 if (!associator_) { |
| 583 ProfileSyncService* service = ProfileSyncServiceFactory::GetInstance()-> | 671 ProfileSyncService* service = ProfileSyncServiceFactory::GetInstance()-> |
| 584 GetForProfile(browser_->profile()); | 672 GetForProfile(browser_->profile()); |
| 585 // Only return the associator if it exists and it is done syncing sessions. | 673 // Only return the associator if it exists and it is done syncing sessions. |
| 586 if (service && service->ShouldPushChanges()) | 674 if (service && service->ShouldPushChanges()) |
| 587 associator_ = service->GetSessionModelAssociator(); | 675 associator_ = service->GetSessionModelAssociator(); |
| 588 } | 676 } |
| 589 return associator_; | 677 return associator_; |
| 590 } | 678 } |
| 679 |
| 680 void RecentTabsSubMenuModel::TabRestoreServiceChanged( |
| 681 TabRestoreService* service) { |
| 682 ui::MenuModelDelegate* menu_model_delegate = GetMenuModelDelegate(); |
| 683 if (menu_model_delegate) { |
| 684 menu_model_delegate->PrepareForChange(); |
| 685 |
| 686 // Notify delegate to remove all local entries from the menu; do so in |
| 687 // decreasing order so that indexes of remaining items don't change. |
| 688 for (int i = last_local_model_index_; i >=0; --i) |
| 689 menu_model_delegate->OnItemRemoved(i); |
| 690 } |
| 691 |
| 692 ClearLocalEntries(); |
| 693 |
| 694 BuildLocalEntries(); |
| 695 |
| 696 if (menu_model_delegate) { |
| 697 // Notify delegate to add the new local entries to the menu. |
| 698 for (int i = 0; i <= last_local_model_index_; ++i) |
| 699 menu_model_delegate->OnItemAdded(i); |
| 700 |
| 701 menu_model_delegate->ChangesDone(); |
| 702 } |
| 703 } |
| 704 |
| 705 void RecentTabsSubMenuModel::TabRestoreServiceDestroyed( |
| 706 TabRestoreService* service) { |
| 707 TabRestoreServiceChanged(service); |
| 708 } |
| OLD | NEW |