MainView.java 33 KB

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