The Eclipse RCP Command Framework

Summary

From beginning on the Eclipse platform was designed for extensibility. Therefore nearly every aspect of the workbench's user interface has a corresponding contribution mechanism. While the Eclipse workbench has evolved from a pure IDE to the RCP platform a big zoo of of extension APIs was created for plug-in provider to facilitate the growing user interface capabilities. Eclipse 3.3 introduced a new and consolidated framework for user interaction with the Eclipse workbench which obsoletes several former extension points and interfaces. The glue within this framework are so called commands. This comprehensive article is targeted towards new Eclipse RCP developers as well as "pre 3.3 Eclipse developers" who want to catch up with new RCP patterns. Due to the included references and examples it may also serve as a companion for day-to-day development tasks.

This article applies to the Eclipse Project, release 3.4. For corrections and other issues with this article please use bugzilla entry #223445.

Draft by Marc R. Hoffmann, Mountainminds GmbH & Co. KG
DRAFT - September, 2008

Contents

Introduction

The Eclipse command framework is the result of long-term effort to streamline the way how user interaction is contributed to the Eclipse workbench. While Eclipse RCP has outgrown the extensible IDE towards a universal platform for all kind of technical and business applications more and more UI capabilities came into picture. The original APIs for facilitating all these capabilities became cumbersome and bloated.

The Original Action Contribution Design

To understand the reasons for introducing a new framework we will take a quick tour through the original contribution mechanisms. A good example for lack of required flexibility is JFace's IAction interface, which abstracts a particular user action from specific widgets like menu items and tool bar buttons:

  interface IAction {
  
    void setText(String text);
    void setImageDescriptor(ImageDescriptor image);
    void setAccelerator(int keycode);
    void setEnabled(boolean enabled);
    void run();
    
    // ... more setters and getters
  }

Note what aspects are tightly coupled by this type definition: The textual label and menu icon, an keyboard accelerator, the enabled state as well as a particular implementation of the action which is directly included in the run() method. So what if you have different implementations of for the same user action depending on the context or even want to allow plug-in providers to supply their own specific implementations? What if you need to maintain several customizable keyboard accelerator schemes? How can the action's enablement dynamically get computed from some properties of the selected elements?

The extension points of the Eclipse workbench UI separate visual aspects from the actual action implementation. While icons and labels are declared in the extension attributes the actual execution is delegated to IActionDelegate implementations. Depending on the placement and activation context different extension points must be used:

Placing menu items or tool bar buttons requires the plug-in developer to pick the right extension points out of this list. On the other hand workbench locations like the status line can not be populated open at all with these extension points.

Moving to a new Architecture

The deficiencies with the original action framework were well identified long time ago. In 2003 bug #36968 ("Improve action contributions") has been opened stating that "the current action contribution story is diverse and complex, and the interactions between key bindings and retargetable actions, unclear". This bug has a reference to a even older issue filed at times when Eclipse bugzilla entries had four digit ids only: Bug #1989 from 2001 is about controlling visibility of menu items.

In 2005 a request for comments by Douglas Pollock named – among a long list of other important requirements – the main properties a new action framework should come with:

  1. Unified concept for contributions to the workbench
  2. Clear separation between behavior and presentation in the user interface

The same RFC proposes a framework centered around so called commands, which was adopted in several steps. While the resulting command framework is a clean and powerful solution it took some time to integrate all aspects into the Eclipse workbench. Starting with Eclipse 3.3 it became possible to rely on the new framework for most action contributions. Eclipse 3.4 opened the framework itself for custom extensions. And happily the 4-digit bug could finally set to resolved fixed in 2007.

The Command Framework

The essential idea of the new approach for user interface contributions is an abstraction layer between the UI presentation and the behavior implementation. This abstraction manifests in so called commands. A command is neither the presentation nor a particular behavior implementation; it is an abstract representation of some semantical behavior. This diagram shows how the command sits between the UI presentation and different behavior implementations:

Command
Figure xxx: The Command Abstraction

