CSSEngine API

Every implementation of SWT CSS Engine , Swing CSS Engine (or other) implements the org.akrogen.tkui.css.core.engine.CSSEngine interface which defines methods for :

The different CSS Engines are based on several concepts and are thus configurable in ways such as :

  • Specifying the SAC parser to use
  • Selectors support (SWT/Swing or HTML...)
  • adding your own CSSproperties (ICSSPropertyHandler ).

CSSEngine Methods

TK-UI implements the generic CSS Engine interface org.akrogen.tkui.css.core.engine.CSSEngine which defines the following methods :

The following examples use a CSSEngine instance named engine . THis instance can be of type Swing :

CSSEngine engine = new CSSSwingEngineImpl();
or SWT :
Display display = new Display();
CSSEngine engine = new CSSSWTEngineImpl(display);

parseStyleSheet

This method is used to load a CSS stylesheet. Here is an example on how to use it :

CSSEngine engine = ....
engine.parseStyleSheet(new StringReader("input{color:red;} textarea{color:green}"));

parseStyleSheet returns a standard w3c StyleSheet instance which is internally stocked in a w3c DocumentCSS field of engine. The DocumentCSS can be retrieved with the method getDocumentCSS :

CSSEngine engine = ...;
DocumentCSS documentCSS = engine.getDocumentCSS();

applyStyles

This method is used to apply the CSS styles (already loaded via the method parseStyleSheet ) on a widget (and possibly on its children). Here is an example on how to apply some loaded styles on a Swing JFrame :

CSSEngine engine = ....
// Apply style declaration to the JFrame and the components children
engine.applyStyles(frame, true);
The first parameter specifies that the styles are to be applied on the JFrame. The second parameter (true) indicates that the styles are to be recursively applied on JFrame and all it's children.

parseStyleDeclaration

This method is used to parse an inline style declaration and returns a CSSStyleDeclaration instance. Here is how it can be used :

CSSEngine engine = ....
// Create CSSStyleDeclaration
CSSStyleDeclaration styleDeclaration = engine.parseStyleDeclaration("color:red;background-color:green");

applyStyleDeclaration

This method can be used to apply a style declaration ( CSSStyleDeclaration ) on a widget. Here is how it can be used :

Text text = ...;
CSSEngine engine = ....
// Create CSSStyleDeclaration
CSSStyleDeclaration styleDeclaration = engine.parseStyleDeclaration("color:red;background-color:green");
// Apply style declaration to the Text widget
engine.applyStyleDeclaration(text, styleDeclaration);

Please not that the loading and the applying of a style declaration can be combined in a single call to the method parseAndApplyStyleDeclaration :

Text text = ...;
CSSEngine engine = ....
// Create CSSStyleDeclaration and apply style declaration to the Text widget
engine.parseAndApplyStyleDeclaration(text, "color:red;background-color:green");

parsePropertyValue

This method parses a String litteral into a CSSValue instance. Here is how it can be used :

CSSEngine engine = ...;
CSSValue value = engine.parsePropertyValue("red");

applyCSSProperty

This method can be used to apply a CSS property on a widget. Here is how it can be used :

Text text = ...;
CSSEngine engine = ...;
CSSValue value = engine.parsePropertyValue("red");
engine.applyCSSProperty(text, "color", value, null);

retrieveCSSProperty

This methods can be used to retrieve in a String the value of a widget's CSS property. Here is how it can be used :

Text text = ...;
CSSEngine engine = ...;
String value = engine.retrieveCSSProperty(text, "color");

reset

This method can be used to reset the loaded styles and to remove any listeners added to widgets to handle dynamic pseudo-classes (:focus, :hover...).

dispose

This method calls the reset method of the engine but also the dispose method of the IResourcesRegistry used by the CSSEngine, and thus allowing to free all the resources previously created (Fonts, Images, etc.).

CSSEngine Concepts

All the CSS Engines are highly configurable through the use of patterns like:

IResourcesLocatorManager

The CSS engine is capable of resolving urls to actual resources like images. Here is an example on how to add an image to an SWT button:

Button {
    background: url(./images/icons/type/class.gif);
}

in order to resolve urls into actual resource's paths, the CSS Engine uses a org.akrogen.core.resources.IResourcesLocatorManager implementation which given an url, can return a java.io.Reader or an java.io.InputStream .

