1. Listening to Eclipse framework events

If the application model changes, the Eclipse framework sends out notifications. The Eclipse 4 framework allows event listeners to be notified if this happens.

For example, the UIEvents.UILifeCycle.APP_STARTUP_COMPLETE event is triggered once the application has started. Application components can register for this event and are called by the framework once it occurs.

If your application model changes, the framework detects these changes. In this case, the IEventBroker propagates an event.

The central class that defines the Eclipse framework events is the UIEvents class from the org.eclipse.e4.ui.workbench package. It contains the events or topics and helper methods for working with the events. This class contains information in its Javadoc about the purpose of events. The Eclipse framework sends out objects of the type org.osgi.service.event.Event.

1.1. Example: Part activation event

Eclipse sends the UIEvents.UILifeCycle.ACTIVATE topic every time a part is activated.

@Inject
@Optional
public void subscribeTopicPartActivation(@UIEventTopic(UIEvents.UILifeCycle.ACTIVATE) Event event) {
    if (event.getProperty(EventTags.ELEMENT) instanceof MPart part) {
        System.out.println("Part activated: " + part.getLabel());
    }
}

The Event class contains properties, such as EventTags.ELEMENT, from which you can retrieve the element associated with this event.

Review the UIEvents class and its internal interfaces, such as UIEvents.EventTags, to see the other events fired by the Eclipse framework.

1.2. Extracting event information

The UIEvents.EventTags interface defines the possible event tags.

EventTags interface with properties of an Event

These event tags are explained in the following sections.

1.2.1. ATTNAME event tag

The ATTNAME property of the event is the name of the model attribute that has been changed. For instance, if you listen for changes to a model element’s label, the ATTNAME of the event will be label.

@Inject
@Optional
public void subscribeTopicLabelChange(@EventTopic(UIEvents.UILabel.TOPIC_LABEL) Event event) {
    Object attributeName = event.getProperty(EventTags.ATTNAME);

    // prints "label" to the system output
    System.out.println(attributeName);
}
Part details with the Label field containing ATTNAME sample label
The label is an XML attribute and can be found in the source of your Application.e4xmi file.
<children xsi:type="basic:Part" xmi:id="_9CJOwNgYEeKX2Jv3m0M6IA"
        elementId="com.sample.application.part.attname"
        contributionURI="bundleclass://com.sample.application/yourpackage.attname"
        label="ATTNAME sample label"/>

1.2.2. ELEMENT event tag

The ELEMENT event tag generally refers to the model element that is associated with the event.

1.2.3. NEW_VALUE and OLD_VALUE event tags

The NEW_VALUE and OLD_VALUE properties contain the values of the element’s attribute after and before the change.

In Eclipse 3.x, you would have registered an IPerspectiveListener for the WorkbenchWindow and implemented the perspectiveChanged(…​) method. In Eclipse 4, you think in a DOM (Document Object Model) manner, where <ELEMENT ATTNAME="NEW_VALUE"> is manipulated and fired within events.

For example, there is no dedicated "perspective changed" event. Instead, you listen for changes of the selectedElement attribute of the MPerspectiveStack. You can then get the new and old MPerspective from the EventTags.NEW_VALUE and EventTags.OLD_VALUE properties.

@Inject
@Optional
public void subscribeTopicSelectedElement(
        @EventTopic(UIEvents.ElementContainer.TOPIC_SELECTEDELEMENT) Event event) {
    // react only if a perspective stack selected a perspective
    if (event.getProperty(EventTags.ELEMENT) instanceof MPerspectiveStack perspectiveStack
            && event.getProperty(EventTags.NEW_VALUE) instanceof MPerspective perspective) {
        System.out.println("Selected perspective of " + perspectiveStack + " is " + perspective.getLabel());
    }
}

It is good to keep the DOM structure of the application model in mind and think about the changes that can occur within the application model.

1.2.4. TYPE event tag

With the TYPE event tag, you can determine what action has been performed on the application model. The UIEvents.EventTypes interface defines the types, which tell you whether a model element was added, created, moved, removed, or an attribute was set.

The UIEvents class offers convenience methods to check for some types.

Convenience methods for event types

The isADD(Event) and isREMOVE(Event) methods apply to both single and multiple items, for example, ADD and ADD_MANY.

1.2.5. POSITION event tag

The POSITION event tag contains the new position of model elements. This property is only set if a collection of elements is concerned.

If you move parts in an MPartStack or between different MPartStack containers, you can listen for changes to the children of an element container like this:

@Inject
@Optional
public void subscribeTopicElementContainerChildren(
        @EventTopic(UIEvents.ElementContainer.TOPIC_CHILDREN) Event event) {
    if (!(event.getProperty(EventTags.ELEMENT) instanceof MPartStack)) {
        return;
    }

    if (UIEvents.isADD(event)) {
        // for an addition the old value is null
        if (event.getProperty(EventTags.NEW_VALUE) instanceof MPart part) {
            System.out.println("Added " + part.getLabel() + " at position: "
                    + event.getProperty(EventTags.POSITION));
        }
    } else if (UIEvents.isREMOVE(event)) {
        // for a removal the new value is null
        if (event.getProperty(EventTags.OLD_VALUE) instanceof MPart part) {
            System.out.println("Removed " + part.getLabel() + " from position: "
                    + event.getProperty(EventTags.POSITION));
        }
    }
}

If you drag and drop an MPart within an MPartStack, the MPart is removed and then added back to the MPartStack.

