1 package net.sourceforge.pmd.util.designer; 2 3 import net.sourceforge.pmd.ast.ASTMethodDeclaration; 4 import net.sourceforge.pmd.ast.SimpleNode; 5 import net.sourceforge.pmd.dfa.IDataFlowNode; 6 import net.sourceforge.pmd.dfa.variableaccess.VariableAccess; 7 import net.sourceforge.pmd.util.LineGetter; 8 import net.sourceforge.pmd.util.StringUtil; 9 10 import javax.swing.*; 11 import javax.swing.event.ListSelectionEvent ; 12 import javax.swing.event.ListSelectionListener ; 13 import java.awt.BorderLayout ; 14 import java.awt.Color ; 15 import java.awt.Dimension ; 16 import java.awt.FontMetrics ; 17 import java.awt.Graphics ; 18 import java.util.Iterator ; 19 import java.util.List ; 20 21 public class DFAPanel extends JComponent implements ListSelectionListener { 22 23 public static class DFACanvas extends JPanel { 24 25 private static final int NODE_RADIUS = 12; 26 private static final int NODE_DIAMETER = 2 * NODE_RADIUS; 27 28 private SimpleNode node; 29 30 private int x = 150; 31 private int y = 50; 32 private LineGetter lines; 33 34 private void addAccessLabel(StringBuffer sb, VariableAccess va) { 35 36 if (va.isDefinition()) { 37 sb.append("d("); 38 } else if (va.isReference()) { 39 sb.append("r("); 40 } else if (va.isUndefinition()) { 41 sb.append("u("); 42 } else { 44 sb.append("?("); 45 } 46 47 sb.append(va.getVariableName()).append(')'); 48 } 49 50 private String childIndicesOf(IDataFlowNode node, String separator) { 51 52 List kids = node.getChildren(); 53 if (kids.isEmpty()) return ""; 54 55 StringBuffer sb = new StringBuffer (); 56 sb.append(((IDataFlowNode)kids.get(0)).getIndex()); 57 58 for (int j = 1; j < node.getChildren().size(); j++) { 59 sb.append(separator); 60 sb.append(((IDataFlowNode)kids.get(j)).getIndex()); 61 } 62 return sb.toString(); 63 } 64 65 private String [] deriveAccessLabels(List flow) { 66 67 if (flow == null || flow.isEmpty()) return StringUtil.EMPTY_STRINGS; 68 69 String [] labels = new String [flow.size()]; 70 71 for (int i=0; i<labels.length; i++) { 72 List access = ((IDataFlowNode) flow.get(i)).getVariableAccess(); 73 74 if (access == null || access.isEmpty()) { 75 continue; } 77 78 StringBuffer exp = new StringBuffer (); 79 addAccessLabel(exp, (VariableAccess) access.get(0)); 80 81 for (int k = 1; k < access.size(); k++) { 82 exp.append(", "); 83 addAccessLabel(exp, (VariableAccess) access.get(k)); 84 } 85 86 labels[i] = exp.toString(); 87 } 88 return labels; 89 } 90 91 private int maxWidthOf(String [] strings, FontMetrics fm) { 92 93 int max = 0; 94 String str; 95 96 for (int i=0; i<strings.length; i++) { 97 str = strings[i]; 98 if (str == null) continue; 99 max = Math.max(max, SwingUtilities.computeStringWidth(fm, str)); 100 } 101 return max; 102 } 103 104 105 public void paintComponent(Graphics g) { 106 super.paintComponent(g); 107 108 if (node == null) return; 109 110 List flow = node.getDataFlowNode().getFlow(); 111 FontMetrics fm = g.getFontMetrics(); 112 int halfFontHeight = fm.getAscent() / 2; 113 114 String [] accessLabels = deriveAccessLabels(flow); 115 int maxAccessLabelWidth = maxWidthOf(accessLabels, fm); 116 117 for (int i = 0; i < flow.size(); i++) { 118 IDataFlowNode inode = (IDataFlowNode) flow.get(i); 119 120 y = computeDrawPos(inode.getIndex()); 121 122 g.drawArc(x, y, NODE_DIAMETER, NODE_DIAMETER, 0, 360); 123 g.drawString(lines.getLine(inode.getLine()), x + 100 + maxAccessLabelWidth, y + 15); 124 125 String idx = String.valueOf(inode.getIndex()); 127 int halfWidth = SwingUtilities.computeStringWidth(fm, idx) / 2; 128 g.drawString(idx, x + NODE_RADIUS - halfWidth, y + NODE_RADIUS + halfFontHeight); 129 130 String accessLabel = accessLabels[i]; 131 if (accessLabel != null) { 132 g.drawString(accessLabel, x + 70, y + 15); 133 } 134 135 for (int j = 0; j < inode.getChildren().size(); j++) { 136 IDataFlowNode n = (IDataFlowNode) inode.getChildren().get(j); 137 drawMyLine(inode.getIndex(), n.getIndex(), g); 138 } 139 String childIndices = childIndicesOf(inode, ", "); 140 g.drawString(childIndices, x - 3 * NODE_DIAMETER, y + NODE_RADIUS - 2); 141 } 142 } 143 144 public void setCode(LineGetter h) { 145 this.lines = h; 146 } 147 148 public void setMethod(SimpleNode node) { 149 this.node = node; 150 } 151 152 private int computeDrawPos(int index) { 153 int z = NODE_RADIUS * 4; 154 return z + index * z; 155 } 156 157 private void drawArrow(Graphics g, int x, int y, int direction) { 158 159 final int height = NODE_RADIUS * 2/3; 160 final int width = NODE_RADIUS * 2/3; 161 162 switch (direction) { 163 case SwingConstants.NORTH : 164 g.drawLine(x, y, x - width/2, y + height); 165 g.drawLine(x, y, x + width/2, y + height); 166 break; 167 case SwingConstants.SOUTH : 168 g.drawLine(x, y, x - width/2, y - height); 169 g.drawLine(x, y, x + width/2, y - height); 170 break; 171 case SwingConstants.EAST : 172 g.drawLine(x, y, x - height, y - width/2); 173 g.drawLine(x, y, x - height, y + width/2); 174 break; 175 case SwingConstants.WEST : 176 g.drawLine(x, y, x + height, y - width/2); 177 g.drawLine(x, y, x + height, y + width/2); 178 } 179 } 180 181 private void drawMyLine(int index1, int index2, Graphics g) { 182 int y1 = this.computeDrawPos(index1); 183 int y2 = this.computeDrawPos(index2); 184 185 int arrow = 6; 186 187 if (index1 < index2) { 188 if (index2 - index1 == 1) { 189 x += NODE_RADIUS; 190 g.drawLine(x, y1 + NODE_DIAMETER, x, y2); 191 drawArrow(g, x, y2, SwingConstants.SOUTH); 193 x -= NODE_RADIUS; 194 } else if (index2 - index1 > 1) { 195 y1 = y1 + NODE_RADIUS; 196 y2 = y2 + NODE_RADIUS; 197 int n = ((index2 - index1 - 2) * 10) + 10; 198 g.drawLine(x, y1, x - n, y1); 199 g.drawLine(x - n, y1, x - n, y2); 200 g.drawLine(x - n, y2, x, y2); 201 drawArrow(g, x,y2, SwingConstants.EAST); 203 } 204 205 } else { 206 if (index1 - index2 > 1) { 207 y1 = y1 + NODE_RADIUS; 208 y2 = y2 + NODE_RADIUS; 209 x = x + NODE_DIAMETER; 210 int n = ((index1 - index2 - 2) * 10) + 10; 211 g.drawLine(x, y1, x + n, y1); 212 g.drawLine(x + n, y1, x + n, y2); 213 g.drawLine(x + n, y2, x, y2); 214 drawArrow(g, x, y2, SwingConstants.WEST); 216 x = x - NODE_DIAMETER; 217 } else if (index1 - index2 == 1) { 218 y2 = y2 + NODE_DIAMETER; 219 g.drawLine(x + NODE_RADIUS, y2, x + NODE_RADIUS, y1); 220 drawArrow(g, x + NODE_RADIUS, y2, SwingConstants.NORTH); 222 } 223 } 224 } 225 } 226 227 private static class ElementWrapper { 228 private ASTMethodDeclaration node; 229 230 public ElementWrapper(ASTMethodDeclaration node) { 231 this.node = node; 232 } 233 234 public ASTMethodDeclaration getNode() { 235 return node; 236 } 237 238 public String toString() { 239 return node.getMethodName(); 240 } 241 } 242 243 private DFACanvas dfaCanvas; 244 private JList nodeList; 245 private DefaultListModel nodes = new DefaultListModel(); 246 247 public DFAPanel() { 248 super(); 249 250 setLayout(new BorderLayout ()); 251 JPanel leftPanel = new JPanel(); 252 253 nodeList = new JList(nodes); 254 nodeList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 255 nodeList.setFixedCellWidth(150); 256 nodeList.setBorder(BorderFactory.createLineBorder(Color.black)); 257 nodeList.addListSelectionListener(this); 258 259 leftPanel.add(nodeList); 260 add(leftPanel, BorderLayout.WEST); 261 262 dfaCanvas = new DFACanvas(); 263 dfaCanvas.setBackground(Color.WHITE); 264 dfaCanvas.setPreferredSize(new Dimension (900, 1400)); 265 266 JScrollPane scrollPane = new JScrollPane(dfaCanvas); 267 268 add(scrollPane, BorderLayout.CENTER); 269 } 270 271 public void valueChanged(ListSelectionEvent event) { 272 ElementWrapper wrapper = null; 273 if (nodes.size() == 1) { 274 wrapper = (ElementWrapper) nodes.get(0); 275 } else if (nodes.isEmpty()) { 276 return; 277 } else if (nodeList.getSelectedValue() == null) { 278 wrapper = (ElementWrapper) nodes.get(0); 279 } else { 280 wrapper = (ElementWrapper) nodeList.getSelectedValue(); 281 } 282 dfaCanvas.setMethod(wrapper.getNode()); 283 dfaCanvas.repaint(); 284 } 285 286 public void resetTo(List newNodes, LineGetter lines) { 287 dfaCanvas.setCode(lines); 288 nodes.clear(); 289 for (Iterator i = newNodes.iterator(); i.hasNext();) { 290 nodes.addElement(new ElementWrapper((ASTMethodDeclaration) i.next())); 291 } 292 nodeList.setSelectedIndex(0); 293 dfaCanvas.setMethod((SimpleNode) newNodes.get(0)); 294 repaint(); 295 } 296 } 297 | Popular Tags |