MainView.java 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827
  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.GridBagConstraints;
  7. import java.awt.GridBagLayout;
  8. import java.awt.GridLayout;
  9. import java.awt.event.ActionEvent;
  10. import java.awt.event.ActionListener;
  11. import java.awt.event.ComponentAdapter;
  12. import java.awt.event.ComponentEvent;
  13. import java.awt.event.FocusEvent;
  14. import java.awt.event.FocusListener;
  15. import java.awt.event.KeyEvent;
  16. import java.awt.event.MouseAdapter;
  17. import java.awt.event.MouseEvent;
  18. import javax.swing.JButton;
  19. import javax.swing.JDialog;
  20. import javax.swing.JFileChooser;
  21. import javax.swing.JFrame;
  22. import javax.swing.JLabel;
  23. import javax.swing.JLayeredPane;
  24. import javax.swing.JOptionPane;
  25. import javax.swing.JPanel;
  26. import javax.swing.JScrollPane;
  27. import javax.swing.JTextArea;
  28. import javax.swing.JTextField;
  29. import javax.swing.JTree;
  30. import javax.swing.event.DocumentEvent;
  31. import javax.swing.event.DocumentListener;
  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 animation.Action;
  37. import animation.AnimationController;
  38. import animation.PseudoCodeNode;
  39. import bk.BKNodePlacement;
  40. import bk.ExtremalLayoutCalc.LayoutType;
  41. import graph.InitializeNodePositions;
  42. import graph.LayeredGraphEdge;
  43. import graph.LayeredGraphNode;
  44. import graph.LayeredNode;
  45. import graph.RandomGraphGenerator;
  46. import graph.io.Reader;
  47. import graph.io.Writer;
  48. import lib.SweepCrossingMinimizer;
  49. import lib.TextLayoutHelper;
  50. /**
  51. * The main window of the application.
  52. * There should only be one instance of this class at the same time.
  53. * The JFrame of that single instance can be accessed by the static field {code MainView.frame}.
  54. * @author kolja
  55. *
  56. */
  57. public class MainView {
  58. /**
  59. * The 'frame' of the main window.
  60. * The reason why there can only be one instance of this class.
  61. */
  62. private static int frameCounter = 0;
  63. private JFrame frame;
  64. private AnimationController controller;
  65. private JButton stepForward;
  66. private JButton stepForwardInto;
  67. private JButton stepForwardOut;
  68. private JButton stepBackward;
  69. private JButton stepBackwardInto;
  70. private JButton stepBackwardOut;
  71. private JButton runForward;
  72. private JButton runBackward;
  73. private JButton pause;
  74. private JButton load;
  75. private JButton save;
  76. private JButton debug;
  77. private JButton randomGraph;
  78. private JLabel delayText;
  79. private JTextField delay;
  80. private JTree pseudoTree;
  81. private LayeredGraphNode graph;
  82. private String debugInfo()
  83. {
  84. String info = "Debug Information Table: \n";
  85. info += "_______________________________________________________________________________________________________________________________________________________________________________________________________________________\n";
  86. 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";
  87. info += "|___________________________________________________| |___________________________________________________| |___________________________________________________| |___________________________________________________|\n";
  88. 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";
  89. for( LayeredGraphNode n : graph.getContainedNodes() )
  90. {
  91. info += "|" + TextLayoutHelper.strToLen( n.getName(), 6 ) +
  92. "|" + TextLayoutHelper.strToLen( n.getShift( LayoutType.TOP_BOTTOM_LEFT ) + "", 7 ) +
  93. "|" + TextLayoutHelper.strToLen( n.getSink( LayoutType.TOP_BOTTOM_LEFT ).getName(), 6 ) +
  94. "|" + TextLayoutHelper.strToLen( n.getRoot( LayoutType.TOP_BOTTOM_LEFT ).getName(), 6 ) +
  95. "|" + TextLayoutHelper.strToLen( n.getAlign( LayoutType.TOP_BOTTOM_LEFT ).getName(), 7 ) +
  96. "|" + TextLayoutHelper.strToLen( n.getX( LayoutType.TOP_BOTTOM_LEFT ) + "", 5 ) +
  97. "|" + TextLayoutHelper.strToLen( !n.isXUndefined( LayoutType.TOP_BOTTOM_LEFT ) + "", 8 ) + "| " +
  98. "|" + TextLayoutHelper.strToLen( n.getName(), 6 ) +
  99. "|" + TextLayoutHelper.strToLen( n.getShift( LayoutType.TOP_BOTTOM_RIGHT ) + "", 7 ) +
  100. "|" + TextLayoutHelper.strToLen( n.getSink( LayoutType.TOP_BOTTOM_RIGHT ).getName(), 6 ) +
  101. "|" + TextLayoutHelper.strToLen( n.getRoot( LayoutType.TOP_BOTTOM_RIGHT ).getName(), 6 ) +
  102. "|" + TextLayoutHelper.strToLen( n.getAlign( LayoutType.TOP_BOTTOM_RIGHT ).getName(), 7 ) +
  103. "|" + TextLayoutHelper.strToLen( n.getX( LayoutType.TOP_BOTTOM_RIGHT ) + "", 5 ) +
  104. "|" + TextLayoutHelper.strToLen( !n.isXUndefined( LayoutType.TOP_BOTTOM_RIGHT ) + "", 8 ) + "| " +
  105. "|" + TextLayoutHelper.strToLen( n.getName(), 6 ) +
  106. "|" + TextLayoutHelper.strToLen( n.getShift( LayoutType.BOTTOM_TOP_LEFT ) + "", 7 ) +
  107. "|" + TextLayoutHelper.strToLen( n.getSink( LayoutType.BOTTOM_TOP_LEFT ).getName(), 6 ) +
  108. "|" + TextLayoutHelper.strToLen( n.getRoot( LayoutType.BOTTOM_TOP_LEFT ).getName(), 6 ) +
  109. "|" + TextLayoutHelper.strToLen( n.getAlign( LayoutType.BOTTOM_TOP_LEFT ).getName(), 7 ) +
  110. "|" + TextLayoutHelper.strToLen( n.getX( LayoutType.BOTTOM_TOP_LEFT ) + "", 5 ) +
  111. "|" + TextLayoutHelper.strToLen( !n.isXUndefined( LayoutType.BOTTOM_TOP_LEFT ) + "", 8 ) + "| " +
  112. "|" + TextLayoutHelper.strToLen( n.getName(), 6 ) +
  113. "|" + TextLayoutHelper.strToLen( n.getShift( LayoutType.BOTTOM_TOP_RIGHT ) + "", 7 ) +
  114. "|" + TextLayoutHelper.strToLen( n.getSink( LayoutType.BOTTOM_TOP_RIGHT ).getName(), 6 ) +
  115. "|" + TextLayoutHelper.strToLen( n.getRoot( LayoutType.BOTTOM_TOP_RIGHT ).getName(), 6 ) +
  116. "|" + TextLayoutHelper.strToLen( n.getAlign( LayoutType.BOTTOM_TOP_RIGHT ).getName(), 7 ) +
  117. "|" + TextLayoutHelper.strToLen( n.getX( LayoutType.BOTTOM_TOP_RIGHT ) + "", 5 ) +
  118. "|" + TextLayoutHelper.strToLen( !n.isXUndefined( LayoutType.BOTTOM_TOP_RIGHT ) + "", 8 ) + "|\n";
  119. }
  120. info += "-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
  121. return info;
  122. }
  123. private void showDebugInfo()
  124. {
  125. JFrame debugFrame = new JFrame();
  126. JTextArea info = new JTextArea();
  127. info.setEditable( false );
  128. info.setFont( new Font( Font.MONOSPACED, Font.PLAIN, 11 ) );
  129. String infoS = debugInfo();
  130. info.setText( infoS );
  131. JScrollPane view = new JScrollPane( info );
  132. debugFrame.add( view );
  133. debugFrame.setSize( frame.getWidth(), frame.getHeight() );
  134. debugFrame.setVisible( true );
  135. System.out.println( infoS );
  136. }
  137. public MainView( ElkNode graph )
  138. {
  139. this( LayeredNode.convertToLayeredGraph( graph ) );
  140. }
  141. /**
  142. * Initialize the window and its contents.
  143. * There is good reason not to split up this method to smaller methods:
  144. * Imagine a tree with a fixed number of nodes, but limited degree of branching.
  145. * The the height of the tree is at least inversely proportional to the degree of branching.
  146. * This means halving the maximum method size by splitting methods would make the call stack twice as high
  147. * and this way debugging twice as time-consuming.
  148. * @param graph the graph that is displayed in this window.
  149. */
  150. public MainView( LayeredGraphNode graph )
  151. {
  152. frameCounter++;
  153. this.graph = graph;
  154. controller = new AnimationController();
  155. frame = new JFrame( "NodeShuffler" );
  156. frame.addWindowListener(new java.awt.event.WindowAdapter() {
  157. @Override
  158. public void windowClosing(java.awt.event.WindowEvent windowEvent) {
  159. frameCounter--;
  160. if( frameCounter == 0 )
  161. System.exit( 0 );
  162. }
  163. });
  164. BKNodePlacement algorithm = new BKNodePlacement( controller, graph, frame );
  165. // Create Menu GUI
  166. stepForward = new NiceButton( "stepForward" );
  167. stepForward.setLocation( 10, 10 );
  168. stepForward.setMnemonic( KeyEvent.VK_DOWN );
  169. stepForward.setToolTipText( "Forward step over (alt + down arrow key)" );
  170. stepForward.addActionListener( new ActionListener() {
  171. @Override
  172. public void actionPerformed(ActionEvent e) {
  173. controller.setContinuous( false );
  174. controller.setNextAction( Action.FORWARD_OVER );
  175. }
  176. });
  177. stepForwardInto = new NiceButton( "stepForwardInto" );
  178. stepForwardInto.setLocation( 60, 10 );
  179. stepForwardInto.setMnemonic( KeyEvent.VK_RIGHT );
  180. stepForwardInto.setToolTipText( "Forward step into (alt + right arrow key)" );
  181. stepForwardInto.addActionListener( new ActionListener() {
  182. @Override
  183. public void actionPerformed(ActionEvent e) {
  184. controller.setContinuous( false );
  185. controller.setNextAction( Action.FORWARD );
  186. }
  187. });
  188. stepForwardOut = new NiceButton( "stepForwardOut" );
  189. stepForwardOut.setLocation( 110, 10 );
  190. stepForwardOut.setMnemonic( KeyEvent.VK_PAGE_DOWN );
  191. stepForwardOut.setToolTipText( "Forward step out (alt + page down key)" );
  192. stepForwardOut.addActionListener( new ActionListener() {
  193. @Override
  194. public void actionPerformed(ActionEvent e) {
  195. controller.setContinuous( false );
  196. controller.setNextAction( Action.FORWARD_OUT );
  197. }
  198. });
  199. runForward = new NiceButton( "runForward" );
  200. runForward.setLocation( 160, 10 );
  201. runForward.setMnemonic( KeyEvent.VK_P );
  202. runForward.setToolTipText( "Run forwards (alt + p)" );
  203. runForward.addActionListener( new ActionListener() {
  204. @Override
  205. public void actionPerformed(ActionEvent e) {
  206. controller.setContinuous( true );
  207. controller.setNextAction( Action.FORWARD );
  208. }
  209. });
  210. runBackward = new NiceButton( "runBackward" );
  211. runBackward.setLocation( 160, 60 );
  212. runBackward.setMnemonic( KeyEvent.VK_R );
  213. runBackward.setToolTipText( "Run backwards (alt + r)" );
  214. runBackward.addActionListener( new ActionListener() {
  215. @Override
  216. public void actionPerformed(ActionEvent e) {
  217. controller.setContinuous( true );
  218. controller.setNextAction( Action.BACKWARD );
  219. }
  220. });
  221. stepBackward = new NiceButton( "stepBackward" );
  222. stepBackward.setLocation( 10, 60 );
  223. stepBackward.setMnemonic( KeyEvent.VK_UP );
  224. stepBackward.setToolTipText( "Backward step over (alt + up arrow key)" );
  225. stepBackward.addActionListener( new ActionListener() {
  226. @Override
  227. public void actionPerformed(ActionEvent e) {
  228. controller.setContinuous( false );
  229. controller.setNextAction( Action.BACKWARD_OVER );
  230. }
  231. });
  232. stepBackwardInto = new NiceButton( "stepBackwardInto" );
  233. stepBackwardInto.setLocation( 60, 60 );
  234. stepBackwardInto.setMnemonic( KeyEvent.VK_LEFT );
  235. stepBackwardInto.setToolTipText( "Backward step into (alt + left arrow key)" );
  236. stepBackwardInto.addActionListener( new ActionListener() {
  237. @Override
  238. public void actionPerformed(ActionEvent e) {
  239. controller.setContinuous( false );
  240. controller.setNextAction( Action.BACKWARD );
  241. }
  242. });
  243. stepBackwardOut = new NiceButton( "stepBackwardOut" );
  244. stepBackwardOut.setLocation( 110, 60 );
  245. stepBackwardOut.setMnemonic( KeyEvent.VK_PAGE_UP );
  246. stepBackwardOut.setToolTipText( "Backward step out (alt + page up)" );
  247. stepBackwardOut.addActionListener( new ActionListener() {
  248. @Override
  249. public void actionPerformed(ActionEvent e) {
  250. controller.setContinuous( false );
  251. controller.setNextAction( Action.BACKWARD_OUT );
  252. }
  253. });
  254. pause = new NiceButton( "pause" );
  255. pause.setLocation( 210, 10 );
  256. pause.setMnemonic( KeyEvent.VK_PAUSE );
  257. pause.setToolTipText( "Pause (alt + pause)" );
  258. pause.addActionListener( new ActionListener() {
  259. @Override
  260. public void actionPerformed(ActionEvent e) {
  261. controller.setContinuous( false );
  262. }
  263. });
  264. debug = new NiceButton( "debug" );
  265. debug.setLocation( 360, 10 );
  266. debug.setMnemonic( KeyEvent.VK_D );
  267. debug.setToolTipText( "Show debug info (alt + d)" );
  268. debug.addActionListener( new ActionListener() {
  269. @Override
  270. public void actionPerformed(ActionEvent e) {
  271. showDebugInfo();
  272. }
  273. });
  274. randomGraph = new NiceButton( "random" );
  275. randomGraph.setLocation( 360, 60 );
  276. randomGraph.setMnemonic( KeyEvent.VK_G );
  277. randomGraph.setToolTipText( "Generate random graph (alt + g)" );
  278. randomGraph.addActionListener( new ActionListener() {
  279. @Override
  280. public void actionPerformed(ActionEvent e) {
  281. JDialog diag = new JDialog( frame, "Generate random graph" );
  282. diag.setLayout( new GridBagLayout() );
  283. GridBagConstraints c = new GridBagConstraints();
  284. c.gridx = 0;
  285. c.gridy = 0;
  286. diag.add( new JLabel( "P(subgraph exists)"), c );
  287. c = new GridBagConstraints();
  288. c.gridx = 1;
  289. c.gridy = 0;
  290. JTextField pSubgraph = new JTextField( "0.1" );
  291. pSubgraph.setPreferredSize( new Dimension( 100, 20 ) );
  292. pSubgraph.addFocusListener( new FocusListener() {
  293. @Override
  294. public void focusGained(FocusEvent e) {
  295. pSubgraph.setBackground( Color.WHITE );
  296. }
  297. @Override
  298. public void focusLost(FocusEvent e) {
  299. try {
  300. double d = Double.parseDouble( pSubgraph.getText() );
  301. if( d > 1 || d < 0 )
  302. pSubgraph.setBackground( Color.RED );
  303. } catch( Exception e1 )
  304. {
  305. pSubgraph.setBackground( Color.RED );
  306. }
  307. }
  308. });
  309. diag.add( pSubgraph, c );
  310. c = new GridBagConstraints();
  311. c.gridx = 0;
  312. c.gridy = 1;
  313. diag.add( new JLabel( "P(edge exists)"), c );
  314. c = new GridBagConstraints();
  315. c.gridx = 1;
  316. c.gridy = 1;
  317. JTextField pEdge = new JTextField( "0.3" );
  318. pEdge.setPreferredSize( new Dimension( 100, 20 ) );
  319. pEdge.addFocusListener( new FocusListener() {
  320. @Override
  321. public void focusGained(FocusEvent e) {
  322. pEdge.setBackground( Color.WHITE );
  323. }
  324. @Override
  325. public void focusLost(FocusEvent e) {
  326. try {
  327. double d = Double.parseDouble( pEdge.getText() );
  328. if( d > 1 || d < 0 )
  329. pEdge.setBackground( Color.RED );
  330. } catch( Exception e1 )
  331. {
  332. pEdge.setBackground( Color.RED );
  333. }
  334. }
  335. });
  336. diag.add( pEdge, c );
  337. c = new GridBagConstraints();
  338. c.gridx = 0;
  339. c.gridy = 2;
  340. diag.add( new JLabel( "min. num. layers"), c );
  341. c = new GridBagConstraints();
  342. c.gridx = 1;
  343. c.gridy = 2;
  344. JTextField minLayers = new JTextField( "5" );
  345. JTextField maxLayers = new JTextField( "5" );
  346. minLayers.setPreferredSize( new Dimension( 100, 20 ) );
  347. minLayers.addFocusListener( new FocusListener() {
  348. @Override
  349. public void focusGained(FocusEvent e) {
  350. minLayers.setBackground( Color.WHITE );
  351. }
  352. @Override
  353. public void focusLost(FocusEvent e) {
  354. try {
  355. int i = Integer.parseInt( minLayers.getText() );
  356. int max = Integer.parseInt( maxLayers.getText() );
  357. if( i < 1 || i > max )
  358. minLayers.setBackground( Color.RED );
  359. else
  360. maxLayers.setBackground( Color.WHITE );
  361. } catch( Exception e1 )
  362. {
  363. minLayers.setBackground( Color.RED );
  364. }
  365. }
  366. });
  367. diag.add( minLayers, c );
  368. c = new GridBagConstraints();
  369. c.gridx = 0;
  370. c.gridy = 3;
  371. diag.add( new JLabel( "max. num. layers"), c );
  372. c = new GridBagConstraints();
  373. c.gridx = 1;
  374. c.gridy = 3;
  375. maxLayers.setPreferredSize( new Dimension( 100, 20 ) );
  376. maxLayers.addFocusListener( new FocusListener() {
  377. @Override
  378. public void focusGained(FocusEvent e) {
  379. maxLayers.setBackground( Color.WHITE );
  380. }
  381. @Override
  382. public void focusLost(FocusEvent e) {
  383. try {
  384. int i = Integer.parseInt( maxLayers.getText() );
  385. int min = Integer.parseInt( minLayers.getText() );
  386. if( i < min )
  387. maxLayers.setBackground( Color.RED );
  388. else if( min > 0 )
  389. minLayers.setBackground( Color.WHITE );
  390. } catch( Exception e1 )
  391. {
  392. maxLayers.setBackground( Color.RED );
  393. }
  394. }
  395. });
  396. diag.add( maxLayers, c );
  397. c = new GridBagConstraints();
  398. c.gridx = 0;
  399. c.gridy = 4;
  400. diag.add( new JLabel( "min. num. nodes"), c );
  401. c = new GridBagConstraints();
  402. c.gridx = 1;
  403. c.gridy = 4;
  404. JTextField minNodes = new JTextField( "5" );
  405. JTextField maxNodes = new JTextField( "5" );
  406. minNodes.setPreferredSize( new Dimension( 100, 20 ) );
  407. minNodes.setToolTipText( "between 1 and 'min. num. nodes'" );
  408. minNodes.addFocusListener( new FocusListener() {
  409. @Override
  410. public void focusGained(FocusEvent e) {
  411. minNodes.setBackground( Color.WHITE );
  412. }
  413. @Override
  414. public void focusLost(FocusEvent e) {
  415. try {
  416. int i = Integer.parseInt( minNodes.getText() );
  417. int max = Integer.parseInt( maxNodes.getText() );
  418. if( i < 1 || i > max )
  419. minNodes.setBackground( Color.RED );
  420. else
  421. minNodes.setBackground( Color.WHITE );
  422. } catch( Exception e1 )
  423. {
  424. minNodes.setBackground( Color.RED );
  425. }
  426. }
  427. });
  428. diag.add( minNodes, c );
  429. c = new GridBagConstraints();
  430. c.gridx = 0;
  431. c.gridy = 5;
  432. diag.add( new JLabel( "max. num. nodes"), c );
  433. c = new GridBagConstraints();
  434. c.gridx = 1;
  435. c.gridy = 5;
  436. maxNodes.setPreferredSize( new Dimension( 100, 20 ) );
  437. maxNodes.setToolTipText( "between 'min. num. nodes' and +Inf" );
  438. maxNodes.addFocusListener( new FocusListener() {
  439. @Override
  440. public void focusGained(FocusEvent e) {
  441. maxNodes.setBackground( Color.WHITE );
  442. }
  443. @Override
  444. public void focusLost(FocusEvent e) {
  445. try {
  446. int i = Integer.parseInt( maxNodes.getText() );
  447. int min = Integer.parseInt( minNodes.getText() );
  448. if( i < min )
  449. maxNodes.setBackground( Color.RED );
  450. else if( min > 0 )
  451. minNodes.setBackground( Color.WHITE );
  452. } catch( Exception e1 )
  453. {
  454. maxNodes.setBackground( Color.RED );
  455. }
  456. }
  457. });
  458. diag.add( maxNodes, c );
  459. c = new GridBagConstraints();
  460. c.gridx = 0;
  461. c.gridy = 6;
  462. diag.add( new JLabel( "max. hier. depth"), c );
  463. c = new GridBagConstraints();
  464. c.gridx = 1;
  465. c.gridy = 6;
  466. JTextField maxDepth = new JTextField( "1" );
  467. maxDepth.setPreferredSize( new Dimension( 100, 20 ) );
  468. maxDepth.setToolTipText( "between 1 and +Inf" );
  469. maxDepth.addFocusListener( new FocusListener() {
  470. @Override
  471. public void focusGained(FocusEvent e) {
  472. maxDepth.setBackground( Color.WHITE );
  473. }
  474. @Override
  475. public void focusLost(FocusEvent e) {
  476. try {
  477. int i = Integer.parseInt( maxDepth.getText() );
  478. if( i < 1 )
  479. maxDepth.setBackground( Color.RED );
  480. } catch( Exception e1 )
  481. {
  482. maxDepth.setBackground( Color.RED );
  483. }
  484. }
  485. });
  486. diag.add( maxDepth, c );
  487. c = new GridBagConstraints();
  488. c.gridx = 0;
  489. c.gridy = 7;
  490. c.gridwidth = 2;
  491. JButton gen = new JButton( "generate");
  492. gen.addActionListener( new ActionListener() {
  493. @Override
  494. public void actionPerformed(ActionEvent e) {
  495. double pSubGraphD = Double.parseDouble( pSubgraph.getText() );
  496. double pEdgeD = Double.parseDouble( pEdge.getText() );
  497. int minLayerI = Integer.parseInt( minLayers.getText() );
  498. int maxLayerI = Integer.parseInt( maxLayers.getText() );
  499. int minNodeI = Integer.parseInt( minNodes.getText() );
  500. int maxNodeI = Integer.parseInt( maxNodes.getText() );
  501. int maxDepthI = Integer.parseInt( maxDepth.getText() );
  502. boolean ok = true;
  503. if( pSubGraphD < 0 || pSubGraphD > 1 )
  504. {
  505. pSubgraph.setBackground( Color.RED );
  506. ok = false;
  507. }
  508. if( pEdgeD < 0 || pEdgeD > 1 )
  509. {
  510. pEdge.setBackground( Color.RED );
  511. ok = false;
  512. }
  513. if( minLayerI < 1 )
  514. {
  515. minLayers.setBackground( Color.RED );
  516. ok = false;
  517. }
  518. if( maxLayerI < minLayerI )
  519. {
  520. maxLayers.setBackground( Color.RED );
  521. ok = false;
  522. }
  523. if( minNodeI < 1 )
  524. {
  525. minNodes.setBackground( Color.RED );
  526. ok = false;
  527. }
  528. if( maxNodeI < minNodeI )
  529. {
  530. maxNodes.setBackground( Color.RED );
  531. ok = false;
  532. }
  533. if( maxDepthI < 1 )
  534. {
  535. maxDepth.setBackground( Color.RED );
  536. ok = false;
  537. }
  538. if( ok )
  539. {
  540. RandomGraphGenerator r = new RandomGraphGenerator( pSubGraphD, pEdgeD, minLayerI, maxLayerI, minNodeI, maxNodeI, maxDepthI );
  541. try {
  542. LayeredGraphNode graph = r.createRandomNode( null, 0, true );
  543. SweepCrossingMinimizer cminzer = new SweepCrossingMinimizer();
  544. for( int i = 0; i < 10; i++ )
  545. cminzer.minimizeCrossings( graph );
  546. InitializeNodePositions.placeNodes( graph );
  547. new MainView( graph );
  548. diag.setVisible( false );
  549. } catch( Exception e1 )
  550. {
  551. JOptionPane.showMessageDialog(frame, e1.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
  552. }
  553. }
  554. }
  555. });
  556. diag.add( gen, c );
  557. diag.setSize( 270, 220 );
  558. diag.setLocation( frame.getX() + frame.getWidth() / 2 - diag.getWidth() / 2, frame.getY() + frame.getHeight() / 2 - diag.getHeight() / 2 );
  559. diag.setVisible( true );
  560. }
  561. });
  562. delayText = new JLabel( "Delay (ms)" );
  563. delayText.setBounds( 260, 10, 80, 20 );
  564. delay = new JTextField( String.valueOf(AnimationController.DEFAULT_DELAY) );
  565. delay.setBounds( 260, 30, 90, 20 );
  566. delay.getDocument().addDocumentListener( new DocumentListener() {
  567. @Override
  568. public void insertUpdate(DocumentEvent e) {
  569. try
  570. {
  571. controller.setDelay( Integer.parseInt( delay.getText() ) );
  572. delay.setBackground( Color.WHITE );
  573. } catch( Exception e1 )
  574. {
  575. delay.setBackground( Color.RED );
  576. }
  577. }
  578. @Override
  579. public void removeUpdate(DocumentEvent e) {
  580. try
  581. {
  582. controller.setDelay( Integer.parseInt( delay.getText() ) );
  583. delay.setBackground( Color.WHITE );
  584. } catch( Exception e1 )
  585. {
  586. delay.setBackground( Color.RED );
  587. }
  588. }
  589. @Override
  590. public void changedUpdate(DocumentEvent e) {
  591. try
  592. {
  593. controller.setDelay( Integer.parseInt( delay.getText() ) );
  594. delay.setBackground( Color.WHITE );
  595. } catch( Exception e1 )
  596. {
  597. delay.setBackground( Color.RED );
  598. }
  599. }
  600. });
  601. load = new NiceButton( "load" );
  602. load.setLocation( 230, 60 );
  603. load.setMnemonic( KeyEvent.VK_L );
  604. load.setToolTipText( "Load a graph (alt + l)" );
  605. load.addActionListener( new ActionListener() {
  606. @Override
  607. public void actionPerformed(ActionEvent e) {
  608. JFileChooser chooser = new JFileChooser();
  609. chooser.setFileFilter( new FileNameExtensionFilter("Json Graph", "json") );
  610. chooser.showOpenDialog( frame );
  611. if( chooser.getSelectedFile() != null )
  612. {
  613. Reader r = new Reader( chooser.getSelectedFile().getAbsolutePath() );
  614. LayeredGraphNode graph = r.readInputGraph();
  615. InitializeNodePositions.placeNodes( graph );
  616. new MainView( graph );
  617. }
  618. }
  619. });
  620. save = new NiceButton( "save" );
  621. save.setLocation( 295, 60 );
  622. save.setMnemonic( KeyEvent.VK_S );
  623. save.setToolTipText( "Save graph (alt + s)" );
  624. save.addActionListener( new ActionListener() {
  625. @Override
  626. public void actionPerformed(ActionEvent e) {
  627. JFileChooser chooser = new JFileChooser();
  628. chooser.setFileFilter( new FileNameExtensionFilter("Json Graph", "json") );
  629. chooser.showSaveDialog( frame );
  630. if( chooser.getSelectedFile() != null )
  631. {
  632. Writer w = new Writer( chooser.getSelectedFile().getAbsolutePath() );
  633. w.writeOutputGraph( graph );
  634. }
  635. }
  636. });
  637. pseudoTree = new JTree();
  638. pseudoTree.setBackground(RenderHelper.BACKGROUND_COLOR);
  639. PseudoCodeNode tree = algorithm.createPseudocodeTree( pseudoTree );
  640. tree.setController( controller );
  641. pseudoTree.setModel( new DefaultTreeModel( tree ) );
  642. pseudoTree.setCellRenderer( new PseudoCodeRenderer() );
  643. pseudoTree.setSelectionModel( null );
  644. pseudoTree.addMouseListener( new MouseAdapter() {
  645. public void mousePressed(MouseEvent e) {
  646. TreePath selPath = pseudoTree.getPathForLocation(e.getX(), e.getY());
  647. if( selPath != null && e.getClickCount() == 3 ) {
  648. ((PseudoCodeNode)selPath.getLastPathComponent()).setBreakPoint( !((PseudoCodeNode)selPath.getLastPathComponent()).hasBreakPoint() );
  649. if( !pseudoTree.isExpanded( selPath ) )
  650. {
  651. pseudoTree.collapsePath( selPath );
  652. pseudoTree.expandPath( selPath );
  653. }
  654. else
  655. {
  656. pseudoTree.expandPath( selPath );
  657. pseudoTree.collapsePath( selPath );
  658. }
  659. pseudoTree.repaint();
  660. frame.repaint();
  661. }
  662. }
  663. } );
  664. pseudoTree.setRowHeight(15);
  665. JScrollPane treeView = new JScrollPane( pseudoTree );
  666. treeView.setBounds( 10, 110, 390, 380 );
  667. JTextArea debugText = new JTextArea();
  668. debugText.setFont( new Font( "Monospaced", Font.PLAIN, 12 ) );
  669. debugText.setEditable( false );
  670. debugText.setBackground( RenderHelper.BACKGROUND_COLOR );
  671. debugText.setForeground( RenderHelper.FOREGROUND_COLOR );
  672. JScrollPane debugView = new JScrollPane( debugText );
  673. debugView.setBounds( treeView.getX(), treeView.getY() + 500, treeView.getWidth(), 250 );
  674. frame.setSize( (int)graph.getWidth( LayoutType.TOP_BOTTOM_LEFT ) * 2 + 575, (int)graph.getHeight( LayoutType.TOP_BOTTOM_LEFT ) * 2 + 200 );
  675. frame.setLocation( 100, 100 );
  676. frame.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
  677. frame.setVisible( true );
  678. JLayeredPane layne = new JLayeredPane();
  679. JPanel pl = new JPanel();
  680. GridLayout grout = new GridLayout( 2, 2, 10, 10 );
  681. pl.setLayout( grout );
  682. pl.setLocation( 0, 0 );
  683. pl.setSize( frame.getSize() );
  684. NodeView topLeft = createNodeView( graph, LayoutType.TOP_BOTTOM_LEFT );
  685. NodeView topRight = createNodeView( graph, LayoutType.TOP_BOTTOM_RIGHT );
  686. NodeView bottomLeft = createNodeView( graph, LayoutType.BOTTOM_TOP_LEFT );
  687. NodeView bottomRight = createNodeView( graph, LayoutType.BOTTOM_TOP_RIGHT );
  688. pl.add( topLeft );
  689. pl.add( topRight );
  690. pl.add( bottomLeft );
  691. pl.add( bottomRight );
  692. layne.add( pl, 1 );
  693. NodeView combined = createNodeView( graph, LayoutType.COMBINED );
  694. combined.setSize( 500, 500 );
  695. layne.add( combined, 0 );
  696. frame.add( layne );
  697. JPanel menue = new JPanel();
  698. menue.setLayout( null );
  699. menue.setPreferredSize( new Dimension( 410, 500 ) );
  700. menue.add( stepForward );
  701. menue.add( stepForwardInto );
  702. menue.add( stepForwardOut );
  703. menue.add( runForward );
  704. menue.add( pause );
  705. menue.add( debug );
  706. menue.add( stepBackward );
  707. menue.add( delayText );
  708. menue.add( delay );
  709. menue.add( treeView );
  710. menue.add( stepBackwardInto );
  711. menue.add( stepBackwardOut );
  712. menue.add( runBackward );
  713. menue.add( randomGraph );
  714. menue.add( save );
  715. menue.add( load );
  716. menue.add( debugView );
  717. frame.add( menue, BorderLayout.EAST );
  718. frame.setSize( frame.getWidth() + 1, frame.getHeight() );
  719. frame.setSize( frame.getWidth() - 1, frame.getHeight() );
  720. frame.validate();
  721. frame.repaint();
  722. frame.addComponentListener(new ComponentAdapter()
  723. {
  724. public void componentResized(ComponentEvent evt) {
  725. pl.setSize( layne.getSize() );
  726. menue.setSize( menue.getWidth(), layne.getHeight() );
  727. treeView.setSize( treeView.getWidth(), layne.getHeight() - 370 );
  728. debugView.setBounds( treeView.getX(), treeView.getY() + treeView.getHeight() + 10, treeView.getWidth(), 240 );
  729. if( graph.getColor( LayoutType.COMBINED ) == null )
  730. {
  731. grout.setHgap( 10 );
  732. grout.setVgap( 10 );
  733. }
  734. else
  735. {
  736. grout.setHgap( layne.getWidth() / 3 );
  737. grout.setVgap( layne.getHeight() / 3 );
  738. }
  739. combined.setSize( layne.getWidth() / 3, layne.getHeight() / 3 );
  740. combined.setLocation( layne.getWidth() / 3, layne.getHeight() / 3 );
  741. debugText.setText( algorithm.getDebugString().trim() );
  742. layne.remove( pl );
  743. layne.add( pl, 1 );
  744. frame.repaint();
  745. }
  746. });
  747. algorithm.start();
  748. }
  749. private NodeView createNodeView( LayeredGraphNode gNode, LayoutType lt )
  750. {
  751. NodeView graphView = new NodeView( gNode, lt );
  752. ((LayeredNode)gNode).setView( graphView, lt );
  753. graphView.setLayout( null );
  754. graphView.setOpaque( true );
  755. for( LayeredGraphNode n : gNode.getContainedNodes() )
  756. {
  757. NodeView nv = createNodeView( n, lt );
  758. nv.setBounds( nv.getX(), nv.getY(), nv.getWidth(), nv.getHeight() );
  759. graphView.add( nv );
  760. }
  761. for( LayeredGraphEdge e : gNode.getContainedEdges() )
  762. {
  763. EdgeView ev = new EdgeView( e, lt );
  764. ev.setOpaque( true );
  765. graphView.add( ev );
  766. }
  767. return graphView;
  768. }
  769. }