This tutorial introduces you to the programming model of Eclipse RCP applications.

1. Introduction to Eclipse based applications

Eclipse RCP (Rich Client Platform) applications, use the Eclipse framework to create feature-rich stand-alone desktop applications.

An Eclipse application consists of individual software components, called plug-ins. Plug-ins can use and extend other plug-ins. For example, a plug-in can create new menu entries for a menu defined by another plug-in.

The Eclipse IDE can be viewed as a special Eclipse RCP application with the focus on supporting software development. For example, the Java development tools (JDT) provide the functionality to develop Java applications.

An Eclipse RCP application typically uses the same base components as the Eclipse IDE. On top of these, the developer of the RCP client add application specific components. This is depicted in the following graphic.

Typical components of an Eclipse RCP application

2. Installation

2.1. Download the Eclipse IDE

The Eclipse IDE provides multiple downloads which be be used to develop Eclipse based applications. The most commonly used are:

  • Eclipse SDK - minimal IDE which you need for RCP development

  • Eclipse IDE for Eclipse Committers package provides additional functionality, e.g. Git support for the Eclipse IDE

  • Eclipse IDE for RCP and RAP Developers package provides even more functionality then the committers package

Download either one of them. We describe two alternatives, the SDK and the RCP and RAP Developers download.

The advantage of the using the SDK download is that it is the minimal set of plug-ins needed for RCP development.

The screenshots in this guide are based on the SDK download.

2.1.1. Alternative 1: Download the Eclipse SDK

To Download the latest release of the Eclipse SDK (Software development kit) build from the SDK download page. Click on the link of the latest released version (the release version with the highest number). The download section should look similar to the following screenshot.

Eclipse.org Download Page

The download is a compressed archive of multiple files. This format depends on you platform:

  • Windows uses the zip format

  • Linux uses the tar.gz format.

  • Mac uses the dmg (Disk Image) format

The Eclipse SDK does not include a Java runtime, you need to provide this separately. If you follow Download the RCP package, you do not need an additional Java installation.

2.1.2. Alternative 2: Download the Eclipse RCP (and RAP) package

Eclipse provides pre-packaged packages which can also be used for RCP development. Open https://www.eclipse.org/downloads/packages/ in your browser and download the Eclipse IDE for RCP and RAP Developers package or download the installer and install this package.

The RCP package also includes an Java runtime, you do not need to install one separately.

You can also use the Eclipse installer to installer this package. See Eclipse installer for information about the installer. The installer is useful, if you want to download several flavors of Eclipse. It uses a shared installation pool for common plug-ins, which reduces the required space.

3. Exercise: Create an RCP application with the wizard

In the following exercise, you’ll create an Eclipse RCP application using a template and launch it via the IDE.

3.1. Create project

Create a project called com.example.e4.rcp via the File  New  Other…​  Plug-in Development  Plug-in Project menu entry.

wizard10

Use the settings similar to the following screenshots.

wizard20

Press Next.

e4 rcp wizard30

Press Next.

wizard40

Press Next.

On the last wizard page, select the Create sample content (parts, menu etc.) flag. Via this flag you configure that the generated application has example content, e.g., a view and some menu and toolbar entries.

rcpwizard50

The wizard adds the clearPersistedState startup option to the product configuration file. This ensures that the latest state of your application model is used once the application is started.

3.2. Launch your application via the product file

Open the generated product file by double-clicking on product file.

Starting the Eclipse 4 application

Switch to the Overview tab in the editor and launch your Eclipse application by pressing the Launch an Eclipse application hyperlink. This selection is highlighted in the following screenshot.

Starting the Eclipse 4 application

3.3. Validate

As a result your Eclipse application should start. The application should look similar to the following screenshot.

wizard70

3.4. Error analysis

If you see an empty window, you pressed Press Finish after selecting the template or forgot to select the Create sample content flag in the last tab.

To fix that, delete the generated plug-in and perform the creation again, this time selecting the correct values in Exercise: Create an RCP application with the wizard.

4. Describing the structure of an Eclipse application

At runtime the structure of an Eclipse application is described via an application model.

This model contains the parts of the application as individual model elements and their hierarchical relationship. Some are visible to the user, for example, windows, parts (views and editors), menus, toolbars. Other elements are not directly visible to the user, for example handlers, commands and key bindings.

Each model element has attributes which describe its current state, e.g. the size and the position of a window. The application model also expresses the relationship of the model elements via a hierarchy. If necessary, a model element contains links to Java classes or static resources. For example, a part contains a link to the Java classes which are initialized if the part becomes visible.

The base of the application model is typically defined as a static file. For RCP application this file is, by default, called Application.e4xmi and located in the main directory of the plug-in which defines the product extension. The Eclipse IDE ships with its own base application file. This file is read at application startup and is used to construct the initial application model. Changes to the model are persisted and if a changed model is present the application is restored from this model the next time it is started.

The application model is extensible, e.g., other plug-ins can contribute to it via model processors and model fragments.

During startup the Eclipse framework parses the available information about the application model (Application.e4xmi, persisted user changes and model contributions). It stores the available information and their hierarchy in Java objects during runtime. These objects are called model objects and at runtime they represent the attributes from the model elements.

Also an Eclipse IDE runtime or an Eclipse RCP application running in compatibility mode will add elements to this model based on 3.x API, like view contributons via plugin.xml.

4.1. Connecting model elements to classes and resources

Model elements can point to a class or to a static resource via a Uniform Resource Identifier (URI). For this purpose Eclipse defines two URI patterns. Eclipse instantiates the referred objects or resources in most cases lazily. For example, the classes for a part are instantiated when the part gets visible.

The following table describes the supported URI patterns. The example assumes that the bundle is called test to have a short name.

Table 1. URI pattern for class and static file references
Pattern Description

bundleclass://Bundle-SymbolicName/package.classname

Example:

bundleclass://test/test.parts.MySavePart

Identifier for a Java class. It consists of the following parts: bundleclass:// is a fixed prefix. Bundle-SymbolicName is defined in MANIFEST.MF file. The Bundle-SymbolicName is followed by a '/' and the fully qualified classname.

platform:/plugin/Bundle-SymbolicName/path/filename.extension

Example:

platform:/plugin/com.example.plugin/icons/save_edit.gif

Used to identify resources. Identifier for a resource in a plug-in. platform:/plugin/ is a fixed prefix, followed by the Bundle-SymbolicName, followed by the path to the file and the filename.

For example a part, has a Class URI attribute which points to a Java class via the bundleclass:// URI. This class provides the concrete implementation of the part.

classuri10

An example for a static resource reference is the Icon URI attribute of a part. This attribute can point to an icon that is used for the part.

4.2. Overview of the model objects

The following text gives an overview of the available model elements in the application model.

4.2.1. Application

The application object is represented as an MApplication object at runtime and is the root of the application.

4.2.2. Window

