NOW Hiring

Quick links

Eclipse framework and model events - Tutorial

Simon Scholz

Lars Vogel

Version 0.2

04.08.2015

Eclipse application model events

This article describes how you can react on changes of the application model.


Table of Contents

1. Listening to Eclipse framework events
2. Example: the part activation event
3. Extract event information
3.1. Available event tags
3.2. ATTNAME event tag
3.3. ELEMENT event tag
3.4. NEW_VALUE and OLD_VALUE event tags
3.5. TYPE event tag
3.6. POSITION event tag
3.7. WIDGET event tag
4. Convenience methods for working with events
4.1. The contains method
4.2. The asIterable method
5. Exercise: Changing the window title on perspective change
5.1. Target
5.2. Clone e4-perspective-switcher
5.3. Add a new model add-on
5.4. Validate
6. About this website
7. Links and Literature
7.1. Application Model Events online resources
7.2. vogella GmbH training and consulting support

1. Listening to Eclipse framework events

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

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

Also if your application model changes like your windows, perspectives, parts and their containers, e.g., application, perspective stacks, part sash container or part stacks, an event is propagated by the IEventBroker.

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

2. Example: the part activation event

A topic, which is fired by Eclipse is the UIEvents.UILifeCycle.ACTIVATE, which is fired every time a part is activated.

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

The Event class contains properties like EventTags.ELEMENT, from which we can receive the element, which is concerned in this event. But there are more and therefore you should have a look at the UIEvents class and its internal interfaces like UIEvents.EventTags.

3. Extract event information

3.1. Available event tags

The UIEvents.EventTags interface define the possible event tags:

EventTags interface with properties of an Event

These event tags are explained in the following sections.

3.2. ATTNAME event tag

The ATTNAME property of the event is the attribute of the model, which has been changed.

So if you for instance listen to changes of 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 element = event.getProperty(EventTags.ATTNAME);
  
  // will print "label" to the system output
  System.out.println(element);
} 

Label ATTNAME

Note

The label is an XML attribute and can be found is 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"/> 

3.3. ELEMENT event tag

The ELEMENT event tag in general is the model element, which is concerned in the event. For an example see Section 2, “Example: the part activation event”

3.4. NEW_VALUE and OLD_VALUE event tags

The NEW_VALUE and OLD_VALUE properties contain the changed value of the element's attribute.

Note

In the old Eclipse 3.x days, you would have registered an IPerspectiveListener for the WorkbenchWindow and implement the perspectiveChanged(...) method. But in Eclipse 4 you'd rather have to think in a DOM(Document Object Model) manner, where <ELEMENT ATTNAME="NEW_VALUE"> are manipulated and fired within events.

A example for using the values of an attribute in the model is a listener for a perspective change.

@Inject
@Optional
public void subscribeTopicSelectedElement(@EventTopic
    (UIEvents.ElementContainer.TOPIC_SELECTEDELEMENT) Event event) {
  Object element = event.getProperty(EventTags.ELEMENT);
  Object newValue = event.getProperty(EventTags.NEW_VALUE);
  // ensure that the selected element of a perspective stack is changed and that this is a perspective
  if (!(element instanceof MPerspectiveStack) || !(newValue instanceof MPerspective)) {
    return;
  }

  MPerspectiveStack perspectiveStack = (MPerspectiveStack) element;
  MPerspective perspective = (MPerspective) newValue;

  System.out.println("Selected perspective of " + perspectiveStack + " is " + perspective.getLabel());
} 

In case you want to listen to a kind of "perspective changed" event, you need to listen to the change of the selectedElement attribute of the MPerspectiveStack and can get the new and old MPerspective from EventTags.NEW_VALUE and EventTags.OLD_VALUE properties.

So you actually listen to the changed selectedElement attribute value of the MPerspectiveStack, rather than looking for a "perspective change" event.

So it is good to keep the DOM structure of the application model in mind and think of the changes, which can occur within the application model.

3.5. TYPE event tag

With the TYPE event tag you may determine what action has been done to the application model.

The different types can be found in the UIEvents.EventTypes interface:

EventTypes interface for changes to the application model

With these event types you are able to figure out, whether a model element was added, created, moved, removed or an attribute was set.

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

Convenience methods for event types.

The isADD(Event) and isREMOVE(Event) methods apply for both single and many, e.g., ADD and ADD_MANY)

For an example see Section 3.6, “POSITION event tag”

3.6. POSITION event tag

The POSITION event tag contains the new position of model elements. So this property is only set in case a collection of elements is concerned.

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

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

  if (UIEvents.isADD(event)) {
    // check new value, because we check for addition and old value will be null
    Object newValue = event.getProperty(EventTags.NEW_VALUE);
    if (newValue instanceof MPart) {
      MPart part = (MPart) newValue;
      System.out.println("Added " + part.getLabel() + " at position: "
          + event.getProperty(EventTags.POSITION));
    }
  } else if (UIEvents.isREMOVE(event)) {
    // check old value, because we check for remove and new value will be null
    Object oldValue = event.getProperty(EventTags.OLD_VALUE);
    if (oldValue instanceof MPart) {
      MPart part = (MPart) oldValue;
      System.out.println("Removed " + part.getLabel() + " from position: "
          + event.getProperty(EventTags.POSITION));
    }
  }
} 

In case you drag and drop a MPart within a MPartStack, the MPart will be removed and afterwards added to the MPartStack.

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

3.7. WIDGET event tag

