summaryrefslogtreecommitdiffstats
path: root/chrome/browser/tab_contents
diff options
context:
space:
mode:
authorasargent@chromium.org <asargent@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-06-03 23:20:49 +0000
committerasargent@chromium.org <asargent@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-06-03 23:20:49 +0000
commit63a414b5568551333549e0147b7bb77e8a0b329c (patch)
tree27515161ccd8ebfb7de557b2c7a93b0d0cbb0f66 /chrome/browser/tab_contents
parent23607ccf23fce3ea302ba779a41e102fc3462dea (diff)
downloadchromium_src-63a414b5568551333549e0147b7bb77e8a0b329c.zip
chromium_src-63a414b5568551333549e0147b7bb77e8a0b329c.tar.gz
chromium_src-63a414b5568551333549e0147b7bb77e8a0b329c.tar.bz2
Fix submenu support for extensions context menu API.
This fixes submenus which broke on all platforms during a recent refactor of the RenderViewContextMenu class, and adds support for more than one level of child menus. BUG=39504 TEST=Create a test extension using the chrome.experimental.contextMenu API and add multiple levels of child menu items. Review URL: http://codereview.chromium.org/2443002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@48892 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/tab_contents')
-rw-r--r--chrome/browser/tab_contents/render_view_context_menu.cc154
-rw-r--r--chrome/browser/tab_contents/render_view_context_menu.h9
2 files changed, 87 insertions, 76 deletions
diff --git a/chrome/browser/tab_contents/render_view_context_menu.cc b/chrome/browser/tab_contents/render_view_context_menu.cc
index cc54c27..d3ea7d6 100644
--- a/chrome/browser/tab_contents/render_view_context_menu.cc
+++ b/chrome/browser/tab_contents/render_view_context_menu.cc
@@ -62,7 +62,12 @@ bool RenderViewContextMenu::IsSyncResourcesURL(const GURL& url) {
}
static const int kSpellcheckRadioGroup = 1;
-static const int kExtensionsRadioGroup = 2;
+
+// For extensions that have multiple top level menu items, we automatically
+// create a submenu item and push the top level menu items into it. This special
+// value takes the place of the ExtensionMenuItem's internal ID for the submenu
+// item inside the extension_item_map_ member variable.
+static const int kExtensionTopLevelItem = -1;
RenderViewContextMenu::RenderViewContextMenu(
TabContents* tab_contents,
@@ -122,97 +127,84 @@ static bool ExtensionContextMatch(ContextMenuParams params,
return false;
}
-void RenderViewContextMenu::GetItemsForExtension(
- const std::string& extension_id,
- std::vector<const ExtensionMenuItem*>* items) {
- ExtensionsService* service = profile_->GetExtensionsService();
-
- // Get the set of possible items, and iterate to find which ones are
- // applicable.
- std::vector<const ExtensionMenuItem*> potential_items =
- service->menu_manager()->MenuItems(extension_id);
-
- std::vector<const ExtensionMenuItem*>::const_iterator i;
- for (i = potential_items.begin(); i != potential_items.end(); ++i) {
- const ExtensionMenuItem* item = *i;
- if (ExtensionContextMatch(params_, item->contexts()))
- items->push_back(item);
+// Given a list of items, returns the ones that match given the contents
+// of |params|.
+static ExtensionMenuItem::List GetRelevantExtensionItems(
+ const ExtensionMenuItem::List& items,
+ ContextMenuParams params) {
+ ExtensionMenuItem::List result;
+ for (ExtensionMenuItem::List::const_iterator i = items.begin();
+ i != items.end(); ++i) {
+ if (ExtensionContextMatch(params, (*i)->contexts()))
+ result.push_back(*i);
}
+ return result;
}
void RenderViewContextMenu::AppendExtensionItems(
const std::string& extension_id, int* index) {
- Extension* extension =
- profile_->GetExtensionsService()->GetExtensionById(extension_id, false);
+ ExtensionsService* service = profile_->GetExtensionsService();
+ ExtensionMenuManager* manager = service->menu_manager();
+ Extension* extension = service->GetExtensionById(extension_id, false);
DCHECK_GE(*index, 0);
int max_index =
IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST - IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST;
if (!extension || *index >= max_index)
return;
- std::vector<const ExtensionMenuItem*> items;
- GetItemsForExtension(extension_id, &items);
+ // Find matching items.
+ const ExtensionMenuItem::List* all_items = manager->MenuItems(extension_id);
+ if (!all_items || all_items->empty())
+ return;
+ ExtensionMenuItem::List items =
+ GetRelevantExtensionItems(*all_items, params_);
if (items.empty())
return;
- string16 selection_text = PrintableSelectionText();
-
// If this is the first extension-provided menu item, add a separator.
if (*index == 0)
menu_model_.AddSeparator();
- // When extensions have more than 1 top-level item or a single parent item
- // with children, we will start a sub menu. In the case of 1 parent with
- // children, we will remove the parent from |items| and insert the children
- // into it. The |index| parameter is incremented if we start a submenu. This
- // returns true if a submenu was started. If we had multiple top-level items
- // that needed to be pushed into a submenu, we'll use |extension_name| as the
- // title.
- menus::SimpleMenuModel* menu_model;
- if (items.empty() || (items.size() == 1 && items[0]->child_count() == 0)) {
- menu_model = &menu_model_;
+ int menu_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + (*index)++;
+
+ // Extensions are only allowed one top-level slot (and it can't be a radio or
+ // checkbox item because we are going to put the extension icon next to it).
+ // If they have more than that, we automatically push them into a submenu.
+ string16 title;
+ ExtensionMenuItem::List submenu_items;
+ if (items.size() > 1 || items[0]->type() != ExtensionMenuItem::NORMAL) {
+ title = UTF8ToUTF16(extension->name());
+ extension_item_map_[menu_id] = kExtensionTopLevelItem;
+ submenu_items = items;
} else {
- menu_model = new menus::SimpleMenuModel(this);
- extension_menu_models_.push_back(menu_model);
-
- int menu_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + (*index)++;
- string16 title;
- if (items[0]->child_count() > 0) {
- title = items[0]->TitleWithReplacement(selection_text);
- extension_item_map_[menu_id] = items[0]->id();
- } else {
- title = UTF8ToUTF16(extension->name());
- }
+ ExtensionMenuItem* item = items[0];
+ extension_item_map_[menu_id] = item->id();
+ title = item->TitleWithReplacement(PrintableSelectionText());
+ submenu_items = GetRelevantExtensionItems(item->children(), params_);
+ }
- menu_model_.AddSubMenu(menu_id, title, menu_model);
-
- // If we have 1 parent item with a submenu of children, pull the
- // parent out of |items| and put the children in.
- if (items.size() == 1 && items[0]->child_count() > 0) {
- const ExtensionMenuItem* parent = items[0];
- items.clear();
- for (int j = 0; j < parent->child_count(); j++) {
- const ExtensionMenuItem* child = parent->ChildAt(j);
- if (ExtensionContextMatch(params_, child->contexts()))
- items.push_back(child);
- }
- }
+ // Now add our item(s) to the menu_model_.
+ if (submenu_items.empty()) {
+ menu_model_.AddItem(menu_id, title);
+ } else {
+ menus::SimpleMenuModel* submenu = new menus::SimpleMenuModel(this);
+ extension_menu_models_.push_back(submenu);
+ menu_model_.AddSubMenu(menu_id, title, submenu);
+ RecursivelyAppendExtensionItems(submenu_items, submenu, index);
}
+}
+void RenderViewContextMenu::RecursivelyAppendExtensionItems(
+ const ExtensionMenuItem::List& items,
+ menus::SimpleMenuModel* menu_model,
+ int *index) {
+ string16 selection_text = PrintableSelectionText();
ExtensionMenuItem::Type last_type = ExtensionMenuItem::NORMAL;
- int radio_group_id = kExtensionsRadioGroup;
- for (std::vector<const ExtensionMenuItem*>::iterator i = items.begin();
+ int radio_group_id = 1;
+
+ for (ExtensionMenuItem::List::const_iterator i = items.begin();
i != items.end(); ++i) {
- const ExtensionMenuItem* item = *i;
- if (item->type() == ExtensionMenuItem::SEPARATOR) {
- // We don't want the case of an extension with one top-level item that is
- // just a separator, so make sure this is inside a submenu.
- if (menu_model != &menu_model_) {
- menu_model->AddSeparator();
- last_type = ExtensionMenuItem::SEPARATOR;
- }
- continue;
- }
+ ExtensionMenuItem* item = *i;
// Auto-prepend a separator, if needed, to visually group radio items
// together.
@@ -229,7 +221,16 @@ void RenderViewContextMenu::AppendExtensionItems(
extension_item_map_[menu_id] = item->id();
string16 title = item->TitleWithReplacement(selection_text);
if (item->type() == ExtensionMenuItem::NORMAL) {
- menu_model->AddItem(menu_id, title);
+ ExtensionMenuItem::List children =
+ GetRelevantExtensionItems(item->children(), params_);
+ if (children.size() == 0) {
+ menu_model->AddItem(menu_id, title);
+ } else {
+ menus::SimpleMenuModel* submenu = new menus::SimpleMenuModel(this);
+ extension_menu_models_.push_back(submenu);
+ menu_model->AddSubMenu(menu_id, title, submenu);
+ RecursivelyAppendExtensionItems(children, submenu, index);
+ }
} else if (item->type() == ExtensionMenuItem::CHECKBOX) {
menu_model->AddCheckItem(menu_id, title);
} else if (item->type() == ExtensionMenuItem::RADIO) {
@@ -680,11 +681,18 @@ bool RenderViewContextMenu::IsCommandIdEnabled(int id) const {
// Extension items.
if (id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST &&
id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) {
- ExtensionMenuItem* item = GetExtensionMenuItem(id);
- if (item)
- return ExtensionContextMatch(params_, item->enabled_contexts());
- else
+ std::map<int, int>::const_iterator i = extension_item_map_.find(id);
+
+ // Unknown item.
+ if (i == extension_item_map_.end())
return false;
+
+ // Auto-inserted top-level extension parent.
+ if (i->second == kExtensionTopLevelItem)
+ return true;
+
+ return ExtensionContextMatch(params_,
+ GetExtensionMenuItem(id)->enabled_contexts());
}
switch (id) {
diff --git a/chrome/browser/tab_contents/render_view_context_menu.h b/chrome/browser/tab_contents/render_view_context_menu.h
index fd264ff..97d0d5c 100644
--- a/chrome/browser/tab_contents/render_view_context_menu.h
+++ b/chrome/browser/tab_contents/render_view_context_menu.h
@@ -80,15 +80,18 @@ class RenderViewContextMenu : public menus::SimpleMenuModel::Delegate {
void AppendSpellcheckOptionsSubMenu();
// Add writing direction sub menu (only used on Mac).
void AppendBidiSubMenu();
- // Fills in |items| with matching items for extension with |extension_id|.
- void GetItemsForExtension(const std::string& extension_id,
- std::vector<const ExtensionMenuItem*>* items);
// This is a helper function to append items for one particular extension.
// The |index| parameter is used for assigning id's, and is incremented for
// each item actually added.
void AppendExtensionItems(const std::string& extension_id, int* index);
+ // Used for recursively adding submenus of extension items.
+ void RecursivelyAppendExtensionItems(
+ const std::vector<ExtensionMenuItem*>& items,
+ menus::SimpleMenuModel* menu_model,
+ int *index);
+
// Opens the specified URL string in a new tab. If |in_current_window| is
// false, a new window is created to hold the new tab.
void OpenURL(const GURL& url,