RSS

Search Engine

Showing posts with label Eclipse 4.0 Application Platform - Tutorial. Show all posts
Showing posts with label Eclipse 4.0 Application Platform - Tutorial. Show all posts

Saturday, October 23, 2010

Eclipse 4.0 SDK and Eclipse e4

1.1. Overview

Eclipse e4 project introduces a new set of technologies into the Eclipse platform that make Eclipse plugins and Eclipse RCP applications easier to write, more configurable and easier to reuse. The first release of the Eclipse e4 project is Eclipse 4.0 SDK. This article is based on the Eclipse 4.0 SDK.

The major enhancements in Eclipse e4 compared to Eclipse 3.x are:

  • The Eclipse workbench UI is described by an EMF model

  • The model is available at design- and runtime

  • Eclipse widgets can be styled via CSS style sheets

  • The existing Eclipse API's are re-worked to make them simpler

  • Eclipse e4 supports dependency injection for services into model components

  • The model elements are decoupled from their presentation via a Renderer Framework

1.2. About this tutorial

The following description will start with the creation of a e4 based application via a wizard to allow people to get quickly started. It describes the modeled workbench concept and the new programming model which is based on annotations and dependency injection. It then covers the declarative styling introduced in e4.

The remainder of the tutorial will be used to develop a e4 based todo application.

Installation

The Eclipse 4.0 SDK comes as a complete all-in-one download version, you find the latest version in http://download.eclipse.org/e4/sdk/ .

This download does not include all tooling which makes working with Eclipse e4 easier. Please use the update site "http://download.eclipse.org/e4/updates/2010" to install the following via the Eclipse update manager .

The tools provides wizards to create e4 artifacts and the specialized model editor for the e4 application model. The CSS tools "Eclipse e4 CSS Support" and "Eclipse E4 UI CSS Source"are required because the extension point "org.eclipse.e4.ui.css.swt.theme" requires the source bundle. The same applies for the "Eclipse e4 Model Workbench" and "Eclipse e4 Model Workbench Source" as the extension "org.eclipse.e4.workbench.model" requires the source feature. The reason for this is that the ".exsd" files for the extension points are part of the source features.

Your first e4 application

This chapter guides you through the first creation of an e4 based application via the available wizard .

3.1. Create project

Eclipse e4 provides a wizard for creating e4 applications. Select File -> New -> Others -> e4 -> "e4 Application Project". Create the project "de.vogella.e4.rcp.wizard" based on the following screenshots.

3.2. Launch

Open your product file "de.vogella.e4.rcp.wizard.product". Switch to the "Overview" tab and launch your product. This should start a small e4 application.

Steps for creating an e4 application

In the last chapter we used a wizard to create an Eclipse e4 application . This chapter provides a checklist of the necessary steps to create a new e4 application. All these steps will be later executed in detail.

To create a new basic e4 based application you:

  • Create a new plugin project

  • Maintain the dependencies to the necessary e4 plugins

  • Create an Application model description in a file which is typically called "Application.e4xmi"

  • You create a product configuration which uses the pre-defined application "org.eclipse.e4.ui.workbench.swt.E4Application".

  • In "plugin.xml" you point your application to the correct Application model description file, via the property "applicationXMI".

The concept of the modeled workbench

5.1. The model

The Eclipse e4 workbench is modeled via Eclipse EMF . This model contains the graphical elements of the workbench, e.g. the parts (views, editors, menu bars) and some non-visual parts of the command framework, e.g. handlers, commands and keybindings. This model of the workbench is available at runtime, e.g. the programmer can access the running model and change it during runtime.

Eclipse 3.x has a different concept of the workbench, in Eclipse 3.x the Ui elements are defined via extension points and stored in registries at runtime. These registries does not contain the actual relationship between the UI elements. In Eclipse 4.0 the workbench is explicitly modeled. It is also much more flexible compared to the Eclipse 3.x. For example you do not need to have perspectives and there is not an inherent distinction anymore between editors and views (both are called "Parts").

The e4 model consists roughly out of the following packages:

  • application: main elements, like IEclipeContext, Application and the following subpackages

  • ui - contains general components, e.g. the Context, menus, toolbars, parts and other UI related model components

  • commands - definition of commands, handlers and keybinding

  • descriptor - used to store information about the ui components

5.2. e4 WorkbenchModel Editor