An IResourcesLocatorManager is basically composed of a list of org.akrogen.core.resources.IResourceLocator .

The default IResourcesLocatorManager used in TK-UI is org.akrogen.core.impl.resources.ResourcesLocatorManager which contains a single instance of org.akrogen.core.impl.resources.FileResourcesLocatorImpl capable of resolving urls corresponding to file names.

To specify which IResourcesLocatorManager implementation to be used by the CSS engine, you may use tje method setResourcesLocatorManager :

public void setResourcesLocatorManager(IResourcesLocatorManager resourcesLocatorManager);

IResourcesRegistry

When the CSS Engine is about to apply a CSS style defined as this :

Label {
    color:red;
}
Button {
    background-color: red;
}

it uses a w3c SAC parser to parse the CSS style. the literal 'res' gets transformed into a w3c CSSValue . But in order to be usable with actual widgets such as label or button, the CSSValue must be converted to a Color instance :

When manipulating resources, we are basically faced with 2 problems :

  • Ressources caching : in the previous example, two Color instances will normally be created (color and background-colol). Yet, both of them represents the red color, so a single instance would have been enough.
  • Resources disposal : (applies only to SWT) the dispose method must be called to free the resources.

To handle these 2 points, the CSS Engine uses an org.akrogen.tkui.css.core.resources.IResourcesRegistry which takes care of :

  • handling resources caching for things like Color, Cursor, Font, Image...using the methods getResource , registerResource , unregisterResource .
  • ressources disposal using the method dispose.

To specify the IResourcesRegistry implementation to be used by the CSS Engine, you may use the method setResourcesRegistry :

public void setResourcesRegistry(IResourcesRegistry resourcesRegistry);

For SWT, the CSS Engine provides a ready-to-use implementation which is org.akrogen.tkui.css.swt.resources.SWTResourcesRegistry Whose constructor takes one parameter (org.eclipse.swt.widgets.Display) to add a listener on SWT.Dispose.

display.addListener(SWT.Dispose, new Listener() {
	public void handleEvent(Event event) {
		dispose();
	}
});
And thus, the dispose method of IResourcesRegisrty gets called when the SWT Display is freed.

CSSStylableElement

To apply a CSS property on a widget, , the CSS Engine uses the interface org.w3c.dom.Element or more precisely org.akrogen.tkui.css.core.dom.CSSStylableElement which extends Element. Every single widget (JComponent in Swing or Control in SWT) gets wrapped in a org.akrogen.tkui.css.core.dom.CSSStylableElement instance.

This way, it is possible to use common SAC factories SelectorFactory , et ConditionFactory for both Swing and SWT, but also use w3c Element . Internally, the CSS Engine uses a w3c implementation og ViewCSS (to calculate widget's CSS style) which has a method named getComputedStyle taking a w3c Element as a parameter.

CSSStylableElement also handles :

  • selector name using the method getLocalName . For example, it is possible to write the following CSS style in SWT :
    Label {
        color:red;
    }
    and by the use of org.akrogen.tkui.css.swt.dom.SWTElement as a CSSStylableElement implmentation whose getLocalName is defined as :
    public String getLocalName() {
       Widget widget = getWidget();
       Class clazz = widget.getClass();
       return ClassUtils.getSimpleName(clazz);
    }
    we can use the SWT Class names as selectors.
  • id using the method getCSSId . For example, it is possible to write the following id based CSS Style :
    Label#MyId {
        color:red;
    }
    and by the use of org.akrogen.tkui.css.swt.dom.SWTElement as a CSSStylableElement impelemntation whose getCSSId is defined as :
    public String getCSSId() {
        Widget widget = getWidget();
        Object id = widget.getData("id");
        if (id != null)
          return id.toString();
        return null;
    }
    it is possible to use id based styles :
    Label label = ...
    label.setData("id", "MyId");
  • class using the method getCSSClass . For example, it is possible to write the following class based CSS Style :
    .redClass {
        color:red;
    }
    and by the use of org.akrogen.tkui.css.swt.dom.SWTElement as a CSSStylableElement impelemntation whose getCSSClass is defined as :
    public String getCSSClass() {
        Widget widget = getWidget();
        Object id = widget.getData("class");
        if (id != null)
          return id.toString();
        return null;
    }
    it is possible to handle class based CSS styles :
    Label label = ...
    label.setData("class", "redClass");
  • style using the method getCSSStyle . it is possible to apply an inline CSS style to a widget as follows:
    Label label = ...
    label.setData("style", "color:red;");
    In SWT, the org.akrogen.tkui.css.swt.dom.SWTElement implementation used is CSSStylableElement , whose getCSSStyle method is defined as follows :
    public String getCSSClass() {
        Widget widget = getWidget();
        Object id = widget.getData("style");
        if (id != null)
          return id.toString();
        return null;
    }

