package view; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import javax.swing.ImageIcon; import javax.swing.JTree; import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.TreeNode; import animation.Memory; import animation.Memory.MemoryType; import animation.PseudoCodeNode; import graph.LayeredGraphEdge; import graph.LayeredGraphNode; import lib.TextLayoutHelper; /** * A tree-like display of pseudocode. * Extends {@link DefaultTreeCellRenderer} * @author kolja * */ public class PseudoCodeRenderer extends DefaultTreeCellRenderer { private static final long serialVersionUID = 1L; private static ImageIcon currentLine = new ImageIcon( PseudoCodeNode.class.getResource( "/img/current_line.png" ) ); private Color specialColor = null; private Memory mem; private String toolTip = ""; public void setMemory( Memory m ) { mem = m; } @Override public Color getBackgroundNonSelectionColor() { if(specialColor != null) { return specialColor; } else { return RenderHelper.BACKGROUND_COLOR; } } @Override public Color getForeground() { return new Color(0xa9b7c6); } private int countChildren( TreeNode treeNode ) { if( treeNode.isLeaf() ) return 0; else { int sum = 0; for( int i = 0; i < treeNode.getChildCount(); i++ ) { sum += countChildren( treeNode.getChildAt( i ) ) + 1; } return sum; } } private int getLineNumber( TreeNode treeNode ) { TreeNode parent = treeNode.getParent(); if( parent == null ) return 1; int sum = getLineNumber( parent ) + 1; for( int i = 0; i < parent.getChildCount(); i++ ) { if( i == parent.getIndex( treeNode ) ) return sum; sum += countChildren( parent.getChildAt( i ) ) + 1; } return 0; } @Override public Font getFont() { return new Font("Monospaced", Font.PLAIN, 12); } @Override public String getToolTipText() { return toolTip; } @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean arg2, boolean arg3, boolean arg4, int arg5, boolean arg6) { PseudoCodeNode node = (PseudoCodeNode) value; int width = 10; if( !node.hasSelectedSubnode() && node.isSelected() ) width += 25; if( node.hasBreakPoint() ) width += 15; String line = "" + getLineNumber( (TreeNode) value ); width += tree.getFontMetrics( this.getFont() ).stringWidth( line ); this.setPreferredSize( new Dimension( width + tree.getFontMetrics( this.getFont() ).stringWidth( (String)node.getUserObject() ) + 5, 30 ) ); this.setSize( new Dimension( width + tree.getFontMetrics( this.getFont() ).stringWidth( (String)node.getUserObject() ) + 5, 30 ) ); this.doLayout(); BufferedImage rowNumerImg = new BufferedImage( width, 30, BufferedImage.TYPE_INT_ARGB ); Graphics2D g = (Graphics2D) rowNumerImg.getGraphics(); int x = 5; if( !node.hasSelectedSubnode() && node.isSelected() ) { g.drawImage( currentLine.getImage(), x, 5, 20, 20, null ); x += 25; } g.setColor( RenderHelper.CURRENT_LINE_COLOR ); g.drawString( line, x, 20 ); x += g.getFontMetrics().stringWidth( line ) + 5; if( node.hasBreakPoint() ) { g.setColor( new Color (0xe7887a) ); g.fillOval(x, 10, 10, 10 ); } g.dispose(); this.setClosedIcon( new ImageIcon( rowNumerImg ) ); this.setOpenIcon( new ImageIcon( rowNumerImg ) ); this.setLeafIcon( new ImageIcon( rowNumerImg ) ); super.getTreeCellRendererComponent(tree, value, arg2, arg3, arg4, arg5, arg6); specialColor = null; if(node.isSelected()) { specialColor = new Color(0x2d6099); } else if (node.hasBreakPoint()) { specialColor = RenderHelper.BREAKPOINT_COLOR; } setText((String)node.getUserObject()); toolTip = ""; for( String var : TextLayoutHelper.getVariables( (String)node.getUserObject() ) ) { if( mem != null && mem.isSomewhereDefined( var, MemoryType.LOCAL ) ) { Object val = mem.read( var, MemoryType.LOCAL ); toolTip += var + "=" + val.toString() + "
"; } } if( toolTip.equals( "" ) ) toolTip += "no variables found in the stack"; else toolTip = toolTip.substring( 0, toolTip.length() - 4 ); toolTip += ""; return this; } }