MidnightJava
MidnightJava

Reputation: 1997

Eclipse RCP Binding Service Sometimes Doesn't find key binding conflicts

My RCP app has key binding conflicts among some of the features I've included, which are shown on the console at launch. Because many of my users are new to Eclipse, I want to handle this for them, so I detect the conflicts and remove them by assigning one command in each conflicting pair to an unused custom context.

This works as desired, except that sometimes the binding service fails to find the conflicts, even though they're reported on the console. This is how I search for the conflicts:

IBindingService bs =
   PlatformUI.getWorkbench().getService(IBindingService.class);
KeySequence keySequence = ...//key sequence known to have binding conflicts
Collection<Binding> bindings = 
   bs.getConflictsFor(KeySequence.getInstance(keySequence));

After changing the context for some of the conflicting bindings, I save them all (with type set to USER) via bs.savePreferences(bs.getActiveScheme(), bindings.toArray(new Binding[0]));

When I do the above on a fresh workspace, the conflicts are resolved as expected for subsequent launches. Then to test the ability to restore them (in case some users want to specify a different resolution) I click "Restore Defaults" on the General-> Keys preference page. Sometimes when I do this, I see the conflicts logged on the console. In this case, I know that when I restart the app, it will once again find the conflicts.

But sometimes I don't see the console message when I restore the default bindings. In that case, for every subsequent launch of the app, the conflicts will be reported on the console, but the binding service will not find them. If I click "Restore Defaults" one more time, or launch in a fresh workspace, then the binding service will find the conflicts.

When the app is in the state where conflicts are reported on the console but not by the binding service, the file org.eclipse.ui.workbench.prefs in the settings area has the following entry: org.eclipse.ui.commands=<?xml version\="1.0" encoding\="UTF-8"?>\n<org.eclipse.ui.commands/>

I can't find any predictor of when the problem will occur or not. It seems to just randomly occur, close to 50% of the time after restoring the default bindings. Since starting in a fresh workspace fixes the problem, it seems that relevant state is being stored somewhere in addition to the org.eclipse.core.runtime settings file, but I have no idea where.

EDIT: I found the scenario in which it breaks. If I launch the app and it saves the customized bindings through the binding service, and then I click "Restore Defaults" (as opposed to relaunching the app and then restoring) I get into the failed state mentioned above.

At that point, the customized bindings are not in the org.eclipse.ui.workbench.prefs settings file, and the app model (workbench.xmi in org.eclipse.e4.workbench) has <bindings> elements with the same key sequence in the same parent <bindingtables> element, but the binding service is not reporting any conflicts (though the console log does). This seems like a bug. I'll report it as such unless someone thinks otherwise.

EDIT2: I failed to notice at first, but the problem is that in the failed state, there is (in the application model xmi file) a child <tags> element for the binding with value deleted. If I manually remove that tag, then the binding service recognizes the conflict. So here now is the actual problem, I think:

When I reset defaults for the key bindings in the same application session in which I saved customized bindings, the default bindings that were restored are tagged as deleted in the application model.

Upvotes: 0

Views: 203

Answers (1)

MidnightJava
MidnightJava

Reputation: 1997

I resolved the problem by adding a line which reads the binding information from the registry and preferences, and overwrites the information in the binding service. I added this line after the code which saves the customized binding preferences.

IBindingService bs = ...
bs.savePreferences(bs.getActiveScheme(), bindings.toArray(new Binding[0]));
bs.readRegistryAndPreferences(null);  //Added this line

Upvotes: 1

Related Questions