Implementing a tree hierarchy in GWT

A simple example of the Node hierarchy described in this post.

If you’re like me, you’re using GWT to push the boundaries of what is possible in an interactive web UI.

One of the data structures I’ve been working with recently that I didn’t see much documentation on is the tree hierarchy, as shown on the right.

Nodes within nodes, within nodes, within nodes, etc.

This method uses the GWT composite to give you full control of the widgets, provides data persistence and provides a simple way to integrate the gwt-dnd library.

We have two classes, one of which is abstract:

public abstract class Node extends Composite {
int nodeID = 0;
Node aboveNode = null;
Node belowNode = null;
Node parentNode = null;
NodeContainer parentContainer = null;
NodeContainer childContainer = new NodeContainer(this);
NodeData data = null;
int level = 0;
Widget widget = null;
}

public class NodeContainer extends VerticalPanel {
ArrayList<Node> nodes = new ArrayList<Node>();
Node parent = null;
}

Each node is stored within a NodeContainer, is also holds a NodeContainer to hold other nodes inside of it.

The NodeContainer needs some logic to handle the nodes, including:
– Add(Node node, Node aboveNode)
Pseudo code: Find the aboveNode and insert this node below it. Update the above, below and parent references of the three nodes so they have an up to date picture of their neighbours.

– Remove(Node)
Pseudo code: Find the node and remove it from the node container, update the above and below for the above and below nodes to point to each other, closing the hole where this node was.

With these functions in place, we can now write a movement function in the node itself.

public void move( Node moveTo, Node aboveNode )
this.getParent().remove(this);  // Remove me from my parent
moveTo.add(this, aboveNode)
this.save(); // Persist node after saving

Great, we can move the node around. For example you might hit a button or press tab to move the node to the right in the hierarchy, or shift+tab to move it backwards. To move it to the right essentially what you’re doing is making the node a child of the node above it. The code is simple:
node.moveTo( this.getAboveNode(), null );

There’s no aboveNode requirement once we’re into the destination node, so that’s null.

Persisting the data
You might have noticed in the move code, we implement a save() function. Each node has a reference to it’s ‘NodeData’. This is your data and all it needs to do is implement a simple interface.

public interface NodeData {
Long getParentID();
void setParentID( Long parentID );
Long getAboveID();
void setAboveID( Long aboveID );
Long getID();
void save();
}

So using the methods that you have written in your data object in order to fulfill the NodeData interface contract, a node is able to set the attributes corresponding to the data ii contains then hit the save() method. Obviously your save method will vary, but in general all it needs to do is send these attributes to the server and save them to the DB. My recommended option would be a simple data store put, using objectify (if you’re using AppEngine) because it’s so damn easy.

The way you style the Nodes to look the way you need them to be is by extending the Node class. It’s simply a composite so you can treat it like one. In the initialising function for your own node extending Widget, you’ll need to call initWidget() in the node class, and then add the nodeContainer to the widget you’ve initialised in the node class. From here you can decorate that initialising widget however you’d like with buttons, text boxes, etc.

I haven’t been able to fit everything into this post (for example loading the widgets, including the algorithm for sorting sibling nodes by aboveID and the recursion function needed to draw the tree), but hopefully this has given you the basis to form a solution. If you’d like the code I’m using for my own hierarchy then just leave a comment and I’ll upload it to GitHub.

Cheers,
Nick Cooper

3 Comments.

  1. Engagement ads are more complex; they allow for things like
    surveys that let the user interact with
    the advertisement. Facebook is more than a recreational site,
    it’s also an important business instrument. Clean out your “likes” and move forward with a fresh start.

  2. This is a message from Pam Lowery (Monday, November 15) riegrdang wifi Guest Access, which explains some of the issues from this weekend Wireless Guest Access is presenting problems at this point in time. UMW technical staff is working to resolve the issue as quickly as possible. To get network / Internet access, you should use a wired connection or log into the Clean Access connection.

  3. Your’s is a point of view where real intelligence shines through.