Toggling a Command contribution
January 15, 2009 | 3 min ReadEvery once in a while something just doesn’t happen to be as intiutive as you would have liked it to be. Lately I was trying to contribute a simple command based toggle button to the workbench. Although it is simple to actually provide the menu contribution and to put the button in visual “toggle” mode, it was so straight forward to actually obtain the state of the button in the UI.
To make the menu contribution show up as a toggleable button you have to provide the style value “toggle” on your commands menu contribution: Next we have too keep track of our actual toggle state. Since it is possible to have multiple menu contributions for the same command, we have to keep track of the state in a central place. Imagine a toggle button triggerable from the main menu and a views toolbar. The state of these buttons are keept in sync by storing the state directly in the command. The key to this is the org.eclipse.jface.commands.ToggleState. This implementation of org.eclipse.core.commands.State is a wrapper for a boolean. To attach such a State object to a command, it is provided during the command declaration: The state element takes the ToggleState class as a state provider and attaches itself to the command. The id of the state has to be unique to identfy the state. With the state attached to our command, how can we access it? In the Handler, reacting to the invocation of the menu contribution, we have to access the current state keept in the ToggleState. The following code demonstrates just that: ICommandService service = (ICommandService) PlatformUI.getWorkbench().getService(ICommandService.class); Command command = service.getCommand("org.eclipse.example.command.toggle"); State state = command.getState("org.eclipse.example.command.toggleState"); state.setValue(!(Boolean) state.getValue());
We obtain our command from the ICommandService and ask it for our toggleState stored within the command. Next we just flip the boolean as to create the new state. Now we can just do whatever we want to do in our Handler using the new state. Great, isn’t it? Of course the ToggleState is only one possible implementation of State. One could also imagine multiple states, radio states, text states etc. Also the State class has a specialization (PersistableState), which can be persisted to the preferences as to keep track of the (toggle) states of your buttons.
But there is thing left to do: what happens to this other button which is also a menu contribution for our command? We need to toggle the pressed state of it, as to reflect the state of the first button. To do so, a Handler has to implement IElementUpdater providing the method updateElements(…). It gets an UIElement as a parementer, which can be used to trigger the toggle state: public void updateElement(UIElement element, Map paramters) { element.setChecked(isSelected); }
To broadcast the refresh event to all menu contributions we use the ICommandService in our Handlers: commandService.refreshElements(executionEvent.getCommand().getId(), null);
I hope you find the information here valuable and i am looking forward to your comments.