PseudoCodeNode.java 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. package processor;
  2. import java.awt.Rectangle;
  3. import javax.swing.JTree;
  4. import javax.swing.SwingUtilities;
  5. import javax.swing.tree.DefaultMutableTreeNode;
  6. import javax.swing.tree.MutableTreeNode;
  7. import javax.swing.tree.TreePath;
  8. import codeline.CodeLine;
  9. import lib.TextLayoutHelper;
  10. /**
  11. * represents a line of pseudocode
  12. * @author kolja
  13. *
  14. */
  15. public class PseudoCodeNode extends DefaultMutableTreeNode {
  16. private static final long serialVersionUID = 7366822030747482541L;
  17. public static enum CodeAction
  18. {
  19. SKIP,
  20. STOP,
  21. CONTINUE
  22. }
  23. private static int nextNodeId = 0;
  24. private final int nodeId;
  25. private ProcessController controller;
  26. private JTree tree;
  27. private CodeLine code;
  28. private boolean selected;
  29. private boolean breakPoint;
  30. public PseudoCodeNode( String description, String[] vars, JTree tree, CodeLine line )
  31. {
  32. super( TextLayoutHelper.setupPseudoCode( description, vars ) );
  33. synchronized( PseudoCodeNode.class )
  34. {
  35. nodeId = nextNodeId++;
  36. }
  37. selected = false;
  38. this.tree = tree;
  39. breakPoint = false;
  40. code = line;
  41. }
  42. public int getId()
  43. {
  44. return nodeId;
  45. }
  46. public void setController( ProcessController c )
  47. {
  48. if( children != null )
  49. {
  50. for( Object ch : children )
  51. {
  52. ((PseudoCodeNode)ch).setController( c );
  53. }
  54. }
  55. controller = c;
  56. }
  57. @Override
  58. public void add( MutableTreeNode node )
  59. {
  60. ((PseudoCodeNode)node).setController( controller );
  61. super.add( node );
  62. }
  63. /**
  64. *
  65. * @return the tree that this node belongs to
  66. */
  67. public JTree getTree()
  68. {
  69. return tree;
  70. }
  71. /**
  72. * checks if this node should be highlighted
  73. * @return true if it should, false otherwise
  74. */
  75. public boolean isSelected()
  76. {
  77. return selected;
  78. }
  79. /**
  80. * checks if one of the subnodes of this node is selected.
  81. * @return true if one is, false otherwise
  82. */
  83. public boolean hasSelectedSubnode()
  84. {
  85. if( children != null )
  86. {
  87. for( Object ch : children )
  88. {
  89. if( ((PseudoCodeNode)ch).isSelected() || ((PseudoCodeNode)ch).hasSelectedSubnode() )
  90. return true;
  91. }
  92. }
  93. return false;
  94. }
  95. private void expandToRoot()
  96. {
  97. if( parent != null )
  98. ((PseudoCodeNode)parent).expandToRoot();
  99. tree.expandPath( new TreePath( this.getPath() ) );
  100. }
  101. /**
  102. * highlight this line of pseudocode.
  103. * should be called when the line is entered, as it triggers breakpoints
  104. * @param selected whether to select or deselect this line
  105. * @return if the automatic execution should continue.
  106. */
  107. public CodeAction setSelected( boolean selected )
  108. {
  109. if( selected && breakPoint )
  110. controller.setContinuous( false );
  111. this.selected = selected;
  112. if( selected )
  113. {
  114. if( tree != null ) {
  115. TreePath path = new TreePath( getPath() );
  116. Rectangle bounds = tree.getPathBounds(path);
  117. if( bounds!= null )
  118. {
  119. bounds.height = (int) (tree.getVisibleRect().height - tree.getVisibleRect().getHeight() / 2);
  120. bounds.x = 0;
  121. SwingUtilities.invokeLater( new Runnable() {
  122. @Override
  123. public void run() {
  124. tree.scrollRectToVisible(bounds);
  125. }
  126. });
  127. }
  128. }
  129. if( controller == null || controller.getStepOption() != 1 || breakPoint )
  130. {
  131. SwingUtilities.invokeLater( new Runnable() {
  132. @Override
  133. public void run() {
  134. expandToRoot();
  135. }
  136. });
  137. }
  138. }
  139. else
  140. {
  141. if( controller == null || controller.getStepOption() != 1 )
  142. {
  143. SwingUtilities.invokeLater( new Runnable() {
  144. @Override
  145. public void run() {
  146. tree.collapsePath( new TreePath( getPath() ) );
  147. }
  148. });
  149. }
  150. }
  151. if( breakPoint && selected )
  152. return CodeAction.STOP; // Breakpoint
  153. if( controller != null && controller.getStepOption() == 1 && !tree.isVisible( new TreePath( this.getPath() ) ) )
  154. return CodeAction.SKIP; // Step would be to detailed
  155. return CodeAction.CONTINUE; // Normal
  156. }
  157. /**
  158. * set a breakpoint at this line of code
  159. * @param breakPoint whether there should be a breakpoint or node
  160. */
  161. public void setBreakPoint( boolean breakPoint )
  162. {
  163. this.breakPoint = breakPoint;
  164. }
  165. /**
  166. * check if there is a breakpoint set at this line of code
  167. * @return true, iff there is a breakpoint
  168. */
  169. public boolean hasBreakPoint()
  170. {
  171. return breakPoint;
  172. }
  173. public ControlFlow forwardStep( Memory m )
  174. {
  175. ControlFlow cf = code.runForward( m );
  176. cf.setJumpBack( this );
  177. return cf;
  178. }
  179. public ControlFlow emptyForwardStep( Memory m )
  180. {
  181. code.createEmptyBackwardsAction();
  182. ControlFlow cf = new ControlFlow( ControlFlow.STEP_OVER );
  183. cf.setJumpBack( this );
  184. return cf;
  185. }
  186. public void backwardStep( Memory m )
  187. {
  188. code.runBackward( m );
  189. }
  190. public String getDebugOutput( Memory m )
  191. {
  192. if( parent == null )
  193. return "";
  194. return ((PseudoCodeNode)parent).getDebugOutput( m );
  195. }
  196. }