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