A good example for this concept is the copy to clipboard command found in nearly every desktop application. On the presentation side we may have a menu item for it in the Edit window menu, a tool bar button, occurrences in several context menus and the user will expect a short key like CTRL+C. On the other side we will need very different handler implementations for the copy command depending on the context: A file navigator will put the currently selected file references to the clip board, a text editor pieces of formatted text and an image viewer might deliver bitmap data to the clipboard. Other examples where the advantage of an abstraction becomes obvious are commands like delete, refresh or select all.

The command framework provides powerful and consistent contribution mechanisms for the presentation side as well as for handler implementations. Therefore every user action in new Eclipse applications should be implemented based on commands.

Commands

As described in the introduction commands are a abstract representation representation of some semantical behavior only. For this purpose a command declaration comes with just a few properties:

While there is a optional default handler property, the command is not required to have a reference to a particular implementation of its behavior. Commands may also declare parameters which can be passed at execution time. See section Parameterized Commands below for details.

Declaring Commands

Due to the abstract concept of commands they are typically declared globally via extension definitions in plugin.xml files. Therefore most commands are available for the entire life cycle of the workbench in all contexts. The corresponding extension point org.eclipse.ui.commands allows declaring commands and group them into categories:

  <extension point="org.eclipse.ui.commands">
     <category name="User Sessions"
               description="Management of user sessions"
               id="com.mountainminds.eclipse.examples.sessions" />
     <command name="Login"
              description="Login a new user"
              id="com.mountainminds.eclipse.examples.login"
              categoryId="com.mountainminds.eclipse.examples.sessions" />
     <command name="Logout"
              description="Logout the current user"
              id="com.mountainminds.eclipse.examples.logout"
              categoryId="com.mountainminds.eclipse.examples.sessions" />
  </extension>

As you can see a command definition consists of a name and description, a unique identifier and an optional category. There is no reference to an specific implementation and no reference to menu items or key bindings for the command. See the online documentation for a complete reference of the optional attributes of the extension point org.eclipse.ui.commands. As the command framework has been refined over the time this extension point carries several deprecated elements and attributes. If you follow the patterns described in this article there is no need to rely on any of the deprecated declaration mechanisms.

Before creating your own command always double-check whether one of the existing commands already provides the required semantic. You'll find a full list of the command predefined by the org.eclipse.ui bundle below.

Defining Commands Programmatically

In special situations you might also use the command service API to define commands programmatically. This can be useful if you retrieve the definitions from some other source than Eclipse' declarative XML based extensions. Due to the abstract nature of commands they typically exist for the entire life time of the contributing bundle and will not change dynamically. Therefore the plugin.xml based declaration described above is the typical approach for Eclipse applications. Anyway, here is an example how the ICommandService can be used to declare our sample category and commands.

  // Retrieve the Command Service
  ICommandService cs = (ICommandService) serviceLocator.getService(ICommandService.class);

  // Define Our Category
  Category category = cs.getCategory("com.mountainminds.eclipse.examples.sessions");
  category.define("User Sessions", "Management of user sessions");

  // Define Login Command
  Command login = cs.getCommand("com.mountainminds.eclipse.examples.login");
  login.define("Login", "Login a new user", category);

  // Define Logout Command
  Command logout = cs.getCommand("com.mountainminds.eclipse.examples.logout");
  logout.define("Logout", "Logout the current user", category);

See the section about services below to learn where you can retrieve a ICommandService instance. As command definitions are declared globally, plug-ins that register commands programatically are also responsible for cleaning them up at the end of their live cycle. So let's behave like a good Eclipse citizen and undefine our examples again:

  cs.getCommand("com.mountainminds.eclipse.examples.login").undefine();
  cs.getCommand("com.mountainminds.eclipse.examples.logout").undefine();
  cs.getCategory("com.mountainminds.eclipse.examples.sessions").undefine();

Predefined Commands

