Minimal Example (Java Model) - Updated Java Version Example with Connections 

Page / - last modified by Niklas Rentz on 2023/09/12 13:04 

Updated Java Version Example with Connections 
last modified by Niklas Rentz
on 2023/09/12 13:04

Table of Contents
The Files

Here you'll find an updated version of the minimal examle:
de.cau.cs.kieler.klighd.example.mydata.zip
 
Use the same procedure to get it to run as described on the parent page.
 
The example runs with the following current (4.12.2014) version of KLighD: 0.6.0 (Pragmatics v. 2014-10)
The visualized diagrams look like this:

Note that this diagram synthesis requests a specific layout algorithm for each case: 
 1.	de.cau.cs.kieler.graphviz.dot for splines, and
 2.	de.cau.cs.kieler.klay.layered for NO splines).
The Files
MyData.java
public class MyData {
   
   public String name;
   public List<MyData> subData = new LinkedList<MyData>();
   
   public static MyData getTestData() {
        MyData d1 = new MyData();
        d1.name = "all data";
        MyData d2 = new MyData();
        d2.name = "outer data";
        MyData d3 = new MyData();
        d3.name = "inner 1";
        MyData d4 = new MyData();
        d4.name = "inner 2";
        MyData d5 = new MyData();
        d5.name = "inner 5";
        MyData d6 = new MyData();
        d6.name = "most inner 6";
        d1.subData.add(d2);
        d2.subData.add(d3); 
        d2.subData.add(d4); 
        d2.subData.add(d5); 
        d4.subData.add(d6); 
       return d1;
   }
   
}
MyDataDiagrammSynthesisHandler.java
/*
 * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient
 *
 * http://www.informatik.uni-kiel.de/rtsys/kieler/
 * 
 * Copyright 2013 by
 * + Christian-Albrechts-University of Kiel
 *   + Department of Computer Science
 *     + Real-Time and Embedded Systems Group
 * 
 * This code is provided under the terms of the Eclipse Public License (EPL).
 * See the file epl-v10.html for the license text.
 */
package de.cau.cs.kieler.klighd.example.mydata;

import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.ui.internal.handlers.WorkbenchWindowHandlerDelegate;

import de.cau.cs.kieler.klighd.kivi.effects.KlighdUpdateDiagramEffect;
import de.cau.cs.kieler.klighd.krendering.SimpleUpdateStrategy;
import de.cau.cs.kieler.klighd.util.KlighdSynthesisProperties;

/**
 * This is a small mininal example action that triggers a diagram synthesis of a
 * static data example. In this example the actions is connected to a tool bar
 * button and can be invoked by clicking on the button.
 * 
 * UPDATED VERSION 4. DECEMBER 2014
 * 
 * @author Christian Motika
 */
public class MyDataDiagrammSynthesisHandler extends
    WorkbenchWindowHandlerDelegate { //IWorkbenchWindowActionDelegate {

   public Object execute(ExecutionEvent event) throws ExecutionException {
       // Get some static dummy test data
       MyData data = MyData.getTestData();

       // Prepare the diagram synthesis: Create a new klighdUpdateDiagramEffect
       KlighdUpdateDiagramEffect klighdEffect = new KlighdUpdateDiagramEffect(
               "de.cau.cs.kieler.klighd.example.mydata.MyDataDiagramSynthesis",
               "KLighD MyData Diagram", data);

       // FIXME: Note that the incremental update currently is under re-development
       // for Eclipse Kepler after large API changes to EMF Compare had been made.
       // At this time we cannot use the incremental update strategy (commented out).
       // As soon as it is fixed, uncomment the line below and delete the 
       // SimpleUpdateStrategy line:
       
       // klighdEffect.setProperty(LightDiagramServices.REQUESTED_UPDATE_STRATEGY,
       // UpdateStrategy.ID);

        klighdEffect.setProperty(
                        KlighdSynthesisProperties.REQUESTED_UPDATE_STRATEGY,
                SimpleUpdateStrategy.ID);

       // Do the diagram synthesis
       klighdEffect.execute();
       return null;
   }

}
MyDataDiagramSynthesis.xtend
/*
* KIELER - Kiel Integrated Environment for Layout Eclipse RichClient
*
* http://www.informatik.uni-kiel.de/rtsys/kieler/
* 
* Copyright 2013 by
* + Christian-Albrechts-University of Kiel
*   + Department of Computer Science
*     + Real-Time and Embedded Systems Group
* 
* This code is provided under the terms of the Eclipse Public License (EPL).
* See the file epl-v10.html for the license text.
*/
package de.cau.cs.kieler.klighd.example.mydata

import com.google.common.collect.ImmutableList
import de.cau.cs.kieler.core.kgraph.KNode
import de.cau.cs.kieler.core.krendering.KColor
import de.cau.cs.kieler.core.krendering.KPolyline
import de.cau.cs.kieler.core.krendering.extensions.KColorExtensions
import de.cau.cs.kieler.core.krendering.extensions.KContainerRenderingExtensions
import de.cau.cs.kieler.core.krendering.extensions.KEdgeExtensions
import de.cau.cs.kieler.core.krendering.extensions.KNodeExtensions
import de.cau.cs.kieler.core.krendering.extensions.KPolylineExtensions
import de.cau.cs.kieler.core.krendering.extensions.KRenderingExtensions
import de.cau.cs.kieler.kiml.options.Direction
import de.cau.cs.kieler.kiml.options.EdgeRouting
import de.cau.cs.kieler.kiml.options.LayoutOptions
import de.cau.cs.kieler.klighd.SynthesisOption
import de.cau.cs.kieler.klighd.syntheses.AbstractDiagramSynthesis
import javax.inject.Inject

import static extension org.eclipse.emf.ecore.util.EcoreUtil.*

