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 }