Browse Source

Merge remote-tracking branch 'origin/master'

Eren Yilmaz 6 years ago
parent
commit
be9bb323a7
65 changed files with 3678 additions and 315 deletions
  1. 3 1
      .gitignore
  2. 995 1
      big.json
  3. 3 1
      doc/chapter/1introduction.tex
  4. 73 43
      doc/chapter/2architecture.tex
  5. 76 39
      doc/chapter/3ui.tex
  6. 26 17
      doc/chapter/4progress.tex
  7. 6 0
      doc/chapter/6contributors.tex
  8. 12 1
      doc/chapter/appendix.tex
  9. 10 0
      doc/doc.tex
  10. BIN
      doc/img/algorithms_animated.pdf
  11. BIN
      doc/img/animation_and_bk.pdf
  12. BIN
      doc/img/bk-example-ours.jpg
  13. BIN
      doc/img/bk-example-ours.png
  14. BIN
      doc/img/buttons.png
  15. BIN
      doc/img/components.pdf
  16. BIN
      doc/img/debug-table.png
  17. BIN
      doc/img/example.jpg
  18. BIN
      doc/img/example.png
  19. BIN
      doc/img/full-application-example.png
  20. BIN
      doc/img/graph.pdf
  21. BIN
      doc/img/logo.jpg
  22. BIN
      doc/img/logo.png
  23. BIN
      doc/img/model.pdf
  24. BIN
      doc/img/random-graph-dialog.png
  25. BIN
      doc/img/skizze.png
  26. BIN
      doc/img/view.pdf
  27. BIN
      doc/vpp/animation_and_bk.vpp
  28. BIN
      doc/vpp/components.vpp
  29. BIN
      doc/vpp/graph.vpp
  30. BIN
      doc/vpp/io.vpp
  31. BIN
      doc/vpp/view.vpp
  32. 141 0
      logo.json
  33. 193 1
      save.json
  34. 5 1
      src/animation/Action.java
  35. 13 0
      src/animation/AlgorithmStage.java
  36. 49 3
      src/animation/AnimatedAlgorithm.java
  37. 78 0
      src/animation/PseudoCodeNode.java
  38. 323 55
      src/bk/BKNodePlacement.java
  39. 63 2
      src/bk/BlockCalc.java
  40. 216 8
      src/bk/Combine.java
  41. 192 15
      src/bk/Compaction.java
  42. 64 1
      src/bk/ConflictDetection.java
  43. 195 19
      src/bk/ExtremalLayoutCalc.java
  44. 1 1
      src/graph/LayeredGraphNode.java
  45. 14 14
      src/graph/LayeredNode.java
  46. 2 0
      src/graph/RandomGraphGenerator.java
  47. BIN
      src/img/debug.png
  48. BIN
      src/img/load.png
  49. BIN
      src/img/pause.png
  50. BIN
      src/img/random.png
  51. BIN
      src/img/runBackward.png
  52. BIN
      src/img/runForward.png
  53. BIN
      src/img/save.png
  54. BIN
      src/img/stepBackward.png
  55. BIN
      src/img/stepBackwardInto.png
  56. BIN
      src/img/stepBackwardOut.png
  57. BIN
      src/img/stepForward.png
  58. BIN
      src/img/stepForwardInto.png
  59. BIN
      src/img/stepForwardOut.png
  60. 2 8
      src/main/Main.java
  61. 670 78
      src/view/MainView.java
  62. 80 0
      src/view/NiceButton.java
  63. 11 5
      src/view/NodeView.java
  64. 88 0
      src/view/PseudoCodeRenderer.java
  65. 74 1
      test.json

+ 3 - 1
.gitignore

@@ -4,4 +4,6 @@ out
 auxil
 auxil
 svg-inkscape
 svg-inkscape
 *.synctex*
 *.synctex*
-*.vpp.bak*
+*.vpp.bak*
+*.vpp.lck
+*.vpp.vbak

+ 995 - 1
big.json

@@ -1 +1,995 @@
-{"layers":[[{"layers":[],"edges":[],"name":"0"}],[{"layers":[],"edges":[],"name":"1"},{"layers":[],"edges":[],"name":"2"},{"layers":[],"edges":[],"name":"3"}],[{"layers":[],"edges":[],"name":"4"},{"layers":[],"edges":[],"name":"5"}],[{"layers":[],"edges":[],"name":"6"},{"layers":[],"edges":[],"name":"7"},{"layers":[],"edges":[],"name":"8"}],[{"layers":[[{"layers":[],"edges":[],"name":"0"},{"layers":[],"edges":[],"name":"1"},{"layers":[],"edges":[],"name":"2"},{"layers":[],"edges":[],"name":"3"}],[{"layers":[],"edges":[],"name":"4"},{"layers":[],"edges":[],"name":"5"},{"layers":[[{"layers":[],"edges":[],"name":"0"},{"layers":[],"edges":[],"name":"1"}],[{"layers":[],"edges":[],"name":"2"}]],"edges":[{"source":"0","target":"2"},{"source":"1","target":"2"}],"name":"6"}],[{"layers":[],"edges":[],"name":"7"},{"layers":[],"edges":[],"name":"8"}],[{"layers":[],"edges":[],"name":"9"}],[{"layers":[],"edges":[],"name":"10"}],[{"layers":[],"edges":[],"name":"11"},{"layers":[],"edges":[],"name":"12"},{"layers":[[{"layers":[],"edges":[],"name":"0"},{"layers":[],"edges":[],"name":"1"}]],"edges":[],"name":"13"},{"layers":[[{"layers":[],"edges":[],"name":"0"}],[{"layers":[],"edges":[],"name":"1"}],[{"layers":[],"edges":[],"name":"2"},{"layers":[],"edges":[],"name":"3"}],[{"layers":[],"edges":[],"name":"4"},{"layers":[],"edges":[],"name":"5"},{"layers":[],"edges":[],"name":"6"},{"layers":[],"edges":[],"name":"7"}],[{"layers":[],"edges":[],"name":"8"},{"layers":[],"edges":[],"name":"9"},{"layers":[],"edges":[],"name":"10"},{"layers":[],"edges":[],"name":"11"}],[{"layers":[],"edges":[],"name":"12"}]],"edges":[{"source":"1","target":"3"},{"source":"3","target":"4"},{"source":"3","target":"5"},{"source":"3","target":"6"},{"source":"7","target":"8"},{"source":"5","target":"9"},{"source":"5","target":"10"},{"source":"7","target":"11"},{"source":"8","target":"12"},{"source":"11","target":"12"}],"name":"14"}]],"edges":[{"source":"0","target":"4"},{"source":"2","target":"4"},{"source":"0","target":"5"}],"name":"9"},{"layers":[],"edges":[],"name":"10"},{"layers":[],"edges":[],"name":"11"}],[{"layers":[[{"layers":[],"edges":[],"name":"0"}],[{"layers":[],"edges":[],"name":"1"},{"layers":[],"edges":[],"name":"2"}],[{"layers":[],"edges":[],"name":"3"},{"layers":[],"edges":[],"name":"4"}],[{"layers":[],"edges":[],"name":"5"},{"layers":[],"edges":[],"name":"6"},{"layers":[],"edges":[],"name":"7"}]],"edges":[{"source":"0","target":"2"},{"source":"4","target":"5"},{"source":"3","target":"6"},{"source":"3","target":"7"}],"name":"12"},{"layers":[],"edges":[],"name":"13"},{"layers":[],"edges":[],"name":"14"}],[{"layers":[],"edges":[],"name":"15"},{"layers":[],"edges":[],"name":"16"},{"layers":[[{"layers":[],"edges":[],"name":"0"}],[{"layers":[],"edges":[],"name":"1"},{"layers":[],"edges":[],"name":"2"},{"layers":[],"edges":[],"name":"3"},{"layers":[],"edges":[],"name":"4"}],[{"layers":[],"edges":[],"name":"5"}],[{"layers":[],"edges":[],"name":"6"},{"layers":[],"edges":[],"name":"7"},{"layers":[],"edges":[],"name":"8"},{"layers":[[{"layers":[],"edges":[],"name":"0"}],[{"layers":[],"edges":[],"name":"1"}],[{"layers":[],"edges":[],"name":"2"}],[{"layers":[],"edges":[],"name":"3"},{"layers":[],"edges":[],"name":"4"}],[{"layers":[],"edges":[],"name":"5"},{"layers":[],"edges":[],"name":"6"},{"layers":[],"edges":[],"name":"7"}],[{"layers":[],"edges":[],"name":"8"}],[{"layers":[],"edges":[],"name":"9"},{"layers":[],"edges":[],"name":"10"},{"layers":[],"edges":[],"name":"11"}],[{"layers":[],"edges":[],"name":"12"},{"layers":[],"edges":[],"name":"13"},{"layers":[],"edges":[],"name":"14"},{"layers":[],"edges":[],"name":"15"}]],"edges":[{"source":"3","target":"6"},{"source":"4","target":"6"},{"source":"8","target":"9"},{"source":"9","target":"14"},{"source":"11","target":"14"},{"source":"9","target":"15"}],"name":"9"}],[{"layers":[],"edges":[],"name":"10"},{"layers":[[{"layers":[],"edges":[],"name":"0"},{"layers":[],"edges":[],"name":"1"},{"layers":[],"edges":[],"name":"2"},{"layers":[],"edges":[],"name":"3"}],[{"layers":[],"edges":[],"name":"4"},{"layers":[],"edges":[],"name":"5"}],[{"layers":[],"edges":[],"name":"6"},{"layers":[],"edges":[],"name":"7"},{"layers":[],"edges":[],"name":"8"},{"layers":[],"edges":[],"name":"9"}],[{"layers":[],"edges":[],"name":"10"},{"layers":[],"edges":[],"name":"11"},{"layers":[],"edges":[],"name":"12"}],[{"layers":[],"edges":[],"name":"13"}],[{"layers":[],"edges":[],"name":"14"},{"layers":[],"edges":[],"name":"15"}],[{"layers":[],"edges":[],"name":"16"}]],"edges":[{"source":"0","target":"5"},{"source":"1","target":"5"},{"source":"2","target":"5"},{"source":"4","target":"7"},{"source":"4","target":"8"},{"source":"7","target":"10"},{"source":"6","target":"11"},{"source":"7","target":"12"},{"source":"9","target":"12"},{"source":"10","target":"13"},{"source":"12","target":"13"},{"source":"13","target":"14"}],"name":"11"}],[{"layers":[],"edges":[],"name":"12"},{"layers":[[{"layers":[],"edges":[],"name":"0"},{"layers":[],"edges":[],"name":"1"},{"layers":[],"edges":[],"name":"2"}],[{"layers":[],"edges":[],"name":"3"},{"layers":[],"edges":[],"name":"4"},{"layers":[],"edges":[],"name":"5"}],[{"layers":[],"edges":[],"name":"6"}],[{"layers":[],"edges":[],"name":"7"},{"layers":[],"edges":[],"name":"8"}]],"edges":[{"source":"2","target":"3"},{"source":"0","target":"4"},{"source":"3","target":"6"}],"name":"13"},{"layers":[],"edges":[],"name":"14"},{"layers":[],"edges":[],"name":"15"}],[{"layers":[],"edges":[],"name":"16"},{"layers":[],"edges":[],"name":"17"},{"layers":[],"edges":[],"name":"18"}]],"edges":[{"source":"0","target":"2"},{"source":"1","target":"5"},{"source":"5","target":"9"},{"source":"6","target":"10"},{"source":"9","target":"10"},{"source":"6","target":"11"},{"source":"11","target":"13"},{"source":"11","target":"15"},{"source":"13","target":"16"},{"source":"12","target":"17"}],"name":"17"}]],"edges":[{"source":"0","target":"1"},{"source":"0","target":"2"},{"source":"0","target":"3"},{"source":"4","target":"6"},{"source":"5","target":"6"},{"source":"8","target":"9"},{"source":"7","target":"10"},{"source":"7","target":"11"},{"source":"8","target":"11"},{"source":"9","target":"13"},{"source":"11","target":"13"},{"source":"9","target":"14"},{"source":"10","target":"14"},{"source":"14","target":"15"},{"source":"12","target":"16"},{"source":"13","target":"16"},{"source":"14","target":"17"}]}
+{
+  "layers": [
+    [
+      {
+        "layers": [],
+        "edges": [],
+        "name": "0"
+      }
+    ],
+    [
+      {
+        "layers": [],
+        "edges": [],
+        "name": "1"
+      },
+      {
+        "layers": [],
+        "edges": [],
+        "name": "2"
+      },
+      {
+        "layers": [],
+        "edges": [],
+        "name": "3"
+      }
+    ],
+    [
+      {
+        "layers": [],
+        "edges": [],
+        "name": "4"
+      },
+      {
+        "layers": [],
+        "edges": [],
+        "name": "5"
+      }
+    ],
+    [
+      {
+        "layers": [],
+        "edges": [],
+        "name": "6"
+      },
+      {
+        "layers": [],
+        "edges": [],
+        "name": "7"
+      },
+      {
+        "layers": [],
+        "edges": [],
+        "name": "8"
+      }
+    ],
+    [
+      {
+        "layers": [
+          [
+            {
+              "layers": [],
+              "edges": [],
+              "name": "0"
+            },
+            {
+              "layers": [],
+              "edges": [],
+              "name": "1"
+            },
+            {
+              "layers": [],
+              "edges": [],
+              "name": "2"
+            },
+            {
+              "layers": [],
+              "edges": [],
+              "name": "3"
+            }
+          ],
+          [
+            {
+              "layers": [],
+              "edges": [],
+              "name": "4"
+            },
+            {
+              "layers": [],
+              "edges": [],
+              "name": "5"
+            },
+            {
+              "layers": [
+                [
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "0"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "1"
+                  }
+                ],
+                [
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "2"
+                  }
+                ]
+              ],
+              "edges": [
+                {
+                  "source": "0",
+                  "target": "2"
+                },
+                {
+                  "source": "1",
+                  "target": "2"
+                }
+              ],
+              "name": "6"
+            }
+          ],
+          [
+            {
+              "layers": [],
+              "edges": [],
+              "name": "7"
+            },
+            {
+              "layers": [],
+              "edges": [],
+              "name": "8"
+            }
+          ],
+          [
+            {
+              "layers": [],
+              "edges": [],
+              "name": "9"
+            }
+          ],
+          [
+            {
+              "layers": [],
+              "edges": [],
+              "name": "10"
+            }
+          ],
+          [
+            {
+              "layers": [],
+              "edges": [],
+              "name": "11"
+            },
+            {
+              "layers": [],
+              "edges": [],
+              "name": "12"
+            },
+            {
+              "layers": [
+                [
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "0"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "1"
+                  }
+                ]
+              ],
+              "edges": [],
+              "name": "13"
+            },
+            {
+              "layers": [
+                [
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "0"
+                  }
+                ],
+                [
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "1"
+                  }
+                ],
+                [
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "2"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "3"
+                  }
+                ],
+                [
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "4"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "5"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "6"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "7"
+                  }
+                ],
+                [
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "8"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "9"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "10"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "11"
+                  }
+                ],
+                [
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "12"
+                  }
+                ]
+              ],
+              "edges": [
+                {
+                  "source": "1",
+                  "target": "3"
+                },
+                {
+                  "source": "3",
+                  "target": "4"
+                },
+                {
+                  "source": "3",
+                  "target": "5"
+                },
+                {
+                  "source": "3",
+                  "target": "6"
+                },
+                {
+                  "source": "7",
+                  "target": "8"
+                },
+                {
+                  "source": "5",
+                  "target": "9"
+                },
+                {
+                  "source": "5",
+                  "target": "10"
+                },
+                {
+                  "source": "7",
+                  "target": "11"
+                },
+                {
+                  "source": "8",
+                  "target": "12"
+                },
+                {
+                  "source": "11",
+                  "target": "12"
+                }
+              ],
+              "name": "14"
+            }
+          ]
+        ],
+        "edges": [
+          {
+            "source": "0",
+            "target": "4"
+          },
+          {
+            "source": "2",
+            "target": "4"
+          },
+          {
+            "source": "0",
+            "target": "5"
+          }
+        ],
+        "name": "9"
+      },
+      {
+        "layers": [],
+        "edges": [],
+        "name": "10"
+      },
+      {
+        "layers": [],
+        "edges": [],
+        "name": "11"
+      }
+    ],
+    [
+      {
+        "layers": [
+          [
+            {
+              "layers": [],
+              "edges": [],
+              "name": "0"
+            }
+          ],
+          [
+            {
+              "layers": [],
+              "edges": [],
+              "name": "1"
+            },
+            {
+              "layers": [],
+              "edges": [],
+              "name": "2"
+            }
+          ],
+          [
+            {
+              "layers": [],
+              "edges": [],
+              "name": "3"
+            },
+            {
+              "layers": [],
+              "edges": [],
+              "name": "4"
+            }
+          ],
+          [
+            {
+              "layers": [],
+              "edges": [],
+              "name": "5"
+            },
+            {
+              "layers": [],
+              "edges": [],
+              "name": "6"
+            },
+            {
+              "layers": [],
+              "edges": [],
+              "name": "7"
+            }
+          ]
+        ],
+        "edges": [
+          {
+            "source": "0",
+            "target": "2"
+          },
+          {
+            "source": "4",
+            "target": "5"
+          },
+          {
+            "source": "3",
+            "target": "6"
+          },
+          {
+            "source": "3",
+            "target": "7"
+          }
+        ],
+        "name": "12"
+      },
+      {
+        "layers": [],
+        "edges": [],
+        "name": "13"
+      },
+      {
+        "layers": [],
+        "edges": [],
+        "name": "14"
+      }
+    ],
+    [
+      {
+        "layers": [],
+        "edges": [],
+        "name": "15"
+      },
+      {
+        "layers": [],
+        "edges": [],
+        "name": "16"
+      },
+      {
+        "layers": [
+          [
+            {
+              "layers": [],
+              "edges": [],
+              "name": "0"
+            }
+          ],
+          [
+            {
+              "layers": [],
+              "edges": [],
+              "name": "1"
+            },
+            {
+              "layers": [],
+              "edges": [],
+              "name": "2"
+            },
+            {
+              "layers": [],
+              "edges": [],
+              "name": "3"
+            },
+            {
+              "layers": [],
+              "edges": [],
+              "name": "4"
+            }
+          ],
+          [
+            {
+              "layers": [],
+              "edges": [],
+              "name": "5"
+            }
+          ],
+          [
+            {
+              "layers": [],
+              "edges": [],
+              "name": "6"
+            },
+            {
+              "layers": [],
+              "edges": [],
+              "name": "7"
+            },
+            {
+              "layers": [],
+              "edges": [],
+              "name": "8"
+            },
+            {
+              "layers": [
+                [
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "0"
+                  }
+                ],
+                [
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "1"
+                  }
+                ],
+                [
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "2"
+                  }
+                ],
+                [
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "3"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "4"
+                  }
+                ],
+                [
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "5"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "6"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "7"
+                  }
+                ],
+                [
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "8"
+                  }
+                ],
+                [
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "9"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "10"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "11"
+                  }
+                ],
+                [
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "12"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "13"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "14"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "15"
+                  }
+                ]
+              ],
+              "edges": [
+                {
+                  "source": "3",
+                  "target": "6"
+                },
+                {
+                  "source": "4",
+                  "target": "6"
+                },
+                {
+                  "source": "8",
+                  "target": "9"
+                },
+                {
+                  "source": "9",
+                  "target": "14"
+                },
+                {
+                  "source": "11",
+                  "target": "14"
+                },
+                {
+                  "source": "9",
+                  "target": "15"
+                }
+              ],
+              "name": "9"
+            }
+          ],
+          [
+            {
+              "layers": [],
+              "edges": [],
+              "name": "10"
+            },
+            {
+              "layers": [
+                [
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "0"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "1"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "2"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "3"
+                  }
+                ],
+                [
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "4"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "5"
+                  }
+                ],
+                [
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "6"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "7"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "8"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "9"
+                  }
+                ],
+                [
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "10"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "11"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "12"
+                  }
+                ],
+                [
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "13"
+                  }
+                ],
+                [
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "14"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "15"
+                  }
+                ],
+                [
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "16"
+                  }
+                ]
+              ],
+              "edges": [
+                {
+                  "source": "0",
+                  "target": "5"
+                },
+                {
+                  "source": "1",
+                  "target": "5"
+                },
+                {
+                  "source": "2",
+                  "target": "5"
+                },
+                {
+                  "source": "4",
+                  "target": "7"
+                },
+                {
+                  "source": "4",
+                  "target": "8"
+                },
+                {
+                  "source": "7",
+                  "target": "10"
+                },
+                {
+                  "source": "6",
+                  "target": "11"
+                },
+                {
+                  "source": "7",
+                  "target": "12"
+                },
+                {
+                  "source": "9",
+                  "target": "12"
+                },
+                {
+                  "source": "10",
+                  "target": "13"
+                },
+                {
+                  "source": "12",
+                  "target": "13"
+                },
+                {
+                  "source": "13",
+                  "target": "14"
+                }
+              ],
+              "name": "11"
+            }
+          ],
+          [
+            {
+              "layers": [],
+              "edges": [],
+              "name": "12"
+            },
+            {
+              "layers": [
+                [
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "0"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "1"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "2"
+                  }
+                ],
+                [
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "3"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "4"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "5"
+                  }
+                ],
+                [
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "6"
+                  }
+                ],
+                [
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "7"
+                  },
+                  {
+                    "layers": [],
+                    "edges": [],
+                    "name": "8"
+                  }
+                ]
+              ],
+              "edges": [
+                {
+                  "source": "2",
+                  "target": "3"
+                },
+                {
+                  "source": "0",
+                  "target": "4"
+                },
+                {
+                  "source": "3",
+                  "target": "6"
+                }
+              ],
+              "name": "13"
+            },
+            {
+              "layers": [],
+              "edges": [],
+              "name": "14"
+            },
+            {
+              "layers": [],
+              "edges": [],
+              "name": "15"
+            }
+          ],
+          [
+            {
+              "layers": [],
+              "edges": [],
+              "name": "16"
+            },
+            {
+              "layers": [],
+              "edges": [],
+              "name": "17"
+            },
+            {
+              "layers": [],
+              "edges": [],
+              "name": "18"
+            }
+          ]
+        ],
+        "edges": [
+          {
+            "source": "0",
+            "target": "2"
+          },
+          {
+            "source": "1",
+            "target": "5"
+          },
+          {
+            "source": "5",
+            "target": "9"
+          },
+          {
+            "source": "6",
+            "target": "10"
+          },
+          {
+            "source": "9",
+            "target": "10"
+          },
+          {
+            "source": "6",
+            "target": "11"
+          },
+          {
+            "source": "11",
+            "target": "13"
+          },
+          {
+            "source": "11",
+            "target": "15"
+          },
+          {
+            "source": "13",
+            "target": "16"
+          },
+          {
+            "source": "12",
+            "target": "17"
+          }
+        ],
+        "name": "17"
+      }
+    ]
+  ],
+  "edges": [
+    {
+      "source": "0",
+      "target": "1"
+    },
+    {
+      "source": "0",
+      "target": "2"
+    },
+    {
+      "source": "0",
+      "target": "3"
+    },
+    {
+      "source": "4",
+      "target": "6"
+    },
+    {
+      "source": "5",
+      "target": "6"
+    },
+    {
+      "source": "8",
+      "target": "9"
+    },
+    {
+      "source": "7",
+      "target": "10"
+    },
+    {
+      "source": "7",
+      "target": "11"
+    },
+    {
+      "source": "8",
+      "target": "11"
+    },
+    {
+      "source": "9",
+      "target": "13"
+    },
+    {
+      "source": "11",
+      "target": "13"
+    },
+    {
+      "source": "9",
+      "target": "14"
+    },
+    {
+      "source": "10",
+      "target": "14"
+    },
+    {
+      "source": "14",
+      "target": "15"
+    },
+    {
+      "source": "12",
+      "target": "16"
+    },
+    {
+      "source": "13",
+      "target": "16"
+    },
+    {
+      "source": "14",
+      "target": "17"
+    }
+  ]
+}

