1. Introduction to Eclipse-based applications

Eclipse RCP (Rich Client Platform) applications leverage the Eclipse framework to build feature-rich, standalone desktop applications.

An Eclipse application consists of individual software components called plug-ins, which can use and extend other plug-ins. For instance, a plug-in can add new entries to a menu defined by another plug-in.

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

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

Typical components of an Eclipse RCP application

2. Why use Eclipse RCP

Desktop applications are still core tools that drive companies.

Companies frequently use desktop applications to handle their internal processes. Their software often requires a complex user interface and is frequently developed in-house, even if software development is not their primary business. These companies rarely have a large software development team dedicated to maintaining and updating their in-house software.

To develop these in-house applications, companies typically prefer solutions that are easy to use, provide a rich API, and ensure a stable application programming interface (API). They require their selected framework to be easy to maintain, especially if they use the software to support their main line of work.

Eclipse RCP excels in this space.

Customers choose Eclipse RCP because the Eclipse framework:

  • forms the foundation of multiple successful IDEs

  • is stable and widely used, which is an important indicator that it will be supported for many years to come

  • provides native user interface components that are fast and reliable

  • has a strong modular approach, allowing developers to design component-based systems

  • is the foundation for products of companies such as Red Hat, IBM, Microsoft, and SAP, ensuring that the Eclipse framework remains flexible, fast, and continues to evolve

Additionally, the Eclipse platform fosters a large community of individuals who provide support, information, and extensions to the Eclipse framework. It enables customers to contribute to the framework to meet their specific needs.

The Eclipse development team makes a significant effort to keep its API stable, enabling developers to use, update, and maintain it with minimal effort. Moreover, the Eclipse API is constantly enhanced and improved, which benefits RCP users with every release.

3. Examples of existing Eclipse RCP applications

Eclipse RCP applications are frequently used as feature-rich desktop applications within companies. Therefore, only a few of these applications are publicly available. This section provides examples of RCP applications to illustrate the capabilities of the Eclipse framework.

Portfolio Performance is an open-source RCP application primarily developed by Andreas Buchen. The Portfolio Performance application is an open-source tool designed for tracking, analyzing, and visualizing investment portfolios. It provides detailed insights into portfolio performance, asset allocation, and returns over time through customizable charts and reports.

Visit https://www.portfolio-performance.info/ for more information.

Portfolio Performance showing the performance dashboard with charts
Portfolio Performance showing a securities table with a price chart

The 4diac IDE, part of the Eclipse 4diac™ project, supports the development of automation systems that comply with the IEC 61499 standard. This software is widely used in the industry and by researchers exploring IEC 61499.

Visit https://github.com/eclipse-4diac/4diac-ide for more information.

4diac IDE showing the function block development perspective
4diac IDE showing an application editor with function block networks

OpenChrom® is an open-source software application for analyzing chromatographic, mass spectrometric, and spectroscopic data in chemical analytics. The software is used in both quality control and research and development. Lablicate GmbH offers commercial extensions for this product.

Visit https://www.openchrom.net and https://www.lablicate.com for more information.

OpenChrom showing chromatograms in a dark theme
OpenChrom showing a two-dimensional chromatogram heat map

4. Installation

4.1. Download the Eclipse IDE

To develop Eclipse plug-ins and applications, you need to download an Eclipse IDE suitable for this task. The Eclipse project offers multiple downloads specifically for this purpose. The most commonly used options are:

  • The Eclipse SDK (Software Development Kit) provides the minimal functionality needed for Eclipse-based development.

  • The Eclipse IDE for Eclipse Committers package provides additional functionality, such as Git support.

This chapter describes both alternatives, with the SDK download being the recommended one.

The appearance of the download page may change over time.

4.1.1. Alternative 1: Download the Eclipse SDK

Open https://download.eclipse.org/eclipse/downloads/ and click the link for the most recent release (the highest version number). The download section looks similar to the following screenshot.

Eclipse.org Download Page

