e4: Updating UI contributions on context switch

During the implementation of a new project, I want to harness the capabilities of the Eclipse application model when it comes to changes in the Eclipse context, or more accurate the de-/activation of context specific handlers.

What does that mean? Lets have a look at the following application model:

contextswitchmodel1 is the global definition of our testCommand, 2 and 3 are perspectives in our application where for the given command a separate handler gets activated due to the context switch from perspectiveA to perspectiveB and vice-versa. 4 is the UI contribution of the command visible to the user in the top window trim.

The resulting application looks like testAppshown on the left hand side. Where the UIContribution 4 is marked with a red arrow. Now the task of the handlers is to toggle between the perspectives and update the UI contribution to either show perspectiveA or perspectiveB.

As described in stackoverflow and the Eclipse forum I did not, at first, find an obvious approach to this (remark in Eclipse 3.x this could be implemented by using an IElementUpdater). After some more analysis I found a way to do so. The source for the following example is certainly available.

Lets fix the example by having a look at HandlerA


public class HandlerA {
    
    @Execute
    public void execute(EPartService partService,
             EModelService modelService, MApplication application) {
        MPerspective perspective = (MPerspective) modelService.find(
                "perspectiveB", application);
        partService.switchPerspective(perspective);
    }

    @Inject
    public void bla(
            @Optional @Active @Named("handler::testCommand") Object value,
            EModelService modelService, MApplication application) {
        if (value == null)
            return;
        List<MHandledItem> findElements = modelService.findElements(
                application, null, MHandledItem.class, null);
        for (MHandledItem mHandledItem : findElements) {
            mHandledItem.setLabel("perspectiveA");
            mHandledItem.setTooltip("perspectiveA now active");
        }
    }
}

The @Execute method does the simple task of toggling the perspective. The updating itself happens in lines 12-23. This method does listen to property changes of handler::testCommand which is the global command (see 1 in the above app model). Each time a context switch happens we get injected the current handler through Object value. So we may act accordingly. Here we act by using the modelService to find all contribution elements subsequently setting a new Label and Tooltip.

If more commands and handlers are in your application you should do a more intelligent search and/or filter on the value to act correct.

This approach, however, is not perfect, as you have to implement this method in both handlers in order to always be able to act upon the change. There are other feasible approaches like creating an Addon where you put the @Inject part, you would have to do this for each command separately, however.

I would prefer to be able to define a class within the MCommand element to put the respective code into which would always be notified in any change that happens related to it. So imagine that a MCommand has an option Class Uri and the respective referenced class could look like this

public class TestCommand {

    @Inject
    EModelService modelService;

    @Inject
    MApplication application;

    @Inject
    public void bla(@Optional @Active MHandler activeHandler,
            @Active MCommand command) {
        if (activeHandler == null)
            return;
        List<MHandledItem> findElements =
                modelService.findElements(
                application, null, MHandledItem.class, null);
        for (MHandledItem mHandledItem : findElements) {
            mHandledItem.setLabel("perspectiveA");
            mHandledItem.setTooltip("perspectiveA now active");
        }
    }
}

Where the injection will happen on change of the activeHandler and I also get the MCommand itself injected. This way one could also efficiently store the given UiContribution elements and limit the searches ….

What do you think? Eager to hear your opinion :)

2 Gedanken zu „e4: Updating UI contributions on context switch“

  1. Putting something on a per-Command basis isn’t enough: your testCommand handler might want its label to be set to „perspectiveA“, but my handler (when active) wants to have a different more meaningful label :-)

    I think you’d also want to avoid the explicit @Named(„handler::testCommand“) as it directly ties your handler to a particular command. You could have your handler implementation be used for a number of commands, that uses some configuration information to change its behaviour.

    1. I understand your first point. So there is not alternative solution than to implement the respective @Inject into each handler class. The second point does not work. Removing @Named(“handler::testCommand”) does lead to no events getting injected at all – and hence no UIContribution updates happening! Could you please elaborate on that? I wanted to go this approach by implementing an Addon, and yet failed to get notified about all handler switches resp. handler activations. – But there is no event for this, just the setting of handler::command_id in the EclipseContext which I can only directly watch by adding the resp. @Named(“handler::command_id”)

Kommentare sind geschlossen.