ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / chrome / browser / ui / toolbar / wrench_menu_model.cc
blobad3717f77a527f3784655e79eb19dc5dbfda5d5b
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/metrics/histogram.h"
12 #include "base/prefs/pref_service.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "chrome/app/chrome_command_ids.h"
17 #include "chrome/browser/browser_process.h"
18 #include "chrome/browser/defaults.h"
19 #include "chrome/browser/extensions/extension_toolbar_model.h"
20 #include "chrome/browser/extensions/extension_util.h"
21 #include "chrome/browser/prefs/incognito_mode_prefs.h"
22 #include "chrome/browser/profiles/profile.h"
23 #include "chrome/browser/profiles/profile_manager.h"
24 #include "chrome/browser/search/search.h"
25 #include "chrome/browser/signin/signin_manager_factory.h"
26 #include "chrome/browser/signin/signin_ui_util.h"
27 #include "chrome/browser/task_manager/task_manager.h"
28 #include "chrome/browser/ui/bookmarks/bookmark_utils.h"
29 #include "chrome/browser/ui/browser.h"
30 #include "chrome/browser/ui/browser_commands.h"
31 #include "chrome/browser/ui/browser_finder.h"
32 #include "chrome/browser/ui/browser_window.h"
33 #include "chrome/browser/ui/global_error/global_error.h"
34 #include "chrome/browser/ui/global_error/global_error_service.h"
35 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
36 #include "chrome/browser/ui/tabs/tab_strip_model.h"
37 #include "chrome/browser/ui/toolbar/bookmark_sub_menu_model.h"
38 #include "chrome/browser/ui/toolbar/encoding_menu_controller.h"
39 #include "chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.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 "components/ui/zoom/zoom_controller.h"
50 #include "components/ui/zoom/zoom_event_manager.h"
51 #include "content/public/browser/host_zoom_map.h"
52 #include "content/public/browser/navigation_entry.h"
53 #include "content/public/browser/notification_service.h"
54 #include "content/public/browser/notification_source.h"
55 #include "content/public/browser/notification_types.h"
56 #include "content/public/browser/user_metrics.h"
57 #include "content/public/browser/web_contents.h"
58 #include "extensions/common/feature_switch.h"
59 #include "grit/theme_resources.h"
60 #include "ui/base/l10n/l10n_util.h"
61 #include "ui/base/layout.h"
62 #include "ui/base/models/button_menu_item_model.h"
63 #include "ui/base/resource/resource_bundle.h"
64 #include "ui/gfx/image/image.h"
65 #include "ui/gfx/image/image_skia.h"
67 #if defined(OS_CHROMEOS)
68 #include "chromeos/chromeos_switches.h"
69 #endif
71 #if defined(OS_WIN)
72 #include "base/win/metro.h"
73 #include "base/win/windows_version.h"
74 #include "chrome/browser/enumerate_modules_model_win.h"
75 #include "chrome/browser/ui/metro_pin_tab_helper_win.h"
76 #include "content/public/browser/gpu_data_manager.h"
77 #endif
79 #if defined(USE_ASH)
80 #include "ash/shell.h"
81 #endif
83 using base::UserMetricsAction;
84 using content::WebContents;
86 namespace {
87 // Conditionally return the update app menu item title based on upgrade detector
88 // state.
89 base::string16 GetUpgradeDialogMenuItemName() {
90 if (UpgradeDetector::GetInstance()->is_outdated_install() ||
91 UpgradeDetector::GetInstance()->is_outdated_install_no_au()) {
92 return l10n_util::GetStringUTF16(IDS_UPGRADE_BUBBLE_MENU_ITEM);
93 } else {
94 return l10n_util::GetStringUTF16(IDS_UPDATE_NOW);
98 } // namespace
100 ////////////////////////////////////////////////////////////////////////////////
101 // EncodingMenuModel
103 EncodingMenuModel::EncodingMenuModel(Browser* browser)
104 : ui::SimpleMenuModel(this),
105 browser_(browser) {
106 Build();
109 EncodingMenuModel::~EncodingMenuModel() {
112 void EncodingMenuModel::Build() {
113 EncodingMenuController::EncodingMenuItemList encoding_menu_items;
114 EncodingMenuController encoding_menu_controller;
115 encoding_menu_controller.GetEncodingMenuItems(browser_->profile(),
116 &encoding_menu_items);
118 int group_id = 0;
119 EncodingMenuController::EncodingMenuItemList::iterator it =
120 encoding_menu_items.begin();
121 for (; it != encoding_menu_items.end(); ++it) {
122 int id = it->first;
123 base::string16& label = it->second;
124 if (id == 0) {
125 AddSeparator(ui::NORMAL_SEPARATOR);
126 } else {
127 if (id == IDC_ENCODING_AUTO_DETECT) {
128 AddCheckItem(id, label);
129 } else {
130 // Use the id of the first radio command as the id of the group.
131 if (group_id <= 0)
132 group_id = id;
133 AddRadioItem(id, label, group_id);
139 bool EncodingMenuModel::IsCommandIdChecked(int command_id) const {
140 WebContents* current_tab =
141 browser_->tab_strip_model()->GetActiveWebContents();
142 if (!current_tab)
143 return false;
144 EncodingMenuController controller;
145 return controller.IsItemChecked(browser_->profile(),
146 current_tab->GetEncoding(), command_id);
149 bool EncodingMenuModel::IsCommandIdEnabled(int command_id) const {
150 bool enabled = chrome::IsCommandEnabled(browser_, command_id);
151 // Special handling for the contents of the Encoding submenu. On Mac OS,
152 // instead of enabling/disabling the top-level menu item, the submenu's
153 // contents get disabled, per Apple's HIG.
154 #if defined(OS_MACOSX)
155 enabled &= chrome::IsCommandEnabled(browser_, IDC_ENCODING_MENU);
156 #endif
157 return enabled;
160 bool EncodingMenuModel::GetAcceleratorForCommandId(
161 int command_id,
162 ui::Accelerator* accelerator) {
163 return false;
166 void EncodingMenuModel::ExecuteCommand(int command_id, int event_flags) {
167 chrome::ExecuteCommand(browser_, command_id);
170 ////////////////////////////////////////////////////////////////////////////////
171 // ZoomMenuModel
173 ZoomMenuModel::ZoomMenuModel(ui::SimpleMenuModel::Delegate* delegate)
174 : SimpleMenuModel(delegate) {
175 Build();
178 ZoomMenuModel::~ZoomMenuModel() {
181 void ZoomMenuModel::Build() {
182 AddItemWithStringId(IDC_ZOOM_PLUS, IDS_ZOOM_PLUS);
183 AddItemWithStringId(IDC_ZOOM_NORMAL, IDS_ZOOM_NORMAL);
184 AddItemWithStringId(IDC_ZOOM_MINUS, IDS_ZOOM_MINUS);
187 ////////////////////////////////////////////////////////////////////////////////
188 // HelpMenuModel
190 #if defined(GOOGLE_CHROME_BUILD)
192 class WrenchMenuModel::HelpMenuModel : public ui::SimpleMenuModel {
193 public:
194 HelpMenuModel(ui::SimpleMenuModel::Delegate* delegate,
195 Browser* browser)
196 : SimpleMenuModel(delegate) {
197 Build(browser);
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::IsNewBookmarkAppsEnabled()) {
243 #if defined(OS_MACOSX)
244 int string_id = IDS_ADD_TO_APPLICATIONS;
245 #elif defined(OS_WIN)
246 int string_id = IDS_ADD_TO_TASKBAR;
247 #else
248 int string_id = IDS_ADD_TO_DESKTOP;
249 #endif
250 #if defined(USE_ASH)
251 if (browser->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH)
252 string_id = IDS_ADD_TO_SHELF;
253 #endif
254 AddItemWithStringId(IDC_CREATE_HOSTED_APP, string_id);
255 AddSeparator(ui::NORMAL_SEPARATOR);
256 } else if (show_create_shortcuts) {
257 AddItemWithStringId(IDC_CREATE_SHORTCUTS, IDS_CREATE_SHORTCUTS);
258 AddSeparator(ui::NORMAL_SEPARATOR);
261 AddItemWithStringId(IDC_MANAGE_EXTENSIONS, IDS_SHOW_EXTENSIONS);
263 if (chrome::CanOpenTaskManager())
264 AddItemWithStringId(IDC_TASK_MANAGER, IDS_TASK_MANAGER);
266 AddItemWithStringId(IDC_CLEAR_BROWSING_DATA, IDS_CLEAR_BROWSING_DATA);
268 #if defined(OS_CHROMEOS)
269 AddItemWithStringId(IDC_TAKE_SCREENSHOT, IDS_TAKE_SCREENSHOT);
270 #endif
272 AddSeparator(ui::NORMAL_SEPARATOR);
274 encoding_menu_model_.reset(new EncodingMenuModel(browser));
275 AddSubMenuWithStringId(IDC_ENCODING_MENU, IDS_ENCODING_MENU,
276 encoding_menu_model_.get());
277 AddItemWithStringId(IDC_VIEW_SOURCE, IDS_VIEW_SOURCE);
278 AddItemWithStringId(IDC_DEV_TOOLS, IDS_DEV_TOOLS);
279 AddItemWithStringId(IDC_DEV_TOOLS_CONSOLE, IDS_DEV_TOOLS_CONSOLE);
280 AddItemWithStringId(IDC_DEV_TOOLS_DEVICES, IDS_DEV_TOOLS_DEVICES);
282 #if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC)
283 AddSeparator(ui::NORMAL_SEPARATOR);
284 AddCheckItemWithStringId(IDC_PROFILING_ENABLED, IDS_PROFILING_ENABLED);
285 #endif
288 ////////////////////////////////////////////////////////////////////////////////
289 // WrenchMenuModel
291 WrenchMenuModel::WrenchMenuModel(ui::AcceleratorProvider* provider,
292 Browser* browser)
293 : ui::SimpleMenuModel(this),
294 uma_action_recorded_(false),
295 provider_(provider),
296 browser_(browser),
297 tab_strip_model_(browser_->tab_strip_model()) {
298 Build();
299 UpdateZoomControls();
301 browser_zoom_subscription_ =
302 ui_zoom::ZoomEventManager::GetForBrowserContext(browser->profile())
303 ->AddZoomLevelChangedCallback(base::Bind(
304 &WrenchMenuModel::OnZoomLevelChanged, base::Unretained(this)));
306 tab_strip_model_->AddObserver(this);
308 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
309 content::NotificationService::AllSources());
312 WrenchMenuModel::~WrenchMenuModel() {
313 if (tab_strip_model_)
314 tab_strip_model_->RemoveObserver(this);
317 bool WrenchMenuModel::DoesCommandIdDismissMenu(int command_id) const {
318 return command_id != IDC_ZOOM_MINUS && command_id != IDC_ZOOM_PLUS;
321 bool WrenchMenuModel::IsItemForCommandIdDynamic(int command_id) const {
322 return command_id == IDC_ZOOM_PERCENT_DISPLAY ||
323 #if defined(OS_MACOSX)
324 command_id == IDC_FULLSCREEN ||
325 #elif defined(OS_WIN)
326 command_id == IDC_PIN_TO_START_SCREEN ||
327 #endif
328 command_id == IDC_UPGRADE_DIALOG ||
329 (!switches::IsNewAvatarMenu() && command_id == IDC_SHOW_SIGNIN);
332 base::string16 WrenchMenuModel::GetLabelForCommandId(int command_id) const {
333 switch (command_id) {
334 case IDC_ZOOM_PERCENT_DISPLAY:
335 return zoom_label_;
336 #if defined(OS_MACOSX)
337 case IDC_FULLSCREEN: {
338 int string_id = IDS_ENTER_FULLSCREEN_MAC; // Default to Enter.
339 // Note: On startup, |window()| may be NULL.
340 if (browser_->window() && browser_->window()->IsFullscreen())
341 string_id = IDS_EXIT_FULLSCREEN_MAC;
342 return l10n_util::GetStringUTF16(string_id);
344 #elif defined(OS_WIN)
345 case IDC_PIN_TO_START_SCREEN: {
346 int string_id = IDS_PIN_TO_START_SCREEN;
347 WebContents* web_contents =
348 browser_->tab_strip_model()->GetActiveWebContents();
349 MetroPinTabHelper* tab_helper =
350 web_contents ? MetroPinTabHelper::FromWebContents(web_contents)
351 : NULL;
352 if (tab_helper && tab_helper->IsPinned())
353 string_id = IDS_UNPIN_FROM_START_SCREEN;
354 return l10n_util::GetStringUTF16(string_id);
356 #endif
357 case IDC_UPGRADE_DIALOG:
358 return GetUpgradeDialogMenuItemName();
359 case IDC_SHOW_SIGNIN:
360 DCHECK(!switches::IsNewAvatarMenu());
361 return signin_ui_util::GetSigninMenuLabel(
362 browser_->profile()->GetOriginalProfile());
363 default:
364 NOTREACHED();
365 return base::string16();
369 bool WrenchMenuModel::GetIconForCommandId(int command_id,
370 gfx::Image* icon) const {
371 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
372 switch (command_id) {
373 case IDC_UPGRADE_DIALOG: {
374 if (UpgradeDetector::GetInstance()->notify_upgrade()) {
375 *icon = rb.GetNativeImageNamed(
376 UpgradeDetector::GetInstance()->GetIconResourceID());
377 return true;
379 return false;
381 case IDC_SHOW_SIGNIN: {
382 DCHECK(!switches::IsNewAvatarMenu());
383 GlobalError* error = signin_ui_util::GetSignedInServiceError(
384 browser_->profile()->GetOriginalProfile());
385 if (error) {
386 int icon_id = error->MenuItemIconResourceID();
387 if (icon_id) {
388 *icon = rb.GetNativeImageNamed(icon_id);
389 return true;
392 return false;
394 default:
395 break;
397 return false;
400 void WrenchMenuModel::ExecuteCommand(int command_id, int event_flags) {
401 GlobalError* error = GlobalErrorServiceFactory::GetForProfile(
402 browser_->profile())->GetGlobalErrorByMenuItemCommandID(command_id);
403 if (error) {
404 error->ExecuteMenuItem(browser_);
405 return;
408 if (!switches::IsNewAvatarMenu() && command_id == IDC_SHOW_SIGNIN) {
409 // If a custom error message is being shown, handle it.
410 GlobalError* error = signin_ui_util::GetSignedInServiceError(
411 browser_->profile()->GetOriginalProfile());
412 if (error) {
413 error->ExecuteMenuItem(browser_);
414 return;
418 LogMenuMetrics(command_id);
419 chrome::ExecuteCommand(browser_, command_id);
422 void WrenchMenuModel::LogMenuMetrics(int command_id) {
423 base::TimeDelta delta = timer_.Elapsed();
425 switch (command_id) {
426 case IDC_NEW_TAB:
427 if (!uma_action_recorded_)
428 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.NewTab", delta);
429 LogMenuAction(MENU_ACTION_NEW_TAB);
430 break;
431 case IDC_NEW_WINDOW:
432 if (!uma_action_recorded_)
433 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.NewWindow", delta);
434 LogMenuAction(MENU_ACTION_NEW_WINDOW);
435 break;
436 case IDC_NEW_INCOGNITO_WINDOW:
437 if (!uma_action_recorded_) {
438 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.NewIncognitoWindow",
439 delta);
441 LogMenuAction(MENU_ACTION_NEW_INCOGNITO_WINDOW);
442 break;
444 // Bookmarks sub menu.
445 case IDC_SHOW_BOOKMARK_BAR:
446 if (!uma_action_recorded_) {
447 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.ShowBookmarkBar",
448 delta);
450 LogMenuAction(MENU_ACTION_SHOW_BOOKMARK_BAR);
451 break;
452 case IDC_SHOW_BOOKMARK_MANAGER:
453 if (!uma_action_recorded_) {
454 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.ShowBookmarkMgr",
455 delta);
457 LogMenuAction(MENU_ACTION_SHOW_BOOKMARK_MANAGER);
458 break;
459 case IDC_IMPORT_SETTINGS:
460 if (!uma_action_recorded_) {
461 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.ImportSettings",
462 delta);
464 LogMenuAction(MENU_ACTION_IMPORT_SETTINGS);
465 break;
466 case IDC_BOOKMARK_PAGE:
467 if (!uma_action_recorded_) {
468 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.BookmarkPage",
469 delta);
471 LogMenuAction(MENU_ACTION_BOOKMARK_PAGE);
472 break;
473 case IDC_BOOKMARK_ALL_TABS:
474 if (!uma_action_recorded_) {
475 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.BookmarkAllTabs",
476 delta);
478 LogMenuAction(MENU_ACTION_BOOKMARK_ALL_TABS);
479 break;
480 case IDC_PIN_TO_START_SCREEN:
481 if (!uma_action_recorded_) {
482 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.PinToStartScreen",
483 delta);
485 LogMenuAction(MENU_ACTION_PIN_TO_START_SCREEN);
486 break;
488 // Recent tabs menu.
489 case IDC_RESTORE_TAB:
490 if (!uma_action_recorded_)
491 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.RestoreTab", delta);
492 LogMenuAction(MENU_ACTION_RESTORE_TAB);
493 break;
495 // Windows.
496 case IDC_WIN_DESKTOP_RESTART:
497 if (!uma_action_recorded_) {
498 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.WinDesktopRestart",
499 delta);
501 LogMenuAction(MENU_ACTION_WIN_DESKTOP_RESTART);
502 break;
503 case IDC_WIN8_METRO_RESTART:
504 if (!uma_action_recorded_) {
505 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.Win8MetroRestart",
506 delta);
508 LogMenuAction(MENU_ACTION_WIN8_METRO_RESTART);
509 break;
511 case IDC_WIN_CHROMEOS_RESTART:
512 if (!uma_action_recorded_) {
513 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.ChromeOSRestart",
514 delta);
516 LogMenuAction(MENU_ACTION_WIN_CHROMEOS_RESTART);
517 break;
518 case IDC_DISTILL_PAGE:
519 if (!uma_action_recorded_) {
520 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.DistillPage",
521 delta);
523 LogMenuAction(MENU_ACTION_DISTILL_PAGE);
524 break;
525 case IDC_SAVE_PAGE:
526 if (!uma_action_recorded_)
527 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.SavePage", delta);
528 LogMenuAction(MENU_ACTION_SAVE_PAGE);
529 break;
530 case IDC_FIND:
531 if (!uma_action_recorded_)
532 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.Find", delta);
533 LogMenuAction(MENU_ACTION_FIND);
534 break;
535 case IDC_PRINT:
536 if (!uma_action_recorded_)
537 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.Print", delta);
538 LogMenuAction(MENU_ACTION_PRINT);
539 break;
541 // Edit menu.
542 case IDC_CUT:
543 if (!uma_action_recorded_)
544 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.Cut", delta);
545 LogMenuAction(MENU_ACTION_CUT);
546 break;
547 case IDC_COPY:
548 if (!uma_action_recorded_)
549 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.Copy", delta);
550 LogMenuAction(MENU_ACTION_COPY);
551 break;
552 case IDC_PASTE:
553 if (!uma_action_recorded_)
554 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.Paste", delta);
555 LogMenuAction(MENU_ACTION_PASTE);
556 break;
558 // Tools menu.
559 case IDC_CREATE_HOSTED_APP:
560 if (!uma_action_recorded_) {
561 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.CreateHostedApp",
562 delta);
564 LogMenuAction(MENU_ACTION_CREATE_HOSTED_APP);
565 break;
566 case IDC_CREATE_SHORTCUTS:
567 if (!uma_action_recorded_)
568 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.CreateShortcuts",
569 delta);
570 LogMenuAction(MENU_ACTION_CREATE_SHORTCUTS);
571 break;
572 case IDC_MANAGE_EXTENSIONS:
573 if (!uma_action_recorded_) {
574 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.ManageExtensions",
575 delta);
577 LogMenuAction(MENU_ACTION_MANAGE_EXTENSIONS);
578 break;
579 case IDC_TASK_MANAGER:
580 if (!uma_action_recorded_) {
581 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.TaskManager",
582 delta);
584 LogMenuAction(MENU_ACTION_TASK_MANAGER);
585 break;
586 case IDC_CLEAR_BROWSING_DATA:
587 if (!uma_action_recorded_) {
588 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.ClearBrowsingData",
589 delta);
591 LogMenuAction(MENU_ACTION_CLEAR_BROWSING_DATA);
592 break;
593 case IDC_VIEW_SOURCE:
594 if (!uma_action_recorded_)
595 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.ViewSource", delta);
596 LogMenuAction(MENU_ACTION_VIEW_SOURCE);
597 break;
598 case IDC_DEV_TOOLS:
599 if (!uma_action_recorded_)
600 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.DevTools", delta);
601 LogMenuAction(MENU_ACTION_DEV_TOOLS);
602 break;
603 case IDC_DEV_TOOLS_CONSOLE:
604 if (!uma_action_recorded_) {
605 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.DevToolsConsole",
606 delta);
608 LogMenuAction(MENU_ACTION_DEV_TOOLS_CONSOLE);
609 break;
610 case IDC_DEV_TOOLS_DEVICES:
611 if (!uma_action_recorded_) {
612 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.DevToolsDevices",
613 delta);
615 LogMenuAction(MENU_ACTION_DEV_TOOLS_DEVICES);
616 break;
617 case IDC_PROFILING_ENABLED:
618 if (!uma_action_recorded_) {
619 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.ProfilingEnabled",
620 delta);
622 LogMenuAction(MENU_ACTION_PROFILING_ENABLED);
623 break;
625 // Zoom menu
626 case IDC_ZOOM_MINUS:
627 if (!uma_action_recorded_) {
628 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.ZoomMinus", delta);
629 LogMenuAction(MENU_ACTION_ZOOM_MINUS);
631 break;
632 case IDC_ZOOM_PLUS:
633 if (!uma_action_recorded_) {
634 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.ZoomPlus", delta);
635 LogMenuAction(MENU_ACTION_ZOOM_PLUS);
637 break;
638 case IDC_FULLSCREEN:
639 content::RecordAction(UserMetricsAction("EnterFullScreenWithWrenchMenu"));
641 if (!uma_action_recorded_) {
642 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.EnterFullScreen",
643 delta);
645 LogMenuAction(MENU_ACTION_FULLSCREEN);
646 break;
648 case IDC_SHOW_HISTORY:
649 if (!uma_action_recorded_) {
650 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.ShowHistory",
651 delta);
653 LogMenuAction(MENU_ACTION_SHOW_HISTORY);
654 break;
655 case IDC_SHOW_DOWNLOADS:
656 if (!uma_action_recorded_) {
657 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.ShowDownloads",
658 delta);
660 LogMenuAction(MENU_ACTION_SHOW_DOWNLOADS);
661 break;
662 case IDC_SHOW_SYNC_SETUP:
663 if (!uma_action_recorded_) {
664 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.ShowSyncSetup",
665 delta);
667 LogMenuAction(MENU_ACTION_SHOW_SYNC_SETUP);
668 break;
669 case IDC_OPTIONS:
670 if (!uma_action_recorded_)
671 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.Settings", delta);
672 LogMenuAction(MENU_ACTION_OPTIONS);
673 break;
674 case IDC_ABOUT:
675 if (!uma_action_recorded_)
676 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.About", delta);
677 LogMenuAction(MENU_ACTION_ABOUT);
678 break;
680 // Help menu.
681 case IDC_HELP_PAGE_VIA_MENU:
682 content::RecordAction(UserMetricsAction("ShowHelpTabViaWrenchMenu"));
684 if (!uma_action_recorded_)
685 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.HelpPage", delta);
686 LogMenuAction(MENU_ACTION_HELP_PAGE_VIA_MENU);
687 break;
688 #if defined(GOOGLE_CHROME_BUILD)
689 case IDC_FEEDBACK:
690 if (!uma_action_recorded_)
691 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.Feedback", delta);
692 LogMenuAction(MENU_ACTION_FEEDBACK);
693 break;
694 #endif
696 case IDC_TOGGLE_REQUEST_TABLET_SITE:
697 if (!uma_action_recorded_) {
698 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.RequestTabletSite",
699 delta);
701 LogMenuAction(MENU_ACTION_TOGGLE_REQUEST_TABLET_SITE);
702 break;
703 case IDC_EXIT:
704 if (!uma_action_recorded_)
705 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.Exit", delta);
706 LogMenuAction(MENU_ACTION_EXIT);
707 break;
710 if (!uma_action_recorded_) {
711 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction", delta);
712 uma_action_recorded_ = true;
716 void WrenchMenuModel::LogMenuAction(int action_id) {
717 UMA_HISTOGRAM_ENUMERATION("WrenchMenu.MenuAction", action_id,
718 LIMIT_MENU_ACTION);
721 bool WrenchMenuModel::IsCommandIdChecked(int command_id) const {
722 if (command_id == IDC_SHOW_BOOKMARK_BAR) {
723 return browser_->profile()->GetPrefs()->GetBoolean(
724 bookmarks::prefs::kShowBookmarkBar);
725 } else if (command_id == IDC_PROFILING_ENABLED) {
726 return Profiling::BeingProfiled();
727 } else if (command_id == IDC_TOGGLE_REQUEST_TABLET_SITE) {
728 return chrome::IsRequestingTabletSite(browser_);
731 return false;
734 bool WrenchMenuModel::IsCommandIdEnabled(int command_id) const {
735 GlobalError* error = GlobalErrorServiceFactory::GetForProfile(
736 browser_->profile())->GetGlobalErrorByMenuItemCommandID(command_id);
737 if (error)
738 return true;
740 return chrome::IsCommandEnabled(browser_, command_id);
743 bool WrenchMenuModel::IsCommandIdVisible(int command_id) const {
744 switch (command_id) {
745 #if defined(OS_WIN)
746 case IDC_VIEW_INCOMPATIBILITIES: {
747 EnumerateModulesModel* loaded_modules =
748 EnumerateModulesModel::GetInstance();
749 if (loaded_modules->confirmed_bad_modules_detected() <= 0)
750 return false;
751 // We'll leave the wrench adornment on until the user clicks the link.
752 if (loaded_modules->modules_to_notify_about() <= 0)
753 loaded_modules->AcknowledgeConflictNotification();
754 return true;
756 case IDC_PIN_TO_START_SCREEN:
757 return base::win::IsMetroProcess();
758 #else
759 case IDC_VIEW_INCOMPATIBILITIES:
760 case IDC_PIN_TO_START_SCREEN:
761 return false;
762 #endif
763 case IDC_UPGRADE_DIALOG:
764 return UpgradeDetector::GetInstance()->notify_upgrade();
765 #if !defined(OS_LINUX) || defined(USE_AURA)
766 case IDC_BOOKMARK_PAGE:
767 return !chrome::ShouldRemoveBookmarkThisPageUI(browser_->profile());
768 case IDC_BOOKMARK_ALL_TABS:
769 return !chrome::ShouldRemoveBookmarkOpenPagesUI(browser_->profile());
770 #endif
771 default:
772 return true;
776 bool WrenchMenuModel::GetAcceleratorForCommandId(
777 int command_id,
778 ui::Accelerator* accelerator) {
779 return provider_->GetAcceleratorForCommandId(command_id, accelerator);
782 void WrenchMenuModel::ActiveTabChanged(WebContents* old_contents,
783 WebContents* new_contents,
784 int index,
785 int reason) {
786 // The user has switched between tabs and the new tab may have a different
787 // zoom setting.
788 UpdateZoomControls();
791 void WrenchMenuModel::TabReplacedAt(TabStripModel* tab_strip_model,
792 WebContents* old_contents,
793 WebContents* new_contents,
794 int index) {
795 UpdateZoomControls();
798 void WrenchMenuModel::TabStripModelDeleted() {
799 // During views shutdown, the tabstrip model/browser is deleted first, while
800 // it is the opposite in gtk land.
801 tab_strip_model_->RemoveObserver(this);
802 tab_strip_model_ = NULL;
805 void WrenchMenuModel::Observe(int type,
806 const content::NotificationSource& source,
807 const content::NotificationDetails& details) {
808 DCHECK(type == content::NOTIFICATION_NAV_ENTRY_COMMITTED);
809 UpdateZoomControls();
812 // For testing.
813 WrenchMenuModel::WrenchMenuModel()
814 : ui::SimpleMenuModel(this),
815 provider_(NULL),
816 browser_(NULL),
817 tab_strip_model_(NULL) {
820 bool WrenchMenuModel::ShouldShowNewIncognitoWindowMenuItem() {
821 if (browser_->profile()->IsGuestSession())
822 return false;
824 return IncognitoModePrefs::GetAvailability(browser_->profile()->GetPrefs()) !=
825 IncognitoModePrefs::DISABLED;
828 void WrenchMenuModel::Build() {
829 #if defined(OS_WIN)
830 AddItem(IDC_VIEW_INCOMPATIBILITIES,
831 l10n_util::GetStringUTF16(IDS_VIEW_INCOMPATIBILITIES));
832 EnumerateModulesModel* model =
833 EnumerateModulesModel::GetInstance();
834 if (model->modules_to_notify_about() > 0 ||
835 model->confirmed_bad_modules_detected() > 0)
836 AddSeparator(ui::NORMAL_SEPARATOR);
837 #endif
839 if (extensions::FeatureSwitch::extension_action_redesign()->IsEnabled())
840 CreateExtensionToolbarOverflowMenu();
842 AddItemWithStringId(IDC_NEW_TAB, IDS_NEW_TAB);
843 AddItemWithStringId(IDC_NEW_WINDOW, IDS_NEW_WINDOW);
845 if (ShouldShowNewIncognitoWindowMenuItem())
846 AddItemWithStringId(IDC_NEW_INCOGNITO_WINDOW, IDS_NEW_INCOGNITO_WINDOW);
848 if (!browser_->profile()->IsGuestSession()) {
849 bookmark_sub_menu_model_.reset(new BookmarkSubMenuModel(this, browser_));
850 AddSubMenuWithStringId(IDC_BOOKMARKS_MENU, IDS_BOOKMARKS_MENU,
851 bookmark_sub_menu_model_.get());
854 if (!browser_->profile()->IsOffTheRecord()) {
855 recent_tabs_sub_menu_model_.reset(new RecentTabsSubMenuModel(provider_,
856 browser_,
857 NULL));
858 AddSubMenuWithStringId(IDC_RECENT_TABS_MENU, IDS_RECENT_TABS_MENU,
859 recent_tabs_sub_menu_model_.get());
862 #if defined(OS_WIN)
863 base::win::Version min_version_for_ash_mode = base::win::VERSION_WIN8;
864 // Windows 7 ASH mode is only supported in DEBUG for now.
865 #if !defined(NDEBUG)
866 min_version_for_ash_mode = base::win::VERSION_WIN7;
867 #endif
868 // Windows 8 can support ASH mode using WARP, but Windows 7 requires a working
869 // GPU compositor.
870 if ((base::win::GetVersion() >= min_version_for_ash_mode &&
871 content::GpuDataManager::GetInstance()->CanUseGpuBrowserCompositor()) ||
872 (base::win::GetVersion() >= base::win::VERSION_WIN8)) {
873 if (browser_->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH) {
874 // ASH/Metro mode, add the 'Relaunch Chrome in desktop mode'.
875 AddSeparator(ui::NORMAL_SEPARATOR);
876 AddItemWithStringId(IDC_WIN_DESKTOP_RESTART, IDS_WIN_DESKTOP_RESTART);
877 } else {
878 // In Windows 8 desktop, add the 'Relaunch Chrome in Windows 8 mode'.
879 // In Windows 7 desktop, add the 'Relaunch Chrome in Windows ASH mode'
880 AddSeparator(ui::NORMAL_SEPARATOR);
881 if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
882 AddItemWithStringId(IDC_WIN8_METRO_RESTART, IDS_WIN8_METRO_RESTART);
883 } else {
884 AddItemWithStringId(IDC_WIN_CHROMEOS_RESTART, IDS_WIN_CHROMEOS_RESTART);
888 #endif
890 // Append the full menu including separators. The final separator only gets
891 // appended when this is a touch menu - otherwise it would get added twice.
892 CreateCutCopyPasteMenu();
894 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
895 switches::kEnableDomDistiller)) {
896 AddItemWithStringId(IDC_DISTILL_PAGE, IDS_DISTILL_PAGE);
899 AddItemWithStringId(IDC_SAVE_PAGE, IDS_SAVE_PAGE);
900 AddItemWithStringId(IDC_FIND, IDS_FIND);
901 AddItemWithStringId(IDC_PRINT, IDS_PRINT);
903 tools_menu_model_.reset(new ToolsMenuModel(this, browser_));
904 CreateZoomMenu();
906 AddItemWithStringId(IDC_SHOW_HISTORY, IDS_SHOW_HISTORY);
907 AddItemWithStringId(IDC_SHOW_DOWNLOADS, IDS_SHOW_DOWNLOADS);
908 AddSeparator(ui::NORMAL_SEPARATOR);
910 #if !defined(OS_CHROMEOS)
911 if (!switches::IsNewAvatarMenu()) {
912 // No "Sign in to Chromium..." menu item on ChromeOS.
913 SigninManager* signin = SigninManagerFactory::GetForProfile(
914 browser_->profile()->GetOriginalProfile());
915 if (signin && signin->IsSigninAllowed()) {
916 const base::string16 short_product_name =
917 l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME);
918 AddItem(IDC_SHOW_SYNC_SETUP, l10n_util::GetStringFUTF16(
919 IDS_SYNC_MENU_PRE_SYNCED_LABEL, short_product_name));
920 AddSeparator(ui::NORMAL_SEPARATOR);
923 #endif
925 AddItemWithStringId(IDC_OPTIONS, IDS_SETTINGS);
927 // On ChromeOS we don't want the about menu option.
928 #if !defined(OS_CHROMEOS)
929 AddItem(IDC_ABOUT, l10n_util::GetStringUTF16(IDS_ABOUT));
930 #endif
932 #if defined(GOOGLE_CHROME_BUILD)
933 help_menu_model_.reset(new HelpMenuModel(this, browser_));
934 AddSubMenuWithStringId(IDC_HELP_MENU, IDS_HELP_MENU,
935 help_menu_model_.get());
936 #endif
938 #if defined(OS_CHROMEOS)
939 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
940 chromeos::switches::kEnableRequestTabletSite))
941 AddCheckItemWithStringId(IDC_TOGGLE_REQUEST_TABLET_SITE,
942 IDS_TOGGLE_REQUEST_TABLET_SITE);
943 #endif
945 if (browser_defaults::kShowUpgradeMenuItem)
946 AddItem(IDC_UPGRADE_DIALOG, GetUpgradeDialogMenuItemName());
948 #if defined(OS_WIN)
949 SetIcon(GetIndexOfCommandId(IDC_VIEW_INCOMPATIBILITIES),
950 ui::ResourceBundle::GetSharedInstance().
951 GetNativeImageNamed(IDR_INPUT_ALERT_MENU));
952 #endif
954 AddGlobalErrorMenuItems();
956 AddSeparator(ui::NORMAL_SEPARATOR);
957 AddSubMenuWithStringId(
958 IDC_ZOOM_MENU, IDS_MORE_TOOLS_MENU, tools_menu_model_.get());
960 bool show_exit_menu = browser_defaults::kShowExitMenuItem;
961 #if defined(OS_WIN)
962 if (browser_->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH)
963 show_exit_menu = false;
964 #endif
966 if (show_exit_menu) {
967 AddSeparator(ui::NORMAL_SEPARATOR);
968 AddItemWithStringId(IDC_EXIT, IDS_EXIT);
971 RemoveTrailingSeparators();
972 uma_action_recorded_ = false;
975 void WrenchMenuModel::AddGlobalErrorMenuItems() {
976 // TODO(sail): Currently we only build the wrench menu once per browser
977 // window. This means that if a new error is added after the menu is built
978 // it won't show in the existing wrench menu. To fix this we need to some
979 // how update the menu if new errors are added.
980 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
981 // GetSignedInServiceErrors() can modify the global error list, so call it
982 // before iterating through that list below.
983 std::vector<GlobalError*> signin_errors;
984 signin_errors = signin_ui_util::GetSignedInServiceErrors(
985 browser_->profile()->GetOriginalProfile());
986 const GlobalErrorService::GlobalErrorList& errors =
987 GlobalErrorServiceFactory::GetForProfile(browser_->profile())->errors();
988 for (GlobalErrorService::GlobalErrorList::const_iterator
989 it = errors.begin(); it != errors.end(); ++it) {
990 GlobalError* error = *it;
991 DCHECK(error);
992 if (error->HasMenuItem()) {
993 #if !defined(OS_CHROMEOS)
994 // Don't add a signin error if it's already being displayed elsewhere.
995 if (std::find(signin_errors.begin(), signin_errors.end(), error) !=
996 signin_errors.end()) {
997 MenuModel* model = this;
998 int index = 0;
999 if (MenuModel::GetModelAndIndexForCommandId(
1000 IDC_SHOW_SIGNIN, &model, &index)) {
1001 continue;
1004 #endif
1006 AddItem(error->MenuItemCommandID(), error->MenuItemLabel());
1007 int icon_id = error->MenuItemIconResourceID();
1008 if (icon_id) {
1009 const gfx::Image& image = rb.GetNativeImageNamed(icon_id);
1010 SetIcon(GetIndexOfCommandId(error->MenuItemCommandID()),
1011 image);
1017 void WrenchMenuModel::CreateExtensionToolbarOverflowMenu() {
1018 // We only add the extensions overflow container if there are any icons that
1019 // aren't shown in the main container.
1020 if (!extensions::ExtensionToolbarModel::Get(browser_->profile())->
1021 all_icons_visible()) {
1022 AddItem(IDC_EXTENSIONS_OVERFLOW_MENU, base::string16());
1023 AddSeparator(ui::UPPER_SEPARATOR);
1027 void WrenchMenuModel::CreateCutCopyPasteMenu() {
1028 AddSeparator(ui::LOWER_SEPARATOR);
1030 #if defined(OS_MACOSX)
1031 // WARNING: Mac does not use the ButtonMenuItemModel, but instead defines the
1032 // layout for this menu item in Toolbar.xib. It does, however, use the
1033 // command_id value from AddButtonItem() to identify this special item.
1034 edit_menu_item_model_.reset(new ui::ButtonMenuItemModel(IDS_EDIT, this));
1035 edit_menu_item_model_->AddGroupItemWithStringId(IDC_CUT, IDS_CUT);
1036 edit_menu_item_model_->AddGroupItemWithStringId(IDC_COPY, IDS_COPY);
1037 edit_menu_item_model_->AddGroupItemWithStringId(IDC_PASTE, IDS_PASTE);
1038 AddButtonItem(IDC_EDIT_MENU, edit_menu_item_model_.get());
1039 #else
1040 // WARNING: views/wrench_menu assumes these items are added in this order. If
1041 // you change the order you'll need to update wrench_menu as well.
1042 AddItemWithStringId(IDC_CUT, IDS_CUT);
1043 AddItemWithStringId(IDC_COPY, IDS_COPY);
1044 AddItemWithStringId(IDC_PASTE, IDS_PASTE);
1045 #endif
1047 AddSeparator(ui::UPPER_SEPARATOR);
1050 void WrenchMenuModel::CreateZoomMenu() {
1051 // This menu needs to be enclosed by separators.
1052 AddSeparator(ui::LOWER_SEPARATOR);
1054 #if defined(OS_MACOSX)
1055 // WARNING: Mac does not use the ButtonMenuItemModel, but instead defines the
1056 // layout for this menu item in Toolbar.xib. It does, however, use the
1057 // command_id value from AddButtonItem() to identify this special item.
1058 zoom_menu_item_model_.reset(
1059 new ui::ButtonMenuItemModel(IDS_ZOOM_MENU, this));
1060 zoom_menu_item_model_->AddGroupItemWithStringId(
1061 IDC_ZOOM_MINUS, IDS_ZOOM_MINUS2);
1062 zoom_menu_item_model_->AddButtonLabel(IDC_ZOOM_PERCENT_DISPLAY,
1063 IDS_ZOOM_PLUS2);
1064 zoom_menu_item_model_->AddGroupItemWithStringId(
1065 IDC_ZOOM_PLUS, IDS_ZOOM_PLUS2);
1066 zoom_menu_item_model_->AddSpace();
1067 zoom_menu_item_model_->AddItemWithImage(
1068 IDC_FULLSCREEN, IDR_FULLSCREEN_MENU_BUTTON);
1069 AddButtonItem(IDC_ZOOM_MENU, zoom_menu_item_model_.get());
1070 #else
1071 // WARNING: views/wrench_menu assumes these items are added in this order. If
1072 // you change the order you'll need to update wrench_menu as well.
1073 AddItemWithStringId(IDC_ZOOM_MINUS, IDS_ZOOM_MINUS);
1074 AddItemWithStringId(IDC_ZOOM_PLUS, IDS_ZOOM_PLUS);
1075 AddItemWithStringId(IDC_FULLSCREEN, IDS_FULLSCREEN);
1076 #endif
1078 AddSeparator(ui::UPPER_SEPARATOR);
1081 void WrenchMenuModel::UpdateZoomControls() {
1082 int zoom_percent = 100;
1083 if (browser_->tab_strip_model()->GetActiveWebContents()) {
1084 zoom_percent = ui_zoom::ZoomController::FromWebContents(
1085 browser_->tab_strip_model()->GetActiveWebContents())
1086 ->GetZoomPercent();
1088 zoom_label_ = l10n_util::GetStringFUTF16(
1089 IDS_ZOOM_PERCENT, base::IntToString16(zoom_percent));
1092 void WrenchMenuModel::OnZoomLevelChanged(
1093 const content::HostZoomMap::ZoomLevelChange& change) {
1094 UpdateZoomControls();