vogella training Android Training Eclipse Training

Eclipse 4 RCP - Tutorial

Building Eclipse RCP applications based on Eclipse 4

Lars Vogel

Version 6.3

20.04.2012

Revision History
Revision 0.1 14.02.2009 Lars
Vogel
created
Revision 0.2 - 6.3 16.02.2009 - 20.04.2012 Lars
Vogel
bug fixes and enhancements

Eclipse e4

This tutorial gives an overview about the Eclipse 4 application platform.

This tutorial describes the creation of Eclipse 4 based applications, e.g. Eclipse RCP applications. It describes the modeled application concept and the new programming model which is based on annotations and dependency injection.


Table of Contents

1. Eclipse 4
1.1. What is Eclipse 4?
1.2. What is the Eclipse e4 project?
1.3. Provisional API
2. The Architecture of Eclipse
2.1. Eclipse based applications
2.2. Terminology
2.3. Important Configuration for Eclipse components
3. Tutorial: Install Eclipse 4.2 for RCP development
3.1. Prerequisites
3.2. Download and Install Eclipse
3.3. Install the Eclipse 4 tooling
3.4. Optional: Download the integration build
3.5. Optional: Remove warnings for provisional API access
4. Tutorial: Eclipse 4 application using the wizard
4.1. Overview
4.2. Create project
4.3. Launch
5. Eclipse 4 application model
5.1. What is the application model?
5.2. Where is the application model defined?
5.3. How is the model connected to my Java classes?
5.4. URI in the Model
5.5. Application model editor
5.6. Model access at runtime
5.7. Meta-model of the application model
5.8. Creation of the Application model
6. Identifiers for model elements
6.1. Identifiers for model elements
6.2. Best practices for naming conventions
7. Bugs in Eclipse 4 M7
7.1. Eclipse 4 templates
8. Tutorial: Create an Eclipse plug-in
8.1. Create plug-in project
8.2. Validate the result
9. Feature Project
10. Tutorial: From Plug-in to Eclipse 4 application
10.1. Create Product configuration
10.2. Create a feature project
10.3. Enter feature dependencies in product
10.4. Create Application model
10.5. Add model elements to application model
10.6. Start Application
10.7. Add plugin dependencies
11. Important User Interface Components
11.1. Windows
11.2. Parts
11.3. Perspective
11.4. Part Stacks and PartSashContainer
12. Tutorial: Modeling a User Interface
12.1. Overview
12.2. Adding model elements
12.3. Create Java classes and connect to the model
12.4. Test
13. Dependency Injections and Annotations
13.1. What is Dependency Injection?
13.2. Define dependencies in Eclipse
13.3. What can get injected?
13.4. How does dependency injection work in Eclipse 4?
14. Behavior Annotations
14.1. API definition via inheritance
14.2. API definition via annotations
14.3. Lifecycle Hooks
15. Tutorial: Using dependency injection
15.1. Getting a Composite
15.2. Validation
16. Exercise: Define Part Lifecycle
16.1. Using @PostConstruct and @PreDestroy
16.2. Validate
17. Commands, Handlers, Menus, Toolbars and Popups
17.1. Overview
17.2. Default commands
17.3. Menus and Toolbar
17.4. View Menus
17.5. Popup Menu - Context Menu
17.6. Scope of handlers
17.7. Core expressions
17.8. Naming schema for command and handler ID
18. Tutorial: Defining and using Commands and Handlers
18.1. Defining Commands
18.2. Defining Handler classes
18.3. Defining Handlers in your model
18.4. Adding a Menu
18.5. Adding a Toolbar
18.6. Closing the application
19. Keybindings
19.1. Overview
19.2. BindingContext entries using by JFace
19.3. Define Shortcuts
20. Scope of injection
20.1. What can be injected?
20.2. How are objects searched?
20.3. What are the relevant classes and interfaces
20.4. Who creates the context for model elements?
21. Model elements and dependency injection
21.1. Available Model elements
21.2. Example: Dynamically create a new Window
21.3. Example: Dynamically create a new Part
21.4. Example: Implement Editor behavior with MDirtyable
21.5. Example: Getting the command line arguments
22. Model Addons
23. Accessing and extending the Eclipse context
23.1. Accessing the context
23.2. Putting objects in the context
23.3. Best practices
24. Using dependency injection for your own Java objects
24.1. Overview
24.2. Using dependency injection to get own objects
24.3. Using dependency injection to create objects
25. Closing words
26. Thank you
27. Questions and Discussion
28. Links and Literature
28.1. Source Code

1. Eclipse 4

1.1. What is Eclipse 4?

Eclipse 4 introduces a new set of technologies which increase the flexibility of Eclipse plug-in development. The next simultaneous release of Eclipse named Juno in June 2012 will be based on Eclipse 4.2.

Eclipse 3.8 will be released in parallel to Eclipse 4.2 but the Eclipse 3.x series will be discontinued after the Eclipse 3.8 release, e.g. there will not be a Eclipse 3.9 release. Eclipse 3.8 will receive bug fixes for a year via service releases.

Eclipse 4 has the goal to solve some of the pain points of Eclipse 3.x development. The major enhancements in Eclipse 4.x compared to Eclipse 3.x are:

  • The Eclipse application is described via a defined structure called the application model.

  • This application model is available and can be modified at development and runtime.

  • Eclipse 4 supports dependency injection.

  • Eclipse widgets can be styled via CSS like files, similar to webpages.

  • The application model is decoupled from its presentation, e.g. different user interface toolkits, e.g. SWT or JavaFX, can be used to render the model.

Eclipse 4 provides a compatibility layer which allows to run Eclipse 3.x plug-ins unmodified.

Eclipse 4 primarily contains enhancements for Eclipse based development. The user of the Eclipse IDE, e.g. a web developer or a Swing developer, will only indirectly benefit because tool development of Eclipse becomes easier. This allows the Eclipse developers to create better tools for the Eclipse users.

1.2. What is the Eclipse e4 project?

"Eclipse e4" is the name of the project which created the Eclipse 4 product. Originally the term "e4" was used for the project as well as for the product. Today it is only the name of the project.

The e4 project includes several technology evaluations. Some of these evaluations have have been ported back to the core Eclipse framework. All functionalities in this description are part of the official Eclipse 4 release, except of the "Eclipse e4 tooling" project.

The subproject "Eclipse e4 tooling" provides tools to develop Eclipse 4 applications. They are very useful, but have not been added to the Eclipse core because they are not as mature as the other components.

Projects like XWT, TM or OpenSocial Gadgets, which are also part of the Eclipse e4 project, are not included in the standard Eclipse 4.2 core platform and are not described in this document.

1.3. Provisional API

Currently the Application Programming Interface (API) for Eclipse 4 is still marked as provisional, i.e. this means that the API might be changed in the future.

Eclipse 4.2 already runs the complete Eclipse IDE. Therefore it is unlikely that dramatic changes will occur in the future.

It is therefore relatively safe to start using the API now, but nevertheless you must be prepared that you might have to do adjustments to your application.

2. The Architecture of Eclipse

2.1. Eclipse based applications

An Eclipse application consists of individual software components. The Eclipse IDE can be viewed as a special Eclipse application with the focus to support software development.

The components of the Eclipse IDE are primarily the following.

Important Eclipse IDE components

OSGi is a specification which describes a modularity approach for Java application. Equinox is one implementation of OSGi and is used by the Eclipse platform. The Equinox runtime provides the necessary framework to run a modular Eclipse application.

