Support free tutorials

vogella training Training Books



Eclipse 4 CSS Styling- Tutorial

Based on Eclipse 4.2 and Eclipse 4.3

Lars Vogel

Version 6.2

10.07.2013

Eclipse 4 and CSS Styling

This tutorial gives an introduction into the CSS styling capabilities of Eclipse 4.


Table of Contents

1. Prerequisites
2. Eclipse and declarative styling
2.1. Styling Eclipse applications
2.2. Limitations
3. Fixed styling in Eclipse
4. Dynamic styling using themes
5. CSS support for standard Eclipse elements
5.1. CSS attributes and selectors
5.2. Styling based on identifiers and classes
5.3. Colors and gradients
6. CSS support for custom widgets
6.1. The org.eclipse.e4.ui.css.core.propertyHandler extension point
6.2. The org.eclipse.e4.ui.css.core.elementProvider extension point
7. CSS Tools
7.1. CSS Spy
7.2. CSS Scratchpad
8. Exercise: Styling with CSS files
8.1. Target
8.2. Create CSS file
8.3. Define applicationCSS property
8.4. Validate
8.5. Adjust build.properties
9. Exercise: Dynamic style switching with themes
9.1. Target
9.2. Add dependencies
9.3. Create CSS file
9.4. Remove the applicationCSS property
9.5. Create theme extensions
9.6. Validate
9.7. Implement a new menu entry
9.8. Validate theme switching
9.9. Adjust build.properties
10. Exercise: Define a custom CSS selector and CSS property
10.1. Target
10.2. Add dependencies
10.3. Adjust custom CSS to your CSS file
10.4. Create the user profile widget
10.5. Adding the org.eclipse.e4.ui.css.core.propertyHandler extension point
10.6. Adding the org.eclipse.e4.ui.css.core.elementProvider extension point
10.7. Validate
11. Learn more about Eclipse 4 RCP development
12. About this website
12.1. Donate to support free tutorials
12.2. Questions and discussion
12.3. License for this tutorial and its code
13. Links and Literature
13.1. Source Code
13.2. CSS styling resources
13.3. vogella Resources

Get the book Eclipse RCP book

1. Prerequisites

The following assumes that you have already basic Eclipse RCP development experience. See the Eclipse RCP Tutorial for details. .

2. Eclipse and declarative styling

2.1. Styling Eclipse applications

The visual appearance of your Eclipse application can be styled via external files similar to the CSS 2.1 standard.

CSS selectors used in Eclipse are identifiers, which relate to widgets or other elements, for example predefined pseudo classes. Non-standard properties are prefixed with either swt- or eclipse-.

The following example shows a CSS file which defines a styling for an Eclipse application.

Label {
  font: Verdana 8px;
  color: black;
}
Composite Label {
  color: black;
}
Text {
  font: Verdana 8px;
}
/* Identifies only those SWT Text elements
appearing within a Composite */
Composite Text {
  background-color: white;
  color: black;
}
SashForm {
  background-color: #c1d5ef;
}
/* background uses a gradient */
.MTrimBar {
  background-color: #e3efff #c1d5ef;
  color: white;
  font: Verdana 8px;
}

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

The Eclipse platform support static as well as dynamic styling of an application. In the case of static styling the styling cannot be exchanged at runtime, while in the case of dynamic styling it is possible to switch the styling at runtime.

2.2. Limitations

SWT as the default user interface toolkit of Eclipse has certain limitations with regards of styling components, which are based on the limitations of the underlying operating system. For example it is not possible to style menus and table headers because this is not supported by the SWT implementation. Also some platforms do not allow the styling of certain widgets, e.g. the Button or the ScrollBar widget.

3. Fixed styling in Eclipse

You can specify a fixed styling of your application via a property in your extension for the org.eclipse.core.runtime.products extension point. Like all extensions this extension is contributed via the plugin.xml file.

The value of the applicationCSS property should point to your CSS file via an URI. The URI follows the platform:/plugin/BundleSymbolicName/path/file convention. For following example demonstrates such a URI:

platform:/plugin/com.example.e4.rcp.todo/css/default.css 

