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

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: TestingFactoryFunction documentation Created 6 years, 4 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 "chrome/common/extensions/api/context_menus.h"
11 #include "content/public/common/context_menu_params.h" 12 #include "content/public/common/context_menu_params.h"
12 #include "extensions/browser/extension_system.h" 13 #include "extensions/browser/extension_system.h"
13 #include "ui/gfx/favicon_size.h" 14 #include "ui/gfx/favicon_size.h"
14 #include "ui/gfx/image/image.h" 15 #include "ui/gfx/image/image.h"
15 16
16 namespace extensions { 17 namespace extensions {
17 18
18 // static 19 // static
19 const size_t ContextMenuMatcher::kMaxExtensionItemTitleLength = 75; 20 const size_t ContextMenuMatcher::kMaxExtensionItemTitleLength = 75;
20 21
21 ContextMenuMatcher::ContextMenuMatcher( 22 ContextMenuMatcher::ContextMenuMatcher(
22 Profile* profile, 23 Profile* profile,
23 ui::SimpleMenuModel::Delegate* delegate, 24 ui::SimpleMenuModel::Delegate* delegate,
24 ui::SimpleMenuModel* menu_model, 25 ui::SimpleMenuModel* menu_model,
25 const base::Callback<bool(const MenuItem*)>& filter) 26 const base::Callback<bool(const MenuItem*)>& filter)
26 : profile_(profile), menu_model_(menu_model), delegate_(delegate), 27 : profile_(profile), menu_model_(menu_model), delegate_(delegate),
27 filter_(filter) { 28 filter_(filter) {
28 } 29 }
29 30
30 void ContextMenuMatcher::AppendExtensionItems( 31 void ContextMenuMatcher::AppendExtensionItems(
31 const MenuItem::ExtensionKey& extension_key, 32 const MenuItem::ExtensionKey& extension_key,
32 const base::string16& selection_text, 33 const base::string16& selection_text,
33 int* index) { 34 int* index,
35 bool is_action_menu) {
34 DCHECK_GE(*index, 0); 36 DCHECK_GE(*index, 0);
35 int max_index = 37 int max_index =
36 IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST - IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST; 38 IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST - IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST;
37 if (*index >= max_index) 39 if (*index >= max_index)
38 return; 40 return;
39 41
40 const Extension* extension = NULL; 42 const Extension* extension = NULL;
41 MenuItem::List items; 43 MenuItem::List items;
42 bool can_cross_incognito; 44 bool can_cross_incognito;
43 if (!GetRelevantExtensionTopLevelItems( 45 if (!GetRelevantExtensionTopLevelItems(
44 extension_key, &extension, &can_cross_incognito, items)) 46 extension_key, &extension, &can_cross_incognito, items))
45 return; 47 return;
46 48
47 if (items.empty()) 49 if (items.empty())
48 return; 50 return;
49 51
50 // If this is the first extension-provided menu item, and there are other 52 // 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. 53 // items in the menu, and the last item is not a separator add a separator.
52 if (*index == 0 && menu_model_->GetItemCount()) 54 if (*index == 0 && menu_model_->GetItemCount())
53 menu_model_->AddSeparator(ui::NORMAL_SEPARATOR); 55 menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
54 56
55 // Extensions (other than platform apps) are only allowed one top-level slot 57 // 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 58 // (and it can't be a radio or checkbox item because we are going to put the
57 // extension icon next to it). 59 // 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. 60 // Action menus do not include the extension action, and they only include
59 if (extension->is_platform_app()) { 61 // items from one extension, so they are not placed within a submenu.
60 RecursivelyAppendExtensionItems(items, can_cross_incognito, selection_text, 62 // Otherwise, we automatically push them into a submenu if there is more than
61 menu_model_, index); 63 // one top-level item.
64 if (extension->is_platform_app() || is_action_menu) {
65 RecursivelyAppendExtensionItems(items,
66 can_cross_incognito,
67 selection_text,
68 menu_model_,
69 index,
70 is_action_menu);
62 } else { 71 } else {
63 int menu_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + (*index)++; 72 int menu_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + (*index)++;
64 base::string16 title; 73 base::string16 title;
65 MenuItem::List submenu_items; 74 MenuItem::List submenu_items;
66 75
67 if (items.size() > 1 || items[0]->type() != MenuItem::NORMAL) { 76 if (items.size() > 1 || items[0]->type() != MenuItem::NORMAL) {
68 title = base::UTF8ToUTF16(extension->name()); 77 title = base::UTF8ToUTF16(extension->name());
69 submenu_items = items; 78 submenu_items = items;
70 } else { 79 } else {
71 MenuItem* item = items[0]; 80 MenuItem* item = items[0];
72 extension_item_map_[menu_id] = item->id(); 81 extension_item_map_[menu_id] = item->id();
73 title = item->TitleWithReplacement(selection_text, 82 title = item->TitleWithReplacement(selection_text,
74 kMaxExtensionItemTitleLength); 83 kMaxExtensionItemTitleLength);
75 submenu_items = GetRelevantExtensionItems(item->children(), 84 submenu_items = GetRelevantExtensionItems(item->children(),
76 can_cross_incognito); 85 can_cross_incognito);
77 } 86 }
78 87
79 // Now add our item(s) to the menu_model_. 88 // Now add our item(s) to the menu_model_.
80 if (submenu_items.empty()) { 89 if (submenu_items.empty()) {
81 menu_model_->AddItem(menu_id, title); 90 menu_model_->AddItem(menu_id, title);
82 } else { 91 } else {
83 ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(delegate_); 92 ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(delegate_);
84 extension_menu_models_.push_back(submenu); 93 extension_menu_models_.push_back(submenu);
85 menu_model_->AddSubMenu(menu_id, title, submenu); 94 menu_model_->AddSubMenu(menu_id, title, submenu);
86 RecursivelyAppendExtensionItems(submenu_items, can_cross_incognito, 95 RecursivelyAppendExtensionItems(submenu_items,
87 selection_text, submenu, index); 96 can_cross_incognito,
97 selection_text,
98 submenu,
99 index,
100 false); // is_action_menu_top_level
88 } 101 }
89 SetExtensionIcon(extension_key.extension_id); 102 if (!is_action_menu)
103 SetExtensionIcon(extension_key.extension_id);
90 } 104 }
91 } 105 }
92 106
93 void ContextMenuMatcher::Clear() { 107 void ContextMenuMatcher::Clear() {
94 extension_item_map_.clear(); 108 extension_item_map_.clear();
95 extension_menu_models_.clear(); 109 extension_menu_models_.clear();
96 } 110 }
97 111
98 base::string16 ContextMenuMatcher::GetTopLevelContextMenuTitle( 112 base::string16 ContextMenuMatcher::GetTopLevelContextMenuTitle(
99 const MenuItem::ExtensionKey& extension_key, 113 const MenuItem::ExtensionKey& extension_key,
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
184 result.push_back(*i); 198 result.push_back(*i);
185 } 199 }
186 return result; 200 return result;
187 } 201 }
188 202
189 void ContextMenuMatcher::RecursivelyAppendExtensionItems( 203 void ContextMenuMatcher::RecursivelyAppendExtensionItems(
190 const MenuItem::List& items, 204 const MenuItem::List& items,
191 bool can_cross_incognito, 205 bool can_cross_incognito,
192 const base::string16& selection_text, 206 const base::string16& selection_text,
193 ui::SimpleMenuModel* menu_model, 207 ui::SimpleMenuModel* menu_model,
194 int* index) 208 int* index,
195 { 209 bool is_action_menu_top_level) {
196 MenuItem::Type last_type = MenuItem::NORMAL; 210 MenuItem::Type last_type = MenuItem::NORMAL;
197 int radio_group_id = 1; 211 int radio_group_id = 1;
212 int num_items = 0;
198 213
199 for (MenuItem::List::const_iterator i = items.begin(); 214 for (MenuItem::List::const_iterator i = items.begin();
200 i != items.end(); ++i) { 215 i != items.end(); ++i) {
201 MenuItem* item = *i; 216 MenuItem* item = *i;
202 217
203 // If last item was of type radio but the current one isn't, auto-insert 218 // If last item was of type radio but the current one isn't, auto-insert
204 // a separator. The converse case is handled below. 219 // a separator. The converse case is handled below.
205 if (last_type == MenuItem::RADIO && 220 if (last_type == MenuItem::RADIO &&
206 item->type() != MenuItem::RADIO) { 221 item->type() != MenuItem::RADIO) {
207 menu_model->AddSeparator(ui::NORMAL_SEPARATOR); 222 menu_model->AddSeparator(ui::NORMAL_SEPARATOR);
208 last_type = MenuItem::SEPARATOR; 223 last_type = MenuItem::SEPARATOR;
209 } 224 }
210 225
211 int menu_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + (*index)++; 226 int menu_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + *index;
212 if (menu_id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) 227 ++num_items;
228 // Action context menus have a limit for top level extension items to
229 // prevent control items from being pushed off the screen, since extension
230 // items will not be placed in a submenu.
231 if (menu_id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST ||
232 (is_action_menu_top_level &&
233 num_items > api::context_menus::ACTION_MENU_TOP_LEVEL_LIMIT))
213 return; 234 return;
235 (*index)++;
Devlin 2014/07/29 20:49:45 nit: ++(*index);
gpdavis 2014/07/30 20:53:02 Done.
214 extension_item_map_[menu_id] = item->id(); 236 extension_item_map_[menu_id] = item->id();
215 base::string16 title = item->TitleWithReplacement(selection_text, 237 base::string16 title = item->TitleWithReplacement(selection_text,
216 kMaxExtensionItemTitleLength); 238 kMaxExtensionItemTitleLength);
217 if (item->type() == MenuItem::NORMAL) { 239 if (item->type() == MenuItem::NORMAL) {
218 MenuItem::List children = 240 MenuItem::List children =
219 GetRelevantExtensionItems(item->children(), can_cross_incognito); 241 GetRelevantExtensionItems(item->children(), can_cross_incognito);
220 if (children.empty()) { 242 if (children.empty()) {
221 menu_model->AddItem(menu_id, title); 243 menu_model->AddItem(menu_id, title);
222 } else { 244 } else {
223 ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(delegate_); 245 ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(delegate_);
224 extension_menu_models_.push_back(submenu); 246 extension_menu_models_.push_back(submenu);
225 menu_model->AddSubMenu(menu_id, title, submenu); 247 menu_model->AddSubMenu(menu_id, title, submenu);
226 RecursivelyAppendExtensionItems(children, can_cross_incognito, 248 RecursivelyAppendExtensionItems(children,
227 selection_text, submenu, index); 249 can_cross_incognito,
250 selection_text,
251 submenu,
252 index,
253 false); // is_action_menu_top_level
228 } 254 }
229 } else if (item->type() == MenuItem::CHECKBOX) { 255 } else if (item->type() == MenuItem::CHECKBOX) {
230 menu_model->AddCheckItem(menu_id, title); 256 menu_model->AddCheckItem(menu_id, title);
231 } else if (item->type() == MenuItem::RADIO) { 257 } else if (item->type() == MenuItem::RADIO) {
232 if (i != items.begin() && 258 if (i != items.begin() &&
233 last_type != MenuItem::RADIO) { 259 last_type != MenuItem::RADIO) {
234 radio_group_id++; 260 radio_group_id++;
235 261
236 // Auto-append a separator if needed. 262 // Auto-append a separator if needed.
237 menu_model->AddSeparator(ui::NORMAL_SEPARATOR); 263 menu_model->AddSeparator(ui::NORMAL_SEPARATOR);
(...skipping 26 matching lines...) Expand all
264 DCHECK_GE(index, 0); 290 DCHECK_GE(index, 0);
265 291
266 const SkBitmap& icon = menu_manager->GetIconForExtension(extension_id); 292 const SkBitmap& icon = menu_manager->GetIconForExtension(extension_id);
267 DCHECK(icon.width() == gfx::kFaviconSize); 293 DCHECK(icon.width() == gfx::kFaviconSize);
268 DCHECK(icon.height() == gfx::kFaviconSize); 294 DCHECK(icon.height() == gfx::kFaviconSize);
269 295
270 menu_model_->SetIcon(index, gfx::Image::CreateFrom1xBitmap(icon)); 296 menu_model_->SetIcon(index, gfx::Image::CreateFrom1xBitmap(icon));
271 } 297 }
272 298
273 } // namespace extensions 299 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698