Community
Participate
Working Groups
3.1M5a. I know the Javadocs say 'experimental, do not use' but I needed to print a sorted list of all commands known to the system and their keybindings (if any) so I tried out the new workbench services for commands, keybindings, and contexts. I'm finding it pretty hard to use as it's written. For example, instead of getting a list of contexts, and for each context getting a list of commands, I can only get a list of all commands so I iterate over all the commands for each context, throwing out the ones for other contexts. Another problem is that String ids are often returned when it would be more convenient to just return the object it's an id for. I have to keep going back to the service to ask for the meaning of ids, and also I find that I have to build lookup tables (like KeysPreferencePage does). Also the concept of objects existing but being undefined complicates the code. You've got services and managers and the distinction isn't clear. You've also got an implementation of commands over in org.eclipse.ui and another one in org.eclipse.core.commands that looks a lot like the first one; sometimes searches pick up the wrong one which is irritating. You've got things like CommandManager which doesn't implement ICommandManager like one might think. None of it feels very elegant. See the snippet below for the code I came up with to do the dumping. Note I'm using the JDK5 syntax to try and simplify the code but, it didn't really help much. See also bug 44156. final ICommandService commandService = (ICommandService) window.getWorkbench().getService( IWorkbenchServices.COMMAND); IBindingService bindingService = (IBindingService) window.getWorkbench().getService( IWorkbenchServices.BINDING); IContextService contextService = (IContextService) window.getWorkbench().getService( IWorkbenchServices.CONTEXT); Set<Binding> allBindings = bindingService.getBindings(); List<String> categoryIds = new ArrayList<String>(commandService.getDefinedCategoryIds()); Collections.sort(categoryIds, new Comparator<String>() { public int compare(String o1, String o2) { try { return commandService.getCategory(o1).getName().compareToIgnoreCase( commandService.getCategory(o2).getName()); } catch (NotDefinedException e) { return 0; } } }); List<String> commandIds = new ArrayList<String>(commandService.getDefinedCommandIds()); Collections.sort(commandIds, new Comparator<String>() { public int compare(String o1, String o2) { try { return commandService.getCommand(o1).getName().compareToIgnoreCase( commandService.getCommand(o2).getName()); } catch (NotDefinedException e) { return 0; } } }); HashMap<String, List<Binding>> bindingsByCommandId = new HashMap<String, List<Binding>>(); for (Binding binding : allBindings) { List<Binding> bindings = bindingsByCommandId.get(binding.getCommandId()); if (bindings == null) { bindings = new LinkedList<Binding>(); } bindings.add(binding); bindingsByCommandId.put(binding.getCommandId(), bindings); } for (String categoryId : categoryIds) { Category category = commandService.getCategory(categoryId); try { System.out.println("\nCategory: " + (category.isDefined() ? category.getName() : categoryId + " undefined")); System.out.println("==========================="); for (String commandId : commandIds) { Command command = commandService.getCommand(commandId); if (!command.isDefined()) { System.out.println(commandId + " undefined"); } else { if (command.getCategory() != category) continue; System.out.println(command.getName() + " (" + command.getDescription() + ")"); List<Binding> bindings = bindingsByCommandId.get(commandId); if (bindings != null) { Collections.sort(bindings, new Comparator<Binding>() { public int compare(Binding o1, Binding o2) { return o1.getTriggerSequence().format().compareToIgnoreCase( o2.getTriggerSequence().format()); } }); for (Binding binding : bindings) { Scheme scheme = bindingService.getScheme(binding.getSchemeId()); Context context = contextService.getContext(binding.getContextId()); System.out.println(" " + binding.getTriggerSequence().format() + " (" + (scheme.isDefined() ? scheme.getName() : scheme.getId() + " undefined") + ":" + (context.isDefined() ? context.getName() : context .getId() + " undefined") + ":" + binding.getLocale() + ":" + binding.getPlatform() + ":" + binding.getType() + ")"); } } } } } catch (NotDefinedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } Sample output: ... Category: Navigate =========================== Back (Navigate back) Backward History (Move backward in the editor navigation history) Alt+Left (Default:In Windows:null:null:0) Forward (Navigate forward) Forward History (Move forward in the editor navigation history) Alt+Right (Default:In Windows:null:null:0) Go Into (Navigate into the selected item) Go to Line (Go to a specified line of text) Ctrl+L (Default:Editing Text:null:null:0) Ctrl+X, G (Emacs:Editing Text:null:null:0) ...etc...
There is a lot in this bug, and a lot has changed during 3.1 M6. I'll try to address some of them, but in general I'd like to close this bug and have you open bugs about specific issues that are still remaining. Otherwise, this bug is going to become too unwieldy. To get a list of key bindings for commands do the following: ICommandService commandService = (ICommandService) workbench.getAdapter(ICommandService.class); IBindingService bindingService = (IBindingService) workbench.getAdapter(IBindingService.class); Collection definedCommandIds = commandService.getDefinedCommandIds(); Iterator commandIdItr = definedCommandIds.iterator(); while (commandIdItr.hasNext()) { String commandId = (String) commandIdItr.next(); TriggerSequence[] bindings = bindingService.getActiveBindingsFor(commandId); } Contexts and commands are not directly associated with each other. Bindings are associated with contexts. The keys preference page builds look-up tables for a different reason. The way SWT builds combos is to take an array of strings. These are names. To get the id back, I need to be able to look based on name. It is also somewhat important to ensure that the names are unique (which is not a fundamental condition of the API). Really, this code would have been better written as a JFace viewer -- allowing better model-view separation. String ids are returned in many places to provide flexibility in terms of the API. I've fixed a few places where it just didn't make sense (e.g., getCategory() on a command). But, in general, objects refer to command identifiers. This allows the command to actually stop existing and for the mechanism based on commands to keep working (to some degree). The issue with migration from org.eclipse.ui to org.eclipse.core.commands is unfortunate. The code should have been put in org.eclipse.core.commands in the first place, but we lost the developer that wrote commands (Chris McLaren) right at the end of the 3.0 development cycle. So, some things just weren't finished properly before the API freeze. As of know, all old API is marked as deprecated.
I can't use bindingService.getActiveBindingsFor(commandId) because it only returns the bindings for the current context, platform, and locale. At least it did in 3.1M5a. The only problem I'm reporting is that this dumping code I wrote is too complicated and inefficient because of the way the API is structured. The rest of the comments in the original report are just my guesses for why that is. If you can write a much better version that does the same thing using new API then you can close out the bug. Consider this a use-case.
Since you moved Commands into core, shouldn't the extension point org.eclipse.ui.commands be moved there too? Same for org.eclipse.ui.handlers. Can a headless program have Commands?
Yes, a headless application can have commands. No, it should not be moved because JFace depends on "org.eclipse.core.commands". As a result, "org.eclipse.core.commands" cannot have any dependencies on the registry mechanism.
Um, I wasn't asking for an easier way to print out key bindings, I was just using this little print thing as an example of the API. Feel free to just close this one out.
Moving Dougs bugs
Is this still a problem in 3.3? PW
Like I said in comment #5 you can close this one.
There are some more bugs open about moving the contexts and commands extension points ... the depend on bug 154130 PW
As of now 'LATER' and 'REMIND' resolutions are no longer supported. Please reopen this bug if it is still valid for you.