+ 3 - 1
doc/chapter/1introduction.tex

@@ -7,5 +7,7 @@ Then each stage of the node placing algorithm by Brandes and Köpf~\cite{brandes
 After each step the current progress of the algorithm is displayed visually.
 After each step the current progress of the algorithm is displayed visually.
 
 
 In chapter~\ref{ch:architecture} we provide an overview over the \appname 's internal architecture while chapter~\ref{ch:ui} presents and explains the graphical user interface.
 In chapter~\ref{ch:architecture} we provide an overview over the \appname 's internal architecture while chapter~\ref{ch:ui} presents and explains the graphical user interface.
-\appname is currently a work in progress so keep in mind that any of the here presented information may be slightly outdated\footnote{even this one}.
 To provide an overview of what is going on, chapter~\ref{ch:progress} lists features and their degree of completion.
 To provide an overview of what is going on, chapter~\ref{ch:progress} lists features and their degree of completion.
+
+\appname is currently a work in progress so keep in mind that any of the here presented screenshot, diagram or other information may be slightly outdated\footnote{even this one}.
+Also note that some pdf viewers have problems with vector graphics exported from visual paradigm, so if you feel like there is a missing line in a class or component diagram, you are wrong.

+ 73 - 43
doc/chapter/2architecture.tex

@@ -6,11 +6,27 @@ The following assumptions are made for the implementation of the node placement
     \item There are no labels.
     \item There are no labels.
     \item There are no cross-hierarchy edges.
     \item There are no cross-hierarchy edges.
     \item No edges over multiple layers (the previous phases should have added dummy nodes).
     \item No edges over multiple layers (the previous phases should have added dummy nodes).
-    \item Graphs are connected (maybe we will get rid of this assumption later, see~\ref{ch:progress}).
+    \item Graphs are connected (maybe we will get rid of this assumption later, see chapter~\ref{ch:progress}).
 \end{itemize}
 \end{itemize}
 
 
-\section{Components}\label{sec:components}
-\TODO{rough architecture}
+
+\section{Overview}\label{sec:components}
+The \code{main} package contains an executable class \code{Main}.
+This classes main method creates a graph or reads it from a file using the \code{graph.io} package and then creates a MainView.
+The view then instantiates a \code{BKNodePlacement} algorithm and runs it.
+The \code{BKNodePlacement} repeatedly asks the \code{AnimationController} if a step should be done (this is further explained in section~\ref{sec:theActualAlgorithm}).
+For each step it uses works with \code{LayeredGraphNode}s and \code{LayeredGraphEdge}s.
+Meanwhile the view displays the same \code{LayeredGraphNode}s and \code{LayeredGraphEdge}s on the screen.
+
+Figure~\ref{fig:components} contains a component diagram that illustrates these dependencies of the packages.
+
+\begin{figure}[htp]
+    \centering
+    \includegraphics[width=\linewidth,trim=0 11cm 0 0,clip]{img/components.pdf}
+    \caption[Component diagram]{Component diagram visualizing the architecture of \appname. Each component resembles a java package.}
+    \label{fig:components}
+\end{figure}
+
 
 
 \section{Input File Format}\label{sec:inputFileFormat}
 \section{Input File Format}\label{sec:inputFileFormat}
 The input to \appname is a JSON file.
 The input to \appname is a JSON file.
@@ -25,7 +41,7 @@ The structure is as follows:
 \end{itemize}
 \end{itemize}
 For parsing the JSON file the JSON-java library~\cite{leary_json-java:_2018} is used.
 For parsing the JSON file the JSON-java library~\cite{leary_json-java:_2018} is used.
 The classes for reading and writing those JSON files are displayed in figure~\ref{fig:io}.
 The classes for reading and writing those JSON files are displayed in figure~\ref{fig:io}.
-The internal representation of graphs is further explained in the section~\ref{sec:model}.
+The internal representation of graphs is further explained in the section~\ref{sec:graph}.
 
 
 \centering
 \centering
 \begin{longtable}{|l|l|l|p{8.5cm}|}
 \begin{longtable}{|l|l|l|p{8.5cm}|}
@@ -34,16 +50,16 @@ The internal representation of graphs is further explained in the section~\ref{s
     name & string & yes & If not omitted, this must be unique for a given parent node. \\\hline
     name & string & yes & If not omitted, this must be unique for a given parent node. \\\hline
     width & integer & yes & The minimum width of the node.
     width & integer & yes & The minimum width of the node.
     The node can be wider if it contains other nodes that need more space.
     The node can be wider if it contains other nodes that need more space.
-    If the whole layout is too large, it is resized, such that all nodes are proportionately shrunk: In that case the minimum width can be undercut.
+    If the whole layout is too large, it is resized, such that all nodes are proportionately shrunk: In that case the minimum width can be exceeded after the shrinking.
     Default 40.\\\hline
     Default 40.\\\hline
     height & integer & yes & The minimum height of the node.
     height & integer & yes & The minimum height of the node.
     The node can be higher if it contains other nodes that need more space.
     The node can be higher if it contains other nodes that need more space.
-    If the whole layout is too large, it is resized, such that all nodes are proportionately shrunk: In that case the minimum height can be undercut.
+    If the whole layout is too large, it is resized, such that all nodes are proportionately shrunk: In that case the minimum height can be exceeded after the shrinking.
     Default 40.\\\hline
     Default 40.\\\hline
-    dummy & boolean & yes & Iff this is set to yes, then the node is a dummy node. \\\hline
+    dummy & boolean & yes & Iff this is explicitly set to yes, then the node is a dummy node. \\\hline
     layers & < < node > > & yes & The layers of nodes inside this node (Hierarchy). \\\hline
     layers & < < node > > & yes & The layers of nodes inside this node (Hierarchy). \\\hline
-    edges & < edge > & yes & The edges between nodes whose parent node is this node. \\\hline
-    \caption{Node Attributes. < \emph{element type} > is a list.}
+    edges & < edge > & yes & The edges between nodes whose parent node is this node. Also see section~\ref{sec:assumptions}. \\\hline
+    \caption[Node Attributes]{Node Attributes. < \emph{element type} > is a list.}
     \label{table:node-attributes}
     \label{table:node-attributes}
 \end{longtable}
 \end{longtable}
 \raggedright
 \raggedright
@@ -51,7 +67,7 @@ The internal representation of graphs is further explained in the section~\ref{s
 \begin{figure}[htp]
 \begin{figure}[htp]
     \centering
     \centering
     \includegraphics[width=\linewidth,trim=0 20cm 0 0,clip]{img/io.pdf}
     \includegraphics[width=\linewidth,trim=0 20cm 0 0,clip]{img/io.pdf}
-    \caption[Class diagram of the \enquote{graph.io} package]{Class diagram of the \enquote{graph.io} package, containing utilities for reading and writing graphs.}
+    \caption[Class diagram of the \code{graph.io} package]{Class diagram of the \code{graph.io} package, containing utilities for reading and writing graphs.}
     \label{fig:io}
     \label{fig:io}
 \end{figure}
 \end{figure}
 
 
@@ -61,9 +77,9 @@ The internal representation of graphs is further explained in the section~\ref{s
         \hline
         \hline
         Attribute & Type & Optional & Explanation \\\hline\hline
         Attribute & Type & Optional & Explanation \\\hline\hline
         source & string & no & The name of the source of this edge.
         source & string & no & The name of the source of this edge.
-        Must be a node with the same parent node as the node specified by the \enquote{target} attribute. \\\hline
+        Must be a node with the same parent node as the node specified by the \code{target} attribute. \\\hline
         target & string & no & The name of the target of this edge.
         target & string & no & The name of the target of this edge.
-        Must be a node with the same parent node as the node specified by the \enquote{source} attribute. \\\hline
+        Must be a node with the same parent node as the node specified by the \code{source} attribute. \\\hline
     \end{longtable}
     \end{longtable}
     \caption{Edge Attributes}
     \caption{Edge Attributes}
     \label{table:edge-attributes}
     \label{table:edge-attributes}
@@ -83,35 +99,40 @@ The internal representation of graphs is further explained in the section~\ref{s
     \label{fig:json-example}
     \label{fig:json-example}
 \end{figure}
 \end{figure}
 
 
-\section{Internal graph representation, \enquote{graph}}\label{sec:model}
+
+\section{Internal graph representation, \code{graph}}\label{sec:graph}
 One feature that is important to us, is to be able to work with hierarchical graphs (cf.\ chapter~\ref{ch:progress}).
 One feature that is important to us, is to be able to work with hierarchical graphs (cf.\ chapter~\ref{ch:progress}).
 Therefore a node not only has edges to other nodes, but also it can contain other nodes and edges.
 Therefore a node not only has edges to other nodes, but also it can contain other nodes and edges.
 So far this is similar to what we described in section~\ref{sec:inputFileFormat}.
 So far this is similar to what we described in section~\ref{sec:inputFileFormat}.
 Additionally, there are multiple attributes that are used during the computation or as output variables.
 Additionally, there are multiple attributes that are used during the computation or as output variables.
 \begin{itemize}
 \begin{itemize}
-    \item The attributes \enquote{shift},  \enquote{sink},  \enquote{root} and  \enquote{align} correspond to the variables used by Brandes and Köpf~\cite{brandes_fast_2001}.
+    \item The attributes \member{shift}, \member{sink},  \member{root} and  \member{align} correspond to the variables used by Brandes and Köpf~\cite{brandes_fast_2001}.
     They are summarized in table~\ref{table:bk-variables}.
     They are summarized in table~\ref{table:bk-variables}.
-    \item The \enquote{parent} of a node is the node that contains it in the hierarchy.
-    \item The attributes $x$ and $y$ are the coordinates of the node relative to its parent node.
-    There is one coordinate for each of the four extremal layouts and on coordinate for the combined layout.
+    \item The \member{parent} of a node is the node that contains it in the hierarchy.
+    \item The attributes \member{x} and \member{y} are the coordinates of the node relative to its \code{parent}.
+    \item The attributes \member{w} and \member{h} are the width and height of the node.
+    \item The attributes \member{color} is the color in which the node is displayed.
+    \item The attribute \member{xUndef} determines whether the x coordinate of the node has already been assigned a value.
+    \item The attribute \member{selected} is used to highlight the node that is currently active in each layout.
 \end{itemize}
 \end{itemize}
+The last five bullet points are available for each of the four extremal layouts and for the combined layout.
+
 Similarly, edges have additional attributes:
 Similarly, edges have additional attributes:
 \begin{itemize}
 \begin{itemize}
-    \item \enquote{dummy} specifies whether they are dummy edges.
-    \item \enquote{conflicted} corresponds to the variable used by Brandes and Köpf~\cite{brandes_fast_2001} and indicates that this edge won't be drawn vertically.
-    \item \enquote{bindPoints} is a list of bend points for the edge, including the beginning and end point of the edge.
+    \item \member{dummyNode} specifies whether they are dummy edges.
+    \item \member{conflicted} corresponds to the variable used by Brandes and Köpf~\cite{brandes_fast_2001} and indicates that this edge won't be drawn vertically.
+    \item \member{bindPoints} is a list of bend points for the edge, including the beginning and end point of the edge.
 \end{itemize}
 \end{itemize}
 
 
-A class diagram of the package \enquote{graph} is displayed in figure~\ref{fig:model}.
+A class diagram of the package \code{graph} is displayed in figure~\ref{fig:graph}.
 
 
 \begin{figure}[htp]
 \begin{figure}[htp]
     \centering
     \centering
-    \includegraphics[width=\linewidth,trim=0 6cm 0 0,clip]{img/model.pdf}
-    \caption{Class diagram of the \enquote{graph} package.}
-    \label{fig:model}
+    \includegraphics[width=\linewidth,trim=0 7.5cm 0 0,clip]{img/graph.pdf}
+    \caption{Class diagram of the \code{graph} package.}
+    \label{fig:graph}
 \end{figure}
 \end{figure}
 
 
-
 \begin{table}[htp]
 \begin{table}[htp]
     \begin{longtable}{|l|p{10cm}|}
     \begin{longtable}{|l|p{10cm}|}
         \hline
         \hline
@@ -128,45 +149,54 @@ A class diagram of the package \enquote{graph} is displayed in figure~\ref{fig:m
     \label{table:bk-variables}
     \label{table:bk-variables}
 \end{table}
 \end{table}
 
 
+
 \section{The actual algorithm}\label{sec:theActualAlgorithm}
 \section{The actual algorithm}\label{sec:theActualAlgorithm}
 This section expects the reader to be familiar with the node placement algorithm by Brandes and Köpf~\cite{brandes_fast_2001}.
 This section expects the reader to be familiar with the node placement algorithm by Brandes and Köpf~\cite{brandes_fast_2001}.
 We recommend section 3.2.1 of Carstens~\cite{carstens_node_2012} for a detailed explanation.
 We recommend section 3.2.1 of Carstens~\cite{carstens_node_2012} for a detailed explanation.
 
 
-A \enquote{stage} of the algorithm, interface \enquote{AlgorithmStage}, is an interval during which each step of the algorithm is performed in a similar way.
+A stage of the algorithm, interface \code{AlgorithmStage}, is an interval during which each step of the algorithm is performed in a similar way.
 Each time such a step is performed it returns whether the stage is already finished.
 Each time such a step is performed it returns whether the stage is already finished.
-For example, a forward step in the stage of calculating one extremal layout, class \enquote{ExtremalLayoutCalc}, consists of either a step of calculating the blocks, class \enquote{BlockCalc}, or a step of compacting the layout, class \enquote{Compaction}.
-All the stages are displayed in class diagram~\ref{fig:animated}.
+For example, a forward step in the stage of calculating one extremal layout, \code{ExtremalLayoutCalc}, consists of either a step of calculating the blocks, \code{BlockCalc}, or a step of compacting the layout, \code{Compaction}.
+All the stages are displayed in class diagram~\ref{fig:animation_and_bk}.
 
 
 To be able to undo a step each stage needs to implement methods for both forward and backward steps.
 To be able to undo a step each stage needs to implement methods for both forward and backward steps.
 
 
-Note that the \enquote{AnimationController} is not a controller in the MVC sense that it processes user input, but in the sense that it \enquote{controls} the execution of steps/stages.
+Note that the \code{AnimationController} is not a controller in the MVC sense that it processes user input, but in the sense that it \emph{controls} the execution of steps/stages.
 This works the following:
 This works the following:
 \begin{enumerate}
 \begin{enumerate}
-    \item The main view creates a node placement algorithm (only \enquote{BKNodePlacement} available).
-    It sends a controller as a parameter for the constructor.
-    \item The algorithm concurrently asks the AnimationController if it should do a forward or backward step.
-    \item The AnimationController waits until it knows which action to take (for example if the user pressed the right arrow key).
-    Alternatively, if the animation is not paused, then it waits until a specific delay has passed.
+    \item The \code{MainView} creates a node placement algorithm (only \code{BKNodePlacement} available).
+    It sends an \code{AnimationController} as a parameter for the constructor.
+    \item The algorithm concurrently asks the \code{AnimationController} if it should do a forward or backward step.
+    \item The \code{AnimationController} waits until it knows which action to take (for example if the user pressed the right arrow key).
+    Alternatively, if the animation is not paused, it waits until a specific delay has passed.
     Then it returns to the algorithm which step to take next.
     Then it returns to the algorithm which step to take next.
-    \item The algorithm potentially calls the step function of other alogrithms while executing one step.
+    \item The algorithm potentially calls one the step methods of other stages while executing one step.
 \end{enumerate}
 \end{enumerate}
 
 
-\TODO{outdated}
 \begin{figure}[htp]
 \begin{figure}[htp]
     \centering
     \centering
-    \includegraphics[width=\linewidth,trim=0 9cm 0 0,clip]{img/algorithms_animated.pdf}
-    \caption{Class diagram of the package \enquote{algorithms.animated}.}
-    \label{fig:animated}
+    \includegraphics[width=\linewidth,trim=0 13cm 0 0,clip]{img/animation_and_bk.pdf}
+    \caption{Class diagram of the packages \code{bk} and \code{animation}.}
+    \label{fig:animation_and_bk}
 \end{figure}
 \end{figure}
 
 
+
 \section{View}\label{sec:view}
 \section{View}\label{sec:view}
 This section only covers the software architecture regarding the views.
 This section only covers the software architecture regarding the views.
 For an explanation of what is actually displayed, see chapter~\ref{ch:ui}
 For an explanation of what is actually displayed, see chapter~\ref{ch:ui}
 
 
 The distinguish two kinds of views:
 The distinguish two kinds of views:
 \begin{itemize}
 \begin{itemize}
-    \item The main window displays four regions for the different extremal layouts while also forwarding keyboard commands to the AnimationController.
-    For this we use a JFrame from the Swing library.
-    \item \enquote{EdgeView} and \enquote{NodeView} are JPanels, which means they can be drawn onto the JFrame.
+    \item The main window displays four regions for the different extremal layouts while also forwarding keyboard commands to the \code{AnimationController}.
+    For this we use a \code{JFrame} from the Swing library.
+    \item \code{EdgeView} and \code{NodeView} are \code{JPanel}s, which means they can be drawn onto the \code{JFrame}.
     For this they have to know about which part of the graph and which layout they belong to.
     For this they have to know about which part of the graph and which layout they belong to.
-\end{itemize}
+\end{itemize}
+A class diagram of the packages \code{view} and \code{main} is displayed in figure~\ref{fig:view}.
+
+\begin{figure}[htp]
+    \centering
+    \includegraphics[width=\linewidth,trim=0 11cm 0 0,clip]{img/view.pdf}
+    \caption{Class diagram of the packages \code{view} and \code{main}.}
+    \label{fig:view}
+\end{figure}

+ 76 - 39
doc/chapter/3ui.tex

@@ -1,10 +1,42 @@
 Note that since the application is still under construction, so not all screenshots may be up to date.
 Note that since the application is still under construction, so not all screenshots may be up to date.
 
 
 \section{Graphical presentation of the running algorithm}\label{sec:graphicalPresentationOfTheRunningAlgorithm}
 \section{Graphical presentation of the running algorithm}\label{sec:graphicalPresentationOfTheRunningAlgorithm}
-\TODO{under construction}
-\TODO{reference~\ref{fig:example}}
-\TODO{reference~\ref{fig:originalpapergraph}}
-\TODO{reference~\ref{fig:sketch}}
+A first sketch of how we want \appname to look is shown in figure~\ref{fig:sketch}.
+The current development status is displayed in figure~\ref{fig:full-application-example}.
+Another example graph and an explanation of the shapes and colors is provided in figure~\ref{fig:example}.
+Figure~\ref{fig:originalpapergraph} compares our results to those of Brandes and Köpf~\cite{brandes_fast_2001}.
+
+\begin{figure}[htp]
+    \centering
+    \includegraphics[width=\linewidth]{img/skizze}
+    \caption[First sketch of the planned layout]{A first sketch of the planned layout, created with Microsoft Paint.
+    The buttons are (first row, from left to right): step over, step into, step out, run, pause, debug; and (second row, from left to right): step back, step back out, run backwards.
+    The actions corresponding to the buttons are the same as described for the keyboard input in table~\ref{table:keys}, at least for the features that are already implemented.
+    The left four rectangles show the progress of the four extremal layouts.
+    The right rectangle shows pseudocode of the algorithm and the position of the current step.}
+    \label{fig:sketch}
+\end{figure}
+
+\begin{figure}[htp]
+    \centering
+    \includegraphics[width=\linewidth]{img/full-application-example}
+    \caption[Full application window]{The full window of the application before any steps of the algorithm have been executed.
+    The displayed graph has been loaded from figure~\ref{fig:json-example}.}
+    \label{fig:full-application-example}
+\end{figure}
+
+\begin{figure}[htp]
+    \centering
+    \includegraphics[width=0.6\linewidth]{img/example}
+    \caption[A simple graph with 5 nodes]{A simple graph with 5 nodes after the four extremal layout have been computed, but not balanced yet.
+    The vertical directions are down (upper row), up (lower row) and the horizontal directions are left (left column) and right (right column).
+    The background colors of the nodes display which block they belong to: For example the two red nodes on the upper right are in the same block.
+    Round nodes are the roots of the blocks.
+    A colored circle on a node indicates the class that this node belongs to and is also the color of the associated sink in the block graph.
+    The node that is currently in the focus of the algorithm (whatever this means for the current stage) is highlighted in black color.
+    Although edges are not drawn during the node placement phase we added them here as straight lines to improve readability.}
+    \label{fig:example}
+\end{figure}
 
 
 \begin{figure}
 \begin{figure}
     \centering
     \centering
@@ -18,49 +50,54 @@ Note that since the application is still under construction, so not all screensh
         \centering
         \centering
         \includegraphics[width=0.4\linewidth]{img/bk-example-ours}
         \includegraphics[width=0.4\linewidth]{img/bk-example-ours}
         \caption[The same graph as~\ref{fig:theirs}, displayed by \appname.]{The same graph as~\ref{fig:theirs}, displayed by \appname.
         \caption[The same graph as~\ref{fig:theirs}, displayed by \appname.]{The same graph as~\ref{fig:theirs}, displayed by \appname.
-        The layouts are leftmost (first column), rightmost (second column), lower (first row) and upper (second row), respectively.}
+        The layouts are leftmost (first column), rightmost (third column), upper (first row) and lower (third row), respectively.
+        The balanced layout is in the center.}
         \label{fig:ours}
         \label{fig:ours}
     \end{subfigure}\\\vspace{4mm}
     \end{subfigure}\\\vspace{4mm}
-    \caption{Comparison of the implementation with the algorithm from the original paper.}
+    \caption[Comparison to Brandes and Köpf]{Comparison of the implementation to the results of Brandes and Köpf~\cite{brandes_fast_2001}}
     \label{fig:originalpapergraph}
     \label{fig:originalpapergraph}
 \end{figure}
 \end{figure}
 
 
-\begin{figure}[htp]
-    \centering
-    \includegraphics[width=0.6\linewidth]{img/example}
-    \caption[A simple graph with 5 nodes]{A simple graph with 5 nodes after the four extremal layout have been computed, but not balanced yet.
-    The vertical directions are down (upper row), up (lower row) and the horizontal directions are left (left column) and right (right column).
-    The background colors of the nodes display which block they belong to: For example the two blue nodes on the top right are in the same block.
-    Round nodes are the roots of the blocks.
-    A colored circle on a node indicates the class that this node belongs to and is also the color of the topmost sink in the block graph.
-    The node that is currently in the focus of the algorithm (whatever this means for the current stage) is highlighted with a grey square (here the node in the rightmost column on the bottom right).
-    Although edges are not drawn during the node placement phase we added them here as straight lines to improve readability.}
-    \label{fig:example}
-\end{figure}
-
-\begin{figure}[htp]
-    \centering
-    \includegraphics[width=\linewidth]{img/skizze}
-    \caption[First sketch of the planned layout]{A first sketch of the planned layout, created with Microsoft Paint.
-    The buttons are (first row, from left to right): step over, step into, step out, run, pause, debug; and (second row, from left to right): step back, step back out, run backwards.
-    The actions corresponding to the buttons will be the same as described for the keyboard input in table~\ref{table:keys}, at least for the features that are already implemented.}
-    \label{fig:sketch}
-\end{figure}
 
 
 \section{User interface}\label{sec:userInterface}
 \section{User interface}\label{sec:userInterface}
-Currently the only way to interact with the application is by keyboard events.
-It is planned to add both additional commands as well as some kind of graphical interface, see chapter~\ref{ch:progress}.
-The possible inputs are listed in table~\ref{table:keys}.
+Currently the two main ways to interact with the application are keyboard events and graphical button-clicking.
+The possible keyboard inputs are listed in table~\ref{table:keys}.
+These can also be used by clicking on one of the buttons displayed in figures~\ref{fig:sketch} and~\ref{fig:full-application-example}.
 
 
-\begin{table}[htp]
-    \begin{longtable}{|l|l|}
+%\begin{table}[htp]
+    \begin{longtable}{|l|p{12cm}|}
         \hline
         \hline
         Key & Action \\\hline\hline
         Key & Action \\\hline\hline
-        Left arrow key & Perform one forward step of the algorithm. \\\hline
-        Right arrow key & Perform one backward step (\enquote{undo one step}) of the algorithm. \\\hline
-        P & Pause/unpause the automatic execution. Initially paused. \\\hline
-        D & Print a debug table to standard out. \\\hline
+        Alt + Left arrow key & Perform one forward step of the algorithm, \enquote{step into}. \\\hline
+        Alt + Right arrow key & Perform one \enquote{step into} in backwards direction---i.e.\ undo one step of the algorithm. \\\hline
+        Alt + Up arrow key & Perform one \enquote{step over} in backwards direction. \\\hline
+        Alt + Down arrow key & Perform one \enquote{step over} in forwards direction. \\\hline
+        Alt + Page down & Perform one \enquote{step out} in forwards direction. \\\hline
+        Alt + Page up & Perform one \enquote{step out} in backwards direction. \\\hline
+        Alt + P & Activate automatic forwards execution. \\\hline
+        Alt + R & Activate automatic backwards execution. \\\hline
+        Alt + Pause & Pause automatic execution. \\\hline
+        Alt + G & Generate a random graph (opens dialog window~\ref{fig:random-graph-dialog}). \\\hline
+        Alt + S & Save the current graph to a file (opens a dialog window). \\\hline
+        Alt + L & Load a graph from a file (opens a dialog window). \\\hline
+        Alt + D & Show a debug table (opens window~\ref{fig:debug-table}). \\\hline
+        \caption[Overview of the available keyboard commands]{Overview of the available keyboard commands.
+        The lazy user might not want to learn these by rote but instead use the buttons displayed in figures~\ref{fig:sketch} and~\ref{fig:full-application-example}.}
+        \label{table:keys}
     \end{longtable}
     \end{longtable}
-    \caption{Overview of the currently available keyboard commands.}
-    \label{table:keys}
-\end{table}
+%\end{table}
+
+One interaction that is available neither on keyboard nor on a button is setting breakpoints.
+For this, the user performs a triple click on one of the lines in the pseudocode.
+Upon reaching the beginning of that stage (beginning in running direction) the automatic execution pauses.
+Imagine the following scenario:
+\begin{enumerate}
+    \item The user starts up \appname.
+    \item The user sets a breakpoint on \enquote{Extremal Layout: leftmost lower} (this is the third extremal layout in the order they are computed).
+    \item The user activates automatic forwards execution.
+    \item The algorithm pauses when reaching the first step of \enquote{Extremal Layout: leftmost lower}.
+    \item The user activates automatic forwards execution again.
+    \item After the stage of \enquote{Extremal Layout: leftmost lower} is roughly halfway finished, the user pauses the automatic execution and activates automatic \emph{backwards} execution.
+    \item The algorithm would stop at the last step of \enquote{Extremal Layout: leftmost lower} (which is the first step in backwards direction), but this is obviously not reached from the middle of that stage.
+    So the algorithm just runs backwards to the beginning of whole BK Node Placement Algorithm (first step of the preprocessing).
+\end{enumerate}

+ 26 - 17
doc/chapter/4progress.tex

@@ -1,38 +1,47 @@
 The following features are either planned (\planned), under construction (\progress) or done (\done):
 The following features are either planned (\planned), under construction (\progress) or done (\done):
 \begin{itemize}
 \begin{itemize}
-    \item[\done] Reading from an input file as described in section~\ref{sec:inputFileFormat}.
+    \item[\done] Reading a graph from an input file as described in section~\ref{sec:inputFileFormat}.
     \item[\done] Creating random graphs for testing purposes.
     \item[\done] Creating random graphs for testing purposes.
     \begin{itemize}
     \begin{itemize}
         \item[\done] Saving those randomly created graphs.
         \item[\done] Saving those randomly created graphs.
     \end{itemize}
     \end{itemize}
     \item[\done] Drawing a graph with specified node sizes and positions.
     \item[\done] Drawing a graph with specified node sizes and positions.
-    \item[\progress] Running the node placement algorithm by Brandes and Köpf~\cite{brandes_fast_2001}.
+    \item[\done] Running the node placement algorithm by Brandes and Köpf~\cite{brandes_fast_2001}.
     \begin{itemize}
     \begin{itemize}
-        \item[\progress] Calculating the conflicts between edges.
+        \item[\done] Calculating the conflicts between edges.
         \begin{itemize}
         \begin{itemize}
-            \item[\progress] Differentiating between dummy nodes and non-dummy nodes.
+            \item[\done] Differentiating between dummy nodes and non-dummy nodes.
         \end{itemize}
         \end{itemize}
-        \item[\progress] Calculating the blocks.
-        \item[\progress] Compacting the layout.
-        \item[\planned] Combining the layouts.
+        \item[\done] Calculating the blocks.
+        \item[\done] Compacting the layout.
+        \item[\done] Combining the layouts.
     \end{itemize}
     \end{itemize}
-    \item[\progress] Illustrating the progress while the algorithm is running in the form of
+    \item[\done] Illustrating the progress while the algorithm is running in the form of
     \begin{itemize}
     \begin{itemize}
         \item[\done] Drawing the nodes at their current position.
         \item[\done] Drawing the nodes at their current position.
         \item[\done] Drawing the nodes in the color of their blocks.
         \item[\done] Drawing the nodes in the color of their blocks.
         \item[\done] Drawing a colored circle to show the class assignments.
         \item[\done] Drawing a colored circle to show the class assignments.
         \item[\done] Drawing the edges just as plain straight lines.
         \item[\done] Drawing the edges just as plain straight lines.
-        \item[\progress] Drawing the four extremal layouts and the combined layout separately.
-        \item[\planned] Drawing the edges of the block graph (in a different color than other edges).
+        \item[\done] Drawing the conflicted edges in a different color.
+        \item[\done] Drawing the four extremal layouts and the combined layout separately.
+        \item[\planned] Drawing the edges of the block graph (yet another color, low priority).
+        \item[\done] Showing pseudocode and the position where the algorithm currently is.
+        \begin{itemize}
+            \item[\done] Clicking on the pseudocode to set a breakpoint at (not \reserved{goto}) a specific location.
+        \end{itemize}
     \end{itemize}
     \end{itemize}
     \item[\done] Running the algorithm step by step manually.
     \item[\done] Running the algorithm step by step manually.
-    \item[\progress] Running the algorithm step by step with configurable delay.
-    \item[\planned] Using debugger-like commands such as \enquote{step into}, \enquote{step over}, \enquote{step out}.
-    \item[\planned] Adding buttons and other graphical elements to support the user interface (low priority).
+    \item[\done] Running the algorithm step by step with configurable delay.
+    \item[\done] Using debugger-like commands such as \enquote{step into}, \enquote{step over}, \enquote{step out}.
+    \item[\done] Adding buttons and other graphical elements to support the user interface (low priority, see figure~\ref{fig:sketch}).
     Currently there is only keyboard input (cf.\ section~\ref{sec:userInterface}).
     Currently there is only keyboard input (cf.\ section~\ref{sec:userInterface}).
+    \begin{itemize}
+        \item[\done] Displaying the buttons.
+        \item[\done] Making all the buttons work.
+    \end{itemize}
     \item[\done] Working with hierarchical graphs.
     \item[\done] Working with hierarchical graphs.
     \item[\done] Scaling the display with the (adjustable) window size.
     \item[\done] Scaling the display with the (adjustable) window size.
-    \item[\planned] Work with disconnected graphs (cf.\ section~\ref{sec:assumptions}), either by modifying the algorithm or by processing the connected components one by one.
-    \item[\planned] Creating ElkNode~\cite{noauthor_elk:_2018} objects from LayeredNode (\ref{sec:model}) objects.
-    \item[\planned] Creating LayeredNode (\ref{sec:model}) objects from ElkNode~\cite{noauthor_elk:_2018} objects (low priority).
-\end{itemize}
+    \item[\planned] Working with disconnected graphs (cf.\ section~\ref{sec:assumptions}), either by modifying the algorithm or by processing the connected components one by one (low priority).
+    \item[\planned] Creating ElkNode~\cite{noauthor_elk:_2018} objects from LayeredNode (\ref{sec:graph}) objects.
+    \item[\planned] Creating LayeredNode (\ref{sec:graph}) objects from ElkNode~\cite{noauthor_elk:_2018} objects (low priority).
+\end{itemize}

+ 6 - 0
doc/chapter/6contributors.tex

@@ -19,7 +19,13 @@
         Director Of Quality Assurance & Eren Bora Yilmaz \\
         Director Of Quality Assurance & Eren Bora Yilmaz \\
         \rowcolor{gray!25}
         \rowcolor{gray!25}
 		Senior Community Manager & Eren Bora Yilmaz \\
 		Senior Community Manager & Eren Bora Yilmaz \\
+		Lead Artist & Eren Bora Yilmaz \\
+        \rowcolor{gray!25}
         Creative Director & Kolja Samuel Strohm \\
         Creative Director & Kolja Samuel Strohm \\
+        Localization Producer & Eren Bora Yilmaz \\
+        \rowcolor{gray!25}
+        Manual Code Formatting & Kolja Samuel Strohm \\
+        Black-Box Testing & Eren Bora Yilmaz \\
         \\\\\rowcolor{gray!25}
         \\\\\rowcolor{gray!25}
 		Special Thanks & Jens Burmeister \\\\
 		Special Thanks & Jens Burmeister \\\\
 	\end{longtable}
 	\end{longtable}

+ 12 - 1
doc/chapter/appendix.tex

@@ -1 +1,12 @@
-\TODO{add class diagrams}
+\begin{figure}[htp]
+    \centering
+    \includegraphics{img/random-graph-dialog}
+    \caption[Random graph dialog]{Dialog for generating random graphs.}
+    \label{fig:random-graph-dialog}
+\end{figure}
+\begin{figure}[htp]
+    \centering
+    \includegraphics[width=\linewidth]{img/debug-table}
+    \caption[Debug Table]{An example for a debug table. The graph used is the same as in figure~\ref{fig:example}}
+    \label{fig:debug-table}
+\end{figure}

+ 10 - 0
doc/doc.tex

@@ -84,6 +84,9 @@
 % Quellcode
 % Quellcode
 % für Formatierung in Quelltexten, hier im Anhang
 % für Formatierung in Quelltexten, hier im Anhang
 \usepackage{listings}
 \usepackage{listings}
+
+% same code font as in eclipse
+\usepackage{inconsolata}
 \usepackage{color, colortbl} % Farben
 \usepackage{color, colortbl} % Farben
 
 
 \colorlet{punct}{red!60!black}
 \colorlet{punct}{red!60!black}
@@ -99,6 +102,13 @@
 \definecolor{deepred}{rgb}{0.8,0,0}
 \definecolor{deepred}{rgb}{0.8,0,0}
 \definecolor{deepgreen}{rgb}{0,0.4,0}
 \definecolor{deepgreen}{rgb}{0,0.4,0}
 \definecolor{grau}{gray}{0.3}
 \definecolor{grau}{gray}{0.3}
+\definecolor{member}{rgb}{0.27,0.37,0.75}
+\definecolor{reserved}{rgb}{0.5,0.,0.333}
+
+\newcommand{\code}[1]{\lstinline[basicstyle=\ttfamily]|#1|}
+\newcommand{\member}[1]{\lstinline[basicstyle=\ttfamily\color{member}]|#1|}
+\newcommand{\reserved}[1]{\lstinline[basicstyle=\ttfamily\color{reserved}]|#1|}
+
 % python style code
 % python style code
 \lstset{
 \lstset{
 extendedchars=true,
 extendedchars=true,

BIN
doc/img/algorithms_animated.pdf


BIN
doc/img/animation_and_bk.pdf


BIN
doc/img/bk-example-ours.jpg


BIN
doc/img/bk-example-ours.png


BIN
doc/img/buttons.png


BIN
doc/img/components.pdf


BIN
doc/img/debug-table.png


BIN
doc/img/example.jpg


BIN
doc/img/example.png


BIN
doc/img/full-application-example.png


BIN
doc/img/graph.pdf


BIN
doc/img/logo.jpg


BIN
doc/img/logo.png


BIN
doc/img/model.pdf


BIN
doc/img/random-graph-dialog.png


BIN
doc/img/skizze.png


BIN
doc/img/view.pdf


BIN
doc/vpp/animation.animated.vpp → doc/vpp/animation_and_bk.vpp


BIN
doc/vpp/components.vpp


BIN
doc/vpp/model.vpp → doc/vpp/graph.vpp


BIN
doc/vpp/io.vpp


BIN
doc/vpp/view.vpp


+ 141 - 0
logo.json

@@ -0,0 +1,141 @@
+{
+  "layers": [
+    [
+      {
+        "layers": [
+          [
+            {
+              "name": "n1"
+            },
+            {
+              "name": "n2"
+            }
+          ],
+          [
+            {
+              "name": "n3"
+            },
+            {
+              "name": "n4"
+            }
+          ]
+        ],
+        "edges": [
+          {
+            "source": "n1",
+            "target": "n4"
+          },
+          {
+            "source": "n2",
+            "target": "n4"
+          }
+        ],
+        "name": "n1"
+      },
+      {
+        "layers": [
+          [
+            {
+              "name": "n1"
+            },
+            {
+              "name": "n2"
+            }
+          ],
+          [
+            {
+              "name": "n3"
+            },
+            {
+              "name": "n4"
+            }
+          ]
+        ],
+        "edges": [
+          {
+            "source": "n1",
+            "target": "n4"
+          },
+          {
+            "source": "n2",
+            "target": "n3"
+          }
+        ],
+        "name": "n2"
+      }
+    ],
+    [
+      {
+        "layers": [
+          [
+            {
+              "name": "n1"
+            },
+            {
+              "name": "n2"
+            }
+          ],
+          [
+            {
+              "name": "n3"
+            },
+            {
+              "name": "n4"
+            }
+          ]
+        ],
+        "edges": [
+          {
+            "source": "n1",
+            "target": "n3"
+          },
+          {
+            "source": "n2",
+            "target": "n4"
+          },
+          {
+            "source": "n2",
+            "target": "n3"
+          }
+        ],
+        "name": "n3"
+      },
+      {
+        "layers": [
+          [
+            {
+              "name": "n1"
+            },
+            {
+              "name": "n2"
+            }
+          ],
+          [
+            {
+              "name": "n3"
+            },
+            {
+              "name": "n4"
+            }
+          ]
+        ],
+        "name": "n4"
+      }
+    ]
+  ],
+  "edges": [
+    {
+      "source": "n1",
+      "target": "n3"
+    },
+    {
+      "source": "n1",
+      "target": "n4"
+    },
+    {
+      "source": "n2",
+      "target": "n4"
+    }
+  ],
+  "name": "n0"
+}

+ 193 - 1
save.json

@@ -1 +1,193 @@
-{"layers":[[{"layers":[],"edges":[],"name":"0"},{"layers":[],"edges":[],"name":"1"},{"layers":[],"edges":[],"name":"2"},{"layers":[],"edges":[],"name":"3"},{"layers":[],"edges":[],"name":"4"}],[{"layers":[],"edges":[],"name":"5"},{"layers":[],"edges":[],"name":"6"},{"layers":[],"edges":[],"name":"7"},{"layers":[],"edges":[],"name":"8"},{"layers":[],"edges":[],"name":"9"}],[{"layers":[],"edges":[],"name":"10"},{"layers":[],"edges":[],"name":"11"},{"layers":[],"edges":[],"name":"12"},{"layers":[],"edges":[],"name":"13"},{"layers":[],"edges":[],"name":"14"}],[{"layers":[],"edges":[],"name":"15"},{"layers":[],"edges":[],"name":"16"},{"layers":[],"edges":[],"name":"17"},{"layers":[],"edges":[],"name":"18"},{"layers":[],"edges":[],"name":"19"}],[{"layers":[],"edges":[],"name":"20"},{"layers":[],"edges":[],"name":"21"},{"layers":[],"edges":[],"name":"22"},{"layers":[],"edges":[],"name":"23"},{"layers":[],"edges":[],"name":"24"}]],"edges":[{"source":"1","target":"8"},{"source":"3","target":"8"},{"source":"0","target":"7"},{"source":"0","target":"6"},{"source":"5","target":"13"},{"source":"6","target":"13"},{"source":"7","target":"14"},{"source":"13","target":"17"},{"source":"10","target":"16"},{"source":"13","target":"16"},{"source":"12","target":"16"},{"source":"19","target":"23"},{"source":"15","target":"22"}]}
+{
+  "layers": [
+    [
+      {
+        "layers": [],
+        "edges": [],
+        "name": "0"
+      },
+      {
+        "layers": [],
+        "edges": [],
+        "name": "1"
+      },
+      {
+        "layers": [],
+        "edges": [],
+        "name": "2"
+      },
+      {
+        "layers": [],
+        "edges": [],
+        "name": "3"
+      },
+      {
+        "layers": [],
+        "edges": [],
+        "name": "4"
+      }
+    ],
+    [
+      {
+        "layers": [],
+        "edges": [],
+        "name": "5"
+      },
+      {
+        "layers": [],
+        "edges": [],
+        "name": "6"
+      },
+      {
+        "layers": [],
+        "edges": [],
+        "name": "7"
+      },
+      {
+        "layers": [],
+        "edges": [],
+        "name": "8"
+      },
+      {
+        "layers": [],
+        "edges": [],
+        "name": "9"
+      }
+    ],
+    [
+      {
+        "layers": [],
+        "edges": [],
+        "name": "10"
+      },
+      {
+        "layers": [],
+        "edges": [],
+        "name": "11"
+      },
+      {
+        "layers": [],
+        "edges": [],
+        "name": "12"
+      },
+      {
+        "layers": [],
+        "edges": [],
+        "name": "13"
+      },
+      {
+        "layers": [],
+        "edges": [],
+        "name": "14"
+      }
+    ],
+    [
+      {
+        "layers": [],
+        "edges": [],
+        "name": "15"
+      },
+      {
+        "layers": [],
+        "edges": [],
+        "name": "16"
+      },
+      {
+        "layers": [],
+        "edges": [],
+        "name": "17"
+      },
+      {
+        "layers": [],
+        "edges": [],
+        "name": "18"
+      },
+      {
+        "layers": [],
+        "edges": [],
+        "name": "19"
+      }
+    ],
+    [
+      {
+        "layers": [],
+        "edges": [],
+        "name": "20"
+      },
+      {
+        "layers": [],
+        "edges": [],
+        "name": "21"
+      },
+      {
+        "layers": [],
+        "edges": [],
+        "name": "22"
+      },
+      {
+        "layers": [],
+        "edges": [],
+        "name": "23"
+      },
+      {
+        "layers": [],
+        "edges": [],
+        "name": "24"
+      }
+    ]
+  ],
+  "edges": [
+    {
+      "source": "1",
+      "target": "8"
+    },
+    {
+      "source": "3",
+      "target": "8"
+    },
+    {
+      "source": "0",
+      "target": "7"
+    },
+    {
+      "source": "0",
+      "target": "6"
+    },
+    {
+      "source": "5",
+      "target": "13"
+    },
+    {
+      "source": "6",
+      "target": "13"
+    },
+    {
+      "source": "7",
+      "target": "14"
+    },
+    {
+      "source": "13",
+      "target": "17"
+    },
+    {
+      "source": "10",
+      "target": "16"
+    },
+    {
+      "source": "13",
+      "target": "16"
+    },
+    {
+      "source": "12",
+      "target": "16"
+    },
+    {
+      "source": "19",
+      "target": "23"
+    },
+    {
+      "source": "15",
+      "target": "22"
+    }
+  ]
+}

+ 5 - 1
src/animation/Action.java

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

+ 13 - 0
src/animation/AlgorithmStage.java

@@ -1,5 +1,7 @@
 package animation;
 package animation;
 
 
+import javax.swing.JTree;
+
 import bk.BlockCalc;
 import bk.BlockCalc;
 
 
 /**
 /**
@@ -18,6 +20,7 @@ public interface AlgorithmStage {
 	public static enum StageStatus
 	public static enum StageStatus
 	{
 	{
 		UNFINISHED,
 		UNFINISHED,
+		BREAKPOINT,
 		FINISHED
 		FINISHED
 	}
 	}
 	
 	
@@ -27,6 +30,10 @@ public interface AlgorithmStage {
      * For example if all steps are reverted, then {@code FINISHED} is returned.
      * For example if all steps are reverted, then {@code FINISHED} is returned.
 	 */
 	 */
 	public StageStatus forwardStep();
 	public StageStatus forwardStep();
+	
+	public StageStatus forwardStepOver();
+	
+    public StageStatus forwardStepOut();
     
     
     /**
     /**
      * undo one atomic step of the algorithm
      * undo one atomic step of the algorithm
@@ -34,4 +41,10 @@ public interface AlgorithmStage {
      * For example if all steps are reverted, then {@code FINISHED} is returned.
      * For example if all steps are reverted, then {@code FINISHED} is returned.
      */
      */
 	public StageStatus backwardStep();
 	public StageStatus backwardStep();
+	
+    public StageStatus backwardStepOver();
+    
+    public StageStatus backwardStepOut();
+	
+    public PseudoCodeNode createPseudocodeTree( JTree tree );
 }
 }

+ 49 - 3
src/animation/AnimatedAlgorithm.java

@@ -1,16 +1,38 @@
 package animation;
 package animation;
 
 
+import java.awt.event.ComponentEvent;
+import java.awt.event.ComponentListener;
+
+import javax.swing.JFrame;
+import javax.swing.JTree;
+import javax.swing.SwingUtilities;
+
 import graph.LayeredGraphNode;
 import graph.LayeredGraphNode;
 
 
 public abstract class AnimatedAlgorithm extends Thread implements AlgorithmStage {
 public abstract class AnimatedAlgorithm extends Thread implements AlgorithmStage {
 
 
 	protected AnimationController ac;
 	protected AnimationController ac;
 	protected LayeredGraphNode graph;
 	protected LayeredGraphNode graph;
+	private JFrame view;
 	
 	
-	public AnimatedAlgorithm( AnimationController controller, LayeredGraphNode graph )
+	public AnimatedAlgorithm( AnimationController controller, LayeredGraphNode graph, JFrame view )
 	{
 	{
 		this.ac = controller;
 		this.ac = controller;
 		this.graph = graph;
 		this.graph = graph;
+		this.view = view;
+	}
+	
+	private void update()
+	{
+        SwingUtilities.invokeLater(new Runnable() {
+            public void run() {
+                view.repaint();
+                for( ComponentListener l : view.getComponentListeners() )
+                {
+                    l.componentResized( new ComponentEvent(view, 0) );
+                }
+            }
+        });
 	}
 	}
 	
 	
 	@Override
 	@Override
@@ -22,13 +44,35 @@ public abstract class AnimatedAlgorithm extends Thread implements AlgorithmStage
 				switch( ac.getNextAction() )
 				switch( ac.getNextAction() )
 				{
 				{
 				case FORWARD:
 				case FORWARD:
-					System.out.println( "FORWARD" );
 					forwardStep();
 					forwardStep();
+					update();
 					break;
 					break;
+                case FORWARD_OUT:
+                    forwardStepOut();
+                    graph.unselectGraph();
+                    update();
+                    break;
+                case FORWARD_OVER:
+                    forwardStepOver();
+                    graph.unselectGraph();
+                    update();
+                    break;
 				case BACKWARD:
 				case BACKWARD:
-					System.out.println( "BACKWARD" );
 					backwardStep();
 					backwardStep();
+                    update();
 					break;
 					break;
+                case BACKWARD_OUT:
+                    backwardStepOut();
+                    graph.unselectGraph();
+                    update();
+                    break;
+                case BACKWARD_OVER:
+                    backwardStepOver();
+                    graph.unselectGraph();
+                    update();
+                    break;
+                default:
+                    break;
 				}
 				}
 			} catch (InterruptedException e) {
 			} catch (InterruptedException e) {
 				e.printStackTrace();
 				e.printStackTrace();
@@ -37,4 +81,6 @@ public abstract class AnimatedAlgorithm extends Thread implements AlgorithmStage
 			
 			
 		}
 		}
 	}
 	}
+	
+    public abstract PseudoCodeNode createPseudocodeTree( JTree tree );
 }
 }

+ 78 - 0
src/animation/PseudoCodeNode.java

@@ -0,0 +1,78 @@
+package animation;
+
+import javax.swing.JTree;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.MutableTreeNode;
+import javax.swing.tree.TreePath;
+
+public class PseudoCodeNode extends DefaultMutableTreeNode {
+
+    /**
+     * 
+     */
+    private static final long serialVersionUID = 1L;
+    
+    private boolean selected;
+    private JTree tree;
+    private boolean breakPoint;
+    private AnimationController controller;
+    
+    public PseudoCodeNode( String description, JTree tree )
+    {
+        super( description );
+        selected = false;
+        this.tree = tree;
+        breakPoint = false;
+    }
+    
+    public void setController( AnimationController c )
+    {
+        if( children != null )
+        {
+            for( Object ch : children )
+            {
+                ((PseudoCodeNode)ch).setController( c );
+            }
+        }
+        controller = c;
+    }
+    
+    @Override
+    public void add( MutableTreeNode node )
+    {
+        ((PseudoCodeNode)node).setController( controller );
+        super.add( node );
+    }
+    
+    public JTree getTree()
+    {
+        return tree;
+    }
+    
+    public boolean isSelected()
+    {
+        return selected;
+    }
+    
+    public boolean setSelected( boolean selected )
+    {
+        if( selected && breakPoint )
+            controller.setContinuous( false );
+        if( selected )
+            tree.expandPath( new TreePath( this.getPath() ) );
+        else
+            tree.collapsePath( new TreePath( this.getPath() ) );
+        this.selected = selected;
+        return !breakPoint || !selected;
+    }
+    
+    public void setBreakPoint( boolean breakPoint )
+    {
+        this.breakPoint = breakPoint;
+    }
+    
+    public boolean hasBreakPoint()
+    {
+        return breakPoint;
+    }
+}

+ 323 - 55
src/bk/BKNodePlacement.java

@@ -1,8 +1,13 @@
 package bk;
 package bk;
 
 
-import animation.AlgorithmStage;
+import java.lang.reflect.InvocationTargetException;
+
+import javax.swing.JFrame;
+import javax.swing.JTree;
+
 import animation.AnimatedAlgorithm;
 import animation.AnimatedAlgorithm;
 import animation.AnimationController;
 import animation.AnimationController;
+import animation.PseudoCodeNode;
 import graph.LayeredGraphNode;
 import graph.LayeredGraphNode;
 
 
 /**
 /**
@@ -30,9 +35,16 @@ public class BKNodePlacement extends AnimatedAlgorithm {
 	private State state;
 	private State state;
 	private ExtremalLayoutCalc layouts[];
 	private ExtremalLayoutCalc layouts[];
 	private Combine combine;
 	private Combine combine;
+    private PseudoCodeNode conflictsNode; 
+    private PseudoCodeNode layout1Node;
+    private PseudoCodeNode layout2Node;
+    private PseudoCodeNode layout3Node;
+    private PseudoCodeNode layout4Node;
+    private PseudoCodeNode combineNode;
+    private boolean inside;
 	
 	
-	public BKNodePlacement(AnimationController controller, LayeredGraphNode graph) {
-		super(controller, graph);
+	public BKNodePlacement(AnimationController controller, LayeredGraphNode graph, JFrame view) {
+		super(controller, graph, view);
 		state = State.CONFLICTS;
 		state = State.CONFLICTS;
 		conftion = new ConflictDetection( graph );
 		conftion = new ConflictDetection( graph );
 		layouts = new ExtremalLayoutCalc[ 4 ];
 		layouts = new ExtremalLayoutCalc[ 4 ];
@@ -41,65 +53,321 @@ public class BKNodePlacement extends AnimatedAlgorithm {
 		layouts[ 2 ] = new ExtremalLayoutCalc( ExtremalLayoutCalc.LayoutType.BOTTOM_TOP_LEFT, graph );
 		layouts[ 2 ] = new ExtremalLayoutCalc( ExtremalLayoutCalc.LayoutType.BOTTOM_TOP_LEFT, graph );
 		layouts[ 3 ] = new ExtremalLayoutCalc( ExtremalLayoutCalc.LayoutType.BOTTOM_TOP_RIGHT, graph );
 		layouts[ 3 ] = new ExtremalLayoutCalc( ExtremalLayoutCalc.LayoutType.BOTTOM_TOP_RIGHT, graph );
 		combine = new Combine( graph );
 		combine = new Combine( graph );
+		inside = false;
 	}
 	}
 
 
 	@Override
 	@Override
 	public StageStatus forwardStep() {
 	public StageStatus forwardStep() {
-		switch( state )
-		{
-		case CONFLICTS:
-			if( conftion.forwardStep() == StageStatus.FINISHED )
-				state = State.LAYOUT1;
-			break;
-		case LAYOUT1:
-			if( layouts[ 0 ].forwardStep() == AlgorithmStage.StageStatus.FINISHED )
-				state = State.LAYOUT2;
-			break;
-		case LAYOUT2:
-			if( layouts[ 1 ].forwardStep() == AlgorithmStage.StageStatus.FINISHED )
-				state = State.LAYOUT3;
-			break;
-		case LAYOUT3:
-			if( layouts[ 2 ].forwardStep() == AlgorithmStage.StageStatus.FINISHED )
-				state = State.LAYOUT4;
-			break;
-		case LAYOUT4:
-			if( layouts[ 3 ].forwardStep() == AlgorithmStage.StageStatus.FINISHED )
-				state = State.COMBINE;
-			break;
-		case COMBINE:
-			return combine.forwardStep();
-		}
-		return StageStatus.UNFINISHED;
+		return forward( "forwardStep" );
 	}
 	}
 
 
 	@Override
 	@Override
 	public StageStatus backwardStep() {
 	public StageStatus backwardStep() {
-		switch( state )
-		{
-		case CONFLICTS:
-			return conftion.backwardStep();
-		case LAYOUT1:
-			if( layouts[ 0 ].backwardStep() == StageStatus.FINISHED )
-				state = State.CONFLICTS;
-			break;
-		case LAYOUT2:
-			if( layouts[ 1 ].backwardStep() == AlgorithmStage.StageStatus.FINISHED )
-				state = State.LAYOUT1;
-			break;
-		case LAYOUT3:
-			if( layouts[ 2 ].backwardStep() == AlgorithmStage.StageStatus.FINISHED )
-				state = State.LAYOUT2;
-			break;
-		case LAYOUT4:
-			if( layouts[ 3 ].backwardStep() == AlgorithmStage.StageStatus.FINISHED )
-				state = State.LAYOUT3;
-			break;
-		case COMBINE:
-			if( combine.backwardStep() == AlgorithmStage.StageStatus.FINISHED )
-				state = State.LAYOUT4;
-			break;
-		}
-		return StageStatus.UNFINISHED;
+	    return backward( "backwardStep" );
+	}
+	
+	@Override
+	public PseudoCodeNode createPseudocodeTree( JTree tree )
+	{
+	    PseudoCodeNode root = new PseudoCodeNode( "BK Node Placement Algorithm", tree );
+	    root.setSelected( true );
+        conflictsNode = conftion.createPseudocodeTree( tree );
+        layout1Node = layouts[ 0 ].createPseudocodeTree( tree );
+        layout2Node = layouts[ 1 ].createPseudocodeTree( tree );
+        layout3Node = layouts[ 2 ].createPseudocodeTree( tree );
+        layout4Node = layouts[ 3 ].createPseudocodeTree( tree );
+        combineNode = combine.createPseudocodeTree( tree );
+        root.add( conflictsNode );
+        root.add( layout1Node );
+        root.add( layout2Node );
+        root.add( layout3Node );
+        root.add( layout4Node );
+        root.add( combineNode );
+        return root;
 	}
 	}
+
+    @Override
+    public StageStatus forwardStepOver() {
+        if( !inside )
+        {
+            State oldState = state;
+            StageStatus status = StageStatus.UNFINISHED;
+            while( state == oldState && status == StageStatus.UNFINISHED )
+                status = forwardStep();
+            return status;
+        }
+        else
+            return forward( "forwardStepOver" );
+    }
+
+    @Override
+    public StageStatus forwardStepOut() {
+        if( !inside )
+        {
+            StageStatus status = StageStatus.UNFINISHED;
+            while( status == StageStatus.UNFINISHED )
+                status = forwardStep();
+            return status;
+        }
+        else
+            return forward( "forwardStepOut" );
+    }
+
+    @Override
+    public StageStatus backwardStepOver() {
+        if( !inside )
+        {
+            State oldState = state;
+            StageStatus status = StageStatus.UNFINISHED;
+            while( state == oldState && status == StageStatus.UNFINISHED )
+                status = backwardStep();
+            return status;
+        }
+        else
+            return backward( "backwardStepOver" );
+    }
+
+    @Override
+    public StageStatus backwardStepOut() {
+        if( !inside )
+        {
+            StageStatus status = StageStatus.UNFINISHED;
+            while( status == StageStatus.UNFINISHED )
+                status = backwardStep();
+            return status;
+        }
+        else
+            return backward( "backwardStepOut" );
+    }
+    
+    private StageStatus forward( String fName )
+    {
+        boolean breakpoint = false;
+        try {
+            switch( state )
+            {
+            case CONFLICTS:
+            	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;
+                }
+                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;
+                }
+                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;
+                }
+                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;
+                }
+                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;
+                }
+                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;
+                }
+            }
+        } catch (IllegalAccessException e) {
+            e.printStackTrace();
+        } catch (IllegalArgumentException e) {
+            e.printStackTrace();
+        } catch (InvocationTargetException e) {
+            e.printStackTrace();
+        } catch (NoSuchMethodException e) {
+            e.printStackTrace();
+        } catch (SecurityException e) {
+            e.printStackTrace();
+        }
+        if( breakpoint )
+            return StageStatus.BREAKPOINT;
+        return StageStatus.UNFINISHED;
+    }
+
+    private StageStatus backward( String fName ) {
+        boolean breakpoint = false;
+        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;
+                }
+            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;
+                }
+                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;
+                }
+                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;
+                }
+                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;
+                }
+                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;
+                }
+                break;
+            }
+        } catch (IllegalAccessException e) {
+            e.printStackTrace();
+        } catch (IllegalArgumentException e) {
+            e.printStackTrace();
+        } catch (InvocationTargetException e) {
+            e.printStackTrace();
+        } catch (NoSuchMethodException e) {
+            e.printStackTrace();
+        } catch (SecurityException e) {
+            e.printStackTrace();
+        }
+        if( breakpoint )
+            return StageStatus.BREAKPOINT;
+        return StageStatus.UNFINISHED;
+    }
+    
 }
 }

+ 63 - 2
src/bk/BlockCalc.java

@@ -4,8 +4,11 @@ import java.awt.Color;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Collections;
 
 
+import javax.swing.JTree;
+
 import animation.AlgorithmStage;
 import animation.AlgorithmStage;
 import animation.BackwardAction;
 import animation.BackwardAction;
+import animation.PseudoCodeNode;
 import bk.ExtremalLayoutCalc.LayoutType;
 import bk.ExtremalLayoutCalc.LayoutType;
 import graph.LayeredGraphEdge;
 import graph.LayeredGraphEdge;
 import graph.LayeredGraphNode;
 import graph.LayeredGraphNode;
@@ -24,6 +27,7 @@ public class BlockCalc implements AlgorithmStage {
 	private ArrayList< ArrayList< ExtremalLayoutCalc > > subgraphAlgs;
 	private ArrayList< ArrayList< ExtremalLayoutCalc > > subgraphAlgs;
 	private ArrayList< BackwardAction > backwards; // TODO: evtl richtigen "Stack" benutzen
 	private ArrayList< BackwardAction > backwards; // TODO: evtl richtigen "Stack" benutzen
 	private LayoutType layout;
 	private LayoutType layout;
+	private PseudoCodeNode loopNode;
 	int step;
 	int step;
 	
 	
 	public BlockCalc( LayeredGraphNode graph, LayoutType layout )
 	public BlockCalc( LayeredGraphNode graph, LayoutType layout )
@@ -88,9 +92,20 @@ public class BlockCalc implements AlgorithmStage {
 		if( current.getContainedNodes().size() > 0 )
 		if( current.getContainedNodes().size() > 0 )
 		{
 		{
 			if( subgraphAlgs.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ) == null )
 			if( subgraphAlgs.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ) == null )
-				subgraphAlgs.get( calcLayerIndex() ).set( calcNodeIndex( nodeIndex ), new ExtremalLayoutCalc( layout, current ) );
-			if( subgraphAlgs.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).forwardStep() == StageStatus.UNFINISHED )
+			{
+			    ExtremalLayoutCalc extcalc = new ExtremalLayoutCalc( layout, current );
+			    loopNode.add( extcalc.createPseudocodeTree( loopNode.getTree() ) );
+				subgraphAlgs.get( calcLayerIndex() ).set( calcNodeIndex( nodeIndex ), extcalc );
+			}
+			switch( subgraphAlgs.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).forwardStep() )
+			{
+            case BREAKPOINT:
+                return StageStatus.BREAKPOINT;
+			case UNFINISHED:
 				return StageStatus.UNFINISHED;
 				return StageStatus.UNFINISHED;
+            default:
+                break;
+			}
 		}
 		}
 		ArrayList< LayeredGraphEdge > incommingEdges = null;
 		ArrayList< LayeredGraphEdge > incommingEdges = null;
         if( layout == LayoutType.TOP_BOTTOM_LEFT || layout == LayoutType.TOP_BOTTOM_RIGHT )
         if( layout == LayoutType.TOP_BOTTOM_LEFT || layout == LayoutType.TOP_BOTTOM_RIGHT )
@@ -166,10 +181,14 @@ public class BlockCalc implements AlgorithmStage {
 	
 	
 	private StageStatus calcNextState()
 	private StageStatus calcNextState()
 	{
 	{
+        boolean breakpoint = !loopNode.setSelected( true );
 		if( layerIndex >= graph.getContainedLayers().size() - 1 )
 		if( layerIndex >= graph.getContainedLayers().size() - 1 )
 		{
 		{
 			if( nodeIndex >= graph.getContainedLayers().get( calcLayerIndex() ).size() -1 )
 			if( nodeIndex >= graph.getContainedLayers().get( calcLayerIndex() ).size() -1 )
+			{
+                loopNode.setSelected( false );
 				return StageStatus.FINISHED;
 				return StageStatus.FINISHED;
+			}
 		}
 		}
 		nodeIndex++;
 		nodeIndex++;
 		if( nodeIndex >= graph.getContainedLayers().get( calcLayerIndex() ).size() )
 		if( nodeIndex >= graph.getContainedLayers().get( calcLayerIndex() ).size() )
@@ -182,6 +201,8 @@ public class BlockCalc implements AlgorithmStage {
 			   this.r = oldR;
 			   this.r = oldR;
 			});
 			});
 		}
 		}
+		if( breakpoint )
+		    return StageStatus.BREAKPOINT;
 		return StageStatus.UNFINISHED;
 		return StageStatus.UNFINISHED;
 	}
 	}
 
 
@@ -213,10 +234,14 @@ public class BlockCalc implements AlgorithmStage {
 	
 	
 	private StageStatus calcBeforeState()
 	private StageStatus calcBeforeState()
 	{
 	{
+	    boolean breakpoint = !loopNode.setSelected( true );
 		if( layerIndex == 0 )
 		if( layerIndex == 0 )
 		{
 		{
 			if( nodeIndex == 0 )
 			if( nodeIndex == 0 )
+			{
+		        loopNode.setSelected( false );
 				return StageStatus.FINISHED;
 				return StageStatus.FINISHED;
+			}	
 		}
 		}
 		nodeIndex--;
 		nodeIndex--;
 		if( nodeIndex < 0 )
 		if( nodeIndex < 0 )
@@ -226,6 +251,42 @@ public class BlockCalc implements AlgorithmStage {
 	        backwards.remove( 0 );
 	        backwards.remove( 0 );
 			nodeIndex = graph.getContainedLayers().get( calcLayerIndex() ).size() - 1;
 			nodeIndex = graph.getContainedLayers().get( calcLayerIndex() ).size() - 1;
 		}
 		}
+        if( breakpoint )
+            return StageStatus.BREAKPOINT;
 		return StageStatus.UNFINISHED;
 		return StageStatus.UNFINISHED;
 	}
 	}
+
+    @Override
+    public PseudoCodeNode createPseudocodeTree( JTree tree ) {
+        PseudoCodeNode root = new PseudoCodeNode( "Vertical alignment", tree );
+        loopNode = new PseudoCodeNode( "Loop through all nodes...", tree );
+        root.add( loopNode );
+        return root;
+    }
+
+    @Override
+    public StageStatus forwardStepOver() {
+        return forwardStep();
+    }
+
+    @Override
+    public StageStatus forwardStepOut() {
+        StageStatus status = StageStatus.UNFINISHED;
+        while( status == StageStatus.UNFINISHED )
+            status = forwardStep();
+        return status;
+    }
+
+    @Override
+    public StageStatus backwardStepOver() {
+        return backwardStep();
+    }
+
+    @Override
+    public StageStatus backwardStepOut() {
+        StageStatus status = StageStatus.UNFINISHED;
+        while( status == StageStatus.UNFINISHED )
+            status = backwardStep();
+        return status;
+    }
 }
 }

+ 216 - 8
src/bk/Combine.java

@@ -1,10 +1,16 @@
 package bk;
 package bk;
 
 
 import java.awt.Color;
 import java.awt.Color;
+import java.util.ArrayList;
+import java.util.Collections;
+
+import javax.swing.JTree;
 
 
 import animation.AlgorithmStage;
 import animation.AlgorithmStage;
+import animation.BackwardAction;
+import animation.PseudoCodeNode;
+import bk.ExtremalLayoutCalc.LayoutType;
 import graph.LayeredGraphNode;
 import graph.LayeredGraphNode;
-import view.MainView;
 
 
 /**
 /**
  * The stage of the combination of the four extremal layouts.
  * The stage of the combination of the four extremal layouts.
@@ -15,24 +21,226 @@ public class Combine implements AlgorithmStage {
 
 
 	LayeredGraphNode graph;
 	LayeredGraphNode graph;
 	
 	
+	private enum State
+	{
+		ALIGN,
+		SET_COORDINATES
+	}
+	
+	private State state;
+	private int btlOffset;
+	private int btrOffset;
+	private int tblOffset;
+	private int tbrOffset;
+	private int vIndex;
+	private ArrayList< BackwardAction > actions;
+    private PseudoCodeNode alignNode;
+    private PseudoCodeNode setNode;
+    private PseudoCodeNode loopNode;
+    private boolean inside;
+    private boolean breakPoint;
+	
 	public Combine( LayeredGraphNode graph )
 	public Combine( LayeredGraphNode graph )
 	{
 	{
 		this.graph = graph;
 		this.graph = graph;
+		state = State.ALIGN;
+		vIndex = 0;
+		actions = new ArrayList<>();
+		inside = false;
 	}
 	}
 	
 	
 	@Override
 	@Override
 	public StageStatus forwardStep() {
 	public StageStatus forwardStep() {
-		MainView.frame.setSize( MainView.frame.getWidth() + 1, MainView.frame.getHeight() );
-		MainView.frame.setSize( MainView.frame.getWidth() - 1, MainView.frame.getHeight() );
-		
-		graph.setColor( Color.BLACK, null );
-		return null;
+		breakPoint = false;
+		if( state == State.ALIGN )
+		{
+		    inside = false;
+		    if( !alignNode.isSelected() )
+		    	breakPoint |= !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 );
+			int btrw = (int)graph.getWidth( LayoutType.BOTTOM_TOP_RIGHT );
+			LayoutType minLayout = LayoutType.TOP_BOTTOM_LEFT;
+			int minWidth = tblw;
+			if( tbrw < minWidth )
+			{
+				minWidth = tbrw;
+				minLayout = LayoutType.TOP_BOTTOM_RIGHT;
+			}
+			if( btlw < minWidth )
+			{
+				minWidth = btlw;
+				minLayout = LayoutType.BOTTOM_TOP_LEFT;
+			}
+			if( btrw < minWidth )
+			{
+				minWidth = btrw;
+				minLayout = LayoutType.BOTTOM_TOP_RIGHT;
+			}
+			int minX = calcMinX( minLayout );
+			btlOffset = minX - calcMinX( LayoutType.BOTTOM_TOP_LEFT );
+			tblOffset = minX - calcMinX( LayoutType.TOP_BOTTOM_LEFT );
+			btrOffset = minWidth - btrw;
+			tbrOffset = minWidth - tbrw;
+			graph.setColor( Color.BLACK, null );
+			//MainView.frame.setSize( MainView.frame.getWidth() + 1, MainView.frame.getHeight() );
+			//MainView.frame.setSize( MainView.frame.getWidth() - 1, MainView.frame.getHeight() );
+			actions.add( 0, () -> {
+                inside = false;
+                setNode.setSelected( false );
+                breakPoint = false;
+    		    if( !alignNode.isSelected() )
+    		    	breakPoint |= !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 );
+		    if( !setNode.isSelected() )
+		    	breakPoint |= !setNode.setSelected( true );
+            breakPoint |= !loopNode.setSelected( true );
+		}
+		else
+		{
+            breakPoint = !loopNode.setSelected( true );
+			if( vIndex >= graph.getContainedNodes().size() )
+			{
+	            inside = false; 
+			    setNode.setSelected( false );
+			    loopNode.setSelected( false );
+				return StageStatus.FINISHED;
+			}
+			else
+	            inside = true;
+			LayeredGraphNode current = graph.getContainedNodes().get( vIndex );
+			current.setSelected( null );
+			ArrayList< Integer > positions = new ArrayList<>();
+			positions.add( (int)current.getX( LayoutType.TOP_BOTTOM_LEFT ) + tblOffset );
+			positions.add( (int)current.getX( LayoutType.TOP_BOTTOM_RIGHT ) + tbrOffset );
+			positions.add( (int)current.getX( LayoutType.BOTTOM_TOP_LEFT ) + btlOffset );
+			positions.add( (int)current.getX( LayoutType.BOTTOM_TOP_RIGHT ) + btrOffset );
+			Collections.sort( positions );
+			int oldX = (int)current.getX( LayoutType.COMBINED );
+			current.setX( (positions.get( 1 ) + positions.get( 2 )) / 2, true, LayoutType.COMBINED );
+			actions.add( 0, () -> {
+                inside = true;
+                breakPoint = false;
+    		    if( !setNode.isSelected() )
+    		    	breakPoint |= !setNode.setSelected( true );
+    		    breakPoint |= !loopNode.setSelected( true );
+				vIndex--;
+				current.setX( oldX, true, LayoutType.COMBINED );
+				current.setSelected( null );
+			});
+			vIndex++;
+		}
+		if( breakPoint )
+		    return StageStatus.BREAKPOINT;
+		return StageStatus.UNFINISHED;
+	}
+	
+	private int calcMinX(  LayoutType layout )
+	{
+		int minX = 0;
+		if( graph.getContainedNodes().size() > 0 )
+			minX = (int)graph.getContainedNodes().get( 0 ).getX( layout );
+		for( LayeredGraphNode n : graph.getContainedNodes() )
+			minX = Math.min( minX, (int)n.getX( layout ) );
+		return minX;
 	}
 	}
 
 
 	@Override
 	@Override
 	public StageStatus backwardStep() {
 	public StageStatus backwardStep() {
-		// TODO Auto-generated method stub
-		return null;
+		if( actions.size() == 0 )
+		{
+            inside = false;
+			return StageStatus.FINISHED;
+		}
+		actions.get( 0 ).reverse();
+		actions.remove( 0 );
+        if( breakPoint )
+            return StageStatus.BREAKPOINT;
+		return StageStatus.UNFINISHED;
 	}
 	}
 
 
+    @Override
+    public PseudoCodeNode createPseudocodeTree( JTree tree ) {
+        PseudoCodeNode root = new PseudoCodeNode( "Balancing", tree );
+        alignNode = new PseudoCodeNode( "Align Layouts", tree );
+        setNode = new PseudoCodeNode( "Align to assignment of smallest width", tree );
+        loopNode = new PseudoCodeNode( "Set coordinates to average median of aligned candidates", tree );
+        setNode.add( loopNode );
+        root.add( alignNode );
+        root.add( setNode );
+        return root;
+    }
+
+    @Override
+    public StageStatus forwardStepOver() {
+        if( !inside )
+        {
+            State oldState = state;
+            StageStatus stage = StageStatus.UNFINISHED;
+            while( state == oldState && stage == StageStatus.UNFINISHED )
+                stage = forwardStep();
+            return stage;
+        }
+        else
+            return forwardStep();
+    }
+
+    @Override
+    public StageStatus forwardStepOut() {
+        if( !inside )
+        {
+            StageStatus status = StageStatus.UNFINISHED;
+            while( status == StageStatus.UNFINISHED )
+                status = forwardStep();
+            return status;
+        }
+        else
+        {
+            State oldState = state;
+            StageStatus stage = StageStatus.UNFINISHED;
+            while( state == oldState && stage == StageStatus.UNFINISHED )
+                stage = forwardStep();
+            return stage;
+        }
+    }
+
+    @Override
+    public StageStatus backwardStepOver() {
+        if( !inside )
+        {
+            State oldState = state;
+            StageStatus stage = StageStatus.UNFINISHED;
+            while( state == oldState && stage == StageStatus.UNFINISHED )
+                stage = backwardStep();
+            return stage;
+        }
+        else
+            return backwardStep();
+    }
+
+    @Override
+    public StageStatus backwardStepOut() {
+        if( !inside )
+        {
+            StageStatus status = StageStatus.UNFINISHED;
+            while( status == StageStatus.UNFINISHED )
+                status = backwardStep();
+            return status;
+        }
+        else
+        {
+            State oldState = state;
+            StageStatus stage = StageStatus.UNFINISHED;
+            while( state == oldState && stage == StageStatus.UNFINISHED )
+                stage = backwardStep();
+            return stage;
+        }
+    }
 }
 }

+ 192 - 15
src/bk/Compaction.java

@@ -2,8 +2,11 @@ package bk;
 
 
 import java.util.ArrayList;
 import java.util.ArrayList;
 
 
+import javax.swing.JTree;
+
 import animation.AlgorithmStage;
 import animation.AlgorithmStage;
 import animation.BackwardAction;
 import animation.BackwardAction;
+import animation.PseudoCodeNode;
 import bk.ExtremalLayoutCalc.LayoutType;
 import bk.ExtremalLayoutCalc.LayoutType;
 import graph.LayeredGraphNode;
 import graph.LayeredGraphNode;
 
 
@@ -34,6 +37,13 @@ public class Compaction implements AlgorithmStage{
 	private ArrayList< StackFrame > stack; // TODO: evtl richtigen "Stack" benutzen
 	private ArrayList< StackFrame > stack; // TODO: evtl richtigen "Stack" benutzen
 	private ArrayList< BackwardAction > actions; // TODO: evtl richtigen "Stack" benutzen
 	private ArrayList< BackwardAction > actions; // TODO: evtl richtigen "Stack" benutzen
 	private LayoutType layout;
 	private LayoutType layout;
+	private PseudoCodeNode placeNode;
+    private PseudoCodeNode placeLoopNode;
+    private PseudoCodeNode applyNode;
+    private PseudoCodeNode applyLoopNode;
+    private boolean breakPoint;
+    private boolean inside;
+	
 	
 	
 	public Compaction( LayeredGraphNode graph, LayoutType layout )
 	public Compaction( LayeredGraphNode graph, LayoutType layout )
 	{
 	{
@@ -43,6 +53,7 @@ public class Compaction implements AlgorithmStage{
 		stack = new ArrayList<>(); // der call-stack des rekursiven algorithmus
 		stack = new ArrayList<>(); // der call-stack des rekursiven algorithmus
 		vIndex = 0;
 		vIndex = 0;
 		actions = new ArrayList<>();
 		actions = new ArrayList<>();
+		inside = false;
 	}
 	}
 	
 	
 	/**
 	/**
@@ -55,7 +66,7 @@ public class Compaction implements AlgorithmStage{
 		for( LayeredGraphNode n : graph.getContainedNodes() )
 		for( LayeredGraphNode n : graph.getContainedNodes() )
 			max = Math.max( max, n.getWidth( layout ) );
 			max = Math.max( max, n.getWidth( layout ) );
 		//return max + 25;
 		//return max + 25;
-		return max;
+		return max + 5;
 	}
 	}
 	
 	
 	private LayeredGraphNode getNodeFromIndex( int index )
 	private LayeredGraphNode getNodeFromIndex( int index )
@@ -72,9 +83,14 @@ public class Compaction implements AlgorithmStage{
 	
 	
 	@Override
 	@Override
 	public StageStatus forwardStep() {
 	public StageStatus forwardStep() {
+		breakPoint = false;
 		int acSize = actions.size();
 		int acSize = actions.size();
 		if( state == CompactionState.PLACE_BLOCKS ) // blöcke platzieren
 		if( state == CompactionState.PLACE_BLOCKS ) // blöcke platzieren
 		{
 		{
+		    inside = true;
+		    if( !placeNode.isSelected() )
+		    	breakPoint = !placeNode.setSelected( true );
+		    breakPoint |= !placeLoopNode.setSelected( true );
 			if( stack.size() == 0 ) // äußere schleife, placeblocks bisher nicht aufgerufen
 			if( stack.size() == 0 ) // äußere schleife, placeblocks bisher nicht aufgerufen
 			{
 			{
 				ArrayList< LayeredGraphNode > nodes = graph.getContainedNodes();
 				ArrayList< LayeredGraphNode > nodes = graph.getContainedNodes();
@@ -95,10 +111,23 @@ public class Compaction implements AlgorithmStage{
 				if( !found )
 				if( !found )
 				{
 				{
 				    // wechsele in die phase des Blöckeshiftens
 				    // wechsele in die phase des Blöckeshiftens
+		            placeNode.setSelected( false );
+		            placeLoopNode.setSelected( false );
+				    if( !applyNode.isSelected() )
+				    	breakPoint |= !applyNode.setSelected( true );
+		            breakPoint |= !applyLoopNode.setSelected( true );
 					state = CompactionState.APPLY_SHIFT;
 					state = CompactionState.APPLY_SHIFT;
+					inside = false;
 					vIndex = 0;
 					vIndex = 0;
 					actions.add( 0, ()-> {
 					actions.add( 0, ()-> {
+	                    applyNode.setSelected( false );
+	                    applyLoopNode.setSelected( false );
+	                    breakPoint = false;
+					    if( !placeNode.isSelected() )
+					    	breakPoint |= !placeNode.setSelected( true );
+	                    breakPoint |= !placeLoopNode.setSelected( true );
 						vIndex = oldVIndex;
 						vIndex = oldVIndex;
+						inside = false;
 						state = CompactionState.PLACE_BLOCKS;
 						state = CompactionState.PLACE_BLOCKS;
 					} );
 					} );
 				}
 				}
@@ -108,13 +137,18 @@ public class Compaction implements AlgorithmStage{
 					f.v = getNodeFromIndex( vIndex );
 					f.v = getNodeFromIndex( vIndex );
 					double oldX = f.v.getX( layout ); // nötig für "undo"
 					double oldX = f.v.getX( layout ); // nötig für "undo"
 					f.v.setX( 0, true, layout );
 					f.v.setX( 0, true, layout );
-					f.v.setSelected( layout ); // zeige knoten als aktiven knoten an
 					f.w = f.v;
 					f.w = f.v;
+                    f.w.setSelected( layout ); // zeige knoten als aktiven knoten an
                     System.out.println( "call place_block( " + f.v + " )" );
                     System.out.println( "call place_block( " + f.v + " )" );
 					stack.add( 0, f );
 					stack.add( 0, f );
 					
 					
 					// die "undo"-action
 					// die "undo"-action
 					actions.add( 0, ()-> {
 					actions.add( 0, ()-> {
+	                    breakPoint = false;
+					    if( !placeNode.isSelected() )
+					    	breakPoint |= !placeNode.setSelected( true );
+                        breakPoint |= !placeLoopNode.setSelected( true );
+					    inside = true;
 						stack.get( 0 ).v.setX( oldX, false, layout );
 						stack.get( 0 ).v.setX( oldX, false, layout );
 						stack.get( 0 ).v.setSelected( layout );
 						stack.get( 0 ).v.setSelected( layout );
 						stack.remove( 0 );
 						stack.remove( 0 );
@@ -129,10 +163,12 @@ public class Compaction implements AlgorithmStage{
 				if( sf.u == null ) // zu beginn der placeblock methode
 				if( sf.u == null ) // zu beginn der placeblock methode
 				{
 				{
                     int posW = graph.getContainedLayers().get( sf.w.getLayer() ).indexOf( sf.w );
                     int posW = graph.getContainedLayers().get( sf.w.getLayer() ).indexOf( sf.w );
-					if( posW >= 1 ) // if pos[w] > 1"
+					if( (posW >= 1 && (layout == LayoutType.BOTTOM_TOP_LEFT || layout == LayoutType.TOP_BOTTOM_LEFT)) || (posW < graph.getContainedLayers().get( sf.w.getLayer() ).size() - 1 && (layout == LayoutType.BOTTOM_TOP_RIGHT || layout == LayoutType.TOP_BOTTOM_RIGHT)) ) // if pos[w] > 1"
 					{
 					{
-
-                        sf.u = graph.getContainedLayers().get( sf.w.getLayer() ).get( posW - 1 ).getRoot( layout );
+					    int offset = -1;
+					    if( layout == LayoutType.BOTTOM_TOP_RIGHT || layout == LayoutType.TOP_BOTTOM_RIGHT )
+					        offset = 1;
+                        sf.u = graph.getContainedLayers().get( sf.w.getLayer() ).get( posW + offset ).getRoot( layout );
 						
 						
 						if( sf.u.isXUndefined( layout ) ) // nötig placeblock aufzurufen?
 						if( sf.u.isXUndefined( layout ) ) // nötig placeblock aufzurufen?
 						{// ja
 						{// ja
@@ -140,13 +176,18 @@ public class Compaction implements AlgorithmStage{
 							nsf.v = sf.u;
 							nsf.v = sf.u;
 							double oldX = nsf.v.getX( layout ); // nötig für "undo"
 							double oldX = nsf.v.getX( layout ); // nötig für "undo"
 							nsf.v.setX( 0, true, layout );
 							nsf.v.setX( 0, true, layout );
-							nsf.v.setSelected( layout ); // zeige knoten als aktiven knoten an
 							nsf.w = nsf.v;
 							nsf.w = nsf.v;
+                            nsf.w.setSelected( layout ); // zeige knoten als aktiven knoten an
 		                    System.out.println( "call place_block( " + nsf.v + " )" );
 		                    System.out.println( "call place_block( " + nsf.v + " )" );
 							stack.add( 0, nsf );
 							stack.add( 0, nsf );
 		                    
 		                    
 		                    // die "undo"-action
 		                    // die "undo"-action
 							actions.add( 0, ()-> {
 							actions.add( 0, ()-> {
+			                    breakPoint = false;
+							    if( !placeNode.isSelected() )
+							    	breakPoint |= !placeNode.setSelected( true );
+		                        breakPoint |= !placeLoopNode.setSelected( true );
+							    inside = true;
 								stack.get( 0 ).v.setX( oldX, false, layout );
 								stack.get( 0 ).v.setX( oldX, false, layout );
 								stack.get( 0 ).v.setSelected( layout );
 								stack.get( 0 ).v.setSelected( layout );
 								stack.remove( 0 );
 								stack.remove( 0 );
@@ -156,8 +197,13 @@ public class Compaction implements AlgorithmStage{
 						else // nein
 						else // nein
 						{
 						{
 						    // tue nix
 						    // tue nix
-							sf.u.setSelected( layout ); 
+							sf.w.setSelected( layout );
 							actions.add( 0, ()-> {
 							actions.add( 0, ()-> {
+			                    breakPoint = false;
+							    if( !placeNode.isSelected() )
+							    	breakPoint |= !placeNode.setSelected( true );
+		                        breakPoint |= !placeLoopNode.setSelected( true );
+                                inside = true;
 								stack.get( 0 ).u = null;
 								stack.get( 0 ).u = null;
 							});
 							});
 						}
 						}
@@ -172,16 +218,26 @@ public class Compaction implements AlgorithmStage{
                             System.out.println( "return place_block( " + sf.v + " )" );
                             System.out.println( "return place_block( " + sf.v + " )" );
 							stack.remove( 0 );
 							stack.remove( 0 );
 							actions.add( 0, ()-> {
 							actions.add( 0, ()-> {
+			                    breakPoint = false;
+							    if( !placeNode.isSelected() )
+							    	breakPoint |= !placeNode.setSelected( true );
+		                        breakPoint |= !placeLoopNode.setSelected( true );
+                                inside = true;
 								stack.add( 0, sf );
 								stack.add( 0, sf );
-								sf.v.setSelected( layout );
 								sf.w = oldW;
 								sf.w = oldW;
+                                sf.w.setSelected( layout );
 							});
 							});
 						}
 						}
 						else
 						else
 						{ //nur "undo aktion" hinzufügen
 						{ //nur "undo aktion" hinzufügen
 							actions.add( 0, ()-> {
 							actions.add( 0, ()-> {
+			                    breakPoint = false;
+							    if( !placeNode.isSelected() )
+							    	breakPoint |= !placeNode.setSelected( true );
+		                        breakPoint |= !placeLoopNode.setSelected( true );
+                                inside = true;
 								sf.w = oldW;
 								sf.w = oldW;
-								sf.v.setSelected( layout );
+								sf.w.setSelected( layout );
 							});
 							});
 						}
 						}
 					}	
 					}	
@@ -196,18 +252,21 @@ public class Compaction implements AlgorithmStage{
 					boolean oldDef = !sf.v.isXUndefined( layout );
 					boolean oldDef = !sf.v.isXUndefined( layout );
 					
 					
 					// v für visualisierung markieren
 					// v für visualisierung markieren
-					sf.v.setSelected( layout );
+					sf.w.setSelected( layout );
                     
                     
                     if( sf.v.getSink( layout ) == sf.v ) // sink[v] = v?
                     if( sf.v.getSink( layout ) == sf.v ) // sink[v] = v?
                         sf.v.setSink( sf.u.getSink( layout ), layout ); // sink[v] := sink[u]
                         sf.v.setSink( sf.u.getSink( layout ), layout ); // sink[v] := sink[u]
-
+                    int multiplyer = 1;
+                    if( layout == LayoutType.BOTTOM_TOP_RIGHT || layout == LayoutType.TOP_BOTTOM_RIGHT )
+                        multiplyer = -1;
+                    
 					if( sf.v.getSink( layout ) != sf.u.getSink( layout ) ) // sink[v] != sink [u]?
 					if( sf.v.getSink( layout ) != sf.u.getSink( layout ) ) // sink[v] != sink [u]?
 						sf.u.getSink( layout ).setShift( // shift[sink[u]] =
 						sf.u.getSink( layout ).setShift( // shift[sink[u]] =
 						  Math.min( sf.u.getSink( layout ).getShift( layout ),  // min(shift[sink[u]]
 						  Math.min( sf.u.getSink( layout ).getShift( layout ),  // min(shift[sink[u]]
-						          sf.v.getX( layout ) - sf.u.getX( layout ) - calcSpacing() ), layout ); // y_v - y_u - s
+						          multiplyer * (Math.abs(sf.v.getX( layout )) - Math.abs(sf.u.getX( layout )) - calcSpacing()) ), layout ); // y_v - y_u - s
 					else
 					else
 					    // y_v = max {y_v, y_u + s}
 					    // y_v = max {y_v, y_u + s}
-						sf.v.setX( Math.max( sf.v.getX( layout ), sf.u.getX( layout ) + calcSpacing() ), true, layout );
+						sf.v.setX( multiplyer * Math.max( Math.abs( sf.v.getX( layout ) ), Math.abs( sf.u.getX( layout ) ) + calcSpacing() ), true, layout );
 					
 					
 
 
                     // alte Werte merken für undo
                     // alte Werte merken für undo
@@ -222,24 +281,34 @@ public class Compaction implements AlgorithmStage{
 					    System.out.println( "return place_block( " + sf.v + " )" );
 					    System.out.println( "return place_block( " + sf.v + " )" );
 						stack.remove( 0 );
 						stack.remove( 0 );
 						actions.add( 0, ()-> {
 						actions.add( 0, ()-> {
+		                    breakPoint = false;
+						    if( !placeNode.isSelected() )
+						    	breakPoint |= !placeNode.setSelected( true );
+	                        breakPoint |= !placeLoopNode.setSelected( true );
+                            inside = true;
 							stack.add( 0, sf );
 							stack.add( 0, sf );
 							stack.get( 0 ).v.setSink(  oldSink, layout );
 							stack.get( 0 ).v.setSink(  oldSink, layout );
 							sinkOfU.setShift( oldShift, layout );
 							sinkOfU.setShift( oldShift, layout );
 							sf.u = oldU;
 							sf.u = oldU;
 							sf.v.setX( oldX, oldDef, layout );
 							sf.v.setX( oldX, oldDef, layout );
-							sf.v.setSelected( layout );
 							sf.w = oldW;
 							sf.w = oldW;
+                            sf.w.setSelected( layout );
 						});
 						});
 					}
 					}
 					else
 					else
 					{ //nur "undo aktion" hinzufügen
 					{ //nur "undo aktion" hinzufügen
 						actions.add( 0, ()-> {
 						actions.add( 0, ()-> {
+		                    breakPoint = false;
+						    if( !placeNode.isSelected() )
+						    	breakPoint |= !placeNode.setSelected( true );
+	                        breakPoint |= !placeLoopNode.setSelected( true );
+                            inside = true;
 							stack.get( 0 ).v.setSink(  oldSink, layout );
 							stack.get( 0 ).v.setSink(  oldSink, layout );
 							sinkOfU.setShift( oldShift, layout );
 							sinkOfU.setShift( oldShift, layout );
 							sf.u = oldU;
 							sf.u = oldU;
 							sf.v.setX( oldX, oldDef, layout );
 							sf.v.setX( oldX, oldDef, layout );
-							sf.v.setSelected( layout );
 							sf.w = oldW;
 							sf.w = oldW;
+                            sf.w.setSelected( layout );
 						});
 						});
 					}
 					}
 				}
 				}
@@ -247,6 +316,17 @@ public class Compaction implements AlgorithmStage{
 		}
 		}
 		else if( state == CompactionState.APPLY_SHIFT )// "Compute absolute coordinates"
 		else if( state == CompactionState.APPLY_SHIFT )// "Compute absolute coordinates"
 		{
 		{
+            inside = true;
+		    if( !applyNode.isSelected() )
+		    	breakPoint |= !applyNode.setSelected( true );
+            breakPoint |= !applyLoopNode.setSelected( true );
+		    if( vIndex >= graph.getContainedNodes().size() )
+		    {
+                inside = false;
+                applyNode.setSelected( false );
+                applyLoopNode.setSelected( false );
+                return StageStatus.FINISHED;
+		    }
 			LayeredGraphNode v = graph.getContainedNodes().get( vIndex );
 			LayeredGraphNode v = graph.getContainedNodes().get( vIndex );
 			double oldX = v.getX( layout );
 			double oldX = v.getX( layout );
 			boolean oldDef = !v.isXUndefined( layout );
 			boolean oldDef = !v.isXUndefined( layout );
@@ -256,26 +336,123 @@ public class Compaction implements AlgorithmStage{
 			if( v == v.getRoot( layout ) && v.getSink( layout ).getShift( layout ) < Double.POSITIVE_INFINITY )
 			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 );
 				v.setX( v.getX( layout ) + v.getSink( layout ).getShift( layout ), true, layout );
 			actions.add( 0, ()-> {
 			actions.add( 0, ()-> {
+                inside = true;
+                breakPoint = false;
+			    if( !applyNode.isSelected() )
+			    	breakPoint |= !applyNode.setSelected( true );
+                breakPoint |= !applyLoopNode.setSelected( true );
 				v.setX( oldX, oldDef, layout );
 				v.setX( oldX, oldDef, layout );
 				v.setSelected( layout );
 				v.setSelected( layout );
 				vIndex--;
 				vIndex--;
 			} );
 			} );
 			vIndex++;
 			vIndex++;
 			if( vIndex >= graph.getContainedNodes().size() )
 			if( vIndex >= graph.getContainedNodes().size() )
+			{
+                applyNode.setSelected( false );
+                applyLoopNode.setSelected( false );
 				return StageStatus.FINISHED;
 				return StageStatus.FINISHED;
+			}
 		}
 		}
 		if( actions.size() != acSize + 1 )
 		if( actions.size() != acSize + 1 )
 			System.out.println( "ERROR" );
 			System.out.println( "ERROR" );
+		if( breakPoint )
+		    return StageStatus.BREAKPOINT;
 		return StageStatus.UNFINISHED;
 		return StageStatus.UNFINISHED;
 	}
 	}
 
 
 	@Override
 	@Override
 	public StageStatus backwardStep() {
 	public StageStatus backwardStep() {
 		if( actions.size() == 0 )
 		if( actions.size() == 0 )
+		{
+            inside = false;
+            placeNode.setSelected( false );
+            placeLoopNode.setSelected( false );
 			return StageStatus.FINISHED;
 			return StageStatus.FINISHED;
+		}
 		actions.get( 0 ).reverse();
 		actions.get( 0 ).reverse();
 		actions.remove( 0 );
 		actions.remove( 0 );
+        if( breakPoint )
+            return StageStatus.BREAKPOINT;
 		return StageStatus.UNFINISHED;
 		return StageStatus.UNFINISHED;
 	}
 	}
 
 
+    @Override
+    public PseudoCodeNode createPseudocodeTree( JTree tree ) {
+        PseudoCodeNode root = new PseudoCodeNode( "Horizontal compaction", tree );
+        placeNode = new PseudoCodeNode( "Root coordinates relative to sink", tree );
+        placeLoopNode = new PseudoCodeNode( "Loop through root nodes...", tree );
+        placeNode.add( placeLoopNode );
+        applyNode = new PseudoCodeNode( "Absolute coordinates", tree );
+        applyLoopNode = new PseudoCodeNode( "Loop through all nodes...", tree );
+        applyNode.add( applyLoopNode );
+        root.add( placeNode );
+        root.add( applyNode );
+        return root;
+    }
+
+    @Override
+    public StageStatus forwardStepOver() {
+        if( !inside )
+        {
+            CompactionState oldState = state;
+            StageStatus stage = StageStatus.UNFINISHED;
+            while( state == oldState && stage == StageStatus.UNFINISHED )
+                stage = forwardStep();
+            return stage;
+        }
+        else
+            return forwardStep();
+    }
+
+    @Override
+    public StageStatus forwardStepOut() {
+        if( !inside )
+        {
+            StageStatus status = StageStatus.UNFINISHED;
+            while( status == StageStatus.UNFINISHED )
+                status = forwardStep();
+            return status;
+        }
+        else
+        {
+            CompactionState oldState = state;
+            StageStatus stage = StageStatus.UNFINISHED;
+            while( state == oldState && stage == StageStatus.UNFINISHED )
+                stage = forwardStep();
+            return stage;
+        }
+    }
+
+    @Override
+    public StageStatus backwardStepOver() {
+        if( !inside )
+        {
+            CompactionState oldState = state;
+            StageStatus stage = StageStatus.UNFINISHED;
+            while( state == oldState && stage == StageStatus.UNFINISHED )
+                stage = backwardStep();
+            return stage;
+        }
+        else
+            return backwardStep();
+    }
+
+    @Override
+    public StageStatus backwardStepOut() {
+        if( !inside )
+        {
+            StageStatus status = StageStatus.UNFINISHED;
+            while( status == StageStatus.UNFINISHED )
+                status = backwardStep();
+            return status;
+        }
+        else
+        {
+            CompactionState oldState = state;
+            StageStatus stage = StageStatus.UNFINISHED;
+            while( state == oldState && stage == StageStatus.UNFINISHED )
+                stage = backwardStep();
+            return stage;
+        }
+    }
 }
 }

+ 64 - 1
src/bk/ConflictDetection.java

@@ -2,8 +2,11 @@ package bk;
 
 
 import java.util.ArrayList;
 import java.util.ArrayList;
 
 
+import javax.swing.JTree;
+
 import animation.AlgorithmStage;
 import animation.AlgorithmStage;
 import animation.BackwardAction;
 import animation.BackwardAction;
+import animation.PseudoCodeNode;
 import graph.LayeredGraphEdge;
 import graph.LayeredGraphEdge;
 import graph.LayeredGraphNode;
 import graph.LayeredGraphNode;
 
 
@@ -14,6 +17,7 @@ public class ConflictDetection implements AlgorithmStage {
     
     
     private int i;
     private int i;
     private int l1;
     private int l1;
+    private PseudoCodeNode markNode;
     
     
     ConflictDetection( LayeredGraphNode graph )
     ConflictDetection( LayeredGraphNode graph )
     {
     {
@@ -27,8 +31,14 @@ public class ConflictDetection implements AlgorithmStage {
     public StageStatus forwardStep() {
     public StageStatus forwardStep() {
     	int oldI = i;
     	int oldI = i;
     	int oldL1 = l1;
     	int oldL1 = l1;
+    	((PseudoCodeNode)markNode.getParent()).setSelected( true );
+    	boolean breakPoint = !markNode.setSelected( true );
     	if( i + 1 >= graph.getContainedLayers().size() - 1 )
     	if( i + 1 >= graph.getContainedLayers().size() - 1 )
+    	{
+            ((PseudoCodeNode)markNode.getParent()).setSelected( false );
+            markNode.setSelected( false );
     		return StageStatus.FINISHED;
     		return StageStatus.FINISHED;
+    	}
     	LayeredGraphNode curr = graph.getContainedLayers().get( i + 1 ).get( l1 );
     	LayeredGraphNode curr = graph.getContainedLayers().get( i + 1 ).get( l1 );
     	curr.setSelected( null );
     	curr.setSelected( null );
     	ArrayList< LayeredGraphEdge > edges = curr.getIncomingEdges();
     	ArrayList< LayeredGraphEdge > edges = curr.getIncomingEdges();
@@ -60,12 +70,19 @@ public class ConflictDetection implements AlgorithmStage {
         for( LayeredGraphEdge c : conflicts )
         for( LayeredGraphEdge c : conflicts )
         	c.setConflicted( true, null );
         	c.setConflicted( true, null );
     	StageStatus status =  calcNextStatus();
     	StageStatus status =  calcNextStatus();
-    	actions.add( ()->{
+    	actions.add( 0, ()->{
     		i = oldI;
     		i = oldI;
     		l1 = oldL1;
     		l1 = oldL1;
+            if( i + 1 < graph.getContainedLayers().size() - 1 && l1 > 0 )
+            {
+                LayeredGraphNode layde = graph.getContainedLayers().get( i + 1 ).get( l1 - 1 );
+                layde.setSelected( null );
+            }
             for( LayeredGraphEdge c : conflicts )
             for( LayeredGraphEdge c : conflicts )
             	c.setConflicted( false, null );
             	c.setConflicted( false, null );
     	});
     	});
+    	if( status != StageStatus.FINISHED && breakPoint )
+    	    return StageStatus.BREAKPOINT;
     	return status;
     	return status;
     }
     }
     
     
@@ -79,6 +96,8 @@ public class ConflictDetection implements AlgorithmStage {
             {
             {
                 i--;
                 i--;
                 l1--;
                 l1--;
+                ((PseudoCodeNode)markNode.getParent()).setSelected( false );
+                markNode.setSelected( false );
                 return StageStatus.FINISHED;
                 return StageStatus.FINISHED;
             }
             }
             l1 = 0;
             l1 = 0;
@@ -88,10 +107,54 @@ public class ConflictDetection implements AlgorithmStage {
 
 
     @Override
     @Override
     public StageStatus backwardStep() {
     public StageStatus backwardStep() {
+        ((PseudoCodeNode)markNode.getParent()).setSelected( true );
+        boolean breakPoint = !markNode.setSelected( true );
         if( actions.size() == 0 )
         if( actions.size() == 0 )
+        {
+            ((PseudoCodeNode)markNode.getParent()).setSelected( false );
+            markNode.setSelected( false );
         	return StageStatus.FINISHED;
         	return StageStatus.FINISHED;
+        }
         actions.get( 0 ).reverse();
         actions.get( 0 ).reverse();
         actions.remove( 0 );
         actions.remove( 0 );
+        if( breakPoint )
+            return StageStatus.BREAKPOINT;
         return StageStatus.UNFINISHED;
         return StageStatus.UNFINISHED;
     }
     }
+
+    @Override
+    public PseudoCodeNode createPseudocodeTree( JTree tree ) {
+        PseudoCodeNode root = new PseudoCodeNode( "Preprocessing (mark type 1 conflicts)", tree );
+        PseudoCodeNode loopNode = new PseudoCodeNode( "Loop through all nodes...", tree );
+        markNode = new PseudoCodeNode( "If non-inner segment crosses an inner segment whose target is this node, mark the non-inner segment as conflicted", tree );
+        loopNode.add( markNode );
+        root.add( loopNode );
+        return root;
+    }
+
+    @Override
+    public StageStatus forwardStepOver() {
+        return forwardStep();
+    }
+
+    @Override
+    public StageStatus forwardStepOut() {
+        StageStatus status = StageStatus.UNFINISHED;
+        while( status == StageStatus.UNFINISHED )
+            status = forwardStep();
+        return status;
+    }
+
+    @Override
+    public StageStatus backwardStepOver() {
+        return backwardStep();
+    }
+
+    @Override
+    public StageStatus backwardStepOut() {
+        StageStatus status = StageStatus.UNFINISHED;
+        while( status == StageStatus.UNFINISHED )
+            status = backwardStep();
+        return status;
+    }
 }
 }

+ 195 - 19
src/bk/ExtremalLayoutCalc.java

@@ -1,6 +1,11 @@
 package bk;
 package bk;
 
 
+import java.lang.reflect.InvocationTargetException;
+
+import javax.swing.JTree;
+
 import animation.AlgorithmStage;
 import animation.AlgorithmStage;
+import animation.PseudoCodeNode;
 import graph.LayeredGraphNode;
 import graph.LayeredGraphNode;
 
 
 /**
 /**
@@ -24,43 +29,214 @@ public class ExtremalLayoutCalc implements AlgorithmStage {
 		COMPACTION
 		COMPACTION
 	}
 	}
 	
 	
+	private PseudoCodeNode pseudoCode;
 	private BlockCalc bc;
 	private BlockCalc bc;
 	private Compaction cp;
 	private Compaction cp;
 	private LayoutState status;
 	private LayoutState status;
+	private PseudoCodeNode bcNode;
+	private PseudoCodeNode cpNode;
+	private LayoutType type;
+	private boolean inside;
 	
 	
 	
 	
 	public ExtremalLayoutCalc( LayoutType typ, LayeredGraphNode graph )
 	public ExtremalLayoutCalc( LayoutType typ, LayeredGraphNode graph )
 	{
 	{
+	    type = typ;
 		status = LayoutState.BLOCK_CALCULATION;
 		status = LayoutState.BLOCK_CALCULATION;
 		bc = new BlockCalc( graph, typ );
 		bc = new BlockCalc( graph, typ );
 		cp = new Compaction( graph, typ );
 		cp = new Compaction( graph, typ );
+		inside = false;
 	}
 	}
 	
 	
 	@Override
 	@Override
 	public StageStatus forwardStep() {
 	public StageStatus forwardStep() {
-		if( status == LayoutState.BLOCK_CALCULATION )
-		{
-			if( bc.forwardStep() == StageStatus.FINISHED )
-			{
-				status = LayoutState.COMPACTION;
-			}
-			return StageStatus.UNFINISHED;
-		}
-		if( status == LayoutState.COMPACTION )
-			return cp.forwardStep();
-		return StageStatus.UNFINISHED;
+		return forward( "forwardStep" );
 	}
 	}
 
 
 	@Override
 	@Override
 	public StageStatus backwardStep() {
 	public StageStatus backwardStep() {
-		if( status == LayoutState.BLOCK_CALCULATION )
-			return bc.backwardStep();
-		if( status == LayoutState.COMPACTION )
-		{
-			if( cp.backwardStep() == StageStatus.FINISHED )
-				status = LayoutState.BLOCK_CALCULATION;
-		}
-		return StageStatus.UNFINISHED;
+		return backward( "backwardStep" );
 	}
 	}
 
 
+    @Override
+    public PseudoCodeNode createPseudocodeTree( JTree tree ) {
+        if( type == LayoutType.TOP_BOTTOM_LEFT )
+            pseudoCode = new PseudoCodeNode( "Extremal layout: leftmost upper", tree );
+        if( type == LayoutType.TOP_BOTTOM_RIGHT )
+            pseudoCode = new PseudoCodeNode( "Extremal layout: rightmost upper'", tree );
+        if( type == LayoutType.BOTTOM_TOP_LEFT )
+            pseudoCode = new PseudoCodeNode( "Extremal layout: leftmost lower'", tree );;
+        if( type == LayoutType.BOTTOM_TOP_RIGHT )
+            pseudoCode = new PseudoCodeNode( "Extremal layout: rightmost lower'", tree );
+        bcNode = bc.createPseudocodeTree( tree );
+        cpNode = cp.createPseudocodeTree( tree );
+        pseudoCode.add( bcNode );
+        pseudoCode.add( cpNode );
+        return pseudoCode;
+    }
+
+    @Override
+    public StageStatus forwardStepOver() {
+        if( !inside )
+        {
+            LayoutState oldState = status;
+            StageStatus stage = StageStatus.UNFINISHED;
+            while( status == oldState && stage == StageStatus.UNFINISHED )
+                stage = forwardStep();
+            return stage;
+        }
+        else
+            return forward( "forwardStepOver" );
+    }
+
+    @Override
+    public StageStatus forwardStepOut() {
+        if( !inside )
+        {
+            StageStatus status = StageStatus.UNFINISHED;
+            while( status == StageStatus.UNFINISHED )
+                status = forwardStep();
+            return status;
+        }
+        else
+            return forward( "forwardStepOut" );
+    }
+
+    @Override
+    public StageStatus backwardStepOver() {
+        if( !inside )
+        {
+            LayoutState oldState = status;
+            StageStatus stage = StageStatus.UNFINISHED;
+            while( status == oldState && stage == StageStatus.UNFINISHED )
+                stage = backwardStep();
+            return stage;
+        }
+        else
+            return backward( "backwardStepOver" );
+    }
+
+    @Override
+    public StageStatus backwardStepOut() {
+        if( !inside )
+        {
+            StageStatus status = StageStatus.UNFINISHED;
+            while( status == StageStatus.UNFINISHED )
+                status = backwardStep();
+            return status;
+        }
+        else
+            return backward( "backwardStepOut" );
+    }
+    
+    private StageStatus forward( String fName )
+    {
+        boolean breakpoint = false;
+        try {
+            if( status == LayoutState.BLOCK_CALCULATION )
+            {
+            	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;
+                }
+            }
+            else if( status == LayoutState.COMPACTION )
+            {
+            	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;
+                }
+            }
+        } catch (IllegalAccessException e) {
+            e.printStackTrace();
+        } catch (IllegalArgumentException e) {
+            e.printStackTrace();
+        } catch (InvocationTargetException e) {
+            e.printStackTrace();
+        } catch (NoSuchMethodException e) {
+            e.printStackTrace();
+        } catch (SecurityException e) {
+            e.printStackTrace();
+        }
+        if( breakpoint )
+            return StageStatus.BREAKPOINT;
+        return StageStatus.UNFINISHED;
+    }
+    
+    private StageStatus backward( String fName )
+    {
+        boolean breakpoint = false;
+        try {
+            if( status == LayoutState.BLOCK_CALCULATION )
+            {
+            	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;
+                }
+            }
+            else if( status == LayoutState.COMPACTION )
+            {
+            	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;
+                }
+            }
+        } catch (IllegalAccessException e) {
+            e.printStackTrace();
+        } catch (IllegalArgumentException e) {
+            e.printStackTrace();
+        } catch (InvocationTargetException e) {
+            e.printStackTrace();
+        } catch (NoSuchMethodException e) {
+            e.printStackTrace();
+        } catch (SecurityException e) {
+            e.printStackTrace();
+        }
+        if( breakpoint )
+            return StageStatus.BREAKPOINT;
+        return StageStatus.UNFINISHED;
+    }
 }
 }

+ 1 - 1
src/graph/LayeredGraphNode.java

@@ -36,11 +36,11 @@ public interface LayeredGraphNode {
     public String getName();
     public String getName();
     public void setColor( Color c, LayoutType layout );
     public void setColor( Color c, LayoutType layout );
     public Color getColor( LayoutType layout );
     public Color getColor( LayoutType layout );
-    public void update();
     public void setSelected( LayoutType layoutType );
     public void setSelected( LayoutType layoutType );
     public boolean isSelected( LayoutType layout );
     public boolean isSelected( LayoutType layout );
     public void setDummyNode( boolean dummy );
     public void setDummyNode( boolean dummy );
     public boolean isDummyNode();
     public boolean isDummyNode();
+    public void unselectGraph();
     
     
     /**
     /**
      * Setzt den Index des Layers, zu dem der Knoten geh�ren soll
      * Setzt den Index des Layers, zu dem der Knoten geh�ren soll

+ 14 - 14
src/graph/LayeredNode.java

@@ -3,13 +3,10 @@ package graph;
 import java.awt.Color;
 import java.awt.Color;
 import java.util.ArrayList;
 import java.util.ArrayList;
 
 
-import javax.swing.SwingUtilities;
-
 import org.eclipse.elk.graph.ElkEdge;
 import org.eclipse.elk.graph.ElkEdge;
 import org.eclipse.elk.graph.ElkNode;
 import org.eclipse.elk.graph.ElkNode;
 
 
 import bk.ExtremalLayoutCalc.LayoutType;
 import bk.ExtremalLayoutCalc.LayoutType;
-import view.MainView;
 
 
 /**
 /**
  * Die Implementation eines Knotens in einem Layered Graph.
  * Die Implementation eines Knotens in einem Layered Graph.
@@ -263,16 +260,6 @@ public class LayeredNode implements LayeredGraphNode {
         return null;
         return null;
     }
     }
 
 
-    @Override
-    public void update()
-    {
-    	SwingUtilities.invokeLater(new Runnable() {
-		    public void run() {
-		        MainView.frame.repaint();
-		    }
-		});
-    }
-
     @Override
     @Override
     public void setSelected( LayoutType layout )
     public void setSelected( LayoutType layout )
     {
     {
@@ -294,7 +281,20 @@ public class LayeredNode implements LayeredGraphNode {
             this.layouts[ 3 ].selected = true;
             this.layouts[ 3 ].selected = true;
         if( layout == LayoutType.COMBINED )
         if( layout == LayoutType.COMBINED )
         	combined.selected = true;
         	combined.selected = true;
-    	update();
+    }
+    
+    @Override
+    public void unselectGraph()
+    {
+        for( LayeredGraphNode n : nodes)
+        {
+            n.unselectGraph();
+        }
+        this.layouts[ 0 ].selected = false;
+        this.layouts[ 1 ].selected = false;
+        this.layouts[ 2 ].selected = false;
+        this.layouts[ 3 ].selected = false;
+        combined.selected = false;
     }
     }
 
 
     @Override
     @Override

+ 2 - 0
src/graph/RandomGraphGenerator.java

@@ -67,6 +67,8 @@ public class RandomGraphGenerator {
                         }
                         }
                     }
                     }
                     n.setName( "" + (index+1) );
                     n.setName( "" + (index+1) );
+                    n.setWidth( 40, null );
+                    n.setHeight( 40, null );
                     index++;
                     index++;
                 }
                 }
             }
             }

BIN
src/img/debug.png


BIN
src/img/load.png


BIN
src/img/pause.png


BIN
src/img/random.png


BIN
src/img/runBackward.png


BIN
src/img/runForward.png


BIN
src/img/save.png


BIN
src/img/stepBackward.png


BIN
src/img/stepBackwardInto.png


BIN
src/img/stepBackwardOut.png


BIN
src/img/stepForward.png


BIN
src/img/stepForwardInto.png


BIN
src/img/stepForwardOut.png


+ 2 - 8
src/main/Main.java

@@ -1,11 +1,10 @@
 package main;
 package main;
 import graph.InitializeNodePositions;
 import graph.InitializeNodePositions;
 import graph.LayeredGraphNode;
 import graph.LayeredGraphNode;
-import graph.RandomGraphGenerator;
 import graph.io.Reader;
 import graph.io.Reader;
-import lib.SweepCrossingMinimizer;
 import view.MainView;
 import view.MainView;
 
 
+
 /**
 /**
  * The main executable class. Starts the application.
  * The main executable class. Starts the application.
  * @author kolja
  * @author kolja
@@ -18,13 +17,8 @@ public class Main {
      * @param args the command line arguments, currently not in use
      * @param args the command line arguments, currently not in use
      */
      */
 	public static void main(String[] args) {
 	public static void main(String[] args) {
-		Reader r = new Reader( "test3.json" );
+		Reader r = new Reader( "logo.json" );
 		LayeredGraphNode graph = r.readInputGraph();
 		LayeredGraphNode graph = r.readInputGraph();
-	    //RandomGraphGenerator r = new RandomGraphGenerator( 0.1, 0.2, 5,5, 5, 5, 1 );
-	    //LayeredGraphNode graph = r.createRandomNode( null, 0 );
-	    //SweepCrossingMinimizer cminzer = new SweepCrossingMinimizer();
-	    //for( int i = 0; i < 10; i++ )
-	    //	cminzer.minimizeCrossings( graph );
 		InitializeNodePositions.placeNodes( graph );
 		InitializeNodePositions.placeNodes( graph );
 		new MainView( graph );
 		new MainView( graph );
 	}
 	}

+ 670 - 78
src/view/MainView.java

@@ -1,24 +1,51 @@
 package view;
 package view;
 
 
-import java.awt.Component;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
 import java.awt.GridLayout;
 import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
 import java.awt.event.ComponentAdapter;
 import java.awt.event.ComponentAdapter;
 import java.awt.event.ComponentEvent;
 import java.awt.event.ComponentEvent;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
 import java.awt.event.KeyEvent;
 import java.awt.event.KeyEvent;
-import java.awt.event.KeyListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
 
 
 import javax.swing.JButton;
 import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFileChooser;
 import javax.swing.JFrame;
 import javax.swing.JFrame;
+import javax.swing.JLabel;
 import javax.swing.JLayeredPane;
 import javax.swing.JLayeredPane;
 import javax.swing.JPanel;
 import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.JTree;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreePath;
 
 
 import animation.Action;
 import animation.Action;
 import animation.AnimationController;
 import animation.AnimationController;
+import animation.PseudoCodeNode;
 import bk.BKNodePlacement;
 import bk.BKNodePlacement;
 import bk.ExtremalLayoutCalc.LayoutType;
 import bk.ExtremalLayoutCalc.LayoutType;
+import graph.InitializeNodePositions;
 import graph.LayeredGraphEdge;
 import graph.LayeredGraphEdge;
 import graph.LayeredGraphNode;
 import graph.LayeredGraphNode;
+import graph.RandomGraphGenerator;
+import graph.io.Reader;
 import graph.io.Writer;
 import graph.io.Writer;
+import lib.SweepCrossingMinimizer;
 
 
 /**
 /**
  * The main window of the application.
  * The main window of the application.
@@ -32,8 +59,26 @@ public class MainView {
      * The 'frame' of the main window.
      * The 'frame' of the main window.
      * The reason why there can only be one instance of this class.
      * The reason why there can only be one instance of this class.
      */
      */
-    public static JFrame frame;
-	AnimationController controller;
+    private static int frameCounter = 0;
+    private JFrame frame;
+	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 load;
+    private JButton save;
+    private JButton debug;
+    private JButton randomGraph;
+    private JLabel delayText;
+    private JTextField delay;
+    public JTree pseudoTree;
+    private LayeredGraphNode graph;
 	
 	
 	private String strToLen( String s, int l )
 	private String strToLen( String s, int l )
 	{
 	{
@@ -46,91 +91,612 @@ public class MainView {
 		return s;
 		return s;
 	}
 	}
 	
 	
+	private String debugInfo()
+	{
+	    String info = "Debug Information Table: \n";
+	    info += "_______________________________________________________________________________________________________________________________________________________________________________________________________________________\n";
+	    info += "|" + strToLen( "Top -> Bottom :> Left", 51 ) + "| |" + strToLen( "Top -> Bottom :> Right", 51 ) + "| |" + strToLen( "Bottom -> Top :> Left", 51 ) + "| |" + strToLen( "Bottom -> Top :> Right", 51 ) + "|\n";
+	    info += "|___________________________________________________| |___________________________________________________| |___________________________________________________| |___________________________________________________|\n";
+        info += "| Node | Shift | Sink | Root | Align |  x  |  xDef  | | Node | Shift | Sink | Root | Align |  x  |  xDef  | | Node | Shift | Sink | Root | Align |  x  |  xDef  | | Node | Shift | Sink | Root | Align |  x  |  xDef  |\n";
+        for( LayeredGraphNode n : graph.getContainedNodes() )
+        {
+            info += "|" + strToLen( n.getName(), 6 ) + 
+                    "|" + strToLen( n.getShift( LayoutType.TOP_BOTTOM_LEFT ) + "", 7 ) + 
+                    "|" + strToLen( n.getSink( LayoutType.TOP_BOTTOM_LEFT ).getName(), 6 ) + 
+                    "|" + strToLen( n.getRoot( LayoutType.TOP_BOTTOM_LEFT ).getName(), 6 ) + 
+                    "|" + strToLen( n.getAlignedTo( LayoutType.TOP_BOTTOM_LEFT ).getName(), 7 ) + 
+                    "|" + strToLen( n.getX( LayoutType.TOP_BOTTOM_LEFT ) + "", 5 ) + 
+                    "|" + strToLen( !n.isXUndefined( LayoutType.TOP_BOTTOM_LEFT ) + "", 8 ) + "| " +
+                    "|" + strToLen( n.getName(), 6 ) + 
+                    "|" + strToLen( n.getShift( LayoutType.TOP_BOTTOM_RIGHT ) + "", 7 ) + 
+                    "|" + strToLen( n.getSink( LayoutType.TOP_BOTTOM_RIGHT ).getName(), 6 ) + 
+                    "|" + strToLen( n.getRoot( LayoutType.TOP_BOTTOM_RIGHT ).getName(), 6 ) + 
+                    "|" + strToLen( n.getAlignedTo( LayoutType.TOP_BOTTOM_RIGHT ).getName(), 7 ) + 
+                    "|" + strToLen( n.getX( LayoutType.TOP_BOTTOM_RIGHT ) + "", 5 ) + 
+                    "|" + strToLen( !n.isXUndefined( LayoutType.TOP_BOTTOM_RIGHT ) + "", 8 ) + "| " +
+                    "|" + strToLen( n.getName(), 6 ) + 
+                    "|" + strToLen( n.getShift( LayoutType.BOTTOM_TOP_LEFT ) + "", 7 ) + 
+                    "|" + strToLen( n.getSink( LayoutType.BOTTOM_TOP_LEFT ).getName(), 6 ) + 
+                    "|" + strToLen( n.getRoot( LayoutType.BOTTOM_TOP_LEFT ).getName(), 6 ) + 
+                    "|" + strToLen( n.getAlignedTo( LayoutType.BOTTOM_TOP_LEFT ).getName(), 7 ) + 
+                    "|" + strToLen( n.getX( LayoutType.BOTTOM_TOP_LEFT ) + "", 5 ) + 
+                    "|" + strToLen( !n.isXUndefined( LayoutType.BOTTOM_TOP_LEFT ) + "", 8 ) + "| " +
+                    "|" + strToLen( n.getName(), 6 ) + 
+                    "|" + strToLen( n.getShift( LayoutType.BOTTOM_TOP_RIGHT ) + "", 7 ) + 
+                    "|" + strToLen( n.getSink( LayoutType.BOTTOM_TOP_RIGHT ).getName(), 6 ) + 
+                    "|" + strToLen( n.getRoot( LayoutType.BOTTOM_TOP_RIGHT ).getName(), 6 ) + 
+                    "|" + strToLen( n.getAlignedTo( LayoutType.BOTTOM_TOP_RIGHT ).getName(), 7 ) + 
+                    "|" + strToLen( n.getX( LayoutType.BOTTOM_TOP_RIGHT ) + "", 5 ) + 
+                    "|" + strToLen( !n.isXUndefined( LayoutType.BOTTOM_TOP_RIGHT ) + "", 8 ) + "|\n";
+        }
+        info += "-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
+        return info;
+	}
+	
+	private void showDebugInfo()
+	{
+	    JFrame debugFrame = new JFrame();
+	    JTextArea info = new JTextArea();
+	    info.setEditable( false );
+	    info.setFont( new Font( Font.MONOSPACED, Font.PLAIN, 11 ) );
+	    info.setText( debugInfo() );
+	    JScrollPane view = new JScrollPane( info );
+        debugFrame.add( view );
+        debugFrame.setSize( frame.getWidth(), frame.getHeight() );
+	    debugFrame.setVisible( true );
+	}
+	
 	/**
 	/**
 	 * Initialize the window and its contents.
 	 * Initialize the window and its contents.
 	 * @param graph the graph that is displayed in this window.
 	 * @param graph the graph that is displayed in this window.
 	 */
 	 */
 	public MainView( LayeredGraphNode graph )
 	public MainView( LayeredGraphNode graph )
 	{
 	{
-		controller = new AnimationController();
-		controller.setTimeBetween( 10 );
-		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 );
-		frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
-		frame.setVisible( true );
-		
-		frame.addKeyListener( new KeyListener() {
+	    frameCounter++;
+	    this.graph = graph;
+        controller = new AnimationController();
+        controller.setTimeBetween( 50 );
+        frame = new JFrame();
+        frame.addWindowListener(new java.awt.event.WindowAdapter() {
+            @Override
+            public void windowClosing(java.awt.event.WindowEvent windowEvent) {
+                frameCounter--;
+                if( frameCounter == 0 )
+                    System.exit( 0 );
+            }
+        });
+        
+        BKNodePlacement algorithm = new BKNodePlacement( controller, graph, frame );
+        
+        // Create Menu GUI
+	    stepForward = new NiceButton( "stepForward" );
+	    stepForward.setLocation( 10, 10 );
+	    stepForward.setMnemonic( KeyEvent.VK_DOWN );
+	    stepForward.setToolTipText( "Forward step over (alt + down arrow key)" );
+	    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.setMnemonic( KeyEvent.VK_RIGHT );
+	    stepForwardInto.setToolTipText( "Forward step into (alt + right arrow key)" );
+	    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.setMnemonic( KeyEvent.VK_PAGE_DOWN );
+        stepForwardOut.setToolTipText( "Forward step out (alt + page down key)" );
+        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.setMnemonic( KeyEvent.VK_P );
+        runForward.setToolTipText( "Run forwards (alt + p)" );
+        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.setMnemonic( KeyEvent.VK_R );
+        runBackward.setToolTipText( "Run backwards (alt + r)" );
+        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.setMnemonic( KeyEvent.VK_UP );
+        stepBackward.setToolTipText( "Backward step over (alt + up arrow key)" );
+        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.setMnemonic( KeyEvent.VK_LEFT );
+        stepBackwardInto.setToolTipText( "Backward step into (alt + left arrow key)" );
+        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.setMnemonic( KeyEvent.VK_PAGE_UP );
+        stepBackwardOut.setToolTipText( "Backward step out (alt + page up)" );
+        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.setMnemonic( KeyEvent.VK_PAUSE );
+        pause.setToolTipText( "Pause (alt + pause)" );
+        pause.addActionListener( new ActionListener() {
+
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                controller.setContinuous( false );
+            }
+            
+        });
+        debug = new NiceButton( "debug" );
+        debug.setLocation( 350, 10 );
+        debug.setMnemonic( KeyEvent.VK_D );
+        debug.setToolTipText( "Show debug info (alt + d)" );
+        debug.addActionListener( new ActionListener() {
+
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                showDebugInfo();
+            }
+            
+        });
+        randomGraph = new NiceButton( "random" );
+        randomGraph.setLocation( 350, 60 );
+        randomGraph.setMnemonic( KeyEvent.VK_G );
+        randomGraph.setToolTipText( "Generate random graph (alt + g)" );
+        randomGraph.addActionListener( new ActionListener() {
 
 
             @Override
             @Override
-            public void keyTyped(KeyEvent e) {
-                // TODO Auto-generated method stub
-                
+            public void actionPerformed(ActionEvent e) {
+                JDialog diag = new JDialog( frame, "Generate random graph" );
+                diag.setLayout( new GridBagLayout() );
+                GridBagConstraints c = new GridBagConstraints();
+                c.gridx = 0;
+                c.gridy = 0;
+                diag.add( new JLabel( "P(subgraph exists)"), c );
+                c = new GridBagConstraints();
+                c.gridx = 1;
+                c.gridy = 0;
+                JTextField pSubgraph = new JTextField( "0.1" );
+                pSubgraph.setPreferredSize( new Dimension( 100, 20 ) );
+                pSubgraph.addFocusListener( new FocusListener() {
+                    @Override
+                    public void focusGained(FocusEvent e) {
+                        pSubgraph.setBackground( Color.WHITE );
+                    }
+
+                    @Override
+                    public void focusLost(FocusEvent e) {
+                        try {
+                            double d = Double.parseDouble( pSubgraph.getText() );
+                            if( d > 1 || d < 0 )
+                                pSubgraph.setBackground( Color.RED );
+                        } catch( Exception e1 )
+                        {
+                            pSubgraph.setBackground( Color.RED );
+                        }
+                    }
+                });
+                diag.add( pSubgraph, c );
+                c = new GridBagConstraints();
+                c.gridx = 0;
+                c.gridy = 1;
+                diag.add( new JLabel( "P(edge exists)"), c );
+                c = new GridBagConstraints();
+                c.gridx = 1;
+                c.gridy = 1;
+                JTextField pEdge = new JTextField( "0.3" );
+                pEdge.setPreferredSize( new Dimension( 100, 20 ) );
+                pEdge.addFocusListener( new FocusListener() {
+                    @Override
+                    public void focusGained(FocusEvent e) {
+                        pEdge.setBackground( Color.WHITE );
+                    }
+
+                    @Override
+                    public void focusLost(FocusEvent e) {
+                        try {
+                            double d = Double.parseDouble( pEdge.getText() );
+                            if( d > 1 || d < 0 )
+                                pEdge.setBackground( Color.RED );
+                        } catch( Exception e1 )
+                        {
+                            pEdge.setBackground( Color.RED );
+                        }
+                    }
+                });
+                diag.add( pEdge, c );
+                c = new GridBagConstraints();
+                c.gridx = 0;
+                c.gridy = 2;
+                diag.add( new JLabel( "min. num. layers"), c );
+                c = new GridBagConstraints();
+                c.gridx = 1;
+                c.gridy = 2;
+                JTextField minLayers = new JTextField( "5" );
+                JTextField maxLayers = new JTextField( "5" );
+                minLayers.setPreferredSize( new Dimension( 100, 20 ) );
+                minLayers.addFocusListener( new FocusListener() {
+                    @Override
+                    public void focusGained(FocusEvent e) {
+                        minLayers.setBackground( Color.WHITE );
+                    }
+
+                    @Override
+                    public void focusLost(FocusEvent e) {
+                        try {
+                            int i = Integer.parseInt( minLayers.getText() );
+                            int max = Integer.parseInt( maxLayers.getText() );
+                            if( i < 1 || i > max )
+                                minLayers.setBackground( Color.RED );
+                            else
+                                maxLayers.setBackground( Color.WHITE );
+                        } catch( Exception e1 )
+                        {
+                            minLayers.setBackground( Color.RED );
+                        }
+                    }
+                });
+                diag.add( minLayers, c );
+                c = new GridBagConstraints();
+                c.gridx = 0;
+                c.gridy = 3;
+                diag.add( new JLabel( "max. num. layers"), c );
+                c = new GridBagConstraints();
+                c.gridx = 1;
+                c.gridy = 3;
+                maxLayers.setPreferredSize( new Dimension( 100, 20 ) );
+                maxLayers.addFocusListener( new FocusListener() {
+                    @Override
+                    public void focusGained(FocusEvent e) {
+                        maxLayers.setBackground( Color.WHITE );
+                    }
+
+                    @Override
+                    public void focusLost(FocusEvent e) {
+                        try {
+                            int i = Integer.parseInt( maxLayers.getText() );
+                            int min = Integer.parseInt( minLayers.getText() );
+                            if( i < min )
+                                maxLayers.setBackground( Color.RED );
+                            else if( min > 0 )
+                                minLayers.setBackground( Color.WHITE );
+                        } catch( Exception e1 )
+                        {
+                            maxLayers.setBackground( Color.RED );
+                        }
+                    }
+                });
+                diag.add( maxLayers, c );
+                c = new GridBagConstraints();
+                c.gridx = 0;
+                c.gridy = 4;
+                diag.add( new JLabel( "min. num. nodes"), c );
+                c = new GridBagConstraints();
+                c.gridx = 1;
+                c.gridy = 4;
+                JTextField minNodes = new JTextField( "5" );
+                JTextField maxNodes = new JTextField( "5" );
+                minNodes.setPreferredSize( new Dimension( 100, 20 ) );
+                minNodes.setToolTipText( "between 1 and 'min. num. nodes'" );
+                minNodes.addFocusListener( new FocusListener() {
+                    @Override
+                    public void focusGained(FocusEvent e) {
+                        minNodes.setBackground( Color.WHITE );
+                    }
+
+                    @Override
+                    public void focusLost(FocusEvent e) {
+                        try {
+                            int i = Integer.parseInt( minNodes.getText() );
+                            int max = Integer.parseInt( maxNodes.getText() );
+                            if( i < 1 || i > max )
+                                minNodes.setBackground( Color.RED );
+                            else
+                                minNodes.setBackground( Color.WHITE );
+                        } catch( Exception e1 )
+                        {
+                            minNodes.setBackground( Color.RED );
+                        }
+                    }
+                });
+                diag.add( minNodes, c );
+                c = new GridBagConstraints();
+                c.gridx = 0;
+                c.gridy = 5;
+                diag.add( new JLabel( "max. num. nodes"), c );
+                c = new GridBagConstraints();
+                c.gridx = 1;
+                c.gridy = 5;
+                maxNodes.setPreferredSize( new Dimension( 100, 20 ) );
+                maxNodes.setToolTipText( "between 'min. num. nodes' and +Inf" );
+                maxNodes.addFocusListener( new FocusListener() {
+                    @Override
+                    public void focusGained(FocusEvent e) {
+                        maxNodes.setBackground( Color.WHITE );
+                    }
+
+                    @Override
+                    public void focusLost(FocusEvent e) {
+                        try {
+                            int i = Integer.parseInt( maxNodes.getText() );
+                            int min = Integer.parseInt( minNodes.getText() );
+                            if( i < min )
+                                maxNodes.setBackground( Color.RED );
+                            else if( min > 0 )
+                                minNodes.setBackground( Color.WHITE );
+                        } catch( Exception e1 )
+                        {
+                            maxNodes.setBackground( Color.RED );
+                        }
+                    }
+                });
+                diag.add( maxNodes, c );
+                c = new GridBagConstraints();
+                c.gridx = 0;
+                c.gridy = 6;
+                diag.add( new JLabel( "max. hier. depth"), c );
+                c = new GridBagConstraints();
+                c.gridx = 1;
+                c.gridy = 6;
+                JTextField maxDepth = new JTextField( "1" );
+                maxDepth.setPreferredSize( new Dimension( 100, 20 ) );
+                maxDepth.setToolTipText( "between 1 and +Inf" );
+                maxDepth.addFocusListener( new FocusListener() {
+                    @Override
+                    public void focusGained(FocusEvent e) {
+                        maxDepth.setBackground( Color.WHITE );
+                    }
+
+                    @Override
+                    public void focusLost(FocusEvent e) {
+                        try {
+                            int i = Integer.parseInt( maxDepth.getText() );
+                            if( i < 1 )
+                                maxDepth.setBackground( Color.RED );
+                        } catch( Exception e1 )
+                        {
+                            maxDepth.setBackground( Color.RED );
+                        }
+                    }
+                });
+                diag.add( maxDepth, c );
+                c = new GridBagConstraints();
+                c.gridx = 0;
+                c.gridy = 7;
+                c.gridwidth = 2;
+                JButton gen = new JButton( "generate");
+                gen.addActionListener( new ActionListener() {
+
+                    @Override
+                    public void actionPerformed(ActionEvent e) {
+                        double pSubGraphD = Double.parseDouble( pSubgraph.getText() );
+                        double pEdgeD = Double.parseDouble( pEdge.getText() );
+                        int minLayerI = Integer.parseInt( minLayers.getText() );
+                        int maxLayerI = Integer.parseInt( maxLayers.getText() );
+                        int minNodeI = Integer.parseInt( minNodes.getText() );
+                        int maxNodeI = Integer.parseInt( maxNodes.getText() );
+                        int maxDepthI = Integer.parseInt( maxDepth.getText() );
+                        boolean ok = true;
+                        if( pSubGraphD < 0 || pSubGraphD > 1 )
+                        {
+                            pSubgraph.setBackground( Color.RED );
+                            ok = false;
+                        }
+                        if( pEdgeD < 0 || pEdgeD > 1 )
+                        {
+                            pEdge.setBackground( Color.RED );
+                            ok = false;
+                        }
+                        if( minLayerI < 1 )
+                        {
+                            minLayers.setBackground( Color.RED );
+                            ok = false;
+                        }
+                        if( maxLayerI < minLayerI )
+                        {
+                            maxLayers.setBackground( Color.RED );
+                            ok = false;
+                        }
+                        if( minNodeI < 1 )
+                        {
+                            minNodes.setBackground( Color.RED );
+                            ok = false;
+                        }
+                        if( maxNodeI < minNodeI )
+                        {
+                            maxNodes.setBackground( Color.RED );
+                            ok = false;
+                        }
+                        if( maxDepthI < 1 )
+                        {
+                            maxDepth.setBackground( Color.RED );
+                            ok = false;
+                        }
+                        if( ok )
+                        {                            
+                            RandomGraphGenerator r = new RandomGraphGenerator( pSubGraphD, pEdgeD, minLayerI, maxLayerI, minNodeI, maxNodeI, maxDepthI );
+                            LayeredGraphNode graph = r.createRandomNode( null, 0 );
+                            SweepCrossingMinimizer cminzer = new SweepCrossingMinimizer();
+                            for( int i = 0; i < 10; i++ )
+                              cminzer.minimizeCrossings( graph );
+                            InitializeNodePositions.placeNodes( graph );
+                            new MainView( graph );
+                            diag.setVisible( false );
+                        }
+                    }
+                    
+                });
+                diag.add( gen, c );
+                diag.setSize( 270, 220 );
+                diag.setLocation( frame.getX() + frame.getWidth() / 2 - diag.getWidth() / 2, frame.getY() + frame.getHeight() / 2 - diag.getHeight() / 2 );
+                diag.setVisible( true );
             }
             }
+        });
+        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
             @Override
-            public void keyPressed(KeyEvent e) {
-                if( e.getKeyCode() == KeyEvent.VK_S )
+            public void insertUpdate(DocumentEvent e) {
+                try
+                {
+                    controller.setTimeBetween( Integer.parseInt( delay.getText() ) );
+                    delay.setBackground( Color.WHITE );
+                } catch( Exception e1 )
                 {
                 {
-                    Writer w = new Writer( "save.json" );
+                    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 );
+                }
+            }
+            
+        });
+        load = new NiceButton( "load" );
+        load.setLocation( 230, 60 );
+        load.setMnemonic( KeyEvent.VK_L );
+        load.setToolTipText( "Load a graph (alt + l)" );
+        load.addActionListener( new ActionListener() {
+
+            @Override
+            public void actionPerformed(ActionEvent e) {
+
+                JFileChooser chooser = new JFileChooser();
+                chooser.setFileFilter( new FileNameExtensionFilter("Json Graph", "json") );
+                chooser.showOpenDialog( frame );
+                if( chooser.getSelectedFile() != null )
+                {
+                    Reader r = new Reader( chooser.getSelectedFile().getAbsolutePath() );
+                    LayeredGraphNode graph = r.readInputGraph();
+                    InitializeNodePositions.placeNodes( graph );
+                    new MainView( graph );
+                }
+            }
+            
+        });
+        save = new NiceButton( "save" );
+        save.setLocation( 285, 60 );
+        save.setMnemonic( KeyEvent.VK_S );
+        save.setToolTipText( "Save graph (alt + s)" );
+        save.addActionListener( new ActionListener() {
+
+            @Override
+            public void actionPerformed(ActionEvent e) {
+
+                JFileChooser chooser = new JFileChooser();
+                chooser.setFileFilter( new FileNameExtensionFilter("Json Graph", "json") );
+                chooser.showSaveDialog( frame );
+                if( chooser.getSelectedFile() != null )
+                {
+                    Writer w = new Writer( chooser.getSelectedFile().getAbsolutePath() );
                     w.writeOutputGraph( graph );
                     w.writeOutputGraph( graph );
                 }
                 }
-                if( e.getKeyCode() == KeyEvent.VK_LEFT )
-                	controller.setNextAction( Action.BACKWARD );
-                if( e.getKeyCode() == KeyEvent.VK_RIGHT )
-                	controller.setNextAction( Action.FORWARD );
-                if( e.getKeyCode() == KeyEvent.VK_P )
-                	controller.setContinuous( !controller.isContinuous() );
-        		frame.validate();
-        		if( e.getKeyCode() == KeyEvent.VK_D )
-        		{
-        			System.out.println( "Debug Information Table: " );
-        			System.out.println( "_______________________________________________________________________________________________________________________________________________________________________________________________________________________" );
-        			System.out.println( "|" + strToLen( "Top -> Bottom :> Left", 51 ) + "| |" + strToLen( "Top -> Bottom :> Right", 51 ) + "| |" + strToLen( "Bottom -> Top :> Left", 51 ) + "| |" + strToLen( "Bottom -> Top :> Right", 51 ) + "|" );
-        			System.out.println( "|___________________________________________________| |___________________________________________________| |___________________________________________________| |___________________________________________________|" );
-        			System.out.println( "| Node | Shift | Sink | Root | Align |  x  |  xDef  | | Node | Shift | Sink | Root | Align |  x  |  xDef  | | Node | Shift | Sink | Root | Align |  x  |  xDef  | | Node | Shift | Sink | Root | Align |  x  |  xDef  |" );
-        			for( LayeredGraphNode n : graph.getContainedNodes() )
-        			{
-        				System.out.println( "|" + strToLen( n.getName(), 6 ) + 
-		        						    "|" + strToLen( n.getShift( LayoutType.TOP_BOTTOM_LEFT ) + "", 7 ) + 
-		        						    "|" + strToLen( n.getSink( LayoutType.TOP_BOTTOM_LEFT ).getName(), 6 ) + 
-		        						    "|" + strToLen( n.getRoot( LayoutType.TOP_BOTTOM_LEFT ).getName(), 6 ) + 
-		        						    "|" + strToLen( n.getAlignedTo( LayoutType.TOP_BOTTOM_LEFT ).getName(), 7 ) + 
-		        						    "|" + strToLen( n.getX( LayoutType.TOP_BOTTOM_LEFT ) + "", 5 ) + 
-		        						    "|" + strToLen( !n.isXUndefined( LayoutType.TOP_BOTTOM_LEFT ) + "", 8 ) + "| " +
-		        						    "|" + strToLen( n.getName(), 6 ) + 
-		        						    "|" + strToLen( n.getShift( LayoutType.TOP_BOTTOM_RIGHT ) + "", 7 ) + 
-		        						    "|" + strToLen( n.getSink( LayoutType.TOP_BOTTOM_RIGHT ).getName(), 6 ) + 
-		        						    "|" + strToLen( n.getRoot( LayoutType.TOP_BOTTOM_RIGHT ).getName(), 6 ) + 
-		        						    "|" + strToLen( n.getAlignedTo( LayoutType.TOP_BOTTOM_RIGHT ).getName(), 7 ) + 
-		        						    "|" + strToLen( n.getX( LayoutType.TOP_BOTTOM_RIGHT ) + "", 5 ) + 
-		        						    "|" + strToLen( !n.isXUndefined( LayoutType.TOP_BOTTOM_RIGHT ) + "", 8 ) + "| " +
-		        						    "|" + strToLen( n.getName(), 6 ) + 
-		        						    "|" + strToLen( n.getShift( LayoutType.BOTTOM_TOP_LEFT ) + "", 7 ) + 
-		        						    "|" + strToLen( n.getSink( LayoutType.BOTTOM_TOP_LEFT ).getName(), 6 ) + 
-		        						    "|" + strToLen( n.getRoot( LayoutType.BOTTOM_TOP_LEFT ).getName(), 6 ) + 
-		        						    "|" + strToLen( n.getAlignedTo( LayoutType.BOTTOM_TOP_LEFT ).getName(), 7 ) + 
-		        						    "|" + strToLen( n.getX( LayoutType.BOTTOM_TOP_LEFT ) + "", 5 ) + 
-		        						    "|" + strToLen( !n.isXUndefined( LayoutType.BOTTOM_TOP_LEFT ) + "", 8 ) + "| " +
-		        						    "|" + strToLen( n.getName(), 6 ) + 
-		        						    "|" + strToLen( n.getShift( LayoutType.BOTTOM_TOP_RIGHT ) + "", 7 ) + 
-		        						    "|" + strToLen( n.getSink( LayoutType.BOTTOM_TOP_RIGHT ).getName(), 6 ) + 
-		        						    "|" + strToLen( n.getRoot( LayoutType.BOTTOM_TOP_RIGHT ).getName(), 6 ) + 
-		        						    "|" + strToLen( n.getAlignedTo( LayoutType.BOTTOM_TOP_RIGHT ).getName(), 7 ) + 
-		        						    "|" + strToLen( n.getX( LayoutType.BOTTOM_TOP_RIGHT ) + "", 5 ) + 
-		        						    "|" + strToLen( !n.isXUndefined( LayoutType.BOTTOM_TOP_RIGHT ) + "", 8 ) + "|");
-        			}
-        			System.out.println( "-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------" );
-        		}
-            }
-
-            @Override
-            public void keyReleased(KeyEvent e) {
-                // TODO Auto-generated method stub
-                
-            }
-		    
-		});
+            }
+            
+        });
+        pseudoTree = new JTree();
+        PseudoCodeNode tree = algorithm.createPseudocodeTree( pseudoTree );
+        tree.setController( controller );
+        pseudoTree.setModel( new DefaultTreeModel( tree ) );
+        pseudoTree.setCellRenderer( new PseudoCodeRenderer() );
+        pseudoTree.setSelectionModel( null );
+        pseudoTree.addMouseListener( new MouseAdapter() {
+            public void mousePressed(MouseEvent e) {
+                TreePath selPath = pseudoTree.getPathForLocation(e.getX(), e.getY());
+                if( selPath != null && e.getClickCount() == 3 ) {
+                    ((PseudoCodeNode)selPath.getLastPathComponent()).setBreakPoint( !((PseudoCodeNode)selPath.getLastPathComponent()).hasBreakPoint() );
+                    pseudoTree.repaint();
+                }
+            }
+        } );
+        JScrollPane treeView = new JScrollPane( pseudoTree );
+        treeView.setBounds( 10,  110,  380, 380 );
+        
+        frame.setSize( (int)graph.getWidth( LayoutType.TOP_BOTTOM_LEFT ) * 2 + 575, (int)graph.getHeight( LayoutType.TOP_BOTTOM_LEFT ) * 2 + 200 );
+		frame.setLocation( 100, 100 );
+		frame.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
+		frame.setVisible( true );
 		
 		
 		JLayeredPane layne = new JLayeredPane();
 		JLayeredPane layne = new JLayeredPane();
 		JPanel pl = new JPanel();
 		JPanel pl = new JPanel();
@@ -151,6 +717,28 @@ public class MainView {
 		combined.setSize( 500, 500 );
 		combined.setSize( 500, 500 );
 		layne.add( combined, 0 );
 		layne.add( combined, 0 );
 		frame.add( layne );
 		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 );
+        menue.add( randomGraph );
+        menue.add( save );
+        menue.add( load );
+		frame.add( menue, BorderLayout.EAST );
+		frame.setSize( frame.getWidth() + 1, frame.getHeight() );
+        frame.setSize( frame.getWidth() - 1, frame.getHeight() );
 		frame.validate();
 		frame.validate();
 		frame.repaint();
 		frame.repaint();
 		
 		
@@ -158,6 +746,8 @@ public class MainView {
 		{  
 		{  
 	        public void componentResized(ComponentEvent evt) {
 	        public void componentResized(ComponentEvent evt) {
 	    		pl.setSize( layne.getSize() );
 	    		pl.setSize( layne.getSize() );
+	    		menue.setSize( menue.getWidth(), layne.getHeight() );
+	    		treeView.setSize( treeView.getWidth(), layne.getHeight() - 120 );
 	    		if( graph.getColor( LayoutType.COMBINED ) == null )
 	    		if( graph.getColor( LayoutType.COMBINED ) == null )
 	    		{
 	    		{
 		    		grout.setHgap( 10 );
 		    		grout.setHgap( 10 );
@@ -170,11 +760,13 @@ public class MainView {
 	    		}
 	    		}
 	    		combined.setSize( layne.getWidth() / 3, layne.getHeight() / 3 );
 	    		combined.setSize( layne.getWidth() / 3, layne.getHeight() / 3 );
 	    		combined.setLocation( layne.getWidth() / 3, layne.getHeight() / 3 );
 	    		combined.setLocation( layne.getWidth() / 3, layne.getHeight() / 3 );
-	    		frame.validate();
-	    		frame.repaint();
+	    		
+	    		layne.remove( pl );
+	            layne.add( pl, 1 );
+	            frame.repaint();
 	        }
 	        }
 		});
 		});
-		new BKNodePlacement( controller, graph ).start();
+        algorithm.start();
 	}
 	}
 	
 	
 	private NodeView createNodeView( LayeredGraphNode gNode, LayoutType lt )
 	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( "../img/" + name + ".png" ) != null ? makeColorTransparent( new ImageIcon( NiceButton.class.getResource( "../img/" + 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) );
+    }
+}

