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/extensions/extension_toolbar_model.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_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/bookmarks/bookmark_utils.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/tabs/tab_strip_model.h"
34 #include "chrome/browser/ui/toolbar/bookmark_sub_menu_model.h"
35 #include "chrome/browser/ui/toolbar/encoding_menu_controller.h"
36 #include "chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h"
37 #include "chrome/browser/ui/zoom/zoom_controller.h"
38 #include "chrome/browser/ui/zoom/zoom_event_manager.h"
39 #include "chrome/browser/upgrade_detector.h"
40 #include "chrome/common/chrome_paths.h"
41 #include "chrome/common/chrome_switches.h"
42 #include "chrome/common/pref_names.h"
43 #include "chrome/common/profiling.h"
44 #include "components/signin/core/browser/signin_manager.h"
45 #include "components/signin/core/common/profile_management_switches.h"
46 #include "content/public/browser/host_zoom_map.h"
47 #include "content/public/browser/navigation_entry.h"
48 #include "content/public/browser/notification_service.h"
49 #include "content/public/browser/notification_source.h"
50 #include "content/public/browser/notification_types.h"
51 #include "content/public/browser/user_metrics.h"
52 #include "content/public/browser/web_contents.h"
53 #include "extensions/common/feature_switch.h"
54 #include "grit/chromium_strings.h"
55 #include "grit/generated_resources.h"
56 #include "grit/theme_resources.h"
57 #include "ui/base/l10n/l10n_util.h"
58 #include "ui/base/layout.h"
59 #include "ui/base/models/button_menu_item_model.h"
60 #include "ui/base/resource/resource_bundle.h"
61 #include "ui/gfx/image/image.h"
62 #include "ui/gfx/image/image_skia.h"
64 #if defined(OS_CHROMEOS)
65 #include "chromeos/chromeos_switches.h"
69 #include "base/win/metro.h"
70 #include "base/win/windows_version.h"
71 #include "chrome/browser/enumerate_modules_model_win.h"
72 #include "chrome/browser/ui/metro_pin_tab_helper_win.h"
73 #include "content/public/browser/gpu_data_manager.h"
77 #include "ash/shell.h"
80 using base::UserMetricsAction
;
81 using content::HostZoomMap
;
82 using content::WebContents
;
85 // Conditionally return the update app menu item title based on upgrade detector
87 base::string16
GetUpgradeDialogMenuItemName() {
88 if (UpgradeDetector::GetInstance()->is_outdated_install() ||
89 UpgradeDetector::GetInstance()->is_outdated_install_no_au()) {
90 return l10n_util::GetStringUTF16(IDS_UPGRADE_BUBBLE_MENU_ITEM
);
92 return l10n_util::GetStringUTF16(IDS_UPDATE_NOW
);
98 ////////////////////////////////////////////////////////////////////////////////
101 EncodingMenuModel::EncodingMenuModel(Browser
* browser
)
102 : ui::SimpleMenuModel(this),
107 EncodingMenuModel::~EncodingMenuModel() {
110 void EncodingMenuModel::Build() {
111 EncodingMenuController::EncodingMenuItemList encoding_menu_items
;
112 EncodingMenuController encoding_menu_controller
;
113 encoding_menu_controller
.GetEncodingMenuItems(browser_
->profile(),
114 &encoding_menu_items
);
117 EncodingMenuController::EncodingMenuItemList::iterator it
=
118 encoding_menu_items
.begin();
119 for (; it
!= encoding_menu_items
.end(); ++it
) {
121 base::string16
& label
= it
->second
;
123 AddSeparator(ui::NORMAL_SEPARATOR
);
125 if (id
== IDC_ENCODING_AUTO_DETECT
) {
126 AddCheckItem(id
, label
);
128 // Use the id of the first radio command as the id of the group.
131 AddRadioItem(id
, label
, group_id
);
137 bool EncodingMenuModel::IsCommandIdChecked(int command_id
) const {
138 WebContents
* current_tab
=
139 browser_
->tab_strip_model()->GetActiveWebContents();
142 EncodingMenuController controller
;
143 return controller
.IsItemChecked(browser_
->profile(),
144 current_tab
->GetEncoding(), command_id
);
147 bool EncodingMenuModel::IsCommandIdEnabled(int command_id
) const {
148 bool enabled
= chrome::IsCommandEnabled(browser_
, command_id
);
149 // Special handling for the contents of the Encoding submenu. On Mac OS,
150 // instead of enabling/disabling the top-level menu item, the submenu's
151 // contents get disabled, per Apple's HIG.
152 #if defined(OS_MACOSX)
153 enabled
&= chrome::IsCommandEnabled(browser_
, IDC_ENCODING_MENU
);
158 bool EncodingMenuModel::GetAcceleratorForCommandId(
160 ui::Accelerator
* accelerator
) {
164 void EncodingMenuModel::ExecuteCommand(int command_id
, int event_flags
) {
165 chrome::ExecuteCommand(browser_
, command_id
);
168 ////////////////////////////////////////////////////////////////////////////////
171 ZoomMenuModel::ZoomMenuModel(ui::SimpleMenuModel::Delegate
* delegate
)
172 : SimpleMenuModel(delegate
) {
176 ZoomMenuModel::~ZoomMenuModel() {
179 void ZoomMenuModel::Build() {
180 AddItemWithStringId(IDC_ZOOM_PLUS
, IDS_ZOOM_PLUS
);
181 AddItemWithStringId(IDC_ZOOM_NORMAL
, IDS_ZOOM_NORMAL
);
182 AddItemWithStringId(IDC_ZOOM_MINUS
, IDS_ZOOM_MINUS
);
185 ////////////////////////////////////////////////////////////////////////////////
188 #if defined(GOOGLE_CHROME_BUILD)
190 class WrenchMenuModel::HelpMenuModel
: public ui::SimpleMenuModel
{
192 HelpMenuModel(ui::SimpleMenuModel::Delegate
* delegate
,
194 : SimpleMenuModel(delegate
) {
197 virtual ~HelpMenuModel() {
201 void Build(Browser
* browser
) {
202 int help_string_id
= IDS_HELP_PAGE
;
203 #if defined(OS_CHROMEOS) && defined(OFFICIAL_BUILD)
204 if (!CommandLine::ForCurrentProcess()->HasSwitch(
205 chromeos::switches::kDisableGeniusApp
)) {
206 help_string_id
= IDS_GET_HELP
;
209 AddItemWithStringId(IDC_HELP_PAGE_VIA_MENU
, help_string_id
);
210 if (browser_defaults::kShowHelpMenuItemIcon
) {
211 ui::ResourceBundle
& rb
= ResourceBundle::GetSharedInstance();
212 SetIcon(GetIndexOfCommandId(IDC_HELP_PAGE_VIA_MENU
),
213 rb
.GetNativeImageNamed(IDR_HELP_MENU
));
216 AddItemWithStringId(IDC_FEEDBACK
, IDS_FEEDBACK
);
219 DISALLOW_COPY_AND_ASSIGN(HelpMenuModel
);
222 #endif // defined(GOOGLE_CHROME_BUILD)
224 ////////////////////////////////////////////////////////////////////////////////
227 ToolsMenuModel::ToolsMenuModel(ui::SimpleMenuModel::Delegate
* delegate
,
229 : SimpleMenuModel(delegate
) {
233 ToolsMenuModel::~ToolsMenuModel() {}
235 void ToolsMenuModel::Build(Browser
* browser
) {
236 bool show_create_shortcuts
= true;
237 #if defined(OS_CHROMEOS) || defined(OS_MACOSX)
238 show_create_shortcuts
= false;
239 #elif defined(USE_ASH)
240 if (browser
->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH
)
241 show_create_shortcuts
= false;
244 if (CommandLine::ForCurrentProcess()->HasSwitch(
245 switches::kEnableStreamlinedHostedApps
)) {
246 AddItemWithStringId(IDC_CREATE_HOSTED_APP
, IDS_CREATE_HOSTED_APP
);
247 AddSeparator(ui::NORMAL_SEPARATOR
);
248 } else if (show_create_shortcuts
) {
249 AddItemWithStringId(IDC_CREATE_SHORTCUTS
, IDS_CREATE_SHORTCUTS
);
250 AddSeparator(ui::NORMAL_SEPARATOR
);
253 AddItemWithStringId(IDC_MANAGE_EXTENSIONS
, IDS_SHOW_EXTENSIONS
);
255 if (chrome::CanOpenTaskManager())
256 AddItemWithStringId(IDC_TASK_MANAGER
, IDS_TASK_MANAGER
);
258 AddItemWithStringId(IDC_CLEAR_BROWSING_DATA
, IDS_CLEAR_BROWSING_DATA
);
260 AddSeparator(ui::NORMAL_SEPARATOR
);
262 encoding_menu_model_
.reset(new EncodingMenuModel(browser
));
263 AddSubMenuWithStringId(IDC_ENCODING_MENU
, IDS_ENCODING_MENU
,
264 encoding_menu_model_
.get());
265 AddItemWithStringId(IDC_VIEW_SOURCE
, IDS_VIEW_SOURCE
);
266 AddItemWithStringId(IDC_DEV_TOOLS
, IDS_DEV_TOOLS
);
267 AddItemWithStringId(IDC_DEV_TOOLS_CONSOLE
, IDS_DEV_TOOLS_CONSOLE
);
268 AddItemWithStringId(IDC_DEV_TOOLS_DEVICES
, IDS_DEV_TOOLS_DEVICES
);
270 #if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC)
271 AddSeparator(ui::NORMAL_SEPARATOR
);
272 AddCheckItemWithStringId(IDC_PROFILING_ENABLED
, IDS_PROFILING_ENABLED
);
276 ////////////////////////////////////////////////////////////////////////////////
279 WrenchMenuModel::WrenchMenuModel(ui::AcceleratorProvider
* provider
,
281 : ui::SimpleMenuModel(this),
284 tab_strip_model_(browser_
->tab_strip_model()) {
286 UpdateZoomControls();
288 content_zoom_subscription_
= content::HostZoomMap::GetForBrowserContext(
289 browser
->profile())->AddZoomLevelChangedCallback(
290 base::Bind(&WrenchMenuModel::OnZoomLevelChanged
,
291 base::Unretained(this)));
293 browser_zoom_subscription_
= ZoomEventManager::GetForBrowserContext(
294 browser
->profile())->AddZoomLevelChangedCallback(
295 base::Bind(&WrenchMenuModel::OnZoomLevelChanged
,
296 base::Unretained(this)));
298 tab_strip_model_
->AddObserver(this);
300 registrar_
.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED
,
301 content::NotificationService::AllSources());
304 WrenchMenuModel::~WrenchMenuModel() {
305 if (tab_strip_model_
)
306 tab_strip_model_
->RemoveObserver(this);
309 bool WrenchMenuModel::DoesCommandIdDismissMenu(int command_id
) const {
310 return command_id
!= IDC_ZOOM_MINUS
&& command_id
!= IDC_ZOOM_PLUS
;
313 bool WrenchMenuModel::IsItemForCommandIdDynamic(int command_id
) const {
314 return command_id
== IDC_ZOOM_PERCENT_DISPLAY
||
315 #if defined(OS_MACOSX)
316 command_id
== IDC_FULLSCREEN
||
317 #elif defined(OS_WIN)
318 command_id
== IDC_PIN_TO_START_SCREEN
||
320 command_id
== IDC_UPGRADE_DIALOG
||
321 (!switches::IsNewAvatarMenu() && command_id
== IDC_SHOW_SIGNIN
);
324 base::string16
WrenchMenuModel::GetLabelForCommandId(int command_id
) const {
325 switch (command_id
) {
326 case IDC_ZOOM_PERCENT_DISPLAY
:
328 #if defined(OS_MACOSX)
329 case IDC_FULLSCREEN
: {
330 int string_id
= IDS_ENTER_FULLSCREEN_MAC
; // Default to Enter.
331 // Note: On startup, |window()| may be NULL.
332 if (browser_
->window() && browser_
->window()->IsFullscreen())
333 string_id
= IDS_EXIT_FULLSCREEN_MAC
;
334 return l10n_util::GetStringUTF16(string_id
);
336 #elif defined(OS_WIN)
337 case IDC_PIN_TO_START_SCREEN
: {
338 int string_id
= IDS_PIN_TO_START_SCREEN
;
339 WebContents
* web_contents
=
340 browser_
->tab_strip_model()->GetActiveWebContents();
341 MetroPinTabHelper
* tab_helper
=
342 web_contents
? MetroPinTabHelper::FromWebContents(web_contents
)
344 if (tab_helper
&& tab_helper
->IsPinned())
345 string_id
= IDS_UNPIN_FROM_START_SCREEN
;
346 return l10n_util::GetStringUTF16(string_id
);
349 case IDC_UPGRADE_DIALOG
:
350 return GetUpgradeDialogMenuItemName();
351 case IDC_SHOW_SIGNIN
:
352 DCHECK(!switches::IsNewAvatarMenu());
353 return signin_ui_util::GetSigninMenuLabel(
354 browser_
->profile()->GetOriginalProfile());
357 return base::string16();
361 bool WrenchMenuModel::GetIconForCommandId(int command_id
,
362 gfx::Image
* icon
) const {
363 ui::ResourceBundle
& rb
= ui::ResourceBundle::GetSharedInstance();
364 switch (command_id
) {
365 case IDC_UPGRADE_DIALOG
: {
366 if (UpgradeDetector::GetInstance()->notify_upgrade()) {
367 *icon
= rb
.GetNativeImageNamed(
368 UpgradeDetector::GetInstance()->GetIconResourceID());
373 case IDC_SHOW_SIGNIN
: {
374 DCHECK(!switches::IsNewAvatarMenu());
375 GlobalError
* error
= signin_ui_util::GetSignedInServiceError(
376 browser_
->profile()->GetOriginalProfile());
378 int icon_id
= error
->MenuItemIconResourceID();
380 *icon
= rb
.GetNativeImageNamed(icon_id
);
392 void WrenchMenuModel::ExecuteCommand(int command_id
, int event_flags
) {
393 GlobalError
* error
= GlobalErrorServiceFactory::GetForProfile(
394 browser_
->profile())->GetGlobalErrorByMenuItemCommandID(command_id
);
396 error
->ExecuteMenuItem(browser_
);
400 if (!switches::IsNewAvatarMenu() && command_id
== IDC_SHOW_SIGNIN
) {
401 // If a custom error message is being shown, handle it.
402 GlobalError
* error
= signin_ui_util::GetSignedInServiceError(
403 browser_
->profile()->GetOriginalProfile());
405 error
->ExecuteMenuItem(browser_
);
410 if (command_id
== IDC_HELP_PAGE_VIA_MENU
)
411 content::RecordAction(UserMetricsAction("ShowHelpTabViaWrenchMenu"));
413 if (command_id
== IDC_FULLSCREEN
) {
414 // We issue the UMA command here and not in BrowserCommandController or even
415 // FullscreenController since we want to be able to distinguish this event
416 // and a menu which is under development.
417 content::RecordAction(UserMetricsAction("EnterFullScreenWithWrenchMenu"));
420 chrome::ExecuteCommand(browser_
, command_id
);
423 bool WrenchMenuModel::IsCommandIdChecked(int command_id
) const {
424 if (command_id
== IDC_SHOW_BOOKMARK_BAR
) {
425 return browser_
->profile()->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar
);
426 } else if (command_id
== IDC_PROFILING_ENABLED
) {
427 return Profiling::BeingProfiled();
428 } else if (command_id
== IDC_TOGGLE_REQUEST_TABLET_SITE
) {
429 return chrome::IsRequestingTabletSite(browser_
);
435 bool WrenchMenuModel::IsCommandIdEnabled(int command_id
) const {
436 GlobalError
* error
= GlobalErrorServiceFactory::GetForProfile(
437 browser_
->profile())->GetGlobalErrorByMenuItemCommandID(command_id
);
441 return chrome::IsCommandEnabled(browser_
, command_id
);
444 bool WrenchMenuModel::IsCommandIdVisible(int command_id
) const {
445 switch (command_id
) {
447 case IDC_VIEW_INCOMPATIBILITIES
: {
448 EnumerateModulesModel
* loaded_modules
=
449 EnumerateModulesModel::GetInstance();
450 if (loaded_modules
->confirmed_bad_modules_detected() <= 0)
452 // We'll leave the wrench adornment on until the user clicks the link.
453 if (loaded_modules
->modules_to_notify_about() <= 0)
454 loaded_modules
->AcknowledgeConflictNotification();
457 case IDC_PIN_TO_START_SCREEN
:
458 return base::win::IsMetroProcess();
460 case IDC_VIEW_INCOMPATIBILITIES
:
461 case IDC_PIN_TO_START_SCREEN
:
464 case IDC_UPGRADE_DIALOG
:
465 return UpgradeDetector::GetInstance()->notify_upgrade();
466 #if !defined(OS_LINUX) || defined(USE_AURA)
467 case IDC_BOOKMARK_PAGE
:
468 return !chrome::ShouldRemoveBookmarkThisPageUI(browser_
->profile());
469 case IDC_BOOKMARK_ALL_TABS
:
470 return !chrome::ShouldRemoveBookmarkOpenPagesUI(browser_
->profile());
477 bool WrenchMenuModel::GetAcceleratorForCommandId(
479 ui::Accelerator
* accelerator
) {
480 return provider_
->GetAcceleratorForCommandId(command_id
, accelerator
);
483 void WrenchMenuModel::ActiveTabChanged(WebContents
* old_contents
,
484 WebContents
* new_contents
,
487 // The user has switched between tabs and the new tab may have a different
489 UpdateZoomControls();
492 void WrenchMenuModel::TabReplacedAt(TabStripModel
* tab_strip_model
,
493 WebContents
* old_contents
,
494 WebContents
* new_contents
,
496 UpdateZoomControls();
499 void WrenchMenuModel::TabStripModelDeleted() {
500 // During views shutdown, the tabstrip model/browser is deleted first, while
501 // it is the opposite in gtk land.
502 tab_strip_model_
->RemoveObserver(this);
503 tab_strip_model_
= NULL
;
506 void WrenchMenuModel::Observe(int type
,
507 const content::NotificationSource
& source
,
508 const content::NotificationDetails
& details
) {
509 DCHECK(type
== content::NOTIFICATION_NAV_ENTRY_COMMITTED
);
510 UpdateZoomControls();
514 WrenchMenuModel::WrenchMenuModel()
515 : ui::SimpleMenuModel(this),
518 tab_strip_model_(NULL
) {
521 bool WrenchMenuModel::ShouldShowNewIncognitoWindowMenuItem() {
522 if (browser_
->profile()->IsSupervised())
525 return !browser_
->profile()->IsGuestSession();
528 void WrenchMenuModel::Build() {
530 AddItem(IDC_VIEW_INCOMPATIBILITIES
,
531 l10n_util::GetStringUTF16(IDS_VIEW_INCOMPATIBILITIES
));
532 EnumerateModulesModel
* model
=
533 EnumerateModulesModel::GetInstance();
534 if (model
->modules_to_notify_about() > 0 ||
535 model
->confirmed_bad_modules_detected() > 0)
536 AddSeparator(ui::NORMAL_SEPARATOR
);
539 if (extensions::FeatureSwitch::extension_action_redesign()->IsEnabled())
540 CreateExtensionToolbarOverflowMenu();
542 AddItemWithStringId(IDC_NEW_TAB
, IDS_NEW_TAB
);
543 AddItemWithStringId(IDC_NEW_WINDOW
, IDS_NEW_WINDOW
);
545 if (ShouldShowNewIncognitoWindowMenuItem())
546 AddItemWithStringId(IDC_NEW_INCOGNITO_WINDOW
, IDS_NEW_INCOGNITO_WINDOW
);
548 #if defined(OS_WIN) && !defined(NDEBUG) && defined(USE_ASH)
549 if (base::win::GetVersion() < base::win::VERSION_WIN8
&&
550 chrome::HOST_DESKTOP_TYPE_NATIVE
!= chrome::HOST_DESKTOP_TYPE_ASH
) {
551 AddItemWithStringId(IDC_TOGGLE_ASH_DESKTOP
,
552 ash::Shell::HasInstance() ? IDS_CLOSE_ASH_DESKTOP
:
553 IDS_OPEN_ASH_DESKTOP
);
557 bookmark_sub_menu_model_
.reset(new BookmarkSubMenuModel(this, browser_
));
558 AddSubMenuWithStringId(IDC_BOOKMARKS_MENU
, IDS_BOOKMARKS_MENU
,
559 bookmark_sub_menu_model_
.get());
561 if (!browser_
->profile()->IsOffTheRecord()) {
562 recent_tabs_sub_menu_model_
.reset(new RecentTabsSubMenuModel(provider_
,
565 AddSubMenuWithStringId(IDC_RECENT_TABS_MENU
, IDS_RECENT_TABS_MENU
,
566 recent_tabs_sub_menu_model_
.get());
571 #if defined(USE_AURA)
572 if (base::win::GetVersion() >= base::win::VERSION_WIN8
&&
573 content::GpuDataManager::GetInstance()->CanUseGpuBrowserCompositor()) {
574 if (browser_
->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH
) {
575 // Metro mode, add the 'Relaunch Chrome in desktop mode'.
576 AddSeparator(ui::NORMAL_SEPARATOR
);
577 AddItemWithStringId(IDC_WIN8_DESKTOP_RESTART
, IDS_WIN8_DESKTOP_RESTART
);
579 // In Windows 8 desktop, add the 'Relaunch Chrome in Windows 8 mode'.
580 AddSeparator(ui::NORMAL_SEPARATOR
);
581 AddItemWithStringId(IDC_WIN8_METRO_RESTART
, IDS_WIN8_METRO_RESTART
);
585 if (base::win::IsMetroProcess()) {
586 // Metro mode, add the 'Relaunch Chrome in desktop mode'.
587 AddSeparator(ui::NORMAL_SEPARATOR
);
588 AddItemWithStringId(IDC_WIN8_DESKTOP_RESTART
, IDS_WIN8_DESKTOP_RESTART
);
590 // In Windows 8 desktop, add the 'Relaunch Chrome in Windows 8 mode'.
591 AddSeparator(ui::NORMAL_SEPARATOR
);
592 AddItemWithStringId(IDC_WIN8_METRO_RESTART
, IDS_WIN8_METRO_RESTART
);
598 // Append the full menu including separators. The final separator only gets
599 // appended when this is a touch menu - otherwise it would get added twice.
600 CreateCutCopyPasteMenu();
602 if (CommandLine::ForCurrentProcess()->HasSwitch(
603 switches::kEnableDomDistiller
)) {
604 AddItemWithStringId(IDC_DISTILL_PAGE
, IDS_DISTILL_PAGE
);
607 AddItemWithStringId(IDC_SAVE_PAGE
, IDS_SAVE_PAGE
);
608 AddItemWithStringId(IDC_FIND
, IDS_FIND
);
609 AddItemWithStringId(IDC_PRINT
, IDS_PRINT
);
611 tools_menu_model_
.reset(new ToolsMenuModel(this, browser_
));
614 AddItemWithStringId(IDC_SHOW_HISTORY
, IDS_SHOW_HISTORY
);
615 AddItemWithStringId(IDC_SHOW_DOWNLOADS
, IDS_SHOW_DOWNLOADS
);
616 AddSeparator(ui::NORMAL_SEPARATOR
);
618 #if !defined(OS_CHROMEOS)
619 if (!switches::IsNewAvatarMenu()) {
620 // No "Sign in to Chromium..." menu item on ChromeOS.
621 SigninManager
* signin
= SigninManagerFactory::GetForProfile(
622 browser_
->profile()->GetOriginalProfile());
623 if (signin
&& signin
->IsSigninAllowed()) {
624 const base::string16 short_product_name
=
625 l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME
);
626 AddItem(IDC_SHOW_SYNC_SETUP
, l10n_util::GetStringFUTF16(
627 IDS_SYNC_MENU_PRE_SYNCED_LABEL
, short_product_name
));
628 AddSeparator(ui::NORMAL_SEPARATOR
);
633 AddItemWithStringId(IDC_OPTIONS
, IDS_SETTINGS
);
635 // On ChromeOS we don't want the about menu option.
636 #if !defined(OS_CHROMEOS)
637 AddItem(IDC_ABOUT
, l10n_util::GetStringUTF16(IDS_ABOUT
));
640 #if defined(GOOGLE_CHROME_BUILD)
641 help_menu_model_
.reset(new HelpMenuModel(this, browser_
));
642 AddSubMenuWithStringId(IDC_HELP_MENU
, IDS_HELP_MENU
,
643 help_menu_model_
.get());
646 #if defined(OS_CHROMEOS)
647 if (CommandLine::ForCurrentProcess()->HasSwitch(
648 chromeos::switches::kEnableRequestTabletSite
))
649 AddCheckItemWithStringId(IDC_TOGGLE_REQUEST_TABLET_SITE
,
650 IDS_TOGGLE_REQUEST_TABLET_SITE
);
653 if (browser_defaults::kShowUpgradeMenuItem
)
654 AddItem(IDC_UPGRADE_DIALOG
, GetUpgradeDialogMenuItemName());
657 SetIcon(GetIndexOfCommandId(IDC_VIEW_INCOMPATIBILITIES
),
658 ui::ResourceBundle::GetSharedInstance().
659 GetNativeImageNamed(IDR_INPUT_ALERT_MENU
));
662 AddGlobalErrorMenuItems();
664 AddSeparator(ui::NORMAL_SEPARATOR
);
665 AddSubMenuWithStringId(
666 IDC_ZOOM_MENU
, IDS_MORE_TOOLS_MENU
, tools_menu_model_
.get());
668 bool show_exit_menu
= browser_defaults::kShowExitMenuItem
;
670 if (browser_
->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH
)
671 show_exit_menu
= false;
674 if (show_exit_menu
) {
675 AddSeparator(ui::NORMAL_SEPARATOR
);
676 AddItemWithStringId(IDC_EXIT
, IDS_EXIT
);
679 RemoveTrailingSeparators();
682 void WrenchMenuModel::AddGlobalErrorMenuItems() {
683 // TODO(sail): Currently we only build the wrench menu once per browser
684 // window. This means that if a new error is added after the menu is built
685 // it won't show in the existing wrench menu. To fix this we need to some
686 // how update the menu if new errors are added.
687 ui::ResourceBundle
& rb
= ui::ResourceBundle::GetSharedInstance();
688 // GetSignedInServiceErrors() can modify the global error list, so call it
689 // before iterating through that list below.
690 std::vector
<GlobalError
*> signin_errors
;
691 signin_errors
= signin_ui_util::GetSignedInServiceErrors(
692 browser_
->profile()->GetOriginalProfile());
693 const GlobalErrorService::GlobalErrorList
& errors
=
694 GlobalErrorServiceFactory::GetForProfile(browser_
->profile())->errors();
695 for (GlobalErrorService::GlobalErrorList::const_iterator
696 it
= errors
.begin(); it
!= errors
.end(); ++it
) {
697 GlobalError
* error
= *it
;
699 if (error
->HasMenuItem()) {
700 #if !defined(OS_CHROMEOS)
701 // Don't add a signin error if it's already being displayed elsewhere.
702 if (std::find(signin_errors
.begin(), signin_errors
.end(), error
) !=
703 signin_errors
.end()) {
704 MenuModel
* model
= this;
706 if (MenuModel::GetModelAndIndexForCommandId(
707 IDC_SHOW_SIGNIN
, &model
, &index
)) {
713 AddItem(error
->MenuItemCommandID(), error
->MenuItemLabel());
714 int icon_id
= error
->MenuItemIconResourceID();
716 const gfx::Image
& image
= rb
.GetNativeImageNamed(icon_id
);
717 SetIcon(GetIndexOfCommandId(error
->MenuItemCommandID()),
724 void WrenchMenuModel::CreateExtensionToolbarOverflowMenu() {
725 #if defined(TOOLKIT_VIEWS)
726 AddItem(IDC_EXTENSIONS_OVERFLOW_MENU
, base::string16());
727 // We only add the separator if there are > 0 items to show in the overflow.
728 extensions::ExtensionToolbarModel
* toolbar_model
=
729 extensions::ExtensionToolbarModel::Get(browser_
->profile());
730 // A count of -1 means all actions are visible.
731 if (toolbar_model
->GetVisibleIconCount() != -1)
732 AddSeparator(ui::UPPER_SEPARATOR
);
733 #endif // defined(TOOLKIT_VIEWS)
736 void WrenchMenuModel::CreateCutCopyPasteMenu() {
737 AddSeparator(ui::LOWER_SEPARATOR
);
739 #if defined(OS_POSIX) && !defined(TOOLKIT_VIEWS)
740 // WARNING: Mac does not use the ButtonMenuItemModel, but instead defines the
741 // layout for this menu item in Toolbar.xib. It does, however, use the
742 // command_id value from AddButtonItem() to identify this special item.
743 edit_menu_item_model_
.reset(new ui::ButtonMenuItemModel(IDS_EDIT
, this));
744 edit_menu_item_model_
->AddGroupItemWithStringId(IDC_CUT
, IDS_CUT
);
745 edit_menu_item_model_
->AddGroupItemWithStringId(IDC_COPY
, IDS_COPY
);
746 edit_menu_item_model_
->AddGroupItemWithStringId(IDC_PASTE
, IDS_PASTE
);
747 AddButtonItem(IDC_EDIT_MENU
, edit_menu_item_model_
.get());
749 // WARNING: views/wrench_menu assumes these items are added in this order. If
750 // you change the order you'll need to update wrench_menu as well.
751 AddItemWithStringId(IDC_CUT
, IDS_CUT
);
752 AddItemWithStringId(IDC_COPY
, IDS_COPY
);
753 AddItemWithStringId(IDC_PASTE
, IDS_PASTE
);
756 AddSeparator(ui::UPPER_SEPARATOR
);
759 void WrenchMenuModel::CreateZoomMenu() {
760 // This menu needs to be enclosed by separators.
761 AddSeparator(ui::LOWER_SEPARATOR
);
763 #if defined(OS_POSIX) && !defined(TOOLKIT_VIEWS)
764 // WARNING: Mac does not use the ButtonMenuItemModel, but instead defines the
765 // layout for this menu item in Toolbar.xib. It does, however, use the
766 // command_id value from AddButtonItem() to identify this special item.
767 zoom_menu_item_model_
.reset(
768 new ui::ButtonMenuItemModel(IDS_ZOOM_MENU
, this));
769 zoom_menu_item_model_
->AddGroupItemWithStringId(
770 IDC_ZOOM_MINUS
, IDS_ZOOM_MINUS2
);
771 zoom_menu_item_model_
->AddButtonLabel(IDC_ZOOM_PERCENT_DISPLAY
,
773 zoom_menu_item_model_
->AddGroupItemWithStringId(
774 IDC_ZOOM_PLUS
, IDS_ZOOM_PLUS2
);
775 zoom_menu_item_model_
->AddSpace();
776 zoom_menu_item_model_
->AddItemWithImage(
777 IDC_FULLSCREEN
, IDR_FULLSCREEN_MENU_BUTTON
);
778 AddButtonItem(IDC_ZOOM_MENU
, zoom_menu_item_model_
.get());
780 // WARNING: views/wrench_menu assumes these items are added in this order. If
781 // you change the order you'll need to update wrench_menu as well.
782 AddItemWithStringId(IDC_ZOOM_MINUS
, IDS_ZOOM_MINUS
);
783 AddItemWithStringId(IDC_ZOOM_PLUS
, IDS_ZOOM_PLUS
);
784 AddItemWithStringId(IDC_FULLSCREEN
, IDS_FULLSCREEN
);
787 AddSeparator(ui::UPPER_SEPARATOR
);
790 void WrenchMenuModel::UpdateZoomControls() {
791 int zoom_percent
= 100;
792 if (browser_
->tab_strip_model()->GetActiveWebContents()) {
793 zoom_percent
= ZoomController::FromWebContents(
794 browser_
->tab_strip_model()->GetActiveWebContents())
797 zoom_label_
= l10n_util::GetStringFUTF16(
798 IDS_ZOOM_PERCENT
, base::IntToString16(zoom_percent
));
801 void WrenchMenuModel::OnZoomLevelChanged(
802 const content::HostZoomMap::ZoomLevelChange
& change
) {
803 UpdateZoomControls();