Eclipse applications consist of one or more windows, its model representation is an MWindow or the MTrimmedWindow object. MTrimmedWindow can contain trimbars (which can hold toolbars).

Eclipse application showing 2 windows

4.2.3. Parts

Parts are user interface components which allow you to navigate and modify data, , its model representation is an MPart . Parts can be stacked or positioned next to each other depending on the container into which they are dropped. A part can have a drop-down menu, context menus and a toolbar.

Eclipse application with a few parts

Parts can be classified as views and editors.

Views are typically used to display and modify a set of data, like a tree or table of data elements. If the view allows you to change data, this change is typically directly applied to the underlying data structure without the need to save explicitly.

For example, the Project Explorer view in the Eclipse IDE allows you to browse a set of files. If you rename a file via the Package Explorer view, the file name is directly changed on the file system.

Editors are typically used to modify a single data element. To apply the changes made in an editor to the data structure, the user has to explicitly save the editor content.

For example, the Java editor is used to modify Java source files. Changes to the source file are applied once the user selects the Save button. A dirty editor tab is marked with an asterisk left to the name of the modified file.

Editor marked as dirty

4.2.4. Available part containers

Parts can be directly assigned to a window or a perspective. They can also be grouped and arranged via stacks (Part Stack) or sash containers (Part Sash Container).

A part stack arranges its children similar to a browser. It contains a stack of parts and shows their headers while content of one part is displayed. The user can switch to another part by selecting the corresponding tab.

A part sash container displays all its children at the same time either horizontally or vertically aligned.

The following screenshot shows a simple Eclipse application layout using two part sash containers and three part stacks.

An example arrangement of Parts in an Eclipse application

On the top of this layout there is a part sash container which contains another part sash container and one part stacks. These two elements are displayed side by side. The part sash container on the next level contains two part stacks. The hierarchy is depicted in the following graphic.

The hierarchy of Parts using PartStacks and PartSashcontainers.

You can use the Container Data attribute on a child of a part sash container to assign a layout weight. This layout weight is interpreted as the relative space the corresponding child element should get assigned in the part sash container. The setting is depicted in the following screenshot.

Container data for layouting

If you set the Container Data for one element, you must define it for all the other elements, too. Otherwise the missing values are interpreted as very high and these elements take up all available space.

TIP:The initial total of all the container data values is maintained when elements in the sash are moved. In order to allow fine grained/smooth dragging this total must be similar to the screen resolution. A too low value (i.e., 50 / 50) causes the part to be moved multiple pixels per sash unit, which the user will realize as a jerky movement. Therefore, use a sufficient high value, e.g., 10000.

4.2.5. Perspective

A perspective is an optional container for other part containers and parts. It is presented by MPerspective objects, which must be placed in an MPerspectiveStack object. Only one of the perspectives in a perspective stack and be activated and made visible. It is possible have shared elements between perspectives.

For example, the Eclipse IDE uses perspectives to provide view arrangements appropriate for different tasks, like development or debugging.

Switching perspectives can be done via the EPartService service provided by the Eclipse platform.

4.2.6. Other available model objects

The following table lists the types of the important model objects.

Table 2. Eclipse model elements
Model element Description

MApplication

Describes the application object. All other model elements are contained in this object.

MAddon

A self-contained component typically without user interface. It can register for events in the application life cycle and handle these events.

MWindow

Represents a window in your application.

MTrimmedWindow

Similar to MWindow but it allows containing toolbars for the windows (via the TrimBars model elements).

MPerspective

Represents a different layout of parts to be shown inside the window. Should be contained in a MPerspectiveStack.

MPart

Represents the model element part, e.g., a view or an editor.

MDirtyable

Property of MPart which can be injected. If set to true, this property informs the Eclipse platform that this Part contains unsaved data (is dirty). In a handler you can query this property to provide a save possibility.

MPartDescriptor

MPartDescriptor is a template for new parts. A new part based on this part descriptor can be created and shown via the Eclipse framework.

Snippets

Snippets can be used to pre-configure model parts which you want to create via your program. You can use the Eclipse framework to clone such a snippet and use the result object to attach it to the application model at runtime.

5. Extending the application model from other plug-ins

5.1. Contributions

Every plug-in can contribute to the application model via:

  • Static contributions - contributed via text files; these extensions are called fragments or model fragments.

  • Dynamic contributions - contributions are contributed via Java classes; these extensions are called processors or model processors.

These model contributions must be registered via the org.eclipse.e4.workbench.model extension point. They are read during startup and are used to build the runtime application model.

This runtime application model reflects your current application. Changes in the application during runtime of the application, are written back to the model. For example, if the user positions a part into another stack via drag and drop.

If the Eclipse application is closed, these changes are recorded and saved in the workbench.xmi file. This file is located in the .metadata/.plugins/org.eclipse.e4.workbench folder. If certain model elements should not be persisted during shutdown, you can add the constant "persistState" defined via IWorkbench.PERSIST_STATE to the persistedState of the model element.

You can change the application via your code by changing the model elements. The Eclipse platform has listeners registered on most parts of the model and updates the application if you change the model.

The persisted state of the application model can be deleted at start of your application via the clearPersistedState parameter as a launch parameter. In most cases this is undesired behavior for an exported application and only used during development.

Comparison with Eclipse 3.x

The programming model of Eclipse 3.x primarily uses extension points to define contributions to the application. These extensions define new parts, new menus, etc. In modern Eclipse RCP applications you use fragments and processors.

5.2. Model fragments

A model fragment is a file which typically ends with the .e4xmi extension. It specifies additional model elements and which model element it extends. For example, a fragment can contribute a new menu containing several new menu entries to the main menu of the application.

In the fragment the Featurename is a link to the model element which you want to extend. The following table lists some Featurename values and their purposes.

Table 3. Contribution, Featurename and Element id
You want to contribute to a Featurename Element Id

Command to the application

commands

ID of your application

Handler to the application

handlers

ID of your application

New MenuItem / HandledMenuItem to existing menu

children

ID of the menu

New menu to the main menu of the window

children

ID of your main menu

New Part to existing PartStack

children

ID of your PartStack

5.2.1. Defining the model element which gets extended

If you want to contribute to an element of the application model you can:

  • specify the ID of the element to which you are contributing

  • use an XPath expression to describe the model element which should get extended

The following table gives several examples how you can use XPath expressions to define the model element you want to extend.

Table 4. Sample XPaths for the Application Model
XPath Element in Application Model

xpath:/

The slash (/) always addresses the root element of an XML file, which always is the MApplication element.

xpath://mainMenu

Contribute to the main menu.

xpath://mainMenu/children

Contribute to all children of the main menu, e.g. to every menu in it.

xpath://mainMenu/*[1]

Contribute to the first child of the main menu. In most applications this would be the menu:File menu.

xpath://mainMenu/[@[local-name()='type' and .='menu:Menu']]

