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.
5 #include "chrome/browser/ui/app_list/app_context_menu.h"
7 #include "base/command_line.h"
8 #include "chrome/app/chrome_command_ids.h"
9 #include "chrome/browser/extensions/context_menu_matcher.h"
10 #include "chrome/browser/prefs/incognito_mode_prefs.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/ui/app_list/app_context_menu_delegate.h"
13 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
14 #include "chrome/common/chrome_switches.h"
15 #include "chrome/common/extensions/manifest_url_handler.h"
16 #include "content/public/common/context_menu_params.h"
17 #include "grit/chromium_strings.h"
18 #include "grit/generated_resources.h"
19 #include "ui/base/l10n/l10n_util.h"
22 #include "ash/shell.h"
37 MENU_NEW_INCOGNITO_WINDOW,
38 // Order matters in LAUNCHER_TYPE_xxxx and must match LaunchType.
39 LAUNCH_TYPE_START = 200,
40 LAUNCH_TYPE_PINNED_TAB = LAUNCH_TYPE_START,
41 LAUNCH_TYPE_REGULAR_TAB,
42 LAUNCH_TYPE_FULLSCREEN,
47 bool MenuItemHasLauncherContext(const extensions::MenuItem* item) {
48 return item->contexts().Contains(extensions::MenuItem::LAUNCHER);
53 AppContextMenu::AppContextMenu(AppContextMenuDelegate* delegate,
55 const std::string& app_id,
56 AppListControllerDelegate* controller,
58 bool is_search_result)
59 : delegate_(delegate),
62 controller_(controller),
63 is_platform_app_(is_platform_app),
64 is_search_result_(is_search_result) {
67 AppContextMenu::~AppContextMenu() {}
69 ui::MenuModel* AppContextMenu::GetMenuModel() {
70 if (!controller_->IsExtensionInstalled(profile_, app_id_))
73 if (menu_model_.get())
74 return menu_model_.get();
76 menu_model_.reset(new ui::SimpleMenuModel(this));
78 if (app_id_ == extension_misc::kChromeAppId) {
79 menu_model_->AddItemWithStringId(
81 IDS_APP_LIST_NEW_WINDOW);
82 if (!profile_->IsOffTheRecord()) {
83 menu_model_->AddItemWithStringId(
84 MENU_NEW_INCOGNITO_WINDOW,
85 IDS_APP_LIST_NEW_INCOGNITO_WINDOW);
88 extension_menu_items_.reset(new extensions::ContextMenuMatcher(
89 profile_, this, menu_model_.get(),
90 base::Bind(MenuItemHasLauncherContext)));
92 if (!is_platform_app_)
93 menu_model_->AddItem(LAUNCH_NEW, string16());
96 extension_menu_items_->AppendExtensionItems(app_id_, string16(),
99 // Show Pin/Unpin option if shelf is available.
100 if (controller_->GetPinnable() != AppListControllerDelegate::NO_PIN) {
101 menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
102 menu_model_->AddItemWithStringId(
104 controller_->IsAppPinned(app_id_) ?
105 IDS_APP_LIST_CONTEXT_MENU_UNPIN :
106 IDS_APP_LIST_CONTEXT_MENU_PIN);
109 if (controller_->CanDoCreateShortcutsFlow()) {
110 menu_model_->AddItemWithStringId(CREATE_SHORTCUTS,
111 IDS_NEW_TAB_APP_CREATE_SHORTCUT);
114 if (!is_platform_app_) {
115 menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
116 // Streamlined hosted apps can only toggle between LAUNCH_WINDOW and
118 if (CommandLine::ForCurrentProcess()->HasSwitch(
119 switches::kEnableStreamlinedHostedApps)) {
120 menu_model_->AddCheckItemWithStringId(
121 LAUNCH_TYPE_REGULAR_TAB,
122 IDS_APP_CONTEXT_MENU_OPEN_TAB);
124 menu_model_->AddCheckItemWithStringId(
125 LAUNCH_TYPE_REGULAR_TAB,
126 IDS_APP_CONTEXT_MENU_OPEN_REGULAR);
127 menu_model_->AddCheckItemWithStringId(
128 LAUNCH_TYPE_PINNED_TAB,
129 IDS_APP_CONTEXT_MENU_OPEN_PINNED);
130 #if defined(OS_MACOSX)
131 // Mac does not support standalone web app browser windows or maximize.
132 menu_model_->AddCheckItemWithStringId(
133 LAUNCH_TYPE_FULLSCREEN,
134 IDS_APP_CONTEXT_MENU_OPEN_FULLSCREEN);
136 menu_model_->AddCheckItemWithStringId(
138 IDS_APP_CONTEXT_MENU_OPEN_WINDOW);
139 // Even though the launch type is Full Screen it is more accurately
140 // described as Maximized in Ash.
141 menu_model_->AddCheckItemWithStringId(
142 LAUNCH_TYPE_FULLSCREEN,
143 IDS_APP_CONTEXT_MENU_OPEN_MAXIMIZED);
146 menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
147 menu_model_->AddItemWithStringId(OPTIONS, IDS_NEW_TAB_APP_OPTIONS);
150 menu_model_->AddItemWithStringId(DETAILS, IDS_NEW_TAB_APP_DETAILS);
151 menu_model_->AddItemWithStringId(
153 is_platform_app_ ? IDS_APP_LIST_UNINSTALL_ITEM
154 : IDS_EXTENSIONS_UNINSTALL);
157 return menu_model_.get();
160 bool AppContextMenu::IsItemForCommandIdDynamic(int command_id) const {
161 return command_id == TOGGLE_PIN || command_id == LAUNCH_NEW;
164 string16 AppContextMenu::GetLabelForCommandId(int command_id) const {
165 if (command_id == TOGGLE_PIN) {
166 return controller_->IsAppPinned(app_id_) ?
167 l10n_util::GetStringUTF16(IDS_APP_LIST_CONTEXT_MENU_UNPIN) :
168 l10n_util::GetStringUTF16(IDS_APP_LIST_CONTEXT_MENU_PIN);
169 } else if (command_id == LAUNCH_NEW) {
170 #if defined(OS_MACOSX)
171 // Even fullscreen windows launch in a browser tab on Mac.
172 const bool launches_in_tab = true;
174 const bool launches_in_tab = IsCommandIdChecked(LAUNCH_TYPE_PINNED_TAB) ||
175 IsCommandIdChecked(LAUNCH_TYPE_REGULAR_TAB);
177 return launches_in_tab ?
178 l10n_util::GetStringUTF16(IDS_APP_LIST_CONTEXT_MENU_NEW_TAB) :
179 l10n_util::GetStringUTF16(IDS_APP_LIST_CONTEXT_MENU_NEW_WINDOW);
186 bool AppContextMenu::IsCommandIdChecked(int command_id) const {
187 if (command_id >= LAUNCH_TYPE_START && command_id < LAUNCH_TYPE_LAST) {
188 return static_cast<int>(controller_->GetExtensionLaunchType(
189 profile_, app_id_)) + LAUNCH_TYPE_START == command_id;
190 } else if (command_id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST &&
191 command_id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) {
192 return extension_menu_items_->IsCommandIdChecked(command_id);
197 bool AppContextMenu::IsCommandIdEnabled(int command_id) const {
198 if (command_id == TOGGLE_PIN) {
199 return controller_->GetPinnable() ==
200 AppListControllerDelegate::PIN_EDITABLE;
201 } else if (command_id == OPTIONS) {
202 return controller_->HasOptionsPage(profile_, app_id_);
203 } else if (command_id == UNINSTALL) {
204 return controller_->UserMayModifySettings(profile_, app_id_);
205 } else if (command_id == DETAILS) {
206 return controller_->IsAppFromWebStore(profile_, app_id_);
207 } else if (command_id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST &&
208 command_id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) {
209 return extension_menu_items_->IsCommandIdEnabled(command_id);
210 } else if (command_id == MENU_NEW_WINDOW) {
211 // "Normal" windows are not allowed when incognito is enforced.
212 return IncognitoModePrefs::GetAvailability(profile_->GetPrefs()) !=
213 IncognitoModePrefs::FORCED;
214 } else if (command_id == MENU_NEW_INCOGNITO_WINDOW) {
215 // Incognito windows are not allowed when incognito is disabled.
216 return IncognitoModePrefs::GetAvailability(profile_->GetPrefs()) !=
217 IncognitoModePrefs::DISABLED;
222 bool AppContextMenu::GetAcceleratorForCommandId(
224 ui::Accelerator* acclelrator) {
228 void AppContextMenu::ExecuteCommand(int command_id, int event_flags) {
229 if (command_id == LAUNCH_NEW) {
230 delegate_->ExecuteLaunchCommand(event_flags);
231 } else if (command_id == TOGGLE_PIN && controller_->GetPinnable() ==
232 AppListControllerDelegate::PIN_EDITABLE) {
233 if (controller_->IsAppPinned(app_id_))
234 controller_->UnpinApp(app_id_);
236 controller_->PinApp(app_id_);
237 } else if (command_id == CREATE_SHORTCUTS) {
238 controller_->DoCreateShortcutsFlow(profile_, app_id_);
239 } else if (command_id >= LAUNCH_TYPE_START &&
240 command_id < LAUNCH_TYPE_LAST) {
241 extensions::ExtensionPrefs::LaunchType launch_type =
242 static_cast<extensions::ExtensionPrefs::LaunchType>(
243 command_id - LAUNCH_TYPE_START);
244 // Streamlined hosted apps can only toggle between LAUNCH_WINDOW and
246 if (CommandLine::ForCurrentProcess()->HasSwitch(
247 switches::kEnableStreamlinedHostedApps)) {
248 launch_type = controller_->GetExtensionLaunchType(profile_, app_id_) ==
249 extensions::ExtensionPrefs::LAUNCH_REGULAR
250 ? extensions::ExtensionPrefs::LAUNCH_WINDOW
251 : extensions::ExtensionPrefs::LAUNCH_REGULAR;
253 controller_->SetExtensionLaunchType(profile_,
256 } else if (command_id == OPTIONS) {
257 controller_->ShowOptionsPage(profile_, app_id_);
258 } else if (command_id == UNINSTALL) {
259 controller_->UninstallApp(profile_, app_id_);
260 } else if (command_id == DETAILS) {
261 controller_->ShowAppInWebStore(profile_, app_id_, is_search_result_);
262 } else if (command_id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST &&
263 command_id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) {
264 extension_menu_items_->ExecuteCommand(command_id, NULL,
265 content::ContextMenuParams());
266 } else if (command_id == MENU_NEW_WINDOW) {
267 controller_->CreateNewWindow(profile_, false);
268 } else if (command_id == MENU_NEW_INCOGNITO_WINDOW) {
269 controller_->CreateNewWindow(profile_, true);
273 } // namespace app_list