Eclipse Search

Loading

Dec 21, 2009

Toggle Commands the toggle other contributions

Found this one on Phil's blog. Republishing it with his permission. Thanks Phil!

Introduction

This is a follow up to Commands Part 6: Toggle & Radio menu contributions of fellow blogger Prakash G.R.. He described how to use command toggle and radio states. Here I will show you how to drive other contributions in the Eclipse Workbench using a toggle command.

What we want to achieve

I needed to show another toolbar button when a certain toggle command was executed. Imagine something like "Show clock" that will show or hide a little clock in the worbench window status bar.
Such contribution can be easily added using a menuContribution for the trim area. First create a toolbar in the trim area and then contribute controls/commands to this toolbar also using the menuContribution extension point.
Since we want the clock contribution


<menucontribution locationuri="toolbar:mytoolbar">
<control class="test.ui.clocl.internal.ClockControlContribution" id="test.ui.clock">
<visiblewhen checkenabled="false">
  <with variable="activeWorkbenchWindow">
    <test args="test.ui.clock.ToggleCommand"
      forcepluginactivation="true"
      property="org.eclipse.core.commands.toggle"
      value="true"/>
  </with>
</visiblewhen>

</control>
</menucontribution>

That will create a toolbar contribution that is only visible when the test.ui.clock.ToggleCommand is in the "true" state, when its checked.

Lets define the command:
<command defaulthandler="org.eclipse.core.commands.extender.ToggleCommandHandler" id="test.ui.clock.ToggleCommand" name="Show clock">
<state
  class="org.eclipse.ui.handlers.RegistryToggleState:true"
  id="org.eclipse.ui.commands.toggleState">
</state>

</command>

How this command works and what the state is you have already read in Prakash's blog entry. The default handler for this command does a little more than the one in the latter mentioned blog entry. It is defined like this:

/**
* Generic command that toggles the executed command and re-evaluates property testers for the
* org.eclipse.core.commands.toggle property.
*
*/
public class ToggleCommandHandler extends AbstractHandler {

public Object execute(final ExecutionEvent event) throws ExecutionException {
  HandlerUtil.toggleCommandState(event.getCommand());
  final IWorkbenchWindow ww = HandlerUtil.getActiveWorkbenchWindowChecked(event);
  final IEvaluationService service = (IEvaluationService) ww.getService(IEvaluationService.class);
  if (service != null) {
    service.requestEvaluation("org.eclipse.core.commands.toggle");
  }
  return null;
}
}

How do toggle the visibility of the clock contribution


The connection between toggling the command and making the clock contribution visible is hidden in a property tester, that the clock contribution uses:

public class CommandsPropertyTester extends PropertyTester {
public static final String NAMESPACE = "org.eclipse.core.commands"; //$NON-NLS-1$
public static final String PROPERTY_BASE = NAMESPACE + '.';
public static final String TOGGLE_PROPERTY_NAME = "toggle"; //$NON-NLS-1$
public static final String TOGGLE_PROPERTY = PROPERTY_BASE + TOGGLE_PROPERTY_NAME;

public boolean test(final Object receiver, final String property, final Object[] args, final Object expectedValue) {
  if (receiver instanceof IServiceLocator && args.length == 1 && args[0] instanceof String) {
    final IServiceLocator locator = (IServiceLocator) receiver;
    if (TOGGLE_PROPERTY_NAME.equals(property)) {
      final String commandId = args[0].toString();
      final ICommandService commandService = (ICommandService)locator.getService(ICommandService.class);
      final Command command = commandService.getCommand(commandId);
      final State state = command.getState(RegistryToggleState.STATE_ID);
      if (state != null) {
        return state.getValue().equals(expectedValue);
      }
    }
  }
  return false;
}
}


It is defined in plugin.xml like this:
<propertytester
class="org.eclipse.core.commands.extender.internal.CommandsPropertyTester"
id="org.eclipse.core.expressions.testers.CommandsPropertyTester"
namespace="org.eclipse.core.commands"
properties="toggle"
type="org.eclipse.ui.services.IServiceLocator"/>

That means we define a new property for the namespace "org.eclipse.core.command" and the property is named "toggle". It will operate on IServiceLocator variables. Such variable that is an IServiceLocator is the "activeWorkbenchWindow" variable. Now you should understand the visibleWhen expression of the clock contribution. It should be only visible when the toggle for the clock toggle command is "true". The re-evaluation of the property testers is triggered by the generic ToggleCommand.


A little tip at the end

If you put the ToggleCommand and property tester in a seperate bundle for easier re-use in all your projects and other bundles make sure you either start the bundle at the beginning or set the "test" expressions "forcePluginActivation" to true to let the Eclipse expression framework activate the bundle for you. Otherwise the property tester is completly ignored and the clock would be always visible.

Bonus

Since the state of the toggle is preserved in an instance preference value the visibility of all associated contributions that use the property tester to check for the toggle state of the command.

Of course you can also reverse the test expression for your contributions if you have a toggle command that says something like "Hide clock".

Click here for the original entry.

Dec 2, 2009

Reload your plugins without restarting Eclipse

When you are developing Eclipse plugins, sometimes its annoying that the changes in the plugin.xml won't reflect immediately. You need to restart the target Eclipse to see the changes. This will be painful if you are playing with trial-n-error stuff like the menu urls. In this tip, I'll explain how to make Eclipse reread your plugin.xml without restarting the target.


  • Create a plugin, launch as an Eclipse Application (you don't even need to Debug, just Run would do)
  • Check the UI contributions of your plugin.
  • Make the desired change in your plugin.xml. Right now, I've changed a Command's name; added a Command contribution to an existing menu; added a new view and made changes to an existing perspective
  • In your target, open the Plug-ins Registry view and in the pull down menu, check the 'Show Advanced Operations'
  • Right click your plugin and select Disable.
  • Then right click again and select Enable.
  • Since you have made changes to the current perspective by adding a view, you would be greeted with this Dialog.
  • Say Yes. There you go. Now all the changes in the plugin.xml would reflect in the UI



While this may not be applicable for all the changes you make in plugin.xml, this should cover up for most the changes.