Upstream version 5.34.104.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     std::string extension_id) {
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, extension_id));
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 kCannotFindItemError[];
42 extern const char kCheckedError[];
43 extern const char kDuplicateIDError[];
44 extern const char kLauncherNotAllowedError[];
45 extern const char kOnclickDisallowedError[];
46 extern const char kParentsMustBeNormalError[];
47 extern const char kTitleNeededError[];
48
49 std::string GetIDString(const MenuItem::Id& id);
50
51 MenuItem* GetParent(MenuItem::Id parent_id,
52                     const MenuManager* menu_manager,
53                     std::string* error);
54
55 template<typename PropertyWithEnumT>
56 MenuItem::ContextList GetContexts(const PropertyWithEnumT& property) {
57   MenuItem::ContextList contexts;
58   for (size_t i = 0; i < property.contexts->size(); ++i) {
59     switch (property.contexts->at(i)) {
60       case PropertyWithEnumT::CONTEXTS_TYPE_ALL:
61         contexts.Add(extensions::MenuItem::ALL);
62         break;
63       case PropertyWithEnumT::CONTEXTS_TYPE_PAGE:
64         contexts.Add(extensions::MenuItem::PAGE);
65         break;
66       case PropertyWithEnumT::CONTEXTS_TYPE_SELECTION:
67         contexts.Add(extensions::MenuItem::SELECTION);
68         break;
69       case PropertyWithEnumT::CONTEXTS_TYPE_LINK:
70         contexts.Add(extensions::MenuItem::LINK);
71         break;
72       case PropertyWithEnumT::CONTEXTS_TYPE_EDITABLE:
73         contexts.Add(extensions::MenuItem::EDITABLE);
74         break;
75       case PropertyWithEnumT::CONTEXTS_TYPE_IMAGE:
76         contexts.Add(extensions::MenuItem::IMAGE);
77         break;
78       case PropertyWithEnumT::CONTEXTS_TYPE_VIDEO:
79         contexts.Add(extensions::MenuItem::VIDEO);
80         break;
81       case PropertyWithEnumT::CONTEXTS_TYPE_AUDIO:
82         contexts.Add(extensions::MenuItem::AUDIO);
83         break;
84       case PropertyWithEnumT::CONTEXTS_TYPE_FRAME:
85         contexts.Add(extensions::MenuItem::FRAME);
86         break;
87       case PropertyWithEnumT::CONTEXTS_TYPE_LAUNCHER:
88         contexts.Add(extensions::MenuItem::LAUNCHER);
89         break;
90       case PropertyWithEnumT::CONTEXTS_TYPE_NONE:
91         NOTREACHED();
92     }
93   }
94   return contexts;
95 }
96
97 template<typename PropertyWithEnumT>
98 MenuItem::Type GetType(const PropertyWithEnumT& property,
99                        MenuItem::Type default_type) {
100   switch (property.type) {
101     case PropertyWithEnumT::TYPE_NONE:
102       return default_type;
103     case PropertyWithEnumT::TYPE_NORMAL:
104       return extensions::MenuItem::NORMAL;
105     case PropertyWithEnumT::TYPE_CHECKBOX:
106       return extensions::MenuItem::CHECKBOX;
107     case PropertyWithEnumT::TYPE_RADIO:
108       return extensions::MenuItem::RADIO;
109     case PropertyWithEnumT::TYPE_SEPARATOR:
110       return extensions::MenuItem::SEPARATOR;
111   }
112   return extensions::MenuItem::NORMAL;
113 }
114
115 // Creates and adds a menu item from |create_properties|.
116 template<typename PropertyWithEnumT>
117 bool CreateMenuItem(const PropertyWithEnumT& create_properties,
118                     Profile* profile,
119                     const Extension* extension,
120                     const MenuItem::Id& item_id,
121                     std::string* error) {
122   MenuManager* menu_manager = MenuManager::Get(profile);
123
124   if (menu_manager->GetItemById(item_id)) {
125     *error = ErrorUtils::FormatErrorMessage(kDuplicateIDError,
126                                             GetIDString(item_id));
127     return false;
128   }
129
130   if (BackgroundInfo::HasLazyBackgroundPage(extension) &&
131       create_properties.onclick.get()) {
132     *error = kOnclickDisallowedError;
133     return false;
134   }
135
136   // Contexts.
137   MenuItem::ContextList contexts;
138   if (create_properties.contexts.get())
139     contexts = GetContexts(create_properties);
140   else
141     contexts.Add(MenuItem::PAGE);
142
143   if (contexts.Contains(MenuItem::LAUNCHER) && !extension->is_platform_app()) {
144     *error = kLauncherNotAllowedError;
145     return false;
146   }
147
148   // Title.
149   std::string title;
150   if (create_properties.title.get())
151     title = *create_properties.title;
152
153   MenuItem::Type type = GetType(create_properties, MenuItem::NORMAL);
154   if (title.empty() && type != MenuItem::SEPARATOR) {
155     *error = kTitleNeededError;
156     return false;
157   }
158
159   // Checked state.
160   bool checked = false;
161   if (create_properties.checked.get())
162     checked = *create_properties.checked;
163
164   // Enabled.
165   bool enabled = true;
166   if (create_properties.enabled.get())
167     enabled = *create_properties.enabled;
168
169   scoped_ptr<MenuItem> item(
170       new MenuItem(item_id, title, checked, enabled, type, contexts));
171
172   // URL Patterns.
173   if (!item->PopulateURLPatterns(
174           create_properties.document_url_patterns.get(),
175           create_properties.target_url_patterns.get(),
176           error)) {
177     return false;
178   }
179
180   // Parent id.
181   bool success = true;
182   scoped_ptr<MenuItem::Id> parent_id(GetParentId(create_properties,
183                                                  profile->IsOffTheRecord(),
184                                                  extension->id()));
185   if (parent_id.get()) {
186     MenuItem* parent = GetParent(*parent_id, menu_manager, error);
187     if (!parent)
188       return false;
189     success = menu_manager->AddChildItem(parent->id(), item.release());
190   } else {
191     success = menu_manager->AddContextItem(extension, item.release());
192   }
193
194   if (!success)
195     return false;
196
197   menu_manager->WriteToStorage(extension);
198   return true;
199 }
200
201 // Updates a menu item from |update_properties|.
202 template<typename PropertyWithEnumT>
203 bool UpdateMenuItem(const PropertyWithEnumT& update_properties,
204                     Profile* profile,
205                     const Extension* extension,
206                     const MenuItem::Id& item_id,
207                     std::string* error) {
208   bool radio_item_updated = false;
209   MenuManager* menu_manager = MenuManager::Get(profile);
210
211   MenuItem* item = menu_manager->GetItemById(item_id);
212   if (!item || item->extension_id() != extension->id()){
213     *error = ErrorUtils::FormatErrorMessage(
214         kCannotFindItemError, GetIDString(item_id));
215     return false;
216   }
217
218   // Type.
219   MenuItem::Type type = GetType(update_properties, item->type());
220
221   if (type != item->type()) {
222     if (type == MenuItem::RADIO || item->type() == MenuItem::RADIO)
223       radio_item_updated = true;
224     item->set_type(type);
225   }
226
227   // Title.
228   if (update_properties.title.get()) {
229     std::string title(*update_properties.title);
230     if (title.empty() && item->type() != MenuItem::SEPARATOR) {
231       *error = kTitleNeededError;
232       return false;
233     }
234     item->set_title(title);
235   }
236
237   // Checked state.
238   if (update_properties.checked.get()) {
239     bool checked = *update_properties.checked;
240     if (checked &&
241         item->type() != MenuItem::CHECKBOX &&
242         item->type() != MenuItem::RADIO) {
243       *error = kCheckedError;
244       return false;
245     }
246     if (checked != item->checked()) {
247       if (!item->SetChecked(checked)) {
248         *error = kCheckedError;
249         return false;
250       }
251       radio_item_updated = true;
252     }
253   }
254
255   // Enabled.
256   if (update_properties.enabled.get())
257     item->set_enabled(*update_properties.enabled);
258
259   // Contexts.
260   MenuItem::ContextList contexts;
261   if (update_properties.contexts.get()) {
262     contexts = GetContexts(update_properties);
263
264     if (contexts.Contains(MenuItem::LAUNCHER) &&
265         !extension->is_platform_app()) {
266       *error = kLauncherNotAllowedError;
267       return false;
268     }
269
270     if (contexts != item->contexts())
271       item->set_contexts(contexts);
272   }
273
274   // Parent id.
275   MenuItem* parent = NULL;
276   scoped_ptr<MenuItem::Id> parent_id(GetParentId(update_properties,
277                                                  profile->IsOffTheRecord(),
278                                                  extension->id()));
279   if (parent_id.get()) {
280     MenuItem* parent = GetParent(*parent_id, menu_manager, error);
281     if (!parent || !menu_manager->ChangeParent(item->id(), &parent->id()))
282       return false;
283   }
284
285   // URL Patterns.
286   if (!item->PopulateURLPatterns(
287           update_properties.document_url_patterns.get(),
288           update_properties.target_url_patterns.get(), error)) {
289     return false;
290   }
291
292   // There is no need to call ItemUpdated if ChangeParent is called because
293   // all sanitation is taken care of in ChangeParent.
294   if (!parent && radio_item_updated && !menu_manager->ItemUpdated(item->id()))
295     return false;
296
297   menu_manager->WriteToStorage(extension);
298   return true;
299 }
300
301 }  // namespace context_menus_api_helpers
302 }  // namespace extensions
303
304 #endif  // CHROME_BROWSER_EXTENSIONS_API_CONTEXT_MENUS_CONTEXT_MENUS_API_HELPERS_H_