Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(174)

Side by Side Diff: chrome/browser/extensions/context_menu_matcher.cc

Issue 359493005: Extend contextMenus API to support browser/page actions (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Small changes, formatting Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/strings/utf_string_conversions.h" 5 #include "base/strings/utf_string_conversions.h"
6 #include "chrome/app/chrome_command_ids.h" 6 #include "chrome/app/chrome_command_ids.h"
7 #include "chrome/browser/extensions/context_menu_matcher.h" 7 #include "chrome/browser/extensions/context_menu_matcher.h"
8 #include "chrome/browser/extensions/extension_service.h" 8 #include "chrome/browser/extensions/extension_service.h"
9 #include "chrome/browser/extensions/extension_util.h" 9 #include "chrome/browser/extensions/extension_util.h"
10 #include "chrome/browser/profiles/profile.h" 10 #include "chrome/browser/profiles/profile.h"
11 #include "content/public/common/context_menu_params.h" 11 #include "content/public/common/context_menu_params.h"
12 #include "extensions/browser/extension_system.h" 12 #include "extensions/browser/extension_system.h"
13 #include "ui/gfx/favicon_size.h" 13 #include "ui/gfx/favicon_size.h"
14 #include "ui/gfx/image/image.h" 14 #include "ui/gfx/image/image.h"
15 15
16 namespace extensions { 16 namespace extensions {
17 namespace api {
18 namespace context_menus {
19
20 extern const int ACTION_MENU_TOP_LEVEL_LIMIT;
Yoyo Zhou 2014/07/22 00:44:32 Why not include the generated chrome/common/extens
gpdavis 2014/07/22 18:52:52 Ah, that is more convenient. I wasn't sure exactl
21
22 } // namespace context_menus
23 } // namespace api
17 24
18 // static 25 // static
19 const size_t ContextMenuMatcher::kMaxExtensionItemTitleLength = 75; 26 const size_t ContextMenuMatcher::kMaxExtensionItemTitleLength = 75;
20 27
21 ContextMenuMatcher::ContextMenuMatcher( 28 ContextMenuMatcher::ContextMenuMatcher(
22 Profile* profile, 29 Profile* profile,
23 ui::SimpleMenuModel::Delegate* delegate, 30 ui::SimpleMenuModel::Delegate* delegate,
24 ui::SimpleMenuModel* menu_model, 31 ui::SimpleMenuModel* menu_model,
25 const base::Callback<bool(const MenuItem*)>& filter) 32 const base::Callback<bool(const MenuItem*)>& filter)
26 : profile_(profile), menu_model_(menu_model), delegate_(delegate), 33 : profile_(profile), menu_model_(menu_model), delegate_(delegate),
27 filter_(filter) { 34 filter_(filter) {
28 } 35 }
29 36
30 void ContextMenuMatcher::AppendExtensionItems( 37 void ContextMenuMatcher::AppendExtensionItems(
31 const MenuItem::ExtensionKey& extension_key, 38 const MenuItem::ExtensionKey& extension_key,
32 const base::string16& selection_text, 39 const base::string16& selection_text,
33 int* index) { 40 int* index,
41 bool is_action_menu) {
34 DCHECK_GE(*index, 0); 42 DCHECK_GE(*index, 0);
35 int max_index = 43 int max_index =
36 IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST - IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST; 44 IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST - IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST;
37 if (*index >= max_index) 45 if (*index >= max_index)
38 return; 46 return;
39 47
40 const Extension* extension = NULL; 48 const Extension* extension = NULL;
41 MenuItem::List items; 49 MenuItem::List items;
42 bool can_cross_incognito; 50 bool can_cross_incognito;
43 if (!GetRelevantExtensionTopLevelItems( 51 if (!GetRelevantExtensionTopLevelItems(
44 extension_key, &extension, &can_cross_incognito, items)) 52 extension_key, &extension, &can_cross_incognito, items))
45 return; 53 return;
46 54
47 if (items.empty()) 55 if (items.empty())
48 return; 56 return;
49 57
50 // If this is the first extension-provided menu item, and there are other 58 // If this is the first extension-provided menu item, and there are other
51 // items in the menu, and the last item is not a separator add a separator. 59 // items in the menu, and the last item is not a separator add a separator.
52 if (*index == 0 && menu_model_->GetItemCount()) 60 if (*index == 0 && menu_model_->GetItemCount())
53 menu_model_->AddSeparator(ui::NORMAL_SEPARATOR); 61 menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
54 62
55 // Extensions (other than platform apps) are only allowed one top-level slot 63 // Extensions (other than platform apps) are only allowed one top-level slot
56 // (and it can't be a radio or checkbox item because we are going to put the 64 // (and it can't be a radio or checkbox item because we are going to put the
57 // extension icon next to it). 65 // extension icon next to it), unless the context menu is an an action menu.
58 // If they have more than that, we automatically push them into a submenu. 66 // Action menus only include items from one extension, and do not include the
Yoyo Zhou 2014/07/22 00:44:32 Rewrite this: Action menus do not include the exte
gpdavis 2014/07/22 18:52:52 Done.
59 if (extension->is_platform_app()) { 67 // extension icon, so they are not placed within a submenu. Otherwise, we
60 RecursivelyAppendExtensionItems(items, can_cross_incognito, selection_text, 68 // automatically push them into a submenu if there is more than one top-level
61 menu_model_, index); 69 // item.
70 if (extension->is_platform_app() || is_action_menu) {
71 RecursivelyAppendExtensionItems(items,
72 can_cross_incognito,
73 selection_text,
74 menu_model_,
75 index,
76 is_action_menu);
62 } else { 77 } else {
63 int menu_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + (*index)++; 78 int menu_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + (*index)++;
64 base::string16 title; 79 base::string16 title;
65 MenuItem::List submenu_items; 80 MenuItem::List submenu_items;
66 81
67 if (items.size() > 1 || items[0]->type() != MenuItem::NORMAL) { 82 if (items.size() > 1 || items[0]->type() != MenuItem::NORMAL) {
68 title = base::UTF8ToUTF16(extension->name()); 83 title = base::UTF8ToUTF16(extension->name());
69 submenu_items = items; 84 submenu_items = items;
70 } else { 85 } else {
71 MenuItem* item = items[0]; 86 MenuItem* item = items[0];
72 extension_item_map_[menu_id] = item->id(); 87 extension_item_map_[menu_id] = item->id();
73 title = item->TitleWithReplacement(selection_text, 88 title = item->TitleWithReplacement(selection_text,
74 kMaxExtensionItemTitleLength); 89 kMaxExtensionItemTitleLength);
75 submenu_items = GetRelevantExtensionItems(item->children(), 90 submenu_items = GetRelevantExtensionItems(item->children(),
76 can_cross_incognito); 91 can_cross_incognito);
77 } 92 }
78 93
79 // Now add our item(s) to the menu_model_. 94 // Now add our item(s) to the menu_model_.
80 if (submenu_items.empty()) { 95 if (submenu_items.empty()) {
81 menu_model_->AddItem(menu_id, title); 96 menu_model_->AddItem(menu_id, title);
82 } else { 97 } else {
83 ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(delegate_); 98 ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(delegate_);
84 extension_menu_models_.push_back(submenu); 99 extension_menu_models_.push_back(submenu);
85 menu_model_->AddSubMenu(menu_id, title, submenu); 100 menu_model_->AddSubMenu(menu_id, title, submenu);
86 RecursivelyAppendExtensionItems(submenu_items, can_cross_incognito, 101 RecursivelyAppendExtensionItems(submenu_items,
87 selection_text, submenu, index); 102 can_cross_incognito,
103 selection_text,
104 submenu,
105 index,
106 false);
88 } 107 }
89 SetExtensionIcon(extension_key.extension_id); 108 if (!is_action_menu)
109 SetExtensionIcon(extension_key.extension_id);
90 } 110 }
91 } 111 }
92 112
93 void ContextMenuMatcher::Clear() { 113 void ContextMenuMatcher::Clear() {
94 extension_item_map_.clear(); 114 extension_item_map_.clear();
95 extension_menu_models_.clear(); 115 extension_menu_models_.clear();
96 } 116 }
97 117
98 base::string16 ContextMenuMatcher::GetTopLevelContextMenuTitle( 118 base::string16 ContextMenuMatcher::GetTopLevelContextMenuTitle(
99 const MenuItem::ExtensionKey& extension_key, 119 const MenuItem::ExtensionKey& extension_key,
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
184 result.push_back(*i); 204 result.push_back(*i);
185 } 205 }
186 return result; 206 return result;
187 } 207 }
188 208
189 void ContextMenuMatcher::RecursivelyAppendExtensionItems( 209 void ContextMenuMatcher::RecursivelyAppendExtensionItems(
190 const MenuItem::List& items, 210 const MenuItem::List& items,
191 bool can_cross_incognito, 211 bool can_cross_incognito,
192 const base::string16& selection_text, 212 const base::string16& selection_text,
193 ui::SimpleMenuModel* menu_model, 213 ui::SimpleMenuModel* menu_model,
194 int* index) 214 int* index,
195 { 215 bool is_action_menu_top_level) {
196 MenuItem::Type last_type = MenuItem::NORMAL; 216 MenuItem::Type last_type = MenuItem::NORMAL;
197 int radio_group_id = 1; 217 int radio_group_id = 1;
218 int num_items = 0;
198 219
199 for (MenuItem::List::const_iterator i = items.begin(); 220 for (MenuItem::List::const_iterator i = items.begin();
200 i != items.end(); ++i) { 221 i != items.end(); ++i) {
201 MenuItem* item = *i; 222 MenuItem* item = *i;
202 223
203 // If last item was of type radio but the current one isn't, auto-insert 224 // If last item was of type radio but the current one isn't, auto-insert
204 // a separator. The converse case is handled below. 225 // a separator. The converse case is handled below.
205 if (last_type == MenuItem::RADIO && 226 if (last_type == MenuItem::RADIO &&
206 item->type() != MenuItem::RADIO) { 227 item->type() != MenuItem::RADIO) {
207 menu_model->AddSeparator(ui::NORMAL_SEPARATOR); 228 menu_model->AddSeparator(ui::NORMAL_SEPARATOR);
208 last_type = MenuItem::SEPARATOR; 229 last_type = MenuItem::SEPARATOR;
209 } 230 }
210 231
211 int menu_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + (*index)++; 232 int menu_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + *index;
212 if (menu_id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) 233 num_items++;
234 // Action context menus have a limit for top level extension items to
235 // prevent control items from being pushed off the screen, since extension
236 // items will not be placed in a submenu.
237 if (menu_id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST ||
238 (is_action_menu_top_level &&
239 num_items > api::context_menus::ACTION_MENU_TOP_LEVEL_LIMIT))
213 return; 240 return;
241 (*index)++;
214 extension_item_map_[menu_id] = item->id(); 242 extension_item_map_[menu_id] = item->id();
215 base::string16 title = item->TitleWithReplacement(selection_text, 243 base::string16 title = item->TitleWithReplacement(selection_text,
216 kMaxExtensionItemTitleLength); 244 kMaxExtensionItemTitleLength);
217 if (item->type() == MenuItem::NORMAL) { 245 if (item->type() == MenuItem::NORMAL) {
218 MenuItem::List children = 246 MenuItem::List children =
219 GetRelevantExtensionItems(item->children(), can_cross_incognito); 247 GetRelevantExtensionItems(item->children(), can_cross_incognito);
220 if (children.empty()) { 248 if (children.empty()) {
221 menu_model->AddItem(menu_id, title); 249 menu_model->AddItem(menu_id, title);
222 } else { 250 } else {
223 ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(delegate_); 251 ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(delegate_);
224 extension_menu_models_.push_back(submenu); 252 extension_menu_models_.push_back(submenu);
225 menu_model->AddSubMenu(menu_id, title, submenu); 253 menu_model->AddSubMenu(menu_id, title, submenu);
226 RecursivelyAppendExtensionItems(children, can_cross_incognito, 254 RecursivelyAppendExtensionItems(children,
227 selection_text, submenu, index); 255 can_cross_incognito,
256 selection_text,
257 submenu,
258 index,
259 false);
228 } 260 }
229 } else if (item->type() == MenuItem::CHECKBOX) { 261 } else if (item->type() == MenuItem::CHECKBOX) {
230 menu_model->AddCheckItem(menu_id, title); 262 menu_model->AddCheckItem(menu_id, title);
231 } else if (item->type() == MenuItem::RADIO) { 263 } else if (item->type() == MenuItem::RADIO) {
232 if (i != items.begin() && 264 if (i != items.begin() &&
233 last_type != MenuItem::RADIO) { 265 last_type != MenuItem::RADIO) {
234 radio_group_id++; 266 radio_group_id++;
235 267
236 // Auto-append a separator if needed. 268 // Auto-append a separator if needed.
237 menu_model->AddSeparator(ui::NORMAL_SEPARATOR); 269 menu_model->AddSeparator(ui::NORMAL_SEPARATOR);
(...skipping 26 matching lines...) Expand all
264 DCHECK_GE(index, 0); 296 DCHECK_GE(index, 0);
265 297
266 const SkBitmap& icon = menu_manager->GetIconForExtension(extension_id); 298 const SkBitmap& icon = menu_manager->GetIconForExtension(extension_id);
267 DCHECK(icon.width() == gfx::kFaviconSize); 299 DCHECK(icon.width() == gfx::kFaviconSize);
268 DCHECK(icon.height() == gfx::kFaviconSize); 300 DCHECK(icon.height() == gfx::kFaviconSize);
269 301
270 menu_model_->SetIcon(index, gfx::Image::CreateFrom1xBitmap(icon)); 302 menu_model_->SetIcon(index, gfx::Image::CreateFrom1xBitmap(icon));
271 } 303 }
272 304
273 } // namespace extensions 305 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698