Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / toolbar / wrench_menu_model.cc
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.
4
5 #include "chrome/browser/ui/toolbar/wrench_menu_model.h"
6
7 #include <algorithm>
8 #include <cmath>
9
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"
58
59 #if defined(OS_CHROMEOS)
60 #include "chromeos/chromeos_switches.h"
61 #endif
62
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 #endif
70
71 #if defined(USE_ASH)
72 #include "ash/shell.h"
73 #endif
74
75 using base::UserMetricsAction;
76 using content::HostZoomMap;
77 using content::WebContents;
78
79 namespace {
80 // Conditionally return the update app menu item title based on upgrade detector
81 // state.
82 base::string16 GetUpgradeDialogMenuItemName() {
83   if (UpgradeDetector::GetInstance()->is_outdated_install() ||
84       UpgradeDetector::GetInstance()->is_outdated_install_no_au()) {
85     return l10n_util::GetStringUTF16(IDS_UPGRADE_BUBBLE_MENU_ITEM);
86   } else {
87     return l10n_util::GetStringUTF16(IDS_UPDATE_NOW);
88   }
89 }
90
91 }  // namespace
92
93 ////////////////////////////////////////////////////////////////////////////////
94 // EncodingMenuModel
95
96 EncodingMenuModel::EncodingMenuModel(Browser* browser)
97     : ui::SimpleMenuModel(this),
98       browser_(browser) {
99   Build();
100 }
101
102 EncodingMenuModel::~EncodingMenuModel() {
103 }
104
105 void EncodingMenuModel::Build() {
106   EncodingMenuController::EncodingMenuItemList encoding_menu_items;
107   EncodingMenuController encoding_menu_controller;
108   encoding_menu_controller.GetEncodingMenuItems(browser_->profile(),
109                                                 &encoding_menu_items);
110
111   int group_id = 0;
112   EncodingMenuController::EncodingMenuItemList::iterator it =
113       encoding_menu_items.begin();
114   for (; it != encoding_menu_items.end(); ++it) {
115     int id = it->first;
116     base::string16& label = it->second;
117     if (id == 0) {
118       AddSeparator(ui::NORMAL_SEPARATOR);
119     } else {
120       if (id == IDC_ENCODING_AUTO_DETECT) {
121         AddCheckItem(id, label);
122       } else {
123         // Use the id of the first radio command as the id of the group.
124         if (group_id <= 0)
125           group_id = id;
126         AddRadioItem(id, label, group_id);
127       }
128     }
129   }
130 }
131
132 bool EncodingMenuModel::IsCommandIdChecked(int command_id) const {
133   WebContents* current_tab =
134       browser_->tab_strip_model()->GetActiveWebContents();
135   if (!current_tab)
136     return false;
137   EncodingMenuController controller;
138   return controller.IsItemChecked(browser_->profile(),
139                                   current_tab->GetEncoding(), command_id);
140 }
141
142 bool EncodingMenuModel::IsCommandIdEnabled(int command_id) const {
143   bool enabled = chrome::IsCommandEnabled(browser_, command_id);
144   // Special handling for the contents of the Encoding submenu. On Mac OS,
145   // instead of enabling/disabling the top-level menu item, the submenu's
146   // contents get disabled, per Apple's HIG.
147 #if defined(OS_MACOSX)
148   enabled &= chrome::IsCommandEnabled(browser_, IDC_ENCODING_MENU);
149 #endif
150   return enabled;
151 }
152
153 bool EncodingMenuModel::GetAcceleratorForCommandId(
154     int command_id,
155     ui::Accelerator* accelerator) {
156   return false;
157 }
158
159 void EncodingMenuModel::ExecuteCommand(int command_id, int event_flags) {
160   chrome::ExecuteCommand(browser_, command_id);
161 }
162
163 ////////////////////////////////////////////////////////////////////////////////
164 // ZoomMenuModel
165
166 ZoomMenuModel::ZoomMenuModel(ui::SimpleMenuModel::Delegate* delegate)
167     : SimpleMenuModel(delegate) {
168   Build();
169 }
170
171 ZoomMenuModel::~ZoomMenuModel() {
172 }
173
174 void ZoomMenuModel::Build() {
175   AddItemWithStringId(IDC_ZOOM_PLUS, IDS_ZOOM_PLUS);
176   AddItemWithStringId(IDC_ZOOM_NORMAL, IDS_ZOOM_NORMAL);
177   AddItemWithStringId(IDC_ZOOM_MINUS, IDS_ZOOM_MINUS);
178 }
179
180 ////////////////////////////////////////////////////////////////////////////////
181 // ToolsMenuModel
182
183 ToolsMenuModel::ToolsMenuModel(ui::SimpleMenuModel::Delegate* delegate,
184                                Browser* browser)
185     : SimpleMenuModel(delegate) {
186   Build(browser);
187 }
188
189 ToolsMenuModel::~ToolsMenuModel() {}
190
191 void ToolsMenuModel::Build(Browser* browser) {
192   bool show_create_shortcuts = true;
193 #if defined(OS_CHROMEOS) || defined(OS_MACOSX)
194   show_create_shortcuts = false;
195 #elif defined(USE_ASH)
196   if (browser->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH)
197     show_create_shortcuts = false;
198 #endif
199
200   if (CommandLine::ForCurrentProcess()->HasSwitch(
201       switches::kEnableStreamlinedHostedApps)) {
202     AddItemWithStringId(IDC_CREATE_HOSTED_APP, IDS_CREATE_HOSTED_APP);
203     AddSeparator(ui::NORMAL_SEPARATOR);
204   } else if (show_create_shortcuts) {
205     AddItemWithStringId(IDC_CREATE_SHORTCUTS, IDS_CREATE_SHORTCUTS);
206     AddSeparator(ui::NORMAL_SEPARATOR);
207   }
208
209   AddItemWithStringId(IDC_MANAGE_EXTENSIONS, IDS_SHOW_EXTENSIONS);
210
211   if (chrome::CanOpenTaskManager())
212     AddItemWithStringId(IDC_TASK_MANAGER, IDS_TASK_MANAGER);
213
214   AddItemWithStringId(IDC_CLEAR_BROWSING_DATA, IDS_CLEAR_BROWSING_DATA);
215
216   AddSeparator(ui::NORMAL_SEPARATOR);
217
218 #if defined(GOOGLE_CHROME_BUILD)
219 #if !defined(OS_CHROMEOS)
220   // Show IDC_FEEDBACK in "Tools" menu for non-ChromeOS platforms.
221   AddItemWithStringId(IDC_FEEDBACK, IDS_FEEDBACK);
222   AddSeparator(ui::NORMAL_SEPARATOR);
223 #endif
224 #endif // GOOGLE_CHROME_BUILD
225
226   encoding_menu_model_.reset(new EncodingMenuModel(browser));
227   AddSubMenuWithStringId(IDC_ENCODING_MENU, IDS_ENCODING_MENU,
228                          encoding_menu_model_.get());
229   AddItemWithStringId(IDC_VIEW_SOURCE, IDS_VIEW_SOURCE);
230   AddItemWithStringId(IDC_DEV_TOOLS, IDS_DEV_TOOLS);
231   AddItemWithStringId(IDC_DEV_TOOLS_CONSOLE, IDS_DEV_TOOLS_CONSOLE);
232   AddItemWithStringId(IDC_DEV_TOOLS_DEVICES, IDS_DEV_TOOLS_DEVICES);
233
234 #if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC)
235   AddSeparator(ui::NORMAL_SEPARATOR);
236   AddCheckItemWithStringId(IDC_PROFILING_ENABLED, IDS_PROFILING_ENABLED);
237 #endif
238 }
239
240 ////////////////////////////////////////////////////////////////////////////////
241 // WrenchMenuModel
242
243 WrenchMenuModel::WrenchMenuModel(ui::AcceleratorProvider* provider,
244                                  Browser* browser,
245                                  bool is_new_menu)
246     : ui::SimpleMenuModel(this),
247       provider_(provider),
248       browser_(browser),
249       tab_strip_model_(browser_->tab_strip_model()) {
250   Build(is_new_menu);
251   UpdateZoomControls();
252
253   zoom_subscription_ = HostZoomMap::GetForBrowserContext(
254       browser->profile())->AddZoomLevelChangedCallback(
255           base::Bind(&WrenchMenuModel::OnZoomLevelChanged,
256                      base::Unretained(this)));
257
258   tab_strip_model_->AddObserver(this);
259
260   registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
261                  content::NotificationService::AllSources());
262 }
263
264 WrenchMenuModel::~WrenchMenuModel() {
265   if (tab_strip_model_)
266     tab_strip_model_->RemoveObserver(this);
267 }
268
269 bool WrenchMenuModel::DoesCommandIdDismissMenu(int command_id) const {
270   return command_id != IDC_ZOOM_MINUS && command_id != IDC_ZOOM_PLUS;
271 }
272
273 bool WrenchMenuModel::IsItemForCommandIdDynamic(int command_id) const {
274   return command_id == IDC_ZOOM_PERCENT_DISPLAY ||
275 #if defined(OS_MACOSX)
276          command_id == IDC_FULLSCREEN ||
277 #elif defined(OS_WIN)
278          command_id == IDC_PIN_TO_START_SCREEN ||
279 #endif
280          command_id == IDC_UPGRADE_DIALOG ||
281          command_id == IDC_SHOW_SIGNIN;
282 }
283
284 base::string16 WrenchMenuModel::GetLabelForCommandId(int command_id) const {
285   switch (command_id) {
286     case IDC_ZOOM_PERCENT_DISPLAY:
287       return zoom_label_;
288 #if defined(OS_MACOSX)
289     case IDC_FULLSCREEN: {
290       int string_id = IDS_ENTER_FULLSCREEN_MAC;  // Default to Enter.
291       // Note: On startup, |window()| may be NULL.
292       if (browser_->window() && browser_->window()->IsFullscreen())
293         string_id = IDS_EXIT_FULLSCREEN_MAC;
294       return l10n_util::GetStringUTF16(string_id);
295     }
296 #elif defined(OS_WIN)
297     case IDC_PIN_TO_START_SCREEN: {
298       int string_id = IDS_PIN_TO_START_SCREEN;
299       WebContents* web_contents =
300           browser_->tab_strip_model()->GetActiveWebContents();
301       MetroPinTabHelper* tab_helper =
302           web_contents ? MetroPinTabHelper::FromWebContents(web_contents)
303                        : NULL;
304       if (tab_helper && tab_helper->IsPinned())
305         string_id = IDS_UNPIN_FROM_START_SCREEN;
306       return l10n_util::GetStringUTF16(string_id);
307     }
308 #endif
309     case IDC_UPGRADE_DIALOG:
310       return GetUpgradeDialogMenuItemName();
311     case IDC_SHOW_SIGNIN:
312       return signin_ui_util::GetSigninMenuLabel(
313           browser_->profile()->GetOriginalProfile());
314     default:
315       NOTREACHED();
316       return base::string16();
317   }
318 }
319
320 bool WrenchMenuModel::GetIconForCommandId(int command_id,
321                                           gfx::Image* icon) const {
322   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
323   switch (command_id) {
324     case IDC_UPGRADE_DIALOG: {
325       if (UpgradeDetector::GetInstance()->notify_upgrade()) {
326         *icon = rb.GetNativeImageNamed(
327             UpgradeDetector::GetInstance()->GetIconResourceID(
328                 UpgradeDetector::UPGRADE_ICON_TYPE_MENU_ICON));
329         return true;
330       }
331       return false;
332     }
333     case IDC_SHOW_SIGNIN: {
334       GlobalError* error = signin_ui_util::GetSignedInServiceError(
335           browser_->profile()->GetOriginalProfile());
336       if (error) {
337         int icon_id = error->MenuItemIconResourceID();
338         if (icon_id) {
339           *icon = rb.GetNativeImageNamed(icon_id);
340           return true;
341         }
342       }
343       return false;
344     }
345     default:
346       break;
347   }
348   return false;
349 }
350
351 void WrenchMenuModel::ExecuteCommand(int command_id, int event_flags) {
352   GlobalError* error = GlobalErrorServiceFactory::GetForProfile(
353       browser_->profile())->GetGlobalErrorByMenuItemCommandID(command_id);
354   if (error) {
355     error->ExecuteMenuItem(browser_);
356     return;
357   }
358
359   if (command_id == IDC_SHOW_SIGNIN) {
360     // If a custom error message is being shown, handle it.
361     GlobalError* error = signin_ui_util::GetSignedInServiceError(
362         browser_->profile()->GetOriginalProfile());
363     if (error) {
364       error->ExecuteMenuItem(browser_);
365       return;
366     }
367   }
368
369   if (command_id == IDC_HELP_PAGE_VIA_MENU)
370     content::RecordAction(UserMetricsAction("ShowHelpTabViaWrenchMenu"));
371
372   if (command_id == IDC_FULLSCREEN) {
373     // We issue the UMA command here and not in BrowserCommandController or even
374     // FullscreenController since we want to be able to distinguish this event
375     // and a menu which is under development.
376     content::RecordAction(UserMetricsAction("EnterFullScreenWithWrenchMenu"));
377   }
378
379   chrome::ExecuteCommand(browser_, command_id);
380 }
381
382 bool WrenchMenuModel::IsCommandIdChecked(int command_id) const {
383   if (command_id == IDC_SHOW_BOOKMARK_BAR) {
384     return browser_->profile()->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar);
385   } else if (command_id == IDC_PROFILING_ENABLED) {
386     return Profiling::BeingProfiled();
387   } else if (command_id == IDC_TOGGLE_REQUEST_TABLET_SITE) {
388     return chrome::IsRequestingTabletSite(browser_);
389   }
390
391   return false;
392 }
393
394 bool WrenchMenuModel::IsCommandIdEnabled(int command_id) const {
395   GlobalError* error = GlobalErrorServiceFactory::GetForProfile(
396       browser_->profile())->GetGlobalErrorByMenuItemCommandID(command_id);
397   if (error)
398     return true;
399
400   return chrome::IsCommandEnabled(browser_, command_id);
401 }
402
403 bool WrenchMenuModel::IsCommandIdVisible(int command_id) const {
404   switch (command_id) {
405 #if defined(OS_WIN)
406     case IDC_VIEW_INCOMPATIBILITIES: {
407       EnumerateModulesModel* loaded_modules =
408           EnumerateModulesModel::GetInstance();
409       if (loaded_modules->confirmed_bad_modules_detected() <= 0)
410         return false;
411       // We'll leave the wrench adornment on until the user clicks the link.
412       if (loaded_modules->modules_to_notify_about() <= 0)
413         loaded_modules->AcknowledgeConflictNotification();
414       return true;
415     }
416     case IDC_PIN_TO_START_SCREEN:
417       return base::win::IsMetroProcess();
418 #else
419     case IDC_VIEW_INCOMPATIBILITIES:
420     case IDC_PIN_TO_START_SCREEN:
421       return false;
422 #endif
423     case IDC_UPGRADE_DIALOG:
424       return UpgradeDetector::GetInstance()->notify_upgrade();
425 #if !defined(OS_LINUX) || defined(USE_AURA)
426     case IDC_BOOKMARK_PAGE:
427       return !chrome::ShouldRemoveBookmarkThisPageUI(browser_->profile());
428     case IDC_BOOKMARK_ALL_TABS:
429       return !chrome::ShouldRemoveBookmarkOpenPagesUI(browser_->profile());
430 #endif
431     default:
432       return true;
433   }
434 }
435
436 bool WrenchMenuModel::GetAcceleratorForCommandId(
437       int command_id,
438       ui::Accelerator* accelerator) {
439   return provider_->GetAcceleratorForCommandId(command_id, accelerator);
440 }
441
442 void WrenchMenuModel::ActiveTabChanged(WebContents* old_contents,
443                                        WebContents* new_contents,
444                                        int index,
445                                        int reason) {
446   // The user has switched between tabs and the new tab may have a different
447   // zoom setting.
448   UpdateZoomControls();
449 }
450
451 void WrenchMenuModel::TabReplacedAt(TabStripModel* tab_strip_model,
452                                     WebContents* old_contents,
453                                     WebContents* new_contents,
454                                     int index) {
455   UpdateZoomControls();
456 }
457
458 void WrenchMenuModel::TabStripModelDeleted() {
459   // During views shutdown, the tabstrip model/browser is deleted first, while
460   // it is the opposite in gtk land.
461   tab_strip_model_->RemoveObserver(this);
462   tab_strip_model_ = NULL;
463 }
464
465 void WrenchMenuModel::Observe(int type,
466                               const content::NotificationSource& source,
467                               const content::NotificationDetails& details) {
468   DCHECK(type == content::NOTIFICATION_NAV_ENTRY_COMMITTED);
469   UpdateZoomControls();
470 }
471
472 // For testing.
473 WrenchMenuModel::WrenchMenuModel()
474     : ui::SimpleMenuModel(this),
475       provider_(NULL),
476       browser_(NULL),
477       tab_strip_model_(NULL) {
478 }
479
480 bool WrenchMenuModel::ShouldShowNewIncognitoWindowMenuItem() {
481   if (browser_->profile()->IsManaged())
482     return false;
483
484   return !browser_->profile()->IsGuestSession();
485 }
486
487 void WrenchMenuModel::Build(bool is_new_menu) {
488 #if defined(OS_WIN)
489   AddItem(IDC_VIEW_INCOMPATIBILITIES,
490       l10n_util::GetStringUTF16(IDS_VIEW_INCOMPATIBILITIES));
491   EnumerateModulesModel* model =
492       EnumerateModulesModel::GetInstance();
493   if (model->modules_to_notify_about() > 0 ||
494       model->confirmed_bad_modules_detected() > 0)
495     AddSeparator(ui::NORMAL_SEPARATOR);
496 #endif
497
498   AddItemWithStringId(IDC_NEW_TAB, IDS_NEW_TAB);
499   AddItemWithStringId(IDC_NEW_WINDOW, IDS_NEW_WINDOW);
500
501   if (ShouldShowNewIncognitoWindowMenuItem())
502     AddItemWithStringId(IDC_NEW_INCOGNITO_WINDOW, IDS_NEW_INCOGNITO_WINDOW);
503
504 #if defined(OS_WIN) && !defined(NDEBUG) && defined(USE_ASH)
505   if (base::win::GetVersion() < base::win::VERSION_WIN8 &&
506       chrome::HOST_DESKTOP_TYPE_NATIVE != chrome::HOST_DESKTOP_TYPE_ASH) {
507     AddItemWithStringId(IDC_TOGGLE_ASH_DESKTOP,
508                         ash::Shell::HasInstance() ? IDS_CLOSE_ASH_DESKTOP :
509                                                     IDS_OPEN_ASH_DESKTOP);
510   }
511 #endif
512
513   bookmark_sub_menu_model_.reset(new BookmarkSubMenuModel(this, browser_));
514   AddSubMenuWithStringId(IDC_BOOKMARKS_MENU, IDS_BOOKMARKS_MENU,
515                          bookmark_sub_menu_model_.get());
516
517   if (!browser_->profile()->IsOffTheRecord()) {
518     recent_tabs_sub_menu_model_.reset(new RecentTabsSubMenuModel(provider_,
519                                                                  browser_,
520                                                                  NULL));
521     AddSubMenuWithStringId(IDC_RECENT_TABS_MENU, IDS_RECENT_TABS_MENU,
522                            recent_tabs_sub_menu_model_.get());
523   }
524
525 #if defined(OS_WIN)
526
527 #if defined(USE_AURA)
528  if (base::win::GetVersion() >= base::win::VERSION_WIN8 &&
529      content::GpuDataManager::GetInstance()->CanUseGpuBrowserCompositor()) {
530     if (browser_->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH) {
531       // Metro mode, add the 'Relaunch Chrome in desktop mode'.
532       AddSeparator(ui::NORMAL_SEPARATOR);
533       AddItemWithStringId(IDC_WIN8_DESKTOP_RESTART, IDS_WIN8_DESKTOP_RESTART);
534     } else {
535       // In Windows 8 desktop, add the 'Relaunch Chrome in Windows 8 mode'.
536       AddSeparator(ui::NORMAL_SEPARATOR);
537       AddItemWithStringId(IDC_WIN8_METRO_RESTART, IDS_WIN8_METRO_RESTART);
538     }
539   }
540 #else
541   if (base::win::IsMetroProcess()) {
542     // Metro mode, add the 'Relaunch Chrome in desktop mode'.
543     AddSeparator(ui::NORMAL_SEPARATOR);
544     AddItemWithStringId(IDC_WIN8_DESKTOP_RESTART, IDS_WIN8_DESKTOP_RESTART);
545   } else {
546     // In Windows 8 desktop, add the 'Relaunch Chrome in Windows 8 mode'.
547     AddSeparator(ui::NORMAL_SEPARATOR);
548     AddItemWithStringId(IDC_WIN8_METRO_RESTART, IDS_WIN8_METRO_RESTART);
549   }
550 #endif
551
552 #endif
553
554   // Append the full menu including separators. The final separator only gets
555   // appended when this is a touch menu - otherwise it would get added twice.
556   CreateCutCopyPasteMenu(is_new_menu);
557
558   if (!is_new_menu)
559     CreateZoomMenu(is_new_menu);
560
561   AddItemWithStringId(IDC_SAVE_PAGE, IDS_SAVE_PAGE);
562   AddItemWithStringId(IDC_FIND, IDS_FIND);
563   AddItemWithStringId(IDC_PRINT, IDS_PRINT);
564
565   tools_menu_model_.reset(new ToolsMenuModel(this, browser_));
566   // In case of touch this is the last item.
567   if (!is_new_menu) {
568     AddSubMenuWithStringId(IDC_ZOOM_MENU, IDS_TOOLS_MENU,
569                            tools_menu_model_.get());
570   }
571
572   if (is_new_menu)
573     CreateZoomMenu(is_new_menu);
574   else
575     AddSeparator(ui::NORMAL_SEPARATOR);
576
577   AddItemWithStringId(IDC_SHOW_HISTORY, IDS_SHOW_HISTORY);
578   AddItemWithStringId(IDC_SHOW_DOWNLOADS, IDS_SHOW_DOWNLOADS);
579   AddSeparator(ui::NORMAL_SEPARATOR);
580
581 #if !defined(OS_CHROMEOS)
582   // No "Sign in to Chromium..." menu item on ChromeOS.
583   SigninManager* signin = SigninManagerFactory::GetForProfile(
584       browser_->profile()->GetOriginalProfile());
585   if (signin && signin->IsSigninAllowed()) {
586     const base::string16 short_product_name =
587         l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME);
588     AddItem(IDC_SHOW_SYNC_SETUP, l10n_util::GetStringFUTF16(
589         IDS_SYNC_MENU_PRE_SYNCED_LABEL, short_product_name));
590     AddSeparator(ui::NORMAL_SEPARATOR);
591   }
592 #endif
593
594   AddItemWithStringId(IDC_OPTIONS, IDS_SETTINGS);
595
596 #if defined(OS_CHROMEOS)
597   if (CommandLine::ForCurrentProcess()->HasSwitch(
598           chromeos::switches::kEnableRequestTabletSite))
599     AddCheckItemWithStringId(IDC_TOGGLE_REQUEST_TABLET_SITE,
600                              IDS_TOGGLE_REQUEST_TABLET_SITE);
601 #endif
602
603 // On ChromeOS-Touch, we don't want the about menu option.
604 #if defined(OS_CHROMEOS)
605   if (!is_new_menu)
606 #endif
607   {
608     AddItem(IDC_ABOUT, l10n_util::GetStringUTF16(IDS_ABOUT));
609   }
610
611   if (browser_defaults::kShowUpgradeMenuItem)
612     AddItem(IDC_UPGRADE_DIALOG, GetUpgradeDialogMenuItemName());
613
614 #if defined(OS_WIN)
615   SetIcon(GetIndexOfCommandId(IDC_VIEW_INCOMPATIBILITIES),
616           ui::ResourceBundle::GetSharedInstance().
617               GetNativeImageNamed(IDR_INPUT_ALERT_MENU));
618 #endif
619
620   if (!is_new_menu) {
621     AddItemWithStringId(IDC_HELP_PAGE_VIA_MENU, IDS_HELP_PAGE);
622
623     if (browser_defaults::kShowHelpMenuItemIcon) {
624       ui::ResourceBundle& rb = ResourceBundle::GetSharedInstance();
625       SetIcon(GetIndexOfCommandId(IDC_HELP_PAGE_VIA_MENU),
626               rb.GetNativeImageNamed(IDR_HELP_MENU));
627     }
628   }
629
630 #if defined(GOOGLE_CHROME_BUILD)
631 #if defined(OS_CHROMEOS)
632   AddItemWithStringId(IDC_FEEDBACK, IDS_FEEDBACK);
633 #endif
634 #endif
635
636   AddGlobalErrorMenuItems();
637
638   if (is_new_menu) {
639     AddSubMenuWithStringId(IDC_ZOOM_MENU, IDS_MORE_TOOLS_MENU,
640                            tools_menu_model_.get());
641   }
642
643   bool show_exit_menu = browser_defaults::kShowExitMenuItem;
644 #if defined(OS_WIN)
645   if (browser_->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH)
646     show_exit_menu = false;
647 #endif
648
649   if (show_exit_menu) {
650     AddSeparator(ui::NORMAL_SEPARATOR);
651     AddItemWithStringId(IDC_EXIT, IDS_EXIT);
652   }
653 }
654
655 void WrenchMenuModel::AddGlobalErrorMenuItems() {
656   // TODO(sail): Currently we only build the wrench menu once per browser
657   // window. This means that if a new error is added after the menu is built
658   // it won't show in the existing wrench menu. To fix this we need to some
659   // how update the menu if new errors are added.
660   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
661   // GetSignedInServiceErrors() can modify the global error list, so call it
662   // before iterating through that list below.
663   std::vector<GlobalError*> signin_errors =
664       signin_ui_util::GetSignedInServiceErrors(
665           browser_->profile()->GetOriginalProfile());
666   const GlobalErrorService::GlobalErrorList& errors =
667       GlobalErrorServiceFactory::GetForProfile(browser_->profile())->errors();
668   for (GlobalErrorService::GlobalErrorList::const_iterator
669        it = errors.begin(); it != errors.end(); ++it) {
670     GlobalError* error = *it;
671     DCHECK(error);
672     if (error->HasMenuItem()) {
673 #if !defined(OS_CHROMEOS)
674       // Don't add a signin error if it's already being displayed elsewhere.
675       if (std::find(signin_errors.begin(), signin_errors.end(), error) !=
676           signin_errors.end()) {
677         MenuModel* model = this;
678         int index = 0;
679         if (MenuModel::GetModelAndIndexForCommandId(
680                 IDC_SHOW_SIGNIN, &model, &index)) {
681           continue;
682         }
683       }
684 #endif
685
686       AddItem(error->MenuItemCommandID(), error->MenuItemLabel());
687       int icon_id = error->MenuItemIconResourceID();
688       if (icon_id) {
689         const gfx::Image& image = rb.GetNativeImageNamed(icon_id);
690         SetIcon(GetIndexOfCommandId(error->MenuItemCommandID()),
691                 image);
692       }
693     }
694   }
695 }
696
697 void WrenchMenuModel::CreateCutCopyPasteMenu(bool new_menu) {
698   AddSeparator(new_menu ? ui::LOWER_SEPARATOR : ui::NORMAL_SEPARATOR);
699
700 #if defined(OS_POSIX) && !defined(TOOLKIT_VIEWS)
701   // WARNING: Mac does not use the ButtonMenuItemModel, but instead defines the
702   // layout for this menu item in Toolbar.xib. It does, however, use the
703   // command_id value from AddButtonItem() to identify this special item.
704   edit_menu_item_model_.reset(new ui::ButtonMenuItemModel(IDS_EDIT, this));
705   edit_menu_item_model_->AddGroupItemWithStringId(IDC_CUT, IDS_CUT);
706   edit_menu_item_model_->AddGroupItemWithStringId(IDC_COPY, IDS_COPY);
707   edit_menu_item_model_->AddGroupItemWithStringId(IDC_PASTE, IDS_PASTE);
708   AddButtonItem(IDC_EDIT_MENU, edit_menu_item_model_.get());
709 #else
710   // WARNING: views/wrench_menu assumes these items are added in this order. If
711   // you change the order you'll need to update wrench_menu as well.
712   AddItemWithStringId(IDC_CUT, IDS_CUT);
713   AddItemWithStringId(IDC_COPY, IDS_COPY);
714   AddItemWithStringId(IDC_PASTE, IDS_PASTE);
715 #endif
716
717   if (new_menu)
718     AddSeparator(ui::UPPER_SEPARATOR);
719 }
720
721 void WrenchMenuModel::CreateZoomMenu(bool new_menu) {
722   // This menu needs to be enclosed by separators.
723   AddSeparator(new_menu ? ui::LOWER_SEPARATOR : ui::NORMAL_SEPARATOR);
724
725 #if defined(OS_POSIX) && !defined(TOOLKIT_VIEWS)
726   // WARNING: Mac does not use the ButtonMenuItemModel, but instead defines the
727   // layout for this menu item in Toolbar.xib. It does, however, use the
728   // command_id value from AddButtonItem() to identify this special item.
729   zoom_menu_item_model_.reset(
730       new ui::ButtonMenuItemModel(IDS_ZOOM_MENU, this));
731   zoom_menu_item_model_->AddGroupItemWithStringId(
732       IDC_ZOOM_MINUS, IDS_ZOOM_MINUS2);
733   zoom_menu_item_model_->AddButtonLabel(IDC_ZOOM_PERCENT_DISPLAY,
734                                         IDS_ZOOM_PLUS2);
735   zoom_menu_item_model_->AddGroupItemWithStringId(
736       IDC_ZOOM_PLUS, IDS_ZOOM_PLUS2);
737   zoom_menu_item_model_->AddSpace();
738   zoom_menu_item_model_->AddItemWithImage(
739       IDC_FULLSCREEN, IDR_FULLSCREEN_MENU_BUTTON);
740   AddButtonItem(IDC_ZOOM_MENU, zoom_menu_item_model_.get());
741 #else
742   // WARNING: views/wrench_menu assumes these items are added in this order. If
743   // you change the order you'll need to update wrench_menu as well.
744   AddItemWithStringId(IDC_ZOOM_MINUS, IDS_ZOOM_MINUS);
745   AddItemWithStringId(IDC_ZOOM_PLUS, IDS_ZOOM_PLUS);
746   AddItemWithStringId(IDC_FULLSCREEN, IDS_FULLSCREEN);
747 #endif
748
749   AddSeparator(new_menu ? ui::UPPER_SEPARATOR : ui::NORMAL_SEPARATOR);
750 }
751
752 void WrenchMenuModel::UpdateZoomControls() {
753   bool enable_increment = false;
754   bool enable_decrement = false;
755   int zoom_percent = 100;
756   if (browser_->tab_strip_model()->GetActiveWebContents()) {
757     zoom_percent =
758         browser_->tab_strip_model()->GetActiveWebContents()->GetZoomPercent(
759             &enable_increment, &enable_decrement);
760   }
761   zoom_label_ = l10n_util::GetStringFUTF16(
762       IDS_ZOOM_PERCENT, base::IntToString16(zoom_percent));
763 }
764
765 void WrenchMenuModel::OnZoomLevelChanged(
766     const content::HostZoomMap::ZoomLevelChange& change) {
767   UpdateZoomControls();
768 }