Procházet zdrojové kódy

Merge remote-tracking branch 'origin/master'

Eren Yilmaz před 6 roky
rodič
revize
be9bb323a7
65 změnil soubory, kde provedl 3678 přidání a 315 odebrání
  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ární
      doc/img/algorithms_animated.pdf
  11. binární
      doc/img/animation_and_bk.pdf
  12. binární
      doc/img/bk-example-ours.jpg
  13. binární
      doc/img/bk-example-ours.png
  14. binární
      doc/img/buttons.png
  15. binární
      doc/img/components.pdf
  16. binární
      doc/img/debug-table.png
  17. binární
      doc/img/example.jpg
  18. binární
      doc/img/example.png
  19. binární
      doc/img/full-application-example.png
  20. binární
      doc/img/graph.pdf
  21. binární
      doc/img/logo.jpg
  22. binární
      doc/img/logo.png
  23. binární
      doc/img/model.pdf
  24. binární
      doc/img/random-graph-dialog.png
  25. binární
      doc/img/skizze.png
  26. binární
      doc/img/view.pdf
  27. binární
      doc/vpp/animation_and_bk.vpp
  28. binární
      doc/vpp/components.vpp
  29. binární
      doc/vpp/graph.vpp
  30. binární
      doc/vpp/io.vpp
  31. binární
      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ární
      src/img/debug.png
  48. binární
      src/img/load.png
  49. binární
      src/img/pause.png
  50. binární
      src/img/random.png
  51. binární
      src/img/runBackward.png
  52. binární
      src/img/runForward.png
  53. binární
      src/img/save.png
  54. binární
      src/img/stepBackward.png
  55. binární
      src/img/stepBackwardInto.png
  56. binární
      src/img/stepBackwardOut.png
  57. binární
      src/img/stepForward.png
  58. binární
      src/img/stepForwardInto.png
  59. binární
      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
 svg-inkscape
 *.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.
 
 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.
+
+\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 cross-hierarchy edges.
     \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}
 
-\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}
 The input to \appname is a JSON file.
@@ -25,7 +41,7 @@ The structure is as follows:
 \end{itemize}
 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 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
 \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
     width & integer & yes & The minimum width of the node.
     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
     height & integer & yes & The minimum height of the node.
     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
-    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
-    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}
 \end{longtable}
 \raggedright
@@ -51,7 +67,7 @@ The internal representation of graphs is further explained in the section~\ref{s
 \begin{figure}[htp]
     \centering
     \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}
 \end{figure}
 
@@ -61,9 +77,9 @@ The internal representation of graphs is further explained in the section~\ref{s
         \hline
         Attribute & Type & Optional & Explanation \\\hline\hline
         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.
-        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}
     \caption{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}
 \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}).
 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}.
 Additionally, there are multiple attributes that are used during the computation or as output variables.
 \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}.
-    \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}
+The last five bullet points are available for each of the four extremal layouts and for the combined layout.
+
 Similarly, edges have additional attributes:
 \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}
 
-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]
     \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}
 
-
 \begin{table}[htp]
     \begin{longtable}{|l|p{10cm}|}
         \hline
@@ -128,45 +149,54 @@ A class diagram of the package \enquote{graph} is displayed in figure~\ref{fig:m
     \label{table:bk-variables}
 \end{table}
 
+
 \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}.
 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.
-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.
 
-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:
 \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.
-    \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}
 
-\TODO{outdated}
 \begin{figure}[htp]
     \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}
 
+
 \section{View}\label{sec:view}
 This section only covers the software architecture regarding the views.
 For an explanation of what is actually displayed, see chapter~\ref{ch:ui}
 
 The distinguish two kinds of views:
 \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.
-\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.
 
 \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}
     \centering
@@ -18,49 +50,54 @@ Note that since the application is still under construction, so not all screensh
         \centering
         \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.
-        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}
     \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}
 \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}
-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
         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}
-    \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):
 \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.
     \begin{itemize}
         \item[\done] Saving those randomly created graphs.
     \end{itemize}
     \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}
-        \item[\progress] Calculating the conflicts between edges.
+        \item[\done] Calculating the conflicts between edges.
         \begin{itemize}
