Don't show supervised user as "already on this device" while they're being imported.
[chromium-blink-merge.git] / chrome / browser / ui / toolbar / wrench_menu_model.cc
blobab6e717a9ecfe100f13e0a1557d03acbc61f51b7
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/component_toolbar_actions_factory.h"
39 #include "chrome/browser/ui/toolbar/encoding_menu_controller.h"
40 #include "chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h"
41 #include "chrome/browser/upgrade_detector.h"
42 #include "chrome/common/chrome_paths.h"
43 #include "chrome/common/chrome_switches.h"
44 #include "chrome/common/pref_names.h"
45 #include "chrome/common/profiling.h"
46 #include "chrome/grit/chromium_strings.h"
47 #include "chrome/grit/generated_resources.h"
48 #include "components/signin/core/browser/signin_manager.h"
49 #include "components/signin/core/common/profile_management_switches.h"
50 #include "components/ui/zoom/zoom_controller.h"
51 #include "components/ui/zoom/zoom_event_manager.h"
52 #include "content/public/browser/host_zoom_map.h"
53 #include "content/public/browser/navigation_entry.h"
54 #include "content/public/browser/notification_service.h"
55 #include "content/public/browser/notification_source.h"
56 #include "content/public/browser/notification_types.h"
57 #include "content/public/browser/user_metrics.h"
58 #include "content/public/browser/web_contents.h"
59 #include "extensions/common/feature_switch.h"
60 #include "grit/theme_resources.h"
61 #include "ui/base/l10n/l10n_util.h"
62 #include "ui/base/layout.h"
63 #include "ui/base/models/button_menu_item_model.h"
64 #include "ui/base/resource/resource_bundle.h"
65 #include "ui/gfx/image/image.h"
66 #include "ui/gfx/image/image_skia.h"
68 #if defined(OS_CHROMEOS)
69 #include "chromeos/chromeos_switches.h"
70 #endif
72 #if defined(OS_WIN)
73 #include "base/win/metro.h"
74 #include "base/win/windows_version.h"
75 #include "chrome/browser/enumerate_modules_model_win.h"
76 #include "chrome/browser/ui/metro_pin_tab_helper_win.h"
77 #include "content/public/browser/gpu_data_manager.h"
78 #endif
80 #if defined(USE_ASH)
81 #include "ash/shell.h"
82 #endif
84 using base::UserMetricsAction;
85 using content::WebContents;
87 namespace {
88 // Conditionally return the update app menu item title based on upgrade detector
89 // state.
90 base::string16 GetUpgradeDialogMenuItemName() {
91 if (UpgradeDetector::GetInstance()->is_outdated_install() ||
92 UpgradeDetector::GetInstance()->is_outdated_install_no_au()) {
93 return l10n_util::GetStringUTF16(IDS_UPGRADE_BUBBLE_MENU_ITEM);
94 } else {
95 return l10n_util::GetStringUTF16(IDS_UPDATE_NOW);
99 #if defined(OS_WIN)
100 bool GetRestartMenuItemIfRequired(const chrome::HostDesktopType& desktop_type,
101 int* command_id,
102 int* string_id) {
103 if (base::win::GetVersion() == base::win::VERSION_WIN8 ||
104 base::win::GetVersion() == base::win::VERSION_WIN8_1) {
105 if (desktop_type != chrome::HOST_DESKTOP_TYPE_ASH) {
106 *command_id = IDC_WIN8_METRO_RESTART;
107 *string_id = IDS_WIN8_METRO_RESTART;
108 } else {
109 *command_id = IDC_WIN_DESKTOP_RESTART;
110 *string_id = IDS_WIN_DESKTOP_RESTART;
112 return true;
115 // Windows 7 ASH mode is only supported in DEBUG for now.
116 #if !defined(NDEBUG)
117 // Windows 8 can support ASH mode using WARP, but Windows 7 requires a working
118 // GPU compositor.
119 if (base::win::GetVersion() == base::win::VERSION_WIN7 &&
120 content::GpuDataManager::GetInstance()->CanUseGpuBrowserCompositor()) {
121 if (desktop_type != chrome::HOST_DESKTOP_TYPE_ASH) {
122 *command_id = IDC_WIN_CHROMEOS_RESTART;
123 *string_id = IDS_WIN_CHROMEOS_RESTART;
124 } else {
125 *command_id = IDC_WIN_DESKTOP_RESTART;
126 *string_id = IDS_WIN_DESKTOP_RESTART;
128 return true;
130 #endif
131 return false;
133 #endif
135 } // namespace
137 ////////////////////////////////////////////////////////////////////////////////
138 // EncodingMenuModel
140 EncodingMenuModel::EncodingMenuModel(Browser* browser)
141 : ui::SimpleMenuModel(this),
142 browser_(browser) {
143 Build();
146 EncodingMenuModel::~EncodingMenuModel() {
149 void EncodingMenuModel::Build() {
150 EncodingMenuController::EncodingMenuItemList encoding_menu_items;
151 EncodingMenuController encoding_menu_controller;
152 encoding_menu_controller.GetEncodingMenuItems(browser_->profile(),
153 &encoding_menu_items);
155 int group_id = 0;
156 EncodingMenuController::EncodingMenuItemList::iterator it =
157 encoding_menu_items.begin();
158 for (; it != encoding_menu_items.end(); ++it) {
159 int id = it->first;
160 base::string16& label = it->second;
161 if (id == 0) {
162 AddSeparator(ui::NORMAL_SEPARATOR);
163 } else {
164 if (id == IDC_ENCODING_AUTO_DETECT) {
165 AddCheckItem(id, label);
166 } else {
167 // Use the id of the first radio command as the id of the group.
168 if (group_id <= 0)
169 group_id = id;
170 AddRadioItem(id, label, group_id);
176 bool EncodingMenuModel::IsCommandIdChecked(int command_id) const {
177 WebContents* current_tab =
178 browser_->tab_strip_model()->GetActiveWebContents();
179 if (!current_tab)
180 return false;
181 EncodingMenuController controller;
182 return controller.IsItemChecked(browser_->profile(),
183 current_tab->GetEncoding(), command_id);
186 bool EncodingMenuModel::IsCommandIdEnabled(int command_id) const {
187 bool enabled = chrome::IsCommandEnabled(browser_, command_id);
188 // Special handling for the contents of the Encoding submenu. On Mac OS,
189 // instead of enabling/disabling the top-level menu item, the submenu's
190 // contents get disabled, per Apple's HIG.
191 #if defined(OS_MACOSX)
192 enabled &= chrome::IsCommandEnabled(browser_, IDC_ENCODING_MENU);
193 #endif
194 return enabled;
197 bool EncodingMenuModel::GetAcceleratorForCommandId(
198 int command_id,
199 ui::Accelerator* accelerator) {
200 return false;
203 void EncodingMenuModel::ExecuteCommand(int command_id, int event_flags) {
204 chrome::ExecuteCommand(browser_, command_id);
207 ////////////////////////////////////////////////////////////////////////////////
208 // ZoomMenuModel
210 ZoomMenuModel::ZoomMenuModel(ui::SimpleMenuModel::Delegate* delegate)
211 : SimpleMenuModel(delegate) {
212 Build();
215 ZoomMenuModel::~ZoomMenuModel() {
218 void ZoomMenuModel::Build() {
219 AddItemWithStringId(IDC_ZOOM_PLUS, IDS_ZOOM_PLUS);
220 AddItemWithStringId(IDC_ZOOM_NORMAL, IDS_ZOOM_NORMAL);
221 AddItemWithStringId(IDC_ZOOM_MINUS, IDS_ZOOM_MINUS);
224 ////////////////////////////////////////////////////////////////////////////////
225 // HelpMenuModel
227 #if defined(GOOGLE_CHROME_BUILD)
229 class WrenchMenuModel::HelpMenuModel : public ui::SimpleMenuModel {
230 public:
231 HelpMenuModel(ui::SimpleMenuModel::Delegate* delegate,
232 Browser* browser)
233 : SimpleMenuModel(delegate) {
234 Build(browser);
237 private:
238 void Build(Browser* browser) {
239 #if defined(OS_CHROMEOS) && defined(OFFICIAL_BUILD)
240 int help_string_id = IDS_GET_HELP;
241 #else
242 int help_string_id = IDS_HELP_PAGE;
243 #endif
244 AddItemWithStringId(IDC_HELP_PAGE_VIA_MENU, help_string_id);
245 if (browser_defaults::kShowHelpMenuItemIcon) {
246 ui::ResourceBundle& rb = ResourceBundle::GetSharedInstance();
247 SetIcon(GetIndexOfCommandId(IDC_HELP_PAGE_VIA_MENU),
248 rb.GetNativeImageNamed(IDR_HELP_MENU));
251 AddItemWithStringId(IDC_FEEDBACK, IDS_FEEDBACK);
254 DISALLOW_COPY_AND_ASSIGN(HelpMenuModel);
257 #endif // defined(GOOGLE_CHROME_BUILD)
259 ////////////////////////////////////////////////////////////////////////////////
260 // ToolsMenuModel
262 ToolsMenuModel::ToolsMenuModel(ui::SimpleMenuModel::Delegate* delegate,
263 Browser* browser)
264 : SimpleMenuModel(delegate) {
265 Build(browser);
268 ToolsMenuModel::~ToolsMenuModel() {}
270 void ToolsMenuModel::Build(Browser* browser) {
271 bool show_create_shortcuts = true;
272 #if defined(OS_CHROMEOS) || defined(OS_MACOSX)
273 show_create_shortcuts = false;
274 #elif defined(USE_ASH)
275 if (browser->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH)
276 show_create_shortcuts = false;
277 #endif
279 AddItemWithStringId(IDC_CLEAR_BROWSING_DATA, IDS_CLEAR_BROWSING_DATA);
280 AddItemWithStringId(IDC_MANAGE_EXTENSIONS, IDS_SHOW_EXTENSIONS);
282 if (chrome::CanOpenTaskManager())
283 AddItemWithStringId(IDC_TASK_MANAGER, IDS_TASK_MANAGER);
285 if (extensions::util::IsNewBookmarkAppsEnabled()) {
286 #if defined(OS_MACOSX)
287 int string_id = IDS_ADD_TO_APPLICATIONS;
288 #elif defined(OS_WIN)
289 int string_id = IDS_ADD_TO_TASKBAR;
290 #else
291 int string_id = IDS_ADD_TO_DESKTOP;
292 #endif
293 #if defined(USE_ASH)
294 if (browser->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH)
295 string_id = IDS_ADD_TO_SHELF;
296 #endif
297 AddItemWithStringId(IDC_CREATE_HOSTED_APP, string_id);
298 } else if (show_create_shortcuts) {
299 AddItemWithStringId(IDC_CREATE_SHORTCUTS, IDS_CREATE_SHORTCUTS);
302 #if defined(OS_CHROMEOS)
303 AddItemWithStringId(IDC_TAKE_SCREENSHOT, IDS_TAKE_SCREENSHOT);
304 #endif
306 encoding_menu_model_.reset(new EncodingMenuModel(browser));
307 AddSubMenuWithStringId(IDC_ENCODING_MENU, IDS_ENCODING_MENU,
308 encoding_menu_model_.get());
309 AddSeparator(ui::NORMAL_SEPARATOR);
310 AddItemWithStringId(IDC_DEV_TOOLS, IDS_DEV_TOOLS);
311 AddItemWithStringId(IDC_VIEW_SOURCE, IDS_VIEW_SOURCE);
312 AddItemWithStringId(IDC_DEV_TOOLS_CONSOLE, IDS_DEV_TOOLS_CONSOLE);
313 AddItemWithStringId(IDC_DEV_TOOLS_DEVICES, IDS_DEV_TOOLS_DEVICES);
315 #if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC)
316 AddSeparator(ui::NORMAL_SEPARATOR);
317 AddCheckItemWithStringId(IDC_PROFILING_ENABLED, IDS_PROFILING_ENABLED);
318 #endif
321 ////////////////////////////////////////////////////////////////////////////////
322 // WrenchMenuModel
324 WrenchMenuModel::WrenchMenuModel(ui::AcceleratorProvider* provider,
325 Browser* browser)
326 : ui::SimpleMenuModel(this),
327 uma_action_recorded_(false),
328 provider_(provider),
329 browser_(browser),
330 tab_strip_model_(browser_->tab_strip_model()) {
331 Build();
332 UpdateZoomControls();
334 browser_zoom_subscription_ =
335 ui_zoom::ZoomEventManager::GetForBrowserContext(browser->profile())
336 ->AddZoomLevelChangedCallback(base::Bind(
337 &WrenchMenuModel::OnZoomLevelChanged, base::Unretained(this)));
339 tab_strip_model_->AddObserver(this);
341 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
342 content::NotificationService::AllSources());
345 WrenchMenuModel::~WrenchMenuModel() {
346 if (tab_strip_model_)
347 tab_strip_model_->RemoveObserver(this);
350 bool WrenchMenuModel::DoesCommandIdDismissMenu(int command_id) const {
351 return command_id != IDC_ZOOM_MINUS && command_id != IDC_ZOOM_PLUS;
354 bool WrenchMenuModel::IsItemForCommandIdDynamic(int command_id) const {
355 return command_id == IDC_ZOOM_PERCENT_DISPLAY ||
356 #if defined(OS_MACOSX)
357 command_id == IDC_FULLSCREEN ||
358 #elif defined(OS_WIN)
359 command_id == IDC_PIN_TO_START_SCREEN ||
360 #endif
361 command_id == IDC_UPGRADE_DIALOG ||
362 (!switches::IsNewAvatarMenu() && command_id == IDC_SHOW_SIGNIN);
365 base::string16 WrenchMenuModel::GetLabelForCommandId(int command_id) const {
366 switch (command_id) {
367 case IDC_ZOOM_PERCENT_DISPLAY:
368 return zoom_label_;
369 #if defined(OS_MACOSX)
370 case IDC_FULLSCREEN: {
371 int string_id = IDS_ENTER_FULLSCREEN_MAC; // Default to Enter.
372 // Note: On startup, |window()| may be NULL.
373 if (browser_->window() && browser_->window()->IsFullscreen())
374 string_id = IDS_EXIT_FULLSCREEN_MAC;
375 return l10n_util::GetStringUTF16(string_id);
377 #elif defined(OS_WIN)
378 case IDC_PIN_TO_START_SCREEN: {
379 int string_id = IDS_PIN_TO_START_SCREEN;
380 WebContents* web_contents =
381 browser_->tab_strip_model()->GetActiveWebContents();
382 MetroPinTabHelper* tab_helper =
383 web_contents ? MetroPinTabHelper::FromWebContents(web_contents)
384 : NULL;
385 if (tab_helper && tab_helper->IsPinned())
386 string_id = IDS_UNPIN_FROM_START_SCREEN;
387 return l10n_util::GetStringUTF16(string_id);
389 #endif
390 case IDC_UPGRADE_DIALOG:
391 return GetUpgradeDialogMenuItemName();
392 case IDC_SHOW_SIGNIN:
393 DCHECK(!switches::IsNewAvatarMenu());
394 return signin_ui_util::GetSigninMenuLabel(
395 browser_->profile()->GetOriginalProfile());
396 default:
397 NOTREACHED();
398 return base::string16();
402 bool WrenchMenuModel::GetIconForCommandId(int command_id,
403 gfx::Image* icon) const {
404 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
405 switch (command_id) {
406 case IDC_UPGRADE_DIALOG: {
407 if (UpgradeDetector::GetInstance()->notify_upgrade()) {
408 *icon = rb.GetNativeImageNamed(
409 UpgradeDetector::GetInstance()->GetIconResourceID());
410 return true;
412 return false;
414 case IDC_SHOW_SIGNIN: {
415 DCHECK(!switches::IsNewAvatarMenu());
416 GlobalError* error = signin_ui_util::GetSignedInServiceError(
417 browser_->profile()->GetOriginalProfile());
418 if (error) {
419 int icon_id = error->MenuItemIconResourceID();
420 if (icon_id) {
421 *icon = rb.GetNativeImageNamed(icon_id);
422 return true;
425 return false;
427 default:
428 break;
430 return false;
433 void WrenchMenuModel::ExecuteCommand(int command_id, int event_flags) {
434 GlobalError* error = GlobalErrorServiceFactory::GetForProfile(
435 browser_->profile())->GetGlobalErrorByMenuItemCommandID(command_id);
436 if (error) {
437 error->ExecuteMenuItem(browser_);
438 return;
441 if (!switches::IsNewAvatarMenu() && command_id == IDC_SHOW_SIGNIN) {
442 // If a custom error message is being shown, handle it.
443 GlobalError* error = signin_ui_util::GetSignedInServiceError(
444 browser_->profile()->GetOriginalProfile());
445 if (error) {
446 error->ExecuteMenuItem(browser_);
447 return;
451 LogMenuMetrics(command_id);
452 chrome::ExecuteCommand(browser_, command_id);
455 void WrenchMenuModel::LogMenuMetrics(int command_id) {
456 base::TimeDelta delta = timer_.Elapsed();
458 switch (command_id) {
459 case IDC_NEW_TAB:
460 if (!uma_action_recorded_)
461 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.NewTab", delta);
462 LogMenuAction(MENU_ACTION_NEW_TAB);
463 break;
464 case IDC_NEW_WINDOW:
465 if (!uma_action_recorded_)
466 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.NewWindow", delta);
467 LogMenuAction(MENU_ACTION_NEW_WINDOW);
468 break;
469 case IDC_NEW_INCOGNITO_WINDOW:
470 if (!uma_action_recorded_) {
471 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.NewIncognitoWindow",
472 delta);
474 LogMenuAction(MENU_ACTION_NEW_INCOGNITO_WINDOW);
475 break;
477 // Bookmarks sub menu.
478 case IDC_SHOW_BOOKMARK_BAR:
479 if (!uma_action_recorded_) {
480 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.ShowBookmarkBar",
481 delta);
483 LogMenuAction(MENU_ACTION_SHOW_BOOKMARK_BAR);
484 break;
485 case IDC_SHOW_BOOKMARK_MANAGER:
486 if (!uma_action_recorded_) {
487 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.ShowBookmarkMgr",
488 delta);
490 LogMenuAction(MENU_ACTION_SHOW_BOOKMARK_MANAGER);
491 break;
492 case IDC_IMPORT_SETTINGS:
493 if (!uma_action_recorded_) {
494 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.ImportSettings",
495 delta);
497 LogMenuAction(MENU_ACTION_IMPORT_SETTINGS);
498 break;
499 case IDC_BOOKMARK_PAGE:
500 if (!uma_action_recorded_) {
501 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.BookmarkPage",
502 delta);
504 LogMenuAction(MENU_ACTION_BOOKMARK_PAGE);
505 break;
506 case IDC_BOOKMARK_ALL_TABS:
507 if (!uma_action_recorded_) {
508 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.BookmarkAllTabs",
509 delta);
511 LogMenuAction(MENU_ACTION_BOOKMARK_ALL_TABS);
512 break;
513 case IDC_PIN_TO_START_SCREEN:
514 if (!uma_action_recorded_) {
515 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.PinToStartScreen",
516 delta);
518 LogMenuAction(MENU_ACTION_PIN_TO_START_SCREEN);
519 break;
521 // Recent tabs menu.
522 case IDC_RESTORE_TAB:
523 if (!uma_action_recorded_)
524 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.RestoreTab", delta);
525 LogMenuAction(MENU_ACTION_RESTORE_TAB);
526 break;
528 // Windows.
529 case IDC_WIN_DESKTOP_RESTART:
530 if (!uma_action_recorded_) {
531 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.WinDesktopRestart",
532 delta);
534 LogMenuAction(MENU_ACTION_WIN_DESKTOP_RESTART);
535 break;
536 case IDC_WIN8_METRO_RESTART:
537 if (!uma_action_recorded_) {
538 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.Win8MetroRestart",
539 delta);
541 LogMenuAction(MENU_ACTION_WIN8_METRO_RESTART);
542 break;
544 case IDC_WIN_CHROMEOS_RESTART:
545 if (!uma_action_recorded_) {
546 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.ChromeOSRestart",
547 delta);
549 LogMenuAction(MENU_ACTION_WIN_CHROMEOS_RESTART);
550 break;
551 case IDC_DISTILL_PAGE:
552 if (!uma_action_recorded_) {
553 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.DistillPage",
554 delta);
556 LogMenuAction(MENU_ACTION_DISTILL_PAGE);
557 break;
558 case IDC_SAVE_PAGE:
559 if (!uma_action_recorded_)
560 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.SavePage", delta);
561 LogMenuAction(MENU_ACTION_SAVE_PAGE);
562 break;
563 case IDC_FIND:
564 if (!uma_action_recorded_)
565 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.Find", delta);
566 LogMenuAction(MENU_ACTION_FIND);
567 break;
568 case IDC_PRINT:
569 if (!uma_action_recorded_)
570 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.Print", delta);
571 LogMenuAction(MENU_ACTION_PRINT);
572 break;
574 // Edit menu.
575 case IDC_CUT:
576 if (!uma_action_recorded_)
577 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.Cut", delta);
578 LogMenuAction(MENU_ACTION_CUT);
579 break;
580 case IDC_COPY:
581 if (!uma_action_recorded_)
582 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.Copy", delta);
583 LogMenuAction(MENU_ACTION_COPY);
584 break;
585 case IDC_PASTE:
586 if (!uma_action_recorded_)
587 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.Paste", delta);
588 LogMenuAction(MENU_ACTION_PASTE);
589 break;
591 // Tools menu.
592 case IDC_CREATE_HOSTED_APP:
593 if (!uma_action_recorded_) {
594 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.CreateHostedApp",
595 delta);
597 LogMenuAction(MENU_ACTION_CREATE_HOSTED_APP);
598 break;
599 case IDC_CREATE_SHORTCUTS:
600 if (!uma_action_recorded_)
601 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.CreateShortcuts",
602 delta);
603 LogMenuAction(MENU_ACTION_CREATE_SHORTCUTS);
604 break;
605 case IDC_MANAGE_EXTENSIONS:
606 if (!uma_action_recorded_) {
607 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.ManageExtensions",
608 delta);
610 LogMenuAction(MENU_ACTION_MANAGE_EXTENSIONS);
611 break;
612 case IDC_TASK_MANAGER:
613 if (!uma_action_recorded_) {
614 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.TaskManager",
615 delta);
617 LogMenuAction(MENU_ACTION_TASK_MANAGER);
618 break;
619 case IDC_CLEAR_BROWSING_DATA:
620 if (!uma_action_recorded_) {
621 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.ClearBrowsingData",
622 delta);
624 LogMenuAction(MENU_ACTION_CLEAR_BROWSING_DATA);
625 break;
626 case IDC_VIEW_SOURCE:
627 if (!uma_action_recorded_)
628 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.ViewSource", delta);
629 LogMenuAction(MENU_ACTION_VIEW_SOURCE);
630 break;
631 case IDC_DEV_TOOLS:
632 if (!uma_action_recorded_)
633 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.DevTools", delta);
634 LogMenuAction(MENU_ACTION_DEV_TOOLS);
635 break;
636 case IDC_DEV_TOOLS_CONSOLE:
637 if (!uma_action_recorded_) {
638 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.DevToolsConsole",
639 delta);
641 LogMenuAction(MENU_ACTION_DEV_TOOLS_CONSOLE);
642 break;
643 case IDC_DEV_TOOLS_DEVICES:
644 if (!uma_action_recorded_) {
645 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.DevToolsDevices",
646 delta);
648 LogMenuAction(MENU_ACTION_DEV_TOOLS_DEVICES);
649 break;
650 case IDC_PROFILING_ENABLED:
651 if (!uma_action_recorded_) {
652 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.ProfilingEnabled",
653 delta);
655 LogMenuAction(MENU_ACTION_PROFILING_ENABLED);
656 break;
658 // Zoom menu
659 case IDC_ZOOM_MINUS:
660 if (!uma_action_recorded_) {
661 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.ZoomMinus", delta);
662 LogMenuAction(MENU_ACTION_ZOOM_MINUS);
664 break;
665 case IDC_ZOOM_PLUS:
666 if (!uma_action_recorded_) {
667 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.ZoomPlus", delta);
668 LogMenuAction(MENU_ACTION_ZOOM_PLUS);
670 break;
671 case IDC_FULLSCREEN:
672 content::RecordAction(UserMetricsAction("EnterFullScreenWithWrenchMenu"));
674 if (!uma_action_recorded_) {
675 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.EnterFullScreen",
676 delta);
678 LogMenuAction(MENU_ACTION_FULLSCREEN);
679 break;
681 case IDC_SHOW_HISTORY:
682 if (!uma_action_recorded_) {
683 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.ShowHistory",
684 delta);
686 LogMenuAction(MENU_ACTION_SHOW_HISTORY);
687 break;
688 case IDC_SHOW_DOWNLOADS:
689 if (!uma_action_recorded_) {
690 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.ShowDownloads",
691 delta);
693 LogMenuAction(MENU_ACTION_SHOW_DOWNLOADS);
694 break;
695 case IDC_SHOW_SYNC_SETUP:
696 if (!uma_action_recorded_) {
697 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.ShowSyncSetup",
698 delta);
700 LogMenuAction(MENU_ACTION_SHOW_SYNC_SETUP);
701 break;
702 case IDC_OPTIONS:
703 if (!uma_action_recorded_)
704 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.Settings", delta);
705 LogMenuAction(MENU_ACTION_OPTIONS);
706 break;
707 case IDC_ABOUT:
708 if (!uma_action_recorded_)
709 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.About", delta);
710 LogMenuAction(MENU_ACTION_ABOUT);
711 break;
713 // Help menu.
714 case IDC_HELP_PAGE_VIA_MENU:
715 content::RecordAction(UserMetricsAction("ShowHelpTabViaWrenchMenu"));
717 if (!uma_action_recorded_)
718 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.HelpPage", delta);
719 LogMenuAction(MENU_ACTION_HELP_PAGE_VIA_MENU);
720 break;
721 #if defined(GOOGLE_CHROME_BUILD)
722 case IDC_FEEDBACK:
723 if (!uma_action_recorded_)
724 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.Feedback", delta);
725 LogMenuAction(MENU_ACTION_FEEDBACK);
726 break;
727 #endif
729 case IDC_TOGGLE_REQUEST_TABLET_SITE:
730 if (!uma_action_recorded_) {
731 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.RequestTabletSite",
732 delta);
734 LogMenuAction(MENU_ACTION_TOGGLE_REQUEST_TABLET_SITE);
735 break;
736 case IDC_EXIT:
737 if (!uma_action_recorded_)
738 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.Exit", delta);
739 LogMenuAction(MENU_ACTION_EXIT);
740 break;
743 if (!uma_action_recorded_) {
744 UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction", delta);
745 uma_action_recorded_ = true;
749 void WrenchMenuModel::LogMenuAction(int action_id) {
750 UMA_HISTOGRAM_ENUMERATION("WrenchMenu.MenuAction", action_id,
751 LIMIT_MENU_ACTION);
754 bool WrenchMenuModel::IsCommandIdChecked(int command_id) const {
755 if (command_id == IDC_SHOW_BOOKMARK_BAR) {
756 return browser_->profile()->GetPrefs()->GetBoolean(
757 bookmarks::prefs::kShowBookmarkBar);
758 } else if (command_id == IDC_PROFILING_ENABLED) {
759 return Profiling::BeingProfiled();
760 } else if (command_id == IDC_TOGGLE_REQUEST_TABLET_SITE) {
761 return chrome::IsRequestingTabletSite(browser_);
764 return false;
767 bool WrenchMenuModel::IsCommandIdEnabled(int command_id) const {
768 GlobalError* error = GlobalErrorServiceFactory::GetForProfile(
769 browser_->profile())->GetGlobalErrorByMenuItemCommandID(command_id);
770 if (error)
771 return true;
773 return chrome::IsCommandEnabled(browser_, command_id);
776 bool WrenchMenuModel::IsCommandIdVisible(int command_id) const {
777 switch (command_id) {
778 #if defined(OS_WIN)
779 case IDC_VIEW_INCOMPATIBILITIES: {
780 EnumerateModulesModel* loaded_modules =
781 EnumerateModulesModel::GetInstance();
782 if (loaded_modules->confirmed_bad_modules_detected() <= 0)
783 return false;
784 // We'll leave the wrench adornment on until the user clicks the link.
785 if (loaded_modules->modules_to_notify_about() <= 0)
786 loaded_modules->AcknowledgeConflictNotification();
787 return true;
789 case IDC_PIN_TO_START_SCREEN:
790 return base::win::IsMetroProcess();
791 #else
792 case IDC_VIEW_INCOMPATIBILITIES:
793 case IDC_PIN_TO_START_SCREEN:
794 return false;
795 #endif
796 case IDC_UPGRADE_DIALOG:
797 return browser_defaults::kShowUpgradeMenuItem &&
798 UpgradeDetector::GetInstance()->notify_upgrade();
799 #if !defined(OS_LINUX) || defined(USE_AURA)
800 case IDC_BOOKMARK_PAGE:
801 return !chrome::ShouldRemoveBookmarkThisPageUI(browser_->profile());
802 case IDC_BOOKMARK_ALL_TABS:
803 return !chrome::ShouldRemoveBookmarkOpenPagesUI(browser_->profile());
804 #endif
805 default:
806 return true;
810 bool WrenchMenuModel::GetAcceleratorForCommandId(
811 int command_id,
812 ui::Accelerator* accelerator) {
813 return provider_->GetAcceleratorForCommandId(command_id, accelerator);
816 void WrenchMenuModel::ActiveTabChanged(WebContents* old_contents,
817 WebContents* new_contents,
818 int index,
819 int reason) {
820 // The user has switched between tabs and the new tab may have a different
821 // zoom setting.
822 UpdateZoomControls();
825 void WrenchMenuModel::TabReplacedAt(TabStripModel* tab_strip_model,
826 WebContents* old_contents,
827 WebContents* new_contents,
828 int index) {
829 UpdateZoomControls();
832 void WrenchMenuModel::TabStripModelDeleted() {
833 // During views shutdown, the tabstrip model/browser is deleted first, while
834 // it is the opposite in gtk land.
835 tab_strip_model_->RemoveObserver(this);
836 tab_strip_model_ = NULL;
839 void WrenchMenuModel::Observe(int type,
840 const content::NotificationSource& source,
841 const content::NotificationDetails& details) {
842 DCHECK(type == content::NOTIFICATION_NAV_ENTRY_COMMITTED);
843 UpdateZoomControls();
846 // For testing.
847 WrenchMenuModel::WrenchMenuModel()
848 : ui::SimpleMenuModel(this),
849 provider_(NULL),
850 browser_(NULL),
851 tab_strip_model_(NULL) {
854 bool WrenchMenuModel::ShouldShowNewIncognitoWindowMenuItem() {
855 if (browser_->profile()->IsGuestSession())
856 return false;
858 return IncognitoModePrefs::GetAvailability(browser_->profile()->GetPrefs()) !=
859 IncognitoModePrefs::DISABLED;
862 // Note: When adding new menu items please place under an appropriate section.
863 // Menu is organised as follows:
864 // - Extension toolbar overflow.
865 // - Global browser errors and warnings.
866 // - Tabs and windows.
867 // - Places previously been e.g. History, bookmarks, recent tabs.
868 // - Page actions e.g. zoom, edit, find, print.
869 // - Learn about the browser and global customisation e.g. settings, help.
870 // - Browser relaunch, quit.
871 void WrenchMenuModel::Build() {
872 if (extensions::FeatureSwitch::extension_action_redesign()->IsEnabled())
873 CreateExtensionToolbarOverflowMenu();
875 AddItem(IDC_VIEW_INCOMPATIBILITIES,
876 l10n_util::GetStringUTF16(IDS_VIEW_INCOMPATIBILITIES));
877 SetIcon(GetIndexOfCommandId(IDC_VIEW_INCOMPATIBILITIES),
878 ui::ResourceBundle::GetSharedInstance().
879 GetNativeImageNamed(IDR_INPUT_ALERT_MENU));
881 if (IsCommandIdVisible(IDC_UPGRADE_DIALOG))
882 AddItem(IDC_UPGRADE_DIALOG, GetUpgradeDialogMenuItemName());
884 if (AddGlobalErrorMenuItems() ||
885 IsCommandIdVisible(IDC_VIEW_INCOMPATIBILITIES) ||
886 IsCommandIdVisible(IDC_UPGRADE_DIALOG))
887 AddSeparator(ui::NORMAL_SEPARATOR);
889 AddItemWithStringId(IDC_NEW_TAB, IDS_NEW_TAB);
890 AddItemWithStringId(IDC_NEW_WINDOW, IDS_NEW_WINDOW);
891 if (ShouldShowNewIncognitoWindowMenuItem())
892 AddItemWithStringId(IDC_NEW_INCOGNITO_WINDOW, IDS_NEW_INCOGNITO_WINDOW);
894 AddSeparator(ui::NORMAL_SEPARATOR);
896 AddItemWithStringId(IDC_SHOW_HISTORY, IDS_SHOW_HISTORY);
897 AddItemWithStringId(IDC_SHOW_DOWNLOADS, IDS_SHOW_DOWNLOADS);
899 if (!browser_->profile()->IsOffTheRecord()) {
900 recent_tabs_sub_menu_model_.reset(new RecentTabsSubMenuModel(provider_,
901 browser_,
902 NULL));
903 AddSubMenuWithStringId(IDC_RECENT_TABS_MENU, IDS_RECENT_TABS_MENU,
904 recent_tabs_sub_menu_model_.get());
907 if (!browser_->profile()->IsGuestSession()) {
908 bookmark_sub_menu_model_.reset(new BookmarkSubMenuModel(this, browser_));
909 AddSubMenuWithStringId(IDC_BOOKMARKS_MENU, IDS_BOOKMARKS_MENU,
910 bookmark_sub_menu_model_.get());
913 CreateZoomMenu();
915 AddItemWithStringId(IDC_PRINT, IDS_PRINT);
916 AddItemWithStringId(IDC_SAVE_PAGE, IDS_SAVE_PAGE);
917 AddItemWithStringId(IDC_FIND, IDS_FIND);
918 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
919 switches::kEnableDomDistiller))
920 AddItemWithStringId(IDC_DISTILL_PAGE, IDS_DISTILL_PAGE);
921 tools_menu_model_.reset(new ToolsMenuModel(this, browser_));
922 AddSubMenuWithStringId(
923 IDC_MORE_TOOLS_MENU, IDS_MORE_TOOLS_MENU, tools_menu_model_.get());
925 // Append the full menu including separators. The final separator only gets
926 // appended when this is a touch menu - otherwise it would get added twice.
927 CreateCutCopyPasteMenu();
929 AddItemWithStringId(IDC_OPTIONS, IDS_SETTINGS);
931 #if !defined(OS_CHROMEOS)
932 if (!switches::IsNewAvatarMenu()) {
933 // No "Sign in to Chromium..." menu item on ChromeOS.
934 SigninManager* signin = SigninManagerFactory::GetForProfile(
935 browser_->profile()->GetOriginalProfile());
936 if (signin && signin->IsSigninAllowed() &&
937 signin_ui_util::GetSignedInServiceErrors(
938 browser_->profile()->GetOriginalProfile()).empty()) {
939 AddItem(IDC_SHOW_SYNC_SETUP,
940 l10n_util::GetStringFUTF16(
941 IDS_SYNC_MENU_PRE_SYNCED_LABEL,
942 l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)));
945 #endif
947 // On ChromeOS we don't want the about menu option.
948 #if !defined(OS_CHROMEOS)
949 AddItem(IDC_ABOUT, l10n_util::GetStringUTF16(IDS_ABOUT));
950 #endif
952 #if defined(GOOGLE_CHROME_BUILD)
953 help_menu_model_.reset(new HelpMenuModel(this, browser_));
954 AddSubMenuWithStringId(IDC_HELP_MENU, IDS_HELP_MENU,
955 help_menu_model_.get());
956 #endif
958 #if defined(OS_CHROMEOS)
959 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
960 chromeos::switches::kEnableRequestTabletSite))
961 AddCheckItemWithStringId(IDC_TOGGLE_REQUEST_TABLET_SITE,
962 IDS_TOGGLE_REQUEST_TABLET_SITE);
963 #endif
965 #if defined(OS_WIN)
966 int command_id = IDC_WIN_DESKTOP_RESTART;
967 int string_id = IDS_WIN_DESKTOP_RESTART;
968 if (GetRestartMenuItemIfRequired(browser_->host_desktop_type(),
969 &command_id,
970 &string_id)) {
971 AddSeparator(ui::NORMAL_SEPARATOR);
972 AddItemWithStringId(command_id, string_id);
974 #endif
976 bool show_exit_menu = browser_defaults::kShowExitMenuItem;
977 #if defined(OS_WIN)
978 if (browser_->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH)
979 show_exit_menu = false;
980 #endif
982 if (show_exit_menu) {
983 AddSeparator(ui::NORMAL_SEPARATOR);
984 AddItemWithStringId(IDC_EXIT, IDS_EXIT);
986 uma_action_recorded_ = false;
989 bool WrenchMenuModel::AddGlobalErrorMenuItems() {
990 // TODO(sail): Currently we only build the wrench menu once per browser
991 // window. This means that if a new error is added after the menu is built
992 // it won't show in the existing wrench menu. To fix this we need to some
993 // how update the menu if new errors are added.
994 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
995 // GetSignedInServiceErrors() can modify the global error list, so call it
996 // before iterating through that list below.
997 std::vector<GlobalError*> signin_errors;
998 signin_errors = signin_ui_util::GetSignedInServiceErrors(
999 browser_->profile()->GetOriginalProfile());
1000 const GlobalErrorService::GlobalErrorList& errors =
1001 GlobalErrorServiceFactory::GetForProfile(browser_->profile())->errors();
1002 bool menu_items_added = false;
1003 for (GlobalErrorService::GlobalErrorList::const_iterator
1004 it = errors.begin(); it != errors.end(); ++it) {
1005 GlobalError* error = *it;
1006 DCHECK(error);
1007 if (error->HasMenuItem()) {
1008 #if !defined(OS_CHROMEOS)
1009 // Don't add a signin error if it's already being displayed elsewhere.
1010 if (std::find(signin_errors.begin(), signin_errors.end(), error) !=
1011 signin_errors.end()) {
1012 MenuModel* model = this;
1013 int index = 0;
1014 if (MenuModel::GetModelAndIndexForCommandId(
1015 IDC_SHOW_SIGNIN, &model, &index)) {
1016 continue;
1019 #endif
1021 AddItem(error->MenuItemCommandID(), error->MenuItemLabel());
1022 int icon_id = error->MenuItemIconResourceID();
1023 if (icon_id) {
1024 const gfx::Image& image = rb.GetNativeImageNamed(icon_id);
1025 SetIcon(GetIndexOfCommandId(error->MenuItemCommandID()),
1026 image);
1028 menu_items_added = true;
1031 return menu_items_added;
1034 void WrenchMenuModel::CreateExtensionToolbarOverflowMenu() {
1035 // We only add the extensions overflow container if there are any icons that
1036 // aren't shown in the main container or if there are component actions.
1037 // TODO(apacible): Remove check for component actions when
1038 // ExtensionToolbarModel can support them.
1039 if (!extensions::ExtensionToolbarModel::Get(browser_->profile())->
1040 all_icons_visible() ||
1041 ComponentToolbarActionsFactory::GetInstance()->
1042 GetNumComponentActions() > 0) {
1043 AddItem(IDC_EXTENSIONS_OVERFLOW_MENU, base::string16());
1044 AddSeparator(ui::UPPER_SEPARATOR);
1048 void WrenchMenuModel::CreateCutCopyPasteMenu() {
1049 AddSeparator(ui::LOWER_SEPARATOR);
1051 // WARNING: Mac does not use the ButtonMenuItemModel, but instead defines the
1052 // layout for this menu item in WrenchMenu.xib. It does, however, use the
1053 // command_id value from AddButtonItem() to identify this special item.
1054 edit_menu_item_model_.reset(new ui::ButtonMenuItemModel(IDS_EDIT, this));
1055 edit_menu_item_model_->AddGroupItemWithStringId(IDC_CUT, IDS_CUT);
1056 edit_menu_item_model_->AddGroupItemWithStringId(IDC_COPY, IDS_COPY);
1057 edit_menu_item_model_->AddGroupItemWithStringId(IDC_PASTE, IDS_PASTE);
1058 AddButtonItem(IDC_EDIT_MENU, edit_menu_item_model_.get());
1060 AddSeparator(ui::UPPER_SEPARATOR);
1063 void WrenchMenuModel::CreateZoomMenu() {
1064 // This menu needs to be enclosed by separators.
1065 AddSeparator(ui::LOWER_SEPARATOR);
1067 // WARNING: Mac does not use the ButtonMenuItemModel, but instead defines the
1068 // layout for this menu item in WrenchMenu.xib. It does, however, use the
1069 // command_id value from AddButtonItem() to identify this special item.
1070 zoom_menu_item_model_.reset(
1071 new ui::ButtonMenuItemModel(IDS_ZOOM_MENU, this));
1072 zoom_menu_item_model_->AddGroupItemWithStringId(IDC_ZOOM_MINUS,
1073 IDS_ZOOM_MINUS2);
1074 zoom_menu_item_model_->AddGroupItemWithStringId(IDC_ZOOM_PLUS,
1075 IDS_ZOOM_PLUS2);
1076 zoom_menu_item_model_->AddItemWithImage(IDC_FULLSCREEN,
1077 IDR_FULLSCREEN_MENU_BUTTON);
1078 AddButtonItem(IDC_ZOOM_MENU, zoom_menu_item_model_.get());
1080 AddSeparator(ui::UPPER_SEPARATOR);
1083 void WrenchMenuModel::UpdateZoomControls() {
1084 int zoom_percent = 100;
1085 if (browser_->tab_strip_model() &&
1086 browser_->tab_strip_model()->GetActiveWebContents()) {
1087 zoom_percent = ui_zoom::ZoomController::FromWebContents(
1088 browser_->tab_strip_model()->GetActiveWebContents())
1089 ->GetZoomPercent();
1091 zoom_label_ = l10n_util::GetStringFUTF16(
1092 IDS_ZOOM_PERCENT, base::IntToString16(zoom_percent));
1095 void WrenchMenuModel::OnZoomLevelChanged(
1096 const content::HostZoomMap::ZoomLevelChange& change) {
1097 UpdateZoomControls();