skip to main content
Programmer's documentation > Developing with the JViews Diagrammer SDK > Using and adding renderers > The Flag renderer example
 
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.
*Overview
*Provides an overview of the example.
*Header part
*Describes the FlagRenderer class as used in this example.
*Bean properties
*Describes the bean properties as used in this example.
*Private methods
*Describes the private methods of the FlagRenderer class as used in this example.
*Overloading methods of the Filter class
*Describes overloading in the FlagRenderer class.
*Integrating the Flag renderer
*Shows how to integrate the new Flag renderer.
*Possible enhancements
*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:
*addNodeGraphic
*propertiesChanged
*removeNodeGraphic
*nodeGraphicBBoxChanged
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
*Register the 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.