SWT is the standard UI component library used by Eclipse and JFace provides some convenient API on top of SWT. The workbench provides the framework for your application. The workbench is responsible for displaying all other UI components.

On top of these base components, the Eclipse IDE adds components which are important for an IDE application, for example the Java Development Tools (JDT) or version control support (EGit).

Eclipse 4 has a different programming model then Eclipse 3.x. Therefore the "3.x Compatibility Layer" components maps the 3.x API to the 4.0 API. This allows to run Eclipse 3.x based components unmodified on Eclipse 4.

Eclipse based applications which are not primary used as software development tools are called Eclipse RCP applications. An Eclipse 4 RCP application typically use the base components of the Eclipse platform and add additional application specific components.

Typical components of an Eclipse RCP application

Equinox allows to define dynamic software components, i.e. OSGi services, which can also be part of an Eclipse based application.

2.2. Terminology

An Eclipse application consists out of several Eclipse components. A software component in Eclipse is called "Plug-in". A software component in OSGi is called "bundle". Both terms can be used interchangeably.

This description uses the terms "Eclipse based applications", "Eclipse application", "Eclipse 4 application" and "Eclipse RCP application" interchangeably for referring to an application which is based on the Eclipse 4 framework.

If a certain concept refers to Eclipse 3.x, then it is explicitly stated.

2.3. Important Configuration for Eclipse components

An Eclipse plug-in has the following main configuration files.

  • MANIFEST.MF - contains the OSGi configuration information.

  • plugin.xml - Contains information an Eclipse specific extension mechanisms

An Eclipse plug-in defines its API via the MANIFEST.MF file, e.g. the Java packages which can be used by other plug-ins and its dependencies, e.g. the packages or plug-ins which are required by the plug-in.

The plugin.xml file allows to define extension points and extensions. Extension-points define interfaces for other plug-ins to contribute functionality (code and non-code). Extensions contribute functionality to these interfaces. (code and non-code).

In Eclipse 4 the usage of extension points and extensions is very limited. They are mostly used to define pointers to other Eclipse 4 configuration files.

3. Tutorial: Install Eclipse 4.2 for RCP development

3.1. Prerequisites

The following assumes that you have Java installed in at least version 1.6.

3.2. Download and Install Eclipse

The Eclipse e4 project create regular milestone and release candidate builds. Integration builds of the current source are triggered weekly.

Download the Eclipse M7 Build of Eclipse 4.2 for your operating system using the following link.

http://download.eclipse.org/eclipse/downloads/

The download is a zip file, which is a compressed archive of multiple files. Most operating systems can extract zip files in their file browser. For example if you are using Windows7 as operating system, right mouse click on the file in the explorer and select "Extract all...". If in doubt how to unzip, search via Google for "How to unzip a file on ...", replacing "..." with your operating system.

Do not extract Eclipse to a directory with a path which contains spaces; this might lead to problems in the usage of Eclipse.

After you extracted the zip file, double-click the file "Eclipse.exe" (Windows) or "eclipse" (Linux) (or the launcher icon specific to your platform) to start Eclipse.

Select an empty directory as the workspace. The workspace contains all your project files. To avoid any collision with existing work, we want to use a new one.

3.3. Install the Eclipse 4 tooling

The Eclipse SDK download does not include the Eclipse e4 tooling, which makes creating Eclipse 4 applications easier. These tools provide wizards to create Eclipse 4 artifacts and the specialized model editor for the application model.

The correct update side for the Eclipse tooling fitting to the Eclipse 4.2 release from above is the following.

http://download.eclipse.org/e4/downloads/drops/S-0.12M7-201205032200/repository/

From this update side, install only the "E4 CSS Spy" and the "Eclipse e4 Tools".

Install the Eclipse 4 tooling

3.4. Optional: Download the integration build

The milestones builds (M-build) and release candidates (RC-builds) should be relatively stable. Sometimes you want to test a recent fix; for this you can download an integration build. An integration build is typically created once per week while a milestone build is created approx. every 4-6 weeks.

The latest Integration Build of Eclipse 4.2 can also be found on the Eclipse Download Site under the "Stream Integration Builds" label.

If you install the latest integration build, you should use the corresponding update site for the e4 tooling, which is Eclipse e4 tools integration update site .

3.5. Optional: Remove warnings for provisional API access

The Eclipse 4 API has not yet been released. Per default Eclipse will create warnings in your coding if you use provisional API.

You can turn of these warnings for your workspace via WindowPreferencesJavaCompilerErrors/Warnings and setting the "Discouraged Access" to ignore.

Turning of the Eclipse warnings

Alternatively you can turn these warnings of on a per project basis, via right-click on the project PropertiesJava Compiler and afterwards the same path as the global settings. You might have to activate the "Enable project specific settings" checkbox.

4. Tutorial: Eclipse 4 application using the wizard

4.1. Overview

The Eclipse 4 tooling project provides a project generation wizard which allows you to create a working Eclipse 4 based RCP application.

4.2. Create project

Select FileNewOtherse4e4 Application Project .

Create a project called de.vogella.e4.rcp.wizard using the default settings. This should be similar to the following screenshots.

This wizard created all necessary files to start your application. The central file for starting your application is the .product file, created in your project folder.

4.3. Launch

Open your "de.vogella.e4.rcp.wizard.product" product configuration file. Switch to the "Overview" tab and launch your product by pressing the "Launch an Eclipse application" hyperlink. This should start the generated Eclipse application.

5. Eclipse 4 application model

5.1. What is the application model?

The visual part of an Eclipse application consists of Perspectives, Parts (Views and Editors), Menus etc. An Eclipse application also includes non-visual components, e.g. Handlers, Commands and Keybindings.

Eclipse 4 uses an abstract description; called the application model; to describe the structure of an application. This application model contains the visual elements as well as some non-visual elements of the Eclipse 4 application.

Each model element has attributes which describe its current state, e.g. the size and the position for a Window. Model elements might be in a hierarchical order, for example Parts might be grouped below a Perspective.

The application model defines the structure of the application; it does not describe the content of the individual user interface components.

For example the application model describes which Parts are available. But it does not describe the content of the Part, e.g. the labels, text fields and button it consists of. The content of the Part is still defined by your source code.

If the application model would be a house, it would describe the available rooms (Parts) and their arrangement (Perspectives, Stacks, Sashes) but not the furniture of the rooms. This is illustrated by the following image.

Limits of the modeled workbench

5.2. Where is the application model defined?

The application model is extensible. The basis of this model is typically defined as a static file. The default name for this file is Application.e4xmi.

You can change the default via the org.eclipse.core.runtime.products extension point to specify the model file via the applicationXMI parameter.

The XMI file is read at application startup and the initial application model is constructed from this file.

5.3. How is the model connected to my Java classes?

Application model elements can contain references to Java classes via an URI.

The URI describes the location of the Java class. The first part of this URI is the plug-in, the second one the package and the last one the class.

For example a model description for a part (View or Editor) contains attributes like labels, tooltips and icon URI's. It also contains a class URI which points to a Java class for this element. If the model elements get activated this class will get instantiated.

The objects created based on the application model are called model objects.

5.4. URI in the Model

URI's follow two patterns. One for identifying resources and another one for identifying classes.

Table 1. URI pattern

Pattern Description

bundleclass://Bundle-SymbolicName/package.classname

Example:

bundleclass://com.example.e4.playground3/com.example.e4.playground3.parts.MySavePart

