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 "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/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/common/chrome_switches.h"
16 #include "chrome/common/extensions/extension_constants.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"
24 #include "ash/shell.h"
39 MENU_NEW_INCOGNITO_WINDOW
,
40 // Order matters in USE_LAUNCH_TYPE_* and must match the LaunchType enum.
41 USE_LAUNCH_TYPE_COMMAND_START
= 200,
42 USE_LAUNCH_TYPE_PINNED
= USE_LAUNCH_TYPE_COMMAND_START
,
43 USE_LAUNCH_TYPE_REGULAR
,
44 USE_LAUNCH_TYPE_FULLSCREEN
,
45 USE_LAUNCH_TYPE_WINDOW
,
46 USE_LAUNCH_TYPE_COMMAND_END
,
49 bool MenuItemHasLauncherContext(const extensions::MenuItem
* item
) {
50 return item
->contexts().Contains(extensions::MenuItem::LAUNCHER
);
55 AppContextMenu::AppContextMenu(AppContextMenuDelegate
* delegate
,
57 const std::string
& app_id
,
58 AppListControllerDelegate
* controller
,
60 bool is_search_result
)
61 : delegate_(delegate
),
64 controller_(controller
),
65 is_platform_app_(is_platform_app
),
66 is_search_result_(is_search_result
) {
69 AppContextMenu::~AppContextMenu() {}
71 ui::MenuModel
* AppContextMenu::GetMenuModel() {
72 if (!controller_
->IsExtensionInstalled(profile_
, app_id_
))
75 if (menu_model_
.get())
76 return menu_model_
.get();
78 menu_model_
.reset(new ui::SimpleMenuModel(this));
80 if (app_id_
== extension_misc::kChromeAppId
) {
81 menu_model_
->AddItemWithStringId(
83 IDS_APP_LIST_NEW_WINDOW
);
84 if (!profile_
->IsOffTheRecord()) {
85 menu_model_
->AddItemWithStringId(
86 MENU_NEW_INCOGNITO_WINDOW
,
87 IDS_APP_LIST_NEW_INCOGNITO_WINDOW
);
90 extension_menu_items_
.reset(new extensions::ContextMenuMatcher(
91 profile_
, this, menu_model_
.get(),
92 base::Bind(MenuItemHasLauncherContext
)));
94 if (!is_platform_app_
)
95 menu_model_
->AddItem(LAUNCH_NEW
, base::string16());
98 extension_menu_items_
->AppendExtensionItems(app_id_
, 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
);
116 if (!is_platform_app_
) {
117 menu_model_
->AddSeparator(ui::NORMAL_SEPARATOR
);
118 // Streamlined hosted apps can only toggle between USE_LAUNCH_TYPE_WINDOW
119 // and USE_LAUNCH_TYPE_REGULAR.
120 if (CommandLine::ForCurrentProcess()->HasSwitch(
121 switches::kEnableStreamlinedHostedApps
)) {
122 menu_model_
->AddCheckItemWithStringId(
123 USE_LAUNCH_TYPE_REGULAR
,
124 IDS_APP_CONTEXT_MENU_OPEN_TAB
);
126 menu_model_
->AddCheckItemWithStringId(
127 USE_LAUNCH_TYPE_REGULAR
,
128 IDS_APP_CONTEXT_MENU_OPEN_REGULAR
);
129 menu_model_
->AddCheckItemWithStringId(
130 USE_LAUNCH_TYPE_PINNED
,
131 IDS_APP_CONTEXT_MENU_OPEN_PINNED
);
132 #if defined(OS_MACOSX)
133 // Mac does not support standalone web app browser windows or maximize.
134 menu_model_
->AddCheckItemWithStringId(
135 USE_LAUNCH_TYPE_FULLSCREEN
,
136 IDS_APP_CONTEXT_MENU_OPEN_FULLSCREEN
);
138 menu_model_
->AddCheckItemWithStringId(
139 USE_LAUNCH_TYPE_WINDOW
,
140 IDS_APP_CONTEXT_MENU_OPEN_WINDOW
);
141 // Even though the launch type is Full Screen it is more accurately
142 // described as Maximized in Ash.
143 menu_model_
->AddCheckItemWithStringId(
144 USE_LAUNCH_TYPE_FULLSCREEN
,
145 IDS_APP_CONTEXT_MENU_OPEN_MAXIMIZED
);
148 menu_model_
->AddSeparator(ui::NORMAL_SEPARATOR
);
149 menu_model_
->AddItemWithStringId(OPTIONS
, IDS_NEW_TAB_APP_OPTIONS
);
152 menu_model_
->AddItemWithStringId(DETAILS
, IDS_NEW_TAB_APP_DETAILS
);
153 menu_model_
->AddItemWithStringId(
155 is_platform_app_
? IDS_APP_LIST_UNINSTALL_ITEM
156 : IDS_EXTENSIONS_UNINSTALL
);
159 return menu_model_
.get();
162 bool AppContextMenu::IsItemForCommandIdDynamic(int command_id
) const {
163 return command_id
== TOGGLE_PIN
|| command_id
== LAUNCH_NEW
;
166 base::string16
AppContextMenu::GetLabelForCommandId(int command_id
) const {
167 if (command_id
== TOGGLE_PIN
) {
168 return controller_
->IsAppPinned(app_id_
) ?
169 l10n_util::GetStringUTF16(IDS_APP_LIST_CONTEXT_MENU_UNPIN
) :
170 l10n_util::GetStringUTF16(IDS_APP_LIST_CONTEXT_MENU_PIN
);
171 } else if (command_id
== LAUNCH_NEW
) {
172 #if defined(OS_MACOSX)
173 // Even fullscreen windows launch in a browser tab on Mac.
174 const bool launches_in_tab
= true;
176 const bool launches_in_tab
= IsCommandIdChecked(USE_LAUNCH_TYPE_PINNED
) ||
177 IsCommandIdChecked(USE_LAUNCH_TYPE_REGULAR
);
179 return launches_in_tab
?
180 l10n_util::GetStringUTF16(IDS_APP_LIST_CONTEXT_MENU_NEW_TAB
) :
181 l10n_util::GetStringUTF16(IDS_APP_LIST_CONTEXT_MENU_NEW_WINDOW
);
184 return base::string16();
188 bool AppContextMenu::IsCommandIdChecked(int command_id
) const {
189 if (command_id
>= USE_LAUNCH_TYPE_COMMAND_START
&&
190 command_id
< USE_LAUNCH_TYPE_COMMAND_END
) {
191 return static_cast<int>(controller_
->GetExtensionLaunchType(
192 profile_
, app_id_
)) + USE_LAUNCH_TYPE_COMMAND_START
== command_id
;
193 } else if (command_id
>= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST
&&
194 command_id
<= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST
) {
195 return extension_menu_items_
->IsCommandIdChecked(command_id
);
200 bool AppContextMenu::IsCommandIdEnabled(int command_id
) const {
201 if (command_id
== TOGGLE_PIN
) {
202 return controller_
->GetPinnable() ==
203 AppListControllerDelegate::PIN_EDITABLE
;
204 } else if (command_id
== OPTIONS
) {
205 return controller_
->HasOptionsPage(profile_
, app_id_
);
206 } else if (command_id
== UNINSTALL
) {
207 return controller_
->UserMayModifySettings(profile_
, app_id_
);
208 } else if (command_id
== DETAILS
) {
209 return controller_
->IsAppFromWebStore(profile_
, app_id_
);
210 } else if (command_id
>= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST
&&
211 command_id
<= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST
) {
212 return extension_menu_items_
->IsCommandIdEnabled(command_id
);
213 } else if (command_id
== MENU_NEW_WINDOW
) {
214 // "Normal" windows are not allowed when incognito is enforced.
215 return IncognitoModePrefs::GetAvailability(profile_
->GetPrefs()) !=
216 IncognitoModePrefs::FORCED
;
217 } else if (command_id
== MENU_NEW_INCOGNITO_WINDOW
) {
218 // Incognito windows are not allowed when incognito is disabled.
219 return IncognitoModePrefs::GetAvailability(profile_
->GetPrefs()) !=
220 IncognitoModePrefs::DISABLED
;
225 bool AppContextMenu::GetAcceleratorForCommandId(
227 ui::Accelerator
* acclelrator
) {
231 void AppContextMenu::ExecuteCommand(int command_id
, int event_flags
) {
232 if (command_id
== LAUNCH_NEW
) {
233 delegate_
->ExecuteLaunchCommand(event_flags
);
234 } else if (command_id
== TOGGLE_PIN
&& controller_
->GetPinnable() ==
235 AppListControllerDelegate::PIN_EDITABLE
) {
236 if (controller_
->IsAppPinned(app_id_
))
237 controller_
->UnpinApp(app_id_
);
239 controller_
->PinApp(app_id_
);
240 } else if (command_id
== CREATE_SHORTCUTS
) {
241 controller_
->DoCreateShortcutsFlow(profile_
, app_id_
);
242 } else if (command_id
>= USE_LAUNCH_TYPE_COMMAND_START
&&
243 command_id
< USE_LAUNCH_TYPE_COMMAND_END
) {
244 extensions::LaunchType launch_type
= static_cast<extensions::LaunchType
>(
245 command_id
- USE_LAUNCH_TYPE_COMMAND_START
);
246 // Streamlined hosted apps can only toggle between LAUNCH_TYPE_WINDOW and
247 // LAUNCH_TYPE_REGULAR.
248 if (CommandLine::ForCurrentProcess()->HasSwitch(
249 switches::kEnableStreamlinedHostedApps
)) {
250 launch_type
= (controller_
->GetExtensionLaunchType(profile_
, app_id_
) ==
251 extensions::LAUNCH_TYPE_REGULAR
) ?
252 extensions::LAUNCH_TYPE_WINDOW
:
253 extensions::LAUNCH_TYPE_REGULAR
;
255 controller_
->SetExtensionLaunchType(profile_
, app_id_
, launch_type
);
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