Overview of recursive layout

This layout feature is implemented by the class IlvRecursiveLayout from the package ilog.views.graphlayout.recursive. The IlvRecursiveLayout class is internally used by the graph layout renderer of a diagram component; in Rogue Wave®  JViews Diagrammer, the rendering mechanism is transparent so that you never need to deal with this class.
Important
The Recursive Layout can be used only in Java™ code. No CSS syntax is available for this layout.
The Recursive Layout class is not a layout algorithm but rather a facility to apply another layout algorithm recursively on a nested graph. It traverses the nesting structure starting from the graph that is attached to the Recursive Layout itself and recursively applies a layout on all subgraphs. You can tailor which sublayout must be applied to which subgraph.
There are basically two scenarios:
  • The same layout style must be applied to all subgraphs.
  • An individual layout style must be applied to each subgraph.
UML diagram
showing IlvRecursiveLayout and its relationship to IlvGraphLayout
and IlvLayoutProvider
The class IlvRecursiveLayout which manages sublayouts for nested graphs

Code sample: same layout style everywhere

This sample assumes that you want to apply a Tree Layout to a nested graph and that each subgraph should be laid out with the same global layout parameters.
The Tree Layout algorithm handles only flat graphs, that is, if applied to an attached graph, it lays out only the nodes and links of the attached graph, but not the nodes and links of the subgraphs that are nested inside the attached graph. Hence the Tree Layout must be encapsulated in a Recursive Layout.
The Recursive Layout traverses the entire nesting hierarchy of the attached graph, while the encapsulated Tree Layout lays out each (flat) subgraph of the nesting hierarchy during the traversal.
Java code sample
...
import ilog.views.*;
import ilog.views.graphlayout;
import ilog.views.graphlayout.recursive.*;
import ilog.views.graphlayout.tree.*;

IlvRecursiveLayout layout = new IlvRecursiveLayout(IlvTreeLayout());

IlvGrapher topLevelGrapher = ...
layout.attach(topLevelGrapher);
try {
        IlvRecursiveLayoutReport layoutReport =
              (IlvRecursiveLayoutReport)layout.performLayout();

        int code = layoutReport.getCode();

        System.out.println("Layout completed (" +
          layoutReport.codeToString(code) + ")");
}
catch (IlvGraphLayoutException e) {
        System.err.println(e.getMessage());
}
...
// detach the Recursive Layout when it is no longer needed
layout.detach();
...
This mode of the Recursive Layout is called reference layout mode. In this case, a Tree Layout is performed recursively on the top-level graph and on each subgraph. All layouts are performed with the same global layout parameters.
Note
The term “global layout parameter” applies to the parameters that do not depend on a specific node or link. For example, Tree Layout has a global layout parameter set by setGlobalLinkStyle , as well as a layout parameter set by setLinkStyle(link, style) which is local to a link.
You can change the global layout parameters by accessing the reference layout of the Recursive Layout:
IlvTreeLayout treeLayout = (IlvTreeLayout)layout.getReferenceLayout();
treeLayout.setFlowDirection(IlvDirection.Left);
Technically, the reference layout instance is not applied to each subgraph because each subgraph needs an individual layout instance. The reference layout instance is only applied to the top-level graph. Furthermore, a clone of the reference instance is created for each subgraph. This clone remains attached to the subgraph as long as the Recursive Layout is attached to the top-level graph. Before layout is performed, the global layout parameters are copied from the reference layout instance to each cloned layout instance.
Sometimes, you want to specify local layout parameters for individual nodes and links. In this case, you need to access the cloned layout instance that is attached to the subgraph that owns the node or link. For example, for the link style of an individual link, use:
IlvTreeLayout treeLayout = 
(IlvTreeLayout)layout.getLayout(link.getGraphicBag());
treeLayout.setLinkStyle(link, IlvTreeLayout.ORTHOGONAL_STYLE); 
You cannot use the reference layout mode in the following cases:
  • The layout algorithm to be applied on subgraphs is not the same as the algorithm needed for the topmost graph (the reference layout).
  • The same layout algorithm, but using different global parameter settings, needs to be applied on different subgraphs.
In these cases, you can use one of the other modes.

Java code sample: Mixing different layout styles

The following example shows the second scenario: Each subgraph should be laid out by a different layout style or with individual global layout parameters. In this case, you use the internal provider mode of the Recursive Layout.
Assume that you have a graph with three subgraphs. The top-level graph and the first subgraph should be processed with Tree Layout, the second subgraph with Bus Layout, and the third subgraph with Grid Layout. You have to specify which layout must be used for which subgraph, and then you can perform the layout.
...
import ilog.views.*;
import ilog.views.graphlayout.*;
import ilog.views.graphlayout.recursive.*;
import ilog.views.graphlayout.tree.*;
import ilog.views.graphlayout.bus.*;
import ilog.views.graphlayout.grid.*;

IlvRecursiveLayout layout = new IlvRecursiveLayout();
IlvGrapher topLevelGrapher = ...
layout.attach(topLevelGrapher);