In e4 the application is based on a EMF model . This model can be created and changed via the standard EMF tooling . The Eclipse e4 provides a specialized model editor (mainly developed by Tom Schindl ) which makes the easier to change an e4 application model. To open the model editor double-click on "Application.e4xmi" (or right click on it and select "Open-with"-> "e4 Workbenchmodel Editor".

5.3. Contributing to the e4 model

The base e4 application model is placed in an XMI file. This file is a standard XMI / text file. The application is at startup informed which file to use via the parameter "applicationXMI" of the extension point "org.eclipse.core.runtime.products". The XMI file is read at start time of the application and the initial application model is constructed from this file.

Model elements can also be supplied via the extension point "org.eclipse.e4.workbench.model". Model elements can be contributed via xmi (fragments) or via code (processors). These elements are merged into the application model. User changes are also recorded and saved independently.

The model information is read during startup and the contained information is to construct the workbench. The complete constructed model is available during runtime. Changes during runtime, e.g. the user moves a part, are written back to the model. If user changes should not be applied to the model you can specific the "-clearPersistedState" parameter as launch parameter. This would then be similar to the configurer.setSaveAndRestore(false) flag in Eclipse 3.x.

5.4. Merging model elements at startup

The e4 model has three potential parts which will be combined at runtime.

  1. The application defines in its "Application.e4xmi" file a base model (for example, main menu, perhaps UI elements like views that are always there, etc). This file changes over time as new versions of the application are being developed and released.

  2. Other plug-ins add to that model through our model extension point. Plug-ins can be installed and un-installed. This means that we have a model that results from combining the base model with these contributions. Of course, this means that there is an additional source of change to the model, but it is pretty clear how these contributions get merged into the model.

  3. While the application is running, the model objects can be changed. For example, views are closed, or menus/toolbars were customized, new views were opened, etc. These changes need to be persisted across sessions, and ideally even across updating plug-ins or the base application. The model delta are captured based on the difference to the real model, e.g. if you move View A to another place and move it back to the original position no delta is saved

The workbench model needs to the user changes and must be able to react to changes in the Application.e4xmi and the model contributions. The workbench models handles this as follows: On first startup, populate the model as described under 1 and 2. Changes during the session will be recorded as deltas, and we persist these deltas instead of the whole model when we shut down. Then, for subsequent startups, populate the model as described under 1 and 2 and then apply any persisted deltas from 3. If there are deltas that don't make any sense then skip them. The delta are applied to the model based on the ID's of the UI component.

5.5. Where to find the meta-model

The workbench model is defined in the plugin "org.eclipse.e4.ui.model.workbench" in the file "model/UIElements.ecore". The "UIElements.genmodel" defines among other things that interfaces for the workbench model starts with M.

Programming model with Dependency Injection and Annotations

Eclipse e4 introduces a new programming model based on annotations and dependency injection . This new programming approach allows to avoid the usage of Singletons and emphasis loosely coupled components. Using Eclipse Singletons should be avoided in an Eclipse based application because this couples the code tightly to a special implementation of the platform and make it difficult to test the application.

6.1. e4 runtime

We learned in the Eclipse e4 model chapter that the Eclipse workbench is described by a EMF model . This model contains references to Java classes. During startup the e4 runtime evaluates the model and instantiate these class if required. The life cycle of every model element is therefore controlled by the e4 runtime. The e4 runtime instantiated and destroys the Java objects which are referred to by model elements if required. The model elements can also contain annotations which describe their dependencies and / or which methods should be executed at which point in time. The e4 runtimes scans every objects for these annotations and based on the annotations it performs certain actions. For example the @inject annotation indicates that the e4 framework should inject other Java Objects or OSGi Services into the Java Object for the model element. Other annotations control which methods are called at certain points of the object life cycles, e.g. the @execute annotations describes which method should be called in a command handler is called.

6.2. Using Dependency Injection

In every model element you can automatically retrieve services and other objects via annotations if these services and objects are known to the Eclipse e4 runtime. For non model elements the programmer has to call a framework method to get the known Services may be pre-defined by the Eclipse platform or may be defined by the programmer. All objects which can be injected into a model element are stored in the so-called IEclipseContext. This Context can be extended via additional OSGi services or by own objects.

To describe dependencies the following annotations are available.

Table 1. Annotations for dependency injection

AnnotationDescription
@javax.inject.InjectMark a field/constructor/method to be injected by the DI-Framework
@javax.inject.NamedDefine the key for the value which should be injected. By default the fully qualified class name is used.
@org.eclipse.e4.core.di.annotations.OptionalMark an inject value to be optional so if it can’t be found no error is thrown. This also ensures that the value is unset if the inject value is set to null.
@org.eclipse.e4.core.di.extensions.PreferenceMarked field/method-parameter will be filled with a value from the preference store

6.3. IEclipseContext

For the purpose of dependency injection Eclipse provides the IEclipseContext. IEclipseContext is a mechanism to find for a service or object request the fitting one. The IEclipseContext is hierarchical structured and every model elements has its own context. If a service cannot be found in a local context then the parent context is searched. OSGi services are part of the application context which is the highest level is the hierarchy. The application context is the interface to the OSGi services.

The IEclipseContext contains two types of elements: workbench model objects and service. The IEclipseContext is hierarchical and every Model objects that are themselves MContext instances will have their own content. This content will also include a reference to the Model object itself.

Services and model compoenents can be injected into a Eclipse e4 model component via the @Inject annotation. As said the content is hierarchical and the Eclipse dependency injection framework will first try to find the object in the content closest to the object and then move up to the next level. If the service cannot be found in the context then the framework will try to find the object as OSGi service.

See Eclipse e4 services Wiki for an overview of the available services. The usage of these services is also described Available services for dependency injection .

6.4. Available services

Workbench Services follow usually with E*Service pattern. For example you have:

  • org.eclipse.e4.core.commands.ECommandService

  • org.eclipse.e4.core.commands.EHandlerService

  • org.eclipse.e4.workbench.modeling.EPartService

  • org.eclipse.e4.workbench.modeling.EModelService

  • org.eclipse.e4.workbench.modeling.ESelectionService

  • org.eclipse.e4.ui.bindings.EBindingService

  • org.eclipse.e4.ui.services.EContextService

Other available services are:

  • org.eclipse.e4.core.services.Adapter

  • org.eclipse.e4.core.services.StatusReporter

  • org.eclipse.e4.core.services.Logger

  • org.eclipse.e4.core.services.events.IEventBroker

  • org.eclipse.e4.workbench.ui.IPresentationEngine

  • org.eclipse.jface.window.IShellProvider

6.5. Annotations for application hooks

Eclipse e4 uses annotations to indicate that certain behavior is expected from the framework. These annotations can indicate that certain values should be injected in model parts (see later the description of dependency injection), or are used to indicate that methods should be called at certain events. The following annotations stear workbench behavior; we will later see the annotations for dependency injections. are most important.

Table 2. Eclipse e4 annotations with no relationship to DI

AnnotationDescription
@org.eclipse.e4.core.di.annotations.ExecuteMarks a method in a command to be executed
@org.eclipse.e4.core.di.annotations.CanExecuteMark a method to be visited by the Command- Framework to check if a command is enabled
@org.eclipse.e4.workbench.ui.Persistannotates method. If used in a Part-POJO this method will be called when the workbench issues a save-request

6.6. Example

The following shows a part (view). Via the @inject annotation it specifies that it requires object of type Logger, the IEcipseContext and a Composite. At runtime the e4 runtime will create an instance of this part. During this creation it checks of annotations and injects the required objects into the view if they are available.

    
package de.vogella.e4.rcp.first.parts;

import javax.inject.Inject;

import org.eclipse.e4.core.services.Logger;
import org.eclipse.e4.core.services.annotations.PostConstruct;
import org.eclipse.e4.core.services.context.IEclipseContext;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;

public class View1 {

@Inject private Logger logger;
@Inject private IEclipseContext context;
@Inject private Composite parent;

// PostConstruct ensures that the dependency injection has been finished
// this this method is called
@PostConstruct
public void init() {
// If you don't inject the Logger you could alternatively
// get it via the IEclipseContext with the following statement
// Logger log= (Logger) context.get(Logger.class.getName());
System.out.println(context!=null);
System.out.println(logger!=null);
logger.info("UI will start to build");

Label label = new Label(parent, SWT.NONE);
label.setText("E4 is new");
Text text = new Text(parent, SWT.NONE);
text.setText("and different");
}

}

Styling your UI with css

7.1. Defining the stylesheet

Eclipse e4 allows to style your UI widgets via CSS properties. This is similar to styling webpages with Cascading Style Sheets (CSS) .

To style an Eclipse 4.0 based application you first define a file which contains the styling information. Each UI widget can be addressed via the corresponding CSS class. Colors of widgets can defined via differences ways, e.g. the color white can be described via #white, rgb(255,255,2555) or #ffffff. The Eclipse wiki describes the details of the possible mapping in Eclipse Wiki Entry for SWT Mapping .

It is also to set a data tag for a specific SWT UI element and use this data tag in the CSS. For example you can set the tag for an label via:

    
Label label = new Label(parenet, SWT.NONE);
label.setData("org.eclipse.e4.ui.css.id","MyCSSTagForLabel");

This element can be addressed in the CSS via:

    
#MyCSSTagForLabel{
color:#blue;
}

