Bug 2682 - [UI] EC: Can't contribute submenu items (1GI3XO6)
Summary: [UI] EC: Can't contribute submenu items (1GI3XO6)
Status: RESOLVED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 2.0   Edit
Hardware: All Windows 2000
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Unknown User CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2001-10-10 22:41 EDT by Nick Edgar CLA
Modified: 2005-01-18 16:45 EST (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Nick Edgar CLA 2001-10-10 22:41:23 EDT
EC post "Menus and submenus" by GB on Aug 2, 2001:

I am trying to create a cascading menu under my own menu.

MyMenu
Menu1->Submenu1
       Submenu2


I cannot get this to work.

I can, using the same technique as outlined in the help,  add the submenu
to the Window menu, and it works. 

Window
Menu1->Submenu1
       Submenu2

But when I try to add the submenu to my menu, the menu shows up but it is
grayed and none of the Submenu items are available. 

MyMenu
Menu1 (grayed)

The log reports
1 org.eclipse.core.resources 4 Invalid Menu Extension (Path is invalid):
SubMenu1Id

Here is the sample I based the code on. This is from the Eclipse
documentation.
<extension 
    point = "org.eclipse.ui.actionSets">
    <actionSet id="org_eclipse_ui_examples_readmetool_actionSet"
        label="ReadMe Actions"
        visible="true">
        <menu id="org_eclipse_ui_examples_readmetool"
            label="Readme &File Editor"
            path="window/additions"> 
            <separator name="slot1"/>
            <separator name="slot2"/>
            <separator name="slot3"/>
        </menu>
        <action id="org_eclipse_ui_examples_readmetool_readmeAction"
            menubarPath="window/org_eclipse_ui_examples_readmetool/slot1"
            toolbarPath="readme"
            label="&Open Readme Browser@Ctrl+R"
            tooltip="Open Readme Browser"
           
helpContextId="org.eclipse.ui.examples.readmetool.open_browser_action_context"
            icon="icons/basic/ctool16/openbrwsr.gif"
            class="org.eclipse.ui.examples.readmetool.WindowActionDelegate"
            enablesFor="1">
            <selection class="org.eclipse.core.resources.IFile"
                name="*.readme">
            </selection>

Here is a version that I got to work in my own application.

<actionSet
   id="com.rational.test.ft.wswplugin.TestActionSet"
    visible="true"
   label="MyMenu">
   <menu
    id = "MyMenuId"
    label = "&MyMenu">
    <separator name = "Menu1Slot" />
   </menu>
   <menu id="Menu1Id"
    label = "&Menu1"
    path ="window/additions">
    <separator name="slot1" />
    <separator name="slot2" />
    <separator name="slot3" />
   </menu>
   <action
    id = "SubMenu1Id"
    menubarPath = "window/Menu1Id/slot1"
    label = "&SubMenu1"
    class = "com.rational.test.ft.wswplugin.x">
   </action>


Here is a version that fails in my application. The only difference is
that instead of window, I use MyMenu and instead of additions, I use
MyMenu1Slot. I tried variations on ids and slots, but nothing changed.

<actionSet
   id="com.rational.test.ft.wswplugin.TestActionSet"
    visible="true"
   label="MyMenu">
   <menu
    id = "MyMenuId"
    label = "&MyMenu">
    <separator name = "Menu1Slot" />
   </menu>
   <menu id="Menu1Id"
    label = "&Menu1"
    path ="MyMenuId/Menu1Slot">
    <separator name="slot1" />
    <separator name="slot2" />
    <separator name="slot3" />
   </menu>
   <action
    id = "SubMenu1Id"
    menubarPath = "MyMenuId/Menu1Id/slot1"
    label = "&SubMenu1"
    class = "com.rational.test.ft.wswplugin.x">
   </action>


NOTES:

NE (8/7/01 5:25:18 PM)	
	Reproduced both success case and fail case.
	Problem is that the call to parent.findMenuUsingPath(mpath) in 
PlugActionSetBuilder.contributeMenuAction()
	returns null when mpath has multiple segments.
	This is because SubMenuManager.findUsingPath calls findUsingPath on the 
parentMgr,
	and MenuManager.findUsingPath tests whether the parent menu is an 
IMenuManager,
	which it is not in this case.  It was wrapped in an 
ActionSetContributionItem (subclass of SubContributionItem).
	Should change SubMenuManager.findUsingPath to recurse itself, 
unwrapping at each stage.

NE (08/07/01 6:01:14 PM)
	Suggested fix:

Change SubContributionManager.find() to unwrap (it doesn't currently, but 
should):
public IContributionItem find(String id) {
	IContributionItem item = parentMgr.find(id);
	if (item instanceof SubContributionItem) {
		return ((SubContributionItem)item).getInnerItem();
	} else {
		return item;
	}
}

Change SubMenuManager.getWrapper(IMenuManager) to always create wrapper (as 
spec'ed).
Also added @param tag:

/**
 * Returns the menu wrapper for a menu manager.
 * <p>
 * The sub menus within this menu are wrapped within a 
<code>SubMenuManager</code> to
 * monitor additions and removals.  If the visibility of this menu is modified
 * the visibility of the sub menus is also modified.
 * <p>
 *
 * @param menu the menu manager to wrap
 * @return the menu wrapper
 */
private IMenuManager getWrapper(IMenuManager menu) {
	if (mapMenuToWrapper == null) {
		mapMenuToWrapper = new HashMap(4);
	}
	SubMenuManager wrapper = (SubMenuManager) mapMenuToWrapper.get(menu);
	if (wrapper == null) {
		wrapper = wrapMenu(menu);
		mapMenuToWrapper.put(menu, wrapper);
	}
	return wrapper;
}

Change SubMenuManager.findMenuUsingPath to just call getWrapper() rather than 
getWrapper then putWrapper if null:
public IMenuManager findMenuUsingPath(String path) {
	IContributionItem item = findUsingPath(path);
	if (item instanceof IMenuManager) {
		IMenuManager menu = (IMenuManager)item;
		return getWrapper(menu);
	}
	return null;
}

Change SubMenuManager.findUsingPath to use same algorithm as 
MenuManager.findUsingPath, but wrapping
submenus along the way:
public IContributionItem findUsingPath(String path) {
	String id = path;
	String rest = null;
	int separator = path.indexOf('/');
	if (separator != -1) {
		id = path.substring(0, separator);
		rest = path.substring(separator + 1);
	}
	IContributionItem item = find(id); // unwraps item
	if (rest != null && item instanceof IMenuManager) {
		IMenuManager menu = (IMenuManager) item;
		// wrap menu, just like findMenuUsingPath
		IMenuManager wrapper = getWrapper(menu);
		return wrapper.findUsingPath(rest);
	}
	return item;
}

Delete SubMenuManager.putWrapper -- it's no longer needed.
Comment 1 Unknown User CLA 2001-10-15 12:30:12 EDT
This is fixed.  Changes were made to SubContributionManager, SubMenuManager, 
and ActionSetMenuManager.

To test I created the following action sets.  The first is for this bug.  The 
2nd, third and fourth are for a problem reported by a customer (can't find pr), 
where you turn on A, B, and C, turn off A, turn on A and off B, then turn on B 
and off C.  At this point B used to disappear also.  

<extension point = "org.eclipse.ui.actionSets">
	<actionSet
	   id="com.rational.test.ft.wswplugin.TestActionSet"
	    visible="true"
	   label="MyMenu">
	   <menu
	    id = "MyMenuId"
	    label = "&MyMenu">
	    <separator name = "Menu1Slot" />
	   </menu>
	   <menu id="Menu1Id"
	    label = "&Menu1"
	    path ="MyMenuId/Menu1Slot">
	    <separator name="slot1" />
	    <separator name="slot2" />
	    <separator name="slot3" />
	   </menu>
	   <action
	    id = "SubMenu1Id"
	    menubarPath = "MyMenuId/Menu1Id/slot1"
	    label = "&SubMenu1"
	    class = "com.rational.test.ft.wswplugin.x">
	   </action>
	   <action
	    id = "SubMenu2Id"
	    menubarPath = "MyMenuId/Menu1Id/slot1"
	    label = "&SubMenu2"
	    class = "com.rational.test.ft.wswplugin.x">
	   </action>
	   <action
	    id = "SubMenu3Id"
	    menubarPath = "MyMenuId/Menu1Id/slot1"
	    label = "&SubMenu3"
	    class = "com.rational.test.ft.wswplugin.x">
	   </action>
	</actionSet>
</extension>

<extension point = "org.eclipse.ui.actionSets">
	<actionSet
	   id="com.rational.test.ft.wswplugin.TestActionSetA"
	   label="A">
	   <menu
	    id = "Top"
	    label = "&Top">
	    <separator name = "a" />
	    <separator name = "b" />
	    <separator name = "c" />
	   </menu>
	   <action
	    id = "SubMenu1Id"
	    menubarPath = "Top/a"
	    label = "a"
	    class = "com.rational.test.ft.wswplugin.x">
	   </action>
	</actionSet>
</extension>

<extension point = "org.eclipse.ui.actionSets">
	<actionSet
	   id="com.rational.test.ft.wswplugin.TestActionSetB"
	   label="B">
	   <menu
	    id = "Top"
	    label = "&Top">
	    <separator name = "a" />
	    <separator name = "b" />
	    <separator name = "c" />
	   </menu>
	   <action
	    id = "SubMenu1Id"
	    menubarPath = "Top/b"
	    label = "b"
	    class = "com.rational.test.ft.wswplugin.x">
	   </action>
	</actionSet>
</extension>

<extension point = "org.eclipse.ui.actionSets">
	<actionSet
	   id="com.rational.test.ft.wswplugin.TestActionSetC"
	   label="C">
	   <menu
	    id = "Top"
	    label = "&Top">
	    <separator name = "a" />
	    <separator name = "b" />
	    <separator name = "c" />
	   </menu>
	   <action
	    id = "SubMenu1Id"
	    menubarPath = "Top/c"
	    label = "c"
	    class = "com.rational.test.ft.wswplugin.x">
	   </action>
	</actionSet>
</extension>

Note: I applied all of NEs changes except for one change in findUsingPath. 
In this code he will wrap any submenu which we drill into.  I decided not to do 
this.  There is no reason to wrap a menu unless the user adds a contribution to 
it.  We assume this is only the case when findMenuUsingPath is called, and do 
the wrapping there.  Thus, the SubMenuManager only wraps those subs which are 
modified.  
Comment 2 DJ Houghton CLA 2001-10-29 19:09:22 EST
PRODUCT VERSION:
0.9