// specify the layout of the top level graph
layout.setLayout(null, new IlvTreeLayout()); 
// specify the layout of subgraphs
layout.setLayout(subgraph1, new IlvTreeLayout());
layout.setLayout(subgraph2, new IlvBusLayout());
layout.setLayout(subgraph3, new IlvGridLayout());

// perform layout
try {
        IlvRecursiveLayoutReport layoutReport =
              (IlvRecursiveLayoutReport)layout.performLayout();

        int code = layoutReport.getCode();

        System.out.println("Layout completed (" +
          layoutReport.codeToString(code) + ")");
}
catch (IlvGraphLayoutException e) {
        System.err.println(e.getMessage());
}
...
// detach the Recursive Layout when it is no longer needed
layout.detach();
...
In this scenario, there is no reference layout. All layout parameters of different subgraphs are independent. You need to specify new, independent layout instances for each subgraph; otherwise no layout will be performed for the corresponding subgraph. The layout instances are attached to the subgraph as long as the Recursive Layout is attached to the top-level graph. You can specify in this example different global layout parameters for the Tree Layout of the top-level graph and the Tree Layout of subgraph1 . You access the layout instance of each individual subgraph to change global layout parameters for this subgraph as well as parameters of nodes and links of the subgraph. For instance if node1 belongs to subgraph1 and node2 belongs to subgraph2 , you can set individual global and local layout parameters in this way:
// access the layout of the top level graph
IlvTreeLayout treeLayout1 = (IlvTreeLayout)layout.getLayout(null);
treeLayout1.setFlowDirection(IlvDirection.Bottom);
// access the layouts of the subgraphs
IlvTreeLayout treeLayout2 = (IlvTreeLayout)layout.getLayout(subgraph1);
treeLayout2.setFlowDirection(IlvDirection.Left);
treeLayout2.setAlignment(node1, IlvTreeLayout.TIP_OVER);
IlvBusLayout busLayout = (IlvBusLayout)layout.getLayout(subgraph2);
busLayout.setOrdering(IlvBusLayout.ORDER_BY_HEIGHT);
busLayout.setBus(node2);
IlvGridLayout gridLayout = (IlvGridLayout)layout.getLayout(subgraph3);
gridLayout.setLayoutMode(IlvGridLayout.TILE_TO_COLUMNS);

Java code sample: Using a specified layout provider

The Rogue Wave JViews Diagrammer Graph Layout library provides a flexible mechanism for the choice of the layout instance to be applied to each subgraph in a nested graph: the layout provider. In the previous example, a layout provider was used internally. For simplicity, the details of the mechanism are hidden, and you select the choice of layout by using the method setLayout on the Recursive Layout instance. Therefore, this layout mode is called internal provider mode.
You can also design your own layout provider and use it inside the Recursive Layout. This is the specified provider mode of the Recursive Layout.
A layout provider is a class that implements the interface IlvLayoutProvider . The interface has a single method:
getGraphLayout(IlvGraphModel graphModel)  
This method must return the layout instance to be used for the graph model passed as the argument, or null if no layout is required for this graph. When performing the Recursive Layout, these methods get the layout instance to be used for each graph from the specified layout provider.
To implement the interface IlvLayoutProvider , you must decide how the choice of the layout instance is done. This can be based on some criteria such as the type of graph (eventually known in advance), or a choice already made by the user and recorded, for example, in a property of the graph. A possible implementation of the getGraphLayout method is:
public IlvGraphLayout getGraphLayout(IlvGraphModel graphModel)
{
  Object prop = graphModel.getProperty("layout type");
  // if none, return null (no layout needed for this graph)
  if (!(prop instanceof String))
    return null;

  IlvGraphLayout layout = null;
  String name = (String)prop;

  if (name.equals("tree"))
    layout = new IlvTreeLayout();
  else if (name.equals("flow"))
    layout = new IlvHierarchicalLayout();
  else
    throw new RuntimeException("unsupported layout choice: " + name);

  layout.attach(graphModel);

  return layout;
}
This implementation is only an example among many possible implementations. The implementation may decide to store the newly allocated layout instance to avoid allocating a new one when the method is again called for the same graph.
If you have implemented a layout provider, you can use it in the Recursive Layout in the following way:
..
import ilog.views.*;
import ilog.views.graphlayout.*;
import ilog.views.graphlayout.recursive.*;

IlvLayoutProvider layoutProvider = ...
IlvRecursiveLayout layout = new IlvRecursiveLayout(layoutProvider);
IlvGrapher topLevelGrapher = ...
layout.attach(topLevelGrapher);

// Perform the layout
try {
        IlvRecursiveLayoutReport layoutReport =
              (IlvRecursiveLayoutReport)layout.performLayout();

        int code = layoutReport.getCode();

        System.out.println("Layout completed (" +
          layoutReport.codeToString(code) + ")");
}
catch (IlvGraphLayoutException e) {
        System.err.println(e.getMessage());
}
...
// detach the Recursive Layout when it is no longer needed
layout.detach();
...