Contribute to the first Menu of the main menu. This xpath is more detailed than the one above since it also requires that the main menu child is of type menu:Menu. In most applications this would be the menu:File menu.

xpath://trimBars[@side="Bottom"]

Contribute to the bottom trimbar.

xpath://trimBars[not(@side)]

Contribute to the top trimbar. When the MTrimBar is on top the side attribute is omitted, therefore not(@side) is used.

xpath://children[@*[local-name()='type' and .='basic:Part']]

Contribute to a MPart.

xpath://children[@*[local-name()='type' and .='basic:Part']][./tags = 'Editor']

Contribute to a MPart which is tagged with the Editor tag.

A nice tool for evaluating XPaths is the Eclipse XPath evaluation plug-in.

Eclipse XPath plugin in the marketplace

5.2.2. Position of new model elements

Fragments define the desired position of new model elements via the Position in List attribute. The following values are allowed:

Table 5. Position in list
Value Description

first

Positions the element on the beginning of the list.

index:theIndex

Places the new model elements at position theIndex. Example: index:0

before:theOtherElementsId

Places the new model elements before the model element with the ID theOtherElementsId.

after:theotherelementsid

Places the new model elements after the model element with the ID theotherelementsid.

Fragments of independent plug-ins are processed in the order of the dependencies in the MANIFEST.MF file. Therefore, first or index might not always result in the desired outcome.

5.3. Model processors

A processor allows contributing to the model via program code. This enables the dynamic creation of model elements during the start of the application.

5.4. Examples of model fragment and model processors

The usage of model fragment and model processors is explained later in https://learn.vogella.com/courses/rich-client-platform once you learned about menu, command and handlers and the Eclipse services.

6. Exercise: Creating an Eclipse RCP application

In this exercise you create a standard Eclipse plug-in. Afterwards, you convert the generated plug-in into an Eclipse RCP application. This plug-in is used as the basis for your user interface components.

Depending on your previous work, you may see additional or less projects compared to the screenshots.

If you created other projects earlier, it is recommended that you close them or remove them from the workspace to avoid side effects. To close a project, right click on it and select Close from the content menu. To remove a project from the workspace, right click on it and select Delete from the content menu. In the resulting dialog DO NOT set the "Delete project content on disk" flag, this way you can later import the project again, if needed.

If you are using a target definition file, the corresponding project must of course stay (open) in the workspace.

6.1. Creating a plug-in project

Create the com.vogella.tasks.ui plug-in project via the File  New  Other…​  Plug-in Development  Plug-in Project menu entry.

Selection the Eclipse Plug-in Wizard

On the first wizard page enter com.vogella.tasks.ui as project name and press the Next button.

First page of the Eclipse Plug-in Wizard specifying the project name.

On the next wizard page ensure the following settings are made:

  • Select No at the Would you like to create a rich client application? option

  • Uncheck the This plug-in will make contributions to the UI option

  • Uncheck the Generate an activator, a Java class that controls the plug-in’s life cycle option

Second page of the Eclipse Plug-in Wizard specifying the plug-in ID

Press the Finish button.

If you click the Next button instead of Finish, the wizard shows you a template selection page. So do not make a selection and finish the wizard.

6.2. Review the generated code

Open the project and ensure that no Java classes were created in the src folder.

In the manifest editor switch to the Dependencies tab and ensure that there are no entries.

6.3. Create a feature project

Create a new feature project called com.vogella.tasks.feature via File  New  Other…​  Plug-in Development  Feature Project.

You can press the Finish button on the first wizard page.

Feature project

Afterwards select the Included Plug-ins tab in the editor of the feature.xml file. Press the Add…​ button and include the com.vogella.tasks.ui plug-in into this feature.

Feature project

Ensure you have added the plug-in on the Included Plug-ins tab to include it into your feature. Using the Dependencies tab is wrong for this exercise.

6.4. Create a project to host the product configuration file

Create a new project called com.vogella.tasks.product via the File  New  Other…​  General  Project menu entry.

productproject10
productproject12

Press Finish.

6.5. Create a product configuration file

Right-click on the com.vogella.tasks.product project and select New  Other…​  Plug-in Development  Product Configuration.

training product10

Create a product configuration file called taskmanagement.product inside the com.vogella.tasks.product folder.

training product20

Press the Finish button. The file is created and opened in an editor.

Press the New…​ button on the Overview tab of the product editor.

Press the new button in the product editor

Use the following data:

  • taskmanagement as the Product Name

  • your plug-in as the Defining Plug-in

  • product as the Product ID

  • org.eclipse.e4.ui.workbench.swt.E4Application in the Application combo box.

Entering the product details

Ensure that a ID, version and Name is set. Version should be set to 0.0.1 (or any other three numbers separated by dots) as this is required for the command line build. Also ensure that you have select that the product configuration is based on "plug-ins and features".

Entering the product version

6.6. Enter the feature as content into the product

Select the Contents tab and add the following features via the Add Feature…​ button.

  • com.vogella.tasks.feature

  • org.eclipse.e4.rcp

  • org.eclipse.emf.ecore

  • org.eclipse.emf.common

The result should look similar to the following screenshot.

Adding the required features to your product

6.7. Configure the start levels

Switch to the Configuration tab in the product editor and press the Add Recommended…​ button. These settings are for example used by the Maven/Tycho build system, hence it is good practice to configure them.

Setting the default start level

6.8. Create an application model

Create an application model file in your com.vogella.tasks.ui plug-in via the File  New  Other…​  Eclipse 4  Model  New Application Model menu entry.

training product48

Enter your com.vogella.tasks.ui application plug-in as the container and use the file name suggested by the wizard.

training product50

Press the Finish button to create the application model file and to open it in an editor.

6.9. Add a window to the application model

Add one window to your application model.

Right-click on the Windows node, and select Trimmed Window as depicted in the following screenshot.

Adding a trimmed window

Enter an ID with the taskmanager suffix, the position and size of the window and a label as shown in the screenshot below.

Enter the data for the TrimmedWindow in the model editor

6.10. Ensure to delete the persisted user interface state at startup

If you start and close your application the last state of the application is persisted by the framework and restored the next time you start this application. This is undesired during development, as the latest state from the application model file should be used. To ensure that always the latest version of your application model is used, add the -clearPersistedState parameter to your product configuration file.

The following screenshot shows this setting in the product configuration file.

Delete persisted Eclipse application model

Ensure that you used the - sign and that the parameter is typed correctly. Is must be: -clearPersistedState

6.11. Set the launch name

Your command line build which you configure later should create a executable named Tasksman. Switch to the Launching tab and enter Taskman in the Launcher Name field.

taskman as launcher

6.12. Start the application and validate the result

Open the product file and select the Overview tab. Press the Launch an Eclipse application hyperlink in the Testing section.

Starting the product