Used to identify Java classes. It consists of the following parts: "bundleclass://" is a fixed schema, Bundle-SymbolicName as defined in the MANIFEST.MF file, and the fully qualified classname.

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

Example:

platform:/plugin/com.exmaple.e4.playground3/icons/save_edit.gif

Identifier for a resource in the plug-in. "platform:/plugin/" is a fixed schema, followed by the Bundle-SymbolicName of the MANIFEST.MF file, followed by the path to the file and the filename.

5.5. Application model editor

The Eclipse tooling project provides an editor which makes it easier to work on an application model.

To open the model editor double-click on your Application.e4xmi file (or right click on it and select Open-Withe4 Workbenchmodel Editor .

Open editor for the Eclipse modeled workbench

The model editor has also several preference settings which can be reached via WindowPreferencesModel Editor. The following screenshot shows the preference page.

Preference Page for the model editor

5.6. Model access at runtime

The application model is also available at runtime. The application can access the model and change it via a defined API.

Add the org.eclipse.e4.tools.emf.liveeditor plug-in and its dependencies to your launch configuration to make the model editor available in your application.

Afterwards you can open the model editor for your running application via the ALT+Shift+F9 shortcut. This also works for the Eclipse 4 IDE itself.

You can change your application model directly at runtime by using the model editor. Most changes are directly applied, e.g. if you change the orientation of a perspective your user interface will update itself automatically.

In the life model editor, you can select the Part element, right click on it and select Show Control to get the Part highlighted.

5.7. Meta-model of the application model

The possible structure of the application model is defined by an Eclipse EMF meta-model.

Eclipse EMF is a popular general purpose modeling framework. Eclipse EMF uses an .ecore file to define the structure.

The meta-model of the Eclipse application model is stored in the org.eclipse.e4.ui.model.workbench plug-in in model folder. The base model definition can be found in the UIElements.ecore file. Based on this meta-model Eclipse EMF is used to generate the model classes.

If you want to investigate this model, you could install the EMF tooling via the Eclipse update manager and import the defining plug-in into your workspace. To import a plug-in from your current Target Platform (default is the Eclipse IDE) into your workspace, use the Plug-ins View, right click on a plug-in and select Import-asSource Project.

5.8. Creation of the Application model

During startup the Eclipse runtime creates the application model and instantiates the referred classes in the model if required.

The life cycle of every model object is therefore controlled by the Eclipse runtime. The Eclipse runtime instantiates and destroys the model objects.

6. Identifiers for model elements

6.1. Identifiers for model elements

Every model elements allow to define an ID. This ID is used by the Eclipse framework to identify this model element. Make sure you always maintain an ID for every model elements and ensure that these ID's are unique.

Therefore make sure that all your model elements have an ID assigned to them.

6.2. Best practices for naming conventions

The following suggest best practises for naming convensions, which are also used in this description.

Table 2.  Naming conventions

Object Description
Project Names The plug-in project name is the same as the top-level package name.
Packages For plug-in containing lots of user interface components use sub-packages based on the primary purpose of the components. For example the com.example package may have the com.example.parts and com.example.handler sub-package.
Class names for model elements Use the primary purpose of the model element as a suffix in the class name. For example a class which represents a Part which displays Todo objects, might be called TodoOverviewPart.
ID's

The ID's of your application model and your plugin.xml file are API, therefore define clear rules for naming ID's in plugin.xml.

ID's should always start with the top-level package. If appropriate use the sub-package of the implementing class also. The remainder of the ID should be descriptive for the purpose of the component. For example: "com.example.parts.todolist".

ID should be only lower cases (some Eclipse projects also use camelCase for the last part of the ID).


7. Bugs in Eclipse 4 M7

8. Tutorial: Create an Eclipse plug-in

8.1. Create plug-in project

In the following tutorial we will create a standard Eclipse Plug-in called "com.example.e4.rcp.todo".

In Eclipse select FileNew Project

Selection the Eclipse Plug-in Wizard

Give your plug-in the name "com.example.e4.rcp.todo".

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

Press Next and make the following settings. Select No at the question Would you like to create a rich client application and uncheck This plug-in will make contributions to the UI . Uncheck the Generate an activator, a Java class that controls the plug-ins life-cycle `` 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; we will not use a template.

8.2. Validate the result

Open the project and check if Java classes were created. You should have no classes in the source folder.

Open the MANIFEST.MF file and switch to the tab Extensions. Validate that the list of Extensions is currently empty.

9. Feature Project

An Eclipse feature project contains features . A features has a name, version number, a software license and contains a list of plug-ins and other features which can be understood as a logical unit.

A feature is described via a feature.xmlfile in the Eclipse feature project.

Features are used for the Eclipse update manager, the build process and optionally for the definition of Eclipse products. Features can also be used as the basis for a launch configuration.

Eclipse provides several predefined features, e.g. org.eclipse.rcp for Eclipse 3.x based RCP applications or org.eclipse.e4.rcp for Eclipse 4.x based RCP applications.

You can create a new feature project via the following menu path. File NewOtherPlug-in Development Feature Project .

If you open the "feature.xml" you can change the feature properties via a special editor.

The tab "Plug-ins" allows you to change the included plug-ins in the feature.

The "feature.xml" file is a simple text file. For example the "feature.xml" file might look like the following in a text editor.

			
<?xml version="1.0" encoding="UTF-8"?>
<feature
      id="de.vogella.featuretest.feature"
      label="Feature"
      version="1.0.0.qualifier">

   <description url="http://www.example.com/description">
      [Enter Feature Description here.]
   </description>

   <copyright url="http://www.example.com/copyright">
      [Enter Copyright Description here.]
   </copyright>

   <license url="http://www.example.com/license">
      [Enter License Description here.]
   </license>

   <plugin
         id="de.vogella.featuretest.testplugin"
         download-size="0"
         install-size="0"
         version="0.0.0"
         unpack="false"/>

</feature>

		

10. Tutorial: From Plug-in to Eclipse 4 application

In this chapter we convert the Eclipse plug-in into an Eclipse 4 application.

10.1. Create Product configuration

We will now create a "todo.product" product configuration file which uses the E4Application.

Right click on your project and select NewProduct Configuration

To define that your product uses the E4Application application, press the New button on the Overview tab of the product editor. Enter to-do as the name, the defining plug-in is your plug-in and use the name product as ID.

We must use the E4Application class.

10.2. Create a feature project

Create the com.example.e4.rcp.todo.feature feature project.

Include the com.example.e4.rcp.todo plug-in into that feature.

10.3. Enter feature dependencies in product

Change your product configuration file to use features. To do this open your product configuration file and select the Feature option on the Overview tab of the product editor.

Switching to feature on the product configuration file

Select the Dependencies tab and add the org.eclipse.e4.rcp and the com.example.e4.rcp.todo.feature features as dependency via the Add button.

Switching to feature on the product configuration file

Press the Add Required button. This will add the org.eclipse.emf.common and org.eclipse.emf.ecore features to the dependencies.

10.4. Create Application model

Select FileNewOthere4 ModelNew Application Model to open a wizard. Use the project as container and the file name suggested by the wizard.

This will create the Application.e4xmi file and open this file with the application model editor.

10.5. Add model elements to application model

Add one Window to your application model to have a visual component.

Select the Windows node and press the + Button (the Add... button) for a TrimmedWindow.

Adding a trimmed window

Enter an ID, the position and size of the window and a label as giving in the screenshot below.

Enter the data for the TrimmedWindow in the model editor

10.6. Start Application

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. It should be an empty application, which can be moved and closed.

10.7. Add plugin dependencies

We want in later chapters to use functionality from specific other plug-ins which we add here.

Open your plugin.xml file and select the Dependency tab. Use the Add button to add the following plug-ins as dependency.

  • org.eclipse.swt

  • javax.inject

  • org.eclipse.e4.core.di

  • org.eclipse.e4.ui.workbench

11. Important User Interface Components

This chapter gives an overview of the purpose of the model elements created by the model editor. It will cover the most important model elements.

11.1. Windows

Eclipse applications consist out of one or more Windows. Typically an application has only one Window but you are not not limited to that, e.g. if you want to support multiple displays for two connected monitors.

Eclipse application showing 2 windows

11.2. Parts

Parts are user interface components which allow to navigate and modify data. Parts are typically divided into Views and Editors.

Eclipse application with a few parts

The distinction into Views and Editors is primarily not based on technical differences, but on a different concept of using and arranging these Parts.

A View is typically used to work on a set of data, which might be hierarchical structured. If data is changed via the View, this change is typically directly applied to the underlying data structure. A View sometimes allows us to open an Editor for a selected set of the data.

An example for a View is the Java Package Explorer, which allow you browse the files of Eclipse Projects. If you choose to change data in the Package Explorer, e.g. if you rename a file, the file name is directly changed on the filesystem.

Editors are typically used to modify a single data element, e.g. a file or a data object. To apply the changes done in an editor to the data structure, the user has to explicitly save the editor content.

Editors were traditionally placed in a certain area, called the "editor area". Until Eclipse 4 this was a hard limitation, it was not possible to move an Editor out of this area; Eclipse 4 allows to place Editors at any position in a Perspective.

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" command.

11.3. Perspective

A Perspective is a visual container for a set of Parts. The Eclipse IDE uses Perspectives to arrange Parts for different development tasks.

You can change the layout and content within a Perspective by opening or closing Parts and by re-arranging them.

As of Eclipse 4.x Perspectives are optional elements for Eclipse applications.

11.4. Part Stacks and PartSashContainer

Parts can be directly assigned to a Window or a Perspective. If you want to group and arrange Parts you can use PartStacks and PartSashContainers. PartStacks contain a stack of Parts of which only one is visible at the same time and can be selected via tabs. A PartSashContainer displays all its children at the same time horizontally or vertically.

The following shows a simple Eclipse application layout using two PartSashContainers and a few PartStacks.

An example arrangement of Parts in an Eclipse application

On the top of this layout there is a horizontal PartSashContainer which contains another PartSashContainer and some Part Stacks. The hierachy is depicted in the following graphic.

The hierarchy of Parts using Part Stacks and PartSashcontainers.

12. Tutorial: Modeling a User Interface

12.1. Overview

In this chapter you extend the user interface of your Eclipse 4 application.

You will add a Perspective to the Window. This Perspective will contain a PartSashContainer. This container will divide its children horizontally.

The PartSashContainer will contain a Stack and another PartSashContainer. This second PartSashContainer will contain two Stacks and divide them vertically.

Each stack will get one Part assigned to it.

After these changes, your user interface should look like the following:

12.2. Adding model elements

Open the Application.e4xmi file. Go to your Window and select the Controls node. Add a PerspectiveStack. Press the Add button to create a Perspective entry.

Enter the value To-Do in the field label and the value com.example.e4.rcp.todo.simple in the field ID.

Adding a Perspective to the Eclipse 4 application

Select Controls below the newly created perspective and add a PartSashContainer. Change its Orientation attribute to Horizontal.

Change the orientation attribute

In the drop-down list of the PartSashContainer select PartStack and press the Add button to add a stack.

Re-select the parent PartSashContainer and add another PartSashContainer. Now add two Stacks to the second PartSashContainer.

Adding a Stack and PartSashContainer to a PartSashContainer

Add a Part to each Stack. For each ID use the prefix com.example.e4.rcp.ui.parts and the suffix from the following table.

Table 3. Label and ID from the Parts

ID Suffix Label
*.todooverview To-Dos
*.tododetails Details
*.playground Playground


The following screenshots shows the data of one Part.

The model editor support re You can reassignment of elements via drag-and drop.

Start your product and validate that the user interface looks as planned. Reassign your Parts to other Stacks, if required.

Please note that you have not yet created a Java class for our application.

12.3. Create Java classes and connect to the model

In the following you will create Java objects and connect them to the application model.

Create the com.example.e4.rcp.todo.ui.parts package.

Create three Java classes called TodoOverviewPart TodoDetailsPart and PlaygroundPart in this package. These classes do not extend another class, nor do they implement any interface.

Open the Application.e4xmi file and connect the class with the correct model object. You can do this via the Class URI property of the Part model element.

How to connect the model element with the Java object

The following table gives and overview, which elements should be connected.

Table 4. Connection Java class with Model Element

Class Part ID suffix
TodoOverviewPart *.todooverview
TodoDetailsPart *.tododetail
PlaygroundPart *.playground


The Eclipse 4 model editor allow to seach for existing class via the "Find..." button. The initial list is empty, start typing the class name to see results.

12.4. Test

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

To validate that the model objects are created by the Eclipse runtime, create a no-argument constructor, e.g. with no parameters, for one of the classes and add a System.out.println() statement. Afterwards verify that the constructor is called, once you start your application.

13. Dependency Injections and Annotations

13.1. What is Dependency Injection?

The general concept behind dependency injection is called Inversion of Control. A class should not configure itself but should be configured from outside.

Dependency injection is a concept which is not limited to Java. But we will look at dependency injection from a Java point of view.

A Java class has a dependency on another class if it uses this class as a variable. For example a class which accesses a logger service has a dependency on this service.

Ideally Java classes should be as independent as possible from other Java classes. This increases the possibility to reuse these classes and to test them independently from other classes, for example for unit testing.

If the Java class directly creates an instance of another class via the new() operator, it cannot be used and tested independently from this class.

To decouple Java classes its dependencies should be fulfilled from the outside. A Java class would simply define its requirements like in the following example:

			
public class MyPart {
	
	@Inject private Logger logger;
	// DatabaseAccessClass would talk to the DB
	@Inject private DatabaseAccessClass dao;
	
	@Inject
	public void init(Composite parent) {
		logger.info("UI will start to build");
		Label label = new Label(parent, SWT.NONE);
		label.setText("Eclipse 4");
		Text text = new Text(parent, SWT.NONE);
		text.setText(dao.getNumber());
	}

}
		

Another class could read these dependencies and create an instance of the class, injecting objects into the defined dependency. This can be done via the Java reflection functionality. This class is usually called the dependency container.

This way the Java class has no hard dependencies. For example if you want to test a class which uses another object which directly uses a database, you could inject a mock object.

Mock objects are objects which act as if they are the real object but only simulate their behavior. They mock to be these objects, therefore the name.

If dependency injection is used, a Java class can be tested in isolation, which is good.

Dependency injection can happen on:

  • the constructor of the class (construction injection)

  • a setter (setter injection)

  • a field (field injection)

13.2. Define dependencies in Eclipse

Eclipse 4 supports field, constructor and method injection. It uses the standard Java @Inject and @Named annotations, which were defined in the Java Specification Request 330 (JSR330). In addition to these standard annotations, it declares the @Optional and @Preference annotations

The following table gives an overview of the dependency injection (DI) annotations.

Table 5. Annotations for Dependency Injection

Annotation Description
@javax.inject.Inject Marks a field, a constructor or a method. The Eclipse framework tries to inject the parameter.
@javax.inject.Named Defines the name of the key for the value which should be injected. By default the fully qualified class name is used as key. Several default values are defined as constants in the IServiceConstants interface.
@org.eclipse.e4.core.di.annotations.Optional

Marks an injected value to be optional, so if it can’t be found no error is thrown.

The specific behavior depends where @Optional is used:

  • for parameters: a null value will be injected;

  • for methods: the method calls will be skipped

  • for fields: the values will not be injected.

@org.eclipse.e4.core.di.extensions.Preference Eclipse can store key/values as so-called preferences. The @Preference annotation defines that the annotated value should be filled from the preference store.


13.3. What can get injected?

Eclipse allows to use dependency injection for Java objects, OSGi services and Preferences.

13.4. How does dependency injection work in Eclipse 4?

The Eclipse 4 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. First the constructor injection is performed and afterwards the field and constructor injections.

Constructors are called, before the fields are injected. Accessing an injected field in the constructor will result in an error.

The Eclipse framework also tracks the injected values and if they change, it can re-inject the new values. For example you can define that you want to get the current selection injected. If the selection changes, Eclipse will inject the new value.

14. Behavior Annotations

14.1. API definition via inheritance

Each framework defines an application programming interface (API).

If you use a framework you need to have a convention which methods are called at which point of the execution of your program. For example if a Java class is responsible for handling a toolbar button click, the framework needs to know which method of this class it should call.

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

The framework defines via an abstract class which methods must be implemented. In the above example the method might be called execute() and the framework knows that this method must be called once the toolbar button is clicked.

For example in Eclipse 3.x a View would extend the abstract ViewPart class. This class defines the createPartControl() method.

The Eclipse 3.x framework knows that createPartControl() is responsible for creating the user interface and calls this method once the View becomes visible.

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.

14.2. API definition via annotations

Eclipse 4 does not require that classes extend framework classes. Eclipse 4 uses annotations to indicate that a certain behavior is expected from the framework.

I like to call these annotations "behavior annotations".

Behavior annotations are used to indicate that certain methods should be called at certain events. The following tables list the available behavior annotations.

Table 6. Eclipse lifecycle annotations for Parts

Annotation Description
@PostConstruct Eclipse calls this method once the class is constructed and the field injection has been performed.
@PreDestroy Eclipse calls this method before the class is destroyed. Can be used to clean up resources.
@Focus Indicates that this method should be called, once the Part gets the focus.
@Persist Eclipse calls this method if a save request is triggered. Can for example be used to save the data of a part.
@PersistState Eclipse calls this method if before the model object is disposed, so that the object can save its state.


Table 7. Other Eclipse behavior annotations

Annotation Description
@Execute Marks a method in a command to be executed
@CanExecute Marks a method to be visited by the Command- Framework to check if a command is enabled
@GroupUpdates Indicates that updates for this @Inject should be batched. If you change such objects in the IEclipseContext the update will be triggered by the processWaiting() method on IEclipseContext.
@EventTopic and @UIEventTopic Allows to subscribe to events send by the Event Admin service.


All these annotations will also trigger dependency injections. Therefore you do not need to add the @Inject annotation, if you use these annotations.

The @PostConstruct, @PreDestroy annotations are included in the javax.inject package.

The org.eclipse.e4.core.di.annotations package contains the @Execute, @CanExecute annotations.

@Persists, @PersistState and @Focus are part of the org.eclipse.e4.ui.di package.

14.3. Lifecycle Hooks

Typically some functionality should be triggered if an application is stared or stopped. Eclipse 4 provides the possibility to register a class to predefined events of this lifecycle. For example you can use these lifecycle hooks to create a login screen before the actual application is started.

The org.eclipse.core.runtime.product extension point allows to define this lifecycle class class with a property with the lifeCycleURI key.

This property points to a class via the bundleclass:// schema.

In the lifecycle class you can use the following annotations. The annotated methods will be called by the framework depending on the life cycle of your application.

Table 8. Life Cycle Annotations

Annotation Description
@PostContextCreate Is called after the Application’s IEclipseContext is created, can be used to add objects, services, etc. to the context.
@ProcessAdditions Is called directly before the model is passed to the renderer, can be used to add additional elements to the model.
@ProcessRemovals Same as @ProcessAdditions but for removals.
@Presave Is called before the application model is saved. You can modify the model before it is persisted.


For example lets assume you have registered a lifecycle class in your plugin.xml file.

				
<?xml version="1.0" encoding="UTF-8"?>
<plugin>

   <extension
         id="product"
         point="org.eclipse.core.runtime.products">
      <product
            name="testing"
            application="org.eclipse.e4.ui.workbench.swt.E4Application">
         <property
               name="appName"
               value="testing">
         </property>
         <property
               name="applicationXMI"
               value="testing/Application.e4xmi">
         </property>
         <property
               name="applicationCSS"
               value="platform:/plugin/testing/css/default.css">
         </property>
         <property
               name="lifeCycleURI"
               value="bundleclass://testing/testing.LifeCycleManager">
         </property>
      </product>
   </extension>

</plugin>

			

The following coding will display a shell.

				
package testing;

import org.eclipse.e4.core.services.events.IEventBroker;
import org.eclipse.e4.ui.workbench.UIEvents;
import org.eclipse.e4.ui.workbench.lifecycle.PostContextCreate;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Shell;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventHandler;

public class LifeCycleManager {
	@PostContextCreate
	void postContextCreate(final IEventBroker eventBroker) {
		final Shell shell = new Shell(SWT.TOOL | SWT.NO_TRIM);

		// Will close the shell once a part gets focus
		// Should be easier see bug
		// https://bugs.eclipse.org/bugs/show_bug.cgi?id=376821
		
		eventBroker.subscribe(UIEvents.UILifeCycle.ACTIVATE,
				new EventHandler() {
					@Override
					public void handleEvent(Event event) {
						shell.close();
						shell.dispose();
						System.out.println("Closed");
						eventBroker.unsubscribe(this);
					}
				});
		shell.open();
		
	}

}

			

15. Tutorial: Using dependency injection

15.1. Getting a Composite

In the following tutorial we extend our classes to use dependency injection.

Change the TodoOverviewPart class to the following:

				
package com.example.e4.rcp.todo.ui.parts;

import javax.inject.Inject;

import org.eclipse.swt.widgets.Composite;

public class TodoOverviewPart {
	
	
  @Inject 
  public TodoOverviewPart(Composite parent) {
	if (parent != null) {
	// Print the layout to the console
	  System.out.println("Got Composite via DI.");
	  System.out.println("Layout: " + parent.getLayout().getClass());
	} else {
	  System.out.println("No Composite available.");
	}
  }
}
			

15.2. Validation

Run your application and check in the console View of your Eclipse IDE, if the parameter Composite got injected or not. Note down the class which the Composite got assigned, if it is not null.

16. Exercise: Define Part Lifecycle

16.1. Using @PostConstruct and @PreDestroy

In the following tutorial we use the @PostConstruct and @PreDestroy annotations.

Add the following method to your TodoOverviewPart and TodoDetailsPart class.

				
public void createControls(Composite parent) {

}
			

Annotate the method with @PostContruct.

Create an empty public void dispose() method and annotate it with @PreDestroy.

Remove all constructors from your classes.

16.2. Validate

Run your application and validate that the @PostContruct method is called. Use either debugging or a System.out.println() statement. If you are familiar with SWT, add a few controls to your user interface.

17. Commands, Handlers, Menus, Toolbars and Popups

17.1. Overview

The Eclipse application model can contain commands and handlers.

A command in Eclipse 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 behavior of a command is defined via a handler. A handler defines a class via the contributionURI attribute of the handler. This attribute is displayed as "Class URI" in the model editor.

This class uses the @Execute annotation to define which method is called once the handler is executed. The @CanExecute annotation defines the method which evaluates if the handler is currently active.

@CanExecute is called by the framework if the SWT.SHOW event happens. This event is for example triggered if a new Part is displayed.

Also if you add items to the toolbar, a timer automatically registered by the Eclipse framework will, as of the time of this writing, execute every 400 Milliseconds. This timer will check the @CanExecute to enable or disable the related toolbar entry.

In the handler class you can determine the command ID if the command was triggered via the user interface. Determining the ID is not possible, if it was triggered via the command service (limitation). The following code snippet shows how to get the command ID.

				
@Execute
public void execute(MHandledItem item) {
  MCommand command = item.getCommand();
  // Prints out the commmand ID
  System.out.println(command.getElementId());
}
			

17.2. Default commands

If you know Eclipse 3.x you are probably searching for the predefined commands which you can re-use. The Eclipse 4 platform tries to be as lean as possible.

Eclipse 4 does not include standard commands anymore. You have to define all your commands.

17.3. Menus and Toolbar

You can add menus and toolbars to the application model for the Window and for Parts. Menu and toolbars items contain references to commands. If a command is select the runtime will determine the relevant handlers for the command.

For simple cases you can also use the "Direct MenuItem" or a "Direct ToolItem", which allows to define a handler class directly. Using a Handler gives you more flexibility, for example you can have different Handlers for different scopes (Applications or Views) and you can define Keybindings for your Handlers.

Toolbars in the application are represented in the application model via the trimbar model element. A trimbar can be defined for Windows. Via its attribute you define if the trimbar should be placed on the top, left, right or bottom corner of the Window.

The related command is assigned to the menu and toolbar entry. Menus and toolbars support separators. Menus can have submenus.

17.4. View Menus

To show a menu for a View you have to add a tag to the corresponding entry in the Application.e4xmi file. This tag must be defined before the menu children are defined and looks like the following.

				
<tags>ViewMenu</tags>
			

To add such a View menu entry, select the entry Menu under our Part, select ViewMenu and press the Add button. Eclipse 4.2M7 or earlier releases required that you add this tag manually in the source code.

Adding a View menu

17.5. Popup Menu - Context Menu

You can also define a popup menu for SWT controls. For this you define a "Popup Menu" for your Part in the application model.

You can then assign it via the EMenuService class to a SWT control. The following coding shows an example.

				
package testing.parts;

import javax.annotation.PostConstruct;

import org.eclipse.e4.ui.workbench.swt.modeling.EMenuService;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Text;

public class Detail {

	@PostConstruct
	public void createUi(Composite parent, EMenuService service) {
		final Text text = new Text(parent, SWT.BORDER);
		text.setText("Hello");
		service.registerContextMenu(text, "popuptest");
	}
}

			

17.6. Scope of handlers

Each command can have only one valid handler for a given scope. The application model allows to define a handler for the application, specific for a Window and for a Part.

If more than one handler is defined for a command, Eclipse will select the handler most specific to the model element.

For example if you define a handler for the "Copy" command for your Window and if you define another "Copy" handler for your Part, the runtime will select the handlers closest to model element.

During this evaluation the @CanExecute is considered, e.g. if the "Copy" handler for a Part is not active at a given point, the handler defined for the application will be called.

17.7. Core expressions

The visibility of menus, toolbars and their entries can be restricted via the core expressions. You add the corresponding attribute in the application model to the ID defined by the org.eclipse.core.expressions.definitions extension point.

This approach is similar to the definition of core expressions in Eclipse 3.x.

17.8. Naming schema for command and handler ID

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

The ID's of commands and handler 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 ID for the handler. If you have more then one handler defined, add another suffix to it, describing its purpose, e.g. "com.example.contacts.handler.show.details".

In case you implement commonly used functions, e.g. save, copy, you should use the existing platform IDs, as some Eclipse contributions expect these IDs.

Table 9. 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. Tutorial: Defining and using Commands and Handlers

18.1. Defining Commands

You will now define commands and handlers for your application. Open the Application.e4xmi file and select Commands. We will define our handlers for the whole application. Alternatively you could also define them specific for Parts.

Adding commands to your application

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

Table 10. Commands

ID Name
org.eclipse.ui.file.save Save
org.eclipse.ui.file.exit Exit
com.example.e4.rcp.todo.new New Todo
com.example.e4.rcp.todo.remove Remove Todo
com.example.e4.rcp.todo.test For testing


18.2. Defining Handler classes

Create the com.example.e4.rcp.todo.handlers package for your handler classes.

All handler classes will implement the execute() method.

				
package com.example.e4.rcp.todo.handlers;

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

public class SaveHandler {
	@Execute
	public void execute() {
	  System.out.println("Called");
	}

	@CanExecute
	public boolean canExecute() {
		return true;
	}

}
			

Using this templates for all classes, implement the following classes.

  • SaveHandler

  • ExitHandler

  • NewTodoHandler

  • RemoveTodoHandler

  • TestHandler

18.3. Defining Handlers in your model

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

Table 11. Handlers

Handler ID Command - Class
org.eclipse.ui.file.save.handler Save - SaveHandler
org.eclipse.ui.file.exit.handler Exit - ExitHandler
com.example.e4.rcp.todo.new.handler New Todo - NewTodoHandler
com.example.e4.rcp.todo.remove.handler Remove Todo - RemoveTodoHandler
com.example.e4.rcp.todo.test.handler 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 define the class name to make the table more readable.

Defining a handler in Eclipse 4

18.4. Adding a Menu

You will now add a Menu to your application model.

Select Application.e4xmi. To add a menu to a Window or TrimmedWindow select the entry in the model and flag the "Main Menu" attribute.

Give the "org.eclipse.ui.main.menu" ID to your main menu.

Add two menus, one with the name "File" and the other one with the name "Edit". You only need to enter the "Label" attribute.

Also set the "org.eclipse.ui.file.menu" ID for the file menu.

Creating a menu

Add a "HandledMenuItem" 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 and add after that an entry for the exit command.

Add all other commmands to the "Edit" menu.

18.5. Adding a Toolbar

Select the node "TrimBars" under your Window and press the "Add..." button. The "Side" attribute should be set to "Top", so that all toolbars assigned to that TrimBar appear on the top of the application.

Add a "ToolBar" to your TrimBar. Add a "Handled ToolItem" to this ToolBar, which points to the org.eclipse.ui.file.save command.

Set the label for this entry to "Save".

Adding a menu item to the menu

18.6. Closing the application

To test if your handler is working, change your ExitHandler class, so that it will close your application.

				
package de.vogella.e4.todo.handler;

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


			

19. Keybindings

19.1. Overview

It is also possible to define Keybindings (shortcuts) for your Eclipse application. This requires two steps, first you need to enter values for the "Binding Context" node of your application model.

Afterwards you need to enter the keybindings for the relevant Binding Context in the Binding Table node of your application model.

19.2. BindingContext entries using by JFace

The BindingContext is defined via its ID. You can use any ID you like. BindingContext ID's can be assigned to a Window in the application model. This would define which BindingContexts are valid for this Window. If nothing is defined in the Window then all shortcuts are valid.

Eclipse JFace uses predefined BindingContext identifier which are based on the org.eclipse.jface.contexts.IContextIds class. JFace distingish between shortscuts for dialogs, windows or both.

The following gives an overview of the supported ID and the validity of keybindings defined with reference to this Context ID.

Table 12. Default BindingContext values

Context ID Description
org.eclipse.ui.contexts.dialogAndWindow Keybindings valid for Dialogs and Windows.
org.eclipse.ui.contexts.dialog Keybindings valid in Dialogs.
org.eclipse.ui.contexts.window Keybindings valid for Windows.


19.3. Define Shortcuts

The BindingTable node in the application model allows to define shortcuts for a specific BindingContext.

To define a shortcut you create a new node for BindingTable and define a reference for the Context ID.

In your keybinding you define the key "Sequence" and the command associate with this shortcut.

How to add the Binding Context Entries

The control keys are different for the different platforms, e.g. on the Mac vs. a Linux system. For example you can use Ctrl but this would be hardcoded. Better use the metakeys M1 - M4.

Table 13. Key Mapping

Control Key Mapping for Windows and Linux Mapping for Mac
M1 Ctrl Command
M2 Shift Shift
M3 Alt Alt
M4 Undefined Ctrl

These values are defined in the SWTKeyLookup class

20. Scope of injection

20.1. What can be injected?

We covered how dependency injection works and which annotations can be used to define the behavior of the Java classes. But we have not yet covered what the scope of injection is, e.g. what you can inject into your model classes.

The Eclipse runtime creates a context in which the possible values for injection can be stored. This context can be modified, e.g. the application and the framework can add elements to the context.

The Eclipse context contains:

  • all objects associated with the application model

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

  • all Preferences - key/value pairs which typically used to configure the application

  • OSGi services - software components which can be dynamically consumed

20.2. How are objects searched?

All possible values for dependency injection can be accessed via the context.

The context contains Java objects which can be accessed via keys. Access to the context works similar to accessing a Java Map data structure.

Internally the context is not a flat structure like a Java map, it is hierarchical and can also dynamically compute values for requested keys.

A context can be local to an object and can have a parent context.

Each model element has its own context assigned to it. The main context is created by the Eclipse Framework and all context objects of the model elements are hierarchically connected to the main context object.

Model objects that implement the MContext interface have their own local context. This is for example the case for MWindow and MPart. Each context for a model element contains a reference to the Model object itself.

If for example a Part requests an object by a certain key from the context, Eclipse will first search for this object in the local context of the part. If it does not find the key in the local context it will search the parent context. This process continues until the main context has been reached. At this point the framework would check for fitting OSGi services in the OSGi registry.

This happens transparently for the caller of the context and is considered as an implementation detail.

20.3. What are the relevant classes and interfaces

The interface for the context object is the IEclipseContext interface.

The OSGiContextStrategy class is responsible for searching for OSGi service if the Eclipse framework does not find the requested key in the hierarchy of IEclipseContext objects.

20.4. Who creates the context for model elements?

Eclipse 4 has a flexible renderer framework. For each model element the framework determines a renderer class which is responsible for creating the Java object associated with the model element. This renderer class creates, if required, the local context for the model element and connects this local context to the context hierarchy.

For example the ContributedPartRenderer class is responsible for creating the Java objects for Parts in the model. The interface for Parts is MPart.

ContributedPartRenderer creates a Composite for every Part and injects this Composite into the local context of the Part.

Another example is the WBWRenderer which is responsible for creating a Window. This class puts an instance of IWindowCloseHandler and ISaveHandler into the context of the Window. The first is responsible for the behavior of a Window during close, the other one for saving. For example the default IWindowCloseHandler would prompt you if you want to save Parts as dirty. You can change this default IWindowCloseHandler via the MWindow model object. The following example show this.

				
@Execute
public void execute(final Shell shell, EModelService service, MWindow window) {
	IWindowCloseHandler handler = new IWindowCloseHandler() {
		@Override
		public boolean close(MWindow window) {
			MessageDialog.openConfirm(shell, "Really close?",
			"You will loose data");
			return true;
		}
	};
window.getContext().set(IWindowCloseHandler.class, handler);
}
			

21. Model elements and dependency injection

21.1. Available Model elements

We have learned about the model workbench and dependency injection. As the model is interactive you can change it at runtime, for example you can change the size of the current window, add Parts to your application or remove menu entries.

But what is the best way to access these models?

Model elements have Java classes associated with them. As the model is interactive you can use these model elements to change its attributes or children.

The following is a table of important model elements based on their Java classes.

Table 14. Eclipse 4 model element

Model element Description
MApplication Describes the application object. Can be used for example to add new windows to your application
MWindow Represents a Window in your application.
MTrimWindow Represents a Window in your application. The underlying SWT shell has been created with the SWT.SHELL_TRIM attribute which means, it has a tile, a minimize, maximize and resize button.
MPerspective Object for the perspective model element.
MPart Represents the model element part, e.g. a View or a Editor.
MDirtyable Property of MPart which can be injected. If set to true, this property informs the mode that this Part contains unsaved data (is dirty). In a Handler you can query this property can trigger a save.
MPartDescriptor MPartDescriptor is a template for new Parts. You define in your application model a PartDescripter. A new Part based on this PartDescriptor can be created with the via the EPartService and its showPart() method.
Snippets Snippets can be used to pre-configure model parts which you want to create via your program. You can use EcoreUtil.copy to copy a Snippets and assign it then to another model element, e.g. on a MSash you can a newly copied MStack called "copy", via getChildren().add(copy).


21.2. Example: Dynamically create a new Window

To create new model objects you can use the MBasicFactory.INSTANCE class. This is a factory to create new model objects via typed create*() methods. For example you can create a new Window at runtime as show in the following snippet.

				
// Create a new window and set its size
MWindow window = MBasicFactory.INSTANCE.createTrimmedWindow();
window.setWidth(200);
window.setHeight(300);

// Create a new part and assign it to the window
MPart part = MBasicFactory.INSTANCE.createPart();
window.getChildren().add(part);

// Add new Window to the application
application.getChildren().add(window);
			

21.3. Example: Dynamically create a new Part

For example the following adds a new part to the currently active window.

				
package testing.handlers;

import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.e4.ui.model.application.descriptor.basic.MPartDescriptor;
import org.eclipse.e4.ui.model.application.ui.basic.MBasicFactory;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import org.eclipse.e4.ui.model.application.ui.basic.MWindow;

public class AddPartHandler {
	@Execute
	public void execute(MWindow window) {
		MPart part = MBasicFactory.INSTANCE.createPart();
		part.setLabel("New part");
		part.setContributionURI("platform:/plugin/testing/testing.MyView");
		window.getChildren().add(part);

	}
}

			

21.4. Example: Implement Editor behavior with MDirtyable

The following snippet demonstrates how to use the MDirtyable model property in a part to flag it as a Part which should be saved by the corresponding workbench action.

				
import javax.annotation.PostConstruct;
import javax.inject.Inject;

import org.eclipse.e4.ui.di.Persist;
import org.eclipse.e4.ui.model.application.ui.MDirtyable;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;

public class MySavePart {

	@Inject
	MDirtyable dirty;

	@PostConstruct
	public void createControls(Composite parent) {
		Button button = new Button(parent, SWT.PUSH);
		button.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				dirty.setDirty(true);
			}
		});
	}

	@Persist
	public void save() {
		System.out.println("Saving data");
		// Save the data
		// ...
		// Now set the dirty flag to false
		dirty.setDirty(false);
	}

}
			

