Styling > Customizing Network Elements > Customizing Network Element Types > Extending the Class IltNEBaseRenderer

This section explains with an example how to create a new type of network element by implementing a subclass of IltNEBaseRenderer.

Drawing Principles

The base of a network element has four different visual aspects, each corresponding to one of the following fundamental states. 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. In our example, we add myServer to the existing types (NE, MD, NMW, BTS, and so forth). Then this new symbolic type must be associated with the drawing class. This is performed using the mapping function IltSettings.SetValue or global CSS settings.

An Example

This section illustrates how to define a new type of network element called Server. The four graphic states that this new network element type can have are illustrated in Figure 3.11.

images/ch6-fourstates.gif

Figure 3.11 The Server Graphic States

You extend the class IltNEBaseRenderer in three steps:

Step 1--Create the drawing class and define its basic methods

This section explains how to write a class that extends IltNEBaseRenderer and redefine its method getPreferredSize. This class will be enhanced later on to draw the Server element base.

The definition of the class ServerBaseRenderer is given below.

How to Extend a Network Element
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 noncollapsed 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.

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.

Creating 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.

Here the new palettes are declared as fields and initialized in initResources.

How to Initialize and Use New Palettes
    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);
    }

Step 2--Define the drawMain method

The programming principle for the drawMain method is similar to the draw method of an IlvGraphic. The method receives a graphic to draw with, a transformer linked to the associated view, and an IlvRect that gives the size and position of the base.

Here is the beginning of the drawMain function.

How to Define the Main Drawing Method
    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 piece of code, we get the position of the base, its style (OOS, NT, CT or NI--see Figure 3.11), and the standard palettes. We can start the drawings with IltGraphicUtil, a collection of graphic functions that simplify the drawing of common shapes.

Here is the code to start drawing the base.

How to Draw the Base of a New Type of Network Element
      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 good looking drawings. 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. If the object that you want to draw is not a rectangle, but a phone 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.

How to Implement a Method for Drawing 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);
    }
  }

Step 3--Run the sample program

The main file of this example creates and registers a network element of type server.

How to Create and Register a Network Element Type (using the API)
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)

The new network element type can also be created using global CSS settings, 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 to first 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 the following methods:

ne.setType (Server);

or

ne.setAttributeValue (IltNetworkElement.TypeAttribute, Server);