-            \item[\progress] Differentiating between dummy nodes and non-dummy nodes.
+            \item[\done] Differentiating between dummy nodes and non-dummy nodes.
         \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}
-    \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}
         \item[\done] Drawing the nodes at their current position.
         \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 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}
     \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}).
+    \begin{itemize}
+        \item[\done] Displaying the buttons.
+        \item[\done] Making all the buttons work.
+    \end{itemize}
     \item[\done] Working with hierarchical graphs.
     \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 \\
         \rowcolor{gray!25}
 		Senior Community Manager & Eren Bora Yilmaz \\
+		Lead Artist & Eren Bora Yilmaz \\
+        \rowcolor{gray!25}
         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}
 		Special Thanks & Jens Burmeister \\\\
 	\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
 % für Formatierung in Quelltexten, hier im Anhang
 \usepackage{listings}
+
+% same code font as in eclipse
+\usepackage{inconsolata}
 \usepackage{color, colortbl} % Farben
 
 \colorlet{punct}{red!60!black}
@@ -99,6 +102,13 @@
 \definecolor{deepred}{rgb}{0.8,0,0}
 \definecolor{deepgreen}{rgb}{0,0.4,0}
 \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
 \lstset{
 extendedchars=true,

binární
doc/img/algorithms_animated.pdf


binární
doc/img/animation_and_bk.pdf


binární
doc/img/bk-example-ours.jpg


binární
doc/img/bk-example-ours.png


binární
doc/img/buttons.png


binární
doc/img/components.pdf


binární
doc/img/debug-table.png


binární
doc/img/example.jpg


binární
doc/img/example.png


binární
doc/img/full-application-example.png


binární
doc/img/graph.pdf


binární
doc/img/logo.jpg


binární
doc/img/logo.png


binární
doc/img/model.pdf


binární
doc/img/random-graph-dialog.png


binární
doc/img/skizze.png


binární
doc/img/view.pdf


binární
doc/vpp/animation.animated.vpp → doc/vpp/animation_and_bk.vpp


binární
doc/vpp/components.vpp


binární
doc/vpp/model.vpp → doc/vpp/graph.vpp


binární
doc/vpp/io.vpp


binární
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 {
 	FORWARD,
-	BACKWARD
+	FORWARD_OVER,
+	FORWARD_OUT,
+	BACKWARD,
+	BACKWARD_OVER,
+	BACKWARD_OUT
 }

+ 13 - 0
src/animation/AlgorithmStage.java

@@ -1,5 +1,7 @@
 package animation;
 
+import javax.swing.JTree;
+
 import bk.BlockCalc;
 
 /**
@@ -18,6 +20,7 @@ public interface AlgorithmStage {
 	public static enum StageStatus
 	{
 		UNFINISHED,
+		BREAKPOINT,
 		FINISHED
 	}
 	
@@ -27,6 +30,10 @@ public interface AlgorithmStage {
      * For example if all steps are reverted, then {@code FINISHED} is returned.
 	 */
 	public StageStatus forwardStep();
+	
+	public StageStatus forwardStepOver();
+	
+    public StageStatus forwardStepOut();
     
     /**
      * 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.
      */
 	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;
 
+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;
 
 public abstract class AnimatedAlgorithm extends Thread implements AlgorithmStage {
 
 	protected AnimationController ac;
 	protected LayeredGraphNode graph;
+	private JFrame view;
 	
-	public AnimatedAlgorithm( AnimationController controller, LayeredGraphNode graph )
+	public AnimatedAlgorithm( AnimationController controller, LayeredGraphNode graph, JFrame view )
 	{
 		this.ac = controller;
 		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
@@ -22,13 +44,35 @@ public abstract class AnimatedAlgorithm extends Thread implements AlgorithmStage
 				switch( ac.getNextAction() )
 				{
 				case FORWARD:
-					System.out.println( "FORWARD" );
 					forwardStep();
+					update();
 					break;
+                case FORWARD_OUT:
+                    forwardStepOut();
+                    graph.unselectGraph();
+                    update();
+                    break;
+                case FORWARD_OVER:
+                    forwardStepOver();
+                    graph.unselectGraph();
+                    update();
+                    break;
 				case BACKWARD:
-					System.out.println( "BACKWARD" );
 					backwardStep();
+                    update();
 					break;
+                case BACKWARD_OUT:
+                    backwardStepOut();
+                    graph.unselectGraph();
+                    update();
+                    break;
+                case BACKWARD_OVER:
+                    backwardStepOver();
+                    graph.unselectGraph();
+                    update();
+                    break;
+                default:
+                    break;
 				}
 			} catch (InterruptedException e) {
 				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;
 
-import animation.AlgorithmStage;
+import java.lang.reflect.InvocationTargetException;
+
+import javax.swing.JFrame;
+import javax.swing.JTree;
+
 import animation.AnimatedAlgorithm;
 import animation.AnimationController;
+import animation.PseudoCodeNode;
 import graph.LayeredGraphNode;
 
 /**
@@ -30,9 +35,16 @@ public class BKNodePlacement extends AnimatedAlgorithm {
 	private State state;
 	private ExtremalLayoutCalc layouts[];
 	private Combine combine;
+    private PseudoCodeNode conflictsNode; 
+    private PseudoCodeNode layout1Node;
+    private PseudoCodeNode layout2Node;
+    private PseudoCodeNode layout3Node;
+    private PseudoCodeNode layout4Node;
+    private PseudoCodeNode combineNode;
+    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;
 		conftion = new ConflictDetection( graph );
 		layouts = new ExtremalLayoutCalc[ 4 ];
@@ -41,65 +53,321 @@ public class BKNodePlacement extends AnimatedAlgorithm {
 		layouts[ 2 ] = new ExtremalLayoutCalc( ExtremalLayoutCalc.LayoutType.BOTTOM_TOP_LEFT, graph );
 		layouts[ 3 ] = new ExtremalLayoutCalc( ExtremalLayoutCalc.LayoutType.BOTTOM_TOP_RIGHT, graph );
 		combine = new Combine( graph );
+		inside = false;
 	}
 
 	@Override
 	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
 	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.Collections;
 
+import javax.swing.JTree;
+
 import animation.AlgorithmStage;
 import animation.BackwardAction;
+import animation.PseudoCodeNode;
 import bk.ExtremalLayoutCalc.LayoutType;
 import graph.LayeredGraphEdge;
 import graph.LayeredGraphNode;
@@ -24,6 +27,7 @@ public class BlockCalc implements AlgorithmStage {
 	private ArrayList< ArrayList< ExtremalLayoutCalc > > subgraphAlgs;
 	private ArrayList< BackwardAction > backwards; // TODO: evtl richtigen "Stack" benutzen
 	private LayoutType layout;
+	private PseudoCodeNode loopNode;
 	int step;
 	
 	public BlockCalc( LayeredGraphNode graph, LayoutType layout )
@@ -88,9 +92,20 @@ public class BlockCalc implements AlgorithmStage {
 		if( current.getContainedNodes().size() > 0 )
 		{
 			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;
+            default:
+                break;
+			}
 		}
 		ArrayList< LayeredGraphEdge > incommingEdges = null;
         if( layout == LayoutType.TOP_BOTTOM_LEFT || layout == LayoutType.TOP_BOTTOM_RIGHT )
@@ -166,10 +181,14 @@ public class BlockCalc implements AlgorithmStage {
 	
 	private StageStatus calcNextState()
 	{
+        boolean breakpoint = !loopNode.setSelected( true );
 		if( layerIndex >= graph.getContainedLayers().size() - 1 )
 		{
 			if( nodeIndex >= graph.getContainedLayers().get( calcLayerIndex() ).size() -1 )
+			{
+                loopNode.setSelected( false );
 				return StageStatus.FINISHED;
+			}
 		}
 		nodeIndex++;
 		if( nodeIndex >= graph.getContainedLayers().get( calcLayerIndex() ).size() )
@@ -182,6 +201,8 @@ public class BlockCalc implements AlgorithmStage {
 			   this.r = oldR;
 			});
 		}
+		if( breakpoint )
+		    return StageStatus.BREAKPOINT;
 		return StageStatus.UNFINISHED;
 	}
 
@@ -213,10 +234,14 @@ public class BlockCalc implements AlgorithmStage {
 	
 	private StageStatus calcBeforeState()
 	{
+	    boolean breakpoint = !loopNode.setSelected( true );
 		if( layerIndex == 0 )
 		{
 			if( nodeIndex == 0 )
+			{
+		        loopNode.setSelected( false );
 				return StageStatus.FINISHED;
+			}	
 		}
 		nodeIndex--;
 		if( nodeIndex < 0 )
@@ -226,6 +251,42 @@ public class BlockCalc implements AlgorithmStage {
 	        backwards.remove( 0 );
 			nodeIndex = graph.getContainedLayers().get( calcLayerIndex() ).size() - 1;
 		}
+        if( breakpoint )
+            return StageStatus.BREAKPOINT;
 		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;
 
 import java.awt.Color;
+import java.util.ArrayList;
+import java.util.Collections;
+
+import javax.swing.JTree;
 
 import animation.AlgorithmStage;
+import animation.BackwardAction;
+import animation.PseudoCodeNode;
+import bk.ExtremalLayoutCalc.LayoutType;
 import graph.LayeredGraphNode;
-import view.MainView;
 
 /**
  * The stage of the combination of the four extremal layouts.
@@ -15,24 +21,226 @@ public class Combine implements AlgorithmStage {
 
 	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 )
 	{
 		this.graph = graph;
+		state = State.ALIGN;
+		vIndex = 0;
+		actions = new ArrayList<>();
+		inside = false;
 	}
 	
 	@Override
 	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
 	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 javax.swing.JTree;
+
 import animation.AlgorithmStage;
 import animation.BackwardAction;
+import animation.PseudoCodeNode;
 import bk.ExtremalLayoutCalc.LayoutType;
 import graph.LayeredGraphNode;
 
@@ -34,6 +37,13 @@ public class Compaction implements AlgorithmStage{
 	private ArrayList< StackFrame > stack; // TODO: evtl richtigen "Stack" benutzen
 	private ArrayList< BackwardAction > actions; // TODO: evtl richtigen "Stack" benutzen
 	private LayoutType layout;
+	private PseudoCodeNode placeNode;
+    private PseudoCodeNode placeLoopNode;
+    private PseudoCodeNode applyNode;
+    private PseudoCodeNode applyLoopNode;
+    private boolean breakPoint;
+    private boolean inside;
+	
 	
 	public Compaction( LayeredGraphNode graph, LayoutType layout )
 	{
@@ -43,6 +53,7 @@ public class Compaction implements AlgorithmStage{
 		stack = new ArrayList<>(); // der call-stack des rekursiven algorithmus
 		vIndex = 0;
 		actions = new ArrayList<>();
+		inside = false;
 	}
 	
 	/**
@@ -55,7 +66,7 @@ public class Compaction implements AlgorithmStage{
 		for( LayeredGraphNode n : graph.getContainedNodes() )
 			max = Math.max( max, n.getWidth( layout ) );
 		//return max + 25;
-		return max;
+		return max + 5;
 	}
 	
 	private LayeredGraphNode getNodeFromIndex( int index )
@@ -72,9 +83,14 @@ public class Compaction implements AlgorithmStage{
 	
 	@Override
 	public StageStatus forwardStep() {
+		breakPoint = false;
 		int acSize = actions.size();
 		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
 			{
 				ArrayList< LayeredGraphNode > nodes = graph.getContainedNodes();
@@ -95,10 +111,23 @@ public class Compaction implements AlgorithmStage{
 				if( !found )
 				{
 				    // 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;
+					inside = false;
 					vIndex = 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;
+						inside = false;
 						state = CompactionState.PLACE_BLOCKS;
 					} );
 				}
@@ -108,13 +137,18 @@ public class Compaction implements AlgorithmStage{
 					f.v = getNodeFromIndex( vIndex );
 					double oldX = f.v.getX( layout ); // nötig für "undo"
 					f.v.setX( 0, true, layout );
-					f.v.setSelected( layout ); // zeige knoten als aktiven knoten an
 					f.w = f.v;
+                    f.w.setSelected( layout ); // zeige knoten als aktiven knoten an
                     System.out.println( "call place_block( " + f.v + " )" );
 					stack.add( 0, f );
 					
 					// die "undo"-action
 					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.setSelected( layout );
 						stack.remove( 0 );
@@ -129,10 +163,12 @@ public class Compaction implements AlgorithmStage{
 				if( sf.u == null ) // zu beginn der placeblock methode
 				{
                     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?
 						{// ja
@@ -140,13 +176,18 @@ public class Compaction implements AlgorithmStage{
 							nsf.v = sf.u;
 							double oldX = nsf.v.getX( layout ); // nötig für "undo"
 							nsf.v.setX( 0, true, layout );
-							nsf.v.setSelected( layout ); // zeige knoten als aktiven knoten an
 							nsf.w = nsf.v;
+                            nsf.w.setSelected( layout ); // zeige knoten als aktiven knoten an
 		                    System.out.println( "call place_block( " + nsf.v + " )" );
 							stack.add( 0, nsf );
 		                    
 		                    // die "undo"-action
 							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.setSelected( layout );
 								stack.remove( 0 );
@@ -156,8 +197,13 @@ public class Compaction implements AlgorithmStage{
 						else // nein
 						{
 						    // tue nix
-							sf.u.setSelected( layout ); 
+							sf.w.setSelected( layout );
 							actions.add( 0, ()-> {
+			                    breakPoint = false;
+							    if( !placeNode.isSelected() )
+							    	breakPoint |= !placeNode.setSelected( true );
+		                        breakPoint |= !placeLoopNode.setSelected( true );
+                                inside = true;
 								stack.get( 0 ).u = null;
 							});
 						}
@@ -172,16 +218,26 @@ public class Compaction implements AlgorithmStage{
                             System.out.println( "return place_block( " + sf.v + " )" );
 							stack.remove( 0 );
 							actions.add( 0, ()-> {
+			                    breakPoint = false;
+							    if( !placeNode.isSelected() )
+							    	breakPoint |= !placeNode.setSelected( true );
+		                        breakPoint |= !placeLoopNode.setSelected( true );
+                                inside = true;
 								stack.add( 0, sf );
-								sf.v.setSelected( layout );
 								sf.w = oldW;
+                                sf.w.setSelected( layout );
 							});
 						}
 						else
 						{ //nur "undo aktion" hinzufügen
 							actions.add( 0, ()-> {
+			                    breakPoint = false;
+							    if( !placeNode.isSelected() )
+							    	breakPoint |= !placeNode.setSelected( true );
+		                        breakPoint |= !placeLoopNode.setSelected( true );
+                                inside = true;
 								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 );
 					
 					// v für visualisierung markieren
-					sf.v.setSelected( layout );
+					sf.w.setSelected( layout );
                     
                     if( sf.v.getSink( layout ) == sf.v ) // sink[v] = v?
                         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]?
 						sf.u.getSink( layout ).setShift( // 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
 					    // 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
@@ -222,24 +281,34 @@ public class Compaction implements AlgorithmStage{
 					    System.out.println( "return place_block( " + sf.v + " )" );
 						stack.remove( 0 );
 						actions.add( 0, ()-> {
+		                    breakPoint = false;
+						    if( !placeNode.isSelected() )
+						    	breakPoint |= !placeNode.setSelected( true );
+	                        breakPoint |= !placeLoopNode.setSelected( true );
+                            inside = true;
 							stack.add( 0, sf );
 							stack.get( 0 ).v.setSink(  oldSink, layout );
 							sinkOfU.setShift( oldShift, layout );
 							sf.u = oldU;
 							sf.v.setX( oldX, oldDef, layout );
-							sf.v.setSelected( layout );
 							sf.w = oldW;
+                            sf.w.setSelected( layout );
 						});
 					}
 					else
 					{ //nur "undo aktion" hinzufügen
 						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 );
 							sinkOfU.setShift( oldShift, layout );
 							sf.u = oldU;
 							sf.v.setX( oldX, oldDef, layout );
-							sf.v.setSelected( layout );
 							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"
 		{
+            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 );
 			double oldX = v.getX( 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 )
 				v.setX( v.getX( layout ) + v.getSink( layout ).getShift( layout ), true, layout );
 			actions.add( 0, ()-> {
+                inside = true;
+                breakPoint = false;
+			    if( !applyNode.isSelected() )
+			    	breakPoint |= !applyNode.setSelected( true );
+                breakPoint |= !applyLoopNode.setSelected( true );
 				v.setX( oldX, oldDef, layout );
 				v.setSelected( layout );
 				vIndex--;
 			} );
 			vIndex++;
 			if( vIndex >= graph.getContainedNodes().size() )
+			{
+                applyNode.setSelected( false );
+                applyLoopNode.setSelected( false );
 				return StageStatus.FINISHED;
+			}
 		}
 		if( actions.size() != acSize + 1 )
 			System.out.println( "ERROR" );
+		if( breakPoint )
+		    return StageStatus.BREAKPOINT;
 		return StageStatus.UNFINISHED;
 	}
 
 	@Override
 	public StageStatus backwardStep() {
 		if( actions.size() == 0 )
+		{
+            inside = false;
+            placeNode.setSelected( false );
+            placeLoopNode.setSelected( 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( "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 javax.swing.JTree;
+
 import animation.AlgorithmStage;
 import animation.BackwardAction;
+import animation.PseudoCodeNode;
 import graph.LayeredGraphEdge;
 import graph.LayeredGraphNode;
 
@@ -14,6 +17,7 @@ public class ConflictDetection implements AlgorithmStage {
     
     private int i;
     private int l1;
+    private PseudoCodeNode markNode;
     
     ConflictDetection( LayeredGraphNode graph )
     {
@@ -27,8 +31,14 @@ public class ConflictDetection implements AlgorithmStage {
     public StageStatus forwardStep() {
     	int oldI = i;
     	int oldL1 = l1;
+    	((PseudoCodeNode)markNode.getParent()).setSelected( true );
+    	boolean breakPoint = !markNode.setSelected( true );
     	if( i + 1 >= graph.getContainedLayers().size() - 1 )
+    	{
+            ((PseudoCodeNode)markNode.getParent()).setSelected( false );
+            markNode.setSelected( false );
     		return StageStatus.FINISHED;
+    	}
     	LayeredGraphNode curr = graph.getContainedLayers().get( i + 1 ).get( l1 );
     	curr.setSelected( null );
     	ArrayList< LayeredGraphEdge > edges = curr.getIncomingEdges();
@@ -60,12 +70,19 @@ public class ConflictDetection implements AlgorithmStage {
         for( LayeredGraphEdge c : conflicts )
         	c.setConflicted( true, null );
     	StageStatus status =  calcNextStatus();
-    	actions.add( ()->{
+    	actions.add( 0, ()->{
     		i = oldI;
     		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 )
             	c.setConflicted( false, null );
     	});
+    	if( status != StageStatus.FINISHED && breakPoint )
+    	    return StageStatus.BREAKPOINT;
     	return status;
     }
     
@@ -79,6 +96,8 @@ public class ConflictDetection implements AlgorithmStage {
             {
                 i--;
                 l1--;
+                ((PseudoCodeNode)markNode.getParent()).setSelected( false );
+                markNode.setSelected( false );
                 return StageStatus.FINISHED;
             }
             l1 = 0;
@@ -88,10 +107,54 @@ public class ConflictDetection implements AlgorithmStage {
 
     @Override
     public StageStatus backwardStep() {
+        ((PseudoCodeNode)markNode.getParent()).setSelected( true );
+        boolean breakPoint = !markNode.setSelected( true );
         if( actions.size() == 0 )
+        {
+            ((PseudoCodeNode)markNode.getParent()).setSelected( false );
+            markNode.setSelected( false );
         	return StageStatus.FINISHED;
+        }
         actions.get( 0 ).reverse();
         actions.remove( 0 );
+        if( breakPoint )
+            return StageStatus.BREAKPOINT;
         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;
 
+import java.lang.reflect.InvocationTargetException;
+
+import javax.swing.JTree;
+
 import animation.AlgorithmStage;
+import animation.PseudoCodeNode;
 import graph.LayeredGraphNode;
 
 /**
@@ -24,43 +29,214 @@ public class ExtremalLayoutCalc implements AlgorithmStage {
 		COMPACTION
 	}
 	
+	private PseudoCodeNode pseudoCode;
 	private BlockCalc bc;
 	private Compaction cp;
 	private LayoutState status;
+	private PseudoCodeNode bcNode;
+	private PseudoCodeNode cpNode;
+	private LayoutType type;
+	private boolean inside;
 	
 	
 	public ExtremalLayoutCalc( LayoutType typ, LayeredGraphNode graph )
 	{
+	    type = typ;
 		status = LayoutState.BLOCK_CALCULATION;
 		bc = new BlockCalc( graph, typ );
 		cp = new Compaction( graph, typ );
+		inside = false;
 	}
 	
 	@Override
 	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
 	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 void setColor( Color c, LayoutType layout );
     public Color getColor( LayoutType layout );
-    public void update();
     public void setSelected( LayoutType layoutType );
     public boolean isSelected( LayoutType layout );
     public void setDummyNode( boolean dummy );
     public boolean isDummyNode();
+    public void unselectGraph();
     
     /**
      * 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.util.ArrayList;
 
-import javax.swing.SwingUtilities;
-
 import org.eclipse.elk.graph.ElkEdge;
 import org.eclipse.elk.graph.ElkNode;
 
 import bk.ExtremalLayoutCalc.LayoutType;
-import view.MainView;
 
 /**
  * Die Implementation eines Knotens in einem Layered Graph.
@@ -263,16 +260,6 @@ public class LayeredNode implements LayeredGraphNode {
         return null;
     }
 
-    @Override
-    public void update()
-    {
-    	SwingUtilities.invokeLater(new Runnable() {
-		    public void run() {
-		        MainView.frame.repaint();
-		    }
-		});
-    }
-
     @Override
     public void setSelected( LayoutType layout )
     {
@@ -294,7 +281,20 @@ public class LayeredNode implements LayeredGraphNode {
             this.layouts[ 3 ].selected = true;
         if( layout == LayoutType.COMBINED )
         	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

+ 2 - 0
src/graph/RandomGraphGenerator.java

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

binární
src/img/debug.png


binární
src/img/load.png


binární
src/img/pause.png


binární
src/img/random.png


binární
src/img/runBackward.png


binární
src/img/runForward.png


binární
src/img/save.png


binární
src/img/stepBackward.png


binární
src/img/stepBackwardInto.png


binární
src/img/stepBackwardOut.png


binární
src/img/stepForward.png


binární
src/img/stepForwardInto.png


binární
src/img/stepForwardOut.png


+ 2 - 8
src/main/Main.java

@@ -1,11 +1,10 @@
 package main;
 import graph.InitializeNodePositions;
 import graph.LayeredGraphNode;
-import graph.RandomGraphGenerator;
 import graph.io.Reader;
-import lib.SweepCrossingMinimizer;
 import view.MainView;
 
+
 /**
  * The main executable class. Starts the application.
  * @author kolja
@@ -18,13 +17,8 @@ public class Main {
      * @param args the command line arguments, currently not in use
      */
 	public static void main(String[] args) {
-		Reader r = new Reader( "test3.json" );
+		Reader r = new Reader( "logo.json" );
 		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 );
 		new MainView( graph );
 	}

+ 670 - 78
src/view/MainView.java

@@ -1,24 +1,51 @@
 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.event.ActionEvent;
+import java.awt.event.ActionListener;
 import java.awt.event.ComponentAdapter;
 import java.awt.event.ComponentEvent;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
 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.JDialog;
+import javax.swing.JFileChooser;
 import javax.swing.JFrame;
+import javax.swing.JLabel;
 import javax.swing.JLayeredPane;
 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.AnimationController;
+import animation.PseudoCodeNode;
 import bk.BKNodePlacement;
 import bk.ExtremalLayoutCalc.LayoutType;
+import graph.InitializeNodePositions;
 import graph.LayeredGraphEdge;
 import graph.LayeredGraphNode;
+import graph.RandomGraphGenerator;
+import graph.io.Reader;
 import graph.io.Writer;
+import lib.SweepCrossingMinimizer;
 
 /**
  * The main window of the application.
@@ -32,8 +59,26 @@ public class MainView {
      * The 'frame' of the main window.
      * 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 )
 	{
@@ -46,91 +91,612 @@ public class MainView {
 		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.
 	 * @param graph the graph that is displayed in this window.
 	 */
 	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
-            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
-            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 );
                 }