Styling supports gradients for the background color of UI controls. Linear and radial gradients are supported. To define a gradient use:

    
// linear gradient
background-color: gradient linear color_1 [color_2]* [percentage]*

// For example
background-color: gradient linear white black
background-color: gradient linear white black blue
background-color: gradient linear white black 50%
background-color: gradient linear white black 50% 20%

// radial gradient
background-color: gradient linear color_1 color_2 [percentage]

// For example
background-color: gradient radial white black
background-color: gradient radial white black 50%

If you use the optional percentage in the definition then the color change will be done after the defined percentage.

7.2. Using the styling

After defining your style sheet you have to tell your application to use it. Here you have two different options.

  • Specify the property css on the product

  • Use the theme manager

The first approach is simple, you just define the property "applicationCSS" on the product in "plugin.xml" pointing to the file. This way your application will be styled at startup.

The second approach is more flexible but requires a bit more work. You define an extension for the extension point "org.eclipse.e4.ui.css.swt.theme" which basically defines an id and a pointer to the CSS file. You then you define t

Getting started with the Todo application

In the following chapters we will create a basis for a Todo application with the e4 framework. We will create the e4 application from scratch to get a deeper understanding.

8.1. Create project

Create a new Plugin project "de.vogella.e4.todo", based on the Equinox runtime. Do not select "Generate an activator". Do not select a template.

Create the package "de.vogella.e4.todo".

8.2. Add dependencies

You need to add several dependencies to your MANIFEST.MF to be able to use the programming model of e4. We also add the SWT plugin which we later require.

  • org.eclipse.core.runtime

  • org.eclipse.e4.ui.workbench

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

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

  • org.eclipse.e4.ui.css.swt.theme

  • org.eclipse.e4.core.services

  • org.eclipse.e4.core.di

  • org.eclipse.e4.core.contexts

  • org.eclipse.e4.ui.services

  • javax.inject

  • javax.annotation

  • org.eclipse.equinox.ds

  • org.eclipse.equinox.event

  • org.eclipse.swt

