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](../../../GraphLayout/_media/dia_recursivelayout4_default.png)
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(); ...