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"
8 #include "chrome/browser/extensions/context_menu_matcher.h"
9 #include "chrome/browser/extensions/extension_util.h"
10 #include "chrome/browser/extensions/menu_manager.h"
11 #include "chrome/browser/prefs/incognito_mode_prefs.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/browser/ui/app_list/app_context_menu_delegate.h"
14 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
15 #include "chrome/grit/chromium_strings.h"
16 #include "chrome/grit/generated_resources.h"
17 #include "content/public/common/context_menu_params.h"
18 #include "extensions/common/manifest_url_handlers.h"
19 #include "ui/base/l10n/l10n_util.h"
22 #include "ash/shell.h"
38 MENU_NEW_INCOGNITO_WINDOW
,
39 // Order matters in USE_LAUNCH_TYPE_* and must match the LaunchType enum.
40 USE_LAUNCH_TYPE_COMMAND_START
= 200,
41 USE_LAUNCH_TYPE_PINNED
= USE_LAUNCH_TYPE_COMMAND_START
,
42 USE_LAUNCH_TYPE_REGULAR
,
43 USE_LAUNCH_TYPE_FULLSCREEN
,
44 USE_LAUNCH_TYPE_WINDOW
,
45 USE_LAUNCH_TYPE_COMMAND_END
,
48 bool MenuItemHasLauncherContext(const extensions::MenuItem
* item
) {
49 return item
->contexts().Contains(extensions::MenuItem::LAUNCHER
);
54 AppContextMenu::AppContextMenu(AppContextMenuDelegate
* delegate
,
56 const std::string
& app_id
,
57 AppListControllerDelegate
* controller
)
58 : delegate_(delegate
),
61 controller_(controller
),
62 is_platform_app_(false),
63 is_search_result_(false),
64 is_in_folder_(false) {
67 AppContextMenu::~AppContextMenu() {
70 ui::MenuModel
* AppContextMenu::GetMenuModel() {
71 if (!controller_
->IsExtensionInstalled(profile_
, app_id_
))
74 if (menu_model_
.get())
75 return menu_model_
.get();
77 menu_model_
.reset(new ui::SimpleMenuModel(this));
79 if (app_id_
== extension_misc::kChromeAppId
) {
80 menu_model_
->AddItemWithStringId(
82 IDS_APP_LIST_NEW_WINDOW
);
83 if (!profile_
->IsOffTheRecord()) {
84 menu_model_
->AddItemWithStringId(
85 MENU_NEW_INCOGNITO_WINDOW
,
86 IDS_APP_LIST_NEW_INCOGNITO_WINDOW
);
88 if (controller_
->CanDoShowAppInfoFlow()) {
89 menu_model_
->AddItemWithStringId(SHOW_APP_INFO
,
90 IDS_APP_CONTEXT_MENU_SHOW_INFO
);
93 extension_menu_items_
.reset(new extensions::ContextMenuMatcher(
94 profile_
, this, menu_model_
.get(),
95 base::Bind(MenuItemHasLauncherContext
)));
97 // First, add the primary actions.
98 if (!is_platform_app_
)
99 menu_model_
->AddItem(LAUNCH_NEW
, base::string16());
101 // Show Pin/Unpin option if shelf is available.
102 if (controller_
->GetPinnable() != AppListControllerDelegate::NO_PIN
) {
103 menu_model_
->AddSeparator(ui::NORMAL_SEPARATOR
);
104 menu_model_
->AddItemWithStringId(
106 controller_
->IsAppPinned(app_id_
) ?
107 IDS_APP_LIST_CONTEXT_MENU_UNPIN
:
108 IDS_APP_LIST_CONTEXT_MENU_PIN
);
111 if (controller_
->CanDoCreateShortcutsFlow()) {
112 menu_model_
->AddItemWithStringId(CREATE_SHORTCUTS
,
113 IDS_NEW_TAB_APP_CREATE_SHORTCUT
);
115 menu_model_
->AddSeparator(ui::NORMAL_SEPARATOR
);
117 if (!is_platform_app_
) {
118 // When bookmark apps are enabled, hosted apps can only toggle between
119 // USE_LAUNCH_TYPE_WINDOW and USE_LAUNCH_TYPE_REGULAR.
120 if (extensions::util::CanHostedAppsOpenInWindows() &&
121 extensions::util::IsNewBookmarkAppsEnabled()) {
122 // When both flags are enabled, only allow toggling between
123 // USE_LAUNCH_TYPE_WINDOW and USE_LAUNCH_TYPE_REGULAR
124 menu_model_
->AddCheckItemWithStringId(
125 USE_LAUNCH_TYPE_WINDOW
, IDS_APP_CONTEXT_MENU_OPEN_WINDOW
);
126 } else if (!extensions::util::IsNewBookmarkAppsEnabled()) {
127 // When new bookmark apps are disabled, add pinned and full screen
128 // options as well. Add open as window if CanHostedAppsOpenInWindows
130 menu_model_
->AddCheckItemWithStringId(
131 USE_LAUNCH_TYPE_REGULAR
,
132 IDS_APP_CONTEXT_MENU_OPEN_REGULAR
);
133 menu_model_
->AddCheckItemWithStringId(
134 USE_LAUNCH_TYPE_PINNED
,
135 IDS_APP_CONTEXT_MENU_OPEN_PINNED
);
136 if (extensions::util::CanHostedAppsOpenInWindows()) {
137 menu_model_
->AddCheckItemWithStringId(
138 USE_LAUNCH_TYPE_WINDOW
,
139 IDS_APP_CONTEXT_MENU_OPEN_WINDOW
);
141 #if defined(OS_MACOSX)
142 // Mac does not support standalone web app browser windows or maximize.
143 menu_model_
->AddCheckItemWithStringId(
144 USE_LAUNCH_TYPE_FULLSCREEN
,
145 IDS_APP_CONTEXT_MENU_OPEN_FULLSCREEN
);
147 // Even though the launch type is Full Screen it is more accurately
148 // described as Maximized in Ash.
149 menu_model_
->AddCheckItemWithStringId(
150 USE_LAUNCH_TYPE_FULLSCREEN
,
151 IDS_APP_CONTEXT_MENU_OPEN_MAXIMIZED
);
154 menu_model_
->AddSeparator(ui::NORMAL_SEPARATOR
);
157 // Assign unique IDs to commands added by the app itself.
158 int index
= USE_LAUNCH_TYPE_COMMAND_END
;
159 extension_menu_items_
->AppendExtensionItems(
160 extensions::MenuItem::ExtensionKey(app_id_
),
163 false); // is_action_menu
165 // If at least 1 item was added, add another separator after the list.
166 if (index
> USE_LAUNCH_TYPE_COMMAND_END
)
167 menu_model_
->AddSeparator(ui::NORMAL_SEPARATOR
);
169 if (!is_platform_app_
)
170 menu_model_
->AddItemWithStringId(OPTIONS
, IDS_NEW_TAB_APP_OPTIONS
);
172 menu_model_
->AddItemWithStringId(UNINSTALL
,
174 ? IDS_APP_LIST_UNINSTALL_ITEM
175 : IDS_APP_LIST_EXTENSIONS_UNINSTALL
);
177 if (controller_
->CanDoShowAppInfoFlow()) {
178 menu_model_
->AddItemWithStringId(SHOW_APP_INFO
,
179 IDS_APP_CONTEXT_MENU_SHOW_INFO
);
183 return menu_model_
.get();
186 bool AppContextMenu::IsItemForCommandIdDynamic(int command_id
) const {
187 return command_id
== TOGGLE_PIN
|| command_id
== LAUNCH_NEW
;
190 base::string16
AppContextMenu::GetLabelForCommandId(int command_id
) const {
191 if (command_id
== TOGGLE_PIN
) {
192 // Return "{Pin to, Unpin from} shelf". Note this only exists on Ash
194 return controller_
->IsAppPinned(app_id_
) ?
195 l10n_util::GetStringUTF16(IDS_APP_LIST_CONTEXT_MENU_UNPIN
) :
196 l10n_util::GetStringUTF16(IDS_APP_LIST_CONTEXT_MENU_PIN
);
199 DCHECK_EQ(LAUNCH_NEW
, command_id
);
201 #if defined(OS_MACOSX)
202 // Full screen on Mac launches in a tab.
203 bool launches_in_window
= extensions::util::CanHostedAppsOpenInWindows() &&
204 IsCommandIdChecked(USE_LAUNCH_TYPE_WINDOW
);
206 // If --enable-new-bookmark-apps is enabled, then only check if
207 // USE_LAUNCH_TYPE_WINDOW is checked, as USE_LAUNCH_TYPE_PINNED (i.e. open
208 // as pinned tab) and fullscreen-by-default windows do not exist.
209 bool launches_in_window
=
210 (extensions::util::IsNewBookmarkAppsEnabled()
211 ? IsCommandIdChecked(USE_LAUNCH_TYPE_WINDOW
)
212 : !(IsCommandIdChecked(USE_LAUNCH_TYPE_PINNED
) ||
213 IsCommandIdChecked(USE_LAUNCH_TYPE_REGULAR
)));
216 return launches_in_window
?
217 l10n_util::GetStringUTF16(IDS_APP_LIST_CONTEXT_MENU_NEW_WINDOW
) :
218 l10n_util::GetStringUTF16(IDS_APP_LIST_CONTEXT_MENU_NEW_TAB
);
221 bool AppContextMenu::IsCommandIdChecked(int command_id
) const {
222 if (command_id
>= USE_LAUNCH_TYPE_COMMAND_START
&&
223 command_id
< USE_LAUNCH_TYPE_COMMAND_END
) {
224 return static_cast<int>(controller_
->GetExtensionLaunchType(
225 profile_
, app_id_
)) + USE_LAUNCH_TYPE_COMMAND_START
== command_id
;
226 } else if (extensions::ContextMenuMatcher::IsExtensionsCustomCommandId(
228 return extension_menu_items_
->IsCommandIdChecked(command_id
);
233 bool AppContextMenu::IsCommandIdEnabled(int command_id
) const {
234 if (command_id
== TOGGLE_PIN
) {
235 return controller_
->GetPinnable() ==
236 AppListControllerDelegate::PIN_EDITABLE
;
237 } else if (command_id
== OPTIONS
) {
238 return controller_
->HasOptionsPage(profile_
, app_id_
);
239 } else if (command_id
== UNINSTALL
) {
240 return controller_
->UserMayModifySettings(profile_
, app_id_
);
241 } else if (extensions::ContextMenuMatcher::IsExtensionsCustomCommandId(
243 return extension_menu_items_
->IsCommandIdEnabled(command_id
);
244 } else if (command_id
== MENU_NEW_WINDOW
) {
245 // "Normal" windows are not allowed when incognito is enforced.
246 return IncognitoModePrefs::GetAvailability(profile_
->GetPrefs()) !=
247 IncognitoModePrefs::FORCED
;
248 } else if (command_id
== MENU_NEW_INCOGNITO_WINDOW
) {
249 // Incognito windows are not allowed when incognito is disabled.
250 return IncognitoModePrefs::GetAvailability(profile_
->GetPrefs()) !=
251 IncognitoModePrefs::DISABLED
;
256 bool AppContextMenu::GetAcceleratorForCommandId(
258 ui::Accelerator
* accelerator
) {
262 void AppContextMenu::ExecuteCommand(int command_id
, int event_flags
) {
263 if (command_id
== LAUNCH_NEW
) {
264 delegate_
->ExecuteLaunchCommand(event_flags
);
265 } else if (command_id
== TOGGLE_PIN
&& controller_
->GetPinnable() ==
266 AppListControllerDelegate::PIN_EDITABLE
) {
267 if (controller_
->IsAppPinned(app_id_
))
268 controller_
->UnpinApp(app_id_
);
270 controller_
->PinApp(app_id_
);
271 } else if (command_id
== CREATE_SHORTCUTS
) {
272 controller_
->DoCreateShortcutsFlow(profile_
, app_id_
);
273 } else if (command_id
== SHOW_APP_INFO
) {
274 controller_
->DoShowAppInfoFlow(profile_
, app_id_
);
275 } else if (command_id
>= USE_LAUNCH_TYPE_COMMAND_START
&&
276 command_id
< USE_LAUNCH_TYPE_COMMAND_END
) {
277 extensions::LaunchType launch_type
= static_cast<extensions::LaunchType
>(
278 command_id
- USE_LAUNCH_TYPE_COMMAND_START
);
279 // When bookmark apps are enabled, hosted apps can only toggle between
280 // LAUNCH_TYPE_WINDOW and LAUNCH_TYPE_REGULAR.
281 if (extensions::util::IsNewBookmarkAppsEnabled()) {
282 launch_type
= (controller_
->GetExtensionLaunchType(profile_
, app_id_
) ==
283 extensions::LAUNCH_TYPE_WINDOW
)
284 ? extensions::LAUNCH_TYPE_REGULAR
285 : extensions::LAUNCH_TYPE_WINDOW
;
287 controller_
->SetExtensionLaunchType(profile_
, app_id_
, launch_type
);
288 } else if (command_id
== OPTIONS
) {
289 controller_
->ShowOptionsPage(profile_
, app_id_
);
290 } else if (command_id
== UNINSTALL
) {
291 controller_
->UninstallApp(profile_
, app_id_
);
292 } else if (extensions::ContextMenuMatcher::IsExtensionsCustomCommandId(
294 extension_menu_items_
->ExecuteCommand(command_id
, NULL
,
295 content::ContextMenuParams());
296 } else if (command_id
== MENU_NEW_WINDOW
) {
297 controller_
->CreateNewWindow(profile_
, false);
298 } else if (command_id
== MENU_NEW_INCOGNITO_WINDOW
) {
299 controller_
->CreateNewWindow(profile_
, true);
303 } // namespace app_list