Architectural Notes for the Diagram Framework

A Violet graph consists of an unordered collection of nodes and an unordered collection of directed edges. Each node and edge can be customized by setting JavaBeans properties. In addition, each node has a Point2D location and an ordered collection of child nodes. There is no other persistent information.

A graph is saved using an XMLEncoder, by writing statements that add nodes, add children, connect nodes with edges, and set node and edge properties. An XMLDecoder reconstructs the graph by executing these statements.

After a graph is read in, and after each editing mutation, the graph is laid out. The layout may modify the positions, bounds, and z-order of nodes, but it should not make structural modifications. In particular, layout should not change node or edge properties, and it should not add or remove child nodes.

The Graph class simply calls layout on each top-level node. Parents are responsible for laying out their children.

After layout is complete, the graph is drawn. Nodes are opaque, so there is a need for controlling the order in which they are drawn. The Graph class calls draw on all nodes in increasing z-order, first drawing the nodes with z = 0, then with z = 1, etc., and then calls draw on all edges.

A graph can be mutated by the following editing operations:

Note that edges are always innocent bystanders. They do not participate in the decision making, and they cannot be moved.

The graph mutations will give rise to a sequence of atomic operations:

The UI controller should call the editing operations, not the atomic operations. The atomic operations are intended for system-level tasks such as undo, load, and network synchronization.

When any atomic operations occurs, the graph fires events to registered GraphModificationListener instances. The undo mechanism is one such listener. It simply reverses the atomic operations, each of which is trivially reversible.

Implementors of graph and node subclasses need to be mindful of the event firing. The Graph and AbstractNode class fire the correct events when adding or removing nodes or children, and when moving nodes through setBounds or translate. However, when setting graph properties, the events need to be generated manually.