Validate that your application starts. You should see an empty window, which can be moved, resized, minimized, maximized and closed.

6.13. Desired user interface

In this exercise, you create the basis of the application user interface. At the end of this exercise, your user interface should look similar to the following screenshot.

Screenshot of the application

Open the Application.e4xmi file in the Eclipse model editor via a double-click or right-click on it and select Open With.

6.13.1. Add part sash and part stack containers

Select Controls below the window and add a part sash container element.

Add PartSashContainer

Change its Orientation attribute to Horizontal and enter into the ID field the com.vogella.tasks.ui.partsashcontainer.main value.

Change the orientation attribute

Add a part stack as the first child to your part sash container element.

Re-select the parent part sash container and add a part sash container element. Add two part stacks to this new element.

After these changes your application model should look similar to the following screenshot.

Application model structure

6.13.2. Create the parts

Add one part to each stack. Use the IDs and labels from the following table.

Enter the name first, the ID should be adjusted based on the name, if the label was empty.

Table 6. Label and ID for the parts
ID Suffix Label

com.vogella.tasks.ui.part.overview

Overview

com.vogella.tasks.ui.part.details

Details

com.vogella.tasks.ui.part.playground

Playground

The final structure of your application model should be similar to the following screenshot. In the screenshot the overview part is selected in the tree hence you see its data.

Part data

6.13.3. Validate the user interface

Start your product and validate that the user interface looks as planned. See Desired user interface for the desired result.

Reassign your model elements, if required. The model editor supports drag-and drop for reassignment.

Also note that you can already see the structure, even though you have not created any Java classes so far.

6.14. Define the API which can be used

To use classes from other plug-ins in a plug-in, you need to add dependencies to them in the MANIFEST.MF file of the plug-in. In this exercise you prepare the usage of classes from other plug-in.

Open the META-INF/MANIFEST.MF file in your com.vogella.tasks.ui plug-in and select the Dependencies tab. Use the Add…​ button in the Required Plug-ins section to add the following plug-ins as dependencies:

  • org.eclipse.core.runtime

  • org.eclipse.jface

  • org.eclipse.e4.core.di

  • org.eclipse.e4.ui.workbench

  • org.eclipse.e4.ui.di

  • org.eclipse.e4.core.di.extensions

  • org.eclipse.e4.core.contexts

jface provides also swt

Use the Add…​ button in the Imported Packages section to add the following plug-ins as dependencies:

  • javax.annotation

  • javax.inject

The result should be similar to the following screenshot (version may differ).

Plug-in Dependencies
The added version numbers are minimum version numbers, so they still allow you to use a newer version of the plug-in but prevent you from using an older version which may not have the API you are planning to use.
Show Solution

The following is a potential solution (plug-in versions have been removed from the listing)

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Ui
Bundle-SymbolicName: com.vogella.tasks.ui;singleton:=true
Bundle-Version: 1.0.0.qualifier
Bundle-Vendor: VOGELLA
Automatic-Module-Name: com.vogella.tasks.ui
Bundle-RequiredExecutionEnvironment: JavaSE-17
Require-Bundle: org.eclipse.core.runtime,
 org.eclipse.jface,
 org.eclipse.e4.core.di,
 org.eclipse.e4.ui.workbench,
 org.eclipse.e4.ui.di,
 org.eclipse.e4.core.di.extensions
Import-Package: javax.annotation;version="1.3.5",
 javax.inject;version="1.0.0"

6.15. Create Java classes and connect with the parts

6.15.1. Create a new package and some Java classes

Create the com.vogella.tasks.ui.parts package in the application plug-in.

Create the following three Java classes in this package:

  • TodoOverviewPart

  • TodoDetailsPart

  • PlaygroundPart

Theses classes should not extend another class, nor should they implement any interface.

You can create the classes by clicking on the Class URI hyperlink in the detail pane of the model editor for the part. This also connects the created class to the model object. If you do this, you can skip Connect the Java classes with your parts.

The following code shows the TodoDetailsPart class.

package com.vogella.tasks.ui.parts;

public class TodoDetailsPart {
    public TodoDetailsPart() {
        System.out.println(this.getClass().getSimpleName() + " constructed");
    }
}

6.15.2. Connect the Java classes with your parts

In your application model connect the class with the corresponding part model element. You can do this via the Class URI property of the part model element.

The model editor allows you to search for an existing class via the Find…​ button. The initial list of Contribution Classes is empty, start typing in the Class Name field to see the results.

The following table gives an overview of which elements should be connected.

Table 7. Mapping Java classes with part model element
Class Part ID suffix

TodoOverviewPart

com.vogella.tasks.ui.part.overview

TodoDetailsPart

com.vogella.tasks.ui.part.details

PlaygroundPart

com.vogella.tasks.ui.part.playground

The following screenshot shows the result for the overview part.

Finding a model class in the Application model

6.15.3. Validate

Start your application. It should start, but you should see no difference in the user interface.

To validate that the model objects are created at runtime check the Console view of Eclipse for the output of the System.out.println() statements.

7. More exercises, examples and videos

See Commercial Eclipse RCP training for explanation and demo videos, more content and exercises.

8. Exercise: Contributing a part descriptor via model fragments

In this exercise, you create a model fragment to contribute a part descriptor. This extension can be used in an Eclipse IDE or a RCP application.

8.1. Create a new plug-in

Create a simple plug-in project named com.vogella.contribute.parts. The following description abbreviates the plug-in name to the contribute.parts plug-in.

8.2. Add the dependencies

In the MANIFEST.MF file select the Dependencies tab.

fragments view10

Add the following plug-ins as dependencies to your contribute.parts plug-in.

  • org.eclipse.core.runtime

  • org.eclipse.jface (which also provides org.eclipse.swt)

  • org.eclipse.e4.core.di

  • org.eclipse.e4.ui.workbench

  • org.eclipse.e4.ui.di

Also add the following package dependencies.

  • javax.annotation

fragments view20
Show Solution

The manifest should look similar to the following listing. Version numbers have been removed as they change frequently.

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Parts
Bundle-SymbolicName: com.vogella.contribute.parts
Bundle-Version: 1.0.0.qualifier
Bundle-Vendor: VOGELLA
Automatic-Module-Name: com.vogella.contribute.parts
Bundle-RequiredExecutionEnvironment: JavaSE-17
Require-Bundle: org.eclipse.core.runtime,
 org.eclipse.jface,
 org.eclipse.e4.core.di,
 org.eclipse.e4.ui.workbench,
 org.eclipse.e4.ui.di
Import-Package: javax.annotation

8.3. Enable activation

Set the Activate this plug-in when one of its classes is loaded flag in the MANIFEST. This enables the registration of the fragment via the MANIFEST.MF

8.4. Create a part implementation

Create the following class.

package com.vogella.contribute.parts;

import javax.annotation.PostConstruct;

import org.eclipse.jface.widgets.TextFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;