The download format depends on your platform:

  • Windows uses the zip format.

  • Linux uses the tar.gz format.

  • macOS uses the DMG (Disk Image) format.

The Eclipse SDK does not include a Java runtime, so you need to provide one separately.

4.1.2. Alternative 2: Download the Eclipse IDE for Eclipse Committers package

Download the Eclipse IDE for Eclipse Committers package from the Eclipse packages website.

Eclipse.org download page entry for the Eclipse IDE for Eclipse Committers package

This package includes a Java runtime, so you do not need to install one separately.

Alternatively, you can install this package with the Eclipse installer. The installer is useful if you want to install several versions of Eclipse, as it uses a shared installation pool for common plug-ins, which reduces the required space.

5. Exercise: Create an RCP application using the Eclipse wizard

In this exercise, you create an Eclipse RCP application using a template and launch it via the IDE. The generated files are not yet explained, but this should enable you to see a running application and review the involved configuration files.

5.1. Create project

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

New wizard dialog filtered to the Plug-in Project entry

Use settings similar to the following screenshots.

First page of the New Plug-in Project wizard

Press Next.

Content page of the New Plug-in Project wizard

Press Next.

Templates page of the New Plug-in Project wizard

Press Next.

On the last wizard page, select the Create sample content (part, menu, command…​) flag. This flag adds example content to the generated application, for example a part and some menu and toolbar entries.

Eclipse RCP Application wizard page with sample content option

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

5.2. Launch the application using the product file

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

Starting the Eclipse 4 application

Switch to the Overview tab in the editor and press the Launch an Eclipse application hyperlink to start your application. This option is highlighted in the screenshot below.

Starting the Eclipse 4 application

5.3. Validate

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

Running Eclipse RCP application with a Sample Part and sample items

5.4. Error analysis

If you see an empty window, it means you pressed the Finish button prematurely (after selecting the template) or forgot to select the Create sample content flag on the last tab.

To fix this, delete the generated plug-in and create it again, making sure to select the correct values as described in Exercise: Create an RCP application using the Eclipse wizard.

6. Describing the structure of an Eclipse application

The structure of an Eclipse application is described via an application model. At startup, this application model is constructed from multiple configuration files and adjusted by code, resulting in the runtime application model. The runtime application model is the basis for the running application, and the framework keeps it in sync with the application during runtime.

Diagram of the relationships between application model elements

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

Each model element has attributes that describe its current state, for example, the size and the position of a window. The application model expresses the relationship between model elements via a hierarchy. If necessary, a model element can contain links to Java classes or static resources. For example, a part contains a link to the Java class that is instantiated when the part becomes visible.

The base of the application model is typically defined as a static file. For an Eclipse RCP application, this file is called Application.e4xmi by default and is located in the root directory of the plug-in that defines the product extension. The Eclipse IDE ships with its own base application file provided by the Eclipse Platform.

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, 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 this information and its hierarchy in Java objects, called model objects, which represent the attributes of the model elements at runtime.

An Eclipse IDE runtime or an Eclipse RCP application running in compatibility mode adds model elements based on other configuration data, like view contributions via plugin.xml.

6.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 supports two URI patterns. In most cases, Eclipse instantiates the referred objects or resources lazily. For example, the classes for a part are instantiated when the part becomes visible.

The following table describes the supported URI patterns. The example assumes that the bundle is called test for brevity.

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 the MANIFEST.MF file. The Bundle-SymbolicName is followed by a '/' and the fully qualified class name.

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

Example:

platform:/plugin/test/icons/save_edit.png

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 that points to a Java class via the bundleclass:// URI. This class provides the specific implementation of the part.

Part detail form showing the Class URI attribute

An example of 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.

6.2. Overview of the model objects

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

6.2.1. Application

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

6.2.2. Windows

Eclipse applications consist of one or more windows, represented by MWindow or MTrimmedWindow model elements. MTrimmedWindow can contain trimbars (that can hold toolbars).

Eclipse application showing 2 windows

6.2.3. Parts