21.5. Example: Getting the command line arguments

The IApplicationContext gives access to the command line arguments which were used to start the Eclipse application, e.g. via the run configuration in the "Arguments" tab or via the .ini file of your exported product.

				
import java.util.Map;

import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.equinox.app.IApplicationContext;

public class GetArgumentsHandler {
	@Execute
	public void execute(IApplicationContext context) {
	    // OSGi consumes framework arguments
		String[] args = (String[]) context.getArguments().get(
				IApplicationContext.APPLICATION_ARGS);
		for (Object value : args) {
			System.out.println(value);
		}
	}
}
			

22. Model Addons

Eclipse 4 tries to keep the core framework as minimal as possible. Addons model object can be registered globally on the application model and can enhance the application with additional functionality.

Currently the following Add-ons are useful for Eclipse applications. Their class names give an indication of their provided functionality. Check their Javadoc to get a short description of their purpose.

Table 15. Model Add-ons

Add-on ID Class
org.eclipse.e4.core.commands.service CommandServiceAddon
org.eclipse.e4.ui.contexts.service ContextServiceAddon
org.eclipse.e4.ui.bindings.service BindingServiceAddon
org.eclipse.e4.ui.workbench.commands.model CommandProcessingAddon
org.eclipse.e4.ui.workbench.contexts.model ContextProcessingAddon
org.eclipse.e4.ui.workbench.bindings.model BindingProcessingAddon