public class AdditionalInformationPart {
    @PostConstruct
    public void postConstruct(Composite parent) {
        TextFactory.newText(SWT.BORDER |SWT.MULTI).create(parent);
    }
}

8.5. Create a model fragment

Create a new model fragment via the File  New  Other…​  Eclipse 4  Model  New Model Fragment menu entry.

Creating fragments with the wizard

Select the contribute.parts plug-in as the container and use parts.e4xmi as the name for the file.

Creating fragments with the wizard

Press the Finish button.

8.6. Validate that the fragment is registered via the MANIFEST.MF

The fragment creation wizard also adds the Model-Fragment key to your MANIFEST.MF file. To review this, open the MANIFEST.MF file and select the MANIFEST.MF tab in the editor. The resulting file should look similar to the following code, the versions have been removed in this listing, as the versions you see depend on the release you are using.

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Parts
Bundle-SymbolicName: com.vogella.contribute.parts
Bundle-Version: 1.0.0.qualifier
Bundle-Vendor: VOGELLA
Require-Bundle: org.eclipse.core.runtime,
 org.eclipse.jface,
 org.eclipse.e4.core.di,
 org.eclipse.e4.ui.workbench,
 org.eclipse.e4.ui.di,
 org.eclipse.e4.ui.model.workbench
Bundle-RequiredExecutionEnvironment: JavaSE-17
Automatic-Module-Name: com.vogella.contribute.parts
Model-Fragment: parts.e4xmi
Import-Package: javax.annotation
Bundle-ActivationPolicy: lazy

8.7. Adding model elements

Open the parts.e4xmi file in its editor. Select the Model Fragments node and press the Add button.

Adding the fragment to the extensions

Use xpath:/ as extended element id and descriptors as Feature name.

Adding a part descriptor 1

Right click on this entry and select Add Child  PartDescriptor. Select the Part Descriptor and press the Find button for the Class URI field. Choose the AdditionalInformationPart class.

Adding a part descriptor 2

The generated entry should look like the following coding:

bundleclass://com.vogella.contribute.parts/com.vogella.contribute.parts.AdditionalInformationPart

Now switch to the Supplementary tab and add the following tag:

  • View

To add a tag, enter it and press the Add button, after you entered the text.

Adding a part descriptor 2

The View tag ensures that the Eclipse IDE accepts this part descriptor as valid view, if you use this plug-in in the Eclipse IDE. For pure e4 RCP applications this flag is not needed.

8.8. Update product

Add the new plug-ins to your feature and start via the product file.

8.9. Validate

As you add a part descriptor, this element will not be visible in the RCP application.

Add the Eclipse model spy to your runtime application and ensure that you see the part descriptor. Optional create a new handler which opens a new part based on this part descriptor. This can be done similar to the implementation of the editor per task.

9. Dependency injection and Eclipse

9.1. Define class dependencies in Eclipse

The programming model in Eclipse supports constructor, method and field injection according to the Java Specification Request 330 (JSR330). Eclipse also defines additional annotations for the purpose of dependency injection. The most important annotations are covered in Annotations to define class dependencies in Eclipse, other more special annotations are covered in their corresponding chapters.

The Eclipse dependency framework ensures that the key and the type of the injected object is correct. For example, if you specify that you want to have an object of type Todo for the "xyz" key, as shown in the following field declaration, the framework will only inject an object if it finds one with an assignable type.

@Inject @Named("xyz") Todo todo;

9.2. Annotations to define class dependencies in Eclipse

The following table gives an overview of dependency injection related annotations based on JSR330 and the Eclipse specific ones.

Table 8. Basic annotations for dependency injection
Annotation Description

@javax.inject.Inject

Defined by JSR330, can be added to a field, a constructor or a method. The Eclipse framework tries to inject the corresponding objects into the fields or the parameters of the instance.

@javax.inject.Named

Defined by JSR330, defines the key for the value which should be injected. By default, the fully qualified class name is used as the key. Several keys for default values are defined as constants in the IServiceConstants interface.

@Optional

Eclipse specific annotation, marks an injected value to be optional. If no valid object can be determined for the given key (and type), the framework does not throw an exception.

The specific behavior depends on where the @Optional is placed. The following description is based on the key. If the key cannot be resolved the following happens:

* for parameters: a null value will be injected; * for methods: the method calls will be skipped * for fields: the values will not be injected.

Note that null is an acceptable value to be set in the context, and it is different from a key being removed from the context. For example, if the following is called context.set(SOMEKEY, null), anybody listening for SOMEKEY will be injected with null.

@GroupUpdates

Eclipse specific annotation, indicates that updates for this @Inject should be batched. If you change such objects in the Eclipse context, the update is triggered by the processWaiting() method of the IEclipseContext object. This annotation is intended to be used by the platform for performance optimization and should rarely be necessary in RCP applications.

The Eclipse platform supports additional annotations for special purposes, e.g., for receiving events (sent by the event service) or working with preferences.

9.3. On which objects does Eclipse perform dependency injection?

The Eclipse runtime creates objects for the Java classes referred by the application model. During this instantiation the Eclipse runtime scans the class definition for annotations. Based on these annotations the Eclipse framework performs the injection.

Eclipse does not automatically perform dependency injection on objects which are created in your code with the new operator.

9.4. Dynamic dependency injection based on key / value changes

The Eclipse framework tracks which object expressed a dependency to which key and type. If the value to which a key points changes, the Eclipse framework re-injects the new value in the object which expressed a dependency to the corresponding type. This means applications can be freed from having to install (and remove) listeners.

For example, you can define via @Inject that you want to get the current selection injected. If the selection changes, the Eclipse framework will inject the new value.

The re-injection only works on methods and fields which are marked with @Inject. It will not work on parameters injected into constructors and methods which are marked with @PostConstruct, as these methods are only executed once.

This does not mean that Eclipse tracks the fields of the value to which the key points. For example if the mykey1 key points to a Todo object as value, and the key points to a new object, this triggers the re-injection of the value to all objects which have a relevant class dependency. But if a field inside the existing Todo object changes, it does not trigger a re-injection.

9.5. OSGi services and Eclipse dependency injection

OSGi services are available for dependency injection in Eclipse applications. If you define your custom OSGi services, you can inject them into your model objects. This removes the need to create singleton or factory implementations in your application to access data.

If a requested key is not found in the Eclipse context hierarchy, the Eclipse framework dynamically queries for a fitting OSGi service in the OSGi registry.

Context hierarchy with OSGi

For example, if you have an OSGi service declared for the TaskService interface you can inject it via the following code snippet into a field of an Eclipse part.

@Inject TaskService service;

10. The Eclipse context

10.1. What is the Eclipse context?

During startup of an Eclipse application the Eclipse runtime creates an object based on the IEclipseContext interface. This object is called the context or the Eclipse context.

