Using advanced features in Eclipse popup menus
One of the first Hello World examples when dealing with contributions to Eclipse extension points is adding an objectContribution or a viewerContribution to a popup menu. However, if one wants to add a more flexible contribution which is hided or disabled in certain circumstances, documentation gets rare.
This article describes how to implement these advanced featues by example. Let’s assume we have an EMF model of objects MyObject which implement a property called type. EMF can generate item and label providers for tree editors. Let’s assume we have implemented such an editor and we want to contribute an action which is only visible for a particular type value.
Update: This article uses the old API of contributing actions to views’ and objects’ popup menus. There is a new API which is described in another post.
As a first step we implement the corresponding ActionDelegate and register it as an object contribution: This
<extension point="org.eclipse.ui.popupMenus">
<objectContribution
adaptable="false"
id="my.contribution.id"
objectClass="my.model.MyObject">
<action
class="my.contribution.MyActionDelegate"
enablesFor="1"
id="my.contribution.action.id"
label="Do something only with type FOO"
menubarPath="additions">
</action>
</objectContribution>
</extension>
This way, however, the contribution is visible and enabled always. We want to hide (or disable) it, if selectedObject.getType() is not equal to "FOO". The popupMenus extension point lets us specify visibility and enablement constraints and we can use the objectState element to query the object’s state. However, this is not as simple as it sounds, because objectState can only query objects which implement the IActionFilter interface and since MyObject is a EMF generated class, we cannot simply implement the interface.
But what we can do, is adapt. So we write an adapter and its factory:
public class MyObjectToActionFilterAdapter implements IActionFilter {
private static final Object MYOBJECT_TYPE = "objectType";
private static ArtifactToActionFilterAdapter INSTANCE = new ArtifactToActionFilterAdapter();
private ArtifactToActionFilterAdapter() {}
@Override
public boolean testAttribute(Object target, String name, String value) {
if (target instanceof MyObject) {
MyObject obj = (MyObject) target;
if(MYOBJECT_TYPE.equals(name)) {
return value.equals(obj.getType());
}
}
return false;
}
public static ArtifactToActionFilterAdapter getInstance() {
return INSTANCE;
}
}
public class MyActionFilterAdapterFactory implements IAdapterFactory {
@SuppressWarnings("unchecked")
@Override
public Object getAdapter(Object adaptableObject, Class adapterType) {
if(adapterType == IActionFilter.class)
return MyObjectToActionFilterAdapter.getInstance();
return null;
}
@SuppressWarnings("unchecked")
@Override
public Class[] getAdapterList() {
return new Class[] {IActionFilter.class};
}
}
Note that the adapter can be implemented as a singleton because the testAttribute implementation is called with the object to be tested.
Now we have to register our adapter factory using:
<extension point="org.eclipse.core.runtime.adapters">
<factory
adaptableType="my.model.MyObject"
class="my.contribution.MyActionFilterAdapterFactory">
<adapter
type="org.eclipse.ui.IActionFilter">
</adapter>
</factory>
</extension>
and after that we are ready to declare our constraints:
<extension point="org.eclipse.ui.popupMenus">
<objectContribution
adaptable="false"
id="my.contribution.id"
objectClass="my.model.MyObject">
<action
class="my.contribution.MyActionDelegate"
enablesFor="1"
id="my.contribution.action.id"
label="Do something only with type FOO"
menubarPath="additions">
</action>
<visibility>
<objectState
name="objectType"
value="FOO">
</objectState>
</visibility>
</objectContribution>
</extension>
This causes the action to appear only if the property type of MyObject has the value FOO.
Instead of hiding the action, we can also disable it using the element <enablement> istead of <visibility>. In this case, however, the <enablement> constraint has to be a child of the <action> element instead of a sibling.
3 Comments
Leave a Comment
You must be logged in to post a comment.





robin · August 11th, 2008 at 2:19 pm #
If i am not wrong, the adapters will come into play after the action has been initialized ( the action needs to be executed once to get initialized ), which means the enablement will not work until an action is executed from the pop up menu. And if my above observation is true, is there any way to get the enablement work without the need of executing the action once from the menu??
TIA
xpomul · August 11th, 2008 at 2:48 pm #
Hmm … interesting. I only tried with visibility, which worked as expected. Maybe because it has a different location in the extension point XML structure.
As I tried to search the net for comments on this case, I found this eclipse help section, which states that the extension point org.eclipse.ui.popupMenus is legacy and that there is a new extension point org.eclipse.ui.menus which might address the problem more elegantly, because it separates location and enablement state.
If I have some time in the future, I’ll have a look at this extension point and I’ll post my experiences.
XPOMUL - The ruler of chaos » Blog Archive » Advanced features in Eclipse popup menus - Take 2: The new API · August 12th, 2008 at 4:14 pm #
[...] Robin’s comment on my earlier post I found the new API (Extension point description of org.eclipse.ui.menus) which unifies all command [...]