wrench_menu_model.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/ui/toolbar/wrench_menu_model.h" 6 7#include <algorithm> 8#include <cmath> 9 10#include "base/command_line.h" 11#include "base/i18n/number_formatting.h" 12#include "base/prefs/pref_service.h" 13#include "base/string_util.h" 14#include "base/strings/string_number_conversions.h" 15#include "base/utf_string_conversions.h" 16#include "chrome/app/chrome_command_ids.h" 17#include "chrome/browser/browser_process.h" 18#include "chrome/browser/defaults.h" 19#include "chrome/browser/profiles/profile.h" 20#include "chrome/browser/profiles/profile_manager.h" 21#include "chrome/browser/search/search.h" 22#include "chrome/browser/signin/signin_manager.h" 23#include "chrome/browser/signin/signin_manager_factory.h" 24#include "chrome/browser/signin/signin_ui_util.h" 25#include "chrome/browser/task_manager/task_manager.h" 26#include "chrome/browser/ui/browser.h" 27#include "chrome/browser/ui/browser_commands.h" 28#include "chrome/browser/ui/browser_finder.h" 29#include "chrome/browser/ui/browser_window.h" 30#include "chrome/browser/ui/global_error/global_error.h" 31#include "chrome/browser/ui/global_error/global_error_service.h" 32#include "chrome/browser/ui/global_error/global_error_service_factory.h" 33#include "chrome/browser/ui/send_feedback_experiment.h" 34#include "chrome/browser/ui/tabs/tab_strip_model.h" 35#include "chrome/browser/ui/toolbar/bookmark_sub_menu_model.h" 36#include "chrome/browser/ui/toolbar/encoding_menu_controller.h" 37#include "chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h" 38#include "chrome/browser/upgrade_detector.h" 39#include "chrome/common/chrome_paths.h" 40#include "chrome/common/chrome_switches.h" 41#include "chrome/common/pref_names.h" 42#include "chrome/common/profiling.h" 43#include "content/public/browser/host_zoom_map.h" 44#include "content/public/browser/navigation_entry.h" 45#include "content/public/browser/notification_service.h" 46#include "content/public/browser/notification_source.h" 47#include "content/public/browser/notification_types.h" 48#include "content/public/browser/user_metrics.h" 49#include "content/public/browser/web_contents.h" 50#include "grit/chromium_strings.h" 51#include "grit/generated_resources.h" 52#include "grit/theme_resources.h" 53#include "ui/base/l10n/l10n_util.h" 54#include "ui/base/layout.h" 55#include "ui/base/models/button_menu_item_model.h" 56#include "ui/base/resource/resource_bundle.h" 57#include "ui/gfx/image/image.h" 58#include "ui/gfx/image/image_skia.h" 59 60#if defined(OS_CHROMEOS) 61#include "chromeos/chromeos_switches.h" 62#endif 63 64#if defined(OS_WIN) 65#include "base/win/metro.h" 66#include "base/win/windows_version.h" 67#include "chrome/browser/enumerate_modules_model_win.h" 68#include "chrome/browser/ui/metro_pin_tab_helper_win.h" 69#include "win8/util/win8_util.h" 70#endif 71 72#if defined(USE_ASH) 73#include "ash/shell.h" 74#endif 75 76using content::HostZoomMap; 77using content::UserMetricsAction; 78using content::WebContents; 79 80namespace { 81// Conditionally return the update app menu item title based on upgrade detector 82// state. 83string16 GetUpgradeDialogMenuItemName() { 84 if (UpgradeDetector::GetInstance()->is_outdated_install()) { 85 return l10n_util::GetStringFUTF16( 86 IDS_UPGRADE_BUBBLE_MENU_ITEM, 87 l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)); 88 } else { 89 return l10n_util::GetStringUTF16(IDS_UPDATE_NOW); 90 } 91} 92 93} // namespace 94 95//////////////////////////////////////////////////////////////////////////////// 96// EncodingMenuModel 97 98EncodingMenuModel::EncodingMenuModel(Browser* browser) 99 : ui::SimpleMenuModel(this), 100 browser_(browser) { 101 Build(); 102} 103 104EncodingMenuModel::~EncodingMenuModel() { 105} 106 107void EncodingMenuModel::Build() { 108 EncodingMenuController::EncodingMenuItemList encoding_menu_items; 109 EncodingMenuController encoding_menu_controller; 110 encoding_menu_controller.GetEncodingMenuItems(browser_->profile(), 111 &encoding_menu_items); 112 113 int group_id = 0; 114 EncodingMenuController::EncodingMenuItemList::iterator it = 115 encoding_menu_items.begin(); 116 for (; it != encoding_menu_items.end(); ++it) { 117 int id = it->first; 118 string16& label = it->second; 119 if (id == 0) { 120 AddSeparator(ui::NORMAL_SEPARATOR); 121 } else { 122 if (id == IDC_ENCODING_AUTO_DETECT) { 123 AddCheckItem(id, label); 124 } else { 125 // Use the id of the first radio command as the id of the group. 126 if (group_id <= 0) 127 group_id = id; 128 AddRadioItem(id, label, group_id); 129 } 130 } 131 } 132} 133 134bool EncodingMenuModel::IsCommandIdChecked(int command_id) const { 135 WebContents* current_tab = 136 browser_->tab_strip_model()->GetActiveWebContents(); 137 if (!current_tab) 138 return false; 139 EncodingMenuController controller; 140 return controller.IsItemChecked(browser_->profile(), 141 current_tab->GetEncoding(), command_id); 142} 143 144bool EncodingMenuModel::IsCommandIdEnabled(int command_id) const { 145 bool enabled = chrome::IsCommandEnabled(browser_, command_id); 146 // Special handling for the contents of the Encoding submenu. On Mac OS, 147 // instead of enabling/disabling the top-level menu item, the submenu's 148 // contents get disabled, per Apple's HIG. 149#if defined(OS_MACOSX) 150 enabled &= chrome::IsCommandEnabled(browser_, IDC_ENCODING_MENU); 151#endif 152 return enabled; 153} 154 155bool EncodingMenuModel::GetAcceleratorForCommandId( 156 int command_id, 157 ui::Accelerator* accelerator) { 158 return false; 159} 160 161void EncodingMenuModel::ExecuteCommand(int command_id, int event_flags) { 162 chrome::ExecuteCommand(browser_, command_id); 163} 164 165//////////////////////////////////////////////////////////////////////////////// 166// ZoomMenuModel 167 168ZoomMenuModel::ZoomMenuModel(ui::SimpleMenuModel::Delegate* delegate) 169 : SimpleMenuModel(delegate) { 170 Build(); 171} 172 173ZoomMenuModel::~ZoomMenuModel() { 174} 175 176void ZoomMenuModel::Build() { 177 AddItemWithStringId(IDC_ZOOM_PLUS, IDS_ZOOM_PLUS); 178 AddItemWithStringId(IDC_ZOOM_NORMAL, IDS_ZOOM_NORMAL); 179 AddItemWithStringId(IDC_ZOOM_MINUS, IDS_ZOOM_MINUS); 180} 181 182//////////////////////////////////////////////////////////////////////////////// 183// ToolsMenuModel 184 185ToolsMenuModel::ToolsMenuModel(ui::SimpleMenuModel::Delegate* delegate, 186 Browser* browser) 187 : SimpleMenuModel(delegate) { 188 Build(browser); 189} 190 191ToolsMenuModel::~ToolsMenuModel() {} 192 193void ToolsMenuModel::Build(Browser* browser) { 194#if !defined(OS_CHROMEOS) && !defined(OS_MACOSX) 195 AddItemWithStringId(IDC_CREATE_SHORTCUTS, IDS_CREATE_SHORTCUTS); 196 AddSeparator(ui::NORMAL_SEPARATOR); 197#endif 198 199 AddItemWithStringId(IDC_MANAGE_EXTENSIONS, IDS_SHOW_EXTENSIONS); 200 201 if (chrome::CanOpenTaskManager()) 202 AddItemWithStringId(IDC_TASK_MANAGER, IDS_TASK_MANAGER); 203 204 AddItemWithStringId(IDC_CLEAR_BROWSING_DATA, IDS_CLEAR_BROWSING_DATA); 205 206 AddSeparator(ui::NORMAL_SEPARATOR); 207 208#if !defined(OS_CHROMEOS) 209 // Show IDC_FEEDBACK in "Tools" menu for non-ChromeOS platforms. 210 if (!chrome::UseAlternateSendFeedbackLocation()) { 211 AddItemWithStringId(IDC_FEEDBACK, 212 chrome::GetSendFeedbackMenuLabelID()); 213 AddSeparator(ui::NORMAL_SEPARATOR); 214 } 215#else 216 if (chrome::UseAlternateSendFeedbackLocation()) { 217 AddItemWithStringId(IDC_FEEDBACK, 218 chrome::GetSendFeedbackMenuLabelID()); 219 AddSeparator(ui::NORMAL_SEPARATOR); 220 } 221#endif 222 223 encoding_menu_model_.reset(new EncodingMenuModel(browser)); 224 AddSubMenuWithStringId(IDC_ENCODING_MENU, IDS_ENCODING_MENU, 225 encoding_menu_model_.get()); 226 AddItemWithStringId(IDC_VIEW_SOURCE, IDS_VIEW_SOURCE); 227 AddItemWithStringId(IDC_DEV_TOOLS, IDS_DEV_TOOLS); 228 AddItemWithStringId(IDC_DEV_TOOLS_CONSOLE, IDS_DEV_TOOLS_CONSOLE); 229 230#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC) 231 AddSeparator(ui::NORMAL_SEPARATOR); 232 AddCheckItemWithStringId(IDC_PROFILING_ENABLED, IDS_PROFILING_ENABLED); 233#endif 234} 235 236//////////////////////////////////////////////////////////////////////////////// 237// WrenchMenuModel 238 239WrenchMenuModel::WrenchMenuModel(ui::AcceleratorProvider* provider, 240 Browser* browser, 241 bool is_new_menu) 242 : ui::SimpleMenuModel(this), 243 provider_(provider), 244 browser_(browser), 245 tab_strip_model_(browser_->tab_strip_model()), 246 zoom_callback_(base::Bind(&WrenchMenuModel::OnZoomLevelChanged, 247 base::Unretained(this))) { 248 Build(is_new_menu); 249 UpdateZoomControls(); 250 251 HostZoomMap::GetForBrowserContext( 252 browser->profile())->AddZoomLevelChangedCallback(zoom_callback_); 253 254 tab_strip_model_->AddObserver(this); 255 256 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, 257 content::NotificationService::AllSources()); 258} 259 260WrenchMenuModel::~WrenchMenuModel() { 261 if (tab_strip_model_) 262 tab_strip_model_->RemoveObserver(this); 263 264 if (browser()) { 265 HostZoomMap::GetForBrowserContext( 266 browser()->profile())->RemoveZoomLevelChangedCallback(zoom_callback_); 267 } 268} 269 270bool WrenchMenuModel::DoesCommandIdDismissMenu(int command_id) const { 271 return command_id != IDC_ZOOM_MINUS && command_id != IDC_ZOOM_PLUS; 272} 273 274bool WrenchMenuModel::IsItemForCommandIdDynamic(int command_id) const { 275 return command_id == IDC_ZOOM_PERCENT_DISPLAY || 276#if defined(OS_MACOSX) 277 command_id == IDC_FULLSCREEN || 278#elif defined(OS_WIN) 279 command_id == IDC_PIN_TO_START_SCREEN || 280#endif 281 command_id == IDC_VIEW_BACKGROUND_PAGES || 282 command_id == IDC_UPGRADE_DIALOG || 283 command_id == IDC_SHOW_SIGNIN; 284} 285 286string16 WrenchMenuModel::GetLabelForCommandId(int command_id) const { 287 switch (command_id) { 288 case IDC_ZOOM_PERCENT_DISPLAY: 289 return zoom_label_; 290#if defined(OS_MACOSX) 291 case IDC_FULLSCREEN: { 292 int string_id = IDS_ENTER_FULLSCREEN_MAC; // Default to Enter. 293 // Note: On startup, |window()| may be NULL. 294 if (browser_->window() && browser_->window()->IsFullscreen()) 295 string_id = IDS_EXIT_FULLSCREEN_MAC; 296 return l10n_util::GetStringUTF16(string_id); 297 } 298#elif defined(OS_WIN) 299 case IDC_PIN_TO_START_SCREEN: { 300 int string_id = IDS_PIN_TO_START_SCREEN; 301 WebContents* web_contents = 302 browser_->tab_strip_model()->GetActiveWebContents(); 303 MetroPinTabHelper* tab_helper = 304 web_contents ? MetroPinTabHelper::FromWebContents(web_contents) 305 : NULL; 306 if (tab_helper && tab_helper->IsPinned()) 307 string_id = IDS_UNPIN_FROM_START_SCREEN; 308 return l10n_util::GetStringUTF16(string_id); 309 } 310#endif 311 case IDC_VIEW_BACKGROUND_PAGES: { 312 string16 num_background_pages = base::FormatNumber( 313 TaskManager::GetBackgroundPageCount()); 314 return l10n_util::GetStringFUTF16(IDS_VIEW_BACKGROUND_PAGES, 315 num_background_pages); 316 } 317 case IDC_UPGRADE_DIALOG: 318 return GetUpgradeDialogMenuItemName(); 319 case IDC_SHOW_SIGNIN: 320 return signin_ui_util::GetSigninMenuLabel( 321 browser_->profile()->GetOriginalProfile()); 322 default: 323 NOTREACHED(); 324 return string16(); 325 } 326} 327 328bool WrenchMenuModel::GetIconForCommandId(int command_id, 329 gfx::Image* icon) const { 330 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 331 switch (command_id) { 332 case IDC_UPGRADE_DIALOG: { 333 if (UpgradeDetector::GetInstance()->notify_upgrade()) { 334 *icon = rb.GetNativeImageNamed( 335 UpgradeDetector::GetInstance()->GetIconResourceID( 336 UpgradeDetector::UPGRADE_ICON_TYPE_MENU_ICON)); 337 return true; 338 } 339 return false; 340 } 341 case IDC_SHOW_SIGNIN: { 342 GlobalError* error = signin_ui_util::GetSignedInServiceError( 343 browser_->profile()->GetOriginalProfile()); 344 if (error) { 345 int icon_id = error->MenuItemIconResourceID(); 346 if (icon_id) { 347 *icon = rb.GetNativeImageNamed(icon_id); 348 return true; 349 } 350 } 351 return false; 352 } 353 default: 354 break; 355 } 356 return false; 357} 358 359void WrenchMenuModel::ExecuteCommand(int command_id, int event_flags) { 360 GlobalError* error = GlobalErrorServiceFactory::GetForProfile( 361 browser_->profile())->GetGlobalErrorByMenuItemCommandID(command_id); 362 if (error) { 363 error->ExecuteMenuItem(browser_); 364 return; 365 } 366 367 if (command_id == IDC_SHOW_SIGNIN) { 368 // If a custom error message is being shown, handle it. 369 GlobalError* error = signin_ui_util::GetSignedInServiceError( 370 browser_->profile()->GetOriginalProfile()); 371 if (error) { 372 error->ExecuteMenuItem(browser_); 373 return; 374 } 375 } 376 377 if (command_id == IDC_HELP_PAGE_VIA_MENU) 378 content::RecordAction(UserMetricsAction("ShowHelpTabViaWrenchMenu")); 379 380 if (command_id == IDC_FULLSCREEN) { 381 // We issue the UMA command here and not in BrowserCommandController or even 382 // FullscreenController since we want to be able to distinguish this event 383 // and a menu which is under development. 384 content::RecordAction(UserMetricsAction("EnterFullScreenWithWrenchMenu")); 385 } 386 387 chrome::ExecuteCommand(browser_, command_id); 388} 389 390bool WrenchMenuModel::IsCommandIdChecked(int command_id) const { 391 if (command_id == IDC_SHOW_BOOKMARK_BAR) { 392 return browser_->profile()->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar); 393 } else if (command_id == IDC_PROFILING_ENABLED) { 394 return Profiling::BeingProfiled(); 395 } else if (command_id == IDC_TOGGLE_REQUEST_TABLET_SITE) { 396 return chrome::IsRequestingTabletSite(browser_); 397 } 398 399 return false; 400} 401 402bool WrenchMenuModel::IsCommandIdEnabled(int command_id) const { 403 GlobalError* error = GlobalErrorServiceFactory::GetForProfile( 404 browser_->profile())->GetGlobalErrorByMenuItemCommandID(command_id); 405 if (error) 406 return true; 407 408 return chrome::IsCommandEnabled(browser_, command_id); 409} 410 411bool WrenchMenuModel::IsCommandIdVisible(int command_id) const { 412#if defined(OS_WIN) 413 if (command_id == IDC_VIEW_INCOMPATIBILITIES) { 414 EnumerateModulesModel* loaded_modules = 415 EnumerateModulesModel::GetInstance(); 416 if (loaded_modules->confirmed_bad_modules_detected() <= 0) 417 return false; 418 loaded_modules->AcknowledgeConflictNotification(); 419 return true; 420 } else if (command_id == IDC_PIN_TO_START_SCREEN) { 421 return base::win::IsMetroProcess(); 422#else 423 if (command_id == IDC_VIEW_INCOMPATIBILITIES || 424 command_id == IDC_PIN_TO_START_SCREEN) { 425 return false; 426#endif 427 } else if (command_id == IDC_UPGRADE_DIALOG) { 428 return UpgradeDetector::GetInstance()->notify_upgrade(); 429 } else if (command_id == IDC_VIEW_BACKGROUND_PAGES) { 430 return TaskManager::GetBackgroundPageCount() > 0; 431 } 432 return true; 433} 434 435bool WrenchMenuModel::GetAcceleratorForCommandId( 436 int command_id, 437 ui::Accelerator* accelerator) { 438 return provider_->GetAcceleratorForCommandId(command_id, accelerator); 439} 440 441void WrenchMenuModel::ActiveTabChanged(WebContents* old_contents, 442 WebContents* new_contents, 443 int index, 444 int reason) { 445 // The user has switched between tabs and the new tab may have a different 446 // zoom setting. 447 UpdateZoomControls(); 448} 449 450void WrenchMenuModel::TabReplacedAt(TabStripModel* tab_strip_model, 451 WebContents* old_contents, 452 WebContents* new_contents, 453 int index) { 454 UpdateZoomControls(); 455} 456 457void WrenchMenuModel::TabStripModelDeleted() { 458 // During views shutdown, the tabstrip model/browser is deleted first, while 459 // it is the opposite in gtk land. 460 tab_strip_model_->RemoveObserver(this); 461 tab_strip_model_ = NULL; 462} 463 464void WrenchMenuModel::Observe(int type, 465 const content::NotificationSource& source, 466 const content::NotificationDetails& details) { 467 DCHECK(type == content::NOTIFICATION_NAV_ENTRY_COMMITTED); 468 UpdateZoomControls(); 469} 470 471// For testing. 472WrenchMenuModel::WrenchMenuModel() 473 : ui::SimpleMenuModel(this), 474 provider_(NULL), 475 browser_(NULL), 476 tab_strip_model_(NULL) { 477} 478 479void WrenchMenuModel::Build(bool is_new_menu) { 480 AddItemWithStringId(IDC_NEW_TAB, IDS_NEW_TAB); 481#if defined(OS_WIN) 482 if (win8::IsSingleWindowMetroMode()) { 483 // In Win8's single window Metro mode, we only show the New Window options 484 // if there isn't already a window of the requested type (incognito or not) 485 // that is available. 486 if (browser_->profile()->IsOffTheRecord()) { 487 if (chrome::FindBrowserWithProfile( 488 browser_->profile()->GetOriginalProfile(), 489 browser_->host_desktop_type()) == NULL) { 490 AddItemWithStringId(IDC_NEW_WINDOW, IDS_NEW_WINDOW); 491 } 492 } else if (!browser_->profile()->HasOffTheRecordProfile()) { 493 AddItemWithStringId(IDC_NEW_INCOGNITO_WINDOW, IDS_NEW_INCOGNITO_WINDOW); 494 } 495 } else { 496 AddItemWithStringId(IDC_NEW_WINDOW, IDS_NEW_WINDOW); 497 AddItemWithStringId(IDC_NEW_INCOGNITO_WINDOW, IDS_NEW_INCOGNITO_WINDOW); 498 } 499#if !defined(NDEBUG) && defined(USE_ASH) 500 if (base::win::GetVersion() < base::win::VERSION_WIN8 && 501 chrome::HOST_DESKTOP_TYPE_NATIVE != chrome::HOST_DESKTOP_TYPE_ASH) { 502 AddItemWithStringId(IDC_TOGGLE_ASH_DESKTOP, 503 ash::Shell::HasInstance() ? IDS_CLOSE_ASH_DESKTOP : 504 IDS_OPEN_ASH_DESKTOP); 505 } 506#endif 507#else // defined(OS_WIN) 508 AddItemWithStringId(IDC_NEW_WINDOW, IDS_NEW_WINDOW); 509#if defined(OS_CHROMEOS) 510 if (!CommandLine::ForCurrentProcess()->HasSwitch( 511 chromeos::switches::kGuestSession)) 512 AddItemWithStringId(IDC_NEW_INCOGNITO_WINDOW, IDS_NEW_INCOGNITO_WINDOW); 513#else 514 AddItemWithStringId(IDC_NEW_INCOGNITO_WINDOW, IDS_NEW_INCOGNITO_WINDOW); 515#endif 516 517#endif // else of defined(OS_WIN) 518 519 bookmark_sub_menu_model_.reset(new BookmarkSubMenuModel(this, browser_)); 520 AddSubMenuWithStringId(IDC_BOOKMARKS_MENU, IDS_BOOKMARKS_MENU, 521 bookmark_sub_menu_model_.get()); 522 523 if (chrome::IsInstantExtendedAPIEnabled()) { 524 recent_tabs_sub_menu_model_.reset(new RecentTabsSubMenuModel(provider_, 525 browser_, 526 NULL)); 527 AddSubMenuWithStringId(IDC_RECENT_TABS_MENU, IDS_RECENT_TABS_MENU, 528 recent_tabs_sub_menu_model_.get()); 529 } 530 531#if defined(OS_WIN) && !defined(USE_ASH) 532 if (base::win::IsMetroProcess()) { 533 // Metro mode, add the 'Relaunch Chrome in desktop mode'. 534 AddSeparator(ui::SPACING_SEPARATOR); 535 AddItemWithStringId(IDC_WIN8_DESKTOP_RESTART, IDS_WIN8_DESKTOP_RESTART); 536 } else if (base::win::GetVersion() >= base::win::VERSION_WIN8) { 537 // In Windows 8 desktop, add the 'Relaunch Chrome in Windows 8 mode'. 538 AddSeparator(ui::SPACING_SEPARATOR); 539 AddItemWithStringId(IDC_WIN8_METRO_RESTART, IDS_WIN8_METRO_RESTART); 540 } 541#endif 542 543 // Append the full menu including separators. The final separator only gets 544 // appended when this is a touch menu - otherwise it would get added twice. 545 CreateCutCopyPasteMenu(is_new_menu); 546 547 if (!is_new_menu) 548 CreateZoomMenu(is_new_menu); 549 550 AddItemWithStringId(IDC_SAVE_PAGE, IDS_SAVE_PAGE); 551 AddItemWithStringId(IDC_FIND, IDS_FIND); 552 AddItemWithStringId(IDC_PRINT, IDS_PRINT); 553 554 tools_menu_model_.reset(new ToolsMenuModel(this, browser_)); 555 // In case of touch this is the last item. 556 if (!is_new_menu) { 557 AddSubMenuWithStringId(IDC_ZOOM_MENU, IDS_TOOLS_MENU, 558 tools_menu_model_.get()); 559 } 560 561 if (is_new_menu) 562 CreateZoomMenu(is_new_menu); 563 else 564 AddSeparator(ui::NORMAL_SEPARATOR); 565 566 AddItemWithStringId(IDC_SHOW_HISTORY, IDS_SHOW_HISTORY); 567 AddItemWithStringId(IDC_SHOW_DOWNLOADS, IDS_SHOW_DOWNLOADS); 568 AddSeparator(ui::NORMAL_SEPARATOR); 569 570#if !defined(OS_CHROMEOS) 571 // No "Sign in to Chromium..." menu item on ChromeOS. 572 SigninManager* signin = SigninManagerFactory::GetForProfile( 573 browser_->profile()->GetOriginalProfile()); 574 if (signin && signin->IsSigninAllowed()) { 575 const string16 short_product_name = 576 l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME); 577 AddItem(IDC_SHOW_SYNC_SETUP, l10n_util::GetStringFUTF16( 578 IDS_SYNC_MENU_PRE_SYNCED_LABEL, short_product_name)); 579 AddSeparator(ui::NORMAL_SEPARATOR); 580 } 581#endif 582 583 AddItemWithStringId(IDC_OPTIONS, IDS_SETTINGS); 584 585#if defined(OS_CHROMEOS) 586 if (CommandLine::ForCurrentProcess()->HasSwitch( 587 switches::kEnableRequestTabletSite)) 588 AddCheckItemWithStringId(IDC_TOGGLE_REQUEST_TABLET_SITE, 589 IDS_TOGGLE_REQUEST_TABLET_SITE); 590#endif 591 592// On ChromeOS-Touch, we don't want the about/background pages menu options. 593#if defined(OS_CHROMEOS) 594 if (!is_new_menu) 595#endif 596 { 597 AddItem(IDC_ABOUT, l10n_util::GetStringUTF16(IDS_ABOUT)); 598 // We use the task manager to show background pages. 599 if (chrome::CanOpenTaskManager()) { 600 string16 num_background_pages = base::FormatNumber( 601 TaskManager::GetBackgroundPageCount()); 602 AddItem(IDC_VIEW_BACKGROUND_PAGES, l10n_util::GetStringFUTF16( 603 IDS_VIEW_BACKGROUND_PAGES, num_background_pages)); 604 } 605 } 606 607 if (browser_defaults::kShowUpgradeMenuItem) 608 AddItem(IDC_UPGRADE_DIALOG, GetUpgradeDialogMenuItemName()); 609 610 AddItem(IDC_VIEW_INCOMPATIBILITIES, l10n_util::GetStringUTF16( 611 IDS_VIEW_INCOMPATIBILITIES)); 612 613#if defined(OS_WIN) 614 SetIcon(GetIndexOfCommandId(IDC_VIEW_INCOMPATIBILITIES), 615 ui::ResourceBundle::GetSharedInstance(). 616 GetNativeImageNamed(IDR_INPUT_ALERT_MENU)); 617#endif 618 619 if (!is_new_menu) { 620 AddItemWithStringId(IDC_HELP_PAGE_VIA_MENU, IDS_HELP_PAGE); 621 622 if (browser_defaults::kShowHelpMenuItemIcon) { 623 ui::ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 624 SetIcon(GetIndexOfCommandId(IDC_HELP_PAGE_VIA_MENU), 625 rb.GetNativeImageNamed(IDR_HELP_MENU)); 626 } 627 } 628 629 if (browser_defaults::kShowFeedbackMenuItem && 630 !chrome::UseAlternateSendFeedbackLocation()) { 631 AddItemWithStringId(IDC_FEEDBACK, 632 chrome::GetSendFeedbackMenuLabelID()); 633 } 634 635 AddGlobalErrorMenuItems(); 636 637 if (is_new_menu) { 638 AddSubMenuWithStringId(IDC_ZOOM_MENU, IDS_MORE_TOOLS_MENU, 639 tools_menu_model_.get()); 640 } 641 642#if !defined(OS_CHROMEOS) 643 // For Send Feedback Link experiment (crbug.com/169339). 644 if (chrome::UseAlternateSendFeedbackLocation()) 645 AddItemWithStringId(IDC_FEEDBACK, 646 chrome::GetSendFeedbackMenuLabelID()); 647#endif 648 649 bool show_exit_menu = browser_defaults::kShowExitMenuItem; 650#if defined(OS_WIN) && defined(USE_AURA) 651 if (browser_->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH) 652 show_exit_menu = false; 653#endif 654 655 if (show_exit_menu) { 656 AddSeparator(ui::NORMAL_SEPARATOR); 657 AddItemWithStringId(IDC_EXIT, IDS_EXIT); 658 } 659} 660 661void WrenchMenuModel::AddGlobalErrorMenuItems() { 662 // TODO(sail): Currently we only build the wrench menu once per browser 663 // window. This means that if a new error is added after the menu is built 664 // it won't show in the existing wrench menu. To fix this we need to some 665 // how update the menu if new errors are added. 666 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 667 const GlobalErrorService::GlobalErrorList& errors = 668 GlobalErrorServiceFactory::GetForProfile(browser_->profile())->errors(); 669 for (GlobalErrorService::GlobalErrorList::const_iterator 670 it = errors.begin(); it != errors.end(); ++it) { 671 GlobalError* error = *it; 672 if (error->HasMenuItem()) { 673 // Don't add a signin error if it's already being displayed elsewhere. 674#if !defined(OS_CHROMEOS) 675 if (error == signin_ui_util::GetSignedInServiceError( 676 browser_->profile()->GetOriginalProfile())) { 677 MenuModel* model = this; 678 int index = 0; 679 if (MenuModel::GetModelAndIndexForCommandId( 680 IDC_SHOW_SIGNIN, &model, &index)) { 681 continue; 682 } 683 } 684#endif 685 686 AddItem(error->MenuItemCommandID(), error->MenuItemLabel()); 687 int icon_id = error->MenuItemIconResourceID(); 688 if (icon_id) { 689 const gfx::Image& image = rb.GetNativeImageNamed(icon_id); 690 SetIcon(GetIndexOfCommandId(error->MenuItemCommandID()), 691 image); 692 } 693 } 694 } 695} 696 697void WrenchMenuModel::CreateCutCopyPasteMenu(bool new_menu) { 698 AddSeparator(new_menu ? ui::LOWER_SEPARATOR : ui::NORMAL_SEPARATOR); 699 700#if defined(OS_POSIX) && !defined(TOOLKIT_VIEWS) 701 // WARNING: Mac does not use the ButtonMenuItemModel, but instead defines the 702 // layout for this menu item in Toolbar.xib. It does, however, use the 703 // command_id value from AddButtonItem() to identify this special item. 704 edit_menu_item_model_.reset(new ui::ButtonMenuItemModel(IDS_EDIT, this)); 705 edit_menu_item_model_->AddGroupItemWithStringId(IDC_CUT, IDS_CUT); 706 edit_menu_item_model_->AddGroupItemWithStringId(IDC_COPY, IDS_COPY); 707 edit_menu_item_model_->AddGroupItemWithStringId(IDC_PASTE, IDS_PASTE); 708 AddButtonItem(IDC_EDIT_MENU, edit_menu_item_model_.get()); 709#else 710 // WARNING: views/wrench_menu assumes these items are added in this order. If 711 // you change the order you'll need to update wrench_menu as well. 712 AddItemWithStringId(IDC_CUT, IDS_CUT); 713 AddItemWithStringId(IDC_COPY, IDS_COPY); 714 AddItemWithStringId(IDC_PASTE, IDS_PASTE); 715#endif 716 717 if (new_menu) 718 AddSeparator(ui::UPPER_SEPARATOR); 719} 720 721void WrenchMenuModel::CreateZoomMenu(bool new_menu) { 722 // This menu needs to be enclosed by separators. 723 AddSeparator(new_menu ? ui::LOWER_SEPARATOR : ui::NORMAL_SEPARATOR); 724 725#if defined(OS_POSIX) && !defined(TOOLKIT_VIEWS) 726 // WARNING: Mac does not use the ButtonMenuItemModel, but instead defines the 727 // layout for this menu item in Toolbar.xib. It does, however, use the 728 // command_id value from AddButtonItem() to identify this special item. 729 zoom_menu_item_model_.reset( 730 new ui::ButtonMenuItemModel(IDS_ZOOM_MENU, this)); 731 zoom_menu_item_model_->AddGroupItemWithStringId( 732 IDC_ZOOM_MINUS, IDS_ZOOM_MINUS2); 733 zoom_menu_item_model_->AddButtonLabel(IDC_ZOOM_PERCENT_DISPLAY, 734 IDS_ZOOM_PLUS2); 735 zoom_menu_item_model_->AddGroupItemWithStringId( 736 IDC_ZOOM_PLUS, IDS_ZOOM_PLUS2); 737 zoom_menu_item_model_->AddSpace(); 738 zoom_menu_item_model_->AddItemWithImage( 739 IDC_FULLSCREEN, IDR_FULLSCREEN_MENU_BUTTON); 740 AddButtonItem(IDC_ZOOM_MENU, zoom_menu_item_model_.get()); 741#else 742 // WARNING: views/wrench_menu assumes these items are added in this order. If 743 // you change the order you'll need to update wrench_menu as well. 744 AddItemWithStringId(IDC_ZOOM_MINUS, IDS_ZOOM_MINUS); 745 AddItemWithStringId(IDC_ZOOM_PLUS, IDS_ZOOM_PLUS); 746 AddItemWithStringId(IDC_FULLSCREEN, IDS_FULLSCREEN); 747#endif 748 749 AddSeparator(new_menu ? ui::UPPER_SEPARATOR : ui::NORMAL_SEPARATOR); 750} 751 752void WrenchMenuModel::UpdateZoomControls() { 753 bool enable_increment = false; 754 bool enable_decrement = false; 755 int zoom_percent = 100; 756 if (browser_->tab_strip_model()->GetActiveWebContents()) { 757 zoom_percent = 758 browser_->tab_strip_model()->GetActiveWebContents()->GetZoomPercent( 759 &enable_increment, &enable_decrement); 760 } 761 zoom_label_ = l10n_util::GetStringFUTF16( 762 IDS_ZOOM_PERCENT, base::IntToString16(zoom_percent)); 763} 764 765void WrenchMenuModel::OnZoomLevelChanged( 766 const content::HostZoomMap::ZoomLevelChange& change) { 767 UpdateZoomControls(); 768} 769