Contents
- TODO
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:
-
org.eclipse.ui.actionSets: Action sets are contributions to the main menu and tool bar. Some abstraction from the implementation is possible by declaring a contributed action as retargetable. In this case parts can register local handlers via API. -
org.eclipse.ui.editorActions: This extension point also allows contributions to the main menu and tool bar which are bound to a particular editor type. -
org.eclipse.ui.actionSetPartAssociations: While the former extension point allows editor specific contributions to the main menu and tool bar this one provides a similar functionality for all parts including views: It controls the visibility of action sets depending whether a particular editor or part is active within the workbench window. -
org.eclipse.ui.viewActions: Each view may have a local tool bar and pull-down menu. This is the extension point to populate them for particular view types. -
org.eclipse.ui.popupMenus: For additions to context menus, either for specific views (viewerContribution) or for particular objects wherever they appear in the views (objectContribution).
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:
- Unified concept for contributions to the workbench
- 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
- Involved Services
- Structure of the article with links
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:
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
- APIs Querying Commands
- Command icons
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:
- Unique Identifier: A unique identifier allows references to the command.
- Name: A display name for the user which also serves as the default label for associated menu items and default tool tip for tool bar buttons derived from this command.
- Description: User readable description of the command.
- Category Id: Commands are organized in categories, therefore every command should be assigned to one. The primary purpose is to help the user navigating the commands e.g. when creating custom key bindings.
- Help Context Id: To interlink directly with the Eclipse help system commands might declare a help context id.
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).
| Name | ID |
|---|---|
| Category File | org.eclipse.ui.category.file |
org.eclipse.ui.newWizard | |
org.eclipse.ui.file.close | |
org.eclipse.ui.file.closeAll | |
org.eclipse.ui.file.import | |
org.eclipse.ui.file.export | |
org.eclipse.ui.file.save | |
org.eclipse.ui.file.saveAs | |
org.eclipse.ui.file.saveAll | |
org.eclipse.ui.file.print | |
org.eclipse.ui.file.revert | |
org.eclipse.ui.file.restartWorkbench | |
org.eclipse.ui.file.refresh | |
org.eclipse.ui.file.properties | |
org.eclipse.ui.file.exit | |
org.eclipse.ui.edit.move | |
org.eclipse.ui.edit.rename | |
org.eclipse.ui.file.closeOthers | |
| Category Edit | org.eclipse.ui.category.edit |
org.eclipse.ui.edit.undo | |
org.eclipse.ui.edit.redo | |
org.eclipse.ui.edit.cut | |
org.eclipse.ui.edit.copy | |
org.eclipse.ui.edit.paste | |
org.eclipse.ui.edit.delete | |
org.eclipse.ui.edit.text.contentAssist.proposals | |
org.eclipse.ui.edit.text.contentAssist.contextInformation | |
org.eclipse.ui.edit.selectAll | |
org.eclipse.ui.edit.findReplace | |
org.eclipse.ui.edit.addBookmark | |
| Category Navigate | org.eclipse.ui.category.navigate |
org.eclipse.ui.navigate.goInto | |
org.eclipse.ui.navigate.back | |
org.eclipse.ui.navigate.forward | |
org.eclipse.ui.navigate.up | |
org.eclipse.ui.navigate.next | |
org.eclipse.ui.navigate.backwardHistory | |
org.eclipse.ui.navigate.forwardHistory | |
org.eclipse.ui.navigate.previous | |
org.eclipse.ui.navigate.linkWithEditor | |
org.eclipse.ui.part.nextPage | |
org.eclipse.ui.part.previousPage | |
org.eclipse.ui.navigate.collapseAll | |
org.eclipse.ui.navigate.showIn | |
| Category Window | org.eclipse.ui.category.window |
org.eclipse.ui.window.newWindow | |
org.eclipse.ui.window.newEditor | |
org.eclipse.ui.window.openEditorDropDown | |
org.eclipse.ui.window.quickAccess | |
org.eclipse.ui.window.switchToEditor | |
org.eclipse.ui.window.showSystemMenu | |
org.eclipse.ui.window.showViewMenu | |
org.eclipse.ui.window.activateEditor | |
org.eclipse.ui.window.maximizePart | |
org.eclipse.ui.window.minimizePart | |
org.eclipse.ui.window.nextEditor | |
org.eclipse.ui.window.previousEditor | |
org.eclipse.ui.window.nextView | |
org.eclipse.ui.window.previousView | |
org.eclipse.ui.window.nextPerspective | |
org.eclipse.ui.window.previousPerspective | |
org.eclipse.ui.window.closeAllPerspectives | |
org.eclipse.ui.window.closePerspective | |
org.eclipse.ui.file.closePart | |
org.eclipse.ui.window.customizePerspective | |
org.eclipse.ui.window.hideShowEditors | |
org.eclipse.ui.window.lockToolBar | |
org.eclipse.ui.window.pinEditor | |
org.eclipse.ui.window.preferences | |
org.eclipse.ui.window.resetPerspective | |
org.eclipse.ui.window.savePerspective | |
org.eclipse.ui.window.showKeyAssist | |
org.eclipse.ui.ToggleCoolbarAction | |
| Category Help | org.eclipse.ui.category.help |
org.eclipse.ui.help.helpContents | |
org.eclipse.ui.help.helpSearch | |
org.eclipse.ui.help.dynamicHelp | |
org.eclipse.ui.help.quickStartAction | |
org.eclipse.ui.help.tipsAndTricksAction | |
org.eclipse.ui.help.aboutAction | |
org.eclipse.ui.help.displayHelp | |
| Category Views | org.eclipse.ui.category.views |
org.eclipse.ui.views.showView | |
| Category Perspectives | org.eclipse.ui.category.perspectives |
org.eclipse.ui.perspectives.showPerspective |
org.eclipse.ui
Parameterized Commands
- TODO
Menu Contributions
- Example 1: "Hello World" command placed at all possible locations (base for screenshot above).
- ui.menus extension point
- Addressing scheme
- Reference of all well known menu ids
- Stateful items (toggle, check, radio)
- Dynamic contributions, examples: history, customazible favourites, domain specific items (e.g. related Java types, calendar dates).
- Creating custom controls in toolbars.
- Image+Text Toolbars
- Writing extensible plugins
- In case you're project is an add-on to another product (e.g. the Eclipse IDE) try to be un-obtrusive and avoid prominent placement of menu items. If users installes several add-ons they would flood their workbench windows. Especially Command1, Command2 are most likely unapropriate places for add-in programs. Instead try to find appropriate locations where similar functionality can already be found and everybody will expect it. [TODO: Put on best practices list]
- Eclipse Help Issue: "org.eclipse.ui.any.popup" must read "org.eclipse.ui.popup.any"
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:
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
- Purpose and properties
- Default handler, specific/local handers
- Nested IHandlerService implementations, scope of handlers
- Declaring handlers via extension point (for enablement check only instantiated, when the bundle is activated
- Declaring handlers via API
- Handler lifecycle
- UI element updates
Expressions
- Complete Reference Where Expressions are used in RCP Extension points.
- Examples for Common Tasks
org.eclipse.core.expressions.definitions:org.eclipse.debug.ui.detailPaneFactories:org.eclipse.debug.ui.launchShortcuts:org.eclipse.debug.ui.memoryRenderings:org.eclipse.ltk.*:org.eclipse.ui.actionSets:org.eclipse.ui.activities:org.eclipse.ui.console.consolePageParticipants:org.eclipse.ui.console.consolePatternMatchListeners:org.eclipse.ui.decorators:org.eclipse.ui.editorActions:org.eclipse.ui.handlers:org.eclipse.ui.menus:org.eclipse.ui.navigator.linkHelper:org.eclipse.ui.navigator.navigatorContent:org.eclipse.ui.popupMenus:org.eclipse.ui.propertyPages:org.eclipse.ui.viewActions:
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
- Custom sources
Services
- List of involved services
- Where to find
IServiceLocators in the workbench - Service Nesting
- Custom Services
Contexts
Debugging
Migrating old Code to the Command Framework
- Adapters for Legacy Actions
- Migrating to the ui.menues extension point
More Topics
- Using Commands in Help Contents
- Commands for non-UI applications
- Stateful contribution items (toggle, check, radio)
Example Plug-ins
- Sample plug-ins demonstrating different kind of contribution
scenarios, check
org.eclipse.ui.examples.contributions - Generic command browser plug-in to explore and debug an existing RCP application, Browser: Workbench, Window, Page, View for Service Location
Best Practices Check List
- Use the new extension point
org.eclipse.ui.menuin favour of the formerorg.eclipse.ui.editorActions,org.eclipse.ui.viewActionsandorg.eclipse.ui.popupMenus. - Before defining a new command check for semantically similar global command definitions that can be re-used in the specific context.
- Consider using a parameterized command instead of multiple different commands in case these commands just describe variations of the same behaviour.
- Always register the viewers within your workbench parts (views and editors) as selection provider to make the command framework aware of the current selection.
References
- Douglas Pollock (2005). Improve Action Contributions. Request for Comments at dev.eclipse.org
http://dev.eclipse.org/viewcvs/index.cgi/platform-ui-home/R3_1/contributions-proposal/requestForComments.html?revision=1.3 - Paul Webster et al (2007). Platform Command Framwork. wiki.eclipse.org
http://wiki.eclipse.org/Platform_Command_Framework - Paul Webster et al (2008). Command Core Expressions. wiki.eclipse.org
http://wiki.eclipse.org/Command_Core_Expressions - Paul Webster et al (2008). Menu Contributions. wiki.eclipse.org
http://wiki.eclipse.org/Menu_Contributions - Paul Webster (2007). Menu Extension Mapping. wiki.eclipse.org
http://wiki.eclipse.org/Menus_Extension_Mapping - Basic workbench extension points using commands. Eclipse 3.4 Online Help
http://help.eclipse.org/ganymede/topic/org.eclipse.platform.doc.isv/guide/workbench_cmd.htm - Tonny Madsen (2007). Working with the menus extension point. blog.rcp-company.com
http://blog.rcp-company.com/2007/06/working-with-menus-extension-point.html - Karsten Voigt (2008). Configuring and adding menu items in Eclipse V3.3. IBM developerWorks
http://www.ibm.com/developerworks/library/os-eclipse-3.3menu/index.html - Paul Webster (2008). Using Commands and Menu Contributions. Tutorial at EclipseCon 2008
http://www.eclipsecon.org/2008/?page=sub/&id=221
Feedback
Please use bug entry 223445 to report any issues with this article.