Browse Source

Merge remote-tracking branch 'origin/master'

Eren Yilmaz 7 years ago
parent
commit
b51df1e421

+ 5 - 1
src/animation/Action.java

@@ -10,5 +10,9 @@ package animation;
  */
 public enum Action {
 	FORWARD,
-	BACKWARD
+	FORWARD_OVER,
+	FORWARD_OUT,
+	BACKWARD,
+	BACKWARD_OVER,
+	BACKWARD_OUT
 }

+ 2 - 0
src/animation/AlgorithmStage.java

@@ -34,4 +34,6 @@ public interface AlgorithmStage {
      * For example if all steps are reverted, then {@code FINISHED} is returned.
      */
 	public StageStatus backwardStep();
+	
+    public PseudoCodeNode createPseudocodeTree();
 }

+ 12 - 0
src/animation/AnimatedAlgorithm.java

@@ -25,10 +25,20 @@ public abstract class AnimatedAlgorithm extends Thread implements AlgorithmStage
 					System.out.println( "FORWARD" );
 					forwardStep();
 					break;
+                case FORWARD_OUT:
+                    break;
+                case FORWARD_OVER:
+                    break;
 				case BACKWARD:
 					System.out.println( "BACKWARD" );
 					backwardStep();
 					break;
+                case BACKWARD_OUT:
+                    break;
+                case BACKWARD_OVER:
+                    break;
+                default:
+                    break;
 				}
 			} catch (InterruptedException e) {
 				e.printStackTrace();
@@ -37,4 +47,6 @@ public abstract class AnimatedAlgorithm extends Thread implements AlgorithmStage
 			
 		}
 	}
+	
+    public abstract PseudoCodeNode createPseudocodeTree();
 }

+ 36 - 0
src/animation/PseudoCodeNode.java

@@ -0,0 +1,36 @@
+package animation;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.TreePath;
+
+import view.MainView;
+
+public class PseudoCodeNode extends DefaultMutableTreeNode {
+
+    /**
+     * 
+     */
+    private static final long serialVersionUID = 1L;
+    
+    private boolean selected;
+    
+    public PseudoCodeNode( String description )
+    {
+        super( description );
+        selected = false;
+    }
+    
+    public boolean isSelected()
+    {
+        return selected;
+    }
+    
+    public void setSelected( boolean selected )
+    {
+        if( selected )
+            MainView.pseudoTree.expandPath( new TreePath( this.getPath() ) );
+        else
+            MainView.pseudoTree.collapsePath( new TreePath( this.getPath() ) );
+        this.selected = selected;
+    }
+}

+ 70 - 4
src/bk/BKNodePlacement.java

@@ -3,6 +3,7 @@ package bk;
 import animation.AlgorithmStage;
 import animation.AnimatedAlgorithm;
 import animation.AnimationController;