Addons are created before the rendering engine renders the model. This allows Addons to alter the user interface that is produced by the rendering engine. For example, the min/max Addon changes the tab folders created for MPartStacks to have min/max buttons in the corner.

Addons use the bundleclass:// URI convention to extend your application model with add-ons.

Having these Add-ons registered allows them to be enhanced or replaced by the Eclipse platform team or by a customer specific implementation in case the need arises.

Additional Add-ons are available, e.g. to support drag-and-drop of Parts in your application.

To support drag-and-drop for Parts you need to add the org.eclipse.e4.ui.workbench.addons.swt plug-in to your product configuration file. Then you can use the DnDAddon and the CleanupAddon from this bundle as Add-ons in your application model.

23. Accessing and extending the Eclipse context

23.1. Accessing the context

To access an existing context you can use dependency injection, if the relevant object is managed by the Eclipse runtime, i.e. if you are using a model object.

				
package com.example.e4.rcp.todo.handlers;

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

public class ShowMapHandler {
	@Execute
	public void execute(IEclipseContext context) {
		// Add objects to this local context of this handler
		// ...
	}

}
			

				
package com.example.e4.rcp.todo.handlers;

import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.equinox.app.IApplicationContext;

public class ShowMapHandler {
	@Execute
	public void execute(IApplicationContext context) {
		// Add objects to the application context 
		// This way is would be accessible for other 
		// model objects
		// ...
	}

}
			

