Friday, June 16, 2006

Building a Common Navigator based viewer, Part III: Configuring Menus

Action is eloquence.
Coriolanus, Act 3, Scene 2

In earlier posts, we walked through how to construct a Common Navigator Framework (CNF) viewer and a basic extension to render property files. Now we will walk through how to configure the menu for a CNF viewer and how to add actions to our viewer to manipulate our content.

Let's take a small step back though, and look at the current roadmap for upcoming posts:
  • Configuring CNF viewer popup menus (Part III). This post will describe how to configure the popup menu of a CNF viewer, how to describe the insertion points and separators for a popup menu, and how to toggle whether a CNF viewer honors the org.eclipse.ui.popupMenus extension point.

  • Adding Actions to a CNF viewer through Object Contributions (Part IV). Part IV will cover how to add actions through Object Contributions. Object Contributions allow you to add actions (and even define menu sub-structures) for specific object types. Object Contributions are not specific to CNF viewers, but they are useful for adding menu actions without alot of code.

  • Adding Actions to a CNF viewer through Action Providers (Part V). Part V will cover how to programmatically configure CNF menus and adjust the retagetable actions for the Workbench. In particularly, the example will cover how to add a custom Open action for individual property types.


There are two basic options for adding actions to a Common Navigator Framework (CNF) viewer:
  • Contribute actions using org.eclipse.ui.popupMenus as objectContributions or viewerContributions. The ...popupMenus extension point allows you to contribute individual action delegates throughout the Eclipse Workbench. CNF viewers can be configured to honor these contributions (which is the default) or to ignore them. In the case of the Project Explorer contributed by Platform/UI, object and viewer contributions are honored. (To be covered in detail in Part IV.)

  • Contribute actions using org.eclipse.ui.navigator.navigatorContent as actionProviders. Sometimes, clients require more programmatic control over exactly what actions are contributed to a given menu in a particular context, as well as what retargetable actions are configured based on the current selection. CNF Action Providers are only honored by CNF viewers. (To be covered in detail in Part V.)
Configuring Menu Structure

In Part I, we defined our example <viewer /> element, and popup menus were briefly mentioned.

Recall that there are two means to configure a popup menu. The first possibility is simply to specify a value for the popupMenuId of the <viewer /> element in org.eclipse.ui.navigator.viewer. The second possibility is to take a more active role in configuring the insertion points the menu supports.

Tip: It is an error condition if both the popupMenuId is specified as well as the popupMenu element.

If we were to set the popupMenuId, we might have something like the following:

The identifier can be used by extenders of org.eclipse.ui.popupMenus to add viewerContributions specific to the view; however, no identifier is required for objectContributions.

When only the popupMenuId attribute is specified, the default set of insertion points are automatically configured in the popup menu. These are documented in the schema reference for org.eclipse.ui.navigator.viewer, but are duplicated here for convenience:

"" separator="true"
"" separator="true"
"group.edit" separator="true"
"" separator="true"
"group.port" separator="true"
"group.generate" separator="true"
"" separator="true"
"" separator="true"
"additions" separator="true"
"" separator="true"

These values can be used by the menubarPath attribute of elements in org.eclipse.ui.popupMenus.

These values can also be used when programmatically using or searching for menu items (see org.eclipse.jface.action.IContributionManager, particularly insertAfter(), insertBefore(), and appendToGroup().

All of the string constants ("group.*") are immortalized in org.eclipse.ui.navigator.ICommonMenuConstants for programmatic usage.

Alternatively, we could choose to define a <popupMenu /> element as a child of <viewer />, where we could then define our own mix of insertion points. Remember, that you can use the Extensions tab of the Plug-in Manifest Editor to drive the creation of extension elements from the menu.

For our example, we can use the same menu configuration as the Project Explorer:

Each <insertionPoint /> element indicates a GroupMarker that is accessible through the IContributionMenu API. Where ever the separator attribute is set to true, the menu will render a horizontal line. The menus in Eclipse are smart enough to only render the line if necessary, so two lines back to back only renders as one horizontal line.

Also, take note of the allowsPlatformContributions="true" attribute of <popupMenu /> element. By default, CNF viewers are enabled to honor ..popupMenus contributions. Setting this attribute to false will restrict the menu to only honoring Action Providers.

The example above doesn't do anything fancy, but in your own CNF viewer, you could define your own menu insertion point ("group.example") where ever it makes sense for your scenarios. The recommended naming convention is "group.*", as the above insertion points follow, with the exception of the special additions group.

Some comments on extending or manipulating the set of insertion points on a CNF menu. It is not possible to declaratively manipulate or extend the set of insertion points for an already configured viewer. It is possible to programmatically add new GroupMarkers or Separators through Action Providers, but this practice should be used with care. We will get into the details of how this might be done in Part V, but for now just heed the warning that this practice should be used with caution, and only when taking advantage of the dependsOn attribute of the <actionProvider /> element, where the value indicates the identifier of an Action Provider that adds extra insertion points to the menu. Insertion points should never be programmatically removed as other extensions may depend on them. If your own custom viewer has no use for a particular insertion point, then you can leave it out when you define your own <popupMenu /> element.


In this article, we have discussed how to configure a menu for a Common Navigator Framework (CNF) viewer. In the next few articles, we will discuss how we can add to this menu using org.eclipse.ui.popupMenus and org.eclipse.ui.navigator.navigatorContent/actionProvider.