The resulting "MANIFEST.MF" should look like the following. I have removed the version so that you should be able to copy the MANIFEST.MF.

    
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Todo
Bundle-SymbolicName: de.vogella.e4.todo
Bundle-Version: 1.0.0.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Require-Bundle: org.eclipse.core.runtime,
org.eclipse.e4.ui.workbench,
org.eclipse.e4.ui.workbench.swt,
org.eclipse.e4.ui.workbench.renderers.swt,
org.eclipse.e4.ui.css.swt.theme,
org.eclipse.e4.core.services,
org.eclipse.e4.ui.services,
javax.inject,
javax.annotation,
org.eclipse.equinox.ds,
org.eclipse.equinox.event,
org.eclipse.swt,
org.eclipse.e4.core.di,
org.eclipse.e4.core.contexts

8.3. Create product configuration

Create a new product configuration "Todo.product". The creation of a product configuration is similar to the task for Eclipse 3.6 RCP applications. Please see Creating a product configuration

Make sure you select "org.eclipse.e4.ui.workbench.swt.E4Application" as the application.

The result should look like the following.

Switch the "Dependencies" tab on your product file and add as dependency the plugin "de.vogella.e4.todo". Press afterwards the "Add required plugins" button.

8.4. Maintain Extension points

During the product creation the extension point "org.eclipse.core.runtime.products" was autommatically added to the file "plugin.xml". Open this file and select the tab "Extensions". If the tab extension is hidden, select "Extensions" on the tab Overview. Verify that "org.eclipse.e4.ui.workbench.swt.E4Application" is selected as application.

Every e4 application must define a base model. This is done via a property of the product. Maintain the properties "applicationXMI" with the value "de.vogella.e4.todo/Application.e4xmi". This points to the initial model which we will create soon. The resulting plugin.xml should look like the following.

    



id="product"
point="org.eclipse.core.runtime.products">

application="org.eclipse.e4.ui.workbench.swt.E4Application"
name="Todo">
name="appName"
value="Todo">

name="applicationXMI"
value="de.vogella.e4.todo/Application.e4xmi">





8.5. Create the initial workbench model

Create the file "Application.e4xmi" via File -> New -> Other -> Model -> Application Model.

This will create the file "Application.e4xmi" which is a representation on an EMF model. It describes a workbench model which currently has not even a window. You can create the file directly with the content from below.

    



Open "Application.e4xmi" with the "e4 WorkbenchModel Editor". This editor allows you to modify your "Application.e4xmi" file.

Select the entry window and add a new TrimmedWindow. Maintain the width, height and Label.

Your model now describes an application with an empty window.

8.6. Run your application

This should be sufficient to run your application. Create a launch configuration based for your product and run your application. The result should look like the following.

Congratulations. You have hand-crafted your first full featured Eclipse e4 application.

Parts, Toolbar and Menu

We will extend our minimal e4 application with parts, a menu and a toolbar. Remember that e4 does not make anymore a distinction between editors and views, both are parts.

9.1. Add a part to the application

To add a part to an Eclipse 4.0 application you add a model element to your application model "Application.e4xmi" and define the class which represents the part via the "URL" property of the model element.

Create the following class. Notice that the TodoOverview.java code does not have any dependency to the Eclipse / OSGi framework. Just a simple POJO. By using the @inject annotation you are telling the Eclipse framework to inject a composite into the view.

    
package de.vogella.e4.todo.parts;

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

import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.core.services.log.Logger;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;

public class TodoOverview {

@Inject
private Logger logger;
@Inject
private IEclipseContext context;

// PostConstruct ensures that the dependency injection has been finished
// this this method is called

private final Composite parent;

// e4 will inject the composite "parent" into the view
@Inject
public TodoOverview(Composite parent) {
// the following is standard SWT Stuff
this.parent = parent;
}

@PostConstruct
public void buildUI() {
logger.info("Start building UI");
final GridLayout layout = new GridLayout(2, false);
parent.setLayout(layout);
createLable("e4 Release");
createText("Eclipse 4.0 SDK");
createLable("Purpose");
createText("Doing awesome stuff");

}

// Standard SWT Stuff
private void createLable(String text) {
Label label = new Label(parent, SWT.NONE);
label.setText(text);
GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
gridData.horizontalIndent = 20;
label.setLayoutData(gridData);
}

// Standard SWT Stuff
private void createText(String text) {
GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
Text textField = new Text(parent, SWT.NONE);
textField.setText(text);
textField.setLayoutData(gridData);
}

}

To add this view to your application open the "Application.e4xmi" in the editor, switch to controls under Windows, select "Part" and press add and maintain the values displayed below.

The URI describes the location of your view. The first part of this URI is the plugin and the second one the package. Make sure you don't have a typo here.

Run again your application you it should look like the following.

9.2. Menu, Toolbar and command handler

To add a menu entry or a toolbar entry you have to follow the same approach as with the Part. You have to create the model elements and these model elements must point to classes if required. Create the class which will handle the command. The @Execute annotation tells the framework which method should be called if this class is used as a handler.

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


Select "Application.e4xmi" and add a menu and a toolbar. To add a menu select the window and select the "Main Menu" attribute.

Add a menu with one "DirectMenuItem" and a toolbar and The result should look like the following screenshot.

Also add a trimbar.

    

















If you run the application it should look like.

9.3. Add a container

You can either use a sash or a stack to display other containers or parts. A sash will divide the space between its container elements will a stack will only show the select element on top. We will now add another part and use a sash to divide two stacks to show both parts.

