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/ash/launcher/launcher_context_menu.h" 6 7#include <string> 8 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_widget.h" 13#include "ash/shell.h" 14#include "base/bind.h" 15#include "base/command_line.h" 16#include "base/prefs/pref_service.h" 17#include "chrome/browser/extensions/context_menu_matcher.h" 18#include "chrome/browser/fullscreen.h" 19#include "chrome/browser/prefs/incognito_mode_prefs.h" 20#include "chrome/browser/profiles/profile.h" 21#include "chrome/browser/ui/ash/chrome_shell_delegate.h" 22#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" 23#include "chrome/common/chrome_switches.h" 24#include "chrome/common/extensions/extension_constants.h" 25#include "content/public/common/context_menu_params.h" 26#include "grit/ash_strings.h" 27#include "grit/generated_resources.h" 28#include "ui/base/l10n/l10n_util.h" 29 30namespace { 31 32bool MenuItemHasLauncherContext(const extensions::MenuItem* item) { 33 return item->contexts().Contains(extensions::MenuItem::LAUNCHER); 34} 35 36} // namespace 37 38LauncherContextMenu::LauncherContextMenu(ChromeLauncherController* controller, 39 const ash::LauncherItem* item, 40 aura::Window* root) 41 : ui::SimpleMenuModel(NULL), 42 controller_(controller), 43 item_(*item), 44 shelf_alignment_menu_(root), 45 root_window_(root) { 46 DCHECK(item); 47 DCHECK(root_window_); 48 Init(); 49} 50 51LauncherContextMenu::LauncherContextMenu(ChromeLauncherController* controller, 52 aura::Window* root) 53 : ui::SimpleMenuModel(NULL), 54 controller_(controller), 55 item_(ash::LauncherItem()), 56 shelf_alignment_menu_(root), 57 extension_items_(new extensions::ContextMenuMatcher( 58 controller->profile(), this, this, 59 base::Bind(MenuItemHasLauncherContext))), 60 root_window_(root) { 61 DCHECK(root_window_); 62 Init(); 63} 64 65void LauncherContextMenu::Init() { 66 extension_items_.reset(new extensions::ContextMenuMatcher( 67 controller_->profile(), this, this, 68 base::Bind(MenuItemHasLauncherContext))); 69 set_delegate(this); 70 71 if (is_valid_item()) { 72 if (item_.type == ash::TYPE_APP_SHORTCUT || 73 item_.type == ash::TYPE_WINDOWED_APP) { 74 // V1 apps can be started from the menu - but V2 apps should not. 75 if (!controller_->IsPlatformApp(item_.id)) { 76 AddItem(MENU_OPEN_NEW, base::string16()); 77 AddSeparator(ui::NORMAL_SEPARATOR); 78 } 79 AddItem( 80 MENU_PIN, 81 l10n_util::GetStringUTF16(controller_->IsPinned(item_.id) ? 82 IDS_LAUNCHER_CONTEXT_MENU_UNPIN : 83 IDS_LAUNCHER_CONTEXT_MENU_PIN)); 84 if (controller_->IsOpen(item_.id)) { 85 AddItem(MENU_CLOSE, 86 l10n_util::GetStringUTF16(IDS_LAUNCHER_CONTEXT_MENU_CLOSE)); 87 } 88 if (!controller_->IsPlatformApp(item_.id) && 89 item_.type != ash::TYPE_WINDOWED_APP) { 90 AddSeparator(ui::NORMAL_SEPARATOR); 91 if (CommandLine::ForCurrentProcess()->HasSwitch( 92 switches::kEnableStreamlinedHostedApps)) { 93 // Streamlined hosted apps launch in a window by default. This menu 94 // item is re-interpreted as a single, toggle-able option to launch 95 // the hosted app as a tab. 96 AddCheckItemWithStringId( 97 LAUNCH_TYPE_REGULAR_TAB, 98 IDS_APP_CONTEXT_MENU_OPEN_TAB); 99 } else { 100 AddCheckItemWithStringId( 101 LAUNCH_TYPE_REGULAR_TAB, 102 IDS_APP_CONTEXT_MENU_OPEN_REGULAR); 103 AddCheckItemWithStringId( 104 LAUNCH_TYPE_PINNED_TAB, 105 IDS_APP_CONTEXT_MENU_OPEN_PINNED); 106 AddCheckItemWithStringId( 107 LAUNCH_TYPE_WINDOW, 108 IDS_APP_CONTEXT_MENU_OPEN_WINDOW); 109 // Even though the launch type is Full Screen it is more accurately 110 // described as Maximized in Ash. 111 AddCheckItemWithStringId( 112 LAUNCH_TYPE_FULLSCREEN, 113 IDS_APP_CONTEXT_MENU_OPEN_MAXIMIZED); 114 } 115 } 116 } else if (item_.type == ash::TYPE_BROWSER_SHORTCUT) { 117 AddItem(MENU_NEW_WINDOW, 118 l10n_util::GetStringUTF16(IDS_LAUNCHER_NEW_WINDOW)); 119 if (!controller_->IsLoggedInAsGuest()) { 120 AddItem(MENU_NEW_INCOGNITO_WINDOW, 121 l10n_util::GetStringUTF16(IDS_LAUNCHER_NEW_INCOGNITO_WINDOW)); 122 } 123 } else { 124 if (item_.type == ash::TYPE_PLATFORM_APP) { 125 AddItem( 126 MENU_PIN, 127 l10n_util::GetStringUTF16(IDS_LAUNCHER_CONTEXT_MENU_PIN)); 128 } 129 if (controller_->IsOpen(item_.id)) { 130 AddItem(MENU_CLOSE, 131 l10n_util::GetStringUTF16(IDS_LAUNCHER_CONTEXT_MENU_CLOSE)); 132 } 133 } 134 AddSeparator(ui::NORMAL_SEPARATOR); 135 if (item_.type == ash::TYPE_APP_SHORTCUT || 136 item_.type == ash::TYPE_WINDOWED_APP || 137 item_.type == ash::TYPE_PLATFORM_APP) { 138 std::string app_id = controller_->GetAppIDForLauncherID(item_.id); 139 if (!app_id.empty()) { 140 int index = 0; 141 extension_items_->AppendExtensionItems( 142 app_id, base::string16(), &index); 143 AddSeparator(ui::NORMAL_SEPARATOR); 144 } 145 } 146 } 147 // In fullscreen, the launcher is either hidden or autohidden depending on 148 // the type of fullscreen. Do not show the auto-hide menu item while in 149 // fullscreen because it is confusing when the preference appears not to 150 // apply. 151 if (!IsFullScreenMode()) { 152 AddCheckItemWithStringId(MENU_AUTO_HIDE, 153 IDS_ASH_SHELF_CONTEXT_MENU_AUTO_HIDE); 154 } 155 if (ash::ShelfWidget::ShelfAlignmentAllowed()) { 156 AddSubMenuWithStringId(MENU_ALIGNMENT_MENU, 157 IDS_ASH_SHELF_CONTEXT_MENU_POSITION, 158 &shelf_alignment_menu_); 159 } 160#if defined(OS_CHROMEOS) 161 AddItem(MENU_CHANGE_WALLPAPER, 162 l10n_util::GetStringUTF16(IDS_AURA_SET_DESKTOP_WALLPAPER)); 163#endif 164} 165 166LauncherContextMenu::~LauncherContextMenu() { 167} 168 169bool LauncherContextMenu::IsItemForCommandIdDynamic(int command_id) const { 170 return command_id == MENU_OPEN_NEW; 171} 172 173base::string16 LauncherContextMenu::GetLabelForCommandId(int command_id) const { 174 if (command_id == MENU_OPEN_NEW) { 175 if (item_.type == ash::TYPE_PLATFORM_APP) { 176 return l10n_util::GetStringUTF16(IDS_LAUNCHER_CONTEXT_MENU_NEW_WINDOW); 177 } 178 switch (controller_->GetLaunchType(item_.id)) { 179 case extensions::LAUNCH_TYPE_PINNED: 180 case extensions::LAUNCH_TYPE_REGULAR: 181 return l10n_util::GetStringUTF16(IDS_LAUNCHER_CONTEXT_MENU_NEW_TAB); 182 case extensions::LAUNCH_TYPE_FULLSCREEN: 183 case extensions::LAUNCH_TYPE_WINDOW: 184 return l10n_util::GetStringUTF16(IDS_LAUNCHER_CONTEXT_MENU_NEW_WINDOW); 185 } 186 } 187 NOTREACHED(); 188 return base::string16(); 189} 190 191bool LauncherContextMenu::IsCommandIdChecked(int command_id) const { 192 switch (command_id) { 193 case LAUNCH_TYPE_PINNED_TAB: 194 return controller_->GetLaunchType(item_.id) == 195 extensions::LAUNCH_TYPE_PINNED; 196 case LAUNCH_TYPE_REGULAR_TAB: 197 return controller_->GetLaunchType(item_.id) == 198 extensions::LAUNCH_TYPE_REGULAR; 199 case LAUNCH_TYPE_WINDOW: 200 return controller_->GetLaunchType(item_.id) == 201 extensions::LAUNCH_TYPE_WINDOW; 202 case LAUNCH_TYPE_FULLSCREEN: 203 return controller_->GetLaunchType(item_.id) == 204 extensions::LAUNCH_TYPE_FULLSCREEN; 205 case MENU_AUTO_HIDE: 206 return controller_->GetShelfAutoHideBehavior(root_window_) == 207 ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS; 208 default: 209 return extension_items_->IsCommandIdChecked(command_id); 210 } 211} 212 213bool LauncherContextMenu::IsCommandIdEnabled(int command_id) const { 214 switch (command_id) { 215 case MENU_PIN: 216 return controller_->IsPinnable(item_.id); 217#if defined(OS_CHROMEOS) 218 case MENU_CHANGE_WALLPAPER: 219 return ash::Shell::GetInstance()->user_wallpaper_delegate()-> 220 CanOpenSetWallpaperPage(); 221#endif 222 case MENU_NEW_WINDOW: 223 // "Normal" windows are not allowed when incognito is enforced. 224 return IncognitoModePrefs::GetAvailability( 225 controller_->profile()->GetPrefs()) != IncognitoModePrefs::FORCED; 226 case MENU_AUTO_HIDE: 227 return controller_->CanUserModifyShelfAutoHideBehavior(root_window_); 228 case MENU_NEW_INCOGNITO_WINDOW: 229 // Incognito windows are not allowed when incognito is disabled. 230 return IncognitoModePrefs::GetAvailability( 231 controller_->profile()->GetPrefs()) != IncognitoModePrefs::DISABLED; 232 default: 233 return extension_items_->IsCommandIdEnabled(command_id); 234 } 235} 236 237bool LauncherContextMenu::GetAcceleratorForCommandId( 238 int command_id, 239 ui::Accelerator* accelerator) { 240 return false; 241} 242 243void LauncherContextMenu::ExecuteCommand(int command_id, int event_flags) { 244 switch (static_cast<MenuItem>(command_id)) { 245 case MENU_OPEN_NEW: 246 controller_->Launch(item_.id, ui::EF_NONE); 247 break; 248 case MENU_CLOSE: 249 controller_->Close(item_.id); 250 ash::Shell::GetInstance()->metrics()->RecordUserMetricsAction( 251 ash::UMA_CLOSE_THROUGH_CONTEXT_MENU); 252 break; 253 case MENU_PIN: 254 controller_->TogglePinned(item_.id); 255 break; 256 case LAUNCH_TYPE_PINNED_TAB: 257 controller_->SetLaunchType(item_.id, extensions::LAUNCH_TYPE_PINNED); 258 break; 259 case LAUNCH_TYPE_REGULAR_TAB: { 260 extensions::LaunchType launch_type = 261 extensions::LAUNCH_TYPE_REGULAR; 262 // Streamlined hosted apps can only toggle between LAUNCH_WINDOW and 263 // LAUNCH_REGULAR. 264 if (CommandLine::ForCurrentProcess()->HasSwitch( 265 switches::kEnableStreamlinedHostedApps)) { 266 launch_type = controller_->GetLaunchType(item_.id) == 267 extensions::LAUNCH_TYPE_REGULAR 268 ? extensions::LAUNCH_TYPE_WINDOW 269 : extensions::LAUNCH_TYPE_REGULAR; 270 } 271 controller_->SetLaunchType(item_.id, launch_type); 272 break; 273 } 274 case LAUNCH_TYPE_WINDOW: 275 controller_->SetLaunchType(item_.id, extensions::LAUNCH_TYPE_WINDOW); 276 break; 277 case LAUNCH_TYPE_FULLSCREEN: 278 controller_->SetLaunchType(item_.id, extensions::LAUNCH_TYPE_FULLSCREEN); 279 break; 280 case MENU_AUTO_HIDE: 281 controller_->ToggleShelfAutoHideBehavior(root_window_); 282 break; 283 case MENU_NEW_WINDOW: 284 controller_->CreateNewWindow(); 285 break; 286 case MENU_NEW_INCOGNITO_WINDOW: 287 controller_->CreateNewIncognitoWindow(); 288 break; 289 case MENU_ALIGNMENT_MENU: 290 break; 291#if defined(OS_CHROMEOS) 292 case MENU_CHANGE_WALLPAPER: 293 ash::Shell::GetInstance()->user_wallpaper_delegate()-> 294 OpenSetWallpaperPage(); 295 break; 296#endif 297 default: 298 extension_items_->ExecuteCommand(command_id, NULL, 299 content::ContextMenuParams()); 300 } 301} 302