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 :
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();
Display display = new Display(); CSSEngine engine = new CSSSWTEngineImpl(display);
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();
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);
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");
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");
This method parses a String litteral into a CSSValue instance. Here is how it can be used :
CSSEngine engine = ...; CSSValue value = engine.parsePropertyValue("red");
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);
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");
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...).
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.).
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);
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 :
To handle these 2 points, the CSS Engine uses an org.akrogen.tkui.css.core.resources.IResourcesRegistry which takes care of :
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(); } });
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 :
Label { color:red; }
public String getLocalName() { Widget widget = getWidget(); Class clazz = widget.getClass(); return ClassUtils.getSimpleName(clazz); }
Label#MyId { color:red; }
public String getCSSId() { Widget widget = getWidget(); Object id = widget.getData("id"); if (id != null) return id.toString(); return null; }
Label label = ... label.setData("id", "MyId");
.redClass { color:red; }
public String getCSSClass() { Widget widget = getWidget(); Object id = widget.getData("class"); if (id != null) return id.toString(); return null; }
Label label = ... label.setData("class", "redClass");
Label label = ... label.setData("style", "color:red;");
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:
Text { color:red; }
input[type=text] { color:red; }
JTextField { color:red; }
input[type=text] { color:red; }
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);
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; }
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.