Parts are user interface components that allow you to navigate and modify data. Their 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, such as 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 Project 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 must 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 saves the editor. A dirty editor tab is marked with an asterisk to the left of the name of the modified file.

Two editor tabs where the second tab is marked dirty with an asterisk

6.2.4. Available part containers

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

A part stack arranges its children like a browser. It contains a stack of parts and shows their headers while the 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 that contains another part sash container and one part stack. 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 layout

If you set the Container Data for one element, you must define it for all the other elements as well. Otherwise, the missing values default to 5000, so these elements take up most of the available space if the other values are small.

The initial total of all the container data values is maintained when elements in the sash are moved. To allow fine-grained dragging, this total must be commensurate with the screen resolution. A value that is too low (for example, 50 / 50) moves the sash by multiple pixels per unit, which the user perceives as a jerky movement. Therefore, use sufficiently high values, for example, a total of 10000.

6.2.5. Perspectives

A perspective is an optional container for other part containers and parts. It is represented by MPerspective objects that must be placed in an MPerspectiveStack object. Only one of the perspectives in a perspective stack can be active and visible. Perspectives can share elements.

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

You can switch perspectives via the switchPerspective() method of the EPartService service.

6.2.6. Table overview of 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 lifecycle and handle these events.

MWindow

Represents a window in your application.

MTrimmedWindow

Similar to MWindow, but it can contain toolbars (via trim bar model elements).

MPerspective

Represents a layout of parts to be shown inside the window. Must be contained in an MPerspectiveStack.

MPart

Represents the model element part, such as a view or an editor.

MDirtyable

Interface of MPart which provides the dirty flag. If set to true, it informs the Eclipse platform that this part contains unsaved data. In a handler, you can query this flag to provide a save option.

MPartDescriptor

A template for new parts. The EPartService creates and shows new parts based on a part descriptor.

Snippets

Snippets pre-configure model elements that you want to create during runtime. The EModelService clones such a snippet, and you attach the resulting object to the application model.

7. Extending the application model from other plug-ins

7.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 - 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 during the application’s runtime are written back to the model. For example, the user can move 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 the start of your application using the clearPersistedState parameter as a launch parameter. In most cases, this is undesirable behavior for an exported application and is 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 applications you use fragments and processors.

7.2. Model fragments

A model fragment is a file that 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 Feature Name is a link to the model element that you want to extend. The following table lists some Feature Name values and their purposes.

Table 3. Contribution, Feature Name and Element id
You want to contribute to a Feature Name 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

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 that should be extended

The following table gives several examples of 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 is always 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 is the 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 requires that the main menu child is of type menu:Menu. In most applications this is the 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 that is tagged with the Editor tag.

7.3. 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 at 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, the use of first and index might not always give the desired result.

7.4. Model processors

With a processor you can modify the application model via program code during the start of the application. This enables the dynamic creation, removal or modification of model elements.

8. Exercise: Create 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 fewer projects compared to the screenshots.

To avoid confusion with earlier generated projects, you may want to close them. Closed projects are ignored during development. To close a project, right-click on it and select Close Project from the context menu. To open it again, right-click on it again and select Open Project.

Do not close the project that contains your target definition file; otherwise your target platform will become invalid.

8.1. Creating a plug-in project

Create a new plug-in project via the File  New  Other…​  Plug-in Development  Plug-in Project menu entry.

New wizard selecting Plug-in Project

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

First page of the New Plug-in Project wizard with the project name com.vogella.tasks.ui

On the next wizard page, ensure the following settings:

  • 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 option

Second page of the Eclipse Plug-in Wizard specifying the plug-in ID, version, Name, Activator and the RCP type

Press the Finish button.

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

8.2. Review the generated project

Open the project and verify that the src folder contains no Java classes.

Open the META-INF/MANIFEST.MF file. In the manifest editor, switch to the Dependencies tab and ensure that there are no entries.

Manifest editor showing the empty Dependencies tab

8.3. Create a feature project

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

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

New Feature wizard page with the project name com.vogella.tasks.feature

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.

