Handlers

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.

Associating a default handler with a command

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>
      ...

Associating a handler with a command while a part type is active

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.

Associating a handler programmically with a command while a specific part is active

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.

  1. IHandlerService from the workbench is the global handler service. it provides no special activation scoping or lifecycle.
  2. IHandlerService from the workbench window is the window handler service. Any handlers activated through the window handler service will be active when that window is active. Any listeners added to the window handler service will be removed when the window is disposed, and any active handlers will be deactivated (but not disposed).
  3. IHandlerService from the workbench part site is the part handler service. Any handlers activated through the part handlers service will only be active when that part is active. Any listeners added to the part handler service will be removed when the part is disposed, and any active handlers will be deactivated (but not disposed).

Implementing the handler

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.