Extending the class IltNEBaseRenderer

Drawing principles

The base of a network element has four different visual aspects, each corresponding to one of the following fundamental states:
Out Of Service (OOS)
The base has a hatched outline. Inside the base, drawings are not displayed.
In service, carrying No Traffic (NT)
The base and its inside drawings are in full outline.
In service, Carrying Traffic (CT)
The base and its inside drawings are in relief.
Not Installed (NI)
The base is striped and has a hatched outline. Inside the base, drawings are not displayed. This is a special case where the base drawing changes when a secondary state is represented.
These fundamental states are enumerated in the class IltBaseStyle.
The drawings representing the network element base are specified in a single class that inherits from IltNEBaseRenderer. The four visual aspects of the base are drawn using the drawMain method to draw the base and additional methods to access the resources used to draw the base.To create new vector drawings for network elements, you have to extend the IltNEBaseRenderer class and override the methods drawMain and getPreferredSize.
Once the class is created, you must tell JViews TGO how to use it to draw a network element of a particular type. To do so, you must create a new IltNetworkElement.Type., add it to the existing types, and associate it with the drawing class using the mapping function SetValue or global CSS settings.

How to extend a network element

This example illustrates how to define a new type of network element called Server . You add myServer to the existing types ( NE , MD , NMW , BTS , and so on).
The four graphic states that the new network element type can have are illustrated in The Server graphic states .
ch6-fourstates.gif
The Server graphic states
When you extend the class IltNEBaseRenderer , you must create the drawing class and define its basic methods and the drawMain method.
The following code shows how to write a class ServerBaseRenderer that extends IltNEBaseRenderer and redefine its method getPreferredSize. This class will be enhanced later on to draw the Server element base.
static class ServerBaseRenderer extends IltNEBaseRenderer {
  private static Dimension NormalSize = new Dimension(25,40);
  private static Dimension SmallSize = new Dimension(13,21);
  public Dimension getPreferredSize (boolean collapsed) {
      if (collapsed)
        return SmallSize;
      else
        return NormalSize;
  }
}
The two fields NormalSize and SmallSize define the normal dimension of the base and its dimension when it is collapsed. Calling getPreferredSize returns the current size of the base.
The following fields are added to initialize numbers that are used to draw the base. Since there is only one method to draw both collapsed and expanded bases, these numbers ease the readability of the code.
// Some factors for drawing:
private static final float _XGrid = 4.0f / 25.0f;
private static final float _YGrid = 4.0f / 40.0f;
private static final float _WGrid = 13.0f / 25.0f;
private static final float _HGrid = 1.0f / 40.0f;
private static final float _VStepGrid = 2.0f / 40.0f;
private static final float _XButton = 19.0f / 25.0f;
private static final float _YButton = 4.0f / 40.0f;
private static final float _WButton = 2.0f / 25.0f;
private static final float _HButton = 2.0f / 40.0f;
private static final float _XDisk = 18.0f / 25.0f;
private static final float _YDisk = 23.0f / 40.0f;
private static final float _WDisk = 3.0f / 25.0f;
private static final float _HDisk = 12.0f / 40.0f;

Standard palettes

The class IltNEBaseRenderer provides three standard drawing palettes that you can access easily with the methods getPalette, getBrightPalette, and getDarkPalette.
  • getPalette returns the ordinary palette, commonly used to draw the face part.
  • getBrightPalette returns the palette used to draw the bright parts of a 3D border.
  • getDarkPalette returns the palette used to draw the ordinary border, and the dark parts of a 3D border.
These palettes automatically take into account the semantic state of the associated IltNetworkElement when changing colors. For example, when a new alarm is set to an object the ordinary palette may become red instead of grey.

How to initialize and use new palettes

It is necessary to define new palettes when the base drawings include elements that are not represented in the standard palettes. These palettes are initialized in the initResources method and used in the drawMain method.
In the following code, the new palettes are declared as fields and initialized in initResources.
private static Color GridColor =
      IltrColor.NewColor("server grid color", IltrColor._90PctGrey);
    private static Color ButtonColor =
      IltrColor.NewColor("server button color", Color.blue);

    private Ilt2DPalette GridPalette;
    private Ilt2DPalette ButtonPalette;

    protected void initResources () {
      super.initResources();
      GridPalette = Ilt2DPalette.NewSimple2DPalette(GridColor);
      ButtonPalette = Ilt2DPalette.NewSimple2DPalette(ButtonColor);
    }