+ 11 - 5
src/view/NodeView.java

@@ -57,8 +57,6 @@ public class NodeView extends JPanel {
         }
         }
         for( Component c : getComponents() )
         for( Component c : getComponents() )
         {
         {
-            if( c.getLocation().x < 0 )
-                System.out.println( "x: " + c.getLocation().x + " y: " + c.getLocation().y );
             c.paint( g.create( 
             c.paint( g.create( 
                     c.getLocation().x + 25 - (int)minX, 
                     c.getLocation().x + 25 - (int)minX, 
                     c.getLocation().y + 25, 
                     c.getLocation().y + 25, 
@@ -80,9 +78,12 @@ public class NodeView extends JPanel {
 			else
 			else
 				g2.fillRect( 0, 0, (int)model.getWidth( layout )-1, (int)model.getHeight( layout )-1 );
 				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 );
+			if( model.getContainedNodes().size() > 0 )
+			    g.setColor( Color.GRAY );
 			g.fillRect( 0, 0, (int)model.getWidth( layout )-1, (int)model.getHeight( layout )-1 );
 			g.fillRect( 0, 0, (int)model.getWidth( layout )-1, (int)model.getHeight( layout )-1 );
 		}
 		}
 		Border linebor = BorderFactory.createLineBorder(model.getColor( layout ), 5);
 		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 ) );
     		g.setColor( model.getRoot( layout ).getSink( layout ).getColor( layout ) );
     		if( model.getContainedNodes().size() == 0 )
     		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 );
+    		}
 		}
 		}
 	}
 	}
 }
 }