The org.eclipse.ui bundle comes with a set of predefined commands in several categories. These commands form the basic user operations of the workbench like opening views or saving editors. Most of them are probably required by any custom RCP application and have already global command handlers associated to them. For example the handler of the Save command will delegate to the ISaveablePart.doSave() method of the active editor. Other commands might be re-used in local contexts to implement specific behavior for a common concept. For example a Order Items view might implement a local handler for the Delete (org.eclipse.ui.edit.delete) command to remove the selected item from the shopping basket. Re-using existing command definitions for semantically similar operations is a good coding practice as it will lead to applications with consistent user experience: Whenever a particular item can be deleted the according command has the same icon, the expected key binding (the Delete key) is active and global menu entries like Edit → Delete are automatically enabled.

The following table list all categories and commands defined by the org.eclipse.ui bundle along with the respective command ids. For historical reasons the id naming scheme and categorization isn't consistent in all places. Unfortunately there are no Java constants for the command ids in Eclipse 3.4 (Issue #54581).

NameID
Category Fileorg.eclipse.ui.category.file
New Neworg.eclipse.ui.newWizard
Close Closeorg.eclipse.ui.file.close
Close All Close Allorg.eclipse.ui.file.closeAll
Import Importorg.eclipse.ui.file.import
Export Exportorg.eclipse.ui.file.export
Save Saveorg.eclipse.ui.file.save
Save As Save Asorg.eclipse.ui.file.saveAs
Save All Save Allorg.eclipse.ui.file.saveAll
Print Printorg.eclipse.ui.file.print
Revert Revertorg.eclipse.ui.file.revert
Restart Restartorg.eclipse.ui.file.restartWorkbench
Refresh Refreshorg.eclipse.ui.file.refresh
Properties Propertiesorg.eclipse.ui.file.properties
Exit Exitorg.eclipse.ui.file.exit
Move... Move...org.eclipse.ui.edit.move
Rename Renameorg.eclipse.ui.edit.rename
Close Others Close Othersorg.eclipse.ui.file.closeOthers
Category Editorg.eclipse.ui.category.edit
Undo Undoorg.eclipse.ui.edit.undo
Redo Redoorg.eclipse.ui.edit.redo
Cut Cutorg.eclipse.ui.edit.cut
Copy Copyorg.eclipse.ui.edit.copy
Paste Pasteorg.eclipse.ui.edit.paste
Delete Deleteorg.eclipse.ui.edit.delete
Content Assist Content Assistorg.eclipse.ui.edit.text.contentAssist.proposals
Context Information Context Informationorg.eclipse.ui.edit.text.contentAssist.contextInformation
Select All Select Allorg.eclipse.ui.edit.selectAll
Find and Replace Find and Replaceorg.eclipse.ui.edit.findReplace
Add Bookmark Add Bookmarkorg.eclipse.ui.edit.addBookmark
Category Navigateorg.eclipse.ui.category.navigate
Go Into Go Intoorg.eclipse.ui.navigate.goInto
Back Backorg.eclipse.ui.navigate.back
Forward Forwardorg.eclipse.ui.navigate.forward
Up Uporg.eclipse.ui.navigate.up
Next Nextorg.eclipse.ui.navigate.next
Backward History Backward Historyorg.eclipse.ui.navigate.backwardHistory
Forward History Forward Historyorg.eclipse.ui.navigate.forwardHistory
Previous Previousorg.eclipse.ui.navigate.previous
Toggle Link with Editor Toggle Link with Editor org.eclipse.ui.navigate.linkWithEditor
Next Page Next Pageorg.eclipse.ui.part.nextPage
Previous Page Previous Pageorg.eclipse.ui.part.previousPage
Collapse All Collapse Allorg.eclipse.ui.navigate.collapseAll
Show In Show Inorg.eclipse.ui.navigate.showIn
Category Windoworg.eclipse.ui.category.window
New Window New Windoworg.eclipse.ui.window.newWindow
New Editor New Editororg.eclipse.ui.window.newEditor
Quick Switch Editor Quick Switch Editororg.eclipse.ui.window.openEditorDropDown
Quick Access Quick Accessorg.eclipse.ui.window.quickAccess
Switch to Editor Switch to Editororg.eclipse.ui.window.switchToEditor
Show System Menu Show System Menuorg.eclipse.ui.window.showSystemMenu
Show View Menu Show View Menuorg.eclipse.ui.window.showViewMenu
Activate Editor Activate Editororg.eclipse.ui.window.activateEditor
Maximize Active View or Editor Maximize Active View or Editororg.eclipse.ui.window.maximizePart
Minimize Active View or Editor Minimize Active View or Editororg.eclipse.ui.window.minimizePart
Next Editor Next Editororg.eclipse.ui.window.nextEditor
Previous Editor Previous Editororg.eclipse.ui.window.previousEditor
Next View Next Vieworg.eclipse.ui.window.nextView
Previous View Previous Vieworg.eclipse.ui.window.previousView
Next Perspective Next Perspectiveorg.eclipse.ui.window.nextPerspective
Previous Perspective Previous Perspectiveorg.eclipse.ui.window.previousPerspective
Close All Perspectives Close All Perspectivesorg.eclipse.ui.window.closeAllPerspectives
Close Perspective Close Perspectiveorg.eclipse.ui.window.closePerspective
Close Part Close Partorg.eclipse.ui.file.closePart
Customize Perspective Customize Perspectiveorg.eclipse.ui.window.customizePerspective
Hide Editors Hide Editorsorg.eclipse.ui.window.hideShowEditors
Lock the Toolbars Lock the Toolbarsorg.eclipse.ui.window.lockToolBar
Pin Editor Pin Editororg.eclipse.ui.window.pinEditor
Preferences Preferencesorg.eclipse.ui.window.preferences
Reset Perspective Reset Perspectiveorg.eclipse.ui.window.resetPerspective
Save Perspective As Save Perspective Asorg.eclipse.ui.window.savePerspective
Show Key Assist Show Key Assistorg.eclipse.ui.window.showKeyAssist
Toggle Toolbar Visibility Toggle Toolbar Visibilityorg.eclipse.ui.ToggleCoolbarAction
Category Helporg.eclipse.ui.category.help
Help Contents Help Contentsorg.eclipse.ui.help.helpContents
Help Search Help Searchorg.eclipse.ui.help.helpSearch
Dynamic Help Dynamic Helporg.eclipse.ui.help.dynamicHelp
Welcome Welcomeorg.eclipse.ui.help.quickStartAction
Tips and Tricks Tips and Tricksorg.eclipse.ui.help.tipsAndTricksAction
About Aboutorg.eclipse.ui.help.aboutAction
Display Help Display Helporg.eclipse.ui.help.displayHelp
Category Viewsorg.eclipse.ui.category.views
Show View Show Vieworg.eclipse.ui.views.showView
Category Perspectivesorg.eclipse.ui.category.perspectives
Show Perspective Show Perspectiveorg.eclipse.ui.perspectives.showPerspective
Figure xxx: Commands defined in plug-in org.eclipse.ui

Parameterized Commands

Menu Contributions

An important simplification that comes with the new command framework is the way how menus and tool bars can be populated. Now we have a single extension mechanism to contribute action items as well as other widgets to all possible locations within the workbench window. The following screen shows many examples where items can be placed:

Menu Contributions
Figure xxx: Possible menu contributions to the Eclipse workbench

With the new contribution framework the extension point org.eclipse.ui.menus is the only mechanism you need to know to populate tool bars and menus of the RCP workbench.

Key Bindings

Handlers

Expressions

Example: ActionSet is active

Example: One ore more elements selected

  <with variable="selection">
    <count value="+"/>
  </with>

Example: Only Elements selected that adapt to IResource

Example: Exactly one element selected that adapts to IResource

Sources

Services

Contexts

Debugging

Migrating old Code to the Command Framework

More Topics

Example Plug-ins

Best Practices Check List

References

Feedback

Please use bug entry 223445 to report any issues with this article.