Included Plug-ins tab of the feature editor showing com.vogella.tasks.ui

Add the plug-in on the Included Plug-ins tab, not on the Dependencies tab.

8.4. Create a project to host the product configuration file

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

New wizard selecting the General Project entry
New Project wizard page with the project name com.vogella.tasks.product

Press Finish.

8.5. Create a product configuration file

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

New wizard selecting the Product Configuration entry

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

New Product Configuration wizard page with the file name taskmanagement.product

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

  • com.vogella.tasks.ui as the Defining Plug-in

  • product as the Product ID

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

New Product Definition dialog with the product details

Ensure that an ID, version, and name are set. Version should be set to 1.0.0. Also ensure that you have selected that the product configuration is based on plug-ins and features.

Overview tab of the product editor with product version 1.0.0

8.6. Enter the feature as content into the product

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

  • org.eclipse.e4.rcp

  • com.vogella.tasks.feature

The expected output is shown in the screenshot below.

Contents tab of the product editor listing the required features

8.7. Configure the start levels

Switch to the Configuration tab in the product editor and press the Add Recommended…​ button. The Maven/Tycho build system uses these settings, so it is good practice to configure them.

Configuration tab of the product editor with the start levels

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

New wizard selecting the New Application Model entry

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

New application model wizard page with the container com.vogella.tasks.ui

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

8.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 the com.vogella.tasks.ui.trimmedwindow.taskmanager ID, 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

8.10. Delete persisted UI 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 undesirable during development, as the latest state from the application model file should be used. To ensure that the latest version of your application model is always used, add the following parameter to your product file on the Launching tab.

-clearPersistedState

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

Launching tab of the product editor with the -clearPersistedState program argument

Ensure that the parameter starts with a hyphen and is typed exactly as -clearPersistedState.

8.11. Set the launcher name

Your command line build, which you will configure later, should create an executable named Taskman. On the Launching tab of your product file, enter Taskman in the Launcher Name field.

taskman as launcher

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

Testing section of the product editor with the Launch an Eclipse application hyperlink

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

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

Task Manager application with Overview, Details and Playground parts

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

8.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 the com.vogella.tasks.ui.partsashcontainer.main value into the ID field.

Change the orientation attribute

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

Reselect 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

8.13.2. Create the parts

Add one part to each stack by right-clicking on the part stack and selecting the Add Child  Part menu entry. Use the IDs and labels from the following table.

Enter the label first. While the label field has focus, the editor generates the ID from the project name, the element type and the label. Verify the generated ID against the table.

Table 6. Label and ID for the parts
Label ID

Overview

com.vogella.tasks.ui.part.overview

Details

com.vogella.tasks.ui.part.details

Playground

com.vogella.tasks.ui.part.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, so you see its data.

Part data

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

8.14. Define the API that 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 to use classes from other plug-ins.

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

The org.eclipse.jface plug-in also provides access to the org.eclipse.swt plug-in (as it re-exports its packages).

Use the Add…​ button in the Imported Packages section to add the following packages.

  • jakarta.annotation

  • jakarta.inject

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

Dependencies tab of the manifest editor listing the required plug-ins and imported packages
The added version numbers are minimum versions, allowing you to use a newer version of the plug-in while preventing the use of an older version that may lack the required API.

You can see the resulting changes on the MANIFEST.MF tab of the manifest editor. 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-25
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,
 org.eclipse.e4.core.contexts
Import-Package: jakarta.annotation,
 jakarta.inject

8.15. Create Java classes and connect with the parts

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

These 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 connects the created class to the model object. If you do this, you can skip Connect the Java classes with the parts.

Add a constructor to each class that prints the class name to the console. The following code shows the TodoDetailsPart class.

package com.vogella.tasks.ui.parts;

public class TodoDetailsPart {
    public TodoDetailsPart() {
        System.out.println(getClass().getSimpleName());
    }
}

8.15.2. Connect the Java classes with the 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.

Part detail form showing the Class URI of the overview part