+ 88 - 0
src/view/PseudoCodeRenderer.java

@@ -0,0 +1,88 @@
+package view;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+
+import javax.swing.ImageIcon;
+import javax.swing.JTree;
+import javax.swing.tree.DefaultTreeCellRenderer;
+import javax.swing.tree.TreeNode;
+
+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;
+        }
+    }
+    
+    private int countChildren( TreeNode treeNode )
+    {
+        if( treeNode.isLeaf() )
+            return 0;
+        else
+        {
+            int sum = 0;
+            for( int i = 0; i < treeNode.getChildCount(); i++ )
+            {
+                sum += countChildren( treeNode.getChildAt( i ) ) + 1;
+            }
+            return sum;
+        }
+    }
+
+    private int getLineNumber( TreeNode treeNode )
+    {
+        TreeNode parent = treeNode.getParent();
+        if( parent == null )
+            return 1;
+        int sum = getLineNumber( parent ) + 1;
+        for( int i = 0; i < parent.getChildCount(); i++ )
+        {
+            if( i == parent.getIndex( treeNode ) )
+                return sum;
+            sum += countChildren( parent.getChildAt( i ) ) + 1;
+        }
+        return 0;
+    }
+
+    @Override
+    public Component getTreeCellRendererComponent(JTree tree, Object value, boolean arg2, boolean arg3, boolean arg4, int arg5, boolean arg6) {
+
+        PseudoCodeNode node = (PseudoCodeNode) value;
+        BufferedImage rowNumerImg = new BufferedImage( 30, 30, BufferedImage.TYPE_INT_ARGB );
+        Graphics2D g = (Graphics2D) rowNumerImg.getGraphics();
+        if( node.hasBreakPoint() )
+        {
+            g.setColor( Color.RED );
+            g.fillOval(20, 10, 10, 10 );
+        }
+        g.setColor( Color.BLACK );
+        g.drawString( "" + getLineNumber( (TreeNode) value ), 5, 20 );
+        g.dispose();
+        this.setClosedIcon( new ImageIcon( rowNumerImg ) );
+        this.setOpenIcon( new ImageIcon( rowNumerImg ) );
+        this.setLeafIcon( new ImageIcon( rowNumerImg ) );
+        Component c = super.getTreeCellRendererComponent(tree, value, arg2, arg3, arg4, arg5, arg6);
+        specialColor = false;
+        if(node.isSelected()) {
+            specialColor = true;
+        }
+        return c;
+    }
+
+}

