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