MainView.java 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714
  1. package view;
  2. import java.awt.BorderLayout;
  3. import java.awt.Dimension;
  4. import java.awt.Font;
  5. import java.awt.GridLayout;
  6. import java.awt.event.ActionEvent;
  7. import java.awt.event.ActionListener;
  8. import java.awt.event.ComponentAdapter;
  9. import java.awt.event.ComponentEvent;
  10. import java.awt.event.ComponentListener;
  11. import java.awt.event.KeyEvent;
  12. import java.awt.event.MouseAdapter;
  13. import java.awt.event.MouseEvent;
  14. import java.beans.PropertyChangeEvent;
  15. import java.beans.PropertyChangeListener;
  16. import javax.swing.JButton;
  17. import javax.swing.JFileChooser;
  18. import javax.swing.JFrame;
  19. import javax.swing.JLabel;
  20. import javax.swing.JLayeredPane;
  21. import javax.swing.JMenu;
  22. import javax.swing.JMenuItem;
  23. import javax.swing.JPanel;
  24. import javax.swing.JPopupMenu;
  25. import javax.swing.JScrollPane;
  26. import javax.swing.JSplitPane;
  27. import javax.swing.JTextArea;
  28. import javax.swing.JTextField;
  29. import javax.swing.JTree;
  30. import javax.swing.filechooser.FileNameExtensionFilter;
  31. import javax.swing.tree.DefaultTreeModel;
  32. import javax.swing.tree.TreePath;
  33. import org.eclipse.elk.graph.ElkNode;
  34. import animation.Action;
  35. import animation.AnimationController;
  36. import animation.PseudoCodeNode;
  37. import bk.BKNodePlacement;
  38. import bk.BKNodePlacement.State;
  39. import bk.LayoutType;
  40. import graph.LayeredGraphEdge;
  41. import graph.LayeredGraphNode;
  42. import graph.LayeredNode;
  43. import graph.io.Reader;
  44. import graph.io.Writer;
  45. import lib.SimpleNodePlacement;
  46. import lib.TextLayoutHelper;
  47. /**
  48. * The main window of the application.
  49. * There should only be one instance of this class at the same time.
  50. * The JFrame of that single instance can be accessed by the static field {code MainView.frame}.
  51. * @author kolja
  52. *
  53. */
  54. public class MainView {
  55. /**
  56. * The 'frame' of the main window.
  57. * The reason why there can only be one instance of this class.
  58. */
  59. private static int frameCounter = 0;
  60. /**
  61. * Random Graph Generator should olny exist once for all windows (so the values will be stored)
  62. */
  63. private static final RandomGraphDialog randomDialog = new RandomGraphDialog();
  64. private JFrame frame;
  65. private AnimationController controller;
  66. private JButton stepForward;
  67. private JButton stepForwardInto;
  68. private JButton stepForwardOut;
  69. private JButton stepBackward;
  70. private JButton stepBackwardInto;
  71. private JButton stepBackwardOut;
  72. private JButton runForward;
  73. private JButton runBackward;
  74. private JButton pause;
  75. private JButton load;
  76. private JButton save;
  77. private JButton debug;
  78. private JButton options;
  79. private JButton randomGraph;
  80. private JLabel delayText;
  81. private JTextField delay;
  82. private JTree pseudoTree;
  83. private LayeredGraphNode graph;
  84. private OptionsDialog optionsDialog;
  85. private String debugInfo()
  86. {
  87. String info = "Debug Information Table: \n";
  88. info += "_______________________________________________________________________________________________________________________________________________________________________________________________________________________\n";
  89. info += "|" + TextLayoutHelper.strToLen( "Top -> Bottom :> Left", 51 ) + "| |" + TextLayoutHelper.strToLen( "Top -> Bottom :> Right", 51 ) + "| |" + TextLayoutHelper.strToLen( "Bottom -> Top :> Left", 51 ) + "| |" + TextLayoutHelper.strToLen( "Bottom -> Top :> Right", 51 ) + "|\n";
  90. info += "|___________________________________________________| |___________________________________________________| |___________________________________________________| |___________________________________________________|\n";
  91. 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";
  92. for( LayeredGraphNode n : graph.getContainedNodes() )
  93. {
  94. info += "|" + TextLayoutHelper.strToLen( n.toString(), 6 ) +
  95. "|" + TextLayoutHelper.strToLen( n.getShift( LayoutType.TOP_BOTTOM_LEFT ) + "", 7 ) +
  96. "|" + TextLayoutHelper.strToLen( n.getSink( LayoutType.TOP_BOTTOM_LEFT ).toString(), 6 ) +
  97. "|" + TextLayoutHelper.strToLen( n.getRoot( LayoutType.TOP_BOTTOM_LEFT ).toString(), 6 ) +
  98. "|" + TextLayoutHelper.strToLen( n.getAlign( LayoutType.TOP_BOTTOM_LEFT ).toString(), 7 ) +
  99. "|" + TextLayoutHelper.strToLen( n.getX( LayoutType.TOP_BOTTOM_LEFT ) + "", 5 ) +
  100. "|" + TextLayoutHelper.strToLen( !n.isXUndefined( LayoutType.TOP_BOTTOM_LEFT ) + "", 8 ) + "| " +
  101. "|" + TextLayoutHelper.strToLen( n.toString(), 6 ) +
  102. "|" + TextLayoutHelper.strToLen( n.getShift( LayoutType.TOP_BOTTOM_RIGHT ) + "", 7 ) +
  103. "|" + TextLayoutHelper.strToLen( n.getSink( LayoutType.TOP_BOTTOM_RIGHT ).toString(), 6 ) +
  104. "|" + TextLayoutHelper.strToLen( n.getRoot( LayoutType.TOP_BOTTOM_RIGHT ).toString(), 6 ) +
  105. "|" + TextLayoutHelper.strToLen( n.getAlign( LayoutType.TOP_BOTTOM_RIGHT ).toString(), 7 ) +
  106. "|" + TextLayoutHelper.strToLen( n.getX( LayoutType.TOP_BOTTOM_RIGHT ) + "", 5 ) +
  107. "|" + TextLayoutHelper.strToLen( !n.isXUndefined( LayoutType.TOP_BOTTOM_RIGHT ) + "", 8 ) + "| " +
  108. "|" + TextLayoutHelper.strToLen( n.toString(), 6 ) +
  109. "|" + TextLayoutHelper.strToLen( n.getShift( LayoutType.BOTTOM_TOP_LEFT ) + "", 7 ) +
  110. "|" + TextLayoutHelper.strToLen( n.getSink( LayoutType.BOTTOM_TOP_LEFT ).toString(), 6 ) +
  111. "|" + TextLayoutHelper.strToLen( n.getRoot( LayoutType.BOTTOM_TOP_LEFT ).toString(), 6 ) +
  112. "|" + TextLayoutHelper.strToLen( n.getAlign( LayoutType.BOTTOM_TOP_LEFT ).toString(), 7 ) +
  113. "|" + TextLayoutHelper.strToLen( n.getX( LayoutType.BOTTOM_TOP_LEFT ) + "", 5 ) +
  114. "|" + TextLayoutHelper.strToLen( !n.isXUndefined( LayoutType.BOTTOM_TOP_LEFT ) + "", 8 ) + "| " +
  115. "|" + TextLayoutHelper.strToLen( n.toString(), 6 ) +
  116. "|" + TextLayoutHelper.strToLen( n.getShift( LayoutType.BOTTOM_TOP_RIGHT ) + "", 7 ) +
  117. "|" + TextLayoutHelper.strToLen( n.getSink( LayoutType.BOTTOM_TOP_RIGHT ).toString(), 6 ) +
  118. "|" + TextLayoutHelper.strToLen( n.getRoot( LayoutType.BOTTOM_TOP_RIGHT ).toString(), 6 ) +
  119. "|" + TextLayoutHelper.strToLen( n.getAlign( LayoutType.BOTTOM_TOP_RIGHT ).toString(), 7 ) +
  120. "|" + TextLayoutHelper.strToLen( n.getX( LayoutType.BOTTOM_TOP_RIGHT ) + "", 5 ) +
  121. "|" + TextLayoutHelper.strToLen( !n.isXUndefined( LayoutType.BOTTOM_TOP_RIGHT ) + "", 8 ) + "|\n";
  122. }
  123. info += "-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
  124. return info;
  125. }
  126. private void showDebugInfo()
  127. {
  128. JFrame debugFrame = new JFrame();
  129. JTextArea info = new JTextArea();
  130. info.setEditable( false );
  131. info.setFont( new Font( Font.MONOSPACED, Font.PLAIN, 11 ) );
  132. String infoS = debugInfo();
  133. info.setText( infoS );
  134. JScrollPane view = new JScrollPane( info );
  135. debugFrame.add( view );
  136. debugFrame.setSize( frame.getWidth(), frame.getHeight() );
  137. debugFrame.setVisible( true );
  138. if (infoS.trim().equals("")) {
  139. System.out.println( "" );
  140. System.out.println( "Debug info:" );
  141. System.out.println( infoS );
  142. System.out.println( "" );
  143. }
  144. }
  145. public MainView( ElkNode graph )
  146. {
  147. this( LayeredNode.convertToLayeredGraph( graph ) );
  148. }
  149. /**
  150. * Initialize the window and its contents.
  151. * There is good reason not to split up this method to smaller methods:
  152. * Imagine a tree with a fixed number of nodes, but limited degree of branching.
  153. * The the height of the tree is at least inversely proportional to the degree of branching.
  154. * This means halving the maximum method size by splitting methods would make the call stack twice as high
  155. * and this way debugging twice as time-consuming.
  156. * @param graph the graph that is displayed in this window.
  157. */
  158. public MainView( LayeredGraphNode graph )
  159. {
  160. RenderHelper.font = new Font("Monospaced", Font.PLAIN, 12);
  161. graph.setColor( null, null );
  162. frameCounter++;
  163. this.graph = graph;
  164. controller = new AnimationController();
  165. frame = new JFrame( "NodeShuffler" );
  166. frame.addWindowListener(new java.awt.event.WindowAdapter() {
  167. @Override
  168. public void windowClosing(java.awt.event.WindowEvent windowEvent) {
  169. frameCounter--;
  170. if( frameCounter == 0 )
  171. System.exit( 0 );
  172. }
  173. });
  174. BKNodePlacement algorithm = new BKNodePlacement( controller, graph, frame );
  175. // Create Menu GUI
  176. stepForward = new NiceButton( "stepForward" );
  177. stepForward.setLocation( 10, 10 );
  178. stepForward.setMnemonic( KeyEvent.VK_DOWN );
  179. stepForward.setToolTipText( "Forward step over (alt + down arrow key)" );
  180. stepForward.addActionListener( new ActionListener() {
  181. @Override
  182. public void actionPerformed(ActionEvent e) {
  183. controller.setContinuous( false );
  184. controller.setNextAction( Action.FORWARD_OVER );
  185. }
  186. });
  187. stepForwardInto = new NiceButton( "stepForwardInto" );
  188. stepForwardInto.setLocation( 60, 10 );
  189. stepForwardInto.setMnemonic( KeyEvent.VK_RIGHT );
  190. stepForwardInto.setToolTipText( "Forward step into (alt + right arrow key)" );
  191. stepForwardInto.addActionListener( new ActionListener() {
  192. @Override
  193. public void actionPerformed(ActionEvent e) {
  194. controller.setContinuous( false );
  195. controller.setNextAction( Action.FORWARD );
  196. }
  197. });
  198. stepForwardOut = new NiceButton( "stepForwardOut" );
  199. stepForwardOut.setLocation( 110, 10 );
  200. stepForwardOut.setMnemonic( KeyEvent.VK_PAGE_DOWN );
  201. stepForwardOut.setToolTipText( "Forward step out (alt + page down key)" );
  202. stepForwardOut.addActionListener( new ActionListener() {
  203. @Override
  204. public void actionPerformed(ActionEvent e) {
  205. controller.setContinuous( false );
  206. controller.setNextAction( Action.FORWARD_OUT );
  207. }
  208. });
  209. runForward = new NiceButton( "runForward" );
  210. runForward.setLocation( 160, 10 );
  211. runForward.setMnemonic( KeyEvent.VK_P );
  212. runForward.setToolTipText( "Run forwards (alt + p)" );
  213. runForward.addActionListener( new ActionListener() {
  214. @Override
  215. public void actionPerformed(ActionEvent e) {
  216. controller.setContinuous( true );
  217. controller.setNextAction( Action.FORWARD );
  218. }
  219. });
  220. runBackward = new NiceButton( "runBackward" );
  221. runBackward.setLocation( 160, 60 );
  222. runBackward.setMnemonic( KeyEvent.VK_R );
  223. runBackward.setToolTipText( "Run backwards (alt + r)" );
  224. runBackward.addActionListener( new ActionListener() {
  225. @Override
  226. public void actionPerformed(ActionEvent e) {
  227. controller.setContinuous( true );
  228. controller.setNextAction( Action.BACKWARD );
  229. }
  230. });
  231. options = new NiceButton( "settings" );
  232. options.setLocation( 210, 60 );
  233. options.setMnemonic( KeyEvent.VK_O );
  234. options.setToolTipText( "Preferences (alt + o)" );
  235. options.addActionListener( new ActionListener() {
  236. @Override
  237. public void actionPerformed(ActionEvent e) {
  238. optionsDialog.setVisible( true );
  239. }
  240. });
  241. stepBackward = new NiceButton( "stepBackward" );
  242. stepBackward.setLocation( 10, 60 );
  243. stepBackward.setMnemonic( KeyEvent.VK_UP );
  244. stepBackward.setToolTipText( "Backward step over (alt + up arrow key)" );
  245. stepBackward.addActionListener( new ActionListener() {
  246. @Override
  247. public void actionPerformed(ActionEvent e) {
  248. controller.setContinuous( false );
  249. controller.setNextAction( Action.BACKWARD_OVER );
  250. }
  251. });
  252. stepBackwardInto = new NiceButton( "stepBackwardInto" );
  253. stepBackwardInto.setLocation( 60, 60 );
  254. stepBackwardInto.setMnemonic( KeyEvent.VK_LEFT );
  255. stepBackwardInto.setToolTipText( "Backward step into (alt + left arrow key)" );
  256. stepBackwardInto.addActionListener( new ActionListener() {
  257. @Override
  258. public void actionPerformed(ActionEvent e) {
  259. controller.setContinuous( false );
  260. controller.setNextAction( Action.BACKWARD );
  261. }
  262. });
  263. stepBackwardOut = new NiceButton( "stepBackwardOut" );
  264. stepBackwardOut.setLocation( 110, 60 );
  265. stepBackwardOut.setMnemonic( KeyEvent.VK_PAGE_UP );
  266. stepBackwardOut.setToolTipText( "Backward step out (alt + page up)" );
  267. stepBackwardOut.addActionListener( new ActionListener() {
  268. @Override
  269. public void actionPerformed(ActionEvent e) {
  270. controller.setContinuous( false );
  271. controller.setNextAction( Action.BACKWARD_OUT );
  272. }
  273. });
  274. pause = new NiceButton( "pause" );
  275. pause.setLocation( 210, 10 );
  276. pause.setMnemonic( KeyEvent.VK_PAUSE );
  277. pause.setToolTipText( "Pause (alt + pause)" );
  278. pause.addActionListener( new ActionListener() {
  279. @Override
  280. public void actionPerformed(ActionEvent e) {
  281. controller.setContinuous( false );
  282. }
  283. });
  284. debug = new NiceButton( "debug" );
  285. debug.setLocation( 360, 10 );
  286. debug.setMnemonic( KeyEvent.VK_D );
  287. debug.setToolTipText( "Show debug info (alt + d)" );
  288. debug.addActionListener( new ActionListener() {
  289. @Override
  290. public void actionPerformed(ActionEvent e) {
  291. showDebugInfo();
  292. }
  293. });
  294. randomGraph = new NiceButton( "random" );
  295. randomGraph.setLocation( 360, 60 );
  296. randomGraph.setMnemonic( KeyEvent.VK_G );
  297. randomGraph.setToolTipText( "Generate random graph (alt + g)" );
  298. randomGraph.addActionListener( new ActionListener() {
  299. @Override
  300. public void actionPerformed(ActionEvent e) {
  301. randomDialog.setVisible( true );
  302. }
  303. });
  304. delayText = new JLabel( "Delay (ms)" );
  305. delayText.setBounds( 260, 10, 80, 20 );
  306. delay = new JTextField( String.valueOf(AnimationController.DEFAULT_DELAY) );
  307. delay.setBounds( 260, 30, 90, 20 );
  308. delay.getDocument().addDocumentListener( new NumberDocumentListener( new NumberDocumentListener.Action() {
  309. @Override
  310. public void action(int val) {
  311. controller.setDelay( Integer.parseInt( delay.getText() ) );
  312. }
  313. }, delay ) );
  314. load = new NiceButton( "load" );
  315. load.setLocation( 260, 60 );
  316. load.setMnemonic( KeyEvent.VK_L );
  317. load.setToolTipText( "Load a graph (alt + l)" );
  318. load.addActionListener( new ActionListener() {
  319. @Override
  320. public void actionPerformed(ActionEvent e) {
  321. JFileChooser chooser = new JFileChooser();
  322. chooser.setFileFilter( new FileNameExtensionFilter("Json Graph", "json") );
  323. chooser.showOpenDialog( frame );
  324. if( chooser.getSelectedFile() != null )
  325. {
  326. Reader r = new Reader( chooser.getSelectedFile().getAbsolutePath() );
  327. LayeredGraphNode graph = r.readInputGraph();
  328. SimpleNodePlacement.placeNodes( graph );
  329. new MainView( graph );
  330. }
  331. }
  332. });
  333. save = new NiceButton( "save" );
  334. save.setLocation( 310, 60 );
  335. save.setMnemonic( KeyEvent.VK_S );
  336. save.setToolTipText( "Save graph (alt + s)" );
  337. save.addActionListener( new ActionListener() {
  338. @Override
  339. public void actionPerformed(ActionEvent e) {
  340. JFileChooser chooser = new JFileChooser();
  341. chooser.setFileFilter( new FileNameExtensionFilter("Json Graph", "json") );
  342. chooser.showSaveDialog( frame );
  343. if( chooser.getSelectedFile() != null )
  344. {
  345. Writer w = new Writer( chooser.getSelectedFile().getAbsolutePath() );
  346. w.writeOutputGraph( graph );
  347. }
  348. }
  349. });
  350. pseudoTree = new JTree();
  351. pseudoTree.setBackground(RenderHelper.BACKGROUND_COLOR);
  352. PseudoCodeNode tree = algorithm.createPseudocodeTree( pseudoTree );
  353. tree.setController( controller );
  354. pseudoTree.setModel( new DefaultTreeModel( tree ) );
  355. pseudoTree.setCellRenderer( new PseudoCodeRenderer() );
  356. pseudoTree.setSelectionModel( null );
  357. pseudoTree.setToolTipText("");
  358. pseudoTree.putClientProperty("JTree.lineStyle", "Angled");
  359. pseudoTree.addMouseListener( new MouseAdapter() {
  360. public void mousePressed(MouseEvent e) {
  361. TreePath selPath = pseudoTree.getPathForLocation(e.getX(), e.getY());
  362. if( selPath != null && e.getClickCount() == 3 ) {
  363. ((PseudoCodeNode)selPath.getLastPathComponent()).setBreakPoint( !((PseudoCodeNode)selPath.getLastPathComponent()).hasBreakPoint() );
  364. if( !pseudoTree.isExpanded( selPath ) )
  365. {
  366. pseudoTree.collapsePath( selPath );
  367. pseudoTree.expandPath( selPath );
  368. }
  369. else
  370. {
  371. pseudoTree.expandPath( selPath );
  372. pseudoTree.collapsePath( selPath );
  373. }
  374. pseudoTree.repaint();
  375. frame.repaint();
  376. }
  377. if( e.getButton() == MouseEvent.BUTTON3 )
  378. {
  379. JPopupMenu menu = new JPopupMenu();
  380. JMenu expandM = new JMenu( "expand ..." );
  381. JMenuItem exAll = new JMenuItem( "all" );
  382. exAll.addActionListener( new ActionListener() {
  383. @Override
  384. public void actionPerformed(ActionEvent e) {
  385. for( int i = 0; i < pseudoTree.getRowCount(); i++ )
  386. pseudoTree.expandRow( i );
  387. }
  388. });
  389. expandM.add( exAll );
  390. JMenuItem exTop = new JMenuItem( "top level lines" );
  391. exTop.addActionListener( new ActionListener() {
  392. @Override
  393. public void actionPerformed(ActionEvent e) {
  394. for( int i = 0; i < pseudoTree.getRowCount(); i++ )
  395. {
  396. if( pseudoTree.getPathForRow( i ).getPathCount() < 3 )
  397. pseudoTree.expandRow( i );
  398. }
  399. }
  400. });
  401. expandM.add( exTop );
  402. JMenuItem exSec = new JMenuItem( "second level lines" );
  403. exSec.addActionListener( new ActionListener() {
  404. @Override
  405. public void actionPerformed(ActionEvent e) {
  406. for( int i = 0; i < pseudoTree.getRowCount(); i++ )
  407. {
  408. if( pseudoTree.getPathForRow( i ).getPathCount() < 4 )
  409. pseudoTree.expandRow( i );
  410. }
  411. }
  412. });
  413. expandM.add( exSec );
  414. JMenuItem exThi = new JMenuItem( "third level lines" );
  415. exThi.addActionListener( new ActionListener() {
  416. @Override
  417. public void actionPerformed(ActionEvent e) {
  418. for( int i = 0; i < pseudoTree.getRowCount(); i++ )
  419. {
  420. if( pseudoTree.getPathForRow( i ).getPathCount() < 5 )
  421. pseudoTree.expandRow( i );
  422. }
  423. }
  424. });
  425. expandM.add( exThi );
  426. menu.add( expandM );
  427. JMenu collapsM = new JMenu( "collapse ..." );
  428. JMenuItem colAll = new JMenuItem( "all" );
  429. colAll.addActionListener( new ActionListener() {
  430. @Override
  431. public void actionPerformed(ActionEvent e) {
  432. for( int i = pseudoTree.getRowCount() - 1; i > 0; i-- )
  433. pseudoTree.collapseRow( i );
  434. }
  435. });
  436. collapsM.add( colAll );
  437. JMenuItem colTop = new JMenuItem( "top level lines" );
  438. colTop.addActionListener( new ActionListener() {
  439. @Override
  440. public void actionPerformed(ActionEvent e) {
  441. for( int i = pseudoTree.getRowCount() - 1; i > 0; i-- )
  442. {
  443. if( pseudoTree.getPathForRow( i ).getPathCount() >= 2 )
  444. pseudoTree.collapseRow( i );
  445. }
  446. }
  447. });
  448. collapsM.add( colTop );
  449. JMenuItem colSec = new JMenuItem( "second level lines" );
  450. colSec.addActionListener( new ActionListener() {
  451. @Override
  452. public void actionPerformed(ActionEvent e) {
  453. for( int i = pseudoTree.getRowCount() - 1; i > 0; i-- )
  454. {
  455. if( pseudoTree.getPathForRow( i ).getPathCount() >= 3 )
  456. pseudoTree.collapseRow( i );
  457. }
  458. }
  459. });
  460. collapsM.add( colSec );
  461. JMenuItem colThi = new JMenuItem( "third level lines" );
  462. colThi.addActionListener( new ActionListener() {
  463. @Override
  464. public void actionPerformed(ActionEvent e) {
  465. for( int i = pseudoTree.getRowCount() - 1; i > 0; i-- )
  466. {
  467. if( pseudoTree.getPathForRow( i ).getPathCount() >= 4 )
  468. pseudoTree.collapseRow( i );
  469. }
  470. }
  471. });
  472. collapsM.add( colThi );
  473. menu.add( collapsM );
  474. menu.show( e.getComponent(), e.getX(), e.getY() );
  475. }
  476. }
  477. } );
  478. pseudoTree.setRowHeight(15);
  479. ((PseudoCodeRenderer)pseudoTree.getCellRenderer()).setMemory( algorithm.getProcessor().getMemory());
  480. JScrollPane treeView = new JScrollPane( pseudoTree );
  481. PseudoCodeLines lineView = new PseudoCodeLines( pseudoTree );
  482. treeView.setRowHeaderView( lineView );
  483. treeView.setBounds( 10, 110, 390, 380 );
  484. JTextArea debugText = new JTextArea();
  485. debugText.setFont( RenderHelper.font );
  486. debugText.setEditable( false );
  487. debugText.setBackground( RenderHelper.BACKGROUND_COLOR );
  488. debugText.setForeground( RenderHelper.FOREGROUND_COLOR );
  489. JScrollPane debugView = new JScrollPane( debugText );
  490. debugView.setBounds( treeView.getX(), treeView.getY() + 500, treeView.getWidth(), 250 );
  491. frame.setSize( (int)graph.getWidth( LayoutType.TOP_BOTTOM_LEFT ) * 2 + 450, (int)graph.getHeight( LayoutType.TOP_BOTTOM_LEFT ) * 2 + 50 );
  492. frame.setLocation( 100, 100 );
  493. frame.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
  494. frame.setVisible( true );
  495. JLayeredPane layne = new JLayeredPane();
  496. layne.setLayout( new BorderLayout() );
  497. JPanel pl = new JPanel();
  498. GridLayout grout = new GridLayout( 2, 2, 10, 10 );
  499. pl.setLayout( grout );
  500. pl.setLocation( 0, 0 );
  501. pl.setSize( frame.getSize() );
  502. NodeView topLeft = createNodeView( graph, LayoutType.TOP_BOTTOM_LEFT );
  503. NodeView topRight = createNodeView( graph, LayoutType.TOP_BOTTOM_RIGHT );
  504. NodeView bottomLeft = createNodeView( graph, LayoutType.BOTTOM_TOP_LEFT );
  505. NodeView bottomRight = createNodeView( graph, LayoutType.BOTTOM_TOP_RIGHT );
  506. pl.add( topLeft );
  507. pl.add( topRight );
  508. pl.add( bottomLeft );
  509. pl.add( bottomRight );
  510. NodeView combined = createNodeView( graph, LayoutType.COMBINED );
  511. combined.setSize( 500, 500 );
  512. layne.add( combined, 0 );
  513. layne.add( pl, 1 );
  514. JSplitPane spane = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT );
  515. spane.setLeftComponent( layne );
  516. spane.setResizeWeight(0.5);
  517. JPanel menue = new JPanel();
  518. menue.setLayout( null );
  519. menue.setPreferredSize( new Dimension( 410, 500 ) );
  520. menue.setMinimumSize( new Dimension( 410, 300 ) );
  521. menue.add( stepForward );
  522. menue.add( stepForwardInto );
  523. menue.add( stepForwardOut );
  524. menue.add( runForward );
  525. menue.add( pause );
  526. menue.add( debug );
  527. menue.add( stepBackward );
  528. menue.add( delayText );
  529. menue.add( delay );
  530. menue.add( stepBackwardInto );
  531. menue.add( stepBackwardOut );
  532. menue.add( runBackward );
  533. menue.add( randomGraph );
  534. menue.add( save );
  535. menue.add( load );
  536. menue.add( options );
  537. JSplitPane spane2 = new JSplitPane( JSplitPane.VERTICAL_SPLIT );
  538. spane2.setBounds( 10, 110, 390, 650 );
  539. spane2.setTopComponent( treeView );
  540. spane2.setBottomComponent( debugView );
  541. spane2.setDividerLocation( 390 );
  542. spane2.setResizeWeight(0.5);
  543. menue.add( spane2 );
  544. spane.setRightComponent( menue);
  545. spane.setContinuousLayout( true );
  546. spane.setDividerLocation( frame.getWidth() - 430 );
  547. spane.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, new PropertyChangeListener() {
  548. @Override
  549. public void propertyChange(PropertyChangeEvent evt) {
  550. frame.getComponentListeners()[ 0 ].componentResized( null );
  551. }
  552. });
  553. frame.add( spane );
  554. frame.revalidate();
  555. frame.repaint();
  556. State old = algorithm.getAlgorithmState();
  557. frame.addComponentListener(new ComponentAdapter()
  558. {
  559. public void componentResized(ComponentEvent evt) {
  560. menue.setSize( menue.getWidth(), layne.getHeight() );
  561. spane2.setSize( menue.getWidth() - 20, menue.getHeight() - 120 );
  562. if( graph.getColor( null ) == null )
  563. {
  564. grout.setHgap( 10 );
  565. grout.setVgap( 10 );
  566. combined.setVisible( false );
  567. }
  568. else
  569. {
  570. grout.setHgap( layne.getWidth() / 3 );
  571. grout.setVgap( layne.getHeight() / 3 );
  572. combined.setVisible( true );
  573. combined.doLayout();
  574. }
  575. combined.setSize( layne.getWidth() / 3, layne.getHeight() / 3 );
  576. combined.setLocation( layne.getWidth() / 3, layne.getHeight() / 3 );
  577. debugText.setText( algorithm.getDebugString().trim() );
  578. layne.remove( pl );
  579. layne.add( pl, 1 );
  580. if( optionsDialog != null && optionsDialog.getLayerDisplayOption() == 1 && old != algorithm.getAlgorithmState() )
  581. {
  582. pl.remove( topLeft );
  583. pl.remove( topRight );
  584. pl.remove( bottomLeft );
  585. pl.remove( bottomRight );
  586. pl.remove( combined );
  587. switch( algorithm.getAlgorithmState() )
  588. {
  589. case CONFLICTS:
  590. pl.add( topLeft );
  591. break;
  592. case LAYOUT1:
  593. pl.add( topLeft );
  594. break;
  595. case LAYOUT2:
  596. pl.add( topRight );
  597. break;
  598. case LAYOUT3:
  599. pl.add( bottomLeft );
  600. break;
  601. case LAYOUT4:
  602. pl.add( bottomRight );
  603. break;
  604. case COMBINE:
  605. pl.add( combined );
  606. break;
  607. }
  608. pl.revalidate();
  609. }
  610. treeView.revalidate();
  611. frame.repaint();
  612. }
  613. });
  614. frame.setSize( frame.getWidth() + 1, frame.getHeight() );
  615. frame.setSize( frame.getWidth() - 1, frame.getHeight() );
  616. if( frame.getHeight() < (int)graph.getHeight( LayoutType.TOP_BOTTOM_LEFT ) * 2 + 50 )
  617. {
  618. double factor = (graph.getHeight( LayoutType.TOP_BOTTOM_LEFT ) * 2) / (frame.getHeight()-50);
  619. frame.setSize( (int)((frame.getWidth() - 450) / factor) + 450, frame.getHeight() );
  620. spane.setDividerLocation( frame.getWidth() - 430 );
  621. }
  622. optionsDialog = new OptionsDialog();
  623. optionsDialog.addActionListener( new ActionListener() {
  624. @Override
  625. public void actionPerformed(ActionEvent e) {
  626. controller.setStepOption( optionsDialog.getRunStepsOption() );
  627. RenderHelper.font = new Font( "Monospaced", Font.PLAIN, optionsDialog.getFontSize() );
  628. debugText.setFont( RenderHelper.font );
  629. pseudoTree.setFont( RenderHelper.font );
  630. pseudoTree.setRowHeight( (int)(15.0/12 * optionsDialog.getFontSize() ) );
  631. for( ComponentListener l : frame.getComponentListeners() )
  632. l.componentResized( new ComponentEvent( frame, 0 ) );
  633. }
  634. });
  635. algorithm.start();
  636. }
  637. private NodeView createNodeView( LayeredGraphNode gNode, LayoutType lt )
  638. {
  639. NodeView graphView = new NodeView( gNode, lt, frame );
  640. ((LayeredNode)gNode).setView( graphView, lt );
  641. graphView.setLayout( null );
  642. graphView.setOpaque( true );
  643. for( LayeredGraphNode n : gNode.getContainedNodes() )
  644. {
  645. NodeView nv = createNodeView( n, lt );
  646. nv.setBounds( nv.getX(), nv.getY(), nv.getWidth(), nv.getHeight() );
  647. graphView.add( nv );
  648. }
  649. for( LayeredGraphEdge e : gNode.getContainedEdges() )
  650. {
  651. EdgeView ev = new EdgeView( e, lt );
  652. ev.setOpaque( true );
  653. graphView.add( ev );
  654. }
  655. return graphView;
  656. }
  657. }