The screenshot shows an example for the plugin.xml file which the applicationCSS property defined.

applicationCSS entered on the product extension

The corresponding file is shown below. It leaves out possible other properties you have set, e.g. for a life cycle handler.

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

 <extension
   id="product"
   point="org.eclipse.core.runtime.products">
  <product
     application="org.eclipse.e4.ui.workbench.swt.E4Application"
      name="to-do">
   <property
       name="appName"
       value="to-do">
   </property>
   <property
     name="applicationCSS"
     value="platform:/plugin/com.example.e4.rcp.todo/css/default.css">
   </property>
  </product>
 </extension>

</plugin> 

4. Dynamic styling using themes

You can define multiples themes via an extension in the plugin.xml file. The Eclipse platform provides the theme service with an instance of the IThemeEngine interface. Via this instance you can change the active theme at runtime.

To create new themes you define extensions for the org.eclipse.e4.ui.css.swt.theme extension point. Such a extension defines an ID for the style and a pointer to the CSS file.

You must also define the default theme via the cssTheme property in your org.eclipse.core.runtime.products extension. This can also be used to define a fixed styling.

Warning

If cssTheme is not set, the IThemeEngine service is not registered as service by the Eclipse platform.

The switching of themes is demonstrated in the following handler code.

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

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

public class ThemeSwitchHandler {
  private static final String DEFAULT_THEME = "com.example.e4.rcp.todo.default";
  private static final String RAINBOW_THEME = "com.example.e4.rcp.todo.rainbow";
  
  // Remember the state
  static boolean defaulttheme= true;
  @Execute
  public void switchTheme(IThemeEngine engine) {
    // second argument defines that change is 
    //persisted and restored on restart
    if (!engine.getActiveTheme().getId().equals(DEFAULT_THEME)){
      engine.setTheme(DEFAULT_THEME, true);
    } else {
      engine.setTheme(RAINBOW_THEME, true);
    }
  }
} 

5. CSS support for standard Eclipse elements

5.1. CSS attributes and selectors

The CSS attributes for SWT widgets which can be styled are listed under the following link:

http://wiki.eclipse.org/E4/CSS/SWT_Mapping 

Eclipse application model elements, e.g. MPartStack or MPart can also be styled. The CSS selectors are based on the Java classes for the model elements. Some examples are given in the following table.

Table 1. Model elements and CSS selectors

Model Element CSS Selector
MPart .MPart
MPartStack .MPartStack
MPartSashContainer .MPartSashContainer


For example you could hide the minimize and maximize button of a MPartStack via the following CSS rule.

.MPartStack {
  swt-maximize-visible: false;
  swt-minimize-visible: false;
} 

Eclipse supports also CSS pseudo classes. The following tables lists several of these pseudo classes.

Table 2. CSS pseudo classes in Eclipse

CSS pseudo classes Description
Button:checked Selects checked buttons
:active For example shell:active selects the active shell\
:selected Allows to style a selected element, e.g. a part in a PartStack.


5.2. Styling based on identifiers and classes

You can specify tags on widgets in your source code and use these tags for styling. You can specify an identifier or a class. A identifier is supposed to be unique while a class can be assigned to several elements.

The following example demonstrates how to set the identifier and the class on SWT widgets.

// IStylingEngine is injected
@Inject IStylingEngine engine;

// more code....

Label label = new Label(parent, SWT.NONE);
Text text = new Text(parent, SWT.BORDER);

// set the ID, must be unique in the same window
engine.setID(label, "MyCSSTagForLabel"); 

// set the class, can be used several times
engine.setClassname(text, "error"); 

These elements can be addressed in the CSS file via:

#MyCSSTagForLabel{
  color:#blue;
}

.error { 
  border: 1px red; 
} 

5.3. Colors and gradients

Colors can be defined in different ways, e.g. the color white can be described as #white, rgb(255,255,2555) or #ffffff.

Styling supports gradients for the background color of user interface widgets. Linear and radial gradients are supported. The definition of gradients is demonstrated in the following listing.

// 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 radial 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. The following picture shows the result of different settings.

