A U-Bend In The Tubes

Tuesday, July 15, 2008

How to use eclipse Contexts for Core Commands

One of the things that has pissed me off more than anything else throughout my odyssey with eclipse RCP has been the utterly, UTTERLY awful documentation for the declarative Commands framework. I’m sure you know the basics…

  • You define “Command”s as xml entities through your plugin.xml / extensions browser. They shouldn’t contain anything more than presentation information. They are then included on menus and Tool/Coolbars.
  • Unless there’s some behaviour associated with that “Command” that is Always available – where you provide a link to the class that implements that behaviour as a “Default Handler”
  • A Handler is the implementation that is associated with a given Command. If they’re not always available, then they should be defined in the “Handlers” extenstion point.

Now, this is where it got me… Most of the time you need to stop idiot bastard users from clicking on the “Commit” button when there isn’t a Database connection, or whatever. So you need to ghost the menu / toolbar items, right?

However, in eclipse, you don’t get hold of the widget itself and set it to a “ghost” state, you actually need to disable the implementation, so that there are no active handlers for that Command. The Command itself is still there, but since eclipse hasn’t got anything for it to do, it’s disabled, right?

OK – so here’s the thing. There’s an arcane language for logical assessment, all part of the Core Expression Framework. Just so you don’t think I’m being mean for the sake of it, this is the eclipse wiki page for it:

http://wiki.eclipse.org/Command_Core_Expressions

Clear as dogpiss? Hmmm?

Right, I’m going to explain what I’ve worked out as simply as I can. The handlers have an “enabledWhen” element defined by their schema. enabledWhen has a bunch of logical operators associated with it, the most frequently used one I’ve seen at this level being “with”.

With takes a variable, and the variable needs to come from an ISource. Don’t worry about that too much if you don’t need to, because the Sources defined by default are the ones defined in the link above. You’re interested in “activeContexts”, which is basically a collection of Strings, saying which context (Read UI State) you’re in. The Strings correspond to the ID value of a Context object. You can then use an “equals” value to get to the Context you’re interested in. XML looks like this:

       <enabledWhen>
          <with
                variable="activeContexts">
             <iterate
                   ifEmpty="false"
                   operator="or">
                <equals
                      value="trainer.context">
                </equals>
             </iterate>
             <and>
                <iterate
                      ifEmpty="false"
                      operator="or">
                   <equals
                         value="database.context">
                   </equals>
                </iterate></and>
          </with>
       </enabledWhen>

Now that that’s halfway explained, how would someone go about turning contexts on / off?

The package documentation is here:
http://help.eclipse.org/help33/index.jsp?topic=/org.eclipse.platform.doc.isv/reference/api/org/eclipse/core/commands/contexts/package-summary.html

But basically, the gist of it is that you need to get hold of the IContextService for your PlatformUI, calling the IContextService.activateContext() method, saving the IActivation object that gets returned so you can deactivate that Context later… Like this:

public class ContextHelper {
  private static final IContextService service = (IContextService) PlatformUI.getWorkbench().getService(IContextService.class);
  private static IContextActivation database;
    public static void enableDatabase(){
      database = service.activateContext("database.context");

}

    public static void disableDatabase(){
      service.deactivateContext(database);
    }
  }

If you implement it this way, you don't need to define any Contexts in your extensions, and you've basically got yourself a nice little class that'll work like a switch...

I'm bitterly aware that this probably isn't the best way of implementing Contexts, but it's the best that I've worked out. If there's anyone who knows how to do it "properly", then please, please, PLEASE comment telling me how you do it...

Until next time.

posted by Bradshaw at 09:59  

1 Comment »

  1. Nice! Been struggling with the same thing all morning. Got the scent of this solution from one of the forum posts, so was searching some more based on that and found this post. I would have worked it out, but you saved me some time — many thanks.

    Comment by Millard — 18/09/2009 @ 18:35

RSS feed for comments on this post. TrackBack URI

Leave a comment

Powered by WordPress