The context is similar to a Map data structure, in which objects can be placed under a certain key. The key is a String and in several cases the fully qualified class name is used as key. The value (to which the key points) can be injected into other objects. But unlike a map, the Eclipse context is hierarchical and can also dynamically compute values for requested keys.

For certain model objects (see Which model elements have a local context?) a local context is created. Such a context is associated with an application model object.

The different context objects are connected to form a hierarchical tree structure based on the structure of your application model. The highest level in this hierarchy is the application context.

A sample context hierarchy is depicted in the following picture.

Context hierarchy

Objects can be placed at different levels in the context hierarchy. This enables the same key to point to different objects in the hierarchy.

For example, a part can express a dependency to a Composite object via a field declaration similar to: @Inject Composite parent; Since parts have different local contexts they can receive different objects of the type Composite.

10.2. Which model elements have a local context?

Currently the following model elements implement the MContext interface and therefore have their own context:

  • MApplication

  • MWindow

  • MPerspective

  • MPart

  • MPopupMenu

10.3. Life cycle of the Eclipse context

The Eclipse framework creates the context hierarchy based on the application model during the start process. By default, it places certain objects under predefined keys into the context, e.g., services to control the Eclipse framework functionality.

The model objects and the created objects based on the class URI attributes are created by the Eclipse platform. For each model element with a custom context the Eclipse framework determines which objects should be available in the local context of the model object. If required, it also creates the required Java objects referred by the Class URI property of the model elements. This is for example the case if a part is visible to the user.

The renderer framework is responsible for creating the local context of the UI related model elements. This framework allows you to define classes which are responsible for setting up the UI implementation of the model objects. A class responsible for a model element is called the renderer for this model element.

For example, the ContributedPartRenderer class is the default renderer for part model objects. This renderer creates a Composite for every part and puts this Composite into the local context of the part.

After the initial creation of the Eclipse context hierarchy, the framework or the application code can change the key-value pairs stored in the context. In this case objects which were created with the related Eclipse functionality (for example by the Eclipse dependency injection framework) are updated with the new values.

Objects in the context are persisted in memory (transient), i.e., once the application is stopped the context gets destroyed.

10.4. How are objects selected for dependency injection

As described in On which objects does Eclipse perform dependency injection? an object which is created by Eclipse can use annotations to describe its class dependencies.

During dependency injection for an object created by Eclipse, the Eclipse framework searches for a fitting object based on the specified key. The search starts in the local context associated with the application model object. If this key is not available, Eclipse continues to search in the parent context. This process continues until the main context has been reached.

Context hierarchy with OSGi

As you learn in later chapters the Eclipse context is not the only possible source of objects which can get injected. Other examples which are covered later are OSGi services, preferences, events and custom objects. The search happens (mostly) transparently for the caller of the injection.

10.5. How to access the model objects?

For the class references in the application model, the Eclipse framework creates the corresponding objects when needed. Such an object has access to its corresponding model object via dependency injection.

For example, in the implementation of a part you can access the model information of a part via: @Inject MPart part;

10.6. Default entries in the Eclipse context

The Eclipse framework creates several objects in the context. These are:

  • model objects - contain the data of the application model

  • services - software components which are defined by the Eclipse platform or via the OSGi service registry

  • several other objects which have explicitly been added to the context

The context can be modified by the application code and the framework. As the Eclipse framework automatically tracks the dependencies of the objects it creates, it can update them as described in Dynamic dependency injection based on key / value changes.

10.7. Qualifiers for accessing the active part or shell

The Eclipse platform places the part which is currently selected and the active shell into the IEclipseContext of the application object. The related keys are defined in the IServiceConstants interface.

For example, the following method would allow you to track the current active part in another part.

// tracks the active part
@Inject
@Optional
public void receiveActivePart(
    @Named(IServiceConstants.ACTIVE_PART) MPart activePart) {
    if (activePart != null) {
        System.out.println("Active part changed "
                + activePart.getLabel());
    }
}

To track the active shell use the IServiceConstants.ACTIVE_SHELL key.

// tracks the active shell
@Inject
@Optional
public void receiveActiveShell(
    @Named(IServiceConstants.ACTIVE_SHELL) Shell shell) {
    if (shell != null) {
        System.out.println("Active shell (Window) changed");
    }
}

Eclipse uses handlers to define actions which can be triggered via menu or toolbar entries. For a handler implementation class it is not necessary to use these qualifiers, as a handler is executed in the active context of the application.

10.8. Tracking a child context with @Active

The @Active annotation allows you to track values in a child context. The Eclipse framework keeps track of the current active branch in the hierarchy of the IEclipseContext. For example, if the user selects a part, the path in the IEclipseContext hierarchy from the root to the IEclipseContext of the part is the current active branch.

With the @Active annotation you can track values in the current active branch of a child element. Whenever the active branch changes and the value of the referred key changes this value is re-injected into the object which uses the @Active annotation.

The usage of this annotation is demonstrated by the following code snippet.

public class MyOwnClass {
    @Inject
    void setChildValue(
            @Optional @Named("key_of_child_value") @Active String value) {
        this.childValue = value;
    }
}

The @Active annotation is currently not used within the Eclipse framework itself and the author of this tutorial has not yet managed to find a good use case for this annotation.

11. Using annotations to define behavior

11.1. API definition in a framework

If you use a framework in your application, you need to have a convention for how your application interacts with the framework. For example, if a Java object is responsible for handling a toolbar button click, the framework needs to know which method of this object needs to be called.

For this purpose every framework defines an Application Programming Interface (API). This API defines how you can interact with the framework from your code. The API also defines the interaction of application objects created or controlled by the framework. Typically, a framework uses inheritance or annotations for this purpose.

11.2. API definition via inheritance

The "traditional" way of defining an API is via inheritance. This approach requires that your classes extend or implement framework classes and interfaces. The Eclipse 3.x platform API used this approach.

The framework defines, for example, an abstract class which defines methods to be implemented.

In the example of the toolbar button the method might be called execute() and the framework knows that this method must be called once the button is clicked.

API definition via inheritance is a simple way to define an API, but it also couples the classes tightly to the framework. For example, testing the class without the framework is difficult. It also makes extending or updating the framework difficult as such an update may affect clients. This is why the Eclipse 4.x does not use this approach anymore.

11.3. API definition via annotations

The Eclipse 4.x platform API is based on annotations, e.g., annotations are used to identify which methods should be called at a certain point in time. These annotations are called behavior annotations.

The following table lists the available behavior annotations for parts.

Table 9. Eclipse life cycle annotations for parts
Annotation Description

@PostConstruct

Is called after the class is constructed and the field and method injection has been performed.

@PreDestroy

Is called before the class is destroyed. Can be used to clean up resources.

@Focus

Is called whenever the part gets the focus.

@Persist

Is called if a save request on the part is triggered by the Eclipse framework.

@PersistState

