Applying CSS to Java objects
Shows how to apply the CSS to Java™ objects.
Provides an overview of how to map the CSS mechanism to the hierarchy of Java™ objects
Describes the CSS engine and what it does at load time and at run time.
Describes the input data model and the information it supplies to the CSS engine.
Explains recursion in CSS documents.
Explains how to use expressions in CSS declarations.
Describes the differences between the CSS2 syntax and the style sheets used in Rogue Wave® JViews Diagrammer.
Overview
The CSS selector mechanism was designed to match elements in HTML or XML documents. It can also be used to match a hierarchy of Java™ objects accessible from a model interface. In this context, the CSS level 2 recommendation is transposed for the Java language and used to set bean properties according to the Java object hierarchy and state.
In applying CSS to Java objects, the term
model objects is used as the equivalent of the term
elements in the W3C recommendation.
The CSS declarations for each model object are sorted and used according to the application that controls the CSS engine. The declarations represent
property settings on a target object. The target object concerned depends on the way the CSS engine is used.
Rogue Wave® JViews Diagrammer uses CSS declarations to create and customize one graphic object for each object in the data model, and to create and customize renderers according to user settings.
The CSS engine
The CSS engine has different responsibilities at load time and at run time:
At load time: creating and customizing graphic objects and renderers
At run time: customizing the graphic objects according to model changes
Usually the left side of a declaration represents a bean
property of the graphic object. The right side is a literal and, if it needs type conversion, the Java method s
etAsText is invoked on the Property Editor associated with the bean property.
The data model
The input data model represents the seed of the “CSS for Java™” engine. It provides three important kinds of information to the CSS engine, required to resolve the selectors:
The tree structure of objects, which will be used by selector transitions.
Object type, ID, and tag (or user-defined type), which match element type, ID, and CSS classes. IDs and types are strings; CSS classes are words separated by a space character. ID is not required to be unique, although it is wise to assume so.
Attribute, which matches an attribute of the same name in an attribute condition within the selector.
The target object is the graphic object associated with the model object. The declarations change property values of the graphic object that corresponds to the matching model object, thereby customizing the graphic appearance given by the rendering.
In Rogue Wave® JViews Diagrammer the target object is an
IlvGraphic instance (see
Graphic objects in
The Essential JViews Framework,for information about
IlvGraphic objects) or a composite graphic.
Object types and attribute matching
The following code example shows a rule that matches the object of class (type) test_Vehicle, with the attribute model equal to sport, and sets the property icon of the graphic object associated with this object (defined elsewhere) to sport-car.gif.
test_Vehicle[model=sport] {icon : "sport-car.gif";}
Attribute matching can be used to add dynamic behavior: a PropertyChange event occurring on the model can activate the CSS engine to set new property values on the graphic objects.
The following code example shows a rule that changes the color of any object of CSS class computer whenever the model attribute state is set to down.
.computer[state = down] {color : "gray"}
For more information on attribute matching see also
Attribute matching.
Object identifiers and CSS classes
The Java model provides a
getID method which represents the ID of a model object. This ID can be checked against the # selector of a rule.
If there is a single CSS class in the selector, it is resolved with the
getTag method in the model.
Additional CSS classes can be set for an object in a property called CSSclass. The engine automatically merges the result of getTag with the value of the CSSclass property.
CSS classes are not necessarily related to data model semantics; they are devices to add to the
pattern-matching capabilities in the style sheet. An object belongs to only one class (its type) but can belong to several (or no) CSS classes. A check on a CSS class is for its presence or absence. Therefore a CSS class can be seen as an attribute without a value.
By default, an XML element name is defined as a CSS class. If, for example, a simple XML file contains the element names root and leaf, then the following code example shows how to change the color of leaf nodes to an RGB color specification.
node.leaf {
fillColor1 : 255,198,202 ;
foreground : 153,40,100 ;
}
The RGB color specification shown for the foreground (border) color is magenta.
Class name
The class property is a reserved keyword indicating the class name of the generated graphic object. Obviously the class declaration is applied only when there is a creation request. If the model state is changed, the graphic objects are customized by applying only new declarations coming from new matching rules of the style sheet. The class declaration is then simply ignored.
To change the class, you must remove the model object and add it again.
The right side of a class declaration may be:
The class name, loaded with the system class loader. For example:
link {
class : ilog.views.sdm.graphic.IlvGeneralLink;
foreground : red;
}
A factory (interface
IlvRectangularObjectFactory). The factory requires an
IlvRect object which should be present in the declarations. This rectangle will be passed as a parameter of the factory. For example:
node {
class : ilog.views.interactor.IlvMakeFilledRectangleInteractor;
IlvRect : 0,0,100,200;
}
There is a factory for most of the available graphic components. See
IlvGraphicFactories for more details.
A path name to a file. The class name is forwarded to the beans library (method
java.beans.Beans.instantiate ) so a serialized bean is suitable. For example:
link {
class : data.beans.gauge;
foreground : red;
}
When beanName is used as a serialized object name, the given beanName is converted to a resource path name and a trailing .ser suffix is added. An attempt is made to load a serialized object from that resource.
In this example, Beans.instantiate would try to read a serialized object from the resource data/beans/gauge.ser.
Pseudo-classes and pseudo-elements
Pseudo-classes are the minimal building blocks of a selector which match model objects according to an external context. The syntax is like a CSS class but with a colon instead of a dot. For example,
node:selected matches a
node only if the node is selected. The user agent can resolve this
pseudo-class at run time according to the state of each node.
A pseudo-class has the same specificity as a CSS class.
Pseudo-elements are metaclasses, like pseudo-classes, but match document structure instead of the user agent state.
Model indirection
The right side of a declaration resolves to a literal that is determined at run time by a Property Editor. However, if the literal is prefixed by @, the remainder of the string is interpreted as a model attribute name. The declaration takes the value from the model object, as shown in the following code example.
node { label : "@caption" ; title : "CSS rocks" ;}
The label property will be set to the value of the attribute called caption in the model. If the specified attribute does not exist for the object, it is searched for recursively in the model ascendancy. The title property will be set to the literal CSS rocks.
Such indirection is also used in the opposite direction, that is, to retrieve the name of the model attribute that controls a graphic property. This allows user interactions to modify the data model correctly. Two special names,
@_ID and
@_TAG, represent values returned by the model method calls
getID and
getTag getTag respectively.
In a palette symbol CSS, the indirection cannot directly access the properties of the SDM object that is rendered by the palette symbol. In this case, the indirection can only access the symbol parameters. If you want a property of a graphic element of the symbol to be mapped to a property of the corresponding SDM object, you have to define a parameter and use it as an intermediate property. The ID of this parameter can then be accessed in the symbol CSS as an object property. In the outer CSS, you can use this parameter ID as a bean property.
Resolving URLs
Sometimes declaration values are URLs relative to the style sheet location. A special construct, standard in CSS level2, allows you to create a URL from the base URL of the current style sheet. For example:
imageURL : url(images/icon.gif) ;
This declaration extends the path of the current style sheet URL with images/icon.gif. This construct is very useful for creating a style sheet with images located relative to it, because the URL remains valid even if the style sheet is cascaded or imported elsewhere.
CSS recursion
You are likely to want to specify a Java™ object as the value of a declaration. A simple convention allows you to recurse in the style sheet, that is, to define a new Java object which has the same style sheet but is unrelated to the current data model.
@# construct
Prefix the value with @# to create new beans when required as shown in the following code example.
Creating a bean in a declaration
form {
date : "@#dateBean" ;
title : "CSS rules" ;
}
Subobject#dateBean {
class : ’java.util.Date’ ;
time : ’23849291’ ;
}
The @# operator extends the current data model by adding a dummy model object as the child of the current object. The object ID of the dummy object is the remainder of the string, beyond the @# operator. The type of the dummy object is Subobject. The dummy object inherits CSS classes and attributes from its parent.
The CSS engine creates and customizes a new subobject according to the declarations it finds for the dummy object. This means, in particular, that the Java class of the subobject is determined by the value of the class property. The newly created subobject becomes the value of the @# expression. In the declarations for the subobject, attribute references through the @ operator refer to the attributes of the parent object.
Once the subobject is completed, the previous model is restored so that normal processing is resumed.
In code example
Creating a bean in a declaration, a
java.util.Date object is created, with the
time property set to
23849291. This new object is assigned to the
date property of the
form object.
@= and @+ constructs
There are two refinements of the @#ID operator:
'
@=ID'
Using @=ID instead of @#ID shares the instance. The first time the declaration is resolved, the object is created as with the @# operator. But for all subsequent access to the same value, @=ID will return the same instance, the one created the first time, without applying the rules. Note that all instances created with @= are cleared when a new style sheet is applied.
'
@+ID'
Using @+ID instead of @#ID avoids useless creation. Basically @+ID customizes only the object currently assigned to the property, unless it does not exist or its class is not the same as the one defined in the #ID rule. In this case, the object is first created, then customized, and then assigned to the property, the same as with an @# construct.
The need for these refinements arises from a performance issue. The @# operator creates a new object each time a declaration is resolved. Usually a declaration is applied whenever a property changes. Under certain circumstances, the creation of objects may lead to expensive processing, so Rogue Wave® JViews Diagrammer provides an optional mechanism to minimize the creation of objects during property changes.
@| construct
A CSS declaration value starting with
@| is interpreted as an expression (see
Expressions).
@ construct
A CSS declaration value that is exactly @ means cancel the property setting made in a previous rule. This construct is useful to prevent a property from being modified, especially when the default value is unknown. For example:
Canceling a property setting
node {
width : 23 ;
}
node.fixed {
width : @ ;
}
These two rules say that the width property value should be set to 23, unless the node has the CSS class fixed. Without the @ ability, the default value of width would have to be written down in the CSS.
Expressions
The value in a CSS declaration is usually a literal. However, it is possible to write an expression in place of a literal.
If the value begins with @|, then the remainder of the value is processed as an expression.
The syntax of the expressions, after the @| prefix, is close to the Java syntax. The expression type can be arithmetic (type int, long, float, or double ), Boolean, or String. Examples:
@|3+2*5 -> 13
@|true&&(true||!true) -> true
@|start+end -> "startend"
You can use the following regular arithmetic operators, listed here in decreasing precedence:
Unary operators
+,
-,
!Exponentiation operator
^Multiplicative operators
*,
/,
%Additive operators
+,
-Relational operators
==,
!=,
<,
>,
<=,
>=Conditional operators
&&,
||Conditional operator
?:NOTE >> The conditional operator is left-associative, unlike in Java where it is right-associative. In CSS, the expression a ? b : c ? d : e is equivalent to (a ? b : c) ? d : e, whereas in Java it is equivalent to a ? b : (c ? d : e).
In conditional expressions such as A ? B : C, put spaces around the colon because a colon can also be part of a subexpression, for example, when B is @abc.
An expression can refer to model attributes. The syntax is the usual one:
@|@speed/100+@drift -> 1/100 of the value of speed plus the value of drift. speed and drift are attributes of the current object.
'@|"name is: " + @name' -> "name is: Bob", if the value of the current object attribute name is Bob. Note the use of quotation marks to keep the space characters. You could use the backslash (\) character instead, directly preceding the space characters to retain them. The backslash works to quote any character that directly follows it. The use of the backslash character makes sure that the character thus quoted is not interpreted by the expression parser.
For example, when you edit a style sheet directly and you use double quotation marks for the entire declaration value specification, you must use escaped double quotation marks for inner strings of CSS expressions.
node {
name: "@|concat(\"Name is \", @name)" ;
}
Alternatively, you can use quotation marks:
node {
name: '@|concat("Name is ", @name)' ;
}
The standard functions abs(), acos(), asin(), atan(), ceil(), cos(), exp(), floor(), log(), pi, rint(), round(), sin(), sqrt(), and tan() are accepted, as in, for example:
@|3+sin(pi/2) -> 4
The following functions are also available:
Function | Description |
concat(arg1,...,argn) | Returns the concatenation of the arguments arg1,...,argn as strings. |
emptyString() | Returns an empty string. |
messageFormat(format,arg0,arg1,... | Returns a formatted string. The formatting is done through the object MessageFormat corresponding to the first argument. See class java.text.MessageFormat for details. |
decimalFormat(format, arg) | Returns a formatted string. The formatting is done through the object DecimalFormat corresponding to the first argument. See class java.text.DecimalFormat for details. |
simpleDateFormat(format, arg[, locale]) | Returns a formatted string. The formatting is done through the object SimpleDateFormat corresponding to the first argument. See class java.text.SimpleDateFormat for details. |
customFormat(formatBean,arg0,arg1,...) | Returns a formatted string. formatBean must be a Java object of type MessageFormat, NumberFormat, or DateFormat, usually defined using the @#id syntax. |
locale() | Returns the locale of the object being styled or of the current context. |
localized(resourceBundleName, resourceName[, locale]) | Returns the localized value of the designated resource, fetched from a ResourceBundle, as a string. |
id() | Returns the ID of the object being styled. |
type() | Returns the CSS type of the object being styled. |
cast(expr,type) | Casts a value to a type. The second argument can be a fully qualified class name (entered as a string) or a class object. |
double(expr) | Evaluates the argument as an expression. The result is a number of type Double. |
float(expr) | Evaluates the argument as an expression. The result is a number of type Float. |
int(expr) | Evaluates the argument as an expression. The result is a number of type Integer. |
long(expr) | Evaluates the argument as an expression. The result is a number of type Long. |
min(arg0,arg1, ...) | Returns the smallest number among the arguments. All arguments must be numbers. Unless otherwise specified, the arguments are interpreted as numbers of type Double. |
max(arg0,arg1, ...) | Returns the largest number among the arguments. All arguments must be numbers. Unless otherwise specified, the arguments are interpreted as numbers of type Double. |
invoke(obj,methodname,signature,arg...) | Invokes a method on the object by introspection. The signature string specifies the argument types of the method as a comma separated list of (fully qualified) type names. The object and the arguments must be cast accordingly. For example, the specification @|invoke(cast(@val,java.lang.String),substring,"int,int",int(3),int(6)) corresponds to the call ((String)@val).substring(3,6). |
invokeStatic(classname,methodname,signature,arg...) | Invokes a static method on the specified class by introspection. The signature string specifies the argument types of the method as a comma separated list of (fully qualified) type names. The arguments must be cast accordingly. For example, the specification @|invokeStatic("java.lang.Math","atan2","double,double",double(0.6),double(0.4)) corresponds to the call java.lang.Math.atan2(0.6,0.4). |
new(classname,signature,arg...) | Invokes a constructor on the specified class by introspection. The signature string specifies the argument types of the method as a comma separated list of (fully qualified) type names. The arguments must be cast accordingly. For example, the specification @|new("java.util.Date","long",long(1293840000000)) corresponds to the call java.util.Date(1293840000000L). |
random() | Returns a random number between 0 (inclusive) and 1 (exclusive). |
random(n) | Returns a random number between 0 (inclusive) and n (exclusive). |
point(x, y) | Returns a point of type IlvPoint. |
rect(x, y, w, h) | Returns a rectangle of type IlvRect. |
blinkingColor(onColor, offColor) | Returns a blinking color with the timing specified in the IlvBlinkingRenderer. |
blinkingColor(onColor, offColor, onTime, offTime) | Returns a blinking color with the timing onTime and offTime specified in milliseconds. |
brighterColor(color) | Returns a brighter color. Corresponds to Color.brighter. |
darkerColor(color) | Returns a darker color. Corresponds to Color.darker. |
styleSheetURL() | Returns the URL of the current style sheet, if any. |
styleSheetURL(path) | Returns a URL specified by a path relative to the location of the style sheet. |
getGraphicFromId(id) | Returns the graphic object that corresponds to the SDM model object with the specified ID. |
childrenCount() | Returns the number of children in the SDM model for the current node, for instance if the current node is a subgraph. |
childrenCount(tag) | Returns the number of children with a given tag in the SDM model for the current node, for instance if the current node is a subgraph. |
depends(expr, prop1, ...,propn) | Returns the value of the expression argument. The expression is declared to depend on the mode properties prop1 to propn. When these properties change, the expression is re-evaluated. |
Divergences from CSS2
Java™ objects are not HTML documents. The CSS2 syntax remains, so that a CSS editor can still be used to create the style sheet. However, the differences lead to adaptations of the CSS mechanism so that its power can be fully exploited and to some specific behavior.
Cascading
Cascading is explicit: the API offers a means of cascading style sheets. However, the !important and inherit tags are not supported for the sake of simplicity.
Pseudo-classes and pseudo-elements
The pseudo-class construct is fully implemented and used to represent renderer-specific states or GUI items. The list of predefined pseudo-classes and where they are used is as follows:
init (is automatically enabled at creation time only.
:init rules are not used if the bean is customized only)
selected (any renderer)
collapsed or
expanded (
expandCollapseRenderer )
<renderer_name>, for example,
legendRenderer (to specify that the rule applies only to rendering properties and not graphic object properties)
renderer (to specify a property belonging to a renderer, as opposed to one with the same name belonging to the graphic object)
tree (Workflow Modeler)
table ( Workflow Modeler)
You can add custom pseudo-classes with the method IlvSDMEngine:setPseudoClasses.
The CSS2 predefined pseudo-elements and pseudo-classes ( :link, :hover, and so forth) are not implemented because they have no meaning in Java.
Attribute matching
The attribute pattern in CSS2 makes the following checks for strings: presence [ att ], equality [ att= val], and inclusion [ att~= val]. The |= operator is disabled.
For Java objects, there are the following numeric comparators >, >=, <>, <=, <, with the usual semantics.
There are also equal and not-equal comparators which make the distinction between string comparison and numerical comparison:
Equal: "A==B" is true if and only if A and B are numerically equal (for example, 10 == 10.0); use "=" to test the equality of two Strings.
Not-equal: "A~B" is true if and only if A and B are two different Strings (for example, "10" ~ "10.0"); use "<>" to test the inequality of two numbers.
Operators available in the attribute selectors
Operator | Meaning | Applicable To |
A | present | strings |
A=val | equals | strings |
A~val | not equals | strings |
A~=val | contains the word | strings |
A==val | equals | numbers |
A<>val | not equals | numbers |
A<val | less than | numbers |
A<=val | less than or equals | numbers |
A>val | greater than | numbers |
A>=val | greater than or equals | numbers |
Syntax enhancement
CSS for Java requires the use of quotation marks when a token contains special characters, such as dot (.), colon (:), at sign (@), number sign (also known as hash sign, #), space ( ), and so on.
Quotes can be used almost everywhere, in particular to delimit a declaration value, an element type, or a CSS class with reserved characters.
The closing “;” is optional.
Null value
Sometimes it makes sense to specify a null value in a declaration. By convention, null is a zero-length string '' or "". For example:
node.not-handled {
class : '' ;
}
When a null class name is specified, no object is created at all, and no error is reported as it would be for a malformed class name.
The notation '' is also used to denote a null array for properties expecting an array of values.
Empty string
The null syntax does not allow you to specify an empty string in the style sheet. Instead, you can create an empty string, as shown in the following code example.
node {
label : @#emptyString ;
}
Subobject#emptyString {
class : 'java.lang.String';
}
Better still, you can use the sharing mechanism to avoid the creation of several strings. The
@= construct will create the empty string the first time only and will then reuse the same instance for all other occurrences of
@#emptyString, see
Sharing an empty string.
Sharing an empty string
node {
label : @=emptyString ;
}
Subobject#emptyString {
class : 'java.lang.String';
}
Copyright © 2018, Rogue Wave Software, Inc. All Rights Reserved.