Page tree

Versions Compared

Key

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

KIELER Lightweight Diagrams (KLighD) allows you to develop visualizations for data structures quite easily. In this tutorial, we will install Eclipse and all the necessary components to develop KLighD visualizations before moving on to actually develop a visualization of a state machine.

...

:

Image Added

Preliminaries

There's a few things to do before we dive into the tutorial itself. For example, to do Eclipse programming, you will have to get your hands on an Eclipse installation first. Read through the following sections to get ready for the tutorial tasks.

...

The imported projects contain a meta model for Turing machines. (You may notice that this tutorial thus also slips in a perfect opportunity to brush up on your knowledge of Turing machines. Consider it a public service and thank us later.) It does not model the tape or the head, only its states and transitions. It is these Turing machines that we will develop a visualization for over the course of this tutorial.

Tip
titleFixing Problems

Should your projects be marked with a big red exclamation mark, there might be build path problems. To fix them, complete these steps with all such projects:

  1. Right-click a project and select Properties.
  2. In the dialog that opens up, navigate to the Java Compiler category.
  3. Chances are that project-specific settings are enabled here. Disable them and click OK.

If that wasn't the source of the problem, ask your advisor.

Creating a Visualization

Now that we have the model of what we want to visualize, it's time to program the actual visualization. But first, let's take a minute to think about what we need to do here. Take a look at the following diagram:

...

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(
        LayoutOptionsCoreOptions.NODE_SIZE_CONSTRAINTCONSTRAINTS,
        EnumSet.of(SizeConstraint.MINIMUM_SIZE, SizeConstraint.NODE_LABELS));
  4. Now that we know how to transform states, we have to call our new method from the main transformation method. Replace the comment in its body with the following line of code:

    Code Block
    languagescala
    linenumberstrue
    model.states.forEach[ s | root.children += transform(s) ]

Let's see if our visualization works. Start your program (if you don't know how to do that, check out our Eclipse Plug-ins and Extension Points tutorial) and follow these steps:

...

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);
    }
];

The result should look something like this (I told you it was going to be hideous):

Visualizing Transitions

Now that we have our states, it's time to visualize transitions as well. It would be nice to just transform transitions leaving a given state while we're transforming that state. Let's do that:

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

    Code Block
    languagescala
    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
    languagescala
    linenumberstrue
    // Add a label to the edge
    val label = KGraphUtil.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
    languagescala
    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.

Start your program again, open your Turing machine file and add an outgoing transition to your Wilhelm Tell state. Change the  properties 'New Char' and 'Trigger' to arbirtary characters (but not 0, since that translates to the ASCII char null and will kill your Label).  Set the Apple state as the transition's target state. Save the model and fire up a KLighD view. It should look something like this:

Image Added

Going Further

This concludes our little KLighD tutorial, but of course there's a lot you haven't seen yet. To go further, take a look at the KLighD pages in our KIELER Confluence space and the examples described there. Also, try solving the assignment below, if you like.

Panel
titleAssignment

In text files, lists can be written like this:

Code Block
* Monday
  * Prepare lecture
  * Meeting
  * Prepare lecture again
* Tuesday
  * Throw away lecture
  * Prepare exam
    * Assignment 1
    * Assignment 2
    * Assignment 3
* Wednesday
  * Do nothing

Create a new project that provides a menu item that fires up a visualization for this kind of list format. The visualization should look something like this:

Image Added

  1. Create a new KLighD Project that visualizes String instances. Let the wizard create a context menu item for files with the extension textlist.
  2. The generated command handler will try to let the Eclipse Modeling Framework load the file. Replace this code with code that simply opens the file and reads its content into a String.
  3. Write a synthesis that turns a String into a KGraph. You can use the synthesis from our tutorial as a template.

When parsing the string, you can simply assume that each level of the list gets indented by exactly two spaces, and that the text of each list item starts after an asterisk followed by a space. No need to build fancy error checking into your solution.