CSSStylableElement encapsulates an SWT or Swing widget and handles the id, class, style, etc. fields TK-UI provides multiple CSSStylableElement implementations:

IElementProvider

Hence, it is possible to control the CSSEngine behaviour (style, id, class) by providing a specific CSSStylableElement implementation. To control which CSSStylableElement to use, the org.akrogen.tkui.css.core.dom.IElementProvider interface must be implemented.

public interface IElementProvider {

	/**
	 * Return the w3c Element which wrap the native widget<code>element</code>
	 * (SWT Control, Swing JComponent). The <code>element</code> can be the
	 * w3c Element.
	 * 
	 * @param element
	 * @return
	 */
	public Element getElement(Object element);

}

TK-UI provides multiple IElementProvider implementations:

To control which IElementProvider implementation to be used by the CSS Engine, you may use the setElementProvider method:

public void setElementProvider(IElementProvider elementProvider);

ICSSPropertyHandler

To apply a CSS property on a widget, the CSS Engine uses the ICSSPropertyHandler interface:

public interface ICSSPropertyHandler {
	/**
	 * Apply CSS Property <code>property</code> (ex : background-color) with
	 * CSSValue <code>value</code> (ex : red) into the <code>element</code>
	 * (ex : Swing Component, SWT Widget).
	 * 
	 * @param element
	 *            Swing Component, SWT Widget...
	 * @param property
	 *            CSS Property
	 * @param value
	 *            CSS value
	 * @param pseudo
	 * @param engine
	 *            CSS Engine
	 * @return
	 * @throws Exception
	 */
	public boolean applyCSSProperty(Object element, String property,
			CSSValue value, String pseudo, CSSEngine engine) throws 
                  Exception;

	/**
	 * Retrieve CSS value (ex : red) of CSS Property <code>property</code> (ex :
	 * background-color) from the <code>element</code> (ex : Swing Component,
	 * SWT Widget).
	 * 
	 * @param element
	 * @param property
	 *            CSS Property
	 * @param engine
	 *            CSS Engine
	 * @return
	 * @throws Exception
	 */
	public String retrieveCSSProperty(Object element, String property,
			CSSEngine engine) throws Exception;
}
There are two ways of specifying a CSSproperty to the CSS Engine:
  • By explicitly specifying the mapping between the handler and the CSS property name.
  • By naming convention : the handler class name corresponds to the CSS property name.
You may consult the developper's Guide for more information (TODO).

ICSSValueConverter

The CSS Engine internally keeps CSSValue instances. When a style is about to be applied on a Swing or SWT widget, the CSSValue must be converted into a UI instance (ex: convert CSSValue (red) into a java.awt.Color for Swing). A ICSSValueConverter implementation is used for this conversion to happen. Here is the source code of ICSSValueConverter :

public interface ICSSValueConverter {

	/**
	 * Returns the type to which this converter can convert. The return type is
	 * Object rather than Class to optionally support richer type systems than
	 * the one provided by Java reflection.
	 * 
	 * @return the type to which this converter can convert, or null if this
	 *         converter is untyped
	 */
	public Object getToType();

	/**
	 * Returns the result of the conversion of the given CSSValue
	 * <code>value</code>.
	 * 
	 * @param value
	 *            the CSSValue to convert, of type {@link #getFromType()}
	 * @return the converted object, of type {@link #getToType()}
	 */
	public Object convert(CSSValue value, CSSEngine engine, Object context)
			throws Exception;

	public String convert(Object value, CSSEngine engine, Object context)
			throws Exception;

	public String convert(Object value, CSSEngine engine, Object context,
			ICSSValueConverterConfig config) throws Exception;
}

When calling the convert method of CSSEngine, the latter first verifies that the resource (SWT, Swing) is not in the cache IResourcesRegistry before calling the adequate converter.