001 package org.shiftone.jrat.provider.tree.ui.trace.graph; 002 003 004 import org.shiftone.jrat.core.MethodKey; 005 import org.shiftone.jrat.provider.tree.ui.TraceTreeNode; 006 import org.shiftone.jrat.provider.tree.ui.trace.PercentColorLookup; 007 import org.shiftone.jrat.util.log.Logger; 008 009 import javax.swing.*; 010 import java.awt.*; 011 import java.awt.geom.Rectangle2D; 012 import java.text.DecimalFormat; 013 014 015 /** 016 * @author jeff@shiftone.org (Jeff Drost) 017 */ 018 public class TreeGraphComponent extends BufferedJComponent implements Scrollable { 019 020 private static final Logger LOG = Logger.getLogger(TreeGraphComponent.class); 021 private TraceTreeNode node; 022 private Color LINE_COLOR = Color.LIGHT_GRAY; 023 private PercentColorLookup colorLookup = new PercentColorLookup(); 024 private DecimalFormat pctDecimalFormat = new DecimalFormat("#,###.#'%'"); 025 private Font font = new Font("SansSerif", Font.PLAIN, 9); 026 private int rowHeight = 12; 027 028 public TreeGraphComponent() { 029 setDoubleBuffered(false); 030 setBackground(Color.WHITE); 031 } 032 033 034 protected void paintBuffer(Graphics2D g) { 035 036 Graphics2D g2d = (Graphics2D) g; 037 038 g.setColor(getBackground()); 039 g.fillRect(0, 0, getWidth(), getHeight()); 040 041 if ((node != null) && !node.isRootNode() && (node.getTotalExits() != 0)) { 042 paint(g2d, node, 0, 0, getWidth()); 043 } 044 } 045 046 047 /** 048 * @todo clean up this ugly code 049 */ 050 private void paint(Graphics2D g, TraceTreeNode node, int x, int row, int width) { 051 052 g.setFont(font); 053 054 FontMetrics metrics = g.getFontMetrics(); 055 Color color = colorLookup.getColor(node.getPctOfAvgParentDuration()); 056 int height = metrics.getHeight() + metrics.getDescent(); 057 int y = row * height; 058 059 rowHeight = height; 060 061 g.setColor(color); 062 g.fill3DRect(x, y, width, height, true); 063 064 // print the text on the node 065 Graphics gg = g.create(x, y, width, height); 066 067 gg.setColor(Color.BLACK); 068 069 MethodKey methodKey = node.getMethodKey(); 070 String text = methodKey.getClassName() 071 + "." + methodKey.getMethodName() 072 + " " + pctDecimalFormat.format(node.getPctOfAvgRootDuration()); 073 074 Rectangle2D stringBounds = metrics.getStringBounds(text, g); 075 076 if (stringBounds.getWidth() < width) { 077 gg.drawString(text, (int) (width / 2 - stringBounds.getWidth() / 2), (int) (stringBounds.getHeight())); 078 } else { 079 text = methodKey.getMethodName() + " " + pctDecimalFormat.format(node.getPctOfAvgRootDuration()); 080 stringBounds = metrics.getStringBounds(text, g); 081 082 if (stringBounds.getWidth() < width) { 083 gg.drawString(text, (int) (width / 2 - stringBounds.getWidth() / 2), (int) (stringBounds.getHeight())); 084 } 085 } 086 087 // print the children 088 long total = node.getTotalDuration(); 089 090 if ((total > 0) && (node.getChildCount() > 0)) { 091 int childX = 0; 092 093 for (int i = 0; i < node.getChildCount(); i++) { 094 TraceTreeNode child = (TraceTreeNode) node.getChildAt(i); 095 long part = child.getTotalDuration(); 096 int partWidth = (int) ((part * (long) width) / total); 097 098 if (partWidth > 1) { 099 paint(g, child, x + childX, row + 1, partWidth); 100 } else { 101 g.setColor(LINE_COLOR); 102 g.drawLine(x + childX, (row + 1) * height, x + childX, (row + 1 + node.getMaxDepth()) * height); 103 } 104 105 childX += partWidth; 106 } 107 } 108 } 109 110 111 public synchronized void setStackTreeNode(TraceTreeNode node) { 112 113 //LOG.info("setStackTreeNode " + node + " " + node.getMaxDepth()); 114 this.node = node; 115 116 dataChanged(); 117 setPreferredSize(new Dimension(getWidth(), (int) (rowHeight * node.getMaxDepth()))); 118 setSize(getPreferredSize()); 119 // LOG.info("getPreferredSize " + getPreferredSize()); 120 if (isVisible()) { 121 repaint(); 122 } 123 } 124 125 126 public Dimension getPreferredScrollableViewportSize() { 127 return getPreferredSize(); 128 } 129 130 131 public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) { 132 return (int) rowHeight; 133 } 134 135 136 public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) { 137 return (int) rowHeight; 138 } 139 140 141 public boolean getScrollableTracksViewportWidth() { 142 return true; 143 } 144 145 146 public boolean getScrollableTracksViewportHeight() { 147 return false; 148 } 149 }