Eclipse Tips & Tricks: Label-Updating Command Handler

This time I’ll show another barely documented feature of Eclipse’ Command Core framework: Having commands update their labels based on a selection or whatever else. I believe, not knowing how this is done using declarations in plugin.xml files still causes many developers to hard code actions in their classes instead of using commands and handlers. Read on to learn about a better way today.

This post bases on the Command Core Expressions example I published earlier. So you should follow that one first or download the ZIP at its end and import the two projects into your workspace.

The Goal

In the toolbar the “Bar” command should display itself with a different label and tooltip based on the selection done in the viewer.

The Changes

By default toolbar commands don’t print their label. But you can force commands to do so by setting its mode to FORCE_TEXT in the command definition in the plugin.xml.
plugin.xml (de.rowlo.rcp.cce.app):

1
2
3
4
5
6
7
8
9
   ...
             <command
                   commandId="de.rowlo.rcp.cce.app.command.Bar"
                   icon="icons/bar.png"
                   label="Bar"
                   mode="FORCE_TEXT"
                   style="push">
             </command>
   ...

Once an IHandler implements the interface IElementUpdater Eclipse’s command framework will use that class to update the label, tooltip, or even images of a command. For this example, I’ll change the BarHandler to implement the interface IElementUpdater.
BarHandler.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import static de.rowlo.rcp.cce.foobar.FooBarSelectionListener.findViewer;
 
import java.util.Map;
 
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.commands.IElementUpdater;
import org.eclipse.ui.menus.UIElement;
 
import de.rowlo.rcp.cce.app.View;
 
public class BarHandler extends AbstractHandler implements IElementUpdater {
	...
	@Override
	public void updateElement(UIElement element, @SuppressWarnings("rawtypes") Map parameters) {
		Viewer viewer = findViewer(View.ID);
		if (viewer != null) {
			ISelection selection = viewer.getSelection();
			if (selection instanceof IStructuredSelection &amp;&amp; !selection.isEmpty()) {
				IStructuredSelection sel = (IStructuredSelection) selection;
				Object firstElement = sel.getFirstElement();
				String text = firstElement.toString();
				element.setTooltip(text + " Bar tooltip");
				element.setText(text + " Bar");
				return;
			}
		}
		element.setTooltip("");
		element.setText("");
	}
}

Although this method is called by the command framework it won’t be called on a regular basis or when the selection in viewers change. You need to take care of triggering the refresh of such an element updater yourself. In case of this example application a selection listener is already registered at the viewer. So, the FooBarSelectionListener will be extended now.
FooBarSelectionListener.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
...
import org.eclipse.ui.commands.ICommandService;
...
public class FooBarSelectionListener implements ISelectionChangedListener {
	...
	protected void requestRefresh() {
		IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
		...
		ICommandService commandService = (ICommandService) window.getService(ICommandService.class);
		if (commandService != null) {
			commandService.refreshElements("de.rowlo.rcp.cce.app.command.Bar", null);
		}
	}
}

Right now, the label would only change if the element “Two” is selected. That’s because the FooBarPropertyTester is configured that way. For better results of this example the “Bar” command should be enabled on the elements “One”, “Two”, and “Three”.
FooBarPropertyTester.java#test(Object, String, Object[], Object):

1
2
3
4
5
6
7
8
9
10
	@Override
	public boolean test(Object receiver, String property, Object[] args, Object expectedValue) {
		if (PROPERTY_CAN_FOO.equals(property)) {
			return viewerSelectionContains(View.ID, "One");
		} else if (PROPERTY_CAN_BAR.equals(property)) {
			return viewerSelectionContains(View.ID, "One") || viewerSelectionContains(View.ID, "Two")
					|| viewerSelectionContains(View.ID, "Three");
		}
		return false;
	}

Now run the application and play with the selection in the viewer. Also hover the mouse above the “Bar” command to check the different tooltips.

Final Words

I hope this example also helps other developers in stop using hard coded actions and start using commands and handlers instead. Commands truely are superior. Especially now that you now how to update them when I need to.

The example is available for download here: de.rowlo.rcp.cce2.zip

3 comments to Eclipse Tips & Tricks: Label-Updating Command Handler

Leave a Reply

  

  

  

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>