Is called before the model object is disposed, so that the part is able to save its instance state. This method is called before the @PreDestroy method.

The @PostConstruct, @PreDestroy annotations are included in the javax.annotation package. @Persist, @PersistState and @Focus are part of the org.eclipse.e4.ui.di package.

Eclipse defines additional behavior annotations for commands and for the application life cycle which are covered in the respective chapters.

Behavior annotations imply that the framework needs to provide the specified parameters to the method, i.e., the framework also performs method dependency injection. If you also add the @Inject annotation, the method is called twice, first during the dependency injection phase and later for the behavior annotation. This is typically undesired and therefore an error.

11.4. Use the @PostConstruct method to build the user interface

It is recommended to construct the user interface of a part in a method annotated with the @PostConstruct annotation. It would also be possible to create the user interface in the constructor, but this is not recommended as field and method injection have not been done at this point.

Creating the user interface in an @PostConstruct method requires that @Inject methods are aware that the user interface might not have been created yet.

Why is the @PostConstruct method not called?

The following description is only valid for Eclipse versions before the Eclipse 4.6 (Eclipse Neon) release. As of Eclipse 4.6 the framework uses the Java version of @PostConstruct and the problem described here, cannot happen anymore.

Before Eclipse 4.6, both Java 7 and the Eclipse platform exposed the @PostConstruct annotation. In your Eclipse application you need to tell the framework that the annotation from the Eclipse platform should be used. org.eclipse.core.runtime exports javax.annotation in the correct version. If, for some reasons, you want to avoid a dependency to org.eclipse.core.runtime, you could define a package dependency to the javax.annotation package and set the version to 1.0.0. See Eclipse 4 RCP FAQ for details on this issue.

12. Exercise: Using @PostConstruct

12.1. Implement an @PostConstruct method

Add the following method to your TodoOverviewPart, TodoDetailsPart and PlaygroundPart classes. In case you created constructors for these classes you can remove them.

import javax.annotation.PostConstruct;
import org.eclipse.swt.widgets.Composite;

// more code

@PostConstruct
public void createControls(Composite parent) {
    System.out.println(this.getClass().getSimpleName()
    + " @PostConstruct method called.");
}

12.2. Validate

Run your application and validate that the @PostConstruct method is called.

If you receive an error message similar to the following: Unable to process "TodoOverviewPart#createControls()": no actual value was found for the argument "Composite"., ensure that your import statement is correct.

import org.eclipse.swt.widgets.Composite;

// MORE code

12.3. Using dependency injection for your code

Dependency injection is triggered for the objects created by the framework and only for the object in which the framework support implemented dependency injection.

In case you want to use DI for the creation of your custom objects you can use the ContextInjectFactory as demonstrated in this example.

Create the following class.

package com.vogella.tasks.ui;

import javax.inject.Inject;

public class ACustomClass {
    @Inject
    public String string;
//
    @Override
    public String toString() {
        return string;
    }
}

Change your playground part to the following.

package com.vogella.tasks.ui;

import javax.inject.Inject;

import org.eclipse.e4.core.contexts.ContextInjectionFactory;
import org.eclipse.e4.core.contexts.EclipseContextFactory;
import org.eclipse.e4.core.contexts.IEclipseContext;

public class PlaygroundPart {
    @Inject
    public PlaygroundPart() {

        IEclipseContext localCtx = EclipseContextFactory.create();
        localCtx.set(String.class, "Hello");

        // You could also connect your new local context with an existing context hierarchy
//      localCtx.setParent(context);

        // Create instance via factory (DI!)
        ACustomClass p = ContextInjectionFactory.make(ACustomClass.class, localCtx);
        System.out.println(p);
    }


}

12.4. Validate

Start your product and ensure that you see the correct output on the console if the playground part is opened. Afterwards remove the System.out statement.

13.1. Adding menu and toolbar entries

You can add menus and toolbars to your Eclipse application via the application model. These entries can be positioned at various places. You can, for example, add a menu to a window or a part. Each element define, directly or indirectly, one or several links to a class which is responsible for the execution. These classes are responsible for the behavior once the menu or toolbar entry is selected. Such a class is called handler class.

13.2. The usage of commands and handlers

The Eclipse application model allows you to specify commands and handlers.

The usage of the commands and handlers model element is optional. You can use the Direct MenuItem or a Direct ToolItem model elements. These entries define a reference to a class (handler class). An instance of this handler class is created by the framework and its annotated methods are called by the framework if necessary. Menus and toolbars support separators.

A command is a declarative description of an abstract action which can be performed, for example, save, edit or copy.

A command is independent from its implementation details. The Eclipse framework does not provide standard commands, e.g., you have to create all required commands in your application model.

The behavior of a command is defined via a handler. A handler model element points to a class (handler class) via the contributionURI property of the handler. This attribute is displayed as Class URI in the model editor.

Commands are used by the Handled MenuItem and Handled ToolItem model elements.

Prefer the usage of commands over the usage of direct (menu or tool) items. Using commands together with handlers allows you to define different handlers for different scopes (applications or part) and you can define key bindings for the handler’s associated commands.

13.3. Behavior annotations and dependency injection for handler classes

In a handler class exactly one method must be annotated with the @Execute annotation. In additional, you can also annotate one method with the @CanExecute annotation. If you annotate more than one method with the same annotation, the framework calls only one of them. The Eclipse runtime uses dependency injection to provide the parameters of the method. The purpose of these annotations are described in the following table.

Table 10. Behavior annotations for handler classes
Annotation Description

@Execute

Marks the method which is responsible for the action of the handler class. The framework executes this method once the related user interface element, e.g., the menu entry, is selected.

@CanExecute

Marks a method to be visited by the Eclipse framework to check if the handler class can be executed. If a handler class returns false in this method, Eclipse disables the corresponding user interface element. For example, the save button is active if the handler class returns true in the @CanExecute method. The default for this method is true, which means, if the handler class can always be executed, it does not need to implement a @CanExecute method.

The following example demonstrates the implementation of a handler class.

package com.vogella.tasks.ui.handlers;

// import statements cut out
// ..

public class ExitHandler {
    @Execute
    public void execute(IWorkbench workbench) {
        workbench.close();
    }

    // NOT REQUIRED IN THIS EXAMPLE
    // just to demonstrates the usage of
    // the annotation
    @CanExecute
    public boolean canExecute() {
        return true;
    }

}

A handler instance does not have its own Eclipse context ( IEclipseContext). It is executed with the Eclipse context of the active model element which has a Eclipse context. In most common cases this is the context of the active part.

All required parameters should be injected into the method annotated with @Execute, as you want the handler class to retrieve its runtime information during execution.

To ensure that you get the expected values from the active context ALWAYS get the required values injected as parameters into your methods annotated with @Execute or @CanExecute.

13.4. Determining the relevant handler for a command