+import animation.PseudoCodeNode;
 import graph.LayeredGraphNode;
 
 /**
@@ -30,6 +31,12 @@ public class BKNodePlacement extends AnimatedAlgorithm {
 	private State state;
 	private ExtremalLayoutCalc layouts[];
 	private Combine combine;
+    private PseudoCodeNode conflictsNode; 
+    private PseudoCodeNode layout1Node;
+    private PseudoCodeNode layout2Node;
+    private PseudoCodeNode layout3Node;
+    private PseudoCodeNode layout4Node;
+    private PseudoCodeNode combineNode;
 	
 	public BKNodePlacement(AnimationController controller, LayeredGraphNode graph) {
 		super(controller, graph);
@@ -48,24 +55,45 @@ public class BKNodePlacement extends AnimatedAlgorithm {
 		switch( state )
 		{
 		case CONFLICTS:
+		    conflictsNode.setSelected( true );
 			if( conftion.forwardStep() == StageStatus.FINISHED )
+			{
+	            conflictsNode.setSelected( false );
+	            layout1Node.setSelected( true );
 				state = State.LAYOUT1;
+			}
 			break;
 		case LAYOUT1:
-			if( layouts[ 0 ].forwardStep() == AlgorithmStage.StageStatus.FINISHED )
+			if( layouts[ 0 ].forwardStep() == StageStatus.FINISHED )
+			{
+	            layout1Node.setSelected( false );
+	            layout2Node.setSelected( true );
 				state = State.LAYOUT2;
+			}
 			break;
 		case LAYOUT2:
-			if( layouts[ 1 ].forwardStep() == AlgorithmStage.StageStatus.FINISHED )
+			if( layouts[ 1 ].forwardStep() == StageStatus.FINISHED )
+			{
+	            layout2Node.setSelected( false );
+                layout3Node.setSelected( true );
 				state = State.LAYOUT3;
+			}
 			break;
 		case LAYOUT3:
-			if( layouts[ 2 ].forwardStep() == AlgorithmStage.StageStatus.FINISHED )
+			if( layouts[ 2 ].forwardStep() == StageStatus.FINISHED )
+			{
+                layout3Node.setSelected( false );
+                layout4Node.setSelected( true );
 				state = State.LAYOUT4;
+			}
 			break;
 		case LAYOUT4:
-			if( layouts[ 3 ].forwardStep() == AlgorithmStage.StageStatus.FINISHED )
+			if( layouts[ 3 ].forwardStep() == StageStatus.FINISHED )
+			{
+	            layout4Node.setSelected( false );
+                combineNode.setSelected( true );
 				state = State.COMBINE;
+			}
 			break;
 		case COMBINE:
 			return combine.forwardStep();
@@ -81,25 +109,63 @@ public class BKNodePlacement extends AnimatedAlgorithm {
 			return conftion.backwardStep();
 		case LAYOUT1:
 			if( layouts[ 0 ].backwardStep() == StageStatus.FINISHED )
+			{
+	            layout1Node.setSelected( false );
+	            conflictsNode.setSelected( true );
 				state = State.CONFLICTS;
+			}
 			break;
 		case LAYOUT2:
 			if( layouts[ 1 ].backwardStep() == AlgorithmStage.StageStatus.FINISHED )
+			{
+	            layout2Node.setSelected( false );
+	            layout1Node.setSelected( true );
 				state = State.LAYOUT1;
+			}
 			break;
 		case LAYOUT3:
 			if( layouts[ 2 ].backwardStep() == AlgorithmStage.StageStatus.FINISHED )
+			{
+	            layout3Node.setSelected( false );
+	            layout2Node.setSelected( true );
 				state = State.LAYOUT2;
+			}
 			break;
 		case LAYOUT4:
 			if( layouts[ 3 ].backwardStep() == AlgorithmStage.StageStatus.FINISHED )
+			{
+                layout4Node.setSelected( false );
+                layout3Node.setSelected( true );
 				state = State.LAYOUT3;
+			}
 			break;
 		case COMBINE:
 			if( combine.backwardStep() == AlgorithmStage.StageStatus.FINISHED )
+			{
+	            combineNode.setSelected( false );
+	            layout4Node.setSelected( true );
 				state = State.LAYOUT4;
+			}
 			break;
 		}
 		return StageStatus.UNFINISHED;
 	}
+	
+	public PseudoCodeNode createPseudocodeTree()
+	{
+	    PseudoCodeNode root = new PseudoCodeNode( "BK Node Placement Algorithm" );
+        conflictsNode = conftion.createPseudocodeTree();
+        layout1Node = layouts[ 0 ].createPseudocodeTree();
+        layout2Node = layouts[ 1 ].createPseudocodeTree();
+        layout3Node = layouts[ 2 ].createPseudocodeTree();
+        layout4Node = layouts[ 3 ].createPseudocodeTree();
+        combineNode = combine.createPseudocodeTree();
+        root.add( conflictsNode );
+        root.add( layout1Node );
+        root.add( layout2Node );
+        root.add( layout3Node );
+        root.add( layout4Node );
+        root.add( combineNode );
+        return root;
+	}
 }

+ 18 - 0
src/bk/BlockCalc.java

@@ -6,6 +6,7 @@ import java.util.Collections;
 
 import animation.AlgorithmStage;
 import animation.BackwardAction;
+import animation.PseudoCodeNode;
 import bk.ExtremalLayoutCalc.LayoutType;
 import graph.LayeredGraphEdge;
 import graph.LayeredGraphNode;
@@ -24,6 +25,7 @@ public class BlockCalc implements AlgorithmStage {
 	private ArrayList< ArrayList< ExtremalLayoutCalc > > subgraphAlgs;
 	private ArrayList< BackwardAction > backwards; // TODO: evtl richtigen "Stack" benutzen
 	private LayoutType layout;
+	private PseudoCodeNode loopNode;
 	int step;
 	
 	public BlockCalc( LayeredGraphNode graph, LayoutType layout )
@@ -166,10 +168,14 @@ public class BlockCalc implements AlgorithmStage {
 	
 	private StageStatus calcNextState()
 	{
+        loopNode.setSelected( true );
 		if( layerIndex >= graph.getContainedLayers().size() - 1 )
 		{
 			if( nodeIndex >= graph.getContainedLayers().get( calcLayerIndex() ).size() -1 )
+			{
+                loopNode.setSelected( false );
 				return StageStatus.FINISHED;
+			}
 		}
 		nodeIndex++;
 		if( nodeIndex >= graph.getContainedLayers().get( calcLayerIndex() ).size() )
@@ -213,10 +219,14 @@ public class BlockCalc implements AlgorithmStage {
 	
 	private StageStatus calcBeforeState()
 	{
+	    loopNode.setSelected( true );
 		if( layerIndex == 0 )
 		{
 			if( nodeIndex == 0 )
+			{
+		        loopNode.setSelected( false );
 				return StageStatus.FINISHED;
+			}	
 		}
 		nodeIndex--;
 		if( nodeIndex < 0 )
@@ -228,4 +238,12 @@ public class BlockCalc implements AlgorithmStage {
 		}
 		return StageStatus.UNFINISHED;
 	}
+
+    @Override
+    public PseudoCodeNode createPseudocodeTree() {
+        PseudoCodeNode root = new PseudoCodeNode( "Berechne den Block Graph" );
+        loopNode = new PseudoCodeNode( "Loop durch alle Knoten..." );
+        root.add( loopNode );
+        return root;
+    }
 }

+ 27 - 0
src/bk/Combine.java

@@ -6,6 +6,7 @@ import java.util.Collections;
 
 import animation.AlgorithmStage;
 import animation.BackwardAction;
+import animation.PseudoCodeNode;
 import bk.ExtremalLayoutCalc.LayoutType;
 import graph.LayeredGraphNode;
 import view.MainView;
@@ -32,6 +33,9 @@ public class Combine implements AlgorithmStage {
 	private int tbrOffset;
 	private int vIndex;
 	private ArrayList< BackwardAction > actions;
+    private PseudoCodeNode alignNode;
+    private PseudoCodeNode setNode;
+    private PseudoCodeNode loopNode;
 	
 	public Combine( LayeredGraphNode graph )
 	{
@@ -45,6 +49,7 @@ public class Combine implements AlgorithmStage {
 	public StageStatus forwardStep() {
 		if( state == State.ALIGN )
 		{
+		    alignNode.setSelected( true );
 			int tblw = (int)graph.getWidth( LayoutType.TOP_BOTTOM_LEFT );
 			int tbrw = (int)graph.getWidth( LayoutType.TOP_BOTTOM_RIGHT );
 			int btlw = (int)graph.getWidth( LayoutType.BOTTOM_TOP_LEFT );
@@ -75,17 +80,26 @@ public class Combine implements AlgorithmStage {
 			MainView.frame.setSize( MainView.frame.getWidth() + 1, MainView.frame.getHeight() );
 			MainView.frame.setSize( MainView.frame.getWidth() - 1, MainView.frame.getHeight() );
 			actions.add( 0, () -> {
+	            setNode.setSelected( false );
+                alignNode.setSelected( true );
 				state = State.ALIGN;
 				graph.setColor( null, null );
 				MainView.frame.setSize( MainView.frame.getWidth() + 1, MainView.frame.getHeight() );
 				MainView.frame.setSize( MainView.frame.getWidth() - 1, MainView.frame.getHeight() );
 			});
 			state = State.SET_COORDINATES;
+            alignNode.setSelected( false );
+            setNode.setSelected( true );
+            loopNode.setSelected( true );
 		}
 		else
 		{
 			if( vIndex >= graph.getContainedNodes().size() )
+			{
+			    setNode.setSelected( false );
+			    loopNode.setSelected( false );
 				return StageStatus.FINISHED;
+			}
 			LayeredGraphNode current = graph.getContainedNodes().get( vIndex );
 			current.setSelected( null );
 			ArrayList< Integer > positions = new ArrayList<>();
@@ -97,6 +111,8 @@ public class Combine implements AlgorithmStage {
 			int oldX = (int)current.getX( LayoutType.COMBINED );
 			current.setX( (positions.get( 1 ) + positions.get( 2 )) / 2, true, LayoutType.COMBINED );
 			actions.add( 0, () -> {
+                setNode.setSelected( true );
+                loopNode.setSelected( true );
 				vIndex--;
 				current.setX( oldX, true, LayoutType.COMBINED );
 				current.setSelected( null );
@@ -125,4 +141,15 @@ public class Combine implements AlgorithmStage {
 		return StageStatus.UNFINISHED;
 	}
 
+    @Override
+    public PseudoCodeNode createPseudocodeTree() {
+        PseudoCodeNode root = new PseudoCodeNode( "Berechne das durchschnittliche Layout" );
+        alignNode = new PseudoCodeNode( "Align Layouts" );
+        setNode = new PseudoCodeNode( "Setze Koordinaten auf Mittelwert" );
+        loopNode = new PseudoCodeNode( "Loop durch alle Knoten");
+        setNode.add( loopNode );
+        root.add( alignNode );
+        root.add( setNode );
+        return root;
+    }
 }

+ 39 - 0
src/bk/Compaction.java

@@ -4,6 +4,7 @@ import java.util.ArrayList;
 
 import animation.AlgorithmStage;
 import animation.BackwardAction;
+import animation.PseudoCodeNode;
 import bk.ExtremalLayoutCalc.LayoutType;
 import graph.LayeredGraphNode;
 
@@ -34,6 +35,11 @@ public class Compaction implements AlgorithmStage{
 	private ArrayList< StackFrame > stack; // TODO: evtl richtigen "Stack" benutzen
 	private ArrayList< BackwardAction > actions; // TODO: evtl richtigen "Stack" benutzen
 	private LayoutType layout;
+	private PseudoCodeNode placeNode;
+    private PseudoCodeNode placeLoopNode;
+    private PseudoCodeNode applyNode;
+    private PseudoCodeNode applyLoopNode;
+	
 	
 	public Compaction( LayeredGraphNode graph, LayoutType layout )
 	{
@@ -75,6 +81,8 @@ public class Compaction implements AlgorithmStage{
 		int acSize = actions.size();
 		if( state == CompactionState.PLACE_BLOCKS ) // blöcke platzieren
 		{
+		    placeNode.setSelected( true );
+		    placeLoopNode.setSelected( true );
 			if( stack.size() == 0 ) // äußere schleife, placeblocks bisher nicht aufgerufen
 			{
 				ArrayList< LayeredGraphNode > nodes = graph.getContainedNodes();
@@ -95,9 +103,17 @@ public class Compaction implements AlgorithmStage{
 				if( !found )
 				{
 				    // wechsele in die phase des Blöckeshiftens
+		            placeNode.setSelected( false );
+		            placeLoopNode.setSelected( false );
+		            applyNode.setSelected( true );
+		            applyLoopNode.setSelected( true );
 					state = CompactionState.APPLY_SHIFT;
 					vIndex = 0;
 					actions.add( 0, ()-> {
+	                    applyNode.setSelected( false );
+	                    applyLoopNode.setSelected( false );
+                        placeNode.setSelected( true );
+                        placeLoopNode.setSelected( true );
 						vIndex = oldVIndex;
 						state = CompactionState.PLACE_BLOCKS;
 					} );
@@ -261,13 +277,19 @@ public class Compaction implements AlgorithmStage{
 			if( v == v.getRoot( layout ) && v.getSink( layout ).getShift( layout ) < Double.POSITIVE_INFINITY )
 				v.setX( v.getX( layout ) + v.getSink( layout ).getShift( layout ), true, layout );
 			actions.add( 0, ()-> {
+                applyNode.setSelected( true );
+                applyLoopNode.setSelected( true );
 				v.setX( oldX, oldDef, layout );
 				v.setSelected( layout );
 				vIndex--;
 			} );
 			vIndex++;
 			if( vIndex >= graph.getContainedNodes().size() )
+			{
+                applyNode.setSelected( false );
+                applyLoopNode.setSelected( false );
 				return StageStatus.FINISHED;
+			}
 		}
 		if( actions.size() != acSize + 1 )
 			System.out.println( "ERROR" );
@@ -277,10 +299,27 @@ public class Compaction implements AlgorithmStage{
 	@Override
 	public StageStatus backwardStep() {
 		if( actions.size() == 0 )
+		{
+            placeNode.setSelected( false );
+            placeLoopNode.setSelected( false );
 			return StageStatus.FINISHED;
+		}
 		actions.get( 0 ).reverse();
 		actions.remove( 0 );
 		return StageStatus.UNFINISHED;
 	}
 
+    @Override
+    public PseudoCodeNode createPseudocodeTree() {
+        PseudoCodeNode root = new PseudoCodeNode( "Plaziere die Knoten" );
+        placeNode = new PseudoCodeNode( "Berechne die Klasen und Plaziere sie" );
+        placeLoopNode = new PseudoCodeNode( "Loop durch alle Wurzelknoten..." );
+        placeNode.add( placeLoopNode );
+        applyNode = new PseudoCodeNode( "Shift anwenden" );
+        applyLoopNode = new PseudoCodeNode( "Loop durch alle Knoten..." );
+        applyNode.add( applyLoopNode );
+        root.add( placeNode );
+        root.add( applyNode );
+        return root;
+    }
 }

+ 24 - 0
src/bk/ConflictDetection.java

@@ -4,6 +4,7 @@ import java.util.ArrayList;
 
 import animation.AlgorithmStage;
 import animation.BackwardAction;
+import animation.PseudoCodeNode;
 import graph.LayeredGraphEdge;
 import graph.LayeredGraphNode;
 
@@ -14,6 +15,7 @@ public class ConflictDetection implements AlgorithmStage {
     
     private int i;
     private int l1;
+    private PseudoCodeNode markNode;
     
     ConflictDetection( LayeredGraphNode graph )
     {
@@ -27,8 +29,14 @@ public class ConflictDetection implements AlgorithmStage {
     public StageStatus forwardStep() {
     	int oldI = i;
     	int oldL1 = l1;
+    	((PseudoCodeNode)markNode.getParent()).setSelected( true );
+    	markNode.setSelected( true );
     	if( i + 1 >= graph.getContainedLayers().size() - 1 )
+    	{
+            ((PseudoCodeNode)markNode.getParent()).setSelected( false );
+            markNode.setSelected( false );
     		return StageStatus.FINISHED;
+    	}
     	LayeredGraphNode curr = graph.getContainedLayers().get( i + 1 ).get( l1 );
     	curr.setSelected( null );
     	ArrayList< LayeredGraphEdge > edges = curr.getIncomingEdges();
@@ -93,10 +101,26 @@ public class ConflictDetection implements AlgorithmStage {
 
     @Override
     public StageStatus backwardStep() {
+        ((PseudoCodeNode)markNode.getParent()).setSelected( true );
+        markNode.setSelected( true );
         if( actions.size() == 0 )
+        {
+            ((PseudoCodeNode)markNode.getParent()).setSelected( false );
+            markNode.setSelected( false );
         	return StageStatus.FINISHED;
+        }
         actions.get( 0 ).reverse();
         actions.remove( 0 );
         return StageStatus.UNFINISHED;
     }
+
+    @Override
+    public PseudoCodeNode createPseudocodeTree() {
+        PseudoCodeNode root = new PseudoCodeNode( "Markiere alle Konflikte mit inneren Kantensegmenten" );
+        PseudoCodeNode loopNode = new PseudoCodeNode( "Loop durch alle Knoten" );
+        markNode = new PseudoCodeNode( "Wenn eine eingehende Kante aus einem Inneren segmen existiert, markiere alle anderen Kanten die diese Kreuzen als Conflicted" );
+        loopNode.add( markNode );
+        root.add( loopNode );
+        return root;
+    }
 }

+ 35 - 2
src/bk/ExtremalLayoutCalc.java

@@ -1,6 +1,7 @@
 package bk;
 
 import animation.AlgorithmStage;
+import animation.PseudoCodeNode;
 import graph.LayeredGraphNode;
 
 /**
@@ -24,9 +25,12 @@ public class ExtremalLayoutCalc implements AlgorithmStage {
 		COMPACTION
 	}
 	
+	private PseudoCodeNode pseudoCode;
 	private BlockCalc bc;
 	private Compaction cp;
 	private LayoutState status;
+	private PseudoCodeNode bcNode;
+	private PseudoCodeNode cpNode;
 	
 	
 	public ExtremalLayoutCalc( LayoutType typ, LayeredGraphNode graph )
@@ -40,27 +44,56 @@ public class ExtremalLayoutCalc implements AlgorithmStage {
 	public StageStatus forwardStep() {
 		if( status == LayoutState.BLOCK_CALCULATION )
 		{
+		    bcNode.setSelected( true );
 			if( bc.forwardStep() == StageStatus.FINISHED )
 			{
+	            bcNode.setSelected( false );
+	            cpNode.setSelected( true );
 				status = LayoutState.COMPACTION;
 			}
 			return StageStatus.UNFINISHED;
 		}
 		if( status == LayoutState.COMPACTION )
-			return cp.forwardStep();
+		{
+			if( cp.forwardStep() == StageStatus.FINISHED )
+			{
+			    cpNode.setSelected( false );
+			    return StageStatus.FINISHED;
+			}
+		}
 		return StageStatus.UNFINISHED;
 	}
 
 	@Override
 	public StageStatus backwardStep() {
 		if( status == LayoutState.BLOCK_CALCULATION )
-			return bc.backwardStep();
+		{
+            bcNode.setSelected( true );
+			if( bc.backwardStep() == StageStatus.FINISHED )
+			{
+	            bcNode.setSelected( false );
+                return StageStatus.FINISHED;
+			}
+		}
 		if( status == LayoutState.COMPACTION )
 		{
+            cpNode.setSelected( true );
 			if( cp.backwardStep() == StageStatus.FINISHED )
+			{
+	            cpNode.setSelected( false );
 				status = LayoutState.BLOCK_CALCULATION;
+			}
 		}
 		return StageStatus.UNFINISHED;
 	}
 
+    @Override
+    public PseudoCodeNode createPseudocodeTree() {
+        pseudoCode = new PseudoCodeNode( "Berechne extremes Layout" );
+        bcNode = bc.createPseudocodeTree();
+        cpNode = cp.createPseudocodeTree();
+        pseudoCode.add( bcNode );
+        pseudoCode.add( cpNode );
+        return pseudoCode;
+    }
 }

BIN
src/images/debug.png


BIN
src/images/pause.png


BIN
src/images/runBackward.png


BIN
src/images/runForward.png


BIN
src/images/stepBackward.png


BIN
src/images/stepBackwardOut.png


BIN
src/images/stepForward.png


BIN
src/images/stepForwardInto.png


BIN
src/images/stepForwardOut.png


+ 212 - 4
src/view/MainView.java

@@ -1,14 +1,26 @@
 package view;
 
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
 import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
 import java.awt.event.ComponentAdapter;
 import java.awt.event.ComponentEvent;
 import java.awt.event.KeyEvent;
 import java.awt.event.KeyListener;
 
+import javax.swing.JButton;
 import javax.swing.JFrame;
+import javax.swing.JLabel;
 import javax.swing.JLayeredPane;
 import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+import javax.swing.JTree;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
 
 import animation.Action;
 import animation.AnimationController;
@@ -31,7 +43,21 @@ public class MainView {
      * The reason why there can only be one instance of this class.
      */
     public static JFrame frame;