//import static de.cau.cs.kieler.klighd.example.mydata.MyDataDiagramSynthesis.*
/**
* This is a small mininal example that creates a hierarchical KLighD diagram
* out of very simple hierarchical data structure (MyData). 
* 
* @author Christian Motika
*/
class MyDataDiagramSynthesis extends AbstractDiagramSynthesis<MyData> {

   @Inject extension KNodeExtensions
   @Inject extension KEdgeExtensions

   //    @Inject extension KPortExtensions
   //    @Inject extension KLabelExtensions
   @Inject extension KRenderingExtensions
   @Inject extension KContainerRenderingExtensions
   @Inject extension KPolylineExtensions
   @Inject extension KColorExtensions

   // Some self-defined colors
    private static val KColor BLUE1 = RENDERING_FACTORY.createKColor() =>
        [it.red = 248; it.green = 249; it.blue = 253];
    private static val KColor BLUE2 = RENDERING_FACTORY.createKColor() =>
        [it.red = 205; it.green = 220; it.blue = 243];

   // Additional transformation option to hide or show a shadow    
    private static val SynthesisOption SHOW_SHADOW = SynthesisOption::createCheckOption("Shadow", true);
    private static SynthesisOption EDGE_STYLE = SynthesisOption::createCheckOption("Spline", false);

   // Add all transformation options (comma separated)
    override getDisplayedSynthesisOptions() {
       return ImmutableList::of(
            SHOW_SHADOW,
            EDGE_STYLE
        );
    }

    override KNode transform(MyData data) {
        val rootNode = data.createNode()

       if (EDGE_STYLE.booleanValue) {
            rootNode.setLayoutOption(LayoutOptions::SPACING, Float::valueOf("25.0"));
            rootNode.setLayoutOption(LayoutOptions::DIRECTION, Direction::DOWN);
            rootNode.addLayoutParam(LayoutOptions::EDGE_ROUTING, EdgeRouting::SPLINES);
            rootNode.addLayoutParam(LayoutOptions::ALGORITHM, "de.cau.cs.kieler.graphviz.dot");
        } else {
            rootNode.setLayoutOption(LayoutOptions::SPACING, Float::valueOf("15.0"));
            rootNode.setLayoutOption(LayoutOptions::DIRECTION, Direction::DOWN);
            rootNode.addLayoutParam(LayoutOptions::EDGE_ROUTING, EdgeRouting::ORTHOGONAL);
            rootNode.addLayoutParam(LayoutOptions::ALGORITHM, "de.cau.cs.kieler.klay.layered");
        }

        buildNodes(data, rootNode)
        buildConnections(data, rootNode)

       return rootNode;
    }

   def void buildNodes(MyData parentData, KNode rootNode) {
        val root = parentData.createNode()
        root.putToLookUpWith(parentData) => [
           // Optional Layout parameters can be set
           //it.addLayoutParam(LayoutOptions::ALGORITHM, "de.cau.cs.kieler.kiml.ogdf.planarization");
           //it.addLayoutParam(LayoutOptions::SPACING, 75f);
           //it.addLayoutParam(LayoutOptions::DIRECTION, Direction::UP);
           // A rounded rectangle is created for every MyData instance
            it.addRoundedRectangle(5, 5) => [
               // Set linewith, foreground color, and a fading background color
                it.lineWidth = 1;
                it.setForeground("darkGray".color)
               // We need a fresh copy of each color item, because it is contained by its element
                it.setBackgroundGradient(BLUE1.copy, BLUE2.copy, 90)
               // Here we see a how to use a boolean transformation/diagram option
               if (SHOW_SHADOW.booleanValue) {
                    it.shadow = "black".color;
                }
               // Set a text
                it.addText("  " + parentData.name + " ") => [
                    it.setFontSize(9)
                    it.setForeground("black".color)
                ]
               // If this is a hierarchical MyData instance, then create horizontal splitter, 
               // a child area, and add its children
               if (parentData.subData.length > 0) {
                    it.setGridPlacement(1);
                    it.addHorizontalSeperatorLine(1, 2).setForeground("darkGray".color)
                    it.addChildArea().setGridPlacementData() => [
                        from(LEFT, 3, 0, TOP, 3, 0).to(RIGHT, 3, 0, BOTTOM, 3, 0)
                        minCellHeight = 5;
                        minCellWidth = 5;
                    ];
                   for (subData : parentData.subData) {

                       // To the recursive call to transform for all children
                        val child = subData.transform

                       // It is important to add all children to the root!
                        root.children.add(child)
                    }
                }
            ]
        ]

    }

   // Connect every first child to all childs (including itself!) 
   def void buildConnections(MyData parentData, KNode rootNode) {

       // only if there is any child there
       if (parentData.subData.size > 0) {
            val firstChild = parentData.subData.get(0);

           for (child : parentData.subData) {

               // BE CAREFUL IF YOU CREATE A MAPPING LIKE THIS THERE WILL JUST BE CREATED ONE
               // EDGE PER "firstchild". That's why better use the child, because we iterate
               // over different child-objects (targets) but always habe the same firstChild-
               // -object.
               //val kEdge = firstChild.createEdge()  // THIS IS MOST LIKELY WRONG
                
                val kEdge = child.createEdge()
                kEdge.source = firstChild.node;
                kEdge.target = child.node;

                System::out.println("Connect " + firstChild.name + " to " + child.name);

               if (!EDGE_STYLE.booleanValue) {
                    kEdge.addPolyline(2)
                } else {
                    kEdge.addSpline(2);
                }

                kEdge.KRendering as KPolyline => [
                    it.addArrowDecorator()
                    it.setLineWidth(2)
                ];

                child.buildConnections(rootNode);
            }
        }

    }

}