Managing Graph Hierarchies

The management of a graph hierarchy is a multi-faceted undertaking that is handled by a small number of classes. Adding support for grouping and nesting to a "flat" graph can easily be achieved with little effort.

Class HierarchyManager

Class HierarchyManager maintains the model that is behind graph hierarchies, and manages all changes relevant to this model. Among other things, the HierarchyManager's responsibilities include:

  • Creation and removal of group nodes and folder nodes
  • Grouping and ungrouping nodes
  • Nesting and un-nesting of graph structures
  • Creation of a folder node's inner graph
  • Handling of inter-edges
  • Maintenance of the node visiting order for both hit-testing and drawing the graph elements
  • Provision of graph element information

Adding support for both grouping and nesting to a graph is achieved by creating a HierarchyManager object that is associated with a given graph, which is considered the hierarchy's root graph. Example 7.1, “Adding support for grouping and nesting to a graph” demonstrates how to add a HierarchyManager object to a yet "flat" graph, i.e., one that lacks support for grouping or nesting.

Important

There must not be more than one HierarchyManager associated with a given graph.

Example 7.1. Adding support for grouping and nesting to a graph

// 'rootGraph' is of type y.base.Graph2D. 

// Create a hierarchy manager with the given graph. 
HierarchyManager hm = new HierarchyManager(rootGraph);

Creating Grouped Nodes

Conceptually, grouped nodes are one level below their containing group node in the graph hierarchy. Technically, however, they are in the same graph as their enclosing group node. Example 7.2, “Grouping nodes” shows the creation of a group node and how to add content to it.

Example 7.2. Grouping nodes

// 'hm' is of type y.view.hierarchy.HierarchyManager. 

NodeList nl = new NodeList();
nl.add(rootGraph.firstNode());

// Create a new node in the root graph that is a group node. 
Node groupNode = hm.createGroupNode(rootGraph);

// Add a single node to the group. 
hm.groupSubgraph(nl, groupNode);

Creating Nested Graphs

Conceptually, a nested graph structure is contained within its folder node. In the graph hierarchy, it is one level below its folder node, and is accordingly called the inner graph of the folder node. Technically, however, a nested graph structure is a proper graph that is stored separately from its parent graph, i.e., the graph where the folder node resides in.

The folder node within the parent graph serves as an anchor for the nested graph structure. This is why a folder node is also called an anchor node sometimes. Example 7.3, “Nesting nodes” shows the creation of a folder node and how to add content to it. Also, extracting a nested graph structure from a folder node is shown, too.

Example 7.3. Nesting nodes

// 'hm' is of type y.view.hierarchy.HierarchyManager. 

NodeList nl = new NodeList();
nl.add(rootGraph.firstNode());

// Create a new node in the root graph that is a folder node. 
Node folderNode = hm.createFolderNode(rootGraph);

// Add a single node to the folder. 
hm.foldSubgraph(nl, folderNode);

// Count the inner graph's nodes. 
int innerGraphNodeCount = hm.getInnerGraph(folderNode).N();

// Move the folder node's content up one level back to the parent graph. 
hm.unfoldSubGraph(hm.getInnerGraph(folderNode), nl);

Whenever the HierarchyManager is asked to populate a folder node, the involved nodes are removed from their original graph and created anew inside the folder node's inner graph.

Handling Inter-edges

In a hierarchically organized graph that contains folder nodes, there can also occur edges that connect nodes from inner graphs to nodes from other graphs within the graph hierarchy. Generally, these edges have to be remodeled to connect nodes that are on the same hierarchy level, since an edge whose nodes are in different graphs is not legal.

Remodeling an edge to an inter-edge that represents its original is automatically done by the HierarchyManager. Both edge ends are promoted to the nearest common graph up in the hierarchy that contains all folder nodes of the involved inner graphs.

The HierarchyManager afterwards provides information on the "real" source and target of the inter-edge. See API Excerpt 7.1, “Methods relating to inter-edges” for the methods to get the real source and target of an inter-edge.

API Excerpt 7.1. Methods relating to inter-edges

// Returns the real source node associated with the given inter-edge. 
Node getRealSource(Edge interEdge)

// Returns the real target node associated with the given inter-edge. 
Node getRealTarget(Edge interEdge)

Node Visiting Order

The HierarchyManager instance that has been added to a graph is also responsible for maintaining the node visiting order that is used, e.g., for drawing or for hit-testing the graph elements. API Excerpt 7.2, “Methods to control the node visiting order” lists methods that provide a way to affect the node visiting order by changing the order of children of either group node or folder node.

API Excerpt 7.2. Methods to control the node visiting order

// Makes the given node the first child of its parent. 
void moveToFirst(Node childNode)

// Makes the given node the last child of its parent. 
void moveToLast(Node childNode)

Important

The visiting order that is maintained by class HierarchyManager is not preserved when the hierarchically organized graph is saved to a file.

To preserve the visiting order between file export and import, all HierarchyManager operations that affect the node order have to be accompanied by corresponding Graph operations on the particular graph (root graph or nested graph). See Table 7.1, “Corresponding node order methods”.

Table 7.1. Corresponding node order methods

HierarchyManager Graph
moveToFirst(Node) moveToFirst(Node)
moveToLast(Node) moveToLast(Node)

Traversal Policies

Class HierarchyManager offers two different node traversal orders which can be applied to a hierarchically organized graph:

  • Pre-traverse visits the parent before the children, and the children themselves from first to last.
  • Post-visit visits the children before the parent, and the children themselves from last to first.

API Excerpt 7.3, “Node traversal methods” lists HierarchyManager's methods for both traversal policies.

API Excerpt 7.3. Node traversal methods

// Node traversal used for drawing. 
void postTraverse(HierarchyManager.NodeVisitor visitor)
void postTraverse(Node rootNode, HierarchyManager.NodeVisitor visitor)

// Node traversal used for hit-testing. 
void preTraverse(HierarchyManager.NodeVisitor visitor)
void preTraverse(Node rootNode, HierarchyManager.NodeVisitor visitor)

Pre-traverse is used, e.g., for drawing the nodes of a hierarchically organized graph, since it makes sure that children are drawn atop their parents. Post-traverse on the other hand, is useful for hit-testing the graph elements, since elements atop of others should receive hit events first.

Class DefaultHierarchyGraphFactory

Class DefaultHierarchyGraphFactory is used by HierarchyManager objects to have new graph elements within the hierarchically organized graph created and properly configured. The graph factory handles creation of both normal graph elements as well nested graph structures. It also creates and configures the corresponding proxy nodes, i.e., either group nodes or folder nodes.

Nested graph structures created by DefaultHierarchyGraphFactory are of type Graph2D, the realizer implementations taken for group nodes and folder nodes can be controlled using appropriate methods. By default, class GroupNodeRealizer is used for both group nodes and folder nodes, since it can render both presentations. See also the section called “Node Realizers”.

Figure 7.4. Class DefaultHierarchyGraphFactory

Class DefaultHierarchyGraphFactory.

Whenever a new graph is created by this graph factory, it will inherit all listeners that are registered with its parent graph, i.e., all GraphListener, Graph2DListener, and Graph2DSelectionListener references are copied.

To control the creation of graph objects the instance of DefaultGraphFactory that is used can be replaced with a customized factory using the appropriate method of class HierarchyManager.

Tutorial Demo Code

HierarchyDemo.java is an extensive tutorial demo application that discusses all aspects of graph hierarchies. The README file gives an overview of the application's features and functionality.