Alternatively if your model object extends MContext you can use DI to get the model object injected and use the getContext() method to access its context. For example Parts, Windows, Applications and Perspectives extend MContext.

				
package com.example.e4.rcp.todo.ui.parts;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import org.eclipse.swt.widgets.Composite;

public class TodoDetailsPart {

	@PostConstruct
	public void createControls(Composite parent, MPart part) {
		IEclipseContext context = part.getContext();
	}
}
			

If you are outside of a model object, you still can access the global context via the following:

				
public Object start() {
  // Get Bundle Information
  Bundle bundle = FrameworkUtil.getBundle(getClass());
  BundleContext bundleContext = bundle.getBundleContext();
  IEclipseContext eclipseCtx =   
      EclipseContextFactory.getServiceContext(bundleContext);

  // Fill Context with information using set(String,Object)
  // ....
  
  // Create instance of class
  ContextInjectionFactory.make(MyPart.class, eclipseCtx);
}

			

23.2. Putting objects in the context

The recommended way to add objects to the context is to use OSGi services. OSGi services are automatically available in the context.

Sometimes it might be more efficient to add objects directly to the IEclipseContext. For example you want to test your Java objects and want to supply mock (test) objects to them via dependency injection.

To create a new context, you can use the EclipseContextFactory.create() factory method call. Adding objects to it can be done via the set() method on IEclipseContext.

				
@Inject
public void addingContext(IEclipseContext context) {
	// We want to add objects to context

	// Create instance of class
	IEclipseContext myContext = EclipseContextFactory.create();

	// Putting in some values
	myContext.set("mykey1", "Hello1");
	myContext.set("mykey2", "Hello2");

	// Adding a parent relationship
	myContext.setParent(context);

}


			

