Event Architecture from Model to Diagram Elements
There is little documented about how changes to the UML model are reflected on the diagram in a consistent way. Diagrams and diagram elements (Figs) have been designed by various developers without a common standard. Over time implementation of notations and change of UML model repository have introduced changes which have unexpected side effects and for which there are short term work around.
This page is an attempt to formalize a common way of working for all diagram elements. It is to clearly separate GUI from notation and UML model and prevent excessive reconstruction of the GUI composite parts and excessive adding and removal of listeners from the GUI to notation and UML model.
The existing diagrams do not fit what is described here. This description is documenting the approach taken in development of the Activity diagram for UML2. Once development of that diagram is stable the lessons learned here will be used in other diagram types as they split out into their own modules.
Example problem of current implementation
?FigAttribute gets the model element via notation so that it changes it text.
?FigClass also gets a notification because its possible that the attribute text change means that the whole bounds of the class needs to change to fit that text. The ?FigClass then rearranges all the child Figs it contains.
The problem may be deeper than this. The child Figs may well be deleted and recreated in this process. It may also be that listeners to the model are dropped and then added again. As a result some events from the model might be missed.
Progress an an improved implementation
As part of the implementation of the UML2 activity diagram work is progressing to improve this.
The implementation so far is -
When the name of a text Fig changes due to a notation event its own setBounds() method is called to change the size of itself. setBounds fires a "bounds" ?PropertyEvent
The parent Fig that contains that text Fig is listening to its child for that event. When received it determines if the child still fits inside itself. If not it resizes all of its children (but no recreation of Figs or listeners).
That resize will be by calling its own setBounds. The next step was going to be to make the next level up Fig listen for that "bounds" change until the events have bounced all the way up. At this point work has paused.
Potential problems with improved implemention
The solution developed so far has some drawbacks.
Typically a Fig is responsible for laying out all the child Figs inside itself. It can check the max and min size of each and then place them where required. It's setBoundsImpl() where this layout takes place.
Those child figs then layout out their own children etc.
There is a danger that if things aren't coded carefully an event will bounce up a level asking for a re-layout. That may result in change in size of the child fig that requested it and that again in turn request the parent to lay out again. We get a constant loop.
Even if things were done perfectly there can still be too many repeated calls to layout the Figs.
An attribute grows so its compartment grows and lays out all its attributes.
Because the compartment grows the class grows and lays out all its compartments (which in turns lays out all the attributes in the attribute compartment)
A Proposed Solution
Do not use events - this is overkill as there is a composite relationship between parent and child already.
When a notation changes a text Fig, the follow should happen -
The text Fig calculates its minimum size. If its minimum size is greater than its actual size it calls the childLayoutRequest method of its parent Fig.
The parent Fig will do the same with no layout taking place of its own Figs - checking only its own minimum size against its current size.
The calls continue up from parent to child until either there is no parent or the minimum size fits the parent.
At this point the parent level reach repositions its own child Fig and those children reposition their own children rattling downwards just once.
Simple Diagram Elements
A Fig is the most basic diagram element in the GEF library. It has an optional "owner" which is typically a UML element.
All Figs must implement a getMinimumSize method to prevent them from being sized smaller than they can display their own contents.
?FigText - TODO
A ?FigNotation is a specialist ?FigText for displaying (and possibly editing) text for some UML element. Its minimum size is the width and height that will fit that text for its current font. A ?FigNotation will always have an owner.
?FigLine - TODO
?FigRect - TODO
FigRRect - TODO
?FigCircle - TODO
Composite Diagram Elements
A ?FigGroup is a composite Fig made up of several child Figs. A ?FigGroup knows its own bounds but has no direct knowledge of its own shape. That is defined by the composite child Figs and how they are layed out.
A ?FigCompartment is a specialist ?FigGroup where all child Figs are displayed vertically. The minimum height if the sum of the minimum height of all child figs. The minimum width is the same as the child Fig with the largest minimum width. When resizing all child Figs resize to the width of the compartment.
A ?FigNameCompartment is a specialist ?FigCompartment that would only be expected to hold two children. The ?FigNotation for displaying and editing the name of the UML element that owns the Fig and a child ?FigCompartment that contains a list of ?FigNotations for each stereotype.
Complex Diagram Elements
A ?FigRectNotation is a specialist ?FigGroup containing a ?FigNotation and a ?FigRect. On resize the children are laid out so that the text dispaly within the rectangle The minimum size is that allowed big the notation with a border surrounding it.
A FigRRectNotation is a specialist ?FigGroup containing a ?FigNotation and a FigRRect. On resize the children are laid out so that the text dispaly within the rectangle The minimum size is that allowed big the notation with a border surrounding it.
All composite Figs must implement a setBoundsImpl(x, y, w, h) method which will both set their own bounds and also layout any child Figs contained within themselves to fit those bounds. The logic of how the child Figs are layed out belongs to the setBoundsImpl of the composite that contains those children but that logic must respect the minimum size of each child as part of the layout.
The getMinimumSize() method of a composite Fig must calculate its minimum size based on the minimum size of the child Figs and its own logic of how these are to be layed out.
Resizing of diagram nodes
As a ?FigBaseNode is resized by the user its setBounds method is called in order to resize its contents.
It is not possible to resize the node smaller than its minimum size
Reacting to model elements changes represented as text
Reacting to model elements changes represented as composite parts