Different Gradient settings

Note

Please note that the current gradient specification is not compliant with the CSS specification and that it might change in the future.

6. CSS support for custom widgets

The CSS support offers two extension points org.eclipse.e4.ui.css.core.propertyHandler and org.eclipse.e4.ui.css.core.elementProvider, where you may define custom CSS selectors and CSS properties for your own widgets.

Those extension points are defined in the org.eclipse.e4.ui.css.core plug-in, so you need at least a dependency to this plug-in. In order to use some predefined implementations for SWT you may also want to use the org.eclipse.e4.ui.css.swt plug-in.

The org.eclipse.e4.ui.css.core.propertyHandler extension in general defines an adapter (ElementAdapter) implementation to wrap a certain widget for the CSS framework. And a handler (ICSSPropertyHandler) implementation must also be defined, which applies the CSS properties, which are also defined under the handler in the plugin.xml, to the actual widget.

The org.eclipse.e4.ui.css.core.elementProvider extension defines an IElementProvider, which in general returns the widgets adapter(ElementAdapter). Under this provider you may specify for which widgets the IElementProvider is responsible.

6.1. The org.eclipse.e4.ui.css.core.propertyHandler extension point

In the org.eclipse.e4.ui.css.core.propertyHandler extension point you define an ElementAdapter for your widget and an implementation of an ICSSPropertyHandler, where different property-names for the widget can be defined.

Here you can see a sample of the org.eclipse.e4.ui.css.swt projects propertyHandler extension point:

PropertyHandler extension point for org.eclipse.e4.ui.css.swt

These are the default ElementAdapter implementations for the adapter property in the screenshot above:

ElementAdapter type hierarchy

In the ICSSPropertyHandler implementation those property-names are read and applied to the actual widget.

The CSSPropertyBackgroundSWTHandler and it's parent AbstractCSSPropertyBackgroundHandler are examples of such an implementation of the ICSSPropertyHandler, where the background behavior is applied for certain widgets.

The AbstractCSSPropertyBackgroundHandler class delegates to the methods for the property-names, which are applied in the propertyHandler extension point, to its subclasses like the CSSPropertyBackgroundSWTHandler.

@Override
  public boolean applyCSSProperty(Object element, String property,
      CSSValue value, String pseudo, CSSEngine engine) throws Exception {
    if ("background".equals(property)) {
      applyCSSPropertyBackground(element, value, pseudo, engine);
    }
    if ("background-attachment".equals(property)) {
      applyCSSPropertyBackgroundAttachment(element, value, pseudo, engine);
    }
    if ("background-color".equals(property)) {
      applyCSSPropertyBackgroundColor(element, value, pseudo, engine);
    }
    if ("background-image".equals(property)) {
      applyCSSPropertyBackgroundImage(element, value, pseudo, engine);
    }
    if ("background-position".equals(property)) {
      applyCSSPropertyBackgroundPosition(element, value, pseudo, engine);
    }
    if ("background-repeat".equals(property)) {
      applyCSSPropertyBackgroundRepeat(element, value, pseudo, engine);
    }
    return false;
  } 

The following listing is the applyCSSPropertyBackgroundColor method of the CSSPropertyBackgroundSWTHandler and shows how the background-color property-name will be applied for several widgets:

