public class RecursiveGroupLayout extends AbstractLayoutStage
layout algorithms
which are
applied to the different group nodes. RecursiveGroupLayout
is able to produce different layout styles for the
content of each group node.
This layout algorithm can be either applied if a layout algorithm
cannot handle grouped graphs
by itself or if the content of (some) group nodes should be arranged differently.
RecursiveGroupLayout
uses a hierarchy tree representation of the grouped graph in which the content nodes are
the children of their containing group node. That way, it can traverse the tree recursively while arranging only the
direct children of each group node. The layout algorithm starts by arranging the leaves in the hierarchy tree, then
works its way up to the root computing the layout for each group node in the tree.
All nodes other than the direct children are temporarily hidden. The layout algorithm performs two steps for each group node.
core layout algorithm
or a
special layout algorithm retrieved from a IDataProvider
registered with
GROUP_NODE_LAYOUT_DPKEY
. The content of group nodes among the children is already arranged at this time and
will be ignored. These group nodes are handled like normal nodes with a size that encloses the content.
RecursiveGroupLayout
computes the final size of the group node using an implementation of
IGroupBoundsCalculator
. Customized IGroupBoundsCalculator
s can be specified using
GroupBoundsCalculator
. Aside from the resulting layout,
this size is used in the following iteration.
After a layout is applied to all group nodes, the layout algorithm computes routes for the edges whose source node is
located at a different hierarchy level than its target node. The edge routing algorithm for these so-called inter-edges
can be customized
.
Note that RecursiveGroupLayout
can run without a
core layout algorithm
. In this case no layout is calculated, instead the
group node bounds are merely adjusted to fit their respective contents.
layout algorithm
by registering a IDataProvider
with key GROUP_NODE_LAYOUT_DPKEY
. The content of the hierarchy root is arranged with the
core layout algorithm
.
LayoutMultiplexer
as core layout algorithm
.
Since RecursiveGroupLayout
delegates the actual arrangement of the graph to other layout algorithms, it will
support the same features as the currently used layout algorithm.
The improvement of the routing of inter-edges is based on the insertion
of PortCandidate
s or the conversion
of
PortConstraint
s into PortCandidate
s. Hence, they only work well if the applied layout algorithm
supports PortCandidate
s.
This algorithm also provides a From Sketch mode
that should be activated if the
applied layout algorithm runs in From Sketch mode, too. Otherwise, the initial coordinates may not be considered
correctly.
Modifier and Type | Field and Description |
---|---|
static NodeDpKey<ILayoutAlgorithm> |
GROUP_NODE_LAYOUT_DPKEY
A
DataProvider key for arranging the content of each group node with an individual layout algorithm.
|
static ILayoutAlgorithm |
NULL_LAYOUT
A constant that represents a
ILayoutAlgorithm implementation that does nothing. |
static EdgeDpKey<Object> |
SOURCE_SPLIT_ID_DPKEY
A
DataProvider key for assigning source split ids to edges connecting to group nodes.
|
static EdgeDpKey<Object> |
TARGET_SPLIT_ID_DPKEY
A
DataProvider key for assigning target split ids to edges connecting to group nodes.
|
Constructor and Description |
---|
RecursiveGroupLayout()
Creates a new instance of
RecursiveGroupLayout with an optional
core layout algorithm . |
RecursiveGroupLayout(ILayoutAlgorithm core)
Creates a new instance of
RecursiveGroupLayout with an optional
core layout algorithm . |
RecursiveGroupLayout(ILayoutAlgorithm core,
IGroupBoundsCalculator gbc)
Creates a new instance of
RecursiveGroupLayout with default settings using the given layout algorithm
and IGroupBoundsCalculator implementation. |
Modifier and Type | Method and Description |
---|---|
void |
applyLayout(LayoutGraph graph)
Invokes a recursive traversal through the grouping hierarchy of the given graph during which the specified
layout algorithms
are applied to the content of the groups. |
IGroupBoundsCalculator |
getGroupBoundsCalculator()
Gets a
IGroupBoundsCalculator which computes the sizes of all group nodes. |
ILayoutAlgorithm |
getInterEdgeRouter()
Gets the current edge routing algorithm for handling inter-edges.
|
Object |
getInterEdgesDpKey()
Gets the key for marking the inter-edges to be routed.
|
boolean |
isEmptyGroupsConsiderationEnabled()
Gets whether empty group nodes are handled like group nodes with content or like normal nodes.
|
boolean |
isFromSketchModeEnabled()
Gets whether or not to consider the initial coordinates of the graph elements.
|
boolean |
isPortCandidatesAutoAssignmentEnabled()
Gets whether or not temporary
PortCandidate s are inserted to improve the routing of inter-edges. |
boolean |
isPortConstraintsReplacementEnabled()
Gets whether or not
PortConstraint s of inter-edges are temporarily replaced by PortCandidate s. |
protected void |
routeInterEdges(LayoutGraph graph,
EdgeList interEdges)
Reroutes the given inter-edges using the current
edge routing algorithm . |
void |
setEmptyGroupsConsiderationEnabled(boolean value)
Sets whether empty group nodes are handled like group nodes with content or like normal nodes.
|
void |
setFromSketchModeEnabled(boolean value)
Sets whether or not to consider the initial coordinates of the graph elements.
|
void |
setGroupBoundsCalculator(IGroupBoundsCalculator value)
Sets a
IGroupBoundsCalculator which computes the sizes of all group nodes. |
void |
setInterEdgeRouter(ILayoutAlgorithm value)
Sets the current edge routing algorithm for handling inter-edges.
|
void |
setInterEdgesDpKey(Object value)
Sets the key for marking the inter-edges to be routed.
|
void |
setPortCandidatesAutoAssignmentEnabled(boolean value)
Sets whether or not temporary
PortCandidate s are inserted to improve the routing of inter-edges. |
void |
setPortConstraintsReplacementEnabled(boolean value)
Sets whether or not
PortConstraint s of inter-edges are temporarily replaced by PortCandidate s. |
applyLayoutCore, getCoreLayout, setCoreLayout
public static final NodeDpKey<ILayoutAlgorithm> GROUP_NODE_LAYOUT_DPKEY
DataProvider
key for arranging the content of each group node with an individual layout algorithm.
The specified layouter instance is applied to the content of the group node. To arrange the top level elements the core layout algorithm
is used.
NULL_LAYOUT
.IDataProvider
returns null
, RecursiveGroupLayout
handles the corresponding group node
non-recursively. The group node and its content is arranged using the ILayoutAlgorithm
instance specified for
the nearest ancestor of the group node which is associated with a layout algorithm
.NULL_LAYOUT
public static final ILayoutAlgorithm NULL_LAYOUT
ILayoutAlgorithm
implementation that does nothing.
This implementation can be assigned to group nodes to keep their content unchanged. The layout algorithm will still calculate the sizes of the group nodes.
public static final EdgeDpKey<Object> SOURCE_SPLIT_ID_DPKEY
DataProvider
key for assigning source split ids to edges connecting to group nodes.
The edges will be aligned with edges that connect to the same group node and have the same split id at their source (preferably) or target.
HierarchicLayout
is used as core layout algorithm. Also, the edges need to be
routed directly from the content of a group to the group itself
.TARGET_SPLIT_ID_DPKEY
,
HierarchicLayout
,
EdgeLayoutDescriptor.setDirectGroupContentEdgeRoutingEnabled(boolean)
public static final EdgeDpKey<Object> TARGET_SPLIT_ID_DPKEY
DataProvider
key for assigning target split ids to edges connecting to group nodes.
The edges will be aligned with edges that connect to the same group node and have the same split id at their source or target (preferably).
HierarchicLayout
is used as core layout algorithm. Also, the edges need to be
routed directly from the content of a group to the group itself
.SOURCE_SPLIT_ID_DPKEY
,
HierarchicLayout
,
EdgeLayoutDescriptor.setDirectGroupContentEdgeRoutingEnabled(boolean)
public RecursiveGroupLayout()
RecursiveGroupLayout
with an optional
core layout algorithm
.public RecursiveGroupLayout(ILayoutAlgorithm core)
RecursiveGroupLayout
with an optional
core layout algorithm
.core
- The layout algorithm that is applied in each recursion step.public RecursiveGroupLayout(ILayoutAlgorithm core, IGroupBoundsCalculator gbc)
RecursiveGroupLayout
with default settings using the given layout algorithm
and IGroupBoundsCalculator
implementation.core
- the layout algorithm that is applied in each step of the recursiongbc
- the IGroupBoundsCalculator
for calculating group sizespublic void applyLayout(LayoutGraph graph)
layout algorithms
are applied to the content of the groups.applyLayout
in interface ILayoutAlgorithm
applyLayout
in class AbstractLayoutStage
graph
- the input graphpublic IGroupBoundsCalculator getGroupBoundsCalculator()
IGroupBoundsCalculator
which computes the sizes of all group nodes.
This IGroupBoundsCalculator
is used each time after calculating the layout for a content graph.
MinimumSizeGroupBoundsCalculator
IGroupBoundsCalculator
instancesetGroupBoundsCalculator(IGroupBoundsCalculator)
public ILayoutAlgorithm getInterEdgeRouter()
During layout, edges that connect from outside a group node to the content inside (inter-edges) are temporarily connected to the group node itself. Hence, these edges have to be routed after restoring the original graph structure using this edge routing algorithm.
It is required that a suitable selection key
is specified. The same selection key
must be used for setting the sphere of action for the edge router.
null
. Edges are routed as straight lines from source to target.setInterEdgesDpKey(Object)
,
setInterEdgeRouter(ILayoutAlgorithm)
public Object getInterEdgesDpKey()
The key should be used by the specified inter-edge routing algorithm
to obtain the edges
to be routed. This layouter automatically marks these edges and registers the IDataProvider
using the specified
key.
IllegalArgumentException
- if the specified key is null
LayoutKeys.AFFECTED_EDGES_DPKEY
getInterEdgeRouter()
,
setInterEdgesDpKey(Object)
public boolean isEmptyGroupsConsiderationEnabled()
If they are handled like other group nodes, RecursiveGroupLayout
will resize them according to their
(non-existing) content. This results in small empty group nodes. Handled like normal nodes, empty group nodes will keep
their initial size.
true
. Empty group nodes are resized.true
if empty groups are treated like group nodes, false
if they are treated like normal nodessetEmptyGroupsConsiderationEnabled(boolean)
public boolean isFromSketchModeEnabled()
When using the initial coordinates, RecursiveGroupLayout
sets the coordinates of the nodes to their initial
position before the corresponding layout algorithm
is called.
RecursiveGroupLayout
uses a layout algorithm
that runs
in From Sketch mode.false
. The initial coordinates of the nodes are not taken into account.true
if the initial coordinates of the graph elements are considered, false
otherwisesetFromSketchModeEnabled(boolean)
public boolean isPortCandidatesAutoAssignmentEnabled()
PortCandidate
s are inserted to improve the routing of inter-edges.
If enabled, RecursiveGroupLayout
will insert PortCandidate
s for all inter-edges that cross a group node
border. Those PortCandidate
s are located at the relative position of the real source/target node. Inter-edges
that connect to such PortCandidate
s will be routed when the layout of the containing group node is calculated
and will not be rerouted
later. This may produce more suitable edge
routes but cannot prevent edges from crossing nodes.
Without temporary or user specified PortCandidate
s, inter-edges will always end at the border/center of the
corresponding group node. Thus, they are rerouted afterwards using an
edge routing algorithm
.
PortCandidate
s are always satisfied depending on the used layout algorithm, even if this option is
disabled.PortCandidate
s will only have an effect if the layout algorithm supports them.false
. No temporary PortCandidate
s are added.true
if temporary port candidates are insertedrouteInterEdges(LayoutGraph, EdgeList)
,
setInterEdgeRouter(ILayoutAlgorithm)
,
PortCandidate
,
setPortCandidatesAutoAssignmentEnabled(boolean)
public boolean isPortConstraintsReplacementEnabled()
PortConstraint
s of inter-edges are temporarily replaced by PortCandidate
s.
If disabled, inter-edges will always end at the border/center of the corresponding group node, even if those edges have
port constraints. Thus, they are rerouted
later without considering the
constraint. Enabling this settings may produce more suitable edge routes but cannot prevent edges from crossing nodes.
Port candidates are automatically redirected to their original location. Hence, enabling this option may produce more suitable edge routes if the layout algorithm applied to the content of a group node can handle port candidates.
PortCandidate
s are always satisfied depending on the used layout algorithm, even if this option is
disabled.PortConstraint
s will only have an effect if the layout algorithm supports
PortCandidate
s.true
. Existing PortConstraint
s are temporarily replaced with corresponding PortCandidate
s.routeInterEdges(LayoutGraph, EdgeList)
,
PortCandidate
,
setPortConstraintsReplacementEnabled(boolean)
protected void routeInterEdges(LayoutGraph graph, EdgeList interEdges)
edge routing algorithm
.
This method is called after calculating the overall layout when the positions of all nodes and normal edges are fixed.
If no inter-edge router
is specified, this method resets the path
of all inter-edges that don't connect to the proper location within the group. This may happen for inter-edges without
PortCandidate
s or if the applied layout algorithm doesn't support such constraints.
graph
- the input graphinterEdges
- the edges which traverse the boundary of a group nodesetPortCandidatesAutoAssignmentEnabled(boolean)
,
setPortConstraintsReplacementEnabled(boolean)
,
setInterEdgeRouter(ILayoutAlgorithm)
public void setEmptyGroupsConsiderationEnabled(boolean value)
If they are handled like other group nodes, RecursiveGroupLayout
will resize them according to their
(non-existing) content. This results in small empty group nodes. Handled like normal nodes, empty group nodes will keep
their initial size.
true
. Empty group nodes are resized.value
- true
if empty groups are treated like group nodes, false
if they are treated like normal nodesisEmptyGroupsConsiderationEnabled()
public void setFromSketchModeEnabled(boolean value)
When using the initial coordinates, RecursiveGroupLayout
sets the coordinates of the nodes to their initial
position before the corresponding layout algorithm
is called.
RecursiveGroupLayout
uses a layout algorithm
that runs
in From Sketch mode.false
. The initial coordinates of the nodes are not taken into account.value
- true
if the initial coordinates of the graph elements are considered, false
otherwiseisFromSketchModeEnabled()
public void setGroupBoundsCalculator(IGroupBoundsCalculator value)
IGroupBoundsCalculator
which computes the sizes of all group nodes.
This IGroupBoundsCalculator
is used each time after calculating the layout for a content graph.
MinimumSizeGroupBoundsCalculator
value
- the current IGroupBoundsCalculator
instancegetGroupBoundsCalculator()
public void setInterEdgeRouter(ILayoutAlgorithm value)
During layout, edges that connect from outside a group node to the content inside (inter-edges) are temporarily connected to the group node itself. Hence, these edges have to be routed after restoring the original graph structure using this edge routing algorithm.
It is required that a suitable selection key
is specified. The same selection key
must be used for setting the sphere of action for the edge router.
null
. Edges are routed as straight lines from source to target.value
- the edge routing algorithm for inter-edgessetInterEdgesDpKey(Object)
,
getInterEdgeRouter()
public void setInterEdgesDpKey(Object value)
The key should be used by the specified inter-edge routing algorithm
to obtain the edges
to be routed. This layouter automatically marks these edges and registers the IDataProvider
using the specified
key.
IllegalArgumentException
- if the specified key is null
LayoutKeys.AFFECTED_EDGES_DPKEY
value
- the inter edge selection keygetInterEdgeRouter()
,
getInterEdgesDpKey()
public void setPortCandidatesAutoAssignmentEnabled(boolean value)
PortCandidate
s are inserted to improve the routing of inter-edges.
If enabled, RecursiveGroupLayout
will insert PortCandidate
s for all inter-edges that cross a group node
border. Those PortCandidate
s are located at the relative position of the real source/target node. Inter-edges
that connect to such PortCandidate
s will be routed when the layout of the containing group node is calculated
and will not be rerouted
later. This may produce more suitable edge
routes but cannot prevent edges from crossing nodes.
Without temporary or user specified PortCandidate
s, inter-edges will always end at the border/center of the
corresponding group node. Thus, they are rerouted afterwards using an
edge routing algorithm
.
PortCandidate
s are always satisfied depending on the used layout algorithm, even if this option is
disabled.PortCandidate
s will only have an effect if the layout algorithm supports them.false
. No temporary PortCandidate
s are added.value
- true
if temporary port candidates are insertedrouteInterEdges(LayoutGraph, EdgeList)
,
setInterEdgeRouter(ILayoutAlgorithm)
,
PortCandidate
,
isPortCandidatesAutoAssignmentEnabled()
public void setPortConstraintsReplacementEnabled(boolean value)
PortConstraint
s of inter-edges are temporarily replaced by PortCandidate
s.
If disabled, inter-edges will always end at the border/center of the corresponding group node, even if those edges have
port constraints. Thus, they are rerouted
later without considering the
constraint. Enabling this settings may produce more suitable edge routes but cannot prevent edges from crossing nodes.
Port candidates are automatically redirected to their original location. Hence, enabling this option may produce more suitable edge routes if the layout algorithm applied to the content of a group node can handle port candidates.
PortCandidate
s are always satisfied depending on the used layout algorithm, even if this option is
disabled.PortConstraint
s will only have an effect if the layout algorithm supports
PortCandidate
s.true
. Existing PortConstraint
s are temporarily replaced with corresponding PortCandidate
s.value
- whether or not port constraints are replacedrouteInterEdges(LayoutGraph, EdgeList)
,
PortCandidate
,
isPortConstraintsReplacementEnabled()