How to define the main drawing method

The programming principle for the drawMain method is similar to the draw method of an IlvGraphic object. The method receives a graphic to draw with, a transformer linked to the associated view, and an IlvRect object that gives the size and position of the base.
The following code shows the beginning of the drawMain function.
public void drawMain (Graphics g, IlvTransformer t, IlvRect rect) {

      // Get the corners of the base rectangle.
      int x1 = (int)rect.x;
      int y1 = (int)rect.y;
      int x2 = x1 + (int)rect.width-1;
      int y2 = y1 + (int)rect.height-1;

      // Get the state dependent parameters.
      IltDetailLevel detailLevel = getDetailLevel();
      Ilt2DPalette palette = getPalette();
      Ilt2DPalette brightPalette = getBrightPalette();
      Ilt2DPalette darkPalette = getDarkPalette();
      int borderThickness = getBorderThickness();
In this code, there are the position of the base, its style (OOS, NT, CT or NI—see The Server graphic states ), and the standard palettes.

How to draw the base of a new type of network element

You can start drawing with IltGraphicUtil, a collection of graphic functions that simplify the drawing of common shapes.
The following code starts drawing the base.
if (x1<=x2 && y1<=y2) {

        IltGraphicUtil.FillRect(g,t,x1,y1,x2,y2,palette);

        // Paint the border
        if (detailLevel.equals(IltDetailLevel.MaximumDetails)) {
        if   (rect.width < 20 && borderThickness > 1)
        IltGraphicUtil.DrawReliefRect (g,t,x1,y1,x2,y2,
                                        brightPalette, darkPalette,
                                        borderThickness);
          else {
        IltGraphicUtil.DrawRect(g,t,x1,y1,x2,y2,
                                 darkPalette,
                                 borderThickness);
       }
The code has to manage the four different styles of the base, so the border thickness is taken into account to get drawings that look nice. The rest of the drawMain method must also manage the different styles and the two different dimensions of the base.
        // Paint the grid, button and disk.
        if (detailLevel.equals(IltDetailLevel.MaximumDetails)
            ||  detailLevel.equals(IltDetailLevel.FewDetails)){
          // Grid, button and disk dimensions.
          final int gridWidth = Math.round(rect.width * _WGrid);
          final int gridHeight = Math.round(rect.height * _HGrid);
          final int buttonWidth = Math.round(rect.width * _WButton);
          final int buttonHeight = Math.round(rect.height * _HButton);
          final int diskWidth = Math.round(rect.width * _WDisk);
          final int diskHeight = Math.round(rect.height * _HDisk);
          // Grid rectangle corners.
          final int gx1 = x1 + Math.round(rect.width * _XGrid);
          int gy1 = y1 + Math.round(rect.height * _YGrid);
          final int gx2 = gx1 + gridWidth-1;
          int gy2 = gy1 + gridHeight-1;
          final int gvstep = Math.round(rect.height * _VStepGrid);
          // Button rectangle corners.
          final int bx1 = x1 + Math.round(rect.width * _XButton);
          final int by1 = y1 + Math.round(rect.height * _YButton);
          final int bx2 = bx1 + buttonWidth-1;
          final int by2 = by1 + buttonHeight-1;
          // Disk rectangle corners.
          final int dx1 = x1 + Math.round(rect.width * _XDisk);
          final int dy1 = y1 + Math.round(rect.height * _YDisk);
          final int dx2 = dx1 + diskWidth-1;
          final int dy2 = dy1 + diskHeight-1;
          // Grid and button colors.
          final Ilt2DPalette gridPalette =
            (detailLevel.equals(IltDetailLevel.FewDetails) ? darkPalette
 : GridPalette);
          final Ilt2DPalette buttonPalette =
            (detailLevel.equals(IltDetailLevel.FewDetails) ? darkPalette 
: ButtonPalette);
          // Paint the grid.
          if (gvstep > 1) {
            for (int i = 0; i < 7; i++) {
              IltGraphicUtil._FillRect(g,t, gx1,gy1,gx2,gy2, gridPalette);
              gy1 += gvstep; gy2 += gvstep;
            }
          } else if (gvstep == 1) {
            // Paint a grey rectangle instead of the grid.
            Color rectColor = palette.getForeground();
            Color gridColor = gridPalette.getForeground();
            Color greyColor =
              new Color((rectColor.getRed()+gridColor.getRed())/2,
                        (rectColor.getGreen()+gridColor.getGreen())/2,
                        (rectColor.getBlue()+gridColor.getBlue())/2);
            Ilt2DPalette greyPalette =
              Ilt2DPalette.NewSimple2DPalette(greyColor);
            IltGraphicUtil._FillRect(g,t, gx1,gy1,gx2,gy2+6*gvstep,
                                     greyPalette);
          }

          // Paint the button.
          IltGraphicUtil._FillRect(g,t, bx1,by1,bx2,by2, buttonPalette);

          // Paint the disk.
          if (detailLevel.equals(IltDetailLevel.FewDetails)) {
            IltGraphicUtil._FillRect(g,t, dx1,dy1,dx2,dy2, darkPalette);
          } else {
            IltGraphicUtil._FillRect(g,t, dx1,dy1,dx2,dy2, palette);
            IltGraphicUtil.DrawReliefRect(g,t, dx1,dy1,dx2,dy2,
                                          brightPalette,darkPalette,
                                          1);
         }
The method drawExtraBorders is the standard method used in this example.

How to implement a method for drawing a rectangular base

If the object that you want to draw is not a rectangle, but a telephone for example, you must override this method to get a selection border that is tightly drawn around the base.
The following code shows the default implementation used for a rectangular base.
protected void drawExtraBorders (Graphics g, IlvTransformer t, IlvRect rect) {
    { // Draw the alarm border, if needed according to the state.
      Color c = getAlarmBorderColor();
      if (c != null)
        drawExtraBorder(g,t,rect,c,0,IltrThickness.AlarmBorderThickness);
    }
    { // Draw the selection border, if the object is currently selected.
      Color c = getSelectionBorderForeground();
      if (c != null)
        drawExtraBorder(g,t,rect,c,IltrThickness.AlarmBorderThickness,
                        IltrThickness.SelectionBorderThickness);
    }
  }

How to create and register a network element type (using the API)

If you run the sample program, the main file creates and registers a network element of type server.
static IltNetworkElement.Type Server = new IltNetworkElement.Type("Server");

  static {
    IltSettings.SetValue("NetworkElement.Type.Server.Renderer", 
                         new IltBaseRendererFactory() {
                           public IltBaseRenderer createValue() {
                             return new ServerBaseRenderer();
                           }
                         }
    );
  }

IltDefaultDataSource dataSource = new IltDefaultDataSource();
IltNetworkElement ne = new IltNetworkElement
                      ("NE", Server, new IltOSIObjectState());
ne.setAttributeValue(IltObject.PositionAttribute, new IlpPoint(100,100));
dataSource.addObject(ne);
IlpNetwork network = new IlpNetwork();
network.setDataSource(dataSource);

How to create and register a network element type (using CSS)

You can create the new network element type using global CSS settings instead of the API, as follows.
setting."ilog.tgo.model.IltNetworkElement"{
  types[0]: @+neType0;
}
Subobject#neType0 {
  class: 'ilog.tgo.model.IltNetworkElement.Type'; 
  name: "Server";
}
To customize the renderer using global CSS settings, you need first to create a renderer factory class and make sure it is included in the search path.
public class MyNERendererFactory implements IltBaseRendererFactory {
   public IltBaseRenderer createValue() {
      return new ServerBaseRenderer();
   }
}
Then you can customize the renderer in CSS as follows:
setting."ilog.tgo.model.IltNetworkElement.Type"[name="Server"] { 
   renderer: @+neRendererFactory0;
}
Subobject#neRendererFactory0 {
   class: 'MyNERendererFactory';
}
As illustrated in this example, you can create a network element with a specific type or set a type for it afterwards with either one of two methods.
ne.setType (Server);
or
ne.setAttributeValue (IltNetworkElement.TypeAttribute, Server);