The Flag renderer example
Provides an example of a custom renderer that displays a flag on the node that remains visible even if the object is hidden.
Provides an overview of the example.
Describes the
FlagRenderer class as used in this example.
Describes the bean properties as used in this example.
Describes the private methods of the
FlagRenderer class as used in this example.
Describes overloading in the
FlagRenderer class.
Shows how to integrate the new Flag renderer.
Describes enhancements that could be made to the Flag renderer example.
Overview
The Flag Renderer example addresses a typical graphical need that can be answered with an SDM renderer. The need is to set a decoration on a node that will always be visible, for example, if the state of a model object changes and it needs to catch the user’s attention. The renderer must display a flag on the node such that the flag remains visible even if the object is hidden by another graphic object.
The source code of the Flag renderer example is supplied in the
<installdir>/jviews-diagrammer/codefragments/renderer directory and described in this section.
The following figure shows an example of a flag on a node, as it would be displayed by the Flag renderer.
An example of a flag displayed by the Flag renderer
Header part
The class
FlagRenderer extends
IlvFilterSDMRenderer, so it does not need to redefine all unused renderer methods.
The following code example shows the packages imported and the class declaration.
The statements for the class
package tutorial;
import ilog.views.sdm.*;
import ilog.views.sdm.model.*;
import ilog.views.sdm.graphic.*;
import ilog.views.sdm.renderer.*;
import ilog.views.*;
import ilog.views.graphic.*;
/**
* The class <code>FlagRenderer</code> is a filtering renderer that
* sticks various IlvGraphic (the flags) to a node. Flags are located
* in a separate layer, typically over all other layers to have them
* always visible.
* <P>This renderer defines the following graphic properties:
* <UL>
* <LI>Flag: an IlvGraphic that represents the decorations<\LI>
* <\UL>
* */
public class FlagRenderer extends IlvFilterSDMRenderer
{
The following code example shows the internal variables and the constructors.
Internal variables and constructors
private int _flagLayer = 20;
static final String[] REND_CLASS = {"renderer", "flagRenderer" };
static final String FLAG = "Flag";
static final String FLAG_GRAPHICS = "Flag-graphic";
//////////////////////
// constructors
/**
* Creates a new flag renderer for a specified
* filtered renderer.
*/
public FlagRenderer(IlvSDMRenderer renderer) {
super(renderer);
}
/**
* Creates a new flag renderer with a <code>null</code>
* filtered renderer.
*/
public FlagRenderer(){
this(null);
}
The internal variables are as follows:
_flagLayer is the layer where the flags will be added.
REND_CLASS is the
CSS pseudo-class of this renderer, for use in the style sheet.
The other constants set string literals.
Bean properties
The bean properties allow you to customize the renderer.
In this example, you need to change only the flag layer value. The setter and getter methods are shown in the following code example.
Setter and getter methods for the bean property Flag Layer
/////////////////////////
// Bean properties
/**
* Sets flag layer. Default is 20.
* */
public void setFlagLayer(int v) {
_flagLayer = v;
}
/*
* Returns flag layer.
* @see setDebugMask
*/
public int getFlagLayer() {
return _flagLayer;
}
Private methods
The following private methods of the Flag Renderer handle the flag on a node:
checkNode cleanNode moveNode The following code example shows the code for checkNode.
Checking for a flag
//////////////
// local method
The checkNode method fetches the graphic property to see if a flag is defined for the node in its current state.
// manage graphic props
private void checkNode(IlvSDMEngine engine, Object obj,
IlvGraphic graphic) {
Object rawFlag = IlvRendererUtil.getGraphicProperty(engine, obj,
FLAG, REND_CLASS, null);
if (rawFlag != null && rawFlag instanceof IlvGraphic) {
IlvGraphic g = (IlvGraphic) rawFlag;
// set flag location at top left corner
IlvRect r = graphic.boundingBox(null);
g.move(r.x, r.y);
// add object
engine.getGrapher().addObject(g, _flagLayer, true);
// save flag in the graphic itself
graphic.addProperty(FLAG_GRAPHICS, g);
}
}
The checkNode method checks if a flag is requested and renders the flag if necessary by adding it at the upper left of the object.
The following code example shows the code for cleanNode.
Removing a flag
// remove previous flag
private void cleanNode(IlvSDMEngine engine, IlvGraphic graphic) {
// get the flag object from the source
Object previous = graphic.getProperty(FLAG_GRAPHICS);
if (previous != null) {
// remove it and clear the property
engine.getGrapher().removeObject((IlvGraphic)previous,true);
graphic.removeProperty(FLAG_GRAPHICS);
}
}
The cleanNode method is used to remove the flag when it is no longer needed.
The following code example shows the code for moveNode.
Moving the flag with the node
// adjust flag position
private void moveNode(IlvRect newBBox, IlvGraphic flag) {
if (flag == null)
return;
flag.move(newBBox.x, newBBox.y);
}
The moveNode method is used to move only the flag, according to the new bounding box of the node on which it appears.
Overloading methods of the Filter class
The Flag Renderer overloads the following
IlvFilterSDMRenderer methods:
The overloaded methods start by calling super, which calls the superclass method of the same name before processing the flag.
Creating the flag
/**
* Creates flag.
* */
public void addNodeGraphic(IlvSDMEngine engine,
java.lang.Object node,
IlvGraphic graphic,
boolean redraw) {
super.addNodeGraphic(engine,node,graphic,redraw);
checkNode(engine, node, graphic);
}
The addNodeGraphic method creates the flag when a new node is added.
Cleaning and re-creating a flag
/**
* Recreates flag.
* */
public void propertyChanged(IlvSDMEngine engine,
java.lang.Object object,
java.lang.String propertyName,
java.lang.Object oldValue,
java.lang.Object newValue,
IlvGraphic graphic) {
super.propertyChanged(engine,object,propertyName,
oldValue,newValue,graphic);
if (!engine.getModel().isLink(object)) {
cleanNode(engine, graphic);
checkNode(engine, object, graphic);
}
}
A property change may or may not change the flag. Therefore, the propertyChanged method clears the flag and re-creates it.
Clearing a flag
/**
* Clears flag.
* */
public void removeNodeGraphic(IlvSDMEngine engine,
java.lang.Object node,
IlvGraphic graphic,
boolean redraw){
super.removeNodeGraphic(engine, node, graphic, redraw);
cleanNode(engine, graphic);
}
The removeNodeGraphic method clears the flag when a node is removed.
Moving the flag with the node
/**
* Adjusts flag position.
* */
public void nodeGraphicBBoxChanged(IlvSDMEngine engine,
java.lang.Object node,
IlvGraphic graphic,
IlvRect oldBBox,
IlvRect newBBox,
java.lang.String[] pseudoClasses) {
super.nodeGraphicBBoxChanged(engine,node,graphic,
oldBBox,newBBox,pseudoClasses);
moveNode(newBBox,(IlvGraphic)graphic.getProperty(FLAG_GRAPHICS));
}
The nodeGraphicBBoxChanged method is called when the bounding box of the node is changed. Note that no property change event is sent, although x and y may change.
Integrating the Flag renderer
There are two ways to integrate a new renderer:
Declare the renderer
For maximum efficiency, declare the flag renderer in the style sheet.
In this example, there is a specific rule to create the flag if the model object matches a particular state. The Flag renderer fetches the graphic property Flag from the rule to get the IlvGraphic object that will represent the flag, in this case the label “ALARM HERE”.
The following code example shows the style rules needed.
The style rules for the flag
node[state=alarm] {
Flag : @#alarm
}
Subobject#alarm {
class : 'ilog.views.sdm.graphic.IlvGraphicFactories$ZoomableLabel';
label : "ALARM HERE";
antialiasing : true;
leftMargin : 5;
rightMargin : 5;
topMargin : 5;
bottomMargin : 5;
foreground : red;
}
node {
Flag : ’’;
}
The rules operate as follows:
1. The first rule sets an indirection to create the IlvGraphic object when it is needed.
2. The second rule creates the flag as a simple red label.
3. The third rule clears the flag when the node reverts to its normal state. The default value for the flag is then null.
Register the renderer
The simplest way to integrate a renderer is to register the renderer so that it will be understood when the style sheet is read.
To register a renderer, just call the static method
addRendererAlias, in the class
IlvRendererUtil.. You must do this before you load a style sheet. The following code example shows the code line (highlighted) for the Flag Renderer.
Registering the Flag renderer in Java™ code
public static void main(String[] args) {
IlvRendererUtil.addRendererAlias("Flag", "tutorial.FlagRenderer");
SDMViewer v = new SDMViewer();
v.init(args);
}
The arguments of the method are as follows:
First argument: the symbolic name used in the style sheet
Second argument: the fully qualified class name of the renderer, which will be dynamically loaded when needed
After being registered, the Flag renderer is ready to use in a style sheet, like any other renderer. The following code example shows a simple example of rules that use it.
Simple style rules for a registered Flag renderer
SDM {
Flag : true;
}
Flag {
flagLayer : 30;
}
Possible enhancements
The Flag renderer example is deliberately kept simple. You could make various enhancements, for example:
Visibility
If a node changes its visibility, the flag remains visible. This may seem to be what is wanted at first sight, because the flag is raised even if the node is not present. However, a dangling flag seems strange. Therefore, a better implementation is to listen to the
IlvManager. property changes on its objects, and then set the visibility of the flag according to the visibility of the node.
Position
You can position the flag somewhere other than the top-left corner. For example, you can set the flag location as an offset when you create it, and use another graphic property, FlagAnchor, to set the position of the corner of the node to which the flag is to be attached.
Several flags
You can add several flags to the same node. Make sure that you control the layout of the flags so that they operate in a coherent way.
Copyright © 2018, Rogue Wave Software, Inc. All Rights Reserved.