Adding instrumentation to locate the source of jankiness
[chromium-blink-merge.git] / chrome / browser / ui / toolbar / wrench_menu_model.cc
blob907b472182156981c1a566f5fb0c406a033680e1
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"
7 #include <algorithm>
8 #include <cmath>
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/extensions/extension_util.h"
20 #include "chrome/browser/profiles/profile.h"
21 #include "chrome/browser/profiles/profile_manager.h"
22 #include "chrome/browser/search/search.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/bookmarks/bookmark_utils.h"
27 #include "chrome/browser/ui/browser.h"
28 #include "chrome/browser/ui/browser_commands.h"
29 #include "chrome/browser/ui/browser_finder.h"
30 #include "chrome/browser/ui/browser_window.h"
31 #include "chrome/browser/ui/global_error/global_error.h"
32 #include "chrome/browser/ui/global_error/global_error_service.h"
33 #include "chrome/browser/ui/global_error/global_error_service_factory.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/ui/zoom/zoom_controller.h"
39 #include "chrome/browser/ui/zoom/zoom_event_manager.h"
40 #include "chrome/browser/upgrade_detector.h"
41 #include "chrome/common/chrome_paths.h"
42 #include "chrome/common/chrome_switches.h"
43 #include "chrome/common/pref_names.h"
44 #include "chrome/common/profiling.h"
45 #include "chrome/grit/chromium_strings.h"
46 #include "chrome/grit/generated_resources.h"
47 #include "components/signin/core/browser/signin_manager.h"
48 #include "components/signin/core/common/profile_management_switches.h"
49 #include "content/public/browser/host_zoom_map.h"
50 #include "content/public/browser/navigation_entry.h"
51 #include "content/public/browser/notification_service.h"
52 #include "content/public/browser/notification_source.h"
53 #include "content/public/browser/notification_types.h"
54 #include "content/public/browser/user_metrics.h"
55 #include "content/public/browser/web_contents.h"
56 #include "extensions/common/feature_switch.h"
57 #include "grit/theme_resources.h"
58 #include "ui/base/l10n/l10n_util.h"
59 #include "ui/base/layout.h"
60 #include "ui/base/models/button_menu_item_model.h"
61 #include "ui/base/resource/resource_bundle.h"
62 #include "ui/gfx/image/image.h"
63 #include "ui/gfx/image/image_skia.h"
65 #if defined(OS_CHROMEOS)
66 #include "chromeos/chromeos_switches.h"
67 #endif
69 #if defined(OS_WIN)
70 #include "base/win/metro.h"
71 #include "base/win/windows_version.h"
72 #include "chrome/browser/enumerate_modules_model_win.h"
73 #include "chrome/browser/ui/metro_pin_tab_helper_win.h"
74 #include "content/public/browser/gpu_data_manager.h"
75 #endif
77 #if defined(USE_ASH)
78 #include "ash/shell.h"
79 #endif
81 using base::UserMetricsAction;
82 using content::WebContents;
84 namespace {
85 // Conditionally return the update app menu item title based on upgrade detector
86 // state.
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);
91 } else {
92 return l10n_util::GetStringUTF16(IDS_UPDATE_NOW);
96 } // namespace
98 ////////////////////////////////////////////////////////////////////////////////
99 // EncodingMenuModel
101 EncodingMenuModel::EncodingMenuModel(Browser* browser)
102 : ui::SimpleMenuModel(this),
103 browser_(browser) {
104 Build();
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);
116 int group_id = 0;
117 EncodingMenuController::EncodingMenuItemList::iterator it =
118 encoding_menu_items.begin();
119 for (; it != encoding_menu_items.end(); ++it) {
120 int id = it->first;
121 base::string16& label = it->second;
122 if (id == 0) {
123 AddSeparator(ui::NORMAL_SEPARATOR);
124 } else {
125 if (id == IDC_ENCODING_AUTO_DETECT) {
126 AddCheckItem(id, label);
127 } else {
128 // Use the id of the first radio command as the id of the group.
129 if (group_id <= 0)
130 group_id = id;
131 AddRadioItem(id, label, group_id);
137 bool EncodingMenuModel::IsCommandIdChecked(int command_id) const {
138 WebContents* current_tab =
139 browser_->tab_strip_model()->GetActiveWebContents();
140 if (!current_tab)
141 return false;
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);
154 #endif
155 return enabled;
158 bool EncodingMenuModel::GetAcceleratorForCommandId(
159 int command_id,
160 ui::Accelerator* accelerator) {
161 return false;
164 void EncodingMenuModel::ExecuteCommand(int command_id, int event_flags) {
165 chrome::ExecuteCommand(browser_, command_id);
168 ////////////////////////////////////////////////////////////////////////////////
169 // ZoomMenuModel
171 ZoomMenuModel::ZoomMenuModel(ui::SimpleMenuModel::Delegate* delegate)
172 : SimpleMenuModel(delegate) {
173 Build();
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 ////////////////////////////////////////////////////////////////////////////////
186 // HelpMenuModel
188 #if defined(GOOGLE_CHROME_BUILD)
190 class WrenchMenuModel::HelpMenuModel : public ui::SimpleMenuModel {
191 public:
192 HelpMenuModel(ui::SimpleMenuModel::Delegate* delegate,
193 Browser* browser)
194 : SimpleMenuModel(delegate) {
195 Build(browser);
197 virtual ~HelpMenuModel() {
200 private:
201 void Build(Browser* browser) {
202 #if defined(OS_CHROMEOS) && defined(OFFICIAL_BUILD)
203 int help_string_id = IDS_GET_HELP;
204 #else
205 int help_string_id = IDS_HELP_PAGE;
206 #endif
207 AddItemWithStringId(IDC_HELP_PAGE_VIA_MENU, help_string_id);
208 if (browser_defaults::kShowHelpMenuItemIcon) {
209 ui::ResourceBundle& rb = ResourceBundle::GetSharedInstance();
210 SetIcon(GetIndexOfCommandId(IDC_HELP_PAGE_VIA_MENU),
211 rb.GetNativeImageNamed(IDR_HELP_MENU));
214 AddItemWithStringId(IDC_FEEDBACK, IDS_FEEDBACK);
217 DISALLOW_COPY_AND_ASSIGN(HelpMenuModel);
220 #endif // defined(GOOGLE_CHROME_BUILD)
222 ////////////////////////////////////////////////////////////////////////////////
223 // ToolsMenuModel
225 ToolsMenuModel::ToolsMenuModel(ui::SimpleMenuModel::Delegate* delegate,
226 Browser* browser)
227 : SimpleMenuModel(delegate) {
228 Build(browser);
231 ToolsMenuModel::~ToolsMenuModel() {}
233 void ToolsMenuModel::Build(Browser* browser) {
234 bool show_create_shortcuts = true;
235 #if defined(OS_CHROMEOS) || defined(OS_MACOSX)
236 show_create_shortcuts = false;
237 #elif defined(USE_ASH)
238 if (browser->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH)
239 show_create_shortcuts = false;
240 #endif
242 if (extensions::util::IsStreamlinedHostedAppsEnabled()) {
243 AddItemWithStringId(IDC_CREATE_HOSTED_APP, IDS_CREATE_HOSTED_APP);
244 AddSeparator(ui::NORMAL_SEPARATOR);
245 } else if (show_create_shortcuts) {
246 AddItemWithStringId(IDC_CREATE_SHORTCUTS, IDS_CREATE_SHORTCUTS);
247 AddSeparator(ui::NORMAL_SEPARATOR);
250 AddItemWithStringId(IDC_MANAGE_EXTENSIONS, IDS_SHOW_EXTENSIONS);
252 if (chrome::CanOpenTaskManager())
253 AddItemWithStringId(IDC_TASK_MANAGER, IDS_TASK_MANAGER);
255 AddItemWithStringId(IDC_CLEAR_BROWSING_DATA, IDS_CLEAR_BROWSING_DATA);
257 AddSeparator(ui::NORMAL_SEPARATOR);
259 encoding_menu_model_.reset(new EncodingMenuModel(browser));
260 AddSubMenuWithStringId(IDC_ENCODING_MENU, IDS_ENCODING_MENU,
261 encoding_menu_model_.get());
262 AddItemWithStringId(IDC_VIEW_SOURCE, IDS_VIEW_SOURCE);
263 AddItemWithStringId(IDC_DEV_TOOLS, IDS_DEV_TOOLS);
264 AddItemWithStringId(IDC_DEV_TOOLS_CONSOLE, IDS_DEV_TOOLS_CONSOLE);
265 AddItemWithStringId(IDC_DEV_TOOLS_DEVICES, IDS_DEV_TOOLS_DEVICES);
267 #if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC)
268 AddSeparator(ui::NORMAL_SEPARATOR);
269 AddCheckItemWithStringId(IDC_PROFILING_ENABLED, IDS_PROFILING_ENABLED);
270 #endif
273 ////////////////////////////////////////////////////////////////////////////////
274 // WrenchMenuModel
276 WrenchMenuModel::WrenchMenuModel(ui::AcceleratorProvider* provider,
277 Browser* browser)
278 : ui::SimpleMenuModel(this),
279 provider_(provider),
280 browser_(browser),
281 tab_strip_model_(browser_->tab_strip_model()) {
282 Build();
283 UpdateZoomControls();
285 content_zoom_subscription_ =
286 content::HostZoomMap::GetDefaultForBrowserContext(browser->profile())
287 ->AddZoomLevelChangedCallback(base::Bind(
288 &WrenchMenuModel::OnZoomLevelChanged, base::Unretained(this)));
290 browser_zoom_subscription_ = ZoomEventManager::GetForBrowserContext(
291 browser->profile())->AddZoomLevelChangedCallback(
292 base::Bind(&WrenchMenuModel::OnZoomLevelChanged,
293 base::Unretained(this)));
295 tab_strip_model_->AddObserver(this);
297 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
298 content::NotificationService::AllSources());
301 WrenchMenuModel::~WrenchMenuModel() {
302 if (tab_strip_model_)
303 tab_strip_model_->RemoveObserver(this);
306 bool WrenchMenuModel::DoesCommandIdDismissMenu(int command_id) const {
307 return command_id != IDC_ZOOM_MINUS && command_id != IDC_ZOOM_PLUS;
310 bool WrenchMenuModel::IsItemForCommandIdDynamic(int command_id) const {
311 return command_id == IDC_ZOOM_PERCENT_DISPLAY ||
312 #if defined(OS_MACOSX)
313 command_id == IDC_FULLSCREEN ||
314 #elif defined(OS_WIN)
315 command_id == IDC_PIN_TO_START_SCREEN ||
316 #endif
317 command_id == IDC_UPGRADE_DIALOG ||
318 (!switches::IsNewAvatarMenu() && command_id == IDC_SHOW_SIGNIN);
321 base::string16 WrenchMenuModel::GetLabelForCommandId(int command_id) const {
322 switch (command_id) {
323 case IDC_ZOOM_PERCENT_DISPLAY:
324 return zoom_label_;
325 #if defined(OS_MACOSX)
326 case IDC_FULLSCREEN: {
327 int string_id = IDS_ENTER_FULLSCREEN_MAC; // Default to Enter.
328 // Note: On startup, |window()| may be NULL.
329 if (browser_->window() && browser_->window()->IsFullscreen())
330 string_id = IDS_EXIT_FULLSCREEN_MAC;
331 return l10n_util::GetStringUTF16(string_id);
333 #elif defined(OS_WIN)
334 case IDC_PIN_TO_START_SCREEN: {
335 int string_id = IDS_PIN_TO_START_SCREEN;
336 WebContents* web_contents =
337 browser_->tab_strip_model()->GetActiveWebContents();
338 MetroPinTabHelper* tab_helper =
339 web_contents ? MetroPinTabHelper::FromWebContents(web_contents)
340 : NULL;
341 if (tab_helper && tab_helper->IsPinned())
342 string_id = IDS_UNPIN_FROM_START_SCREEN;
343 return l10n_util::GetStringUTF16(string_id);
345 #endif
346 case IDC_UPGRADE_DIALOG:
347 return GetUpgradeDialogMenuItemName();
348 case IDC_SHOW_SIGNIN:
349 DCHECK(!switches::IsNewAvatarMenu());
350 return signin_ui_util::GetSigninMenuLabel(
351 browser_->profile()->GetOriginalProfile());
352 default:
353 NOTREACHED();
354 return base::string16();
358 bool WrenchMenuModel::GetIconForCommandId(int command_id,
359 gfx::Image* icon) const {
360 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
361 switch (command_id) {
362 case IDC_UPGRADE_DIALOG: {
363 if (UpgradeDetector::GetInstance()->notify_upgrade()) {
364 *icon = rb.GetNativeImageNamed(
365 UpgradeDetector::GetInstance()->GetIconResourceID());
366 return true;
368 return false;
370 case IDC_SHOW_SIGNIN: {
371 DCHECK(!switches::IsNewAvatarMenu());
372 GlobalError* error = signin_ui_util::GetSignedInServiceError(
373 browser_->profile()->GetOriginalProfile());
374 if (error) {
375 int icon_id = error->MenuItemIconResourceID();
376 if (icon_id) {
377 *icon = rb.GetNativeImageNamed(icon_id);
378 return true;
381 return false;
383 default:
384 break;
386 return false;
389 void WrenchMenuModel::ExecuteCommand(int command_id, int event_flags) {
390 GlobalError* error = GlobalErrorServiceFactory::GetForProfile(
391 browser_->profile())->GetGlobalErrorByMenuItemCommandID(command_id);
392 if (error) {
393 error->ExecuteMenuItem(browser_);
394 return;
397 if (!switches::IsNewAvatarMenu() && command_id == IDC_SHOW_SIGNIN) {
398 // If a custom error message is being shown, handle it.
399 GlobalError* error = signin_ui_util::GetSignedInServiceError(
400 browser_->profile()->GetOriginalProfile());
401 if (error) {
402 error->ExecuteMenuItem(browser_);
403 return;
407 if (command_id == IDC_HELP_PAGE_VIA_MENU)
408 content::RecordAction(UserMetricsAction("ShowHelpTabViaWrenchMenu"));
410 if (command_id == IDC_FULLSCREEN) {
411 // We issue the UMA command here and not in BrowserCommandController or even
412 // FullscreenController since we want to be able to distinguish this event
413 // and a menu which is under development.
414 content::RecordAction(UserMetricsAction("EnterFullScreenWithWrenchMenu"));
417 chrome::ExecuteCommand(browser_, command_id);
420 bool WrenchMenuModel::IsCommandIdChecked(int command_id) const {
421 if (command_id == IDC_SHOW_BOOKMARK_BAR) {
422 return browser_->profile()->GetPrefs()->GetBoolean(
423 bookmarks::prefs::kShowBookmarkBar);
424 } else if (command_id == IDC_PROFILING_ENABLED) {
425 return Profiling::BeingProfiled();
426 } else if (command_id == IDC_TOGGLE_REQUEST_TABLET_SITE) {
427 return chrome::IsRequestingTabletSite(browser_);
430 return false;
433 bool WrenchMenuModel::IsCommandIdEnabled(int command_id) const {
434 GlobalError* error = GlobalErrorServiceFactory::GetForProfile(
435 browser_->profile())->GetGlobalErrorByMenuItemCommandID(command_id);
436 if (error)
437 return true;
439 return chrome::IsCommandEnabled(browser_, command_id);
442 bool WrenchMenuModel::IsCommandIdVisible(int command_id) const {
443 switch (command_id) {
444 #if defined(OS_WIN)
445 case IDC_VIEW_INCOMPATIBILITIES: {
446 EnumerateModulesModel* loaded_modules =
447 EnumerateModulesModel::GetInstance();
448 if (loaded_modules->confirmed_bad_modules_detected() <= 0)
449 return false;
450 // We'll leave the wrench adornment on until the user clicks the link.
451 if (loaded_modules->modules_to_notify_about() <= 0)
452 loaded_modules->AcknowledgeConflictNotification();
453 return true;
455 case IDC_PIN_TO_START_SCREEN:
456 return base::win::IsMetroProcess();
457 #else
458 case IDC_VIEW_INCOMPATIBILITIES:
459 case IDC_PIN_TO_START_SCREEN:
460 return false;
461 #endif
462 case IDC_UPGRADE_DIALOG:
463 return UpgradeDetector::GetInstance()->notify_upgrade();
464 #if !defined(OS_LINUX) || defined(USE_AURA)
465 case IDC_BOOKMARK_PAGE:
466 return !chrome::ShouldRemoveBookmarkThisPageUI(browser_->profile());
467 case IDC_BOOKMARK_ALL_TABS:
468 return !chrome::ShouldRemoveBookmarkOpenPagesUI(browser_->profile());
469 #endif
470 default:
471 return true;
475 bool WrenchMenuModel::GetAcceleratorForCommandId(
476 int command_id,
477 ui::Accelerator* accelerator) {
478 return provider_->GetAcceleratorForCommandId(command_id, accelerator);
481 void WrenchMenuModel::ActiveTabChanged(WebContents* old_contents,
482 WebContents* new_contents,
483 int index,
484 int reason) {
485 // The user has switched between tabs and the new tab may have a different
486 // zoom setting.
487 UpdateZoomControls();
490 void WrenchMenuModel::TabReplacedAt(TabStripModel* tab_strip_model,
491 WebContents* old_contents,
492 WebContents* new_contents,
493 int index) {
494 UpdateZoomControls();
497 void WrenchMenuModel::TabStripModelDeleted() {
498 // During views shutdown, the tabstrip model/browser is deleted first, while
499 // it is the opposite in gtk land.
500 tab_strip_model_->RemoveObserver(this);
501 tab_strip_model_ = NULL;
504 void WrenchMenuModel::Observe(int type,
505 const content::NotificationSource& source,
506 const content::NotificationDetails& details) {
507 DCHECK(type == content::NOTIFICATION_NAV_ENTRY_COMMITTED);
508 UpdateZoomControls();
511 // For testing.
512 WrenchMenuModel::WrenchMenuModel()
513 : ui::SimpleMenuModel(this),
514 provider_(NULL),
515 browser_(NULL),
516 tab_strip_model_(NULL) {
519 bool WrenchMenuModel::ShouldShowNewIncognitoWindowMenuItem() {
520 if (browser_->profile()->IsSupervised())
521 return false;
523 return !browser_->profile()->IsGuestSession();
526 void WrenchMenuModel::Build() {
527 #if defined(OS_WIN)
528 AddItem(IDC_VIEW_INCOMPATIBILITIES,
529 l10n_util::GetStringUTF16(IDS_VIEW_INCOMPATIBILITIES));
530 EnumerateModulesModel* model =
531 EnumerateModulesModel::GetInstance();
532 if (model->modules_to_notify_about() > 0 ||
533 model->confirmed_bad_modules_detected() > 0)
534 AddSeparator(ui::NORMAL_SEPARATOR);
535 #endif
537 if (extensions::FeatureSwitch::extension_action_redesign()->IsEnabled())
538 CreateExtensionToolbarOverflowMenu();
540 AddItemWithStringId(IDC_NEW_TAB, IDS_NEW_TAB);
541 AddItemWithStringId(IDC_NEW_WINDOW, IDS_NEW_WINDOW);
543 if (ShouldShowNewIncognitoWindowMenuItem())
544 AddItemWithStringId(IDC_NEW_INCOGNITO_WINDOW, IDS_NEW_INCOGNITO_WINDOW);
546 bookmark_sub_menu_model_.reset(new BookmarkSubMenuModel(this, browser_));
547 AddSubMenuWithStringId(IDC_BOOKMARKS_MENU, IDS_BOOKMARKS_MENU,
548 bookmark_sub_menu_model_.get());
550 if (!browser_->profile()->IsOffTheRecord()) {
551 recent_tabs_sub_menu_model_.reset(new RecentTabsSubMenuModel(provider_,
552 browser_,
553 NULL));
554 AddSubMenuWithStringId(IDC_RECENT_TABS_MENU, IDS_RECENT_TABS_MENU,
555 recent_tabs_sub_menu_model_.get());
558 #if defined(OS_WIN)
559 // Windows 8 can support ASH mode using WARP, but Windows 7 requires a working
560 // GPU compositor.
561 if ((base::win::GetVersion() >= base::win::VERSION_WIN7 &&
562 content::GpuDataManager::GetInstance()->CanUseGpuBrowserCompositor()) ||
563 (base::win::GetVersion() >= base::win::VERSION_WIN8)) {
564 if (browser_->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH) {
565 // ASH/Metro mode, add the 'Relaunch Chrome in desktop mode'.
566 AddSeparator(ui::NORMAL_SEPARATOR);
567 AddItemWithStringId(IDC_WIN_DESKTOP_RESTART, IDS_WIN_DESKTOP_RESTART);
568 } else {
569 // In Windows 8 desktop, add the 'Relaunch Chrome in Windows 8 mode'.
570 // In Windows 7 desktop, add the 'Relaunch Chrome in Windows ASH mode'
571 AddSeparator(ui::NORMAL_SEPARATOR);
572 if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
573 AddItemWithStringId(IDC_WIN8_METRO_RESTART, IDS_WIN8_METRO_RESTART);
574 } else {
575 AddItemWithStringId(IDC_WIN_CHROMEOS_RESTART, IDS_WIN_CHROMEOS_RESTART);
579 #endif
581 // Append the full menu including separators. The final separator only gets
582 // appended when this is a touch menu - otherwise it would get added twice.
583 CreateCutCopyPasteMenu();
585 if (CommandLine::ForCurrentProcess()->HasSwitch(
586 switches::kEnableDomDistiller)) {
587 AddItemWithStringId(IDC_DISTILL_PAGE, IDS_DISTILL_PAGE);
590 AddItemWithStringId(IDC_SAVE_PAGE, IDS_SAVE_PAGE);
591 AddItemWithStringId(IDC_FIND, IDS_FIND);
592 AddItemWithStringId(IDC_PRINT, IDS_PRINT);
594 tools_menu_model_.reset(new ToolsMenuModel(this, browser_));
595 CreateZoomMenu();
597 AddItemWithStringId(IDC_SHOW_HISTORY, IDS_SHOW_HISTORY);
598 AddItemWithStringId(IDC_SHOW_DOWNLOADS, IDS_SHOW_DOWNLOADS);
599 AddSeparator(ui::NORMAL_SEPARATOR);
601 #if !defined(OS_CHROMEOS)
602 if (!switches::IsNewAvatarMenu()) {
603 // No "Sign in to Chromium..." menu item on ChromeOS.
604 SigninManager* signin = SigninManagerFactory::GetForProfile(
605 browser_->profile()->GetOriginalProfile());
606 if (signin && signin->IsSigninAllowed()) {
607 const base::string16 short_product_name =
608 l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME);
609 AddItem(IDC_SHOW_SYNC_SETUP, l10n_util::GetStringFUTF16(
610 IDS_SYNC_MENU_PRE_SYNCED_LABEL, short_product_name));
611 AddSeparator(ui::NORMAL_SEPARATOR);
614 #endif
616 AddItemWithStringId(IDC_OPTIONS, IDS_SETTINGS);
618 // On ChromeOS we don't want the about menu option.
619 #if !defined(OS_CHROMEOS)
620 AddItem(IDC_ABOUT, l10n_util::GetStringUTF16(IDS_ABOUT));
621 #endif
623 #if defined(GOOGLE_CHROME_BUILD)
624 help_menu_model_.reset(new HelpMenuModel(this, browser_));
625 AddSubMenuWithStringId(IDC_HELP_MENU, IDS_HELP_MENU,
626 help_menu_model_.get());
627 #endif
629 #if defined(OS_CHROMEOS)
630 if (CommandLine::ForCurrentProcess()->HasSwitch(
631 chromeos::switches::kEnableRequestTabletSite))
632 AddCheckItemWithStringId(IDC_TOGGLE_REQUEST_TABLET_SITE,
633 IDS_TOGGLE_REQUEST_TABLET_SITE);
634 #endif
636 if (browser_defaults::kShowUpgradeMenuItem)
637 AddItem(IDC_UPGRADE_DIALOG, GetUpgradeDialogMenuItemName());
639 #if defined(OS_WIN)
640 SetIcon(GetIndexOfCommandId(IDC_VIEW_INCOMPATIBILITIES),
641 ui::ResourceBundle::GetSharedInstance().
642 GetNativeImageNamed(IDR_INPUT_ALERT_MENU));
643 #endif
645 AddGlobalErrorMenuItems();
647 AddSeparator(ui::NORMAL_SEPARATOR);
648 AddSubMenuWithStringId(
649 IDC_ZOOM_MENU, IDS_MORE_TOOLS_MENU, tools_menu_model_.get());
651 bool show_exit_menu = browser_defaults::kShowExitMenuItem;
652 #if defined(OS_WIN)
653 if (browser_->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH)
654 show_exit_menu = false;
655 #endif
657 if (show_exit_menu) {
658 AddSeparator(ui::NORMAL_SEPARATOR);
659 AddItemWithStringId(IDC_EXIT, IDS_EXIT);
662 RemoveTrailingSeparators();
665 void WrenchMenuModel::AddGlobalErrorMenuItems() {
666 // TODO(sail): Currently we only build the wrench menu once per browser
667 // window. This means that if a new error is added after the menu is built
668 // it won't show in the existing wrench menu. To fix this we need to some
669 // how update the menu if new errors are added.
670 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
671 // GetSignedInServiceErrors() can modify the global error list, so call it
672 // before iterating through that list below.
673 std::vector<GlobalError*> signin_errors;
674 signin_errors = signin_ui_util::GetSignedInServiceErrors(
675 browser_->profile()->GetOriginalProfile());
676 const GlobalErrorService::GlobalErrorList& errors =
677 GlobalErrorServiceFactory::GetForProfile(browser_->profile())->errors();
678 for (GlobalErrorService::GlobalErrorList::const_iterator
679 it = errors.begin(); it != errors.end(); ++it) {
680 GlobalError* error = *it;
681 DCHECK(error);
682 if (error->HasMenuItem()) {
683 #if !defined(OS_CHROMEOS)
684 // Don't add a signin error if it's already being displayed elsewhere.
685 if (std::find(signin_errors.begin(), signin_errors.end(), error) !=
686 signin_errors.end()) {
687 MenuModel* model = this;
688 int index = 0;
689 if (MenuModel::GetModelAndIndexForCommandId(
690 IDC_SHOW_SIGNIN, &model, &index)) {
691 continue;
694 #endif
696 AddItem(error->MenuItemCommandID(), error->MenuItemLabel());
697 int icon_id = error->MenuItemIconResourceID();
698 if (icon_id) {
699 const gfx::Image& image = rb.GetNativeImageNamed(icon_id);
700 SetIcon(GetIndexOfCommandId(error->MenuItemCommandID()),
701 image);
707 void WrenchMenuModel::CreateExtensionToolbarOverflowMenu() {
708 #if defined(TOOLKIT_VIEWS)
709 AddItem(IDC_EXTENSIONS_OVERFLOW_MENU, base::string16());
710 // We only add the separator if there are > 0 items to show in the overflow.
711 extensions::ExtensionToolbarModel* toolbar_model =
712 extensions::ExtensionToolbarModel::Get(browser_->profile());
713 // A count of -1 means all actions are visible.
714 if (toolbar_model->GetVisibleIconCount() != -1)
715 AddSeparator(ui::UPPER_SEPARATOR);
716 #endif // defined(TOOLKIT_VIEWS)
719 void WrenchMenuModel::CreateCutCopyPasteMenu() {
720 AddSeparator(ui::LOWER_SEPARATOR);
722 #if defined(OS_POSIX) && !defined(TOOLKIT_VIEWS)
723 // WARNING: Mac does not use the ButtonMenuItemModel, but instead defines the
724 // layout for this menu item in Toolbar.xib. It does, however, use the
725 // command_id value from AddButtonItem() to identify this special item.
726 edit_menu_item_model_.reset(new ui::ButtonMenuItemModel(IDS_EDIT, this));
727 edit_menu_item_model_->AddGroupItemWithStringId(IDC_CUT, IDS_CUT);
728 edit_menu_item_model_->AddGroupItemWithStringId(IDC_COPY, IDS_COPY);
729 edit_menu_item_model_->AddGroupItemWithStringId(IDC_PASTE, IDS_PASTE);
730 AddButtonItem(IDC_EDIT_MENU, edit_menu_item_model_.get());
731 #else
732 // WARNING: views/wrench_menu assumes these items are added in this order. If
733 // you change the order you'll need to update wrench_menu as well.
734 AddItemWithStringId(IDC_CUT, IDS_CUT);
735 AddItemWithStringId(IDC_COPY, IDS_COPY);
736 AddItemWithStringId(IDC_PASTE, IDS_PASTE);
737 #endif
739 AddSeparator(ui::UPPER_SEPARATOR);
742 void WrenchMenuModel::CreateZoomMenu() {
743 // This menu needs to be enclosed by separators.
744 AddSeparator(ui::LOWER_SEPARATOR);
746 #if defined(OS_POSIX) && !defined(TOOLKIT_VIEWS)
747 // WARNING: Mac does not use the ButtonMenuItemModel, but instead defines the
748 // layout for this menu item in Toolbar.xib. It does, however, use the
749 // command_id value from AddButtonItem() to identify this special item.
750 zoom_menu_item_model_.reset(
751 new ui::ButtonMenuItemModel(IDS_ZOOM_MENU, this));
752 zoom_menu_item_model_->AddGroupItemWithStringId(
753 IDC_ZOOM_MINUS, IDS_ZOOM_MINUS2);
754 zoom_menu_item_model_->AddButtonLabel(IDC_ZOOM_PERCENT_DISPLAY,
755 IDS_ZOOM_PLUS2);
756 zoom_menu_item_model_->AddGroupItemWithStringId(
757 IDC_ZOOM_PLUS, IDS_ZOOM_PLUS2);
758 zoom_menu_item_model_->AddSpace();
759 zoom_menu_item_model_->AddItemWithImage(
760 IDC_FULLSCREEN, IDR_FULLSCREEN_MENU_BUTTON);
761 AddButtonItem(IDC_ZOOM_MENU, zoom_menu_item_model_.get());
762 #else
763 // WARNING: views/wrench_menu assumes these items are added in this order. If
764 // you change the order you'll need to update wrench_menu as well.
765 AddItemWithStringId(IDC_ZOOM_MINUS, IDS_ZOOM_MINUS);
766 AddItemWithStringId(IDC_ZOOM_PLUS, IDS_ZOOM_PLUS);
767 AddItemWithStringId(IDC_FULLSCREEN, IDS_FULLSCREEN);
768 #endif
770 AddSeparator(ui::UPPER_SEPARATOR);
773 void WrenchMenuModel::UpdateZoomControls() {
774 int zoom_percent = 100;
775 if (browser_->tab_strip_model()->GetActiveWebContents()) {
776 zoom_percent = ZoomController::FromWebContents(
777 browser_->tab_strip_model()->GetActiveWebContents())
778 ->GetZoomPercent();
780 zoom_label_ = l10n_util::GetStringFUTF16(
781 IDS_ZOOM_PERCENT, base::IntToString16(zoom_percent));
784 void WrenchMenuModel::OnZoomLevelChanged(
785 const content::HostZoomMap::ZoomLevelChange& change) {
786 UpdateZoomControls();