The WIDGET event tag can be used to get the underlying widget, e.g., a Composite, of the model element, which is concerned in the event.

So you are also able to directly interact with the underlying widget. But in most cases this is not necessary, because the model elements themselves provide the most of the methods to interact with the widget, like setLabel or setVisible methods and so on.

4. 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.

4.1. The contains method

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

Imagine you listen for changed tags on a certain model element and want to determine, if a certain tag is part of the tags of the given model element. In this case the contains method helps you with that task.

An example for 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) {

  Object changedObj = event.getProperty(EventTags.ELEMENT);

  // this should only be applied to MToolbar elements
  if (!(changedObj instanceof MToolBar)) {
    return;
  }

  final MUIElement changedElement = (MUIElement) changedObj;

  // In case tags have been added and the new tag list contains the 
  // IPresentationEngine.HIDDEN_EXPLICITLY String, the element should be hidden
  if (UIEvents.isADD(event)) {
    if (UIEvents.contains(event, UIEvents.EventTags.NEW_VALUE, 
        IPresentationEngine.HIDDEN_EXPLICITLY)) {
      changedElement.setVisible(false);
      changedElement.setToBeRendered(false);
    }
  // If IPresentationEngine.HIDDEN_EXPLICITLY tag was removed the element should be visible again 
  } else if (UIEvents.isREMOVE(event)) {
    if (UIEvents.contains(event, UIEvents.EventTags.OLD_VALUE, 
        IPresentationEngine.HIDDEN_EXPLICITLY)) {
      changedElement.setVisible(true);
      changedElement.setToBeRendered(true);
    }
  }
} 

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

4.2. The asIterable method

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

Let's take the example from Section 3.6, “POSITION event tag”, where we listened to the UIEvents.ElementContainer.TOPIC_CHILDREN event and checked the new position.

This sample lacks in case we add more than one child to the MPartStack, so that we have the UIEvents.EventTypes.ADD_MANY event type. In this case nothing would be printed to the system out, because we have a list in the EventTags.NEW_VALUE property rather than an MPart.

So we need to enhance our subscribeTopicElementContainerChildren method like this:

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

  if (UIEvents.isADD(event)) {
    // check new value, because we check for addition and old value will
    // be null
    Iterable<?> asIterable = UIEvents.asIterable(event, EventTags.NEW_VALUE);
    for (Object object : asIterable) {
      if (object instanceof MPart) {
        MPart part = (MPart) object;
        System.out.println("Added " + part.getLabel() + " at position: "
            + event.getProperty(EventTags.POSITION));
      }
    }
  } else if (UIEvents.isREMOVE(event)) {
    // check old value, because we check for remove and new value will
    // be null
    Iterable<?> asIterable = UIEvents.asIterable(event, EventTags.OLD_VALUE);
    for (Object object : asIterable) {
      if (object instanceof MPart) {
        MPart part = (MPart) object;
        System.out.println("Removed " + part.getLabel() + " from position: "
            + event.getProperty(EventTags.POSITION));
      }
    }
  }
} 

5. Exercise: Changing the window title on perspective change

5.1. Target

In this exercise we will change the window title according to the active perspective.

5.2. Clone e4-perspective-switcher

In order to have a running example with different perspectives you should clone the e4-perspective-switcher git@github.com:vogellacompany/e4-perspective-switcher.git into a new workspace.

Clone the e4-perspective-switcher

After you cloned the e4-perspective-switcher, you should have 3 projects in your workspace:

  • com.sample.application

  • com.sample.feature

  • org.eclipse.e4.ui.workbench.commands.swt

In the com.sample.application project you can find the com.sample.application.product, which you should start in order to see a running example of the e4-perspective-switcher.

5.3. Add a new model add-on

Now we add a new add-on to the application model, which will be used to listen for the perspective change event.

Perspective switch addon

The implementation of the PerspectiveSwitchAddon looks like this:

package com.sample.application.addons;

import javax.inject.Inject;

import org.eclipse.e4.core.di.annotations.Optional;
import org.eclipse.e4.core.di.extensions.EventTopic;
import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import org.eclipse.e4.ui.model.application.ui.basic.MPartStack;
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(@EventTopic(UIEvents.ElementContainer.TOPIC_SELECTEDELEMENT) Event event) {
    Object newValue = event.getProperty(EventTags.NEW_VALUE);

    // only run this, if the NEW_VALUE is a MPerspective
    if (!(newValue instanceof MPerspective)) {
      return;
    }
    
    MPerspective perspective = (MPerspective) newValue;
    
    // Get the MWindow, where we want to change the label
    MWindow topLevelWindowOfPerspective = modelService.getTopLevelWindowFor(perspective);

    topLevelWindowOfPerspective.setLabel(perspective.getLabel());
  }
} 

5.4. Validate

Start your application again and make sure that you used the -clearPersistedState program argument, so that the new addon is available and active.

The result should look similar to this one, where you can see that the window title has been changed to the name of the currently selected perspective:

Perspective switch addon result

6. About this website

7. Links and Literature

7.1. Application Model Events online resources

Eclipse 4 Event System

7.2. vogella GmbH training and consulting support

TRAINING SERVICE & SUPPORT
The vogella company provides comprehensive training and education services from experts in the areas of Eclipse RCP, Android, Git, Java, Gradle and Spring. We offer both public and inhouse training. Whichever course you decide to take, you are guaranteed to experience what many before you refer to as “The best IT class I have ever attended”. The vogella company offers expert consulting services, development support and coaching. Our customers range from Fortune 100 corporations to individual developers.