-	AnimationController controller;
+	private AnimationController controller;
+    private JButton stepForward;
+    private JButton stepForwardInto;
+    private JButton stepForwardOut;
+    private JButton stepBackward;
+    private JButton stepBackwardInto;
+    private JButton stepBackwardOut;
+    private JButton runForward;
+    private JButton runBackward;
+    private JButton pause;
+    private JButton debug;
+    private JButton generateRandom;
+    private JLabel delayText;
+    private JTextField delay;
+    public static JTree pseudoTree;
 	
 	private String strToLen( String s, int l )
 	{
@@ -50,8 +76,171 @@ public class MainView {
 	 */
 	public MainView( LayeredGraphNode graph )
 	{
-		controller = new AnimationController();
-		controller.setTimeBetween( 10 );
+        controller = new AnimationController();
+        controller.setTimeBetween( 50 );
+        BKNodePlacement algorithm = new BKNodePlacement( controller, graph );
+        
+        // Create Menu GUI
+	    stepForward = new NiceButton( "stepForward" );
+	    stepForward.setLocation( 10, 10 );
+	    stepForward.addActionListener( new ActionListener() {
+
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                controller.setContinuous( false );
+                controller.setNextAction( Action.FORWARD_OVER );
+            }
+            
+        });
+	    stepForwardInto = new NiceButton( "stepForwardInto" );
+	    stepForwardInto.setLocation( 60, 10 );
+	    stepForwardInto.addActionListener( new ActionListener() {
+
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                controller.setContinuous( false );
+                controller.setNextAction( Action.FORWARD );
+            }
+            
+        });
+        stepForwardOut = new NiceButton( "stepForwardOut" );
+        stepForwardOut.setLocation( 110, 10 );
+        stepForwardOut.addActionListener( new ActionListener() {
+
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                controller.setContinuous( false );
+                controller.setNextAction( Action.FORWARD_OUT );
+            }
+            
+        });
+        runForward = new NiceButton( "runForward" );
+        runForward.setLocation( 160, 10 );
+        runForward.addActionListener( new ActionListener() {
+
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                controller.setContinuous( true );
+                controller.setNextAction( Action.FORWARD );
+            }
+            
+        });
+        runBackward = new NiceButton( "runBackward" );
+        runBackward.setLocation( 160, 60 );
+        runBackward.addActionListener( new ActionListener() {
+
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                controller.setContinuous( true );
+                controller.setNextAction( Action.BACKWARD );
+            }
+            
+        });
+        stepBackward = new NiceButton( "stepBackward" );
+        stepBackward.setLocation( 10, 60 );
+        stepBackward.addActionListener( new ActionListener() {
+
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                controller.setContinuous( false );
+                controller.setNextAction( Action.BACKWARD_OVER );
+            }
+            
+        });
+        stepBackwardInto = new NiceButton( "stepBackwardInto" );
+        stepBackwardInto.setLocation( 60, 60 );
+        stepBackwardInto.addActionListener( new ActionListener() {
+
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                controller.setContinuous( false );
+                controller.setNextAction( Action.BACKWARD );
+            }
+            
+        });
+        stepBackwardOut = new NiceButton( "stepBackwardOut" );
+        stepBackwardOut.setLocation( 110, 60 );
+        stepBackwardOut.addActionListener( new ActionListener() {
+
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                controller.setContinuous( false );
+                controller.setNextAction( Action.BACKWARD_OUT );
+            }
+            
+        });
+        pause = new NiceButton( "pause" );
+        pause.setLocation( 210, 10 );
+        pause.addActionListener( new ActionListener() {
+
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                controller.setContinuous( false );
+            }
+            
+        });
+        debug = new NiceButton( "debug" );
+        debug.setLocation( 350, 10 );
+        generateRandom = new NiceButton( "generateRandom" );
+        generateRandom.setLocation( 350, 60 );
+        generateRandom.addActionListener( new ActionListener() {
+
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                
+            }
+            
+        });
+        delayText = new JLabel( "Delay (ms)" );
+        delayText.setBounds( 260, 10, 80, 20 );
+        delay = new JTextField( "50" );
+        delay.setBounds( 260, 30, 80, 20 );
+        delay.getDocument().addDocumentListener( new DocumentListener() {
+
+            @Override
+            public void insertUpdate(DocumentEvent e) {
+                try
+                {
+                    controller.setTimeBetween( Integer.parseInt( delay.getText() ) );
+                    delay.setBackground( Color.WHITE );
+                } catch( Exception e1 )
+                {
+                    delay.setBackground( Color.RED );
+                }
+            }
+
+            @Override
+            public void removeUpdate(DocumentEvent e) {
+                try
+                {
+                    controller.setTimeBetween( Integer.parseInt( delay.getText() ) );
+                    delay.setBackground( Color.WHITE );
+                } catch( Exception e1 )
+                {
+                    delay.setBackground( Color.RED );
+                }
+            }
+
+            @Override
+            public void changedUpdate(DocumentEvent e) {
+                try
+                {
+                    controller.setTimeBetween( Integer.parseInt( delay.getText() ) );
+                    delay.setBackground( Color.WHITE );
+                } catch( Exception e1 )
+                {
+                    delay.setBackground( Color.RED );
+                }
+            }
+            
+        });
+        pseudoTree = new JTree( algorithm.createPseudocodeTree() );
+        pseudoTree.setEnabled( false );
+        pseudoTree.setCellRenderer( new PseudoCodeRenderer() );
+        
+        JScrollPane treeView = new JScrollPane( pseudoTree );
+        treeView.setBounds( 10,  110,  380, 380 );
+        
 		frame = new JFrame(); // this may write to a static field because there should be only one instance of this class.
         frame.setSize( Math.min( (int)graph.getWidth( LayoutType.TOP_BOTTOM_LEFT ) * 2 + 200, 1700 ), Math.min( (int)graph.getHeight( LayoutType.TOP_BOTTOM_LEFT ) * 2 + 200, 900 ) );
 		frame.setLocation( 100, 100 );
