Jelajahi Sumber

Merge branch 'master' of https://koljastrohm-games.com:3000/GraphDrawer/NodeShuffler

Kolja Strohm 6 tahun lalu
induk
melakukan
7bcd724124

+ 17 - 36
src/graph/LayeredEdge.java

@@ -58,7 +58,7 @@ public class LayeredEdge implements LayeredGraphEdge {
 
     @Override
     public boolean isConflicted( LayoutType layout )
-    {
+    {   // see javadoc for better understanding of what this does
         if( layout == LayoutType.LEFTMOST_UPPER )
             return conflicted[ 0 ];
         if( layout == LayoutType.RIGHTMOST_UPPER )
@@ -72,36 +72,9 @@ public class LayeredEdge implements LayeredGraphEdge {
         return false;
     }
     
-    @Override
-    public ArrayList<LayeredGraphEdge> calcEdgeCrossings()
-    {
-        ArrayList<LayeredGraphEdge> list = new ArrayList<>();
-        ArrayList<LayeredGraphNode> l = graph.getContainedLayers().get( sources.get( 0 ).getLayer() );
-        ArrayList<LayeredGraphNode> l2 = graph.getContainedLayers().get( targets.get( 0 ).getLayer() );
-        int startIndex = l.indexOf( sources.get( 0 ) );
-        int endIndex = l2.indexOf( targets.get( 0 ) );
-        for( int i = 0; i < l.size(); i++ )
-        {
-            if( i == startIndex )
-                continue;
-            for( LayeredGraphEdge e : l.get( i ).getOutgoingEdges() )
-            {
-                int i2 = l2.indexOf( e.getTargets().get( 0 ) );
-                if( i2 == endIndex )
-                    continue;
-                if( i < startIndex && i2 > endIndex || i > startIndex && i2 < endIndex )
-                {
-                    if( !list.contains( e ) )
-                        list.add( e );
-                }
-            }
-        }
-        return list;
-    };
-    
     @Override
     public void setConflicted( boolean conflicted, LayoutType layout )
-    {
+    {   // see javadoc for better understanding of what this does
         if( layout == null )
         {
             this.conflicted[ 0 ] = conflicted;
@@ -124,7 +97,7 @@ public class LayeredEdge implements LayeredGraphEdge {
     
     @Override
     public void setStartPoint( int x, int y, LayoutType layout )
-    {
+    {   // see javadoc for better understanding of what this does
         if( layout == null )
         {
             bindPoints[ 0 ].set( 0, new Point( x, y ) );
@@ -147,7 +120,7 @@ public class LayeredEdge implements LayeredGraphEdge {
     
     @Override
     public void addBindPoint( int x, int y, LayoutType layout )
-    {
+    {   // see javadoc for better understanding of what this does
         if( layout == null )
         {
             bindPoints[ 0 ].add( bindPoints[ 0 ].size() - 1, new Point( x, y ) );
@@ -170,7 +143,7 @@ public class LayeredEdge implements LayeredGraphEdge {
     
     @Override
     public void setEndPoint( int x, int y, LayoutType layout )
-    {
+    {   // see javadoc for better understanding of what this does
         if( layout == null )
         {
             bindPoints[ 0 ].set( bindPoints[ 0 ].size() - 1, new Point( x, y ) );
@@ -193,7 +166,7 @@ public class LayeredEdge implements LayeredGraphEdge {
 
     @Override
     public ArrayList<Point> getLinePoints( LayoutType layout )
-    {
+    {   // see javadoc for better understanding of what this does
         NodeView sourceView = ((LayeredNode)sources.get( 0 )).getView( layout );
         NodeView targetView = ((LayeredNode)targets.get( 0 )).getView( layout );
         setStartPoint( sourceView.getVirtualX() + sourceView.getVirtualWidth() / 2, sourceView.getVirtualY() + sourceView.getVirtualHeight(), layout );
@@ -233,12 +206,14 @@ public class LayeredEdge implements LayeredGraphEdge {
 
     @Override
     public boolean isCrossLayerEdge() {
+        // check source
         int sl = sources.get( 0 ).getLayer();
         for( LayeredGraphNode s : sources )
         {
             if( sl != s.getLayer() )
                 return true;
         }
+        // check target
         int tl = targets.get( 0 ).getLayer();
         if( Math.abs( tl - sl ) != 1 )
             return true;
@@ -252,16 +227,17 @@ public class LayeredEdge implements LayeredGraphEdge {
 
     @Override
     public void replaceByDummyNodes() {
-        if( isCrossLayerEdge() )
+        if( isCrossLayerEdge() ) // cross layer edge?
         {
-            remove();
+            remove(); // remove this edge
             if( sources.size() == 1 && targets.size() == 1 )
             {
                 LayeredGraphNode last = sources.get( 0 );
                 int sl = last.getLayer();
                 int tl = targets.get( 0 ).getLayer();
-                for( int i = sl + 1; i < tl; i++ )
+                for( int i = sl + 1; i < tl; i++ ) // for each layer
                 {
+                    // add a dummy edge and a dummy node
                     LayeredGraphNode n = graph.createNode( null );
                     n.setLayer( i );
                     LayeredGraphEdge e = graph.createSimpleEdge( original, last, n );
@@ -270,6 +246,7 @@ public class LayeredEdge implements LayeredGraphEdge {
                         e.setReversedEdge();
                     last = n;
                 }
+                // create last dummy edge
                 LayeredGraphEdge e = graph.createSimpleEdge( original, last, targets.get( 0 ) );
                 e.setDummyEdge();
                 if( reversed )
@@ -295,7 +272,9 @@ public class LayeredEdge implements LayeredGraphEdge {
     public void removeDummyNodes() {
         if( isDummyEdge() )
         {
+            // remove the dummy edge
             remove();
+            // remove the sources
             ArrayList< LayeredGraphNode > sours = sources;
             for( int i = 0; i < sours.size(); i++ )
             {
@@ -310,6 +289,7 @@ public class LayeredEdge implements LayeredGraphEdge {
                     }
                 }
             }
+            // remove the targets
             ArrayList< LayeredGraphNode > targs = targets;
             for( int i = 0; i < targs.size(); i++ )
             {
@@ -325,6 +305,7 @@ public class LayeredEdge implements LayeredGraphEdge {
                 }
                     
             }
+            // add old edge again
             LayeredGraphEdge e = graph.createEdge( original, sours, targs );
             if( reversed )
                 e.setReversedEdge();

+ 0 - 6
src/graph/LayeredGraphEdge.java

@@ -27,12 +27,6 @@ public interface LayeredGraphEdge {
      */
     public boolean isConflicted( LayoutType layout );
     
-    /**
-     * Computes a list of edges that cross this edge.
-     * @return the list.
-     */
-    public ArrayList<LayeredGraphEdge> calcEdgeCrossings();
-    
     /**
      * Mark this edge as conflicted in the given layout.
      * @param conflicted Whether to mark the edge as conflicted or to remove this mark.

+ 60 - 2
src/graph/LayeredNode.java

@@ -68,8 +68,10 @@ public class LayeredNode implements LayeredGraphNode {
      */
     public static LayeredGraphNode convertToLayeredGraph(ElkNode n) {
         LayeredNode ln = new LayeredNode(n, null);
+        // nodes
         for (ElkNode node : n.getChildren())
             ln.addNode(convertToLayeredGraph(node));
+        // edges
         for (ElkEdge edge : n.getContainedEdges()) {
             // TODO n.getProperty(Properties.LAYERPOS) reads position of node n in his layer
             ArrayList<LayeredGraphNode> sources = new ArrayList<>();
@@ -146,6 +148,7 @@ public class LayeredNode implements LayeredGraphNode {
      * @param layout the layout
      */
     public void setView(NodeView view, LayoutType layout) {
+        // see javadoc for better understanding of what this does
         if (layout == LayoutType.LEFTMOST_UPPER)
             this.layouts[0].view = view;
         if (layout == LayoutType.RIGHTMOST_UPPER)
@@ -165,6 +168,7 @@ public class LayeredNode implements LayeredGraphNode {
      * @return the view
      */
     public NodeView getView(LayoutType layout) {
+        // see javadoc for better understanding of what this does
         if (layout == LayoutType.LEFTMOST_UPPER)
             return layouts[0].view;
         if (layout == LayoutType.RIGHTMOST_UPPER)
@@ -190,6 +194,7 @@ public class LayeredNode implements LayeredGraphNode {
 
     @Override
     public void setShift(double shift, LayoutType layout) {
+        // see javadoc for better understanding of what this does
         if (layout == null) {
             this.layouts[0].shift = shift;
             this.layouts[1].shift = shift;
@@ -208,6 +213,7 @@ public class LayeredNode implements LayeredGraphNode {
 
     @Override
     public double getShift(LayoutType layout) {
+        // see javadoc for better understanding of what this does
         if (layout == LayoutType.LEFTMOST_UPPER)
             return this.layouts[0].shift;
         if (layout == LayoutType.RIGHTMOST_UPPER)
@@ -221,6 +227,7 @@ public class LayeredNode implements LayeredGraphNode {
 
     @Override
     public void setSink(LayeredGraphNode sink, LayoutType layout) {
+        // see javadoc for better understanding of what this does
         if (layout == null) {
             this.layouts[0].sink = sink;
             this.layouts[1].sink = sink;
@@ -239,6 +246,7 @@ public class LayeredNode implements LayeredGraphNode {
 
     @Override
     public LayeredGraphNode getSink(LayoutType layout) {
+        // see javadoc for better understanding of what this does
         if (layout == LayoutType.LEFTMOST_UPPER)
             return this.layouts[0].sink;
         if (layout == LayoutType.RIGHTMOST_UPPER)
@@ -252,6 +260,7 @@ public class LayeredNode implements LayeredGraphNode {
 
     @Override
     public boolean isXUndefined(LayoutType layout) {
+        // see javadoc for better understanding of what this does
         if (layout == LayoutType.LEFTMOST_UPPER)
             return this.layouts[0].xUndef;
         if (layout == LayoutType.RIGHTMOST_UPPER)
@@ -265,6 +274,7 @@ public class LayeredNode implements LayeredGraphNode {
 
     @Override
     public void setAlign(LayeredGraphNode align, LayoutType layout) {
+        // see javadoc for better understanding of what this does
         if (layout == null) {
             this.layouts[0].align = align;
             this.layouts[1].align = align;
@@ -283,6 +293,7 @@ public class LayeredNode implements LayeredGraphNode {
 
     @Override
     public LayeredGraphNode getAlign(LayoutType layout) {
+        // see javadoc for better understanding of what this does
         if (layout == LayoutType.LEFTMOST_UPPER)
             return this.layouts[0].align;
         if (layout == LayoutType.RIGHTMOST_UPPER)
@@ -296,6 +307,7 @@ public class LayeredNode implements LayeredGraphNode {
 
     @Override
     public void setRoot(LayeredGraphNode root, LayoutType layout) {
+        // see javadoc for better understanding of what this does
         if (layout == null) {
             this.layouts[0].root = root;
             this.layouts[1].root = root;
@@ -314,6 +326,7 @@ public class LayeredNode implements LayeredGraphNode {
 
     @Override
     public LayeredGraphNode getRoot(LayoutType layout) {
+        // see javadoc for better understanding of what this does
         if (layout == LayoutType.LEFTMOST_UPPER)
             return this.layouts[0].root;
         if (layout == LayoutType.RIGHTMOST_UPPER)
@@ -327,6 +340,7 @@ public class LayeredNode implements LayeredGraphNode {
 
     @Override
     public void setSelected(LayoutType layout) {
+        // see javadoc for better understanding of what this does
         if (layout == null) {
             this.layouts[0].selected = true;
             this.layouts[1].selected = true;
@@ -348,6 +362,7 @@ public class LayeredNode implements LayeredGraphNode {
 
     @Override
     public void unselectGraph() {
+        // see javadoc for better understanding of what this does
         for (LayeredGraphNode n : nodes) {
             n.unselectGraph();
         }
@@ -360,6 +375,7 @@ public class LayeredNode implements LayeredGraphNode {
 
     @Override
     public boolean isSelected(LayoutType layout) {
+        // see javadoc for better understanding of what this does
         if (layout == LayoutType.LEFTMOST_UPPER) {
             return layouts[0].selected;
         }
@@ -381,6 +397,7 @@ public class LayeredNode implements LayeredGraphNode {
     @Override
     public void setColor( Color c, LayoutType layout )
     {
+        // see javadoc for better understanding of what this does
         if( layout == null )
         {
             this.layouts[ 0 ].color = c;
@@ -411,30 +428,39 @@ public class LayeredNode implements LayeredGraphNode {
 
     @Override
     public Color getClassColor(LayoutType layout) {
+        // leftmost upper
         if (layout == LayoutType.LEFTMOST_UPPER && this.layouts[0].sink == this && calcClassSize(this, layout) == 1)
             return Color.LIGHT_GRAY;
         if (layout == LayoutType.LEFTMOST_UPPER && this.layouts[0].sink == this)
             return this.layouts[0].color;
         else if (layout == LayoutType.LEFTMOST_UPPER)
             return this.layouts[0].sink.getClassColor(layout);
+        
+        // rightmost upper
         if (layout == LayoutType.RIGHTMOST_UPPER && this.layouts[1].sink == this && calcClassSize(this, layout) == 1)
             return Color.LIGHT_GRAY;
         if (layout == LayoutType.RIGHTMOST_UPPER && this.layouts[1].sink == this)
             return this.layouts[1].color;
         else if (layout == LayoutType.RIGHTMOST_UPPER)
             return this.layouts[1].sink.getClassColor(layout);
+        
+        // leftmost lower
         if (layout == LayoutType.LEFTMOST_LOWER && this.layouts[2].sink == this && calcClassSize(this, layout) == 1)
             return Color.LIGHT_GRAY;
         if (layout == LayoutType.LEFTMOST_LOWER && this.layouts[2].sink == this)
             return this.layouts[2].color;
         else if (layout == LayoutType.LEFTMOST_LOWER)
             return this.layouts[2].sink.getClassColor(layout);
+        
+        // rightmost lower
         if (layout == LayoutType.RIGHTMOST_LOWER && this.layouts[3].sink == this && calcClassSize(this, layout) == 1)
             return Color.LIGHT_GRAY;
         if( layout == LayoutType.RIGHTMOST_LOWER && this.layouts[ 3 ].sink == this )
             return this.layouts[ 3 ].color;
         else if( layout == LayoutType.RIGHTMOST_LOWER )
             return this.layouts[ 3 ].sink.getClassColor( layout );
+        
+        // no colors in the combined layout
         if( layout == LayoutType.COMBINED )
             return Color.LIGHT_GRAY;
         return null;
@@ -443,6 +469,7 @@ public class LayeredNode implements LayeredGraphNode {
     @Override
     public Color getColor( LayoutType layout )
     {
+        // leftmost upper
         if( layout == null )
             return this.layouts[ 0 ].color;
         if( layout == LayoutType.LEFTMOST_UPPER && this.layouts[ 0 ].root == this && this.layouts[ 0 ].align == this )
@@ -451,12 +478,16 @@ public class LayeredNode implements LayeredGraphNode {
             return this.layouts[0].root.getColor(layout);
         if (layout == LayoutType.LEFTMOST_UPPER)
             return this.layouts[0].color;
+        
+        // rightmost upper
         if (layout == LayoutType.RIGHTMOST_UPPER && this.layouts[1].root == this && this.layouts[1].align == this)
             return Color.LIGHT_GRAY;
         if (layout == LayoutType.RIGHTMOST_UPPER && this.layouts[1].root != this)
             return this.layouts[1].root.getColor(layout);
         if (layout == LayoutType.RIGHTMOST_UPPER)
             return this.layouts[1].color;
+        
+        // leftmost lower
         if (layout == LayoutType.LEFTMOST_LOWER && this.layouts[2].root == this && this.layouts[2].align == this)
             return Color.LIGHT_GRAY;
         if (layout == LayoutType.LEFTMOST_LOWER && this.layouts[2].root != this)
@@ -465,10 +496,14 @@ public class LayeredNode implements LayeredGraphNode {
             return this.layouts[2].color;
         if (layout == LayoutType.RIGHTMOST_LOWER && this.layouts[3].root == this && this.layouts[3].align == this)
             return Color.LIGHT_GRAY;
+        
+        // rightmost lower
         if( layout == LayoutType.RIGHTMOST_LOWER && this.layouts[ 3 ].root != this )
             return this.layouts[ 3 ].root.getColor( layout );
         if( layout == LayoutType.RIGHTMOST_LOWER )
             return this.layouts[ 3 ].color;
+        
+        // no colors in the combined layout
         if( layout == LayoutType.COMBINED )
             return Color.LIGHT_GRAY;
         return null;
@@ -506,6 +541,7 @@ public class LayeredNode implements LayeredGraphNode {
 
     @Override
     public void setX(double x, boolean def, LayoutType layout) {
+        // see javadoc for better understanding of what this does
         if (layout == null) {
             layouts[0].x = x;
             layouts[1].x = x;
@@ -535,6 +571,7 @@ public class LayeredNode implements LayeredGraphNode {
 
     @Override
     public void setY(double y, LayoutType layout) {
+        // see javadoc for better understanding of what this does
         if (layout == null) {
             layouts[0].y = y;
             layouts[1].y = y;
@@ -556,6 +593,7 @@ public class LayeredNode implements LayeredGraphNode {
 
     @Override
     public double getX(LayoutType layout) {
+        // see javadoc for better understanding of what this does
         if (layout == LayoutType.LEFTMOST_UPPER)
             return this.layouts[0].x;
         if (layout == LayoutType.RIGHTMOST_UPPER)
@@ -571,6 +609,7 @@ public class LayeredNode implements LayeredGraphNode {
 
     @Override
     public double getY(LayoutType layout) {
+        // see javadoc for better understanding of what this does
         if (layout == LayoutType.LEFTMOST_UPPER)
             return this.layouts[0].y;
         if (layout == LayoutType.RIGHTMOST_UPPER)
@@ -589,6 +628,7 @@ public class LayeredNode implements LayeredGraphNode {
         if (nodes.size() > 0) {
             double max = 0;
             double min = Double.POSITIVE_INFINITY;
+            // check contained nodes
             for( LayeredGraphNode n : nodes )
             {
                 if( max < n.getX(layout) + n.getWidth(layout) )
@@ -624,6 +664,7 @@ public class LayeredNode implements LayeredGraphNode {
         if( nodes.size() > 0 )
         {
         	double max = 0;
+          // check contained nodes
         	for( LayeredGraphNode n : nodes )
         	{
         		if( max < n.getY(layout) + n.getHeight(layout) )
@@ -655,6 +696,7 @@ public class LayeredNode implements LayeredGraphNode {
 
     @Override
     public void setWidth(double w, LayoutType layout) {
+        // see javadoc for better understanding of what this does
         if (layout == null) {
             this.layouts[0].w = w;
             this.layouts[1].w = w;
@@ -676,6 +718,7 @@ public class LayeredNode implements LayeredGraphNode {
 
     @Override
     public void setHeight(double h, LayoutType layout) {
+        // see javadoc for better understanding of what this does
         if (layout == null) {
             this.layouts[0].h = h;
             this.layouts[1].h = h;
@@ -702,11 +745,14 @@ public class LayeredNode implements LayeredGraphNode {
 
     @Override
     public void removeNode(LayeredGraphNode n) {
+        // remove all edges containing this node
         for (LayeredGraphEdge e : n.getIncomingEdges())
             e.remove();
         for (LayeredGraphEdge e : n.getOutgoingEdges())
             e.remove();
+        // remove node itself
         nodes.remove(n);
+        // remove node from layers
         for (ArrayList<LayeredGraphNode> l : layers) {
             l.remove(n);
         }
@@ -714,18 +760,24 @@ public class LayeredNode implements LayeredGraphNode {
 
     @Override
     public void setNodeLayer(LayeredGraphNode n, int index) {
+        // add new layers
         while (index >= layers.size())
             layers.add(new ArrayList<>());
+        // remove from old layer
         int old = n.getLayer();
         if (old >= 0)
             layers.get(old).remove(n);
+        // add to new layer
         layers.get(index).add(n);
     }
 
     @Override
     public void setOrderedLayer(ArrayList<Double> indizes, int layerIndex) {
+        // which layer?
         ArrayList<LayeredGraphNode> l2 = layers.get(layerIndex);
         ArrayList<LayeredGraphNode> result = new ArrayList<LayeredGraphNode>();
+        
+        // sort layer
         while (indizes.size() > 0) {
             int mIndex = 0;
             double min = indizes.get(0);
@@ -799,7 +851,7 @@ public class LayeredNode implements LayeredGraphNode {
     public ArrayList<LayeredGraphEdge> getOutgoingEdges(LayeredGraphNode n) {
         ArrayList<LayeredGraphEdge> result = new ArrayList<>();
         for( LayeredGraphEdge e : edges )
-        {
+        { // is this edge outgoing?
             if( e.getSources().contains( n ) && !result.contains( e ) )
                 result.add( e );
         }
@@ -810,7 +862,7 @@ public class LayeredNode implements LayeredGraphNode {
     public ArrayList<LayeredGraphEdge> getIncomingEdges(LayeredGraphNode n) {
         ArrayList<LayeredGraphEdge> result = new ArrayList<>();
         for( LayeredGraphEdge e : edges )
-        {
+        { // is this edge incoming?
             if( e.getTargets().contains( n ) && !result.contains( e ) )
                 result.add( e );
         }
@@ -819,10 +871,13 @@ public class LayeredNode implements LayeredGraphNode {
 
     @Override
     public ArrayList<LayeredGraphEdge> getSortedOutgoingEdges(LayeredGraphNode n) {
+        // get edges
         ArrayList<LayeredGraphEdge> result = new ArrayList<>();
     	if( n.getLayer() + 1 >= layers.size() )
     		return result;
         ArrayList< LayeredGraphEdge > unsorted = getOutgoingEdges( n );
+        
+        // sort
         for( LayeredGraphNode node : layers.get( n.getLayer() + 1 ) )
         {
         	for( LayeredGraphEdge e : unsorted )
@@ -836,9 +891,12 @@ public class LayeredNode implements LayeredGraphNode {
 
     @Override
     public ArrayList<LayeredGraphEdge> getSortedIncomingEdges(LayeredGraphNode n) {
+        // get edges
         ArrayList<LayeredGraphEdge> result = new ArrayList<>();
     	if( n.getLayer() - 1 < 0 )
     		return result;
+    	
+        // sort
         ArrayList< LayeredGraphEdge > unsorted = getIncomingEdges( n );
         for( LayeredGraphNode node : layers.get( n.getLayer() - 1 ) )
         {

+ 20 - 0
src/graph/io/Reader.java

@@ -34,6 +34,7 @@ public class Reader {
     public LayeredGraphNode readInputGraph()
     {
         String file = "";
+        // read file
         try {
             BufferedReader r = new BufferedReader( new FileReader( fileName ) );
             String tmp = null;
@@ -43,6 +44,7 @@ public class Reader {
         } catch (IOException e) {
             e.printStackTrace();
         }
+        // parse json
         try {
             JSONObject json = new JSONObject( file );
             return parseNode( json, null );
@@ -57,24 +59,34 @@ public class Reader {
         LayeredGraphNode newNode = new LayeredNode( null, null );
         if( parent != null )
             newNode = parent.createNode( null );
+        
+        // dummy
         if( node.has( "dummy" ) && node.getBoolean( "dummy" ) )
         {
             newNode.setDummyNode( true );
         }
+        
+        // name
         if( node.has( "name" ) )
         {
             if( parent != null && parent.findNodeByName( node.getString( "name" ) ) != null )
                 throw new JSONException( "Node " + node.getString( "name" ) + " is already known" );
             newNode.setName( node.getString( "name" ) );
         }
+        
+        // width
         if( node.has( "width" ) )
             newNode.setWidth( node.getInt( "width" ), null );
         else
             newNode.setWidth( 40, null );
+        
+        // height
         if( node.has( "height" ) )
             newNode.setHeight( node.getInt( "height" ), null );
         else
             newNode.setHeight( 40, null );
+        
+        // layers
         if( node.has( "layers" ) )
         {
             JSONArray layers = node.getJSONArray( "layers" );
@@ -84,6 +96,8 @@ public class Reader {
                     n.setLayer( i );
             }
         }
+        
+        // edges
         if( node.has( "edges" ) )
         {
             JSONArray edges = node.getJSONArray( "edges" );
@@ -98,18 +112,24 @@ public class Reader {
 
     private LayeredGraphEdge parseEdge( JSONObject edge, LayeredGraphNode parent ) throws JSONException
     {
+        // check if attributes are available
         if( !edge.has( "source" ) || !edge.has( "target" ) )
             throw new JSONException( edge + " is not a valid LayeredGraphEdge." );
         if( parent.findNodeByName( edge.getString( "source" ) ) == null )
             throw new JSONException( edge + " is not a valid LayeredGraphEdge." );
         if( parent.findNodeByName( edge.getString( "target" ) ) == null )
             throw new JSONException( edge + " is not a valid LayeredGraphEdge." );
+        
+        // create the edges
         LayeredGraphEdge newEdge = parent.createSimpleEdge( null, parent.findNodeByName( edge.getString( "source" ) ), parent.findNodeByName( edge.getString( "target" ) ) );
         if( parent.findNodeByName( edge.getString( "source" ) ).isDummyNode() && parent.findNodeByName( edge.getString( "target" ) ).isDummyNode() )
             newEdge.setDummyEdge();
         return newEdge;
     }
 
+    /**
+     * parse a whole layer of nodes
+     */
     private ArrayList<LayeredGraphNode> parseLayer( JSONArray layer, LayeredGraphNode parent ) throws JSONException
     {
         ArrayList<LayeredGraphNode> nodes = new ArrayList<>();

+ 8 - 0
src/graph/io/Writer.java

@@ -46,6 +46,7 @@ public class Writer {
         JSONObject node = new JSONObject();
         JSONArray layers = new JSONArray();
         int id = 0;
+        // layers
         for( ArrayList<LayeredGraphNode> l : graph.getContainedLayers() )
         {
             JSONArray layer = new JSONArray();
@@ -57,15 +58,22 @@ public class Writer {
             layers.put( layer );
         }
         node.put( "layers", layers );
+        
+        // edges
         JSONArray edges = new JSONArray();
         for( LayeredGraphEdge e : graph.getContainedEdges() )
         {
             edges.put( parseEdge( e ) );
         }
         node.put( "edges", edges );
+        
+        // name
         node.put( "name", graph.toString() );
+        
+        // dummy
         if( graph.isDummyNode() )
             node.put( "dummy", "true" );
+        
         return node;
     }
     

+ 3 - 0
src/main/Main.java

@@ -17,9 +17,12 @@ public class Main {
      * @param args the command line arguments, currently not in use
      */
     public static void main(String[] args) {
+        // read a graph from a file
         Reader r = new Reader( "logo.json" );
         LayeredGraphNode graph = r.readInputGraph();
+        // compute some initial position for the graph
         SimpleNodePlacement.placeNodes( graph );
+        // create the view
         new MainView( graph );
     }
  

+ 18 - 0
src/processor/Action.java

@@ -9,10 +9,28 @@ package processor;
  *
  */
 public enum Action {
+    /**
+     *  step into in forwards direction
+     */
     FORWARD,
+    /**
+     *  step over in forwards direction
+     */
     FORWARD_OVER,
+    /**
+     *  step out in forwards direction
+     */
     FORWARD_OUT,
+    /**
+     *  step into in backwards direction
+     */
     BACKWARD,
+    /**
+     *  step over in backwards direction
+     */
     BACKWARD_OVER,
+    /**
+     *  step out in backwards direction
+     */
     BACKWARD_OUT
 }

+ 3 - 3
src/processor/ControlFlow.java

@@ -35,8 +35,8 @@ public class ControlFlow {
      */
     public ControlFlow( PseudoCodeNode functionNode )
     {
-    	status = CALL;
-    	function = functionNode;
+        status = CALL;
+        function = functionNode;
         jumpBack = null;
         reverse = null;
     }
@@ -69,7 +69,7 @@ public class ControlFlow {
     
     PseudoCodeNode getFunction()
     {
-    	return function;
+        return function;
     }
     
     int getStatus()

+ 40 - 18
src/processor/Memory.java

@@ -92,12 +92,14 @@ public class Memory {
         switch( visibility )
         {
         case GLOBAL:
+            // declare the variable in the global memory
             this.global.declare( name, value );
             break;
         case COMPLETE_STACK:
         case LOCAL:
-        	if( stack.size() == 0 )
-        		return;
+            if( stack.size() == 0 )
+                return;
+            // declare the variable in the topmost stack frame
             stack.peek().declare( name, value );
             break;
         default:
@@ -119,23 +121,26 @@ public class Memory {
         switch( visibility )
         {
         case GLOBAL:
+            // set the variable in the global memory
             this.global.set( name, value );
             break;
         case COMPLETE_STACK:
         case LOCAL:
-        	int index = stack.size() - 1;
-        	while( index >= 0 ) {
-        	   StackFrame stackF = stack.get( index-- );
-        	   if( stackF.isDefined( name ) )
-        	   {
-        		   stackF.set( name, value );
-        		   return;
-        	   }
-        	   if( stackF.getType() == FrameType.FUNCTION )
-        		   break;
-        	}
-        	break;
+            // search the stack of the current function for this variable
+            int index = stack.size() - 1;
+            while( index >= 0 ) {
+               StackFrame stackF = stack.get( index-- );
+               if( stackF.isDefined( name ) )
+               {
+                   stackF.set( name, value );
+                   return;
+               }
+               if( stackF.getType() == FrameType.FUNCTION )
+                   break;
+            }
+            break;
         default:
+            // should never happen
             assert false;
             break;
         }
@@ -154,8 +159,10 @@ public class Memory {
         switch( visibility )
         {
         case GLOBAL:
+            // read from global memory
             return this.global.get( name );
         case LOCAL:
+            // search the stack of this function
             while( index >= 0 ) {
                 StackFrame stackF = stack.get( index-- );
                 if( stackF.isDefined( name ) )
@@ -165,6 +172,7 @@ public class Memory {
              }
             break;
         case COMPLETE_STACK:
+            // search the complete stack
             while( index >= 0 ) {
                 StackFrame stackF = stack.get( index-- );
                 if( stackF.isDefined( name ) )
@@ -172,6 +180,7 @@ public class Memory {
              }
             break;
         default:
+            // should never happen
             assert false;
             break;
         }
@@ -191,8 +200,10 @@ public class Memory {
         switch( visibility )
         {
         case GLOBAL:
+            // search in global memory
             return this.global.isDefined( name );
         case LOCAL:
+            // search in the stack of the current function
             while( index >= 0 ) {
                 StackFrame stackF = stack.get( index-- );
                 if( stackF.isDefined( name ) )
@@ -202,6 +213,7 @@ public class Memory {
              }
             break;
         case COMPLETE_STACK:
+          // search the whole stack
             while( index >= 0 ) {
                 StackFrame stackF = stack.get( index-- );
                 if( stackF.isDefined( name ) )
@@ -209,9 +221,11 @@ public class Memory {
              }
             break;
         default:
+            // should never happen
+            assert false;
             break;
         }
-    	return false;
+        return false;
     }
     
     /**
@@ -226,16 +240,20 @@ public class Memory {
         switch( visibility )
         {
         case GLOBAL:
+            // search in global memory
             return this.global.isDefined( name );
         case COMPLETE_STACK:
         case LOCAL:
+            // search the stack
             if( stack.size() == 0 )
                 return false;
             return stack.peek().isDefined( name );
         default:
+            // should never happen
+            assert false;
             break;
         }
-    	return false;
+        return false;
     }
     
     
@@ -249,15 +267,19 @@ public class Memory {
         switch( visibility )
         {
         case GLOBAL:
+            // undeclare global variable
             this.global.undeclare( name );
             break;
         case COMPLETE_STACK:
         case LOCAL:
-        	if( stack.size() == 0 )
-        		return;
+            // undeclare local variable in topmost frame
+            if( stack.size() == 0 )
+                return;
             stack.peek().undeclare( name );
             break;
         default:
+            // should never happen
+            assert false;
             break;
         }
     }

+ 2 - 0
src/processor/ProcessController.java

@@ -42,12 +42,14 @@ public class ProcessController {
     {
         long old = lastTime;
         Action ret = null;
+        // wait until we know which action to do next
         synchronized( this ) {
             while( next == null )
                 wait();
             lastTime = System.currentTimeMillis();
             ret = next;
         }
+        // if we are in automatic execution mode, wait some time
         if( !continuous )
             next = null;
         else

+ 14 - 23
src/processor/PseudoCodeNode.java

@@ -51,7 +51,7 @@ public class PseudoCodeNode extends DefaultMutableTreeNode {
         super( TextLayoutHelper.setupPseudoCode( description, vars ) );
         synchronized( PseudoCodeNode.class )
         {
-        	nodeId = nextNodeId++;
+            nodeId = nextNodeId++;
         }
         selected = false;
         this.tree = tree;
@@ -70,6 +70,7 @@ public class PseudoCodeNode extends DefaultMutableTreeNode {
      */
     public void setController( ProcessController c )
     {
+        // set the controller of all children
         if( children != null )
         {
             for( Object ch : children )
@@ -77,6 +78,7 @@ public class PseudoCodeNode extends DefaultMutableTreeNode {
                 ((PseudoCodeNode)ch).setController( c );
             }
         }
+        // set own controller
         controller = c;
     }
     
@@ -105,27 +107,10 @@ public class PseudoCodeNode extends DefaultMutableTreeNode {
         return selected;
     }
     
-    /**
-     * checks if one of the subnodes of this node is selected.
-     * @return true if one is, false otherwise
-     */
-    public boolean hasSelectedSubnode()
-    {
-    	if( children != null )
-    	{
-	    	for( Object ch : children )
-	        {
-	            if( ((PseudoCodeNode)ch).isSelected() || ((PseudoCodeNode)ch).hasSelectedSubnode() )
-	            	return true;
-	        }
-    	}
-    	return false;
-    }
-    
     private void expandToRoot()
     {
-    	if( parent != null )
-    		((PseudoCodeNode)parent).expandToRoot();
+        if( parent != null )
+            ((PseudoCodeNode)parent).expandToRoot();
         tree.expandPath( new TreePath( this.getPath() ) );
     }
 
@@ -137,13 +122,16 @@ public class PseudoCodeNode extends DefaultMutableTreeNode {
      */
     public CodeAction setSelected( boolean selected )
     {
+        // breakpoint reached? then stop
         if( selected && breakPoint )
             controller.setContinuous( false );
+        
         this.selected = selected;
-        if( selected )
-        {
+        if( selected ) 
+        { // node has just been selected
             if( tree != null ) {
                 TreePath path = new TreePath( getPath() );
+                // check where the line is
                 Rectangle bounds = tree.getPathBounds(path);
                 if( bounds!= null )
                 {
@@ -152,6 +140,7 @@ public class PseudoCodeNode extends DefaultMutableTreeNode {
                     SwingUtilities.invokeLater( new Runnable() {
                         @Override
                         public void run() {
+                            // scroll to the code line
                             tree.scrollRectToVisible(bounds);
                         }
                     });
@@ -162,13 +151,14 @@ public class PseudoCodeNode extends DefaultMutableTreeNode {
                 SwingUtilities.invokeLater( new Runnable() {
                     @Override
                     public void run() {
+                        // expand everything up to this line
                         expandToRoot();
                     }
                 });
             }
         }
         else
-        {
+        { // selection was removed
             if( controller != null && controller.getAutoCollapseOption() == 1 )
             {
                 SwingUtilities.invokeLater( new Runnable() {
@@ -222,6 +212,7 @@ public class PseudoCodeNode extends DefaultMutableTreeNode {
      */
     public ControlFlow emptyForwardStep( Memory m )
     {
+        // add an action to undo the step (empty backwards action)
         code.createEmptyBackwardsAction();
         ControlFlow cf = new ControlFlow( ControlFlow.STEP_OVER );
         cf.setJumpBack( this );

+ 89 - 43
src/processor/PseudoCodeProcessor.java

@@ -42,7 +42,7 @@ public class PseudoCodeProcessor extends Thread {
     private boolean renderImage = true;
     private JFrame view;
     private ProcessController controller;
-    private boolean insideNotSkipLoop = false; // needet to avoid stack overflow errors
+    private boolean insideNotSkipLoop = false; // needed to avoid stack overflow errors
     
     /**
      * creates a new {@link PseudoCodeProcessor}
@@ -65,30 +65,57 @@ public class PseudoCodeProcessor extends Thread {
     
     public ProcessController getController()
     {
-    	return controller;
+        return controller;
     }
     
     private CodeStatus selectNextNode( PseudoCodeNode next, PseudoCodeNode last )
     {
         programPointer = next;
         last.setSelected( false );
-        switch( next.setSelected( true ) )
-        {
+        switch( next.setSelected( true ) ) // check which node should be executed next
+        { 
         case CONTINUE:
+            // just do the next step
             skip = false;
             return CodeStatus.UNFINISHED;
         case SKIP:
+            // node is folded so it is skipped
             skip = true;
             if( insideNotSkipLoop )
                 return CodeStatus.UNFINISHED;
             return forwardStepOverUntilNotSkip();
         case STOP:
+            // a breakpoint was reached
             skip = false;
             return CodeStatus.BREAKPOINT;
         default:
-            break;
+            return CodeStatus.UNFINISHED;
+        }
+    }
+    
+    private CodeStatus selectBeforeNode( PseudoCodeNode next, PseudoCodeNode last )
+    {
+        programPointer = next;
+        last.setSelected( false );
+        switch( next.setSelected( true ) ) // check which node should be executed next
+        {
+        case CONTINUE:
+            // just do the previous step
+            skip = false;
+            return CodeStatus.UNFINISHED;
+        case SKIP:
+            // node is folded so it is skipped
+            skip = true;
+            if( insideNotSkipLoop )
+                return CodeStatus.UNFINISHED;
+            return backwardStepOverUntilNotSkip();
+        case STOP:
+            // a breakpoint was reached
+            skip = false;
+            return CodeStatus.BREAKPOINT;
+        default:
+            return CodeStatus.UNFINISHED;
         }
-        return CodeStatus.UNFINISHED;
     }
     
     /**
@@ -97,11 +124,16 @@ public class PseudoCodeProcessor extends Thread {
      */
     protected CodeStatus forwardStep()
     {
+        // is the program pointer still available?
         if( programPointer == null )
             return CodeStatus.FINISHED;
+        
+        // read topmost stack frame
         StackFrame before = mem.removeFrame();
         mem.addFrame( before );
         ControlFlow cf = null;
+        
+        // remember if this node has already been called
         if( mem.isDefined( "_call" + programPointer.getId(), Visibility.LOCAL ) )
         {
             String name = "_call" + programPointer.getId();
@@ -113,11 +145,16 @@ public class PseudoCodeProcessor extends Thread {
         }
         else
             cf = programPointer.forwardStep( mem );
+        // remember all ControlFlow actions that have been done to be able to undo it later
         controlStack.push( cf );
+        
+        // get the debug output
         currentDebugOutput = programPointer.getDebugOutput( mem );
+        
         switch( cf.getStatus() )
-        {
+        { // we are doing a "step into"
         case ControlFlow.STEP_INTO:
+            // remember current line to be able to jump back to
             if( mem.isDefined( "_returnTo" + programPointer.getId(), Visibility.GLOBAL ) )
             {
                 String name = "_returnTo" + programPointer.getId();
@@ -132,9 +169,10 @@ public class PseudoCodeProcessor extends Thread {
                 throw new IllegalStateException( "A Codeline without sublines tried to make a STEP_INTO." );
             else
                 return selectNextNode( (PseudoCodeNode)programPointer.getFirstChild(), programPointer );
-        case ControlFlow.STEP_OVER:
+        case ControlFlow.STEP_OVER: // we are doing a "step over"
             if( programPointer.getParent() == null )
                 return CodeStatus.FINISHED;
+            // remember current line to be able to jump back to
             if( before.isDefined( "_returnTo" + programPointer.getId() ) )
             {
                 String name = "_returnTo" + programPointer.getId();
@@ -143,15 +181,18 @@ public class PseudoCodeProcessor extends Thread {
                 cf.setBackwardAction( (Memory m) -> {
                     before.declare( name, nextPC );
                 });
+                // continue with next node
                 return selectNextNode( nextPC, programPointer );
             }
+            // update program pointer
             PseudoCodeNode nextPC = (PseudoCodeNode) ((PseudoCodeNode)programPointer.getParent()).getChildAfter( programPointer );
             if( nextPC == null )
                 return selectNextNode( (PseudoCodeNode)programPointer.getParent(), programPointer );
             else
                 return selectNextNode( nextPC, programPointer );
-        case ControlFlow.CALL:
+        case ControlFlow.CALL: // we are doing a function call
             PseudoCodeNode f = cf.getFunction();
+            // remember current line to be able to jump back to
             String name = "_call" + programPointer.getId();
             mem.declare( name, true, Visibility.LOCAL );
             mem.declare( "_returnTo" + f.getId(), cf.getJumpBack(), Visibility.GLOBAL );
@@ -159,17 +200,19 @@ public class PseudoCodeProcessor extends Thread {
                 m.undeclare( "_returnTo" + f.getId(), Visibility.GLOBAL );
                 m.undeclare( name, Visibility.LOCAL );
             });
+            // go to next node
             return selectNextNode( f, programPointer );
         default:
-            break;
+            throw new IllegalStateException( "Unknown ControlFlow action" );
         }
-        throw new IllegalStateException( "Unknown ControlFlow action" );
     }
     
     private CodeStatus forwardStepOverUntilNotSkip() {
+        // is the program pointer still available?
         if( programPointer == null )
             return CodeStatus.FINISHED;
         CodeStatus status = CodeStatus.UNFINISHED;
+        // perform steps until someone sets skip to false
         do {
             insideNotSkipLoop = true;
             status = forwardStep();
@@ -180,10 +223,13 @@ public class PseudoCodeProcessor extends Thread {
     
     protected CodeStatus forwardStepOver()
     {
+        // is the program pointer still available?
         if( programPointer == null )
             return CodeStatus.FINISHED;
+        // remember stack size
         int stackSize = mem.getSize();
         CodeStatus status = CodeStatus.UNFINISHED;
+        // perform steps until we arrive at the same stack size again
         do {
             status = forwardStep();
         } while( mem.getSize() > stackSize && status == CodeStatus.UNFINISHED );
@@ -192,39 +238,23 @@ public class PseudoCodeProcessor extends Thread {
     
     protected CodeStatus forwardStepOut()
     {
+        // is the program pointer still available?
         if( programPointer == null )
             return CodeStatus.FINISHED;
+        // remember stack size
         int stackSize = mem.getSize();
         CodeStatus status = CodeStatus.UNFINISHED;
+        // perform steps until we arrive at a smaller stack size
         do {
             status = forwardStep();
         } while( mem.getSize() >= stackSize && status == CodeStatus.UNFINISHED );
         return status;
     }
     
-    private CodeStatus selectBeforeNode( PseudoCodeNode next, PseudoCodeNode last )
-    {
-        programPointer = next;
-        last.setSelected( false );
-        switch( next.setSelected( true ) )
-        {
-        case CONTINUE:
-            skip = false;
-            return CodeStatus.UNFINISHED;
-        case SKIP:
-            skip = true;
-            if( insideNotSkipLoop )
-                return CodeStatus.UNFINISHED;
-            return backwardStepOverUntilNotSkip();
-        case STOP:
-            skip = false;
-            return CodeStatus.BREAKPOINT;
-        default:
-            break;
-        }
-        return CodeStatus.UNFINISHED;
-    }
-    
+    /**
+     * returns the program pointer of the previous step
+     * @return the node that was previously executed
+     */
     protected PseudoCodeNode getLastProgramPointer() {
         if( controlStack.isEmpty() )
             return null;
@@ -233,21 +263,28 @@ public class PseudoCodeProcessor extends Thread {
     
     protected CodeStatus backwardStep()
     {
+        // check if we arrived at the beginning
         if( controlStack.isEmpty() )
             return CodeStatus.FINISHED;
+        // what did we do before?
         ControlFlow cf = controlStack.pop();
+        // where where we before?
         PseudoCodeNode nextPC = cf.getJumpBack();
+        // undo action
         cf.backward( mem );
         nextPC.backwardStep( mem );
+        
         currentDebugOutput = nextPC.getDebugOutput( mem );
         return selectBeforeNode( nextPC, programPointer );
     }
     
     private CodeStatus backwardStepOverUntilNotSkip()
     {
+        // check if we arrived at the beginning
         if( programPointer == null )
             return CodeStatus.FINISHED;
         CodeStatus status = CodeStatus.UNFINISHED;
+        // perform steps until someone sets skip to false
         do {
             insideNotSkipLoop = true;
             status = backwardStep();
@@ -258,10 +295,13 @@ public class PseudoCodeProcessor extends Thread {
     
     protected CodeStatus backwardStepOver()
     {
+        // check if we arrived at the beginning
         if( programPointer == null )
             return CodeStatus.FINISHED;
+        
         int stackSize = mem.getSize();
         CodeStatus status = CodeStatus.UNFINISHED;
+        // perform steps until we arrrive at the same stack size again
         do {
             status = backwardStep();
         } while( mem.getSize() > stackSize && status == CodeStatus.UNFINISHED );
@@ -270,10 +310,13 @@ public class PseudoCodeProcessor extends Thread {
     
     protected CodeStatus backwardStepOut()
     {
+        // check if we arrived at the beginning
         if( programPointer == null )
             return CodeStatus.FINISHED;
+        
         int stackSize = mem.getSize();
         CodeStatus status = CodeStatus.UNFINISHED;
+        // perform steps until we arrrive at a smaller stack size
         do {
             status = backwardStep();
         } while( mem.getSize() >= stackSize && status == CodeStatus.UNFINISHED );
@@ -305,14 +348,14 @@ public class PseudoCodeProcessor extends Thread {
     {
         while( true ) // if this loop would end we could not undo steps any more
         {
-        	CodeStatus status = null;
+            CodeStatus status = null;
             try {
-                Action action = controller.getNextAction();
-                graph.unselectGraph();
-                switch( action )
+                Action action = controller.getNextAction(); // what action is next?
+                graph.unselectGraph(); // remove selection from any nodes in the graph
+                switch( action ) // perform the action
                 {
                 case FORWARD:
-                	status = forwardStep();
+                    status = forwardStep();
                     break;
                 case FORWARD_OUT:
                     status = forwardStepOut();
@@ -341,11 +384,14 @@ public class PseudoCodeProcessor extends Thread {
                 e.printStackTrace();
                 return;
             }
-            update();
-            if( status == CodeStatus.FINISHED )
+            
+            // update the drawing
+            update(); 
+            
+            if( status == CodeStatus.FINISHED ) // stop at the end
             {
-            	controller.setContinuous( false );
-            	controller.setNextAction( null );
+                controller.setContinuous( false );
+                controller.setNextAction( null );
             }
         }
     }

+ 7 - 7
src/processor/StackFrame.java

@@ -15,23 +15,23 @@ public class StackFrame {
      * @author kolja
      *
      */
-	public enum FrameType {
-		FUNCTION,
-		LOOP
-	}
-	
+    public enum FrameType {
+        FUNCTION,
+        LOOP
+    }
+
     private HashMap< String, Object > data;
     private FrameType type;
     
     public StackFrame( FrameType type )
     {
-    	this.type = type;
+        this.type = type;
         data = new HashMap< String, Object >();
     }
     
     public FrameType getType()
     {
-    	return type;
+        return type;
     }
     
     /**

+ 1 - 1
src/view/PseudoCodeLines.java

@@ -128,7 +128,7 @@ public class PseudoCodeLines extends JComponent implements MouseListener{
             Rectangle rect = tree.getRowBounds( i );
             String text = String.valueOf( number );
             int yPosition = rect.y + rect.height / 2 + 4;
-            if( !node.hasSelectedSubnode() && node.isSelected() )
+            if( node.isSelected() )
                 g.drawImage( currentLine.getImage(), HORIZONTAL_PADDING, rect.y + rect.height / 2 - 10, 20, 20, null );
             g2d.drawString( text, HORIZONTAL_PADDING * 2 + 20, yPosition );
             if( node.hasBreakPoint() )