Spring++ Implementation

Overview

This picture shows the most important classes of Spring++ and their relations:

Primitives

Graphics code operates on basic primitives such as points, sizes, vectors and rectangles:

GDI+

Spring++ uses the Microsoft GDI+ graphics library (https://learn.microsoft.com/en-us/windows/win32/gdiplus/-gdiplus-gdi-start) that contains a rich set of drawing components. Spring++ uses only a subset of those:

Diagram Elements

The DiagramElement class is the base class of all diagram elements. Each element has a bounding rectangle and a name. All elements can measure their dimensions, draw themselves to the graphics surface, clone themselves, return their attributes as XML and parse the attributes back from XML:

Layout

Layout contain subdimensions, colors, fonts and paddings of diagram elements. The unit of measure of all layout elements is millimeter. The layout is saved as XML to the layout.xml file located in the layout subdirectory of the springpp directory.

Overview

This picture contains the layout classes:

Fundamental Layout Elements

The LayoutElement class is the base class of all layout elements. Each layout element has a name, can return its attributes as XML and parse attributes back from XML.

The fundamental layout elements contain color, font and padding attributes:

Container Layout Elements

The container layout elements contain the line widths, colors, fonts and paddings of the class, object and note diagram elements:

Other Layout Elements

The rest layout elements contains the widths, heights, radii, colors, fonts and paddings of the rest of diagram elements:

Helper Classes

Connector

The Connector class represents an ID of an endpoint of a container class. Each container object has twelve endpoints, three on each side of the container object. In addition a class element has one endpoint for each operation and attribute, and an object element has one endpoint for each attribute.

The primary connector point specifies the side of the container element: left, top, right, or bottom, or it can be operation or attribute. The secondary connector point specifies one of the three points: left and right sides have top, center and bottom points, and the top and bottom sides have left, center and right points. If the primary point is operation or attribute the secondary point is the index of the corresponding operation or attribute in a container element.

EndPoint

The EndPoint class represents an endpoint of a relationship element. It has a reference to a diagram element, that is a container element, an operation element or an attribute element. It has also a connector, a calculated canvas point, two text elements and an index of a container element in a diagram. The primary text element contains the text drawn above the relationship line and the secondary text element contains the text drawn below the relationship line.

IndexList

IndexList is a class template that is specialized for the DiagramElement, AttributeElement or OperationElement. The IndexList owns its elements. The elements are referenced by their index in the list.

Configuration

The Configuration class is a singleton that holds a Layout object. It is used by the diagram elements to access the layout.

Container Elements

The ContainerElement class contains references to relationships that the container element is part of. When the location or size of the container element changes its Measure method will be called. It calculates new source and target points for the relationships.

Class Element

The ClassElement class contains an isAbstract flag that tells whether the class is abstract or not. When the isAbstract flag is changed, the rep member is also changed to a new instance of ConcreteClassElement or AbstractClassElement.

The measuring and drawing of the class element is delegated to the representation class. The GetClassLayout method of the representation returns an instance of the ConcreteClassLayoutElement or AbstractClassLayoutElement depending whether the representation is concrete or abstract. The font style of the caption in the concrete layout is bold and in the abstract layout it is bold italic.

Object Element

The ObjectElement class is simpler than the class element. The DrawFrame method draws a rounded rectangle frame to the object element.

Note Element

The NoteElement class has a vector of text lines. The Draw method draws a frame with a note corner bitmap and calls the graphics.DrawString() method to draw the text lines.

Child Elements

Instances of the AttributeElement class are contained by object or class elements. Instances of the OperationElement class are contained by class elements. Attributes and operations have a reference to their container element and they may be part of a relationship.

Relationships

Relationship Element

The RelationshipElement class represents a relationship between two container elements. It has rkind member that is the kind of relationship represented, cardinality that holds the cardinality of the relationship, source and target endpoints and a vector of routing points.

When the rkind member changes, the SetRep method is called to create a new instance of relationship representation and set it as the value of the rep member.

The Measure method calculates the sizes of primary and secondary text elements for the source and target endpoints, and then calls the SetTextLocations method to set new locations for those text elements.

Inheritance Relationship

The Inheritance class is an example of a concrete relationship. The Draw method draws a line from the starting point of the inheritance arrow to the first routing point of the inheritance. Then it draws the line from the previous routing point to the next routing point in turn. Finally it calculates the points of the lines that consist the target end of the inheritance arrow and draws the lines.

For the rest of the concrete releationships, the implementations are analogous.

Text Element

The TextElement represents text drawn above or below a relationship line segment either near to the source or target endpoint of the relationship. If the tkind is primaryText the text is drawn above the line segment, and if it is secondaryText the text is drawn below the line segment.

The SetSourceLocation and SetTargetLocation methods calculate the location of the text element for the source and target endpoints respectively.

As an example of the location calculation code for the SetPrimarySourceLocation is shown. In this case the line parameter is the starting line segment of the relationship line. First the line segment is converted to a vector u. Then the code branches depending on the quarter of the circle the vector u points to. The code is shown when the angle of the vector is between 0° and 90°. Spring++ follows a common convention of graphics systems that the x axis points to the right and the y axis points down. Thus the x_unit and y_unit vectors are set accordingly. The variable h is set as the height of the bounding rectangle of the text element.

The code is based on vector mathematics and geometry, specifically properties of similar right triangles.

The calculations for other quarters of the circle are analogous but differ slightly.

Undo and Redo

To support undo and redo, user actions are captured as Commands and saved to a CommandList. The command list is owned by the Diagram class.

Command List

The CommandList class holds commands and keeps track of current command index.

The AddCommand method calls the Finalize method of the command and saves the command to the current index position, or adds the command to the end of the command list, if the current index is equal to the number of commands in the list. Then the current index is incremented and the list is resized to hold exactly current index number of commands.

The CanUndo method returns true if the current command index is positive and false otherwise.

The Undo method decrements the current command index and then calls the Undo method of the command at the current command index.

The CanRedo method returns true if the current command index is less then the number of commands in the list and false otherwise.

The Redo method calls the Redo method of the command at the current command index, and increments the current command index.

The CanUndo and CanRedo methods are used to enable and disable the Undo and Redo menu items respectively.

Selections

There are three kind of selections derived from the Selection base class: the EmptySelection is the default when nothing is selected, the ElementSelection contains indeces of diagram elements selected by control+clicking them, and the RectangleSelection is created by dragging a rectangle around diagram elements.

Context Menu Actions

Actions are added to a context menu when user right-clicks either an individual diagram element or a selection.

Diagram Element Actions

Actions derived from the DiagramElementAction are added to a context menu by the AddActions method of a diagram element when it is right-clicked. When user selects a menu item from the context menu, the Execute method of a diagram element action gets called.

Diagram Actions

Actions derived from the DiagramAction are added to a context menu by the AddActions method of a selection when it is right-clicked. When user selects a menu item from the context menu, the Execute method of a diagram action gets called.