Lets first add another part to our application. Add the following Java class.

    
package de.vogella.e4.todo.parts;
import javax.inject.Inject;

import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;

public class TodoDetails {

private final Composite parent;

// e4 will inject the composite "parent" into the view
@Inject
public TodoDetails(Composite parent) {
// the following is standard SWT Stuff
this.parent = parent;

final GridLayout layout = new GridLayout(2, false);
parent.setLayout(layout);

createLable("Release");
Button button = new Button(parent, SWT.BORDER);
button.setText("Do nothing");
}

// Standard SWT Stuff
private void createLable(String text) {
Label label = new Label(parent, SWT.NONE);
label.setText(text);
GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
gridData.horizontalIndent = 20;
label.setLayoutData(gridData);
}


}

Use the e4 editor to add a "PartSashContainer". The model editor allow you to set the model properties. Set the "orientation" to horizontal. Add twice a "PartStack" to the sash container. Use drag and drop to assign the first part to the first stack and then add the second part to the second stack. The result should look like the following.

The resulting "Application.e4xmi" should look like:


Launch your application. It should look like:

Styling the todo application

10.1. Create stylesheet

We first create the css file and then demonstrate both possible ways to use the css file. Create the folder "css" in your application and create the following file "default.css".

    
Label {
font: Verdana 8px;
color: black;
}

Composite Label {
color: black;
}


Text {
font: Verdana 8px;
}

Composite Text {
background-color: white;
color: black;
}

SashForm {
background-color: #c1d5ef;
}


.MTrimBar {
background-color: #e3efff #c1d5ef;
color: white;
font: Verdana 8px;
}

Shell {
background-color: #e3efff #c1d5ef 60%;
}

10.2. Use css via property at startup

Add the property "applicationCSS" with the value "platform:/plugin/de.vogella.e4.todo/css/default.css"to your application in extension point "org.eclipse.core.runtime.products". This property points to the css file.

Run your application it should look like the following.

10.3. Theme Manager and switching styles

Remove the "applicationCSS" property again and create two extension for extension point "org.eclipse.e4.ui.css.swt.theme".

Add the "cssTheme" parameter to your product.

    
package de.vogella.e4.todo.handler;

import javax.inject.Named;

import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.e4.ui.css.swt.theme.IThemeEngine;
import org.eclipse.e4.ui.workbench.IWorkbench;


public class ThemeSwitchHandler {
@Execute
public void switchTheme(IThemeEngine engine) {
engine.setTheme("de.vogella.e4.todo.redtheme", true);
}
}

Create the following file "css/red.css".

    
CTabItem, ToolBar, Button, CBanner, CoolBar {
font-size: 9;
background-color: red;
}


Add the menu entry to your application.


If you run your application you should be able to select the "Themes" and switch your application to a red style.

Services

11.1. Using services

As explained earlier you can use the Eclipse e4 dependency injection mechanism to inject your own OSGi services into your model elements. This removes the need for you to create your own singletons. In the following we will use OSGi declarative services to define a service which maintains our current todo items. You could use other approaches but declarative services are a simple way to creating services. For details on creating DS Services please see OSGi Tutorial .

A service in OSGi is defined by a standard Java class or interface. It is common practice to define the service via a bundle which only contains the interface definition. This allows to change the implementation of the service via a different bundle.

11.2. Todo model and service interface

Create a plugin project "de.vogella.e4.todo.model" which will contains the model and the definition of the service interface. You do not need an activator. Create also the package "de.vogella.e4.todo.model". Do not use a template. Select "plugin.xml" and the "Runtime" tab. Add "de.vogella.e4.todo.model" to the exported packages.

Create the following data model.

    
package de.vogella.e4.todo.model;

public class Todo {
private String summary="";
private String description="";

public Todo(String summary) {
this.summary = summary;
}

public Todo(String summary, String description){
this.summary = summary;
this.description = description;

}

public String getSummary() {
return summary;
}
public void setSummary(String summary) {
this.summary = summary;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}

@Override
public String toString() {
return "Todo: " + summary;
}
}

Create the following interface "ITodoModel".

    
package de.vogella.e4.todo.model;

import java.util.List;

public interface ITodoModel {
List getTodos();
}

11.3. Todo model service

Create a plugin project "de.vogella.e4.todo.model.servicemock". Do not use a template. You do not need an activator. Create the package "de.vogella.e4.todo.model.servicemock". Add "de.vogella.e4.todo.model" as a dependency. Also set the overview tab "MANIFEST.MF" and set the flag "Activate this plugin when one of its classed id loaded".

Create the Folder "OSGI-INF" in your project. Select the new folder, right-click on it and select New -> Other -> Plug-in Development -> Component Definition. Create the file with the following content.

    








Create the implementation class for this service.

    
package de.vogella.e4.todo.model.servicemock;

import java.util.ArrayList;
import java.util.List;

import de.vogella.e4.todo.model.ITodoModel;
import de.vogella.e4.todo.model.Todo;

public class TodoMockModel implements ITodoModel {

@Override
public List getTodos() {
List todos = new ArrayList();
Todo todo = new Todo("Write more about e4");
todos.add(todo);
todo = new Todo("Android", "Write a widget.");
todos.add(todo);
return todos;
}

}

