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