@Override
  public void applyCSSPropertyBackgroundColor(Object element, CSSValue value,
      String pseudo, CSSEngine engine) throws Exception {
    Widget widget = (Widget) ((WidgetElement) element).getNativeWidget();
    if (value.getCssValueType() == CSSValue.CSS_PRIMITIVE_VALUE) {
      Color newColor = (Color) engine.convert(value, Color.class, widget
          .getDisplay());
      if (widget instanceof CTabItem) {
        CTabFolder folder = ((CTabItem) widget).getParent();
        if ("selected".equals(pseudo)) {
          // tab folder selection manages gradients
          CSSSWTColorHelper.setSelectionBackground(folder, newColor);
        } else {
          CSSSWTColorHelper.setBackground(folder, newColor);
        }
      } else if (widget instanceof Control) {
        GradientBackgroundListener.remove((Control) widget);
        CSSSWTColorHelper.setBackground((Control) widget, newColor);
        CompositeElement.setBackgroundOverriddenByCSSMarker(widget);
      }
    } else if (value.getCssValueType() == CSSValue.CSS_VALUE_LIST) {
      Gradient grad = (Gradient) engine.convert(value, Gradient.class,
          widget.getDisplay());
      if (grad == null) {
        return; // warn?
      }
      if (widget instanceof CTabItem) {
        CTabFolder folder = ((CTabItem) widget).getParent();
        Color[] colors = CSSSWTColorHelper.getSWTColors(grad,
            folder.getDisplay(), engine);
        int[] percents = CSSSWTColorHelper.getPercents(grad);

        if ("selected".equals(pseudo)) {
          folder.setSelectionBackground(colors, percents, true);
        } else {
          folder.setBackground(colors, percents, true);
        }

      } else if (widget instanceof Control) {
        GradientBackgroundListener.handle((Control) widget, grad);
        CompositeElement.setBackgroundOverriddenByCSSMarker(widget);
      }
    }
  } 

6.2. The org.eclipse.e4.ui.css.core.elementProvider extension point

With the org.eclipse.e4.ui.css.core.elementProvider extension point you need to implement an IElementProvider, which returns an org.w3c.dom.Element.

ElementAdapter type hierarchy

In general the returned org.w3c.dom.Element is an instance of an ElementAdapter, which we already saw in the propertyHandler extension point and the screenshot of the ElementAdapter's type hierarchy before.

By the widget properties under the provider, you see in the screenshot above, you point to the class of the actual widget, like org.eclipse.swt.widgets.Control, for which the provider is responsible.

The SWTElementProvider for instance contains those ElementAdapter implementations, which are shown in the type hierarchy screenshot and looks like this:

/** * Returns the CSS class which is responsible for styling a SWT widget * * Registered via the "org.eclipse.e4.ui.css.core.elementProvider" extension * point for the SWT widgets * * * * {@link IElementProvider} SWT implementation to retrieve w3c Element * {@link SWTElement} linked to SWT widget. * */
public class SWTElementProvider implements IElementProvider { public static final IElementProvider INSTANCE = new SWTElementProvider(); @Override public Element getElement(Object element, CSSEngine engine) { if (element instanceof Text) { return new TextElement((Text) element, engine); } if (element instanceof Button) { return new ButtonElement((Button) element, engine); } if (element instanceof Scale) { return new ScaleElement((Scale) element, engine); } if (element instanceof Shell) { return new ShellElement((Shell) element, engine); } if (element instanceof CTabFolder) { return new CTabFolderElement((CTabFolder) element, engine); } if (element instanceof ToolBar) { return new ToolBarElement((ToolBar) element, engine); } if (element instanceof Composite) { return new CompositeElement((Composite) element, engine); } if (element instanceof Control) { return new ControlElement((Control) element, engine); } if (element instanceof CTabItem) { return new CTabItemElement((CTabItem) element, engine); } if (element instanceof TableItem) { return new TableItemElement((TableItem) element, engine); } if (element instanceof ToolItem) { return new ToolItemElement((ToolItem) element, engine); } if (element instanceof Item) { return new ItemElement((Item) element, engine); } if (element instanceof Widget) { return new WidgetElement((Widget) element, engine); } return null; } }

See the following URL: Eclipse 4 CSS Wiki for more information.

7. CSS Tools

7.1. CSS Spy

The CSS spy tool helps to see the possible styling options for selected elements. CSS spy is part of the e4 tooling project and can be installed from its update site. See the Eclipse 4 installation description for details.

You can open the CSS spy via the Shift+Alt+F5 shortcut.

CSS spy allows you to see the available properties and the current style settings.

The CSS Spy in action

7.2. CSS Scratchpad

The CSS Scratchpad allows to change CSS rules interactively. is also part of the e4 tooling project.

You open it via the Ctrl+Shift+Alt+F6 shortcut.

If you click the Apply button, the entered CSS is applied at runtime to your application.

8. Exercise: Styling with CSS files