Also make sure that the entry "Service-Component: OSGI-INF/component.xml" is available in "MANIFEST.MF".

    
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Servicemock
Bundle-SymbolicName: de.vogella.e4.todo.model.servicemock
Bundle-Version: 1.0.0.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Require-Bundle: de.vogella.e4.todo.model;bundle-version="1.0.0"
Service-Component: OSGI-INF/component.xml

11.4. Using the model service

Add the two new bundles to your runtime configuration and add a dependency to "de.vogella.e4.todo.model" in the plugin "de.vogella.e4.todo". Change your view so that the new services gets injected into your view. Currently we will just verify that the service was injected by displaying the total number of todos.

    
package de.vogella.e4.todo.parts;

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

import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.core.services.log.Logger;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;

import de.vogella.e4.todo.model.ITodoModel;

public class TodoOverview {

@Inject
private Logger logger;
@Inject
private IEclipseContext context;
@Inject
private ITodoModel model;

// PostConstruct ensures that the dependency injection has been finished
// this this method is called

private final Composite parent;

// e4 will inject the composite "parent" into the view
@Inject
public TodoOverview(Composite parent) {
// the following is standard SWT Stuff
this.parent = parent;
}

@PostConstruct
public void buildUI() {
logger.info("Start building UI");
final GridLayout layout = new GridLayout(2, false);
parent.setLayout(layout);
createLable("Number of Todo entries:");
createText(String.valueOf(model.getTodos().size()));

}

// Standard SWT Stuff
private void createLable(String text) {
Label label = new Label(parent, SWT.NONE);
label.setText(text);
GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
gridData.horizontalIndent = 20;
label.setLayoutData(gridData);
}

// Standard SWT Stuff
private void createText(String text) {
GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
Text textField = new Text(parent, SWT.NONE);
textField.setText(text);
textField.setLayoutData(gridData);
}

}


Using the selection and part service

Eclipse e4 provides several services which can be used in your RCP application. For example the selection service (ESelectionService). A client can get the selection service via @Inject ESelectionService and the set the selection. The consumer simple defines a method with a named parameter (IServiceConstants.ACTIVE_SELECTION) and a type. The e4 framework will make sure that selections are only injected if they have the fitting type.

EPartService allows to find and perform actions on parts of the model. We will use this service to find the todo details view and hide it if in the tree a category has been selected.

We will now create a JFace tree on the TodoOverview part which will display the Todos. Add "org.eclipse.jface" to the dependencies in "sawan.modi.e4.todo".

We will display the Todo in a Eclipse JFace Tree. Create the following content provider.

  
package sawan.modi.e4.todo.provider;

import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;

import sawan.modi.e4.todo.model.ITodoModel;

public class TodoContentProvider implements ITreeContentProvider {

private ITodoModel model;

@Override
public void dispose() {
}

@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
this.model = (ITodoModel) newInput;
}

@Override
public Object[] getElements(Object inputElement) {
return model.getTodos().toArray();
}

@Override
public Object[] getChildren(Object parentElement) {
return null;
}

@Override
public Object getParent(Object element) {
return null;
}

@Override
public boolean hasChildren(Object element) {
return false;
}

}

Change the TodoOvervier.java to the following. This class will aquire the selection service and set it once the user selects a value in the tree. It also will use the EPartService to hide and show the details view based on the selection.

  
package sawan.modi.e4.todo.parts;

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

import org.eclipse.e4.core.services.log.Logger;
import org.eclipse.e4.ui.di.Focus;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import org.eclipse.e4.ui.workbench.modeling.EPartService;
import org.eclipse.e4.ui.workbench.modeling.EPartService.PartState;
import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;

import sawan.modi.e4.todo.model.Category;
import sawan.modi.e4.todo.model.ITodoModel;
import sawan.modi.e4.todo.model.Todo;
import sawan.modi.e4.todo.provider.TodoContentProvider;

public class TodoOverview {

@Inject
ESelectionService selectionService;
@Inject
private Logger logger;
@Inject
private ITodoModel model;
@Inject
private EPartService service;


// PostConstruct ensures that the dependency injection has been finished
// this this method is called

private final Composite parent;
private TreeViewer viewer;
private MPart findPart;

// e4 will inject the composite "parent" into the view
@Inject
public TodoOverview(Composite parent) {
this.parent = parent;
}

@PostConstruct
public void buildUi() {
findPart = service.findPart("sawan.modi.e4.tododetails");


logger.info("Start building UI");

final GridLayout layout = new GridLayout(2, false);
parent.setLayout(layout);

createLable("Number of Categories:");
createText(String.valueOf(model.getCategories().size()));

viewer = new TreeViewer(parent);
viewer.setLabelProvider(new ColumnLabelProvider() {
@Override
public String getText(Object element) {
if (element instanceof Category) {
Category category = (Category) element;
return category.getName();
}
return ((Todo) element).getSummary();
}
});

viewer.setContentProvider(new TodoContentProvider());
viewer.setInput(model);
viewer.setAutoExpandLevel(2);
GridData gridData = new GridData();
gridData.verticalAlignment = GridData.FILL;
gridData.horizontalSpan = 2;
gridData.grabExcessHorizontalSpace = true;
gridData.grabExcessVerticalSpace = true;
gridData.horizontalAlignment = GridData.FILL;

viewer.getControl().setLayoutData(gridData);
viewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {

IStructuredSelection selection = (IStructuredSelection) viewer
.getSelection();
Object firstElement = selection.getFirstElement();
if (firstElement instanceof Category) {
service.hidePart(findPart);
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=328178
// findPart.setToBeRendered(false);
} else {
// findPart.setVisible(true);
// findPart.setToBeRendered(true);
service.showPart(findPart, PartState.VISIBLE);
}
selectionService.setSelection(selection.getFirstElement());
}
});


}