8.15.3. Validate

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

To validate the creation of model objects at runtime, check the Console view for System.out.println() output.

9. More exercises, examples and videos

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

10. Creating (Simple) Plug-ins

The Eclipse IDE provides multiple templates and options for creating plug-ins. These templates and options add code or configuration elements to the generated code and often help you complete tasks more quickly. In this tutorial, we typically want to maintain control and understand what we are doing, so we often avoid these additional options.

If you are asked to create a simple plug-in via the File  New  Other…​  Plug-in Development  Plug-in Project menu entry, use the following options:

  • No activator

  • No contributions to the user interface

  • Not a rich client application

  • Generated without a template

11. 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 the Eclipse IDE or an RCP application.

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

11.2. Add the dependencies

In the MANIFEST.MF file, select the Dependencies tab.

Dependencies tab of the manifest editor of the contribute.parts plug-in

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

  • org.eclipse.core.runtime

  • org.eclipse.jface (which re-exports org.eclipse.swt)

  • org.eclipse.e4.core.di

  • org.eclipse.e4.ui.workbench

  • org.eclipse.e4.ui.di

Also add the jakarta.annotation package dependency.

Dependencies tab of the manifest editor listing the required plug-ins and imported packages

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-25
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: jakarta.annotation

11.3. Enable activation

Set the Activate this plug-in when one of its classes is loaded flag on the Overview tab of the MANIFEST.MF editor.

11.4. Create a part implementation

Create the following class.

package com.vogella.contribute.parts;

import jakarta.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);
    }
}

11.5. Create a model fragment

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

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, Part 2

Press the Finish button.

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

The model fragment wizard adds the Model-Fragment header for the registration and the org.eclipse.e4.ui.model.workbench dependency 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 listing, in which the versions have been removed, as they 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-25
Automatic-Module-Name: com.vogella.contribute.parts
Model-Fragment: parts.e4xmi
Import-Package: jakarta.annotation
Bundle-ActivationPolicy: lazy

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

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

Switch to the Supplementary tab and add the View tag.

To add a tag, enter its name and press the Add button.

Supplementary tab of the Part Descriptor with the View tag

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

11.8. Update product

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

11.9. Validate

A part descriptor is only a template, so it is not visible in the RCP application until a part is created from it.

Add the Eclipse model spy to your runtime application and ensure that you see the part descriptor.

Optionally, create a new direct menu item via the fragment to open this part descriptor.

12. Dependency injection in Eclipse

12.1. Define class dependencies in Eclipse

The programming model in Eclipse supports constructor, method and field injection. It uses the annotations originally defined in Java Specification Request 330 (JSR 330), which have moved to the jakarta.inject namespace. The most important annotations are covered in Annotations to define class dependencies in Eclipse, more specialized annotations are covered in their corresponding chapters.

The Eclipse dependency framework verifies that the key and the type of the injected object are valid. For example, the following field declaration requests an object of type Task for the "xyz" key, and the framework only injects an object with an assignable type.

@Inject @Named("xyz") Task task;

12.2. Annotations to define class dependencies in Eclipse

The following table gives an overview of the dependency injection annotations from JSR 330 and the Eclipse-specific ones.

Table 8. Basic annotations for dependency injection
Annotation Description

@jakarta.inject.Inject

Defined by JSR 330, 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.

@jakarta.inject.Named

Defined by JSR 330, defines the key for the value which should be injected. Without @Named, the fully qualified class name of the injected type 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 as 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. If the key cannot be resolved, the following occurs:

  • for parameters: a null value is injected

  • for methods: the method call is skipped

  • for fields: the value is not injected

Note that null is a valid value in the context, which is different from a key being removed from the context. For example, after context.set(SOMEKEY, null), all objects listening for SOMEKEY get null injected.

@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 for performance optimization in the platform and should rarely be necessary in RCP applications.

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

12.3. The objects on which Eclipse performs dependency injection

The Eclipse runtime creates objects for the Java classes referred to by the application model. During this instantiation, the Eclipse runtime scans the class definition for annotations and performs the injection based on them.

