| 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" |
| 11 #include "chrome/app/chrome_command_ids.h" | 11 #include "chrome/app/chrome_command_ids.h" |
| 12 #include "chrome/browser/favicon/favicon_service_factory.h" | 12 #include "chrome/browser/favicon/favicon_service_factory.h" |
| 13 #include "chrome/browser/prefs/scoped_user_pref_update.h" | 13 #include "chrome/browser/prefs/scoped_user_pref_update.h" |
| 14 #include "chrome/browser/profiles/profile.h" | 14 #include "chrome/browser/profiles/profile.h" |
| 15 #include "chrome/browser/search/search.h" | 15 #include "chrome/browser/search/search.h" |
| 16 #include "chrome/browser/sessions/session_restore.h" | 16 #include "chrome/browser/sessions/session_restore.h" |
| 17 #include "chrome/browser/sessions/tab_restore_service.h" | 17 #include "chrome/browser/sessions/tab_restore_service.h" |
| 18 #include "chrome/browser/sessions/tab_restore_service_delegate.h" | 18 #include "chrome/browser/sessions/tab_restore_service_delegate.h" |
| 19 #include "chrome/browser/sessions/tab_restore_service_factory.h" | 19 #include "chrome/browser/sessions/tab_restore_service_factory.h" |
| 20 #include "chrome/browser/sync/glue/session_model_associator.h" | 20 #include "chrome/browser/sync/glue/session_model_associator.h" |
| 21 #include "chrome/browser/sync/glue/synced_session.h" | 21 #include "chrome/browser/sync/glue/synced_session.h" |
| 22 #include "chrome/browser/sync/profile_sync_service.h" | 22 #include "chrome/browser/sync/profile_sync_service.h" |
| 23 #include "chrome/browser/sync/profile_sync_service_factory.h" | 23 #include "chrome/browser/sync/profile_sync_service_factory.h" |
| 24 #include "chrome/browser/ui/browser.h" | 24 #include "chrome/browser/ui/browser.h" |
| 25 #include "chrome/browser/ui/browser_commands.h" | 25 #include "chrome/browser/ui/browser_commands.h" |
| 26 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 26 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| 27 #include "chrome/browser/ui/toolbar/wrench_menu_model.h" | |
| 28 #include "chrome/common/favicon/favicon_types.h" | 27 #include "chrome/common/favicon/favicon_types.h" |
| 29 #include "chrome/common/pref_names.h" | 28 #include "chrome/common/pref_names.h" |
| 30 #include "grit/browser_resources.h" | 29 #include "grit/browser_resources.h" |
| 31 #include "grit/generated_resources.h" | 30 #include "grit/generated_resources.h" |
| 32 #include "grit/theme_resources.h" | 31 #include "grit/theme_resources.h" |
| 33 #include "grit/ui_resources.h" | 32 #include "grit/ui_resources.h" |
| 34 #include "ui/base/accelerators/accelerator.h" | 33 #include "ui/base/accelerators/accelerator.h" |
| 35 #include "ui/base/l10n/l10n_util.h" | 34 #include "ui/base/l10n/l10n_util.h" |
| 36 #include "ui/base/resource/resource_bundle.h" | 35 #include "ui/base/resource/resource_bundle.h" |
| 37 #include "ui/gfx/favicon_size.h" | 36 #include "ui/gfx/favicon_size.h" |
| 38 | 37 |
| 39 #if defined(USE_ASH) | 38 #if defined(USE_ASH) |
| 40 #include "ash/accelerators/accelerator_table.h" | 39 #include "ash/accelerators/accelerator_table.h" |
| 41 #endif // defined(USE_ASH) | 40 #endif // defined(USE_ASH) |
| 42 | 41 |
| 43 namespace { | 42 namespace { |
| 44 | 43 |
| 45 // First comamnd id for navigatable (and hence executable) tab menu item. | 44 // First comamnd id for navigatable (and hence executable) tab menu item. |
| 46 // The models and menu are not 1-1: | 45 // The models and menu are not 1-1: |
| 47 // - menu has "Reopen closed tab", "No tabs from other devices", device section | 46 // - menu has "Reopen closed tab", "No tabs from other devices", device section |
| 48 // headers, separators and executable tab items. | 47 // headers, separators and executable tab items. |
| 49 // - |tab_navigation_items_| only has navigatabale/executable tab items. | 48 // - |tab_navigation_items_| only has navigatabale/executable tab items. |
| 50 // - |window_items_| only has executable open window items. | 49 // - |window_items_| only has executable open window items. |
| 51 // Using an initial command ids for tab/window items makes it easier and less | 50 // Using an initial command ids for tab/window items makes it easier and less |
| 52 // error-prone to manipulate the models and menu. | 51 // error-prone to manipulate the models and menu. |
| 53 // These values must be bigger than the maximum possible number of items in | 52 // These values must be bigger than the maximum possible number of items in |
| 54 // menu, so that index of last menu item doesn't clash with this value when menu | 53 // menu, so that index of last menu item doesn't clash with this value when menu |
| 55 // items are retrieved via GetIndexOfCommandId. | 54 // items are retrieved via GetIndexOfCommandId. |
| 56 // The range of all command ID's used in RecentTabsSubMenuModel must be between | 55 const int kFirstTabCommandId = 100; |
| 57 // WrenchMenuModel::kMinRecentTabsCommandId i.e. 1001 and 1200 | 56 const int kFirstWindowCommandId = 200; |
| 58 // (WrenchMenuModel::kMaxRecentTabsCommandId) inclusively. | |
| 59 const int kFirstTabCommandId = WrenchMenuModel::kMinRecentTabsCommandId; | |
| 60 const int kFirstWindowCommandId = 1051; | |
| 61 const int kMinDeviceNameCommandId = 1100; | |
| 62 const int kMaxDeviceNameCommandId = 1110; | |
| 63 | 57 |
| 64 // The maximum number of recently closed entries to be shown in the menu. | 58 // The maximum number of recently closed entries to be shown in the menu. |
| 65 const int kMaxRecentlyClosedEntries = 8; | 59 const int kMaxRecentlyClosedEntries = 8; |
| 66 | 60 |
| 67 // Comparator function for use with std::sort that will sort sessions by | 61 // Comparator function for use with std::sort that will sort sessions by |
| 68 // descending modified_time (i.e., most recent first). | 62 // descending modified_time (i.e., most recent first). |
| 69 bool SortSessionsByRecency(const browser_sync::SyncedSession* s1, | 63 bool SortSessionsByRecency(const browser_sync::SyncedSession* s1, |
| 70 const browser_sync::SyncedSession* s2) { | 64 const browser_sync::SyncedSession* s2) { |
| 71 return s1->modified_time > s2->modified_time; | 65 return s1->modified_time > s2->modified_time; |
| 72 } | 66 } |
| 73 | 67 |
| 74 // Comparator function for use with std::sort that will sort tabs by | 68 // Comparator function for use with std::sort that will sort tabs by |
| 75 // descending timestamp (i.e., most recent first). | 69 // descending timestamp (i.e., most recent first). |
| 76 bool SortTabsByRecency(const SessionTab* t1, const SessionTab* t2) { | 70 bool SortTabsByRecency(const SessionTab* t1, const SessionTab* t2) { |
| 77 return t1->timestamp > t2->timestamp; | 71 return t1->timestamp > t2->timestamp; |
| 78 } | 72 } |
| 79 | 73 |
| 80 // Returns true if the command id is related to a tab model index. | 74 // Returns true if the command id is related to a tab model index. |
| 81 bool IsTabModelCommandId(int command_id) { | 75 bool IsTabModelCommandId(int command_id) { |
| 82 return command_id >= kFirstTabCommandId && command_id < kFirstWindowCommandId; | 76 return command_id >= kFirstTabCommandId && command_id < kFirstWindowCommandId; |
| 83 } | 77 } |
| 84 | 78 |
| 85 // Returns true if the command id is related to a window model index. | 79 // Returns true if the command id is related to a window model index. |
| 86 bool IsWindowModelCommandId(int command_id) { | 80 bool IsWindowModelCommandId(int command_id) { |
| 87 return command_id >= kFirstWindowCommandId && | 81 return command_id >= kFirstWindowCommandId && |
| 88 command_id < RecentTabsSubMenuModel::kRecentlyClosedHeaderCommandId; | 82 command_id < RecentTabsSubMenuModel::kRecentlyClosedHeaderCommandId; |
| 89 } | 83 } |
| 90 | 84 |
| 91 bool IsDeviceNameCommandId(int command_id) { | |
| 92 return command_id >= kMinDeviceNameCommandId && | |
| 93 command_id <= kMaxDeviceNameCommandId; | |
| 94 } | |
| 95 | |
| 96 // Convert |tab_model_index| to command id of menu item. | 85 // Convert |tab_model_index| to command id of menu item. |
| 97 int TabModelIndexToCommandId(int tab_model_index) { | 86 int TabModelIndexToCommandId(int tab_model_index) { |
| 98 int command_id = tab_model_index + kFirstTabCommandId; | 87 int command_id = tab_model_index + kFirstTabCommandId; |
| 99 DCHECK_LT(command_id, kFirstWindowCommandId); | 88 DCHECK_LT(command_id, kFirstWindowCommandId); |
| 100 return command_id; | 89 return command_id; |
| 101 } | 90 } |
| 102 | 91 |
| 103 // Convert |command_id| of menu item to index in tab model. | 92 // Convert |command_id| of menu item to index in tab model. |
| 104 int CommandIdToTabModelIndex(int command_id) { | 93 int CommandIdToTabModelIndex(int command_id) { |
| 105 DCHECK_GE(command_id, kFirstTabCommandId); | 94 DCHECK_GE(command_id, kFirstTabCommandId); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 150 bool operator<(const TabNavigationItem& other) const { | 139 bool operator<(const TabNavigationItem& other) const { |
| 151 return url < other.url; | 140 return url < other.url; |
| 152 } | 141 } |
| 153 | 142 |
| 154 std::string session_tag; // Empty for local tabs, non-empty for foreign tabs. | 143 std::string session_tag; // Empty for local tabs, non-empty for foreign tabs. |
| 155 SessionID::id_type tab_id; // -1 for invalid, >= 0 otherwise. | 144 SessionID::id_type tab_id; // -1 for invalid, >= 0 otherwise. |
| 156 string16 title; | 145 string16 title; |
| 157 GURL url; | 146 GURL url; |
| 158 }; | 147 }; |
| 159 | 148 |
| 160 const int RecentTabsSubMenuModel::kRecentlyClosedHeaderCommandId = 1120; | 149 const int RecentTabsSubMenuModel::kRecentlyClosedHeaderCommandId = 500; |
| 161 const int RecentTabsSubMenuModel::kDisabledRecentlyClosedHeaderCommandId = 1121; | 150 const int RecentTabsSubMenuModel::kDisabledRecentlyClosedHeaderCommandId = 501; |
| 151 const int RecentTabsSubMenuModel::kDeviceNameCommandId = 1000; |
| 162 | 152 |
| 163 RecentTabsSubMenuModel::RecentTabsSubMenuModel( | 153 RecentTabsSubMenuModel::RecentTabsSubMenuModel( |
| 164 ui::AcceleratorProvider* accelerator_provider, | 154 ui::AcceleratorProvider* accelerator_provider, |
| 165 Browser* browser, | 155 Browser* browser, |
| 166 browser_sync::SessionModelAssociator* associator) | 156 browser_sync::SessionModelAssociator* associator) |
| 167 : ui::SimpleMenuModel(this), | 157 : ui::SimpleMenuModel(this), |
| 168 browser_(browser), | 158 browser_(browser), |
| 169 associator_(associator), | 159 associator_(associator), |
| 170 default_favicon_(ResourceBundle::GetSharedInstance(). | 160 default_favicon_(ResourceBundle::GetSharedInstance(). |
| 171 GetNativeImageNamed(IDR_DEFAULT_FAVICON)), | 161 GetNativeImageNamed(IDR_DEFAULT_FAVICON)), |
| (...skipping 23 matching lines...) Expand all Loading... |
| 195 RecentTabsSubMenuModel::~RecentTabsSubMenuModel() { | 185 RecentTabsSubMenuModel::~RecentTabsSubMenuModel() { |
| 196 } | 186 } |
| 197 | 187 |
| 198 bool RecentTabsSubMenuModel::IsCommandIdChecked(int command_id) const { | 188 bool RecentTabsSubMenuModel::IsCommandIdChecked(int command_id) const { |
| 199 return false; | 189 return false; |
| 200 } | 190 } |
| 201 | 191 |
| 202 bool RecentTabsSubMenuModel::IsCommandIdEnabled(int command_id) const { | 192 bool RecentTabsSubMenuModel::IsCommandIdEnabled(int command_id) const { |
| 203 if (command_id == kRecentlyClosedHeaderCommandId || | 193 if (command_id == kRecentlyClosedHeaderCommandId || |
| 204 command_id == kDisabledRecentlyClosedHeaderCommandId || | 194 command_id == kDisabledRecentlyClosedHeaderCommandId || |
| 205 command_id == IDC_RECENT_TABS_NO_DEVICE_TABS || | 195 command_id == kDeviceNameCommandId || |
| 206 IsDeviceNameCommandId(command_id)) { | 196 command_id == IDC_RECENT_TABS_NO_DEVICE_TABS) { |
| 207 return false; | 197 return false; |
| 208 } | 198 } |
| 209 return true; | 199 return true; |
| 210 } | 200 } |
| 211 | 201 |
| 212 bool RecentTabsSubMenuModel::GetAcceleratorForCommandId( | 202 bool RecentTabsSubMenuModel::GetAcceleratorForCommandId( |
| 213 int command_id, ui::Accelerator* accelerator) { | 203 int command_id, ui::Accelerator* accelerator) { |
| 214 // If there are no recently closed items, we show the accelerator beside | 204 // If there are no recently closed items, we show the accelerator beside |
| 215 // the header, otherwise, we show it beside the first item underneath it. | 205 // the header, otherwise, we show it beside the first item underneath it. |
| 216 int index_in_menu = GetIndexOfCommandId(command_id); | 206 int index_in_menu = GetIndexOfCommandId(command_id); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 227 void RecentTabsSubMenuModel::ExecuteCommand(int command_id, int event_flags) { | 217 void RecentTabsSubMenuModel::ExecuteCommand(int command_id, int event_flags) { |
| 228 if (command_id == IDC_SHOW_HISTORY) { | 218 if (command_id == IDC_SHOW_HISTORY) { |
| 229 UMA_HISTOGRAM_ENUMERATION("WrenchMenu.RecentTabsSubMenu", SHOW_MORE, | 219 UMA_HISTOGRAM_ENUMERATION("WrenchMenu.RecentTabsSubMenu", SHOW_MORE, |
| 230 LIMIT_RECENT_TAB_ACTION); | 220 LIMIT_RECENT_TAB_ACTION); |
| 231 // We show all "other devices" on the history page. | 221 // We show all "other devices" on the history page. |
| 232 chrome::ExecuteCommandWithDisposition(browser_, IDC_SHOW_HISTORY, | 222 chrome::ExecuteCommandWithDisposition(browser_, IDC_SHOW_HISTORY, |
| 233 ui::DispositionFromEventFlags(event_flags)); | 223 ui::DispositionFromEventFlags(event_flags)); |
| 234 return; | 224 return; |
| 235 } | 225 } |
| 236 | 226 |
| 227 DCHECK_NE(kDeviceNameCommandId, command_id); |
| 237 DCHECK_NE(IDC_RECENT_TABS_NO_DEVICE_TABS, command_id); | 228 DCHECK_NE(IDC_RECENT_TABS_NO_DEVICE_TABS, command_id); |
| 238 DCHECK(!IsDeviceNameCommandId(command_id)); | |
| 239 | 229 |
| 240 WindowOpenDisposition disposition = | 230 WindowOpenDisposition disposition = |
| 241 ui::DispositionFromEventFlags(event_flags); | 231 ui::DispositionFromEventFlags(event_flags); |
| 242 if (disposition == CURRENT_TAB) // Force to open a new foreground tab. | 232 if (disposition == CURRENT_TAB) // Force to open a new foreground tab. |
| 243 disposition = NEW_FOREGROUND_TAB; | 233 disposition = NEW_FOREGROUND_TAB; |
| 244 | 234 |
| 245 TabRestoreService* service = | 235 TabRestoreService* service = |
| 246 TabRestoreServiceFactory::GetForProfile(browser_->profile()); | 236 TabRestoreServiceFactory::GetForProfile(browser_->profile()); |
| 247 TabRestoreServiceDelegate* delegate = | 237 TabRestoreServiceDelegate* delegate = |
| 248 TabRestoreServiceDelegate::FindDelegateForWebContents( | 238 TabRestoreServiceDelegate::FindDelegateForWebContents( |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 285 UMA_HISTOGRAM_ENUMERATION("WrenchMenu.RecentTabsSubMenu", RESTORE_WINDOW, | 275 UMA_HISTOGRAM_ENUMERATION("WrenchMenu.RecentTabsSubMenu", RESTORE_WINDOW, |
| 286 LIMIT_RECENT_TAB_ACTION); | 276 LIMIT_RECENT_TAB_ACTION); |
| 287 service->RestoreEntryById(delegate, window_items_[model_idx], | 277 service->RestoreEntryById(delegate, window_items_[model_idx], |
| 288 browser_->host_desktop_type(), disposition); | 278 browser_->host_desktop_type(), disposition); |
| 289 } | 279 } |
| 290 } | 280 } |
| 291 } | 281 } |
| 292 | 282 |
| 293 const gfx::Font* RecentTabsSubMenuModel::GetLabelFontAt(int index) const { | 283 const gfx::Font* RecentTabsSubMenuModel::GetLabelFontAt(int index) const { |
| 294 int command_id = GetCommandIdAt(index); | 284 int command_id = GetCommandIdAt(index); |
| 295 if (command_id == kRecentlyClosedHeaderCommandId || | 285 if (command_id == kDeviceNameCommandId || |
| 296 IsDeviceNameCommandId(command_id)) { | 286 command_id == kRecentlyClosedHeaderCommandId) { |
| 297 return &ResourceBundle::GetSharedInstance().GetFont( | 287 return &ResourceBundle::GetSharedInstance().GetFont( |
| 298 ResourceBundle::BoldFont); | 288 ResourceBundle::BoldFont); |
| 299 } | 289 } |
| 300 return NULL; | 290 return NULL; |
| 301 } | 291 } |
| 302 | 292 |
| 303 int RecentTabsSubMenuModel::GetMaxWidthForItemAtIndex(int item_index) const { | 293 int RecentTabsSubMenuModel::GetMaxWidthForItemAtIndex(int item_index) const { |
| 304 int command_id = GetCommandIdAt(item_index); | 294 int command_id = GetCommandIdAt(item_index); |
| 305 if (command_id == IDC_RECENT_TABS_NO_DEVICE_TABS || | 295 if (command_id == IDC_RECENT_TABS_NO_DEVICE_TABS || |
| 306 command_id == kRecentlyClosedHeaderCommandId || | 296 command_id == kRecentlyClosedHeaderCommandId || |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 434 } | 424 } |
| 435 } | 425 } |
| 436 if (tabs_in_session.empty()) | 426 if (tabs_in_session.empty()) |
| 437 continue; | 427 continue; |
| 438 std::sort(tabs_in_session.begin(), tabs_in_session.end(), | 428 std::sort(tabs_in_session.begin(), tabs_in_session.end(), |
| 439 SortTabsByRecency); | 429 SortTabsByRecency); |
| 440 | 430 |
| 441 // Add the header for the device session. | 431 // Add the header for the device session. |
| 442 DCHECK(!session->session_name.empty()); | 432 DCHECK(!session->session_name.empty()); |
| 443 AddSeparator(ui::NORMAL_SEPARATOR); | 433 AddSeparator(ui::NORMAL_SEPARATOR); |
| 444 AddItem(kMinDeviceNameCommandId + i, UTF8ToUTF16(session->session_name)); | 434 AddItem(kDeviceNameCommandId, UTF8ToUTF16(session->session_name)); |
| 445 AddDeviceFavicon(GetItemCount() - 1, session->device_type); | 435 AddDeviceFavicon(GetItemCount() - 1, session->device_type); |
| 446 | 436 |
| 447 // Build tab menu items from sorted session tabs. | 437 // Build tab menu items from sorted session tabs. |
| 448 const size_t kMaxTabsPerSessionToShow = 4; | 438 const size_t kMaxTabsPerSessionToShow = 4; |
| 449 for (size_t k = 0; | 439 for (size_t k = 0; |
| 450 k < std::min(tabs_in_session.size(), kMaxTabsPerSessionToShow); | 440 k < std::min(tabs_in_session.size(), kMaxTabsPerSessionToShow); |
| 451 ++k) { | 441 ++k) { |
| 452 BuildForeignTabItem(session_tag, *tabs_in_session[k]); | 442 BuildForeignTabItem(session_tag, *tabs_in_session[k]); |
| 453 } // for all tabs in one session | 443 } // for all tabs in one session |
| 454 | 444 |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 591 RecentTabsSubMenuModel::GetModelAssociator() { | 581 RecentTabsSubMenuModel::GetModelAssociator() { |
| 592 if (!associator_) { | 582 if (!associator_) { |
| 593 ProfileSyncService* service = ProfileSyncServiceFactory::GetInstance()-> | 583 ProfileSyncService* service = ProfileSyncServiceFactory::GetInstance()-> |
| 594 GetForProfile(browser_->profile()); | 584 GetForProfile(browser_->profile()); |
| 595 // Only return the associator if it exists and it is done syncing sessions. | 585 // Only return the associator if it exists and it is done syncing sessions. |
| 596 if (service && service->ShouldPushChanges()) | 586 if (service && service->ShouldPushChanges()) |
| 597 associator_ = service->GetSessionModelAssociator(); | 587 associator_ = service->GetSessionModelAssociator(); |
| 598 } | 588 } |
| 599 return associator_; | 589 return associator_; |
| 600 } | 590 } |
| OLD | NEW |