Toutes les implémentations des moteurs CSS SWT , moteurs CSS Swing (ou autres) implémente l'interface org.akrogen.tkui.css.core.engine.CSSEngine qui fournit des méthodes qui permettent entre autres de :
Les moteurs CSS s'appuient sur différents concepts qui rendent les moteurs CSS configurables comme :
TK-UI implémente l'interface générique de moteur CSS org.akrogen.tkui.css.core.engine.CSSEngine qui propose plusieurs méthodes :
Les examples suivants s'appuient sur une instance CSSEngine engine . Cette instance peut etre de type Swing :
CSSEngine engine = new CSSSwingEngineImpl();
Display display = new Display(); CSSEngine engine = new CSSSWTEngineImpl(display);
Cette méthode permet de charger une feuille de style CSS. Voici un exemple de code d'utilisation de cette méthode :
CSSEngine engine = .... engine.parseStyleSheet(new StringReader("input{color:red;} textarea{color:green}"));
parseStyleSheet retourne une instance w3c StyleSheet qui est stockée en interne dans une instance w3c DocumentCSS de engine. DocumentCSS peut être accéssible via la méthode getDocumentCSS :
CSSEngine engine = ...; DocumentCSS documentCSS = engine.getDocumentCSS();
Cette méthode permet d'appliquer les styles CSS (chargés préalablement à l'aide de la méthode parseStyleSheet ) à une widget (et ses widgets enfants). Voici un exemple de code qui applique les styles CSS chargées à une JFrame Swing :
CSSEngine engine = .... // Apply style declaration to the JFrame and the components children engine.applyStyles(frame, true);
Cette méthode permet de parser un style inline et de retourner une instance CSSStyleDeclaration . Voici un exemple de code d'utilisation de cette méthode :
CSSEngine engine = .... // Create CSSStyleDeclaration CSSStyleDeclaration styleDeclaration = engine.parseStyleDeclaration("color:red;background-color:green");
Cette méthode permet d'appliquer une déclaration d'un style CSSStyleDeclaration à une widget. Voici un exemple de code d'utilisation de cette méthode :
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);
L'application d'une declaration de style peut s'effectuer de la même manière à l'aide de la méthode parseAndApplyStyleDeclaration :
Text text = ...; CSSEngine engine = .... // Create CSSStyleDeclaration and apply style declaration to the Text widget engine.parseAndApplyStyleDeclaration(text, "color:red;background-color:green");
Cette méthode permet de parser une valeur String en instance CSSValue . Voici un exemple de code qui permet de récupérer une instance CSSValue :
CSSEngine engine = ...; CSSValue value = engine.parsePropertyValue("red");
Cette méthode permet d'appliquer la valeur CSS d'une propriété CSS à une widget. Voici un exemple de code d'utilisation de cette méthode :
Text text = ...; CSSEngine engine = ...; CSSValue value = engine.parsePropertyValue("red"); engine.applyCSSProperty(text, "color", value, null);
Cette méthode permet de retrouver la valeur CSS (String) d'une propriété CSS d'une widget. Voici un exemple de code d'utilisation de cette méthode :
Text text = ...; CSSEngine engine = ...; String value = engine.retrieveCSSProperty(text, "color");
Cette méthode permet de reinitialiser les feuilles de styles CSS et de supprimer les listeners ajoutés aux widgets lorsque gérer les pseudo classes dynamiques (:focus, :hover...).
Cette méthode appelle la méthod reset et appelle la méthode dispose du IResourcesRegistry enregistré dans l'instance CSSEngine, ce qui permet de libérer les ressources créées et mises en cache par le moteur CSS.
Le moteur CSS est capable de gérer des url sur des ressources. Voici un exemple SWT de style que l'on peut ecrire pour ajouter une image dans un bouton.
Button { background: url(./images/icons/type/class.gif); }
Une image doit donc être chargée à partir de l'url défini. Pour résoudre les url et charger les resources, le moteur CSS utilise une implémentation de org.akrogen.core.resources.IResourcesLocatorManager qui permet de résoudre l'url et retourner un java.io.Reader ou java.io.InputStream .
Une instance IResourcesLocatorManager est constituée d'une liste de org.akrogen.core.resources.IResourceLocator qui permet de retourner un java.io.Reader ou java.io.InputStream à partir d'un uri.
Par défaut l'instance IResourcesLocatorManager utilisé dans TK-UI est org.akrogen.core.impl.resources.ResourcesLocatorManager qui contient une instance org.akrogen.core.impl.resources.FileResourcesLocatorImpl qui permet de resoudre les url de type file.
Pour enregistrer l'implémentation de IResourcesLocatorManager a utiliser par le moteur CSS, la méthode setResourcesLocatorManager doit être appelée.
public void setResourcesLocatorManager(IResourcesLocatorManager resourcesLocatorManager);
Lorsque le moteur CSS doit appliquer le style :
Label { color:red; } Button { background-color: red; }
Le moteur CSS utilise un parseur w3c SAC pour parser les styles CSS. Il transforme la string red en instance w3c CSSValue . La couleur red doit etre ensuite appliquée aux widgets Label et Button, autrement dit le CSSValue red doit etre transformé en instance Color de l'UI :
Il existe deux problèmes lorsque l'on manipule des ressources :
Pour résoudre ces deux problématiques, le moteur CSS peut utiliser une l'implémentation de org.akrogen.tkui.css.core.resources.IResourcesRegistry qui permet de :
Pour enregistrer l'implémentation de IResourcesRegistry à utiliser par le moteur CSS, la méthode setResourcesRegistry doit être appelée.
public void setResourcesRegistry(IResourcesRegistry resourcesRegistry);
Dans le cas de SWT, la classe org.akrogen.tkui.css.swt.resources.SWTResourcesRegistry est utilisée et permet de gérer le cache et la libération des des ressources Color, Cursor, Font, Image. Le constructeur SWTResourcesRegistry attend le paramètre org.eclipse.swt.widgets.Display qui ajoute un listener sur SWT.Dispose.
display.addListener(SWT.Dispose, new Listener() { public void handleEvent(Event event) { dispose(); } });
Pour appliquer la valeur d'une propriété CSS à une widget, le moteur CSS travaille avec une interface unique org.w3c.dom.Element ou plus exactement org.akrogen.tkui.css.core.dom.CSSStylableElement qui hérite de Element. Chacune des widgets (JComponent Swing ou Control SWT) sont wrappés par une instance org.akrogen.tkui.css.core.dom.CSSStylableElement .
Cette solution permet d'une part d'utiliser des factory communes SAC SelectorFactory , et ConditionFactory pour Swing et SWT, mais d'autre part utiliser les interfaces w3c qui utilise des Element w3c. La moteur CSS utilise par exemple en interne une implémentation w3c de ViewCSS (pour calculer les styles CSS d'une widget) qui a une méthode getComputedStyle qui attend en paramètre une instance Element w3c.
CSSStylableElement permet aussi de gérer les informations :
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 wrappe une widget (SWT ou Swing) et permet de gérer ses informations id, class, style... TK-UI fournit plusieurs implémentation de CSSStylableElement :
Text { color:red; }
input[type=text] { color:red; }
JTextField { color:red; }
input[type=text] { color:red; }
Il est ainsi possible de personnaliser le moteur CSS pour gérer les id, class, style à l'aide d'une implémentation de CSSStylableElement décrit ci dessus. Pour indiquer au moteur CSS l'implémentation CSSStylableElement à utiliser, il faut implémenter l'interface org.akrogen.tkui.css.core.dom.IElementProvider .
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 fournit plusieurs implémentation de IElementProvider :
Pour enregistrer l'implémentation de IElementProvider a utiliser par le moteur CSS, la méthode setElementProvider doit être appelée.
public void setElementProvider(IElementProvider elementProvider);
Pour appliquer la valeur d'une propriété CSS à une widget, le moteur CSS utilise une interface ICSSPropertyHandler.
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; }
Le moteur CSS stocke en interne des instances CSSValue. Lorsque 'un style doit être appliqué, à une widget SWT ou un Component Swing, l'instance CSSValue doit être converti en instance de l'UI (ex: convertir une CSSValue (red) en objet java.awt.Color Swing). Une implémentation de ICSSValueConverter permet de convertir une instance CSSValue en objet utilisable par l'UI. Voici le code de 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; }
En appelant la méthode convert de CSSEngine, le moteur CSS vérifie dans un premier temps que la ressource (Swing ou SWT) n'est pas dans le cache IResourcesRegistry avant d'appeler le converter adéquate.