Eclipse does not automatically inject dependencies into objects that are created with the new operator.

12.4. Dynamic dependency injection based on key-value changes

The Eclipse framework tracks which object expressed a dependency on which key and type. If the value associated with a key changes, the Eclipse framework re-injects the new value into all objects that depend on this key. This frees applications 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 injects the new value.

The reinjection only works on methods and fields that are marked with @Inject. It does not work for constructor parameters or for methods marked with @PostConstruct, as these are executed only once.

Eclipse does not track the fields of the value to which the key points. For example, if the mykey1 key points to a Task object and you set a new Task object for this key, the new value is re-injected into all objects that depend on mykey1. But if a field inside the existing Task object changes, no reinjection is triggered.

12.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 searches dynamically for a suitable 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 into a field of an Eclipse part via the following code snippet.

@Inject
TaskService service;

13. The Eclipse context

13.1. Definition of 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 the key. The value (to which the key points) can be injected into other objects. Unlike a map, the Eclipse context is hierarchical and can 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.

Diagram of a sample 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 on a Composite object via a field declaration similar to @Inject Composite parent;. Since parts have different local contexts, they receive different objects of the type Composite.

13.2. Which model elements have a local context?

The following model elements implement the MContext interface and therefore have their own context.

  • MApplication

  • MWindow

  • MPerspective

  • MPart

  • MPopupMenu

13.3. Life cycle of the Eclipse context

During startup, the Eclipse framework creates the context hierarchy from the application model. By default, it assigns specific objects to predefined keys in the context, such as services that control Eclipse framework functionality.

The Eclipse platform creates both model objects and objects derived from class URI attributes. For each model element with its own context, the Eclipse framework determines which objects should be available in the local context of the model object. If required, it creates the Java objects referred to by the Class URI property of the model elements, for example, once a part becomes 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 that 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 created by the Eclipse framework are updated with the new values.

The context is only kept in memory, it is destroyed when the application stops.

13.4. Object selection for dependency injection

As described in The objects on which Eclipse performs dependency injection, an object that 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 suitable 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 application context has been reached.

Diagram of a context hierarchy with the OSGi service lookup

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

13.5. Accessing model objects in the code

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 the part via @Inject MPart part;.

13.6. Default entries in the Eclipse context

The Eclipse framework creates several objects in the context, including:

  • model objects, which contain the data of the application model

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

  • other objects that 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.

13.7. Qualifiers for accessing the active part or shell

The Eclipse platform places the part that 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 tracks the 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 that 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.

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

Whenever the active branch changes and the value of the referred key changes, this value is re-injected into the object that uses the @Active annotation.

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

public class MyOwnClass {
    private String childValue;

    @Inject
    void setChildValue(
            @Optional @Named("key_of_child_value") @Active String value) {
        childValue = value;
    }
}

The Eclipse framework rarely uses the @Active annotation. One example is the progress service of the org.eclipse.e4.ui.progress plug-in, which tracks the active window via @Inject @Optional @Active MWindow window;.

13.9. DI in Eclipse 3.x API code

Eclipse dependency injection was developed for the Eclipse 4.x release. Code that is still based on the 3.x API and runs on a 4.x runtime can access objects available for dependency injection via the PlatformUI class.

// the workbench context, getActiveLeaf() returns the active child context
IEclipseContext context = PlatformUI.getWorkbench().getService(IEclipseContext.class);
IEclipseContext activeContext = context.getActiveLeaf();
// or retrieve an object directly
MyOSGiService osgiService = PlatformUI.getWorkbench().getService(MyOSGiService.class);

14. Using annotations to define behavior

14.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 your code, and the objects created or controlled by the framework, interact with the framework. Typically, a framework uses inheritance or annotations for this purpose.

14.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 with methods to be implemented. In the example of the toolbar button, the method might be called execute(), and the framework calls this method once the button is clicked.

API definition via inheritance is a simple way to define an API, but it 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, because such an update may affect clients. This is why Eclipse 4.x no longer uses this approach.