If a command is selected, the runtime determines the relevant handler for the command. The application model allows you to create a handler for the application, a window and a part.

Each command can have only one valid handler for a given scope. The Eclipse framework selects the handler most specific to the model element.

For example, if you have two handlers for the "Copy" command, one for the window and another one for the part then the runtime selects the handlers closest to model element which is currently selected by the user.

13.5. Evaluation of @CanExecute

A method annotated with @CanExecute is called by the framework, if a change in the Eclipse context happens. For example, if you select a new part. If the method returns false, the framework disables any menu and tool items that point to that command.

You can request the re-evaluation of the @CanExecute methods by sending out an event via the event broker.

// evaluate all @CanExecute methods
eventBroker.post(UIEvents.REQUEST_ENABLEMENT_UPDATE_TOPIC, UIEvents.ALL_ELEMENT_ID);

// evaluate a context via a selector
Selector s = (a selector that has an MApplicationElement or an ID);
eventBroker.post(UIEvents.REQUEST_ENABLEMENT_UPDATE_TOPIC, s);


//See  https://bugs.eclipse.org/bugs/show_bug.cgi?id=427465 for details

13.6. Mnemonics

The application model allows you to define mnemonics. A mnemonic appears as an underlined letter in the menu when the user presses and holds the ALT key and allows the user to quickly access menu entries by keyboard.

You specify mnemonics by prefixing the letter intended to be the mnemonic with an ampersand (&) in the label definition. For example, if you use the label &Save, the S will be underlined if the Alt key is pressed.

13.7. Naming schema for command and handler IDs

A good convention is to start IDs with the top level package name of your project and to use only lower case letters.

The IDs of commands and handlers should reflect their relationship. For example, if you implement a command with the com.example.contacts.commands.show ID, you should use com.example.contacts.handler.show as the ID for the handler. If you have more than one handler for one command, add another suffix to it, describing its purpose, e.g., com.example.contacts.handler.show.details.

In case you implement commonly used functions in your RCP application, e.g., save, copy, you should use the existing platform IDs, as some Eclipse contributions expect these IDs to better integrate with the OS (e.g., on Mac OS, preferences are normally placed under the first menu). A more complete list of command IDs is available in org.eclipse.ui.IWorkbenchCommandConstants.

Table 11. Default IDs for commonly used commands
Command ID

Save

org.eclipse.ui.file.save

Save All

org.eclipse.ui.file.saveAll

Undo

org.eclipse.ui.edit.undo

Redo

org.eclipse.ui.edit.redo

Cut

org.eclipse.ui.edit.cut

Copy

org.eclipse.ui.edit.copy

Paste

org.eclipse.ui.edit.paste

Delete

org.eclipse.ui.edit.delete

Import

org.eclipse.ui.file.import

Export

org.eclipse.ui.file.export

Select All

org.eclipse.ui.edit.selectAll

About

org.eclipse.ui.help.aboutAction

Preferences

org.eclipse.ui.window.preferences

Exit

org.eclipse.ui.file.exit

14. Exercise: Adding menus

In this exercise you create commands and handlers for your application. Afterwards you will create menu entries using these commands.

14.1. Create command model elements

Open the Application.e4xmi file of your com.vogella.tasks.ui plug-in and select the Commands entry. This selection is highlighted in the following screenshot.

Adding commands to your application

Via the Add…​ button you can create new commands. The name and the ID are the important fields. Create the following commands.

Table 12. Commands
ID Name

org.eclipse.ui.file.saveAll

Save

org.eclipse.ui.file.exit

Exit

com.vogella.tasks.ui.command.createtask

Create task

com.vogella.tasks.ui.command.removetask

Remove task

com.vogella.tasks.ui.command.fortesting

For testing

14.2. Creating the handler classes

Create the com.vogella.tasks.ui.handlers package for your handler classes.

All handler classes implement an execute() method annotated with @Execute.

package com.vogella.tasks.ui.handlers;

import org.eclipse.e4.core.di.annotations.Execute;

public class SaveAllHandler {
    @Execute
    public void execute() {
      System.out.println((this.getClass().getSimpleName() + " called"));
    }
}

Create now the following classes by copying the above class.

  • SaveAllHandler

  • ExitHandler

  • NewTaskHandler

  • RemoveTaskHandler

  • TestHandler

14.3. Creating handler model elements

Select the application-scoped Handlers entry in your application model and create the handlers from the following table for your commands. For the definition of handlers the ID, command and class are the relevant information.

Use the com.vogella.tasks.ui.handler prefix for all IDs of the handlers.

Table 13. Handlers
Handler ID Command Class

.saveall

Save

SaveAllHandler

.exit

Exit

ExitHandler

.newtask

Create task

NewTaskHandler

.removetask

Remove task

RemoveTaskHandler

.fortesting

For testing

TestHandler

The application model editor shows both the name and the ID of the command. The class URI follows the bundleclass:// schema, the table only defines the class name to make the table more readable. For example, for the handler with the com.vogella.tasks.ui.handler.saveall id uses the following entry to point to his handler class.

bundleclass://com.vogella.tasks.ui/com.vogella.tasks.ui.handlers.SaveAllHandler
Defining a handler in Eclipse 4

14.4. Adding a menu

In your Application.e4xmi file select your TrimmedWindow entry in the model and flag the Main Menu attribute.

menu04

Assign the org.eclipse.ui.main.menu ID to your main menu.

Ensure that this ID of the main menu is correct. You use it later to contribute another menu entry via another plug-in.

Add two menus, one with the name "File" and the other one with the name "Edit" in the Label attribute.

Also set the org.eclipse.ui.file.menu ID for the File menu. Use com.vogella.tasks.ui.menu.edit as ID for the Edit menu.

Creating a menu

Add a Handled MenuItem model element to the File menu. This item should point to the Save command via the Command attribute.

Adding a menu item to the menu

Add a Separator after the Save: menu item into your File. Also add a _Handled MenuItem model element pointing to the Exit via the Command attribute.

Add all other commands you created to the Edit menu.

14.5. Implement a handler class for exit

To test if your handler is working, change your ExitHandler class, so that it closes your application, once selected.

package com.vogella.tasks.ui.handlers;

import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.e4.ui.workbench.IWorkbench;

public class ExitHandler {
    @Execute
    public void execute(IWorkbench workbench) {
        workbench.close();
    }
}

14.6. Validate

Validate that your save handlers are called if you select them in the menu.

14.7. Possible issue: Exit menu entry on a MacOS

If you use the org.eclipse.ui.file.exit ID for your exit command, the Eclipse framework maps the menu entry to its default menu location on the MacOS. If you don’t see your exit menu, in its defined position, check this location.

15. Learn more and get support

This tutorial continues on Eclipse RCP online training or Eclipse IDE extensions with lots of video material, additional exercises and much more content.

If you need more assistance we offer Online Training and Onsite training as well as consulting