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/ash/launcher/launcher_context_menu.h"
9 #include "ash/desktop_background/user_wallpaper_delegate.h"
10 #include "ash/metrics/user_metrics_recorder.h"
11 #include "ash/root_window_controller.h"
12 #include "ash/shelf/shelf_item_delegate.h"
13 #include "ash/shelf/shelf_widget.h"
14 #include "ash/shell.h"
15 #include "base/bind.h"
16 #include "base/command_line.h"
17 #include "base/prefs/pref_service.h"
18 #include "chrome/browser/extensions/context_menu_matcher.h"
19 #include "chrome/browser/fullscreen.h"
20 #include "chrome/browser/prefs/incognito_mode_prefs.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/ui/ash/chrome_shell_delegate.h"
23 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
24 #include "chrome/common/chrome_switches.h"
25 #include "chrome/common/extensions/extension_constants.h"
26 #include "content/public/common/context_menu_params.h"
27 #include "grit/ash_strings.h"
28 #include "grit/generated_resources.h"
29 #include "ui/base/l10n/l10n_util.h"
33 bool MenuItemHasLauncherContext(const extensions::MenuItem* item) {
34 return item->contexts().Contains(extensions::MenuItem::LAUNCHER);
39 LauncherContextMenu::LauncherContextMenu(ChromeLauncherController* controller,
40 const ash::LauncherItem* item,
42 : ui::SimpleMenuModel(NULL),
43 controller_(controller),
45 shelf_alignment_menu_(root),
47 item_delegate_(NULL) {
53 LauncherContextMenu::LauncherContextMenu(
54 ChromeLauncherController* controller,
55 ash::ShelfItemDelegate* item_delegate,
56 ash::LauncherItem* item,
58 : ui::SimpleMenuModel(NULL),
59 controller_(controller),
61 shelf_alignment_menu_(root),
63 item_delegate_(item_delegate) {
69 LauncherContextMenu::LauncherContextMenu(ChromeLauncherController* controller,
71 : ui::SimpleMenuModel(NULL),
72 controller_(controller),
73 item_(ash::LauncherItem()),
74 shelf_alignment_menu_(root),
75 extension_items_(new extensions::ContextMenuMatcher(
76 controller->profile(), this, this,
77 base::Bind(MenuItemHasLauncherContext))),
79 item_delegate_(NULL) {
84 void LauncherContextMenu::Init() {
85 extension_items_.reset(new extensions::ContextMenuMatcher(
86 controller_->profile(), this, this,
87 base::Bind(MenuItemHasLauncherContext)));
90 if (is_valid_item()) {
91 if (item_.type == ash::TYPE_APP_SHORTCUT ||
92 item_.type == ash::TYPE_WINDOWED_APP) {
93 // V1 apps can be started from the menu - but V2 apps should not.
94 if (!controller_->IsPlatformApp(item_.id)) {
95 AddItem(MENU_OPEN_NEW, base::string16());
96 AddSeparator(ui::NORMAL_SEPARATOR);
100 l10n_util::GetStringUTF16(controller_->IsPinned(item_.id) ?
101 IDS_LAUNCHER_CONTEXT_MENU_UNPIN :
102 IDS_LAUNCHER_CONTEXT_MENU_PIN));
103 if (controller_->IsOpen(item_.id)) {
105 l10n_util::GetStringUTF16(IDS_LAUNCHER_CONTEXT_MENU_CLOSE));
107 if (!controller_->IsPlatformApp(item_.id) &&
108 item_.type != ash::TYPE_WINDOWED_APP) {
109 AddSeparator(ui::NORMAL_SEPARATOR);
110 if (CommandLine::ForCurrentProcess()->HasSwitch(
111 switches::kEnableStreamlinedHostedApps)) {
112 // Streamlined hosted apps launch in a window by default. This menu
113 // item is re-interpreted as a single, toggle-able option to launch
114 // the hosted app as a tab.
115 AddCheckItemWithStringId(
116 LAUNCH_TYPE_REGULAR_TAB,
117 IDS_APP_CONTEXT_MENU_OPEN_TAB);
119 AddCheckItemWithStringId(
120 LAUNCH_TYPE_REGULAR_TAB,
121 IDS_APP_CONTEXT_MENU_OPEN_REGULAR);
122 AddCheckItemWithStringId(
123 LAUNCH_TYPE_PINNED_TAB,
124 IDS_APP_CONTEXT_MENU_OPEN_PINNED);
125 AddCheckItemWithStringId(
127 IDS_APP_CONTEXT_MENU_OPEN_WINDOW);
128 // Even though the launch type is Full Screen it is more accurately
129 // described as Maximized in Ash.
130 AddCheckItemWithStringId(
131 LAUNCH_TYPE_FULLSCREEN,
132 IDS_APP_CONTEXT_MENU_OPEN_MAXIMIZED);
135 } else if (item_.type == ash::TYPE_BROWSER_SHORTCUT) {
136 AddItem(MENU_NEW_WINDOW,
137 l10n_util::GetStringUTF16(IDS_LAUNCHER_NEW_WINDOW));
138 if (!controller_->IsLoggedInAsGuest()) {
139 AddItem(MENU_NEW_INCOGNITO_WINDOW,
140 l10n_util::GetStringUTF16(IDS_LAUNCHER_NEW_INCOGNITO_WINDOW));
142 } else if (item_.type == ash::TYPE_DIALOG) {
144 l10n_util::GetStringUTF16(IDS_LAUNCHER_CONTEXT_MENU_CLOSE));
146 if (item_.type == ash::TYPE_PLATFORM_APP) {
149 l10n_util::GetStringUTF16(IDS_LAUNCHER_CONTEXT_MENU_PIN));
151 if (controller_->IsOpen(item_.id)) {
153 l10n_util::GetStringUTF16(IDS_LAUNCHER_CONTEXT_MENU_CLOSE));
156 AddSeparator(ui::NORMAL_SEPARATOR);
157 if (item_.type == ash::TYPE_APP_SHORTCUT ||
158 item_.type == ash::TYPE_WINDOWED_APP ||
159 item_.type == ash::TYPE_PLATFORM_APP) {
160 std::string app_id = controller_->GetAppIDForLauncherID(item_.id);
161 if (!app_id.empty()) {
163 extension_items_->AppendExtensionItems(
164 app_id, base::string16(), &index);
165 AddSeparator(ui::NORMAL_SEPARATOR);
169 // In fullscreen, the launcher is either hidden or autohidden depending on
170 // the type of fullscreen. Do not show the auto-hide menu item while in
171 // fullscreen because it is confusing when the preference appears not to
173 if (!IsFullScreenMode() &&
174 controller_->CanUserModifyShelfAutoHideBehavior(root_window_)) {
175 AddCheckItemWithStringId(MENU_AUTO_HIDE,
176 IDS_ASH_SHELF_CONTEXT_MENU_AUTO_HIDE);
178 if (ash::ShelfWidget::ShelfAlignmentAllowed()) {
179 AddSubMenuWithStringId(MENU_ALIGNMENT_MENU,
180 IDS_ASH_SHELF_CONTEXT_MENU_POSITION,
181 &shelf_alignment_menu_);
183 #if defined(OS_CHROMEOS)
184 AddItem(MENU_CHANGE_WALLPAPER,
185 l10n_util::GetStringUTF16(IDS_AURA_SET_DESKTOP_WALLPAPER));
189 LauncherContextMenu::~LauncherContextMenu() {
192 bool LauncherContextMenu::IsItemForCommandIdDynamic(int command_id) const {
193 return command_id == MENU_OPEN_NEW;
196 base::string16 LauncherContextMenu::GetLabelForCommandId(int command_id) const {
197 if (command_id == MENU_OPEN_NEW) {
198 if (item_.type == ash::TYPE_PLATFORM_APP) {
199 return l10n_util::GetStringUTF16(IDS_LAUNCHER_CONTEXT_MENU_NEW_WINDOW);
201 switch (controller_->GetLaunchType(item_.id)) {
202 case extensions::LAUNCH_TYPE_PINNED:
203 case extensions::LAUNCH_TYPE_REGULAR:
204 return l10n_util::GetStringUTF16(IDS_LAUNCHER_CONTEXT_MENU_NEW_TAB);
205 case extensions::LAUNCH_TYPE_FULLSCREEN:
206 case extensions::LAUNCH_TYPE_WINDOW:
207 return l10n_util::GetStringUTF16(IDS_LAUNCHER_CONTEXT_MENU_NEW_WINDOW);
210 return base::string16();
214 return base::string16();
217 bool LauncherContextMenu::IsCommandIdChecked(int command_id) const {
218 switch (command_id) {
219 case LAUNCH_TYPE_PINNED_TAB:
220 return controller_->GetLaunchType(item_.id) ==
221 extensions::LAUNCH_TYPE_PINNED;
222 case LAUNCH_TYPE_REGULAR_TAB:
223 return controller_->GetLaunchType(item_.id) ==
224 extensions::LAUNCH_TYPE_REGULAR;
225 case LAUNCH_TYPE_WINDOW:
226 return controller_->GetLaunchType(item_.id) ==
227 extensions::LAUNCH_TYPE_WINDOW;
228 case LAUNCH_TYPE_FULLSCREEN:
229 return controller_->GetLaunchType(item_.id) ==
230 extensions::LAUNCH_TYPE_FULLSCREEN;
232 return controller_->GetShelfAutoHideBehavior(root_window_) ==
233 ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS;
235 return extension_items_->IsCommandIdChecked(command_id);
239 bool LauncherContextMenu::IsCommandIdEnabled(int command_id) const {
240 switch (command_id) {
242 return controller_->IsPinnable(item_.id);
243 #if defined(OS_CHROMEOS)
244 case MENU_CHANGE_WALLPAPER:
245 return ash::Shell::GetInstance()->user_wallpaper_delegate()->
246 CanOpenSetWallpaperPage();
248 case MENU_NEW_WINDOW:
249 // "Normal" windows are not allowed when incognito is enforced.
250 return IncognitoModePrefs::GetAvailability(
251 controller_->profile()->GetPrefs()) != IncognitoModePrefs::FORCED;
253 return controller_->CanUserModifyShelfAutoHideBehavior(root_window_);
254 case MENU_NEW_INCOGNITO_WINDOW:
255 // Incognito windows are not allowed when incognito is disabled.
256 return IncognitoModePrefs::GetAvailability(
257 controller_->profile()->GetPrefs()) != IncognitoModePrefs::DISABLED;
259 return extension_items_->IsCommandIdEnabled(command_id);
263 bool LauncherContextMenu::GetAcceleratorForCommandId(
265 ui::Accelerator* accelerator) {
269 void LauncherContextMenu::ExecuteCommand(int command_id, int event_flags) {
270 switch (static_cast<MenuItem>(command_id)) {
272 controller_->Launch(item_.id, ui::EF_NONE);
275 if (item_.type == ash::TYPE_DIALOG) {
276 DCHECK(item_delegate_);
277 item_delegate_->Close();
279 // TODO(simonhong): Use ShelfItemDelegate::Close().
280 controller_->Close(item_.id);
282 ash::Shell::GetInstance()->metrics()->RecordUserMetricsAction(
283 ash::UMA_CLOSE_THROUGH_CONTEXT_MENU);
286 controller_->TogglePinned(item_.id);
288 case LAUNCH_TYPE_PINNED_TAB:
289 controller_->SetLaunchType(item_.id, extensions::LAUNCH_TYPE_PINNED);
291 case LAUNCH_TYPE_REGULAR_TAB: {
292 extensions::LaunchType launch_type =
293 extensions::LAUNCH_TYPE_REGULAR;
294 // Streamlined hosted apps can only toggle between LAUNCH_WINDOW and
296 if (CommandLine::ForCurrentProcess()->HasSwitch(
297 switches::kEnableStreamlinedHostedApps)) {
298 launch_type = controller_->GetLaunchType(item_.id) ==
299 extensions::LAUNCH_TYPE_REGULAR
300 ? extensions::LAUNCH_TYPE_WINDOW
301 : extensions::LAUNCH_TYPE_REGULAR;
303 controller_->SetLaunchType(item_.id, launch_type);
306 case LAUNCH_TYPE_WINDOW:
307 controller_->SetLaunchType(item_.id, extensions::LAUNCH_TYPE_WINDOW);
309 case LAUNCH_TYPE_FULLSCREEN:
310 controller_->SetLaunchType(item_.id, extensions::LAUNCH_TYPE_FULLSCREEN);
313 controller_->ToggleShelfAutoHideBehavior(root_window_);
315 case MENU_NEW_WINDOW:
316 controller_->CreateNewWindow();
318 case MENU_NEW_INCOGNITO_WINDOW:
319 controller_->CreateNewIncognitoWindow();
321 case MENU_ALIGNMENT_MENU:
323 #if defined(OS_CHROMEOS)
324 case MENU_CHANGE_WALLPAPER:
325 ash::Shell::GetInstance()->user_wallpaper_delegate()->
326 OpenSetWallpaperPage();
330 extension_items_->ExecuteCommand(command_id, NULL,
331 content::ContextMenuParams());