Add unit test for the Settings API Bubble.
[chromium-blink-merge.git] / chrome / browser / ui / toolbar / wrench_menu_model.cc
blobe2ca7b5d995df26e25c0f5e6bf4d0b3c1bf37cc9
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/profiles/profile.h"
19 #include "chrome/browser/profiles/profile_manager.h"
20 #include "chrome/browser/search/search.h"
21 #include "chrome/browser/signin/signin_manager_factory.h"
22 #include "chrome/browser/signin/signin_ui_util.h"
23 #include "chrome/browser/task_manager/task_manager.h"
24 #include "chrome/browser/ui/bookmarks/bookmark_utils.h"
25 #include "chrome/browser/ui/browser.h"
26 #include "chrome/browser/ui/browser_commands.h"
27 #include "chrome/browser/ui/browser_finder.h"
28 #include "chrome/browser/ui/browser_window.h"
29 #include "chrome/browser/ui/global_error/global_error.h"
30 #include "chrome/browser/ui/global_error/global_error_service.h"
31 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
32 #include "chrome/browser/ui/tabs/tab_strip_model.h"
33 #include "chrome/browser/ui/toolbar/bookmark_sub_menu_model.h"
34 #include "chrome/browser/ui/toolbar/encoding_menu_controller.h"
35 #include "chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h"
36 #include "chrome/browser/upgrade_detector.h"
37 #include "chrome/common/chrome_paths.h"
38 #include "chrome/common/chrome_switches.h"
39 #include "chrome/common/pref_names.h"
40 #include "chrome/common/profiling.h"
41 #include "components/signin/core/browser/signin_manager.h"
42 #include "content/public/browser/host_zoom_map.h"
43 #include "content/public/browser/navigation_entry.h"
44 #include "content/public/browser/notification_service.h"
45 #include "content/public/browser/notification_source.h"
46 #include "content/public/browser/notification_types.h"
47 #include "content/public/browser/user_metrics.h"
48 #include "content/public/browser/web_contents.h"
49 #include "grit/chromium_strings.h"
50 #include "grit/generated_resources.h"
51 #include "grit/theme_resources.h"
52 #include "ui/base/l10n/l10n_util.h"
53 #include "ui/base/layout.h"
54 #include "ui/base/models/button_menu_item_model.h"
55 #include "ui/base/resource/resource_bundle.h"
56 #include "ui/gfx/image/image.h"
57 #include "ui/gfx/image/image_skia.h"
59 #if defined(OS_CHROMEOS)
60 #include "chromeos/chromeos_switches.h"
61 #endif
63 #if defined(OS_WIN)
64 #include "base/win/metro.h"
65 #include "base/win/windows_version.h"
66 #include "chrome/browser/enumerate_modules_model_win.h"
67 #include "chrome/browser/ui/metro_pin_tab_helper_win.h"
68 #include "content/public/browser/gpu_data_manager.h"
69 #include "win8/util/win8_util.h"
70 #endif
72 #if defined(USE_ASH)
73 #include "ash/shell.h"
74 #endif
76 using base::UserMetricsAction;
77 using content::HostZoomMap;
78 using content::WebContents;
80 namespace {
81 // Conditionally return the update app menu item title based on upgrade detector
82 // state.
83 base::string16 GetUpgradeDialogMenuItemName() {
84 if (UpgradeDetector::GetInstance()->is_outdated_install() ||
85 UpgradeDetector::GetInstance()->is_outdated_install_no_au()) {
86 return l10n_util::GetStringUTF16(IDS_UPGRADE_BUBBLE_MENU_ITEM);
87 } else {
88 return l10n_util::GetStringUTF16(IDS_UPDATE_NOW);
92 } // namespace
94 ////////////////////////////////////////////////////////////////////////////////
95 // EncodingMenuModel
97 EncodingMenuModel::EncodingMenuModel(Browser* browser)
98 : ui::SimpleMenuModel(this),
99 browser_(browser) {
100 Build();
103 EncodingMenuModel::~EncodingMenuModel() {
106 void EncodingMenuModel::Build() {
107 EncodingMenuController::EncodingMenuItemList encoding_menu_items;
108 EncodingMenuController encoding_menu_controller;
109 encoding_menu_controller.GetEncodingMenuItems(browser_->profile(),
110 &encoding_menu_items);
112 int group_id = 0;
113 EncodingMenuController::EncodingMenuItemList::iterator it =
114 encoding_menu_items.begin();
115 for (; it != encoding_menu_items.end(); ++it) {
116 int id = it->first;
117 base::string16& label = it->second;
118 if (id == 0) {
119 AddSeparator(ui::NORMAL_SEPARATOR);
120 } else {
121 if (id == IDC_ENCODING_AUTO_DETECT) {
122 AddCheckItem(id, label);
123 } else {
124 // Use the id of the first radio command as the id of the group.
125 if (group_id <= 0)
126 group_id = id;
127 AddRadioItem(id, label, group_id);
133 bool EncodingMenuModel::IsCommandIdChecked(int command_id) const {
134 WebContents* current_tab =
135 browser_->tab_strip_model()->GetActiveWebContents();
136 if (!current_tab)
137 return false;
138 EncodingMenuController controller;
139 return controller.IsItemChecked(browser_->profile(),
140 current_tab->GetEncoding(), command_id);
143 bool EncodingMenuModel::IsCommandIdEnabled(int command_id) const {
144 bool enabled = chrome::IsCommandEnabled(browser_, command_id);
145 // Special handling for the contents of the Encoding submenu. On Mac OS,
146 // instead of enabling/disabling the top-level menu item, the submenu's
147 // contents get disabled, per Apple's HIG.
148 #if defined(OS_MACOSX)
149 enabled &= chrome::IsCommandEnabled(browser_, IDC_ENCODING_MENU);
150 #endif
151 return enabled;
154 bool EncodingMenuModel::GetAcceleratorForCommandId(
155 int command_id,
156 ui::Accelerator* accelerator) {
157 return false;
160 void EncodingMenuModel::ExecuteCommand(int command_id, int event_flags) {
161 chrome::ExecuteCommand(browser_, command_id);
164 ////////////////////////////////////////////////////////////////////////////////
165 // ZoomMenuModel
167 ZoomMenuModel::ZoomMenuModel(ui::SimpleMenuModel::Delegate* delegate)
168 : SimpleMenuModel(delegate) {
169 Build();
172 ZoomMenuModel::~ZoomMenuModel() {
175 void ZoomMenuModel::Build() {
176 AddItemWithStringId(IDC_ZOOM_PLUS, IDS_ZOOM_PLUS);
177 AddItemWithStringId(IDC_ZOOM_NORMAL, IDS_ZOOM_NORMAL);
178 AddItemWithStringId(IDC_ZOOM_MINUS, IDS_ZOOM_MINUS);
181 ////////////////////////////////////////////////////////////////////////////////
182 // ToolsMenuModel
184 ToolsMenuModel::ToolsMenuModel(ui::SimpleMenuModel::Delegate* delegate,
185 Browser* browser)
186 : SimpleMenuModel(delegate) {
187 Build(browser);
190 ToolsMenuModel::~ToolsMenuModel() {}
192 void ToolsMenuModel::Build(Browser* browser) {
193 bool show_create_shortcuts = true;
194 #if defined(OS_CHROMEOS) || defined(OS_MACOSX)
195 show_create_shortcuts = false;
196 #elif defined(USE_ASH)
197 if (browser->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH)
198 show_create_shortcuts = false;
199 #endif
201 if (CommandLine::ForCurrentProcess()->HasSwitch(
202 switches::kEnableStreamlinedHostedApps)) {
203 AddItemWithStringId(IDC_CREATE_HOSTED_APP, IDS_CREATE_HOSTED_APP);
204 AddSeparator(ui::NORMAL_SEPARATOR);
205 } else if (show_create_shortcuts) {
206 AddItemWithStringId(IDC_CREATE_SHORTCUTS, IDS_CREATE_SHORTCUTS);
207 AddSeparator(ui::NORMAL_SEPARATOR);
210 AddItemWithStringId(IDC_MANAGE_EXTENSIONS, IDS_SHOW_EXTENSIONS);
212 if (chrome::CanOpenTaskManager())
213 AddItemWithStringId(IDC_TASK_MANAGER, IDS_TASK_MANAGER);
215 AddItemWithStringId(IDC_CLEAR_BROWSING_DATA, IDS_CLEAR_BROWSING_DATA);
217 AddSeparator(ui::NORMAL_SEPARATOR);
219 #if defined(GOOGLE_CHROME_BUILD)
220 #if !defined(OS_CHROMEOS)
221 // Show IDC_FEEDBACK in "Tools" menu for non-ChromeOS platforms.
222 AddItemWithStringId(IDC_FEEDBACK, IDS_FEEDBACK);
223 AddSeparator(ui::NORMAL_SEPARATOR);
224 #endif
225 #endif // GOOGLE_CHROME_BUILD
227 encoding_menu_model_.reset(new EncodingMenuModel(browser));
228 AddSubMenuWithStringId(IDC_ENCODING_MENU, IDS_ENCODING_MENU,
229 encoding_menu_model_.get());
230 AddItemWithStringId(IDC_VIEW_SOURCE, IDS_VIEW_SOURCE);
231 AddItemWithStringId(IDC_DEV_TOOLS, IDS_DEV_TOOLS);
232 AddItemWithStringId(IDC_DEV_TOOLS_CONSOLE, IDS_DEV_TOOLS_CONSOLE);
233 AddItemWithStringId(IDC_DEV_TOOLS_DEVICES, IDS_DEV_TOOLS_DEVICES);
235 #if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC)
236 AddSeparator(ui::NORMAL_SEPARATOR);
237 AddCheckItemWithStringId(IDC_PROFILING_ENABLED, IDS_PROFILING_ENABLED);
238 #endif
241 ////////////////////////////////////////////////////////////////////////////////
242 // WrenchMenuModel
244 WrenchMenuModel::WrenchMenuModel(ui::AcceleratorProvider* provider,
245 Browser* browser,
246 bool is_new_menu)
247 : ui::SimpleMenuModel(this),
248 provider_(provider),
249 browser_(browser),
250 tab_strip_model_(browser_->tab_strip_model()) {
251 Build(is_new_menu);
252 UpdateZoomControls();
254 zoom_subscription_ = HostZoomMap::GetForBrowserContext(
255 browser->profile())->AddZoomLevelChangedCallback(
256 base::Bind(&WrenchMenuModel::OnZoomLevelChanged,
257 base::Unretained(this)));
259 tab_strip_model_->AddObserver(this);
261 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
262 content::NotificationService::AllSources());
265 WrenchMenuModel::~WrenchMenuModel() {
266 if (tab_strip_model_)
267 tab_strip_model_->RemoveObserver(this);
270 bool WrenchMenuModel::DoesCommandIdDismissMenu(int command_id) const {
271 return command_id != IDC_ZOOM_MINUS && command_id != IDC_ZOOM_PLUS;
274 bool WrenchMenuModel::IsItemForCommandIdDynamic(int command_id) const {
275 return command_id == IDC_ZOOM_PERCENT_DISPLAY ||
276 #if defined(OS_MACOSX)
277 command_id == IDC_FULLSCREEN ||
278 #elif defined(OS_WIN)
279 command_id == IDC_PIN_TO_START_SCREEN ||
280 #endif
281 command_id == IDC_UPGRADE_DIALOG ||
282 command_id == IDC_SHOW_SIGNIN;
285 base::string16 WrenchMenuModel::GetLabelForCommandId(int command_id) const {
286 switch (command_id) {
287 case IDC_ZOOM_PERCENT_DISPLAY:
288 return zoom_label_;
289 #if defined(OS_MACOSX)
290 case IDC_FULLSCREEN: {
291 int string_id = IDS_ENTER_FULLSCREEN_MAC; // Default to Enter.
292 // Note: On startup, |window()| may be NULL.
293 if (browser_->window() && browser_->window()->IsFullscreen())
294 string_id = IDS_EXIT_FULLSCREEN_MAC;
295 return l10n_util::GetStringUTF16(string_id);
297 #elif defined(OS_WIN)
298 case IDC_PIN_TO_START_SCREEN: {
299 int string_id = IDS_PIN_TO_START_SCREEN;
300 WebContents* web_contents =
301 browser_->tab_strip_model()->GetActiveWebContents();
302 MetroPinTabHelper* tab_helper =
303 web_contents ? MetroPinTabHelper::FromWebContents(web_contents)
304 : NULL;
305 if (tab_helper && tab_helper->IsPinned())
306 string_id = IDS_UNPIN_FROM_START_SCREEN;
307 return l10n_util::GetStringUTF16(string_id);
309 #endif
310 case IDC_UPGRADE_DIALOG:
311 return GetUpgradeDialogMenuItemName();
312 case IDC_SHOW_SIGNIN:
313 return signin_ui_util::GetSigninMenuLabel(
314 browser_->profile()->GetOriginalProfile());
315 default:
316 NOTREACHED();
317 return base::string16();
321 bool WrenchMenuModel::GetIconForCommandId(int command_id,
322 gfx::Image* icon) const {
323 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
324 switch (command_id) {
325 case IDC_UPGRADE_DIALOG: {
326 if (UpgradeDetector::GetInstance()->notify_upgrade()) {
327 *icon = rb.GetNativeImageNamed(
328 UpgradeDetector::GetInstance()->GetIconResourceID(
329 UpgradeDetector::UPGRADE_ICON_TYPE_MENU_ICON));
330 return true;
332 return false;
334 case IDC_SHOW_SIGNIN: {
335 GlobalError* error = signin_ui_util::GetSignedInServiceError(
336 browser_->profile()->GetOriginalProfile());
337 if (error) {
338 int icon_id = error->MenuItemIconResourceID();
339 if (icon_id) {
340 *icon = rb.GetNativeImageNamed(icon_id);
341 return true;
344 return false;
346 default:
347 break;
349 return false;
352 void WrenchMenuModel::ExecuteCommand(int command_id, int event_flags) {
353 GlobalError* error = GlobalErrorServiceFactory::GetForProfile(
354 browser_->profile())->GetGlobalErrorByMenuItemCommandID(command_id);
355 if (error) {
356 error->ExecuteMenuItem(browser_);
357 return;
360 if (command_id == IDC_SHOW_SIGNIN) {
361 // If a custom error message is being shown, handle it.
362 GlobalError* error = signin_ui_util::GetSignedInServiceError(
363 browser_->profile()->GetOriginalProfile());
364 if (error) {
365 error->ExecuteMenuItem(browser_);
366 return;
370 if (command_id == IDC_HELP_PAGE_VIA_MENU)
371 content::RecordAction(UserMetricsAction("ShowHelpTabViaWrenchMenu"));
373 if (command_id == IDC_FULLSCREEN) {
374 // We issue the UMA command here and not in BrowserCommandController or even
375 // FullscreenController since we want to be able to distinguish this event
376 // and a menu which is under development.
377 content::RecordAction(UserMetricsAction("EnterFullScreenWithWrenchMenu"));
380 chrome::ExecuteCommand(browser_, command_id);
383 bool WrenchMenuModel::IsCommandIdChecked(int command_id) const {
384 if (command_id == IDC_SHOW_BOOKMARK_BAR) {
385 return browser_->profile()->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar);
386 } else if (command_id == IDC_PROFILING_ENABLED) {
387 return Profiling::BeingProfiled();
388 } else if (command_id == IDC_TOGGLE_REQUEST_TABLET_SITE) {
389 return chrome::IsRequestingTabletSite(browser_);
392 return false;
395 bool WrenchMenuModel::IsCommandIdEnabled(int command_id) const {
396 GlobalError* error = GlobalErrorServiceFactory::GetForProfile(
397 browser_->profile())->GetGlobalErrorByMenuItemCommandID(command_id);
398 if (error)
399 return true;
401 return chrome::IsCommandEnabled(browser_, command_id);
404 bool WrenchMenuModel::IsCommandIdVisible(int command_id) const {
405 switch (command_id) {
406 #if defined(OS_WIN)
407 case IDC_VIEW_INCOMPATIBILITIES: {
408 EnumerateModulesModel* loaded_modules =
409 EnumerateModulesModel::GetInstance();
410 if (loaded_modules->confirmed_bad_modules_detected() <= 0)
411 return false;
412 // We'll leave the wrench adornment on until the user clicks the link.
413 if (loaded_modules->modules_to_notify_about() <= 0)
414 loaded_modules->AcknowledgeConflictNotification();
415 return true;
417 case IDC_PIN_TO_START_SCREEN:
418 return base::win::IsMetroProcess();
419 #else
420 case IDC_VIEW_INCOMPATIBILITIES:
421 case IDC_PIN_TO_START_SCREEN:
422 return false;
423 #endif
424 case IDC_UPGRADE_DIALOG:
425 return UpgradeDetector::GetInstance()->notify_upgrade();
426 #if !defined(OS_LINUX) || defined(USE_AURA)
427 case IDC_BOOKMARK_PAGE:
428 return !chrome::ShouldRemoveBookmarkThisPageUI(browser_->profile());
429 case IDC_BOOKMARK_ALL_TABS:
430 return !chrome::ShouldRemoveBookmarkOpenPagesUI(browser_->profile());
431 #endif
432 default:
433 return true;
437 bool WrenchMenuModel::GetAcceleratorForCommandId(
438 int command_id,
439 ui::Accelerator* accelerator) {
440 return provider_->GetAcceleratorForCommandId(command_id, accelerator);
443 void WrenchMenuModel::ActiveTabChanged(WebContents* old_contents,
444 WebContents* new_contents,
445 int index,
446 int reason) {
447 // The user has switched between tabs and the new tab may have a different
448 // zoom setting.
449 UpdateZoomControls();
452 void WrenchMenuModel::TabReplacedAt(TabStripModel* tab_strip_model,
453 WebContents* old_contents,
454 WebContents* new_contents,
455 int index) {
456 UpdateZoomControls();
459 void WrenchMenuModel::TabStripModelDeleted() {
460 // During views shutdown, the tabstrip model/browser is deleted first, while
461 // it is the opposite in gtk land.
462 tab_strip_model_->RemoveObserver(this);
463 tab_strip_model_ = NULL;
466 void WrenchMenuModel::Observe(int type,
467 const content::NotificationSource& source,
468 const content::NotificationDetails& details) {
469 DCHECK(type == content::NOTIFICATION_NAV_ENTRY_COMMITTED);
470 UpdateZoomControls();
473 // For testing.
474 WrenchMenuModel::WrenchMenuModel()
475 : ui::SimpleMenuModel(this),
476 provider_(NULL),
477 browser_(NULL),
478 tab_strip_model_(NULL) {
481 bool WrenchMenuModel::ShouldShowNewIncognitoWindowMenuItem() {
482 if (browser_->profile()->IsManaged())
483 return false;
485 #if defined(OS_WIN)
486 if (win8::IsSingleWindowMetroMode() &&
487 browser_->profile()->HasOffTheRecordProfile()) {
488 return false;
490 #endif
492 return !browser_->profile()->IsGuestSession();
495 bool WrenchMenuModel::ShouldShowNewWindowMenuItem() {
496 #if defined(OS_WIN)
497 if (!win8::IsSingleWindowMetroMode())
498 return true;
500 // In Win8's single window Metro mode, we only show the New Window options
501 // if there isn't already a window of the requested type (incognito or not)
502 // that is available.
503 return browser_->profile()->IsOffTheRecord() &&
504 !chrome::FindBrowserWithProfile(
505 browser_->profile()->GetOriginalProfile(),
506 browser_->host_desktop_type());
507 #else
508 return true;
509 #endif
512 void WrenchMenuModel::Build(bool is_new_menu) {
513 #if defined(OS_WIN)
514 AddItem(IDC_VIEW_INCOMPATIBILITIES,
515 l10n_util::GetStringUTF16(IDS_VIEW_INCOMPATIBILITIES));
516 EnumerateModulesModel* model =
517 EnumerateModulesModel::GetInstance();
518 if (model->modules_to_notify_about() > 0 ||
519 model->confirmed_bad_modules_detected() > 0)
520 AddSeparator(ui::NORMAL_SEPARATOR);
521 #endif
523 AddItemWithStringId(IDC_NEW_TAB, IDS_NEW_TAB);
524 if (ShouldShowNewWindowMenuItem())
525 AddItemWithStringId(IDC_NEW_WINDOW, IDS_NEW_WINDOW);
527 if (ShouldShowNewIncognitoWindowMenuItem())
528 AddItemWithStringId(IDC_NEW_INCOGNITO_WINDOW, IDS_NEW_INCOGNITO_WINDOW);
530 #if defined(OS_WIN) && !defined(NDEBUG) && defined(USE_ASH)
531 if (base::win::GetVersion() < base::win::VERSION_WIN8 &&
532 chrome::HOST_DESKTOP_TYPE_NATIVE != chrome::HOST_DESKTOP_TYPE_ASH) {
533 AddItemWithStringId(IDC_TOGGLE_ASH_DESKTOP,
534 ash::Shell::HasInstance() ? IDS_CLOSE_ASH_DESKTOP :
535 IDS_OPEN_ASH_DESKTOP);
537 #endif
539 bookmark_sub_menu_model_.reset(new BookmarkSubMenuModel(this, browser_));
540 AddSubMenuWithStringId(IDC_BOOKMARKS_MENU, IDS_BOOKMARKS_MENU,
541 bookmark_sub_menu_model_.get());
543 if (chrome::IsInstantExtendedAPIEnabled()) {
544 recent_tabs_sub_menu_model_.reset(new RecentTabsSubMenuModel(provider_,
545 browser_,
546 NULL));
547 AddSubMenuWithStringId(IDC_RECENT_TABS_MENU, IDS_RECENT_TABS_MENU,
548 recent_tabs_sub_menu_model_.get());
551 #if defined(OS_WIN)
553 #if defined(USE_AURA)
554 if (base::win::GetVersion() >= base::win::VERSION_WIN8 &&
555 content::GpuDataManager::GetInstance()->CanUseGpuBrowserCompositor()) {
556 if (browser_->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH) {
557 // Metro mode, add the 'Relaunch Chrome in desktop mode'.
558 AddSeparator(ui::NORMAL_SEPARATOR);
559 AddItemWithStringId(IDC_WIN8_DESKTOP_RESTART, IDS_WIN8_DESKTOP_RESTART);
560 } else {
561 // In Windows 8 desktop, add the 'Relaunch Chrome in Windows 8 mode'.
562 AddSeparator(ui::NORMAL_SEPARATOR);
563 AddItemWithStringId(IDC_WIN8_METRO_RESTART, IDS_WIN8_METRO_RESTART);
566 #else
567 if (base::win::IsMetroProcess()) {
568 // Metro mode, add the 'Relaunch Chrome in desktop mode'.
569 AddSeparator(ui::NORMAL_SEPARATOR);
570 AddItemWithStringId(IDC_WIN8_DESKTOP_RESTART, IDS_WIN8_DESKTOP_RESTART);
571 } else {
572 // In Windows 8 desktop, add the 'Relaunch Chrome in Windows 8 mode'.
573 AddSeparator(ui::NORMAL_SEPARATOR);
574 AddItemWithStringId(IDC_WIN8_METRO_RESTART, IDS_WIN8_METRO_RESTART);
576 #endif
578 #endif
580 // Append the full menu including separators. The final separator only gets
581 // appended when this is a touch menu - otherwise it would get added twice.
582 CreateCutCopyPasteMenu(is_new_menu);
584 if (!is_new_menu)
585 CreateZoomMenu(is_new_menu);
587 AddItemWithStringId(IDC_SAVE_PAGE, IDS_SAVE_PAGE);
588 AddItemWithStringId(IDC_FIND, IDS_FIND);
589 AddItemWithStringId(IDC_PRINT, IDS_PRINT);
591 tools_menu_model_.reset(new ToolsMenuModel(this, browser_));
592 // In case of touch this is the last item.
593 if (!is_new_menu) {
594 AddSubMenuWithStringId(IDC_ZOOM_MENU, IDS_TOOLS_MENU,
595 tools_menu_model_.get());
598 if (is_new_menu)
599 CreateZoomMenu(is_new_menu);
600 else
601 AddSeparator(ui::NORMAL_SEPARATOR);
603 AddItemWithStringId(IDC_SHOW_HISTORY, IDS_SHOW_HISTORY);
604 AddItemWithStringId(IDC_SHOW_DOWNLOADS, IDS_SHOW_DOWNLOADS);
605 AddSeparator(ui::NORMAL_SEPARATOR);
607 #if !defined(OS_CHROMEOS)
608 // No "Sign in to Chromium..." menu item on ChromeOS.
609 SigninManager* signin = SigninManagerFactory::GetForProfile(
610 browser_->profile()->GetOriginalProfile());
611 if (signin && signin->IsSigninAllowed()) {
612 const base::string16 short_product_name =
613 l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME);
614 AddItem(IDC_SHOW_SYNC_SETUP, l10n_util::GetStringFUTF16(
615 IDS_SYNC_MENU_PRE_SYNCED_LABEL, short_product_name));
616 AddSeparator(ui::NORMAL_SEPARATOR);
618 #endif
620 AddItemWithStringId(IDC_OPTIONS, IDS_SETTINGS);
622 #if defined(OS_CHROMEOS)
623 if (CommandLine::ForCurrentProcess()->HasSwitch(
624 chromeos::switches::kEnableRequestTabletSite))
625 AddCheckItemWithStringId(IDC_TOGGLE_REQUEST_TABLET_SITE,
626 IDS_TOGGLE_REQUEST_TABLET_SITE);
627 #endif
629 // On ChromeOS-Touch, we don't want the about menu option.
630 #if defined(OS_CHROMEOS)
631 if (!is_new_menu)
632 #endif
634 AddItem(IDC_ABOUT, l10n_util::GetStringUTF16(IDS_ABOUT));
637 if (browser_defaults::kShowUpgradeMenuItem)
638 AddItem(IDC_UPGRADE_DIALOG, GetUpgradeDialogMenuItemName());
640 #if defined(OS_WIN)
641 SetIcon(GetIndexOfCommandId(IDC_VIEW_INCOMPATIBILITIES),
642 ui::ResourceBundle::GetSharedInstance().
643 GetNativeImageNamed(IDR_INPUT_ALERT_MENU));
644 #endif
646 if (!is_new_menu) {
647 AddItemWithStringId(IDC_HELP_PAGE_VIA_MENU, IDS_HELP_PAGE);
649 if (browser_defaults::kShowHelpMenuItemIcon) {
650 ui::ResourceBundle& rb = ResourceBundle::GetSharedInstance();
651 SetIcon(GetIndexOfCommandId(IDC_HELP_PAGE_VIA_MENU),
652 rb.GetNativeImageNamed(IDR_HELP_MENU));
656 #if defined(GOOGLE_CHROME_BUILD)
657 #if defined(OS_CHROMEOS)
658 AddItemWithStringId(IDC_FEEDBACK, IDS_FEEDBACK);
659 #endif
660 #endif
662 AddGlobalErrorMenuItems();
664 if (is_new_menu) {
665 AddSubMenuWithStringId(IDC_ZOOM_MENU, IDS_MORE_TOOLS_MENU,
666 tools_menu_model_.get());
669 bool show_exit_menu = browser_defaults::kShowExitMenuItem;
670 #if defined(OS_WIN)
671 if (browser_->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH)
672 show_exit_menu = false;
673 #endif
675 if (show_exit_menu) {
676 AddSeparator(ui::NORMAL_SEPARATOR);
677 AddItemWithStringId(IDC_EXIT, IDS_EXIT);
681 void WrenchMenuModel::AddGlobalErrorMenuItems() {
682 // TODO(sail): Currently we only build the wrench menu once per browser
683 // window. This means that if a new error is added after the menu is built
684 // it won't show in the existing wrench menu. To fix this we need to some
685 // how update the menu if new errors are added.
686 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
687 // GetSignedInServiceErrors() can modify the global error list, so call it
688 // before iterating through that list below.
689 std::vector<GlobalError*> signin_errors =
690 signin_ui_util::GetSignedInServiceErrors(
691 browser_->profile()->GetOriginalProfile());
692 const GlobalErrorService::GlobalErrorList& errors =
693 GlobalErrorServiceFactory::GetForProfile(browser_->profile())->errors();
694 for (GlobalErrorService::GlobalErrorList::const_iterator
695 it = errors.begin(); it != errors.end(); ++it) {
696 GlobalError* error = *it;
697 DCHECK(error);
698 if (error->HasMenuItem()) {
699 #if !defined(OS_CHROMEOS)
700 // Don't add a signin error if it's already being displayed elsewhere.
701 if (std::find(signin_errors.begin(), signin_errors.end(), error) !=
702 signin_errors.end()) {
703 MenuModel* model = this;
704 int index = 0;
705 if (MenuModel::GetModelAndIndexForCommandId(
706 IDC_SHOW_SIGNIN, &model, &index)) {
707 continue;
710 #endif
712 AddItem(error->MenuItemCommandID(), error->MenuItemLabel());
713 int icon_id = error->MenuItemIconResourceID();
714 if (icon_id) {
715 const gfx::Image& image = rb.GetNativeImageNamed(icon_id);
716 SetIcon(GetIndexOfCommandId(error->MenuItemCommandID()),
717 image);
723 void WrenchMenuModel::CreateCutCopyPasteMenu(bool new_menu) {
724 AddSeparator(new_menu ? ui::LOWER_SEPARATOR : ui::NORMAL_SEPARATOR);
726 #if defined(OS_POSIX) && !defined(TOOLKIT_VIEWS)
727 // WARNING: Mac does not use the ButtonMenuItemModel, but instead defines the
728 // layout for this menu item in Toolbar.xib. It does, however, use the
729 // command_id value from AddButtonItem() to identify this special item.
730 edit_menu_item_model_.reset(new ui::ButtonMenuItemModel(IDS_EDIT, this));
731 edit_menu_item_model_->AddGroupItemWithStringId(IDC_CUT, IDS_CUT);
732 edit_menu_item_model_->AddGroupItemWithStringId(IDC_COPY, IDS_COPY);
733 edit_menu_item_model_->AddGroupItemWithStringId(IDC_PASTE, IDS_PASTE);
734 AddButtonItem(IDC_EDIT_MENU, edit_menu_item_model_.get());
735 #else
736 // WARNING: views/wrench_menu assumes these items are added in this order. If
737 // you change the order you'll need to update wrench_menu as well.
738 AddItemWithStringId(IDC_CUT, IDS_CUT);
739 AddItemWithStringId(IDC_COPY, IDS_COPY);
740 AddItemWithStringId(IDC_PASTE, IDS_PASTE);
741 #endif
743 if (new_menu)
744 AddSeparator(ui::UPPER_SEPARATOR);
747 void WrenchMenuModel::CreateZoomMenu(bool new_menu) {
748 // This menu needs to be enclosed by separators.
749 AddSeparator(new_menu ? ui::LOWER_SEPARATOR : ui::NORMAL_SEPARATOR);
751 #if defined(OS_POSIX) && !defined(TOOLKIT_VIEWS)
752 // WARNING: Mac does not use the ButtonMenuItemModel, but instead defines the
753 // layout for this menu item in Toolbar.xib. It does, however, use the
754 // command_id value from AddButtonItem() to identify this special item.
755 zoom_menu_item_model_.reset(
756 new ui::ButtonMenuItemModel(IDS_ZOOM_MENU, this));
757 zoom_menu_item_model_->AddGroupItemWithStringId(
758 IDC_ZOOM_MINUS, IDS_ZOOM_MINUS2);
759 zoom_menu_item_model_->AddButtonLabel(IDC_ZOOM_PERCENT_DISPLAY,
760 IDS_ZOOM_PLUS2);
761 zoom_menu_item_model_->AddGroupItemWithStringId(
762 IDC_ZOOM_PLUS, IDS_ZOOM_PLUS2);
763 zoom_menu_item_model_->AddSpace();
764 zoom_menu_item_model_->AddItemWithImage(
765 IDC_FULLSCREEN, IDR_FULLSCREEN_MENU_BUTTON);
766 AddButtonItem(IDC_ZOOM_MENU, zoom_menu_item_model_.get());
767 #else
768 // WARNING: views/wrench_menu assumes these items are added in this order. If
769 // you change the order you'll need to update wrench_menu as well.
770 AddItemWithStringId(IDC_ZOOM_MINUS, IDS_ZOOM_MINUS);
771 AddItemWithStringId(IDC_ZOOM_PLUS, IDS_ZOOM_PLUS);
772 AddItemWithStringId(IDC_FULLSCREEN, IDS_FULLSCREEN);
773 #endif
775 AddSeparator(new_menu ? ui::UPPER_SEPARATOR : ui::NORMAL_SEPARATOR);
778 void WrenchMenuModel::UpdateZoomControls() {
779 bool enable_increment = false;
780 bool enable_decrement = false;
781 int zoom_percent = 100;
782 if (browser_->tab_strip_model()->GetActiveWebContents()) {
783 zoom_percent =
784 browser_->tab_strip_model()->GetActiveWebContents()->GetZoomPercent(
785 &enable_increment, &enable_decrement);
787 zoom_label_ = l10n_util::GetStringFUTF16(
788 IDS_ZOOM_PERCENT, base::IntToString16(zoom_percent));
791 void WrenchMenuModel::OnZoomLevelChanged(
792 const content::HostZoomMap::ZoomLevelChange& change) {
793 UpdateZoomControls();