23.3. Best practices

It is not recommended to add new objects to an existing Eclipse Context as you may override existing objects which the intention of doing so.

If you want to add new objects to an existing context, it is best practice to create a new context and set the existing context as parent of the new one via the setParent() method.

The IEclipseContext should also not be used to transfer data within your application. For example you should not put your model objects directly into the context to be able to access the data from other parts of your application.

For this you would either define an own OSGi services or use the EventAdmin Service to communicate within your application.

24. Using dependency injection for your own Java objects

24.1. Overview

Using dependency injection for your own Java objects has two flavors. First you want the Eclipse dependency container to create your own objects and get them injected into your model objects. Second you want to create objects which declare there dependencies with @Inject and want to create it via dependency injection.

Both approaches are described here.

24.2. Using dependency injection to get own objects

If you want the Eclipse dependency injector to create your objects for you, annotate them with @Creatable. This way you telling the Eclipse DI container that it should create a new instance of this object if it does not find an instance in the context.

The Eclipse DI container will try to find a suitable constructor for this class. You can also use @Inject on the constructor to indicate that Eclipse should try to run dependency injection also for this constructor.

For example, assume that you have the following domain model.

				
@Creatable
class Todo {
 @Inject
 public Todo(Dependent depend, YourOSGiService service) {
     // placeholder
 }
}
 
