This article describes how you can react to changes in the application model.
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.

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);
}

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.

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:

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.

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
3.1. vogella Java example code
If you need more assistance we offer Online Training and Onsite training as well as consulting