8.1. Target

In this exercise you style your application with a CSS file.

8.2. Create CSS file

Create a folder called css in your com.example.e4.rcp.todo plug-in and create the following default.css file.

Label {
  font: Verdana 8px;
  color: black;
}
Composite Label {
  color: black;
}
Text {
  font: Verdana 8px;
}
/* Identifies only those SWT Text elements
appearing within a Composite */
Composite Text {
  background-color: white;
  color: black;
}
SashForm {
  background-color: #c1d5ef;
}
/* background uses a gradient */
.MTrimBar {
  background-color: #e3efff #c1d5ef;
  color: white;
  font: Verdana 8px;
}

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

8.3. Define applicationCSS property

Open the plugin.xml file in your com.example.e4.rcp.todo plug-in. Select the Extensions tab.

Selecting the extension

Right-click on your product entry and select Newproperty.

Adding a property

Use applicationCSS as name for the property. The value of this property should use the following identifier.

platform:/plugin/com.example.e4.rcp.todo/css/default.css 

Setting the CSS property

8.4. Validate

Start your application. The application should be styled according to your CSS file.

Change the CSS style sheet and restart your application to see the effect.

8.5. Adjust build.properties

Add the created CSS file to your build.properties file in the com.example.e4.rcp.todo plug-in to make it available in an exported application.

9. Exercise: Dynamic style switching with themes

9.1. Target

The following exercises assumes that you already implemented CSS support for your application based on the last exercise. In this exercise you use the IThemeEngine to introduce the ability to switch the application styling at runtime.

9.2. Add dependencies

Add the org.eclipse.e4.ui.css.swt.theme plug-in as dependency to your application plug-in.

9.3. Create CSS file

Create the following css/rainbow.css file.

Shell {
  background-color: red orange yellow green orange 30% 60% 75% 95%
}

.MPartStack {
  font-size: 22px;
  color:orange;
}  

.MPart:selected {
   visible:gone;
   background-color:black;
}

.MPartStack {
border-visible:false;
} 

9.4. Remove the applicationCSS property

Remove the applicationCSS property from your product extension. For this select the property and press the Remove button as depicted in the following screenshot.

Remove applicationCSS

9.5. Create theme extensions

Select the Extensions tab in the editor for the plugin.xml file and create two extensions for the org.eclipse.e4.ui.css.swt.theme extension point.

You create an extension in the Extensions tab by pressing the Add... button.

Add button in extension points

Select the org.eclipse.e4.ui.css.swt.theme extension point and press the Finish button.

Selecting

Right-click on the org.eclipse.e4.ui.css.swt.theme extension to create a new theme. The following screenshots show the extensions which you should create.

The relevant part in the plugin.xml file should look like the following.

<extension
         point="org.eclipse.e4.ui.css.swt.theme">
      <theme
            basestylesheeturi="css/default.css"
            id="com.example.e4.rcp.todo.default"
            label="Default Theme">
      </theme>
      <theme
            basestylesheeturi="css/rainbow.css"
            id="com.example.e4.rcp.todo.rainbow"
            label="Rainbow">
      </theme>
</extension> 

Add the cssTheme property to your product. It should point to the com.example.e4.rcp.todo.default theme you created.

Warning

Ensure that the cssTheme property is correctly set. Without this initial setting the IThemeEngine does not work.

9.6. Validate

Start your application and ensure that the application is styled according to the cssTheme property setting.

9.7. Implement a new menu entry

Create a new Java class, which allows you to switch between the themes.

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

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

public class ThemeSwitchHandler {
  private static final String DEFAULT_THEME = "com.example.e4.rcp.todo.default";
  private static final String RAINBOW_THEME = "com.example.e4.rcp.todo.rainbow";
  
  // Remember the state
  static boolean defaulttheme= true;
  @Execute
  public void switchTheme(IThemeEngine engine) {
    // second argument defines that change is 
    //persisted and restored on restart
    if (!engine.getActiveTheme().getId().equals(DEFAULT_THEME)){
      engine.setTheme(DEFAULT_THEME, true);
    } else {
      engine.setTheme(RAINBOW_THEME, true);
    }
  }
} 