14.3. API definition via annotations

The Eclipse 4.x platform API is based on annotations, for example, annotations 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 lifecycle 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 and @PreDestroy annotations are included in the jakarta.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 lifecycle, which are covered in the respective chapters.

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

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

Construct the user interface of a part in a method annotated with @PostConstruct. You could create the user interface in the constructor, but 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.

15. Exercise: Use @PostConstruct

15.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 jakarta.annotation.PostConstruct;

import org.eclipse.swt.widgets.Composite;
// more code

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

15.2. Validate

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

If you receive an error message similar to Unable to process "TodoOverviewPart#createControls()": no actual value was found for the argument "Composite"., ensure that you imported the SWT Composite.

import org.eclipse.swt.widgets.Composite;

// MORE code

16. Exercise: Using dependency injection in the code

You can create objects using dependency injection and make them available for other objects by placing them in the IEclipseContext. To use dependency injection for the creation of your custom objects, use the ContextInjectionFactory, as demonstrated in this example.

16.1. Implementation

Create the following class.

package com.vogella.tasks.ui.parts;

import jakarta.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.parts;

import jakarta.inject.Inject;
import jakarta.inject.Named;

import org.eclipse.e4.core.contexts.ContextInjectionFactory;
import org.eclipse.e4.core.contexts.EclipseContextFactory;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.ui.workbench.IWorkbench;

public class PlaygroundPart {
    @Inject
    public PlaygroundPart(@Named(IWorkbench.APPLICATION_CONTEXT_KEY) IEclipseContext ctx) { (1)
        IEclipseContext localCtx = EclipseContextFactory.create();
        localCtx.set(String.class, "My object available for DI");

        // optionally connect the local context with the existing context hierarchy
        // localCtx.setParent(ctx);

        ACustomClass p = ContextInjectionFactory.make(ACustomClass.class, localCtx); (2)
        ctx.set(ACustomClass.class, p); (3)
    }
}
1 Injects the application context.
2 Creates the instance via dependency injection, using the local context.
3 Stores the new object in the application context, which makes it available for dependency injection in the whole application.

16.2. Retrieve the created object via DI

Adjust your TodoDetailsPart class to get the new object injected.

package com.vogella.tasks.ui.parts;

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

import jakarta.inject.Inject;

public class TodoDetailsPart {

    @Inject
    @Optional (1)
    public void receiveCustomObject(ACustomClass customObject) {
        System.out.println("Received: " + customObject);
    }
}
1 Using @Optional at the method level instructs the framework to call this method only if the context key can be found in the relevant IEclipseContext hierarchy.

16.3. Validate

Start your product and ensure that you see the correct output on the console. Afterwards, remove the System.out statement.

17.1. Adding menu and toolbar entries

You can add menus and toolbars to your Eclipse application using the application model and position these entries at various locations. You can, for example, add a menu to a window or a part. Each element defines, directly or indirectly, one or more links to a class that is responsible for the execution. Such a class is called a handler class and defines the behavior once the menu or toolbar entry is selected.

17.2. Using commands and handlers

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

You can use the Direct MenuItem or Direct ToolItem model elements. These entries define a reference to a class (handler class). The framework creates an instance of this handler class and calls its annotated methods when necessary. Menus and toolbars support separators.

A command is a declarative description of an abstract action that can be performed, for example, Save, Edit, or Copy.

A command is independent of its implementation details. The Eclipse framework does not provide standard commands, so 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 commands over direct (menu or tool) items. Commands together with handlers allow you to define different handlers for different scopes (application, window or part), and you can define key bindings for the commands.

17.3. Behavior annotations and dependency injection for handler classes

In a handler class, exactly one method must be annotated with @Execute. In addition, you can annotate one method with @CanExecute. If multiple methods in a handler class are annotated with the same annotation, the framework executes only one of them. The Eclipse runtime uses dependency injection to provide the parameters of the method. The purpose of these annotations is 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, for example, the menu entry, is selected.

