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.HasLines;
8
9 import javax.swing.*;
10 import javax.swing.event.ListSelectionEvent;
11 import javax.swing.event.ListSelectionListener;
12 import java.awt.BorderLayout;
13 import java.awt.Canvas;
14 import java.awt.Color;
15 import java.awt.Dimension;
16 import java.awt.Graphics;
17 import java.util.Iterator;
18 import java.util.List;
19
20 public class DFAPanel extends JComponent implements ListSelectionListener {
21
22 public static class DFACanvas extends Canvas {
23
24 private static final int NODE_RADIUS = 10;
25 private static final int NODE_DIAMETER = 2 * NODE_RADIUS;
26
27 private SimpleNode node;
28
29 private int x = 150;
30 private int y = 50;
31 private HasLines lines;
32
33 public void paint(Graphics g) {
34 super.paint(g);
35 if (node == null) {
36 return;
37 }
38 List flow = node.getDataFlowNode().getFlow();
39 for (int i = 0; i < flow.size(); i++) {
40 IDataFlowNode inode = (IDataFlowNode) flow.get(i);
41
42 y = computeDrawPos(inode.getIndex());
43
44 g.drawArc(x, y, NODE_DIAMETER, NODE_DIAMETER, 0, 360);
45 g.drawString(lines.getLine(inode.getLine()), x + 200, y + 15);
46
47
48 String idx = String.valueOf(inode.getIndex());
49 int hack = 4 * (idx.length() / 2);
50 g.drawString(idx, x + NODE_RADIUS - 2 - hack, y + NODE_RADIUS + 4);
51
52 List access = inode.getVariableAccess();
53 if (access != null) {
54 StringBuffer exp = new StringBuffer();
55 for (int k = 0; k < access.size(); k++) {
56 VariableAccess va = (VariableAccess) access.get(k);
57 if (va.isDefinition()) {
58 exp.append("d(");
59 } else if (va.isReference()) {
60 exp.append("r(");
61 } else if (va.isUndefinition()) {
62 exp.append("u(");
63
64 } else {
65 exp.append("?(");
66 }
67 exp.append(va.getVariableName() + "), ");
68 }
69 g.drawString(exp.toString(), x + 70, y + 15);
70 }
71
72 for (int j = 0; j < inode.getChildren().size(); j++) {
73 IDataFlowNode n = (IDataFlowNode) inode.getChildren().get(j);
74 this.drawMyLine(inode.getIndex(), n.getIndex(), g);
75 String output = (j == 0 ? "" : ",") + String.valueOf(n.getIndex());
76 g.drawString(output, x - 3 * NODE_DIAMETER + (j * 20), y + NODE_RADIUS - 2);
77 }
78 }
79 }
80
81 public void setCode(HasLines h) {
82 this.lines = h;
83 }
84
85 public void setMethod(SimpleNode node) {
86 this.node = node;
87 }
88
89 private int computeDrawPos(int index) {
90 int z = NODE_RADIUS * 4;
91 return z + index * z;
92 }
93
94 private void drawMyLine(int index1, int index2, Graphics g) {
95 int y1 = this.computeDrawPos(index1);
96 int y2 = this.computeDrawPos(index2);
97
98 int arrow = 3;
99
100 if (index1 < index2) {
101 if (index2 - index1 == 1) {
102 x += NODE_RADIUS;
103 g.drawLine(x, y1 + NODE_DIAMETER, x, y2);
104 g.fillRect(x - arrow, y2 - arrow, arrow * 2, arrow * 2);
105 x -= NODE_RADIUS;
106 } else if (index2 - index1 > 1) {
107 y1 = y1 + NODE_RADIUS;
108 y2 = y2 + NODE_RADIUS;
109 int n = ((index2 - index1 - 2) * 10) + 10;
110 g.drawLine(x, y1, x - n, y1);
111 g.drawLine(x - n, y1, x - n, y2);
112 g.drawLine(x - n, y2, x, y2);
113 g.fillRect(x - arrow, y2 - arrow, arrow * 2, arrow * 2);
114 }
115
116 } else {
117 if (index1 - index2 > 1) {
118 y1 = y1 + NODE_RADIUS;
119 y2 = y2 + NODE_RADIUS;
120 x = x + NODE_DIAMETER;
121 int n = ((index1 - index2 - 2) * 10) + 10;
122 g.drawLine(x, y1, x + n, y1);
123 g.drawLine(x + n, y1, x + n, y2);
124 g.drawLine(x + n, y2, x, y2);
125 g.fillRect(x - arrow, y2 - arrow, arrow * 2, arrow * 2);
126 x = x - NODE_DIAMETER;
127 } else if (index1 - index2 == 1) {
128 y2 = y2 + NODE_DIAMETER;
129 g.drawLine(x + NODE_RADIUS, y2, x + NODE_RADIUS, y1);
130 g.fillRect(x + NODE_RADIUS - arrow, y2 - arrow, arrow * 2, arrow * 2);
131 }
132 }
133 }
134 }
135
136 private static class ElementWrapper {
137 private ASTMethodDeclaration node;
138
139 public ElementWrapper(ASTMethodDeclaration node) {
140 this.node = node;
141 }
142
143 public ASTMethodDeclaration getNode() {
144 return node;
145 }
146
147 public String toString() {
148 return node.getMethodName();
149 }
150 }
151
152 private DFACanvas dfaCanvas;
153 private JList nodeList;
154 private DefaultListModel nodes = new DefaultListModel();
155 private JPanel wrapperPanel;
156
157 public DFAPanel() {
158 super();
159
160 setLayout(new BorderLayout());
161 JPanel leftPanel = new JPanel();
162 nodeList = new JList(nodes);
163 nodeList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
164 nodeList.setFixedCellWidth(150);
165 nodeList.setBorder(BorderFactory.createLineBorder(Color.black));
166 nodeList.addListSelectionListener(this);
167 leftPanel.add(nodeList);
168 add(leftPanel, BorderLayout.WEST);
169
170 dfaCanvas = new DFACanvas();
171 JScrollPane scrollPane = new JScrollPane();
172 scrollPane.setPreferredSize(new Dimension(800, 450));
173 dfaCanvas.setSize(2000, 4000);
174 scrollPane.add(dfaCanvas);
175 wrapperPanel = new JPanel();
176 wrapperPanel.add(scrollPane);
177 wrapperPanel.setBorder(BorderFactory.createLineBorder(Color.black));
178 add(wrapperPanel, BorderLayout.EAST);
179 }
180
181 public void valueChanged(ListSelectionEvent event) {
182 ElementWrapper wrapper = null;
183 if (nodes.size() == 1) {
184 wrapper = (ElementWrapper) nodes.get(0);
185 } else if (nodes.isEmpty()) {
186 return;
187 } else if (nodeList.getSelectedValue() == null) {
188 wrapper = (ElementWrapper) nodes.get(0);
189 } else {
190 wrapper = (ElementWrapper) nodeList.getSelectedValue();
191 }
192 dfaCanvas.setMethod(wrapper.getNode());
193 dfaCanvas.repaint();
194 }
195
196 public void resetTo(List newNodes, HasLines lines) {
197 dfaCanvas.setCode(lines);
198 nodes.clear();
199 for (Iterator i = newNodes.iterator(); i.hasNext();) {
200 nodes.addElement(new ElementWrapper((ASTMethodDeclaration) i.next()));
201 }
202 nodeList.setSelectedIndex(0);
203 dfaCanvas.setMethod((SimpleNode) newNodes.get(0));
204 repaint();
205 }
206 }
207