Simple recursion: applying the same layout to all subgraphs

You can apply the same layout where both the following conditions hold:
  • The same layout algorithm needs to be applied to the topmost graph and all its subgraphs.
  • The settings of the layout algorithm (that is, the layout parameters) need to be the same for the topmost graph as for all the subgraphs.
The following figure shows an example where a Tree Layout is applied to the topmost graph as well as to all its subgraphs. Moreover, the settings of the Tree Layout algorithm are the same for all the graphs: the application does not need, for example, one flow direction in the topmost graph and a different one in the subgraphs.
Example
of a recursive layout of a nested graph showing on the left, Part
1 containing Network 1 with two subgraphs, Network 1.1 and 1.2, and
on the right, Part 2 containing Network 2 with two subgraphs, Network
2.1 and 2.2. Read Part 1 before Part 2. Network 1 contains one node
at the first level, three nodes at the second level, and two nodes
at the third level. The nodes on the second and third levels are laid
out horizontally. Node 1 links to all nodes on the second level. The
middle node on the second level links to both nodes on the third level.
Network 2 has the same layout as Network 1. Network 1.1 contains one
node at the first level, two nodes at the second level, and three
nodes at the third level. The nodes on the second and third levels
are laid out horizontally. Node 1 links to all nodes on the second
level. The node on the right of the second level links to all the
nodes on the third level. Network 2.1 has the same layout as Network
1.1. Network 1.2 contains one node at the first level and three nodes
at the second level. The nodes on the second level are laid out horizontally.
Node 1 links to all nodes on the second level. Network 2.2 has the
same layout as Network 1.2.
Example of a recursive layout of a nested graph
Obtaining such recursive layouts is easy. The class IlvGraphLayout provides a special version of the performLayout method:
performLayout(boolean force, boolean redraw, boolean traverse)  
When the last boolean argument is set to true , the layout is applied not only to the graph attached to the layout instance, but also, in a recursive way, to its subgraphs.

Internal mechanism

The internal mechanism is based on the principle that a layout instance is used for only one graph and is not reused for its subgraphs. Therefore, the Tree Layout instance is automatically “cloned” using the copy method of the class IlvGraphLayout .
The graph layout is applied to a graph model, and the same principle holds for the graph models (see Using the graph model): a graph model instance is used for only one graph and is not reused for subgraphs.
The graph models for the subgraphs are created by calls to the getGraphModel method of the class IlvGraphLayout , which in turn creates the graph model using the method createGraphModel of the class IlvGraphModel .
All these operations are done automatically, in a transparent way. All you have to do is to call the method performLayout with the traverse argument set to true .
If needed, you can get the layout instances applied on the subgraphs by calling the following method on IlvGraphLayout :
Enumeration getLayouts(boolean preOrder)  
This method returns an enumeration of instances of IlvGraphLayout . If the preOrder flag is true , the layout of the parent graph occurs before the layout of its child nodes in the enumeration. If the preorder flag is false , the layout of the parent graph occurs after the layout of its child nodes. For example, in the graph of Nesting structure in a graph, the call getLayouts(true) returns the layouts for the subgraphs in this order: L1, L1.1, L1.1.1, L1.1.2, L1.2. The call getLayouts(false) returns the layouts for the subgraphs in this order: L1.1.1, L1.1.2, L1.1, L1.2, L1.

Java code sample

The following Java™ code sample illustrates how to apply a single layout algorithm to a nested graph:
...
IlvGrapher grapherA = new IlvGrapher();
IlvGrapher grapherB = new IlvGrapher();

// Fill the graphers with nodes and links
...
// grapherB is added as a subgraph of grapherA
grapherA.addNode(grapherB, false);

// Create the layout instance
IlvTreeLayout layout = new IlvTreeLayout();

// Attach the topmost grapher to the layout
layout.attach(grapherA);

// Perform the recursive layout
try {
        int code = layout.performLayout(true, true, true);

        System.out.println("Layout completed (code " +
          code + ")");
}
catch (IlvGraphLayoutException e) {
        System.err.println(e.getMessage());
}
...
// Detach the grapher when layout no more needed
layout.detach();
...

For experts

In this first variant, the grapher adapter (the graph model of IlvGrapher) is handled internally. If a grapher adapter is explicitly allocated, it must be disposed of when no longer necessary. However, all grapher adapters that are created internally are always disposed of automatically. Here is an equivalent variant that shows how to use the grapher adapter:
...
IlvGrapher grapherA = new IlvGrapher();
IlvGrapher grapherB = new IlvGrapher();

// Fill the graphers with nodes and links
...
// grapherB is added as a subgraph of grapherA
grapherA.addNode(grapherB, false);

// Create the layout instance
IlvTreeLayout layout = new IlvTreeLayout();

// Create a grapher adapter for the topmost grapher
IlvGrapherAdapter adapter = new IlvGrapherAdapter(grapherA);

// Attach the adapter to the layout
layout.attach(adapter);

// Perform the recursive layout
try {
        // perform the layout with argument traverse = true
        int code = layout.performLayout(true, true, true);

        System.out.println("Layout completed (code " +
          code + ")");
}
catch (IlvGraphLayoutException e) {
        System.err.println(e.getMessage());
}
...
// Detach the adapter when layout no more needed
layout.detach();
...

Layout parameters

Section Internal mechanism explains that, when applying the same layout algorithm in a recursive way, the layout instances for the subgraphs are obtained by “cloning” the layout instance attached to the topmost graph.
The layout parameters of the “clone” are the same as the parameters of the topmost layout, except for the parameters that are specific to a node or a link. Such parameters are not copied when the layouts are cloned and need to be set separately for each layout instance.
For example, if you need to declare a node node1 contained in the subgraph grapherB of the topmost graph grapherA as fixed (seePreserve fixed nodes), you can use the following code:
...
IlvGrapher grapherA = new IlvGrapher();
IlvGrapher grapherB = new IlvGrapher();

// fill the graphers with nodes and links;
// grapherB is added as a subgraph of grapherA
grapherA.addNode(grapherB, false);

// Create the layout instance
IlvTreeLayout layout = new IlvTreeLayout();

// Attach the topmost grapher to the layout
layout.attach(grapherA);

// Ask the layout algorithm to not move the nodes
// specified as fixed. This settings is automatically
// copied on the sublayouts. Do not specify this global
// settings directly on the sublayout, because it gets automatically
// the same settings as the topmost layout
layout.setPreserveFixedNodes(true);

// Search the layout instance used for grapherB
IlvGraphLayout subLayout = null;
Enumeration layouts = layout.getLayouts(true);
while (layouts.hasMoreElements()) {
       subLayout = (IlvGraphLayout)layouts.nextElement();
       if (subLayout.getGraphModel().getGrapher() == grapherB)
              break;
}

// Specify node1 (contained in grapherB) as fixed
subLayout.setFixed(node1, true);

// Now perform the recursive layout. The node node1 will be considered as fixed
// by the layout applied to grapherB
...
Note
You should not try to change any global settings of the layouts applied to the subgraphs (that is, settings that are not specific to a node or a link). These settings are copied anyway from the layout instance of the topmost grapher, so your changes would be erased just before the recursive layout runs.