@CanExecute

Marks a method which the Eclipse framework calls to check if the handler class can be executed. If this method returns false, Eclipse disables the corresponding user interface element. For example, the save button is only enabled if the handler class returns true in its @CanExecute method. Without a @CanExecute method, the handler can always be executed.

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 demonstrate the usage of the annotation
    @CanExecute
    public boolean canExecute() {
        return true;
    }
}

A handler instance does not have its own IEclipseContext. It is executed with the Eclipse context of the active model element that has an Eclipse context. In most cases, this is the context of the active part.

Inject all required parameters into the method annotated with @Execute, as the handler class should retrieve its runtime information during execution.

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

17.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 currently selected model element.

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

17.5. Trigger the evaluation of the @CanExecute method

The framework calls a method annotated with @CanExecute if the Eclipse context changes, for example, if you select a new part. If the method returns false, the framework disables the menu and tool items that point to that command. Menu items are evaluated whenever the menu is shown.

You can request the re-evaluation of the @CanExecute methods of tool items by sending out an event via the event broker. The event data is either UIEvents.ALL_ELEMENT_ID, the ID of a model element or a Selector.

// evaluate all tool items
eventBroker.post(UIEvents.REQUEST_ENABLEMENT_UPDATE_TOPIC, UIEvents.ALL_ELEMENT_ID);

// evaluate the tool items selected by a Selector
Selector selector = element -> element.getTags().contains("refreshable");
eventBroker.post(UIEvents.REQUEST_ENABLEMENT_UPDATE_TOPIC, selector);

17.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 as the mnemonic with an ampersand (&) in the label definition. For example, if you use the label &Save, the S is underlined if the Alt key is pressed.

17.7. Naming scheme 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 lowercase letters.

The IDs of commands and handlers should reflect their relationship. For example, if you implement a command with the com.example.contacts.command.show ID, 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 describing its purpose, for example, com.example.contacts.handler.show.details.

If you implement commonly used functions in your RCP application, for example, save or copy, use the existing platform IDs, as some Eclipse contributions expect these IDs to better integrate with the OS (for example, on macOS, preferences are normally placed under the first menu). A list of command IDs is available in org.eclipse.ui.IWorkbenchCommandConstants.

.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

18. Exercise: Adding menus

In this exercise, you create commands and handlers for your application and add menu entries for them.

18.1. Create command model elements

Open the Application.e4xmi file of your com.vogella.tasks.ui plug-in and select the Commands entry.

Adding commands to your application

Via the Add…​ button you can create new commands. This selection is highlighted in the following screenshot.

The name and the ID are the important fields. Create the following commands.

Table 11. 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

18.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(getClass().getSimpleName() + " called");
    }
}

Now, create the following classes by copying the above class.

  • SaveAllHandler

  • ExitHandler

  • NewTaskHandler

  • RemoveTaskHandler

  • TestHandler

18.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 handlers, the ID, command and class are the relevant fields.

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

Table 12. 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:// scheme, the table only lists the class name to stay readable. For example, the handler with the com.vogella.tasks.ui.handler.saveall ID uses the following class URI.

bundleclass://com.vogella.tasks.ui/com.vogella.tasks.ui.handlers.SaveAllHandler
Handler with the Save command and the SaveAllHandler class URI

18.4. Adding a menu

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

Trimmed Window detail form with the Main Menu flag set

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

Ensure that the 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 label File and another with the label Edit.

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 reference the Save command via the Command attribute.

Handled Menu Item referencing the Save command

Add a Separator after the Save menu item in your File menu. 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.

Afterwards, the menu structure should be like the following:

File and Edit Menus
File
 ├── Save
 └── Exit
Edit
 ├── Create task
 ├── Remove task
 └── For testing

18.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();
    }
}

18.6. Validate

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

18.7. Possible issue: Exit menu entry on 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 the exit entry is not visible in your menu, look for it in the default location on macOS (the application menu).

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

Home Tutorials Training Consulting Books Company Contact us


Get more...