@Creatable
class Dependent {
 public Dependent() {
 // placeholder
 }
}
			

Assuming that you have defined the required OSGi service, you can get an instance of your Todo data model injected in a Part.

				
// Field Injection
@Inject Todo todo
			

24.3. Using dependency injection to create objects

Using dependency injection is not limited to the objects created by the Eclipse runtime. You can use @Inject in a Java class and use the dependency injection framework to create your class.

				

// Create instance of class
ContextInjectionFactory.make(MyJavaObject.class, context);

			

For this you can either use an existing context as described in the last section or a new context.

				
IEclipse context = EclipseContextFactory.create();

// Add your Java objects to the context
context.set(MyDataObject.class.getName(), data);
// Add your Java objects to the context
context.set(MoreStuff.class.getName(), moreData);




			

25. Closing words

I hope you enjoyed this introduction into the Eclipse 4 framework. Of course there is much more, check out the "Eclipse 4 development" section under my lists of Eclipse Plug-in and Eclipse RCP Tutorials section.

26. Thank you

Please help me to support this article:

Flattr this

27. Questions and Discussion

Before posting questions, please see the vogella FAQ. If you have questions or find an error in this article please use the www.vogella.com Google Group. I have created a short list how to create good questions which might also help you.

28. Links and Literature

28.1. Source Code

Source Code of Examples

http://wiki.eclipse.org/E4 Eclipse E4 - Wiki

Ecipse 4 RCP Wiki

Eclipse RCP

Eclipse EMF

Dependency Injection