// Standard SWT Stuff
private void createLable(String text) {
Label label = new Label(parent, SWT.NONE);
label.setText(text);
GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
gridData.horizontalIndent = 20;
label.setLayoutData(gridData);
}

// Standard SWT Stuff
private void createText(String text) {
GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
Text textField = new Text(parent, SWT.NONE);
textField.setText(text);
textField.setLayoutData(gridData);
}

@Focus
public void havingFocus() {
System.out.println("TodoOveriew has now the focus.");
}

}

Change the TodoDetails.java to the following. This class defines the method setTodo which gets as a named parameter the current selection, if this selection is of type Todo.

  
package sawan.modi.e4.todo.parts;

import java.util.HashMap;
import java.util.Map;

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

import org.eclipse.e4.core.di.annotations.Optional;
import org.eclipse.e4.core.services.events.IEventBroker;
import org.eclipse.e4.ui.di.Focus;
import org.eclipse.e4.ui.services.IServiceConstants;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.osgi.service.event.EventHandler;

import sawan.modi.e4.todo.model.Todo;

public class TodoDetails {
private final Composite parent;
private Todo todo;
private Text summary;
private Text description;

// e4 will inject the composite "parent" into the view
@Inject
public TodoDetails(Composite parent) {
this.parent = parent;
}

@PostConstruct
public void buildUi(){
final GridLayout layout = new GridLayout(2, false);
parent.setLayout(layout);

createLable("Summary:");
GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
summary = new Text(parent, SWT.NONE);
summary.setTextLimit(100);
summary.setLayoutData(gridData);

createLable("Description:");
gridData = new GridData(GridData.FILL_HORIZONTAL);
description = new Text(parent, SWT.NONE);
description.setSize(30, 400);
description.setLayoutData(gridData);
}

// Standard SWT Stuff
private void createLable(String text) {
Label label = new Label(parent, SWT.NONE);
label.setText(text);
GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
gridData.horizontalIndent = 20;
label.setLayoutData(gridData);
}

@Inject
public void setTodo(
@Optional @Named(IServiceConstants.ACTIVE_SELECTION) Todo todo) {
if (todo != null) {
this.todo = todo;
summary.setText(todo.getSummary());
description.setText(todo.getDescription());
}
}

@Focus
public void havingFocus() {
System.out.println("TodoDetails has now the focus.");
}

}

If you now select a Todo in the tree, this will be propagated via the selection service to the TodoDetails view. If you select a category then the detail view will be hidden.

Contribute model elements via plugins

13.1. Contribute a model elements

Eclipse e4 allows that model elements are contributed to the base model (from Applicatin.e4xmi) via the extension point "org.eclipse.e4.workbench.model". Model elements can be contributed via "fragments" or via "processors". A fragment is a xmi file which specifies additional model elements. A processor allows to contribute to the model via program code, e.g. in situations where the model contributions are dynamic. A model fragment is similar to the existing extension mechanism of Eclipse 3.x but is based on the Eclipse 4.0 extension mechanism. A processor allows the dynamic creation of model elements thus giving the developer much more flexibility.

If you want to contribute to a base model via fragments you always specify to which element you are contributing. Therefore this element you are contributing to must have its ID specified.

13.2. Create new plugin

Create a plugin "sawan.modi.e4.todo.contribute" without any templates. Add a dependency to "org.eclipse.e4.ui.workbench" and add the extension point "org.eclipse.e4.workbench.model".

You may need to import the "org.eclipse.e4.workbench.model" from git to make this extension point work for you. See also Bug report .

13.3. Contributing via processors

It is possible to contribute via processors, e.g. Java code which creates and modify model elements. In the following example we will replace the exiting menu entry in our e4 todo application and add a new entry in the menu.

In your plugin "sawan.modi.e4.todo.contribute" add a "processor" for the "org.eclipse.e4.workbench.model" extension point.

The parameter will be the model element which is can later inject into our Java class.

Create the following dialog and handler class. The handler will later be used in the new menu entry.

    
package sawan.modi.e4.todo.contribute;

import javax.inject.Inject;
import javax.inject.Named;

import org.eclipse.e4.ui.services.IServiceConstants;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;

public class ExitDialog extends Dialog {
@Inject
public ExitDialog(@Named(IServiceConstants.ACTIVE_SHELL) Shell shell) {
super(shell);
}

@Override
protected Control createDialogArea(Composite parent) {
Label label = new Label(parent, SWT.NONE);
label.setText("Closing this application may result in data loss. Are you sure you want that");
return parent;
}

}

    
package sawan.modi.e4.todo.contribute.handler;

import org.eclipse.e4.core.contexts.ContextInjectionFactory;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.e4.ui.workbench.IWorkbench;
import org.eclipse.jface.window.Window;

import sawan.modi.e4.todo.contribute.ExitDialog;

