app_context_menu.cc revision 116680a4aac90f2aa7413d9095a592090648e557
1// Copyright 2013 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/app_list/app_context_menu.h" 6 7#include "base/bind.h" 8#include "base/command_line.h" 9#include "chrome/app/chrome_command_ids.h" 10#include "chrome/browser/extensions/context_menu_matcher.h" 11#include "chrome/browser/extensions/menu_manager.h" 12#include "chrome/browser/prefs/incognito_mode_prefs.h" 13#include "chrome/browser/profiles/profile.h" 14#include "chrome/browser/ui/app_list/app_context_menu_delegate.h" 15#include "chrome/browser/ui/app_list/app_list_controller_delegate.h" 16#include "chrome/common/chrome_switches.h" 17#include "chrome/common/extensions/manifest_url_handler.h" 18#include "content/public/common/context_menu_params.h" 19#include "grit/chromium_strings.h" 20#include "grit/generated_resources.h" 21#include "ui/base/l10n/l10n_util.h" 22 23#if defined(USE_ASH) 24#include "ash/shell.h" 25#endif 26 27namespace app_list { 28 29namespace { 30 31enum CommandId { 32 LAUNCH_NEW = 100, 33 TOGGLE_PIN, 34 CREATE_SHORTCUTS, 35 SHOW_APP_INFO, 36 OPTIONS, 37 UNINSTALL, 38 REMOVE_FROM_FOLDER, 39 MENU_NEW_WINDOW, 40 MENU_NEW_INCOGNITO_WINDOW, 41 // Order matters in USE_LAUNCH_TYPE_* and must match the LaunchType enum. 42 USE_LAUNCH_TYPE_COMMAND_START = 200, 43 USE_LAUNCH_TYPE_PINNED = USE_LAUNCH_TYPE_COMMAND_START, 44 USE_LAUNCH_TYPE_REGULAR, 45 USE_LAUNCH_TYPE_FULLSCREEN, 46 USE_LAUNCH_TYPE_WINDOW, 47 USE_LAUNCH_TYPE_COMMAND_END, 48}; 49 50bool MenuItemHasLauncherContext(const extensions::MenuItem* item) { 51 return item->contexts().Contains(extensions::MenuItem::LAUNCHER); 52} 53 54} // namespace 55 56AppContextMenu::AppContextMenu(AppContextMenuDelegate* delegate, 57 Profile* profile, 58 const std::string& app_id, 59 AppListControllerDelegate* controller) 60 : delegate_(delegate), 61 profile_(profile), 62 app_id_(app_id), 63 controller_(controller), 64 is_platform_app_(false), 65 is_search_result_(false), 66 is_in_folder_(false) { 67} 68 69AppContextMenu::~AppContextMenu() { 70} 71 72ui::MenuModel* AppContextMenu::GetMenuModel() { 73 if (!controller_->IsExtensionInstalled(profile_, app_id_)) 74 return NULL; 75 76 if (menu_model_.get()) 77 return menu_model_.get(); 78 79 menu_model_.reset(new ui::SimpleMenuModel(this)); 80 81 if (app_id_ == extension_misc::kChromeAppId) { 82 menu_model_->AddItemWithStringId( 83 MENU_NEW_WINDOW, 84 IDS_APP_LIST_NEW_WINDOW); 85 if (!profile_->IsOffTheRecord()) { 86 menu_model_->AddItemWithStringId( 87 MENU_NEW_INCOGNITO_WINDOW, 88 IDS_APP_LIST_NEW_INCOGNITO_WINDOW); 89 } 90 if (controller_->CanDoShowAppInfoFlow()) { 91 menu_model_->AddItemWithStringId(SHOW_APP_INFO, 92 IDS_APP_CONTEXT_MENU_SHOW_INFO); 93 } 94 } else { 95 extension_menu_items_.reset(new extensions::ContextMenuMatcher( 96 profile_, this, menu_model_.get(), 97 base::Bind(MenuItemHasLauncherContext))); 98 99 // First, add the primary actions. 100 if (!is_platform_app_) 101 menu_model_->AddItem(LAUNCH_NEW, base::string16()); 102 103 // Show Pin/Unpin option if shelf is available. 104 if (controller_->GetPinnable() != AppListControllerDelegate::NO_PIN) { 105 menu_model_->AddSeparator(ui::NORMAL_SEPARATOR); 106 menu_model_->AddItemWithStringId( 107 TOGGLE_PIN, 108 controller_->IsAppPinned(app_id_) ? 109 IDS_APP_LIST_CONTEXT_MENU_UNPIN : 110 IDS_APP_LIST_CONTEXT_MENU_PIN); 111 } 112 113 if (controller_->CanDoCreateShortcutsFlow()) { 114 menu_model_->AddItemWithStringId(CREATE_SHORTCUTS, 115 IDS_NEW_TAB_APP_CREATE_SHORTCUT); 116 } 117 menu_model_->AddSeparator(ui::NORMAL_SEPARATOR); 118 119 if (!is_platform_app_) { 120 // Streamlined hosted apps can only toggle between USE_LAUNCH_TYPE_WINDOW 121 // and USE_LAUNCH_TYPE_REGULAR. 122 if (CommandLine::ForCurrentProcess()->HasSwitch( 123 switches::kEnableStreamlinedHostedApps)) { 124 menu_model_->AddCheckItemWithStringId( 125 USE_LAUNCH_TYPE_REGULAR, 126 IDS_APP_CONTEXT_MENU_OPEN_TAB); 127 } else { 128 menu_model_->AddCheckItemWithStringId( 129 USE_LAUNCH_TYPE_REGULAR, 130 IDS_APP_CONTEXT_MENU_OPEN_REGULAR); 131 menu_model_->AddCheckItemWithStringId( 132 USE_LAUNCH_TYPE_PINNED, 133 IDS_APP_CONTEXT_MENU_OPEN_PINNED); 134#if defined(OS_MACOSX) 135 // Mac does not support standalone web app browser windows or maximize. 136 menu_model_->AddCheckItemWithStringId( 137 USE_LAUNCH_TYPE_FULLSCREEN, 138 IDS_APP_CONTEXT_MENU_OPEN_FULLSCREEN); 139#else 140 menu_model_->AddCheckItemWithStringId( 141 USE_LAUNCH_TYPE_WINDOW, 142 IDS_APP_CONTEXT_MENU_OPEN_WINDOW); 143 // Even though the launch type is Full Screen it is more accurately 144 // described as Maximized in Ash. 145 menu_model_->AddCheckItemWithStringId( 146 USE_LAUNCH_TYPE_FULLSCREEN, 147 IDS_APP_CONTEXT_MENU_OPEN_MAXIMIZED); 148#endif 149 } 150 menu_model_->AddSeparator(ui::NORMAL_SEPARATOR); 151 } 152 153 // Assign unique IDs to commands added by the app itself. 154 int index = USE_LAUNCH_TYPE_COMMAND_END; 155 extension_menu_items_->AppendExtensionItems( 156 extensions::MenuItem::ExtensionKey(app_id_), base::string16(), &index); 157 158 // If at least 1 item was added, add another separator after the list. 159 if (index > USE_LAUNCH_TYPE_COMMAND_END) 160 menu_model_->AddSeparator(ui::NORMAL_SEPARATOR); 161 162 if (!is_platform_app_) 163 menu_model_->AddItemWithStringId(OPTIONS, IDS_NEW_TAB_APP_OPTIONS); 164 165 menu_model_->AddItemWithStringId(UNINSTALL, 166 is_platform_app_ 167 ? IDS_APP_LIST_UNINSTALL_ITEM 168 : IDS_APP_LIST_EXTENSIONS_UNINSTALL); 169 170 if (controller_->CanDoShowAppInfoFlow()) { 171 menu_model_->AddItemWithStringId(SHOW_APP_INFO, 172 IDS_APP_CONTEXT_MENU_SHOW_INFO); 173 } 174 } 175 176 return menu_model_.get(); 177} 178 179bool AppContextMenu::IsItemForCommandIdDynamic(int command_id) const { 180 return command_id == TOGGLE_PIN || command_id == LAUNCH_NEW; 181} 182 183base::string16 AppContextMenu::GetLabelForCommandId(int command_id) const { 184 if (command_id == TOGGLE_PIN) { 185 return controller_->IsAppPinned(app_id_) ? 186 l10n_util::GetStringUTF16(IDS_APP_LIST_CONTEXT_MENU_UNPIN) : 187 l10n_util::GetStringUTF16(IDS_APP_LIST_CONTEXT_MENU_PIN); 188 } else if (command_id == LAUNCH_NEW) { 189#if defined(OS_MACOSX) 190 // Even fullscreen windows launch in a browser tab on Mac. 191 const bool launches_in_tab = true; 192#else 193 const bool launches_in_tab = IsCommandIdChecked(USE_LAUNCH_TYPE_PINNED) || 194 IsCommandIdChecked(USE_LAUNCH_TYPE_REGULAR); 195#endif 196 return launches_in_tab ? 197 l10n_util::GetStringUTF16(IDS_APP_LIST_CONTEXT_MENU_NEW_TAB) : 198 l10n_util::GetStringUTF16(IDS_APP_LIST_CONTEXT_MENU_NEW_WINDOW); 199 } else { 200 NOTREACHED(); 201 return base::string16(); 202 } 203} 204 205bool AppContextMenu::IsCommandIdChecked(int command_id) const { 206 if (command_id >= USE_LAUNCH_TYPE_COMMAND_START && 207 command_id < USE_LAUNCH_TYPE_COMMAND_END) { 208 return static_cast<int>(controller_->GetExtensionLaunchType( 209 profile_, app_id_)) + USE_LAUNCH_TYPE_COMMAND_START == command_id; 210 } else if (command_id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST && 211 command_id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) { 212 return extension_menu_items_->IsCommandIdChecked(command_id); 213 } 214 return false; 215} 216 217bool AppContextMenu::IsCommandIdEnabled(int command_id) const { 218 if (command_id == TOGGLE_PIN) { 219 return controller_->GetPinnable() == 220 AppListControllerDelegate::PIN_EDITABLE; 221 } else if (command_id == OPTIONS) { 222 return controller_->HasOptionsPage(profile_, app_id_); 223 } else if (command_id == UNINSTALL) { 224 return controller_->UserMayModifySettings(profile_, app_id_); 225 } else if (command_id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST && 226 command_id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) { 227 return extension_menu_items_->IsCommandIdEnabled(command_id); 228 } else if (command_id == MENU_NEW_WINDOW) { 229 // "Normal" windows are not allowed when incognito is enforced. 230 return IncognitoModePrefs::GetAvailability(profile_->GetPrefs()) != 231 IncognitoModePrefs::FORCED; 232 } else if (command_id == MENU_NEW_INCOGNITO_WINDOW) { 233 // Incognito windows are not allowed when incognito is disabled. 234 return IncognitoModePrefs::GetAvailability(profile_->GetPrefs()) != 235 IncognitoModePrefs::DISABLED; 236 } 237 return true; 238} 239 240bool AppContextMenu::GetAcceleratorForCommandId( 241 int command_id, 242 ui::Accelerator* acclelrator) { 243 return false; 244} 245 246void AppContextMenu::ExecuteCommand(int command_id, int event_flags) { 247 if (command_id == LAUNCH_NEW) { 248 delegate_->ExecuteLaunchCommand(event_flags); 249 } else if (command_id == TOGGLE_PIN && controller_->GetPinnable() == 250 AppListControllerDelegate::PIN_EDITABLE) { 251 if (controller_->IsAppPinned(app_id_)) 252 controller_->UnpinApp(app_id_); 253 else 254 controller_->PinApp(app_id_); 255 } else if (command_id == CREATE_SHORTCUTS) { 256 controller_->DoCreateShortcutsFlow(profile_, app_id_); 257 } else if (command_id == SHOW_APP_INFO) { 258 controller_->DoShowAppInfoFlow(profile_, app_id_); 259 } else if (command_id >= USE_LAUNCH_TYPE_COMMAND_START && 260 command_id < USE_LAUNCH_TYPE_COMMAND_END) { 261 extensions::LaunchType launch_type = static_cast<extensions::LaunchType>( 262 command_id - USE_LAUNCH_TYPE_COMMAND_START); 263 // Streamlined hosted apps can only toggle between LAUNCH_TYPE_WINDOW and 264 // LAUNCH_TYPE_REGULAR. 265 if (CommandLine::ForCurrentProcess()->HasSwitch( 266 switches::kEnableStreamlinedHostedApps)) { 267 launch_type = (controller_->GetExtensionLaunchType(profile_, app_id_) == 268 extensions::LAUNCH_TYPE_REGULAR) ? 269 extensions::LAUNCH_TYPE_WINDOW : 270 extensions::LAUNCH_TYPE_REGULAR; 271 } 272 controller_->SetExtensionLaunchType(profile_, app_id_, launch_type); 273 } else if (command_id == OPTIONS) { 274 controller_->ShowOptionsPage(profile_, app_id_); 275 } else if (command_id == UNINSTALL) { 276 controller_->UninstallApp(profile_, app_id_); 277 } else if (command_id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST && 278 command_id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) { 279 extension_menu_items_->ExecuteCommand(command_id, NULL, 280 content::ContextMenuParams()); 281 } else if (command_id == MENU_NEW_WINDOW) { 282 controller_->CreateNewWindow(profile_, false); 283 } else if (command_id == MENU_NEW_INCOGNITO_WINDOW) { 284 controller_->CreateNewWindow(profile_, true); 285 } 286} 287 288} // namespace app_list 289