Clover coverage report - PMD - 3.9 Coverage timestamp: Tue Dec 19 2006 09:38:44 EST FRAMES NO FRAMES |
file stats: | LOC: | 296 |  | Methods: | 16
| NCLOC: | 230 |  | Classes: | 3
Source file | Conditionals | Statements | Methods | TOTAL
DFAPanel.java | 0% | 0% | 0% | 0% |

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