Styles and StyleSheets

As you have seen, the visual appearance and behavior of Components can be configured by setting properties on each Component instance. This practice can become very repetitive when dealing with significant numbers of heavily configured Components. To alleviate this problem, Echo provides "Styles" which may be configured to describe common property settings and then assigned to multiple Components.

Creating Styles

Styles are defined using the Style interface. The Style interface itself only specifies a few methods to retrieve property values, e.g., getPropertyValue() and getIndexedPropertyValue(). The MutableStyle class provides an implementation of Style that provides property storage and is suitable for general purpose use. While it is entirely possible to roll your own Style implementation class, it is normally more sensible to create MutableStyle objects and assign properties to them.

Styles may be assigned to multiple Components. Setting the Style of a component will not affect a Component's internal property settings; the information contained in the Style will only be used for rendering.

The following example demonstrates a Style being used by multiple Components:

MutableStyle buttonStyle = new MutableStyle();
buttonStyle.setProperty(
    AbstractButton.PROPERTY_BACKGROUND, Color.GREEN);
buttonStyle.setProperty(
    AbstractButton.PROPERTY_BORDER,
    new Border(2, Color.GREEN, Border.STYLE_GROOVE));
buttonStyle.setProperty(
    AbstractButton.PROPERTY_ROLLOVER_ENABLED, Boolean.TRUE);
buttonStyle.setProperty(
    AbstractButton.PROPERTY_ROLLOVER_FOREGROUND, Color.BLUE);

Button button1 = new Button("Alpha");
button1.setStyle(buttonStyle);
parentComponent.add(button1);

Button button2 = new Button("Bravo");
button2.setBackground(Color.YELLOW);
button2.setStyle(buttonStyle);
parentComponent.add(button2);

CheckBox checkBox = new Button("Charlie");
checkBox.setStyle(buttonStyle);
parentComponent.add(checkBox);

Property Names: The names of properties used in a style may be specified using constants defined within the Component class for which the Style will be used. These property name constants will always start with the prefix "PROPERTY_" followed by the property name, e.g., PROPERTY_FOREGROUND or PROPERTY_BORDER. Properties which do not have a constant with such a prefix, such as "visible" or "locale" cannot be defined using Styles.

Target Components: The buttonStyle in the above example is intended to be used by any AbstractButton. As such, the Style may be used by any AbstractButton-derivative, such as Button and CheckBox as in the example.

Property Precedence: Note as well that in the code configuring button2, a property is directly assigned to the Button. Properties which are directly assigned to a Component will override those specified in the Style. Thus, in the above example, button2 would be rendered with a yellow (rather than green) background color.

StyleSheets

A StyleSheet represents a collection of named Style objects. A single StyleSheet may be assigned to an ApplicationInstance. Components that are registered to that ApplicationInstance will then be able to reference named Styles using String-based identifiers. The Component.setStyleName() method is used to specify the use of a named Style in the StyleSheet by a Component.

Button button1 = new Button("Alpha");
button1.setStyleName("Default");

Programmatically Declaring StyleSheets

StyleSheets may be programmatically created by instantiating a MutableStyleSheet and assigning Styles to it. When a Style is added to a MutableStyleSheet the target Component base class and a style name must be specified. The following code example demonstrates adding Styles to a MutableStyleSheet:

MutableStyleSheet styleSheet = new MutableStyleSheet();
styleSheet.addStyle(AbstractButton.class, "Default", 
    buttonStyle);
styleSheet.addStyle(AbstractButton.class, "Special", 
    specialButtonStyle);
styleSheet.addStyle(TextComponent.class, "Login", 
    loginFieldStyle);

Declaring StyleSheets with XML

StyleSheets may be defined entirely using XML files. Use of this feature is made at the discretion of the developer; as previously shown, StyleSheets can be created entirely without the use of XML if desired.

Loading XML StyleSheets: To load a StyleSheet from an XML file, the nextapp.echo.app.serial.StyleSheetLoader class is used. The various load() methods of this class may be used to create StyleSheet instances from resources in the CLASSPATH or directly from an InputStream. The following example shows a StyleSheet being loaded from a resource in the CLASSPATH and placed in a static constant:

public static final StyleSheet DEFAULT_STYLE_SHEET;
static {
  try {
    DEFAULT_STYLE_SHEET = StyleSheetLoader.load(
        "/echo3example/email/resource/style/Default.stylesheet", 
        Thread.currentThread().getContextClassLoader());
  } catch (SerialException ex) {
    throw new RuntimeException(ex);
  }
}