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 "chrome/common/extensions/api/context_menus.h"
13 #include "extensions/common/error_utils.h"
14 #include "extensions/common/manifest_handlers/background_info.h"
16 namespace extensions
{
17 namespace context_menus_api_helpers
{
21 template <typename PropertyWithEnumT
>
22 scoped_ptr
<extensions::MenuItem::Id
> GetParentId(
23 const PropertyWithEnumT
& property
,
24 bool is_off_the_record
,
25 const MenuItem::ExtensionKey
& key
) {
26 if (!property
.parent_id
)
27 return scoped_ptr
<extensions::MenuItem::Id
>();
29 scoped_ptr
<extensions::MenuItem::Id
> parent_id(
30 new extensions::MenuItem::Id(is_off_the_record
, key
));
31 if (property
.parent_id
->as_integer
)
32 parent_id
->uid
= *property
.parent_id
->as_integer
;
33 else if (property
.parent_id
->as_string
)
34 parent_id
->string_uid
= *property
.parent_id
->as_string
;
37 return parent_id
.Pass();
42 extern const char kActionNotAllowedError
[];
43 extern const char kCannotFindItemError
[];
44 extern const char kCheckedError
[];
45 extern const char kDuplicateIDError
[];
46 extern const char kGeneratedIdKey
[];
47 extern const char kLauncherNotAllowedError
[];
48 extern const char kOnclickDisallowedError
[];
49 extern const char kParentsMustBeNormalError
[];
50 extern const char kTitleNeededError
[];
52 std::string
GetIDString(const MenuItem::Id
& id
);
54 MenuItem
* GetParent(MenuItem::Id parent_id
,
55 const MenuManager
* menu_manager
,
58 MenuItem::ContextList
GetContexts(const std::vector
<
59 extensions::api::context_menus::ContextType
>& in_contexts
);
61 MenuItem::Type
GetType(extensions::api::context_menus::ItemType type
,
62 MenuItem::Type default_type
);
64 // Creates and adds a menu item from |create_properties|.
65 template<typename PropertyWithEnumT
>
66 bool CreateMenuItem(const PropertyWithEnumT
& create_properties
,
68 const Extension
* extension
,
69 const MenuItem::Id
& item_id
,
71 bool is_webview
= item_id
.extension_key
.webview_instance_id
!= 0;
72 MenuManager
* menu_manager
= MenuManager::Get(profile
);
74 if (menu_manager
->GetItemById(item_id
)) {
75 *error
= ErrorUtils::FormatErrorMessage(kDuplicateIDError
,
76 GetIDString(item_id
));
80 if (!is_webview
&& BackgroundInfo::HasLazyBackgroundPage(extension
) &&
81 create_properties
.onclick
.get()) {
82 *error
= kOnclickDisallowedError
;
87 MenuItem::ContextList contexts
;
88 if (create_properties
.contexts
.get())
89 contexts
= GetContexts(*create_properties
.contexts
);
91 contexts
.Add(MenuItem::PAGE
);
93 if (contexts
.Contains(MenuItem::LAUNCHER
)) {
94 // Launcher item is not allowed for <webview>.
95 if (!extension
->is_platform_app() || is_webview
) {
96 *error
= kLauncherNotAllowedError
;
101 if (contexts
.Contains(MenuItem::BROWSER_ACTION
) ||
102 contexts
.Contains(MenuItem::PAGE_ACTION
)) {
103 // Action items are not allowed for <webview>.
104 if (!extension
->is_extension() || is_webview
) {
105 *error
= kActionNotAllowedError
;
112 if (create_properties
.title
.get())
113 title
= *create_properties
.title
;
115 MenuItem::Type type
= GetType(create_properties
.type
, MenuItem::NORMAL
);
116 if (title
.empty() && type
!= MenuItem::SEPARATOR
) {
117 *error
= kTitleNeededError
;
122 bool checked
= false;
123 if (create_properties
.checked
.get())
124 checked
= *create_properties
.checked
;
128 if (create_properties
.enabled
.get())
129 enabled
= *create_properties
.enabled
;
131 scoped_ptr
<MenuItem
> item(
132 new MenuItem(item_id
, title
, checked
, enabled
, type
, contexts
));
135 if (!item
->PopulateURLPatterns(
136 create_properties
.document_url_patterns
.get(),
137 create_properties
.target_url_patterns
.get(),
144 scoped_ptr
<MenuItem::Id
> parent_id(GetParentId(
145 create_properties
, profile
->IsOffTheRecord(), item_id
.extension_key
));
146 if (parent_id
.get()) {
147 MenuItem
* parent
= GetParent(*parent_id
, menu_manager
, error
);
150 success
= menu_manager
->AddChildItem(parent
->id(), item
.release());
152 success
= menu_manager
->AddContextItem(extension
, item
.release());
158 menu_manager
->WriteToStorage(extension
, item_id
.extension_key
);
162 // Updates a menu item from |update_properties|.
163 template<typename PropertyWithEnumT
>
164 bool UpdateMenuItem(const PropertyWithEnumT
& update_properties
,
166 const Extension
* extension
,
167 const MenuItem::Id
& item_id
,
168 std::string
* error
) {
169 bool radio_item_updated
= false;
170 bool is_webview
= item_id
.extension_key
.webview_instance_id
!= 0;
171 MenuManager
* menu_manager
= MenuManager::Get(profile
);
173 MenuItem
* item
= menu_manager
->GetItemById(item_id
);
174 if (!item
|| item
->extension_id() != extension
->id()){
175 *error
= ErrorUtils::FormatErrorMessage(
176 kCannotFindItemError
, GetIDString(item_id
));
181 MenuItem::Type type
= GetType(update_properties
.type
, item
->type());
183 if (type
!= item
->type()) {
184 if (type
== MenuItem::RADIO
|| item
->type() == MenuItem::RADIO
)
185 radio_item_updated
= true;
186 item
->set_type(type
);
190 if (update_properties
.title
.get()) {
191 std::string
title(*update_properties
.title
);
192 if (title
.empty() && item
->type() != MenuItem::SEPARATOR
) {
193 *error
= kTitleNeededError
;
196 item
->set_title(title
);
200 if (update_properties
.checked
.get()) {
201 bool checked
= *update_properties
.checked
;
203 item
->type() != MenuItem::CHECKBOX
&&
204 item
->type() != MenuItem::RADIO
) {
205 *error
= kCheckedError
;
208 if (checked
!= item
->checked()) {
209 if (!item
->SetChecked(checked
)) {
210 *error
= kCheckedError
;
213 radio_item_updated
= true;
218 if (update_properties
.enabled
.get())
219 item
->set_enabled(*update_properties
.enabled
);
222 MenuItem::ContextList contexts
;
223 if (update_properties
.contexts
.get()) {
224 contexts
= GetContexts(*update_properties
.contexts
);
226 if (contexts
.Contains(MenuItem::LAUNCHER
)) {
227 // Launcher item is not allowed for <webview>.
228 if (!extension
->is_platform_app() || is_webview
) {
229 *error
= kLauncherNotAllowedError
;
234 if (contexts
!= item
->contexts())
235 item
->set_contexts(contexts
);
239 MenuItem
* parent
= NULL
;
240 scoped_ptr
<MenuItem::Id
> parent_id(GetParentId(
241 update_properties
, profile
->IsOffTheRecord(), item_id
.extension_key
));
242 if (parent_id
.get()) {
243 MenuItem
* parent
= GetParent(*parent_id
, menu_manager
, error
);
244 if (!parent
|| !menu_manager
->ChangeParent(item
->id(), &parent
->id()))
249 if (!item
->PopulateURLPatterns(
250 update_properties
.document_url_patterns
.get(),
251 update_properties
.target_url_patterns
.get(), error
)) {
255 // There is no need to call ItemUpdated if ChangeParent is called because
256 // all sanitation is taken care of in ChangeParent.
257 if (!parent
&& radio_item_updated
&& !menu_manager
->ItemUpdated(item
->id()))
260 menu_manager
->WriteToStorage(extension
, item_id
.extension_key
);
264 } // namespace context_menus_api_helpers
265 } // namespace extensions
267 #endif // CHROME_BROWSER_EXTENSIONS_API_CONTEXT_MENUS_CONTEXT_MENUS_API_HELPERS_H_