+ 74 - 1
test.json

@@ -1 +1,74 @@
-{"layers": [[{"name": "n1","width":10,"height":10},{"name":"n2","width":10,"height":10}],[{"name":"n3","width":10,"height":10},{"layers": [[{"name": "n1","width":10,"height":10},{"name":"n2","width":10,"height":10}],[{"name":"n3","width":10,"height":10}]],"edges":[{"source":"n1","target":"n3"},{"source":"n2","target":"n3"}],"name":"n0","width":10,"height":10}]],"edges":[{"source":"n1","target":"n3"},{"source":"n2","target":"n0"},{"source":"n2","target":"n3"}],"name":"n0"}
+{
+  "layers": [
+    [
+      {
+        "name": "n1",
+        "width": 10,
+        "height": 10
+      },
+      {
+        "name": "n2",
+        "width": 10,
+        "height": 10
+      }
+    ],
+    [
+      {
+        "name": "n3",
+        "width": 10,
+        "height": 10
+      },
+      {
+        "layers": [
+          [
+            {
+              "name": "n1",
+              "width": 10,
+              "height": 10
+            },
+            {
+              "name": "n2",
+              "width": 10,
+              "height": 10
+            }
+          ],
+          [
+            {
+              "name": "n3",
+              "width": 10,
+              "height": 10
+            }
+          ]
+        ],
+        "edges": [
+          {
+            "source": "n1",
+            "target": "n3"
+          },
+          {
+            "source": "n2",
+            "target": "n3"
+          }
+        ],
+        "name": "n0",
+        "width": 10,
+        "height": 10
+      }
+    ]
+  ],
+  "edges": [
+    {
+      "source": "n1",
+      "target": "n3"
+    },
+    {
+      "source": "n2",
+      "target": "n0"
+    },
+    {
+      "source": "n2",
+      "target": "n3"
+    }
+  ],
+  "name": "n0"
+}