Bug 89149 - [KeyBindings] misc: Make it easier to print out the used key bindings
Summary: [KeyBindings] misc: Make it easier to print out the used key bindings
Status: CLOSED INVALID
Alias: None
Product: Platform
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 3.1   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Platform-UI-Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords: helpwanted, needinfo
Depends on:
Blocks:
 
Reported: 2005-03-25 19:20 EST by Ed Burnette CLA
Modified: 2009-08-30 02:08 EDT (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Ed Burnette CLA 2005-03-25 19:20:58 EST
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...
Comment 1 Douglas Pollock CLA 2005-03-28 10:59:06 EST
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.
Comment 2 Ed Burnette CLA 2005-03-28 12:51:58 EST
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.
Comment 3 Ed Burnette CLA 2005-04-11 13:15:23 EDT
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?
Comment 4 Douglas Pollock CLA 2005-04-11 13:19:30 EDT
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.
Comment 5 Ed Burnette CLA 2006-01-04 14:25:47 EST
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.
Comment 6 Michael Van Meekeren CLA 2006-04-21 13:14:25 EDT
Moving Dougs bugs
Comment 7 Paul Webster CLA 2006-09-28 15:14:33 EDT
Is this still a problem in 3.3?

PW
Comment 8 Ed Burnette CLA 2006-09-28 15:32:26 EDT
Like I said in comment #5 you can close this one.
Comment 9 Paul Webster CLA 2006-09-28 19:54:58 EDT
There are some more bugs open about moving the contexts and commands extension points ... the depend on bug 154130

PW
Comment 10 Denis Roy CLA 2009-08-30 02:08:42 EDT
As of now 'LATER' and 'REMIND' resolutions are no longer supported.
Please reopen this bug if it is still valid for you.