Chapter 18. Commands

In Chapter 12, “Adding Key Bindings,” we were first introduced to commands as a way to add key bindings. The introduction was brief on purpose as actions were still being introduced and not covered in depth as we just did in Chapter 17. One thing that wasn’t mentioned was that the actions and commands frameworks are two different frameworks that accomplish the same thing: contributing bits of functionality to the Workbench. Another thing that wasn’t mentioned was that the actions framework has been around since the very early release of Eclipse and has aged considerably. The actions framework outgrew its initial use cases as the Eclipse platform expanded into new territories. Furthermore, there are many weaknesses in the API, but the main weakness is that the UI and handling of an action are coupled. So an effort was made in Eclipse 3.1 to provide a modern alternative to actions with the introduction of the commands framework. As of Eclipse 3.3, the commands API stabilized and offered a viable alternative to the actions framework.

This chapter is split into two parts. The first explains commands, and the second part upgrades Hyperbola to use commands instead of actions. Specifically in this chapter we’ll show you how to

• Understand the problems surrounding the actions framework

• Use commands to provide menu contributions

• Decide between using commands and actions

• Replace certain actions in Hyperbola with commands

18.1 The Problem with Actions

The deficiencies of the actions API were identified a while ago and documented in Bug 36968. In Chapter 17 some of the complexities involved in using actions as a Workbench contribution mechanism should have become evident. To understand the basics of the problem, it’s best to look at the IAction interface:

image

From the IAction interface, it’s evident that many aspects of an action are tightly coupled that shouldn’t be. The user interface bits of the action (text and image) are coupled to the actual implementation of the action (run). This coupling makes the action framework less flexible, for example, if you wanted to provide different implementations of the same action depending on the context. How can the action’s enablement be dynamically computed based on some external properties or workflow? What happens if you need to maintain several customizable keyboard accelerator codes? Furthermore, the existing action extension points—org.eclipse.ui.actionSets, org.eclipse.ui.popupMenus, org.eclipse.ui.editorActions, and org.eclipse.ui.viewActions—specify both their placement and visibility criteria.

The limitations of actions become apparent if you use them in a large, complex application. Because of these limitations, there was a need for a new framework. This new framework needed to unify the concept of contributions across the Workbench and also have a clean separation between behavior and presentation. The commands framework is the incarnation of this new framework.

Are Actions Deprecated?

As of Eclipse 3.5, the actions framework isn’t deprecated. It may be deprecated in a future release of Eclipse, but that’s doubtful given its widespread usage. In this book we cover both the actions and commands frameworks because both frameworks are used widely.

18.2 Commands

In essence, a command represents the abstraction between presentation and behavior. A command itself doesn’t represent the presentation or the behavior. In concrete terms, a command binds one or more menu contributions (presentation) with one or more handlers (behavior) as shown in Figure 18-1.

Figure 18-1 A command in pictures

image

In Chapter 12, “Adding Key Bindings,” we created our first command in Hyperbola that represented the notion of adding a contact to Hyperbola. This was required in order to take advantage of the key binding support in Eclipse via the org.eclipse.ui.bindings extension point. To understand how to define a command, let’s look at an example:

image

The first step was to define a command category which is a grouping mechanism for commands. A category has an associated name and description. The next step was to define a command with a unique identifier of org.eclipsercp.hyperbola.addContact. The optional categoryId defines the ID for the category to which this command applies. The name and description fields represent human-readable text. Note that there is no reference to a specific implementation, key binding, or menu contribution.

Tip

To observe the execution of commands in the commands framework, you can register an IExecutionListener via the ICommandService. Note that the listener is merely an observer of commands so it can’t veto or modify them.

18.3 Contributions

In Chapter 17, “Actions,” we discussed the four action-related extension points: org.eclipse.ui.actionSets, org.eclipse.ui.popupMenus, org.eclipse.ui.editorActions, and org.eclipse.ui.viewActions. In the commands framework, these extension points have been replaced by the org.eclipse.ui.menus extension point. The org.eclipse.ui.menus extension point is used to define placement and visibility of a command. Specifically, the locationURI attribute dictates the placement of the command. The visibleWhen child element specifies the visibility of the command.

18.3.1 Menu Contributions

Hyperbola already has a named top-level menu. In the ActionBarAdvisor method fillMenu(), the Hyperbola menu is created as a MenuManager using the snippet below. The first parameter to the constructor is the menu name, as shown in the UI, and the second, hyperbola, is the ID of the menu.

org.eclipsercp.hyperbola/ApplicationActionBarAdvisor
MenuManager hyperbolaMenu = new MenuManager("&Hyperbola", "hyperbola");

To place the Hyperbola menu contribution in a declarative fashion using the org.eclipse.ui.menus extension is straightforward via this example:

image

The menuContribution element specifies the placement of the menu via the locationURI attribute. The locationURI has a special syntax and can be broken down into three parts as shown in Figure 18-2: scheme, identifier, and arguments.

Figure 18-2 locationURI syntax

image

The scheme of the locationURI identifies the type of menu contribution. The valid types are

menu—the main application menu or a view pull-down menu

popup—a pop-up (context) menu in a view or editor

toolbar—the main application toolbar or a toolbar within a view

The identifier of the locationURI specifies the unique identifier of the contribution. In the preceding example we added the Hyperbola menu item to the Eclipse main menu using the org.eclipse.ui.main.menu identifier. A list of common locationURI identifiers is provided here:

org.eclipse.ui.main.menu—the main menu

org.eclipse.ui.main.toolbar—the main toolbar

