浏览代码

Steps sind jetzt konfigurierbar (nur ausgeklappte steps werden genommen)

Kolja Strohm 6 年之前
父节点
当前提交
c3b493506a

+ 12 - 0
src/animation/AnimationController.java

@@ -7,9 +7,11 @@ public class AnimationController {
     private boolean continuous;
     private long lastTime;
     private long delay;
+    private int stepOption;
 
     public AnimationController()
     {
+        stepOption = 0;
         next = null;
         continuous = false;
         lastTime = 0;
@@ -81,6 +83,16 @@ public class AnimationController {
             notify();
         }
     }
+    
+    public void setStepOption( int opt )
+    {
+        stepOption = opt;
+    }
+    
+    public int getStepOption()
+    {
+        return stepOption;
+    }
 
     /**
      * checks if automatic execution is active

+ 17 - 6
src/animation/PseudoCodeNode.java

@@ -12,6 +12,13 @@ import javax.swing.tree.TreePath;
  */
 public class PseudoCodeNode extends DefaultMutableTreeNode {
 
+    public static enum CodeAction
+    {
+        SKIP,
+        STOP,
+        CONTINUE
+    }
+    
     private static final long serialVersionUID = 1L;
     
     private boolean selected;
@@ -87,22 +94,26 @@ public class PseudoCodeNode extends DefaultMutableTreeNode {
      * @param selected whether to select or deselect this line
      * @return false iff a breakpoint was reached and the node was set to be selected.
      */
-    public boolean setSelected( boolean selected )
+    public CodeAction setSelected( boolean selected )
     {
         if( selected && breakPoint )
             controller.setContinuous( false );
         this.selected = selected;
         if( selected )
         {
-            tree.collapsePath( new TreePath( this.getPath() ) );
-            tree.expandPath( new TreePath( this.getPath() ) );
+            if( controller == null || controller.getStepOption() != 1 || breakPoint )
+                tree.expandPath( new TreePath( this.getPath() ) );
         }
         else
         {
-            tree.expandPath( new TreePath( this.getPath() ) );
-            tree.collapsePath( new TreePath( this.getPath() ) );
+            if( controller == null || controller.getStepOption() != 1 )
+                tree.collapsePath( new TreePath( this.getPath() ) );
         }
-        return !breakPoint || !selected;
+        if( breakPoint && selected )
+            return CodeAction.STOP; // Breakpoint
+        if( controller != null && controller.getStepOption() == 1 && !tree.isVisible( new TreePath( this.getPath() ) ) )
+            return CodeAction.SKIP; // Step would be to detailed
+        return CodeAction.CONTINUE; // Normal
     }
     
     /**

+ 231 - 162
src/bk/BKNodePlacement.java

@@ -8,6 +8,7 @@ import javax.swing.JTree;
 import animation.AnimatedAlgorithm;
 import animation.AnimationController;
 import animation.PseudoCodeNode;
+import animation.PseudoCodeNode.CodeAction;
 import graph.LayeredGraphNode;
 
 /**
@@ -171,102 +172,136 @@ public class BKNodePlacement extends AnimatedAlgorithm {
     private StageStatus forward( String fName )
     {
         boolean breakpoint = false;
+        CodeAction action = null;
         try {
             switch( state )
             {
             case CONFLICTS:
+                action = conflictsNode.setSelected( true );
                 if( !conflictsNode.isSelected() )
-                    breakpoint |= !conflictsNode.setSelected( true );
-                switch( (StageStatus)(ConflictDetection.class.getMethod( fName ).invoke( conftion ) ) )
-                {
-                case FINISHED:
-                    inside = false;
-                    conflictsNode.setSelected( false );
-                    breakpoint |= !layout1Node.setSelected( true );
-                    state = State.LAYOUT1;
-                    break;
-                case BREAKPOINT:
-                    inside = true;
-                    return StageStatus.BREAKPOINT;
-                case UNFINISHED:
-                    inside = true;
-                }
+                    breakpoint |= action == CodeAction.STOP;
+                do {
+                    switch( (StageStatus)(ConflictDetection.class.getMethod( fName ).invoke( conftion ) ) )
+                    {
+                    case FINISHED:
+                        inside = false;
+                        conflictsNode.setSelected( false );
+                        CodeAction ca = layout1Node.setSelected( true );
+                        breakpoint |= ca == CodeAction.STOP;
+                        state = State.LAYOUT1;
+                        if( ca == CodeAction.SKIP && !breakpoint )
+                            return forward( fName );
+                        break;
+                    case BREAKPOINT:
+                        inside = true;
+                        return StageStatus.BREAKPOINT;
+                    case UNFINISHED:
+                        inside = true;
+                    }
+                } while( !breakpoint && action == CodeAction.SKIP );
                 break;
             case LAYOUT1:
-                switch( (StageStatus)(ExtremalLayoutCalc.class.getMethod( fName ).invoke( layouts[ 0 ] ) ) )
-                {
-                case FINISHED:
-                    inside = false;
-                    layout1Node.setSelected( false );
-                    breakpoint |= !layout2Node.setSelected( true );
-                    state = State.LAYOUT2;
-                    break;
-                case BREAKPOINT:
-                    inside = true;
-                    return StageStatus.BREAKPOINT;
-                case UNFINISHED:
-                    inside = true;
-                }
+                action = layout1Node.setSelected( true );
+                do {
+                    switch( (StageStatus)(ExtremalLayoutCalc.class.getMethod( fName ).invoke( layouts[ 0 ] ) ) )
+                    {
+                    case FINISHED:
+                        inside = false;
+                        layout1Node.setSelected( false );
+                        CodeAction ca = layout2Node.setSelected( true );
+                        breakpoint |= ca == CodeAction.STOP;
+                        state = State.LAYOUT2;
+                        if( ca == CodeAction.SKIP && !breakpoint )
+                            return forward( fName );
+                        break;
+                    case BREAKPOINT:
+                        inside = true;
+                        return StageStatus.BREAKPOINT;
+                    case UNFINISHED:
+                        inside = true;
+                    }
+                } while( !breakpoint && action == CodeAction.SKIP );
                 break;
             case LAYOUT2:
-                switch( (StageStatus)(ExtremalLayoutCalc.class.getMethod( fName ).invoke( layouts[ 1 ] ) ) )
-                {
-                case FINISHED:
-                    inside = false;
-                    layout2Node.setSelected( false );
-                    breakpoint |= !layout3Node.setSelected( true );
-                    state = State.LAYOUT3;
-                    break;
-                case BREAKPOINT:
-                    inside = true;
-                    return StageStatus.BREAKPOINT;
-                case UNFINISHED:
-                    inside = true;
-                }
+                action = layout2Node.setSelected( true );
+                do {
+                    switch( (StageStatus)(ExtremalLayoutCalc.class.getMethod( fName ).invoke( layouts[ 1 ] ) ) )
+                    {
+                    case FINISHED:
+                        inside = false;
+                        layout2Node.setSelected( false );
+                        CodeAction ca = layout3Node.setSelected( true );
+                        breakpoint |= ca == CodeAction.STOP;
+                        state = State.LAYOUT3;
+                        if( ca == CodeAction.SKIP && !breakpoint )
+                            return forward( fName );
+                        break;
+                    case BREAKPOINT:
+                        inside = true;
+                        return StageStatus.BREAKPOINT;
+                    case UNFINISHED:
+                        inside = true;
+                    }
+                } while( !breakpoint && action == CodeAction.SKIP );
                 break;
             case LAYOUT3:
-                switch( (StageStatus)(ExtremalLayoutCalc.class.getMethod( fName ).invoke( layouts[ 2 ] ) ) )
-                {
-                case FINISHED:
-                    inside = false;
-                    layout3Node.setSelected( false );
-                    breakpoint |= !layout4Node.setSelected( true );
-                    state = State.LAYOUT4;
-                    break;
-                case BREAKPOINT:
-                    inside = true;
-                    return StageStatus.BREAKPOINT;
-                case UNFINISHED:
-                    inside = true;
-                }
+                action = layout3Node.setSelected( true );
+                do {
+                    switch( (StageStatus)(ExtremalLayoutCalc.class.getMethod( fName ).invoke( layouts[ 2 ] ) ) )
+                    {
+                    case FINISHED:
+                        inside = false;
+                        layout3Node.setSelected( false );
+                        CodeAction ca = layout4Node.setSelected( true );
+                        breakpoint |= ca == CodeAction.STOP;
+                        state = State.LAYOUT4;
+                        if( ca == CodeAction.SKIP && !breakpoint )
+                            return forward( fName );
+                        break;
+                    case BREAKPOINT:
+                        inside = true;
+                        return StageStatus.BREAKPOINT;
+                    case UNFINISHED:
+                        inside = true;
+                    }
+                } while( !breakpoint && action == CodeAction.SKIP );
                 break;
             case LAYOUT4:
-                switch( (StageStatus)(ExtremalLayoutCalc.class.getMethod( fName ).invoke( layouts[ 3 ] ) ) )
-                {
-                case FINISHED:
-                    inside = false;
-                    layout4Node.setSelected( false );
-                    breakpoint |= !combineNode.setSelected( true );
-                    state = State.COMBINE;
-                    break;
-                case BREAKPOINT:
-                    inside = true;
-                    return StageStatus.BREAKPOINT;
-                case UNFINISHED:
-                    inside = true;
-                }
+                action = layout4Node.setSelected( true );
+                do {
+                    switch( (StageStatus)(ExtremalLayoutCalc.class.getMethod( fName ).invoke( layouts[ 3 ] ) ) )
+                    {
+                    case FINISHED:
+                        inside = false;
+                        layout4Node.setSelected( false );
+                        CodeAction ca = combineNode.setSelected( true );
+                        breakpoint |= ca == CodeAction.STOP;
+                        state = State.COMBINE;
+                        if( ca == CodeAction.SKIP && !breakpoint )
+                            return forward( fName );
+                        break;
+                    case BREAKPOINT:
+                        inside = true;
+                        return StageStatus.BREAKPOINT;
+                    case UNFINISHED:
+                        inside = true;
+                    }
+                } while( !breakpoint && action == CodeAction.SKIP );
                 break;
             case COMBINE:
-                switch( (StageStatus)(Combine.class.getMethod( fName ).invoke( combine ) ) )
-                {
-                case FINISHED:
-                    inside = false;
-                    return StageStatus.FINISHED;
-                case BREAKPOINT:
-                    return StageStatus.BREAKPOINT;
-                case UNFINISHED:
-                    inside = true;
-                }
+                action = combineNode.setSelected( true );
+                do {
+                    switch( (StageStatus)(Combine.class.getMethod( fName ).invoke( combine ) ) )
+                    {
+                    case FINISHED:
+                        inside = false;
+                        return StageStatus.FINISHED;
+                    case BREAKPOINT:
+                        return StageStatus.BREAKPOINT;
+                    case UNFINISHED:
+                        inside = true;
+                    }
+                } while( !breakpoint && action == CodeAction.SKIP );
             }
         } catch (IllegalAccessException e) {
             e.printStackTrace();
@@ -286,100 +321,134 @@ public class BKNodePlacement extends AnimatedAlgorithm {
 
     private StageStatus backward( String fName ) {
         boolean breakpoint = false;
+        CodeAction action = null;
         try {
             switch( state )
             {
             case CONFLICTS:
-                switch( (StageStatus)(ConflictDetection.class.getMethod( fName ).invoke( conftion ) ) )
-                {
-                case FINISHED:
-                    inside = false;
-                    return StageStatus.FINISHED;
-                case BREAKPOINT:
-                    inside = true;
-                    return StageStatus.BREAKPOINT;
-                case UNFINISHED:
-                    inside = true;
-                }
+                action = conflictsNode.setSelected( true );
+                do {
+                    switch( (StageStatus)(ConflictDetection.class.getMethod( fName ).invoke( conftion ) ) )
+                    {
+                    case FINISHED:
+                        inside = false;
+                        return StageStatus.FINISHED;
+                    case BREAKPOINT:
+                        inside = true;
+                        return StageStatus.BREAKPOINT;
+                    case UNFINISHED:
+                        inside = true;
+                    }
+                } while( !breakpoint && action == CodeAction.SKIP );
             case LAYOUT1:
-                switch( (StageStatus)(ExtremalLayoutCalc.class.getMethod( fName ).invoke( layouts[ 0 ] ) ) )
-                {
-                case FINISHED:
-                    inside = false;
-                    layout1Node.setSelected( false );
-                    breakpoint |= !conflictsNode.setSelected( true );
-                    state = State.CONFLICTS;
-                    break;
-                case BREAKPOINT:
-                    inside = true;
-                    return StageStatus.BREAKPOINT;
-                case UNFINISHED:
-                    inside = true;
-                }
+                action = layout1Node.setSelected( true );
+                do {
+                    switch( (StageStatus)(ExtremalLayoutCalc.class.getMethod( fName ).invoke( layouts[ 0 ] ) ) )
+                    {
+                    case FINISHED:
+                        inside = false;
+                        layout1Node.setSelected( false );
+                        CodeAction ca = conflictsNode.setSelected( true );
+                        breakpoint |= ca == CodeAction.STOP;
+                        state = State.CONFLICTS;
+                        if( ca == CodeAction.SKIP && !breakpoint )
+                            return backward( fName );
+                        break;
+                    case BREAKPOINT:
+                        inside = true;
+                        return StageStatus.BREAKPOINT;
+                    case UNFINISHED:
+                        inside = true;
+                    }
+                } while( !breakpoint && action == CodeAction.SKIP );
                 break;
             case LAYOUT2:
-                switch( (StageStatus)(ExtremalLayoutCalc.class.getMethod( fName ).invoke( layouts[ 1 ] ) ) )
-                {
-                case FINISHED:
-                    inside = false;
-                    layout2Node.setSelected( false );
-                    breakpoint |= !layout1Node.setSelected( true );
-                    state = State.LAYOUT1;
-                    break;
-                case BREAKPOINT:
-                    inside = true;
-                    return StageStatus.BREAKPOINT;
-                case UNFINISHED:
-                    inside = true;
-                }
+                action = layout2Node.setSelected( true );
+                do {
+                    switch( (StageStatus)(ExtremalLayoutCalc.class.getMethod( fName ).invoke( layouts[ 1 ] ) ) )
+                    {
+                    case FINISHED:
+                        inside = false;
+                        layout2Node.setSelected( false );
+                        CodeAction ca = layout1Node.setSelected( true );
+                        breakpoint |= ca == CodeAction.STOP;
+                        state = State.LAYOUT1;
+                        if( ca == CodeAction.SKIP && !breakpoint )
+                            return backward( fName );
+                        break;
+                    case BREAKPOINT:
+                        inside = true;
+                        return StageStatus.BREAKPOINT;
+                    case UNFINISHED:
+                        inside = true;
+                    }
+                } while( !breakpoint && action == CodeAction.SKIP );
                 break;
             case LAYOUT3:
-                switch( (StageStatus)(ExtremalLayoutCalc.class.getMethod( fName ).invoke( layouts[ 2 ] ) ) )
-                {
-                case FINISHED:
-                    inside = false;
-                    layout3Node.setSelected( false );
-                    breakpoint |= !layout2Node.setSelected( true );
-                    state = State.LAYOUT2;
-                    break;
-                case BREAKPOINT:
-                    inside = true;
-                    return StageStatus.BREAKPOINT;
-                case UNFINISHED:
-                    inside = true;
-                }
+                action = layout3Node.setSelected( true );
+                do {
+                    switch( (StageStatus)(ExtremalLayoutCalc.class.getMethod( fName ).invoke( layouts[ 2 ] ) ) )
+                    {
+                    case FINISHED:
+                        inside = false;
+                        layout3Node.setSelected( false );
+                        CodeAction ca = layout2Node.setSelected( true );
+                        breakpoint |= ca == CodeAction.STOP;
+                        state = State.LAYOUT2;
+                        if( ca == CodeAction.SKIP && !breakpoint )
+                            return backward( fName );
+                        break;
+                    case BREAKPOINT:
+                        inside = true;
+                        return StageStatus.BREAKPOINT;
+                    case UNFINISHED:
+                        inside = true;
+                    }
+                } while( !breakpoint && action == CodeAction.SKIP );
                 break;
             case LAYOUT4:
-                switch( (StageStatus)(ExtremalLayoutCalc.class.getMethod( fName ).invoke( layouts[ 3 ] ) ) )
-                {
-                case FINISHED:
-                    inside = false;
-                    layout4Node.setSelected( false );
-                    breakpoint |= !layout3Node.setSelected( true );
-                    state = State.LAYOUT3;
-                    break;
-                case BREAKPOINT:
-                    inside = true;
-                    return StageStatus.BREAKPOINT;
-                case UNFINISHED:
-                    inside = true;
-                }
+                action = layout4Node.setSelected( true );
+                do {
+                    switch( (StageStatus)(ExtremalLayoutCalc.class.getMethod( fName ).invoke( layouts[ 3 ] ) ) )
+                    {
+                    case FINISHED:
+                        inside = false;
+                        layout4Node.setSelected( false );
+                        CodeAction ca = layout3Node.setSelected( true );
+                        breakpoint |= ca == CodeAction.STOP;
+                        state = State.LAYOUT3;
+                        if( ca == CodeAction.SKIP && !breakpoint )
+                            return backward( fName );
+                        break;
+                    case BREAKPOINT:
+                        inside = true;
+                        return StageStatus.BREAKPOINT;
+                    case UNFINISHED:
+                        inside = true;
+                    }
+                } while( !breakpoint && action == CodeAction.SKIP );
                 break;
             case COMBINE:
-                switch( (StageStatus)(Combine.class.getMethod( fName ).invoke( combine ) ) )
-                {
-                case FINISHED:
-                    inside = false;
-                    combineNode.setSelected( false );
-                    breakpoint |= !layout4Node.setSelected( true );
-                    state = State.LAYOUT4;
-                    break;
-                case BREAKPOINT:
-                    inside = true;
-                    return StageStatus.BREAKPOINT;
-                case UNFINISHED:
-                    inside = true;
-                }
+                action = combineNode.setSelected( true );
+                do {
+                    switch( (StageStatus)(Combine.class.getMethod( fName ).invoke( combine ) ) )
+                    {
+                    case FINISHED:
+                        inside = false;
+                        combineNode.setSelected( false );
+                        CodeAction ca = layout4Node.setSelected( true );
+                        breakpoint |= ca == CodeAction.STOP;
+                        state = State.LAYOUT4;
+                        if( ca == CodeAction.SKIP && !breakpoint )
+                            return backward( fName );
+                        break;
+                    case BREAKPOINT:
+                        inside = true;
+                        return StageStatus.BREAKPOINT;
+                    case UNFINISHED:
+                        inside = true;
+                    }
+                } while( !breakpoint && action == CodeAction.SKIP );
                 break;
             }
         } catch (IllegalAccessException e) {

+ 128 - 95
src/bk/BlockCalc.java

@@ -8,6 +8,7 @@ import javax.swing.JTree;
 import animation.AlgorithmStage;
 import animation.BackwardAction;
 import animation.PseudoCodeNode;
+import animation.PseudoCodeNode.CodeAction;
 import bk.ExtremalLayoutCalc.LayoutType;
 import graph.LayeredGraphEdge;
 import graph.LayeredGraphNode;
@@ -101,21 +102,25 @@ public class BlockCalc implements AlgorithmStage {
         {
             inside = true;
             boolean breakpoint = false;
+            CodeAction action = subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( true );
             if( !subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).isSelected() )
-                breakpoint |= !subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( true );
-            switch( subgraphAlgs.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).forwardStep() )
-            {
-            case BREAKPOINT:
-                return StageStatus.BREAKPOINT;
-            case UNFINISHED:
-                if( breakpoint )
+                breakpoint |= action == CodeAction.STOP;
+            do {
+                switch( subgraphAlgs.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).forwardStep() )
+                {
+                case BREAKPOINT:
                     return StageStatus.BREAKPOINT;
-                return StageStatus.UNFINISHED;
-            case FINISHED:
-                inside = false;
-                subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( false );
-                break;
-            }
+                case UNFINISHED:
+                    if( breakpoint )
+                        return StageStatus.BREAKPOINT;
+                    return StageStatus.UNFINISHED;
+                case FINISHED:
+                    inside = false;
+                    subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( false );
+                    action = null;
+                    break;
+                }
+            } while( !breakpoint && action == CodeAction.SKIP );
         }
         ArrayList< LayeredGraphEdge > incommingEdges = null;
         if( layout == LayoutType.TOP_BOTTOM_LEFT || layout == LayoutType.TOP_BOTTOM_RIGHT )
@@ -182,13 +187,20 @@ public class BlockCalc implements AlgorithmStage {
                 System.out.println( "Performing Empty Backwards Step..." );
             });
         }
-        //current.update();
-        return calcNextState();
+        CodeAction action = loopNode.setSelected( true );
+        boolean breakpoint = action == CodeAction.STOP;
+        StageStatus status = calcNextState();
+        if( status == StageStatus.FINISHED )
+            return status;
+        if( breakpoint )
+            return StageStatus.BREAKPOINT;
+        if( action == CodeAction.SKIP )
+            return forwardStep();
+        return status;
     }
 
     private StageStatus calcNextState()
     {
-        boolean breakpoint = !loopNode.setSelected( true );
         if( layerIndex >= graph.getContainedLayers().size() - 1 )
         {
             if( nodeIndex >= graph.getContainedLayers().get( calcLayerIndex() ).size() -1 )
@@ -208,8 +220,6 @@ public class BlockCalc implements AlgorithmStage {
                this.r = oldR;
             });
         }
-        if( breakpoint )
-            return StageStatus.BREAKPOINT;
         return StageStatus.UNFINISHED;
     }
 
@@ -219,27 +229,30 @@ public class BlockCalc implements AlgorithmStage {
         {
             inside = true;
             boolean breakpoint = false;
+            CodeAction action = subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( true );
             if( !subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).isSelected() )
-                breakpoint |= !subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( true );
-            switch( subgraphAlgs.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).backwardStep() )
-            {
-            case BREAKPOINT:
-                return StageStatus.BREAKPOINT;
-            case UNFINISHED:
-                LayeredGraphNode current = graph.getContainedLayers().get( calcLayerIndex() ).get( calcNodeIndex(  nodeIndex ) );
-                current.setSelected( layout );
-                if( breakpoint )
+                breakpoint |= action == CodeAction.STOP;
+            do {
+                switch( subgraphAlgs.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).backwardStep() )
+                {
+                case BREAKPOINT:
                     return StageStatus.BREAKPOINT;
-                return StageStatus.UNFINISHED;
-            case FINISHED:
-                inside = false;
-                subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( false );
-                break;
-            }
+                case UNFINISHED:
+                    LayeredGraphNode current = graph.getContainedLayers().get( calcLayerIndex() ).get( calcNodeIndex(  nodeIndex ) );
+                    current.setSelected( layout );
+                    if( breakpoint )
+                        return StageStatus.BREAKPOINT;
+                    return StageStatus.UNFINISHED;
+                case FINISHED:
+                    inside = false;
+                    subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( false );
+                    action = null;
+                    break;
+                }
+            } while( !breakpoint && action == CodeAction.SKIP );
         }
-        StageStatus status = calcBeforeState();
-        if( status == StageStatus.FINISHED )
-            return status;
+        CodeAction action = loopNode.setSelected( true );
+        boolean breakpoint = action == CodeAction.STOP;
         LayeredGraphNode current = graph.getContainedLayers().get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) );
         current.setSelected( layout );
         if( !backwards.isEmpty() )
@@ -247,12 +260,18 @@ public class BlockCalc implements AlgorithmStage {
             backwards.get( 0 ).reverse();
             backwards.remove( 0 );
         }
+        StageStatus status = calcBeforeState();
+        if( status == StageStatus.FINISHED )
+            return status;
+        if( breakpoint )
+            return StageStatus.BREAKPOINT;
+        if( action == CodeAction.SKIP )
+            return backwardStep();
         return status;
     }
 
     private StageStatus calcBeforeState()
     {
-        boolean breakpoint = !loopNode.setSelected( true );
         if( layerIndex == 0 )
         {
             if( nodeIndex == 0 )
@@ -269,8 +288,6 @@ public class BlockCalc implements AlgorithmStage {
             backwards.remove( 0 );
             nodeIndex = graph.getContainedLayers().get( calcLayerIndex() ).size() - 1;
         }
-        if( breakpoint )
-            return StageStatus.BREAKPOINT;
         return StageStatus.UNFINISHED;
     }
 
@@ -303,21 +320,25 @@ public class BlockCalc implements AlgorithmStage {
         else
         {
             boolean breakpoint = false;
+            CodeAction action = subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( true );
             if( !subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).isSelected() )
-                breakpoint |= !subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( true );
-            switch( subgraphAlgs.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).forwardStepOver() )
-            {
-            case BREAKPOINT:
-                return StageStatus.BREAKPOINT;
-            case UNFINISHED:
-                if( breakpoint )
+                breakpoint |= action == CodeAction.STOP;
+            do {
+                switch( subgraphAlgs.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).forwardStepOver() )
+                {
+                case BREAKPOINT:
                     return StageStatus.BREAKPOINT;
-                return StageStatus.UNFINISHED;
-            case FINISHED:
-                inside = false;
-                subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( false );
-                break;
-            }
+                case UNFINISHED:
+                    if( breakpoint )
+                        return StageStatus.BREAKPOINT;
+                    return StageStatus.UNFINISHED;
+                case FINISHED:
+                    inside = false;
+                    subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( false );
+                    action = null;
+                    break;
+                }
+            } while( !breakpoint && action == CodeAction.SKIP );
             return StageStatus.UNFINISHED;
         }
     }
@@ -334,21 +355,25 @@ public class BlockCalc implements AlgorithmStage {
         else
         {
             boolean breakpoint = false;
+            CodeAction action = subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( true );
             if( !subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).isSelected() )
-                breakpoint |= !subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( true );
-            switch( subgraphAlgs.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).forwardStepOut() )
-            {
-            case BREAKPOINT:
-                return StageStatus.BREAKPOINT;
-            case UNFINISHED:
-                if( breakpoint )
+                breakpoint |= action == CodeAction.STOP;
+            do {
+                switch( subgraphAlgs.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).forwardStepOut() )
+                {
+                case BREAKPOINT:
                     return StageStatus.BREAKPOINT;
-                return StageStatus.UNFINISHED;
-            case FINISHED:
-                inside = false;
-                subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( false );
-                break;
-            }
+                case UNFINISHED:
+                    if( breakpoint )
+                        return StageStatus.BREAKPOINT;
+                    return StageStatus.UNFINISHED;
+                case FINISHED:
+                    inside = false;
+                    subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( false );
+                    action = null;
+                    break;
+                }
+            } while( !breakpoint && action == CodeAction.SKIP );
             return StageStatus.UNFINISHED;
         }
     }
@@ -360,23 +385,27 @@ public class BlockCalc implements AlgorithmStage {
         else
         {
             boolean breakpoint = false;
+            CodeAction action = subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( true );
             if( !subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).isSelected() )
-                breakpoint |= !subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( true );
-            switch( subgraphAlgs.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).backwardStepOver() )
-            {
-            case BREAKPOINT:
-                return StageStatus.BREAKPOINT;
-            case UNFINISHED:
-                LayeredGraphNode current = graph.getContainedLayers().get( calcLayerIndex() ).get( nodeIndex );
-                current.setSelected( layout );
-                if( breakpoint )
+                breakpoint |= action == CodeAction.STOP;
+            do {
+                switch( subgraphAlgs.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).backwardStepOver() )
+                {
+                case BREAKPOINT:
                     return StageStatus.BREAKPOINT;
-                return StageStatus.UNFINISHED;
-            case FINISHED:
-                inside = false;
-                subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( false );
-                break;
-            }
+                case UNFINISHED:
+                    LayeredGraphNode current = graph.getContainedLayers().get( calcLayerIndex() ).get( nodeIndex );
+                    current.setSelected( layout );
+                    if( breakpoint )
+                        return StageStatus.BREAKPOINT;
+                    return StageStatus.UNFINISHED;
+                case FINISHED:
+                    inside = false;
+                    subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( false );
+                    action = null;
+                    break;
+                }
+            } while( !breakpoint && action == CodeAction.SKIP );
             return StageStatus.UNFINISHED;
         }
     }
@@ -393,23 +422,27 @@ public class BlockCalc implements AlgorithmStage {
         else
         {
             boolean breakpoint = false;
+            CodeAction action = subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( true );
             if( !subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).isSelected() )
-                breakpoint |= !subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( true );
-            switch( subgraphAlgs.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).backwardStepOut() )
-            {
-            case BREAKPOINT:
-                return StageStatus.BREAKPOINT;
-            case UNFINISHED:
-                LayeredGraphNode current = graph.getContainedLayers().get( calcLayerIndex() ).get( nodeIndex );
-                current.setSelected( layout );
-                if( breakpoint )
+                breakpoint |= action == CodeAction.STOP;
+            do {
+                switch( subgraphAlgs.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).backwardStepOut() )
+                {
+                case BREAKPOINT:
                     return StageStatus.BREAKPOINT;
-                return StageStatus.UNFINISHED;
-            case FINISHED:
-                inside = false;
-                subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( false );
-                break;
-            }
+                case UNFINISHED:
+                    LayeredGraphNode current = graph.getContainedLayers().get( calcLayerIndex() ).get( nodeIndex );
+                    current.setSelected( layout );
+                    if( breakpoint )
+                        return StageStatus.BREAKPOINT;
+                    return StageStatus.UNFINISHED;
+                case FINISHED:
+                    inside = false;
+                    subgraphNodes.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).setSelected( false );
+                    action = null;
+                    break;
+                }
+            } while( !breakpoint && action == CodeAction.SKIP );
             return StageStatus.UNFINISHED;
         }
     }

+ 136 - 91
src/bk/Combine.java

@@ -9,6 +9,7 @@ import javax.swing.JTree;
 import animation.AlgorithmStage;
 import animation.BackwardAction;
 import animation.PseudoCodeNode;
+import animation.PseudoCodeNode.CodeAction;
 import bk.ExtremalLayoutCalc.LayoutType;
 import graph.LayeredGraphNode;
 import lib.TextLayoutHelper;
@@ -41,6 +42,7 @@ public class Combine implements AlgorithmStage {
     private boolean inside;
     private boolean insideSubgraph;
     private boolean breakPoint;
+    private boolean skipBackwards;
     private ArrayList< PseudoCodeNode > subgraphNodes;
     private ArrayList< Combine > subgraphAlgs;
 
@@ -52,6 +54,7 @@ public class Combine implements AlgorithmStage {
         actions = new ArrayList<>();
         inside = false;
         insideSubgraph = false;
+        skipBackwards = false;
         subgraphNodes = new ArrayList<>();
         subgraphAlgs = new ArrayList<>();
         for( @SuppressWarnings("unused") LayeredGraphNode n : graph.getContainedNodes() )
@@ -67,8 +70,9 @@ public class Combine implements AlgorithmStage {
         if( state == State.ALIGN )
         {
             inside = false;
+            CodeAction action = alignNode.setSelected( true );
             if( !alignNode.isSelected() )
-                breakPoint |= !alignNode.setSelected( true );
+                breakPoint |= action == CodeAction.STOP;
             int tblw = (int)calcMaxX( LayoutType.TOP_BOTTOM_LEFT );
             int tbrw = (int)calcMaxX( LayoutType.TOP_BOTTOM_RIGHT );
             int btlw = (int)calcMaxX( LayoutType.BOTTOM_TOP_LEFT );
@@ -103,21 +107,30 @@ public class Combine implements AlgorithmStage {
                 loopNode.setSelected( false );
                 setNode.setSelected( false );
                 breakPoint = false;
+                CodeAction ac = alignNode.setSelected( true );
                 if( !alignNode.isSelected() )
-                    breakPoint |= !alignNode.setSelected( true );
+                    breakPoint |= ac == CodeAction.STOP;
+                skipBackwards = ac == CodeAction.SKIP;
                 state = State.ALIGN;
                 if( oldColor == null )
                     graph.setColor( null, null );
             });
             state = State.SET_COORDINATES;
             alignNode.setSelected( false );
+            CodeAction ac = setNode.setSelected( true );
+            boolean skip = ac == CodeAction.SKIP;
             if( !setNode.isSelected() )
-                breakPoint |= !setNode.setSelected( true );
-            breakPoint |= !loopNode.setSelected( true );
+                breakPoint |= ac == CodeAction.STOP;
+            ac = loopNode.setSelected( true );
+            breakPoint |= ac == CodeAction.STOP;
+            skip |= ac == CodeAction.SKIP;
+            if( (action == CodeAction.SKIP || skip) && !breakPoint )
+                return forwardStep();
         }
         else
         {
-            breakPoint = !loopNode.setSelected( true );
+            CodeAction action = loopNode.setSelected( true );
+            breakPoint = action == CodeAction.STOP;
             if( vIndex >= graph.getContainedNodes().size() )
             {
                 inside = false;
@@ -133,21 +146,25 @@ public class Combine implements AlgorithmStage {
             {
                 insideSubgraph = true;
                 boolean breakpoint = false;
+                CodeAction ac = subgraphNodes.get( vIndex ).setSelected( true );
                 if( !subgraphNodes.get( vIndex ).isSelected() )
-                    breakpoint |= !subgraphNodes.get( vIndex ).setSelected( true );
-                switch( subgraphAlgs.get( vIndex ).forwardStep() )
-                {
-                case BREAKPOINT:
-                    return StageStatus.BREAKPOINT;
-                case UNFINISHED:
-                    if( breakpoint )
+                    breakpoint |= ac == CodeAction.STOP;
+                do {
+                    switch( subgraphAlgs.get( vIndex ).forwardStep() )
+                    {
+                    case BREAKPOINT:
                         return StageStatus.BREAKPOINT;
-                    return StageStatus.UNFINISHED;
-                case FINISHED:
-                    inside = false;
-                    subgraphNodes.get( vIndex ).setSelected( false );
-                    break;
-                }
+                    case UNFINISHED:
+                        if( breakpoint )
+                            return StageStatus.BREAKPOINT;
+                        return StageStatus.UNFINISHED;
+                    case FINISHED:
+                        inside = false;
+                        subgraphNodes.get( vIndex ).setSelected( false );
+                        ac = null;
+                        break;
+                    }
+                } while( ac == CodeAction.SKIP && !breakPoint );
             }
             ArrayList< Integer > positions = new ArrayList<>();
             positions.add( (Integer)(int)current.getX( LayoutType.TOP_BOTTOM_LEFT ) + tblOffset );
@@ -160,14 +177,20 @@ public class Combine implements AlgorithmStage {
             actions.add( 0, () -> {
                 inside = true;
                 breakPoint = false;
+                CodeAction ac = setNode.setSelected( true );
                 if( !setNode.isSelected() )
-                    breakPoint |= !setNode.setSelected( true );
-                breakPoint |= !loopNode.setSelected( true );
+                    breakPoint |= ac == CodeAction.STOP;
+                skipBackwards = ac == CodeAction.SKIP;
+                ac = loopNode.setSelected( true );
+                breakPoint |= ac == CodeAction.STOP;
+                skipBackwards |= ac == CodeAction.SKIP;
                 vIndex--;
                 current.setX( oldX, true, LayoutType.COMBINED );
                 current.setSelected( null );
             });
             vIndex++;
+            if( action == CodeAction.SKIP && !breakPoint )
+                return forwardStep();
         }
         if( breakPoint )
             return StageStatus.BREAKPOINT;
@@ -200,23 +223,27 @@ public class Combine implements AlgorithmStage {
         {
             insideSubgraph = true;
             boolean breakpoint = false;
+            CodeAction action = subgraphNodes.get( vIndex ).setSelected( true );
             if( !subgraphNodes.get( vIndex ).isSelected() )
-                breakpoint |= !subgraphNodes.get( vIndex ).setSelected( true );
-            switch( subgraphAlgs.get( vIndex ).backwardStep() )
-            {
-            case BREAKPOINT:
-                return StageStatus.BREAKPOINT;
-            case UNFINISHED:
-                LayeredGraphNode current = graph.getContainedNodes().get( vIndex );
-                current.setSelected( null );
-                if( breakpoint )
+                breakpoint |= action == CodeAction.STOP;
+            do {
+                switch( subgraphAlgs.get( vIndex ).backwardStep() )
+                {
+                case BREAKPOINT:
                     return StageStatus.BREAKPOINT;
-                return StageStatus.UNFINISHED;
-            case FINISHED:
-                insideSubgraph = false;
-                subgraphNodes.get( vIndex ).setSelected( false );
-                break;
-            }
+                case UNFINISHED:
+                    LayeredGraphNode current = graph.getContainedNodes().get( vIndex );
+                    current.setSelected( null );
+                    if( breakpoint )
+                        return StageStatus.BREAKPOINT;
+                    return StageStatus.UNFINISHED;
+                case FINISHED:
+                    insideSubgraph = false;
+                    subgraphNodes.get( vIndex ).setSelected( false );
+                    action = null;
+                    break;
+                }
+            } while( !breakpoint && action == CodeAction.SKIP );
         }
         if( actions.size() == 0 )
         {
@@ -228,6 +255,8 @@ public class Combine implements AlgorithmStage {
         actions.remove( 0 );
         if( breakPoint )
             return StageStatus.BREAKPOINT;
+        if( skipBackwards )
+            return backwardStep();
         return StageStatus.UNFINISHED;
     }
 
@@ -272,21 +301,25 @@ public class Combine implements AlgorithmStage {
             else
             {
                 boolean breakpoint = false;
+                CodeAction action = subgraphNodes.get( vIndex ).setSelected( true );
                 if( !subgraphNodes.get( vIndex ).isSelected() )
-                    breakpoint |= !subgraphNodes.get( vIndex ).setSelected( true );
-                switch( subgraphAlgs.get( vIndex ).forwardStepOver() )
-                {
-                case BREAKPOINT:
-                    return StageStatus.BREAKPOINT;
-                case UNFINISHED:
-                    if( breakpoint )
+                    breakpoint |= action == CodeAction.STOP;
+                do {
+                    switch( subgraphAlgs.get( vIndex ).forwardStepOver() )
+                    {
+                    case BREAKPOINT:
                         return StageStatus.BREAKPOINT;
-                    return StageStatus.UNFINISHED;
-                case FINISHED:
-                    inside = false;
-                    subgraphNodes.get( vIndex ).setSelected( false );
-                    break;
-                }
+                    case UNFINISHED:
+                        if( breakpoint )
+                            return StageStatus.BREAKPOINT;
+                        return StageStatus.UNFINISHED;
+                    case FINISHED:
+                        inside = false;
+                        subgraphNodes.get( vIndex ).setSelected( false );
+                        action = null;
+                        break;
+                    }
+                } while( !breakpoint && action == CodeAction.SKIP );
                 return StageStatus.UNFINISHED;
             }
         }
@@ -314,21 +347,25 @@ public class Combine implements AlgorithmStage {
             else
             {
                 boolean breakpoint = false;
+                CodeAction action = subgraphNodes.get( vIndex ).setSelected( true );
                 if( !subgraphNodes.get( vIndex ).isSelected() )
-                    breakpoint |= !subgraphNodes.get( vIndex ).setSelected( true );
-                switch( subgraphAlgs.get( vIndex ).forwardStepOut() )
-                {
-                case BREAKPOINT:
-                    return StageStatus.BREAKPOINT;
-                case UNFINISHED:
-                    if( breakpoint )
+                    breakpoint |= action == CodeAction.STOP;
+                do {
+                    switch( subgraphAlgs.get( vIndex ).forwardStepOut() )
+                    {
+                    case BREAKPOINT:
                         return StageStatus.BREAKPOINT;
-                    return StageStatus.UNFINISHED;
-                case FINISHED:
-                    inside = false;
-                    subgraphNodes.get( vIndex ).setSelected( false );
-                    break;
-                }
+                    case UNFINISHED:
+                        if( breakpoint )
+                            return StageStatus.BREAKPOINT;
+                        return StageStatus.UNFINISHED;
+                    case FINISHED:
+                        inside = false;
+                        subgraphNodes.get( vIndex ).setSelected( false );
+                        action = null;
+                        break;
+                    }
+                } while( !breakpoint && action == CodeAction.SKIP );
                 return StageStatus.UNFINISHED;
             }
         }
@@ -351,23 +388,27 @@ public class Combine implements AlgorithmStage {
             else
             {
                 boolean breakpoint = false;
+                CodeAction action = subgraphNodes.get( vIndex ).setSelected( true );
                 if( !subgraphNodes.get( vIndex ).isSelected() )
-                    breakpoint |= !subgraphNodes.get( vIndex ).setSelected( true );
-                switch( subgraphAlgs.get( vIndex ).backwardStepOver() )
-                {
-                case BREAKPOINT:
-                    return StageStatus.BREAKPOINT;
-                case UNFINISHED:
-                    LayeredGraphNode current = graph.getContainedNodes().get( vIndex );
-                    current.setSelected( null );
-                    if( breakpoint )
+                    breakpoint |= action == CodeAction.STOP;
+                do {
+                    switch( subgraphAlgs.get( vIndex ).backwardStepOver() )
+                    {
+                    case BREAKPOINT:
                         return StageStatus.BREAKPOINT;
-                    return StageStatus.UNFINISHED;
-                case FINISHED:
-                    inside = false;
-                    subgraphNodes.get( vIndex ).setSelected( false );
-                    break;
-                }
+                    case UNFINISHED:
+                        LayeredGraphNode current = graph.getContainedNodes().get( vIndex );
+                        current.setSelected( null );
+                        if( breakpoint )
+                            return StageStatus.BREAKPOINT;
+                        return StageStatus.UNFINISHED;
+                    case FINISHED:
+                        inside = false;
+                        subgraphNodes.get( vIndex ).setSelected( false );
+                        action = null;
+                        break;
+                    }
+                } while( !breakpoint && action == CodeAction.SKIP );
                 return StageStatus.UNFINISHED;
             }
         }
@@ -395,23 +436,27 @@ public class Combine implements AlgorithmStage {
             else
             {
                 boolean breakpoint = false;
+                CodeAction action = subgraphNodes.get( vIndex ).setSelected( true );
                 if( !subgraphNodes.get( vIndex ).isSelected() )
-                    breakpoint |= !subgraphNodes.get( vIndex ).setSelected( true );
-                switch( subgraphAlgs.get( vIndex ).backwardStepOut() )
-                {
-                case BREAKPOINT:
-                    return StageStatus.BREAKPOINT;
-                case UNFINISHED:
-                    LayeredGraphNode current = graph.getContainedNodes().get( vIndex );
-                    current.setSelected( null );
-                    if( breakpoint )
+                    breakpoint |= action == CodeAction.STOP;
+                do {
+                    switch( subgraphAlgs.get( vIndex ).backwardStepOut() )
+                    {
+                    case BREAKPOINT:
                         return StageStatus.BREAKPOINT;
-                    return StageStatus.UNFINISHED;
-                case FINISHED:
-                    inside = false;
-                    subgraphNodes.get( vIndex ).setSelected( false );
-                    break;
-                }
+                    case UNFINISHED:
+                        LayeredGraphNode current = graph.getContainedNodes().get( vIndex );
+                        current.setSelected( null );
+                        if( breakpoint )
+                            return StageStatus.BREAKPOINT;
+                        return StageStatus.UNFINISHED;
+                    case FINISHED:
+                        inside = false;
+                        subgraphNodes.get( vIndex ).setSelected( false );
+                        action = null;
+                        break;
+                    }
+                } while( !breakpoint && action == CodeAction.SKIP );
                 return StageStatus.UNFINISHED;
             }
         }

+ 92 - 26
src/bk/Compaction.java

@@ -7,6 +7,7 @@ import javax.swing.JTree;
 import animation.AlgorithmStage;
 import animation.BackwardAction;
 import animation.PseudoCodeNode;
+import animation.PseudoCodeNode.CodeAction;
 import bk.ExtremalLayoutCalc.LayoutType;
 import graph.LayeredGraphNode;
 
@@ -43,6 +44,7 @@ public class Compaction implements AlgorithmStage{
     private PseudoCodeNode applyLoopNode;
     private boolean breakPoint;
     private boolean inside;
+    private boolean skip;
 
 
     public Compaction( LayeredGraphNode graph, LayoutType layout )
@@ -54,6 +56,7 @@ public class Compaction implements AlgorithmStage{
         vIndex = 0;
         actions = new ArrayList<>();
         inside = false;
+        skip = false;
     }
 
     /**
@@ -84,13 +87,18 @@ public class Compaction implements AlgorithmStage{
     @Override
     public StageStatus forwardStep() {
         breakPoint = false;
+        skip = false;
         int acSize = actions.size();
         if( state == CompactionState.PLACE_BLOCKS ) // blöcke platzieren
         {
             inside = true;
+            CodeAction action = placeNode.setSelected( true );
             if( !placeNode.isSelected() )
-                breakPoint = !placeNode.setSelected( true );
-            breakPoint |= !placeLoopNode.setSelected( true );
+                breakPoint = action == CodeAction.STOP;
+            skip |= action == CodeAction.SKIP;
+            action = placeLoopNode.setSelected( true );
+            breakPoint |= action == CodeAction.STOP;
+            skip |= action == CodeAction.SKIP;
             if( stack.size() == 0 ) // äußere schleife, placeblocks bisher nicht aufgerufen
             {
                 ArrayList< LayeredGraphNode > nodes = graph.getContainedNodes();
@@ -113,9 +121,13 @@ public class Compaction implements AlgorithmStage{
                     // wechsele in die phase des Blöckeshiftens
                     placeNode.setSelected( false );
                     placeLoopNode.setSelected( false );
+                    action = applyNode.setSelected( true );
                     if( !applyNode.isSelected() )
-                        breakPoint |= !applyNode.setSelected( true );
-                    breakPoint |= !applyLoopNode.setSelected( true );
+                        breakPoint |= action == CodeAction.STOP;
+                    skip |= action == CodeAction.SKIP;
+                    action = applyLoopNode.setSelected( true );
+                    breakPoint |= action == CodeAction.STOP;
+                    skip |= action == CodeAction.SKIP;
                     state = CompactionState.APPLY_SHIFT;
                     inside = false;
                     vIndex = 0;
@@ -123,9 +135,14 @@ public class Compaction implements AlgorithmStage{
                         applyNode.setSelected( false );
                         applyLoopNode.setSelected( false );
                         breakPoint = false;
+                        skip = false;
+                        CodeAction ac = placeNode.setSelected( true );
                         if( !placeNode.isSelected() )
-                            breakPoint |= !placeNode.setSelected( true );
-                        breakPoint |= !placeLoopNode.setSelected( true );
+                            breakPoint |= ac == CodeAction.STOP;
+                        skip |= ac == CodeAction.SKIP;
+                        ac = placeLoopNode.setSelected( true );
+                        breakPoint |= ac == CodeAction.STOP;
+                        skip |= ac == CodeAction.SKIP;
                         vIndex = oldVIndex;
                         inside = false;
                         state = CompactionState.PLACE_BLOCKS;
@@ -145,9 +162,14 @@ public class Compaction implements AlgorithmStage{
                     // die "undo"-action
                     actions.add( 0, ()-> {
                         breakPoint = false;
+                        skip = false;
+                        CodeAction ac = placeNode.setSelected( true );
                         if( !placeNode.isSelected() )
-                            breakPoint |= !placeNode.setSelected( true );
-                        breakPoint |= !placeLoopNode.setSelected( true );
+                            breakPoint |= ac == CodeAction.STOP;
+                        skip |= ac == CodeAction.SKIP;
+                        ac = placeLoopNode.setSelected( true );
+                        breakPoint |= ac == CodeAction.STOP;
+                        skip |= ac == CodeAction.SKIP;
                         inside = true;
                         stack.get( 0 ).v.setX( oldX, false, layout );
                         stack.get( 0 ).v.setSelected( layout );
@@ -184,9 +206,14 @@ public class Compaction implements AlgorithmStage{
                             // die "undo"-action
                             actions.add( 0, ()-> {
                                 breakPoint = false;
+                                skip = false;
+                                CodeAction ac = placeNode.setSelected( true );
                                 if( !placeNode.isSelected() )
-                                    breakPoint |= !placeNode.setSelected( true );
-                                breakPoint |= !placeLoopNode.setSelected( true );
+                                    breakPoint |= ac == CodeAction.STOP;
+                                skip |= ac == CodeAction.SKIP;
+                                ac = placeLoopNode.setSelected( true );
+                                breakPoint |= ac == CodeAction.STOP;
+                                skip |= ac == CodeAction.SKIP;
                                 inside = true;
                                 stack.get( 0 ).v.setX( oldX, false, layout );
                                 stack.get( 0 ).v.setSelected( layout );
@@ -200,9 +227,14 @@ public class Compaction implements AlgorithmStage{
                             sf.w.setSelected( layout );
                             actions.add( 0, ()-> {
                                 breakPoint = false;
+                                skip = false;
+                                CodeAction ac = placeNode.setSelected( true );
                                 if( !placeNode.isSelected() )
-                                    breakPoint |= !placeNode.setSelected( true );
-                                breakPoint |= !placeLoopNode.setSelected( true );
+                                    breakPoint |= ac == CodeAction.STOP;
+                                skip |= ac == CodeAction.SKIP;
+                                ac = placeLoopNode.setSelected( true );
+                                breakPoint |= ac == CodeAction.STOP;
+                                skip |= ac == CodeAction.SKIP;
                                 inside = true;
                                 stack.get( 0 ).u = null;
                             });
@@ -219,9 +251,14 @@ public class Compaction implements AlgorithmStage{
                             stack.remove( 0 );
                             actions.add( 0, ()-> {
                                 breakPoint = false;
+                                skip = false;
+                                CodeAction ac = placeNode.setSelected( true );
                                 if( !placeNode.isSelected() )
-                                    breakPoint |= !placeNode.setSelected( true );
-                                breakPoint |= !placeLoopNode.setSelected( true );
+                                    breakPoint |= ac == CodeAction.STOP;
+                                skip |= ac == CodeAction.SKIP;
+                                ac = placeLoopNode.setSelected( true );
+                                breakPoint |= ac == CodeAction.STOP;
+                                skip |= ac == CodeAction.SKIP;
                                 inside = true;
                                 stack.add( 0, sf );
                                 sf.w = oldW;
@@ -232,9 +269,14 @@ public class Compaction implements AlgorithmStage{
                         { //nur "undo aktion" hinzufügen
                             actions.add( 0, ()-> {
                                 breakPoint = false;
+                                skip = false;
+                                CodeAction ac = placeNode.setSelected( true );
                                 if( !placeNode.isSelected() )
-                                    breakPoint |= !placeNode.setSelected( true );
-                                breakPoint |= !placeLoopNode.setSelected( true );
+                                    breakPoint |= ac == CodeAction.STOP;
+                                skip |= ac == CodeAction.SKIP;
+                                ac = placeLoopNode.setSelected( true );
+                                breakPoint |= ac == CodeAction.STOP;
+                                skip |= ac == CodeAction.SKIP;
                                 inside = true;
                                 sf.w = oldW;
                                 sf.w.setSelected( layout );
@@ -282,9 +324,14 @@ public class Compaction implements AlgorithmStage{
                         stack.remove( 0 );
                         actions.add( 0, ()-> {
                             breakPoint = false;
+                            skip = false;
+                            CodeAction ac = placeNode.setSelected( true );
                             if( !placeNode.isSelected() )
-                                breakPoint |= !placeNode.setSelected( true );
-                            breakPoint |= !placeLoopNode.setSelected( true );
+                                breakPoint |= ac == CodeAction.STOP;
+                            skip |= ac == CodeAction.SKIP;
+                            ac = placeLoopNode.setSelected( true );
+                            breakPoint |= ac == CodeAction.STOP;
+                            skip |= ac == CodeAction.SKIP;
                             inside = true;
                             stack.add( 0, sf );
                             stack.get( 0 ).v.setSink(  oldSink, layout );
@@ -299,9 +346,14 @@ public class Compaction implements AlgorithmStage{
                     { //nur "undo aktion" hinzufügen
                         actions.add( 0, ()-> {
                             breakPoint = false;
+                            skip = false;
+                            CodeAction ac = placeNode.setSelected( true );
                             if( !placeNode.isSelected() )
-                                breakPoint |= !placeNode.setSelected( true );
-                            breakPoint |= !placeLoopNode.setSelected( true );
+                                breakPoint |= ac == CodeAction.STOP;
+                            skip |= ac == CodeAction.SKIP;
+                            ac = placeLoopNode.setSelected( true );
+                            breakPoint |= ac == CodeAction.STOP;
+                            skip |= ac == CodeAction.SKIP;
                             inside = true;
                             stack.get( 0 ).v.setSink(  oldSink, layout );
                             sinkOfU.setShift( oldShift, layout );
@@ -317,9 +369,14 @@ public class Compaction implements AlgorithmStage{
         else if( state == CompactionState.APPLY_SHIFT )// "Compute absolute coordinates"
         {
             inside = true;
-            if( !applyNode.isSelected() )
-                breakPoint |= !applyNode.setSelected( true );
-            breakPoint |= !applyLoopNode.setSelected( true );
+            skip = false;
+            CodeAction action = applyNode.setSelected( true );
+            if( !placeNode.isSelected() )
+                breakPoint |= action == CodeAction.STOP;
+            skip |= action == CodeAction.SKIP;
+            action = applyLoopNode.setSelected( true );
+            breakPoint |= action == CodeAction.STOP;
+            skip |= action == CodeAction.SKIP;
             if( vIndex >= graph.getContainedNodes().size() )
             {
                 inside = false;
@@ -338,9 +395,14 @@ public class Compaction implements AlgorithmStage{
             actions.add( 0, ()-> {
                 inside = true;
                 breakPoint = false;
-                if( !applyNode.isSelected() )
-                    breakPoint |= !applyNode.setSelected( true );
-                breakPoint |= !applyLoopNode.setSelected( true );
+                skip = false;
+                CodeAction ac = applyNode.setSelected( true );
+                if( !placeNode.isSelected() )
+                    breakPoint |= ac == CodeAction.STOP;
+                skip |= ac == CodeAction.SKIP;
+                ac = applyLoopNode.setSelected( true );
+                breakPoint |= ac == CodeAction.STOP;
+                skip |= ac == CodeAction.SKIP;
                 v.setX( oldX, oldDef, layout );
                 v.setSelected( layout );
                 vIndex--;
@@ -357,6 +419,8 @@ public class Compaction implements AlgorithmStage{
             System.out.println( "ERROR" );
         if( breakPoint )
             return StageStatus.BREAKPOINT;
+        if( skip )
+            return forwardStep();
         return StageStatus.UNFINISHED;
     }
 
@@ -373,6 +437,8 @@ public class Compaction implements AlgorithmStage{
         actions.remove( 0 );
         if( breakPoint )
             return StageStatus.BREAKPOINT;
+        if( skip )
+            return backwardStep();
         return StageStatus.UNFINISHED;
     }
 

+ 9 - 2
src/bk/ConflictDetection.java

@@ -7,6 +7,7 @@ import javax.swing.JTree;
 import animation.AlgorithmStage;
 import animation.BackwardAction;
 import animation.PseudoCodeNode;
+import animation.PseudoCodeNode.CodeAction;
 import graph.LayeredGraphEdge;
 import graph.LayeredGraphNode;
 
@@ -32,7 +33,8 @@ public class ConflictDetection implements AlgorithmStage {
         int oldI = i;
         int oldL1 = l1;
         ((PseudoCodeNode)markNode.getParent()).setSelected( true );
-        boolean breakPoint = !markNode.setSelected( true );
+        CodeAction action = markNode.setSelected( true );
+        boolean breakPoint = action == CodeAction.STOP;
         if( i + 1 >= graph.getContainedLayers().size() - 1 )
         {
             ((PseudoCodeNode)markNode.getParent()).setSelected( false );
@@ -83,6 +85,8 @@ public class ConflictDetection implements AlgorithmStage {
         });
         if( status != StageStatus.FINISHED && breakPoint )
             return StageStatus.BREAKPOINT;
+        if( action == CodeAction.SKIP && status != StageStatus.FINISHED )
+            return forwardStep();
         return status;
     }
     
@@ -108,7 +112,8 @@ public class ConflictDetection implements AlgorithmStage {
     @Override
     public StageStatus backwardStep() {
         ((PseudoCodeNode)markNode.getParent()).setSelected( true );
-        boolean breakPoint = !markNode.setSelected( true );
+        CodeAction action = markNode.setSelected( true );
+        boolean breakPoint = action == CodeAction.STOP;
         if( actions.size() == 0 )
         {
             ((PseudoCodeNode)markNode.getParent()).setSelected( false );
@@ -119,6 +124,8 @@ public class ConflictDetection implements AlgorithmStage {
         actions.remove( 0 );
         if( breakPoint )
             return StageStatus.BREAKPOINT;
+        if( action == CodeAction.SKIP )
+            return backwardStep();
         return StageStatus.UNFINISHED;
     }
 

+ 73 - 55
src/bk/ExtremalLayoutCalc.java

@@ -6,6 +6,7 @@ import javax.swing.JTree;
 
 import animation.AlgorithmStage;
 import animation.PseudoCodeNode;
+import animation.PseudoCodeNode.CodeAction;
 import graph.LayeredGraphNode;
 import lib.TextLayoutHelper;
 
@@ -159,42 +160,51 @@ public class ExtremalLayoutCalc implements AlgorithmStage {
     private StageStatus forward( String fName )
     {
         boolean breakpoint = false;
+        CodeAction action = null;
         try {
             if( status == LayoutState.BLOCK_CALCULATION )
             {
+                action = bcNode.setSelected( true );
                 if( !bcNode.isSelected() )
-                    breakpoint |= !bcNode.setSelected( true );
-                switch( (StageStatus)(BlockCalc.class.getMethod( fName ).invoke( bc ) ) )
-                {
-                case FINISHED:
-                    inside = false;
-                    bcNode.setSelected( false );
-                    cpNode.setSelected( true );
-                    status = LayoutState.COMPACTION;
-                    break;
-                case BREAKPOINT:
-                    inside = true;
-                    return StageStatus.BREAKPOINT;
-                case UNFINISHED:
-                    inside = true;
-                }
+                    breakpoint |= action == CodeAction.STOP;
+                do {
+                    switch( (StageStatus)(BlockCalc.class.getMethod( fName ).invoke( bc ) ) )
+                    {
+                    case FINISHED:
+                        inside = false;
+                        bcNode.setSelected( false );
+                        CodeAction ac = cpNode.setSelected( true );
+                        status = LayoutState.COMPACTION;
+                        if( ac == CodeAction.SKIP && !breakpoint )
+                            return forward( fName );
+                        break;
+                    case BREAKPOINT:
+                        inside = true;
+                        return StageStatus.BREAKPOINT;
+                    case UNFINISHED:
+                        inside = true;
+                    }
+                } while( !breakpoint && action == CodeAction.SKIP );
             }
             else if( status == LayoutState.COMPACTION )
             {
+                action = cpNode.setSelected( true );
                 if( !cpNode.isSelected() )
-                    breakpoint |= !cpNode.setSelected( true );
-                switch( (StageStatus)(Compaction.class.getMethod( fName ).invoke( cp ) ) )
-                {
-                case FINISHED:
-                    inside = false;
-                    cpNode.setSelected( false );
-                    return StageStatus.FINISHED;
-                case BREAKPOINT:
-                    inside = true;
-                    return StageStatus.BREAKPOINT;
-                case UNFINISHED:
-                    inside = true;
-                }
+                    breakpoint |= action == CodeAction.STOP;
+                do {
+                    switch( (StageStatus)(Compaction.class.getMethod( fName ).invoke( cp ) ) )
+                    {
+                    case FINISHED:
+                        inside = false;
+                        cpNode.setSelected( false );
+                        return StageStatus.FINISHED;
+                    case BREAKPOINT:
+                        inside = true;
+                        return StageStatus.BREAKPOINT;
+                    case UNFINISHED:
+                        inside = true;
+                    }
+                } while( !breakpoint && action == CodeAction.SKIP );
             }
         } catch (IllegalAccessException e) {
             e.printStackTrace();
@@ -215,41 +225,49 @@ public class ExtremalLayoutCalc implements AlgorithmStage {
     private StageStatus backward( String fName )
     {
         boolean breakpoint = false;
+        CodeAction action = null;
         try {
             if( status == LayoutState.BLOCK_CALCULATION )
             {
+                action = bcNode.setSelected( true );
                 if( !bcNode.isSelected() )
-                    breakpoint |= !bcNode.setSelected( true );
-                switch( (StageStatus)(BlockCalc.class.getMethod( fName ).invoke( bc ) ) )
-                {
-                case FINISHED:
-                    inside = false;
-                    bcNode.setSelected( false );
-                    return StageStatus.FINISHED;
-                case BREAKPOINT:
-                    inside = true;
-                    return StageStatus.BREAKPOINT;
-                case UNFINISHED:
-                    inside = true;
-                }
+                    breakpoint |= action == CodeAction.STOP;
+                do {
+                    switch( (StageStatus)(BlockCalc.class.getMethod( fName ).invoke( bc ) ) )
+                    {
+                    case FINISHED:
+                        inside = false;
+                        bcNode.setSelected( false );
+                        return StageStatus.FINISHED;
+                    case BREAKPOINT:
+                        inside = true;
+                        return StageStatus.BREAKPOINT;
+                    case UNFINISHED:
+                        inside = true;
+                    }
+                } while( !breakpoint && action == CodeAction.SKIP );
             }
             else if( status == LayoutState.COMPACTION )
             {
+                action = cpNode.setSelected( true );
                 if( !cpNode.isSelected() )
-                    breakpoint |= !cpNode.setSelected( true );
-                switch( (StageStatus)(Compaction.class.getMethod( fName ).invoke( cp ) ) )
-                {
-                case FINISHED:
-                    inside = false;
-                    cpNode.setSelected( false );
-                    status = LayoutState.BLOCK_CALCULATION;
-                    break;
-                case BREAKPOINT:
-                    inside = true;
-                    return StageStatus.BREAKPOINT;
-                case UNFINISHED:
-                    inside = true;
-                }
+                    breakpoint |= action == CodeAction.STOP;
+                do {
+                    switch( (StageStatus)(Compaction.class.getMethod( fName ).invoke( cp ) ) )
+                    {
+                    case FINISHED:
+                        inside = false;
+                        cpNode.setSelected( false );
+                        status = LayoutState.BLOCK_CALCULATION;
+                        action = null;
+                        break;
+                    case BREAKPOINT:
+                        inside = true;
+                        return StageStatus.BREAKPOINT;
+                    case UNFINISHED:
+                        inside = true;
+                    }
+                } while( !breakpoint && action == CodeAction.SKIP );
             }
         } catch (IllegalAccessException e) {
             e.printStackTrace();

+ 7 - 1
src/graph/LayeredEdge.java

@@ -38,7 +38,10 @@ public class LayeredEdge implements LayeredGraphEdge {
         bindPoints = new ArrayList[ 5 ];
         conflicted = new boolean[ 5 ];
         for( int i = 0; i < 5; i++ )
+        {
+            conflicted[ i ] = false;
             bindPoints[ i ] = new ArrayList<>();
+        }
         for( ArrayList<Point> bps : bindPoints )
         {
             bps.add( null );
@@ -80,7 +83,10 @@ public class LayeredEdge implements LayeredGraphEdge {
                 if( i2 == endIndex )
                     continue;
                 if( i < startIndex && i2 > endIndex || i > startIndex && i2 < endIndex )
-                    list.add( e );
+                {
+                    if( !list.contains( e ) )
+                        list.add( e );
+                }
             }
         }
         return list;

+ 9 - 11
src/view/MainView.java

@@ -237,7 +237,7 @@ public class MainView {
             }
             
         });
-        options = new NiceButton( "options" );
+        options = new NiceButton( "settings" );
         options.setLocation( 210, 60 );
         options.setMnemonic( KeyEvent.VK_O );
         options.setToolTipText( "Show Options Dialog (alt + o)" );
@@ -553,6 +553,7 @@ public class MainView {
                     }
                     pl.revalidate();
                 }
+                treeView.revalidate();
                 frame.repaint();
             }
         });
@@ -562,13 +563,15 @@ public class MainView {
 
             @Override
             public void actionPerformed(ActionEvent e) {
+                pl.remove( topLeft );
+                pl.remove( topRight );
+                pl.remove( bottomLeft );
+                pl.remove( bottomRight );
+                pl.remove( combined );
+                layne.remove( combined );
+                controller.setStepOption( optionsDialog.getRunStepsOption() );
                 if( optionsDialog.getLayerDisplayOption() == 0 )
                 {
-                    pl.remove( topLeft );
-                    pl.remove( topRight );
-                    pl.remove( bottomLeft );
-                    pl.remove( bottomRight );
-                    pl.remove( combined );
                     pl.setLayout( grout );
                     pl.add( topLeft );
                     pl.add( topRight );
@@ -579,11 +582,6 @@ public class MainView {
                 }
                 else
                 {
-                    pl.remove( topLeft );
-                    pl.remove( topRight );
-                    pl.remove( bottomLeft );
-                    pl.remove( bottomRight );
-                    layne.remove( combined );
                     pl.setLayout( new BorderLayout() );
                     switch( algorithm.getAlgorithmState() )
                     {

+ 18 - 3
src/view/OptionsDialog.java

@@ -1,6 +1,7 @@
 package view;
 
 import java.awt.GridLayout;
+import java.awt.Toolkit;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.util.ArrayList;
@@ -17,10 +18,12 @@ public class OptionsDialog extends JDialog {
     private ArrayList< ActionListener > listeners;
     private JComboBox<String> display;
     private JButton speichern;
+    private JComboBox<String> run;
     
     private static class Options
     {
         public int layoutDisplaySelection = 0;
+        public int runStepsSelection = 0;
     }
     
     private Options options;
@@ -28,11 +31,15 @@ public class OptionsDialog extends JDialog {
     OptionsDialog()
     {
         setTitle( "Optionen" );
-        setLayout( new GridLayout( 2, 2 ) );
+        setLayout( new GridLayout( 3, 2 ) );
         add( new JLabel( "Dilspay layouts:" ) );
         String[] displayValues = { "All", "Current" };
         display = new JComboBox<String>( displayValues );
         add( display );
+        add( new JLabel( "Run steps:" ) );
+        String[] runValues = { "All", "Only expanded" };
+        run = new JComboBox<String>( runValues );
+        add( run );
         add( new JLabel() );
         speichern = new JButton( "Ok" );
         speichern.addActionListener( new ActionListener() {
@@ -40,8 +47,10 @@ public class OptionsDialog extends JDialog {
             @Override
             public void actionPerformed(ActionEvent e) {
                 try {
-                    boolean change = options.layoutDisplaySelection != display.getSelectedIndex();
+                    boolean change = options.layoutDisplaySelection != display.getSelectedIndex() ||
+                            options.runStepsSelection != run.getSelectedIndex();
                     options.layoutDisplaySelection = display.getSelectedIndex();
+                    options.runStepsSelection = run.getSelectedIndex();
                     if( change )
                     {
                         for( ActionListener l : listeners )
@@ -58,9 +67,10 @@ public class OptionsDialog extends JDialog {
             
         });
         add( speichern );
-        setSize( 300, 200 );
+        setSize( 250, 150 );
         listeners = new ArrayList<ActionListener>();
         options = new Options();
+        setLocation( Toolkit.getDefaultToolkit().getScreenSize().width / 2 - getWidth() / 2, Toolkit.getDefaultToolkit().getScreenSize().height / 2 - getHeight() / 2 );
     }
     
     public int getLayerDisplayOption()
@@ -68,6 +78,11 @@ public class OptionsDialog extends JDialog {
         return options.layoutDisplaySelection;
     }
     
+    public int getRunStepsOption()
+    {
+        return options.runStepsSelection;
+    }
+    
     public void addActionListener( ActionListener al )
     {
         listeners.add( al );