Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / context_menus / context_menus_api_helpers.h
1 // Copyright 2014 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 // Definition of helper functions for the ContextMenus API.
6
7 #ifndef CHROME_BROWSER_EXTENSIONS_API_CONTEXT_MENUS_CONTEXT_MENUS_API_HELPERS_H_
8 #define CHROME_BROWSER_EXTENSIONS_API_CONTEXT_MENUS_CONTEXT_MENUS_API_HELPERS_H_
9
10 #include "chrome/browser/extensions/menu_manager.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "extensions/common/error_utils.h"
13 #include "extensions/common/manifest_handlers/background_info.h"
14
15 namespace extensions {
16 namespace context_menus_api_helpers {
17
18 namespace {
19
20 template <typename PropertyWithEnumT>
21 scoped_ptr<extensions::MenuItem::Id> GetParentId(
22     const PropertyWithEnumT& property,
23     bool is_off_the_record,
24     const MenuItem::ExtensionKey& key) {
25   if (!property.parent_id)
26     return scoped_ptr<extensions::MenuItem::Id>();
27
28   scoped_ptr<extensions::MenuItem::Id> parent_id(
29       new extensions::MenuItem::Id(is_off_the_record, key));
30   if (property.parent_id->as_integer)
31     parent_id->uid = *property.parent_id->as_integer;
32   else if (property.parent_id->as_string)
33     parent_id->string_uid = *property.parent_id->as_string;
34   else
35     NOTREACHED();
36   return parent_id.Pass();
37 }
38
39 }  // namespace
40
41 extern const char kActionNotAllowedError[];
42 extern const char kCannotFindItemError[];
43 extern const char kCheckedError[];
44 extern const char kDuplicateIDError[];
45 extern const char kGeneratedIdKey[];
46 extern const char kLauncherNotAllowedError[];
47 extern const char kOnclickDisallowedError[];
48 extern const char kParentsMustBeNormalError[];
49 extern const char kTitleNeededError[];
50
51 std::string GetIDString(const MenuItem::Id& id);
52
53 MenuItem* GetParent(MenuItem::Id parent_id,
54                     const MenuManager* menu_manager,
55                     std::string* error);
56
57 template<typename PropertyWithEnumT>
58 MenuItem::ContextList GetContexts(const PropertyWithEnumT& property) {
59   MenuItem::ContextList contexts;
60   for (size_t i = 0; i < property.contexts->size(); ++i) {
61     switch (property.contexts->at(i)) {
62       case PropertyWithEnumT::CONTEXTS_TYPE_ALL:
63         contexts.Add(extensions::MenuItem::ALL);
64         break;
65       case PropertyWithEnumT::CONTEXTS_TYPE_PAGE:
66         contexts.Add(extensions::MenuItem::PAGE);
67         break;
68       case PropertyWithEnumT::CONTEXTS_TYPE_SELECTION:
69         contexts.Add(extensions::MenuItem::SELECTION);
70         break;
71       case PropertyWithEnumT::CONTEXTS_TYPE_LINK:
72         contexts.Add(extensions::MenuItem::LINK);
73         break;
74       case PropertyWithEnumT::CONTEXTS_TYPE_EDITABLE:
75         contexts.Add(extensions::MenuItem::EDITABLE);
76         break;
77       case PropertyWithEnumT::CONTEXTS_TYPE_IMAGE:
78         contexts.Add(extensions::MenuItem::IMAGE);
79         break;
80       case PropertyWithEnumT::CONTEXTS_TYPE_VIDEO:
81         contexts.Add(extensions::MenuItem::VIDEO);
82         break;
83       case PropertyWithEnumT::CONTEXTS_TYPE_AUDIO:
84         contexts.Add(extensions::MenuItem::AUDIO);
85         break;
86       case PropertyWithEnumT::CONTEXTS_TYPE_FRAME:
87         contexts.Add(extensions::MenuItem::FRAME);
88         break;
89       case PropertyWithEnumT::CONTEXTS_TYPE_LAUNCHER:
90         // Not available for <webview>.
91         contexts.Add(extensions::MenuItem::LAUNCHER);
92         break;
93       case PropertyWithEnumT::CONTEXTS_TYPE_BROWSER_ACTION:
94         // Not available for <webview>.
95         contexts.Add(extensions::MenuItem::BROWSER_ACTION);
96         break;
97       case PropertyWithEnumT::CONTEXTS_TYPE_PAGE_ACTION:
98         // Not available for <webview>.
99         contexts.Add(extensions::MenuItem::PAGE_ACTION);
100         break;
101       case PropertyWithEnumT::CONTEXTS_TYPE_NONE:
102         NOTREACHED();
103     }
104   }
105   return contexts;
106 }
107
108 template<typename PropertyWithEnumT>
109 MenuItem::Type GetType(const PropertyWithEnumT& property,
110                        MenuItem::Type default_type) {
111   switch (property.type) {
112     case PropertyWithEnumT::TYPE_NONE:
113       return default_type;
114     case PropertyWithEnumT::TYPE_NORMAL:
115       return extensions::MenuItem::NORMAL;
116     case PropertyWithEnumT::TYPE_CHECKBOX:
117       return extensions::MenuItem::CHECKBOX;
118     case PropertyWithEnumT::TYPE_RADIO:
119       return extensions::MenuItem::RADIO;
120     case PropertyWithEnumT::TYPE_SEPARATOR:
121       return extensions::MenuItem::SEPARATOR;
122   }
123   return extensions::MenuItem::NORMAL;
124 }
125
126 // Creates and adds a menu item from |create_properties|.
127 template<typename PropertyWithEnumT>
128 bool CreateMenuItem(const PropertyWithEnumT& create_properties,
129                     Profile* profile,
130                     const Extension* extension,
131                     const MenuItem::Id& item_id,
132                     std::string* error) {
133   bool is_webview = item_id.extension_key.webview_instance_id != 0;
134   MenuManager* menu_manager = MenuManager::Get(profile);
135
136   if (menu_manager->GetItemById(item_id)) {
137     *error = ErrorUtils::FormatErrorMessage(kDuplicateIDError,
138                                             GetIDString(item_id));
139     return false;
140   }
141
142   if (!is_webview && BackgroundInfo::HasLazyBackgroundPage(extension) &&
143       create_properties.onclick.get()) {
144     *error = kOnclickDisallowedError;
145     return false;
146   }
147
148   // Contexts.
149   MenuItem::ContextList contexts;
150   if (create_properties.contexts.get())
151     contexts = GetContexts(create_properties);
152   else
153     contexts.Add(MenuItem::PAGE);
154
155   if (contexts.Contains(MenuItem::LAUNCHER)) {
156     // Launcher item is not allowed for <webview>.
157     if (!extension->is_platform_app() || is_webview) {
158       *error = kLauncherNotAllowedError;
159       return false;
160     }
161   }
162
163   if (contexts.Contains(MenuItem::BROWSER_ACTION) ||
164       contexts.Contains(MenuItem::PAGE_ACTION)) {
165     // Action items are not allowed for <webview>.
166     if (!extension->is_extension() || is_webview) {
167       *error = kActionNotAllowedError;
168       return false;
169     }
170   }
171
172   // Title.
173   std::string title;
174   if (create_properties.title.get())
175     title = *create_properties.title;
176
177   MenuItem::Type type = GetType(create_properties, MenuItem::NORMAL);
178   if (title.empty() && type != MenuItem::SEPARATOR) {
179     *error = kTitleNeededError;
180     return false;
181   }
182
183   // Checked state.
184   bool checked = false;
185   if (create_properties.checked.get())
186     checked = *create_properties.checked;
187
188   // Enabled.
189   bool enabled = true;
190   if (create_properties.enabled.get())
191     enabled = *create_properties.enabled;
192
193   scoped_ptr<MenuItem> item(
194       new MenuItem(item_id, title, checked, enabled, type, contexts));
195
196   // URL Patterns.
197   if (!item->PopulateURLPatterns(
198           create_properties.document_url_patterns.get(),
199           create_properties.target_url_patterns.get(),
200           error)) {
201     return false;
202   }
203
204   // Parent id.
205   bool success = true;
206   scoped_ptr<MenuItem::Id> parent_id(GetParentId(
207       create_properties, profile->IsOffTheRecord(), item_id.extension_key));
208   if (parent_id.get()) {
209     MenuItem* parent = GetParent(*parent_id, menu_manager, error);
210     if (!parent)
211       return false;
212     success = menu_manager->AddChildItem(parent->id(), item.release());
213   } else {
214     success = menu_manager->AddContextItem(extension, item.release());
215   }
216
217   if (!success)
218     return false;
219
220   menu_manager->WriteToStorage(extension, item_id.extension_key);
221   return true;
222 }
223
224 // Updates a menu item from |update_properties|.
225 template<typename PropertyWithEnumT>
226 bool UpdateMenuItem(const PropertyWithEnumT& update_properties,
227                     Profile* profile,
228                     const Extension* extension,
229                     const MenuItem::Id& item_id,
230                     std::string* error) {
231   bool radio_item_updated = false;
232   bool is_webview = item_id.extension_key.webview_instance_id != 0;
233   MenuManager* menu_manager = MenuManager::Get(profile);
234
235   MenuItem* item = menu_manager->GetItemById(item_id);
236   if (!item || item->extension_id() != extension->id()){
237     *error = ErrorUtils::FormatErrorMessage(
238         kCannotFindItemError, GetIDString(item_id));
239     return false;
240   }
241
242   // Type.
243   MenuItem::Type type = GetType(update_properties, item->type());
244
245   if (type != item->type()) {
246     if (type == MenuItem::RADIO || item->type() == MenuItem::RADIO)
247       radio_item_updated = true;
248     item->set_type(type);
249   }
250
251   // Title.
252   if (update_properties.title.get()) {
253     std::string title(*update_properties.title);
254     if (title.empty() && item->type() != MenuItem::SEPARATOR) {
255       *error = kTitleNeededError;
256       return false;
257     }
258     item->set_title(title);
259   }
260
261   // Checked state.
262   if (update_properties.checked.get()) {
263     bool checked = *update_properties.checked;
264     if (checked &&
265         item->type() != MenuItem::CHECKBOX &&
266         item->type() != MenuItem::RADIO) {
267       *error = kCheckedError;
268       return false;
269     }
270     if (checked != item->checked()) {
271       if (!item->SetChecked(checked)) {
272         *error = kCheckedError;
273         return false;
274       }
275       radio_item_updated = true;
276     }
277   }
278
279   // Enabled.
280   if (update_properties.enabled.get())
281     item->set_enabled(*update_properties.enabled);
282
283   // Contexts.
284   MenuItem::ContextList contexts;
285   if (update_properties.contexts.get()) {
286     contexts = GetContexts(update_properties);
287
288     if (contexts.Contains(MenuItem::LAUNCHER)) {
289       // Launcher item is not allowed for <webview>.
290       if (!extension->is_platform_app() || is_webview) {
291         *error = kLauncherNotAllowedError;
292         return false;
293       }
294     }
295
296     if (contexts != item->contexts())
297       item->set_contexts(contexts);
298   }
299
300   // Parent id.
301   MenuItem* parent = NULL;
302   scoped_ptr<MenuItem::Id> parent_id(GetParentId(
303       update_properties, profile->IsOffTheRecord(), item_id.extension_key));
304   if (parent_id.get()) {
305     MenuItem* parent = GetParent(*parent_id, menu_manager, error);
306     if (!parent || !menu_manager->ChangeParent(item->id(), &parent->id()))
307       return false;
308   }
309
310   // URL Patterns.
311   if (!item->PopulateURLPatterns(
312           update_properties.document_url_patterns.get(),
313           update_properties.target_url_patterns.get(), error)) {
314     return false;
315   }
316
317   // There is no need to call ItemUpdated if ChangeParent is called because
318   // all sanitation is taken care of in ChangeParent.
319   if (!parent && radio_item_updated && !menu_manager->ItemUpdated(item->id()))
320     return false;
321
322   menu_manager->WriteToStorage(extension, item_id.extension_key);
323   return true;
324 }
325
326 }  // namespace context_menus_api_helpers
327 }  // namespace extensions
328
329 #endif  // CHROME_BROWSER_EXTENSIONS_API_CONTEXT_MENUS_CONTEXT_MENUS_API_HELPERS_H_