Define a new command and a handler in your application model for switching the style. Assign the above class to the handler.

Add a menu entry to your application model which uses your handler for switching the style.

9.8. Validate theme switching

Start the application and select your new menu entry. Afterwards the styling of your application should use the rainbow theme.

Note

Changes in styling may require a restart of your application if your new style does not override all properties of the old style.

9.9. Adjust build.properties

Ensure that all CSS files are selected in your build.properties file in the com.example.e4.rcp.todo plug-in to make them available in an exported application.

10. Exercise: Define a custom CSS selector and CSS property

10.1. Target

In this exercise you will implement your own custom CSS selector and property for styling the header of an user profile widget.

The aim is to apply this CSS to the user profile widget:

UserProfileWidget {
   header-background-color: red;
} 

As you may see UserProfileWidget is a new CSS selector and header-background-color is a new CSS property.

The result may look like that, where the user profile widget is embedded in a Tooltip:

UserProfileWidget sample

10.2. Add dependencies

Add the org.eclipse.e4.ui.css.core and the org.eclipse.e4.ui.css.swt plug-ins as dependency to your application.

10.3. Adjust custom CSS to your CSS file

Add the following CSS to your CSS file, which is used in your application plug-in.

UserProfileWidget {
   header-background-color: red;
} 

10.4. Create the user profile widget

In order to learn how to implement customizations for CSS we also need a custom widget, which should be styled. So we implement a really simple custom widget, which is a Composite that consists of three other Composites for the header, image and description area.

For the following widget you should create a widget package in your plug-in and place the UserProfileWidget class into it.

package com.vogella.rcp.css.custom.widget;

import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.LocalResourceManager;
import org.eclipse.jface.resource.ResourceManager;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;

public class UserProfileWidget extends Composite {
  private ResourceManager resourceManager;

  private String text = "";
  private String headerText = "";
  private ImageDescriptor imageDescriptor;

  private Label imageLabel;
  private Label headerLabel;
  private Label labelText;

  private Composite head;

  public UserProfileWidget(Composite parent, int style) {
    super(parent, style);
    GridLayoutFactory.swtDefaults().numColumns(2).applyTo(this);

    head = new Composite(this, SWT.NONE);
    GridLayoutFactory.fillDefaults().applyTo(head);
    GridDataFactory.fillDefaults().span(2, 1).grab(true, false).applyTo(head);
    headerLabel = new Label(head, SWT.NONE);
    headerLabel.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
    headerLabel.setText(getHeaderText());

    Composite imageComposite = new Composite(this, SWT.NONE);
    GridLayoutFactory.fillDefaults().applyTo(imageComposite);
    GridDataFactory.fillDefaults().applyTo(imageComposite);
    imageLabel = new Label(imageComposite, SWT.NONE);
    ImageDescriptor imgDescriptor = getImage();
    if (imgDescriptor != null) {
      imageLabel.setImage(getResourceManager().createImage(imgDescriptor));
    }

    Composite textComposite = new Composite(this, SWT.NONE);
    GridLayoutFactory.fillDefaults().applyTo(textComposite);
    GridDataFactory.fillDefaults().grab(true, true).applyTo(textComposite);
    labelText = new Label(textComposite, SWT.NONE);
    labelText.setText(getText());
  }

  protected ResourceManager getResourceManager() {
    if (null == resourceManager) {
      resourceManager = new LocalResourceManager(JFaceResources.getResources(), this);
    }
    return resourceManager;
  }

  protected String getText() {
    return text;
  }

  public void setText(String text) {
    this.text = text;
    if(labelText != null) {
      labelText.setText(text);
    }
  }

  protected String getHeaderText() {
    return headerText;
  }

  public void setHeaderText(String headerText) {
    this.headerText = headerText;
    if (headerLabel != null) {
      headerLabel.setText(headerText);
    }
  }

  protected ImageDescriptor getImage() {
    return imageDescriptor;
  }

  public void setImage(ImageDescriptor imageDescriptor) {
    this.imageDescriptor = imageDescriptor;
    if (imageLabel != null) {
      imageLabel.setImage(getResourceManager().createImage(imageDescriptor));
    }
  }