org.eclipse.ui.views.ProblemView—the Problems view

org.eclipse.ui.views.ContentOutline—the Outline view

org.eclipse.ui.popup.any—any context menu

The final aspect of the locationURI is the arguments. Arguments represent the specific location within a given menu, pop-up, or toolbar where a contribution lives. The arguments are composed of the placement of the contribution, which can be before or after, an equals sign (“=”), and the identifier of some item in the menu, pop-up, or toolbar. The identifier additions can be used to indicate that the contribution placement should happen in the default location within the given menu, pop-up, or toolbar.

Tip

If you’re having trouble finding the proper locationURI identifier for your contribution, consider using the Plug-in Spy (Alt+Shift+F1). Invoke the Plug-in Spy over an editor or view you’re interested in contributing to and the Plug-in Spy will present you with identifiers you can use. If you’re interested in menus, the Menu Spy (Alt+Shift+F2) will give you relevant information related to menu contribution identifiers.

In Hyperbola the Add Contact command is placed in two locations, the main menu and the toolbar. To place the Add Contact command in the main menu, we simply need to add a new menu element under the Hyperbola menu element as shown here:

image

To add the Add Contact command to the toolbar, we need to specify a new locationURI that represents the toolbar location org.eclipse.ui.main.toolbar as shown here:

image

18.3.2 Standard Workbench Contributions

In Hyperbola we created and registered standard Workbench actions like Exit with the ActionFactory class in the makeActions(IWorkbenchWindow window) method as demonstrated in the following snippet:

image

We registered these actions by using the ActionBarAdvisor.register(IAction) method as demonstrated below. Under the covers, this took care of things like registering the standard action’s respective key binding. In terms of presentation, we placed the actions in the ActionBarAdvisor method fillMenu().

image

The commands framework requires a different approach. For example, if we look at the Exit action, we can replicate the behavior and placement using the org.eclipse.ui.menus extension point. To place the Exit action in the proper location, we add a menu child element relative to the Hyperbola menu we defined earlier. To represent the proper exit behavior, we can reuse the existing Exit command identifier provided by the Workbench, org.eclipse.ui.file.exit, as shown in this snippet:

image

This pattern can be applied to the other standard Workbench actions like Preferences and Help. To find existing command identifiers, we recommend that you take a look at the IWorkbenchActionConstants and IIDEActionConstants classes. An even easier way to find existing command identifiers is to use the extension editor and click the Browse... button to bring up a command identifier selection dialog as shown in Figure 18-3.

Figure 18-3 Browsing for command identifiers using the extension editor

image

18.3.3 Contribution Visibility

The visibility of contributions needs to be controlled. For example, imagine if all plug-in developers contributed top-level menu items without any regard for when they should be visible? The user interface would get cluttered quickly. In Hyperbola the Add Contact command should be visible only when a RosterGroup entry is selected. To accomplish this, we need to add a visibleWhen child element to the respective Add Contact menu element.

image

In the visibleWhen expression in this snippet, the selection variable evaluates its child element, or. The or element expresses that the object must be an instance of RosterGroup via the instanceof element.

18.4 Handlers

The behavior of a command is specified via a handler, specifically via the org.eclipse.ui.handlers extension point. Using the org.eclipse.ui.handlers extension point, you can associate one or more classes that implement IHandler and represent the behavior of your command.

Programmatic Commands and Handlers

To programmatically associate a handler with a command, you can use the IHandlerService which is obtained from a view site. To programmatically define or execute a command, you can obtain the ICommandService.

In Hyperbola we can refactor the Add Contact action into a command handler by making AddContactAction extend AbstractHandler instead of Action as shown in the following snippet:

image

The main differences between the old and new AddContactAction is that the logic that was previously in the run() method is now in the execute(ExecutionEvent event) method which is required by extending AbstractHandler. Furthermore, since the Workbench window is no longer passed in as part of the constructor, we have to use the HandlerUtil class to obtain the current Workbench window and selection. When working with handlers, we recommend using the HandlerUtil class for things like acquiring the active editor and current selection.

Now that we have defined a proper handler, the next step is to make the commands framework aware of our handler by using the org.eclipse.ui.handlers extension point as shown here:

image

The handler element acts as the glue between a defined command and the behavior. The class attribute defines a class that implements IHandler or extends AbstractHandler. The commandId attribute represents an identifier that is used to reference an existing command.

Tip

If you have an existing action, you can use the ActionHandler class to convert it into an instance of an IHandler.

Restricting the execution of a handler is done in a similar fashion to the way we restricted menu contributions via visibleWhen expressions, discussed in Section 18.3.3. Within the context of handlers, we have the option of enabledWhen and activeWhen expressions. We recommend always specifying an activeWhen expression to avoid unnecessary plug-in loading. For a handler to be loaded, the command must be selected and the enabledWhen and activeWhen expressions must be satisfied.

18.5 Summary

In this chapter you learned about the existing problems of the actions framework and how the commands framework solves those problems. We even modified existing actions in Hyperbola to take advantage of the commands framework. When you are starting an application from scratch, it’s highly recommended that you use the commands framework instead of the actions framework.

18.6 Pointers

The Eclipse wiki contains a breadth of information regarding the commands framework:

http://wiki.eclipse.org/Platform_Command_Framework

http://wiki.eclipse.org/Command_Core_Expressions

http://wiki.eclipse.org/Menu_Contributions

The Eclipse Platform team has a useful example illustrating different aspects of the commands framework. It’s available in CVS under the org.eclipse.ui.examples name:

http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.ui.examples.contributions/

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset