I'm currently struggling with the following Eclipse RCP commands:
org.eclipse.ui.edit.cut
org.eclipse.ui.edit.copy
org.eclipse.ui.edit.paste
I'm using them as command contributions in the toolbar, but the UIElements (toolbar items) are not updated when the 'handled
' state of those commands changes.
For testing I used a polling mechanism to verify that the state of those commands really changes depending on the currently focussed element, and I found out that the handler remains the same but the handler's 'handled' state changes properly, causing the commands 'handled' state to also change properly.
The only problem is, that neither one of those state changes causes a notification (neither on the command's ICommandListener
, nor on the handler's IHandlerListener
), so the UIElements won't get updated.
Here's some testing code to observe the states of a Command:
ICommandService commandService = (ICommandService) PlatformUI.getWorkbench().getService(ICommandService.class);
final String commandId="org.eclipse.ui.edit.copy";
Command command = commandService.getCommand(commandId);
command.addCommandListener(new ICommandListener() {
public void commandChanged (CommandEvent commandEvent) {
System.out.println(">> Command changed: " + commandId);
}
});
Am I missing something, or is this an bug in the cut/copy/paste handler implementations?
Any insights?
EDIT:
The commands are enabled all the time, and the handler is never exchanged, only the handler's 'handled
' state (and thus also the commmand's 'handled
' state) changes depending on which ui element has the focus. There is however no notification when this state changes.
This results in the toolbar buttons always being enabled, and pressing them will cause a org.eclipse.core.commands.NotHandledException: There is no handler to execute for command
.
Best Solution
The handler which is registered for the cut/copy/paste commands is
org.eclipse.ui.internal.handlers.WidgetMethodHandler
. This handler checks if a given method is declared on the current display's focus control. When executed, that handler will invoke the method using reflection.Snippet from WidgetMethodHandler:
The
getMethodToExecute()
will locate the current focus control usingDisplay.getCurrent().getFocusControl()
, and then check if the given trigger method is declared on it.Widgets such as
org.eclipse.swt.widgets.Text
havecut()
,copy()
andpaste()
methods, so when the focus is on such a widget, the handler will return 'true' forisHandled()
.This handler is however not aware when the current focus control changes (I think there isn't even a way to observe this on the Display), and thus can't notify about changes on its dynamic 'isHandled' state.
This results in the cut/copy/paste commands being fine for popup menus, but they're quite problematic when used in toolbars, as their UI elements can't be updated properly when the handler does no notifications.
This leaves me with either not using those commands in the toolbar, or having a polling mechansim to update the ui elements (which is also bad and error prone). :-(