  public Color getHeaderColor() {
    return head.getBackground();
  }

  public void setHeaderColor(Color color) {
    head.setBackground(color);
    headerLabel.setBackground(color);
  }
} 

The most important method for our custom CSS here is the last setHeaderColor() method, which we will use for our header-background-color CSS property.

In order to test this widget you can place it on a new part in your application or in a tooltip as it is depicted in the screenshot above.

Afterwards you should set a certain header-text, an image and a description-text to the UserProfileWidget.

10.5. Adding the org.eclipse.e4.ui.css.core.propertyHandler extension point

Select the Extensions tab in the editor for the plugin.xml file and add the org.eclipse.e4.ui.css.core.propertyHandler extension point.

You create an extension in the Extensions tab by pressing the Add... button.

Add button in extension points

Select the org.eclipse.e4.ui.css.core.propertyHandler extension point and press the Finish button.

Selecting

There are three properties, which have to be defined for a org.eclipse.e4.ui.css.core.propertyHandler.

Table 3. Properties of the propertyHandler

adapter The ElementAdapter implementation adapts/wraps your custom widget for the CSS framework
composite A boolean, which specifies whether the widget is a composite or not
handler ICSSPropertyHandler implementation, which is responsible for setting a custom CSS property.

By clicking on the adapter hyperlink of the handler in the plugin.xml a "New Java Class" dialog appears, where you define the CompositeElement as superclass, call the class itself UserProfileElementAdapter and place it into a css package.

The UserProfileElementAdapter class should look like this:

package com.vogella.rcp.css.custom.css;

import org.eclipse.e4.ui.css.core.engine.CSSEngine;
import org.eclipse.e4.ui.css.swt.dom.CompositeElement;

import com.vogella.rcp.css.custom.widget.UserProfileWidget;

public class UserProfileElementAdapter extends CompositeElement {

  public UserProfileElementAdapter(UserProfileWidget composite, CSSEngine engine) {
    super(composite, engine);
  }
} 

In this case we only have a custom composite, which needs to be adapted. For other adapters see ??? in the ElementAdapter type hierarchy screenshot or define your own implementation of an ElementAdapter.

The propertyHandler also needs a handler, which has to be an implementation of the ICSSPropertyHandler interface. Therefore we need to click on the handler hyperlink in the plugin.xml and the following "New Java Class" dialog will appear:

The AbstractCSSPropertySWTHandler is an abstraction of the ICSSPropertyHandler interface for SWT widgets and handles the cast to a SWT Control, which is then passed to the applyCSSProperty and retrieveCSSProperty methods.

In the UserProfileCSSHandler implementation we apply the header-background-color to our UserProfileWidget.

package com.vogella.rcp.css.custom.css;

import org.eclipse.e4.ui.css.core.dom.properties.ICSSPropertyHandler;
import org.eclipse.e4.ui.css.core.dom.properties.converters.ICSSValueConverter;
import org.eclipse.e4.ui.css.core.engine.CSSEngine;
import org.eclipse.e4.ui.css.swt.properties.AbstractCSSPropertySWTHandler;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.widgets.Control;
import org.w3c.dom.css.CSSValue;

import com.vogella.rcp.css.custom.widget.UserProfileWidget;

public class UserProfileCSSHandler extends AbstractCSSPropertySWTHandler implements ICSSPropertyHandler {

  private static final String HEADER_COLOR = "header-background-color";

  @Override
  protected void applyCSSProperty(Control control, String property, CSSValue value, String pseudo, CSSEngine engine)
      throws Exception {
    if (control instanceof UserProfileWidget) {
      UserProfileWidget userProfileWidget = (UserProfileWidget) control;
      if (HEADER_COLOR.equalsIgnoreCase(property) && (value.getCssValueType() == CSSValue.CSS_PRIMITIVE_VALUE)) {
        Color newColor = (Color) engine.convert(value, Color.class, control.getDisplay());
        userProfileWidget.setHeaderColor(newColor);
      }
    }
  }

