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.
5 // Definition of helper functions for the ContextMenus API.
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_
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"
15 namespace extensions {
16 namespace context_menus_api_helpers {
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>();
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;
36 return parent_id.Pass();
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[];
49 std::string GetIDString(const MenuItem::Id& id);
51 MenuItem* GetParent(MenuItem::Id parent_id,
52 const MenuManager* menu_manager,
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);
63 case PropertyWithEnumT::CONTEXTS_TYPE_PAGE:
64 contexts.Add(extensions::MenuItem::PAGE);
66 case PropertyWithEnumT::CONTEXTS_TYPE_SELECTION:
67 contexts.Add(extensions::MenuItem::SELECTION);
69 case PropertyWithEnumT::CONTEXTS_TYPE_LINK:
70 contexts.Add(extensions::MenuItem::LINK);
72 case PropertyWithEnumT::CONTEXTS_TYPE_EDITABLE:
73 contexts.Add(extensions::MenuItem::EDITABLE);
75 case PropertyWithEnumT::CONTEXTS_TYPE_IMAGE:
76 contexts.Add(extensions::MenuItem::IMAGE);
78 case PropertyWithEnumT::CONTEXTS_TYPE_VIDEO:
79 contexts.Add(extensions::MenuItem::VIDEO);
81 case PropertyWithEnumT::CONTEXTS_TYPE_AUDIO:
82 contexts.Add(extensions::MenuItem::AUDIO);
84 case PropertyWithEnumT::CONTEXTS_TYPE_FRAME:
85 contexts.Add(extensions::MenuItem::FRAME);
87 case PropertyWithEnumT::CONTEXTS_TYPE_LAUNCHER:
88 contexts.Add(extensions::MenuItem::LAUNCHER);
90 case PropertyWithEnumT::CONTEXTS_TYPE_NONE:
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:
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;
112 return extensions::MenuItem::NORMAL;
115 // Creates and adds a menu item from |create_properties|.
116 template<typename PropertyWithEnumT>
117 bool CreateMenuItem(const PropertyWithEnumT& create_properties,
119 const Extension* extension,
120 const MenuItem::Id& item_id,
121 std::string* error) {
122 MenuManager* menu_manager = MenuManager::Get(profile);
124 if (menu_manager->GetItemById(item_id)) {
125 *error = ErrorUtils::FormatErrorMessage(kDuplicateIDError,
126 GetIDString(item_id));
130 if (BackgroundInfo::HasLazyBackgroundPage(extension) &&
131 create_properties.onclick.get()) {
132 *error = kOnclickDisallowedError;
137 MenuItem::ContextList contexts;
138 if (create_properties.contexts.get())
139 contexts = GetContexts(create_properties);
141 contexts.Add(MenuItem::PAGE);
143 if (contexts.Contains(MenuItem::LAUNCHER) && !extension->is_platform_app()) {
144 *error = kLauncherNotAllowedError;
150 if (create_properties.title.get())
151 title = *create_properties.title;
153 MenuItem::Type type = GetType(create_properties, MenuItem::NORMAL);
154 if (title.empty() && type != MenuItem::SEPARATOR) {
155 *error = kTitleNeededError;
160 bool checked = false;
161 if (create_properties.checked.get())
162 checked = *create_properties.checked;
166 if (create_properties.enabled.get())
167 enabled = *create_properties.enabled;
169 scoped_ptr<MenuItem> item(
170 new MenuItem(item_id, title, checked, enabled, type, contexts));
173 if (!item->PopulateURLPatterns(
174 create_properties.document_url_patterns.get(),
175 create_properties.target_url_patterns.get(),
182 scoped_ptr<MenuItem::Id> parent_id(GetParentId(create_properties,
183 profile->IsOffTheRecord(),
185 if (parent_id.get()) {
186 MenuItem* parent = GetParent(*parent_id, menu_manager, error);
189 success = menu_manager->AddChildItem(parent->id(), item.release());
191 success = menu_manager->AddContextItem(extension, item.release());
197 menu_manager->WriteToStorage(extension);
201 // Updates a menu item from |update_properties|.
202 template<typename PropertyWithEnumT>
203 bool UpdateMenuItem(const PropertyWithEnumT& update_properties,
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);
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));
219 MenuItem::Type type = GetType(update_properties, item->type());
221 if (type != item->type()) {
222 if (type == MenuItem::RADIO || item->type() == MenuItem::RADIO)
223 radio_item_updated = true;
224 item->set_type(type);
228 if (update_properties.title.get()) {
229 std::string title(*update_properties.title);
230 if (title.empty() && item->type() != MenuItem::SEPARATOR) {
231 *error = kTitleNeededError;
234 item->set_title(title);
238 if (update_properties.checked.get()) {
239 bool checked = *update_properties.checked;
241 item->type() != MenuItem::CHECKBOX &&
242 item->type() != MenuItem::RADIO) {
243 *error = kCheckedError;
246 if (checked != item->checked()) {
247 if (!item->SetChecked(checked)) {
248 *error = kCheckedError;
251 radio_item_updated = true;
256 if (update_properties.enabled.get())
257 item->set_enabled(*update_properties.enabled);
260 MenuItem::ContextList contexts;
261 if (update_properties.contexts.get()) {
262 contexts = GetContexts(update_properties);
264 if (contexts.Contains(MenuItem::LAUNCHER) &&
265 !extension->is_platform_app()) {
266 *error = kLauncherNotAllowedError;
270 if (contexts != item->contexts())
271 item->set_contexts(contexts);
275 MenuItem* parent = NULL;
276 scoped_ptr<MenuItem::Id> parent_id(GetParentId(update_properties,
277 profile->IsOffTheRecord(),
279 if (parent_id.get()) {
280 MenuItem* parent = GetParent(*parent_id, menu_manager, error);
281 if (!parent || !menu_manager->ChangeParent(item->id(), &parent->id()))
286 if (!item->PopulateURLPatterns(
287 update_properties.document_url_patterns.get(),
288 update_properties.target_url_patterns.get(), error)) {
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()))
297 menu_manager->WriteToStorage(extension);
301 } // namespace context_menus_api_helpers
302 } // namespace extensions
304 #endif // CHROME_BROWSER_EXTENSIONS_API_CONTEXT_MENUS_CONTEXT_MENUS_API_HELPERS_H_