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.
5 #include "chrome/browser/ui/toolbar/wrench_menu_model.h"
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_factory.h"
22 #include "chrome/browser/signin/signin_ui_util.h"
23 #include "chrome/browser/task_manager/task_manager.h"
24 #include "chrome/browser/ui/bookmarks/bookmark_utils.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 "components/signin/core/browser/signin_manager.h"
42 #include "components/signin/core/common/profile_management_switches.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"
60 #if defined(OS_CHROMEOS)
61 #include "chromeos/chromeos_switches.h"
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 "content/public/browser/gpu_data_manager.h"
73 #include "ash/shell.h"
76 using base::UserMetricsAction;
77 using content::HostZoomMap;
78 using content::WebContents;
81 // Conditionally return the update app menu item title based on upgrade detector
83 base::string16 GetUpgradeDialogMenuItemName() {
84 if (UpgradeDetector::GetInstance()->is_outdated_install() ||
85 UpgradeDetector::GetInstance()->is_outdated_install_no_au()) {
86 return l10n_util::GetStringUTF16(IDS_UPGRADE_BUBBLE_MENU_ITEM);
88 return l10n_util::GetStringUTF16(IDS_UPDATE_NOW);
94 ////////////////////////////////////////////////////////////////////////////////
97 EncodingMenuModel::EncodingMenuModel(Browser* browser)
98 : ui::SimpleMenuModel(this),
103 EncodingMenuModel::~EncodingMenuModel() {
106 void EncodingMenuModel::Build() {
107 EncodingMenuController::EncodingMenuItemList encoding_menu_items;
108 EncodingMenuController encoding_menu_controller;
109 encoding_menu_controller.GetEncodingMenuItems(browser_->profile(),
110 &encoding_menu_items);
113 EncodingMenuController::EncodingMenuItemList::iterator it =
114 encoding_menu_items.begin();
115 for (; it != encoding_menu_items.end(); ++it) {
117 base::string16& label = it->second;
119 AddSeparator(ui::NORMAL_SEPARATOR);
121 if (id == IDC_ENCODING_AUTO_DETECT) {
122 AddCheckItem(id, label);
124 // Use the id of the first radio command as the id of the group.
127 AddRadioItem(id, label, group_id);
133 bool EncodingMenuModel::IsCommandIdChecked(int command_id) const {
134 WebContents* current_tab =
135 browser_->tab_strip_model()->GetActiveWebContents();
138 EncodingMenuController controller;
139 return controller.IsItemChecked(browser_->profile(),
140 current_tab->GetEncoding(), command_id);
143 bool 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);
154 bool EncodingMenuModel::GetAcceleratorForCommandId(
156 ui::Accelerator* accelerator) {
160 void EncodingMenuModel::ExecuteCommand(int command_id, int event_flags) {
161 chrome::ExecuteCommand(browser_, command_id);
164 ////////////////////////////////////////////////////////////////////////////////
167 ZoomMenuModel::ZoomMenuModel(ui::SimpleMenuModel::Delegate* delegate)
168 : SimpleMenuModel(delegate) {
172 ZoomMenuModel::~ZoomMenuModel() {
175 void 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);
181 ////////////////////////////////////////////////////////////////////////////////
184 #if defined(GOOGLE_CHROME_BUILD)
186 class WrenchMenuModel::HelpMenuModel : public ui::SimpleMenuModel {
188 HelpMenuModel(ui::SimpleMenuModel::Delegate* delegate,
190 : SimpleMenuModel(delegate) {
193 virtual ~HelpMenuModel() {
197 void Build(Browser* browser) {
198 int help_string_id = IDS_HELP_PAGE;
199 #if defined(OS_CHROMEOS) && defined(OFFICIAL_BUILD)
200 if (!CommandLine::ForCurrentProcess()->HasSwitch(
201 chromeos::switches::kDisableGeniusApp)) {
202 help_string_id = IDS_GET_HELP;
205 AddItemWithStringId(IDC_HELP_PAGE_VIA_MENU, help_string_id);
206 if (browser_defaults::kShowHelpMenuItemIcon) {
207 ui::ResourceBundle& rb = ResourceBundle::GetSharedInstance();
208 SetIcon(GetIndexOfCommandId(IDC_HELP_PAGE_VIA_MENU),
209 rb.GetNativeImageNamed(IDR_HELP_MENU));
212 AddItemWithStringId(IDC_FEEDBACK, IDS_FEEDBACK);
215 DISALLOW_COPY_AND_ASSIGN(HelpMenuModel);
218 #endif // defined(GOOGLE_CHROME_BUILD)
220 ////////////////////////////////////////////////////////////////////////////////
223 ToolsMenuModel::ToolsMenuModel(ui::SimpleMenuModel::Delegate* delegate,
225 : SimpleMenuModel(delegate) {
229 ToolsMenuModel::~ToolsMenuModel() {}
231 void ToolsMenuModel::Build(Browser* browser) {
232 bool show_create_shortcuts = true;
233 #if defined(OS_CHROMEOS) || defined(OS_MACOSX)
234 show_create_shortcuts = false;
235 #elif defined(USE_ASH)
236 if (browser->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH)
237 show_create_shortcuts = false;
240 if (CommandLine::ForCurrentProcess()->HasSwitch(
241 switches::kEnableStreamlinedHostedApps)) {
242 AddItemWithStringId(IDC_CREATE_HOSTED_APP, IDS_CREATE_HOSTED_APP);
243 AddSeparator(ui::NORMAL_SEPARATOR);
244 } else if (show_create_shortcuts) {
245 AddItemWithStringId(IDC_CREATE_SHORTCUTS, IDS_CREATE_SHORTCUTS);
246 AddSeparator(ui::NORMAL_SEPARATOR);
249 AddItemWithStringId(IDC_MANAGE_EXTENSIONS, IDS_SHOW_EXTENSIONS);
251 if (chrome::CanOpenTaskManager())
252 AddItemWithStringId(IDC_TASK_MANAGER, IDS_TASK_MANAGER);
254 AddItemWithStringId(IDC_CLEAR_BROWSING_DATA, IDS_CLEAR_BROWSING_DATA);
256 AddSeparator(ui::NORMAL_SEPARATOR);
258 encoding_menu_model_.reset(new EncodingMenuModel(browser));
259 AddSubMenuWithStringId(IDC_ENCODING_MENU, IDS_ENCODING_MENU,
260 encoding_menu_model_.get());
261 AddItemWithStringId(IDC_VIEW_SOURCE, IDS_VIEW_SOURCE);
262 AddItemWithStringId(IDC_DEV_TOOLS, IDS_DEV_TOOLS);
263 AddItemWithStringId(IDC_DEV_TOOLS_CONSOLE, IDS_DEV_TOOLS_CONSOLE);
264 AddItemWithStringId(IDC_DEV_TOOLS_DEVICES, IDS_DEV_TOOLS_DEVICES);
266 #if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC)
267 AddSeparator(ui::NORMAL_SEPARATOR);
268 AddCheckItemWithStringId(IDC_PROFILING_ENABLED, IDS_PROFILING_ENABLED);
272 ////////////////////////////////////////////////////////////////////////////////
275 WrenchMenuModel::WrenchMenuModel(ui::AcceleratorProvider* provider,
278 : ui::SimpleMenuModel(this),
281 tab_strip_model_(browser_->tab_strip_model()) {
283 UpdateZoomControls();
285 zoom_subscription_ = HostZoomMap::GetForBrowserContext(
286 browser->profile())->AddZoomLevelChangedCallback(
287 base::Bind(&WrenchMenuModel::OnZoomLevelChanged,
288 base::Unretained(this)));
290 tab_strip_model_->AddObserver(this);
292 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
293 content::NotificationService::AllSources());
296 WrenchMenuModel::~WrenchMenuModel() {
297 if (tab_strip_model_)
298 tab_strip_model_->RemoveObserver(this);
301 bool WrenchMenuModel::DoesCommandIdDismissMenu(int command_id) const {
302 return command_id != IDC_ZOOM_MINUS && command_id != IDC_ZOOM_PLUS;
305 bool WrenchMenuModel::IsItemForCommandIdDynamic(int command_id) const {
306 return command_id == IDC_ZOOM_PERCENT_DISPLAY ||
307 #if defined(OS_MACOSX)
308 command_id == IDC_FULLSCREEN ||
309 #elif defined(OS_WIN)
310 command_id == IDC_PIN_TO_START_SCREEN ||
312 command_id == IDC_UPGRADE_DIALOG ||
313 (!switches::IsNewProfileManagement() && command_id == IDC_SHOW_SIGNIN);
316 base::string16 WrenchMenuModel::GetLabelForCommandId(int command_id) const {
317 switch (command_id) {
318 case IDC_ZOOM_PERCENT_DISPLAY:
320 #if defined(OS_MACOSX)
321 case IDC_FULLSCREEN: {
322 int string_id = IDS_ENTER_FULLSCREEN_MAC; // Default to Enter.
323 // Note: On startup, |window()| may be NULL.
324 if (browser_->window() && browser_->window()->IsFullscreen())
325 string_id = IDS_EXIT_FULLSCREEN_MAC;
326 return l10n_util::GetStringUTF16(string_id);
328 #elif defined(OS_WIN)
329 case IDC_PIN_TO_START_SCREEN: {
330 int string_id = IDS_PIN_TO_START_SCREEN;
331 WebContents* web_contents =
332 browser_->tab_strip_model()->GetActiveWebContents();
333 MetroPinTabHelper* tab_helper =
334 web_contents ? MetroPinTabHelper::FromWebContents(web_contents)
336 if (tab_helper && tab_helper->IsPinned())
337 string_id = IDS_UNPIN_FROM_START_SCREEN;
338 return l10n_util::GetStringUTF16(string_id);
341 case IDC_UPGRADE_DIALOG:
342 return GetUpgradeDialogMenuItemName();
343 case IDC_SHOW_SIGNIN:
344 DCHECK(!switches::IsNewProfileManagement());
345 return signin_ui_util::GetSigninMenuLabel(
346 browser_->profile()->GetOriginalProfile());
349 return base::string16();
353 bool WrenchMenuModel::GetIconForCommandId(int command_id,
354 gfx::Image* icon) const {
355 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
356 switch (command_id) {
357 case IDC_UPGRADE_DIALOG: {
358 if (UpgradeDetector::GetInstance()->notify_upgrade()) {
359 *icon = rb.GetNativeImageNamed(
360 UpgradeDetector::GetInstance()->GetIconResourceID(
361 UpgradeDetector::UPGRADE_ICON_TYPE_MENU_ICON));
366 case IDC_SHOW_SIGNIN: {
367 DCHECK(!switches::IsNewProfileManagement());
368 GlobalError* error = signin_ui_util::GetSignedInServiceError(
369 browser_->profile()->GetOriginalProfile());
371 int icon_id = error->MenuItemIconResourceID();
373 *icon = rb.GetNativeImageNamed(icon_id);
385 void WrenchMenuModel::ExecuteCommand(int command_id, int event_flags) {
386 GlobalError* error = GlobalErrorServiceFactory::GetForProfile(
387 browser_->profile())->GetGlobalErrorByMenuItemCommandID(command_id);
389 error->ExecuteMenuItem(browser_);
393 if (!switches::IsNewProfileManagement() && command_id == IDC_SHOW_SIGNIN) {
394 // If a custom error message is being shown, handle it.
395 GlobalError* error = signin_ui_util::GetSignedInServiceError(
396 browser_->profile()->GetOriginalProfile());
398 error->ExecuteMenuItem(browser_);
403 if (command_id == IDC_HELP_PAGE_VIA_MENU)
404 content::RecordAction(UserMetricsAction("ShowHelpTabViaWrenchMenu"));
406 if (command_id == IDC_FULLSCREEN) {
407 // We issue the UMA command here and not in BrowserCommandController or even
408 // FullscreenController since we want to be able to distinguish this event
409 // and a menu which is under development.
410 content::RecordAction(UserMetricsAction("EnterFullScreenWithWrenchMenu"));
413 chrome::ExecuteCommand(browser_, command_id);
416 bool WrenchMenuModel::IsCommandIdChecked(int command_id) const {
417 if (command_id == IDC_SHOW_BOOKMARK_BAR) {
418 return browser_->profile()->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar);
419 } else if (command_id == IDC_PROFILING_ENABLED) {
420 return Profiling::BeingProfiled();
421 } else if (command_id == IDC_TOGGLE_REQUEST_TABLET_SITE) {
422 return chrome::IsRequestingTabletSite(browser_);
428 bool WrenchMenuModel::IsCommandIdEnabled(int command_id) const {
429 GlobalError* error = GlobalErrorServiceFactory::GetForProfile(
430 browser_->profile())->GetGlobalErrorByMenuItemCommandID(command_id);
434 return chrome::IsCommandEnabled(browser_, command_id);
437 bool WrenchMenuModel::IsCommandIdVisible(int command_id) const {
438 switch (command_id) {
440 case IDC_VIEW_INCOMPATIBILITIES: {
441 EnumerateModulesModel* loaded_modules =
442 EnumerateModulesModel::GetInstance();
443 if (loaded_modules->confirmed_bad_modules_detected() <= 0)
445 // We'll leave the wrench adornment on until the user clicks the link.
446 if (loaded_modules->modules_to_notify_about() <= 0)
447 loaded_modules->AcknowledgeConflictNotification();
450 case IDC_PIN_TO_START_SCREEN:
451 return base::win::IsMetroProcess();
453 case IDC_VIEW_INCOMPATIBILITIES:
454 case IDC_PIN_TO_START_SCREEN:
457 case IDC_UPGRADE_DIALOG:
458 return UpgradeDetector::GetInstance()->notify_upgrade();
459 #if !defined(OS_LINUX) || defined(USE_AURA)
460 case IDC_BOOKMARK_PAGE:
461 return !chrome::ShouldRemoveBookmarkThisPageUI(browser_->profile());
462 case IDC_BOOKMARK_ALL_TABS:
463 return !chrome::ShouldRemoveBookmarkOpenPagesUI(browser_->profile());
470 bool WrenchMenuModel::GetAcceleratorForCommandId(
472 ui::Accelerator* accelerator) {
473 return provider_->GetAcceleratorForCommandId(command_id, accelerator);
476 void WrenchMenuModel::ActiveTabChanged(WebContents* old_contents,
477 WebContents* new_contents,
480 // The user has switched between tabs and the new tab may have a different
482 UpdateZoomControls();
485 void WrenchMenuModel::TabReplacedAt(TabStripModel* tab_strip_model,
486 WebContents* old_contents,
487 WebContents* new_contents,
489 UpdateZoomControls();
492 void WrenchMenuModel::TabStripModelDeleted() {
493 // During views shutdown, the tabstrip model/browser is deleted first, while
494 // it is the opposite in gtk land.
495 tab_strip_model_->RemoveObserver(this);
496 tab_strip_model_ = NULL;
499 void WrenchMenuModel::Observe(int type,
500 const content::NotificationSource& source,
501 const content::NotificationDetails& details) {
502 DCHECK(type == content::NOTIFICATION_NAV_ENTRY_COMMITTED);
503 UpdateZoomControls();
507 WrenchMenuModel::WrenchMenuModel()
508 : ui::SimpleMenuModel(this),
511 tab_strip_model_(NULL) {
514 bool WrenchMenuModel::ShouldShowNewIncognitoWindowMenuItem() {
515 if (browser_->profile()->IsSupervised())
518 return !browser_->profile()->IsGuestSession();
521 void WrenchMenuModel::Build(bool is_new_menu) {
523 AddItem(IDC_VIEW_INCOMPATIBILITIES,
524 l10n_util::GetStringUTF16(IDS_VIEW_INCOMPATIBILITIES));
525 EnumerateModulesModel* model =
526 EnumerateModulesModel::GetInstance();
527 if (model->modules_to_notify_about() > 0 ||
528 model->confirmed_bad_modules_detected() > 0)
529 AddSeparator(ui::NORMAL_SEPARATOR);
532 AddItemWithStringId(IDC_NEW_TAB, IDS_NEW_TAB);
533 AddItemWithStringId(IDC_NEW_WINDOW, IDS_NEW_WINDOW);
535 if (ShouldShowNewIncognitoWindowMenuItem())
536 AddItemWithStringId(IDC_NEW_INCOGNITO_WINDOW, IDS_NEW_INCOGNITO_WINDOW);
538 #if defined(OS_WIN) && !defined(NDEBUG) && defined(USE_ASH)
539 if (base::win::GetVersion() < base::win::VERSION_WIN8 &&
540 chrome::HOST_DESKTOP_TYPE_NATIVE != chrome::HOST_DESKTOP_TYPE_ASH) {
541 AddItemWithStringId(IDC_TOGGLE_ASH_DESKTOP,
542 ash::Shell::HasInstance() ? IDS_CLOSE_ASH_DESKTOP :
543 IDS_OPEN_ASH_DESKTOP);
547 bookmark_sub_menu_model_.reset(new BookmarkSubMenuModel(this, browser_));
548 AddSubMenuWithStringId(IDC_BOOKMARKS_MENU, IDS_BOOKMARKS_MENU,
549 bookmark_sub_menu_model_.get());
551 if (!browser_->profile()->IsOffTheRecord()) {
552 recent_tabs_sub_menu_model_.reset(new RecentTabsSubMenuModel(provider_,
555 AddSubMenuWithStringId(IDC_RECENT_TABS_MENU, IDS_RECENT_TABS_MENU,
556 recent_tabs_sub_menu_model_.get());
561 #if defined(USE_AURA)
562 if (base::win::GetVersion() >= base::win::VERSION_WIN8 &&
563 content::GpuDataManager::GetInstance()->CanUseGpuBrowserCompositor()) {
564 if (browser_->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH) {
565 // Metro mode, add the 'Relaunch Chrome in desktop mode'.
566 AddSeparator(ui::NORMAL_SEPARATOR);
567 AddItemWithStringId(IDC_WIN8_DESKTOP_RESTART, IDS_WIN8_DESKTOP_RESTART);
569 // In Windows 8 desktop, add the 'Relaunch Chrome in Windows 8 mode'.
570 AddSeparator(ui::NORMAL_SEPARATOR);
571 AddItemWithStringId(IDC_WIN8_METRO_RESTART, IDS_WIN8_METRO_RESTART);
575 if (base::win::IsMetroProcess()) {
576 // Metro mode, add the 'Relaunch Chrome in desktop mode'.
577 AddSeparator(ui::NORMAL_SEPARATOR);
578 AddItemWithStringId(IDC_WIN8_DESKTOP_RESTART, IDS_WIN8_DESKTOP_RESTART);
580 // In Windows 8 desktop, add the 'Relaunch Chrome in Windows 8 mode'.
581 AddSeparator(ui::NORMAL_SEPARATOR);
582 AddItemWithStringId(IDC_WIN8_METRO_RESTART, IDS_WIN8_METRO_RESTART);
588 // Append the full menu including separators. The final separator only gets
589 // appended when this is a touch menu - otherwise it would get added twice.
590 CreateCutCopyPasteMenu(is_new_menu);
593 CreateZoomMenu(is_new_menu);
595 if (CommandLine::ForCurrentProcess()->HasSwitch(
596 switches::kEnableDomDistiller)) {
597 AddItemWithStringId(IDC_DISTILL_PAGE, IDS_DISTILL_PAGE);
600 AddItemWithStringId(IDC_SAVE_PAGE, IDS_SAVE_PAGE);
601 AddItemWithStringId(IDC_FIND, IDS_FIND);
602 AddItemWithStringId(IDC_PRINT, IDS_PRINT);
604 tools_menu_model_.reset(new ToolsMenuModel(this, browser_));
605 // In case of touch this is the last item.
607 AddSubMenuWithStringId(IDC_ZOOM_MENU, IDS_TOOLS_MENU,
608 tools_menu_model_.get());
612 CreateZoomMenu(is_new_menu);
614 AddSeparator(ui::NORMAL_SEPARATOR);
616 AddItemWithStringId(IDC_SHOW_HISTORY, IDS_SHOW_HISTORY);
617 AddItemWithStringId(IDC_SHOW_DOWNLOADS, IDS_SHOW_DOWNLOADS);
618 AddSeparator(ui::NORMAL_SEPARATOR);
620 #if !defined(OS_CHROMEOS)
621 if (!switches::IsNewProfileManagement()) {
622 // No "Sign in to Chromium..." menu item on ChromeOS.
623 SigninManager* signin = SigninManagerFactory::GetForProfile(
624 browser_->profile()->GetOriginalProfile());
625 if (signin && signin->IsSigninAllowed()) {
626 const base::string16 short_product_name =
627 l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME);
628 AddItem(IDC_SHOW_SYNC_SETUP, l10n_util::GetStringFUTF16(
629 IDS_SYNC_MENU_PRE_SYNCED_LABEL, short_product_name));
630 AddSeparator(ui::NORMAL_SEPARATOR);
635 AddItemWithStringId(IDC_OPTIONS, IDS_SETTINGS);
637 // On ChromeOS we don't want the about menu option.
638 #if !defined(OS_CHROMEOS)
639 AddItem(IDC_ABOUT, l10n_util::GetStringUTF16(IDS_ABOUT));
642 #if defined(GOOGLE_CHROME_BUILD)
643 help_menu_model_.reset(new HelpMenuModel(this, browser_));
644 AddSubMenuWithStringId(IDC_HELP_MENU, IDS_HELP_MENU,
645 help_menu_model_.get());
648 #if defined(OS_CHROMEOS)
649 if (CommandLine::ForCurrentProcess()->HasSwitch(
650 chromeos::switches::kEnableRequestTabletSite))
651 AddCheckItemWithStringId(IDC_TOGGLE_REQUEST_TABLET_SITE,
652 IDS_TOGGLE_REQUEST_TABLET_SITE);
655 if (browser_defaults::kShowUpgradeMenuItem)
656 AddItem(IDC_UPGRADE_DIALOG, GetUpgradeDialogMenuItemName());
659 SetIcon(GetIndexOfCommandId(IDC_VIEW_INCOMPATIBILITIES),
660 ui::ResourceBundle::GetSharedInstance().
661 GetNativeImageNamed(IDR_INPUT_ALERT_MENU));
664 AddGlobalErrorMenuItems();
667 AddSeparator(ui::NORMAL_SEPARATOR);
668 AddSubMenuWithStringId(IDC_ZOOM_MENU, IDS_MORE_TOOLS_MENU,
669 tools_menu_model_.get());
672 bool show_exit_menu = browser_defaults::kShowExitMenuItem;
674 if (browser_->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH)
675 show_exit_menu = false;
678 if (show_exit_menu) {
679 AddSeparator(ui::NORMAL_SEPARATOR);
680 AddItemWithStringId(IDC_EXIT, IDS_EXIT);
683 RemoveTrailingSeparators();
686 void WrenchMenuModel::AddGlobalErrorMenuItems() {
687 // TODO(sail): Currently we only build the wrench menu once per browser
688 // window. This means that if a new error is added after the menu is built
689 // it won't show in the existing wrench menu. To fix this we need to some
690 // how update the menu if new errors are added.
691 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
692 // GetSignedInServiceErrors() can modify the global error list, so call it
693 // before iterating through that list below.
694 std::vector<GlobalError*> signin_errors;
695 if (!switches::IsNewProfileManagement()) {
696 signin_errors = signin_ui_util::GetSignedInServiceErrors(
697 browser_->profile()->GetOriginalProfile());
699 const GlobalErrorService::GlobalErrorList& errors =
700 GlobalErrorServiceFactory::GetForProfile(browser_->profile())->errors();
701 for (GlobalErrorService::GlobalErrorList::const_iterator
702 it = errors.begin(); it != errors.end(); ++it) {
703 GlobalError* error = *it;
705 if (error->HasMenuItem()) {
706 #if !defined(OS_CHROMEOS)
707 // Don't add a signin error if it's already being displayed elsewhere.
708 if (std::find(signin_errors.begin(), signin_errors.end(), error) !=
709 signin_errors.end()) {
710 MenuModel* model = this;
712 if (MenuModel::GetModelAndIndexForCommandId(
713 IDC_SHOW_SIGNIN, &model, &index)) {
719 AddItem(error->MenuItemCommandID(), error->MenuItemLabel());
720 int icon_id = error->MenuItemIconResourceID();
722 const gfx::Image& image = rb.GetNativeImageNamed(icon_id);
723 SetIcon(GetIndexOfCommandId(error->MenuItemCommandID()),
730 void WrenchMenuModel::CreateCutCopyPasteMenu(bool new_menu) {
731 AddSeparator(new_menu ? ui::LOWER_SEPARATOR : ui::NORMAL_SEPARATOR);
733 #if defined(OS_POSIX) && !defined(TOOLKIT_VIEWS)
734 // WARNING: Mac does not use the ButtonMenuItemModel, but instead defines the
735 // layout for this menu item in Toolbar.xib. It does, however, use the
736 // command_id value from AddButtonItem() to identify this special item.
737 edit_menu_item_model_.reset(new ui::ButtonMenuItemModel(IDS_EDIT, this));
738 edit_menu_item_model_->AddGroupItemWithStringId(IDC_CUT, IDS_CUT);
739 edit_menu_item_model_->AddGroupItemWithStringId(IDC_COPY, IDS_COPY);
740 edit_menu_item_model_->AddGroupItemWithStringId(IDC_PASTE, IDS_PASTE);
741 AddButtonItem(IDC_EDIT_MENU, edit_menu_item_model_.get());
743 // WARNING: views/wrench_menu assumes these items are added in this order. If
744 // you change the order you'll need to update wrench_menu as well.
745 AddItemWithStringId(IDC_CUT, IDS_CUT);
746 AddItemWithStringId(IDC_COPY, IDS_COPY);
747 AddItemWithStringId(IDC_PASTE, IDS_PASTE);
751 AddSeparator(ui::UPPER_SEPARATOR);
754 void WrenchMenuModel::CreateZoomMenu(bool new_menu) {
755 // This menu needs to be enclosed by separators.
756 AddSeparator(new_menu ? ui::LOWER_SEPARATOR : ui::NORMAL_SEPARATOR);
758 #if defined(OS_POSIX) && !defined(TOOLKIT_VIEWS)
759 // WARNING: Mac does not use the ButtonMenuItemModel, but instead defines the
760 // layout for this menu item in Toolbar.xib. It does, however, use the
761 // command_id value from AddButtonItem() to identify this special item.
762 zoom_menu_item_model_.reset(
763 new ui::ButtonMenuItemModel(IDS_ZOOM_MENU, this));
764 zoom_menu_item_model_->AddGroupItemWithStringId(
765 IDC_ZOOM_MINUS, IDS_ZOOM_MINUS2);
766 zoom_menu_item_model_->AddButtonLabel(IDC_ZOOM_PERCENT_DISPLAY,
768 zoom_menu_item_model_->AddGroupItemWithStringId(
769 IDC_ZOOM_PLUS, IDS_ZOOM_PLUS2);
770 zoom_menu_item_model_->AddSpace();
771 zoom_menu_item_model_->AddItemWithImage(
772 IDC_FULLSCREEN, IDR_FULLSCREEN_MENU_BUTTON);
773 AddButtonItem(IDC_ZOOM_MENU, zoom_menu_item_model_.get());
775 // WARNING: views/wrench_menu assumes these items are added in this order. If
776 // you change the order you'll need to update wrench_menu as well.
777 AddItemWithStringId(IDC_ZOOM_MINUS, IDS_ZOOM_MINUS);
778 AddItemWithStringId(IDC_ZOOM_PLUS, IDS_ZOOM_PLUS);
779 AddItemWithStringId(IDC_FULLSCREEN, IDS_FULLSCREEN);
782 AddSeparator(new_menu ? ui::UPPER_SEPARATOR : ui::NORMAL_SEPARATOR);
785 void WrenchMenuModel::UpdateZoomControls() {
786 bool enable_increment = false;
787 bool enable_decrement = false;
788 int zoom_percent = 100;
789 if (browser_->tab_strip_model()->GetActiveWebContents()) {
791 browser_->tab_strip_model()->GetActiveWebContents()->GetZoomPercent(
792 &enable_increment, &enable_decrement);
794 zoom_label_ = l10n_util::GetStringFUTF16(
795 IDS_ZOOM_PERCENT, base::IntToString16(zoom_percent));
798 void WrenchMenuModel::OnZoomLevelChanged(
799 const content::HostZoomMap::ZoomLevelChange& change) {
800 UpdateZoomControls();