public class ExitHandlerWithCheck {
@Execute
public void execute(IEclipseContext context, IWorkbench workbench) {
ExitDialog dialog = ContextInjectionFactory.make(ExitDialog.class, context);
dialog.create();
if (dialog.open() == Window.OK) {
workbench.close();
}
}
}

Create now the model processor class.

    
package sawan.modi.e4.todo.contribute;

import java.util.ArrayList;
import java.util.List;

import javax.inject.Inject;
import javax.inject.Named;

import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.e4.ui.model.application.ui.menu.MDirectMenuItem;
import org.eclipse.e4.ui.model.application.ui.menu.MMenu;
import org.eclipse.e4.ui.model.application.ui.menu.MMenuElement;
import org.eclipse.e4.ui.model.application.ui.menu.MMenuFactory;

public class MenuProcessor {
// I get this via the parameter of the process definition
@Inject
@Named("sawan.modi.e4.todo.filemenu")
private MMenu menu;

@Execute
public void execute() {
// Remove the old exit menu entry
if (menu != null && menu.getChildren() != null) {
List list = new ArrayList();
for (MMenuElement element : menu.getChildren()) {
if (element.getLabel().contains("Exit")) {
list.add(element);
}
}
menu.getChildren().removeAll(list);
}
// Now add a new menu entry
MDirectMenuItem menuItem = MMenuFactory.INSTANCE.createDirectMenuItem();
menuItem.setLabel("Another Exit");
menuItem.setContributionURI("platform:/plugin/sawan.modi.e4.todo.contribute/sawan.modi.e4.todo.contribute.handler.ExitHandlerWithCheck");
menu.getChildren().add(menuItem);
}
}

Add this plugin to your product and run your product. The old exit menu entry should be removed and you should see the new menu entry.

More to come

At this point we have created a simple shell for our application, added two parts and styled them a bit. Obviously this is not a full features Todo application. ;-) I'm publishing this anyhow in the hope that this helps people getting started and I'm planning to extend this application and create a full featured Todo application. '

Deployment

Deployment of an Eclipse e4 application works similar to the deployment of an Eclipse RCP application. Please see Eclipse RCP .

Please make sure that you include all the e4 artifacts in your "build.properties".

e4 and Eclipse RAP

If you want to run Eclipse e4 and the RAP runtime you can look at the following wike Eclipse e4 and Eclipse RAP integration .

Tips

17.1. Allow drag and drop for your parts in the workbench

Eclipse e4 does not support drag and drop of the parts parts (views and editors) within an application by default.

To make this work add a dependency to the plugin “org.eclipse.e4.ui.workbench.addons.swt” and add the Add-On “org.eclipse.e4.ui.workbench.addons.dndaddon.DnDAddon” to your “Application.e4xmi”.

Drag and drop will create new container if required. To remove them automatically also register "platform:/plugin/org.eclipse.e4.ui.workbench.addons.swt/org.eclipse.e4.ui.workbench.addons.cleanupaddon.CleanupAddon".

17.2. Model access at runtime

The model can be accessed at runtime. To see the current model include the plugin "org.eclipse.e4.tools.emf.liveeditor" and its dependencies into your launch configuration. You should then be able to open the model editor of your running application via the shortcut ALT+Shift+F9 depending on your version.

17.3. Persists user changes

Eclipse e4 application allow via startup parameters if the user changes should be persists and how. A similar behavior exists in Eclipse 3.x via the the setSaveAndRestore(true) setting.

Table 3. Sample Table

ParameterDescription
-persistState false|trueDefault is false, if set to false user changes are not recorded.
-clearPersistedStatewill delete the recorded delta of the last session.
-useDeltaRestore true|falseCurrently not working see https://bugs.eclipse.org/bugs/show_bug.cgi?id=313883, should control how the deltas are stored. a) Store deltas and apply them on startup using the Reconciler. This way new contribution will be shown in your application. b) Serialize the complete model (this is similar to 3.x saveAndRestore(true)) and deserialize from XMI

17.4. Styling the Eclipse 4.0 SDK

You can use the ThemeManager to style the Eclipse 4.0 SDK itself. In the Eclipse 4.0 SDK the active theme is selected via Window -> Preferences -> General -> Appearance. These style sheets are stored in the plugin "org.eclipse.platform". This plugin_contains a folder /css which contains the style sheets for the individual platforms (os based).

You can also contribute a new theme via your own plugin. Create a simple plugin (no activator required) which has a single dependency to the plugin "org.eclipse.e4.ui.css.swt.theme". Add the extension point "org.eclipse.e4.ui.css.swt.theme" and add a theme to this extension point. Create a css file and point the theme to this file. If you export your plugin (including the css file )and put it into your Eclipse installation folder into dropin you should be able to select your new theme after restarting the Eclipse 4.0 SDK.

Key classes in e4

The following is a list of important classes in Eclipse e4.

Table 4. e4 classes

ClassPluginDescription
org.eclipse.e4.ui.internal.workbench.swt.E4Application Implementation of the e4 application
org.eclipse.e4.workbench.ui.internal.E4Workbenche4 workbench implementation
org.eclipse.e4.core.services.internal.annotations.AnnotationsSupport Checks for annotations
org.eclipse.e4.workbench.ui.renderers.swt.WorkbenchRendererFactory SWT renderer factory, implements IRendererFactory

Thank you

If you like this tutorial please support this website.