-                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();
 		JPanel pl = new JPanel();
@@ -151,6 +717,28 @@ public class MainView {
 		combined.setSize( 500, 500 );
 		layne.add( combined, 0 );
 		frame.add( layne );
+		JPanel menue = new JPanel();
+		menue.setLayout( null );
+		menue.setPreferredSize( new Dimension( 400, 500 ) );
+		menue.add( stepForward );
+		menue.add( stepForwardInto );
+        menue.add( stepForwardOut );
+        menue.add( runForward );
+        menue.add( pause );
+        menue.add( debug );
+        menue.add( stepBackward );
+        menue.add( delayText );
+        menue.add( delay );
+        menue.add( treeView );
+        menue.add( stepBackwardInto );
+        menue.add( stepBackwardOut );
+        menue.add( runBackward );
+        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.repaint();
 		
@@ -158,6 +746,8 @@ public class MainView {
 		{  
 	        public void componentResized(ComponentEvent evt) {
 	    		pl.setSize( layne.getSize() );
+	    		menue.setSize( menue.getWidth(), layne.getHeight() );
+	    		treeView.setSize( treeView.getWidth(), layne.getHeight() - 120 );
 	    		if( graph.getColor( LayoutType.COMBINED ) == null )
 	    		{
 		    		grout.setHgap( 10 );
@@ -170,11 +760,13 @@ public class MainView {
 	    		}
 	    		combined.setSize( 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 )

+ 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() )
         {
-            if( c.getLocation().x < 0 )
-                System.out.println( "x: " + c.getLocation().x + " y: " + c.getLocation().y );
             c.paint( g.create( 
                     c.getLocation().x + 25 - (int)minX, 
                     c.getLocation().y + 25, 
@@ -80,9 +78,12 @@ public class NodeView extends JPanel {
 			else
 				g2.fillRect( 0, 0, (int)model.getWidth( layout )-1, (int)model.getHeight( layout )-1 );
 		}
-		if( model.isSelected( layout ) )
+		boolean selected = model.isSelected( layout );
+		if( selected )
 		{
-			g.setColor( Color.GRAY );
+			g.setColor( Color.BLACK );
+			if( model.getContainedNodes().size() > 0 )
+			    g.setColor( Color.GRAY );
 			g.fillRect( 0, 0, (int)model.getWidth( layout )-1, (int)model.getHeight( layout )-1 );
 		}
 		Border linebor = BorderFactory.createLineBorder(model.getColor( layout ), 5);
@@ -92,7 +93,12 @@ public class NodeView extends JPanel {
 		{
     		g.setColor( model.getRoot( layout ).getSink( layout ).getColor( layout ) );
     		if( model.getContainedNodes().size() == 0 )
-    		    g.fillOval( (int)model.getWidth( layout ) / 2 - (int)model.getWidth( layout ) / 3, (int)model.getHeight( layout ) / 2 - (int)model.getHeight( layout ) / 3, (int)model.getWidth( layout ) / 3 * 2, (int)model.getHeight( layout ) / 3 * 2 );
+    		{
+    		    if( selected )
+    		        g.fillOval( (int)model.getWidth( layout ) / 2 - (int)model.getWidth( layout ) / 5, (int)model.getHeight( layout ) / 2 - (int)model.getHeight( layout ) / 5, (int)model.getWidth( layout ) / 5 * 2, (int)model.getHeight( layout ) / 5 * 2 );
+    		    else
+    		        g.fillOval( (int)model.getWidth( layout ) / 2 - (int)model.getWidth( layout ) / 3, (int)model.getHeight( layout ) / 2 - (int)model.getHeight( layout ) / 3, (int)model.getWidth( layout ) / 3 * 2, (int)model.getHeight( layout ) / 3 * 2 );
+    		}
 		}
 	}
 }

+ 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"
+}