@@ -149,6 +338,23 @@ public class MainView {
 		combined.setSize( 500, 500 );
 		layne.add( combined, 0 );
 		frame.add( layne );
+		JPanel menue = new JPanel();
+		menue.setLayout( null );
+		menue.setPreferredSize( new Dimension( 400, 500 ) );
+		menue.add( stepForward );
+		menue.add( stepForwardInto );
+        menue.add( stepForwardOut );
+        menue.add( runForward );
+        menue.add( pause );
+        menue.add( debug );
+        menue.add( stepBackward );
+        menue.add( delayText );
+        menue.add( delay );
+        menue.add( treeView );
+        //menue.add( stepBackwardInto );
+        menue.add( stepBackwardOut );
+        menue.add( runBackward );
+		frame.add( menue, BorderLayout.EAST );
 		frame.validate();
 		frame.repaint();
 		
@@ -156,6 +362,8 @@ public class MainView {
 		{  
 	        public void componentResized(ComponentEvent evt) {
 	    		pl.setSize( layne.getSize() );
+	    		menue.setSize( menue.getWidth(), layne.getHeight() );
+	    		treeView.setSize( treeView.getWidth(), layne.getHeight() - 120 );
 	    		if( graph.getColor( LayoutType.COMBINED ) == null )
 	    		{
 		    		grout.setHgap( 10 );
@@ -172,7 +380,7 @@ public class MainView {
 	    		frame.repaint();
 	        }
 		});
-		new BKNodePlacement( controller, graph ).start();
+        algorithm.start();
 	}
 	
 	private NodeView createNodeView( LayeredGraphNode gNode, LayoutType lt )

+ 80 - 0
src/view/NiceButton.java

@@ -0,0 +1,80 @@
+package view;
+
+import java.awt.Color;
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.image.FilteredImageSource;
+import java.awt.image.ImageFilter;
+import java.awt.image.ImageProducer;
+import java.awt.image.RGBImageFilter;
+
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+
+public class NiceButton extends JButton implements MouseListener {
+
+    /**
+     * 
+     */
+    private static final long serialVersionUID = 1L;
+
+    
+    public NiceButton( String name )
+    {
+        super( NiceButton.class.getResource( "../images/" + name + ".png" ) != null ? makeColorTransparent( new ImageIcon( NiceButton.class.getResource( "../images/" + name + ".png" ) ).getImage().getScaledInstance( 40, 40, Image.SCALE_AREA_AVERAGING ), Color.WHITE, 0 ) : new ImageIcon() );
+        setSize( 40, 40 );
+        addMouseListener( this );
+        setBorderPainted( false );
+    }
+
+
+    @Override
+    public void mouseClicked(MouseEvent e) {}
+
+
+    @Override
+    public void mousePressed(MouseEvent e) {}
+
+
+    @Override
+    public void mouseReleased(MouseEvent e) {}
+
+
+    @Override
+    public void mouseEntered(MouseEvent e) {
+        setBorderPainted( true );
+    }
+
+
+    @Override
+    public void mouseExited(MouseEvent e) {
+        setBorderPainted( false );
+    }
+    
+    private static ImageIcon makeColorTransparent(final Image im, final Color color, int tolerance) {
+        int temp = 0;
+        if (tolerance < 0 || tolerance > 100) {
+            temp = 0;
+        } else {
+            temp = tolerance * (0xFF000000 | 0xFF000000) / 100;
+        }
+        final int toleranceRGB = Math.abs(temp);
+        final ImageFilter filter = new RGBImageFilter() {
+
+            public int markerRGBFrom = (color.getRGB() | 0xFF000000) - toleranceRGB;
+            public int markerRGBTo = (color.getRGB() | 0xFF000000) + toleranceRGB;
+            
+            public final int filterRGB(final int x, final int y, final int rgb) {
+                if ((rgb | 0xFF000000) >= markerRGBFrom && (rgb | 0xFF000000) <= markerRGBTo) {
+                    return 0x00FFFFFF & rgb;
+                } else {
+                    return rgb;
+                }
+            }
+        };
+        final ImageProducer ip = new FilteredImageSource(im.getSource(), filter);
+        return new ImageIcon( Toolkit.getDefaultToolkit().createImage(ip) );
+    }
+}

+ 9 - 3
src/view/NodeView.java

@@ -80,9 +80,10 @@ public class NodeView extends JPanel {
 			else
 				g2.fillRect( 0, 0, (int)model.getWidth( layout )-1, (int)model.getHeight( layout )-1 );
 		}
-		if( model.isSelected( layout ) )
+		boolean selected = model.isSelected( layout );
+		if( selected )
 		{
-			g.setColor( Color.GRAY );
+			g.setColor( Color.BLACK );
 			g.fillRect( 0, 0, (int)model.getWidth( layout )-1, (int)model.getHeight( layout )-1 );
 		}
 		Border linebor = BorderFactory.createLineBorder(model.getColor( layout ), 5);
@@ -92,7 +93,12 @@ public class NodeView extends JPanel {
 		{
     		g.setColor( model.getRoot( layout ).getSink( layout ).getColor( layout ) );
     		if( model.getContainedNodes().size() == 0 )
-    		    g.fillOval( (int)model.getWidth( layout ) / 2 - (int)model.getWidth( layout ) / 3, (int)model.getHeight( layout ) / 2 - (int)model.getHeight( layout ) / 3, (int)model.getWidth( layout ) / 3 * 2, (int)model.getHeight( layout ) / 3 * 2 );
+    		{
+    		    if( selected )
+    		        g.fillOval( (int)model.getWidth( layout ) / 2 - (int)model.getWidth( layout ) / 5, (int)model.getHeight( layout ) / 2 - (int)model.getHeight( layout ) / 5, (int)model.getWidth( layout ) / 5 * 2, (int)model.getHeight( layout ) / 5 * 2 );
+    		    else
+    		        g.fillOval( (int)model.getWidth( layout ) / 2 - (int)model.getWidth( layout ) / 3, (int)model.getHeight( layout ) / 2 - (int)model.getHeight( layout ) / 3, (int)model.getWidth( layout ) / 3 * 2, (int)model.getHeight( layout ) / 3 * 2 );
+    		}
 		}
 	}
 }

+ 45 - 0
src/view/PseudoCodeRenderer.java

@@ -0,0 +1,45 @@
+package view;
+
+import java.awt.Color;
+import java.awt.Component;
+
+import javax.swing.JTree;
+import javax.swing.tree.DefaultTreeCellRenderer;
+
+import animation.PseudoCodeNode;
+
+public class PseudoCodeRenderer extends DefaultTreeCellRenderer {
+    
+    /**
+     * 
+     */
+    private static final long serialVersionUID = 1L;
+    
+    boolean specialColor = false;
+
+    @Override
+    public Color getBackgroundNonSelectionColor() {
+        if(specialColor) {
+            return Color.GREEN;
+        } else {
+            return null;
+        }
+    }
+
+
+    @Override
+    public Component getTreeCellRendererComponent(JTree tree, Object value, boolean arg2, boolean arg3, boolean arg4, int arg5, boolean arg6) {
+
+        Component c = super.getTreeCellRendererComponent(tree, value, arg2, arg3, arg4, arg5, arg6);
+        specialColor = false;
+        if( value instanceof PseudoCodeNode )
+        {
+            PseudoCodeNode node = (PseudoCodeNode) value;
+            if(node.isSelected()) {
+                specialColor = true;
+            }
+        }
+        return c;
+    }
+
+}