The details can be seen in the UIEventPublisher.formatData() method in the org.eclipse.e4.ui.internal.workbench package. The position attribute is only used for the move, add, or remove events.

1.2.6. WIDGET event tag

The WIDGET event tag can be used to get the underlying widget of the model element that is associated with the event, for example, a Composite.

You can directly interact with the underlying widget. In most cases, this is not necessary, because the model elements themselves provide most of the methods to interact with the widget, such as setLabel() or setVisible().

1.3. Convenience methods for working with events

Besides the convenience methods for the event types, the UIEvents class offers two more convenience methods:

Additional convenience methods of the UIEvents class

1.3.1. The contains method

The contains method can be used to check whether a certain object is part of an event’s property.

For example, if you listen for changed tags on a model element, the contains method tells you whether a certain tag is part of the tags of this element.

An example of this can be found in the subscribeTopicTagsChanged(Event) method of the ToolBarManagerRenderer class from the Eclipse framework.

@Inject
@Optional
private void subscribeTopicTagsChanged(
        @UIEventTopic(UIEvents.ApplicationElement.TOPIC_TAGS) Event event) {

    // only applies to MToolBar elements
    if (!(event.getProperty(EventTags.ELEMENT) instanceof MToolBar toolBar)) {
        return;
    }

    // hide the toolbar if the HIDDEN_EXPLICITLY tag was added
    if (UIEvents.isADD(event)) {
        if (UIEvents.contains(event, UIEvents.EventTags.NEW_VALUE,
                IPresentationEngine.HIDDEN_EXPLICITLY)) {
            toolBar.setVisible(false);
            toolBar.setToBeRendered(false);
        }
    // show it again if the tag was removed
    } else if (UIEvents.isREMOVE(event)) {
        if (UIEvents.contains(event, UIEvents.EventTags.OLD_VALUE,
                IPresentationEngine.HIDDEN_EXPLICITLY)) {
            toolBar.setVisible(true);
            toolBar.setToBeRendered(true);
        }
    }
}

This code demonstrates how the existence of a certain tag (IPresentationEngine.HIDDEN_EXPLICITLY) is checked with the contains method.

1.3.2. The asIterable method

The asIterable method can be used to get an Iterable of an event’s property.

Take the earlier example that listens for the UIEvents.ElementContainer.TOPIC_CHILDREN event and checks the new position. This example fails if more than one child is added to the MPartStack at once, which results in the UIEvents.EventTypes.ADD_MANY event type. In this case, nothing is printed to System.out, because the EventTags.NEW_VALUE property contains a list rather than an MPart.

To handle this case, enhance the subscribeTopicElementContainerChildren method like this:

@Inject
@Optional
public void subscribeTopicElementContainerChildren(
        @EventTopic(UIEvents.ElementContainer.TOPIC_CHILDREN) Event event) {
    if (!(event.getProperty(EventTags.ELEMENT) instanceof MPartStack)) {
        return;
    }

    if (UIEvents.isADD(event)) {
        // for an addition the old value is null
        for (Object object : UIEvents.asIterable(event, EventTags.NEW_VALUE)) {
            if (object instanceof MPart part) {
                System.out.println("Added " + part.getLabel() + " at position: "
                        + event.getProperty(EventTags.POSITION));
            }
        }
    } else if (UIEvents.isREMOVE(event)) {
        // for a removal the new value is null
        for (Object object : UIEvents.asIterable(event, EventTags.OLD_VALUE)) {
            if (object instanceof MPart part) {
                System.out.println("Removed " + part.getLabel() + " from position: "
                        + event.getProperty(EventTags.POSITION));
            }
        }
    }
}

2. Optional exercise: Window title based on perspective

In this exercise, you change the window title according to the active perspective.

2.1. Add a new model add-on that listens to perspective switches

Create the following PerspectiveSwitchAddon class, which listens for perspective changes.

package com.vogella.tasks.ui.addon;

import jakarta.inject.Inject;

import org.eclipse.e4.core.di.annotations.Optional;
import org.eclipse.e4.ui.di.UIEventTopic;
import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
import org.eclipse.e4.ui.workbench.UIEvents;
import org.eclipse.e4.ui.workbench.UIEvents.EventTags;
import org.eclipse.e4.ui.workbench.modeling.EModelService;
import org.osgi.service.event.Event;

public class PerspectiveSwitchAddon {

    @Inject
    private EModelService modelService;

    @Inject
    @Optional
    public void subscribeTopicSelectedElement(
            @UIEventTopic(UIEvents.ElementContainer.TOPIC_SELECTEDELEMENT) Event event) {
        Object newValue = event.getProperty(EventTags.NEW_VALUE);

        // only run this if the NEW_VALUE is an MPerspective
        if (!(newValue instanceof MPerspective)) {
            return;
        }

        MPerspective perspective = (MPerspective) newValue;

        // get the window whose label should change
        MWindow topLevelWindowOfPerspective = modelService.getTopLevelWindowFor(perspective);

        topLevelWindowOfPerspective.setLabel(perspective.getLabel() + " Window");
    }
}

Add a new model add-on via a model fragment.

Add-on details with the class URI of the PerspectiveSwitchAddon

2.2. Validate

Start your application again. Switch perspectives and observe the window title. The title should change to the label of the perspective followed by "Window".

If the add-on is not active, start your runtime with the -clearPersistedState flag to remove persisted model information.

3. Application Model Events online resources

Home Tutorials Training Consulting Books Company Contact us


Get more...