Page tree

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

We will now start filling in the synthesis skeleton, so open the TuringMachineDiagramSynthesis class:

Code Block
languagejavascala
linenumberstrue
/* Package and import statements... */

class TuringMachineDiagramSynthesis extends AbstractDiagramSynthesis<TuringMachine> {
    
    @Inject extension KNodeExtensions
    @Inject extension KEdgeExtensions
    @Inject extension KPortExtensions
    @Inject extension KLabelExtensions
    @Inject extension KRenderingExtensions
    @Inject extension KContainerRenderingExtensions
    @Inject extension KPolylineExtensions
    @Inject extension KColorExtensions
    extension KRenderingFactory = KRenderingFactory.eINSTANCE
    
    
    override KNode transform(TuringMachine model) {
        val root = model.createNode().associateWith(model);
        
        // Your dsl element <-> diagram figure mapping goes here!!
        
        return root;
    }
    
}

...

  1. Add a new method to your synthesis that transforms a State into a corresponding KNode:

    Code Block
    languagejavascala
    linenumberstrue
    private def KNode transform(State state) {
        val stateNode = state.createNode().associateWith(state);
    
        return stateNode;
    } 
  2. While this method does indeed create a node for the state passed to it, KLighD wouldn't know how to render it yet. Let's draw the node as a rounded rectangle by adding the following line before the return statement:

    Code Block
    languagejava
    linenumberstrue
    stateNode.addRoundedRectangle(4, 4, 2);
  3. The only thing missing now is a label with the state's name:

    Code Block
    languagejava
    linenumberstrue
    stateNode.addInsideCenteredNodeLabel(state.name,
        KlighdConstants.DEFAULT_FONT_SIZE,
        KlighdConstants.DEFAULT_FONT_NAME);
    stateNode.addLayoutParam(
        LayoutOptions.SIZE_CONSTRAINT,
        EnumSet.of(SizeConstraint.MINIMUM_SIZE, SizeConstraint.NODE_LABELS));

...

That's quite nice already, but we have no way to determine which of these states is the default. Let's add a hideously ugly background colour to initial states by changing the line that adds a rounded rectangle:

Code Block
languagescala
linenumberstrue
stateNode.addRoundedRectangle(4, 4, 2) => [ rect |
    if (state.initial) {
        rect.setBackgroundColor(210, 130, 210);
    }
];

...

  1. Add the following code right before the return statement in the state transformation method:

    Code Block
    languagejavascala
    linenumberstrue
    stateNode.outgoingEdges.addAll(state.outgoingTransitions.map[ t | transform(t) ])
  2. Of course, we will have to add a transform method for transitions now:

    Code Block
    languagescala
    linenumberstrue
    private def KEdge transform(Transition trans) {
        val transEdge = trans.createEdge().associateWith(trans)
    
        return transEdge;
    }
  3. Again, we need to tell KLighD how to render the label:

    Code Block
    languagejava
    linenumberstrue
    transEdge.addPolyline(2).addHeadArrowDecorator();
  4. And the edge also needs a label that describes the transition:

    Code Block
    languagejavascala
    linenumberstrue
    // Add a label to the edge
    val label = KimlUtil.createInitializedLabel(transEdge);
    val labelText = trans.trigger + " / "
               + trans.action + " "
               + trans.direction + " "
               + trans.newChar;
    label.configureCenterEdgeLabel(labelText,
        KlighdConstants.DEFAULT_FONT_SIZE,
        KlighdConstants.DEFAULT_FONT_NAME);
  5. What is missing now is to set the edge target to the node that represents the target state. There's a problem here, though: we don't even know if the target state already had a node created for it. Thus, we need to make sure it has:

    Code Block
    languagejava
    linenumberstrue
    transEdge.target = transform(trans.targetState);
  6. This, however, results in a different problem: if the target state already had a node created for it, we now create another node. What we would need the state transformation method to do would be to first check if a node has already been created for a given state, and, if so, return that instead of creating a new one. It turns out that Xtend already supports this pattern. Change the method's declaration and its first line to the following:

    Code Block
    languagejavascala
    linenumberstrue
    private def create stateNode : state.createNode() transform(State state) {
        stateNode.associateWith(state);

    Also, remove the return statement. Xtend now checks if we already created a node for the given state and, if not, execute the code in the method.

...