A handler is the implementation of a command's behaviour. Any plugin can contribute a handler implementation for any command. The workbench uses core expressions and programmatic scoping rules to determine which handler is active at any time. There can either be one handler active for the command, or no handlers active for the command (the command is effectively disabled). When the command has an active handler, we say the command is handled.
While there is a shortcut for a default handler, most handlers are associated with their command using the org.eclipse.ui.handlers extension point.
A command that has default behaviour (it works as long as the workbench is up) can have the default implementation associated in the command definition. The Info example "Global Command" does this:
<command categoryId="org.eclipse.ui.examples.contributions.commands.category" defaultHandler="org.eclipse.ui.examples.contributions.handlers.GlobalMenuHandler" id="org.eclipse.ui.examples.contributions.commands.globalCommand" name="%contributions.commands.globalCommand.name"> </command>
defaultHandler points to the IHandler class that implements the default behaviour for this command. The default handler will always be available unless overriden by a handler association in a more specific scope. This is a shortcut for the equivalent org.eclipse.ui.handlers entry:
... <handler class="org.eclipse.ui.examples.contributions.handlers.GlobalMenuHandler" commandId="org.eclipse.ui.examples.contributions.commands.globalCommand"> </handler> ...
The <activeWhen/> expressions in the plugin.xml and programmatic core expressions are used to help determine the scope of a handlers activation. For example, a specific window, a specific Shell, an active part type or active part.
Here is an example where we are adding some commands to the Info view, org.eclipse.ui.examples.contributions.view. Count to count the number of model elements in the view and swap to swap the 2 selected elements. The command definitions are in the global space as always:
<extension point="org.eclipse.ui.commands"> <command categoryId="org.eclipse.ui.examples.contributions.commands.category" id="org.eclipse.ui.examples.contributions.view.count" description="%contributions.view.count.desc" name="%contributions.view.count.name"> </command> <command categoryId="org.eclipse.ui.examples.contributions.commands.category" id="org.eclipse.ui.examples.contributions.view.swap" name="%contributions.view.swap.name"> </command> ...
We declaratively associate the swap command with a handler that is active while a view with the correct ID is active. When declaring a handler, you can also provide a core expression for declarative enablement. The extension point description for org.eclipse.ui.handlers lists valid elements for the core expression.
<extension point="org.eclipse.core.expressions.definitions"> ... <definition id="org.eclipse.ui.examples.contributions.view.inView"> <with variable="activePartId"> <equals value="org.eclipse.ui.examples.contributions.view"> </equals> </with> </definition> ... </extension> <extension point="org.eclipse.ui.handlers"> ... <handler class="org.eclipse.ui.examples.contributions.view.SwapInfoHandler" commandId="org.eclipse.ui.examples.contributions.view.swap"> <activeWhen> <reference definitionId="org.eclipse.ui.examples.contributions.view.inView"> </reference> </activeWhen> <enabledWhen> <count value="2"> </count> </enabledWhen> </handler> ...
Here we are using another extension point org.eclipse.core.expressions.definitions so we can reuse the same expression in multiple places. The definition's id is org.eclipse.ui.examples.contributions.view.inView and the expression it defines is <with variable="activePartId">...</with>. Whenever another core expression uses <reference definitionId="org.eclipse.ui.examples.contributions.view.inView"/> the <with...> expression will be evaluated.
The <activeWhen/> clause here says the this handler will be active when the activePartId equals our Info view id. The priorities defined in org.eclipse.ui.ISources can give you an idea of the relative importance of different variables, although the priorities alone do not determine a variable's relative importance.
Our handler definition also includes an <enabledWhen> clause. In this case the handler will be enabled when the default variable (the current selection converted into a java.util.Collection of objects) has 2 elements. A core expression that does not include a <with/> element is evaluated against the default variable.
Sometimes it is desirable to instantiate your handlers when your part is created. You can use the org.eclipse.ui.handlers.IHandlerService to activate your handler for your part. Here is the code that activates a handler for the count command.
private static final String VIEW_COUNT_ID = "org.eclipse.ui.examples.contributions.view.count"; //$NON-NLS-1$ ... /** * Instantiate any handlers specific to this view and activate them. */ private void createHandlers() { // 1 - get the handler service from the view site IHandlerService handlerService = (IHandlerService) getSite() .getService(IHandlerService.class); // 2 - create the handler instance countHandler = new AbstractHandler() { public Object execute(ExecutionEvent event) throws ExecutionException { // viewer is an instance variable of InfoView List elements = (List) viewer.getInput(); MessageDialog.openInformation(getSite().getShell(), ContributionMessages.SampleHandler_plugin_name, NLS.bind(ContributionMessages.InfoView_countElements, new Integer(elements.size()))); return null; } }; // 3 - activate this handler instance for the count command handlerService.activateHandler(VIEW_COUNT_ID, countHandler); }
In the InfoView, createHandlers() is called from the end of the createPartControl(Composite) method. org.eclipse.ui.handlers.IHandlerService and org.eclipse.ui.context.IContextService provide scoping of their activations depending on where you get the service.
A handler must implement org.eclipse.core.commands.IHandler although in most cases it is easier to subclass org.eclipse.core.commands.AbstractHandler.
The bulk of the work is done in the execute(ExecutionEvent) method. From the org.eclipse.core.commands.ExecutionEvent you can get any parameters from the calling command object as well as the application context the command was executed in.
Object object = event.getApplicationContext(); if (object instanceof IEvaluationContext) { IEvaluationContext appContext = (IEvaluationContext) object; ... }
The application context provides access to much of the workbench current state. For example, the active workbench window, active shell, active part, active editor, and current selection to name a few. See org.eclipse.ui.handlers.HandlerUtil for an example of extracting variables from the application context and org.eclipse.ui.ISources for a list of variables that are currently supported.
The GlobalMenuHandler is an example of a simple handler that just opens an information popup with a message. The example execute:
public Object execute(ExecutionEvent event) throws ExecutionException { IWorkbenchWindow window = HandlerUtil .getActiveWorkbenchWindowChecked(event); MessageDialog.openInformation(window.getShell(), ContributionMessages.SampleHandler_plugin_name, ContributionMessages.SampleHandler_hello_msg); return null; }
Handlers subclassing
org.eclipse.core.commands.AbstractHandler
or implementing
org.eclipse.core.commands.IHandler2
can implement setEnabled(Object evaluationContext)
. Before the workbench framework
asks a handler for its enabled state, it will call setEnabled
with an
org.eclipse.core.expressions.IEvaluationContext
to allow the handler to update its state.
Without getting into to many details, this uses a HandlerUtil convenience method to extract the active workbench window. Then it opens an information dialog with a "hello world" message. ContributionMessages is an org.eclipse.osgi.util.NLS subclass to help externalize our message strings.