  @Override
  protected String retrieveCSSProperty(Control control, String property, String pseudo, CSSEngine engine)
      throws Exception {
    if (control instanceof UserProfileWidget) {
      UserProfileWidget userProfileWidget = (UserProfileWidget) control;
      if (HEADER_COLOR.equalsIgnoreCase(property)) {
        ICSSValueConverter cssValueConverter = engine.getCSSValueConverter(String.class);
        return cssValueConverter.convert(userProfileWidget.getHeaderColor(), engine, null);
      }
    }
    return null;
  }

} 

At first we check, if the given Control is a UserProfileWidget and cast it. Then we check, if the property, which should be applied, is our header-background-color.

In case these checks are valid the CSSEngine can be used to convert the given CSSValue in our case to a Color. Finally we set this color for the header of our custom widget.

Note

If you are using a different UI toolkit than SWT you must only implement the ICSSPropertyHandler interface, rather than the AbstractCSSPropertySWTHandler, which just passes an java.lang.Object and does not check for a SWT Control .

The last thing we need to do for the propertyHandler extension is to define for which property-name this handler is responsible:

10.6. Adding the org.eclipse.e4.ui.css.core.elementProvider extension point

Now the second and last extension point has to be added:

After adding the org.eclipse.e4.ui.css.core.elementProvider extension point we can add an IElementProvider to it by clicking on the class hyperlink and giving the class the name UserProfileWidgetElementProvider.

The widget property you can see in the screenshot above points to the full qualified name of the UserProfileWidget (com.vogella.rcp.css.custom.widget.UserProfileWidget). The widget property may be used several times, so that one IElementProvider implementation can be in charge of several widgets.

The UserProfileWidgetElementProvider class we just created by clicking the class hyperlink in the plugin.xml implements the IElementProvider interface and should look like this:

package com.vogella.rcp.css.custom.css;

import org.eclipse.e4.ui.css.core.dom.IElementProvider;
import org.eclipse.e4.ui.css.core.engine.CSSEngine;
import org.w3c.dom.Element;

import com.vogella.rcp.css.custom.widget.UserProfileWidget;

public class UserProfileWidgetElementProvider implements IElementProvider {

  @Override
  public Element getElement(Object element, CSSEngine engine) {
    if(element instanceof UserProfileWidget) {
      return new UserProfileElementAdapter((UserProfileWidget) element, engine);
    }
    
    return null;
  }

} 

In this IElementProvider implementation we return the UserProfileElementAdapter, which we previously defined, when we attached this adapter to the propertyHandler.

10.7. Validate

Now we can check, if our custom CSS definitions are applied to the UserProfileWidget. Make sure that you have done all the steps and then start your application.

  • The UserProfileWidget has been applied to a Part and a sample header-text, image and description-text has been set for the widget.

  • The CSS snippet has been added to the active CSS file

  • You have configured the org.eclipse.e4.ui.css.core.propertyHandler and org.eclipse.e4.ui.css.core.elementProvider extension points correctly

11. Learn more about Eclipse 4 RCP development

I hope you enjoyed this tutorial. You find this tutorial and much more information also in the Eclipse 4 RCP book from this author.

12. About this website

12.1. Donate to support free tutorials

Please consider a contribution Support free tutorials if this article helped you. It will help to maintain our content and our Open Source activities.

12.2. Questions and discussion

Writing and updating these tutorials is a lot of work. If this free community service was helpful, you can support the cause by giving a tip as well as reporting typos and factual errors.

If you find errors in this tutorial, please notify me (see the top of the page). Please note that due to the high volume of feedback I receive, I cannot answer questions to your implementation. Ensure you have read the vogella FAQ as I don't respond to questions already answered there.

12.3. License for this tutorial and its code

This tutorial is Open Content under the CC BY-NC-SA 3.0 DE license. Source code in this tutorial is distributed under the Eclipse Public License. See the vogella License page for details on the terms of reuse.

13. Links and Literature

13.1. Source Code

Source Code of Examples

13.2. CSS styling resources

Eclipse Wiki for CSS attributes

13.3. vogella Resources

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